Skip to content

Commit

Permalink
feat: cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Elvis339 committed Sep 19, 2023
1 parent 476940d commit 59b7c9e
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 93 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
num-traits = "0.2.16"
num-bigint = "0.4.3"
25 changes: 25 additions & 0 deletions src/ecc/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use std::fmt;
use std::fmt::Formatter;

#[derive(Debug, Clone, PartialEq)]
pub enum FieldElementError {
FieldNotInRange(String),
InvalidField(String),
PointNotOnTheCurve(String),
}

impl fmt::Display for FieldElementError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
FieldElementError::FieldNotInRange(err) => {
write!(f, "FieldNotInRange({})", err)
}
FieldElementError::InvalidField(err) => {
write!(f, "InvalidField({})", err)
}
FieldElementError::PointNotOnTheCurve(err) => {
write!(f, "PointNotOnTheCurve({})", err)
}
}
}
}
168 changes: 132 additions & 36 deletions src/ecc/field_element.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
use num_bigint::BigInt;
use std::fmt;
use std::ops::{Add, Div, Mul, Sub};

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

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

/// 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.
/// 2. Additive identity; means that 0 exists and has the property a + 0 = a
/// 3. Multiplicative identity; means 1 exists and has the property a * 1 = a
/// 4. Additive inverse; means if a is in the set, -a is in the set,
/// which is defined as the value that makes a + (-a) = 0

#[derive(Debug, Clone)]
pub struct FieldElement {
num: BigInt,
prime: BigInt,
}

