From 351b92f31f5d86a91275276d14c4d4f0a5bdc0dd Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 5 Oct 2021 18:02:08 -0700 Subject: [PATCH 01/13] progress towards Secp256K1Base field --- src/field/mod.rs | 1 + src/field/secp256k1.rs | 257 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 src/field/secp256k1.rs diff --git a/src/field/mod.rs b/src/field/mod.rs index 60948d48..cd8a53e2 100644 --- a/src/field/mod.rs +++ b/src/field/mod.rs @@ -8,6 +8,7 @@ pub(crate) mod interpolation; mod inversion; pub(crate) mod packable; pub(crate) mod packed_field; +pub mod secp256k1; #[cfg(target_feature = "avx2")] pub(crate) mod packed_avx2; diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs new file mode 100644 index 00000000..336e9c26 --- /dev/null +++ b/src/field/secp256k1.rs @@ -0,0 +1,257 @@ +use itertools::Itertools; +use num::bigint::BigUint; +use num::{Integer, One, Zero}; +use std::convert::TryInto; +use std::fmt; +use std::fmt::{Debug, Display, Formatter}; +use std::hash::{Hash, Hasher}; +use std::iter::{Product, Sum}; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use rand::Rng; +use serde::{Deserialize, Serialize}; + +use crate::field::field_types::{Field, PrimeField}; +use crate::field::goldilocks_field::GoldilocksField; + +/// EPSILON = 9 * 2**28 - 1 +const EPSILON: u64 = 2415919103; + +/// A field designed for use with the Crandall reduction algorithm. +/// +/// Its order is +/// ```ignore +/// P = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1 +/// ``` +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct Secp256K1Base(pub [u32; 8]); + +impl Secp256K1Base { + const ORDER_BIGUINT: BigUint = BigUint::from_slice(&[ + 0xFFFFFC2F, + 0xFFFFFFFE, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + ]); + + fn to_canonical_biguint(&self) -> BigUint { + BigUint::from_slice(&self.0).mod_floor(&Self::ORDER_BIGUINT) + } + + fn from_biguint(val: BigUint) -> Self { + Self(val.to_u32_digits().iter().cloned().pad_using(8, |_| 0).collect::>()[..8].try_into().expect("error converting to u32 array; should never happen")) + } +} + +impl Default for Secp256K1Base { + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Secp256K1Base { + fn eq(&self, other: &Self) -> bool { + self.to_canonical_biguint() == other.to_canonical_biguint() + } +} + +impl Eq for Secp256K1Base {} + +impl Hash for Secp256K1Base { + fn hash(&self, state: &mut H) { + self.to_canonical_biguint().iter_u64_digits().for_each(|digit| state.write_u64(digit)) + } +} + +impl Display for Secp256K1Base { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&self.to_canonical_biguint(), f) + } +} + +impl Debug for Secp256K1Base { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.to_canonical_biguint(), f) + } +} + +impl Field for Secp256K1Base { + // TODO: fix + type PrimeField = GoldilocksField; + + const ZERO: Self = Self::from_biguint(BigUint::zero()); + const ONE: Self = Self::from_biguint(BigUint::one()); + const TWO: Self = Self::from_biguint(BigUint::one() + BigUint::one()); + const NEG_ONE: Self = Self::from_biguint(Self::ORDER_BIGUINT - BigUint::one()); + + // TODO: fix + const CHARACTERISTIC: u64 = 0; + const TWO_ADICITY: usize = 1; + + const MULTIPLICATIVE_GROUP_GENERATOR: Self = todo!();//Self(5); + const POWER_OF_TWO_GENERATOR: Self = todo!();//Self(10281950781551402419); + + fn order() -> BigUint { + Self::ORDER_BIGUINT + } + + fn try_inverse(&self) -> Option { + if self.is_zero() { + return None; + } + + // Fermat's Little Theorem + Some(self.exp_biguint(&(Self::ORDER_BIGUINT - BigUint::one() - BigUint::one()))) + } + + #[inline] + fn from_canonical_u64(n: u64) -> Self { + Self([n as u32, (n >> 32) as u32, 0, 0, 0, 0, 0, 0]) + } + + #[inline] + fn from_noncanonical_u128(n: u128) -> Self { + Self([ + n as u32, + (n >> 32) as u32, + (n >> 64) as u32, + (n >> 96) as u32, + 0, + 0, + 0, + 0, + ]) + } + + #[inline] + fn from_noncanonical_u96(n: (u64, u32)) -> Self { + Self([ + n.0 as u32, + (n.0 >> 32) as u32, + n.1, + 0, + 0, + 0, + 0, + 0, + ]) + } + + fn rand_from_rng(rng: &mut R) -> Self { + let mut array = [0u32; 8]; + rng.fill(&mut array); + let mut rand_biguint = BigUint::from_slice(&array); + while rand_biguint > Self::ORDER_BIGUINT { + rng.fill(&mut array); + rand_biguint = BigUint::from_slice(&array); + } + Self(array) + } +} + +impl Neg for Secp256K1Base { + type Output = Self; + + #[inline] + fn neg(self) -> Self { + if self.is_zero() { + Self::ZERO + } else { + Self::from_biguint(Self::ORDER_BIGUINT - self.to_canonical_biguint()) + } + } +} + +impl Add for Secp256K1Base { + type Output = Self; + + #[inline] + + fn add(self, rhs: Self) -> Self { + let mut result = self.to_canonical_biguint() + rhs.to_canonical_biguint(); + if result > Self::ORDER_BIGUINT { + result -= Self::ORDER_BIGUINT; + } + Self::from_biguint(result) + } +} + +impl AddAssign for Secp256K1Base { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +impl Sum for Secp256K1Base { + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |acc, x| acc + x) + } +} + +impl Sub for Secp256K1Base { + type Output = Self; + + #[inline] + #[allow(clippy::suspicious_arithmetic_impl)] + fn sub(self, rhs: Self) -> Self { + Self::from_biguint(self.to_canonical_biguint() + Self::ORDER_BIGUINT - rhs.to_canonical_biguint()) + } +} + +impl SubAssign for Secp256K1Base { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +impl Mul for Secp256K1Base { + type Output = Self; + + #[inline] + fn mul(self, rhs: Self) -> Self { + Self::from_biguint((self.to_canonical_biguint() * rhs.to_canonical_biguint()).mod_floor(&Self::ORDER_BIGUINT)) + } +} + +impl MulAssign for Secp256K1Base { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } +} + +impl Product for Secp256K1Base { + #[inline] + fn product>(iter: I) -> Self { + iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE) + } +} + +impl Div for Secp256K1Base { + type Output = Self; + + #[allow(clippy::suspicious_arithmetic_impl)] + fn div(self, rhs: Self) -> Self::Output { + self * rhs.inverse() + } +} + +impl DivAssign for Secp256K1Base { + fn div_assign(&mut self, rhs: Self) { + *self = *self / rhs; + } +} + +#[cfg(test)] +mod tests { + use crate::{test_field_arithmetic, test_prime_field_arithmetic}; + + test_prime_field_arithmetic!(crate::field::secp256k1::Secp256K1Base); + test_field_arithmetic!(crate::field::secp256k1::Secp256K1Base); +} From 1262c6afd0aa2e165cea5abd2d8bf5be00f11801 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 5 Oct 2021 21:32:18 -0700 Subject: [PATCH 02/13] fixes --- src/field/secp256k1.rs | 54 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index 336e9c26..9d963b2b 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -27,17 +27,6 @@ const EPSILON: u64 = 2415919103; pub struct Secp256K1Base(pub [u32; 8]); impl Secp256K1Base { - const ORDER_BIGUINT: BigUint = BigUint::from_slice(&[ - 0xFFFFFC2F, - 0xFFFFFFFE, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - ]); - fn to_canonical_biguint(&self) -> BigUint { BigUint::from_slice(&self.0).mod_floor(&Self::ORDER_BIGUINT) } @@ -83,20 +72,39 @@ impl Field for Secp256K1Base { // TODO: fix type PrimeField = GoldilocksField; - const ZERO: Self = Self::from_biguint(BigUint::zero()); - const ONE: Self = Self::from_biguint(BigUint::one()); - const TWO: Self = Self::from_biguint(BigUint::one() + BigUint::one()); - const NEG_ONE: Self = Self::from_biguint(Self::ORDER_BIGUINT - BigUint::one()); + const ZERO: Self = Self([0; 8]); + const ONE: Self = Self([1, 0, 0, 0, 0, 0, 0, 0]); + const TWO: Self = Self([2, 0, 0, 0, 0, 0, 0, 0]); + const NEG_ONE: Self = Self([ + 0xFFFFFC2E, + 0xFFFFFFFE, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + ]); // TODO: fix const CHARACTERISTIC: u64 = 0; const TWO_ADICITY: usize = 1; - const MULTIPLICATIVE_GROUP_GENERATOR: Self = todo!();//Self(5); + // Sage: `g = GF(p).multiplicative_generator()` + const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0, 0, 0, 0, 0]); const POWER_OF_TWO_GENERATOR: Self = todo!();//Self(10281950781551402419); fn order() -> BigUint { - Self::ORDER_BIGUINT + BigUint::from_slice(&[ + 0xFFFFFC2F, + 0xFFFFFFFE, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + ]) } fn try_inverse(&self) -> Option { @@ -105,7 +113,7 @@ impl Field for Secp256K1Base { } // Fermat's Little Theorem - Some(self.exp_biguint(&(Self::ORDER_BIGUINT - BigUint::one() - BigUint::one()))) + Some(self.exp_biguint(&(Self::order() - BigUint::one() - BigUint::one()))) } #[inline] @@ -145,7 +153,7 @@ impl Field for Secp256K1Base { let mut array = [0u32; 8]; rng.fill(&mut array); let mut rand_biguint = BigUint::from_slice(&array); - while rand_biguint > Self::ORDER_BIGUINT { + while rand_biguint > Self::order() { rng.fill(&mut array); rand_biguint = BigUint::from_slice(&array); } @@ -161,7 +169,7 @@ impl Neg for Secp256K1Base { if self.is_zero() { Self::ZERO } else { - Self::from_biguint(Self::ORDER_BIGUINT - self.to_canonical_biguint()) + Self::from_biguint(Self::order() - self.to_canonical_biguint()) } } } @@ -173,8 +181,8 @@ impl Add for Secp256K1Base { fn add(self, rhs: Self) -> Self { let mut result = self.to_canonical_biguint() + rhs.to_canonical_biguint(); - if result > Self::ORDER_BIGUINT { - result -= Self::ORDER_BIGUINT; + if result > Self::order() { + result -= Self::order(); } Self::from_biguint(result) } @@ -199,7 +207,7 @@ impl Sub for Secp256K1Base { #[inline] #[allow(clippy::suspicious_arithmetic_impl)] fn sub(self, rhs: Self) -> Self { - Self::from_biguint(self.to_canonical_biguint() + Self::ORDER_BIGUINT - rhs.to_canonical_biguint()) + Self::from_biguint(self.to_canonical_biguint() + Self::order() - rhs.to_canonical_biguint()) } } From a4c89201f3613d572afa0fbf427b9117c0035859 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 5 Oct 2021 21:32:23 -0700 Subject: [PATCH 03/13] fmt --- src/field/secp256k1.rs | 54 ++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index 9d963b2b..b975214b 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -1,6 +1,3 @@ -use itertools::Itertools; -use num::bigint::BigUint; -use num::{Integer, One, Zero}; use std::convert::TryInto; use std::fmt; use std::fmt::{Debug, Display, Formatter}; @@ -8,6 +5,9 @@ use std::hash::{Hash, Hasher}; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use itertools::Itertools; +use num::bigint::BigUint; +use num::{Integer, One, Zero}; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -32,7 +32,15 @@ impl Secp256K1Base { } fn from_biguint(val: BigUint) -> Self { - Self(val.to_u32_digits().iter().cloned().pad_using(8, |_| 0).collect::>()[..8].try_into().expect("error converting to u32 array; should never happen")) + Self( + val.to_u32_digits() + .iter() + .cloned() + .pad_using(8, |_| 0) + .collect::>()[..8] + .try_into() + .expect("error converting to u32 array; should never happen"), + ) } } @@ -52,7 +60,9 @@ impl Eq for Secp256K1Base {} impl Hash for Secp256K1Base { fn hash(&self, state: &mut H) { - self.to_canonical_biguint().iter_u64_digits().for_each(|digit| state.write_u64(digit)) + self.to_canonical_biguint() + .iter_u64_digits() + .for_each(|digit| state.write_u64(digit)) } } @@ -76,13 +86,7 @@ impl Field for Secp256K1Base { const ONE: Self = Self([1, 0, 0, 0, 0, 0, 0, 0]); const TWO: Self = Self([2, 0, 0, 0, 0, 0, 0, 0]); const NEG_ONE: Self = Self([ - 0xFFFFFC2E, - 0xFFFFFFFE, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, + 0xFFFFFC2E, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, ]); @@ -92,17 +96,11 @@ impl Field for Secp256K1Base { // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0, 0, 0, 0, 0]); - const POWER_OF_TWO_GENERATOR: Self = todo!();//Self(10281950781551402419); + const POWER_OF_TWO_GENERATOR: Self = todo!(); //Self(10281950781551402419); fn order() -> BigUint { BigUint::from_slice(&[ - 0xFFFFFC2F, - 0xFFFFFFFE, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, + 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, ]) } @@ -137,16 +135,7 @@ impl Field for Secp256K1Base { #[inline] fn from_noncanonical_u96(n: (u64, u32)) -> Self { - Self([ - n.0 as u32, - (n.0 >> 32) as u32, - n.1, - 0, - 0, - 0, - 0, - 0, - ]) + Self([n.0 as u32, (n.0 >> 32) as u32, n.1, 0, 0, 0, 0, 0]) } fn rand_from_rng(rng: &mut R) -> Self { @@ -223,7 +212,10 @@ impl Mul for Secp256K1Base { #[inline] fn mul(self, rhs: Self) -> Self { - Self::from_biguint((self.to_canonical_biguint() * rhs.to_canonical_biguint()).mod_floor(&Self::ORDER_BIGUINT)) + Self::from_biguint( + (self.to_canonical_biguint() * rhs.to_canonical_biguint()) + .mod_floor(&Self::ORDER_BIGUINT), + ) } } From 5e0d2744d78f08f137ddd4281eaaa3407e3b977d Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 5 Oct 2021 22:01:18 -0700 Subject: [PATCH 04/13] fixes --- src/field/secp256k1.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index b975214b..480413ff 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -28,7 +28,7 @@ pub struct Secp256K1Base(pub [u32; 8]); impl Secp256K1Base { fn to_canonical_biguint(&self) -> BigUint { - BigUint::from_slice(&self.0).mod_floor(&Self::ORDER_BIGUINT) + BigUint::from_slice(&self.0).mod_floor(&Self::order()) } fn from_biguint(val: BigUint) -> Self { @@ -96,7 +96,9 @@ impl Field for Secp256K1Base { // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0, 0, 0, 0, 0]); - const POWER_OF_TWO_GENERATOR: Self = todo!(); //Self(10281950781551402419); + + // Sage: `g_2 = g^((p - 1) / 2^32)` + const POWER_OF_TWO_GENERATOR: Self = Self::NEG_ONE; fn order() -> BigUint { BigUint::from_slice(&[ @@ -213,8 +215,7 @@ impl Mul for Secp256K1Base { #[inline] fn mul(self, rhs: Self) -> Self { Self::from_biguint( - (self.to_canonical_biguint() * rhs.to_canonical_biguint()) - .mod_floor(&Self::ORDER_BIGUINT), + (self.to_canonical_biguint() * rhs.to_canonical_biguint()).mod_floor(&Self::order()), ) } } From 69678f53fcfb6c5a1dc75c4744125feeb4a02606 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 5 Oct 2021 22:02:57 -0700 Subject: [PATCH 05/13] removed prime field tests --- src/field/secp256k1.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index 480413ff..dcf6410a 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -251,8 +251,7 @@ impl DivAssign for Secp256K1Base { #[cfg(test)] mod tests { - use crate::{test_field_arithmetic, test_prime_field_arithmetic}; + use crate::test_field_arithmetic; - test_prime_field_arithmetic!(crate::field::secp256k1::Secp256K1Base); test_field_arithmetic!(crate::field::secp256k1::Secp256K1Base); } From f79419cca33e363d62fa9a2372467900cce3617d Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 6 Oct 2021 09:50:02 -0700 Subject: [PATCH 06/13] add check to primitive_root_order field arithmetic test --- src/field/field_testing.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index 285af2ee..a1efa5f5 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -24,7 +24,8 @@ macro_rules! test_field_arithmetic { #[test] fn primitive_root_order() { - for n_power in 0..8 { + let max_power = 8.min(<$field>::TWO_ADICITY); + for n_power in 0..max_power { let root = <$field>::primitive_root_of_unity(n_power); let order = <$field>::generator_order(root); assert_eq!(order, 1 << n_power, "2^{}'th primitive root", n_power); From c625aae87b9dabb78643a6626ed27cb7dfa849a4 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 6 Oct 2021 11:09:51 -0700 Subject: [PATCH 07/13] cleanup and removed tests for now --- src/field/secp256k1.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index dcf6410a..c94b558e 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -7,15 +7,13 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi use itertools::Itertools; use num::bigint::BigUint; -use num::{Integer, One, Zero}; +use num::{Integer, One}; use rand::Rng; use serde::{Deserialize, Serialize}; -use crate::field::field_types::{Field, PrimeField}; +use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; -/// EPSILON = 9 * 2**28 - 1 -const EPSILON: u64 = 2415919103; /// A field designed for use with the Crandall reduction algorithm. /// @@ -247,11 +245,4 @@ impl DivAssign for Secp256K1Base { fn div_assign(&mut self, rhs: Self) { *self = *self / rhs; } -} - -#[cfg(test)] -mod tests { - use crate::test_field_arithmetic; - - test_field_arithmetic!(crate::field::secp256k1::Secp256K1Base); -} +} \ No newline at end of file From 097059e026e503b66ac2b1734ace1ddb87ce9c05 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 6 Oct 2021 11:20:11 -0700 Subject: [PATCH 08/13] switch to u64 array --- src/field/secp256k1.rs | 63 +++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index c94b558e..7f898cf1 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -14,7 +14,6 @@ use serde::{Deserialize, Serialize}; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; - /// A field designed for use with the Crandall reduction algorithm. /// /// Its order is @@ -22,22 +21,35 @@ use crate::field::goldilocks_field::GoldilocksField; /// P = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1 /// ``` #[derive(Copy, Clone, Serialize, Deserialize)] -pub struct Secp256K1Base(pub [u32; 8]); +pub struct Secp256K1Base(pub [u64; 4]); + +fn biguint_from_array(arr: [u64; 4]) -> BigUint { + BigUint::from_slice(&[ + arr[0] as u32, + (arr[0] >> 32) as u32, + arr[1] as u32, + (arr[1] >> 32) as u32, + arr[2] as u32, + (arr[2] >> 32) as u32, + arr[3] as u32, + (arr[3] >> 32) as u32, + ]) +} impl Secp256K1Base { fn to_canonical_biguint(&self) -> BigUint { - BigUint::from_slice(&self.0).mod_floor(&Self::order()) + biguint_from_array(self.0).mod_floor(&Self::order()) } fn from_biguint(val: BigUint) -> Self { Self( - val.to_u32_digits() + val.to_u64_digits() .iter() .cloned() - .pad_using(8, |_| 0) - .collect::>()[..8] + .pad_using(4, |_| 0) + .collect::>()[..4] .try_into() - .expect("error converting to u32 array; should never happen"), + .expect("error converting to u64 array; should never happen"), ) } } @@ -80,12 +92,14 @@ impl Field for Secp256K1Base { // TODO: fix type PrimeField = GoldilocksField; - const ZERO: Self = Self([0; 8]); - const ONE: Self = Self([1, 0, 0, 0, 0, 0, 0, 0]); - const TWO: Self = Self([2, 0, 0, 0, 0, 0, 0, 0]); + const ZERO: Self = Self([0; 4]); + const ONE: Self = Self([1, 0, 0, 0]); + const TWO: Self = Self([2, 0, 0, 0]); const NEG_ONE: Self = Self([ - 0xFFFFFC2E, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, + 0xFFFFFFFEFFFFFC2E, + 0xFFFFFFFFFFFFFFFF, + 0xFFFFFFFFFFFFFFFF, + 0xFFFFFFFFFFFFFFFF, ]); // TODO: fix @@ -93,7 +107,7 @@ impl Field for Secp256K1Base { const TWO_ADICITY: usize = 1; // Sage: `g = GF(p).multiplicative_generator()` - const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0, 0, 0, 0, 0]); + const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0]); // Sage: `g_2 = g^((p - 1) / 2^32)` const POWER_OF_TWO_GENERATOR: Self = Self::NEG_ONE; @@ -116,35 +130,26 @@ impl Field for Secp256K1Base { #[inline] fn from_canonical_u64(n: u64) -> Self { - Self([n as u32, (n >> 32) as u32, 0, 0, 0, 0, 0, 0]) + Self([n, 0, 0, 0]) } #[inline] fn from_noncanonical_u128(n: u128) -> Self { - Self([ - n as u32, - (n >> 32) as u32, - (n >> 64) as u32, - (n >> 96) as u32, - 0, - 0, - 0, - 0, - ]) + Self([n as u64, (n >> 64) as u64, 0, 0]) } #[inline] fn from_noncanonical_u96(n: (u64, u32)) -> Self { - Self([n.0 as u32, (n.0 >> 32) as u32, n.1, 0, 0, 0, 0, 0]) + Self([n.0, n.1 as u64, 0, 0]) } fn rand_from_rng(rng: &mut R) -> Self { - let mut array = [0u32; 8]; + let mut array = [0u64; 4]; rng.fill(&mut array); - let mut rand_biguint = BigUint::from_slice(&array); + let mut rand_biguint = biguint_from_array(array); while rand_biguint > Self::order() { rng.fill(&mut array); - rand_biguint = BigUint::from_slice(&array); + rand_biguint = biguint_from_array(array); } Self(array) } @@ -245,4 +250,4 @@ impl DivAssign for Secp256K1Base { fn div_assign(&mut self, rhs: Self) { *self = *self / rhs; } -} \ No newline at end of file +} From e8805a126a9bc183366e174cdf4ebb876b8a8e71 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 6 Oct 2021 11:22:21 -0700 Subject: [PATCH 09/13] fix --- src/field/secp256k1.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index 7f898cf1..42784706 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -44,8 +44,7 @@ impl Secp256K1Base { fn from_biguint(val: BigUint) -> Self { Self( val.to_u64_digits() - .iter() - .cloned() + .into_iter() .pad_using(4, |_| 0) .collect::>()[..4] .try_into() From b5fea8d1bbead3654e59d403968eea74467691a8 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 6 Oct 2021 11:24:24 -0700 Subject: [PATCH 10/13] addressed comments --- src/field/secp256k1.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index 42784706..41bdd6ac 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -46,9 +46,9 @@ impl Secp256K1Base { val.to_u64_digits() .into_iter() .pad_using(4, |_| 0) - .collect::>()[..4] + .collect::>()[..] .try_into() - .expect("error converting to u64 array; should never happen"), + .expect("error converting to u64 array"), ) } } @@ -69,9 +69,7 @@ impl Eq for Secp256K1Base {} impl Hash for Secp256K1Base { fn hash(&self, state: &mut H) { - self.to_canonical_biguint() - .iter_u64_digits() - .for_each(|digit| state.write_u64(digit)) + self.to_canonical_biguint().hash(state) } } @@ -108,7 +106,7 @@ impl Field for Secp256K1Base { // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0]); - // Sage: `g_2 = g^((p - 1) / 2^32)` + // Sage: `g_2 = g^((p - 1) / 2)` const POWER_OF_TWO_GENERATOR: Self = Self::NEG_ONE; fn order() -> BigUint { From 695a56c4cad994cd85bf85f7df6f1f1f2a756bfe Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 6 Oct 2021 11:34:50 -0700 Subject: [PATCH 11/13] addressed comments --- Cargo.toml | 2 +- src/field/secp256k1.rs | 15 ++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed5acab6..11aa6e40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ bimap = "0.4.0" env_logger = "0.9.0" log = "0.4.14" itertools = "0.10.0" -num = "0.4" +num = { version = "0.4", features = [ "rand" ] } rand = "0.8.4" rand_chacha = "0.3.1" rayon = "1.5.1" diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index 41bdd6ac..fb48dba0 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -6,7 +6,7 @@ use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use itertools::Itertools; -use num::bigint::BigUint; +use num::bigint::{BigUint, RandBigInt}; use num::{Integer, One}; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -141,14 +141,7 @@ impl Field for Secp256K1Base { } fn rand_from_rng(rng: &mut R) -> Self { - let mut array = [0u64; 4]; - rng.fill(&mut array); - let mut rand_biguint = biguint_from_array(array); - while rand_biguint > Self::order() { - rng.fill(&mut array); - rand_biguint = biguint_from_array(array); - } - Self(array) + Self::from_biguint(rng.gen_biguint_below(&Self::order())) } } @@ -172,7 +165,7 @@ impl Add for Secp256K1Base { fn add(self, rhs: Self) -> Self { let mut result = self.to_canonical_biguint() + rhs.to_canonical_biguint(); - if result > Self::order() { + if result >= Self::order() { result -= Self::order(); } Self::from_biguint(result) @@ -198,7 +191,7 @@ impl Sub for Secp256K1Base { #[inline] #[allow(clippy::suspicious_arithmetic_impl)] fn sub(self, rhs: Self) -> Self { - Self::from_biguint(self.to_canonical_biguint() + Self::order() - rhs.to_canonical_biguint()) + self + -rhs } } From d2c589e281faf2a9b760c0ffe7aaadba6a15bc58 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 6 Oct 2021 11:42:34 -0700 Subject: [PATCH 12/13] addressed comments --- src/field/secp256k1.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index fb48dba0..049334fc 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -38,7 +38,11 @@ fn biguint_from_array(arr: [u64; 4]) -> BigUint { impl Secp256K1Base { fn to_canonical_biguint(&self) -> BigUint { - biguint_from_array(self.0).mod_floor(&Self::order()) + let mut result = biguint_from_array(self.0); + if result > Self::order() { + result -= Self::order(); + } + result } fn from_biguint(val: BigUint) -> Self { @@ -162,7 +166,6 @@ impl Add for Secp256K1Base { type Output = Self; #[inline] - fn add(self, rhs: Self) -> Self { let mut result = self.to_canonical_biguint() + rhs.to_canonical_biguint(); if result >= Self::order() { From 88b528e3fe4f5973cb98cd4293906f7deba5cb4a Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 6 Oct 2021 11:44:02 -0700 Subject: [PATCH 13/13] fix --- src/field/secp256k1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field/secp256k1.rs b/src/field/secp256k1.rs index 049334fc..40e30fa1 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; -/// A field designed for use with the Crandall reduction algorithm. +/// The base field of the secp256k1 elliptic curve. /// /// Its order is /// ```ignore