Skip to content

Commit

Permalink
add mul and div for secp256k1 using order
Browse files Browse the repository at this point in the history
  • Loading branch information
hmzdot committed Mar 4, 2023
1 parent 0abd047 commit d278706
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 22 deletions.
73 changes: 59 additions & 14 deletions src/elliptic_curve/secp256k1.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
use std::{fmt::Display, ops::Mul};
use std::{
fmt::Display,
ops::{Div, Mul},
};

use num_bigint::BigUint;

use super::{curve::Curve, point::Point};
use crate::finite_fields::{element::Felt, modulo::Modulo};
use crate::finite_fields::{element::Felt, macros::impl_refs, modulo::Modulo};

#[derive(Debug, Clone, PartialEq)]
pub struct Secp256k1Felt(Felt);

impl Secp256k1Felt {
pub const SECP256K1_PRIME: &[u8; 64] =
b"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F";
pub const SECP256K1_ORDER: &[u8; 64] =
b"fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141";

pub fn order() -> BigUint {
BigUint::parse_bytes(Self::SECP256K1_ORDER, 16).unwrap_or_default()
}

pub fn prime() -> BigUint {
BigUint::parse_bytes(Self::SECP256K1_PRIME, 16).unwrap()
BigUint::parse_bytes(Self::SECP256K1_PRIME, 16).unwrap_or_default()
}

pub fn new(inner: BigUint) -> Self {
Self(Felt::new(inner, Self::prime()))
}

pub fn inner(&self) -> &Felt {
&self.0
pub fn inner(&self) -> &BigUint {
self.0.inner()
}
}

Expand All @@ -33,10 +42,40 @@ impl From<Secp256k1Felt> for Felt {

impl Display for Secp256k1Felt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:0>64}", self.0.inner())
write!(f, "0x{value:0>64}", value = self.inner().to_str_radix(16))
}
}

impl Mul<Secp256k1Felt> for Secp256k1Felt {
type Output = Secp256k1Felt;

fn mul(self, rhs: Secp256k1Felt) -> Self::Output {
let order = Self::order();
let one = BigUint::from(1u64);
let result = self.0.inner().mul(rhs.0.inner()).modpow(&one, &order);

Self::new(result)
}
}

impl_refs!(Mul, mul, Secp256k1Felt, Secp256k1Felt);

impl Div<Secp256k1Felt> for Secp256k1Felt {
type Output = Secp256k1Felt;

//
fn div(self, rhs: Secp256k1Felt) -> Self::Output {
let one = BigUint::from(1u32);
let exponent = Self::order() - BigUint::from(2u32);
let rhs_inner = rhs.0.inner().modpow(&exponent, &Self::order());
let result = (self.inner() * rhs_inner).modpow(&one, &Self::order());

Self::new(result)
}
}

impl_refs!(Div, div, Secp256k1Felt, Secp256k1Felt);

#[derive(Debug, Clone, PartialEq)]
pub struct Secp256k1Point(Point);

Expand All @@ -49,7 +88,7 @@ impl Secp256k1Point {
b"483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8";

pub fn order() -> BigUint {
BigUint::parse_bytes(Self::SECP256K1_ORDER, 16).unwrap()
BigUint::parse_bytes(Self::SECP256K1_ORDER, 16).unwrap_or_default()
}

pub fn curve() -> Curve {
Expand All @@ -61,11 +100,17 @@ impl Secp256k1Point {

pub fn g() -> Self {
Self::new(
BigUint::parse_bytes(Self::SECP256K1_X, 16).unwrap(),
BigUint::parse_bytes(Self::SECP256K1_Y, 16).unwrap(),
BigUint::parse_bytes(Self::SECP256K1_X, 16).unwrap_or_default(),
BigUint::parse_bytes(Self::SECP256K1_Y, 16).unwrap_or_default(),
)
}

/// Creates a new point on SECP256K1 curve
///
/// # Panics
///
/// Panics if x and y combination is not on the curve
///
pub fn new(x: BigUint, y: BigUint) -> Self {
let curve = Self::curve();
let point = curve
Expand All @@ -86,8 +131,8 @@ impl Mul<u32> for Secp256k1Point {
type Output = Self;

/// Multiplies a secp256k1 point by a scalar
///
/// Since we know the order of the curve generated by the point, we can use take the
///
/// Since we know the order of the curve generated by the point, we can use take the
/// modulo of the scalar as `n * G` is identity
fn mul(self, coefficient: u32) -> Self::Output {
let coefficient = BigUint::from(coefficient).modulo(&Self::order());
Expand All @@ -99,11 +144,11 @@ impl Mul<BigUint> for Secp256k1Point {
type Output = Self;

/// Multiplies a secp256k1 point by a scalar
///
/// Since we know the order of the curve generated by the point, we can use take the
///
/// Since we know the order of the curve generated by the point, we can use take the
/// modulo of the scalar as `n * G` is identity
fn mul(self, coefficient: BigUint) -> Self::Output {
let coefficient = coefficient.modulo(&Self::order());
Self(self.0 * coefficient)
}
}
}
12 changes: 4 additions & 8 deletions src/finite_fields/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl Mul for Felt {
type Output = Self;

fn mul(self, rhs: Self) -> Self::Output {
let result = (self.inner * rhs.inner).modulo(&self.prime);
let result = (self.inner * rhs.inner).modulo(&self.prime);
Self::new(result, self.prime)
}
}
Expand All @@ -121,7 +121,7 @@ impl Div for Felt {

fn div(self, rhs: Self) -> Self::Output {
let exponent = &self.prime - BigUint::from(2u32);
let result = (self.inner * rhs.inner.pow(exponent.try_into().unwrap())).modulo(&self.prime);
let result = (self.inner * rhs.inner.modpow(&exponent, &self.prime)).modulo(&self.prime);
Self::new(result, self.prime)
}
}
Expand Down Expand Up @@ -157,17 +157,13 @@ impl Pow<i64> for Felt {
fn pow(&self, exponent: i64) -> Self::Output {
let inner = if exponent > 0 {
let exponent = BigUint::from(u32::try_from(exponent).unwrap());
self.inner
.pow(exponent.try_into().unwrap())
.modulo(&self.prime)
self.inner.modpow(&exponent, &self.prime)
} else {
// In finite fields we can use the following property:
// a^(-1) = a^(p-2) (mod p)
let prime = &self.prime - BigUint::from(1u32);
let exponent = prime - BigUint::from(u32::try_from(exponent.abs()).unwrap());
self.inner
.pow(exponent.try_into().unwrap())
.modulo(&self.prime)
self.inner.modpow(&exponent, &self.prime)
};

Felt::new(inner, self.prime.clone())
Expand Down

0 comments on commit d278706

Please sign in to comment.