impl FieldElement {
pub fn new(num: i64, prime: i64) -> Result<FieldElement, String> {
pub fn new(num: i64, prime: i64) -> Result<FieldElement, FieldElementError> {

Check warning on line 23 in src/ecc/field_element.rs

View workflow job for this annotation

GitHub Actions / Compile

associated items `new` and `convert` are never used
if num >= prime || num < 0 {
return Err(format!("Num {} not in field range 0 to {}", num, prime - 1));
return Err(FieldElementError::FieldNotInRange(format!(
"Num {} not in field range 0 to {}",
num,
prime - 1
)));
}
Ok(FieldElement {
num: BigInt::from(num),
Expand All @@ -38,8 +45,8 @@ impl FieldElement {
pub fn pow_mod(&self, exponent: BigInt) -> FieldElement {
let mut n = exponent;
let prime = &self.prime;
while n < BigInt::from(0) {
n += prime - 1;
while n < BigInt::zero() {
n += prime - BigInt::one();
}
let num = self.num.modpow(&n, &prime);
FieldElement {
Expand All @@ -56,9 +63,13 @@ impl FieldElement {
Ok((num, prime))
}

pub fn construct_from(num: BigInt, prime: BigInt) -> Result<FieldElement, String> {
if num >= prime || num < BigInt::from(0) {
return Err(format!("Num {} not in field range 0 to {}", num, prime - 1));
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 })
}
Expand All @@ -76,71 +87,144 @@ impl PartialEq for FieldElement {
}
}

// To satisfy `closed` property one of the tools we can use to make a finite field closed under addition,
// subtraction, multiplication, and division is modulo arithmetic.

/// a + b = (a + b) % p
impl Add for FieldElement {
type Output = Result<FieldElement, String>;
type Output = Result<FieldElement, FieldElementError>;

fn add(self, rhs: Self) -> Self::Output {
if self.prime != rhs.prime {
return Err("Cannot add two numbers in different Fields.".to_string());
return Err(FieldElementError::InvalidField(
"Cannot add two numbers in different Fields.".to_string(),
));
}
let prime = self.prime;
let add = self.num + rhs.num;
let num = add % prime.clone();
Ok(FieldElement { num, prime })
let num = add % &self.prime;
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

impl Add<&FieldElement> for FieldElement {
type Output = Result<FieldElement, FieldElementError>;

fn add(self, rhs: &FieldElement) -> Self::Output {
if self.prime != rhs.prime {
return Err(FieldElementError::InvalidField(
"Cannot add two numbers in different Fields.".to_string(),
));
}
let add = self.num + &rhs.num;
let num = add % &self.prime;
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

/// a - b = (a - b) % p
impl Sub for FieldElement {
type Output = Result<FieldElement, String>;
type Output = Result<FieldElement, FieldElementError>;

fn sub(self, rhs: Self) -> Self::Output {
if self.prime != rhs.prime {
return Err("Cannot subtract two numbers in different Fields.".to_string());
return Err(FieldElementError::InvalidField(
"Cannot subtract two numbers in different Fields.".to_string(),
));
}
let prime = self.prime;
let sub = self.num - rhs.num;
let mut num = sub % prime.clone();
let mut num = sub % &self.prime;

if num < BigInt::from(0) {
num += prime.clone();
if num < BigInt::zero() {
num += &self.prime;
}

Ok(FieldElement { num, prime })
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

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

fn sub(self, rhs: &FieldElement) -> Self::Output {
if self.prime != rhs.prime {
return Err(FieldElementError::InvalidField(
"Cannot subtract two numbers in different Fields.".to_string(),
));
}
let sub = &self.num - &rhs.num;
let mut num = sub % &self.prime;

if num < BigInt::zero() {
num += &self.prime;
}

Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

/// a * b = (a * b) % p
impl Mul for FieldElement {
type Output = Result<FieldElement, String>;
type Output = Result<FieldElement, FieldElementError>;

fn mul(self, rhs: Self) -> Self::Output {
if self.prime != rhs.prime {
return Err("Cannot multiply two numbers in different Fields.".to_string());
return Err(FieldElementError::InvalidField(
"Cannot multiply two numbers in different Fields.".to_string(),
));
}
let prime = self.prime;
let mul = self.num * rhs.num;
let num = mul % prime.clone();
Ok(FieldElement { num, prime })
let num = mul % &self.prime;
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

impl Mul<&FieldElement> for FieldElement {
type Output = Result<FieldElement, FieldElementError>;

fn mul(self, rhs: &FieldElement) -> Self::Output {
if self.prime != rhs.prime {
return Err(FieldElementError::InvalidField(
"Cannot multiply two numbers in different Fields.".to_string(),
));
}
let mul = self.num * &rhs.num;
let num = mul % &self.prime;
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

// p = 19
// 2/7 = 2*7^(19-2) = 2 * 7^17 = 465261027974414 % 19 = 3
impl Div for FieldElement {
type Output = Result<FieldElement, String>;
type Output = Result<FieldElement, FieldElementError>;

fn div(self, rhs: Self) -> Self::Output {
if self.prime != rhs.prime {
return Err("Cannot multiply two numbers in different Fields.".to_string());
return Err(FieldElementError::InvalidField(
"Cannot multiply two numbers in different Fields.".to_string(),
));
}
let prime = self.prime;
let num = self.num * rhs.num.modpow(&prime.clone().sub(2), &prime) % prime.clone();
Ok(FieldElement { num, prime })
let exp = &self.prime - BigInt::from(2u8);
let num = self.num * rhs.num.modpow(&exp, &self.prime) % &self.prime;
Ok(FieldElement {
num,
prime: self.prime.clone(),
})
}
}

Expand All @@ -152,6 +236,15 @@ mod tests {
FieldElement::new(num, prime).unwrap()
}

#[test]
fn err() {
assert!(FieldElement::new(5, 3).is_err());
assert!(FieldElement::new(3, 3).is_err());
assert!((new_fe(2, 31) + new_fe(2, 7)).is_err());
assert!((new_fe(2, 31) - new_fe(2, 7)).is_err());
assert!((new_fe(2, 31) * new_fe(2, 7)).is_err());
}

#[test]
fn equality_test() {
let prime = 31;
Expand Down Expand Up @@ -201,12 +294,15 @@ mod tests {
fn pow_mod_test() {
let prime = 31;
let a = new_fe(17, prime.clone());
assert_eq!(a.pow_mod(BigInt::from(3)), new_fe(15, prime.clone()));
assert_eq!(a.pow_mod(BigInt::from(3u8)), new_fe(15, prime.clone()));

let b = new_fe(5, prime.clone());
let c = new_fe(18, prime.clone());

assert_eq!((b.pow_mod(BigInt::from(5)) * c).unwrap(), new_fe(16, prime));
assert_eq!(
(b.pow_mod(BigInt::from(5u8)) * c).unwrap(),
new_fe(16, prime)
);
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions src/ecc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod field_element;
mod point;
mod scalar;
mod error;
Loading

0 comments on commit 59b7c9e

Please sign in to comment.