From 48990fe3f5c00a95d835afe899d4bda90b4027d5 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sun, 14 Jul 2024 03:14:13 -0400 Subject: [PATCH] feat: optimized modular addition --- Cargo.toml | 5 +- src/finite_field.rs | 116 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 +- 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 src/finite_field.rs diff --git a/Cargo.toml b/Cargo.toml index 4843ee6..340cec2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +hex-literal = "0.4.1" +num-traits = "0.2.19" +subtle = "2.6.1" [lib] -[dev-dependencies] \ No newline at end of file +[dev-dependencies] diff --git a/src/finite_field.rs b/src/finite_field.rs new file mode 100644 index 0000000..8bcb47c --- /dev/null +++ b/src/finite_field.rs @@ -0,0 +1,116 @@ +use num_traits::{Inv, One, Zero}; +use std::ops::{Add, Div, Mul, Neg, Sub}; + +// A finite field over the +struct FiniteField { + modulus: [usize; L], + value: [usize; L], +} + +impl FiniteField { + fn new(modulus: [usize; L], value: [usize; L]) -> Self { + Self { modulus, value } + } +} + +/// Addition in a finite field Z_p is modular addition. +impl Add for FiniteField { + type Output = Self; + + fn add(self, other: Self) -> Self { + // Initialize sum to zero + let mut sum = Self::new(self.modulus, [0; L]); + let mut carry = false; + + // Perform addition with carry propagation + for i in 0..L { + let sum_with_other = self.value[i].overflowing_add(other.value[i]); + let sum_with_carry = sum_with_other.0.overflowing_add(if carry { 1 } else { 0 }); + sum.value[i] = sum_with_carry.0; + carry = sum_with_other.1 | sum_with_carry.1; + } + + // Perform trial subtraction of modulus + let mut trial = Self::new(self.modulus, [0; L]); + let mut borrow = false; + for i in 0..L { + // Note: a single overflowing_sub is enough because modulus[i]+borrow can never overflow + let diff_with_borrow = + sum.value[i].overflowing_sub(self.modulus[i] + if borrow { 1 } else { 0 }); + trial.value[i] = diff_with_borrow.0; + borrow = diff_with_borrow.1; + } + + // Select between sum and trial based on borrow flag + let mut result = Self::new(self.modulus, [0; L]); + let select_mask = usize::from(borrow).wrapping_neg(); + for i in 0..L { + // If borrow is true (select_mask is all 1s), choose sum, otherwise choose trial + result.value[i] = (!select_mask & trial.value[i]) | (select_mask & sum.value[i]); + } + result + } +} + +// The additive identity +impl Zero for FiniteField { + fn zero() -> Self { + todo!("Implement zero for FiniteField") + } + + fn is_zero(&self) -> bool { + todo!("Implement is_zero for FiniteField") + } +} + +// Negation in a finite field is the additive inverse +impl Neg for FiniteField { + type Output = Self; + + fn neg(self) -> Self { + todo!("Implement negation for FiniteField") + } +} + +/// Subtraction in a finite field is addition by the additive inverse +impl Sub for FiniteField { + type Output = Self; + + fn sub(self, other: Self) -> Self { + todo!("Implement subtraction for FiniteField") + } +} + +/// Multiplication in a finite field Z_p is modular multiplication. +impl Mul for FiniteField { + type Output = Self; + + fn mul(self, other: Self) -> Self { + todo!("Implement multiplication for FiniteField") + } +} + +/// The multiplicative identity +impl One for FiniteField { + fn one() -> Self { + todo!("Implement one for FiniteField") + } +} + +/// The multiplicative inverse +impl Inv for FiniteField { + type Output = Self; + + fn inv(self) -> Self { + todo!("Implement inversion for FiniteField") + } +} + +/// Division in a finite field is multiplication by the multiplicative inverse +impl Div for FiniteField { + type Output = Self; + + fn div(self, other: Self) -> Self { + todo!("Implement division for FiniteField") + } +} diff --git a/src/lib.rs b/src/lib.rs index 8b13789..e81e508 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1 @@ - +mod finite_field;