Skip to content

Commit

Permalink
feat(secp256k1)
Browse files Browse the repository at this point in the history
  • Loading branch information
Elvis339 committed Sep 21, 2023
1 parent 911d16b commit 8d4deea
Show file tree
Hide file tree
Showing 9 changed files with 688 additions and 246 deletions.
46 changes: 46 additions & 0 deletions src/ecc/abstractions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use std::fmt::Display;
use std::ops::{Add, Div, Mul, Sub};

use num_bigint::BigInt;
use num_traits::{One, Zero};

use crate::ecc::error::FieldElementError;

pub type ArithmeticResult<T> = Result<T, FieldElementError>;

pub trait FieldElementTrait:
Sized
+ Display
+ PartialEq
+ Add<Output = ArithmeticResult<Self>>
+ for<'a> Add<&'a Self, Output = ArithmeticResult<Self>>
+ Sub<Output = ArithmeticResult<Self>>
+ for<'a> Sub<&'a Self, Output = ArithmeticResult<Self>>
+ Mul<Output = ArithmeticResult<Self>>
+ for<'a> Mul<&'a Self, Output = ArithmeticResult<Self>>
+ Div<Output = ArithmeticResult<Self>>
+ for<'a> Div<&'a Self, Output = ArithmeticResult<Self>>
{
fn get_num(&self) -> &BigInt;
fn get_prime(&self) -> &BigInt;
fn from_values(num: BigInt, prime: BigInt) -> Result<Self, FieldElementError>;

fn pow_mod(&self, exponent: BigInt) -> Self {
let mut n = exponent;
let prime: &BigInt = self.get_prime();
while n < BigInt::zero() {
n += prime - BigInt::one();
}
let num = self.get_num().modpow(&n, prime);
Self::from_values(num, prime.clone()).expect("invalid params")
}

fn check_primes(&self, other: &Self) -> Result<(), FieldElementError> {
if *self.get_prime() != *other.get_prime() {
return Err(FieldElementError::InvalidField(
"Operands belong to different fields.".to_string(),
));
}
Ok(())
}
}
224 changes: 120 additions & 104 deletions src/ecc/field_element.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,13 @@
use std::fmt;
use std::fmt::{Display, Formatter};
use std::ops::{Add, Div, Mul, Sub};

use num_bigint::BigInt;
use num_traits::{One, Zero};
use num_traits::Zero;

use crate::ecc::abstractions::{ArithmeticResult, FieldElementTrait};
use crate::ecc::error::FieldElementError;

pub type PrimeCheck = Result<FieldElement, FieldElementError>;

macro_rules! arithmetic_op {
($trait:ident, $method:ident, $op:tt) => {
impl $trait for FieldElement {
type Output = PrimeCheck;

fn $method(self, rhs: Self) -> Self::Output {
self.check_primes(&rhs)?;
let op = self.num $op rhs.num;
let num = op % &self.prime;
Ok(FieldElement { num, prime: self.prime.clone() })
}
}

impl $trait<&FieldElement> for FieldElement {
type Output = PrimeCheck;

fn $method(self, rhs: &FieldElement) -> Self::Output {
self.check_primes(rhs)?;
let op = self.num $op &rhs.num;
let num = op % &self.prime;
Ok(FieldElement { num, prime: self.prime.clone() })
}
}

impl<'a, 'b> $trait<&'b FieldElement> for &'a FieldElement {
type Output = PrimeCheck;

fn $method(self, rhs: &'b FieldElement) -> Self::Output {
self.check_primes(rhs)?;
let op = &self.num $op &rhs.num;
let num = op % &self.prime;
Ok(FieldElement { num, prime: self.prime.clone() })
}
}
};
}

/// Finite Field Definition
/// A finite field is defined as a finite set of numbers and two operations `+` and `*` and properties:
/// 1. Closed property; means if a and b are in the set, a + b and a * b are in the set.
Expand All @@ -58,6 +21,28 @@ pub struct FieldElement {
prime: BigInt,
}

