diff --git a/crypto/src/hash/poseidon/mod.rs b/crypto/src/hash/poseidon/mod.rs index 81da16867..bab32a3fb 100644 --- a/crypto/src/hash/poseidon/mod.rs +++ b/crypto/src/hash/poseidon/mod.rs @@ -147,7 +147,9 @@ where #[cfg(test)] mod tests { use lambdaworks_math::{ - field::fields::u384_prime_field::{IsMontgomeryConfiguration, MontgomeryBackendPrimeField}, + field::fields::montgomery_backed_prime_fields::{ + IsMontgomeryConfiguration, U384PrimeField, + }, unsigned_integer::element::U384, }; @@ -155,12 +157,12 @@ mod tests { #[derive(Clone, Debug)] pub struct TestFieldConfig; - impl IsMontgomeryConfiguration for TestFieldConfig { + impl IsMontgomeryConfiguration<6> for TestFieldConfig { const MODULUS: U384 = U384::from("2000000000000080000000000000000000000000000000000000000000000001"); } - pub type PoseidonTestField = MontgomeryBackendPrimeField; + pub type PoseidonTestField = U384PrimeField; type TestFieldElement = FieldElement; pub fn load_test_parameters() -> Result, String> { diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs index 175f394c8..a5a826859 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs @@ -1,6 +1,8 @@ use crate::field::{ element::FieldElement, - fields::u384_prime_field::{IsMontgomeryConfiguration, MontgomeryBackendPrimeField}, + fields::montgomery_backed_prime_fields::{ + IsMontgomeryConfiguration, MontgomeryBackendPrimeField, + }, }; use crate::unsigned_integer::element::U384; @@ -9,11 +11,11 @@ pub const BLS12377_PRIME_FIELD_ORDER: U384 = U384::from("1ae3a4617c510eac63b05c0 // FPBLS12377 #[derive(Clone, Debug)] pub struct BLS12377FieldConfig; -impl IsMontgomeryConfiguration for BLS12377FieldConfig { +impl IsMontgomeryConfiguration<6> for BLS12377FieldConfig { const MODULUS: U384 = BLS12377_PRIME_FIELD_ORDER; } -pub type BLS12377PrimeField = MontgomeryBackendPrimeField; +pub type BLS12377PrimeField = MontgomeryBackendPrimeField; impl FieldElement { pub fn new_base(a_hex: &str) -> Self { diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs index 5fdb95631..ec5bd4552 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs @@ -4,7 +4,9 @@ use crate::field::{ cubic::{CubicExtensionField, HasCubicNonResidue}, quadratic::{HasQuadraticNonResidue, QuadraticExtensionField}, }, - fields::u384_prime_field::{IsMontgomeryConfiguration, MontgomeryBackendPrimeField}, + fields::montgomery_backed_prime_fields::{ + IsMontgomeryConfiguration, MontgomeryBackendPrimeField, + }, }; use crate::unsigned_integer::element::U384; @@ -13,11 +15,11 @@ pub const BLS12381_PRIME_FIELD_ORDER: U384 = U384::from("1a0111ea397fe69a4b1ba7b // FPBLS12381 #[derive(Clone, Debug)] pub struct BLS12381FieldConfig; -impl IsMontgomeryConfiguration for BLS12381FieldConfig { +impl IsMontgomeryConfiguration<6> for BLS12381FieldConfig { const MODULUS: U384 = BLS12381_PRIME_FIELD_ORDER; } -pub type BLS12381PrimeField = MontgomeryBackendPrimeField; +pub type BLS12381PrimeField = MontgomeryBackendPrimeField; #[derive(Debug, Clone)] pub struct LevelOneResidue; diff --git a/math/src/elliptic_curve/short_weierstrass/curves/test_curve_2.rs b/math/src/elliptic_curve/short_weierstrass/curves/test_curve_2.rs index 9506b684e..db4ed5f40 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/test_curve_2.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/test_curve_2.rs @@ -1,6 +1,6 @@ use crate::elliptic_curve::short_weierstrass::point::ShortWeierstrassProjectivePoint; use crate::elliptic_curve::traits::IsEllipticCurve; -use crate::field::fields::u384_prime_field::{ +use crate::field::fields::montgomery_backed_prime_fields::{ IsMontgomeryConfiguration, MontgomeryBackendPrimeField, }; use crate::unsigned_integer::element::U384; @@ -21,11 +21,11 @@ pub const TEST_CURVE_2_MAIN_SUBGROUP_ORDER: U384 = U384::from("40a065fb5a76390de // FPBLS12381 #[derive(Clone, Debug)] pub struct TestCurve2MontgomeryConfig; -impl IsMontgomeryConfiguration for TestCurve2MontgomeryConfig { +impl IsMontgomeryConfiguration<6> for TestCurve2MontgomeryConfig { const MODULUS: U384 = TEST_CURVE_2_PRIME_FIELD_ORDER; } -type TestCurve2PrimeField = MontgomeryBackendPrimeField; +type TestCurve2PrimeField = MontgomeryBackendPrimeField; /// In F59 the element -1 is not a square. We use this property /// to construct a Quadratic Field Extension out of it by adding diff --git a/math/src/field/fields/mod.rs b/math/src/field/fields/mod.rs index e79c6b653..61a6de417 100644 --- a/math/src/field/fields/mod.rs +++ b/math/src/field/fields/mod.rs @@ -1,3 +1,3 @@ -pub mod u384_prime_field; +pub mod montgomery_backed_prime_fields; /// Implementation of prime fields over 64 bit unsigned integers. pub mod u64_prime_field; diff --git a/math/src/field/fields/montgomery_backed_prime_fields.rs b/math/src/field/fields/montgomery_backed_prime_fields.rs new file mode 100644 index 000000000..16f1d8ee7 --- /dev/null +++ b/math/src/field/fields/montgomery_backed_prime_fields.rs @@ -0,0 +1,775 @@ +use crate::field::element::FieldElement; +use crate::traits::ByteConversion; +use crate::{ + field::traits::IsField, unsigned_integer::element::UnsignedInteger, + unsigned_integer::montgomery::MontgomeryAlgorithms, +}; +use std::fmt::Debug; +use std::marker::PhantomData; + +pub type U384PrimeField = MontgomeryBackendPrimeField; +pub type U256PrimeField = MontgomeryBackendPrimeField; + +/// Computes `- modulus^{-1} mod 2^{64}` +/// This algorithm is given by Dussé and Kaliski Jr. in +/// "S. R. Dussé and B. S. Kaliski Jr. A cryptographic library for the Motorola +/// DSP56000. In I. Damgård, editor, Advances in Cryptology – EUROCRYPT’90, +/// volume 473 of Lecture Notes in Computer Science, pages 230–244. Springer, +/// Heidelberg, May 1991." +const fn compute_mu_parameter(modulus: &UnsignedInteger) -> u64 { + let mut y = 1; + let word_size = 64; + let mut i: usize = 2; + while i <= word_size { + let (_, lo) = UnsignedInteger::mul(modulus, &UnsignedInteger::from_u64(y)); + let least_significant_limb = lo.limbs[NUM_LIMBS - 1]; + if (least_significant_limb << (word_size - i)) >> (word_size - i) != 1 { + y += 1 << (i - 1); + } + i += 1; + } + y.wrapping_neg() +} + +/// Computes 2^{384 * 2} modulo `modulus` +const fn compute_r2_parameter( + modulus: &UnsignedInteger, +) -> UnsignedInteger { + let word_size = 64; + let mut l: usize = 0; + let zero = UnsignedInteger::from_u64(0); + // Define `c` as the largest power of 2 smaller than `modulus` + while l < NUM_LIMBS * word_size { + if UnsignedInteger::const_ne(&modulus.const_shr(l), &zero) { + break; + } + l += 1; + } + let mut c = UnsignedInteger::from_u64(1).const_shl(l); + + // Double `c` and reduce modulo `modulus` until getting + // `2^{2 * number_limbs * word_size}` mod `modulus` + let mut i: usize = 1; + while i <= 2 * NUM_LIMBS * word_size - l { + let (double_c, overflow) = UnsignedInteger::add(&c, &c); + c = if UnsignedInteger::const_le(modulus, &double_c) || overflow { + UnsignedInteger::sub(&double_c, modulus).0 + } else { + double_c + }; + i += 1; + } + c +} + +/// This trait is necessary for us to be able to use unsigned integer types bigger than +/// `u128` (the biggest native `unit`) as constant generics. +/// This trait should be removed when Rust supports this feature. + +pub trait IsMontgomeryConfiguration { + const MODULUS: UnsignedInteger; + const R2: UnsignedInteger = compute_r2_parameter(&Self::MODULUS); + const MU: u64 = compute_mu_parameter(&Self::MODULUS); +} + +#[derive(Clone, Debug)] +pub struct MontgomeryBackendPrimeField { + phantom: PhantomData, +} + +impl MontgomeryBackendPrimeField +where + C: IsMontgomeryConfiguration, +{ + const ZERO: UnsignedInteger = UnsignedInteger::from_u64(0); +} + +impl IsField for MontgomeryBackendPrimeField +where + C: IsMontgomeryConfiguration + Clone + Debug, +{ + type BaseType = UnsignedInteger; + + fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + let (sum, overflow) = UnsignedInteger::add(a, b); + if !overflow { + if sum < C::MODULUS { + sum + } else { + sum - C::MODULUS + } + } else { + let (diff, _) = UnsignedInteger::sub(&sum, &C::MODULUS); + diff + } + } + + fn mul(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + MontgomeryAlgorithms::cios(a, b, &C::MODULUS, &C::MU) + } + + fn sub(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + if b <= a { + a - b + } else { + C::MODULUS - (b - a) + } + } + + fn neg(a: &Self::BaseType) -> Self::BaseType { + if a == &Self::ZERO { + *a + } else { + C::MODULUS - a + } + } + + fn inv(a: &Self::BaseType) -> Self::BaseType { + if a == &Self::ZERO { + panic!("Division by zero error.") + } + Self::pow(a, C::MODULUS - Self::BaseType::from_u64(2)) + } + + fn div(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + Self::mul(a, &Self::inv(b)) + } + + fn eq(a: &Self::BaseType, b: &Self::BaseType) -> bool { + a == b + } + + fn zero() -> Self::BaseType { + Self::ZERO + } + + fn one() -> Self::BaseType { + Self::from_u64(1) + } + + fn from_u64(x: u64) -> Self::BaseType { + MontgomeryAlgorithms::cios(&UnsignedInteger::from_u64(x), &C::R2, &C::MODULUS, &C::MU) + } + + fn from_base_type(x: Self::BaseType) -> Self::BaseType { + MontgomeryAlgorithms::cios(&x, &C::R2, &C::MODULUS, &C::MU) + } + + // TO DO: Add tests for representatives + fn representative(x: Self::BaseType) -> Self::BaseType { + MontgomeryAlgorithms::cios(&x, &UnsignedInteger::from_u64(1), &C::MODULUS, &C::MU) + } +} + +impl ByteConversion + for FieldElement> +where + C: IsMontgomeryConfiguration + Clone + Debug, +{ + fn to_bytes_be(&self) -> Vec { + MontgomeryAlgorithms::cios( + self.value(), + &UnsignedInteger::from_u64(1), + &C::MODULUS, + &C::MU, + ) + .to_bytes_be() + } + + fn to_bytes_le(&self) -> Vec { + MontgomeryAlgorithms::cios( + self.value(), + &UnsignedInteger::from_u64(1), + &C::MODULUS, + &C::MU, + ) + .to_bytes_le() + } + + fn from_bytes_be(bytes: &[u8]) -> Result { + let value = UnsignedInteger::from_bytes_be(bytes)?; + Ok(Self::new(value)) + } + + fn from_bytes_le(bytes: &[u8]) -> Result { + let value = UnsignedInteger::from_bytes_le(bytes)?; + Ok(Self::new(value)) + } +} + +#[cfg(test)] +mod tests_u384_prime_fields { + use crate::field::element::FieldElement; + use crate::field::fields::montgomery_backed_prime_fields::{ + IsMontgomeryConfiguration, U384PrimeField, + }; + use crate::traits::ByteConversion; + use crate::unsigned_integer::element::UnsignedInteger; + use crate::unsigned_integer::element::U384; + + #[derive(Clone, Debug)] + struct U384MontgomeryConfiguration23; + impl IsMontgomeryConfiguration<6> for U384MontgomeryConfiguration23 { + const MODULUS: U384 = UnsignedInteger::from_u64(23); + } + + type U384F23 = U384PrimeField; + type U384F23Element = FieldElement; + + #[test] + fn montgomery_backend_multiplication_works_0() { + let x = U384F23Element::from(11_u64); + let y = U384F23Element::from(10_u64); + let c = U384F23Element::from(110_u64); + assert_eq!(x * y, c); + } + + const ORDER: usize = 23; + #[test] + fn two_plus_one_is_three() { + assert_eq!( + U384F23Element::from(2) + U384F23Element::from(1), + U384F23Element::from(3) + ); + } + + #[test] + fn max_order_plus_1_is_0() { + assert_eq!( + U384F23Element::from((ORDER - 1) as u64) + U384F23Element::from(1), + U384F23Element::from(0) + ); + } + + #[test] + fn when_comparing_13_and_13_they_are_equal() { + let a: U384F23Element = U384F23Element::from(13); + let b: U384F23Element = U384F23Element::from(13); + assert_eq!(a, b); + } + + #[test] + fn when_comparing_13_and_8_they_are_different() { + let a: U384F23Element = U384F23Element::from(13); + let b: U384F23Element = U384F23Element::from(8); + assert_ne!(a, b); + } + + #[test] + fn mul_neutral_element() { + let a: U384F23Element = U384F23Element::from(1); + let b: U384F23Element = U384F23Element::from(2); + assert_eq!(a * b, U384F23Element::from(2)); + } + + #[test] + fn mul_2_3_is_6() { + let a: U384F23Element = U384F23Element::from(2); + let b: U384F23Element = U384F23Element::from(3); + assert_eq!(a * b, U384F23Element::from(6)); + } + + #[test] + fn mul_order_minus_1() { + let a: U384F23Element = U384F23Element::from((ORDER - 1) as u64); + let b: U384F23Element = U384F23Element::from((ORDER - 1) as u64); + assert_eq!(a * b, U384F23Element::from(1)); + } + + #[test] + #[should_panic] + fn inv_0_error() { + U384F23Element::from(0).inv(); + } + + #[test] + fn inv_2() { + let a: U384F23Element = U384F23Element::from(2); + assert_eq!(&a * a.inv(), U384F23Element::from(1)); + } + + #[test] + fn pow_2_3() { + assert_eq!(U384F23Element::from(2).pow(3_u64), U384F23Element::from(8)) + } + + #[test] + fn pow_p_minus_1() { + assert_eq!( + U384F23Element::from(2).pow(ORDER - 1), + U384F23Element::from(1) + ) + } + + #[test] + fn div_1() { + assert_eq!( + U384F23Element::from(2) / U384F23Element::from(1), + U384F23Element::from(2) + ) + } + + #[test] + fn div_4_2() { + assert_eq!( + U384F23Element::from(4) / U384F23Element::from(2), + U384F23Element::from(2) + ) + } + + #[test] + fn div_4_3() { + assert_eq!( + U384F23Element::from(4) / U384F23Element::from(3) * U384F23Element::from(3), + U384F23Element::from(4) + ) + } + + #[test] + fn two_plus_its_additive_inv_is_0() { + let two = U384F23Element::from(2); + + assert_eq!(&two + (-&two), U384F23Element::from(0)) + } + + #[test] + fn four_minus_three_is_1() { + let four = U384F23Element::from(4); + let three = U384F23Element::from(3); + + assert_eq!(four - three, U384F23Element::from(1)) + } + + #[test] + fn zero_minus_1_is_order_minus_1() { + let zero = U384F23Element::from(0); + let one = U384F23Element::from(1); + + assert_eq!(zero - one, U384F23Element::from((ORDER - 1) as u64)) + } + + #[test] + fn neg_zero_is_zero() { + let zero = U384F23Element::from(0); + + assert_eq!(-&zero, zero); + } + + // FP1 + #[derive(Clone, Debug)] + struct U384MontgomeryConfigP1; + impl IsMontgomeryConfiguration<6> for U384MontgomeryConfigP1 { + const MODULUS: U384 = UnsignedInteger { + limbs: [ + 0, + 0, + 0, + 3450888597, + 5754816256417943771, + 15923941673896418529, + ], + }; + } + + type U384FP1 = U384PrimeField; + type U384FP1Element = FieldElement; + + #[test] + fn montgomery_prime_field_addition_works_0() { + let x = U384FP1Element::new(UnsignedInteger::from( + "05ed176deb0e80b4deb7718cdaa075165f149c", + )); + let y = U384FP1Element::new(UnsignedInteger::from( + "5f103b0bd4397d4df560eb559f38353f80eeb6", + )); + let c = U384FP1Element::new(UnsignedInteger::from( + "64fd5279bf47fe02d4185ce279d8aa55e00352", + )); + assert_eq!(x + y, c); + } + + #[test] + fn montgomery_prime_field_multiplication_works_0() { + let x = U384FP1Element::new(UnsignedInteger::from( + "05ed176deb0e80b4deb7718cdaa075165f149c", + )); + let y = U384FP1Element::new(UnsignedInteger::from( + "5f103b0bd4397d4df560eb559f38353f80eeb6", + )); + let c = U384FP1Element::new(UnsignedInteger::from( + "73d23e8d462060dc23d5c15c00fc432d95621a3c", + )); + assert_eq!(x * y, c); + } + + // FP2 + #[derive(Clone, Debug)] + struct U384MontgomeryConfigP2; + impl IsMontgomeryConfiguration<6> for U384MontgomeryConfigP2 { + const MODULUS: U384 = UnsignedInteger { + limbs: [ + 18446744073709551615, + 18446744073709551615, + 18446744073709551615, + 18446744073709551615, + 18446744073709551615, + 18446744073709551275, + ], + }; + } + + type U384FP2 = U384PrimeField; + type U384FP2Element = FieldElement; + + #[test] + fn montgomery_prime_field_addition_works_1() { + let x = U384FP2Element::new(UnsignedInteger::from( + "05ed176deb0e80b4deb7718cdaa075165f149c", + )); + let y = U384FP2Element::new(UnsignedInteger::from( + "5f103b0bd4397d4df560eb559f38353f80eeb6", + )); + let c = U384FP2Element::new(UnsignedInteger::from( + "64fd5279bf47fe02d4185ce279d8aa55e00352", + )); + assert_eq!(x + y, c); + } + + #[test] + fn montgomery_prime_field_multiplication_works_1() { + let x = U384FP2Element::one(); + let y = U384FP2Element::new(UnsignedInteger::from( + "5f103b0bd4397d4df560eb559f38353f80eeb6", + )); + assert_eq!(&y * x, y); + } + + #[test] + fn to_bytes_from_bytes_be_is_the_identity() { + let x = U384FP2Element::new(UnsignedInteger::from( + "5f103b0bd4397d4df560eb559f38353f80eeb6", + )); + assert_eq!(U384FP2Element::from_bytes_be(&x.to_bytes_be()).unwrap(), x); + } + + #[test] + fn from_bytes_to_bytes_be_is_the_identity_for_one() { + let bytes = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + ]; + assert_eq!( + U384FP2Element::from_bytes_be(&bytes).unwrap().to_bytes_be(), + bytes + ); + } + + #[test] + fn to_bytes_from_bytes_le_is_the_identity() { + let x = U384FP2Element::new(UnsignedInteger::from( + "5f103b0bd4397d4df560eb559f38353f80eeb6", + )); + assert_eq!(U384FP2Element::from_bytes_le(&x.to_bytes_le()).unwrap(), x); + } + + #[test] + fn from_bytes_to_bytes_le_is_the_identity_for_one() { + let bytes = vec![ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + assert_eq!( + U384FP2Element::from_bytes_le(&bytes).unwrap().to_bytes_le(), + bytes + ); + } +} + +#[cfg(test)] +mod tests_u256_prime_fields { + use crate::field::element::FieldElement; + use crate::field::fields::montgomery_backed_prime_fields::{ + IsMontgomeryConfiguration, U256PrimeField, + }; + use crate::traits::ByteConversion; + use crate::unsigned_integer::element::UnsignedInteger; + use crate::unsigned_integer::element::U256; + + #[derive(Clone, Debug)] + struct U256MontgomeryConfiguration29; + impl IsMontgomeryConfiguration<4> for U256MontgomeryConfiguration29 { + const MODULUS: U256 = UnsignedInteger::from_u64(29); + } + + type U256F29 = U256PrimeField; + type U256F29Element = FieldElement; + + #[test] + fn montgomery_backend_multiplication_works_0() { + let x = U256F29Element::from(11_u64); + let y = U256F29Element::from(10_u64); + let c = U256F29Element::from(110_u64); + assert_eq!(x * y, c); + } + + const ORDER: usize = 29; + #[test] + fn two_plus_one_is_three() { + assert_eq!( + U256F29Element::from(2) + U256F29Element::from(1), + U256F29Element::from(3) + ); + } + + #[test] + fn max_order_plus_1_is_0() { + assert_eq!( + U256F29Element::from((ORDER - 1) as u64) + U256F29Element::from(1), + U256F29Element::from(0) + ); + } + + #[test] + fn when_comparing_13_and_13_they_are_equal() { + let a: U256F29Element = U256F29Element::from(13); + let b: U256F29Element = U256F29Element::from(13); + assert_eq!(a, b); + } + + #[test] + fn when_comparing_13_and_8_they_are_different() { + let a: U256F29Element = U256F29Element::from(13); + let b: U256F29Element = U256F29Element::from(8); + assert_ne!(a, b); + } + + #[test] + fn mul_neutral_element() { + let a: U256F29Element = U256F29Element::from(1); + let b: U256F29Element = U256F29Element::from(2); + assert_eq!(a * b, U256F29Element::from(2)); + } + + #[test] + fn mul_2_3_is_6() { + let a: U256F29Element = U256F29Element::from(2); + let b: U256F29Element = U256F29Element::from(3); + assert_eq!(a * b, U256F29Element::from(6)); + } + + #[test] + fn mul_order_minus_1() { + let a: U256F29Element = U256F29Element::from((ORDER - 1) as u64); + let b: U256F29Element = U256F29Element::from((ORDER - 1) as u64); + assert_eq!(a * b, U256F29Element::from(1)); + } + + #[test] + #[should_panic] + fn inv_0_error() { + U256F29Element::from(0).inv(); + } + + #[test] + fn inv_2() { + let a: U256F29Element = U256F29Element::from(2); + assert_eq!(&a * a.inv(), U256F29Element::from(1)); + } + + #[test] + fn pow_2_3() { + assert_eq!(U256F29Element::from(2).pow(3_u64), U256F29Element::from(8)) + } + + #[test] + fn pow_p_minus_1() { + assert_eq!( + U256F29Element::from(2).pow(ORDER - 1), + U256F29Element::from(1) + ) + } + + #[test] + fn div_1() { + assert_eq!( + U256F29Element::from(2) / U256F29Element::from(1), + U256F29Element::from(2) + ) + } + + #[test] + fn div_4_2() { + assert_eq!( + U256F29Element::from(4) / U256F29Element::from(2), + U256F29Element::from(2) + ) + } + + #[test] + fn div_4_3() { + assert_eq!( + U256F29Element::from(4) / U256F29Element::from(3) * U256F29Element::from(3), + U256F29Element::from(4) + ) + } + + #[test] + fn two_plus_its_additive_inv_is_0() { + let two = U256F29Element::from(2); + + assert_eq!(&two + (-&two), U256F29Element::from(0)) + } + + #[test] + fn four_minus_three_is_1() { + let four = U256F29Element::from(4); + let three = U256F29Element::from(3); + + assert_eq!(four - three, U256F29Element::from(1)) + } + + #[test] + fn zero_minus_1_is_order_minus_1() { + let zero = U256F29Element::from(0); + let one = U256F29Element::from(1); + + assert_eq!(zero - one, U256F29Element::from((ORDER - 1) as u64)) + } + + #[test] + fn neg_zero_is_zero() { + let zero = U256F29Element::from(0); + + assert_eq!(-&zero, zero); + } + + // FP1 + #[derive(Clone, Debug)] + struct U256MontgomeryConfigP1; + impl IsMontgomeryConfiguration<4> for U256MontgomeryConfigP1 { + const MODULUS: U256 = UnsignedInteger { + limbs: [ + 8366, + 8155137382671976874, + 227688614771682406, + 15723111795979912613, + ], + }; + } + + type U256FP1 = U256PrimeField; + type U256FP1Element = FieldElement; + + #[test] + fn montgomery_prime_field_addition_works_0() { + let x = U256FP1Element::new(UnsignedInteger::from( + "93e712950bf3fe589aa030562a44b1cec66b09192c4bcf705a5", + )); + let y = U256FP1Element::new(UnsignedInteger::from( + "10a712235c1f6b4172a1e35da6aef1a7ec6b09192c4bb88cfa5", + )); + let c = U256FP1Element::new(UnsignedInteger::from( + "a48e24b86813699a0d4213b3d0f3a376b2d61232589787fd54a", + )); + assert_eq!(x + y, c); + } + + #[test] + fn montgomery_prime_field_multiplication_works_0() { + let x = U256FP1Element::new(UnsignedInteger::from( + "93e712950bf3fe589aa030562a44b1cec66b09192c4bcf705a5", + )); + let y = U256FP1Element::new(UnsignedInteger::from( + "10a712235c1f6b4172a1e35da6aef1a7ec6b09192c4bb88cfa5", + )); + let c = U256FP1Element::new(UnsignedInteger::from( + "7808e74c3208d9a66791ef9cc15a46acc9951ee312102684021", + )); + assert_eq!(x * y, c); + } + + // FP2 + #[derive(Clone, Debug)] + struct MontgomeryConfigP2; + impl IsMontgomeryConfiguration<4> for MontgomeryConfigP2 { + const MODULUS: U256 = UnsignedInteger { + limbs: [ + 18446744073709551615, + 18446744073709551615, + 18446744073709551615, + 18446744073709551427, + ], + }; + } + + type FP2 = U256PrimeField; + type FP2Element = FieldElement; + + #[test] + fn montgomery_prime_field_addition_works_1() { + let x = FP2Element::new(UnsignedInteger::from( + "acbbb7ca01c65cfffffc72815b397fff9ab130ad53a5ffffffb8f21b207dfedf", + )); + let y = FP2Element::new(UnsignedInteger::from( + "d65ddbe509d3fffff21f494c588cbdbfe43e929b0543e3ffffffffffffffff43", + )); + let c = FP2Element::new(UnsignedInteger::from( + "831993af0b9a5cfff21bbbcdb3c63dbf7eefc34858e9e3ffffb8f21b207dfedf", + )); + assert_eq!(x + y, c); + } + + #[test] + fn montgomery_prime_field_multiplication_works_1() { + let x = FP2Element::new(UnsignedInteger::from( + "acbbb7ca01c65cfffffc72815b397fff9ab130ad53a5ffffffb8f21b207dfedf", + )); + let y = FP2Element::new(UnsignedInteger::from( + "d65ddbe509d3fffff21f494c588cbdbfe43e929b0543e3ffffffffffffffff43", + )); + let c = FP2Element::new(UnsignedInteger::from( + "2b1e80d553ecab2e4d41eb53c4c8ad89ebacac6cf6b91dcf2213f311093aa05d", + )); + assert_eq!(&y * x, c); + } + + #[test] + fn to_bytes_from_bytes_be_is_the_identity() { + let x = FP2Element::new(UnsignedInteger::from( + "5f103b0bd4397d4df560eb559f38353f80eeb6", + )); + assert_eq!(FP2Element::from_bytes_be(&x.to_bytes_be()).unwrap(), x); + } + + #[test] + fn from_bytes_to_bytes_be_is_the_identity_for_one() { + let bytes = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, + ]; + assert_eq!( + FP2Element::from_bytes_be(&bytes).unwrap().to_bytes_be(), + bytes + ); + } + + #[test] + fn to_bytes_from_bytes_le_is_the_identity() { + let x = FP2Element::new(UnsignedInteger::from( + "5f103b0bd4397d4df560eb559f38353f80eeb6", + )); + assert_eq!(FP2Element::from_bytes_le(&x.to_bytes_le()).unwrap(), x); + } + + #[test] + fn from_bytes_to_bytes_le_is_the_identity_for_one() { + let bytes = vec![ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]; + assert_eq!( + FP2Element::from_bytes_le(&bytes).unwrap().to_bytes_le(), + bytes + ); + } +} diff --git a/math/src/field/fields/u384_prime_field.rs b/math/src/field/fields/u384_prime_field.rs deleted file mode 100644 index a062b39c0..000000000 --- a/math/src/field/fields/u384_prime_field.rs +++ /dev/null @@ -1,571 +0,0 @@ -use crate::field::element::FieldElement; -use crate::traits::ByteConversion; -use crate::unsigned_integer::element::U384; -use crate::{ - field::traits::IsField, unsigned_integer::element::UnsignedInteger, - unsigned_integer::montgomery::MontgomeryAlgorithms, -}; - -use std::fmt::Debug; -use std::marker::PhantomData; - -/// Computes `- modulus^{-1} mod 2^{64}` -/// This algorithm is given by Dussé and Kaliski Jr. in -/// "S. R. Dussé and B. S. Kaliski Jr. A cryptographic library for the Motorola -/// DSP56000. In I. Damgård, editor, Advances in Cryptology – EUROCRYPT’90, -/// volume 473 of Lecture Notes in Computer Science, pages 230–244. Springer, -/// Heidelberg, May 1991." -const fn compute_mu_parameter(modulus: &U384) -> u64 { - let mut y = 1; - let word_size = 64; - let mut i: usize = 2; - while i <= word_size { - let (_, lo) = U384::mul(modulus, &U384::from_u64(y)); - let least_significant_limb = lo.limbs[5]; - if (least_significant_limb << (word_size - i)) >> (word_size - i) != 1 { - y += 1 << (i - 1); - } - i += 1; - } - y.wrapping_neg() -} - -/// Computes 2^{384 * 2} modulo `modulus` -const fn compute_r2_parameter(modulus: &U384) -> U384 { - let number_limbs = 6; - let word_size = 64; - let mut l: usize = 0; - let zero = U384::from_u64(0); - // Define `c` as the largest power of 2 smaller than `modulus` - while l < number_limbs * word_size { - if U384::const_ne(&modulus.const_shr(l), &zero) { - break; - } - l += 1; - } - let mut c = U384::from_u64(1).const_shl(l); - - // Double `c` and reduce modulo `modulus` until getting - // `2^{2 * number_limbs * word_size}` mod `modulus` - let mut i: usize = 1; - while i <= 2 * number_limbs * word_size - l { - let (double_c, overflow) = U384::add(&c, &c); - c = if U384::const_le(modulus, &double_c) || overflow { - U384::sub(&double_c, modulus).0 - } else { - double_c - }; - i += 1; - } - c -} - -/// This trait is necessary for us to be able to use unsigned integer types bigger than -/// `u128` (the biggest native `unit`) as constant generics. -/// This trait should be removed when Rust supports this feature. -pub trait IsMontgomeryConfiguration { - const MODULUS: U384; - const R2: U384 = compute_r2_parameter(&Self::MODULUS); - const MU: u64 = compute_mu_parameter(&Self::MODULUS); -} - -#[derive(Clone, Debug)] -pub struct MontgomeryBackendPrimeField { - phantom: PhantomData, -} - -impl MontgomeryBackendPrimeField -where - C: IsMontgomeryConfiguration, -{ - const ZERO: U384 = UnsignedInteger::from_u64(0); -} - -impl IsField for MontgomeryBackendPrimeField -where - C: IsMontgomeryConfiguration + Clone + Debug, -{ - type BaseType = U384; - - fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { - let (sum, overflow) = UnsignedInteger::add(a, b); - if !overflow { - if sum < C::MODULUS { - sum - } else { - sum - C::MODULUS - } - } else { - let (diff, _) = UnsignedInteger::sub(&sum, &C::MODULUS); - diff - } - } - - fn mul(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { - MontgomeryAlgorithms::cios(a, b, &C::MODULUS, &C::MU) - } - - fn sub(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { - if b <= a { - a - b - } else { - C::MODULUS - (b - a) - } - } - - fn neg(a: &Self::BaseType) -> Self::BaseType { - if a == &Self::ZERO { - *a - } else { - C::MODULUS - a - } - } - - fn inv(a: &Self::BaseType) -> Self::BaseType { - if a == &Self::ZERO { - panic!("Division by zero error.") - } - Self::pow(a, C::MODULUS - Self::BaseType::from_u64(2)) - } - - fn div(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { - Self::mul(a, &Self::inv(b)) - } - - fn eq(a: &Self::BaseType, b: &Self::BaseType) -> bool { - a == b - } - - fn zero() -> Self::BaseType { - Self::ZERO - } - - fn one() -> Self::BaseType { - Self::from_u64(1) - } - - fn from_u64(x: u64) -> Self::BaseType { - MontgomeryAlgorithms::cios(&UnsignedInteger::from_u64(x), &C::R2, &C::MODULUS, &C::MU) - } - - fn from_base_type(x: Self::BaseType) -> Self::BaseType { - MontgomeryAlgorithms::cios(&x, &C::R2, &C::MODULUS, &C::MU) - } - - // TO DO: Add tests for representatives - fn representative(x: Self::BaseType) -> Self::BaseType { - MontgomeryAlgorithms::cios(&x, &U384::from_u64(1), &C::MODULUS, &C::MU) - } -} - -impl ByteConversion for FieldElement> -where - C: IsMontgomeryConfiguration + Clone + Debug, -{ - fn to_bytes_be(&self) -> Vec { - MontgomeryAlgorithms::cios(self.value(), &U384::from_u64(1), &C::MODULUS, &C::MU) - .to_bytes_be() - } - - fn to_bytes_le(&self) -> Vec { - MontgomeryAlgorithms::cios(self.value(), &U384::from_u64(1), &C::MODULUS, &C::MU) - .to_bytes_le() - } - - fn from_bytes_be(bytes: &[u8]) -> Result { - let value = U384::from_bytes_be(bytes)?; - Ok(Self::new(value)) - } - - fn from_bytes_le(bytes: &[u8]) -> Result { - let value = U384::from_bytes_le(bytes)?; - Ok(Self::new(value)) - } -} - -#[cfg(test)] -mod tests { - use crate::{ - field::{ - element::FieldElement, - fields::u384_prime_field::{compute_mu_parameter, compute_r2_parameter}, - }, - traits::ByteConversion, - unsigned_integer::element::{UnsignedInteger, U384}, - }; - - use super::{IsMontgomeryConfiguration, MontgomeryBackendPrimeField}; - - #[test] - fn test_compute_mu_parameter_1() { - let modulus = U384 { - limbs: [0, 0, 0, 0, 0, 23], - }; - let mu = compute_mu_parameter(&modulus); - let expected_mu: u64 = 3208129404123400281; - assert_eq!(mu, expected_mu); - } - - #[test] - fn test_compute_mu_parameter_2() { - let modulus = U384 { - limbs: [ - 0, - 0, - 0, - 3450888597, - 5754816256417943771, - 15923941673896418529, - ], - }; - let mu = compute_mu_parameter(&modulus); - let expected_mu: u64 = 16085280245840369887; - assert_eq!(mu, expected_mu); - } - - #[test] - fn test_compute_mu_parameter_3() { - let modulus = U384 { - limbs: [ - 18446744073709551615, - 18446744073709551615, - 18446744073709551615, - 18446744073709551615, - 18446744073709551615, - 18446744073709551275, - ], - }; - let mu = compute_mu_parameter(&modulus); - let expected_mu: u64 = 14984598558409225213; - assert_eq!(mu, expected_mu); - } - - #[test] - fn test_compute_r2_parameter_1() { - let modulus = U384 { - limbs: [0, 0, 0, 0, 0, 23], - }; - let r2 = compute_r2_parameter(&modulus); - let expected_r2 = U384::from_u64(6); - assert_eq!(r2, expected_r2); - } - - #[test] - fn test_compute_r2_parameter_2() { - let modulus = U384 { - limbs: [ - 0, - 0, - 0, - 3450888597, - 5754816256417943771, - 15923941673896418529, - ], - }; - let r2 = compute_r2_parameter(&modulus); - let expected_r2 = U384 { - limbs: [0, 0, 0, 362264696, 173086217205162856, 7848132598488868435], - }; - assert_eq!(r2, expected_r2); - } - - #[test] - fn test_compute_r2_parameter_3() { - let modulus = U384 { - limbs: [ - 18446744073709551615, - 18446744073709551615, - 18446744073709551615, - 18446744073709551615, - 18446744073709551615, - 18446744073709551275, - ], - }; - let r2 = compute_r2_parameter(&modulus); - let expected_r2 = U384 { - limbs: [0, 0, 0, 0, 0, 116281], - }; - assert_eq!(r2, expected_r2); - } - - // F23 - #[derive(Clone, Debug)] - struct MontgomeryConfig23; - impl IsMontgomeryConfiguration for MontgomeryConfig23 { - const MODULUS: U384 = UnsignedInteger::from_u64(23); - } - - type F23 = MontgomeryBackendPrimeField; - type F23Element = FieldElement; - - #[test] - fn from_base_type_works() { - let x = F23Element::from(&U384::from_u64(1)); - let expected_value = U384::from_u64(12); - assert_eq!(x.value(), &expected_value); - } - - #[test] - fn montgomery_backend_multiplication_works_0() { - let x = F23Element::from(11_u64); - let y = F23Element::from(10_u64); - let c = F23Element::from(110_u64); - assert_eq!(x * y, c); - } - - const ORDER: usize = 23; - #[test] - fn two_plus_one_is_three() { - assert_eq!( - F23Element::from(2) + F23Element::from(1), - F23Element::from(3) - ); - } - - #[test] - fn max_order_plus_1_is_0() { - assert_eq!( - F23Element::from((ORDER - 1) as u64) + F23Element::from(1), - F23Element::from(0) - ); - } - - #[test] - fn when_comparing_13_and_13_they_are_equal() { - let a: F23Element = F23Element::from(13); - let b: F23Element = F23Element::from(13); - assert_eq!(a, b); - } - - #[test] - fn when_comparing_13_and_8_they_are_different() { - let a: F23Element = F23Element::from(13); - let b: F23Element = F23Element::from(8); - assert_ne!(a, b); - } - - #[test] - fn mul_neutral_element() { - let a: F23Element = F23Element::from(1); - let b: F23Element = F23Element::from(2); - assert_eq!(a * b, F23Element::from(2)); - } - - #[test] - fn mul_2_3_is_6() { - let a: F23Element = F23Element::from(2); - let b: F23Element = F23Element::from(3); - assert_eq!(a * b, F23Element::from(6)); - } - - #[test] - fn mul_order_minus_1() { - let a: F23Element = F23Element::from((ORDER - 1) as u64); - let b: F23Element = F23Element::from((ORDER - 1) as u64); - assert_eq!(a * b, F23Element::from(1)); - } - - #[test] - #[should_panic] - fn inv_0_error() { - F23Element::from(0).inv(); - } - - #[test] - fn inv_2() { - let a: F23Element = F23Element::from(2); - assert_eq!(&a * a.inv(), F23Element::from(1)); - } - - #[test] - fn pow_2_3() { - assert_eq!(F23Element::from(2).pow(3_u64), F23Element::from(8)) - } - - #[test] - fn pow_p_minus_1() { - assert_eq!(F23Element::from(2).pow(ORDER - 1), F23Element::from(1)) - } - - #[test] - fn div_1() { - assert_eq!( - F23Element::from(2) / F23Element::from(1), - F23Element::from(2) - ) - } - - #[test] - fn div_4_2() { - assert_eq!( - F23Element::from(4) / F23Element::from(2), - F23Element::from(2) - ) - } - - #[test] - fn div_4_3() { - assert_eq!( - F23Element::from(4) / F23Element::from(3) * F23Element::from(3), - F23Element::from(4) - ) - } - - #[test] - fn two_plus_its_additive_inv_is_0() { - let two = F23Element::from(2); - - assert_eq!(&two + (-&two), F23Element::from(0)) - } - - #[test] - fn four_minus_three_is_1() { - let four = F23Element::from(4); - let three = F23Element::from(3); - - assert_eq!(four - three, F23Element::from(1)) - } - - #[test] - fn zero_minus_1_is_order_minus_1() { - let zero = F23Element::from(0); - let one = F23Element::from(1); - - assert_eq!(zero - one, F23Element::from((ORDER - 1) as u64)) - } - - #[test] - fn neg_zero_is_zero() { - let zero = F23Element::from(0); - - assert_eq!(-&zero, zero); - } - - // FP1 - #[derive(Clone, Debug)] - struct MontgomeryConfigP1; - impl IsMontgomeryConfiguration for MontgomeryConfigP1 { - const MODULUS: U384 = UnsignedInteger { - limbs: [ - 0, - 0, - 0, - 3450888597, - 5754816256417943771, - 15923941673896418529, - ], - }; - } - - #[test] - fn montgomery_prime_field_addition_works_0() { - let x = FP1Element::new(UnsignedInteger::from( - "05ed176deb0e80b4deb7718cdaa075165f149c", - )); - let y = FP1Element::new(UnsignedInteger::from( - "5f103b0bd4397d4df560eb559f38353f80eeb6", - )); - let c = FP1Element::new(UnsignedInteger::from( - "64fd5279bf47fe02d4185ce279d8aa55e00352", - )); - assert_eq!(x + y, c); - } - - type FP1 = MontgomeryBackendPrimeField; - type FP1Element = FieldElement; - #[test] - fn montgomery_prime_field_multiplication_works_0() { - let x = FP1Element::new(UnsignedInteger::from( - "05ed176deb0e80b4deb7718cdaa075165f149c", - )); - let y = FP1Element::new(UnsignedInteger::from( - "5f103b0bd4397d4df560eb559f38353f80eeb6", - )); - let c = FP1Element::new(UnsignedInteger::from( - "73d23e8d462060dc23d5c15c00fc432d95621a3c", - )); - assert_eq!(x * y, c); - } - - // FP2 - #[derive(Clone, Debug)] - struct MontgomeryConfigP2; - impl IsMontgomeryConfiguration for MontgomeryConfigP2 { - const MODULUS: U384 = UnsignedInteger { - limbs: [ - 18446744073709551615, - 18446744073709551615, - 18446744073709551615, - 18446744073709551615, - 18446744073709551615, - 18446744073709551275, - ], - }; - } - - type FP2 = MontgomeryBackendPrimeField; - type FP2Element = FieldElement; - - #[test] - fn montgomery_prime_field_addition_works_1() { - let x = FP2Element::new(UnsignedInteger::from( - "05ed176deb0e80b4deb7718cdaa075165f149c", - )); - let y = FP2Element::new(UnsignedInteger::from( - "5f103b0bd4397d4df560eb559f38353f80eeb6", - )); - let c = FP2Element::new(UnsignedInteger::from( - "64fd5279bf47fe02d4185ce279d8aa55e00352", - )); - assert_eq!(x + y, c); - } - - #[test] - fn montgomery_prime_field_multiplication_works_1() { - let x = FP2Element::one(); - let y = FP2Element::new(UnsignedInteger::from( - "5f103b0bd4397d4df560eb559f38353f80eeb6", - )); - assert_eq!(&y * x, y); - } - - #[test] - fn to_bytes_from_bytes_be_is_the_identity() { - let x = FP2Element::new(UnsignedInteger::from( - "5f103b0bd4397d4df560eb559f38353f80eeb6", - )); - assert_eq!(FP2Element::from_bytes_be(&x.to_bytes_be()).unwrap(), x); - } - - #[test] - fn from_bytes_to_bytes_be_is_the_identity_for_one() { - let bytes = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - ]; - assert_eq!( - FP2Element::from_bytes_be(&bytes).unwrap().to_bytes_be(), - bytes - ); - } - - #[test] - fn to_bytes_from_bytes_le_is_the_identity() { - let x = FP2Element::new(UnsignedInteger::from( - "5f103b0bd4397d4df560eb559f38353f80eeb6", - )); - assert_eq!(FP2Element::from_bytes_le(&x.to_bytes_le()).unwrap(), x); - } - - #[test] - fn from_bytes_to_bytes_le_is_the_identity_for_one() { - let bytes = vec![ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - assert_eq!( - FP2Element::from_bytes_le(&bytes).unwrap().to_bytes_le(), - bytes - ); - } -} diff --git a/proving-system/stark/src/lib.rs b/proving-system/stark/src/lib.rs index dd0dea910..7b2f3f572 100644 --- a/proving-system/stark/src/lib.rs +++ b/proving-system/stark/src/lib.rs @@ -7,20 +7,20 @@ use lambdaworks_math::polynomial::{self, Polynomial}; use lambdaworks_math::field::element::FieldElement; use lambdaworks_math::{ - field::fields::u384_prime_field::{IsMontgomeryConfiguration, MontgomeryBackendPrimeField}, + field::fields::montgomery_backed_prime_fields::{IsMontgomeryConfiguration, U384PrimeField}, unsigned_integer::element::U384, }; // DEFINITION OF THE USED FIELD #[derive(Clone, Debug)] pub struct MontgomeryConfig; -impl IsMontgomeryConfiguration for MontgomeryConfig { +impl IsMontgomeryConfiguration<6> for MontgomeryConfig { const MODULUS: U384 = // hex 17 U384::from("800000000000011000000000000000000000000000000000000000000000001"); } -pub type PrimeField = MontgomeryBackendPrimeField; +pub type PrimeField = U384PrimeField; pub type FE = FieldElement; const MODULUS_MINUS_1: U384 = U384::sub(&MontgomeryConfig::MODULUS, &U384::from("1")).0;