impl FieldElementTrait for FieldElement {
fn get_num(&self) -> &BigInt {
&self.num
}

fn get_prime(&self) -> &BigInt {
&self.prime
}

fn from_values(num: BigInt, prime: BigInt) -> Result<FieldElement, FieldElementError> {
if num >= prime || num < BigInt::zero() {
return Err(FieldElementError::FieldNotInRange(format!(
"Num {} not in field range 0 to {}",
num,
prime - 1
)));
}

Ok(Self { num, prime })
}
}

impl FieldElement {
pub fn new(num: i64, prime: i64) -> Result<FieldElement, FieldElementError> {
if num >= prime || num < 0 {
Expand All @@ -72,74 +57,64 @@ impl FieldElement {
prime: BigInt::from(prime),
})
}
}

fn check_primes(&self, other: &FieldElement) -> Result<(), FieldElementError> {
if self.prime != other.prime {
return Err(FieldElementError::InvalidField(
"Operands belong to different fields.".to_string(),
));
}
Ok(())
impl Display for FieldElement {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "FieldElement_{}({})", self.prime, self.num)
}
}

pub fn get_num(&self) -> &BigInt {
&self.num
impl PartialEq for FieldElement {
fn eq(&self, other: &Self) -> bool {
self.num.eq(&other.num) && self.prime.eq(&other.prime)
}
}

pub fn get_prime(&self) -> &BigInt {
&self.prime
}
impl Add for FieldElement {
type Output = ArithmeticResult<FieldElement>;

pub fn pow_mod(&self, exponent: BigInt) -> FieldElement {
let mut n = exponent;
let prime = &self.prime;
while n < BigInt::zero() {
n += prime - BigInt::one();
}
let num = self.num.modpow(&n, &prime);
FieldElement {
fn add(self, rhs: Self) -> Self::Output {
self.check_primes(&rhs)?;
let res = self.num + rhs.num;
let num = res % &self.prime;
Ok(FieldElement {
num,
prime: prime.clone(),
}
prime: self.prime.clone(),
})
}
}

pub fn convert<T: TryFrom<BigInt>>(&self) -> Result<(T, T), &'static str> {
let num = T::try_from(self.num.clone()).map_err(|_| "Overflow while converting num!")?;
let prime =
T::try_from(self.prime.clone()).map_err(|_| "Overflow while converting prime!")?;

Ok((num, prime))
}
impl<'a> Add<&'a FieldElement> for FieldElement {
type Output = ArithmeticResult<FieldElement>;

pub fn construct_from(num: BigInt, prime: BigInt) -> Result<FieldElement, FieldElementError> {
if num >= prime || num < BigInt::zero() {
return Err(FieldElementError::FieldNotInRange(format!(
"Num {} not in field range 0 to {}",
num,
prime - BigInt::one()
)));
}
Ok(Self { num, prime })
fn add(self, rhs: &'a Self) -> Self::Output {
self.check_primes(rhs)?;
let res = &self.num + rhs.get_num(); // Assuming get_num() returns &BigInt
let num = res % &self.prime; // Assuming get_prime() returns &BigInt
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

impl fmt::Display for FieldElement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FieldElement_{}({})", self.prime, self.num)
}
}
impl<'a, 'b> Add<&'b FieldElement> for &'a FieldElement {
type Output = ArithmeticResult<FieldElement>;

impl PartialEq for FieldElement {
fn eq(&self, other: &Self) -> bool {
self.num.eq(&other.num) && self.prime.eq(&other.prime)
fn add(self, rhs: &'b FieldElement) -> Self::Output {
self.check_primes(rhs)?;
let res = self.get_num() + rhs.get_num(); // Assuming get_num() returns &BigInt
let num = res % self.get_prime(); // Assuming get_prime() returns &BigInt
Ok(FieldElement {
num,
prime: self.get_prime().clone(),
})
}
}

arithmetic_op!(Add, add, +);
arithmetic_op!(Mul, mul, *);

impl Sub for FieldElement {
type Output = Result<FieldElement, FieldElementError>;
type Output = ArithmeticResult<FieldElement>;

fn sub(self, rhs: Self) -> Self::Output {
self.check_primes(&rhs)?;
Expand All @@ -157,12 +132,12 @@ impl Sub for FieldElement {
}
}

impl Sub<&FieldElement> for FieldElement {
type Output = Result<FieldElement, FieldElementError>;
impl<'a> Sub<&'a FieldElement> for FieldElement {
type Output = ArithmeticResult<FieldElement>;

fn sub(self, rhs: &FieldElement) -> Self::Output {
self.check_primes(rhs)?;
let sub = &self.num - &rhs.num;
fn sub(self, rhs: &'a Self) -> Self::Output {
self.check_primes(&rhs)?;
let sub = &self.num - rhs.get_num();
let mut num = sub % &self.prime;

if num < BigInt::zero() {
Expand All @@ -177,7 +152,7 @@ impl Sub<&FieldElement> for FieldElement {
}

impl<'a, 'b> Sub<&'b FieldElement> for &'a FieldElement {
type Output = Result<FieldElement, FieldElementError>;
type Output = ArithmeticResult<FieldElement>;

fn sub(self, rhs: &'b FieldElement) -> Self::Output {
self.check_primes(rhs)?;
Expand All @@ -195,10 +170,50 @@ impl<'a, 'b> Sub<&'b FieldElement> for &'a FieldElement {
}
}

// p = 19
// 2/7 = 2*7^(19-2) = 2 * 7^17 = 465261027974414 % 19 = 3
impl Mul for FieldElement {
type Output = ArithmeticResult<FieldElement>;

fn mul(self, rhs: Self) -> Self::Output {
self.check_primes(&rhs)?;
let res = self.num * rhs.num;
let num = res % &self.prime;
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

impl<'a> Mul<&'a FieldElement> for FieldElement {
type Output = ArithmeticResult<FieldElement>;

fn mul(self, rhs: &'a Self) -> Self::Output {
self.check_primes(&rhs)?;
let res = &self.num * rhs.get_num();
let num = res % &self.prime;
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

impl<'a, 'b> Mul<&'b FieldElement> for &'a FieldElement {
type Output = ArithmeticResult<FieldElement>;

fn mul(self, rhs: &'b FieldElement) -> Self::Output {
self.check_primes(&rhs)?;
let res = &self.num * &rhs.num;
let num = res % &self.prime;
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

impl Div for FieldElement {
type Output = Result<FieldElement, FieldElementError>;
type Output = ArithmeticResult<FieldElement>;

fn div(self, rhs: Self) -> Self::Output {
if self.prime != rhs.prime {
Expand All @@ -215,17 +230,17 @@ impl Div for FieldElement {
}
}

impl Div<&FieldElement> for FieldElement {
type Output = Result<FieldElement, FieldElementError>;
impl<'a> Div<&'a FieldElement> for FieldElement {
type Output = ArithmeticResult<FieldElement>;

fn div(self, rhs: &FieldElement) -> Self::Output {
fn div(self, rhs: &'a Self) -> Self::Output {
if self.prime != rhs.prime {
return Err(FieldElementError::InvalidField(
"Cannot divide two numbers in different Fields.".to_string(),
));
}
let exp = &self.prime - BigInt::from(2u8);
let num = self.num * rhs.num.modpow(&exp, &self.prime) % &self.prime;
let num = &self.num * rhs.get_num().modpow(&exp, &self.prime) % &self.prime;
Ok(FieldElement {
num,
prime: self.prime.clone(),
Expand All @@ -234,7 +249,7 @@ impl Div<&FieldElement> for FieldElement {
}

impl<'a, 'b> Div<&'b FieldElement> for &'a FieldElement {
type Output = Result<FieldElement, FieldElementError>;
type Output = ArithmeticResult<FieldElement>;

fn div(self, rhs: &'b FieldElement) -> Self::Output {
if self.prime != rhs.prime {
Expand Down Expand Up @@ -285,6 +300,7 @@ mod tests {
let prime = 31;
let a = new_fe(2, prime.clone());
let b = new_fe(15, prime.clone());
assert_eq!((&a + &b).unwrap(), new_fe(17, prime.clone()));
assert_eq!((a + b).unwrap(), new_fe(17, prime.clone()));

let c = new_fe(17, prime.clone());
Expand Down
2 changes: 2 additions & 0 deletions src/ecc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ mod field_element;
mod scalar;
mod error;
mod point;
mod abstractions;
mod s256_field;
3 changes: 2 additions & 1 deletion src/ecc/point/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mod point;
mod point;
mod s256_point;
Loading

0 comments on commit 8d4deea

Please sign in to comment.