From 0b1c3c58ba3c917fa411b3e0aae46aedd3967122 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Mon, 10 Jan 2022 00:03:51 -0800 Subject: [PATCH 01/32] `const` generics for `Fp` & no Montgomery default * Switches from hardcoded `FpXYZ` to `Fp` based on const generics. * Moves Montgomery arithmetic to an optional backend --- ff/src/biginteger/arithmetic.rs | 43 +- ff/src/biginteger/mod.rs | 52 +- ff/src/const_helpers.rs | 10 + ff/src/fields/arithmetic.rs | 294 ------ ff/src/fields/macros.rs | 746 -------------- ff/src/fields/mod.rs | 173 +--- ff/src/fields/models/cubic_extension.rs | 22 +- ff/src/fields/models/fp/buffer_helpers.rs | 251 +++++ ff/src/fields/models/fp/mod.rs | 940 ++++++++++++++++++ ff/src/fields/models/fp/montgomery_backend.rs | 480 +++++++++ ff/src/fields/models/mod.rs | 71 +- ff/src/fields/models/quadratic_extension.rs | 22 +- ff/src/lib.rs | 4 +- ff/src/to_field_vec.rs | 4 +- 14 files changed, 1797 insertions(+), 1315 deletions(-) create mode 100644 ff/src/const_helpers.rs delete mode 100644 ff/src/fields/macros.rs create mode 100644 ff/src/fields/models/fp/buffer_helpers.rs create mode 100644 ff/src/fields/models/fp/mod.rs create mode 100644 ff/src/fields/models/fp/montgomery_backend.rs diff --git a/ff/src/biginteger/arithmetic.rs b/ff/src/biginteger/arithmetic.rs index 64ed704a1..59c7f1335 100644 --- a/ff/src/biginteger/arithmetic.rs +++ b/ff/src/biginteger/arithmetic.rs @@ -2,38 +2,29 @@ use ark_std::vec::Vec; /// Calculate a + b + carry, returning the sum and modifying the /// carry value. -macro_rules! adc { - ($a:expr, $b:expr, &mut $carry:expr$(,)?) => {{ - let tmp = ($a as u128) + ($b as u128) + ($carry as u128); - - $carry = (tmp >> 64) as u64; - - tmp as u64 - }}; +#[inline(always)] +pub(crate) const fn adc(a: u64, b: u64, carry: &mut u64) -> u64 { + let tmp = (a as u128) + (b as u128) + (*carry as u128); + *carry = (tmp >> 64) as u64; + tmp as u64 } /// Calculate a + (b * c) + carry, returning the least significant digit /// and setting carry to the most significant digit. -macro_rules! mac_with_carry { - ($a:expr, $b:expr, $c:expr, &mut $carry:expr$(,)?) => {{ - let tmp = ($a as u128) + ($b as u128 * $c as u128) + ($carry as u128); - - $carry = (tmp >> 64) as u64; - - tmp as u64 - }}; +#[inline(always)] +pub(crate) const fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 { + let tmp = (a as u128) + (b as u128 * c as u128) + (*carry as u128); + *carry = (tmp >> 64) as u64; + tmp as u64 } /// Calculate a - b - borrow, returning the result and modifying /// the borrow value. -macro_rules! sbb { - ($a:expr, $b:expr, &mut $borrow:expr$(,)?) => {{ - let tmp = (1u128 << 64) + ($a as u128) - ($b as u128) - ($borrow as u128); - - $borrow = if tmp >> 64 == 0 { 1 } else { 0 }; - - tmp as u64 - }}; +#[inline(always)] +pub(crate) const fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 { + let tmp = (1u128 << 64) + (a as u128) - (b as u128) - (*borrow as u128); + *borrow = if tmp >> 64 == 0 { 1 } else { 0 }; + tmp as u64 } /// Calculate a + b * c, returning the lower 64 bits of the result and setting @@ -66,7 +57,7 @@ pub fn find_wnaf(num: &[u64]) -> Vec { let mut borrow = 0; for (a, b) in num.iter_mut().zip(other) { - *a = sbb!(*a, b, &mut borrow); + *a = sbb(*a, b, &mut borrow); } }; let add_nocarry = |num: &mut [u64], z: u64| { @@ -75,7 +66,7 @@ pub fn find_wnaf(num: &[u64]) -> Vec { let mut carry = 0; for (a, b) in num.iter_mut().zip(other) { - *a = adc!(*a, b, &mut carry); + *a = adc(*a, b, &mut carry); } }; let div2 = |num: &mut [u64]| { diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index fb293501d..cbcebca3b 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -53,12 +53,13 @@ impl BigInteger for BigInt { #[cfg(not(all(target_arch = "x86_64", feature = "asm")))] { - self.0[i] = adc!(self.0[i], other.0[i], &mut carry); + self.0[i] = arithmetic::adc(self.0[i], other.0[i], &mut carry); } } carry != 0 } + #[inline] #[ark_ff_asm::unroll_for_loops] fn sub_noborrow(&mut self, other: &Self) -> bool { @@ -74,7 +75,7 @@ impl BigInteger for BigInt { #[cfg(not(all(target_arch = "x86_64", feature = "asm")))] { - self.0[i] = sbb!(self.0[i], other.0[i], &mut borrow); + self.0[i] = arithmetic::sbb(self.0[i], other.0[i], &mut borrow); } } @@ -115,7 +116,7 @@ impl BigInteger for BigInt { #[ark_ff_asm::unroll_for_loops] fn muln(&mut self, mut n: u32) { if n >= (64 * N) as u32 { - *self = Self::from(0); + *self = Self::from(0u64); return; } @@ -158,7 +159,7 @@ impl BigInteger for BigInt { #[ark_ff_asm::unroll_for_loops] fn divn(&mut self, mut n: u32) { if n >= (64 * N) as u32 { - *self = Self::from(0); + *self = Self::from(0u64); return; } @@ -381,19 +382,44 @@ impl From for BigInt { repr } } + +impl From for BigInt { + #[inline] + fn from(val: u32) -> BigInt { + let mut repr = Self::default(); + repr.0[0] = u64::from(val); + repr + } +} + +impl From for BigInt { + #[inline] + fn from(val: u16) -> BigInt { + let mut repr = Self::default(); + repr.0[0] = u64::from(val); + repr + } +} + +impl From for BigInt { + #[inline] + fn from(val: u8) -> BigInt { + let mut repr = Self::default(); + repr.0[0] = u64::from(val); + repr + } +} + impl TryFrom for BigInt { - type Error = ark_std::string::String; + type Error = (); + /// Returns `Err(())` if the bit size of `val` is more than `N * 64`. #[inline] fn try_from(val: num_bigint::BigUint) -> Result, Self::Error> { let bytes = val.to_bytes_le(); if bytes.len() > N * 8 { - Err(format!( - "A BigUint of {} bytes cannot fit into {} limbs.", - bytes.len(), - N - )) + Err(()) } else { let mut limbs = [0u64; N]; @@ -418,6 +444,7 @@ impl From> for BigUint { BigUint::from_bytes_le(&val.to_bytes_le()) } } + /// Compute the signed modulo operation on a u64 representation, returning the result. /// If n % modulus > modulus / 2, return modulus - n /// # Example @@ -470,7 +497,10 @@ pub trait BigInteger: + AsMut<[u64]> + AsRef<[u64]> + From - + TryFrom + + From + + From + + From + + TryFrom + Into { /// Number of 64-bit limbs representing `Self`. diff --git a/ff/src/const_helpers.rs b/ff/src/const_helpers.rs new file mode 100644 index 000000000..91b8a1c4f --- /dev/null +++ b/ff/src/const_helpers.rs @@ -0,0 +1,10 @@ +#[macro_export] +macro_rules! for_loop { + (($i:ident in $start:tt..$end:tt) $code:expr ) => {{ + let $i = $start; + while $i < $end { + $code + $i += 1; + } + }}; +} diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index e324c940b..99f78ad4b 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -1,297 +1,3 @@ -/// This modular multiplication algorithm uses Montgomery -/// reduction for efficient implementation. It also additionally -/// uses the "no-carry optimization" outlined -/// [here](https://hackmd.io/@zkteam/modular_multiplication) if -/// `P::MODULUS` has (a) a non-zero MSB, and (b) at least one -/// zero bit in the rest of the modulus. -macro_rules! impl_field_mul_assign { - ($limbs:expr) => { - #[inline] - #[ark_ff_asm::unroll_for_loops] - fn mul_assign(&mut self, other: &Self) { - // Checking the modulus at compile time - let first_bit_set = P::MODULUS.0[$limbs - 1] >> 63 != 0; - // $limbs can be 1, hence we can run into a case with an unused mut. - #[allow(unused_mut)] - let mut all_bits_set = P::MODULUS.0[$limbs - 1] == !0 - (1 << 63); - for i in 1..$limbs { - all_bits_set &= P::MODULUS.0[$limbs - i - 1] == !0u64; - } - let _no_carry: bool = !(first_bit_set || all_bits_set); - - // No-carry optimisation applied to CIOS - if _no_carry { - #[cfg(use_asm)] - #[allow(unsafe_code, unused_mut)] - { - // Tentatively avoid using assembly for `$limbs == 1`. - if $limbs <= 6 && $limbs > 1 { - ark_ff_asm::x86_64_asm_mul!($limbs, (self.0).0, (other.0).0); - self.reduce(); - return; - } - } - let mut r = [0u64; $limbs]; - let mut carry1 = 0u64; - let mut carry2 = 0u64; - - for i in 0..$limbs { - r[0] = fa::mac(r[0], (self.0).0[0], (other.0).0[i], &mut carry1); - let k = r[0].wrapping_mul(P::INV); - fa::mac_discard(r[0], k, P::MODULUS.0[0], &mut carry2); - for j in 1..$limbs { - r[j] = mac_with_carry!(r[j], (self.0).0[j], (other.0).0[i], &mut carry1); - r[j - 1] = mac_with_carry!(r[j], k, P::MODULUS.0[j], &mut carry2); - } - r[$limbs - 1] = carry1 + carry2; - } - (self.0).0 = r; - self.reduce(); - // Alternative implementation - } else { - *self = self.mul_without_reduce(other, P::MODULUS, P::INV); - self.reduce(); - } - } - }; -} - -macro_rules! impl_field_into_repr { - ($limbs:expr, $BigIntegerType:ty) => { - #[inline] - #[ark_ff_asm::unroll_for_loops] - #[allow(clippy::modulo_one)] - fn into_repr(&self) -> $BigIntegerType { - let mut tmp = self.0; - let mut r = tmp.0; - // Montgomery Reduction - for i in 0..$limbs { - let k = r[i].wrapping_mul(P::INV); - let mut carry = 0; - - mac_with_carry!(r[i], k, P::MODULUS.0[0], &mut carry); - for j in 1..$limbs { - r[(j + i) % $limbs] = - mac_with_carry!(r[(j + i) % $limbs], k, P::MODULUS.0[j], &mut carry); - } - r[i % $limbs] = carry; - } - tmp.0 = r; - tmp - } - }; -} - -macro_rules! impl_field_square_in_place { - ($limbs: expr) => { - #[inline] - #[ark_ff_asm::unroll_for_loops] - #[allow(unused_braces, clippy::absurd_extreme_comparisons)] - fn square_in_place(&mut self) -> &mut Self { - if $limbs == 1 { - // We default to multiplying with `self` using the `Mul` impl - // for the 1 limb case - *self = *self * *self; - return self; - } - #[cfg(use_asm)] - #[allow(unsafe_code, unused_mut)] - { - // Checking the modulus at compile time - let first_bit_set = P::MODULUS.0[$limbs - 1] >> 63 != 0; - let mut all_bits_set = P::MODULUS.0[$limbs - 1] == !0 - (1 << 63); - for i in 1..$limbs { - all_bits_set &= P::MODULUS.0[$limbs - i - 1] == core::u64::MAX; - } - let _no_carry: bool = !(first_bit_set || all_bits_set); - - if $limbs <= 6 && _no_carry { - ark_ff_asm::x86_64_asm_square!($limbs, (self.0).0); - self.reduce(); - return self; - } - } - let mut r = [0u64; $limbs * 2]; - - let mut carry = 0; - for i in 0..$limbs { - if i < $limbs - 1 { - for j in 0..$limbs { - if j > i { - r[i + j] = - mac_with_carry!(r[i + j], (self.0).0[i], (self.0).0[j], &mut carry); - } - } - r[$limbs + i] = carry; - carry = 0; - } - } - r[$limbs * 2 - 1] = r[$limbs * 2 - 2] >> 63; - for i in 0..$limbs { - // This computes `r[2 * ($limbs - 1) - (i + 1)]`, but additionally - // handles the case where the index underflows. - // Note that we should never hit this case because it only occurs - // when `$limbs == 1`, but we handle that separately above. - let subtractor = (2 * ($limbs - 1usize)) - .checked_sub(i + 1) - .map(|index| r[index]) - .unwrap_or(0); - r[2 * ($limbs - 1) - i] = (r[2 * ($limbs - 1) - i] << 1) | (subtractor >> 63); - } - for i in 3..$limbs { - r[$limbs + 1 - i] = (r[$limbs + 1 - i] << 1) | (r[$limbs - i] >> 63); - } - r[1] <<= 1; - - for i in 0..$limbs { - r[2 * i] = mac_with_carry!(r[2 * i], (self.0).0[i], (self.0).0[i], &mut carry); - // need unused assignment because the last iteration of the loop produces an - // assignment to `carry` that is unused. - #[allow(unused_assignments)] - { - r[2 * i + 1] = adc!(r[2 * i + 1], 0, &mut carry); - } - } - // Montgomery reduction - let mut _carry2 = 0; - for i in 0..$limbs { - let k = r[i].wrapping_mul(P::INV); - let mut carry = 0; - mac_with_carry!(r[i], k, P::MODULUS.0[0], &mut carry); - for j in 1..$limbs { - r[j + i] = mac_with_carry!(r[j + i], k, P::MODULUS.0[j], &mut carry); - } - r[$limbs + i] = adc!(r[$limbs + i], _carry2, &mut carry); - _carry2 = carry; - } - (self.0).0.copy_from_slice(&r[$limbs..]); - self.reduce(); - self - } - }; -} - -macro_rules! impl_field_bigint_conv { - ($field: ident, $bigint: ident, $params: ident) => { - impl Into<$bigint> for $field

{ - fn into(self) -> $bigint { - self.into_repr() - } - } - - impl From<$bigint> for $field

{ - /// Converts `Self::BigInteger` into `Self` - /// - /// # Panics - /// This method panics if `int` is larger than `P::MODULUS`. - fn from(int: $bigint) -> Self { - Self::from_repr(int).unwrap() - } - } - }; -} - -macro_rules! impl_prime_field_standard_sample { - ($field: ident, $params: ident) => { - impl ark_std::rand::distributions::Distribution<$field

> - for ark_std::rand::distributions::Standard - { - #[inline] - fn sample(&self, rng: &mut R) -> $field

{ - loop { - let mut tmp = $field( - rng.sample(ark_std::rand::distributions::Standard), - PhantomData, - ); - - // Mask away the unused bits at the beginning. - assert!(P::REPR_SHAVE_BITS <= 64); - let mask = if P::REPR_SHAVE_BITS == 64 { - 0 - } else { - core::u64::MAX >> P::REPR_SHAVE_BITS - }; - tmp.0.as_mut().last_mut().map(|val| *val &= mask); - - if tmp.is_valid() { - return tmp; - } - } - } - } - }; -} - -macro_rules! impl_prime_field_from_int { - ($field: ident, 128, $params: ident, $limbs:expr) => { - impl From for $field

{ - fn from(other: u128) -> Self { - let mut default_int = P::BigInt::default(); - if $limbs == 1 { - default_int.0[0] = (other % u128::from(P::MODULUS.0[0])) as u64; - } else { - let upper = (other >> 64) as u64; - let lower = ((other << 64) >> 64) as u64; - // This is equivalent to the following, but satisfying the compiler: - // default_int.0[0] = lower; - // default_int.0[1] = upper; - let limbs = [lower, upper]; - for (cur, other) in default_int.0.iter_mut().zip(&limbs) { - *cur = *other; - } - } - Self::from_repr(default_int).unwrap() - } - } - - impl From for $field

{ - fn from(other: i128) -> Self { - let abs = Self::from(other.unsigned_abs()); - if other.is_positive() { - abs - } else { - -abs - } - } - } - }; - ($field: ident, bool, $params: ident, $limbs:expr) => { - impl From for $field

{ - fn from(other: bool) -> Self { - if $limbs == 1 { - Self::from_repr(P::BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() - } else { - Self::from_repr(P::BigInt::from(u64::from(other))).unwrap() - } - } - } - }; - ($field: ident, $int: expr, $params: ident, $limbs:expr) => { - paste::paste!{ - impl From<[]> for $field

{ - fn from(other: []) -> Self { - if $limbs == 1 { - Self::from_repr(P::BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() - } else { - Self::from_repr(P::BigInt::from(u64::from(other))).unwrap() - } - } - } - - impl From<[]> for $field

{ - fn from(other: []) -> Self { - let abs = Self::from(other.unsigned_abs()); - if other.is_positive() { - abs - } else { - -abs - } - } - } - } - }; -} - macro_rules! sqrt_impl { ($Self:ident, $P:tt, $self:expr) => {{ // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) diff --git a/ff/src/fields/macros.rs b/ff/src/fields/macros.rs deleted file mode 100644 index 4245768f7..000000000 --- a/ff/src/fields/macros.rs +++ /dev/null @@ -1,746 +0,0 @@ -macro_rules! impl_prime_field_serializer { - ($field: ident, $params: ident, $byte_size: expr) => { - impl CanonicalSerializeWithFlags for $field

{ - fn serialize_with_flags( - &self, - mut writer: W, - flags: F, - ) -> Result<(), SerializationError> { - // All reasonable `Flags` should be less than 8 bits in size - // (256 values are enough for anyone!) - if F::BIT_SIZE > 8 { - return Err(SerializationError::NotEnoughSpace); - } - - // Calculate the number of bytes required to represent a field element - // serialized with `flags`. If `F::BIT_SIZE < 8`, - // this is at most `$byte_size + 1` - let output_byte_size = buffer_byte_size(P::MODULUS_BITS as usize + F::BIT_SIZE); - - // Write out `self` to a temporary buffer. - // The size of the buffer is $byte_size + 1 because `F::BIT_SIZE` - // is at most 8 bits. - let mut bytes = [0u8; $byte_size + 1]; - self.write(&mut bytes[..$byte_size])?; - - // Mask out the bits of the last byte that correspond to the flag. - bytes[output_byte_size - 1] |= flags.u8_bitmask(); - - writer.write_all(&bytes[..output_byte_size])?; - Ok(()) - } - - // Let `m = 8 * n` for some `n` be the smallest multiple of 8 greater - // than `P::MODULUS_BITS`. - // If `(m - P::MODULUS_BITS) >= F::BIT_SIZE` , then this method returns `n`; - // otherwise, it returns `n + 1`. - fn serialized_size_with_flags(&self) -> usize { - buffer_byte_size(P::MODULUS_BITS as usize + F::BIT_SIZE) - } - } - - impl CanonicalSerialize for $field

{ - #[inline] - fn serialize( - &self, - writer: W, - ) -> Result<(), SerializationError> { - self.serialize_with_flags(writer, EmptyFlags) - } - - #[inline] - fn serialized_size(&self) -> usize { - self.serialized_size_with_flags::() - } - } - - impl CanonicalDeserializeWithFlags for $field

{ - fn deserialize_with_flags( - mut reader: R, - ) -> Result<(Self, F), SerializationError> { - // All reasonable `Flags` should be less than 8 bits in size - // (256 values are enough for anyone!) - if F::BIT_SIZE > 8 { - return Err(SerializationError::NotEnoughSpace); - } - // Calculate the number of bytes required to represent a field element - // serialized with `flags`. If `F::BIT_SIZE < 8`, - // this is at most `$byte_size + 1` - let output_byte_size = buffer_byte_size(P::MODULUS_BITS as usize + F::BIT_SIZE); - - let mut masked_bytes = [0; $byte_size + 1]; - reader.read_exact(&mut masked_bytes[..output_byte_size])?; - - let flags = F::from_u8_remove_flags(&mut masked_bytes[output_byte_size - 1]) - .ok_or(SerializationError::UnexpectedFlags)?; - - Ok((Self::read(&masked_bytes[..])?, flags)) - } - } - - impl CanonicalDeserialize for $field

{ - fn deserialize(reader: R) -> Result { - Self::deserialize_with_flags::(reader).map(|(r, _)| r) - } - } - }; -} - -macro_rules! impl_Fp { - ($Fp:ident, $FpParameters:ident, $BigInteger:ident, $BigIntegerType:ty, $limbs:expr, $field_size:expr) => { - /// Trait for prime field parameters of size at most - #[doc = $field_size] - /// bits. - pub trait $FpParameters: FpParameters> {} - - /// Represents an element of the prime field F_p, where `p == P::MODULUS`. - /// This type can represent elements in any field of size at most - #[doc = $field_size] - /// bits. - #[derive(Derivative)] - #[derivative( - Default(bound = ""), - Hash(bound = ""), - Clone(bound = ""), - Copy(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") - )] - pub struct $Fp

( - pub $BigIntegerType, - #[derivative(Debug = "ignore")] - #[doc(hidden)] - pub PhantomData

, - ); - - impl

$Fp

{ - /// Construct a new prime element directly from its underlying - /// `BigInteger` data type. The `BigInteger` should be in - /// Montgomery representation. If it is not, use `Self::from_repr`. - #[inline] - pub const fn new(element: $BigIntegerType) -> Self { - Self(element, PhantomData) - } - - #[ark_ff_asm::unroll_for_loops] - const fn const_is_zero(&self) -> bool { - let mut is_zero = true; - for i in 0..$limbs { - is_zero &= (self.0).0[i] == 0; - } - is_zero - } - - const fn const_neg(self, modulus: $BigIntegerType) -> Self { - if !self.const_is_zero() { - Self::new(Self::sub_noborrow(&modulus, &self.0)) - } else { - self - } - } - - /// Interpret a string of decimal numbers as a prime field element. - /// Does not accept unnecessary leading zeroes or a blank string. - /// For *internal* use only; please use the `field_new` macro instead - /// of this method - #[doc(hidden)] - pub const fn const_from_str(limbs: &[u64], is_positive: bool, r2: $BigIntegerType, modulus: $BigIntegerType, inv: u64) -> Self { - let mut repr = BigInt::<$limbs>([0; $limbs]); - let mut i = 0; - while i < limbs.len() { - repr.0[i] = limbs[i]; - i += 1; - } - let res = Self::const_from_repr(repr, r2, modulus, inv); - if is_positive { - res - } else { - res.const_neg(modulus) - } - } - - #[inline] - pub(crate) const fn const_from_repr(repr: $BigIntegerType, r2: $BigIntegerType, modulus: $BigIntegerType, inv: u64) -> Self { - let mut r = Self::new(repr); - if r.const_is_zero() { - r - } else { - r = r.const_mul(&$Fp(r2, PhantomData), modulus, inv); - r - } - } - - #[ark_ff_asm::unroll_for_loops] - const fn mul_without_reduce(mut self, other: &Self, modulus: $BigIntegerType, inv: u64) -> Self { - let mut r = [0u64; $limbs * 2]; - - for i in 0..$limbs { - let mut carry = 0; - for j in 0..$limbs { - r[j + i] = mac_with_carry!(r[j + i], (self.0).0[i], (other.0).0[j], &mut carry); - } - r[$limbs + i] = carry; - } - // Montgomery reduction - let mut _carry2 = 0; - for i in 0..$limbs { - let k = r[i].wrapping_mul(inv); - let mut carry = 0; - mac_with_carry!(r[i], k, modulus.0[0], &mut carry); - for j in 1..$limbs { - r[j + i] = mac_with_carry!(r[j + i], k, modulus.0[j], &mut carry); - } - r[$limbs + i] = adc!(r[$limbs + i], _carry2, &mut carry); - _carry2 = carry; - } - - for i in 0..$limbs { - (self.0).0[i] = r[$limbs + i]; - } - self - } - - #[ark_ff_asm::unroll_for_loops] - const fn const_mul(mut self, other: &Self, modulus: $BigIntegerType, inv: u64) -> Self { - self = self.mul_without_reduce(other, modulus, inv); - self.const_reduce(modulus) - } - - - #[ark_ff_asm::unroll_for_loops] - const fn const_is_valid(&self, modulus: $BigIntegerType) -> bool { - for i in 0..$limbs { - if (self.0).0[($limbs - i - 1)] < modulus.0[($limbs - i - 1)] { - return true - } else if (self.0).0[($limbs - i - 1)] > modulus.0[($limbs - i - 1)] { - return false - } - } - false - } - - #[inline] - const fn const_reduce(mut self, modulus: $BigIntegerType) -> Self { - if !self.const_is_valid(modulus) { - self.0 = Self::sub_noborrow(&self.0, &modulus); - } - self - } - - #[ark_ff_asm::unroll_for_loops] - // need unused assignment because the last iteration of the loop produces an assignment - // to `borrow` that is unused. - #[allow(unused_assignments)] - const fn sub_noborrow(a: &$BigIntegerType, b: &$BigIntegerType) -> $BigInteger { - let mut a = *a; - let mut borrow = 0; - for i in 0..$limbs { - a.0[i] = sbb!(a.0[i], b.0[i], &mut borrow); - } - a - } - } - - impl $Fp

{ - #[inline(always)] - pub(crate) fn is_valid(&self) -> bool { - self.0 < P::MODULUS - } - - #[inline] - fn reduce(&mut self) { - if !self.is_valid() { - self.0.sub_noborrow(&P::MODULUS); - } - } - } - - impl

ark_std::fmt::Debug for $Fp

{ - fn fmt(&self, f: &mut ark_std::fmt::Formatter<'_>) -> ark_std::fmt::Result { - ark_std::fmt::Debug::fmt(&self.0, f) - } - } - - impl Zero for $Fp

{ - #[inline] - fn zero() -> Self { - $Fp::

($BigInteger::from(0), PhantomData) - } - - #[inline] - fn is_zero(&self) -> bool { - self.0.is_zero() - } - } - - impl One for $Fp

{ - #[inline] - fn one() -> Self { - $Fp::

(P::R, PhantomData) - } - - #[inline] - fn is_one(&self) -> bool { - self.0 == P::R - } - } - - impl Field for $Fp

{ - type BasePrimeField = Self; - - fn extension_degree() -> u64 { - 1 - } - - fn from_base_prime_field_elems(elems: &[Self::BasePrimeField]) -> Option { - if elems.len() != (Self::extension_degree() as usize) { - return None; - } - Some(elems[0]) - } - - #[inline] - fn double(&self) -> Self { - let mut temp = *self; - temp.double_in_place(); - temp - } - - #[inline] - fn double_in_place(&mut self) -> &mut Self { - // This cannot exceed the backing capacity. - self.0.mul2(); - // However, it may need to be reduced. - self.reduce(); - self - } - - #[inline] - fn characteristic() -> &'static [u64] { - P::MODULUS.as_ref() - } - - #[inline] - fn from_random_bytes_with_flags(bytes: &[u8]) -> Option<(Self, F)> { - if F::BIT_SIZE > 8 { - return None - } else { - let mut result_bytes = [0u8; $limbs * 8 + 1]; - // Copy the input into a temporary buffer. - result_bytes.iter_mut().zip(bytes).for_each(|(result, input)| { - *result = *input; - }); - // This mask retains everything in the last limb - // that is below `P::MODULUS_BITS`. - let last_limb_mask = (u64::MAX >> P::REPR_SHAVE_BITS).to_le_bytes(); - let mut last_bytes_mask = [0u8; 9]; - last_bytes_mask[..8].copy_from_slice(&last_limb_mask); - - - // Length of the buffer containing the field element and the flag. - let output_byte_size = buffer_byte_size(P::MODULUS_BITS as usize + F::BIT_SIZE); - // Location of the flag is the last byte of the serialized - // form of the field element. - let flag_location = output_byte_size - 1; - - // At which byte is the flag located in the last limb? - let flag_location_in_last_limb = flag_location - (8 * ($limbs - 1)); - - // Take all but the last 9 bytes. - let last_bytes = &mut result_bytes[8 * ($limbs - 1)..]; - - // The mask only has the last `F::BIT_SIZE` bits set - let flags_mask = u8::MAX.checked_shl(8 - (F::BIT_SIZE as u32)).unwrap_or(0); - - // Mask away the remaining bytes, and try to reconstruct the - // flag - let mut flags: u8 = 0; - for (i, (b, m)) in last_bytes.iter_mut().zip(&last_bytes_mask).enumerate() { - if i == flag_location_in_last_limb { - flags = *b & flags_mask - } - *b &= m; - } - Self::deserialize(&result_bytes[..($limbs * 8)]) - .ok() - .and_then(|f| F::from_u8(flags).map(|flag| (f, flag))) - } - } - - #[inline] - fn square(&self) -> Self { - let mut temp = self.clone(); - temp.square_in_place(); - temp - } - - impl_field_square_in_place!($limbs); - - #[inline] - fn inverse(&self) -> Option { - if self.is_zero() { - None - } else { - // Guajardo Kumar Paar Pelzl - // Efficient Software-Implementation of Finite Fields with Applications to - // Cryptography - // Algorithm 16 (BEA for Inversion in Fp) - - let one = $BigInteger::from(1); - - let mut u = self.0; - let mut v = P::MODULUS; - let mut b = $Fp::

(P::R2, PhantomData); // Avoids unnecessary reduction step. - let mut c = Self::zero(); - - while u != one && v != one { - while u.is_even() { - u.div2(); - - if b.0.is_even() { - b.0.div2(); - } else { - b.0.add_nocarry(&P::MODULUS); - b.0.div2(); - } - } - - while v.is_even() { - v.div2(); - - if c.0.is_even() { - c.0.div2(); - } else { - c.0.add_nocarry(&P::MODULUS); - c.0.div2(); - } - } - - if v < u { - u.sub_noborrow(&v); - b.sub_assign(&c); - } else { - v.sub_noborrow(&u); - c.sub_assign(&b); - } - } - - if u == one { - Some(b) - } else { - Some(c) - } - } - } - - fn inverse_in_place(&mut self) -> Option<&mut Self> { - if let Some(inverse) = self.inverse() { - *self = inverse; - Some(self) - } else { - None - } - } - - /// The Frobenius map has no effect in a prime field. - #[inline] - fn frobenius_map(&mut self, _: usize) {} - } - - impl PrimeField for $Fp

{ - type Params = P; - type BigInt = $BigIntegerType; - - #[inline] - fn from_repr(r: $BigIntegerType) -> Option { - let mut r = $Fp(r, PhantomData); - if r.is_zero() { - Some(r) - } else if r.is_valid() { - r *= &$Fp(P::R2, PhantomData); - Some(r) - } else { - None - } - } - - impl_field_into_repr!($limbs, $BigIntegerType); - } - - impl FftField for $Fp

{ - type FftParams = P; - - #[inline] - fn two_adic_root_of_unity() -> Self { - $Fp::

(P::TWO_ADIC_ROOT_OF_UNITY, PhantomData) - } - - #[inline] - fn large_subgroup_root_of_unity() -> Option { - Some($Fp::

(P::LARGE_SUBGROUP_ROOT_OF_UNITY?, PhantomData)) - } - - #[inline] - fn multiplicative_generator() -> Self { - $Fp::

(P::GENERATOR, PhantomData) - } - } - - impl SquareRootField for $Fp

{ - #[inline] - fn legendre(&self) -> LegendreSymbol { - use crate::fields::LegendreSymbol::*; - - // s = self^((MODULUS - 1) // 2) - let s = self.pow(P::MODULUS_MINUS_ONE_DIV_TWO); - if s.is_zero() { - Zero - } else if s.is_one() { - QuadraticResidue - } else { - QuadraticNonResidue - } - } - - #[inline] - fn sqrt(&self) -> Option { - sqrt_impl!(Self, P, self) - } - - fn sqrt_in_place(&mut self) -> Option<&mut Self> { - (*self).sqrt().map(|sqrt| { - *self = sqrt; - self - }) - } - } - - /// Note that this implementation of `Ord` compares field elements viewing - /// them as integers in the range 0, 1, ..., P::MODULUS - 1. However, other - /// implementations of `PrimeField` might choose a different ordering, and - /// as such, users should use this `Ord` for applications where - /// any ordering suffices (like in a BTreeMap), and not in applications - /// where a particular ordering is required. - impl Ord for $Fp

{ - #[inline(always)] - fn cmp(&self, other: &Self) -> Ordering { - self.into_repr().cmp(&other.into_repr()) - } - } - - /// Note that this implementation of `PartialOrd` compares field elements viewing - /// them as integers in the range 0, 1, ..., `P::MODULUS` - 1. However, other - /// implementations of `PrimeField` might choose a different ordering, and - /// as such, users should use this `PartialOrd` for applications where - /// any ordering suffices (like in a BTreeMap), and not in applications - /// where a particular ordering is required. - impl PartialOrd for $Fp

{ - #[inline(always)] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - impl_prime_field_from_int!($Fp, 128, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, 64, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, 32, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, 16, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, 8, $FpParameters, $limbs); - impl_prime_field_from_int!($Fp, bool, $FpParameters, $limbs); - - impl_prime_field_standard_sample!($Fp, $FpParameters); - - impl_prime_field_serializer!($Fp, $FpParameters, $limbs * 8); - - impl ToBytes for $Fp

{ - #[inline] - fn write(&self, writer: W) -> IoResult<()> { - self.into_repr().write(writer) - } - } - - impl FromBytes for $Fp

{ - #[inline] - fn read(reader: R) -> IoResult { - $BigInteger::read(reader).and_then(|b| - match $Fp::from_repr(b) { - Some(f) => Ok(f), - None => Err(crate::error("FromBytes::read failed")), - }) - } - } - - impl FromStr for $Fp

{ - type Err = (); - - /// Interpret a string of numbers as a (congruent) prime field element. - /// Does not accept unnecessary leading zeroes or a blank string. - fn from_str(s: &str) -> Result { - if s.is_empty() { - return Err(()); - } - - if s == "0" { - return Ok(Self::zero()); - } - - let mut res = Self::zero(); - - let ten = Self::from(::BigInt::from(10)); - - let mut first_digit = true; - - for c in s.chars() { - match c.to_digit(10) { - Some(c) => { - if first_digit { - if c == 0 { - return Err(()); - } - - first_digit = false; - } - - res.mul_assign(&ten); - let digit = Self::from(u64::from(c)); - res.add_assign(&digit); - }, - None => { - return Err(()); - }, - } - } - if !res.is_valid() { - Err(()) - } else { - Ok(res) - } - } - } - - /// Outputs a string containing the value of `self`, chunked up into - /// 64-bit limbs. - impl Display for $Fp

{ - #[inline] - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, stringify!($Fp "({})"), self.into_repr()) - } - } - - impl Neg for $Fp

{ - type Output = Self; - #[inline] - #[must_use] - fn neg(self) -> Self { - if !self.is_zero() { - let mut tmp = P::MODULUS; - tmp.sub_noborrow(&self.0); - $Fp::

(tmp, PhantomData) - } else { - self - } - } - } - - impl<'a, P: $FpParameters> Add<&'a $Fp

> for $Fp

{ - type Output = Self; - - #[inline] - fn add(mut self, other: &Self) -> Self { - self.add_assign(other); - self - } - } - - impl<'a, P: $FpParameters> Sub<&'a $Fp

> for $Fp

{ - type Output = Self; - - #[inline] - fn sub(mut self, other: &Self) -> Self { - self.sub_assign(other); - self - } - } - - impl<'a, P: $FpParameters> Mul<&'a $Fp

> for $Fp

{ - type Output = Self; - - #[inline] - fn mul(mut self, other: &Self) -> Self { - self.mul_assign(other); - self - } - } - - impl<'a, P: $FpParameters> Div<&'a $Fp

> for $Fp

{ - type Output = Self; - - /// Returns `self * other.inverse()` if `other.inverse()` is `Some`, and - /// panics otherwise. - #[inline] - fn div(mut self, other: &Self) -> Self { - self.mul_assign(&other.inverse().unwrap()); - self - } - } - - impl_additive_ops_from_ref!($Fp, $FpParameters); - impl_multiplicative_ops_from_ref!($Fp, $FpParameters); - - impl<'a, P: $FpParameters> AddAssign<&'a Self> for $Fp

{ - #[inline] - fn add_assign(&mut self, other: &Self) { - // This cannot exceed the backing capacity. - self.0.add_nocarry(&other.0); - // However, it may need to be reduced - self.reduce(); - } - } - - impl<'a, P: $FpParameters> SubAssign<&'a Self> for $Fp

{ - #[inline] - fn sub_assign(&mut self, other: &Self) { - // If `other` is larger than `self`, add the modulus to self first. - if other.0 > self.0 { - self.0.add_nocarry(&P::MODULUS); - } - self.0.sub_noborrow(&other.0); - } - } - - impl<'a, P: $FpParameters> MulAssign<&'a Self> for $Fp

{ - impl_field_mul_assign!($limbs); - } - - /// Computes `self *= other.inverse()` if `other.inverse()` is `Some`, and - /// panics otherwise. - impl<'a, P: $FpParameters> DivAssign<&'a Self> for $Fp

{ - #[inline] - fn div_assign(&mut self, other: &Self) { - self.mul_assign(&other.inverse().unwrap()); - } - } - - impl zeroize::Zeroize for $Fp

{ - // The phantom data does not contain element-specific data - // and thus does not need to be zeroized. - fn zeroize(&mut self) { - self.0.zeroize(); - } - } - - impl From for $Fp

{ - #[inline] - fn from(val: num_bigint::BigUint) -> $Fp

{ - $Fp::

::from_le_bytes_mod_order(&val.to_bytes_le()) - } - } - - impl From<$Fp

> for num_bigint::BigUint { - #[inline] - fn from(other: $Fp

) -> Self { - other.into_repr().into() - } - } - } -} diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index bc6df82de..f7c1dc61c 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -1,9 +1,4 @@ -use crate::{ - biginteger::BigInteger, - bytes::{FromBytes, ToBytes}, - fields::utils::k_adicity, - UniformRand, -}; +use crate::{biginteger::BigInteger, fields::utils::k_adicity, UniformRand}; use ark_serialize::{ CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, CanonicalSerializeWithFlags, EmptyFlags, Flags, @@ -18,11 +13,10 @@ use ark_std::{ }; pub use ark_ff_macros; +use num_bigint::BigUint; use num_traits::{One, Zero}; use zeroize::Zeroize; -#[macro_use] -pub mod macros; pub mod utils; #[macro_use] @@ -39,7 +33,7 @@ use rayon::prelude::*; #[macro_export] macro_rules! field_new { ($name:ident, $c0:expr) => {{ - use $crate::FpParameters; + use $crate::FpConfig; type Params = <$name as $crate::PrimeField>::Params; let (is_positive, limbs) = $crate::ark_ff_macros::to_sign_and_limbs!($c0); $name::const_from_str( @@ -64,9 +58,7 @@ macro_rules! field_new { /// The interface for a generic field. pub trait Field: - ToBytes - + 'static - + FromBytes + 'static + Copy + Clone + Debug @@ -205,8 +197,8 @@ pub trait Field: } /// A trait that defines parameters for a field that can be used for FFTs. -pub trait FftParameters: 'static + Send + Sync + Sized { - type BigInt: BigInteger; +pub trait FftConfig: 'static + Send + Sync + Sized { + type Field: Field; /// Let `N` be the size of the multiplicative group defined by the field. /// Then `TWO_ADICITY` is the two-adicity of `N`, i.e. the integer `s` @@ -214,7 +206,7 @@ pub trait FftParameters: 'static + Send + Sync + Sized { const TWO_ADICITY: u32; /// 2^s root of unity computed by GENERATOR^t - const TWO_ADIC_ROOT_OF_UNITY: Self::BigInt; + const TWO_ADIC_ROOT_OF_UNITY: Self::Field; /// An integer `b` such that there exists a multiplicative subgroup /// of size `b^k` for some integer `k`. @@ -227,53 +219,12 @@ pub trait FftParameters: 'static + Send + Sync + Sized { /// GENERATOR^((MODULUS-1) / (2^s * /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix /// FFT. - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; -} - -/// A trait that defines parameters for a prime field. -pub trait FpParameters: FftParameters { - /// The modulus of the field. - const MODULUS: Self::BigInt; - - /// The number of bits needed to represent the `Self::MODULUS`. - const MODULUS_BITS: u32; - - /// The number of bits that must be shaved from the beginning of - /// the representation when randomly sampling. - const REPR_SHAVE_BITS: u32; - - /// Let `M` be the power of 2^64 nearest to `Self::MODULUS_BITS`. Then - /// `R = M % Self::MODULUS`. - const R: Self::BigInt; - - /// R2 = R^2 % Self::MODULUS - const R2: Self::BigInt; - - /// INV = -MODULUS^{-1} mod 2^64 - const INV: u64; - - /// A multiplicative generator of the field. - /// `Self::GENERATOR` is an element having multiplicative order - /// `Self::MODULUS - 1`. - const GENERATOR: Self::BigInt; - - /// The number of bits that can be reliably stored. - /// (Should equal `SELF::MODULUS_BITS - 1`) - const CAPACITY: u32; - - /// t for 2^s * t = MODULUS - 1, and t coprime to 2. - const T: Self::BigInt; - - /// (t - 1) / 2 - const T_MINUS_ONE_DIV_TWO: Self::BigInt; - - /// (Self::MODULUS - 1) / 2 - const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; } /// The interface for fields that are able to be used in FFTs. pub trait FftField: Field { - type FftParams: FftParameters; + type FftConfig: FftConfig; /// Returns the 2^s root of unity. fn two_adic_root_of_unity() -> Self; @@ -295,10 +246,10 @@ pub trait FftField: Field { fn get_root_of_unity(n: usize) -> Option { let mut omega: Self; if let Some(large_subgroup_root_of_unity) = Self::large_subgroup_root_of_unity() { - let q = Self::FftParams::SMALL_SUBGROUP_BASE.expect( + let q = Self::FftConfig::SMALL_SUBGROUP_BASE.expect( "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE", ) as usize; - let small_subgroup_base_adicity = Self::FftParams::SMALL_SUBGROUP_BASE_ADICITY.expect( + let small_subgroup_base_adicity = Self::FftConfig::SMALL_SUBGROUP_BASE_ADICITY.expect( "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE_ADICITY", ); @@ -309,7 +260,7 @@ pub trait FftField: Field { let two_part = 1 << two_adicity; if n != two_part * q_part - || (two_adicity > Self::FftParams::TWO_ADICITY) + || (two_adicity > Self::FftConfig::TWO_ADICITY) || (q_adicity > small_subgroup_base_adicity) { return None; @@ -320,7 +271,7 @@ pub trait FftField: Field { omega = omega.pow(&[q as u64]); } - for _ in two_adicity..Self::FftParams::TWO_ADICITY { + for _ in two_adicity..Self::FftConfig::TWO_ADICITY { omega.square_in_place(); } } else { @@ -328,14 +279,14 @@ pub trait FftField: Field { let size = n.next_power_of_two() as u64; let log_size_of_group = ark_std::log2(usize::try_from(size).expect("too large")); - if n != size as usize || log_size_of_group > Self::FftParams::TWO_ADICITY { + if n != size as usize || log_size_of_group > Self::FftConfig::TWO_ADICITY { return None; } // Compute the generator for the multiplicative subgroup. // It should be 2^(log_size_of_group) root of unity. omega = Self::two_adic_root_of_unity(); - for _ in log_size_of_group..Self::FftParams::TWO_ADICITY { + for _ in log_size_of_group..Self::FftConfig::TWO_ADICITY { omega.square_in_place(); } } @@ -343,32 +294,42 @@ pub trait FftField: Field { } } -/// The interface for a prime field. +/// The interface for a prime field, i.e. the field of integers modulo a prime p. pub trait PrimeField: Field - + FftField::Params> + + FftField + FromStr + From<::BigInt> + Into<::BigInt> + From + Into { - /// Associated `FpParameters` that define this field. - type Params: FpParameters; - /// A `BigInteger` type that can represent elements of this field. type BigInt: BigInteger; - /// Returns a prime field element from its underlying representation. - fn from_repr(repr: Self::BigInt) -> Option; + /// The modulus `p`. + const MODULUS: Self::BigInt; + /// The value `(p - 1)/ 2`. + const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt; + /// The size of the modulus in bits. + const MODULUS_BIT_SIZE: u16; + /// The trace of the field is defined as the smallest integer `t` such that by + /// `2^s * t = p - 1`, and `t` is coprime to 2. + const TRACE: Self::BigInt; + /// The value `(t - 1)/ 2`. + const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt; - /// Returns the underlying representation of the prime field element. - fn into_repr(&self) -> Self::BigInt; + /// Construct a prime field element from an integer in the range 0..(p - 1). + fn from_bigint(repr: Self::BigInt) -> Option; + + /// Converts an element of the prime field into an integer in the range 0..(p - 1). + fn into_bigint(&self) -> Self::BigInt; /// Reads bytes in big-endian, and converts them to a field element. - /// If the bytes are larger than the modulus, it will reduce them. + /// If the integer represented by `bytes` is larger than the modulus `p`, this method + /// performs the appropriate reduction. fn from_be_bytes_mod_order(bytes: &[u8]) -> Self { - let num_modulus_bytes = ((Self::Params::MODULUS_BITS + 7) / 8) as usize; + let num_modulus_bytes = ((Self::MODULUS_BIT_SIZE + 7) / 8) as usize; let num_bytes_to_directly_convert = min(num_modulus_bytes - 1, bytes.len()); // Copy the leading big-endian bytes directly into a field element. // The number of bytes directly converted must be less than the @@ -393,43 +354,19 @@ pub trait PrimeField: } /// Reads bytes in little-endian, and converts them to a field element. - /// If the bytes are larger than the modulus, it will reduce them. + /// If the integer represented by `bytes` is larger than the modulus `p`, this method + /// performs the appropriate reduction. fn from_le_bytes_mod_order(bytes: &[u8]) -> Self { let mut bytes_copy = bytes.to_vec(); bytes_copy.reverse(); Self::from_be_bytes_mod_order(&bytes_copy) } - /// Return the QNR^t, for t defined by - /// `2^s * t = MODULUS - 1`, and t coprime to 2. + /// Return QNR^t, and t coprime to 2, and for + /// a given quadratic non-residue. fn qnr_to_t() -> Self { Self::two_adic_root_of_unity() } - - /// Returns the field size in bits. - fn size_in_bits() -> usize { - Self::Params::MODULUS_BITS as usize - } - - /// Returns the trace. - fn trace() -> Self::BigInt { - Self::Params::T - } - - /// Returns the trace minus one divided by two. - fn trace_minus_one_div_two() -> Self::BigInt { - Self::Params::T_MINUS_ONE_DIV_TWO - } - - /// Returns the modulus. - fn modulus() -> Self::BigInt { - Self::Params::MODULUS - } - - /// Returns the modulus minus one divided by two. - fn modulus_minus_one_div_two() -> Self::BigInt { - Self::Params::MODULUS_MINUS_ONE_DIV_TWO - } } /// The interface for a field that supports an efficient square-root operation. @@ -488,10 +425,10 @@ impl LegendreSymbol { /// /// # Examples /// ``` - /// # use ark_test_curves::bls12_381::{Fq, Fq2Parameters}; + /// # use ark_test_curves::bls12_381::{Fq, Fq2Config}; /// # use ark_ff::{LegendreSymbol, SquareRootField}; - /// # use ark_ff::Fp2Parameters; - /// let a: Fq = Fq2Parameters::NONRESIDUE; + /// # use ark_ff::Fp2Config; + /// let a: Fq = Fq2Config::NONRESIDUE; /// assert!(a.legendre().is_qnr()); /// ``` pub fn is_qnr(&self) -> bool { @@ -597,20 +534,6 @@ impl> Iterator for BitIteratorLE { } } -use crate::biginteger::{ - BigInteger256, BigInteger320, BigInteger384, BigInteger448, BigInteger64, BigInteger768, - BigInteger832, -}; -use num_bigint::BigUint; - -impl_field_bigint_conv!(Fp64, BigInteger64, Fp64Parameters); -impl_field_bigint_conv!(Fp256, BigInteger256, Fp256Parameters); -impl_field_bigint_conv!(Fp320, BigInteger320, Fp320Parameters); -impl_field_bigint_conv!(Fp384, BigInteger384, Fp384Parameters); -impl_field_bigint_conv!(Fp448, BigInteger448, Fp448Parameters); -impl_field_bigint_conv!(Fp768, BigInteger768, Fp768Parameters); -impl_field_bigint_conv!(Fp832, BigInteger832, Fp832Parameters); - // Given a vector of field elements {v_i}, compute the vector {v_i^(-1)} pub fn batch_inversion(v: &mut [F]) { batch_inversion_and_mul(v, &F::one()); @@ -699,13 +622,13 @@ mod std_tests { mod no_std_tests { use super::*; use ark_std::test_rng; - // TODO: only Fr & FrParameters should need to be imported. + // TODO: only Fr & FrConfig should need to be imported. // The rest of imports are caused by cargo not resolving the deps properly // from this crate and from ark_test_curves use ark_test_curves::{ batch_inversion, batch_inversion_and_mul, - bls12_381::{Fr, FrParameters}, - BigInteger, FpParameters, PrimeField, + bls12_381::{Fr, FrConfig}, + BigInteger, FpConfig, PrimeField, }; #[test] @@ -737,8 +660,8 @@ mod no_std_tests { fn test_from_into_biguint() { let mut rng = ark_std::test_rng(); - let modulus_bits = FrParameters::MODULUS_BITS; - let modulus: num_bigint::BigUint = FrParameters::MODULUS.into(); + let modulus_bits = FrConfig::MODULUS_BITS; + let modulus: num_bigint::BigUint = FrConfig::MODULUS.into(); let mut rand_bytes = Vec::new(); for _ in 0..(2 * modulus_bits / 8) { diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 970c5c3d5..09e05809a 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -5,7 +5,7 @@ use ark_serialize::{ use ark_std::{ cmp::{Ord, Ordering, PartialOrd}, fmt, - io::{Read, Result as IoResult, Write}, + io::{Read, Write}, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, vec::Vec, }; @@ -19,7 +19,6 @@ use ark_std::rand::{ }; use crate::{ - bytes::{FromBytes, ToBytes}, fields::{Field, PrimeField}, ToConstraintField, UniformRand, }; @@ -433,25 +432,6 @@ impl From for CubicExtField

{ } } -impl ToBytes for CubicExtField

{ - #[inline] - fn write(&self, mut writer: W) -> IoResult<()> { - self.c0.write(&mut writer)?; - self.c1.write(&mut writer)?; - self.c2.write(writer) - } -} - -impl FromBytes for CubicExtField

{ - #[inline] - fn read(mut reader: R) -> IoResult { - let c0 = P::BaseField::read(&mut reader)?; - let c1 = P::BaseField::read(&mut reader)?; - let c2 = P::BaseField::read(reader)?; - Ok(CubicExtField::new(c0, c1, c2)) - } -} - impl Neg for CubicExtField

{ type Output = Self; #[inline] diff --git a/ff/src/fields/models/fp/buffer_helpers.rs b/ff/src/fields/models/fp/buffer_helpers.rs new file mode 100644 index 000000000..c21453e20 --- /dev/null +++ b/ff/src/fields/models/fp/buffer_helpers.rs @@ -0,0 +1,251 @@ +use ark_serialize::{Read, Write}; +use ark_std::ops::{Index, IndexMut}; + +use crate::BigInt; + +/// A buffer to hold values of size 2 * N. This is mostly +/// a hack that's necessary until `generic_const_exprs` is stable. +#[derive(Copy, Clone)] +pub(super) struct MulBuffer { + pub(super) b0: [u64; N], + pub(super) b1: [u64; N], +} + +impl MulBuffer { + pub(super) const fn new(b0: [u64; N], b1: [u64; N]) -> Self { + Self { b0, b1 } + } + + pub(super) const fn zeroed() -> Self { + Self { + b0: [0u64; N], + b1: [0u64; N], + } + } + + #[inline(always)] + pub(super) const fn get(&self, index: usize) -> &u64 { + if index < N { + &self.b0[index] + } else { + &self.b1[index + N] + } + } + + #[inline(always)] + pub(super) const fn get_mut(&mut self, index: usize) -> &mut u64 { + if index < N { + &mut self.b0[index] + } else { + &mut self.b1[index + N] + } + } +} + +impl Index for MulBuffer { + type Output = u64; + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + self.get(index) + } +} + +impl IndexMut for MulBuffer { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_mut(index) + } +} + +/// A buffer to hold values of size 2 * N. This is mostly +/// a hack that's necessary until `generic_const_exprs` is stable. +#[derive(Copy, Clone)] +pub(super) struct SerBuffer { + pub(super) buffers: [[u8; 8]; N], + pub(super) last: u8, +} + +impl SerBuffer { + pub(super) const fn new(buffers: [[u8; 8]; N], last: u8) -> Self { + Self { buffers, last } + } + + pub(super) const fn zeroed() -> Self { + Self { + buffers: [[0u8; 8]; N], + last: 0u8, + } + } + + #[inline(always)] + pub(super) const fn get(&self, index: usize) -> &u8 { + if index == 8 * N { + &self.last + } else { + let part = index / 8; + let in_buffer_index = index % 8; + &self.buffers[part][index] + } + } + + #[inline(always)] + pub(super) const fn get_mut(&mut self, index: usize) -> &mut u8 { + if index == 8 * N { + &mut self.last + } else { + let part = index / 8; + let in_buffer_index = index % 8; + &mut self.buffers[part][index] + } + } + + #[inline(always)] + pub(super) fn iter(&self) -> impl Iterator { + self.buffers + .iter() + .flat_map(|b| b.iter()) + .chain(ark_std::iter::once(&self.last)) + } + + #[inline(always)] + pub(super) fn iter_mut(&mut self) -> impl Iterator { + self.buffers + .iter_mut() + .flat_map(|b| b.iter_mut()) + .chain(ark_std::iter::once(&mut self.last)) + } + + #[inline(always)] + pub(super) fn last_n_plus_1_bytes_mut(&mut self) -> impl Iterator { + self.buffers[N - 1] + .iter_mut() + .chain(ark_std::iter::once(&mut self.last)) + } + + #[inline(always)] + pub(super) fn copy_from_u8_slice(&mut self, other: &[u8]) { + other.chunks(8).enumerate().for_each(|(i, chunk)| { + if i < N { + self.buffers[i].copy_from_slice(chunk) + } else { + self.last = chunk[0] + } + }); + } + + #[inline(always)] + pub(super) fn copy_from_u64_slice(&mut self, other: &[u64; N]) { + other + .iter() + .zip(&mut self.buffers) + .for_each(|(other, this)| *this = other.to_le_bytes()); + } + + #[inline(always)] + pub(super) fn to_bigint(&self) -> BigInt { + let mut self_integer = BigInt::from(0u64); + self_integer + .0 + .iter_mut() + .zip(self.buffers) + .for_each(|(other, this)| *other = u64::from_le_bytes(this)); + self_integer + } + + #[inline(always)] + /// Write up to `num_bytes` bytes from `self` to `other`. + /// `num_bytes` is allowed to range from `8 * (N - 1)` to `8 * N + 1`. + pub(super) fn write_up_to( + &self, + other: impl Write, + num_bytes: usize, + ) -> ark_std::io::Result<()> { + debug_assert!(num_bytes <= 8 * N + 1, "index too large"); + debug_assert!(num_bytes > 8 * (N - 1), "index too small"); + // unconditionally write first `N - 1` limbs. + for i in 0..(N - 1) { + other.write_all(&self.buffers[i])?; + } + // for the `N`-th limb, depending on `index`, we can write anywhere from + // 1 to all bytes. + // If `index % N == ` + let remaining_bytes = num_bytes - (8 * (N - 1)); + let write_last_byte = remaining_bytes > 8; + let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); + other.write_all(&self.buffers[N][..num_last_limb_bytes])?; + if write_last_byte { + other.write_all(&[self.last])?; + } + Ok(()) + } + + #[inline(always)] + /// Read up to `num_bytes` bytes from `other` to `self`. + /// `num_bytes` is allowed to range from `8 * (N - 1)` to `8 * N + 1`. + pub(super) fn read_exact_up_to( + &mut self, + other: impl Read, + num_bytes: usize, + ) -> ark_std::io::Result<()> { + debug_assert!(num_bytes <= 8 * N + 1, "index too large"); + debug_assert!(num_bytes > 8 * (N - 1), "index too small"); + // unconditionally write first `N - 1` limbs. + for i in 0..(N - 1) { + other.read_exact(&mut self.buffers[i])?; + } + // for the `N`-th limb, depending on `index`, we can write anywhere from + // 1 to all bytes. + // If `index % N == ` + let remaining_bytes = num_bytes - (8 * (N - 1)); + let write_last_byte = remaining_bytes > 8; + let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); + other.read_exact(&mut self.buffers[N][..num_last_limb_bytes])?; + if write_last_byte { + other.read_exact(&mut [self.last])?; + } + Ok(()) + } +} + +impl Index for SerBuffer { + type Output = u8; + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + self.get(index) + } +} + +impl IndexMut for SerBuffer { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_mut(index) + } +} + +mod tests { + #[test] + fn test_mul_buffer_correctness() { + type Buf = MulBuffer<10>; + let temp = Buf::new([10u64; 10], [20u64; 10]); + + for i in 0..20 { + if i < 10 { + assert_eq!(temp[i], 10); + } else { + assert_eq!(temp[i], 20); + } + } + } + + #[test] + #[should_panic] + fn test_mul_buffer_soundness() { + type Buf = MulBuffer<10>; + let temp = Buf::new([10u64; 10], [10u64; 10]); + + for i in 20..21 { + // indexing `temp[20]` should panic + assert_eq!(temp[i], 10); + } + } +} diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs new file mode 100644 index 000000000..ec7ee2449 --- /dev/null +++ b/ff/src/fields/models/fp/mod.rs @@ -0,0 +1,940 @@ +use ark_serialize::{ + buffer_byte_size, CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, + CanonicalSerializeWithFlags, EmptyFlags, Flags, SerializationError, +}; +use ark_std::{ + cmp::{Ord, Ordering, PartialOrd}, + fmt::{Display, Formatter, Result as FmtResult}, + io::{Read, Result as IoResult, Write}, + marker::PhantomData, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, + str::FromStr, + One, Zero, +}; + +mod buffer_helpers; + +mod montgomery_backend; +pub use montgomery_backend::*; + +use crate::{BigInt, BigInteger, FftField, Field, LegendreSymbol, PrimeField, SquareRootField}; +/// A trait that specifies the configuration of a prime field. +/// Also specifies how to perform arithmetic on field elements. +pub trait FpConfig: crate::FftConfig> { + /// The modulus of the field. + const MODULUS: crate::BigInt; + + /// The number of bits needed to represent the `Self::MODULUS`. + const MODULUS_BIT_SIZE: u16; + + /// A multiplicative generator of the field. + /// `Self::GENERATOR` is an element having multiplicative order + /// `Self::MODULUS - 1`. + const GENERATOR: Fp; + + /// Additive identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e + f = f`. + const ZERO: Fp; + + /// Multiplicative identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e * f = f`. + const ONE: Fp; + + /// t for 2^s * t = MODULUS - 1, and t coprime to 2. + // TODO: compute this directly from `MODULUS` once + // const fns in traits are stable. + const T: crate::BigInt; + + /// (t - 1) / 2 + // TODO: compute this directly from `T` once + // const fns in traits are stable. + const T_MINUS_ONE_DIV_TWO: crate::BigInt; + + /// (Self::MODULUS - 1) / 2 + // TODO: compute this directly from `MODULUS` once + // const fns in traits are stable. + const MODULUS_MINUS_ONE_DIV_TWO: crate::BigInt; + + /// Set a += b. + fn add_assign(a: &mut Fp, b: &Fp); + + /// Set a -= b. + fn sub_assign(a: &mut Fp, b: &Fp); + + /// Set a = a + a. + fn double_in_place(a: &mut Fp); + + /// Set a *= b. + fn mul_assign(a: &mut Fp, b: &Fp); + + /// Set a *= b. + fn square_in_place(a: &mut Fp); + + /// Compute a^{-1} if it exists. + fn inverse(a: &Fp) -> Option>; + + /// Construct a field element from an integer in the range `0..(Self::MODULUS - 1)`. + /// Returns `None` if the integer is outside this range. + fn from_bigint(other: BigInt) -> Option>; + + /// Convert a field element to an integer in the range `0..(Self::MODULUS - 1)`. + fn into_bigint(other: Fp) -> BigInt; +} + +/// Represents an element of the prime field F_p, where `p == P::MODULUS`. +/// This type can represent elements in any field of size at most N * 64 bits. +#[derive(Derivative)] +#[derivative( + Default(bound = ""), + Hash(bound = ""), + Clone(bound = ""), + Copy(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +pub struct Fp( + pub BigInt, + #[derivative(Debug = "ignore")] + #[doc(hidden)] + pub PhantomData

, +); + +impl Fp { + /// Construct a new prime element directly from its underlying + /// `BigInteger` data type. + #[inline] + pub const fn new(element: BigInt) -> Self { + Self(element, PhantomData) + } +} + +impl, const N: usize> Fp { + #[inline(always)] + pub(crate) fn is_valid(&self) -> bool { + self.0 < P::MODULUS + } + + #[inline] + fn reduce(&mut self) { + if !self.is_valid() { + self.0.sub_noborrow(&P::MODULUS); + } + } + + fn shave_bits() -> usize { + 64 * N - usize::from(P::MODULUS_BIT_SIZE) + } +} + +impl ark_std::fmt::Debug for Fp { + fn fmt(&self, f: &mut ark_std::fmt::Formatter<'_>) -> ark_std::fmt::Result { + ark_std::fmt::Debug::fmt(&self.0, f) + } +} + +impl, const N: usize> Zero for Fp { + #[inline] + fn zero() -> Self { + P::ZERO + } + + #[inline] + fn is_zero(&self) -> bool { + *self == P::ZERO + } +} + +impl, const N: usize> One for Fp { + #[inline] + fn one() -> Self { + P::ONE + } + + #[inline] + fn is_one(&self) -> bool { + *self == P::ONE + } +} + +impl, const N: usize> Field for Fp { + type BasePrimeField = Self; + + fn extension_degree() -> u64 { + 1 + } + + fn from_base_prime_field_elems(elems: &[Self::BasePrimeField]) -> Option { + if elems.len() != (Self::extension_degree() as usize) { + return None; + } + Some(elems[0]) + } + + #[inline] + fn double(&self) -> Self { + let mut temp = *self; + temp.double_in_place(); + temp + } + + #[inline] + fn double_in_place(&mut self) -> &mut Self { + P::double_in_place(self); + self + } + + #[inline] + fn characteristic() -> &'static [u64] { + P::MODULUS.as_ref() + } + + #[inline] + fn from_random_bytes_with_flags(bytes: &[u8]) -> Option<(Self, F)> { + if F::BIT_SIZE > 8 { + return None; + } else { + let shave_bits = Self::shave_bits(); + let mut result_bytes = buffer_helpers::SerBuffer::zeroed(); + // Copy the input into a temporary buffer. + result_bytes.copy_from_u8_slice(bytes); + // This mask retains everything in the last limb + // that is below `P::MODULUS_BIT_SIZE`. + let last_limb_mask = (u64::MAX >> shave_bits).to_le_bytes(); + let mut last_bytes_mask = [0u8; 9]; + last_bytes_mask[..8].copy_from_slice(&last_limb_mask); + + // Length of the buffer containing the field element and the flag. + let output_byte_size = buffer_byte_size(P::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); + // Location of the flag is the last byte of the serialized + // form of the field element. + let flag_location = output_byte_size - 1; + + // At which byte is the flag located in the last limb? + let flag_location_in_last_limb = flag_location - (8 * (N - 1)); + + // Take all but the last 9 bytes. + let last_bytes = result_bytes.last_n_plus_1_bytes_mut(); + + // The mask only has the last `F::BIT_SIZE` bits set + let flags_mask = u8::MAX.checked_shl(8 - (F::BIT_SIZE as u32)).unwrap_or(0); + + // Mask away the remaining bytes, and try to reconstruct the + // flag + let mut flags: u8 = 0; + for (i, (b, m)) in last_bytes.zip(&last_bytes_mask).enumerate() { + if i == flag_location_in_last_limb { + flags = *b & flags_mask + } + *b &= m; + } + Self::deserialize(&result_bytes[..(N * 8)]) + .ok() + .and_then(|f| F::from_u8(flags).map(|flag| (f, flag))) + } + } + + #[inline] + fn square(&self) -> Self { + let mut temp = self.clone(); + temp.square_in_place(); + temp + } + + fn square_in_place(&mut self) -> &mut Self { + P::square_in_place(self); + self + } + + #[inline] + fn inverse(&self) -> Option { + P::inverse(&self) + } + + fn inverse_in_place(&mut self) -> Option<&mut Self> { + if let Some(inverse) = self.inverse() { + *self = inverse; + Some(self) + } else { + None + } + } + + /// The Frobenius map has no effect in a prime field. + #[inline] + fn frobenius_map(&mut self, _: usize) {} +} + +impl, const N: usize> PrimeField for Fp { + type BigInt = BigInt; + const MODULUS: Self::BigInt = P::MODULUS; + const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt = P::MODULUS_MINUS_ONE_DIV_TWO; + const TRACE: Self::BigInt = P::T; + const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt = P::T_MINUS_ONE_DIV_TWO; + const MODULUS_BIT_SIZE: u16 = P::MODULUS_BIT_SIZE; + + #[inline] + fn from_bigint(r: BigInt) -> Option { + P::from_bigint(r) + } + + fn into_bigint(&self) -> BigInt { + P::into_bigint(*self) + } +} + +impl, const N: usize> FftField for Fp { + type FftConfig = P; + + #[inline] + fn two_adic_root_of_unity() -> Self { + P::TWO_ADIC_ROOT_OF_UNITY + } + + #[inline] + fn large_subgroup_root_of_unity() -> Option { + P::LARGE_SUBGROUP_ROOT_OF_UNITY + } + + #[inline] + fn multiplicative_generator() -> Self { + P::GENERATOR + } +} + +impl, const N: usize> SquareRootField for Fp { + #[inline] + fn legendre(&self) -> LegendreSymbol { + use crate::fields::LegendreSymbol::*; + + // s = self^((MODULUS - 1) // 2) + let s = self.pow(P::MODULUS_MINUS_ONE_DIV_TWO); + if s.is_zero() { + Zero + } else if s.is_one() { + QuadraticResidue + } else { + QuadraticNonResidue + } + } + + #[inline] + fn sqrt(&self) -> Option { + sqrt_impl!(Self, P, self) + } + + fn sqrt_in_place(&mut self) -> Option<&mut Self> { + (*self).sqrt().map(|sqrt| { + *self = sqrt; + self + }) + } +} + +/// Note that this implementation of `Ord` compares field elements viewing +/// them as integers in the range 0, 1, ..., P::MODULUS - 1. However, other +/// implementations of `PrimeField` might choose a different ordering, and +/// as such, users should use this `Ord` for applications where +/// any ordering suffices (like in a BTreeMap), and not in applications +/// where a particular ordering is required. +impl, const N: usize> Ord for Fp { + #[inline(always)] + fn cmp(&self, other: &Self) -> Ordering { + self.into_bigint().cmp(&other.into_bigint()) + } +} + +/// Note that this implementation of `PartialOrd` compares field elements viewing +/// them as integers in the range 0, 1, ..., `P::MODULUS` - 1. However, other +/// implementations of `PrimeField` might choose a different ordering, and +/// as such, users should use this `PartialOrd` for applications where +/// any ordering suffices (like in a BTreeMap), and not in applications +/// where a particular ordering is required. +impl, const N: usize> PartialOrd for Fp { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl, const N: usize> From for Fp { + fn from(other: u128) -> Self { + let mut default_int = BigInt::default(); + if N == 1 { + default_int.0[0] = (other % u128::from(P::MODULUS.0[0])) as u64; + } else { + let upper = (other >> 64) as u64; + let lower = ((other << 64) >> 64) as u64; + // This is equivalent to the following, but satisfying the compiler: + // default_int.0[0] = lower; + // default_int.0[1] = upper; + let limbs = [lower, upper]; + for (cur, other) in default_int.0.iter_mut().zip(&limbs) { + *cur = *other; + } + } + Self::from_bigint(default_int).unwrap() + } +} + +impl, const N: usize> From for Fp { + fn from(other: i128) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: bool) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u64::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: u64) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u64::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: i64) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: u32) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u32::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: i32) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: u16) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u16::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: i16) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: u8) -> Self { + if N == 1 { + Self::from_bigint(BigInt::from(u64::from(other) % P::MODULUS.0[0])).unwrap() + } else { + Self::from_bigint(BigInt::from(u8::from(other))).unwrap() + } + } +} + +impl, const N: usize> From for Fp { + fn from(other: i8) -> Self { + let abs = Self::from(other.unsigned_abs()); + if other.is_positive() { + abs + } else { + -abs + } + } +} + +impl, const N: usize> ark_std::rand::distributions::Distribution> + for ark_std::rand::distributions::Standard +{ + #[inline] + fn sample(&self, rng: &mut R) -> Fp { + loop { + let mut tmp = Fp::new(rng.sample(ark_std::rand::distributions::Standard)); + let shave_bits = Fp::::shave_bits(); + // Mask away the unused bits at the beginning. + assert!(shave_bits <= 64); + let mask = if shave_bits == 64 { + 0 + } else { + core::u64::MAX >> shave_bits + }; + tmp.0 .0.last_mut().map(|val| *val &= mask); + + if tmp.is_valid() { + return tmp; + } + } + } +} + +impl, const N: usize> CanonicalSerializeWithFlags for Fp { + fn serialize_with_flags( + &self, + mut writer: W, + flags: F, + ) -> Result<(), SerializationError> { + let bigint_byte_size = N * 8; + // All reasonable `Flags` should be less than 8 bits in size + // (256 values are enough for anyone!) + if F::BIT_SIZE > 8 { + return Err(SerializationError::NotEnoughSpace); + } + + // Calculate the number of bytes required to represent a field element + // serialized with `flags`. If `F::BIT_SIZE < 8`, + // this is at most `N * 8 + 1` + let output_byte_size = buffer_byte_size(P::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); + + // Write out `self` to a temporary buffer. + // The size of the buffer is $byte_size + 1 because `F::BIT_SIZE` + // is at most 8 bits. + let mut bytes = buffer_helpers::SerBuffer::zeroed(); + bytes.copy_from_u64_slice(&self.into_bigint().0); + // Mask out the bits of the last byte that correspond to the flag. + bytes[output_byte_size - 1] |= flags.u8_bitmask(); + + bytes.write_up_to(writer, output_byte_size)?; + Ok(()) + } + + // Let `m = 8 * n` for some `n` be the smallest multiple of 8 greater + // than `P::MODULUS_BIT_SIZE`. + // If `(m - P::MODULUS_BIT_SIZE) >= F::BIT_SIZE` , then this method returns `n`; + // otherwise, it returns `n + 1`. + fn serialized_size_with_flags(&self) -> usize { + buffer_byte_size(P::MODULUS_BIT_SIZE as usize + F::BIT_SIZE) + } +} + +impl, const N: usize> CanonicalSerialize for Fp { + #[inline] + fn serialize(&self, writer: W) -> Result<(), SerializationError> { + self.serialize_with_flags(writer, EmptyFlags) + } + + #[inline] + fn serialized_size(&self) -> usize { + self.serialized_size_with_flags::() + } +} + +impl, const N: usize> CanonicalDeserializeWithFlags for Fp { + fn deserialize_with_flags( + mut reader: R, + ) -> Result<(Self, F), SerializationError> { + // All reasonable `Flags` should be less than 8 bits in size + // (256 values are enough for anyone!) + if F::BIT_SIZE > 8 { + return Err(SerializationError::NotEnoughSpace); + } + // Calculate the number of bytes required to represent a field element + // serialized with `flags`. If `F::BIT_SIZE < 8`, + // this is at most `$byte_size + 1` + let output_byte_size = buffer_byte_size(P::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); + + let mut masked_bytes = buffer_helpers::SerBuffer::zeroed(); + masked_bytes.read_exact_up_to(reader, output_byte_size); + let flags = F::from_u8_remove_flags(&mut masked_bytes[output_byte_size - 1]) + .ok_or(SerializationError::UnexpectedFlags)?; + + let self_integer = masked_bytes.to_bigint(); + Self::from_bigint(self_integer) + .map(|v| (v, flags)) + .ok_or(SerializationError::InvalidData) + } +} + +impl, const N: usize> CanonicalDeserialize for Fp { + fn deserialize(reader: R) -> Result { + Self::deserialize_with_flags::(reader).map(|(r, _)| r) + } +} + +impl, const N: usize> FromStr for Fp { + type Err = (); + + /// Interpret a string of numbers as a (congruent) prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + fn from_str(s: &str) -> Result { + if s.is_empty() { + return Err(()); + } + + if s == "0" { + return Ok(Self::zero()); + } + + let mut res = Self::zero(); + + let ten = Self::from(BigInt::from(10u8)); + + let mut first_digit = true; + + for c in s.chars() { + match c.to_digit(10) { + Some(c) => { + if first_digit { + if c == 0 { + return Err(()); + } + + first_digit = false; + } + + res.mul_assign(&ten); + let digit = Self::from(u64::from(c)); + res.add_assign(&digit); + } + None => { + return Err(()); + } + } + } + if !res.is_valid() { + Err(()) + } else { + Ok(res) + } + } +} + +/// Outputs a string containing the value of `self`, chunked up into +/// 64-bit limbs. +impl, const N: usize> Display for Fp { + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, stringify!(Fp "({})"), self.into_bigint()) + } +} + +impl, const N: usize> Neg for Fp { + type Output = Self; + #[inline] + #[must_use] + fn neg(self) -> Self { + if !self.is_zero() { + let mut tmp = P::MODULUS; + tmp.sub_noborrow(&self.0); + Fp::new(tmp) + } else { + self + } + } +} + +impl<'a, P: FpConfig, const N: usize> Add<&'a Fp> for Fp { + type Output = Self; + + #[inline] + fn add(mut self, other: &Self) -> Self { + self.add_assign(other); + self + } +} + +impl<'a, P: FpConfig, const N: usize> Sub<&'a Fp> for Fp { + type Output = Self; + + #[inline] + fn sub(mut self, other: &Self) -> Self { + self.sub_assign(other); + self + } +} + +impl<'a, P: FpConfig, const N: usize> Mul<&'a Fp> for Fp { + type Output = Self; + + #[inline] + fn mul(mut self, other: &Self) -> Self { + self.mul_assign(other); + self + } +} + +impl<'a, P: FpConfig, const N: usize> Div<&'a Fp> for Fp { + type Output = Self; + + /// Returns `self * other.inverse()` if `other.inverse()` is `Some`, and + /// panics otherwise. + #[inline] + fn div(mut self, other: &Self) -> Self { + self.mul_assign(&other.inverse().unwrap()); + self + } +} + +impl<'a, P: FpConfig, const N: usize> AddAssign<&'a Self> for Fp { + #[inline] + fn add_assign(&mut self, other: &Self) { + P::add_assign(self, other) + } +} + +impl<'a, P: FpConfig, const N: usize> SubAssign<&'a Self> for Fp { + #[inline] + fn sub_assign(&mut self, other: &Self) { + P::sub_assign(self, other); + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::Add for Fp { + type Output = Self; + + #[inline] + fn add(mut self, other: Self) -> Self { + self.add_assign(&other); + self + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::Add<&'a mut Self> for Fp { + type Output = Self; + + #[inline] + fn add(mut self, other: &'a mut Self) -> Self { + self.add_assign(&*other); + self + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::Sub for Fp { + type Output = Self; + + #[inline] + fn sub(self, other: Self) -> Self { + self.sub_assign(&other); + self + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::Sub<&'a mut Self> for Fp { + type Output = Self; + + #[inline] + fn sub(mut self, other: &'a mut Self) -> Self { + self.sub_assign(&*other); + self + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::iter::Sum for Fp { + fn sum>(iter: I) -> Self { + iter.fold(Self::zero(), core::ops::Add::add) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::iter::Sum<&'a Self> for Fp { + fn sum>(iter: I) -> Self { + iter.fold(Self::zero(), core::ops::Add::add) + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::AddAssign for Fp { + fn add_assign(&mut self, other: Self) { + self.add_assign(&other) + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::SubAssign for Fp { + fn sub_assign(&mut self, other: Self) { + self.sub_assign(&other) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::AddAssign<&'a mut Self> for Fp { + fn add_assign(&mut self, other: &'a mut Self) { + self.add_assign(&*other) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::SubAssign<&'a mut Self> for Fp { + fn sub_assign(&mut self, other: &'a mut Self) { + self.sub_assign(&*other) + } +} + +impl<'a, P: FpConfig, const N: usize> MulAssign<&'a Self> for Fp { + #[inline] + fn mul_assign(&mut self, other: &Self) { + P::mul_assign(self, other) + } +} + +/// Computes `self *= other.inverse()` if `other.inverse()` is `Some`, and +/// panics otherwise. +impl<'a, P: FpConfig, const N: usize> DivAssign<&'a Self> for Fp { + #[inline] + fn div_assign(&mut self, other: &Self) { + self.mul_assign(&other.inverse().unwrap()); + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::Mul for Fp { + type Output = Self; + + #[inline] + fn mul(mut self, other: Self) -> Self { + self.mul_assign(&other); + self + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::Div for Fp { + type Output = Self; + + #[inline] + fn div(mut self, other: Self) -> Self { + self.div_assign(&other); + self + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::Mul<&'a mut Self> for Fp { + type Output = Self; + + #[inline] + fn mul(mut self, other: &'a mut Self) -> Self { + self.mul_assign(&*other); + self + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::Div<&'a mut Self> for Fp { + type Output = Self; + + #[inline] + fn div(mut self, other: &'a mut Self) -> Self { + self.div_assign(&*other); + self + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::iter::Product for Fp { + fn product>(iter: I) -> Self { + iter.fold(Self::one(), core::ops::Mul::mul) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::iter::Product<&'a Self> for Fp { + fn product>(iter: I) -> Self { + iter.fold(Self::one(), Mul::mul) + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::MulAssign for Fp { + fn mul_assign(&mut self, other: Self) { + self.mul_assign(&other) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::DivAssign<&'a mut Self> for Fp { + fn div_assign(&mut self, other: &'a mut Self) { + self.div_assign(&*other) + } +} + +#[allow(unused_qualifications)] +impl<'a, P: FpConfig, const N: usize> core::ops::MulAssign<&'a mut Self> for Fp { + fn mul_assign(&mut self, other: &'a mut Self) { + self.mul_assign(&*other) + } +} + +#[allow(unused_qualifications)] +impl, const N: usize> core::ops::DivAssign for Fp { + fn div_assign(&mut self, other: Self) { + self.div_assign(&other) + } +} + +impl, const N: usize> zeroize::Zeroize for Fp { + // The phantom data does not contain element-specific data + // and thus does not need to be zeroized. + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl, const N: usize> From for Fp { + #[inline] + fn from(val: num_bigint::BigUint) -> Fp { + Fp::::from_le_bytes_mod_order(&val.to_bytes_le()) + } +} + +impl, const N: usize> From> for num_bigint::BigUint { + #[inline] + fn from(other: Fp) -> Self { + other.into_bigint().into() + } +} + +impl, const N: usize> Into> for Fp { + fn into(self) -> BigInt { + self.into_bigint() + } +} + +impl, const N: usize> From> for Fp { + /// Converts `Self::BigInteger` into `Self` + fn from(int: BigInt) -> Self { + Self::from_bigint(int).unwrap() + } +} diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs new file mode 100644 index 000000000..b8b23d833 --- /dev/null +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -0,0 +1,480 @@ +use ark_std::{marker::PhantomData, Zero}; + +use super::{Fp, FpConfig}; +use crate::{biginteger::arithmetic as fa, BigInt, BigInteger, FftConfig}; + +/// A trait that defines parameters for a prime field. +pub trait MontConfig: 'static + Copy + Sync + Send { + /// The modulus of the field. + const MODULUS: BigInt; + + /// The number of bits needed to represent the `Self::MODULUS`. + const MODULUS_BIT_SIZE: u16; + + /// Let `M` be the power of 2^64 nearest to `Self::MODULUS_BITS`. Then + /// `R = M % Self::MODULUS`. + const R: BigInt; + + /// R2 = R^2 % Self::MODULUS + const R2: BigInt; + + /// INV = -MODULUS^{-1} mod 2^64 + const INV: u64; + + /// A multiplicative generator of the field. + /// `Self::GENERATOR` is an element having multiplicative order + /// `Self::MODULUS - 1`. + const GENERATOR: Fp, N>; + + /// The number of bits that can be reliably stored. + /// (Should equal `SELF::MODULUS_BITS - 1`) + const CAPACITY: u32; + + /// t for 2^s * t = MODULUS - 1, and t coprime to 2. + const T: BigInt; + + /// (t - 1) / 2 + const T_MINUS_ONE_DIV_TWO: BigInt; + + /// (Self::MODULUS - 1) / 2 + const MODULUS_MINUS_ONE_DIV_TWO: BigInt; + + /// Let `N` be the size of the multiplicative group defined by the field. + /// Then `TWO_ADICITY` is the two-adicity of `N`, i.e. the integer `s` + /// such that `N = 2^s * t` for some odd integer `t`. + const TWO_ADICITY: u32; + + /// 2^s root of unity computed by GENERATOR^t + const TWO_ADIC_ROOT_OF_UNITY: Fp, N>; + + /// An integer `b` such that there exists a multiplicative subgroup + /// of size `b^k` for some integer `k`. + const SMALL_SUBGROUP_BASE: Option = None; + + /// The integer `k` such that there exists a multiplicative subgroup + /// of size `Self::SMALL_SUBGROUP_BASE^k`. + const SMALL_SUBGROUP_BASE_ADICITY: Option = None; + + /// GENERATOR^((MODULUS-1) / (2^s * + /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix + /// FFT. + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option, N>> = None; +} + +pub struct MontBackend, const N: usize>(PhantomData); + +impl, const N: usize> FftConfig for MontBackend { + type Field = Fp; + const TWO_ADICITY: u32 = T::TWO_ADICITY; + const TWO_ADIC_ROOT_OF_UNITY: Self::Field = T::TWO_ADIC_ROOT_OF_UNITY; + const SMALL_SUBGROUP_BASE: Option = T::SMALL_SUBGROUP_BASE; + const SMALL_SUBGROUP_BASE_ADICITY: Option = T::SMALL_SUBGROUP_BASE_ADICITY; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = T::LARGE_SUBGROUP_ROOT_OF_UNITY; +} + +impl, const N: usize> FpConfig for MontBackend { + /// The modulus of the field. + const MODULUS: crate::BigInt = T::MODULUS; + + /// The number of bits needed to represent the `Self::MODULUS`. + const MODULUS_BIT_SIZE: u16 = T::MODULUS_BIT_SIZE; + + /// A multiplicative generator of the field. + /// `Self::GENERATOR` is an element having multiplicative order + /// `Self::MODULUS - 1`. + const GENERATOR: Fp = T::GENERATOR; + + /// Additive identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e + f = f`. + const ZERO: Fp = Fp::new(BigInt([0u64; N])); + + /// Multiplicative identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e * f = f`. + const ONE: Fp = Fp::new(T::R); + + /// t for 2^s * t = MODULUS - 1, and t coprime to 2. + // TODO: compute this directly from `MODULUS` + const T: crate::BigInt = T::T; + + /// (t - 1) / 2 + // TODO: compute this directly from `T` + const T_MINUS_ONE_DIV_TWO: crate::BigInt = T::T_MINUS_ONE_DIV_TWO; + + /// (Self::MODULUS - 1) / 2 + // TODO: compute this directly from `MODULUS` + const MODULUS_MINUS_ONE_DIV_TWO: crate::BigInt = T::MODULUS_MINUS_ONE_DIV_TWO; + + /// Set a += b; + fn add_assign(a: &mut Fp, b: &Fp) { + // This cannot exceed the backing capacity. + a.0.add_nocarry(&b.0); + // However, it may need to be reduced + a.reduce(); + } + + fn sub_assign(a: &mut Fp, b: &Fp) { + // If `other` is larger than `self`, add the modulus to self first. + if b.0 > a.0 { + a.0.add_nocarry(&Self::MODULUS); + } + a.0.sub_noborrow(&b.0); + } + + fn double_in_place(a: &mut Fp) { + // This cannot exceed the backing capacity. + a.0.mul2(); + // However, it may need to be reduced. + a.reduce(); + } + + /// This modular multiplication algorithm uses Montgomery + /// reduction for efficient implementation. It also additionally + /// uses the "no-carry optimization" outlined + /// [here](https://hackmd.io/@zkteam/modular_multiplication) if + /// `P::MODULUS` has (a) a non-zero MSB, and (b) at least one + /// zero bit in the rest of the modulus. + #[inline] + #[ark_ff_asm::unroll_for_loops] + fn mul_assign(a: &mut Fp, b: &Fp) { + // Checking the modulus at compile time + let first_bit_set = T::MODULUS.0[N - 1] >> 63 != 0; + // N can be 1, hence we can run into a case with an unused mut. + #[allow(unused_mut)] + let mut all_bits_set = T::MODULUS.0[N - 1] == !0 - (1 << 63); + for i in 1..N { + all_bits_set &= T::MODULUS.0[N - i - 1] == !0u64; + } + let no_carry = !(first_bit_set || all_bits_set); + + // No-carry optimisation applied to CIOS + if no_carry { + #[cfg(use_asm)] + #[allow(unsafe_code, unused_mut)] + { + // Tentatively avoid using assembly for `$limbs == 1`. + if N <= 6 && N > 1 { + ark_ff_asm::x86_64_asm_mul!($limbs, (a.0).0, (b.0).0); + self.reduce(); + return; + } + } + let mut r = [0u64; N]; + let mut carry1 = 0u64; + let mut carry2 = 0u64; + + for i in 0..N { + r[0] = fa::mac(r[0], (a.0).0[0], (b.0).0[i], &mut carry1); + let k = r[0].wrapping_mul(T::INV); + fa::mac_discard(r[0], k, T::MODULUS.0[0], &mut carry2); + for j in 1..N { + r[j] = fa::mac_with_carry(r[j], (a.0).0[j], (b.0).0[i], &mut carry1); + r[j - 1] = fa::mac_with_carry(r[j], k, T::MODULUS.0[j], &mut carry2); + } + r[N - 1] = carry1 + carry2; + } + (a.0).0 = r; + a.reduce(); + // Alternative implementation + } else { + *a = a.mul_without_reduce(b, T::MODULUS, T::INV); + a.reduce(); + } + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + #[allow(unused_braces, clippy::absurd_extreme_comparisons)] + fn square_in_place(a: &mut Fp) { + if N == 1 { + // We default to multiplying with `a` using the `Mul` impl + // for the N == 1 case + Self::mul_assign(a, &*a); + return; + } + #[cfg(use_asm)] + #[allow(unsafe_code, unused_mut)] + { + // Checking the modulus at compile time + let first_bit_set = T::MODULUS.0[N - 1] >> 63 != 0; + let mut all_bits_set = T::MODULUS.0[N - 1] == !0 - (1 << 63); + for i in 1..N { + all_bits_set &= T::MODULUS.0[N - i - 1] == core::u64::MAX; + } + let no_carry: bool = !(first_bit_set || all_bits_set); + + if N <= 6 && no_carry { + ark_ff_asm::x86_64_asm_square!(N, (a.0).0); + a.reduce(); + return a; + } + } + let mut r = super::buffer_helpers::MulBuffer::new([0u64; N], [0u64; N]); + + let mut carry = 0; + for i in 0..N { + if i < N - 1 { + for j in 0..N { + if j > i { + r[i + j] = fa::mac_with_carry(r[i + j], (a.0).0[i], (a.0).0[j], &mut carry); + } + } + r.b1[i] = carry; + carry = 0; + } + } + r.b1[N - 1] >>= 63; + for i in 0..N { + r[2 * (N - 1) - i] = (r[2 * (N - 1) - i] << 1) | (r[2 * (N - 1) - (i + 1)] >> 63); + } + for i in 3..N { + r[N + 1 - i] = (r[N + 1 - i] << 1) | (r[N - i] >> 63); + } + r.b0[1] <<= 1; + + for i in 0..N { + r[2 * i] = fa::mac_with_carry(r[2 * i], (a.0).0[i], (a.0).0[i], &mut carry); + // need unused assignment because the last iteration of the loop produces an + // assignment to `carry` that is unused. + #[allow(unused_assignments)] + { + r[2 * i + 1] = fa::adc(r[2 * i + 1], 0, &mut carry); + } + } + // Montgomery reduction + let mut _carry2 = 0; + for i in 0..N { + let k = r[i].wrapping_mul(T::INV); + let mut carry = 0; + fa::mac_with_carry(r[i], k, T::MODULUS.0[0], &mut carry); + for j in 1..N { + r[j + i] = fa::mac_with_carry(r[j + i], k, T::MODULUS.0[j], &mut carry); + } + r.b1[i] = fa::adc(r.b1[i], _carry2, &mut carry); + _carry2 = carry; + } + (a.0).0.copy_from_slice(&r.b1); + a.reduce(); + } + + fn inverse(a: &Fp) -> Option> { + if a.is_zero() { + None + } else { + // Guajardo Kumar Paar Pelzl + // Efficient Software-Implementation of Finite Fields with Applications to + // Cryptography + // Algorithm 16 (BEA for Inversion in Fp) + + let one = BigInt::from(1u64); + + let mut u = a.0; + let mut v = T::MODULUS; + let mut b = Fp::new(T::R2); // Avoids unnecessary reduction step. + let mut c = Fp::zero(); + + while u != one && v != one { + while u.is_even() { + u.div2(); + + if b.0.is_even() { + b.0.div2(); + } else { + b.0.add_nocarry(&T::MODULUS); + b.0.div2(); + } + } + + while v.is_even() { + v.div2(); + + if c.0.is_even() { + c.0.div2(); + } else { + c.0.add_nocarry(&T::MODULUS); + c.0.div2(); + } + } + + if v < u { + u.sub_noborrow(&v); + b -= &c; + } else { + v.sub_noborrow(&u); + c -= &b; + } + } + + if u == one { + Some(b) + } else { + Some(c) + } + } + } + + fn from_bigint(r: BigInt) -> Option> { + let mut r = Fp::new(r); + if r.is_zero() { + return Some(r); + } else if r.is_valid() { + r *= &Fp::new(T::R2); + Some(r) + } else { + None + } + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + #[allow(clippy::modulo_one)] + fn into_bigint(a: Fp) -> BigInt { + let mut tmp = a.0; + let mut r = tmp.0; + // Montgomery Reduction + for i in 0..N { + let k = r[i].wrapping_mul(T::INV); + let mut carry = 0; + + fa::mac_with_carry(r[i], k, T::MODULUS.0[0], &mut carry); + for j in 1..N { + r[(j + i) % N] = fa::mac_with_carry(r[(j + i) % N], k, T::MODULUS.0[j], &mut carry); + } + r[i % N] = carry; + } + tmp.0 = r; + tmp + } +} + +impl, const N: usize> Fp, N> { + #[ark_ff_asm::unroll_for_loops] + const fn const_is_zero(&self) -> bool { + let mut is_zero = true; + crate::for_loop!((i in 0..N) { + is_zero &= (self.0).0[i] == 0; + }); + is_zero + } + + const fn const_neg(self, modulus: BigInt) -> Self { + if !self.const_is_zero() { + Self::new(Self::sub_noborrow(&modulus, &self.0)) + } else { + self + } + } + + /// Interpret a string of decimal numbers as a prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + /// For *internal* use only; please use the `field_new` macro instead + /// of this method + #[doc(hidden)] + pub const fn const_from_str( + limbs: &[u64], + is_positive: bool, + r2: BigInt, + modulus: BigInt, + inv: u64, + ) -> Self { + let mut repr = BigInt::([0; N]); + crate::for_loop!((i in 0..(limbs.len())) { + repr.0[i] = limbs[i]; + }); + let res = Self::const_from_bigint(repr, r2, modulus, inv); + if is_positive { + res + } else { + res.const_neg(modulus) + } + } + + #[inline] + pub(crate) const fn const_from_bigint( + repr: BigInt, + r2: BigInt, + modulus: BigInt, + inv: u64, + ) -> Self { + let mut r = Self::new(repr); + if r.const_is_zero() { + r + } else { + r = r.const_mul(&Fp(r2, PhantomData), modulus, inv); + r + } + } + + #[ark_ff_asm::unroll_for_loops] + const fn mul_without_reduce(mut self, other: &Self, modulus: BigInt, inv: u64) -> Self { + use crate::biginteger::arithmetic as fa; + + let mut r = super::buffer_helpers::MulBuffer::zeroed(); + + crate::for_loop!((i in 0..N) { + let mut carry = 0; + crate::for_loop!((j in 0..N) { + *r.get_mut(j + i) = fa::mac_with_carry(*r.get(j + i), (self.0).0[i], (other.0).0[j], &mut carry); + }); + r.b1[i] = carry; + i += 1; + + }); + // Montgomery reduction + let mut _carry2 = 0; + crate::for_loop!((i in 0..N) { + let k = r.b0[i].wrapping_mul(inv); + let mut carry = 0; + fa::mac_with_carry(r.b0[i], k, modulus.0[0], &mut carry); + crate::for_loop!((j in 1..N) { + *r.get_mut(j + i) = fa::mac_with_carry(*r.get(j + i), k, modulus.0[j], &mut carry); + }); + r.b1[i] = fa::adc(r.b1[i], _carry2, &mut carry); + _carry2 = carry; + }); + + crate::for_loop!((i in 0..N) { + (self.0).0[i] = r.b1[i]; + }); + self + } + + #[ark_ff_asm::unroll_for_loops] + const fn const_mul(mut self, other: &Self, modulus: BigInt, inv: u64) -> Self { + self = self.mul_without_reduce(other, modulus, inv); + self.const_reduce(modulus) + } + + #[ark_ff_asm::unroll_for_loops] + const fn const_is_valid(&self, modulus: BigInt) -> bool { + crate::for_loop!((i in 0..N) { + if (self.0).0[(N - i - 1)] < modulus.0[(N - i - 1)] { + return true + } else if (self.0).0[(N - i - 1)] > modulus.0[(N - i - 1)] { + return false + } + }); + false + } + + #[inline] + const fn const_reduce(mut self, modulus: BigInt) -> Self { + if !self.const_is_valid(modulus) { + self.0 = Self::sub_noborrow(&self.0, &modulus); + } + self + } + + #[ark_ff_asm::unroll_for_loops] + // need unused assignment because the last iteration of the loop produces an assignment + // to `borrow` that is unused. + #[allow(unused_assignments)] + const fn sub_noborrow(a: &BigInt, b: &BigInt) -> BigInt { + use crate::biginteger::arithmetic::sbb; + let mut a = *a; + let mut borrow = 0; + crate::for_loop!((i in 0..N) { + a.0[i] = sbb(a.0[i], b.0[i], &mut borrow); + }); + a + } +} diff --git a/ff/src/fields/models/mod.rs b/ff/src/fields/models/mod.rs index 4f70b4fe4..31f9d0c75 100644 --- a/ff/src/fields/models/mod.rs +++ b/ff/src/fields/models/mod.rs @@ -1,72 +1,5 @@ -use ark_std::{ - cmp::{Ord, Ordering, PartialOrd}, - fmt::{Display, Formatter, Result as FmtResult}, - io::{Read, Result as IoResult, Write}, - marker::PhantomData, - ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, - str::FromStr, -}; -use num_traits::{One, Zero}; - -use crate::{ - biginteger::{ - arithmetic as fa, BigInt, BigInteger as _BigInteger, BigInteger256, BigInteger320, - BigInteger384, BigInteger448, BigInteger64, BigInteger768, BigInteger832, - }, - bytes::{FromBytes, ToBytes}, - fields::{FftField, Field, FpParameters, LegendreSymbol, PrimeField, SquareRootField}, -}; -use ark_serialize::*; - -impl_Fp!(Fp64, Fp64Parameters, BigInteger64, BigInteger64, 1, "64"); -impl_Fp!( - Fp256, - Fp256Parameters, - BigInteger256, - BigInteger256, - 4, - "256" -); -impl_Fp!( - Fp320, - Fp320Parameters, - BigInteger320, - BigInteger320, - 5, - "320" -); -impl_Fp!( - Fp384, - Fp384Parameters, - BigInteger384, - BigInteger384, - 6, - "384" -); -impl_Fp!( - Fp448, - Fp448Parameters, - BigInteger448, - BigInteger448, - 7, - "448" -); -impl_Fp!( - Fp768, - Fp768Parameters, - BigInteger768, - BigInteger768, - 12, - "768" -); -impl_Fp!( - Fp832, - Fp832Parameters, - BigInteger832, - BigInteger832, - 13, - "832" -); +pub mod fp; +pub use self::fp::*; pub mod fp2; pub use self::fp2::*; diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 1888297a7..d4ffc12db 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -5,7 +5,7 @@ use ark_serialize::{ use ark_std::{ cmp::{Ord, Ordering, PartialOrd}, fmt, - io::{Read, Result as IoResult, Write}, + io::{Read, Write}, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, vec::Vec, }; @@ -20,7 +20,6 @@ use ark_std::rand::{ use crate::{ biginteger::BigInteger, - bytes::{FromBytes, ToBytes}, fields::{Field, LegendreSymbol, PrimeField, SquareRootField}, ToConstraintField, UniformRand, }; @@ -412,7 +411,7 @@ where // Compute `(p+1)/2` as `1/2`. // This is cheaper than `P::BaseField::one().double().inverse()` - let mut two_inv = P::BasePrimeField::modulus(); + let mut two_inv = P::BasePrimeField::MODULUS; two_inv.add_nocarry(&1u64.into()); two_inv.div2(); @@ -579,23 +578,6 @@ impl From for QuadExtField

{ } } -impl ToBytes for QuadExtField

{ - #[inline] - fn write(&self, mut writer: W) -> IoResult<()> { - self.c0.write(&mut writer)?; - self.c1.write(writer) - } -} - -impl FromBytes for QuadExtField

{ - #[inline] - fn read(mut reader: R) -> IoResult { - let c0 = P::BaseField::read(&mut reader)?; - let c1 = P::BaseField::read(reader)?; - Ok(QuadExtField::new(c0, c1)) - } -} - impl Neg for QuadExtField

{ type Output = Self; #[inline] diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 3c088a184..36d02e7e0 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -29,6 +29,8 @@ pub use self::biginteger::*; pub mod fields; pub use self::fields::*; +pub(crate) mod const_helpers; + pub use ark_std::UniformRand; mod to_field_vec; @@ -41,7 +43,7 @@ pub use ark_std::vec; pub mod prelude { pub use crate::biginteger::BigInteger; - pub use crate::fields::{Field, FpParameters, PrimeField, SquareRootField}; + pub use crate::fields::{Field, PrimeField, SquareRootField}; pub use ark_std::UniformRand; diff --git a/ff/src/to_field_vec.rs b/ff/src/to_field_vec.rs index 721b85d55..c1e3aa3cb 100644 --- a/ff/src/to_field_vec.rs +++ b/ff/src/to_field_vec.rs @@ -1,4 +1,4 @@ -use crate::{biginteger::BigInteger, Field, FpParameters, PrimeField}; +use crate::{biginteger::BigInteger, Field, PrimeField}; use ark_std::vec::Vec; /// Types that can be converted to a vector of `F` elements. Useful for @@ -42,7 +42,7 @@ impl ToConstraintField for () { impl ToConstraintField for [u8] { #[inline] fn to_field_elements(&self) -> Option> { - let max_size = usize::try_from(::Params::CAPACITY / 8).unwrap(); + let max_size = usize::from(ConstraintF::MODULUS_BIT_SIZE / 8); let bigint_size = ::BigInt::NUM_LIMBS * 8; let fes = self .chunks(max_size) From 56e5ecc1d276981c57ca36e0c7cf23bc9ebbb916 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 00:18:27 -0800 Subject: [PATCH 02/32] More powerful compile-time Fp configuration * Rename `field_new` macros. * Introduce `const fn`s for generating many constants. * Add default associated constants to reduce boilerplate. --- ff/src/biginteger/arithmetic.rs | 43 ++- ff/src/biginteger/mod.rs | 168 +++++++++- ff/src/const_helpers.rs | 296 +++++++++++++++++- ff/src/fields/arithmetic.rs | 2 +- ff/src/fields/mod.rs | 24 +- ff/src/fields/models/cubic_extension.rs | 34 +- ff/src/fields/models/fp/buffer_helpers.rs | 251 --------------- ff/src/fields/models/fp/mod.rs | 158 +++++++--- ff/src/fields/models/fp/montgomery_backend.rs | 241 +++++++------- ff/src/fields/models/fp2.rs | 4 +- ff/src/fields/models/fp3.rs | 12 +- ff/src/fields/models/quadratic_extension.rs | 27 +- ff/src/lib.rs | 3 +- ff/src/to_field_vec.rs | 2 +- 14 files changed, 784 insertions(+), 481 deletions(-) delete mode 100644 ff/src/fields/models/fp/buffer_helpers.rs diff --git a/ff/src/biginteger/arithmetic.rs b/ff/src/biginteger/arithmetic.rs index 59c7f1335..a40e25310 100644 --- a/ff/src/biginteger/arithmetic.rs +++ b/ff/src/biginteger/arithmetic.rs @@ -1,30 +1,49 @@ use ark_std::vec::Vec; +macro_rules! adc { + ($a:expr, $b:expr, &mut $carry:expr$(,)?) => {{ + let tmp = ($a as u128) + ($b as u128) + ($carry as u128); + $carry = (tmp >> 64) as u64; + tmp as u64 + }}; +} + /// Calculate a + b + carry, returning the sum and modifying the /// carry value. #[inline(always)] -pub(crate) const fn adc(a: u64, b: u64, carry: &mut u64) -> u64 { - let tmp = (a as u128) + (b as u128) + (*carry as u128); - *carry = (tmp >> 64) as u64; - tmp as u64 +pub(crate) fn adc(a: u64, b: u64, carry: &mut u64) -> u64 { + adc!(a, b, &mut *carry) +} + +macro_rules! mac_with_carry { + ($a:expr, $b:expr, $c:expr, &mut $carry:expr$(,)?) => {{ + let tmp = ($a as u128) + ($b as u128 * $c as u128) + ($carry as u128); + $carry = (tmp >> 64) as u64; + tmp as u64 + }}; } /// Calculate a + (b * c) + carry, returning the least significant digit /// and setting carry to the most significant digit. #[inline(always)] -pub(crate) const fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 { - let tmp = (a as u128) + (b as u128 * c as u128) + (*carry as u128); - *carry = (tmp >> 64) as u64; - tmp as u64 +pub(crate) fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 { + mac_with_carry!(a, b, c, &mut *carry) +} + +#[macro_export] +macro_rules! sbb { + ($a:expr, $b:expr, &mut $borrow:expr$(,)?) => {{ + let tmp = (1u128 << 64) + ($a as u128) - ($b as u128) - ($borrow as u128); + $borrow = if tmp >> 64 == 0 { 1 } else { 0 }; + tmp as u64 + }}; } /// Calculate a - b - borrow, returning the result and modifying /// the borrow value. #[inline(always)] -pub(crate) const fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 { - let tmp = (1u128 << 64) + (a as u128) - (b as u128) - (*borrow as u128); - *borrow = if tmp >> 64 == 0 { 1 } else { 0 }; - tmp as u64 +pub(crate) fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 { + sbb!(a, b, &mut *borrow) } /// Calculate a + b * c, returning the lower 64 bits of the result and setting diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index cbcebca3b..c15f376a8 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -1,7 +1,7 @@ use crate::{ bytes::{FromBytes, ToBytes}, fields::{BitIteratorBE, BitIteratorLE}, - UniformRand, + UniformRand, const_for, }; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ @@ -34,6 +34,172 @@ impl BigInt { Self(value) } } +/// Divide self by another bignum, overwriting `q` with the quotient and `r` with the +/// remainder. +#[doc(hidden)] +macro_rules! const_modulo { + ($a:ident, $divisor:ident) => {{ + // Stupid slow base-2 long division taken from + // https://en.wikipedia.org/wiki/Division_algorithm + assert!(!$divisor.const_is_zero()); + let digit_bits = 64; + let mut quotient = Self::new([0u64; N]); + let mut remainder = Self::new([0u64; N]); + let end = $a.num_bits(); + let mut i = (end - 1) as isize; + while i >= 0 { + remainder = remainder.const_mul2(); + remainder.0[0] |= $a.get_bit(i as usize) as u64; + if remainder.const_geq($divisor) { + let (r, borrow) = remainder.const_sub_noborrow($divisor); + remainder = r; + assert!(!borrow); + // Set bit `i` of q to 1. + let digit_idx = i / digit_bits; + let bit_idx = i % digit_bits; + quotient.0[digit_idx as usize] |= 1 << bit_idx; + } + i -= 1; + } + remainder + }}; +} +impl BigInt { + #[doc(hidden)] + pub const fn const_is_even(&self) -> bool { + self.0[0] % 2 == 0 + } + + #[doc(hidden)] + pub const fn const_is_odd(&self) -> bool { + self.0[0] % 2 == 1 + } + + /// Compute a right shift of `self` + /// This is equivalent to a (saturating) division by 2. + #[doc(hidden)] + pub const fn const_shr(&self) -> Self { + let mut result = *self; + let mut t = 0; + crate::const_for!((i in 0..N) { + let a = result.0[N - i - 1]; + let t2 = a << 63; + result.0[N - i - 1] >>= 1; + result.0[N - i - 1] |= t; + t = t2; + }); + result + } + + const fn const_geq(&self, other: &Self) -> bool { + const_for!((i in 0..N) { + let a = self.0[N - i - 1]; + let b = other.0[N - i - 1]; + if a < b { + return false; + } else if a > b { + return true; + } + }); + true + } + + /// Compute the largest integer `s` such that `self = 2**s * t` for odd `t`. + #[doc(hidden)] + pub const fn two_adic_valuation(mut self) -> u32 { + let mut two_adicity = 0; + assert!(self.const_is_odd()); + // Since `self` is odd, we can always subtract one + // without a borrow + self.0[0] -= 1; + while self.const_is_even() { + self = self.const_shr(); + two_adicity += 1; + } + two_adicity + } + + /// Compute the smallest odd integer `t` such that `self = 2**s * t` for some + /// integer `s = self.two_adic_valuation()`. + #[doc(hidden)] + pub const fn two_adic_coefficient(mut self) -> Self { + assert!(self.const_is_odd()); + // Since `self` is odd, we can always subtract one + // without a borrow + self.0[0] -= 1; + while self.const_is_even() { + self = self.const_shr(); + } + assert!(self.const_is_odd()); + self + } + + /// Divide `self` by 2, rounding down if necessary. + /// That is, if `self.is_odd()`, compute `(self - 1)/2`. + /// Else, compute `self/2`. + #[doc(hidden)] + pub const fn divide_by_2_round_down(mut self) -> Self { + if self.const_is_odd() { + self.0[0] -= 1; + } + self.const_shr() + } + + /// Find the number of bits in the binary decomposition of `self`. + #[doc(hidden)] + pub const fn const_num_bits(self) -> u32 { + ((N - 1) * 64) as u32 + (64 - self.0[N-1].leading_zeros()) + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + pub(crate) const fn const_sub_noborrow(mut self, other: &Self) -> (Self, bool) { + let mut borrow = 0; + + const_for!((i in 0..N) { + self.0[i] = sbb!(self.0[i], other.0[i], &mut borrow); + }); + + (self, borrow != 0) + } + + const fn const_mul2(mut self) -> Self { + let mut last = 0; + crate::const_for!((i in 0..N) { + let a = self.0[i]; + let tmp = a >> 63; + self.0[i] <<= 1; + self.0[i] |= last; + last = tmp; + }); + self + } + + #[ark_ff_asm::unroll_for_loops] + pub(crate) const fn const_is_zero(&self) -> bool { + let mut is_zero = true; + crate::const_for!((i in 0..N) { + is_zero &= self.0[i] == 0; + }); + is_zero + } + + + + /// Computes the Montgomery R constant modulo `self`. + #[doc(hidden)] + pub const fn montgomery_r(&self) -> Self { + let two_pow_n_times_64 = crate::const_helpers::RBuffer::([0u64; N], 1); + const_modulo!(two_pow_n_times_64, self) + } + + /// Computes the Montgomery R2 constant modulo `self`. + #[doc(hidden)] + pub const fn montgomery_r2(&self) -> Self { + let two_pow_n_times_64_square = crate::const_helpers::R2Buffer::([0u64; N], [0u64; N], 1); + const_modulo!(two_pow_n_times_64_square, self) + } +} impl BigInteger for BigInt { const NUM_LIMBS: usize = N; diff --git a/ff/src/const_helpers.rs b/ff/src/const_helpers.rs index 91b8a1c4f..c4a76bd4f 100644 --- a/ff/src/const_helpers.rs +++ b/ff/src/const_helpers.rs @@ -1,10 +1,302 @@ +use ark_serialize::{Read, Write}; +use ark_std::ops::{Index, IndexMut}; + +use crate::BigInt; + + #[macro_export] -macro_rules! for_loop { +macro_rules! const_for { (($i:ident in $start:tt..$end:tt) $code:expr ) => {{ - let $i = $start; + let mut $i = $start; while $i < $end { $code $i += 1; } }}; } + +/// A buffer to hold values of size 2 * N. This is mostly +/// a hack that's necessary until `generic_const_exprs` is stable. +#[derive(Copy, Clone)] +#[repr(C, align(8))] +pub(super) struct MulBuffer { + pub(super) b0: [u64; N], + pub(super) b1: [u64; N], +} + +impl MulBuffer { + const fn new(b0: [u64; N], b1: [u64; N]) -> Self { + Self { b0, b1 } + } + + pub(super) const fn zeroed() -> Self { + let b = [0u64; N]; + Self::new(b, b) + } + + #[inline(always)] + pub(super) const fn get(&self, index: usize) -> &u64 { + if index < N { + &self.b0[index] + } else { + &self.b1[index + N] + } + } + + #[inline(always)] + pub(super) fn get_mut(&mut self, index: usize) -> &mut u64 { + if index < N { + &mut self.b0[index] + } else { + &mut self.b1[index + N] + } + } +} + + +impl Index for MulBuffer { + type Output = u64; + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + self.get(index) + } +} + +impl IndexMut for MulBuffer { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_mut(index) + } +} + +/// A buffer to hold values of size 2 * N. This is mostly +/// a hack that's necessary until `generic_const_exprs` is stable. +#[derive(Copy, Clone)] +#[repr(C, align(1))] +pub(super) struct SerBuffer { + pub(super) buffers: [[u8; 8]; N], + pub(super) last: u8, +} + +impl SerBuffer { + pub(super) const fn zeroed() -> Self { + Self { + buffers: [[0u8; 8]; N], + last: 0u8, + } + } + + #[inline(always)] + pub(super) const fn get(&self, index: usize) -> &u8 { + if index == 8 * N { + &self.last + } else { + let part = index / 8; + let in_buffer_index = index % 8; + &self.buffers[part][in_buffer_index] + } + } + + #[inline(always)] + pub(super) fn get_mut(&mut self, index: usize) -> &mut u8 { + if index == 8 * N { + &mut self.last + } else { + let part = index / 8; + let in_buffer_index = index % 8; + &mut self.buffers[part][in_buffer_index] + } + } + + #[allow(unsafe_code)] + pub(super) fn as_slice(&self) -> &[u8] { + unsafe { + ark_std::slice::from_raw_parts( + (self as *const Self) as *const u8, + 8 * N + 1, + ) + } + } + + #[inline(always)] + pub(super) fn last_n_plus_1_bytes_mut(&mut self) -> impl Iterator { + self.buffers[N - 1] + .iter_mut() + .chain(ark_std::iter::once(&mut self.last)) + } + + #[inline(always)] + pub(super) fn copy_from_u8_slice(&mut self, other: &[u8]) { + other.chunks(8).enumerate().for_each(|(i, chunk)| { + if i < N { + self.buffers[i].copy_from_slice(chunk) + } else { + self.last = chunk[0] + } + }); + } + + #[inline(always)] + pub(super) fn copy_from_u64_slice(&mut self, other: &[u64; N]) { + other + .iter() + .zip(&mut self.buffers) + .for_each(|(other, this)| *this = other.to_le_bytes()); + } + + #[inline(always)] + pub(super) fn to_bigint(&self) -> BigInt { + let mut self_integer = BigInt::from(0u64); + self_integer + .0 + .iter_mut() + .zip(self.buffers) + .for_each(|(other, this)| *other = u64::from_le_bytes(this)); + self_integer + } + + #[inline(always)] + /// Write up to `num_bytes` bytes from `self` to `other`. + /// `num_bytes` is allowed to range from `8 * (N - 1)` to `8 * N + 1`. + pub(super) fn write_up_to( + &self, + mut other: impl Write, + num_bytes: usize, + ) -> ark_std::io::Result<()> { + debug_assert!(num_bytes <= 8 * N + 1, "index too large"); + debug_assert!(num_bytes > 8 * (N - 1), "index too small"); + // unconditionally write first `N - 1` limbs. + for i in 0..(N - 1) { + other.write_all(&self.buffers[i])?; + } + // for the `N`-th limb, depending on `index`, we can write anywhere from + // 1 to all bytes. + // If `index % N == ` + let remaining_bytes = num_bytes - (8 * (N - 1)); + let write_last_byte = remaining_bytes > 8; + let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); + other.write_all(&self.buffers[N][..num_last_limb_bytes])?; + if write_last_byte { + other.write_all(&[self.last])?; + } + Ok(()) + } + + #[inline(always)] + /// Read up to `num_bytes` bytes from `other` to `self`. + /// `num_bytes` is allowed to range from `8 * (N - 1)` to `8 * N + 1`. + pub(super) fn read_exact_up_to( + &mut self, + mut other: impl Read, + num_bytes: usize, + ) -> ark_std::io::Result<()> { + debug_assert!(num_bytes <= 8 * N + 1, "index too large"); + debug_assert!(num_bytes > 8 * (N - 1), "index too small"); + // unconditionally write first `N - 1` limbs. + for i in 0..(N - 1) { + other.read_exact(&mut self.buffers[i])?; + } + // for the `N`-th limb, depending on `index`, we can write anywhere from + // 1 to all bytes. + // If `index % N == ` + let remaining_bytes = num_bytes - (8 * (N - 1)); + let write_last_byte = remaining_bytes > 8; + let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); + other.read_exact(&mut self.buffers[N][..num_last_limb_bytes])?; + if write_last_byte { + other.read_exact(&mut [self.last])?; + } + Ok(()) + } +} + +impl Index for SerBuffer { + type Output = u8; + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + self.get(index) + } +} + +impl IndexMut for SerBuffer { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_mut(index) + } +} + +pub(in super) struct RBuffer(pub [u64; N], pub u64); + +impl RBuffer { + /// Find the number of bits in the binary decomposition of `self`. + pub(in super) const fn num_bits(&self) -> u32 { + (N * 64) as u32 + (64 - self.1.leading_zeros()) + } + + /// Returns the `i`-th bit where bit 0 is the least significant one. + /// In other words, the bit with weight `2^i`. + pub(in super) const fn get_bit(&self, i: usize) -> bool { + let d = i / 64; + let b = i % 64; + if d == N { + (self.1 >> b) & 1 == 1 + } else { + (self.0[d] >> b) & 1 == 1 + } + } + +} + +pub(in super) struct R2Buffer(pub [u64; N], pub [u64; N], pub u64); + +impl R2Buffer { + /// Find the number of bits in the binary decomposition of `self`. + pub(in super) const fn num_bits(&self) -> u32 { + ((2 * N) * 64) as u32 + (64 - self.2.leading_zeros()) + } + + /// Returns the `i`-th bit where bit 0 is the least significant one. + /// In other words, the bit with weight `2^i`. + pub(in super) const fn get_bit(&self, i: usize) -> bool { + let d = i / 64; + let b = i % 64; + if d == 2 * N { + (self.2 >> b ) & 1 == 1 + } else if d >= N { + (self.1[d - N] >> b) & 1 == 1 + } else { + (self.0[d] >> b) & 1 == 1 + } + } +} + + + +mod tests { + #[test] + fn test_mul_buffer_correctness() { + type Buf = MulBuffer<10>; + let temp = Buf::new([10u64; 10], [20u64; 10]); + + for i in 0..20 { + if i < 10 { + assert_eq!(temp[i], 10); + } else { + assert_eq!(temp[i], 20); + } + } + } + + + #[test] + #[should_panic] + fn test_mul_buffer_soundness() { + type Buf = MulBuffer<10>; + let temp = Buf::new([10u64; 10], [10u64; 10]); + + for i in 20..21 { + // indexing `temp[20]` should panic + assert_eq!(temp[i], 10); + } + } +} diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index 99f78ad4b..985322595 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -11,7 +11,7 @@ macro_rules! sqrt_impl { // Check at the end of the algorithm if x was a square root // Begin Tonelli-Shanks let mut z = $Self::qnr_to_t(); - let mut w = $self.pow($P::T_MINUS_ONE_DIV_TWO); + let mut w = $self.pow($P::TRACE_MINUS_ONE_DIV_TWO); let mut x = w * $self; let mut b = x * &w; diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index f7c1dc61c..9ac41a1be 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -1,4 +1,4 @@ -use crate::{biginteger::BigInteger, fields::utils::k_adicity, UniformRand}; +use crate::{biginteger::BigInteger, fields::utils::k_adicity, UniformRand, ToBytes, FromBytes}; use ark_serialize::{ CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, CanonicalSerializeWithFlags, EmptyFlags, Flags, @@ -31,7 +31,7 @@ use ark_std::cmp::max; use rayon::prelude::*; #[macro_export] -macro_rules! field_new { +macro_rules! Fp { ($name:ident, $c0:expr) => {{ use $crate::FpConfig; type Params = <$name as $crate::PrimeField>::Params; @@ -40,20 +40,10 @@ macro_rules! field_new { &limbs, is_positive, Params::R2, - Params::MODULUS, + $name::MODULUS, Params::INV, ) }}; - ($name:ident, $c0:expr, $c1:expr $(,)?) => { - $name { c0: $c0, c1: $c1 } - }; - ($name:ident, $c0:expr, $c1:expr, $c2:expr $(,)?) => { - $name { - c0: $c0, - c1: $c1, - c2: $c2, - } - }; } /// The interface for a generic field. @@ -79,6 +69,8 @@ pub trait Field: + CanonicalSerializeWithFlags + CanonicalDeserialize + CanonicalDeserializeWithFlags + + ToBytes + + FromBytes + Add + Sub + Mul @@ -312,7 +304,11 @@ pub trait PrimeField: /// The value `(p - 1)/ 2`. const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt; /// The size of the modulus in bits. - const MODULUS_BIT_SIZE: u16; + const MODULUS_BIT_SIZE: u32; + + /// The multiplicative generator of this field. + const GENERATOR: Self; + /// The trace of the field is defined as the smallest integer `t` such that by /// `2^s * t = p - 1`, and `t` is coprime to 2. const TRACE: Self::BigInt; diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 09e05809a..472bf2e52 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -5,7 +5,7 @@ use ark_serialize::{ use ark_std::{ cmp::{Ord, Ordering, PartialOrd}, fmt, - io::{Read, Write}, + io::{Read, Result as IoResult, Write}, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, vec::Vec, }; @@ -19,6 +19,7 @@ use ark_std::rand::{ }; use crate::{ + bytes::{ToBytes, FromBytes}, fields::{Field, PrimeField}, ToConstraintField, UniformRand, }; @@ -81,6 +82,18 @@ pub struct CubicExtField { pub c2: P::BaseField, } +/// Construct a `CubicExtension` element from elements of the base field. +#[macro_export] +macro_rules! CubixExt { + ($name:ident, $c0:expr, $c1:expr, $c2:expr $(,)?) => { + $name { + c0: $c0, + c1: $c1, + c2: $c2, + } + }; +} + impl CubicExtField

{ /// Create a new field element from coefficients `c0`, `c1` and `c2` /// so that the result is of the form `c0 + c1 * X + c2 * X^2`. @@ -630,6 +643,25 @@ where } } +impl ToBytes for CubicExtField

{ + #[inline] + fn write(&self, mut writer: W) -> IoResult<()> { + self.c0.write(&mut writer)?; + self.c1.write(&mut writer)?; + self.c2.write(writer) + } +} + +impl FromBytes for CubicExtField

{ + #[inline] + fn read(mut reader: R) -> IoResult { + let c0 = P::BaseField::read(&mut reader)?; + let c1 = P::BaseField::read(&mut reader)?; + let c2 = P::BaseField::read(reader)?; + Ok(CubicExtField::new(c0, c1, c2)) + } +} + #[cfg(test)] mod cube_ext_tests { use super::*; diff --git a/ff/src/fields/models/fp/buffer_helpers.rs b/ff/src/fields/models/fp/buffer_helpers.rs deleted file mode 100644 index c21453e20..000000000 --- a/ff/src/fields/models/fp/buffer_helpers.rs +++ /dev/null @@ -1,251 +0,0 @@ -use ark_serialize::{Read, Write}; -use ark_std::ops::{Index, IndexMut}; - -use crate::BigInt; - -/// A buffer to hold values of size 2 * N. This is mostly -/// a hack that's necessary until `generic_const_exprs` is stable. -#[derive(Copy, Clone)] -pub(super) struct MulBuffer { - pub(super) b0: [u64; N], - pub(super) b1: [u64; N], -} - -impl MulBuffer { - pub(super) const fn new(b0: [u64; N], b1: [u64; N]) -> Self { - Self { b0, b1 } - } - - pub(super) const fn zeroed() -> Self { - Self { - b0: [0u64; N], - b1: [0u64; N], - } - } - - #[inline(always)] - pub(super) const fn get(&self, index: usize) -> &u64 { - if index < N { - &self.b0[index] - } else { - &self.b1[index + N] - } - } - - #[inline(always)] - pub(super) const fn get_mut(&mut self, index: usize) -> &mut u64 { - if index < N { - &mut self.b0[index] - } else { - &mut self.b1[index + N] - } - } -} - -impl Index for MulBuffer { - type Output = u64; - #[inline(always)] - fn index(&self, index: usize) -> &Self::Output { - self.get(index) - } -} - -impl IndexMut for MulBuffer { - #[inline(always)] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - self.get_mut(index) - } -} - -/// A buffer to hold values of size 2 * N. This is mostly -/// a hack that's necessary until `generic_const_exprs` is stable. -#[derive(Copy, Clone)] -pub(super) struct SerBuffer { - pub(super) buffers: [[u8; 8]; N], - pub(super) last: u8, -} - -impl SerBuffer { - pub(super) const fn new(buffers: [[u8; 8]; N], last: u8) -> Self { - Self { buffers, last } - } - - pub(super) const fn zeroed() -> Self { - Self { - buffers: [[0u8; 8]; N], - last: 0u8, - } - } - - #[inline(always)] - pub(super) const fn get(&self, index: usize) -> &u8 { - if index == 8 * N { - &self.last - } else { - let part = index / 8; - let in_buffer_index = index % 8; - &self.buffers[part][index] - } - } - - #[inline(always)] - pub(super) const fn get_mut(&mut self, index: usize) -> &mut u8 { - if index == 8 * N { - &mut self.last - } else { - let part = index / 8; - let in_buffer_index = index % 8; - &mut self.buffers[part][index] - } - } - - #[inline(always)] - pub(super) fn iter(&self) -> impl Iterator { - self.buffers - .iter() - .flat_map(|b| b.iter()) - .chain(ark_std::iter::once(&self.last)) - } - - #[inline(always)] - pub(super) fn iter_mut(&mut self) -> impl Iterator { - self.buffers - .iter_mut() - .flat_map(|b| b.iter_mut()) - .chain(ark_std::iter::once(&mut self.last)) - } - - #[inline(always)] - pub(super) fn last_n_plus_1_bytes_mut(&mut self) -> impl Iterator { - self.buffers[N - 1] - .iter_mut() - .chain(ark_std::iter::once(&mut self.last)) - } - - #[inline(always)] - pub(super) fn copy_from_u8_slice(&mut self, other: &[u8]) { - other.chunks(8).enumerate().for_each(|(i, chunk)| { - if i < N { - self.buffers[i].copy_from_slice(chunk) - } else { - self.last = chunk[0] - } - }); - } - - #[inline(always)] - pub(super) fn copy_from_u64_slice(&mut self, other: &[u64; N]) { - other - .iter() - .zip(&mut self.buffers) - .for_each(|(other, this)| *this = other.to_le_bytes()); - } - - #[inline(always)] - pub(super) fn to_bigint(&self) -> BigInt { - let mut self_integer = BigInt::from(0u64); - self_integer - .0 - .iter_mut() - .zip(self.buffers) - .for_each(|(other, this)| *other = u64::from_le_bytes(this)); - self_integer - } - - #[inline(always)] - /// Write up to `num_bytes` bytes from `self` to `other`. - /// `num_bytes` is allowed to range from `8 * (N - 1)` to `8 * N + 1`. - pub(super) fn write_up_to( - &self, - other: impl Write, - num_bytes: usize, - ) -> ark_std::io::Result<()> { - debug_assert!(num_bytes <= 8 * N + 1, "index too large"); - debug_assert!(num_bytes > 8 * (N - 1), "index too small"); - // unconditionally write first `N - 1` limbs. - for i in 0..(N - 1) { - other.write_all(&self.buffers[i])?; - } - // for the `N`-th limb, depending on `index`, we can write anywhere from - // 1 to all bytes. - // If `index % N == ` - let remaining_bytes = num_bytes - (8 * (N - 1)); - let write_last_byte = remaining_bytes > 8; - let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); - other.write_all(&self.buffers[N][..num_last_limb_bytes])?; - if write_last_byte { - other.write_all(&[self.last])?; - } - Ok(()) - } - - #[inline(always)] - /// Read up to `num_bytes` bytes from `other` to `self`. - /// `num_bytes` is allowed to range from `8 * (N - 1)` to `8 * N + 1`. - pub(super) fn read_exact_up_to( - &mut self, - other: impl Read, - num_bytes: usize, - ) -> ark_std::io::Result<()> { - debug_assert!(num_bytes <= 8 * N + 1, "index too large"); - debug_assert!(num_bytes > 8 * (N - 1), "index too small"); - // unconditionally write first `N - 1` limbs. - for i in 0..(N - 1) { - other.read_exact(&mut self.buffers[i])?; - } - // for the `N`-th limb, depending on `index`, we can write anywhere from - // 1 to all bytes. - // If `index % N == ` - let remaining_bytes = num_bytes - (8 * (N - 1)); - let write_last_byte = remaining_bytes > 8; - let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); - other.read_exact(&mut self.buffers[N][..num_last_limb_bytes])?; - if write_last_byte { - other.read_exact(&mut [self.last])?; - } - Ok(()) - } -} - -impl Index for SerBuffer { - type Output = u8; - #[inline(always)] - fn index(&self, index: usize) -> &Self::Output { - self.get(index) - } -} - -impl IndexMut for SerBuffer { - #[inline(always)] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - self.get_mut(index) - } -} - -mod tests { - #[test] - fn test_mul_buffer_correctness() { - type Buf = MulBuffer<10>; - let temp = Buf::new([10u64; 10], [20u64; 10]); - - for i in 0..20 { - if i < 10 { - assert_eq!(temp[i], 10); - } else { - assert_eq!(temp[i], 20); - } - } - } - - #[test] - #[should_panic] - fn test_mul_buffer_soundness() { - type Buf = MulBuffer<10>; - let temp = Buf::new([10u64; 10], [10u64; 10]); - - for i in 20..21 { - // indexing `temp[20]` should panic - assert_eq!(temp[i], 10); - } - } -} diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index ec7ee2449..22568d414 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -12,21 +12,16 @@ use ark_std::{ One, Zero, }; -mod buffer_helpers; - mod montgomery_backend; pub use montgomery_backend::*; -use crate::{BigInt, BigInteger, FftField, Field, LegendreSymbol, PrimeField, SquareRootField}; +use crate::{BigInt, BigInteger, FftField, Field, LegendreSymbol, PrimeField, SquareRootField, FromBytes, ToBytes}; /// A trait that specifies the configuration of a prime field. /// Also specifies how to perform arithmetic on field elements. pub trait FpConfig: crate::FftConfig> { /// The modulus of the field. const MODULUS: crate::BigInt; - /// The number of bits needed to represent the `Self::MODULUS`. - const MODULUS_BIT_SIZE: u16; - /// A multiplicative generator of the field. /// `Self::GENERATOR` is an element having multiplicative order /// `Self::MODULUS - 1`. @@ -40,21 +35,6 @@ pub trait FpConfig: crate::FftConfig> { /// such that, for all elements `f` of the field, `e * f = f`. const ONE: Fp; - /// t for 2^s * t = MODULUS - 1, and t coprime to 2. - // TODO: compute this directly from `MODULUS` once - // const fns in traits are stable. - const T: crate::BigInt; - - /// (t - 1) / 2 - // TODO: compute this directly from `T` once - // const fns in traits are stable. - const T_MINUS_ONE_DIV_TWO: crate::BigInt; - - /// (Self::MODULUS - 1) / 2 - // TODO: compute this directly from `MODULUS` once - // const fns in traits are stable. - const MODULUS_MINUS_ONE_DIV_TWO: crate::BigInt; - /// Set a += b. fn add_assign(a: &mut Fp, b: &Fp); @@ -70,9 +50,71 @@ pub trait FpConfig: crate::FftConfig> { /// Set a *= b. fn square_in_place(a: &mut Fp); - /// Compute a^{-1} if it exists. + /// Compute a^{-1} if `a` is not zero. fn inverse(a: &Fp) -> Option>; + /// Compute the square root of a, if it exists. + fn square_root(a: &Fp) -> Option> { + // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) + // Actually this is just normal Tonelli-Shanks; since `P::Generator` + // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` + // is also a quadratic non-residue (since `t` is odd). + if a.is_zero() { + return Some(Fp::zero()); + } + // Try computing the square root (x at the end of the algorithm) + // Check at the end of the algorithm if x was a square root + // Begin Tonelli-Shanks + let mut z = Fp::qnr_to_t(); + let mut w = a.pow(Fp::::TRACE_MINUS_ONE_DIV_TWO); + let mut x = w * a; + let mut b = x * &w; + + let mut v = Self::TWO_ADICITY as usize; + + while !b.is_one() { + let mut k = 0usize; + + let mut b2k = b; + while !b2k.is_one() { + // invariant: b2k = b^(2^k) after entering this loop + b2k.square_in_place(); + k += 1; + } + + if k == (Self::TWO_ADICITY as usize) { + // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, + // which means that no square root exists. + return None; + } + let j = v - k; + w = z; + for _ in 1..j { + w.square_in_place(); + } + + z = w.square(); + b *= &z; + x *= &w; + v = k; + } + // Is x the square root? If so, return it. + if x.square() == *a { + return Some(x); + } else { + // Consistency check that if no square root is found, + // it is because none exists. + #[cfg(debug_assertions)] + { + use crate::fields::LegendreSymbol::*; + if a.legendre() != QuadraticNonResidue { + panic!("Input has a square root per its Legendre symbol, but it was not found") + } + } + None + } + } + /// Construct a field element from an integer in the range `0..(Self::MODULUS - 1)`. /// Returns `None` if the integer is outside this range. fn from_bigint(other: BigInt) -> Option>; @@ -110,19 +152,19 @@ impl Fp { impl, const N: usize> Fp { #[inline(always)] - pub(crate) fn is_valid(&self) -> bool { + pub(crate) fn is_less_than_modulus(&self) -> bool { self.0 < P::MODULUS } #[inline] - fn reduce(&mut self) { - if !self.is_valid() { - self.0.sub_noborrow(&P::MODULUS); + fn subtract_modulus(&mut self) { + if !self.is_less_than_modulus() { + self.0.sub_noborrow(&Self::MODULUS); } } - fn shave_bits() -> usize { - 64 * N - usize::from(P::MODULUS_BIT_SIZE) + fn num_bits_to_shave() -> usize { + 64 * N - (Self::MODULUS_BIT_SIZE as usize) } } @@ -193,8 +235,8 @@ impl, const N: usize> Field for Fp { if F::BIT_SIZE > 8 { return None; } else { - let shave_bits = Self::shave_bits(); - let mut result_bytes = buffer_helpers::SerBuffer::zeroed(); + let shave_bits = Self::num_bits_to_shave(); + let mut result_bytes = crate::const_helpers::SerBuffer::::zeroed(); // Copy the input into a temporary buffer. result_bytes.copy_from_u8_slice(bytes); // This mask retains everything in the last limb @@ -204,7 +246,7 @@ impl, const N: usize> Field for Fp { last_bytes_mask[..8].copy_from_slice(&last_limb_mask); // Length of the buffer containing the field element and the flag. - let output_byte_size = buffer_byte_size(P::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); + let output_byte_size = buffer_byte_size(Self::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); // Location of the flag is the last byte of the serialized // form of the field element. let flag_location = output_byte_size - 1; @@ -227,7 +269,7 @@ impl, const N: usize> Field for Fp { } *b &= m; } - Self::deserialize(&result_bytes[..(N * 8)]) + Self::deserialize(&result_bytes.as_slice()[..(N * 8)]) .ok() .and_then(|f| F::from_u8(flags).map(|flag| (f, flag))) } @@ -267,10 +309,11 @@ impl, const N: usize> Field for Fp { impl, const N: usize> PrimeField for Fp { type BigInt = BigInt; const MODULUS: Self::BigInt = P::MODULUS; - const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt = P::MODULUS_MINUS_ONE_DIV_TWO; - const TRACE: Self::BigInt = P::T; - const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt = P::T_MINUS_ONE_DIV_TWO; - const MODULUS_BIT_SIZE: u16 = P::MODULUS_BIT_SIZE; + const GENERATOR: Self = P::GENERATOR; + const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt = Self::MODULUS.divide_by_2_round_down(); + const MODULUS_BIT_SIZE: u32 = Self::MODULUS.const_num_bits(); + const TRACE: Self::BigInt = Self::MODULUS.two_adic_coefficient(); + const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt = Self::TRACE.divide_by_2_round_down(); #[inline] fn from_bigint(r: BigInt) -> Option { @@ -307,7 +350,7 @@ impl, const N: usize> SquareRootField for Fp { use crate::fields::LegendreSymbol::*; // s = self^((MODULUS - 1) // 2) - let s = self.pow(P::MODULUS_MINUS_ONE_DIV_TWO); + let s = self.pow(Self::MODULUS_MINUS_ONE_DIV_TWO); if s.is_zero() { Zero } else if s.is_one() { @@ -319,7 +362,7 @@ impl, const N: usize> SquareRootField for Fp { #[inline] fn sqrt(&self) -> Option { - sqrt_impl!(Self, P, self) + P::square_root(self) } fn sqrt_in_place(&mut self) -> Option<&mut Self> { @@ -488,7 +531,7 @@ impl, const N: usize> ark_std::rand::distributions::Distribution< fn sample(&self, rng: &mut R) -> Fp { loop { let mut tmp = Fp::new(rng.sample(ark_std::rand::distributions::Standard)); - let shave_bits = Fp::::shave_bits(); + let shave_bits = Fp::::num_bits_to_shave(); // Mask away the unused bits at the beginning. assert!(shave_bits <= 64); let mask = if shave_bits == 64 { @@ -498,7 +541,7 @@ impl, const N: usize> ark_std::rand::distributions::Distribution< }; tmp.0 .0.last_mut().map(|val| *val &= mask); - if tmp.is_valid() { + if tmp.is_less_than_modulus() { return tmp; } } @@ -508,10 +551,9 @@ impl, const N: usize> ark_std::rand::distributions::Distribution< impl, const N: usize> CanonicalSerializeWithFlags for Fp { fn serialize_with_flags( &self, - mut writer: W, + writer: W, flags: F, ) -> Result<(), SerializationError> { - let bigint_byte_size = N * 8; // All reasonable `Flags` should be less than 8 bits in size // (256 values are enough for anyone!) if F::BIT_SIZE > 8 { @@ -521,12 +563,12 @@ impl, const N: usize> CanonicalSerializeWithFlags for Fp { // Calculate the number of bytes required to represent a field element // serialized with `flags`. If `F::BIT_SIZE < 8`, // this is at most `N * 8 + 1` - let output_byte_size = buffer_byte_size(P::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); + let output_byte_size = buffer_byte_size(Self::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); // Write out `self` to a temporary buffer. // The size of the buffer is $byte_size + 1 because `F::BIT_SIZE` // is at most 8 bits. - let mut bytes = buffer_helpers::SerBuffer::zeroed(); + let mut bytes = crate::const_helpers::SerBuffer::zeroed(); bytes.copy_from_u64_slice(&self.into_bigint().0); // Mask out the bits of the last byte that correspond to the flag. bytes[output_byte_size - 1] |= flags.u8_bitmask(); @@ -540,7 +582,7 @@ impl, const N: usize> CanonicalSerializeWithFlags for Fp { // If `(m - P::MODULUS_BIT_SIZE) >= F::BIT_SIZE` , then this method returns `n`; // otherwise, it returns `n + 1`. fn serialized_size_with_flags(&self) -> usize { - buffer_byte_size(P::MODULUS_BIT_SIZE as usize + F::BIT_SIZE) + buffer_byte_size(Self::MODULUS_BIT_SIZE as usize + F::BIT_SIZE) } } @@ -558,7 +600,7 @@ impl, const N: usize> CanonicalSerialize for Fp { impl, const N: usize> CanonicalDeserializeWithFlags for Fp { fn deserialize_with_flags( - mut reader: R, + reader: R, ) -> Result<(Self, F), SerializationError> { // All reasonable `Flags` should be less than 8 bits in size // (256 values are enough for anyone!) @@ -568,10 +610,10 @@ impl, const N: usize> CanonicalDeserializeWithFlags for Fp // Calculate the number of bytes required to represent a field element // serialized with `flags`. If `F::BIT_SIZE < 8`, // this is at most `$byte_size + 1` - let output_byte_size = buffer_byte_size(P::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); + let output_byte_size = buffer_byte_size(Self::MODULUS_BIT_SIZE as usize + F::BIT_SIZE); - let mut masked_bytes = buffer_helpers::SerBuffer::zeroed(); - masked_bytes.read_exact_up_to(reader, output_byte_size); + let mut masked_bytes = crate::const_helpers::SerBuffer::zeroed(); + masked_bytes.read_exact_up_to(reader, output_byte_size)?; let flags = F::from_u8_remove_flags(&mut masked_bytes[output_byte_size - 1]) .ok_or(SerializationError::UnexpectedFlags)?; @@ -588,6 +630,20 @@ impl, const N: usize> CanonicalDeserialize for Fp { } } +impl, const N: usize> ToBytes for Fp { + #[inline] + fn write(&self, writer: W) -> IoResult<()> { + self.into_bigint().write(writer) + } +} + +impl, const N: usize> FromBytes for Fp { + #[inline] + fn read(r: R) -> IoResult { + BigInt::read(r).and_then(|b| Fp::from_bigint(b).ok_or(crate::error("FromBytes::read failed"))) + } +} + impl, const N: usize> FromStr for Fp { type Err = (); @@ -628,7 +684,7 @@ impl, const N: usize> FromStr for Fp { } } } - if !res.is_valid() { + if !res.is_less_than_modulus() { Err(()) } else { Ok(res) @@ -743,7 +799,7 @@ impl, const N: usize> core::ops::Sub for Fp { type Output = Self; #[inline] - fn sub(self, other: Self) -> Self { + fn sub(mut self, other: Self) -> Self { self.sub_assign(&other); self } diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index b8b23d833..0da6c2416 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -8,42 +8,21 @@ pub trait MontConfig: 'static + Copy + Sync + Send { /// The modulus of the field. const MODULUS: BigInt; - /// The number of bits needed to represent the `Self::MODULUS`. - const MODULUS_BIT_SIZE: u16; - /// Let `M` be the power of 2^64 nearest to `Self::MODULUS_BITS`. Then /// `R = M % Self::MODULUS`. - const R: BigInt; + const R: BigInt = Self::MODULUS.montgomery_r(); /// R2 = R^2 % Self::MODULUS - const R2: BigInt; + const R2: BigInt = Self::MODULUS.montgomery_r2(); /// INV = -MODULUS^{-1} mod 2^64 - const INV: u64; + const INV: u64 = inv(Self::MODULUS); /// A multiplicative generator of the field. /// `Self::GENERATOR` is an element having multiplicative order /// `Self::MODULUS - 1`. const GENERATOR: Fp, N>; - /// The number of bits that can be reliably stored. - /// (Should equal `SELF::MODULUS_BITS - 1`) - const CAPACITY: u32; - - /// t for 2^s * t = MODULUS - 1, and t coprime to 2. - const T: BigInt; - - /// (t - 1) / 2 - const T_MINUS_ONE_DIV_TWO: BigInt; - - /// (Self::MODULUS - 1) / 2 - const MODULUS_MINUS_ONE_DIV_TWO: BigInt; - - /// Let `N` be the size of the multiplicative group defined by the field. - /// Then `TWO_ADICITY` is the two-adicity of `N`, i.e. the integer `s` - /// such that `N = 2^s * t` for some odd integer `t`. - const TWO_ADICITY: u32; - /// 2^s root of unity computed by GENERATOR^t const TWO_ADIC_ROOT_OF_UNITY: Fp, N>; @@ -61,11 +40,22 @@ pub trait MontConfig: 'static + Copy + Sync + Send { const LARGE_SUBGROUP_ROOT_OF_UNITY: Option, N>> = None; } -pub struct MontBackend, const N: usize>(PhantomData); +/// Compute -M^{-1} mod 2^64. +const fn inv(m: BigInt) -> u64 { + let mut inv = 1u64; + crate::const_for!((_i in 0..63) { + inv = inv.wrapping_mul(inv); + inv = inv.wrapping_mul(m.0[0]); + }); + inv.wrapping_neg() +} + + +pub struct MontBackend(PhantomData); impl, const N: usize> FftConfig for MontBackend { type Field = Fp; - const TWO_ADICITY: u32 = T::TWO_ADICITY; + const TWO_ADICITY: u32 = Self::MODULUS.two_adic_valuation(); const TWO_ADIC_ROOT_OF_UNITY: Self::Field = T::TWO_ADIC_ROOT_OF_UNITY; const SMALL_SUBGROUP_BASE: Option = T::SMALL_SUBGROUP_BASE; const SMALL_SUBGROUP_BASE_ADICITY: Option = T::SMALL_SUBGROUP_BASE_ADICITY; @@ -74,15 +64,12 @@ impl, const N: usize> FftConfig for MontBackend { impl, const N: usize> FpConfig for MontBackend { /// The modulus of the field. - const MODULUS: crate::BigInt = T::MODULUS; - - /// The number of bits needed to represent the `Self::MODULUS`. - const MODULUS_BIT_SIZE: u16 = T::MODULUS_BIT_SIZE; + const MODULUS: crate::BigInt = Self::MODULUS; /// A multiplicative generator of the field. /// `Self::GENERATOR` is an element having multiplicative order /// `Self::MODULUS - 1`. - const GENERATOR: Fp = T::GENERATOR; + const GENERATOR: Fp = Self::GENERATOR; /// Additive identity of the field, i.e. the element `e` /// such that, for all elements `f` of the field, `e + f = f`. @@ -92,24 +79,13 @@ impl, const N: usize> FpConfig for MontBackend { /// such that, for all elements `f` of the field, `e * f = f`. const ONE: Fp = Fp::new(T::R); - /// t for 2^s * t = MODULUS - 1, and t coprime to 2. - // TODO: compute this directly from `MODULUS` - const T: crate::BigInt = T::T; - - /// (t - 1) / 2 - // TODO: compute this directly from `T` - const T_MINUS_ONE_DIV_TWO: crate::BigInt = T::T_MINUS_ONE_DIV_TWO; - - /// (Self::MODULUS - 1) / 2 - // TODO: compute this directly from `MODULUS` - const MODULUS_MINUS_ONE_DIV_TWO: crate::BigInt = T::MODULUS_MINUS_ONE_DIV_TWO; /// Set a += b; fn add_assign(a: &mut Fp, b: &Fp) { // This cannot exceed the backing capacity. a.0.add_nocarry(&b.0); // However, it may need to be reduced - a.reduce(); + a.subtract_modulus(); } fn sub_assign(a: &mut Fp, b: &Fp) { @@ -124,7 +100,7 @@ impl, const N: usize> FpConfig for MontBackend { // This cannot exceed the backing capacity. a.0.mul2(); // However, it may need to be reduced. - a.reduce(); + a.subtract_modulus(); } /// This modular multiplication algorithm uses Montgomery @@ -137,48 +113,49 @@ impl, const N: usize> FpConfig for MontBackend { #[ark_ff_asm::unroll_for_loops] fn mul_assign(a: &mut Fp, b: &Fp) { // Checking the modulus at compile time - let first_bit_set = T::MODULUS.0[N - 1] >> 63 != 0; + let first_bit_set = Self::MODULUS.0[N - 1] >> 63 != 0; // N can be 1, hence we can run into a case with an unused mut. - #[allow(unused_mut)] - let mut all_bits_set = T::MODULUS.0[N - 1] == !0 - (1 << 63); + let mut all_bits_set = Self::MODULUS.0[N - 1] == !0 - (1 << 63); for i in 1..N { - all_bits_set &= T::MODULUS.0[N - i - 1] == !0u64; + all_bits_set &= Self::MODULUS.0[N - i - 1] == !0u64; } let no_carry = !(first_bit_set || all_bits_set); // No-carry optimisation applied to CIOS if no_carry { - #[cfg(use_asm)] - #[allow(unsafe_code, unused_mut)] - { - // Tentatively avoid using assembly for `$limbs == 1`. - if N <= 6 && N > 1 { - ark_ff_asm::x86_64_asm_mul!($limbs, (a.0).0, (b.0).0); - self.reduce(); - return; + if N <= 6 && N > 1 && cfg!(use_asm) { + #[cfg(use_asm)] + #[allow(unsafe_code, unused_mut)] + // Tentatively avoid using assembly for `N == 1`. + match N { + 2 => ark_ff_asm::x86_64_asm_mul!(2, (a.0).0, (b.0).0), + 3 => ark_ff_asm::x86_64_asm_mul!(3, (a.0).0, (b.0).0), + 4 => ark_ff_asm::x86_64_asm_mul!(4, (a.0).0, (b.0).0), + 5 => ark_ff_asm::x86_64_asm_mul!(5, (a.0).0, (b.0).0), + 6 => ark_ff_asm::x86_64_asm_mul!(6, (a.0).0, (b.0).0), } - } - let mut r = [0u64; N]; - let mut carry1 = 0u64; - let mut carry2 = 0u64; - - for i in 0..N { - r[0] = fa::mac(r[0], (a.0).0[0], (b.0).0[i], &mut carry1); - let k = r[0].wrapping_mul(T::INV); - fa::mac_discard(r[0], k, T::MODULUS.0[0], &mut carry2); - for j in 1..N { - r[j] = fa::mac_with_carry(r[j], (a.0).0[j], (b.0).0[i], &mut carry1); - r[j - 1] = fa::mac_with_carry(r[j], k, T::MODULUS.0[j], &mut carry2); + } else { + let mut r = [0u64; N]; + let mut carry1 = 0u64; + let mut carry2 = 0u64; + + for i in 0..N { + r[0] = fa::mac(r[0], (a.0).0[0], (b.0).0[i], &mut carry1); + let k = r[0].wrapping_mul(T::INV); + fa::mac_discard(r[0], k, Self::MODULUS.0[0], &mut carry2); + for j in 1..N { + r[j] = fa::mac_with_carry(r[j], (a.0).0[j], (b.0).0[i], &mut carry1); + r[j - 1] = fa::mac_with_carry(r[j], k, Self::MODULUS.0[j], &mut carry2); + } + r[N - 1] = carry1 + carry2; } - r[N - 1] = carry1 + carry2; + (a.0).0 = r; } - (a.0).0 = r; - a.reduce(); - // Alternative implementation } else { - *a = a.mul_without_reduce(b, T::MODULUS, T::INV); - a.reduce(); + // Alternative implementation + *a = a.mul_without_reduce(b, Self::MODULUS, T::INV); } + a.subtract_modulus(); } #[inline] @@ -188,7 +165,8 @@ impl, const N: usize> FpConfig for MontBackend { if N == 1 { // We default to multiplying with `a` using the `Mul` impl // for the N == 1 case - Self::mul_assign(a, &*a); + let temp = *a; + Self::mul_assign(a, &temp); return; } #[cfg(use_asm)] @@ -204,11 +182,11 @@ impl, const N: usize> FpConfig for MontBackend { if N <= 6 && no_carry { ark_ff_asm::x86_64_asm_square!(N, (a.0).0); - a.reduce(); + a.subtract_modulus(); return a; } } - let mut r = super::buffer_helpers::MulBuffer::new([0u64; N], [0u64; N]); + let mut r = crate::const_helpers::MulBuffer::::zeroed(); let mut carry = 0; for i in 0..N { @@ -241,19 +219,19 @@ impl, const N: usize> FpConfig for MontBackend { } } // Montgomery reduction - let mut _carry2 = 0; + let mut carry2 = 0; for i in 0..N { let k = r[i].wrapping_mul(T::INV); let mut carry = 0; - fa::mac_with_carry(r[i], k, T::MODULUS.0[0], &mut carry); + fa::mac_with_carry(r[i], k, Self::MODULUS.0[0], &mut carry); for j in 1..N { - r[j + i] = fa::mac_with_carry(r[j + i], k, T::MODULUS.0[j], &mut carry); + r[j + i] = fa::mac_with_carry(r[j + i], k, Self::MODULUS.0[j], &mut carry); } - r.b1[i] = fa::adc(r.b1[i], _carry2, &mut carry); - _carry2 = carry; + r.b1[i] = fa::adc(r.b1[i], carry2, &mut carry); + carry2 = carry; } (a.0).0.copy_from_slice(&r.b1); - a.reduce(); + a.subtract_modulus(); } fn inverse(a: &Fp) -> Option> { @@ -268,7 +246,7 @@ impl, const N: usize> FpConfig for MontBackend { let one = BigInt::from(1u64); let mut u = a.0; - let mut v = T::MODULUS; + let mut v = Self::MODULUS; let mut b = Fp::new(T::R2); // Avoids unnecessary reduction step. let mut c = Fp::zero(); @@ -279,7 +257,7 @@ impl, const N: usize> FpConfig for MontBackend { if b.0.is_even() { b.0.div2(); } else { - b.0.add_nocarry(&T::MODULUS); + b.0.add_nocarry(&Self::MODULUS); b.0.div2(); } } @@ -290,7 +268,7 @@ impl, const N: usize> FpConfig for MontBackend { if c.0.is_even() { c.0.div2(); } else { - c.0.add_nocarry(&T::MODULUS); + c.0.add_nocarry(&Self::MODULUS); c.0.div2(); } } @@ -316,7 +294,7 @@ impl, const N: usize> FpConfig for MontBackend { let mut r = Fp::new(r); if r.is_zero() { return Some(r); - } else if r.is_valid() { + } else if r.is_less_than_modulus() { r *= &Fp::new(T::R2); Some(r) } else { @@ -335,9 +313,9 @@ impl, const N: usize> FpConfig for MontBackend { let k = r[i].wrapping_mul(T::INV); let mut carry = 0; - fa::mac_with_carry(r[i], k, T::MODULUS.0[0], &mut carry); + fa::mac_with_carry(r[i], k, Self::MODULUS.0[0], &mut carry); for j in 1..N { - r[(j + i) % N] = fa::mac_with_carry(r[(j + i) % N], k, T::MODULUS.0[j], &mut carry); + r[(j + i) % N] = fa::mac_with_carry(r[(j + i) % N], k, Self::MODULUS.0[j], &mut carry); } r[i % N] = carry; } @@ -346,14 +324,10 @@ impl, const N: usize> FpConfig for MontBackend { } } -impl, const N: usize> Fp, N> { +impl Fp, N> { #[ark_ff_asm::unroll_for_loops] const fn const_is_zero(&self) -> bool { - let mut is_zero = true; - crate::for_loop!((i in 0..N) { - is_zero &= (self.0).0[i] == 0; - }); - is_zero + self.0.const_is_zero() } const fn const_neg(self, modulus: BigInt) -> Self { @@ -374,13 +348,12 @@ impl, const N: usize> Fp, N> { is_positive: bool, r2: BigInt, modulus: BigInt, - inv: u64, ) -> Self { let mut repr = BigInt::([0; N]); - crate::for_loop!((i in 0..(limbs.len())) { + crate::const_for!((i in 0..(limbs.len())) { repr.0[i] = limbs[i]; }); - let res = Self::const_from_bigint(repr, r2, modulus, inv); + let res = Self::const_from_bigint(repr, r2, modulus); if is_positive { res } else { @@ -393,60 +366,70 @@ impl, const N: usize> Fp, N> { repr: BigInt, r2: BigInt, modulus: BigInt, - inv: u64, ) -> Self { let mut r = Self::new(repr); if r.const_is_zero() { r } else { - r = r.const_mul(&Fp(r2, PhantomData), modulus, inv); + r = r.const_mul(&Fp(r2, PhantomData), modulus); r } } #[ark_ff_asm::unroll_for_loops] const fn mul_without_reduce(mut self, other: &Self, modulus: BigInt, inv: u64) -> Self { - use crate::biginteger::arithmetic as fa; - - let mut r = super::buffer_helpers::MulBuffer::zeroed(); - - crate::for_loop!((i in 0..N) { + let (mut lo, mut hi) = ([0u64; N], [0u64; N]); + crate::const_for!((i in 0..N) { let mut carry = 0; - crate::for_loop!((j in 0..N) { - *r.get_mut(j + i) = fa::mac_with_carry(*r.get(j + i), (self.0).0[i], (other.0).0[j], &mut carry); + crate::const_for!((j in 0..N) { + let k = i + j; + if k >= N { + hi[k - N] = mac_with_carry!(hi[k - N], (self.0).0[i], (other.0).0[j], &mut carry); + } else { + lo[k] = mac_with_carry!(lo[k], (self.0).0[i], (other.0).0[j], &mut carry); + } }); - r.b1[i] = carry; - i += 1; - + hi[i] = carry; }); // Montgomery reduction - let mut _carry2 = 0; - crate::for_loop!((i in 0..N) { - let k = r.b0[i].wrapping_mul(inv); + let mut carry2 = 0; + crate::const_for!((i in 0..N) { + let tmp = lo[i].wrapping_mul(inv); let mut carry = 0; - fa::mac_with_carry(r.b0[i], k, modulus.0[0], &mut carry); - crate::for_loop!((j in 1..N) { - *r.get_mut(j + i) = fa::mac_with_carry(*r.get(j + i), k, modulus.0[j], &mut carry); + mac_with_carry!(lo[i], tmp, modulus.0[0], &mut carry); + crate::const_for!((j in 1..N) { + let k = i + j; + if k >= N { + hi[k - N] = mac_with_carry!(hi[k - N], tmp, modulus.0[j], &mut carry); + } else { + lo[k] = mac_with_carry!(lo[k], tmp, modulus.0[j], &mut carry); + } }); - r.b1[i] = fa::adc(r.b1[i], _carry2, &mut carry); - _carry2 = carry; + hi[i] = adc!(hi[i], carry2, &mut carry); + carry2 = carry; }); - crate::for_loop!((i in 0..N) { - (self.0).0[i] = r.b1[i]; + crate::const_for!((i in 0..N) { + (self.0).0[i] = hi[i]; }); self } #[ark_ff_asm::unroll_for_loops] - const fn const_mul(mut self, other: &Self, modulus: BigInt, inv: u64) -> Self { - self = self.mul_without_reduce(other, modulus, inv); + const fn const_mul_without_reduce(self, other: &Self, modulus: BigInt) -> Self { + let inv = inv(modulus); + self.mul_without_reduce(other, modulus, inv) + } + + #[ark_ff_asm::unroll_for_loops] + const fn const_mul(mut self, other: &Self, modulus: BigInt) -> Self { + self = self.const_mul_without_reduce(other, modulus); self.const_reduce(modulus) } #[ark_ff_asm::unroll_for_loops] const fn const_is_valid(&self, modulus: BigInt) -> bool { - crate::for_loop!((i in 0..N) { + crate::const_for!((i in 0..N) { if (self.0).0[(N - i - 1)] < modulus.0[(N - i - 1)] { return true } else if (self.0).0[(N - i - 1)] > modulus.0[(N - i - 1)] { @@ -464,17 +447,7 @@ impl, const N: usize> Fp, N> { self } - #[ark_ff_asm::unroll_for_loops] - // need unused assignment because the last iteration of the loop produces an assignment - // to `borrow` that is unused. - #[allow(unused_assignments)] const fn sub_noborrow(a: &BigInt, b: &BigInt) -> BigInt { - use crate::biginteger::arithmetic::sbb; - let mut a = *a; - let mut borrow = 0; - crate::for_loop!((i in 0..N) { - a.0[i] = sbb(a.0[i], b.0[i], &mut borrow); - }); - a + a.const_sub_noborrow(b).0 } } diff --git a/ff/src/fields/models/fp2.rs b/ff/src/fields/models/fp2.rs index db1634e37..6e2c7b317 100644 --- a/ff/src/fields/models/fp2.rs +++ b/ff/src/fields/models/fp2.rs @@ -3,7 +3,7 @@ use crate::fields::PrimeField; use core::marker::PhantomData; /// Parameters for defining degree-two extension fields. -pub trait Fp2Parameters: 'static + Send + Sync { +pub trait Fp2Parameters: 'static + Send + Sync + Sized { /// Base prime field underlying this extension. type Fp: PrimeField; @@ -13,7 +13,7 @@ pub trait Fp2Parameters: 'static + Send + Sync { const NONRESIDUE: Self::Fp; /// A quadratic nonresidue in Fp2, used for calculating square roots in Fp2. - const QUADRATIC_NONRESIDUE: (Self::Fp, Self::Fp); + const QUADRATIC_NONRESIDUE: Fp2; /// Coefficients for the Frobenius automorphism. const FROBENIUS_COEFF_FP2_C1: &'static [Self::Fp]; diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index 809bfa111..e34e67d05 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -2,7 +2,7 @@ use super::cubic_extension::*; use crate::fields::*; use core::marker::PhantomData; -pub trait Fp3Parameters: 'static + Send + Sync { +pub trait Fp3Parameters: 'static + Send + Sync + Sized { type Fp: PrimeField + SquareRootField; const NONRESIDUE: Self::Fp; @@ -12,9 +12,9 @@ pub trait Fp3Parameters: 'static + Send + Sync { /// p^3 - 1 = 2^s * t, where t is odd. const TWO_ADICITY: u32; - const T_MINUS_ONE_DIV_TWO: &'static [u64]; + const TRACE_MINUS_ONE_DIV_TWO: &'static [u64]; /// t-th power of a quadratic nonresidue in Fp3. - const QUADRATIC_NONRESIDUE_TO_T: (Self::Fp, Self::Fp, Self::Fp); + const QUADRATIC_NONRESIDUE_TO_T: Fp3; #[inline(always)] fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp { @@ -63,11 +63,7 @@ impl Fp3

{ /// Returns the value of QNR^T. #[inline] pub fn qnr_to_t() -> Self { - Self::new( - P::QUADRATIC_NONRESIDUE_TO_T.0, - P::QUADRATIC_NONRESIDUE_TO_T.1, - P::QUADRATIC_NONRESIDUE_TO_T.2, - ) + P::QUADRATIC_NONRESIDUE_TO_T } } diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index d4ffc12db..594dbd4c9 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -5,7 +5,7 @@ use ark_serialize::{ use ark_std::{ cmp::{Ord, Ordering, PartialOrd}, fmt, - io::{Read, Write}, + io::{Read, Result as IoResult, Write}, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, vec::Vec, }; @@ -19,6 +19,7 @@ use ark_std::rand::{ }; use crate::{ + bytes::{FromBytes, ToBytes}, biginteger::BigInteger, fields::{Field, LegendreSymbol, PrimeField, SquareRootField}, ToConstraintField, UniformRand, @@ -141,6 +142,13 @@ pub struct QuadExtField { pub c1: P::BaseField, } +#[macro_export] +macro_rules! QuadExt { + ($name:ident, $c0:expr, $c1:expr $(,)?) => { + $name { c0: $c0, c1: $c1 } + }; +} + impl QuadExtField

{ /// Create a new field element from coefficients `c0` and `c1`, /// so that the result is of the form `c0 + c1 * X`. @@ -751,6 +759,23 @@ where } } +impl ToBytes for QuadExtField

{ + #[inline] + fn write(&self, mut writer: W) -> IoResult<()> { + self.c0.write(&mut writer)?; + self.c1.write(writer) + } +} + +impl FromBytes for QuadExtField

{ + #[inline] + fn read(mut reader: R) -> IoResult { + let c0 = P::BaseField::read(&mut reader)?; + let c1 = P::BaseField::read(reader)?; + Ok(QuadExtField::new(c0, c1)) + } +} + #[cfg(test)] mod quad_ext_tests { use super::*; diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 36d02e7e0..7297db295 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -7,9 +7,8 @@ rust_2021_compatibility )] #![allow(clippy::op_ref, clippy::suspicious_op_assign_impl)] -#![cfg_attr(not(feature = "asm"), forbid(unsafe_code))] +#![deny(unsafe_code)] #![cfg_attr(use_asm, feature(llvm_asm))] -#![cfg_attr(feature = "asm", deny(unsafe_code))] #[macro_use] extern crate ark_std; diff --git a/ff/src/to_field_vec.rs b/ff/src/to_field_vec.rs index c1e3aa3cb..ca921b21f 100644 --- a/ff/src/to_field_vec.rs +++ b/ff/src/to_field_vec.rs @@ -42,7 +42,7 @@ impl ToConstraintField for () { impl ToConstraintField for [u8] { #[inline] fn to_field_elements(&self) -> Option> { - let max_size = usize::from(ConstraintF::MODULUS_BIT_SIZE / 8); + let max_size = (ConstraintF::MODULUS_BIT_SIZE / 8) as usize; let bigint_size = ::BigInt::NUM_LIMBS * 8; let fes = self .chunks(max_size) From 8a81ee79f4485e958d922b54736cbbef07fce165 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 00:21:47 -0800 Subject: [PATCH 03/32] Fix compilation errors in `ark-ec` --- ec/src/models/short_weierstrass_jacobian.rs | 2 +- ec/src/models/twisted_edwards_extended.rs | 4 ++-- ec/src/msm/fixed_base.rs | 6 +++--- ec/src/msm/variable_base/mod.rs | 4 ++-- ec/src/wnaf.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ec/src/models/short_weierstrass_jacobian.rs b/ec/src/models/short_weierstrass_jacobian.rs index 0c1918bd6..677d6fc68 100644 --- a/ec/src/models/short_weierstrass_jacobian.rs +++ b/ec/src/models/short_weierstrass_jacobian.rs @@ -688,7 +688,7 @@ impl<'a, P: Parameters> SubAssign<&'a Self> for GroupProjective

{ impl MulAssign for GroupProjective

{ fn mul_assign(&mut self, other: P::ScalarField) { - *self = self.mul(other.into_repr()) + *self = self.mul(other.into_bigint()) } } diff --git a/ec/src/models/twisted_edwards_extended.rs b/ec/src/models/twisted_edwards_extended.rs index 8f42fe222..ef0aefea2 100644 --- a/ec/src/models/twisted_edwards_extended.rs +++ b/ec/src/models/twisted_edwards_extended.rs @@ -200,7 +200,7 @@ impl<'a, P: Parameters> SubAssign<&'a Self> for GroupAffine

{ impl MulAssign for GroupAffine

{ fn mul_assign(&mut self, other: P::ScalarField) { - *self = self.mul(other.into_repr()).into() + *self = self.mul(other.into_bigint()).into() } } @@ -583,7 +583,7 @@ impl<'a, P: Parameters> SubAssign<&'a Self> for GroupProjective

{ impl MulAssign for GroupProjective

{ fn mul_assign(&mut self, other: P::ScalarField) { - *self = self.mul(other.into_repr()) + *self = self.mul(other.into_bigint()) } } diff --git a/ec/src/msm/fixed_base.rs b/ec/src/msm/fixed_base.rs index 27360fe38..09d9f6189 100644 --- a/ec/src/msm/fixed_base.rs +++ b/ec/src/msm/fixed_base.rs @@ -1,5 +1,5 @@ use crate::{AffineCurve, ProjectiveCurve}; -use ark_ff::{BigInteger, FpParameters, PrimeField}; +use ark_ff::{BigInteger, PrimeField}; use ark_std::{cfg_iter, cfg_iter_mut, vec::Vec}; #[cfg(feature = "parallel")] @@ -63,8 +63,8 @@ impl FixedBase { multiples_of_g: &[Vec], scalar: &T::ScalarField, ) -> T { - let modulus_size = ::Params::MODULUS_BITS as usize; - let scalar_val = scalar.into_repr().to_bits_le(); + let modulus_size = T::ScalarField::MODULUS_BIT_SIZE as usize; + let scalar_val = scalar.into_bigint().to_bits_le(); let mut res = multiples_of_g[0][0].into_projective(); for outer in 0..outerc { diff --git a/ec/src/msm/variable_base/mod.rs b/ec/src/msm/variable_base/mod.rs index 59593f379..76ffcb9eb 100644 --- a/ec/src/msm/variable_base/mod.rs +++ b/ec/src/msm/variable_base/mod.rs @@ -47,8 +47,8 @@ impl VariableBase { super::ln_without_floats(size) + 2 }; - let num_bits = ::Params::MODULUS_BITS as usize; - let fr_one = G::ScalarField::one().into_repr(); + let num_bits = G::ScalarField::MODULUS_BIT_SIZE as usize; + let fr_one = G::ScalarField::one().into_bigint(); let zero = G::Projective::zero(); let window_starts: Vec<_> = (0..num_bits).step_by(c).collect(); diff --git a/ec/src/wnaf.rs b/ec/src/wnaf.rs index 1cfec156a..eda40a78e 100644 --- a/ec/src/wnaf.rs +++ b/ec/src/wnaf.rs @@ -52,7 +52,7 @@ impl WnafContext { if 1 << (self.window_size - 1) > base_table.len() { return None; } - let scalar_wnaf = scalar.into_repr().find_wnaf(self.window_size).unwrap(); + let scalar_wnaf = scalar.into_bigint().find_wnaf(self.window_size).unwrap(); let mut result = G::zero(); From 5fb6ffbeff9c1d4e19dcf0e43f3e4fcb2a043b21 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 00:23:20 -0800 Subject: [PATCH 04/32] Fix compilation errors in `ark-poly` --- poly/src/domain/general.rs | 6 +++--- poly/src/domain/mixed_radix.rs | 14 +++++++------- poly/src/domain/radix2/mod.rs | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/poly/src/domain/general.rs b/poly/src/domain/general.rs index 5db417628..2d200772c 100644 --- a/poly/src/domain/general.rs +++ b/poly/src/domain/general.rs @@ -10,7 +10,7 @@ pub use crate::domain::utils::Elements; use crate::domain::{ DomainCoeff, EvaluationDomain, MixedRadixEvaluationDomain, Radix2EvaluationDomain, }; -use ark_ff::{FftField, FftParameters}; +use ark_ff::{FftField, FftConfig}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ io::{Read, Write}, @@ -171,7 +171,7 @@ impl EvaluationDomain for GeneralEvaluationDomain { return Some(GeneralEvaluationDomain::Radix2(domain)); } - if F::FftParams::SMALL_SUBGROUP_BASE.is_some() { + if F::FftConfig::SMALL_SUBGROUP_BASE.is_some() { return Some(GeneralEvaluationDomain::MixedRadix( MixedRadixEvaluationDomain::new(num_coeffs)?, )); @@ -186,7 +186,7 @@ impl EvaluationDomain for GeneralEvaluationDomain { return Some(domain_size); } - if F::FftParams::SMALL_SUBGROUP_BASE.is_some() { + if F::FftConfig::SMALL_SUBGROUP_BASE.is_some() { return Some(MixedRadixEvaluationDomain::::compute_size_of_domain( num_coeffs, )?); diff --git a/poly/src/domain/mixed_radix.rs b/poly/src/domain/mixed_radix.rs index 07f350a69..70486af2e 100644 --- a/poly/src/domain/mixed_radix.rs +++ b/poly/src/domain/mixed_radix.rs @@ -14,7 +14,7 @@ use crate::domain::{ utils::{best_fft, bitreverse}, DomainCoeff, EvaluationDomain, }; -use ark_ff::{fields::utils::k_adicity, FftField, FftParameters}; +use ark_ff::{fields::utils::k_adicity, FftField, FftConfig}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ cmp::min, @@ -63,7 +63,7 @@ impl EvaluationDomain for MixedRadixEvaluationDomain { /// Construct a domain that is large enough for evaluations of a polynomial /// having `num_coeffs` coefficients. fn new(num_coeffs: usize) -> Option { - let small_subgroup_base = F::FftParams::SMALL_SUBGROUP_BASE?; + let small_subgroup_base = F::FftConfig::SMALL_SUBGROUP_BASE?; // Compute the best size of our evaluation domain. let num_coeffs = best_mixed_domain_size::(num_coeffs); @@ -103,7 +103,7 @@ impl EvaluationDomain for MixedRadixEvaluationDomain { } fn compute_size_of_domain(num_coeffs: usize) -> Option { - let small_subgroup_base = F::FftParams::SMALL_SUBGROUP_BASE?; + let small_subgroup_base = F::FftConfig::SMALL_SUBGROUP_BASE?; // Compute the best size of our evaluation domain. let num_coeffs = best_mixed_domain_size::(num_coeffs); @@ -290,8 +290,8 @@ fn mixed_radix_fft_permute( fn best_mixed_domain_size(min_size: usize) -> usize { let mut best = usize::max_value(); - let small_subgroup_base_adicity = F::FftParams::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); - let small_subgroup_base = usize::try_from(F::FftParams::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); + let small_subgroup_base_adicity = F::FftConfig::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); + let small_subgroup_base = usize::try_from(F::FftConfig::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); for b in 0..=small_subgroup_base_adicity { let mut r = small_subgroup_base.pow(b); @@ -302,7 +302,7 @@ fn best_mixed_domain_size(min_size: usize) -> usize { two_adicity += 1; } - if two_adicity <= F::FftParams::TWO_ADICITY { + if two_adicity <= F::FftConfig::TWO_ADICITY { best = min(best, r); } } @@ -319,7 +319,7 @@ pub(crate) fn serial_mixed_radix_fft, F: FftField>( // and then splits into q sub-arrays q_adicity many times. let n = a.len(); - let q = usize::try_from(F::FftParams::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); + let q = usize::try_from(F::FftConfig::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); let q_adicity = k_adicity(q, n); let q_part = q.pow(q_adicity); diff --git a/poly/src/domain/radix2/mod.rs b/poly/src/domain/radix2/mod.rs index 5900e5ec8..9eb5b3359 100644 --- a/poly/src/domain/radix2/mod.rs +++ b/poly/src/domain/radix2/mod.rs @@ -5,7 +5,7 @@ pub use crate::domain::utils::Elements; use crate::domain::{DomainCoeff, EvaluationDomain}; -use ark_ff::{FftField, FftParameters}; +use ark_ff::{FftField, FftConfig}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ convert::TryFrom, @@ -58,7 +58,7 @@ impl EvaluationDomain for Radix2EvaluationDomain { let log_size_of_group = size.trailing_zeros(); // libfqfft uses > https://github.com/scipr-lab/libfqfft/blob/e0183b2cef7d4c5deb21a6eaf3fe3b586d738fe0/libfqfft/evaluation_domain/domains/basic_radix2_domain.tcc#L33 - if log_size_of_group > F::FftParams::TWO_ADICITY { + if log_size_of_group > F::FftConfig::TWO_ADICITY { return None; } @@ -83,7 +83,7 @@ impl EvaluationDomain for Radix2EvaluationDomain { fn compute_size_of_domain(num_coeffs: usize) -> Option { let size = num_coeffs.checked_next_power_of_two()?; - if size.trailing_zeros() > F::FftParams::TWO_ADICITY { + if size.trailing_zeros() > F::FftConfig::TWO_ADICITY { None } else { Some(size) From e8558d710cf98300ffea11fc7d0b658ce78571f5 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 00:24:14 -0800 Subject: [PATCH 05/32] Fix doctest --- ff/src/fields/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index 9ac41a1be..aa410e35b 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -233,8 +233,8 @@ pub trait FftField: Field { /// of unity of order n (for n a power of 2). /// If a small multiplicative subgroup is defined, this is the root of unity /// of order n for the larger subgroup generated by - /// `FftParams::LARGE_SUBGROUP_ROOT_OF_UNITY` - /// (for n = 2^i * FftParams::SMALL_SUBGROUP_BASE^j for some i, j). + /// `FftConfig::LARGE_SUBGROUP_ROOT_OF_UNITY` + /// (for n = 2^i * FftConfig::SMALL_SUBGROUP_BASE^j for some i, j). fn get_root_of_unity(n: usize) -> Option { let mut omega: Self; if let Some(large_subgroup_root_of_unity) = Self::large_subgroup_root_of_unity() { From 2a478116625055d1a5094c8b55976a798b6bdc61 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 00:24:37 -0800 Subject: [PATCH 06/32] Fix CHANGELOG typos --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a632aa4a0..57666c817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,13 +9,13 @@ - [\#333](https://github.com/arkworks-rs/algebra/pull/333) (ark-poly) Expose more properties of `EvaluationDomain`s. - [\#338](https://github.com/arkworks-rs/algebra/pull/338) (ark-ec) Add missing `UniformRand` trait bound to `GroupAffine`. - [\#338](https://github.com/arkworks-rs/algebra/pull/338) (workspace) Change to Rust 2021 edition. -- [\#345](https://github.com/arkworks-rs/algebra/pull/345) (arc-ec, ark-serialize) Change the serialization format for Twisted Edwards Curves. We now encode the Y coordinate and take the sign bit of the X co-ordinate, the default flag is also now the Positive X value. The old methods for backwards compatibility are located [here](https://github.com/arkworks-rs/algebra/pull/345/files#diff-3621a48bb33f469144044d8d5fc663f767e103132a764812cda6be6c25877494R860) -- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (arc-ec) Rename `msm:{Fixed,Variable}BaseMSM:multi_scalar_mul` to `msm:{Fixed,Variable}:msm` to avoid redundancy. +- [\#345](https://github.com/arkworks-rs/algebra/pull/345) (ark-ec, ark-serialize) Change the serialization format for Twisted Edwards Curves. We now encode the Y coordinate and take the sign bit of the X co-ordinate, the default flag is also now the Positive X value. The old methods for backwards compatibility are located [here](https://github.com/arkworks-rs/algebra/pull/345/files#diff-3621a48bb33f469144044d8d5fc663f767e103132a764812cda6be6c25877494R860) +- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (ark-ec) Rename `msm:{Fixed,Variable}BaseMSM:multi_scalar_mul` to `msm:{Fixed,Variable}:msm` to avoid redundancy. - [\#359](https://github.com/arkworks-rs/algebra/pull/359) (ark-test-templates) Simplify the field and curve test macros. -- [\#365](https://github.com/arkworks-rs/algebra/pull/365) (arc-ec) - - Move `COFACTOR`, `COFACTOR_INV`, and `is_in_correct_subgroup_assuming_on_curve()` from `{SW,TE}ModelParameters` to `ModelParameters`. - - Add `mul_bits()` to `AffineCurve` and provide a default implementation of `mul()` using this. - - Remove duplicate function `scale_by_cofactor()` from `short_weierstrass_jacobian::GroupAffine` and `twisted_edwards_extended::GroupAffine` +- [\#365](https://github.com/arkworks-rs/algebra/pull/365) (ark-ec) + - Move `COFACTOR`, `COFACTOR_INV`, and `is_in_correct_subgroup_assuming_on_curve()` from `{SW,TE}ModelParameters` to `ModelParameters`. + - Add `mul_bits()` to `AffineCurve` and provide a default implementation of `mul()` using this. + - Remove duplicate function `scale_by_cofactor()` from `short_weierstrass_jacobian::GroupAffine` and `twisted_edwards_extended::GroupAffine` - [\#370](https://github.com/arkworks-rs/algebra/pull/370) (all) Set the minimum `rust-version = 1.56` in the manifests of all crates. ### Features From fbede637b7438e72847753ddb0658ea68944342b Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 18:37:48 -0800 Subject: [PATCH 07/32] Everything compiles --- ff/src/biginteger/mod.rs | 28 +-- ff/src/const_helpers.rs | 41 ++-- ff/src/fields/mod.rs | 33 +-- ff/src/fields/models/cubic_extension.rs | 4 +- ff/src/fields/models/fp/mod.rs | 23 ++- ff/src/fields/models/fp/montgomery_backend.rs | 185 +++++++++++------ ff/src/fields/models/mod.rs | 2 + ff/src/fields/models/quadratic_extension.rs | 2 +- poly/src/domain/general.rs | 2 +- poly/src/domain/mixed_radix.rs | 2 +- poly/src/domain/radix2/mod.rs | 2 +- test-curves/src/bls12_381/fq.rs | 188 +++++++++--------- test-curves/src/bls12_381/fq2.rs | 14 +- test-curves/src/bls12_381/fq6.rs | 80 ++++---- test-curves/src/bls12_381/fr.rs | 85 +------- test-curves/src/bls12_381/g1.rs | 12 +- test-curves/src/bls12_381/tests.rs | 4 +- test-curves/src/bn384_small_two_adicity/fq.rs | 138 ++----------- test-curves/src/bn384_small_two_adicity/fr.rs | 150 +++----------- test-curves/src/bn384_small_two_adicity/g1.rs | 10 +- .../src/bn384_small_two_adicity/tests.rs | 4 +- test-curves/src/mnt4_753/fq.rs | 154 +------------- test-curves/src/mnt4_753/fr.rs | 139 +------------ test-curves/src/mnt4_753/g1.rs | 10 +- test-curves/src/mnt6_753/fq.rs | 2 +- test-curves/src/mnt6_753/fq3.rs | 17 +- test-curves/src/mnt6_753/fr.rs | 2 +- test-templates/Cargo.toml | 2 + test-templates/src/curves.rs | 4 +- test-templates/src/fields.rs | 58 +++++- test-templates/src/lib.rs | 13 ++ test-templates/src/msm.rs | 4 +- 32 files changed, 499 insertions(+), 915 deletions(-) diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index c15f376a8..c78f94e5d 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -1,7 +1,8 @@ use crate::{ bytes::{FromBytes, ToBytes}, + const_for, fields::{BitIteratorBE, BitIteratorLE}, - UniformRand, const_for, + UniformRand, }; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ @@ -34,16 +35,12 @@ impl BigInt { Self(value) } } -/// Divide self by another bignum, overwriting `q` with the quotient and `r` with the -/// remainder. #[doc(hidden)] macro_rules! const_modulo { - ($a:ident, $divisor:ident) => {{ + ($a:ident, $divisor:ident) => {{ // Stupid slow base-2 long division taken from // https://en.wikipedia.org/wiki/Division_algorithm assert!(!$divisor.const_is_zero()); - let digit_bits = 64; - let mut quotient = Self::new([0u64; N]); let mut remainder = Self::new([0u64; N]); let end = $a.num_bits(); let mut i = (end - 1) as isize; @@ -54,16 +51,12 @@ macro_rules! const_modulo { let (r, borrow) = remainder.const_sub_noborrow($divisor); remainder = r; assert!(!borrow); - // Set bit `i` of q to 1. - let digit_idx = i / digit_bits; - let bit_idx = i % digit_bits; - quotient.0[digit_idx as usize] |= 1 << bit_idx; } i -= 1; } remainder }}; -} +} impl BigInt { #[doc(hidden)] pub const fn const_is_even(&self) -> bool { @@ -109,7 +102,7 @@ impl BigInt { pub const fn two_adic_valuation(mut self) -> u32 { let mut two_adicity = 0; assert!(self.const_is_odd()); - // Since `self` is odd, we can always subtract one + // Since `self` is odd, we can always subtract one // without a borrow self.0[0] -= 1; while self.const_is_even() { @@ -119,12 +112,12 @@ impl BigInt { two_adicity } - /// Compute the smallest odd integer `t` such that `self = 2**s * t` for some + /// Compute the smallest odd integer `t` such that `self = 2**s * t` for some /// integer `s = self.two_adic_valuation()`. #[doc(hidden)] pub const fn two_adic_coefficient(mut self) -> Self { assert!(self.const_is_odd()); - // Since `self` is odd, we can always subtract one + // Since `self` is odd, we can always subtract one // without a borrow self.0[0] -= 1; while self.const_is_even() { @@ -148,7 +141,7 @@ impl BigInt { /// Find the number of bits in the binary decomposition of `self`. #[doc(hidden)] pub const fn const_num_bits(self) -> u32 { - ((N - 1) * 64) as u32 + (64 - self.0[N-1].leading_zeros()) + ((N - 1) * 64) as u32 + (64 - self.0[N - 1].leading_zeros()) } #[inline] @@ -184,8 +177,6 @@ impl BigInt { is_zero } - - /// Computes the Montgomery R constant modulo `self`. #[doc(hidden)] pub const fn montgomery_r(&self) -> Self { @@ -196,7 +187,8 @@ impl BigInt { /// Computes the Montgomery R2 constant modulo `self`. #[doc(hidden)] pub const fn montgomery_r2(&self) -> Self { - let two_pow_n_times_64_square = crate::const_helpers::R2Buffer::([0u64; N], [0u64; N], 1); + let two_pow_n_times_64_square = + crate::const_helpers::R2Buffer::([0u64; N], [0u64; N], 1); const_modulo!(two_pow_n_times_64_square, self) } } diff --git a/ff/src/const_helpers.rs b/ff/src/const_helpers.rs index c4a76bd4f..e416c6443 100644 --- a/ff/src/const_helpers.rs +++ b/ff/src/const_helpers.rs @@ -3,7 +3,6 @@ use ark_std::ops::{Index, IndexMut}; use crate::BigInt; - #[macro_export] macro_rules! const_for { (($i:ident in $start:tt..$end:tt) $code:expr ) => {{ @@ -39,7 +38,7 @@ impl MulBuffer { if index < N { &self.b0[index] } else { - &self.b1[index + N] + &self.b1[index - N] } } @@ -48,12 +47,11 @@ impl MulBuffer { if index < N { &mut self.b0[index] } else { - &mut self.b1[index + N] + &mut self.b1[index - N] } } } - impl Index for MulBuffer { type Output = u64; #[inline(always)] @@ -110,12 +108,7 @@ impl SerBuffer { #[allow(unsafe_code)] pub(super) fn as_slice(&self) -> &[u8] { - unsafe { - ark_std::slice::from_raw_parts( - (self as *const Self) as *const u8, - 8 * N + 1, - ) - } + unsafe { ark_std::slice::from_raw_parts((self as *const Self) as *const u8, 8 * N + 1) } } #[inline(always)] @@ -129,7 +122,9 @@ impl SerBuffer { pub(super) fn copy_from_u8_slice(&mut self, other: &[u8]) { other.chunks(8).enumerate().for_each(|(i, chunk)| { if i < N { - self.buffers[i].copy_from_slice(chunk) + for j in 0..chunk.len() { + self.buffers[i][j] = chunk[j] + } } else { self.last = chunk[0] } @@ -175,7 +170,7 @@ impl SerBuffer { let remaining_bytes = num_bytes - (8 * (N - 1)); let write_last_byte = remaining_bytes > 8; let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); - other.write_all(&self.buffers[N][..num_last_limb_bytes])?; + other.write_all(&self.buffers[N - 1][..num_last_limb_bytes])?; if write_last_byte { other.write_all(&[self.last])?; } @@ -202,7 +197,7 @@ impl SerBuffer { let remaining_bytes = num_bytes - (8 * (N - 1)); let write_last_byte = remaining_bytes > 8; let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); - other.read_exact(&mut self.buffers[N][..num_last_limb_bytes])?; + other.read_exact(&mut self.buffers[N - 1][..num_last_limb_bytes])?; if write_last_byte { other.read_exact(&mut [self.last])?; } @@ -225,17 +220,17 @@ impl IndexMut for SerBuffer { } } -pub(in super) struct RBuffer(pub [u64; N], pub u64); +pub(super) struct RBuffer(pub [u64; N], pub u64); impl RBuffer { /// Find the number of bits in the binary decomposition of `self`. - pub(in super) const fn num_bits(&self) -> u32 { + pub(super) const fn num_bits(&self) -> u32 { (N * 64) as u32 + (64 - self.1.leading_zeros()) } /// Returns the `i`-th bit where bit 0 is the least significant one. /// In other words, the bit with weight `2^i`. - pub(in super) const fn get_bit(&self, i: usize) -> bool { + pub(super) const fn get_bit(&self, i: usize) -> bool { let d = i / 64; let b = i % 64; if d == N { @@ -244,24 +239,23 @@ impl RBuffer { (self.0[d] >> b) & 1 == 1 } } - } -pub(in super) struct R2Buffer(pub [u64; N], pub [u64; N], pub u64); +pub(super) struct R2Buffer(pub [u64; N], pub [u64; N], pub u64); impl R2Buffer { /// Find the number of bits in the binary decomposition of `self`. - pub(in super) const fn num_bits(&self) -> u32 { + pub(super) const fn num_bits(&self) -> u32 { ((2 * N) * 64) as u32 + (64 - self.2.leading_zeros()) } /// Returns the `i`-th bit where bit 0 is the least significant one. /// In other words, the bit with weight `2^i`. - pub(in super) const fn get_bit(&self, i: usize) -> bool { + pub(super) const fn get_bit(&self, i: usize) -> bool { let d = i / 64; let b = i % 64; if d == 2 * N { - (self.2 >> b ) & 1 == 1 + (self.2 >> b) & 1 == 1 } else if d >= N { (self.1[d - N] >> b) & 1 == 1 } else { @@ -270,11 +264,10 @@ impl R2Buffer { } } - - mod tests { #[test] fn test_mul_buffer_correctness() { + use super::*; type Buf = MulBuffer<10>; let temp = Buf::new([10u64; 10], [20u64; 10]); @@ -287,10 +280,10 @@ mod tests { } } - #[test] #[should_panic] fn test_mul_buffer_soundness() { + use super::*; type Buf = MulBuffer<10>; let temp = Buf::new([10u64; 10], [10u64; 10]); diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index aa410e35b..0ab7fe327 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -1,4 +1,4 @@ -use crate::{biginteger::BigInteger, fields::utils::k_adicity, UniformRand, ToBytes, FromBytes}; +use crate::{biginteger::BigInteger, fields::utils::k_adicity, FromBytes, ToBytes, UniformRand}; use ark_serialize::{ CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, CanonicalSerializeWithFlags, EmptyFlags, Flags, @@ -22,6 +22,7 @@ pub mod utils; #[macro_use] pub mod arithmetic; +#[macro_use] pub mod models; pub use self::models::*; @@ -30,22 +31,6 @@ use ark_std::cmp::max; #[cfg(feature = "parallel")] use rayon::prelude::*; -#[macro_export] -macro_rules! Fp { - ($name:ident, $c0:expr) => {{ - use $crate::FpConfig; - type Params = <$name as $crate::PrimeField>::Params; - let (is_positive, limbs) = $crate::ark_ff_macros::to_sign_and_limbs!($c0); - $name::const_from_str( - &limbs, - is_positive, - Params::R2, - $name::MODULUS, - Params::INV, - ) - }}; -} - /// The interface for a generic field. pub trait Field: 'static @@ -621,11 +606,7 @@ mod no_std_tests { // TODO: only Fr & FrConfig should need to be imported. // The rest of imports are caused by cargo not resolving the deps properly // from this crate and from ark_test_curves - use ark_test_curves::{ - batch_inversion, batch_inversion_and_mul, - bls12_381::{Fr, FrConfig}, - BigInteger, FpConfig, PrimeField, - }; + use ark_test_curves::{batch_inversion, batch_inversion_and_mul, bls12_381::Fr, PrimeField}; #[test] fn test_batch_inversion() { @@ -656,8 +637,8 @@ mod no_std_tests { fn test_from_into_biguint() { let mut rng = ark_std::test_rng(); - let modulus_bits = FrConfig::MODULUS_BITS; - let modulus: num_bigint::BigUint = FrConfig::MODULUS.into(); + let modulus_bits = Fr::MODULUS_BIT_SIZE; + let modulus: num_bigint::BigUint = Fr::MODULUS.into(); let mut rand_bytes = Vec::new(); for _ in 0..(2 * modulus_bits / 8) { @@ -680,10 +661,10 @@ mod no_std_tests { // TODO: Eventually generate all the test vector bytes via computation with the // modulus use ark_std::{rand::Rng, string::ToString}; + use ark_test_curves::BigInteger; use num_bigint::BigUint; - let ref_modulus = - BigUint::from_bytes_be(&::Params::MODULUS.to_bytes_be()); + let ref_modulus = BigUint::from_bytes_be(&Fr::MODULUS.to_bytes_be()); let mut test_vectors = vec![ // 0 diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 472bf2e52..ba2274c84 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -19,7 +19,7 @@ use ark_std::rand::{ }; use crate::{ - bytes::{ToBytes, FromBytes}, + bytes::{FromBytes, ToBytes}, fields::{Field, PrimeField}, ToConstraintField, UniformRand, }; @@ -84,7 +84,7 @@ pub struct CubicExtField { /// Construct a `CubicExtension` element from elements of the base field. #[macro_export] -macro_rules! CubixExt { +macro_rules! CubicExt { ($name:ident, $c0:expr, $c1:expr, $c2:expr $(,)?) => { $name { c0: $c0, diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 22568d414..340206353 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -12,10 +12,14 @@ use ark_std::{ One, Zero, }; +#[macro_use] mod montgomery_backend; pub use montgomery_backend::*; -use crate::{BigInt, BigInteger, FftField, Field, LegendreSymbol, PrimeField, SquareRootField, FromBytes, ToBytes}; +use crate::{ + BigInt, BigInteger, FftField, Field, FromBytes, LegendreSymbol, PrimeField, SquareRootField, + ToBytes, +}; /// A trait that specifies the configuration of a prime field. /// Also specifies how to perform arithmetic on field elements. pub trait FpConfig: crate::FftConfig> { @@ -141,6 +145,20 @@ pub struct Fp( pub PhantomData

, ); +pub type Fp64

= Fp; +pub type Fp128

= Fp; +pub type Fp192

= Fp; +pub type Fp256

= Fp; +pub type Fp320

= Fp; +pub type Fp384

= Fp; +pub type Fp448

= Fp; +pub type Fp512

= Fp; +pub type Fp576

= Fp; +pub type Fp640

= Fp; +pub type Fp704

= Fp; +pub type Fp768

= Fp; +pub type Fp832

= Fp; + impl Fp { /// Construct a new prime element directly from its underlying /// `BigInteger` data type. @@ -640,7 +658,8 @@ impl, const N: usize> ToBytes for Fp { impl, const N: usize> FromBytes for Fp { #[inline] fn read(r: R) -> IoResult { - BigInt::read(r).and_then(|b| Fp::from_bigint(b).ok_or(crate::error("FromBytes::read failed"))) + BigInt::read(r) + .and_then(|b| Fp::from_bigint(b).ok_or(crate::error("FromBytes::read failed"))) } } diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 0da6c2416..002ccf70e 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -4,7 +4,7 @@ use super::{Fp, FpConfig}; use crate::{biginteger::arithmetic as fa, BigInt, BigInteger, FftConfig}; /// A trait that defines parameters for a prime field. -pub trait MontConfig: 'static + Copy + Sync + Send { +pub trait MontConfig: 'static + Sync + Send + Sized { /// The modulus of the field. const MODULUS: BigInt; @@ -38,57 +38,16 @@ pub trait MontConfig: 'static + Copy + Sync + Send { /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix /// FFT. const LARGE_SUBGROUP_ROOT_OF_UNITY: Option, N>> = None; -} - -/// Compute -M^{-1} mod 2^64. -const fn inv(m: BigInt) -> u64 { - let mut inv = 1u64; - crate::const_for!((_i in 0..63) { - inv = inv.wrapping_mul(inv); - inv = inv.wrapping_mul(m.0[0]); - }); - inv.wrapping_neg() -} - - -pub struct MontBackend(PhantomData); - -impl, const N: usize> FftConfig for MontBackend { - type Field = Fp; - const TWO_ADICITY: u32 = Self::MODULUS.two_adic_valuation(); - const TWO_ADIC_ROOT_OF_UNITY: Self::Field = T::TWO_ADIC_ROOT_OF_UNITY; - const SMALL_SUBGROUP_BASE: Option = T::SMALL_SUBGROUP_BASE; - const SMALL_SUBGROUP_BASE_ADICITY: Option = T::SMALL_SUBGROUP_BASE_ADICITY; - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = T::LARGE_SUBGROUP_ROOT_OF_UNITY; -} - -impl, const N: usize> FpConfig for MontBackend { - /// The modulus of the field. - const MODULUS: crate::BigInt = Self::MODULUS; - - /// A multiplicative generator of the field. - /// `Self::GENERATOR` is an element having multiplicative order - /// `Self::MODULUS - 1`. - const GENERATOR: Fp = Self::GENERATOR; - - /// Additive identity of the field, i.e. the element `e` - /// such that, for all elements `f` of the field, `e + f = f`. - const ZERO: Fp = Fp::new(BigInt([0u64; N])); - - /// Multiplicative identity of the field, i.e. the element `e` - /// such that, for all elements `f` of the field, `e * f = f`. - const ONE: Fp = Fp::new(T::R); - /// Set a += b; - fn add_assign(a: &mut Fp, b: &Fp) { + fn add_assign(a: &mut Fp, N>, b: &Fp, N>) { // This cannot exceed the backing capacity. a.0.add_nocarry(&b.0); // However, it may need to be reduced a.subtract_modulus(); } - fn sub_assign(a: &mut Fp, b: &Fp) { + fn sub_assign(a: &mut Fp, N>, b: &Fp, N>) { // If `other` is larger than `self`, add the modulus to self first. if b.0 > a.0 { a.0.add_nocarry(&Self::MODULUS); @@ -96,7 +55,7 @@ impl, const N: usize> FpConfig for MontBackend { a.0.sub_noborrow(&b.0); } - fn double_in_place(a: &mut Fp) { + fn double_in_place(a: &mut Fp, N>) { // This cannot exceed the backing capacity. a.0.mul2(); // However, it may need to be reduced. @@ -111,7 +70,7 @@ impl, const N: usize> FpConfig for MontBackend { /// zero bit in the rest of the modulus. #[inline] #[ark_ff_asm::unroll_for_loops] - fn mul_assign(a: &mut Fp, b: &Fp) { + fn mul_assign(a: &mut Fp, N>, b: &Fp, N>) { // Checking the modulus at compile time let first_bit_set = Self::MODULUS.0[N - 1] >> 63 != 0; // N can be 1, hence we can run into a case with an unused mut. @@ -141,7 +100,7 @@ impl, const N: usize> FpConfig for MontBackend { for i in 0..N { r[0] = fa::mac(r[0], (a.0).0[0], (b.0).0[i], &mut carry1); - let k = r[0].wrapping_mul(T::INV); + let k = r[0].wrapping_mul(Self::INV); fa::mac_discard(r[0], k, Self::MODULUS.0[0], &mut carry2); for j in 1..N { r[j] = fa::mac_with_carry(r[j], (a.0).0[j], (b.0).0[i], &mut carry1); @@ -153,7 +112,7 @@ impl, const N: usize> FpConfig for MontBackend { } } else { // Alternative implementation - *a = a.mul_without_reduce(b, Self::MODULUS, T::INV); + *a = a.mul_without_reduce(b, Self::MODULUS, Self::INV); } a.subtract_modulus(); } @@ -161,7 +120,7 @@ impl, const N: usize> FpConfig for MontBackend { #[inline] #[ark_ff_asm::unroll_for_loops] #[allow(unused_braces, clippy::absurd_extreme_comparisons)] - fn square_in_place(a: &mut Fp) { + fn square_in_place(a: &mut Fp, N>) { if N == 1 { // We default to multiplying with `a` using the `Mul` impl // for the N == 1 case @@ -173,10 +132,10 @@ impl, const N: usize> FpConfig for MontBackend { #[allow(unsafe_code, unused_mut)] { // Checking the modulus at compile time - let first_bit_set = T::MODULUS.0[N - 1] >> 63 != 0; - let mut all_bits_set = T::MODULUS.0[N - 1] == !0 - (1 << 63); + let first_bit_set = Self::MODULUS.0[N - 1] >> 63 != 0; + let mut all_bits_set = Self::MODULUS.0[N - 1] == !0 - (1 << 63); for i in 1..N { - all_bits_set &= T::MODULUS.0[N - i - 1] == core::u64::MAX; + all_bits_set &= Self::MODULUS.0[N - i - 1] == core::u64::MAX; } let no_carry: bool = !(first_bit_set || all_bits_set); @@ -221,7 +180,7 @@ impl, const N: usize> FpConfig for MontBackend { // Montgomery reduction let mut carry2 = 0; for i in 0..N { - let k = r[i].wrapping_mul(T::INV); + let k = r[i].wrapping_mul(Self::INV); let mut carry = 0; fa::mac_with_carry(r[i], k, Self::MODULUS.0[0], &mut carry); for j in 1..N { @@ -234,7 +193,7 @@ impl, const N: usize> FpConfig for MontBackend { a.subtract_modulus(); } - fn inverse(a: &Fp) -> Option> { + fn inverse(a: &Fp, N>) -> Option, N>> { if a.is_zero() { None } else { @@ -247,7 +206,7 @@ impl, const N: usize> FpConfig for MontBackend { let mut u = a.0; let mut v = Self::MODULUS; - let mut b = Fp::new(T::R2); // Avoids unnecessary reduction step. + let mut b = Fp::new(Self::R2); // Avoids unnecessary reduction step. let mut c = Fp::zero(); while u != one && v != one { @@ -290,12 +249,12 @@ impl, const N: usize> FpConfig for MontBackend { } } - fn from_bigint(r: BigInt) -> Option> { + fn from_bigint(r: BigInt) -> Option, N>> { let mut r = Fp::new(r); if r.is_zero() { return Some(r); } else if r.is_less_than_modulus() { - r *= &Fp::new(T::R2); + r *= &Fp::new(Self::R2); Some(r) } else { None @@ -305,17 +264,18 @@ impl, const N: usize> FpConfig for MontBackend { #[inline] #[ark_ff_asm::unroll_for_loops] #[allow(clippy::modulo_one)] - fn into_bigint(a: Fp) -> BigInt { + fn into_bigint(a: Fp, N>) -> BigInt { let mut tmp = a.0; let mut r = tmp.0; // Montgomery Reduction for i in 0..N { - let k = r[i].wrapping_mul(T::INV); + let k = r[i].wrapping_mul(Self::INV); let mut carry = 0; fa::mac_with_carry(r[i], k, Self::MODULUS.0[0], &mut carry); for j in 1..N { - r[(j + i) % N] = fa::mac_with_carry(r[(j + i) % N], k, Self::MODULUS.0[j], &mut carry); + r[(j + i) % N] = + fa::mac_with_carry(r[(j + i) % N], k, Self::MODULUS.0[j], &mut carry); } r[i % N] = carry; } @@ -324,6 +284,102 @@ impl, const N: usize> FpConfig for MontBackend { } } +/// Compute -M^{-1} mod 2^64. +pub const fn inv(m: BigInt) -> u64 { + let mut inv = 1u64; + crate::const_for!((_i in 0..63) { + inv = inv.wrapping_mul(inv); + inv = inv.wrapping_mul(m.0[0]); + }); + inv.wrapping_neg() +} + +#[macro_export] +macro_rules! MontFp { + ($name:ident, $c0:expr) => {{ + use $crate::PrimeField; + let (is_positive, limbs) = $crate::ark_ff_macros::to_sign_and_limbs!($c0); + <$name>::const_from_str(&limbs, is_positive, $name::R2, $name::MODULUS) + }}; +} + +pub use MontFp; + +pub struct MontBackend(PhantomData); + +impl, const N: usize> FftConfig for MontBackend { + type Field = Fp; + const TWO_ADICITY: u32 = Self::MODULUS.two_adic_valuation(); + const TWO_ADIC_ROOT_OF_UNITY: Self::Field = T::TWO_ADIC_ROOT_OF_UNITY; + const SMALL_SUBGROUP_BASE: Option = T::SMALL_SUBGROUP_BASE; + const SMALL_SUBGROUP_BASE_ADICITY: Option = T::SMALL_SUBGROUP_BASE_ADICITY; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = T::LARGE_SUBGROUP_ROOT_OF_UNITY; +} + +impl, const N: usize> FpConfig for MontBackend { + /// The modulus of the field. + const MODULUS: crate::BigInt = T::MODULUS; + + /// A multiplicative generator of the field. + /// `Self::GENERATOR` is an element having multiplicative order + /// `Self::MODULUS - 1`. + const GENERATOR: Fp = T::GENERATOR; + + /// Additive identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e + f = f`. + const ZERO: Fp = Fp::new(BigInt([0u64; N])); + + /// Multiplicative identity of the field, i.e. the element `e` + /// such that, for all elements `f` of the field, `e * f = f`. + const ONE: Fp = Fp::new(T::R); + + fn add_assign(a: &mut Fp, b: &Fp) { + T::add_assign(a, b) + } + + fn sub_assign(a: &mut Fp, b: &Fp) { + T::sub_assign(a, b) + } + + fn double_in_place(a: &mut Fp) { + T::double_in_place(a) + } + + /// This modular multiplication algorithm uses Montgomery + /// reduction for efficient implementation. It also additionally + /// uses the "no-carry optimization" outlined + /// [here](https://hackmd.io/@zkteam/modular_multiplication) if + /// `P::MODULUS` has (a) a non-zero MSB, and (b) at least one + /// zero bit in the rest of the modulus. + #[inline] + #[ark_ff_asm::unroll_for_loops] + fn mul_assign(a: &mut Fp, b: &Fp) { + T::mul_assign(a, b) + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + #[allow(unused_braces, clippy::absurd_extreme_comparisons)] + fn square_in_place(a: &mut Fp) { + T::square_in_place(a) + } + + fn inverse(a: &Fp) -> Option> { + T::inverse(a) + } + + fn from_bigint(r: BigInt) -> Option> { + T::from_bigint(r) + } + + #[inline] + #[ark_ff_asm::unroll_for_loops] + #[allow(clippy::modulo_one)] + fn into_bigint(a: Fp) -> BigInt { + T::into_bigint(a) + } +} + impl Fp, N> { #[ark_ff_asm::unroll_for_loops] const fn const_is_zero(&self) -> bool { @@ -340,7 +396,7 @@ impl Fp, N> { /// Interpret a string of decimal numbers as a prime field element. /// Does not accept unnecessary leading zeroes or a blank string. - /// For *internal* use only; please use the `field_new` macro instead + /// For *internal* use only; please use the `ark_ff::MontFp` macro instead /// of this method #[doc(hidden)] pub const fn const_from_str( @@ -451,3 +507,10 @@ impl Fp, N> { a.const_sub_noborrow(b).0 } } + +impl, const N: usize> Fp, N> { + #[doc(hidden)] + pub const R2: BigInt = T::R2; + #[doc(hidden)] + pub const INV: u64 = T::INV; +} diff --git a/ff/src/fields/models/mod.rs b/ff/src/fields/models/mod.rs index 31f9d0c75..20b0225f3 100644 --- a/ff/src/fields/models/mod.rs +++ b/ff/src/fields/models/mod.rs @@ -18,8 +18,10 @@ pub use self::fp6_3over2::*; pub mod fp12_2over3over2; pub use self::fp12_2over3over2::*; +#[macro_use] pub mod quadratic_extension; pub use quadratic_extension::*; +#[macro_use] pub mod cubic_extension; pub use cubic_extension::*; diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 594dbd4c9..70b0ce839 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -19,8 +19,8 @@ use ark_std::rand::{ }; use crate::{ - bytes::{FromBytes, ToBytes}, biginteger::BigInteger, + bytes::{FromBytes, ToBytes}, fields::{Field, LegendreSymbol, PrimeField, SquareRootField}, ToConstraintField, UniformRand, }; diff --git a/poly/src/domain/general.rs b/poly/src/domain/general.rs index 2d200772c..ae3a24a7a 100644 --- a/poly/src/domain/general.rs +++ b/poly/src/domain/general.rs @@ -10,7 +10,7 @@ pub use crate::domain::utils::Elements; use crate::domain::{ DomainCoeff, EvaluationDomain, MixedRadixEvaluationDomain, Radix2EvaluationDomain, }; -use ark_ff::{FftField, FftConfig}; +use ark_ff::{FftConfig, FftField}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ io::{Read, Write}, diff --git a/poly/src/domain/mixed_radix.rs b/poly/src/domain/mixed_radix.rs index 70486af2e..48b8eaa0c 100644 --- a/poly/src/domain/mixed_radix.rs +++ b/poly/src/domain/mixed_radix.rs @@ -14,7 +14,7 @@ use crate::domain::{ utils::{best_fft, bitreverse}, DomainCoeff, EvaluationDomain, }; -use ark_ff::{fields::utils::k_adicity, FftField, FftConfig}; +use ark_ff::{fields::utils::k_adicity, FftConfig, FftField}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ cmp::min, diff --git a/poly/src/domain/radix2/mod.rs b/poly/src/domain/radix2/mod.rs index 9eb5b3359..a26f234d6 100644 --- a/poly/src/domain/radix2/mod.rs +++ b/poly/src/domain/radix2/mod.rs @@ -5,7 +5,7 @@ pub use crate::domain::utils::Elements; use crate::domain::{DomainCoeff, EvaluationDomain}; -use ark_ff::{FftField, FftConfig}; +use ark_ff::{FftConfig, FftField}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ convert::TryFrom, diff --git a/test-curves/src/bls12_381/fq.rs b/test-curves/src/bls12_381/fq.rs index 2a8ded545..1790cf7e6 100644 --- a/test-curves/src/bls12_381/fq.rs +++ b/test-curves/src/bls12_381/fq.rs @@ -1,31 +1,14 @@ use ark_ff::{ biginteger::BigInt, biginteger::BigInteger384 as BigInteger, - field_new, - fields::{FftParameters, Fp384, Fp384Parameters, FpParameters}, + fields::{Fp384, MontBackend}, + MontFp, }; -pub type Fq = Fp384; +pub struct FqConfig; +pub type Fq = Fp384>; -pub struct FqParameters; - -impl Fp384Parameters for FqParameters {} -impl FftParameters for FqParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 1; - - #[rustfmt::skip] - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<6>([ - 0x43f5fffffffcaaae, - 0x32b7fff2ed47fffd, - 0x7e83a49a2e99d69, - 0xeca8f3318332bb7a, - 0xef148d1ea0f4c069, - 0x40ab3263eff0206, - ]); -} -impl FpParameters for FqParameters { +impl ark_ff::MontConfig<6> for FqConfig { /// MODULUS = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 #[rustfmt::skip] const MODULUS: BigInteger = BigInt::<6>([ @@ -37,80 +20,99 @@ impl FpParameters for FqParameters { 0x1a0111ea397fe69a, ]); - const MODULUS_BITS: u32 = 381; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 3; - - /// R = 3380320199399472671518931668520476396067793891014375699959770179129436917079669831430077592723774664465579537268733 - #[rustfmt::skip] - const R: BigInteger = BigInt::<6>([ - 0x760900000002fffd, - 0xebf4000bc40c0002, - 0x5f48985753c758ba, - 0x77ce585370525745, - 0x5c071a97a256ec6d, - 0x15f65ec3fa80e493, - ]); - - #[rustfmt::skip] - const R2: BigInteger = BigInt::<6>([ - 0xf4df1f341c341746, - 0xa76e6a609d104f1, - 0x8de5476c4c95b6d5, - 0x67eb88a9939d83c0, - 0x9a793e85b519952d, - 0x11988fe592cae3aa, - ]); - - const INV: u64 = 0x89f3fffcfffcfffd; - /// GENERATOR = 2 - /// Encoded in Montgomery form, so the value is - /// 2 * R % q = 2758230843577277949620073511305048635578704962089743514587482222134842183668501798417467556318533664893264801977679 - #[rustfmt::skip] - const GENERATOR: BigInteger = BigInt::<6>([ - 0x321300000006554f, - 0xb93c0018d6c40005, - 0x57605e0db0ddbb51, - 0x8b256521ed1f9bcb, - 0x6cf28d7901622c03, - 0x11ebab9dbb81e28c, - ]); - #[rustfmt::skip] - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 0xdcff7fffffffd555, - 0xf55ffff58a9ffff, - 0xb39869507b587b12, - 0xb23ba5c279c2895f, - 0x258dd3db21a5d66b, - 0xd0088f51cbff34d, - ]); - - /// T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - /// For T coprime to 2 - #[rustfmt::skip] - const T: BigInteger = BigInt::<6>([ - 0xdcff7fffffffd555, - 0xf55ffff58a9ffff, - 0xb39869507b587b12, - 0xb23ba5c279c2895f, - 0x258dd3db21a5d66b, - 0xd0088f51cbff34d, - ]); + const GENERATOR: Fq = ark_ff::MontFp!(Fq, "2"); #[rustfmt::skip] - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 0xee7fbfffffffeaaa, - 0x7aaffffac54ffff, - 0xd9cc34a83dac3d89, - 0xd91dd2e13ce144af, - 0x92c6e9ed90d2eb35, - 0x680447a8e5ff9a6, - ]); + const TWO_ADIC_ROOT_OF_UNITY: Fq = MontFp!(Fq, "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786"); } -pub const FQ_ONE: Fq = field_new!(Fq, "1"); -pub const FQ_ZERO: Fq = field_new!(Fq, "0"); +pub const FQ_ONE: Fq = MontFp!(Fq, "1"); +pub const FQ_ZERO: Fq = MontFp!(Fq, "0"); + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_constants() { + use ark_ff::{MontConfig, PrimeField}; + assert_eq!(Fq::MODULUS_BIT_SIZE, 381); + + assert_eq!(FqConfig::INV, 0x89f3fffcfffcfffd); + + // R = 3380320199399472671518931668520476396067793891014375699959770179129436917079669831430077592723774664465579537268733 + assert_eq!( + FqConfig::R, + BigInt::<6>([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ]) + ); + + assert_eq!( + FqConfig::R2, + BigInt::<6>([ + 0xf4df1f341c341746, + 0xa76e6a609d104f1, + 0x8de5476c4c95b6d5, + 0x67eb88a9939d83c0, + 0x9a793e85b519952d, + 0x11988fe592cae3aa, + ]) + ); + + assert_eq!( + Fq::TRACE, + BigInt::<6>([ + 0xdcff7fffffffd555, + 0xf55ffff58a9ffff, + 0xb39869507b587b12, + 0xb23ba5c279c2895f, + 0x258dd3db21a5d66b, + 0xd0088f51cbff34d, + ]) + ); + assert_eq!( + Fq::MODULUS_MINUS_ONE_DIV_TWO, + BigInt::<6>([ + 0xdcff7fffffffd555, + 0xf55ffff58a9ffff, + 0xb39869507b587b12, + 0xb23ba5c279c2895f, + 0x258dd3db21a5d66b, + 0xd0088f51cbff34d, + ]) + ); + + assert_eq!( + Fq::TRACE_MINUS_ONE_DIV_TWO, + BigInt::<6>([ + 0xee7fbfffffffeaaa, + 0x7aaffffac54ffff, + 0xd9cc34a83dac3d89, + 0xd91dd2e13ce144af, + 0x92c6e9ed90d2eb35, + 0x680447a8e5ff9a6, + ]) + ); + // GENERATOR = 2 + // Encoded in Montgomery form, so the value is + // 2 * R % q = 2758230843577277949620073511305048635578704962089743514587482222134842183668501798417467556318533664893264801977679 + assert_eq!( + FqConfig::GENERATOR, + Fq::new(BigInt::new([ + 0x321300000006554f, + 0xb93c0018d6c40005, + 0x57605e0db0ddbb51, + 0x8b256521ed1f9bcb, + 0x6cf28d7901622c03, + 0x11ebab9dbb81e28c, + ])) + ); + } +} diff --git a/test-curves/src/bls12_381/fq2.rs b/test-curves/src/bls12_381/fq2.rs index 15cfefa70..012b05552 100644 --- a/test-curves/src/bls12_381/fq2.rs +++ b/test-curves/src/bls12_381/fq2.rs @@ -1,5 +1,5 @@ use crate::bls12_381::*; -use ark_ff::{field_new, fields::*}; +use ark_ff::{fields::*, MontFp, QuadExt}; pub type Fq2 = Fp2; @@ -10,19 +10,19 @@ impl Fp2Parameters for Fq2Parameters { /// NONRESIDUE = -1 #[rustfmt::skip] - const NONRESIDUE: Fq = field_new!(Fq, "-1"); + const NONRESIDUE: Fq = MontFp!(Fq, "-1"); /// QUADRATIC_NONRESIDUE = (U + 1) #[rustfmt::skip] - const QUADRATIC_NONRESIDUE: (Fq, Fq) = (FQ_ONE, FQ_ONE); + const QUADRATIC_NONRESIDUE: Fq2 = QuadExt!(Fq2, FQ_ONE, FQ_ONE); /// Coefficients for the Frobenius automorphism. #[rustfmt::skip] const FROBENIUS_COEFF_FP2_C1: &'static [Fq] = &[ // Fq(-1)**(((q^0) - 1) / 2) - field_new!(Fq, "1"), + MontFp!(Fq, "1"), // Fq(-1)**(((q^1) - 1) / 2) - field_new!(Fq, "-1"), + MontFp!(Fq, "-1"), ]; #[inline(always)] @@ -31,5 +31,5 @@ impl Fp2Parameters for Fq2Parameters { } } -pub const FQ2_ZERO: Fq2 = field_new!(Fq2, FQ_ZERO, FQ_ZERO); -pub const FQ2_ONE: Fq2 = field_new!(Fq2, FQ_ONE, FQ_ZERO); +pub const FQ2_ZERO: Fq2 = QuadExt!(Fq2, FQ_ZERO, FQ_ZERO); +pub const FQ2_ONE: Fq2 = QuadExt!(Fq2, FQ_ONE, FQ_ZERO); diff --git a/test-curves/src/bls12_381/fq6.rs b/test-curves/src/bls12_381/fq6.rs index e54b79a03..2fcbff6b6 100644 --- a/test-curves/src/bls12_381/fq6.rs +++ b/test-curves/src/bls12_381/fq6.rs @@ -1,5 +1,5 @@ use crate::bls12_381::*; -use ark_ff::{field_new, fields::*}; +use ark_ff::{fields::*, MontFp, QuadExt}; pub type Fq6 = Fp6; @@ -11,76 +11,76 @@ impl Fp6Parameters for Fq6Parameters { /// NONRESIDUE = (U + 1) #[rustfmt::skip] - const NONRESIDUE: Fq2 = field_new!(Fq2, - field_new!(Fq, "1"), - field_new!(Fq, "1"), + const NONRESIDUE: Fq2 = QuadExt!(Fq2, + MontFp!(Fq, "1"), + MontFp!(Fq, "1"), ); #[rustfmt::skip] const FROBENIUS_COEFF_FP6_C1: &'static [Fq2] = &[ // Fp2::NONRESIDUE^(((q^0) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "1"), - field_new!(Fq, "0"), + QuadExt!(Fq2, + MontFp!(Fq, "1"), + MontFp!(Fq, "0"), ), // Fp2::NONRESIDUE^(((q^1) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "0"), - field_new!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), + QuadExt!(Fq2, + MontFp!(Fq, "0"), + MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), ), // Fp2::NONRESIDUE^(((q^2) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), - field_new!(Fq, "0"), + QuadExt!(Fq2, + MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), + MontFp!(Fq, "0"), ), // Fp2::NONRESIDUE^(((q^3) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "0"), - field_new!(Fq, "1"), + QuadExt!(Fq2, + MontFp!(Fq, "0"), + MontFp!(Fq, "1"), ), // Fp2::NONRESIDUE^(((q^4) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), - field_new!(Fq, "0"), + QuadExt!(Fq2, + MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), + MontFp!(Fq, "0"), ), // Fp2::NONRESIDUE^(((q^5) - 1) / 3) - field_new!(Fq2, - field_new!(Fq, "0"), - field_new!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), + QuadExt!(Fq2, + MontFp!(Fq, "0"), + MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), ), ]; #[rustfmt::skip] const FROBENIUS_COEFF_FP6_C2: &'static [Fq2] = &[ // Fq2(u + 1)**(((2q^0) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "1"), - field_new!(Fq, "0"), + QuadExt!(Fq2, + MontFp!(Fq, "1"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^1) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"), - field_new!(Fq, "0"), + QuadExt!(Fq2, + MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^2) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), - field_new!(Fq, "0"), + QuadExt!(Fq2, + MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^3) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "-1"), - field_new!(Fq, "0"), + QuadExt!(Fq2, + MontFp!(Fq, "-1"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^4) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), - field_new!(Fq, "0"), + QuadExt!(Fq2, + MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), + MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^5) - 2) / 3) - field_new!(Fq2, - field_new!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351"), - field_new!(Fq, "0"), + QuadExt!(Fq2, + MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351"), + MontFp!(Fq, "0"), ), ]; diff --git a/test-curves/src/bls12_381/fr.rs b/test-curves/src/bls12_381/fr.rs index 365289484..a80bb24c0 100644 --- a/test-curves/src/bls12_381/fr.rs +++ b/test-curves/src/bls12_381/fr.rs @@ -1,28 +1,13 @@ use ark_ff::{ biginteger::BigInt, biginteger::BigInteger256 as BigInteger, - fields::{FftParameters, Fp256, Fp256Parameters, FpParameters}, + fields::{Fp256, MontBackend, MontConfig, MontFp}, }; -pub type Fr = Fp256; +pub struct FrConfig; +pub type Fr = Fp256>; -pub struct FrParameters; - -impl Fp256Parameters for FrParameters {} -impl FftParameters for FrParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 32; - - #[rustfmt::skip] - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<4>([ - 0xb9b58d8c5f0e466a, - 0x5b1b4c801819d7ec, - 0xaf53ae352a31e64, - 0x5bf3adda19e9b27b, - ]); -} -impl FpParameters for FrParameters { +impl MontConfig<4> for FrConfig { /// MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513 #[rustfmt::skip] const MODULUS: BigInteger = BigInt::<4>([ @@ -32,70 +17,12 @@ impl FpParameters for FrParameters { 0x73eda753299d7d48, ]); - const MODULUS_BITS: u32 = 255; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 1; - - /// R = 10920338887063814464675503992315976177888879664585288394250266608035967270910 - #[rustfmt::skip] - const R: BigInteger = BigInt::<4>([ - 0x1fffffffe, - 0x5884b7fa00034802, - 0x998c4fefecbc4ff5, - 0x1824b159acc5056f, - ]); - - #[rustfmt::skip] - const R2: BigInteger = BigInt::<4>([ - 0xc999e990f3f29c6d, - 0x2b6cedcb87925c23, - 0x5d314967254398f, - 0x748d9d99f59ff11, - ]); - - const INV: u64 = 0xfffffffeffffffff; - /// GENERATOR = 7 /// Encoded in Montgomery form, so the value here is /// 7 * R % q = 24006497034320510773280787438025867407531605151569380937148207556313189711857 #[rustfmt::skip] - const GENERATOR: BigInteger = BigInt::<4>([ - 0xefffffff1, - 0x17e363d300189c0f, - 0xff9c57876f8457b0, - 0x351332208fc5a8c4, - ]); - - #[rustfmt::skip] - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<4>([ - 0x7fffffff80000000, - 0xa9ded2017fff2dff, - 0x199cec0404d0ec02, - 0x39f6d3a994cebea4, - ]); - - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - // For T coprime to 2 - - // T = (MODULUS - 1) / 2^S = - // 12208678567578594777604504606729831043093128246378069236549469339647 - #[rustfmt::skip] - const T: BigInteger = BigInt::<4>([ - 0xfffe5bfeffffffff, - 0x9a1d80553bda402, - 0x299d7d483339d808, - 0x73eda753, - ]); + const GENERATOR: Fr = MontFp!(Fr, "7"); - // (T - 1) / 2 = - // 6104339283789297388802252303364915521546564123189034618274734669823 #[rustfmt::skip] - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<4>([ - 0x7fff2dff7fffffff, - 0x4d0ec02a9ded201, - 0x94cebea4199cec04, - 0x39f6d3a9, - ]); + const TWO_ADIC_ROOT_OF_UNITY: Fr = MontFp!(Fr, "10238227357739495823651030575849232062558860180284477541189508159991286009131"); } diff --git a/test-curves/src/bls12_381/g1.rs b/test-curves/src/bls12_381/g1.rs index 94f7e12b1..1ed997061 100644 --- a/test-curves/src/bls12_381/g1.rs +++ b/test-curves/src/bls12_381/g1.rs @@ -3,7 +3,7 @@ use ark_ec::{ models::{ModelParameters, SWModelParameters}, short_weierstrass_jacobian::*, }; -use ark_ff::{field_new, Zero}; +use ark_ff::{MontFp, Zero}; pub type G1Affine = GroupAffine; pub type G1Projective = GroupProjective; @@ -21,16 +21,16 @@ impl ModelParameters for Parameters { /// COFACTOR_INV = COFACTOR^{-1} mod r /// = 52435875175126190458656871551744051925719901746859129887267498875565241663483 #[rustfmt::skip] - const COFACTOR_INV: Fr = field_new!(Fr, "52435875175126190458656871551744051925719901746859129887267498875565241663483"); + const COFACTOR_INV: Fr = MontFp!(Fr, "52435875175126190458656871551744051925719901746859129887267498875565241663483"); } impl SWModelParameters for Parameters { /// COEFF_A = 0 - const COEFF_A: Fq = field_new!(Fq, "0"); + const COEFF_A: Fq = MontFp!(Fq, "0"); /// COEFF_B = 4 #[rustfmt::skip] - const COEFF_B: Fq = field_new!(Fq, "4"); + const COEFF_B: Fq = MontFp!(Fq, "4"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = @@ -45,12 +45,12 @@ impl SWModelParameters for Parameters { /// G1_GENERATOR_X = /// 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 #[rustfmt::skip] -pub const G1_GENERATOR_X: Fq = field_new!(Fq, "3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507"); +pub const G1_GENERATOR_X: Fq = MontFp!(Fq, "3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507"); /// G1_GENERATOR_Y = /// 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 #[rustfmt::skip] -pub const G1_GENERATOR_Y: Fq = field_new!(Fq, "1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569"); +pub const G1_GENERATOR_Y: Fq = MontFp!(Fq, "1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569"); #[cfg(test)] mod test { diff --git a/test-curves/src/bls12_381/tests.rs b/test-curves/src/bls12_381/tests.rs index 338770c27..b3954d7fb 100644 --- a/test-curves/src/bls12_381/tests.rs +++ b/test-curves/src/bls12_381/tests.rs @@ -2,12 +2,12 @@ use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; use ark_ff::{Field, One, SquareRootField, UniformRand, Zero}; -use crate::bls12_381::{g1, Fq, Fq2, Fq6, FqParameters, Fr, G1Affine, G1Projective}; +use crate::bls12_381::{g1, Fq, Fq2, Fq6, FqConfig, Fr, FrConfig, G1Affine, G1Projective}; use ark_algebra_test_templates::{ curves::*, fields::*, generate_field_test, generate_g1_test, groups::*, msm::*, }; use ark_std::ops::{AddAssign, MulAssign, SubAssign}; use ark_std::{rand::Rng, test_rng}; -generate_field_test!(bls12_381; fq2; fq6;); +generate_field_test!(bls12_381; fq2; fq6; mont(6, 4); ); generate_g1_test!(bls12_381; curve_tests; sw_tests;); diff --git a/test-curves/src/bn384_small_two_adicity/fq.rs b/test-curves/src/bn384_small_two_adicity/fq.rs index f96b5c00f..7349fe4f1 100644 --- a/test-curves/src/bn384_small_two_adicity/fq.rs +++ b/test-curves/src/bn384_small_two_adicity/fq.rs @@ -1,52 +1,14 @@ use ark_ff::{ biginteger::BigInt, biginteger::BigInteger384 as BigInteger, - fields::{FftParameters, Fp384, Fp384Parameters, FpParameters}, + fields::{Fp384, MontBackend}, + MontFp, }; -pub type Fq = Fp384; +pub struct FqConfig; +pub type Fq = Fp384>; -pub struct FqParameters; - -impl Fp384Parameters for FqParameters {} -impl FftParameters for FqParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 12; - - // TWO_ADIC_ROOT_OF_UNITY = GENERATOR ^ t = - // 4563474743154071393992783416618298946273483760389666561454590580850277486490043009369759159902206584965352075028870 - // t is defined below - // This number needs to be in the Montgomery residue form. - // I.e., write TWO_ADIC_ROOT_OF_UNITY * R - // = 31697142653270303559937416477969693485777517469743380851550419037088206541495408586849687582005649424923407072789 - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<6>([ - 11341361458440748565u64, - 11432203502797436080u64, - 15207341022279519515u64, - 47188373187644751u64, - 123916096934654777u64, - 14839576327112111u64, - ]); - - const SMALL_SUBGROUP_BASE: Option = Some(3); - const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - - // LARGE_SUBGROUP_ROOT_OF_UNITY = GENERATOR ^ (t * 3 ^ 2) = - // 203100967768496856767841701771526315192814992286543641883928020883407386213917566206874176054653008117753458021037 - // I.e., write LARGE_SUBGROUP_ROOT_OF_UNITY * R - // = 81125788721017958531970004711554176763707237538772656640376499392204495132484005854811881368159718832226698073199 - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(BigInt::<6>([ - 6225018931355915375u64, - 180290822448891806u64, - 14465855242330424160u64, - 8575642455718703211u64, - 8320153096556229121u64, - 37980468681094481u64, - ])); -} - -impl FpParameters for FqParameters { +impl ark_ff::MontConfig<6> for FqConfig { /// MODULUS = 5945877603251831796258517492029536515488649313567122628447476625319762940580461319088175968449723373773214087057409 const MODULUS: BigInteger = BigInt::<6>([ 2340831834029625345u64, @@ -57,82 +19,22 @@ impl FpParameters for FqParameters { 2783667458303802095u64, ]); - const MODULUS_BITS: u32 = 382; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 2; - - // R = 2^{384} % MODULUS - // R = 3726740576883488434727935147966394712147843389062710897263433652327144128014442696885210444186575398167343467962362 - const R: BigInteger = BigInt::<6>([ - 4401753069531799546u64, - 11842444440309291617u64, - 10197010816391460981u64, - 1000373976455040278u64, - 1772404322397298239u64, - 1744739323886739041u64, - ]); - - // R2 = R * R % MODULUS - // R2 = 3383647891563276668075677154877236888682502454192504651186644086866057738042913461398173437153800906409349899530047 - const R2: BigInteger = BigInt::<6>([ - 16517710552441204543u64, - 4787934104620433613u64, - 12185556526193827174u64, - 10815510726684521116u64, - 3531299847928964248u64, - 1584114432653590388u64, - ]); + /// GENERATOR = 7 + #[rustfmt::skip] + const GENERATOR: Fq = ark_ff::MontFp!(Fq, "7"); - // INV = -(MODULUS)^{-1} mod 2^64 - const INV: u64 = 887568002135035903u64; - - // GENERATOR = 7 - // This number needs to be in the Montgomery residue form. - // I.e., write 7 * R % MODULUS = - // 2303673625177091858061476067646616923080306469170485767054129065010957133779253601843769235507134292078547927506898 - const GENERATOR: BigInteger = BigInt::<6>([ - 3002200076894543826u64, - 17005097747533029268u64, - 4390106630829661061u64, - 1520619128252124930u64, - 7439518447142769294u64, - 1078505433991964904u64, - ]); + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: Fq = MontFp!(Fq, "4563474743154071393992783416618298946273483760389666561454590580850277486490043009369759159902206584965352075028870"); - // (mod - 1) / 2 = 2972938801625915898129258746014768257744324656783561314223738312659881470290230659544087984224861686886607043528704 - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 10393787953869588480u64, - 3624815648401613602u64, - 8373621135488820726u64, - 7602778866007726483u64, - 16761815040700647461u64, - 1391833729151901047u64, - ]); - - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - // S = 12 - - /// T = (MODULUS - 1) / 2^S = - /// 1451630274231404247133427122077523563351721023820098297960809722978457749165151689230511711047295745550101095473 - const T: BigInteger = BigInt::<6>([ - 7228848894076625969u64, - 13746755992250574892u64, - 3633989981855682676u64, - 336978666793584539u64, - 12609256237382989921u64, - 679606313062451u64, - ]); + const SMALL_SUBGROUP_BASE: Option = Some(3); + const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - /// (T - 1) / 2 = - /// 72581513711570212356671356103876178167586051191004914898040486148922887458257584461525585552364787277505054773 - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 3614424447038312984u64, - 6873377996125287446u64, - 11040367027782617146u64, - 9391861370251568077u64, - 15528000155546270768u64, - 339803156531225u64, - ]); + // LARGE_SUBGROUP_ROOT_OF_UNITY = GENERATOR ^ (t * 3 ^ 2) = + // 203100967768496856767841701771526315192814992286543641883928020883407386213917566206874176054653008117753458021037 + // I.e., write LARGE_SUBGROUP_ROOT_OF_UNITY * R + // = 81125788721017958531970004711554176763707237538772656640376499392204495132484005854811881368159718832226698073199 + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(MontFp!(Fq, "683178638573601328773157856456805978879544571597638024782973348263890473503149166479735097908137632291366958273030")); } + +pub const FQ_ONE: Fq = MontFp!(Fq, "1"); +pub const FQ_ZERO: Fq = MontFp!(Fq, "0"); diff --git a/test-curves/src/bn384_small_two_adicity/fr.rs b/test-curves/src/bn384_small_two_adicity/fr.rs index 49f9dccfc..a849c920d 100644 --- a/test-curves/src/bn384_small_two_adicity/fr.rs +++ b/test-curves/src/bn384_small_two_adicity/fr.rs @@ -1,139 +1,39 @@ use ark_ff::{ biginteger::BigInt, biginteger::BigInteger384 as BigInteger, - fields::{FftParameters, Fp384, Fp384Parameters, FpParameters}, + fields::{Fp384, MontBackend}, }; -pub type Fr = Fp384; +pub struct FrConfig; +pub type Fr = Fp384>; -pub struct FrParameters; - -pub const FR_ONE: Fr = ark_ff::field_new!(Fr, "1"); - -impl Fp384Parameters for FrParameters {} -impl FftParameters for FrParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 12; - - // TWO_ADIC_ROOT_OF_UNITY = GENERATOR ^ T = - // 1685271986666084262778868986067286870708440243287855288358961780551611799713704250599068248127477556627411635786779 - // t is defined below - // This number needs to be in the Montgomery residue form. - // I.e., write TWO_ADIC_ROOT_OF_UNITY * R - // = 1539563187696293616856158973955665088899482868488546332850378941921984564611273075190849188323241758701638100060070 - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<6>([ - 13480433396127238054u64, - 1703594782943735056u64, - 8417751128359587317u64, - 11248980344203883641u64, - 4705241879150942070u64, - 720773657239228462u64, - ]); - - const SMALL_SUBGROUP_BASE: Option = Some(3); - const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - - // LARGE_SUBGROUP_ROOT_OF_UNITY = GENERATOR ^ (T * 3 ^ 2) - // = 3524614118565436050820346784762407349815771892452866211429575895239855511309348587252928054123237406857164753350910 - // This number needs to be in the Montgomery residue form. - // I.e., write LARGE_SUBGROUP_ROOT_OF_UNITY * R - // = 2243640460791708394678669425369274565832631199871689254948845545672204516674256702673568780556211844984291473787379 - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(BigInt::<6>([ - 16448235414327691763u64, - 6101416213029103415u64, - 1714659905601749299u64, - 18157817127906248745u64, - 7986749858655934624u64, - 1050399849371924948u64, - ])); -} -impl FpParameters for FrParameters { +impl ark_ff::MontConfig<6> for FrConfig { /// MODULUS = 5945877603251831796258517492029536515488649313567122628445038208291596545947608789992834434053176523624102324539393 const MODULUS: BigInteger = BigInt::<6>([ - 17382266338285916161u64, - 13339389119208890949u64, - 9581378667081472421u64, - 15205557732015452966u64, - 15076886007691743306u64, - 2783667458303802095u64, - ]); - - const MODULUS_BITS: u32 = 382; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 2; - - // R = 2^{384} % MODULUS - // 3726740576883488434727935147966394712147843389062710897278064154496142495811557871457259650565856499062014043070458 - const R: BigInteger = BigInt::<6>([ - 6386866412541812730u64, - 12197385653294412380u64, - 16298704292349371933u64, - 1000373976455040280u64, - 1772404322397298239u64, - 1744739323886739041u64, - ]); - - // R2 = R * R % MODULUS - // 743374565348571412572717835265798450620415736052604204514879248137607002524418551738269123252154404143816216787227 - const R2: BigInteger = BigInt::<6>([ - 7278302575398336795u64, - 13899913090107078051u64, - 14214418478611586731u64, - 17879031161354349451u64, - 934436771375522906u64, - 348023912527199718u64, + 17382266338285916161, + 13339389119208890949, + 9581378667081472421, + 15205557732015452966, + 15076886007691743306, + 2783667458303802095, ]); - // INV = -(MODULUS)^{-1} mod 2^64 - const INV: u64 = 5652841145273880575; + /// GENERATOR = 5 + #[rustfmt::skip] + const GENERATOR: Fr = ark_ff::MontFp!(Fr, "5"); - // GENERATOR = 5 - // This number needs to be in the Montgomery residue form. - // Here, write 5 * R = 796070074661946784864123263743364014273269004612186601055206147605922841214962987307794950669752924437763241734111 - const GENERATOR: BigInteger = BigInt::<6>([ - 16681021195270418399u64, - 2522016835135837435u64, - 15855897313083339171u64, - 14725428907357497352u64, - 524851736330364506u64, - 372694244522288918u64, - ]); - - // (mod - 1) / 2 = 2972938801625915898129258746014768257744324656783561314222519104145798272973804394996417217026588261812051162269696 - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 17914505205997733888u64, - 15893066596459221282u64, - 4790689333540736210u64, - 7602778866007726483u64, - 16761815040700647461u64, - 1391833729151901047u64, - ]); + /// TWO_ADIC_ROOT_OF_UNITY = GENERATOR ^ T = + /// 1685271986666084262778868986067286870708440243287855288358961780551611799713704250599068248127477556627411635786779 + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: Fr = ark_ff::MontFp!(Fr, "1685271986666084262778868986067286870708440243287855288358961780551611799713704250599068248127477556627411635786779"); - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - // S = 12 - - /// T = (MODULUS - 1) / 2^S = - /// 1451630274231404247133427122077523563351721023820098297960214406321190562975490427244344344251263799712915606577 - const T: BigInteger = BigInt::<6>([ - 2620835100870003761u64, - 11122644166774436482u64, - 3632240503436762713u64, - 336978666793584539u64, - 12609256237382989921u64, - 679606313062451u64, - ]); + const SMALL_SUBGROUP_BASE: Option = Some(3); + const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - /// (T - 1) / 2 = - /// 725815137115702123566713561038761781675860511910049148980107203160595281487745213622172172125631899856457803288 - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<6>([ - 1310417550435001880u64, - 14784694120241994049u64, - 11039492288573157164u64, - 9391861370251568077u64, - 15528000155546270768u64, - 339803156531225u64, - ]); + // LARGE_SUBGROUP_ROOT_OF_UNITY = GENERATOR ^ (t * 3 ^ 2) = + // 4782263695849493583247475447966822177504391850435302761245199662598017278280257369536403760936410198993405011225872 + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(ark_ff::MontFp!(Fr, "4782263695849493583247475447966822177504391850435302761245199662598017278280257369536403760936410198993405011225872")); } + +pub const FR_ONE: Fr = ark_ff::MontFp!(Fr, "1"); +pub const FR_ZERO: Fr = ark_ff::MontFp!(Fr, "0"); diff --git a/test-curves/src/bn384_small_two_adicity/g1.rs b/test-curves/src/bn384_small_two_adicity/g1.rs index 63cd98996..5704db7d2 100644 --- a/test-curves/src/bn384_small_two_adicity/g1.rs +++ b/test-curves/src/bn384_small_two_adicity/g1.rs @@ -2,7 +2,7 @@ use ark_ec::{ models::{ModelParameters, SWModelParameters}, short_weierstrass_jacobian::*, }; -use ark_ff::{field_new, Zero}; +use ark_ff::Zero; use crate::bn384_small_two_adicity::{Fq, Fr, FR_ONE}; @@ -25,10 +25,10 @@ impl ModelParameters for Parameters { impl SWModelParameters for Parameters { /// COEFF_A = 0 - const COEFF_A: Fq = field_new!(Fq, "0"); + const COEFF_A: Fq = ark_ff::MontFp!(Fq, "0"); /// COEFF_B = 17 - const COEFF_B: Fq = field_new!(Fq, "17"); + const COEFF_B: Fq = ark_ff::MontFp!(Fq, "17"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = @@ -41,7 +41,7 @@ impl SWModelParameters for Parameters { } /// G1_GENERATOR_X = -1 -pub const G1_GENERATOR_X: Fq = field_new!(Fq, "-1"); +pub const G1_GENERATOR_X: Fq = ark_ff::MontFp!(Fq, "-1"); /// G1_GENERATOR_Y = 4 -pub const G1_GENERATOR_Y: Fq = field_new!(Fq, "4"); +pub const G1_GENERATOR_Y: Fq = ark_ff::MontFp!(Fq, "4"); diff --git a/test-curves/src/bn384_small_two_adicity/tests.rs b/test-curves/src/bn384_small_two_adicity/tests.rs index 32c6438bd..661857977 100644 --- a/test-curves/src/bn384_small_two_adicity/tests.rs +++ b/test-curves/src/bn384_small_two_adicity/tests.rs @@ -3,12 +3,12 @@ use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCu use ark_ff::{Field, One, SquareRootField, UniformRand, Zero}; use ark_std::{rand::Rng, test_rng}; -use crate::bn384_small_two_adicity::{g1, Fq, FqParameters, Fr, G1Affine, G1Projective}; +use crate::bn384_small_two_adicity::{g1, Fq, FqConfig, Fr, FrConfig, G1Affine, G1Projective}; use ark_algebra_test_templates::{ curves::*, fields::*, generate_field_test, generate_g1_test, groups::*, msm::*, }; use ark_std::ops::{AddAssign, MulAssign, SubAssign}; -generate_field_test!(bn384_small_two_adicity;); +generate_field_test!(bn384_small_two_adicity; mont(6, 6);); generate_g1_test!(bn384_small_two_adicity; curve_tests; sw_tests;); diff --git a/test-curves/src/mnt4_753/fq.rs b/test-curves/src/mnt4_753/fq.rs index 27556c0d6..61ae34c3f 100644 --- a/test-curves/src/mnt4_753/fq.rs +++ b/test-curves/src/mnt4_753/fq.rs @@ -1,54 +1,13 @@ use ark_ff::{ biginteger::BigInt, biginteger::BigInteger768 as BigInteger, - fields::{FftParameters, Fp768, Fp768Parameters, FpParameters}, + fields::{Fp768, MontBackend, MontConfig}, }; -pub type Fq = Fp768; +pub type Fq = Fp768>; +pub struct FqConfig; -pub struct FqParameters; - -impl Fp768Parameters for FqParameters {} -impl FftParameters for FqParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 15; - - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<12>([ - 0x3b079c7556ac378, - 0x2c8c74d04a3f00d4, - 0xd3b001061b90d4cf, - 0x946e77514891b0e6, - 0x79caec8ad6dc9ea1, - 0xbefd780edc81435d, - 0xe093d4dca630b154, - 0x43a0f673199f1c12, - 0x92276c78436253ff, - 0xe249d1cf014fcd24, - 0x96f36471fb7c3ec5, - 0x1080b8906b7c4, - ]); - - const SMALL_SUBGROUP_BASE: Option = Some(5); - const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - /// LARGE_SUBGROUP_ROOT_OF_UNITY = - /// 12249458902762217747626832919710926618510011455364963726393752854649914979954138109976331601455448780251166045203053508523342111624583986869301658366625356826888785691823710598470775453742133593634524619429629803955083254436531 - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(BigInt::<12>([ - 8926681816978929800, - 10873079436792120119, - 6519893728366769435, - 7899277225737766970, - 8416573500933450083, - 12951641800297678468, - 7093775028595490583, - 14327009285082556021, - 18228411097456927576, - 2823658094446565457, - 1708328092507553067, - 109589007594791, - ])); -} -impl FpParameters for FqParameters { +impl MontConfig<12> for FqConfig { /// MODULUS = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601 const MODULUS: BigInteger = BigInt::<12>([ 0x5e9063de245e8001, @@ -65,107 +24,12 @@ impl FpParameters for FqParameters { 0x1c4c62d92c411, ]); - const MODULUS_BITS: u32 = 753; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; + const GENERATOR: Fq = ark_ff::MontFp!(Fq, "17"); - const REPR_SHAVE_BITS: u32 = 15; + const TWO_ADIC_ROOT_OF_UNITY: Fq = ark_ff::MontFp!(Fq, "40577822398412982719876671814347622311725878559400100565221223860226396934830112376659822430317692232440883010225033880793828874730711721234325694240460855741763791540474706150170374090550695427806583236301930157866709353840964"); - const R: BigInteger = BigInt::<12>([ - 0x98a8ecabd9dc6f42, - 0x91cd31c65a034686, - 0x97c3e4a0cd14572e, - 0x79589819c788b601, - 0xed269c942108976f, - 0x1e0f4d8acf031d68, - 0x320c3bb713338559, - 0x598b4302d2f00a62, - 0x4074c9cbfd8ca621, - 0xfa47edb3865e88c, - 0x95455fb31ff9a195, - 0x7b479ec8e242, - ]); - - const R2: BigInteger = BigInt::<12>([ - 0x84717088cfd190c8, - 0xc7d9ff8e7df03c0a, - 0xa24bea56242b3507, - 0xa896a656a0714c7d, - 0x80a46659ff6f3ddf, - 0x2f47839ef88d7ce8, - 0xa8c86d4604a3b597, - 0xe03c79cac4f7ef07, - 0x2505daf1f4a81245, - 0x8e4605754c381723, - 0xb081f15bcbfdacaf, - 0x2a33e89cb485, - ]); - - const INV: u64 = 0xf2044cfbe45e7fff; - - const GENERATOR: BigInteger = BigInt::<12>([ - 0xa8f627f0e629635e, - 0x202afce346c36872, - 0x85e1ece733493254, - 0x6d76e610664ac389, - 0xdf542f3f04441585, - 0x3aa4885bf6d4dd80, - 0xeb8b63c1c0fffc74, - 0xd2488e985f6cfa4e, - 0xcce1c2a623f7a66a, - 0x2a060f4d5085b19a, - 0xa9111a596408842f, - 0x11ca8d50bf627, - ]); - - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<12>([ - 0xaf4831ef122f4000, - 0x71ceaa29166e88cf, - 0x31c40838cd6212f8, - 0x342d6674bb392a52, - 0xdc0786d2e5a9bf1c, - 0xd88bf3bb790c02ce, - 0xcce8926cd0ad7bce, - 0x83fedc92f45076c6, - 0xaf5bf47cb64bec39, - 0xdbfccba82dc7d7f6, - 0x88114811777166d6, - 0xe26316c96208, - ]); - - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - - /// T = (MODULUS - 1) / 2^S = - /// 1278640471433073529124274133033466709233725278318907137200424283478556909563327233064541435662546964154604216671394463687571830033251476599169665701965732619291119517454523942352538645255842982596454713491581459512424155325 - const T: BigInteger = BigInt::<12>([ - 0x233ebd20c7bc48bd, - 0x4be1c73aa8a459ba, - 0xa948c71020e33588, - 0xfc70d0b599d2ece4, - 0xb3b701e1b4b96a6, - 0xef3b622fceede430, - 0xdb1b33a249b342b5, - 0xb0e60ffb724bd141, - 0x5fdabd6fd1f2d92f, - 0x9b5b6ff32ea0b71f, - 0x882220452045ddc5, - 0x3898c5b25, - ]); + const SMALL_SUBGROUP_BASE: Option = Some(5); + const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - /// (T - 1) / 2 = - /// 639320235716536764562137066516733354616862639159453568600212141739278454781663616532270717831273482077302108335697231843785915016625738299584832850982866309645559758727261971176269322627921491298227356745790729756212077662 - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<12>([ - 0x119f5e9063de245e, - 0x25f0e39d54522cdd, - 0x54a4638810719ac4, - 0x7e38685acce97672, - 0x59db80f0da5cb53, - 0xf79db117e776f218, - 0xed8d99d124d9a15a, - 0xd87307fdb925e8a0, - 0xafed5eb7e8f96c97, - 0xcdadb7f997505b8f, - 0xc41110229022eee2, - 0x1c4c62d92, - ]); + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(ark_ff::MontFp!(Fq, "12249458902762217747626832919710926618510011455364963726393752854649914979954138109976331601455448780251166045203053508523342111624583986869301658366625356826888785691823710598470775453742133593634524619429629803955083254436531")); } diff --git a/test-curves/src/mnt4_753/fr.rs b/test-curves/src/mnt4_753/fr.rs index e5f7495e5..ebbd6c16d 100644 --- a/test-curves/src/mnt4_753/fr.rs +++ b/test-curves/src/mnt4_753/fr.rs @@ -1,37 +1,13 @@ use ark_ff::{ biginteger::BigInt, biginteger::BigInteger768 as BigInteger, - fields::{FftParameters, Fp768, Fp768Parameters, FpParameters}, + fields::{Fp768, MontBackend}, }; -pub type Fr = Fp768; +pub type Fr = Fp768>; +pub struct FrConfig; -pub struct FrParameters; - -pub const FR_ONE: Fr = ark_ff::field_new!(Fr, "1"); - -impl Fp768Parameters for FrParameters {} -impl FftParameters for FrParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 30; - - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInt::<12>([ - 0x307f66b297671883, - 0xd72a7f2b1e645f4e, - 0x67079daa9a902283, - 0xf33f7620a86c668b, - 0x8878570d66464c12, - 0xa557af5b524f522b, - 0x5fafa3f6ef19319d, - 0x1eb9e04110a65629, - 0x3f96feb3c639a0b0, - 0x4d4fe37df3ffd732, - 0xadc831bd55bcf3e9, - 0x1b9f32a8bd6ab, - ]); -} -impl FpParameters for FrParameters { +impl ark_ff::MontConfig<12> for FrConfig { /// MODULUS = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001 const MODULUS: BigInteger = BigInt::<12>([ 0xd90776e240000001, @@ -48,107 +24,14 @@ impl FpParameters for FrParameters { 0x1c4c62d92c411, ]); - const MODULUS_BITS: u32 = 753; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 15; - - const R: BigInteger = BigInt::<12>([ - 0xb99680147fff6f42, - 0x4eb16817b589cea8, - 0xa1ebd2d90c79e179, - 0xf725caec549c0da, - 0xab0c4ee6d3e6dad4, - 0x9fbca908de0ccb62, - 0x320c3bb713338498, - 0x598b4302d2f00a62, - 0x4074c9cbfd8ca621, - 0xfa47edb3865e88c, - 0x95455fb31ff9a195, - 0x7b479ec8e242, - ]); - - const R2: BigInteger = BigInt::<12>([ - 0x3f9c69c7b7f4c8d1, - 0x70a50fa9ee48d127, - 0xcdbe6702009569cb, - 0x6bd8c6c6c49edc38, - 0x7955876cc35ee94e, - 0xc7285529be54a3f4, - 0xded52121ecec77cf, - 0x99be80f2ee12ee8e, - 0xc8a0ff01493bdcef, - 0xacc27988f3d9a316, - 0xd9e817a8fb44b3c9, - 0x5b58037e0e4, - ]); - - const INV: u64 = 0xc90776e23fffffff; - - const GENERATOR: BigInteger = BigInt::<12>([ - 0xeee0a5d37ff6635e, - 0xff458536cfa1cff4, - 0x659af978d8169ab0, - 0x1f1841c24780e3f1, - 0x602213036dcfef3a, - 0xd1d5c8f39d72db20, - 0xeb8b63c1c0ffefab, - 0xd2488e985f6cfa4e, - 0xcce1c2a623f7a66a, - 0x2a060f4d5085b19a, - 0xa9111a596408842f, - 0x11ca8d50bf627, - ]); - - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<12>([ - 0xec83bb7120000000, - 0xa7504c8b87d09d27, - 0x6b61c0de1f802bcb, - 0x5ceffcbb1a4c9d52, - 0x9f75e54a1490931b, - 0xd9362e14642cd4cd, - 0xcce8926cd0ad7bce, - 0x83fedc92f45076c6, - 0xaf5bf47cb64bec39, - 0xdbfccba82dc7d7f6, - 0x88114811777166d6, - 0xe26316c96208, - ]); + const GENERATOR: Fr = ark_ff::MontFp!(Fr, "17"); - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + const TWO_ADIC_ROOT_OF_UNITY: Fr = ark_ff::MontFp!(Fr, "40577822398412982719876671814347622311725878559400100565221223860226396934830112376659822430317692232440883010225033880793828874730711721234325694240460855741763791540474706150170374090550695427806583236301930157866709353840964"); - /// T = (MODULUS - 1) / 2^S = - /// 39021010480745652133919498688765463538626870065884617224134041854204007249857398469987226430131438115069708760723898631821547688442835449306011425196003537779414482717728302293895201885929702287178426719326440397855625 - const T: BigInteger = BigInt::<12>([ - 0x3e84e93f641ddb89, - 0xfc015e5d3a82645c, - 0xd264ea935b0e06f0, - 0xa48498dae77fe5d8, - 0x2166a66cfbaf2a50, - 0x856bde76c9b170a3, - 0xa283b63667449366, - 0xb25f61cc1ff6e497, - 0x6e3ebfb57adfa3e5, - 0xbb8b36b6dfe65d41, - 0xb64b1044408a408b, - 0x71318, - ]); + const SMALL_SUBGROUP_BASE: Option = Some(5); + const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); - /// (T - 1) / 2 = - /// 19510505240372826066959749344382731769313435032942308612067020927102003624928699234993613215065719057534854380361949315910773844221417724653005712598001768889707241358864151146947600942964851143589213359663220198927812 - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInt::<12>([ - 0x1f42749fb20eedc4, - 0x7e00af2e9d41322e, - 0x69327549ad870378, - 0x52424c6d73bff2ec, - 0x90b353367dd79528, - 0x42b5ef3b64d8b851, - 0xd141db1b33a249b3, - 0xd92fb0e60ffb724b, - 0xb71f5fdabd6fd1f2, - 0xddc59b5b6ff32ea0, - 0x5b25882220452045, - 0x3898c, - ]); + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(ark_ff::MontFp!(Fr, "12249458902762217747626832919710926618510011455364963726393752854649914979954138109976331601455448780251166045203053508523342111624583986869301658366625356826888785691823710598470775453742133593634524619429629803955083254436531")); } + +pub const FR_ONE: Fr = ark_ff::MontFp!(Fr, "1"); diff --git a/test-curves/src/mnt4_753/g1.rs b/test-curves/src/mnt4_753/g1.rs index f8fe38621..0af29920d 100644 --- a/test-curves/src/mnt4_753/g1.rs +++ b/test-curves/src/mnt4_753/g1.rs @@ -2,7 +2,7 @@ use ark_ec::{ models::{ModelParameters, SWModelParameters}, short_weierstrass_jacobian::*, }; -use ark_ff::field_new; +use ark_ff::MontFp; use crate::mnt4_753::{Fq, Fr, FR_ONE}; @@ -27,12 +27,12 @@ impl ModelParameters for Parameters { impl SWModelParameters for Parameters { /// COEFF_A = 2 #[rustfmt::skip] - const COEFF_A: Fq = field_new!(Fq, "2"); + const COEFF_A: Fq = MontFp!(Fq, "2"); /// COEFF_B = 0x01373684A8C9DCAE7A016AC5D7748D3313CD8E39051C596560835DF0C9E50A5B59B882A92C78DC537E51A16703EC9855C77FC3D8BB21C8D68BB8CFB9DB4B8C8FBA773111C36C8B1B4E8F1ECE940EF9EAAD265458E06372009C9A0491678EF4 /// = 28798803903456388891410036793299405764940372360099938340752576406393880372126970068421383312482853541572780087363938442377933706865252053507077543420534380486492786626556269083255657125025963825610840222568694137138741554679540 #[rustfmt::skip] - const COEFF_B: Fq = field_new!(Fq, "28798803903456388891410036793299405764940372360099938340752576406393880372126970068421383312482853541572780087363938442377933706865252053507077543420534380486492786626556269083255657125025963825610840222568694137138741554679540"); + const COEFF_B: Fq = MontFp!(Fq, "28798803903456388891410036793299405764940372360099938340752576406393880372126970068421383312482853541572780087363938442377933706865252053507077543420534380486492786626556269083255657125025963825610840222568694137138741554679540"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = @@ -44,8 +44,8 @@ impl SWModelParameters for Parameters { // Y = 6913648190367314284606685101150155872986263667483624713540251048208073654617802840433842931301128643140890502238233930290161632176167186761333725658542781350626799660920481723757654531036893265359076440986158843531053720994648, /// G1_GENERATOR_X = #[rustfmt::skip] -pub const G1_GENERATOR_X: Fq = field_new!(Fq, "7790163481385331313124631546957228376128961350185262705123068027727518350362064426002432450801002268747950550964579198552865939244360469674540925037890082678099826733417900510086646711680891516503232107232083181010099241949569"); +pub const G1_GENERATOR_X: Fq = MontFp!(Fq, "7790163481385331313124631546957228376128961350185262705123068027727518350362064426002432450801002268747950550964579198552865939244360469674540925037890082678099826733417900510086646711680891516503232107232083181010099241949569"); /// G1_GENERATOR_Y = #[rustfmt::skip] -pub const G1_GENERATOR_Y: Fq = field_new!(Fq, "6913648190367314284606685101150155872986263667483624713540251048208073654617802840433842931301128643140890502238233930290161632176167186761333725658542781350626799660920481723757654531036893265359076440986158843531053720994648"); +pub const G1_GENERATOR_Y: Fq = MontFp!(Fq, "6913648190367314284606685101150155872986263667483624713540251048208073654617802840433842931301128643140890502238233930290161632176167186761333725658542781350626799660920481723757654531036893265359076440986158843531053720994648"); diff --git a/test-curves/src/mnt6_753/fq.rs b/test-curves/src/mnt6_753/fq.rs index 6a78ced45..d623da5f7 100644 --- a/test-curves/src/mnt6_753/fq.rs +++ b/test-curves/src/mnt6_753/fq.rs @@ -1 +1 @@ -pub use crate::mnt4_753::{Fr as Fq, FrParameters as FqParameters}; +pub use crate::mnt4_753::{Fr as Fq, FrConfig as FqConfig}; diff --git a/test-curves/src/mnt6_753/fq3.rs b/test-curves/src/mnt6_753/fq3.rs index f432c9aac..2ed6dd7ee 100644 --- a/test-curves/src/mnt6_753/fq3.rs +++ b/test-curves/src/mnt6_753/fq3.rs @@ -1,7 +1,7 @@ use crate::mnt6_753::fq::Fq; use ark_ff::{ - field_new, fields::fp3::{Fp3, Fp3Parameters}, + CubicExt, MontFp, }; pub type Fq3 = Fp3; @@ -12,12 +12,12 @@ impl Fp3Parameters for Fq3Parameters { type Fp = Fq; #[rustfmt::skip] - const NONRESIDUE: Fq = field_new!(Fq, "11"); + const NONRESIDUE: Fq = MontFp!(Fq, "11"); const TWO_ADICITY: u32 = 30; #[rustfmt::skip] - const T_MINUS_ONE_DIV_TWO: &'static [u64] = &[ + const TRACE_MINUS_ONE_DIV_TWO: &'static [u64] = &[ 15439605736802142541, 18190868848461853149, 6220121510046940818, @@ -57,8 +57,7 @@ impl Fp3Parameters for Fq3Parameters { /// (11^T, 0, 0) #[rustfmt::skip] - const QUADRATIC_NONRESIDUE_TO_T: (Fq, Fq, Fq) = ( - field_new!(Fq, "22168644070733283197994897338612733221095941481265408161807376791727499343083607817089033595478370212662133368413166734396127674284827734481031659015434501966360165723728649019457855887066657739809176476252080335185730833468062"), + const QUADRATIC_NONRESIDUE_TO_T: Fq3 = CubicExt!(Fq3, MontFp!(Fq, "22168644070733283197994897338612733221095941481265408161807376791727499343083607817089033595478370212662133368413166734396127674284827734481031659015434501966360165723728649019457855887066657739809176476252080335185730833468062"), FQ_ZERO, FQ_ZERO, ); @@ -70,8 +69,8 @@ impl Fp3Parameters for Fq3Parameters { #[rustfmt::skip] const FROBENIUS_COEFF_FP3_C1: &'static [Fq] = &[ FQ_ONE, - field_new!(Fq, "24129022407817241407134263419936114379815707076943508280977368156625538709102831814843582780138963119807143081677569721953561801075623741378629346409604471234573396989178424163772589090105392407118197799904755622897541183052132"), - field_new!(Fq, "17769468560101711995209951371304522748355002843010440790806134764399814103468274958215310983651375801610927890210888755369611256415970113691066895445191924931148019336171640277697829047741006062493737919155152541323243293107868"), + MontFp!(Fq, "24129022407817241407134263419936114379815707076943508280977368156625538709102831814843582780138963119807143081677569721953561801075623741378629346409604471234573396989178424163772589090105392407118197799904755622897541183052132"), + MontFp!(Fq, "17769468560101711995209951371304522748355002843010440790806134764399814103468274958215310983651375801610927890210888755369611256415970113691066895445191924931148019336171640277697829047741006062493737919155152541323243293107868"), ]; // c2 = {c1[0], c1[2], c1[1]} @@ -83,5 +82,5 @@ impl Fp3Parameters for Fq3Parameters { ]; } -pub const FQ_ZERO: Fq = field_new!(Fq, "0"); -pub const FQ_ONE: Fq = field_new!(Fq, "1"); +pub const FQ_ZERO: Fq = MontFp!(Fq, "0"); +pub const FQ_ONE: Fq = MontFp!(Fq, "1"); diff --git a/test-curves/src/mnt6_753/fr.rs b/test-curves/src/mnt6_753/fr.rs index fd483571c..e1476ae75 100644 --- a/test-curves/src/mnt6_753/fr.rs +++ b/test-curves/src/mnt6_753/fr.rs @@ -1 +1 @@ -pub use crate::mnt4_753::{Fq as Fr, FqParameters as FrParameters}; +pub use crate::mnt4_753::{Fq as Fr, FqConfig as FrConfig}; diff --git a/test-templates/Cargo.toml b/test-templates/Cargo.toml index d8927bfa6..58577765e 100644 --- a/test-templates/Cargo.toml +++ b/test-templates/Cargo.toml @@ -18,6 +18,8 @@ ark-std = { version = "^0.3.0", default-features = false } ark-serialize = { version = "^0.3.0", path = "../serialize", default-features = false } ark-ff = { version = "^0.3.0", path = "../ff", default-features = false } ark-ec = { version = "^0.3.0", path = "../ec", default-features = false } +num-bigint = { version = "0.4", default-features = false } +num-integer = { version = "0.1", default-features = false } [features] default = [] diff --git a/test-templates/src/curves.rs b/test-templates/src/curves.rs index 6e5a58980..e9b2fe2c8 100644 --- a/test-templates/src/curves.rs +++ b/test-templates/src/curves.rs @@ -125,8 +125,8 @@ fn random_multiplication_test() { tmp2.add_assign(&b); // Affine multiplication - let mut tmp3 = a_affine.mul(s.into_repr()); - tmp3.add_assign(&b_affine.mul(s.into_repr())); + let mut tmp3 = a_affine.mul(s.into_bigint()); + tmp3.add_assign(&b_affine.mul(s.into_bigint())); assert_eq!(tmp1, tmp2); assert_eq!(tmp1, tmp3); diff --git a/test-templates/src/fields.rs b/test-templates/src/fields.rs index be0003c28..1e78f62e3 100644 --- a/test-templates/src/fields.rs +++ b/test-templates/src/fields.rs @@ -1,6 +1,9 @@ #![allow(unused)] #![allow(clippy::eq_op)] -use ark_ff::fields::{FftField, FftParameters, Field, LegendreSymbol, PrimeField, SquareRootField}; +use ark_ff::{ + fields::{FftConfig, FftField, Field, LegendreSymbol, PrimeField, SquareRootField}, + Fp, MontBackend, MontConfig, +}; use ark_serialize::{buffer_bit_byte_size, Flags, SWFlags}; use ark_std::{io::Cursor, rand::Rng}; @@ -306,18 +309,18 @@ pub fn field_test(a: F, b: F) { pub fn fft_field_test() { assert_eq!( - F::two_adic_root_of_unity().pow([1 << F::FftParams::TWO_ADICITY]), + F::two_adic_root_of_unity().pow([1 << F::FftConfig::TWO_ADICITY]), F::one() ); - if let Some(small_subgroup_base) = F::FftParams::SMALL_SUBGROUP_BASE { - let small_subgroup_base_adicity = F::FftParams::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); + if let Some(small_subgroup_base) = F::FftConfig::SMALL_SUBGROUP_BASE { + let small_subgroup_base_adicity = F::FftConfig::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); let large_subgroup_root_of_unity = F::large_subgroup_root_of_unity().unwrap(); - let pow = (1 << F::FftParams::TWO_ADICITY) + let pow = (1 << F::FftConfig::TWO_ADICITY) * (small_subgroup_base as u64).pow(small_subgroup_base_adicity); assert_eq!(large_subgroup_root_of_unity.pow([pow]), F::one()); - for i in 0..F::FftParams::TWO_ADICITY { + for i in 0..F::FftConfig::TWO_ADICITY { for j in 0..small_subgroup_base_adicity { use core::convert::TryFrom; let size = usize::try_from(1 << i as usize).unwrap() @@ -327,7 +330,7 @@ pub fn fft_field_test() { } } } else { - for i in 0..F::FftParams::TWO_ADICITY { + for i in 0..F::FftConfig::TWO_ADICITY { let size = 1 << i; let root = F::get_root_of_unity(size).unwrap(); assert_eq!(root.pow([size as u64]), F::one()); @@ -338,11 +341,50 @@ pub fn fft_field_test() { pub fn primefield_test() { from_str_test::(); let one = F::one(); - assert_eq!(F::from(one.into_repr()), one); + assert_eq!(F::from(one.into_bigint()), one); fft_field_test::(); } +pub fn montgomery_primefield_test, const N: usize>() { + use num_bigint::BigUint; + use num_integer::Integer; + let modulus: BigUint = T::MODULUS.into(); + let r = BigUint::from(2u8).modpow(&((N * 64) as u64).into(), &modulus); + let r2 = (&r * &r) % &modulus; + assert_eq!(r, T::R.into()); + assert_eq!(r2, T::R2.into()); + assert_eq!( + Fp::, N>::MODULUS_BIT_SIZE as u64, + modulus.bits() + ); + + let modulus_minus_one = &modulus - 1u8; + assert_eq!( + BigUint::from(Fp::, N>::MODULUS_MINUS_ONE_DIV_TWO), + &modulus_minus_one / 2u32 + ); + + let mut two_adicity = 0; + let mut trace = modulus_minus_one.clone(); + while trace.is_even() { + trace /= 2u8; + two_adicity += 1; + } + assert_eq!(two_adicity, MontBackend::::TWO_ADICITY); + assert_eq!(BigUint::from(Fp::, N>::TRACE), trace); + let trace_minus_one_div_two = (&trace - 1u8) / 2u8; + assert_eq!( + BigUint::from(Fp::, N>::TRACE_MINUS_ONE_DIV_TWO), + trace_minus_one_div_two + ); + + let two_adic_root_of_unity: BigUint = + Fp::, N>::two_adic_root_of_unity().into(); + let generator: BigUint = Fp::, N>::GENERATOR.into_bigint().into(); + assert_eq!(two_adic_root_of_unity, generator.modpow(&trace, &modulus)); +} + pub fn sqrt_field_test(elem: F) { let square = elem.square(); let sqrt = square.sqrt().unwrap(); diff --git a/test-templates/src/lib.rs b/test-templates/src/lib.rs index 3fff305a5..f69987c78 100644 --- a/test-templates/src/lib.rs +++ b/test-templates/src/lib.rs @@ -533,6 +533,19 @@ macro_rules! generate_field_test { generate_field_test!($($tail)*); }; + (mont($fq_num_limbs:expr, $fr_num_limbs:expr); $($tail:tt)*) => { + #[test] + fn test_fq_mont() { + montgomery_primefield_test::(); + } + + #[test] + fn test_fr_mont() { + montgomery_primefield_test::(); + } + + generate_field_test!($($tail)*); + } } #[macro_export] diff --git a/test-templates/src/msm.rs b/test-templates/src/msm.rs index b6f08593f..f66ed6802 100644 --- a/test-templates/src/msm.rs +++ b/test-templates/src/msm.rs @@ -22,7 +22,7 @@ pub fn test_var_base_msm() { let mut rng = ark_std::test_rng(); let v = (0..SAMPLES - 1) - .map(|_| G::ScalarField::rand(&mut rng).into_repr()) + .map(|_| G::ScalarField::rand(&mut rng).into_bigint()) .collect::>(); let g = (0..SAMPLES) .map(|_| G::Projective::rand(&mut rng)) @@ -41,7 +41,7 @@ pub fn test_chunked_pippenger() { let mut rng = ark_std::test_rng(); let v = (0..SAMPLES) - .map(|_| G::ScalarField::rand(&mut rng).into_repr()) + .map(|_| G::ScalarField::rand(&mut rng).into_bigint()) .collect::>(); let g = (0..SAMPLES) .map(|_| G::Projective::rand(&mut rng)) From 7ea854b58bfcaa7ce8702fc8a962c78581a2de7c Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 18:57:03 -0800 Subject: [PATCH 08/32] Rename `Parameters` to `Config` for all fields --- ec/Cargo.toml | 2 +- ec/src/models/bls12/mod.rs | 8 +- ec/src/models/bn/mod.rs | 8 +- ec/src/models/bw6/mod.rs | 8 +- ec/src/models/mnt4/mod.rs | 8 +- ec/src/models/mnt6/mod.rs | 8 +- ff-asm/Cargo.toml | 2 +- ff/Cargo.toml | 2 +- ff/README.md | 4 +- ff/src/fields/mod.rs | 17 ++-- ff/src/fields/models/cubic_extension.rs | 98 ++++++++++----------- ff/src/fields/models/fp/mod.rs | 6 +- ff/src/fields/models/fp12_2over3over2.rs | 14 +-- ff/src/fields/models/fp2.rs | 10 +-- ff/src/fields/models/fp3.rs | 10 +-- ff/src/fields/models/fp4.rs | 23 +++-- ff/src/fields/models/fp6_2over3.rs | 38 ++++---- ff/src/fields/models/fp6_3over2.rs | 14 +-- ff/src/fields/models/quadratic_extension.rs | 96 ++++++++++---------- poly/Cargo.toml | 2 +- test-curves/src/bls12_381/fq2.rs | 6 +- test-curves/src/bls12_381/fq6.rs | 8 +- test-curves/src/mnt6_753/fq3.rs | 14 +-- 23 files changed, 201 insertions(+), 205 deletions(-) diff --git a/ec/Cargo.toml b/ec/Cargo.toml index df329fee9..8cb1aded5 100644 --- a/ec/Cargo.toml +++ b/ec/Cargo.toml @@ -11,7 +11,7 @@ categories = ["cryptography"] include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] license = "MIT/Apache-2.0" edition = "2021" -rust-version = "1.56" +rust-version = "1.57" [dependencies] ark-std = { version = "^0.3.0", default-features = false } diff --git a/ec/src/models/bls12/mod.rs b/ec/src/models/bls12/mod.rs index e5b1c50e9..ecdd7fa53 100644 --- a/ec/src/models/bls12/mod.rs +++ b/ec/src/models/bls12/mod.rs @@ -4,8 +4,8 @@ use crate::{ }; use ark_ff::fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, - fp2::Fp2Parameters, - fp6_3over2::Fp6Parameters, + fp2::Fp2Config, + fp6_3over2::Fp6Config, BitIteratorBE, Field, Fp2, PrimeField, SquareRootField, }; use core::marker::PhantomData; @@ -34,8 +34,8 @@ pub trait Bls12Parameters: 'static { const TWIST_TYPE: TwistType; type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fp2Params: Fp2Parameters; - type Fp6Params: Fp6Parameters; + type Fp2Params: Fp2Config; + type Fp6Params: Fp6Config; type Fp12Params: Fp12Parameters; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< diff --git a/ec/src/models/bn/mod.rs b/ec/src/models/bn/mod.rs index 7e1751797..f12b0d2af 100644 --- a/ec/src/models/bn/mod.rs +++ b/ec/src/models/bn/mod.rs @@ -4,8 +4,8 @@ use crate::{ }; use ark_ff::fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, - fp2::Fp2Parameters, - fp6_3over2::Fp6Parameters, + fp2::Fp2Config, + fp6_3over2::Fp6Config, Field, Fp2, PrimeField, SquareRootField, }; use num_traits::One; @@ -32,8 +32,8 @@ pub trait BnParameters: 'static { const TWIST_MUL_BY_Q_X: Fp2; const TWIST_MUL_BY_Q_Y: Fp2; type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fp2Params: Fp2Parameters; - type Fp6Params: Fp6Parameters; + type Fp2Params: Fp2Config; + type Fp6Params: Fp6Config; type Fp12Params: Fp12Parameters; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< diff --git a/ec/src/models/bw6/mod.rs b/ec/src/models/bw6/mod.rs index ff2726e10..69f52aac3 100644 --- a/ec/src/models/bw6/mod.rs +++ b/ec/src/models/bw6/mod.rs @@ -3,8 +3,8 @@ use crate::{ PairingEngine, }; use ark_ff::fields::{ - fp3::Fp3Parameters, - fp6_2over3::{Fp6, Fp6Parameters}, + fp3::Fp3Config, + fp6_2over3::{Fp6, Fp6Config}, BitIteratorBE, Field, PrimeField, SquareRootField, }; use num_traits::One; @@ -25,8 +25,8 @@ pub trait BW6Parameters: 'static + Eq + PartialEq { const ATE_LOOP_COUNT_2_IS_NEGATIVE: bool; const TWIST_TYPE: TwistType; type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fp3Params: Fp3Parameters; - type Fp6Params: Fp6Parameters; + type Fp3Params: Fp3Config; + type Fp6Params: Fp6Config; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Self::Fp, diff --git a/ec/src/models/mnt4/mod.rs b/ec/src/models/mnt4/mod.rs index ea73fdcb2..1bce34496 100644 --- a/ec/src/models/mnt4/mod.rs +++ b/ec/src/models/mnt4/mod.rs @@ -3,8 +3,8 @@ use crate::{ PairingEngine, }; use ark_ff::{ - fp2::{Fp2, Fp2Parameters}, - fp4::{Fp4, Fp4Parameters}, + fp2::{Fp2, Fp2Config}, + fp4::{Fp4, Fp4Config}, BitIteratorBE, Field, PrimeField, SquareRootField, }; use num_traits::{One, Zero}; @@ -32,8 +32,8 @@ pub trait MNT4Parameters: 'static { const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: ::BigInt; type Fp: PrimeField + SquareRootField + Into<::BigInt>; type Fr: PrimeField + SquareRootField + Into<::BigInt>; - type Fp2Params: Fp2Parameters; - type Fp4Params: Fp4Parameters; + type Fp2Params: Fp2Config; + type Fp4Params: Fp4Config; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Fp2, diff --git a/ec/src/models/mnt6/mod.rs b/ec/src/models/mnt6/mod.rs index fe1efa8cb..d8afe31a6 100644 --- a/ec/src/models/mnt6/mod.rs +++ b/ec/src/models/mnt6/mod.rs @@ -3,8 +3,8 @@ use crate::{ PairingEngine, }; use ark_ff::{ - fp3::{Fp3, Fp3Parameters}, - fp6_2over3::{Fp6, Fp6Parameters}, + fp3::{Fp3, Fp3Config}, + fp6_2over3::{Fp6, Fp6Config}, BitIteratorBE, Field, PrimeField, SquareRootField, }; use num_traits::{One, Zero}; @@ -32,8 +32,8 @@ pub trait MNT6Parameters: 'static { const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: ::BigInt; type Fp: PrimeField + SquareRootField + Into<::BigInt>; type Fr: PrimeField + SquareRootField + Into<::BigInt>; - type Fp3Params: Fp3Parameters; - type Fp6Params: Fp6Parameters; + type Fp3Params: Fp3Config; + type Fp6Params: Fp6Config; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Fp3, diff --git a/ff-asm/Cargo.toml b/ff-asm/Cargo.toml index 3cb833a2e..56b375a77 100644 --- a/ff-asm/Cargo.toml +++ b/ff-asm/Cargo.toml @@ -11,7 +11,7 @@ categories = ["cryptography"] include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] license = "MIT/Apache-2.0" edition = "2021" -rust-version = "1.56" +rust-version = "1.57" [dependencies] quote = "1.0.0" diff --git a/ff/Cargo.toml b/ff/Cargo.toml index 0a3fcfd39..fe6f1e793 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -12,7 +12,7 @@ include = ["Cargo.toml", "build.rs", "src", "README.md", "LICENSE-APACHE", "LICE license = "MIT/Apache-2.0" edition = "2021" build = "build.rs" -rust-version = "1.56" +rust-version = "1.57" [dependencies] ark-ff-asm = { version = "^0.3.0", path = "../ff-asm" } diff --git a/ff/README.md b/ff/README.md index 28e4c16d0..c2ea16449 100644 --- a/ff/README.md +++ b/ff/README.md @@ -25,10 +25,10 @@ The models implemented are: - [`Quadratic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs) - [`QuadExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L140) - Struct representing a quadratic extension field, in this case holding two elements -- [`QuadExtParameters`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Quadratic Extension Field +- [`QuadExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Quadratic Extension Field - [`Cubic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs) - [`CubicExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L72) - Struct representing a cubic extension field, holds three elements -- [`CubicExtParameters`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field +- [`CubicExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field The above two models serve as abstractions for constructing the extension fields `Fp^m` directly (i.e. `m` equal 2 or 3) or for creating extension towers to arrive at higher `m`. The latter is done by applying the extensions iteratively, e.g. cubic extension over a quadratic extension field. diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index 0ab7fe327..cb083d231 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -353,9 +353,10 @@ pub trait PrimeField: /// The interface for a field that supports an efficient square-root operation. pub trait SquareRootField: Field { /// Returns a `LegendreSymbol`, which indicates whether this field element - /// is 1 : a quadratic residue - /// 0 : equal to 0 - /// -1 : a quadratic non-residue + /// is + /// - 1: a quadratic residue + /// - 0: equal to 0 + /// - -1: a quadratic non-residue fn legendre(&self) -> LegendreSymbol; /// Returns the square root of self, if it exists. @@ -371,9 +372,8 @@ pub trait SquareRootField: Field { /// # Examples /// ``` /// # use ark_std::test_rng; -/// # use ark_test_curves::bls12_381::Fq as Fp; /// # use ark_std::UniformRand; -/// # use ark_ff::{LegendreSymbol, Field, SquareRootField}; +/// # use ark_test_curves::{LegendreSymbol, Field, SquareRootField, bls12_381::Fq as Fp}; /// let a: Fp = Fp::rand(&mut test_rng()); /// let b = a.square(); /// assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); @@ -391,9 +391,8 @@ impl LegendreSymbol { /// # Examples /// ``` /// # use ark_std::test_rng; - /// # use ark_test_curves::bls12_381::Fq as Fp; /// # use ark_std::UniformRand; - /// # use ark_ff::{LegendreSymbol, Field, SquareRootField}; + /// # use ark_test_curves::{LegendreSymbol, Field, SquareRootField, bls12_381::Fq as Fp}; /// let a: Fp = Fp::rand(&mut test_rng()); /// let b: Fp = a.square(); /// assert!(!b.legendre().is_zero()); @@ -406,9 +405,7 @@ impl LegendreSymbol { /// /// # Examples /// ``` - /// # use ark_test_curves::bls12_381::{Fq, Fq2Config}; - /// # use ark_ff::{LegendreSymbol, SquareRootField}; - /// # use ark_ff::Fp2Config; + /// # use ark_test_curves::{Fp2Config, LegendreSymbol, SquareRootField, bls12_381::{Fq, Fq2Config}}; /// let a: Fq = Fq2Config::NONRESIDUE; /// assert!(a.legendre().is_qnr()); /// ``` diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index ba2274c84..be84c1225 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -25,7 +25,7 @@ use crate::{ }; /// Defines a Cubic extension field from a cubic non-residue. -pub trait CubicExtParameters: 'static + Send + Sync { +pub trait CubicExtConfig: 'static + Send + Sync { /// The prime field that this cubic extension is eventually an extension of. type BasePrimeField: PrimeField; /// The base field that this field is a cubic extension of. @@ -68,15 +68,15 @@ pub trait CubicExtParameters: 'static + Send + Sync { /// represented as c0 + c1 * X + c2 * X^2, for c0, c1, c2 in `P::BaseField`. #[derive(Derivative)] #[derivative( - Default(bound = "P: CubicExtParameters"), - Hash(bound = "P: CubicExtParameters"), - Clone(bound = "P: CubicExtParameters"), - Copy(bound = "P: CubicExtParameters"), - Debug(bound = "P: CubicExtParameters"), - PartialEq(bound = "P: CubicExtParameters"), - Eq(bound = "P: CubicExtParameters") + Default(bound = "P: CubicExtConfig"), + Hash(bound = "P: CubicExtConfig"), + Clone(bound = "P: CubicExtConfig"), + Copy(bound = "P: CubicExtConfig"), + Debug(bound = "P: CubicExtConfig"), + PartialEq(bound = "P: CubicExtConfig"), + Eq(bound = "P: CubicExtConfig") )] -pub struct CubicExtField { +pub struct CubicExtField { pub c0: P::BaseField, pub c1: P::BaseField, pub c2: P::BaseField, @@ -94,7 +94,7 @@ macro_rules! CubicExt { }; } -impl CubicExtField

{ +impl CubicExtField

{ /// Create a new field element from coefficients `c0`, `c1` and `c2` /// so that the result is of the form `c0 + c1 * X + c2 * X^2`. /// @@ -103,7 +103,7 @@ impl CubicExtField

{ /// ``` /// # use ark_std::test_rng; /// # use ark_test_curves::bls12_381::{Fq2 as Fp2, Fq6 as Fp6}; - /// # use ark_test_curves::bls12_381::Fq6Parameters; + /// # use ark_test_curves::bls12_381::Fq6Config; /// # use ark_std::UniformRand; /// # use ark_ff::models::fp6_3over2::Fp6ParamsWrapper; /// use ark_ff::models::cubic_extension::CubicExtField; @@ -111,7 +111,7 @@ impl CubicExtField

{ /// let c0: Fp2 = Fp2::rand(&mut test_rng()); /// let c1: Fp2 = Fp2::rand(&mut test_rng()); /// let c2: Fp2 = Fp2::rand(&mut test_rng()); - /// # type Params = Fp6ParamsWrapper; + /// # type Params = Fp6ParamsWrapper; /// // `Fp6` a degree-3 extension over `Fp2`. /// let c: CubicExtField = Fp6::new(c0, c1, c2); /// ``` @@ -144,7 +144,7 @@ impl CubicExtField

{ } } -impl Zero for CubicExtField

{ +impl Zero for CubicExtField

{ fn zero() -> Self { Self::new( P::BaseField::zero(), @@ -158,7 +158,7 @@ impl Zero for CubicExtField

{ } } -impl One for CubicExtField

{ +impl One for CubicExtField

{ fn one() -> Self { Self::new( P::BaseField::one(), @@ -172,7 +172,7 @@ impl One for CubicExtField

{ } } -impl Field for CubicExtField

{ +impl Field for CubicExtField

{ type BasePrimeField = P::BasePrimeField; fn extension_degree() -> u64 { @@ -305,7 +305,7 @@ impl Field for CubicExtField

{ } /// `CubicExtField` elements are ordered lexicographically. -impl Ord for CubicExtField

{ +impl Ord for CubicExtField

{ #[inline(always)] fn cmp(&self, other: &Self) -> Ordering { let c2_cmp = self.c2.cmp(&other.c2); @@ -323,14 +323,14 @@ impl Ord for CubicExtField

{ } } -impl PartialOrd for CubicExtField

{ +impl PartialOrd for CubicExtField

{ #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Zeroize for CubicExtField

{ +impl Zeroize for CubicExtField

{ // The phantom data does not contain element-specific data // and thus does not need to be zeroized. fn zeroize(&mut self) { @@ -340,14 +340,14 @@ impl Zeroize for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u128) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i128) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -359,14 +359,14 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u64) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i64) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -378,14 +378,14 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u32) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i32) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -397,14 +397,14 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u16) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i16) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -416,14 +416,14 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: u8) -> Self { let fe: P::BaseField = other.into(); Self::new(fe, P::BaseField::zero(), P::BaseField::zero()) } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ #[inline] fn from(val: i8) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -435,7 +435,7 @@ impl From for CubicExtField

{ } } -impl From for CubicExtField

{ +impl From for CubicExtField

{ fn from(other: bool) -> Self { Self::new( u8::from(other).into(), @@ -445,7 +445,7 @@ impl From for CubicExtField

{ } } -impl Neg for CubicExtField

{ +impl Neg for CubicExtField

{ type Output = Self; #[inline] fn neg(mut self) -> Self { @@ -456,7 +456,7 @@ impl Neg for CubicExtField

{ } } -impl Distribution> for Standard { +impl Distribution> for Standard { #[inline] fn sample(&self, rng: &mut R) -> CubicExtField

{ CubicExtField::new( @@ -467,7 +467,7 @@ impl Distribution> for Standard { } } -impl<'a, P: CubicExtParameters> Add<&'a CubicExtField

> for CubicExtField

{ +impl<'a, P: CubicExtConfig> Add<&'a CubicExtField

> for CubicExtField

{ type Output = Self; #[inline] @@ -477,7 +477,7 @@ impl<'a, P: CubicExtParameters> Add<&'a CubicExtField

> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> Sub<&'a CubicExtField

> for CubicExtField

{ +impl<'a, P: CubicExtConfig> Sub<&'a CubicExtField

> for CubicExtField

{ type Output = Self; #[inline] @@ -487,7 +487,7 @@ impl<'a, P: CubicExtParameters> Sub<&'a CubicExtField

> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> Mul<&'a CubicExtField

> for CubicExtField

{ +impl<'a, P: CubicExtConfig> Mul<&'a CubicExtField

> for CubicExtField

{ type Output = Self; #[inline] @@ -497,7 +497,7 @@ impl<'a, P: CubicExtParameters> Mul<&'a CubicExtField

> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> Div<&'a CubicExtField

> for CubicExtField

{ +impl<'a, P: CubicExtConfig> Div<&'a CubicExtField

> for CubicExtField

{ type Output = Self; #[inline] @@ -507,9 +507,9 @@ impl<'a, P: CubicExtParameters> Div<&'a CubicExtField

> for CubicExtField

{ } } -impl_additive_ops_from_ref!(CubicExtField, CubicExtParameters); -impl_multiplicative_ops_from_ref!(CubicExtField, CubicExtParameters); -impl<'a, P: CubicExtParameters> AddAssign<&'a Self> for CubicExtField

{ +impl_additive_ops_from_ref!(CubicExtField, CubicExtConfig); +impl_multiplicative_ops_from_ref!(CubicExtField, CubicExtConfig); +impl<'a, P: CubicExtConfig> AddAssign<&'a Self> for CubicExtField

{ #[inline] fn add_assign(&mut self, other: &Self) { self.c0.add_assign(&other.c0); @@ -518,7 +518,7 @@ impl<'a, P: CubicExtParameters> AddAssign<&'a Self> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> SubAssign<&'a Self> for CubicExtField

{ +impl<'a, P: CubicExtConfig> SubAssign<&'a Self> for CubicExtField

{ #[inline] fn sub_assign(&mut self, other: &Self) { self.c0.sub_assign(&other.c0); @@ -527,7 +527,7 @@ impl<'a, P: CubicExtParameters> SubAssign<&'a Self> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> MulAssign<&'a Self> for CubicExtField

{ +impl<'a, P: CubicExtConfig> MulAssign<&'a Self> for CubicExtField

{ #[inline] #[allow(clippy::many_single_char_names)] fn mul_assign(&mut self, other: &Self) { @@ -557,20 +557,20 @@ impl<'a, P: CubicExtParameters> MulAssign<&'a Self> for CubicExtField

{ } } -impl<'a, P: CubicExtParameters> DivAssign<&'a Self> for CubicExtField

{ +impl<'a, P: CubicExtConfig> DivAssign<&'a Self> for CubicExtField

{ #[inline] fn div_assign(&mut self, other: &Self) { self.mul_assign(&other.inverse().unwrap()); } } -impl fmt::Display for CubicExtField

{ +impl fmt::Display for CubicExtField

{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CubicExtField({}, {}, {})", self.c0, self.c1, self.c2) } } -impl CanonicalSerializeWithFlags for CubicExtField

{ +impl CanonicalSerializeWithFlags for CubicExtField

{ #[inline] fn serialize_with_flags( &self, @@ -591,7 +591,7 @@ impl CanonicalSerializeWithFlags for CubicExtField

{ } } -impl CanonicalSerialize for CubicExtField

{ +impl CanonicalSerialize for CubicExtField

{ #[inline] fn serialize(&self, writer: W) -> Result<(), SerializationError> { self.serialize_with_flags(writer, EmptyFlags) @@ -603,7 +603,7 @@ impl CanonicalSerialize for CubicExtField

{ } } -impl CanonicalDeserializeWithFlags for CubicExtField

{ +impl CanonicalDeserializeWithFlags for CubicExtField

{ #[inline] fn deserialize_with_flags( mut reader: R, @@ -615,7 +615,7 @@ impl CanonicalDeserializeWithFlags for CubicExtField

{ } } -impl CanonicalDeserialize for CubicExtField

{ +impl CanonicalDeserialize for CubicExtField

{ #[inline] fn deserialize(mut reader: R) -> Result { let c0: P::BaseField = CanonicalDeserialize::deserialize(&mut reader)?; @@ -625,7 +625,7 @@ impl CanonicalDeserialize for CubicExtField

{ } } -impl ToConstraintField for CubicExtField

+impl ToConstraintField for CubicExtField

where P::BaseField: ToConstraintField, { @@ -643,7 +643,7 @@ where } } -impl ToBytes for CubicExtField

{ +impl ToBytes for CubicExtField

{ #[inline] fn write(&self, mut writer: W) -> IoResult<()> { self.c0.write(&mut writer)?; @@ -652,7 +652,7 @@ impl ToBytes for CubicExtField

{ } } -impl FromBytes for CubicExtField

{ +impl FromBytes for CubicExtField

{ #[inline] fn read(mut reader: R) -> IoResult { let c0 = P::BaseField::read(&mut reader)?; diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 340206353..b2875c49d 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -328,9 +328,9 @@ impl, const N: usize> PrimeField for Fp { type BigInt = BigInt; const MODULUS: Self::BigInt = P::MODULUS; const GENERATOR: Self = P::GENERATOR; - const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt = Self::MODULUS.divide_by_2_round_down(); - const MODULUS_BIT_SIZE: u32 = Self::MODULUS.const_num_bits(); - const TRACE: Self::BigInt = Self::MODULUS.two_adic_coefficient(); + const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt = P::MODULUS.divide_by_2_round_down(); + const MODULUS_BIT_SIZE: u32 = P::MODULUS.const_num_bits(); + const TRACE: Self::BigInt = P::MODULUS.two_adic_coefficient(); const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt = Self::TRACE.divide_by_2_round_down(); #[inline] diff --git a/ff/src/fields/models/fp12_2over3over2.rs b/ff/src/fields/models/fp12_2over3over2.rs index bd040f29b..d14e1b543 100644 --- a/ff/src/fields/models/fp12_2over3over2.rs +++ b/ff/src/fields/models/fp12_2over3over2.rs @@ -1,6 +1,6 @@ use super::quadratic_extension::*; use crate::{ - fields::{fp6_3over2::*, Field, Fp2, Fp2Parameters}, + fields::{fp6_3over2::*, Field, Fp2, Fp2Config}, One, }; use core::{ @@ -8,10 +8,10 @@ use core::{ ops::{AddAssign, SubAssign}, }; -type Fp2Params

= <

::Fp6Params as Fp6Parameters>::Fp2Params; +type Fp2Params

= <

::Fp6Params as Fp6Config>::Fp2Params; pub trait Fp12Parameters: 'static + Send + Sync + Copy { - type Fp6Params: Fp6Parameters; + type Fp6Params: Fp6Config; /// This *must* equal (0, 1, 0); /// see [[DESD06, Section 6.1]](https://eprint.iacr.org/2006/471.pdf). @@ -33,8 +33,8 @@ pub trait Fp12Parameters: 'static + Send + Sync + Copy { pub struct Fp12ParamsWrapper(PhantomData

); -impl QuadExtParameters for Fp12ParamsWrapper

{ - type BasePrimeField = as Fp2Parameters>::Fp; +impl QuadExtConfig for Fp12ParamsWrapper

{ + type BasePrimeField = as Fp2Config>::Fp; type BaseField = Fp6; type FrobCoeff = Fp2>; @@ -85,7 +85,7 @@ pub type Fp12

= QuadExtField>; impl Fp12

{ pub fn mul_by_fp( &mut self, - element: &<::Fp2Params as Fp2Parameters>::Fp, + element: &<::Fp2Params as Fp2Config>::Fp, ) { self.c0.mul_by_fp(&element); self.c1.mul_by_fp(&element); @@ -138,7 +138,7 @@ impl Fp12

{ // - Robert Granger and Michael Scott // if characteristic_square_mod_6_is_one(Self::characteristic()) { - let fp2_nr = ::mul_fp2_by_nonresidue; + let fp2_nr = ::mul_fp2_by_nonresidue; let r0 = &self.c0.c0; let r4 = &self.c0.c1; diff --git a/ff/src/fields/models/fp2.rs b/ff/src/fields/models/fp2.rs index 6e2c7b317..fe767ee3d 100644 --- a/ff/src/fields/models/fp2.rs +++ b/ff/src/fields/models/fp2.rs @@ -3,7 +3,7 @@ use crate::fields::PrimeField; use core::marker::PhantomData; /// Parameters for defining degree-two extension fields. -pub trait Fp2Parameters: 'static + Send + Sync + Sized { +pub trait Fp2Config: 'static + Send + Sync + Sized { /// Base prime field underlying this extension. type Fp: PrimeField; @@ -50,10 +50,10 @@ pub trait Fp2Parameters: 'static + Send + Sync + Sized { } } -/// Wrapper for Fp2Parameters, allowing combination of Fp2Parameters & QuadExtParameters traits -pub struct Fp2ParamsWrapper(PhantomData

); +/// Wrapper for Fp2Config, allowing combination of Fp2Config & QuadExtConfig traits +pub struct Fp2ParamsWrapper(PhantomData

); -impl QuadExtParameters for Fp2ParamsWrapper

{ +impl QuadExtConfig for Fp2ParamsWrapper

{ type BasePrimeField = P::Fp; type BaseField = P::Fp; type FrobCoeff = P::Fp; @@ -102,7 +102,7 @@ impl QuadExtParameters for Fp2ParamsWrapper

{ /// instantiations involving `Fp2ParamsWrapper`. pub type Fp2

= QuadExtField>; -impl Fp2

{ +impl Fp2

{ /// In-place multiply both coefficients `c0` & `c1` of the extension field /// `Fp2` by an element from `Fp`. The coefficients themselves /// are elements of `Fp`. diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index e34e67d05..caf136750 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -2,7 +2,7 @@ use super::cubic_extension::*; use crate::fields::*; use core::marker::PhantomData; -pub trait Fp3Parameters: 'static + Send + Sync + Sized { +pub trait Fp3Config: 'static + Send + Sync + Sized { type Fp: PrimeField + SquareRootField; const NONRESIDUE: Self::Fp; @@ -22,9 +22,9 @@ pub trait Fp3Parameters: 'static + Send + Sync + Sized { } } -pub struct Fp3ParamsWrapper(PhantomData

); +pub struct Fp3ParamsWrapper(PhantomData

); -impl CubicExtParameters for Fp3ParamsWrapper

{ +impl CubicExtConfig for Fp3ParamsWrapper

{ type BasePrimeField = P::Fp; type BaseField = P::Fp; type FrobCoeff = P::Fp; @@ -53,7 +53,7 @@ impl CubicExtParameters for Fp3ParamsWrapper

{ pub type Fp3

= CubicExtField>; -impl Fp3

{ +impl Fp3

{ pub fn mul_assign_by_fp(&mut self, value: &P::Fp) { self.c0.mul_assign(value); self.c1.mul_assign(value); @@ -67,7 +67,7 @@ impl Fp3

{ } } -impl SquareRootField for Fp3

{ +impl SquareRootField for Fp3

{ /// Returns the Legendre symbol. fn legendre(&self) -> LegendreSymbol { self.norm().legendre() diff --git a/ff/src/fields/models/fp4.rs b/ff/src/fields/models/fp4.rs index 290391028..ba0985c98 100644 --- a/ff/src/fields/models/fp4.rs +++ b/ff/src/fields/models/fp4.rs @@ -1,10 +1,10 @@ use super::quadratic_extension::*; use core::marker::PhantomData; -use crate::fields::{Fp2, Fp2Parameters}; +use crate::fields::{Fp2, Fp2Config}; -pub trait Fp4Parameters: 'static + Send + Sync { - type Fp2Params: Fp2Parameters; +pub trait Fp4Config: 'static + Send + Sync { + type Fp2Params: Fp2Config; /// This *must* equal (0, 1); /// see [[DESD06, Section 5.1]](https://eprint.iacr.org/2006/471.pdf). @@ -12,22 +12,19 @@ pub trait Fp4Parameters: 'static + Send + Sync { /// Coefficients for the Frobenius automorphism. /// non_residue^((modulus^i-1)/4) for i=0,1,2,3 - const FROBENIUS_COEFF_FP4_C1: &'static [::Fp]; + const FROBENIUS_COEFF_FP4_C1: &'static [::Fp]; #[inline(always)] fn mul_fp2_by_nonresidue(fe: &Fp2) -> Fp2 { // see [[DESD06, Section 5.1]](https://eprint.iacr.org/2006/471.pdf). - Fp2::new( - ::NONRESIDUE * &fe.c1, - fe.c0, - ) + Fp2::new(::NONRESIDUE * &fe.c1, fe.c0) } } -pub struct Fp4ParamsWrapper(PhantomData

); +pub struct Fp4ParamsWrapper(PhantomData

); -impl QuadExtParameters for Fp4ParamsWrapper

{ - type BasePrimeField = ::Fp; +impl QuadExtConfig for Fp4ParamsWrapper

{ + type BasePrimeField = ::Fp; type BaseField = Fp2; type FrobCoeff = Self::BasePrimeField; @@ -49,8 +46,8 @@ impl QuadExtParameters for Fp4ParamsWrapper

{ pub type Fp4

= QuadExtField>; -impl Fp4

{ - pub fn mul_by_fp(&mut self, element: &::Fp) { +impl Fp4

{ + pub fn mul_by_fp(&mut self, element: &::Fp) { self.c0.mul_assign_by_fp(element); self.c1.mul_assign_by_fp(element); } diff --git a/ff/src/fields/models/fp6_2over3.rs b/ff/src/fields/models/fp6_2over3.rs index 07a42b222..30bd49fb2 100644 --- a/ff/src/fields/models/fp6_2over3.rs +++ b/ff/src/fields/models/fp6_2over3.rs @@ -1,15 +1,15 @@ use super::quadratic_extension::*; use core::{marker::PhantomData, ops::MulAssign}; -use crate::fields::{Fp3, Fp3Parameters}; +use crate::fields::{Fp3, Fp3Config}; -pub trait Fp6Parameters: 'static + Send + Sync { - type Fp3Params: Fp3Parameters; +pub trait Fp6Config: 'static + Send + Sync { + type Fp3Params: Fp3Config; const NONRESIDUE: Fp3; /// Coefficients for the Frobenius automorphism. - const FROBENIUS_COEFF_FP6_C1: &'static [::Fp]; + const FROBENIUS_COEFF_FP6_C1: &'static [::Fp]; #[inline(always)] fn mul_fp3_by_nonresidue(fe: &Fp3) -> Fp3 { @@ -17,15 +17,15 @@ pub trait Fp6Parameters: 'static + Send + Sync { res.c0 = fe.c2; res.c1 = fe.c0; res.c2 = fe.c1; - res.c0 = ::mul_fp_by_nonresidue(&res.c0); + res.c0 = ::mul_fp_by_nonresidue(&res.c0); res } } -pub struct Fp6ParamsWrapper(PhantomData

); +pub struct Fp6ParamsWrapper(PhantomData

); -impl QuadExtParameters for Fp6ParamsWrapper

{ - type BasePrimeField = ::Fp; +impl QuadExtConfig for Fp6ParamsWrapper

{ + type BasePrimeField = ::Fp; type BaseField = Fp3; type FrobCoeff = Self::BasePrimeField; @@ -47,12 +47,12 @@ impl QuadExtParameters for Fp6ParamsWrapper

{ pub type Fp6

= QuadExtField>; -impl Fp6

{ +impl Fp6

{ pub fn mul_by_034( &mut self, - c0: &::Fp, - c3: &::Fp, - c4: &::Fp, + c0: &::Fp, + c3: &::Fp, + c4: &::Fp, ) { let z0 = self.c0.c0; let z1 = self.c0.c1; @@ -66,9 +66,9 @@ impl Fp6

{ let x4 = *c4; let mut tmp1 = x3; - tmp1.mul_assign(&::NONRESIDUE); + tmp1.mul_assign(&::NONRESIDUE); let mut tmp2 = x4; - tmp2.mul_assign(&::NONRESIDUE); + tmp2.mul_assign(&::NONRESIDUE); self.c0.c0 = x0 * &z0 + &(tmp1 * &z5) + &(tmp2 * &z4); self.c0.c1 = x0 * &z1 + &(x3 * &z3) + &(tmp2 * &z5); @@ -80,9 +80,9 @@ impl Fp6

{ pub fn mul_by_014( &mut self, - c0: &::Fp, - c1: &::Fp, - c4: &::Fp, + c0: &::Fp, + c1: &::Fp, + c4: &::Fp, ) { let z0 = self.c0.c0; let z1 = self.c0.c1; @@ -96,9 +96,9 @@ impl Fp6

{ let x4 = *c4; let mut tmp1 = x1; - tmp1.mul_assign(&::NONRESIDUE); + tmp1.mul_assign(&::NONRESIDUE); let mut tmp2 = x4; - tmp2.mul_assign(&::NONRESIDUE); + tmp2.mul_assign(&::NONRESIDUE); self.c0.c0 = x0 * &z0 + &(tmp1 * &z2) + &(tmp2 * &z4); self.c0.c1 = x0 * &z1 + &(x1 * &z0) + &(tmp2 * &z5); diff --git a/ff/src/fields/models/fp6_3over2.rs b/ff/src/fields/models/fp6_3over2.rs index 1fe91c7ee..974f5e85b 100644 --- a/ff/src/fields/models/fp6_3over2.rs +++ b/ff/src/fields/models/fp6_3over2.rs @@ -2,8 +2,8 @@ use super::cubic_extension::*; use crate::fields::*; use core::marker::PhantomData; -pub trait Fp6Parameters: 'static + Send + Sync + Copy { - type Fp2Params: Fp2Parameters; +pub trait Fp6Config: 'static + Send + Sync + Copy { + type Fp2Params: Fp2Config; const NONRESIDUE: Fp2; @@ -17,10 +17,10 @@ pub trait Fp6Parameters: 'static + Send + Sync + Copy { } } -pub struct Fp6ParamsWrapper(PhantomData

); +pub struct Fp6ParamsWrapper(PhantomData

); -impl CubicExtParameters for Fp6ParamsWrapper

{ - type BasePrimeField = ::Fp; +impl CubicExtConfig for Fp6ParamsWrapper

{ + type BasePrimeField = ::Fp; type BaseField = Fp2; type FrobCoeff = Fp2; @@ -48,14 +48,14 @@ impl CubicExtParameters for Fp6ParamsWrapper

{ pub type Fp6

= CubicExtField>; -impl Fp6

{ +impl Fp6

{ pub fn mul_assign_by_fp2(&mut self, other: Fp2) { self.c0 *= &other; self.c1 *= &other; self.c2 *= &other; } - pub fn mul_by_fp(&mut self, element: &::Fp) { + pub fn mul_by_fp(&mut self, element: &::Fp) { self.c0.mul_assign_by_fp(&element); self.c1.mul_assign_by_fp(&element); self.c2.mul_assign_by_fp(&element); diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 70b0ce839..7718326a1 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -26,7 +26,7 @@ use crate::{ }; /// Defines a Quadratic extension field from a quadratic non-residue. -pub trait QuadExtParameters: 'static + Send + Sync + Sized { +pub trait QuadExtConfig: 'static + Send + Sync + Sized { /// The prime field that this quadratic extension is eventually an extension of. type BasePrimeField: PrimeField; /// The base field that this field is a quadratic extension of. @@ -127,15 +127,15 @@ pub trait QuadExtParameters: 'static + Send + Sync + Sized { /// represented as c0 + c1 * X, for c0, c1 in `P::BaseField`. #[derive(Derivative)] #[derivative( - Default(bound = "P: QuadExtParameters"), - Hash(bound = "P: QuadExtParameters"), - Clone(bound = "P: QuadExtParameters"), - Copy(bound = "P: QuadExtParameters"), - Debug(bound = "P: QuadExtParameters"), - PartialEq(bound = "P: QuadExtParameters"), - Eq(bound = "P: QuadExtParameters") + Default(bound = "P: QuadExtConfig"), + Hash(bound = "P: QuadExtConfig"), + Clone(bound = "P: QuadExtConfig"), + Copy(bound = "P: QuadExtConfig"), + Debug(bound = "P: QuadExtConfig"), + PartialEq(bound = "P: QuadExtConfig"), + Eq(bound = "P: QuadExtConfig") )] -pub struct QuadExtField { +pub struct QuadExtField { /// Coefficient `c0` in the representation of the field element `c = c0 + c1 * X` pub c0: P::BaseField, /// Coefficient `c1` in the representation of the field element `c = c0 + c1 * X` @@ -149,7 +149,7 @@ macro_rules! QuadExt { }; } -impl QuadExtField

{ +impl QuadExtField

{ /// Create a new field element from coefficients `c0` and `c1`, /// so that the result is of the form `c0 + c1 * X`. /// @@ -218,7 +218,7 @@ impl QuadExtField

{ } } -impl Zero for QuadExtField

{ +impl Zero for QuadExtField

{ fn zero() -> Self { QuadExtField::new(P::BaseField::zero(), P::BaseField::zero()) } @@ -228,7 +228,7 @@ impl Zero for QuadExtField

{ } } -impl One for QuadExtField

{ +impl One for QuadExtField

{ fn one() -> Self { QuadExtField::new(P::BaseField::one(), P::BaseField::zero()) } @@ -238,7 +238,7 @@ impl One for QuadExtField

{ } } -impl Field for QuadExtField

{ +impl Field for QuadExtField

{ type BasePrimeField = P::BasePrimeField; fn extension_degree() -> u64 { @@ -376,7 +376,7 @@ impl Field for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> SquareRootField for QuadExtField

+impl<'a, P: QuadExtConfig> SquareRootField for QuadExtField

where P::BaseField: SquareRootField + From, { @@ -463,7 +463,7 @@ where } /// `QuadExtField` elements are ordered lexicographically. -impl Ord for QuadExtField

{ +impl Ord for QuadExtField

{ #[inline(always)] fn cmp(&self, other: &Self) -> Ordering { match self.c1.cmp(&other.c1) { @@ -474,14 +474,14 @@ impl Ord for QuadExtField

{ } } -impl PartialOrd for QuadExtField

{ +impl PartialOrd for QuadExtField

{ #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Zeroize for QuadExtField

{ +impl Zeroize for QuadExtField

{ // The phantom data does not contain element-specific data // and thus does not need to be zeroized. fn zeroize(&mut self) { @@ -490,13 +490,13 @@ impl Zeroize for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u128) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i128) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -508,13 +508,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u64) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i64) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -526,13 +526,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u32) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i32) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -544,13 +544,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u16) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i16) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -562,13 +562,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: u8) -> Self { Self::new(other.into(), P::BaseField::zero()) } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ #[inline] fn from(val: i8) -> Self { let abs = Self::from(val.unsigned_abs()); @@ -580,13 +580,13 @@ impl From for QuadExtField

{ } } -impl From for QuadExtField

{ +impl From for QuadExtField

{ fn from(other: bool) -> Self { Self::new(u8::from(other).into(), P::BaseField::zero()) } } -impl Neg for QuadExtField

{ +impl Neg for QuadExtField

{ type Output = Self; #[inline] #[must_use] @@ -597,14 +597,14 @@ impl Neg for QuadExtField

{ } } -impl Distribution> for Standard { +impl Distribution> for Standard { #[inline] fn sample(&self, rng: &mut R) -> QuadExtField

{ QuadExtField::new(UniformRand::rand(rng), UniformRand::rand(rng)) } } -impl<'a, P: QuadExtParameters> Add<&'a QuadExtField

> for QuadExtField

{ +impl<'a, P: QuadExtConfig> Add<&'a QuadExtField

> for QuadExtField

{ type Output = Self; #[inline] @@ -614,7 +614,7 @@ impl<'a, P: QuadExtParameters> Add<&'a QuadExtField

> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> Sub<&'a QuadExtField

> for QuadExtField

{ +impl<'a, P: QuadExtConfig> Sub<&'a QuadExtField

> for QuadExtField

{ type Output = Self; #[inline] @@ -624,7 +624,7 @@ impl<'a, P: QuadExtParameters> Sub<&'a QuadExtField

> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> Mul<&'a QuadExtField

> for QuadExtField

{ +impl<'a, P: QuadExtConfig> Mul<&'a QuadExtField

> for QuadExtField

{ type Output = Self; #[inline] @@ -634,7 +634,7 @@ impl<'a, P: QuadExtParameters> Mul<&'a QuadExtField

> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> Div<&'a QuadExtField

> for QuadExtField

{ +impl<'a, P: QuadExtConfig> Div<&'a QuadExtField

> for QuadExtField

{ type Output = Self; #[inline] @@ -644,7 +644,7 @@ impl<'a, P: QuadExtParameters> Div<&'a QuadExtField

> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> AddAssign<&'a Self> for QuadExtField

{ +impl<'a, P: QuadExtConfig> AddAssign<&'a Self> for QuadExtField

{ #[inline] fn add_assign(&mut self, other: &Self) { self.c0 += &other.c0; @@ -652,7 +652,7 @@ impl<'a, P: QuadExtParameters> AddAssign<&'a Self> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> SubAssign<&'a Self> for QuadExtField

{ +impl<'a, P: QuadExtConfig> SubAssign<&'a Self> for QuadExtField

{ #[inline] fn sub_assign(&mut self, other: &Self) { self.c0 -= &other.c0; @@ -660,10 +660,10 @@ impl<'a, P: QuadExtParameters> SubAssign<&'a Self> for QuadExtField

{ } } -impl_additive_ops_from_ref!(QuadExtField, QuadExtParameters); -impl_multiplicative_ops_from_ref!(QuadExtField, QuadExtParameters); +impl_additive_ops_from_ref!(QuadExtField, QuadExtConfig); +impl_multiplicative_ops_from_ref!(QuadExtField, QuadExtConfig); -impl<'a, P: QuadExtParameters> MulAssign<&'a Self> for QuadExtField

{ +impl<'a, P: QuadExtConfig> MulAssign<&'a Self> for QuadExtField

{ #[inline] fn mul_assign(&mut self, other: &Self) { // Karatsuba multiplication; @@ -679,20 +679,20 @@ impl<'a, P: QuadExtParameters> MulAssign<&'a Self> for QuadExtField

{ } } -impl<'a, P: QuadExtParameters> DivAssign<&'a Self> for QuadExtField

{ +impl<'a, P: QuadExtConfig> DivAssign<&'a Self> for QuadExtField

{ #[inline] fn div_assign(&mut self, other: &Self) { self.mul_assign(&other.inverse().unwrap()); } } -impl fmt::Display for QuadExtField

{ +impl fmt::Display for QuadExtField

{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "QuadExtField({} + {} * u)", self.c0, self.c1) } } -impl CanonicalSerializeWithFlags for QuadExtField

{ +impl CanonicalSerializeWithFlags for QuadExtField

{ #[inline] fn serialize_with_flags( &self, @@ -710,7 +710,7 @@ impl CanonicalSerializeWithFlags for QuadExtField

{ } } -impl CanonicalSerialize for QuadExtField

{ +impl CanonicalSerialize for QuadExtField

{ #[inline] fn serialize(&self, writer: W) -> Result<(), SerializationError> { self.serialize_with_flags(writer, EmptyFlags) @@ -722,7 +722,7 @@ impl CanonicalSerialize for QuadExtField

{ } } -impl CanonicalDeserializeWithFlags for QuadExtField

{ +impl CanonicalDeserializeWithFlags for QuadExtField

{ #[inline] fn deserialize_with_flags( mut reader: R, @@ -734,7 +734,7 @@ impl CanonicalDeserializeWithFlags for QuadExtField

{ } } -impl CanonicalDeserialize for QuadExtField

{ +impl CanonicalDeserialize for QuadExtField

{ #[inline] fn deserialize(mut reader: R) -> Result { let c0: P::BaseField = CanonicalDeserialize::deserialize(&mut reader)?; @@ -743,7 +743,7 @@ impl CanonicalDeserialize for QuadExtField

{ } } -impl ToConstraintField for QuadExtField

+impl ToConstraintField for QuadExtField

where P::BaseField: ToConstraintField, { @@ -759,7 +759,7 @@ where } } -impl ToBytes for QuadExtField

{ +impl ToBytes for QuadExtField

{ #[inline] fn write(&self, mut writer: W) -> IoResult<()> { self.c0.write(&mut writer)?; @@ -767,7 +767,7 @@ impl ToBytes for QuadExtField

{ } } -impl FromBytes for QuadExtField

{ +impl FromBytes for QuadExtField

{ #[inline] fn read(mut reader: R) -> IoResult { let c0 = P::BaseField::read(&mut reader)?; diff --git a/poly/Cargo.toml b/poly/Cargo.toml index 1b1e8ee74..134197f55 100644 --- a/poly/Cargo.toml +++ b/poly/Cargo.toml @@ -11,7 +11,7 @@ categories = ["cryptography"] include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] license = "MIT/Apache-2.0" edition = "2021" -rust-version = "1.56" +rust-version = "1.57" [dependencies] ark-ff = { version = "^0.3.0", path = "../ff", default-features = false } diff --git a/test-curves/src/bls12_381/fq2.rs b/test-curves/src/bls12_381/fq2.rs index 012b05552..34b58bbd9 100644 --- a/test-curves/src/bls12_381/fq2.rs +++ b/test-curves/src/bls12_381/fq2.rs @@ -1,11 +1,11 @@ use crate::bls12_381::*; use ark_ff::{fields::*, MontFp, QuadExt}; -pub type Fq2 = Fp2; +pub type Fq2 = Fp2; -pub struct Fq2Parameters; +pub struct Fq2Config; -impl Fp2Parameters for Fq2Parameters { +impl Fp2Config for Fq2Config { type Fp = Fq; /// NONRESIDUE = -1 diff --git a/test-curves/src/bls12_381/fq6.rs b/test-curves/src/bls12_381/fq6.rs index 2fcbff6b6..71d108ff9 100644 --- a/test-curves/src/bls12_381/fq6.rs +++ b/test-curves/src/bls12_381/fq6.rs @@ -1,13 +1,13 @@ use crate::bls12_381::*; use ark_ff::{fields::*, MontFp, QuadExt}; -pub type Fq6 = Fp6; +pub type Fq6 = Fp6; #[derive(Clone, Copy)] -pub struct Fq6Parameters; +pub struct Fq6Config; -impl Fp6Parameters for Fq6Parameters { - type Fp2Params = Fq2Parameters; +impl Fp6Config for Fq6Config { + type Fp2Params = Fq2Config; /// NONRESIDUE = (U + 1) #[rustfmt::skip] diff --git a/test-curves/src/mnt6_753/fq3.rs b/test-curves/src/mnt6_753/fq3.rs index 2ed6dd7ee..51ec71ea7 100644 --- a/test-curves/src/mnt6_753/fq3.rs +++ b/test-curves/src/mnt6_753/fq3.rs @@ -1,14 +1,15 @@ use crate::mnt6_753::fq::Fq; use ark_ff::{ - fields::fp3::{Fp3, Fp3Parameters}, - CubicExt, MontFp, + MontFp, + CubicExt, + fields::fp3::{Fp3, Fp3Config}, }; -pub type Fq3 = Fp3; +pub type Fq3 = Fp3; -pub struct Fq3Parameters; +pub struct Fq3Config; -impl Fp3Parameters for Fq3Parameters { +impl Fp3Config for Fq3Config { type Fp = Fq; #[rustfmt::skip] @@ -57,7 +58,8 @@ impl Fp3Parameters for Fq3Parameters { /// (11^T, 0, 0) #[rustfmt::skip] - const QUADRATIC_NONRESIDUE_TO_T: Fq3 = CubicExt!(Fq3, MontFp!(Fq, "22168644070733283197994897338612733221095941481265408161807376791727499343083607817089033595478370212662133368413166734396127674284827734481031659015434501966360165723728649019457855887066657739809176476252080335185730833468062"), + const QUADRATIC_NONRESIDUE_TO_T: Fq3 = CubicExt!(Fq3, + MontFp!(Fq, "22168644070733283197994897338612733221095941481265408161807376791727499343083607817089033595478370212662133368413166734396127674284827734481031659015434501966360165723728649019457855887066657739809176476252080335185730833468062"), FQ_ZERO, FQ_ZERO, ); From dfeea4aaa136a4b66981ebb26baf65a9d86cfec6 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 19:08:20 -0800 Subject: [PATCH 09/32] Update CHANGELOG and fix typos in README --- CHANGELOG.md | 25 ++++++++++++++++--------- ff/README.md | 18 +++++++++--------- test-curves/src/mnt6_753/fq3.rs | 6 +++--- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57666c817..ddadef204 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,12 @@ ### Breaking changes -- [\#300](https://github.com/arkworks-rs/algebra/pull/300) (ark-ec) Change the implementation of `Hash` trait of `GroupProjective` to use the affine coordinates. +- [\#300](https://github.com/arkworks-rs/algebra/pull/300) (ark-ec) Change the implementation of `Hash` trait of `GroupProjective` to use the affine co-ordinates. - [\#310](https://github.com/arkworks-rs/algebra/pull/310) (ark-ec, ark-ff) Remove unnecessary internal `PhantomData`. - [\#333](https://github.com/arkworks-rs/algebra/pull/333) (ark-poly) Expose more properties of `EvaluationDomain`s. - [\#338](https://github.com/arkworks-rs/algebra/pull/338) (ark-ec) Add missing `UniformRand` trait bound to `GroupAffine`. - [\#338](https://github.com/arkworks-rs/algebra/pull/338) (workspace) Change to Rust 2021 edition. -- [\#345](https://github.com/arkworks-rs/algebra/pull/345) (ark-ec, ark-serialize) Change the serialization format for Twisted Edwards Curves. We now encode the Y coordinate and take the sign bit of the X co-ordinate, the default flag is also now the Positive X value. The old methods for backwards compatibility are located [here](https://github.com/arkworks-rs/algebra/pull/345/files#diff-3621a48bb33f469144044d8d5fc663f767e103132a764812cda6be6c25877494R860) +- [\#345](https://github.com/arkworks-rs/algebra/pull/345) (ark-ec, ark-serialize) Change the serialization format for Twisted Edwards Curves. We now encode the Y co-ordinate and take the sign bit of the X co-ordinate, the default flag is also now the Positive X value. The old methods for backwards compatibility are located [here](https://github.com/arkworks-rs/algebra/pull/345/files#diff-3621a48bb33f469144044d8d5fc663f767e103132a764812cda6be6c25877494R860) - [\#348](https://github.com/arkworks-rs/algebra/pull/348) (ark-ec) Rename `msm:{Fixed,Variable}BaseMSM:multi_scalar_mul` to `msm:{Fixed,Variable}:msm` to avoid redundancy. - [\#359](https://github.com/arkworks-rs/algebra/pull/359) (ark-test-templates) Simplify the field and curve test macros. - [\#365](https://github.com/arkworks-rs/algebra/pull/365) (ark-ec) @@ -17,6 +17,13 @@ - Add `mul_bits()` to `AffineCurve` and provide a default implementation of `mul()` using this. - Remove duplicate function `scale_by_cofactor()` from `short_weierstrass_jacobian::GroupAffine` and `twisted_edwards_extended::GroupAffine` - [\#370](https://github.com/arkworks-rs/algebra/pull/370) (all) Set the minimum `rust-version = 1.56` in the manifests of all crates. +- [\#379](https://github.com/arkworks-rs/algebra/pull/379) (ff) Refactor `Field` implementation and `PrimeField` trait: + - Switches from hardcoded `FpXYZ` to `Fp` based on `const` generics. + - Moves Montgomery arithmetic to an optional backend. + - Rename `field_new` macros to `MontFp`, `QuadExt` and `CubicExt` macros. + - Introduce `const fn`s for generating many constants. + - Add default associated constants to reduce boilerplate. + - Rename `Fp*Parameters` to `Fp*Config`. ### Features @@ -35,7 +42,7 @@ ### Bugfixes -- [\#350](https://github.com/arkworks-rs/algebra/pull/350) (ark-serialize) Fix issues with santiation whenever a non-standard `Result` type is in scope. +- [\#350](https://github.com/arkworks-rs/algebra/pull/350) (ark-serialize) Fix issues with hygiene whenever a non-standard `Result` type is in scope. - [\#358](https://github.com/arkworks-rs/algebra/pull/358) (ark-ff) Fix the bug for `QuadExtField::sqrt` when `c1 = 0 && c0.legendre.is_qnr()` - [\#366](https://github.com/arkworks-rs/algebra/pull/366) (ark-ff) Fix `norm()` for cubic extension field towers. @@ -103,11 +110,11 @@ The main features of this release are: Importing these from `ark-ff` is still possible, but is deprecated and will be removed in the following release. - [\#144](https://github.com/arkworks-rs/algebra/pull/144) (ark-poly) Add `CanonicalSerialize` and `CanonicalDeserialize` trait bounds for `Polynomial`. - [\#160](https://github.com/arkworks-rs/algebra/pull/160) (ark-serialize, ark-ff, ark-ec) - - Remove `ConstantSerializedSize`; users should use `serialized_size*` (see next). - - Add `serialized_size_with_flags` method to `CanonicalSerializeWithFlags`. - - Change `from_random_bytes_with_flags` to output `ark_serialize::Flags`. - - Change signatures of `Flags::from_u8*` to output `Option`. - - Change `Flags::from_u8*` to be more strict about the inputs they accept: + - Remove `ConstantSerializedSize`; users should use `serialized_size*` (see next). + - Add `serialized_size_with_flags` method to `CanonicalSerializeWithFlags`. + - Change `from_random_bytes_with_flags` to output `ark_serialize::Flags`. + - Change signatures of `Flags::from_u8*` to output `Option`. + - Change `Flags::from_u8*` to be more strict about the inputs it accepts: if the top bits of the `u8` value do *not* correspond to one of the possible outputs of `Flags::u8_bitmask`, then these methods output `None`, whereas before they output a default value. Downstream users other than `ark-curves` should not see breakage unless they rely on these methods/traits explicitly. @@ -122,7 +129,7 @@ The main features of this release are: - [\#117](https://github.com/arkworks-rs/algebra/pull/117) (ark-poly) Add operations to `SparsePolynomial`, so it implements `Polynomial`. - [\#140](https://github.com/arkworks-rs/algebra/pull/140) (ark-poly) Add support for multilinear extensions in dense and sparse evaluation form. - [\#164](https://github.com/arkworks-rs/algebra/pull/164) (ark-ff) Add methods `from_{be, le}_bytes_mod_order` to the `PrimeField` trait. -- [\#197](https://github.com/arkworks-rs/algebra/pull/197) (ark-test-curves) Add a BN384 curve with low two-arity for mixed-radix testing. +- [\#197](https://github.com/arkworks-rs/algebra/pull/197) (ark-test-curves) Add a BN384 curve with low two-adicity for mixed-radix testing. ### Improvements diff --git a/ff/README.md b/ff/README.md index c2ea16449..3b8abad72 100644 --- a/ff/README.md +++ b/ff/README.md @@ -7,7 +7,7 @@

This crate defines Finite Field traits and useful abstraction models that follow these traits. -Implementations of finite fields with concrete parameters can be found in [`arkworks-rs/curves`](https://github.com/arkworks-rs/curves/README.md) under `arkworks-rs/curves//src/fields/`, which are used for some of the popular curves, such as a specific [`Fq`](https://github.com/arkworks-rs/curves/blob/master/bls12_381/src/fields/fq.rs) used in BLS-381. +Implementations of concrete finite fields for some popular elliptic curves can be found in [`arkworks-rs/curves`](https://github.com/arkworks-rs/curves/README.md) under `arkworks-rs/curves//src/fields/`. This crate contains two types of traits: @@ -16,19 +16,19 @@ This crate contains two types of traits: The available field traits are: -- [`Field`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L66) - Interface for the most generic finte field -- [`FftField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L275) - Exposes methods that allow for performing efficient FFTs on this field's elements -- [`PrimeField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L347) - Field with `p` (`p` prime) elements, later referred to as `Fp`. +- [`Field`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L66) - Interface for a generic finite field. +- [`FftField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L275) - Exposes methods that allow for performing efficient FFTs on field elements. +- [`PrimeField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L347) - Field with a prime `p` number of elements, also referred to as `Fp`. - [`SquareRootField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L431) - Interface for fields that support square-root operations The models implemented are: - [`Quadratic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs) -- [`QuadExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L140) - Struct representing a quadratic extension field, in this case holding two elements -- [`QuadExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Quadratic Extension Field + - [`QuadExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L140) - Struct representing a quadratic extension field, in this case holding two base field elements + - [`QuadExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Quadratic Extension Field - [`Cubic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs) -- [`CubicExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L72) - Struct representing a cubic extension field, holds three elements -- [`CubicExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field + - [`CubicExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L72) - Struct representing a cubic extension field, holds three base field elements + - [`CubicExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field The above two models serve as abstractions for constructing the extension fields `Fp^m` directly (i.e. `m` equal 2 or 3) or for creating extension towers to arrive at higher `m`. The latter is done by applying the extensions iteratively, e.g. cubic extension over a quadratic extension field. @@ -36,4 +36,4 @@ The above two models serve as abstractions for constructing the extension fields - [`Fp3`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp3.rs#L54) - Cubic extension directly on the prime field, i.e. `BaseField == BasePrimeField` - [`Fp6_2over3`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp6_2over3.rs#L48) - Extension tower: quadratic extension on a cubic extension field, i.e. `BaseField = Fp3`, but `BasePrimeField = Fp`. - [`Fp6_3over2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp6_3over2.rs#L49) - Extension tower, similar to the above except that the towering order is reversed: it's a cubic extension on a quadratic extension field, i.e. `BaseField = Fp2`, but `BasePrimeField = Fp`. Only this latter one is exported by default as `Fp6`. -- [`Fp12_2over3over2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp12_2over3over2.rs#L83) - Extension tower: quadratic extension of the `Fp6_3over2`, i.e. `BaseField = Fp6`. +- [`Fp12_2over3over2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp12_2over3over2.rs#L83) - Extension tower: quadratic extension of `Fp6_3over2`, i.e. `BaseField = Fp6`. diff --git a/test-curves/src/mnt6_753/fq3.rs b/test-curves/src/mnt6_753/fq3.rs index 51ec71ea7..03d89472b 100644 --- a/test-curves/src/mnt6_753/fq3.rs +++ b/test-curves/src/mnt6_753/fq3.rs @@ -1,8 +1,7 @@ use crate::mnt6_753::fq::Fq; use ark_ff::{ - MontFp, - CubicExt, fields::fp3::{Fp3, Fp3Config}, + CubicExt, MontFp, }; pub type Fq3 = Fp3; @@ -58,7 +57,8 @@ impl Fp3Config for Fq3Config { /// (11^T, 0, 0) #[rustfmt::skip] - const QUADRATIC_NONRESIDUE_TO_T: Fq3 = CubicExt!(Fq3, + const QUADRATIC_NONRESIDUE_TO_T: Fq3 = CubicExt!( + Fq3, MontFp!(Fq, "22168644070733283197994897338612733221095941481265408161807376791727499343083607817089033595478370212662133368413166734396127674284827734481031659015434501966360165723728649019457855887066657739809176476252080335185730833468062"), FQ_ZERO, FQ_ZERO, From ec89e31071076d5630199a9edb1daf35b9c61633 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 19:15:22 -0800 Subject: [PATCH 10/32] Clean up CHANGELOG further --- CHANGELOG.md | 199 ++++++++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddadef204..0f5cc5bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,76 +4,77 @@ ### Breaking changes -- [\#300](https://github.com/arkworks-rs/algebra/pull/300) (ark-ec) Change the implementation of `Hash` trait of `GroupProjective` to use the affine co-ordinates. -- [\#310](https://github.com/arkworks-rs/algebra/pull/310) (ark-ec, ark-ff) Remove unnecessary internal `PhantomData`. -- [\#333](https://github.com/arkworks-rs/algebra/pull/333) (ark-poly) Expose more properties of `EvaluationDomain`s. -- [\#338](https://github.com/arkworks-rs/algebra/pull/338) (ark-ec) Add missing `UniformRand` trait bound to `GroupAffine`. +- [\#300](https://github.com/arkworks-rs/algebra/pull/300) (`ark-ec`) Change the implementation of `Hash` trait of `GroupProjective` to use the affine co-ordinates. +- [\#310](https://github.com/arkworks-rs/algebra/pull/310) (`ark-ec`, `ark-ff`) Remove unnecessary internal `PhantomData`. +- [\#333](https://github.com/arkworks-rs/algebra/pull/333) (`ark-poly`) Expose more properties of `EvaluationDomain`s. +- [\#338](https://github.com/arkworks-rs/algebra/pull/338) (`ark-ec`) Add missing `UniformRand` trait bound to `GroupAffine`. - [\#338](https://github.com/arkworks-rs/algebra/pull/338) (workspace) Change to Rust 2021 edition. -- [\#345](https://github.com/arkworks-rs/algebra/pull/345) (ark-ec, ark-serialize) Change the serialization format for Twisted Edwards Curves. We now encode the Y co-ordinate and take the sign bit of the X co-ordinate, the default flag is also now the Positive X value. The old methods for backwards compatibility are located [here](https://github.com/arkworks-rs/algebra/pull/345/files#diff-3621a48bb33f469144044d8d5fc663f767e103132a764812cda6be6c25877494R860) -- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (ark-ec) Rename `msm:{Fixed,Variable}BaseMSM:multi_scalar_mul` to `msm:{Fixed,Variable}:msm` to avoid redundancy. +- [\#345](https://github.com/arkworks-rs/algebra/pull/345) (`ark-ec`, `ark-serialize`) Change the serialization format for Twisted Edwards Curves. We now encode the Y co-ordinate and take the sign bit of the X co-ordinate, the default flag is also now the Positive X value. The old methods for backwards compatibility are located [here](https://github.com/arkworks-rs/algebra/pull/345/files#diff-3621a48bb33f469144044d8d5fc663f767e103132a764812cda6be6c25877494R860) +- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (`ark-ec`) Rename `msm:{Fixed,Variable}BaseMSM:multi_scalar_mul` to `msm:{Fixed,Variable}:msm` to avoid redundancy. - [\#359](https://github.com/arkworks-rs/algebra/pull/359) (ark-test-templates) Simplify the field and curve test macros. -- [\#365](https://github.com/arkworks-rs/algebra/pull/365) (ark-ec) +- [\#365](https://github.com/arkworks-rs/algebra/pull/365) (`ark-ec`) - Move `COFACTOR`, `COFACTOR_INV`, and `is_in_correct_subgroup_assuming_on_curve()` from `{SW,TE}ModelParameters` to `ModelParameters`. - Add `mul_bits()` to `AffineCurve` and provide a default implementation of `mul()` using this. - Remove duplicate function `scale_by_cofactor()` from `short_weierstrass_jacobian::GroupAffine` and `twisted_edwards_extended::GroupAffine` - [\#370](https://github.com/arkworks-rs/algebra/pull/370) (all) Set the minimum `rust-version = 1.56` in the manifests of all crates. -- [\#379](https://github.com/arkworks-rs/algebra/pull/379) (ff) Refactor `Field` implementation and `PrimeField` trait: +- [\#379](https://github.com/arkworks-rs/algebra/pull/379) (`ark-ff`) Refactor `Field` implementation and `PrimeField` trait: - Switches from hardcoded `FpXYZ` to `Fp` based on `const` generics. - Moves Montgomery arithmetic to an optional backend. - Rename `field_new` macros to `MontFp`, `QuadExt` and `CubicExt` macros. - Introduce `const fn`s for generating many constants. - Add default associated constants to reduce boilerplate. - Rename `Fp*Parameters` to `Fp*Config`. + - Adds `From`, `From`, and `From` `impl`s for `BigInt`. ### Features -- [\#321](https://github.com/arkworks-rs/algebra/pull/321) (ark-ff) Change bigint conversions to impl `From` instead of `Into`. -- [\#301](https://github.com/arkworks-rs/algebra/pull/301) (ark-ec) Add `GLVParameters` trait definition. -- [\#312](https://github.com/arkworks-rs/algebra/pull/312) (ark-ec) Add `is_in_correct_subgroup_assuming_on_curve` for all `SWModelParameters`. -- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (ark-ec) Add `msm:{Fixed,Variable}Base:msm_checked_len`. -- [\#364](https://github.com/arkworks-rs/algebra/pull/364) (ark-ec) Add `ChunkedPippenger` to variable-base MSM. -- [\#371](https://github.com/arkworks-rs/algebra/pull/371) (ark-serialize) Add serialization impls for arrays +- [\#321](https://github.com/arkworks-rs/algebra/pull/321) (`ark-ff`) Change bigint conversions to impl `From` instead of `Into`. +- [\#301](https://github.com/arkworks-rs/algebra/pull/301) (`ark-ec`) Add `GLVParameters` trait definition. +- [\#312](https://github.com/arkworks-rs/algebra/pull/312) (`ark-ec`) Add `is_in_correct_subgroup_assuming_on_curve` for all `SWModelParameters`. +- [\#348](https://github.com/arkworks-rs/algebra/pull/348) (`ark-ec`) Add `msm:{Fixed,Variable}Base:msm_checked_len`. +- [\#364](https://github.com/arkworks-rs/algebra/pull/364) (`ark-ec`) Add `ChunkedPippenger` to variable-base MSM. +- [\#371](https://github.com/arkworks-rs/algebra/pull/371) (`ark-serialize`) Add serialization impls for arrays ### Improvements -- [\#339](https://github.com/arkworks-rs/algebra/pull/339) (ark-ff) Remove duplicated code from `test_field` module and replace its usage with `ark-test-curves` crate. -- [\#352](https://github.com/arkworks-rs/algebra/pull/352) (ark-ff) Update `QuadExtField::sqrt` for better performance. -- [\#357](https://github.com/arkworks-rs/algebra/pull/357) (ark-poly) Speedup division by vanishing polynomials for dense polynomials. +- [\#339](https://github.com/arkworks-rs/algebra/pull/339) (`ark-ff`) Remove duplicated code from `test_field` module and replace its usage with `ark-test-curves` crate. +- [\#352](https://github.com/arkworks-rs/algebra/pull/352) (`ark-ff`) Update `QuadExtField::sqrt` for better performance. +- [\#357](https://github.com/arkworks-rs/algebra/pull/357) (`ark-poly`) Speedup division by vanishing polynomials for dense polynomials. ### Bugfixes -- [\#350](https://github.com/arkworks-rs/algebra/pull/350) (ark-serialize) Fix issues with hygiene whenever a non-standard `Result` type is in scope. -- [\#358](https://github.com/arkworks-rs/algebra/pull/358) (ark-ff) Fix the bug for `QuadExtField::sqrt` when `c1 = 0 && c0.legendre.is_qnr()` -- [\#366](https://github.com/arkworks-rs/algebra/pull/366) (ark-ff) Fix `norm()` for cubic extension field towers. +- [\#350](https://github.com/arkworks-rs/algebra/pull/350) (`ark-serialize`) Fix issues with hygiene whenever a non-standard `Result` type is in scope. +- [\#358](https://github.com/arkworks-rs/algebra/pull/358) (`ark-ff`) Fix the bug for `QuadExtField::sqrt` when `c1 = 0 && c0.legendre.is_qnr()` +- [\#366](https://github.com/arkworks-rs/algebra/pull/366) (`ark-ff`) Fix `norm()` for cubic extension field towers. ## v0.3.0 ### Breaking changes -- [\#285](https://github.com/arkworks-rs/algebra/pull/285) (ark-ec) Remove `ATE_LOOP_COUNT_IS_NEGATIVE` from BN curve parameter trait. -- [\#292](https://github.com/arkworks-rs/algebra/pull/292) (ark-ec) Remove `CycleEngine`. -- [\#293](https://github.com/arkworks-rs/algebra/pull/293) (ark-ff) Remove `ark_ff::test_rng`. +- [\#285](https://github.com/arkworks-rs/algebra/pull/285) (`ark-ec`) Remove `ATE_LOOP_COUNT_IS_NEGATIVE` from BN curve parameter trait. +- [\#292](https://github.com/arkworks-rs/algebra/pull/292) (`ark-ec`) Remove `CycleEngine`. +- [\#293](https://github.com/arkworks-rs/algebra/pull/293) (`ark-ff`) Remove `ark_ff::test_rng`. ### Features -- [\#230](https://github.com/arkworks-rs/algebra/pull/230) (ark-ec) Add `wnaf_mul` implementation for `ProjectiveCurve`. -- [\#245](https://github.com/arkworks-rs/algebra/pull/245) (ark-poly) Speedup the sequential and parallel radix-2 FFT and IFFT significantly by making the method in which it accesses roots more cache-friendly. -- [\#258](https://github.com/arkworks-rs/algebra/pull/258) (ark-poly) Add `Mul` implementation for `DensePolynomial`. -- [\#259](https://github.com/arkworks-rs/algebra/pull/259) (ark-poly) Add `Mul` implementation for `SparsePolynomial` and `Add>/Sub>` for `DensePolynomial`. -- [\#261](https://github.com/arkworks-rs/algebra/pull/261) (ark-ff) Add support for 448-bit integers and fields. -- [\#263](https://github.com/arkworks-rs/algebra/pull/263) (ark-ff) Add `From` implementations to fields. +- [\#230](https://github.com/arkworks-rs/algebra/pull/230) (`ark-ec`) Add `wnaf_mul` implementation for `ProjectiveCurve`. +- [\#245](https://github.com/arkworks-rs/algebra/pull/245) (`ark-poly`) Speedup the sequential and parallel radix-2 FFT and IFFT significantly by making the method in which it accesses roots more cache-friendly. +- [\#258](https://github.com/arkworks-rs/algebra/pull/258) (`ark-poly`) Add `Mul` implementation for `DensePolynomial`. +- [\#259](https://github.com/arkworks-rs/algebra/pull/259) (`ark-poly`) Add `Mul` implementation for `SparsePolynomial` and `Add>/Sub>` for `DensePolynomial`. +- [\#261](https://github.com/arkworks-rs/algebra/pull/261) (`ark-ff`) Add support for 448-bit integers and fields. +- [\#263](https://github.com/arkworks-rs/algebra/pull/263) (`ark-ff`) Add `From` implementations to fields. - [\#265](https://github.com/arkworks-rs/algebra/pull/265) (ark-serialize) Add hashing as an extension trait of `CanonicalSerialize`. -- [\#280](https://github.com/arkworks-rs/algebra/pull/280) (ark-ff) Add `Into` and `From` implementations to `BigInteger` and `PrimeField`. -- [\#289](https://github.com/arkworks-rs/algebra/pull/289) (ark-ec) Add `Sum` implementation for all `AffineCurve`. +- [\#280](https://github.com/arkworks-rs/algebra/pull/280) (`ark-ff`) Add `Into` and `From` implementations to `BigInteger` and `PrimeField`. +- [\#289](https://github.com/arkworks-rs/algebra/pull/289) (`ark-ec`) Add `Sum` implementation for all `AffineCurve`. ### Improvements -- [\#279](https://github.com/arkworks-rs/algebra/pull/279) (ark-ec) Parallelize miller loop operations for BLS12. +- [\#279](https://github.com/arkworks-rs/algebra/pull/279) (`ark-ec`) Parallelize miller loop operations for BLS12. ### Bugfixes -- [\#252](https://github.com/arkworks-rs/algebra/pull/252) (ark-ff) Fix prime field sampling when `REPR_SHIFT_BITS` is 64. -- [\#284](https://github.com/arkworks-rs/algebra/pull/284) (ark-poly-benches) Fix the panic `subgroup_fft_in_place` benchmark for MNT6-753's Fr. +- [\#252](https://github.com/arkworks-rs/algebra/pull/252) (`ark-ff`) Fix prime field sampling when `REPR_SHIFT_BITS` is 64. +- [\#284](https://github.com/arkworks-rs/algebra/pull/284) (`ark-poly-benches`) Fix the panic `subgroup_fft_in_place` benchmark for MNT6-753's Fr. ## v0.2.0 @@ -91,25 +92,25 @@ The main features of this release are: ### Breaking changes -- [\#20](https://github.com/arkworks-rs/algebra/pull/20) (ark-poly) Move univariate DensePolynomial and SparsePolynomial into a +- [\#20](https://github.com/arkworks-rs/algebra/pull/20) (`ark-poly`) Move univariate DensePolynomial and SparsePolynomial into a univariate sub-crate. Make this change by: find w/ regular expression `ark_poly::(Dense|Sparse)Polynomial`, and replace with `ark_poly::univariate::$1Polynomial`. -- [\#36](https://github.com/arkworks-rs/algebra/pull/36) (ark-ec) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`. -- [\#37](https://github.com/arkworks-rs/algebra/pull/37) (ark-poly) In the `Polynomial` trait, add `Hash` trait bound to `Point`. -- [\#38](https://github.com/arkworks-rs/algebra/pull/38) (ark-poly) Add `Add` and `Neg` trait bounds to `Polynomial`. -- [\#51](https://github.com/arkworks-rs/algebra/pull/51) (ark-ff) Removed `unitary_inverse` from `QuadExtField`. Make this change by +- [\#36](https://github.com/arkworks-rs/algebra/pull/36) (`ark-ec`) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`. +- [\#37](https://github.com/arkworks-rs/algebra/pull/37) (`ark-poly`) In the `Polynomial` trait, add `Hash` trait bound to `Point`. +- [\#38](https://github.com/arkworks-rs/algebra/pull/38) (`ark-poly`) Add `Add` and `Neg` trait bounds to `Polynomial`. +- [\#51](https://github.com/arkworks-rs/algebra/pull/51) (`ark-ff`) Removed `unitary_inverse` from `QuadExtField`. Make this change by replacing `x.unitary_inverse()` with `let mut tmp = x.clone(); tmp.conjugate()`. -- [\#53](https://github.com/arkworks-rs/algebra/pull/53) (ark-poly) Add `Zero` trait bound to `Polynomial`. -- [\#96](https://github.com/arkworks-rs/algebra/pull/96) (ark-ff) Make the `field_new` macro accept values in integer form, without requiring decomposition into limbs, and without requiring encoding in Montgomery form. -- [\#106](https://github.com/arkworks-rs/algebra/pull/106) (ark-ff, ark-ec) Add `Zeroize` trait bound to `Field, ProjectiveGroup, AffineGroup` traits. -- [\#108](https://github.com/arkworks-rs/algebra/pull/108) (ark-ff) Add `extension_degree()` method to `Field`. -- [\#110](https://github.com/arkworks-rs/algebra/pull/110) (ark-ec) Change the trait bound on the scalar for `mul`, from (essentially) `Into` to `AsRef<[u64]>`. -- [\#117](https://github.com/arkworks-rs/algebra/pull/117) (ark-poly) Make the univariate `SparsePolynomial` implement `Polynomial`. Make this change +- [\#53](https://github.com/arkworks-rs/algebra/pull/53) (`ark-poly`) Add `Zero` trait bound to `Polynomial`. +- [\#96](https://github.com/arkworks-rs/algebra/pull/96) (`ark-ff`) Make the `field_new` macro accept values in integer form, without requiring decomposition into limbs, and without requiring encoding in Montgomery form. +- [\#106](https://github.com/arkworks-rs/algebra/pull/106) (`ark-ff`, `ark-ec`) Add `Zeroize` trait bound to `Field, ProjectiveGroup, AffineGroup` traits. +- [\#108](https://github.com/arkworks-rs/algebra/pull/108) (`ark-ff`) Add `extension_degree()` method to `Field`. +- [\#110](https://github.com/arkworks-rs/algebra/pull/110) (`ark-ec`) Change the trait bound on the scalar for `mul`, from (essentially) `Into` to `AsRef<[u64]>`. +- [\#117](https://github.com/arkworks-rs/algebra/pull/117) (`ark-poly`) Make the univariate `SparsePolynomial` implement `Polynomial`. Make this change by replacing `sparse_poly.evaluate(pt)` to `sparse_poly.evaluate(&pt)`. -- [\#129](https://github.com/arkworks-rs/algebra/pull/129) (ark-ff) Move `ark_ff::{UniformRand, test_rng}` to `ark_std::{UniformRand, test_rng}`. +- [\#129](https://github.com/arkworks-rs/algebra/pull/129) (`ark-ff`) Move `ark_ff::{UniformRand, test_rng}` to `ark_std::{UniformRand, test_rng}`. Importing these from `ark-ff` is still possible, but is deprecated and will be removed in the following release. -- [\#144](https://github.com/arkworks-rs/algebra/pull/144) (ark-poly) Add `CanonicalSerialize` and `CanonicalDeserialize` trait bounds for `Polynomial`. -- [\#160](https://github.com/arkworks-rs/algebra/pull/160) (ark-serialize, ark-ff, ark-ec) +- [\#144](https://github.com/arkworks-rs/algebra/pull/144) (`ark-poly`) Add `CanonicalSerialize` and `CanonicalDeserialize` trait bounds for `Polynomial`. +- [\#160](https://github.com/arkworks-rs/algebra/pull/160) (`ark-serialize`, `ark-ff`, `ark-ec`) - Remove `ConstantSerializedSize`; users should use `serialized_size*` (see next). - Add `serialized_size_with_flags` method to `CanonicalSerializeWithFlags`. - Change `from_random_bytes_with_flags` to output `ark_serialize::Flags`. @@ -118,68 +119,68 @@ The main features of this release are: if the top bits of the `u8` value do *not* correspond to one of the possible outputs of `Flags::u8_bitmask`, then these methods output `None`, whereas before they output a default value. Downstream users other than `ark-curves` should not see breakage unless they rely on these methods/traits explicitly. -- [\#165](https://github.com/arkworks-rs/algebra/pull/165) (ark-ff) Add `from_base_field_elements` as a method to the `Field` trait. -- [\#166](https://github.com/arkworks-rs/algebra/pull/166) (ark-ff) Change `BigInt::{from_bytes, to_bits}` to `from_bytes_le, from_bytes_be, to_bits_le, to_bits_be`. +- [\#165](https://github.com/arkworks-rs/algebra/pull/165) (`ark-ff`) Add `from_base_field_elements` as a method to the `Field` trait. +- [\#166](https://github.com/arkworks-rs/algebra/pull/166) (`ark-ff`) Change `BigInt::{from_bytes, to_bits}` to `from_bytes_le, from_bytes_be, to_bits_le, to_bits_be`. ### Features -- [\#20](https://github.com/arkworks-rs/algebra/pull/20) (ark-poly) Add structs/traits for multivariate polynomials. -- [\#96](https://github.com/arkworks-rs/algebra/pull/96) (ark-ff) Make the `field_new` macro accept values in integer form, without requiring decomposition into limbs, and without requiring encoding in Montgomery form. -- [\#106](https://github.com/arkworks-rs/algebra/pull/106) (ark-ff, ark-ec) Add `Zeroize` trait bound to `Field, ProjectiveGroup, AffineGroup` traits. -- [\#117](https://github.com/arkworks-rs/algebra/pull/117) (ark-poly) Add operations to `SparsePolynomial`, so it implements `Polynomial`. -- [\#140](https://github.com/arkworks-rs/algebra/pull/140) (ark-poly) Add support for multilinear extensions in dense and sparse evaluation form. -- [\#164](https://github.com/arkworks-rs/algebra/pull/164) (ark-ff) Add methods `from_{be, le}_bytes_mod_order` to the `PrimeField` trait. -- [\#197](https://github.com/arkworks-rs/algebra/pull/197) (ark-test-curves) Add a BN384 curve with low two-adicity for mixed-radix testing. +- [\#20](https://github.com/arkworks-rs/algebra/pull/20) (`ark-poly`) Add structs/traits for multivariate polynomials. +- [\#96](https://github.com/arkworks-rs/algebra/pull/96) (`ark-ff`) Make the `field_new` macro accept values in integer form, without requiring decomposition into limbs, and without requiring encoding in Montgomery form. +- [\#106](https://github.com/arkworks-rs/algebra/pull/106) (`ark-ff`, `ark-ec`) Add `Zeroize` trait bound to `Field, ProjectiveGroup, AffineGroup` traits. +- [\#117](https://github.com/arkworks-rs/algebra/pull/117) (`ark-poly`) Add operations to `SparsePolynomial`, so it implements `Polynomial`. +- [\#140](https://github.com/arkworks-rs/algebra/pull/140) (`ark-poly`) Add support for multilinear extensions in dense and sparse evaluation form. +- [\#164](https://github.com/arkworks-rs/algebra/pull/164) (`ark-ff`) Add methods `from_{be, le}_bytes_mod_order` to the `PrimeField` trait. +- [\#197](https://github.com/arkworks-rs/algebra/pull/197) (`ark-test-curves`) Add a BN384 curve with low two-adicity for mixed-radix testing. ### Improvements -- [\#22](https://github.com/arkworks-rs/algebra/pull/22) (ark-ec) Speedup fixed-base MSMs. -- [\#28](https://github.com/arkworks-rs/algebra/pull/28) (ark-poly) Add `domain()` method on the `evaluations` struct. -- [\#31](https://github.com/arkworks-rs/algebra/pull/31) (ark-ec) Speedup point doubling on twisted edwards curves. -- [\#35](https://github.com/arkworks-rs/algebra/pull/35) (ark-ff) Implement `ToConstraintField` for `bool`. -- [\#48](https://github.com/arkworks-rs/algebra/pull/48) (ark-ff) Speedup `sqrt` on `QuadExtField`. -- [\#94](https://github.com/arkworks-rs/algebra/pull/94) (ark-ff) Implement `ToBytes` and `FromBytes` for `u128`. -- [\#99](https://github.com/arkworks-rs/algebra/pull/99) (ark-poly) Speedup `evaluate_all_lagrange_coefficients`. -- [\#100](https://github.com/arkworks-rs/algebra/pull/100) (ark-ff) Implement `batch_inverse_and_mul`. -- [\#101](https://github.com/arkworks-rs/algebra/pull/101) (ark-ff) Add `element(i: usize)` on the `Domain` trait. -- [\#107](https://github.com/arkworks-rs/algebra/pull/107) (ark-serialize) Add an impl of `CanonicalSerialize/Deserialize` for `BTreeSet`. -- [\#114](https://github.com/arkworks-rs/algebra/pull/114) (ark-poly) Significantly speedup and reduce memory usage of `DensePolynomial.evaluate`. -- [\#114](https://github.com/arkworks-rs/algebra/pull/114), #119 (ark-poly) Add infrastructure for benchmarking `DensePolynomial` operations. -- [\#115](https://github.com/arkworks-rs/algebra/pull/115) (ark-poly) Add parallel implementation to operations on `Evaluations`. -- [\#115](https://github.com/arkworks-rs/algebra/pull/115) (ark-ff) Add parallel implementation of `batch_inversion`. -- [\#122](https://github.com/arkworks-rs/algebra/pull/122) (ark-poly) Add infrastructure for benchmarking `FFT`s. -- [\#125](https://github.com/arkworks-rs/algebra/pull/125) (ark-poly) Add parallelization to applying coset shifts within `coset_fft`. -- [\#126](https://github.com/arkworks-rs/algebra/pull/126) (ark-ec) Use `ark_ff::batch_inversion` for point normalization. -- [\#131](https://github.com/arkworks-rs/algebra/pull/131), #137 (ark-ff) Speedup `sqrt` on fields when a square root exists. (And slows it down when doesn't exist.) -- [\#141](https://github.com/arkworks-rs/algebra/pull/141) (ark-ff) Add `Fp64`. -- [\#144](https://github.com/arkworks-rs/algebra/pull/144) (ark-poly) Add serialization for polynomials and evaluations. -- [\#149](https://github.com/arkworks-rs/algebra/pull/149) (ark-serialize) Add an impl of `CanonicalSerialize/Deserialize` for `String`. -- [\#153](https://github.com/arkworks-rs/algebra/pull/153) (ark-serialize) Add an impl of `CanonicalSerialize/Deserialize` for `Rc`. -- [\#157](https://github.com/arkworks-rs/algebra/pull/157) (ark-ec) Speed up `variable_base_msm` by not relying on unnecessary normalization. -- [\#158](https://github.com/arkworks-rs/algebra/pull/158) (ark-serialize) Add an impl of `CanonicalSerialize/Deserialize` for `()`. -- [\#166](https://github.com/arkworks-rs/algebra/pull/166) (ark-ff) Add a `to_bytes_be()` and `to_bytes_le` methods to `BigInt`. -- [\#169](https://github.com/arkworks-rs/algebra/pull/169) (ark-poly) Improve radix-2 FFTs by moving to a faster algorithm by Riad S. Wahby. -- [\#171](https://github.com/arkworks-rs/algebra/pull/171), #173, #176 (ark-poly) Apply significant further speedups to the new radix-2 FFT. -- [\#188](https://github.com/arkworks-rs/algebra/pull/188) (ark-ec) Make Short Weierstrass random sampling result in an element with unknown discrete log. -- [\#190](https://github.com/arkworks-rs/algebra/pull/190) (ark-ec) Add curve cycle trait and extended pairing cycle trait for all types of ec cycles. -- [\#201](https://github.com/arkworks-rs/algebra/pull/201) (ark-ec, ark-ff, ark-test-curves, ark-test-templates) Remove the dependency on `rand_xorshift`. -- [\#205](https://github.com/arkworks-rs/algebra/pull/205) (ark-ec, ark-ff) Unroll loops and conditionally use intrinsics in `biginteger` arithmetic, and reduce copies in `ff` and `ec` arithmetic. -- [\#207](https://github.com/arkworks-rs/algebra/pull/207) (ark-ff) Improve performance of extension fields when the non-residue is negative. (Improves fq2, fq12, and g2 speed on bls12 and bn curves.) -- [\#211](https://github.com/arkworks-rs/algebra/pull/211) (ark-ec) Improve performance of BLS12 final exponentiation. -- [\#214](https://github.com/arkworks-rs/algebra/pull/214) (ark-poly) Utilise a more efficient way of evaluating a polynomial at a single point. -- [\#242](https://github.com/arkworks-rs/algebra/pull/242), [\#244][https://github.com/arkworks-rs/algebra/pull/244] (ark-poly) Speedup the sequential radix-2 FFT significantly by making the method in which it accesses roots more cache-friendly. +- [\#22](https://github.com/arkworks-rs/algebra/pull/22) (`ark-ec`) Speedup fixed-base MSMs. +- [\#28](https://github.com/arkworks-rs/algebra/pull/28) (`ark-poly`) Add `domain()` method on the `evaluations` struct. +- [\#31](https://github.com/arkworks-rs/algebra/pull/31) (`ark-ec`) Speedup point doubling on twisted edwards curves. +- [\#35](https://github.com/arkworks-rs/algebra/pull/35) (`ark-ff`) Implement `ToConstraintField` for `bool`. +- [\#48](https://github.com/arkworks-rs/algebra/pull/48) (`ark-ff`) Speedup `sqrt` on `QuadExtField`. +- [\#94](https://github.com/arkworks-rs/algebra/pull/94) (`ark-ff`) Implement `ToBytes` and `FromBytes` for `u128`. +- [\#99](https://github.com/arkworks-rs/algebra/pull/99) (`ark-poly`) Speedup `evaluate_all_lagrange_coefficients`. +- [\#100](https://github.com/arkworks-rs/algebra/pull/100) (`ark-ff`) Implement `batch_inverse_and_mul`. +- [\#101](https://github.com/arkworks-rs/algebra/pull/101) (`ark-ff`) Add `element(i: usize)` on the `Domain` trait. +- [\#107](https://github.com/arkworks-rs/algebra/pull/107) (`ark-serialize`) Add an impl of `CanonicalSerialize/Deserialize` for `BTreeSet`. +- [\#114](https://github.com/arkworks-rs/algebra/pull/114) (`ark-poly`) Significantly speedup and reduce memory usage of `DensePolynomial.evaluate`. +- [\#114](https://github.com/arkworks-rs/algebra/pull/114), #119 (`ark-poly`) Add infrastructure for benchmarking `DensePolynomial` operations. +- [\#115](https://github.com/arkworks-rs/algebra/pull/115) (`ark-poly`) Add parallel implementation to operations on `Evaluations`. +- [\#115](https://github.com/arkworks-rs/algebra/pull/115) (`ark-ff`) Add parallel implementation of `batch_inversion`. +- [\#122](https://github.com/arkworks-rs/algebra/pull/122) (`ark-poly`) Add infrastructure for benchmarking `FFT`s. +- [\#125](https://github.com/arkworks-rs/algebra/pull/125) (`ark-poly`) Add parallelization to applying coset shifts within `coset_fft`. +- [\#126](https://github.com/arkworks-rs/algebra/pull/126) (`ark-ec`) Use `ark_ff::batch_inversion` for point normalization. +- [\#131](https://github.com/arkworks-rs/algebra/pull/131), #137 (`ark-ff`) Speedup `sqrt` on fields when a square root exists. (And slows it down when doesn't exist.) +- [\#141](https://github.com/arkworks-rs/algebra/pull/141) (`ark-ff`) Add `Fp64`. +- [\#144](https://github.com/arkworks-rs/algebra/pull/144) (`ark-poly`) Add serialization for polynomials and evaluations. +- [\#149](https://github.com/arkworks-rs/algebra/pull/149) (`ark-serialize`) Add an impl of `CanonicalSerialize/Deserialize` for `String`. +- [\#153](https://github.com/arkworks-rs/algebra/pull/153) (`ark-serialize`) Add an impl of `CanonicalSerialize/Deserialize` for `Rc`. +- [\#157](https://github.com/arkworks-rs/algebra/pull/157) (`ark-ec`) Speed up `variable_base_msm` by not relying on unnecessary normalization. +- [\#158](https://github.com/arkworks-rs/algebra/pull/158) (`ark-serialize`) Add an impl of `CanonicalSerialize/Deserialize` for `()`. +- [\#166](https://github.com/arkworks-rs/algebra/pull/166) (`ark-ff`) Add a `to_bytes_be()` and `to_bytes_le` methods to `BigInt`. +- [\#169](https://github.com/arkworks-rs/algebra/pull/169) (`ark-poly`) Improve radix-2 FFTs by moving to a faster algorithm by Riad S. Wahby. +- [\#171](https://github.com/arkworks-rs/algebra/pull/171), #173, #176 (`ark-poly`) Apply significant further speedups to the new radix-2 FFT. +- [\#188](https://github.com/arkworks-rs/algebra/pull/188) (`ark-ec`) Make Short Weierstrass random sampling result in an element with unknown discrete log. +- [\#190](https://github.com/arkworks-rs/algebra/pull/190) (`ark-ec`) Add curve cycle trait and extended pairing cycle trait for all types of ec cycles. +- [\#201](https://github.com/arkworks-rs/algebra/pull/201) (`ark-ec`, `ark-ff`, `ark-test-curves`, `ark-test-templates`) Remove the dependency on `rand_xorshift`. +- [\#205](https://github.com/arkworks-rs/algebra/pull/205) (`ark-ec`, `ark-ff`) Unroll loops and conditionally use intrinsics in `biginteger` arithmetic, and reduce copies in `ff` and `ec` arithmetic. +- [\#207](https://github.com/arkworks-rs/algebra/pull/207) (`ark-ff`) Improve performance of extension fields when the non-residue is negative. (Improves fq2, fq12, and g2 speed on bls12 and bn curves.) +- [\#211](https://github.com/arkworks-rs/algebra/pull/211) (`ark-ec`) Improve performance of BLS12 final exponentiation. +- [\#214](https://github.com/arkworks-rs/algebra/pull/214) (`ark-poly`) Utilise a more efficient way of evaluating a polynomial at a single point. +- [\#242](https://github.com/arkworks-rs/algebra/pull/242), [\#244][https://github.com/arkworks-rs/algebra/pull/244] (`ark-poly`) Speedup the sequential radix-2 FFT significantly by making the method in which it accesses roots more cache-friendly. ### Bugfixes -- [\#36](https://github.com/arkworks-rs/algebra/pull/36) (ark-ec) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`. -- [\#107](https://github.com/arkworks-rs/algebra/pull/107) (ark-serialize) Fix handling of `(de)serialize_uncompressed/unchecked` in various impls of `CanonicalSerialize/Deserialize`. -- [\#112](https://github.com/arkworks-rs/algebra/pull/112) (ark-serialize) Make `bool`s checked serialization methods non-malleable. -- [\#119](https://github.com/arkworks-rs/algebra/pull/119) (ark-poly) Fix bugs in degree calculation if adding/subtracting same degree polynomials +- [\#36](https://github.com/arkworks-rs/algebra/pull/36) (`ark-ec`) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`. +- [\#107](https://github.com/arkworks-rs/algebra/pull/107) (`ark-serialize`) Fix handling of `(de)serialize_uncompressed/unchecked` in various impls of `CanonicalSerialize/Deserialize`. +- [\#112](https://github.com/arkworks-rs/algebra/pull/112) (`ark-serialize`) Make `bool`s checked serialization methods non-malleable. +- [\#119](https://github.com/arkworks-rs/algebra/pull/119) (`ark-poly`) Fix bugs in degree calculation if adding/subtracting same degree polynomials whose leading coefficients cancel. -- [\#160](https://github.com/arkworks-rs/algebra/pull/160) (ark-serialize, ark-ff, ark-ec) Support serializing when `MODULUS_BITS + FLAG_BITS` is greater than the multiple of 8 just greater than `MODULUS_BITS`, which is the case for the Pasta curves (fixes #47). -- [\#165](https://github.com/arkworks-rs/algebra/pull/165) (ark-ff) Enforce in the type system that an extension fields `BaseField` extends from the correct `BasePrimeField`. +- [\#160](https://github.com/arkworks-rs/algebra/pull/160) (`ark-serialize`, `ark-ff`, `ark-ec`) Support serializing when `MODULUS_BITS + FLAG_BITS` is greater than the multiple of 8 just greater than `MODULUS_BITS`, which is the case for the Pasta curves (fixes #47). +- [\#165](https://github.com/arkworks-rs/algebra/pull/165) (`ark-ff`) Enforce in the type system that an extension fields `BaseField` extends from the correct `BasePrimeField`. - [\#184](https://github.com/arkworks-rs/algebra/pull/184) Compile with `panic='abort'` in release mode, for safety of the library across FFI boundaries. - [\#192](https://github.com/arkworks-rs/algebra/pull/192) Fix a bug in the assembly backend for finite field arithmetic. -- [\#217](https://github.com/arkworks-rs/algebra/pull/217) (ark-ec) Fix the definition of `PairingFriendlyCycle` introduced in #190. +- [\#217](https://github.com/arkworks-rs/algebra/pull/217) (`ark-ec`) Fix the definition of `PairingFriendlyCycle` introduced in #190. ## v0.1.0 (Initial release of arkworks/algebra) From cc8cb91a9c1dbe3c502637cb2335656e3dc3b4c8 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 20:47:41 -0800 Subject: [PATCH 11/32] Fix assembly --- ff/src/fields/models/fp/montgomery_backend.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 002ccf70e..21b3edc0e 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -92,7 +92,7 @@ pub trait MontConfig: 'static + Sync + Send + Sized { 4 => ark_ff_asm::x86_64_asm_mul!(4, (a.0).0, (b.0).0), 5 => ark_ff_asm::x86_64_asm_mul!(5, (a.0).0, (b.0).0), 6 => ark_ff_asm::x86_64_asm_mul!(6, (a.0).0, (b.0).0), - } + }; } else { let mut r = [0u64; N]; let mut carry1 = 0u64; @@ -140,9 +140,15 @@ pub trait MontConfig: 'static + Sync + Send + Sized { let no_carry: bool = !(first_bit_set || all_bits_set); if N <= 6 && no_carry { - ark_ff_asm::x86_64_asm_square!(N, (a.0).0); + match N { + 2 => ark_ff_asm::x86_64_asm_square!(2, (a.0).0), + 3 => ark_ff_asm::x86_64_asm_square!(3, (a.0).0), + 4 => ark_ff_asm::x86_64_asm_square!(4, (a.0).0), + 5 => ark_ff_asm::x86_64_asm_square!(5, (a.0).0), + 6 => ark_ff_asm::x86_64_asm_square!(6, (a.0).0), + }; a.subtract_modulus(); - return a; + return; } } let mut r = crate::const_helpers::MulBuffer::::zeroed(); From 266b37eed669215dc7f5936e4377238079a2d457 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 20:55:16 -0800 Subject: [PATCH 12/32] Fix indentation --- CHANGELOG.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f5cc5bbf..2bf18c5eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,18 +13,18 @@ - [\#348](https://github.com/arkworks-rs/algebra/pull/348) (`ark-ec`) Rename `msm:{Fixed,Variable}BaseMSM:multi_scalar_mul` to `msm:{Fixed,Variable}:msm` to avoid redundancy. - [\#359](https://github.com/arkworks-rs/algebra/pull/359) (ark-test-templates) Simplify the field and curve test macros. - [\#365](https://github.com/arkworks-rs/algebra/pull/365) (`ark-ec`) - - Move `COFACTOR`, `COFACTOR_INV`, and `is_in_correct_subgroup_assuming_on_curve()` from `{SW,TE}ModelParameters` to `ModelParameters`. - - Add `mul_bits()` to `AffineCurve` and provide a default implementation of `mul()` using this. - - Remove duplicate function `scale_by_cofactor()` from `short_weierstrass_jacobian::GroupAffine` and `twisted_edwards_extended::GroupAffine` + - Move `COFACTOR`, `COFACTOR_INV`, and `is_in_correct_subgroup_assuming_on_curve()` from `{SW,TE}ModelParameters` to `ModelParameters`. + - Add `mul_bits()` to `AffineCurve` and provide a default implementation of `mul()` using this. + - Remove duplicate function `scale_by_cofactor()` from `short_weierstrass_jacobian::GroupAffine` and `twisted_edwards_extended::GroupAffine` - [\#370](https://github.com/arkworks-rs/algebra/pull/370) (all) Set the minimum `rust-version = 1.56` in the manifests of all crates. - [\#379](https://github.com/arkworks-rs/algebra/pull/379) (`ark-ff`) Refactor `Field` implementation and `PrimeField` trait: - - Switches from hardcoded `FpXYZ` to `Fp` based on `const` generics. - - Moves Montgomery arithmetic to an optional backend. - - Rename `field_new` macros to `MontFp`, `QuadExt` and `CubicExt` macros. - - Introduce `const fn`s for generating many constants. - - Add default associated constants to reduce boilerplate. - - Rename `Fp*Parameters` to `Fp*Config`. - - Adds `From`, `From`, and `From` `impl`s for `BigInt`. + - Switches from hardcoded `FpXYZ` to `Fp` based on `const` generics. + - Moves Montgomery arithmetic to an optional backend. + - Rename `field_new` macros to `MontFp`, `QuadExt` and `CubicExt` macros. + - Introduce `const fn`s for generating many constants. + - Add default associated constants to reduce boilerplate. + - Rename `Fp*Parameters` to `Fp*Config`. + - Adds `From`, `From`, and `From` `impl`s for `BigInt`. ### Features @@ -111,11 +111,11 @@ The main features of this release are: Importing these from `ark-ff` is still possible, but is deprecated and will be removed in the following release. - [\#144](https://github.com/arkworks-rs/algebra/pull/144) (`ark-poly`) Add `CanonicalSerialize` and `CanonicalDeserialize` trait bounds for `Polynomial`. - [\#160](https://github.com/arkworks-rs/algebra/pull/160) (`ark-serialize`, `ark-ff`, `ark-ec`) - - Remove `ConstantSerializedSize`; users should use `serialized_size*` (see next). - - Add `serialized_size_with_flags` method to `CanonicalSerializeWithFlags`. - - Change `from_random_bytes_with_flags` to output `ark_serialize::Flags`. - - Change signatures of `Flags::from_u8*` to output `Option`. - - Change `Flags::from_u8*` to be more strict about the inputs it accepts: + - Remove `ConstantSerializedSize`; users should use `serialized_size*` (see next). + - Add `serialized_size_with_flags` method to `CanonicalSerializeWithFlags`. + - Change `from_random_bytes_with_flags` to output `ark_serialize::Flags`. + - Change signatures of `Flags::from_u8*` to output `Option`. + - Change `Flags::from_u8*` to be more strict about the inputs it accepts: if the top bits of the `u8` value do *not* correspond to one of the possible outputs of `Flags::u8_bitmask`, then these methods output `None`, whereas before they output a default value. Downstream users other than `ark-curves` should not see breakage unless they rely on these methods/traits explicitly. From ad1bca71d0162e4b2a4f2f761cc79e582f602e9e Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 20:57:18 -0800 Subject: [PATCH 13/32] Fix assembly --- ff/src/fields/models/fp/montgomery_backend.rs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 21b3edc0e..e4422fb08 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -86,12 +86,13 @@ pub trait MontConfig: 'static + Sync + Send + Sized { #[cfg(use_asm)] #[allow(unsafe_code, unused_mut)] // Tentatively avoid using assembly for `N == 1`. + #[rustfmt::skip] match N { - 2 => ark_ff_asm::x86_64_asm_mul!(2, (a.0).0, (b.0).0), - 3 => ark_ff_asm::x86_64_asm_mul!(3, (a.0).0, (b.0).0), - 4 => ark_ff_asm::x86_64_asm_mul!(4, (a.0).0, (b.0).0), - 5 => ark_ff_asm::x86_64_asm_mul!(5, (a.0).0, (b.0).0), - 6 => ark_ff_asm::x86_64_asm_mul!(6, (a.0).0, (b.0).0), + 2 => { ark_ff_asm::x86_64_asm_mul!(2, (a.0).0, (b.0).0); }, + 3 => { ark_ff_asm::x86_64_asm_mul!(3, (a.0).0, (b.0).0); }, + 4 => { ark_ff_asm::x86_64_asm_mul!(4, (a.0).0, (b.0).0); }, + 5 => { ark_ff_asm::x86_64_asm_mul!(5, (a.0).0, (b.0).0); }, + 6 => { ark_ff_asm::x86_64_asm_mul!(6, (a.0).0, (b.0).0); }, }; } else { let mut r = [0u64; N]; @@ -140,12 +141,13 @@ pub trait MontConfig: 'static + Sync + Send + Sized { let no_carry: bool = !(first_bit_set || all_bits_set); if N <= 6 && no_carry { + #[rustfmt::skip] match N { - 2 => ark_ff_asm::x86_64_asm_square!(2, (a.0).0), - 3 => ark_ff_asm::x86_64_asm_square!(3, (a.0).0), - 4 => ark_ff_asm::x86_64_asm_square!(4, (a.0).0), - 5 => ark_ff_asm::x86_64_asm_square!(5, (a.0).0), - 6 => ark_ff_asm::x86_64_asm_square!(6, (a.0).0), + 2 => { ark_ff_asm::x86_64_asm_square!(2, (a.0).0); }, + 3 => { ark_ff_asm::x86_64_asm_square!(3, (a.0).0); }, + 4 => { ark_ff_asm::x86_64_asm_square!(4, (a.0).0); }, + 5 => { ark_ff_asm::x86_64_asm_square!(5, (a.0).0); }, + 6 => { ark_ff_asm::x86_64_asm_square!(6, (a.0).0); }, }; a.subtract_modulus(); return; From 23868df97cb37a16b4b5f40cb1eef72c05bba206 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 21:00:14 -0800 Subject: [PATCH 14/32] Fix README lint --- ff/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ff/README.md b/ff/README.md index 3b8abad72..ccc5133cc 100644 --- a/ff/README.md +++ b/ff/README.md @@ -24,11 +24,11 @@ The available field traits are: The models implemented are: - [`Quadratic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs) - - [`QuadExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L140) - Struct representing a quadratic extension field, in this case holding two base field elements - - [`QuadExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Quadratic Extension Field + - [`QuadExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L140) - Struct representing a quadratic extension field, in this case holding two base field elements + - [`QuadExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Quadratic Extension Field - [`Cubic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs) - - [`CubicExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L72) - Struct representing a cubic extension field, holds three base field elements - - [`CubicExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field + - [`CubicExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L72) - Struct representing a cubic extension field, holds three base field elements + - [`CubicExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field The above two models serve as abstractions for constructing the extension fields `Fp^m` directly (i.e. `m` equal 2 or 3) or for creating extension towers to arrive at higher `m`. The latter is done by applying the extensions iteratively, e.g. cubic extension over a quadratic extension field. From 7a76bd89e3fe3c71197c778e07cfc689d868e375 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 11 Jan 2022 21:29:01 -0800 Subject: [PATCH 15/32] Fix import --- ff-asm/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ff-asm/src/lib.rs b/ff-asm/src/lib.rs index 9a24909b6..30a9334af 100644 --- a/ff-asm/src/lib.rs +++ b/ff-asm/src/lib.rs @@ -298,9 +298,9 @@ fn generate_impl(num_limbs: usize, is_mul: bool) -> String { if is_mul { ctx.add_declaration("b", "r", "b"); } - ctx.add_declaration("modulus", "r", "&P::MODULUS.0"); + ctx.add_declaration("modulus", "r", "&Self::MODULUS.0"); ctx.add_declaration("0", "i", "0u64"); - ctx.add_declaration("mod_prime", "i", "P::INV"); + ctx.add_declaration("mod_prime", "i", "Self::INV"); if num_limbs > MAX_REGS { ctx.add_buffer(2 * num_limbs); From 9ce6ce91727d5ae7fe202c9ce0256072c120ac91 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 10:13:50 -0800 Subject: [PATCH 16/32] Fix match statement --- ff/src/fields/models/fp/montgomery_backend.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index e4422fb08..9fd058121 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -93,6 +93,7 @@ pub trait MontConfig: 'static + Sync + Send + Sized { 4 => { ark_ff_asm::x86_64_asm_mul!(4, (a.0).0, (b.0).0); }, 5 => { ark_ff_asm::x86_64_asm_mul!(5, (a.0).0, (b.0).0); }, 6 => { ark_ff_asm::x86_64_asm_mul!(6, (a.0).0, (b.0).0); }, + _ => ark_std::hint::unreachable_unchecked(), }; } else { let mut r = [0u64; N]; @@ -148,6 +149,7 @@ pub trait MontConfig: 'static + Sync + Send + Sized { 4 => { ark_ff_asm::x86_64_asm_square!(4, (a.0).0); }, 5 => { ark_ff_asm::x86_64_asm_square!(5, (a.0).0); }, 6 => { ark_ff_asm::x86_64_asm_square!(6, (a.0).0); }, + _ => ark_std::hint::unreachable_unchecked(), }; a.subtract_modulus(); return; From b5f38871453d11a0b7392264bf704bfc3359d465 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 10:29:30 -0800 Subject: [PATCH 17/32] Fix match statement, and move no_carry check to constant --- ff/src/fields/models/fp/montgomery_backend.rs | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 9fd058121..d06384aa8 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -23,6 +23,15 @@ pub trait MontConfig: 'static + Sync + Send + Sized { /// `Self::MODULUS - 1`. const GENERATOR: Fp, N>; + /// Can we use the no-carry optimization for multiplication and squaring + /// outlined [here](https://hackmd.io/@zkteam/modular_multiplication)? + /// + /// This optimization applies if + /// `Self::MODULUS` has (a) a non-zero MSB, and (b) at least one + /// zero bit in the rest of the modulus. + #[doc(hidden)] + const CAN_USE_NO_CARRY_OPT: bool = can_use_no_carry_optimization(&Self::MODULUS); + /// 2^s root of unity computed by GENERATOR^t const TWO_ADIC_ROOT_OF_UNITY: Fp, N>; @@ -66,22 +75,13 @@ pub trait MontConfig: 'static + Sync + Send + Sized { /// reduction for efficient implementation. It also additionally /// uses the "no-carry optimization" outlined /// [here](https://hackmd.io/@zkteam/modular_multiplication) if - /// `P::MODULUS` has (a) a non-zero MSB, and (b) at least one + /// `Self::MODULUS` has (a) a non-zero MSB, and (b) at least one /// zero bit in the rest of the modulus. #[inline] #[ark_ff_asm::unroll_for_loops] fn mul_assign(a: &mut Fp, N>, b: &Fp, N>) { - // Checking the modulus at compile time - let first_bit_set = Self::MODULUS.0[N - 1] >> 63 != 0; - // N can be 1, hence we can run into a case with an unused mut. - let mut all_bits_set = Self::MODULUS.0[N - 1] == !0 - (1 << 63); - for i in 1..N { - all_bits_set &= Self::MODULUS.0[N - i - 1] == !0u64; - } - let no_carry = !(first_bit_set || all_bits_set); - // No-carry optimisation applied to CIOS - if no_carry { + if Self::CAN_USE_NO_CARRY_OPT { if N <= 6 && N > 1 && cfg!(use_asm) { #[cfg(use_asm)] #[allow(unsafe_code, unused_mut)] @@ -93,7 +93,7 @@ pub trait MontConfig: 'static + Sync + Send + Sized { 4 => { ark_ff_asm::x86_64_asm_mul!(4, (a.0).0, (b.0).0); }, 5 => { ark_ff_asm::x86_64_asm_mul!(5, (a.0).0, (b.0).0); }, 6 => { ark_ff_asm::x86_64_asm_mul!(6, (a.0).0, (b.0).0); }, - _ => ark_std::hint::unreachable_unchecked(), + _ => unsafe { ark_std::hint::unreachable_unchecked() }, }; } else { let mut r = [0u64; N]; @@ -134,14 +134,7 @@ pub trait MontConfig: 'static + Sync + Send + Sized { #[allow(unsafe_code, unused_mut)] { // Checking the modulus at compile time - let first_bit_set = Self::MODULUS.0[N - 1] >> 63 != 0; - let mut all_bits_set = Self::MODULUS.0[N - 1] == !0 - (1 << 63); - for i in 1..N { - all_bits_set &= Self::MODULUS.0[N - i - 1] == core::u64::MAX; - } - let no_carry: bool = !(first_bit_set || all_bits_set); - - if N <= 6 && no_carry { + if N <= 6 && Self::CAN_USE_NO_CARRY_OPT { #[rustfmt::skip] match N { 2 => { ark_ff_asm::x86_64_asm_square!(2, (a.0).0); }, @@ -149,7 +142,7 @@ pub trait MontConfig: 'static + Sync + Send + Sized { 4 => { ark_ff_asm::x86_64_asm_square!(4, (a.0).0); }, 5 => { ark_ff_asm::x86_64_asm_square!(5, (a.0).0); }, 6 => { ark_ff_asm::x86_64_asm_square!(6, (a.0).0); }, - _ => ark_std::hint::unreachable_unchecked(), + _ => unsafe { ark_std::hint::unreachable_unchecked() }, }; a.subtract_modulus(); return; @@ -304,6 +297,18 @@ pub const fn inv(m: BigInt) -> u64 { inv.wrapping_neg() } +#[inline] +pub const fn can_use_no_carry_optimization(modulus: &BigInt) -> bool { + // Checking the modulus at compile time + let first_bit_set = modulus.0[N - 1] >> 63 != 0; + // N can be 1, hence we can run into a case with an unused mut. + let mut all_bits_set = modulus.0[N - 1] == !0 - (1 << 63); + crate::const_for!((i in 1..N) { + all_bits_set &= modulus.0[N - i - 1] == !0u64; + }); + !(first_bit_set || all_bits_set) +} + #[macro_export] macro_rules! MontFp { ($name:ident, $c0:expr) => {{ From 923bb3f62ee45cf6337a335eaf7eda6665530391 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 11:41:14 -0800 Subject: [PATCH 18/32] Introduce `BigInt` macro --- ff/src/biginteger/mod.rs | 19 ++++++++++++++++++ ff/src/fields/models/fp/montgomery_backend.rs | 5 +++-- test-curves/src/bls12_381/fq.rs | 15 ++------------ test-curves/src/bls12_381/fr.rs | 20 +++++++------------ test-curves/src/bn384_small_two_adicity/fq.rs | 16 ++------------- test-curves/src/bn384_small_two_adicity/fr.rs | 13 ++---------- test-curves/src/mnt4_753/fq.rs | 17 ++-------------- test-curves/src/mnt4_753/fr.rs | 17 ++-------------- 8 files changed, 39 insertions(+), 83 deletions(-) diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index c78f94e5d..85986d7a9 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -34,7 +34,26 @@ impl BigInt { pub const fn new(value: [u64; N]) -> Self { Self(value) } + + pub const fn zero() -> Self { + Self([0u64; N]) + } +} + +#[macro_export] +macro_rules! BigInt { + ($c0:expr) => {{ + let (is_positive, limbs) = $crate::ark_ff_macros::to_sign_and_limbs!($c0); + assert!(is_positive); + let mut integer = $crate::BigInt::zero(); + assert!(integer.0.len() >= limbs.len()); + crate::const_for!((i in 0..(limbs.len())) { + integer.0[i] = limbs[i]; + }); + integer + }}; } + #[doc(hidden)] macro_rules! const_modulo { ($a:ident, $divisor:ident) => {{ diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index d06384aa8..d13432f39 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -3,7 +3,8 @@ use ark_std::{marker::PhantomData, Zero}; use super::{Fp, FpConfig}; use crate::{biginteger::arithmetic as fa, BigInt, BigInteger, FftConfig}; -/// A trait that defines parameters for a prime field. +/// A trait that specifies the constants and arithmetic procedures +/// for Montgomery arithmetic over the prime field defined by `MODULUS`. pub trait MontConfig: 'static + Sync + Send + Sized { /// The modulus of the field. const MODULUS: BigInt; @@ -314,7 +315,7 @@ macro_rules! MontFp { ($name:ident, $c0:expr) => {{ use $crate::PrimeField; let (is_positive, limbs) = $crate::ark_ff_macros::to_sign_and_limbs!($c0); - <$name>::const_from_str(&limbs, is_positive, $name::R2, $name::MODULUS) + $crate::Fp::const_from_str(&limbs, is_positive, $name::R2, $name::MODULUS) }}; } diff --git a/test-curves/src/bls12_381/fq.rs b/test-curves/src/bls12_381/fq.rs index 1790cf7e6..57750d749 100644 --- a/test-curves/src/bls12_381/fq.rs +++ b/test-curves/src/bls12_381/fq.rs @@ -1,8 +1,7 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger384 as BigInteger, fields::{Fp384, MontBackend}, - MontFp, + BigInt, MontFp, }; pub struct FqConfig; @@ -10,21 +9,11 @@ pub type Fq = Fp384>; impl ark_ff::MontConfig<6> for FqConfig { /// MODULUS = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 - #[rustfmt::skip] - const MODULUS: BigInteger = BigInt::<6>([ - 0xb9feffffffffaaab, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ]); + const MODULUS: BigInteger = BigInt!("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"); /// GENERATOR = 2 - #[rustfmt::skip] const GENERATOR: Fq = ark_ff::MontFp!(Fq, "2"); - #[rustfmt::skip] const TWO_ADIC_ROOT_OF_UNITY: Fq = MontFp!(Fq, "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786"); } diff --git a/test-curves/src/bls12_381/fr.rs b/test-curves/src/bls12_381/fr.rs index a80bb24c0..3d7d0d43c 100644 --- a/test-curves/src/bls12_381/fr.rs +++ b/test-curves/src/bls12_381/fr.rs @@ -1,7 +1,7 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger256 as BigInteger, fields::{Fp256, MontBackend, MontConfig, MontFp}, + BigInt, }; pub struct FrConfig; @@ -9,20 +9,14 @@ pub type Fr = Fp256>; impl MontConfig<4> for FrConfig { /// MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513 - #[rustfmt::skip] - const MODULUS: BigInteger = BigInt::<4>([ - 0xffffffff00000001, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ]); + const MODULUS: BigInteger = + BigInt!("52435875175126190479447740508185965837690552500527637822603658699938581184513"); /// GENERATOR = 7 - /// Encoded in Montgomery form, so the value here is - /// 7 * R % q = 24006497034320510773280787438025867407531605151569380937148207556313189711857 - #[rustfmt::skip] const GENERATOR: Fr = MontFp!(Fr, "7"); - #[rustfmt::skip] - const TWO_ADIC_ROOT_OF_UNITY: Fr = MontFp!(Fr, "10238227357739495823651030575849232062558860180284477541189508159991286009131"); + const TWO_ADIC_ROOT_OF_UNITY: Fr = MontFp!( + Fr, + "10238227357739495823651030575849232062558860180284477541189508159991286009131" + ); } diff --git a/test-curves/src/bn384_small_two_adicity/fq.rs b/test-curves/src/bn384_small_two_adicity/fq.rs index 7349fe4f1..197ade496 100644 --- a/test-curves/src/bn384_small_two_adicity/fq.rs +++ b/test-curves/src/bn384_small_two_adicity/fq.rs @@ -1,8 +1,7 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger384 as BigInteger, fields::{Fp384, MontBackend}, - MontFp, + BigInt, MontFp, }; pub struct FqConfig; @@ -10,20 +9,11 @@ pub type Fq = Fp384>; impl ark_ff::MontConfig<6> for FqConfig { /// MODULUS = 5945877603251831796258517492029536515488649313567122628447476625319762940580461319088175968449723373773214087057409 - const MODULUS: BigInteger = BigInt::<6>([ - 2340831834029625345u64, - 7249631296803227205u64, - 16747242270977641452u64, - 15205557732015452966u64, - 15076886007691743306u64, - 2783667458303802095u64, - ]); + const MODULUS: BigInteger = BigInt!("5945877603251831796258517492029536515488649313567122628447476625319762940580461319088175968449723373773214087057409"); /// GENERATOR = 7 - #[rustfmt::skip] const GENERATOR: Fq = ark_ff::MontFp!(Fq, "7"); - #[rustfmt::skip] const TWO_ADIC_ROOT_OF_UNITY: Fq = MontFp!(Fq, "4563474743154071393992783416618298946273483760389666561454590580850277486490043009369759159902206584965352075028870"); const SMALL_SUBGROUP_BASE: Option = Some(3); @@ -31,8 +21,6 @@ impl ark_ff::MontConfig<6> for FqConfig { // LARGE_SUBGROUP_ROOT_OF_UNITY = GENERATOR ^ (t * 3 ^ 2) = // 203100967768496856767841701771526315192814992286543641883928020883407386213917566206874176054653008117753458021037 - // I.e., write LARGE_SUBGROUP_ROOT_OF_UNITY * R - // = 81125788721017958531970004711554176763707237538772656640376499392204495132484005854811881368159718832226698073199 const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(MontFp!(Fq, "683178638573601328773157856456805978879544571597638024782973348263890473503149166479735097908137632291366958273030")); } diff --git a/test-curves/src/bn384_small_two_adicity/fr.rs b/test-curves/src/bn384_small_two_adicity/fr.rs index a849c920d..dca388ecc 100644 --- a/test-curves/src/bn384_small_two_adicity/fr.rs +++ b/test-curves/src/bn384_small_two_adicity/fr.rs @@ -1,7 +1,7 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger384 as BigInteger, fields::{Fp384, MontBackend}, + BigInt, }; pub struct FrConfig; @@ -9,22 +9,13 @@ pub type Fr = Fp384>; impl ark_ff::MontConfig<6> for FrConfig { /// MODULUS = 5945877603251831796258517492029536515488649313567122628445038208291596545947608789992834434053176523624102324539393 - const MODULUS: BigInteger = BigInt::<6>([ - 17382266338285916161, - 13339389119208890949, - 9581378667081472421, - 15205557732015452966, - 15076886007691743306, - 2783667458303802095, - ]); + const MODULUS: BigInteger = BigInt!("5945877603251831796258517492029536515488649313567122628445038208291596545947608789992834434053176523624102324539393"); /// GENERATOR = 5 - #[rustfmt::skip] const GENERATOR: Fr = ark_ff::MontFp!(Fr, "5"); /// TWO_ADIC_ROOT_OF_UNITY = GENERATOR ^ T = /// 1685271986666084262778868986067286870708440243287855288358961780551611799713704250599068248127477556627411635786779 - #[rustfmt::skip] const TWO_ADIC_ROOT_OF_UNITY: Fr = ark_ff::MontFp!(Fr, "1685271986666084262778868986067286870708440243287855288358961780551611799713704250599068248127477556627411635786779"); const SMALL_SUBGROUP_BASE: Option = Some(3); diff --git a/test-curves/src/mnt4_753/fq.rs b/test-curves/src/mnt4_753/fq.rs index 61ae34c3f..05e659ba1 100644 --- a/test-curves/src/mnt4_753/fq.rs +++ b/test-curves/src/mnt4_753/fq.rs @@ -1,7 +1,7 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger768 as BigInteger, fields::{Fp768, MontBackend, MontConfig}, + BigInt, }; pub type Fq = Fp768>; @@ -9,20 +9,7 @@ pub struct FqConfig; impl MontConfig<12> for FqConfig { /// MODULUS = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601 - const MODULUS: BigInteger = BigInt::<12>([ - 0x5e9063de245e8001, - 0xe39d54522cdd119f, - 0x638810719ac425f0, - 0x685acce9767254a4, - 0xb80f0da5cb537e38, - 0xb117e776f218059d, - 0x99d124d9a15af79d, - 0x7fdb925e8a0ed8d, - 0x5eb7e8f96c97d873, - 0xb7f997505b8fafed, - 0x10229022eee2cdad, - 0x1c4c62d92c411, - ]); + const MODULUS: BigInteger = BigInt!("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601"); const GENERATOR: Fq = ark_ff::MontFp!(Fq, "17"); diff --git a/test-curves/src/mnt4_753/fr.rs b/test-curves/src/mnt4_753/fr.rs index ebbd6c16d..664658a17 100644 --- a/test-curves/src/mnt4_753/fr.rs +++ b/test-curves/src/mnt4_753/fr.rs @@ -1,7 +1,7 @@ use ark_ff::{ - biginteger::BigInt, biginteger::BigInteger768 as BigInteger, fields::{Fp768, MontBackend}, + BigInt, }; pub type Fr = Fp768>; @@ -9,20 +9,7 @@ pub struct FrConfig; impl ark_ff::MontConfig<12> for FrConfig { /// MODULUS = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001 - const MODULUS: BigInteger = BigInt::<12>([ - 0xd90776e240000001, - 0x4ea099170fa13a4f, - 0xd6c381bc3f005797, - 0xb9dff97634993aa4, - 0x3eebca9429212636, - 0xb26c5c28c859a99b, - 0x99d124d9a15af79d, - 0x7fdb925e8a0ed8d, - 0x5eb7e8f96c97d873, - 0xb7f997505b8fafed, - 0x10229022eee2cdad, - 0x1c4c62d92c411, - ]); + const MODULUS: BigInteger = BigInt!("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001"); const GENERATOR: Fr = ark_ff::MontFp!(Fr, "17"); From 61fcbaf3f4c60994d399726c01ce0fed525900fb Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 11:42:04 -0800 Subject: [PATCH 19/32] Fix `CAPACITY` bug --- ff/src/to_field_vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ff/src/to_field_vec.rs b/ff/src/to_field_vec.rs index ca921b21f..7cce46dfb 100644 --- a/ff/src/to_field_vec.rs +++ b/ff/src/to_field_vec.rs @@ -42,7 +42,7 @@ impl ToConstraintField for () { impl ToConstraintField for [u8] { #[inline] fn to_field_elements(&self) -> Option> { - let max_size = (ConstraintF::MODULUS_BIT_SIZE / 8) as usize; + let max_size = ((ConstraintF::MODULUS_BIT_SIZE - 1) / 8) as usize; let bigint_size = ::BigInt::NUM_LIMBS * 8; let fes = self .chunks(max_size) From 2e083db1582e6f236219959f7379e1acfff7d697 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 11:52:10 -0800 Subject: [PATCH 20/32] Make `QuadExt` and `CubicExt` macros more succinct --- ff/src/fields/models/cubic_extension.rs | 4 +-- ff/src/fields/models/quadratic_extension.rs | 4 +-- test-curves/src/bls12_381/fq2.rs | 6 ++-- test-curves/src/bls12_381/fq6.rs | 34 +++++++++------------ test-curves/src/mnt6_753/fq3.rs | 1 - 5 files changed, 21 insertions(+), 28 deletions(-) diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index be84c1225..796c0460b 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -85,8 +85,8 @@ pub struct CubicExtField { /// Construct a `CubicExtension` element from elements of the base field. #[macro_export] macro_rules! CubicExt { - ($name:ident, $c0:expr, $c1:expr, $c2:expr $(,)?) => { - $name { + ($c0:expr, $c1:expr, $c2:expr $(,)?) => { + $crate::CubicExtField { c0: $c0, c1: $c1, c2: $c2, diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 7718326a1..7207855e7 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -144,8 +144,8 @@ pub struct QuadExtField { #[macro_export] macro_rules! QuadExt { - ($name:ident, $c0:expr, $c1:expr $(,)?) => { - $name { c0: $c0, c1: $c1 } + ($c0:expr, $c1:expr $(,)?) => { + $crate::QuadExtField { c0: $c0, c1: $c1 } }; } diff --git a/test-curves/src/bls12_381/fq2.rs b/test-curves/src/bls12_381/fq2.rs index 34b58bbd9..853db847b 100644 --- a/test-curves/src/bls12_381/fq2.rs +++ b/test-curves/src/bls12_381/fq2.rs @@ -14,7 +14,7 @@ impl Fp2Config for Fq2Config { /// QUADRATIC_NONRESIDUE = (U + 1) #[rustfmt::skip] - const QUADRATIC_NONRESIDUE: Fq2 = QuadExt!(Fq2, FQ_ONE, FQ_ONE); + const QUADRATIC_NONRESIDUE: Fq2 = QuadExt!(FQ_ONE, FQ_ONE); /// Coefficients for the Frobenius automorphism. #[rustfmt::skip] @@ -31,5 +31,5 @@ impl Fp2Config for Fq2Config { } } -pub const FQ2_ZERO: Fq2 = QuadExt!(Fq2, FQ_ZERO, FQ_ZERO); -pub const FQ2_ONE: Fq2 = QuadExt!(Fq2, FQ_ONE, FQ_ZERO); +pub const FQ2_ZERO: Fq2 = QuadExt!(FQ_ZERO, FQ_ZERO); +pub const FQ2_ONE: Fq2 = QuadExt!(FQ_ONE, FQ_ZERO); diff --git a/test-curves/src/bls12_381/fq6.rs b/test-curves/src/bls12_381/fq6.rs index 71d108ff9..911aa5b5f 100644 --- a/test-curves/src/bls12_381/fq6.rs +++ b/test-curves/src/bls12_381/fq6.rs @@ -10,41 +10,35 @@ impl Fp6Config for Fq6Config { type Fp2Params = Fq2Config; /// NONRESIDUE = (U + 1) - #[rustfmt::skip] - const NONRESIDUE: Fq2 = QuadExt!(Fq2, - MontFp!(Fq, "1"), - MontFp!(Fq, "1"), - ); + const NONRESIDUE: Fq2 = QuadExt!(MontFp!(Fq, "1"), MontFp!(Fq, "1")); #[rustfmt::skip] const FROBENIUS_COEFF_FP6_C1: &'static [Fq2] = &[ // Fp2::NONRESIDUE^(((q^0) - 1) / 3) - QuadExt!(Fq2, - MontFp!(Fq, "1"), - MontFp!(Fq, "0"), - ), + QuadExt!(MontFp!(Fq, "1"), MontFp!(Fq, "0")), + // Fp2::NONRESIDUE^(((q^1) - 1) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "0"), MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), ), // Fp2::NONRESIDUE^(((q^2) - 1) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), MontFp!(Fq, "0"), ), // Fp2::NONRESIDUE^(((q^3) - 1) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "0"), MontFp!(Fq, "1"), ), // Fp2::NONRESIDUE^(((q^4) - 1) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), MontFp!(Fq, "0"), ), // Fp2::NONRESIDUE^(((q^5) - 1) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "0"), MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), ), @@ -53,32 +47,32 @@ impl Fp6Config for Fq6Config { #[rustfmt::skip] const FROBENIUS_COEFF_FP6_C2: &'static [Fq2] = &[ // Fq2(u + 1)**(((2q^0) - 2) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "1"), MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^1) - 2) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"), MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^2) - 2) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^3) - 2) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "-1"), MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^4) - 2) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), MontFp!(Fq, "0"), ), // Fq2(u + 1)**(((2q^5) - 2) / 3) - QuadExt!(Fq2, + QuadExt!( MontFp!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351"), MontFp!(Fq, "0"), ), diff --git a/test-curves/src/mnt6_753/fq3.rs b/test-curves/src/mnt6_753/fq3.rs index 03d89472b..ce314a591 100644 --- a/test-curves/src/mnt6_753/fq3.rs +++ b/test-curves/src/mnt6_753/fq3.rs @@ -58,7 +58,6 @@ impl Fp3Config for Fq3Config { /// (11^T, 0, 0) #[rustfmt::skip] const QUADRATIC_NONRESIDUE_TO_T: Fq3 = CubicExt!( - Fq3, MontFp!(Fq, "22168644070733283197994897338612733221095941481265408161807376791727499343083607817089033595478370212662133368413166734396127674284827734481031659015434501966360165723728649019457855887066657739809176476252080335185730833468062"), FQ_ZERO, FQ_ZERO, From 054204ba401ae7c1d06c7ff1d793264e4bf26d8f Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 12:24:51 -0800 Subject: [PATCH 21/32] Add documentation for macros --- ff/src/biginteger/mod.rs | 20 ++++++++++++- ff/src/const_helpers.rs | 15 ++++++++++ ff/src/fields/models/cubic_extension.rs | 12 +++++++- ff/src/fields/models/fp/montgomery_backend.rs | 28 +++++++++++++++++++ ff/src/fields/models/quadratic_extension.rs | 11 ++++++++ 5 files changed, 84 insertions(+), 2 deletions(-) diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index 85986d7a9..e7491f5a2 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -40,6 +40,24 @@ impl BigInt { } } +/// Construct a [`struct@BigInt`] element from a literal string. +/// +/// # Panics +/// +/// If the integer represented by the string cannot fit in the number +/// of limbs of the `BigInt`, this macro results in a +/// * compile-time error if used in a const context +/// * run-time error otherwise. +/// +/// # Usage +/// ```rust +/// # use ark_ff::BigInt; +/// const ONE: BigInt<6> = BigInt!("1"); +/// +/// fn check_correctness() { +/// assert_eq!(ONE, BigInt::from(1u8)); +/// } +/// ``` #[macro_export] macro_rules! BigInt { ($c0:expr) => {{ @@ -47,7 +65,7 @@ macro_rules! BigInt { assert!(is_positive); let mut integer = $crate::BigInt::zero(); assert!(integer.0.len() >= limbs.len()); - crate::const_for!((i in 0..(limbs.len())) { + $crate::const_for!((i in 0..(limbs.len())) { integer.0[i] = limbs[i]; }); integer diff --git a/ff/src/const_helpers.rs b/ff/src/const_helpers.rs index e416c6443..5a36fa27b 100644 --- a/ff/src/const_helpers.rs +++ b/ff/src/const_helpers.rs @@ -3,6 +3,21 @@ use ark_std::ops::{Index, IndexMut}; use crate::BigInt; +/// A helper macro for emulating `for` loops in a `const` context. +/// # Usage +/// ```rust +/// # use ark_ff::const_for; +/// const fn for_in_const() { +/// let mut array = [0usize; 4]; +/// const_for!((i in 0..(array.len())) { // We need to wrap the `array.len()` in parenthesis. +/// array[i] = i; +/// }); +/// assert!(array[0] == 0); +/// assert!(array[1] == 1); +/// assert!(array[2] == 2); +/// assert!(array[3] == 3); +/// } +/// ``` #[macro_export] macro_rules! const_for { (($i:ident in $start:tt..$end:tt) $code:expr ) => {{ diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 796c0460b..0709a5313 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -82,7 +82,17 @@ pub struct CubicExtField { pub c2: P::BaseField, } -/// Construct a `CubicExtension` element from elements of the base field. +/// Construct a [`CubicExtField`] element from elements of the base field. This should +/// be used primarily for constructing constant field elements; in a non-const +/// context, [`CubicExtField::new`] is preferable. +/// +/// # Usage +/// ```rust +/// # use ark_test_curves::CubicExt; +/// # use ark_test_curves::mnt6_753 as ark_mnt6_753; +/// use ark_mnt6_753::{FQ_ZERO, FQ_ONE, Fq3}; +/// const ONE: Fq3 = CubicExt!(FQ_ONE, FQ_ZERO, FQ_ZERO); +/// ``` #[macro_export] macro_rules! CubicExt { ($c0:expr, $c1:expr, $c2:expr $(,)?) => { diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index d13432f39..5b8641bf7 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -310,6 +310,33 @@ pub const fn can_use_no_carry_optimization(modulus: &BigInt) !(first_bit_set || all_bits_set) } +/// Construct a [`Fp, N>`] element from a literal string. This should +/// be used primarily for constructing constant field elements; in a non-const +/// context, [`Fp::from_str`](std::str::FromStr::from_str) is preferable. +/// +/// # Panics +/// +/// If the integer represented by the string cannot fit in the number +/// of limbs of the `Fp`, this macro results in a +/// * compile-time error if used in a const context +/// * run-time error otherwise. +/// +/// # Usage +/// +/// ```rust +/// # use ark_test_curves::{MontFp, One}; +/// # use ark_test_curves::bls12_381 as ark_bls12_381; +/// # use ark_std::str::FromStr; +/// use ark_bls12_381::Fq; +/// const ONE: Fq = MontFp!(Fq, "1"); +/// const NEG_ONE: Fq = MontFp!(Fq, "-1"); +/// +/// fn check_correctness() { +/// assert_eq!(ONE, Fq::one()); +/// assert_eq!(Fq::from_str("1").unwrap(), ONE); +/// assert_eq!(NEG_ONE, -Fq::one()); +/// } +/// ``` #[macro_export] macro_rules! MontFp { ($name:ident, $c0:expr) => {{ @@ -422,6 +449,7 @@ impl Fp, N> { modulus: BigInt, ) -> Self { let mut repr = BigInt::([0; N]); + assert!(repr.0.len() == N); crate::const_for!((i in 0..(limbs.len())) { repr.0[i] = limbs[i]; }); diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 7207855e7..e6e52d1e7 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -142,6 +142,17 @@ pub struct QuadExtField { pub c1: P::BaseField, } +/// Construct a [`QuadExtField`] element from elements of the base field. This should +/// be used primarily for constructing constant field elements; in a non-const +/// context, [`QuadExtField::new`] is preferable. +/// +/// # Usage +/// ```rust +/// # use ark_test_curves::QuadExt; +/// # use ark_test_curves::bls12_381 as ark_bls12_381; +/// use ark_bls12_381::{FQ_ZERO, FQ_ONE, Fq2}; +/// const ONE: Fq2 = QuadExt!(FQ_ONE, FQ_ZERO); +/// ``` #[macro_export] macro_rules! QuadExt { ($c0:expr, $c1:expr $(,)?) => { From a5503894b629cadeadc458a0b6046762e7590405 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 12:44:06 -0800 Subject: [PATCH 22/32] fmt --- ff/src/biginteger/mod.rs | 10 +++++----- ff/src/bytes.rs | 1 + ff/src/fields/models/cubic_extension.rs | 2 +- ff/src/fields/models/fp/montgomery_backend.rs | 12 ++++++------ ff/src/fields/models/quadratic_extension.rs | 2 +- ff/src/lib.rs | 1 + 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index e7491f5a2..369e8aa15 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -41,19 +41,19 @@ impl BigInt { } /// Construct a [`struct@BigInt`] element from a literal string. -/// +/// /// # Panics -/// +/// /// If the integer represented by the string cannot fit in the number -/// of limbs of the `BigInt`, this macro results in a +/// of limbs of the `BigInt`, this macro results in a /// * compile-time error if used in a const context /// * run-time error otherwise. -/// +/// /// # Usage /// ```rust /// # use ark_ff::BigInt; /// const ONE: BigInt<6> = BigInt!("1"); -/// +/// /// fn check_correctness() { /// assert_eq!(ONE, BigInt::from(1u8)); /// } diff --git a/ff/src/bytes.rs b/ff/src/bytes.rs index af2e8ef6a..f96ce997a 100644 --- a/ff/src/bytes.rs +++ b/ff/src/bytes.rs @@ -133,6 +133,7 @@ macro_rules! to_bytes { }); } +#[doc(hidden)] #[macro_export] macro_rules! push_to_vec { ($buf:expr, $y:expr, $($x:expr),*) => ({ diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 0709a5313..247ae0b13 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -85,7 +85,7 @@ pub struct CubicExtField { /// Construct a [`CubicExtField`] element from elements of the base field. This should /// be used primarily for constructing constant field elements; in a non-const /// context, [`CubicExtField::new`] is preferable. -/// +/// /// # Usage /// ```rust /// # use ark_test_curves::CubicExt; diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 5b8641bf7..bb72a976e 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -313,16 +313,16 @@ pub const fn can_use_no_carry_optimization(modulus: &BigInt) /// Construct a [`Fp, N>`] element from a literal string. This should /// be used primarily for constructing constant field elements; in a non-const /// context, [`Fp::from_str`](std::str::FromStr::from_str) is preferable. -/// +/// /// # Panics -/// +/// /// If the integer represented by the string cannot fit in the number -/// of limbs of the `Fp`, this macro results in a +/// of limbs of the `Fp`, this macro results in a /// * compile-time error if used in a const context /// * run-time error otherwise. -/// +/// /// # Usage -/// +/// /// ```rust /// # use ark_test_curves::{MontFp, One}; /// # use ark_test_curves::bls12_381 as ark_bls12_381; @@ -330,7 +330,7 @@ pub const fn can_use_no_carry_optimization(modulus: &BigInt) /// use ark_bls12_381::Fq; /// const ONE: Fq = MontFp!(Fq, "1"); /// const NEG_ONE: Fq = MontFp!(Fq, "-1"); -/// +/// /// fn check_correctness() { /// assert_eq!(ONE, Fq::one()); /// assert_eq!(Fq::from_str("1").unwrap(), ONE); diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index e6e52d1e7..fbcb7f447 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -145,7 +145,7 @@ pub struct QuadExtField { /// Construct a [`QuadExtField`] element from elements of the base field. This should /// be used primarily for constructing constant field elements; in a non-const /// context, [`QuadExtField::new`] is preferable. -/// +/// /// # Usage /// ```rust /// # use ark_test_curves::QuadExt; diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 7297db295..35d806aad 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -37,6 +37,7 @@ pub use to_field_vec::ToConstraintField; pub use num_traits::{One, Zero}; +#[doc(hidden)] pub use ark_std::vec; pub mod prelude { From 5f866feaef09efc281e9ef5370cf81ceb35dac98 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 12:45:38 -0800 Subject: [PATCH 23/32] Use singular in CHANGELOG Co-authored-by: Weikeng Chen --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bf18c5eb..e745c024f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,13 +18,13 @@ - Remove duplicate function `scale_by_cofactor()` from `short_weierstrass_jacobian::GroupAffine` and `twisted_edwards_extended::GroupAffine` - [\#370](https://github.com/arkworks-rs/algebra/pull/370) (all) Set the minimum `rust-version = 1.56` in the manifests of all crates. - [\#379](https://github.com/arkworks-rs/algebra/pull/379) (`ark-ff`) Refactor `Field` implementation and `PrimeField` trait: - - Switches from hardcoded `FpXYZ` to `Fp` based on `const` generics. - - Moves Montgomery arithmetic to an optional backend. + - Switch from hardcoded `FpXYZ` to `Fp` based on `const` generics. + - Move Montgomery arithmetic to an optional backend. - Rename `field_new` macros to `MontFp`, `QuadExt` and `CubicExt` macros. - Introduce `const fn`s for generating many constants. - Add default associated constants to reduce boilerplate. - Rename `Fp*Parameters` to `Fp*Config`. - - Adds `From`, `From`, and `From` `impl`s for `BigInt`. + - Add `From`, `From`, and `From` `impl`s for `BigInt`. ### Features From 29649469f1ec7a2da665f5d7c6da1c7e8716604a Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 13:29:51 -0800 Subject: [PATCH 24/32] Clean up some documentation --- ff/README.md | 2 +- ff/src/fields/mod.rs | 2 +- ff/src/fields/models/fp2.rs | 20 +++++++++++--------- ff/src/fields/models/fp3.rs | 9 +++++++++ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/ff/README.md b/ff/README.md index ccc5133cc..3369e497a 100644 --- a/ff/README.md +++ b/ff/README.md @@ -12,7 +12,7 @@ Implementations of concrete finite fields for some popular elliptic curves can b This crate contains two types of traits: - `Field` traits: These define interfaces for manipulating field elements, such as addition, multiplication, inverses, square roots, and more. -- Field Parameters: holds the parameters defining the field in question. For extension fields, it also provides additional functionality required for the field, such as operations involving a (cubic or quadratic) non-residue used for constructing the field (`NONRESIDUE`). +- Field `Config`s: specifies the parameters defining the field in question. For extension fields, it also provides additional functionality required for the field, such as operations involving a (cubic or quadratic) non-residue used for constructing the field (`NONRESIDUE`). The available field traits are: diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index cb083d231..d9c2dd2cb 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -173,7 +173,7 @@ pub trait Field: } } -/// A trait that defines parameters for a field that can be used for FFTs. +/// A trait that specifies the configuration for a field that supports efficient FFTs. pub trait FftConfig: 'static + Send + Sync + Sized { type Field: Field; diff --git a/ff/src/fields/models/fp2.rs b/ff/src/fields/models/fp2.rs index fe767ee3d..7757d1d96 100644 --- a/ff/src/fields/models/fp2.rs +++ b/ff/src/fields/models/fp2.rs @@ -2,12 +2,12 @@ use super::quadratic_extension::*; use crate::fields::PrimeField; use core::marker::PhantomData; -/// Parameters for defining degree-two extension fields. +/// Trait that specifies constants and methods for defining degree-two extension fields. pub trait Fp2Config: 'static + Send + Sync + Sized { /// Base prime field underlying this extension. type Fp: PrimeField; - /// Quadratic non-residue in `Self::Fp` used to construct the extension + /// Quadratic non-residue in [`Self::Fp`] used to construct the extension /// field. That is, `NONRESIDUE` is such that the quadratic polynomial /// `f(X) = X^2 - Self::NONRESIDUE` in Fp\[X\] is irreducible in `Self::Fp`. const NONRESIDUE: Self::Fp; @@ -19,13 +19,15 @@ pub trait Fp2Config: 'static + Send + Sync + Sized { const FROBENIUS_COEFF_FP2_C1: &'static [Self::Fp]; /// Return `fe * Self::NONRESIDUE`. + /// Intended for specialization when [`Self::NONRESIDUE`] has a special + /// structure that can speed up multiplication #[inline(always)] fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp { Self::NONRESIDUE * fe } /// A specializable method for computing `x + mul_base_field_by_nonresidue(y)` - /// This allows for optimizations when the non-residue is + /// This allows for optimizations when [`Self::NONRESIDUE`] is /// canonically negative in the field. #[inline(always)] fn add_and_mul_fp_by_nonresidue(x: &Self::Fp, y: &Self::Fp) -> Self::Fp { @@ -33,7 +35,7 @@ pub trait Fp2Config: 'static + Send + Sync + Sized { } /// A specializable method for computing `x + y + mul_base_field_by_nonresidue(y)` - /// This allows for optimizations when the non-residue is not `-1`. + /// This allows for optimizations when the [`Self::NONRESIDUE`] is not `-1`. #[inline(always)] fn add_and_mul_fp_by_nonresidue_plus_one(x: &Self::Fp, y: &Self::Fp) -> Self::Fp { let mut tmp = *x; @@ -42,7 +44,7 @@ pub trait Fp2Config: 'static + Send + Sync + Sized { } /// A specializable method for computing `x - mul_base_field_by_nonresidue(y)` - /// This allows for optimizations when the non-residue is + /// This allows for optimizations when the [`Self::NONRESIDUE`] is /// canonically negative in the field. #[inline(always)] fn sub_and_mul_fp_by_nonresidue(x: &Self::Fp, y: &Self::Fp) -> Self::Fp { @@ -50,7 +52,7 @@ pub trait Fp2Config: 'static + Send + Sync + Sized { } } -/// Wrapper for Fp2Config, allowing combination of Fp2Config & QuadExtConfig traits +/// Wrapper for [`Fp2Config`], allowing combination of the [`Fp2Config`] and [`QuadExtConfig`] traits. pub struct Fp2ParamsWrapper(PhantomData

); impl QuadExtConfig for Fp2ParamsWrapper

{ @@ -103,9 +105,9 @@ impl QuadExtConfig for Fp2ParamsWrapper

{ pub type Fp2

= QuadExtField>; impl Fp2

{ - /// In-place multiply both coefficients `c0` & `c1` of the extension field - /// `Fp2` by an element from `Fp`. The coefficients themselves - /// are elements of `Fp`. + /// In-place multiply both coefficients `c0` and `c1` of an + /// [`Fp2`] element by an element from [`P::Fp`]. The coefficients themselves + /// are elements of [`P::Fp`]. /// /// # Examples /// diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index caf136750..7cd600048 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -2,9 +2,14 @@ use super::cubic_extension::*; use crate::fields::*; use core::marker::PhantomData; +/// Trait that specifies constants and methods for defining degree-three extension fields. pub trait Fp3Config: 'static + Send + Sync + Sized { + /// Base prime field underlying this extension. type Fp: PrimeField + SquareRootField; + /// Cubic non-residue in `Self::Fp` used to construct the extension + /// field. That is, `NONRESIDUE` is such that the quadratic polynomial + /// `f(X) = X^3 - Self::NONRESIDUE` in Fp\[X\] is irreducible in `Self::Fp`. const NONRESIDUE: Self::Fp; const FROBENIUS_COEFF_FP3_C1: &'static [Self::Fp]; @@ -16,12 +21,16 @@ pub trait Fp3Config: 'static + Send + Sync + Sized { /// t-th power of a quadratic nonresidue in Fp3. const QUADRATIC_NONRESIDUE_TO_T: Fp3; + /// Return `fe * Self::NONRESIDUE`. + /// The default implementation can be specialized if [`Self::NONRESIDUE`] has a special + /// structure that can speed up multiplication #[inline(always)] fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp { Self::NONRESIDUE * fe } } +/// Wrapper for [`Fp3Config`], allowing combination of the [`Fp3Config`] and [`CubicExtConfig`] traits. pub struct Fp3ParamsWrapper(PhantomData

); impl CubicExtConfig for Fp3ParamsWrapper

{ From 5b6642f361104ec2d5c5ccf1aa9d02781b755939 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 13:32:12 -0800 Subject: [PATCH 25/32] Update and format --- ff/src/fields/models/fp3.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index 7cd600048..3a1b56cd8 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -63,6 +63,26 @@ impl CubicExtConfig for Fp3ParamsWrapper

{ pub type Fp3

= CubicExtField>; impl Fp3

{ + /// In-place multiply both coefficients `c0`, `c1`, `c2` of an + /// [`Fp3`] element by an element from [`P::Fp`]. The coefficients themselves + /// are elements of [`P::Fp`]. + /// + /// # Examples + /// + /// ``` + /// # use ark_std::test_rng; + /// # use ark_test_curves::bls12_381::{Fq as Fp, Fq2 as Fp2}; + /// # use ark_std::UniformRand; + /// let c0: Fp = Fp::rand(&mut test_rng()); + /// let c1: Fp = Fp::rand(&mut test_rng()); + /// let mut ext_element: Fp2 = Fp2::new(c0, c1); + /// + /// let base_field_element: Fp = Fp::rand(&mut test_rng()); + /// ext_element.mul_assign_by_fp(&base_field_element); + /// + /// assert_eq!(ext_element.c0, c0*base_field_element); + /// assert_eq!(ext_element.c1, c1*base_field_element); + /// ``` pub fn mul_assign_by_fp(&mut self, value: &P::Fp) { self.c0.mul_assign(value); self.c1.mul_assign(value); From 9f01c8b6e0d810a6eff819749ca27b790230902b Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 13:35:38 -0800 Subject: [PATCH 26/32] Clean up doc test --- ff/src/fields/models/fp2.rs | 4 ++-- ff/src/fields/models/fp3.rs | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ff/src/fields/models/fp2.rs b/ff/src/fields/models/fp2.rs index 7757d1d96..fc269bcd2 100644 --- a/ff/src/fields/models/fp2.rs +++ b/ff/src/fields/models/fp2.rs @@ -122,8 +122,8 @@ impl Fp2

{ /// let base_field_element: Fp = Fp::rand(&mut test_rng()); /// ext_element.mul_assign_by_fp(&base_field_element); /// - /// assert_eq!(ext_element.c0, c0*base_field_element); - /// assert_eq!(ext_element.c1, c1*base_field_element); + /// assert_eq!(ext_element.c0, c0 * base_field_element); + /// assert_eq!(ext_element.c1, c1 * base_field_element); /// ``` pub fn mul_assign_by_fp(&mut self, other: &P::Fp) { self.c0 *= other; diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index 3a1b56cd8..42b890334 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -70,18 +70,23 @@ impl Fp3

{ /// # Examples /// /// ``` + /// + /// # use ark_test_curves::CubicExt; /// # use ark_std::test_rng; - /// # use ark_test_curves::bls12_381::{Fq as Fp, Fq2 as Fp2}; /// # use ark_std::UniformRand; + /// # use ark_test_curves::mnt6_753 as ark_mnt6_753; + /// use ark_mnt6_753::{Fq as Fp, Fq3 as Fp3}; /// let c0: Fp = Fp::rand(&mut test_rng()); /// let c1: Fp = Fp::rand(&mut test_rng()); - /// let mut ext_element: Fp2 = Fp2::new(c0, c1); + /// let c2: Fp = Fp::rand(&mut test_rng()); + /// let mut ext_element: Fp3 = Fp3::new(c0, c1, c2); /// /// let base_field_element: Fp = Fp::rand(&mut test_rng()); /// ext_element.mul_assign_by_fp(&base_field_element); /// - /// assert_eq!(ext_element.c0, c0*base_field_element); - /// assert_eq!(ext_element.c1, c1*base_field_element); + /// assert_eq!(ext_element.c0, c0 * base_field_element); + /// assert_eq!(ext_element.c1, c1 * base_field_element); + /// assert_eq!(ext_element.c2, c2 * base_field_element); /// ``` pub fn mul_assign_by_fp(&mut self, value: &P::Fp) { self.c0.mul_assign(value); From 0d8fcd10fd35aac152ab9dff677e870105747fa7 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 12 Jan 2022 13:52:56 -0800 Subject: [PATCH 27/32] Clean up docs --- ff/src/fields/models/fp/montgomery_backend.rs | 2 +- ff/src/fields/models/fp2.rs | 5 ++--- ff/src/fields/models/fp3.rs | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index bb72a976e..18052c93a 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -312,7 +312,7 @@ pub const fn can_use_no_carry_optimization(modulus: &BigInt) /// Construct a [`Fp, N>`] element from a literal string. This should /// be used primarily for constructing constant field elements; in a non-const -/// context, [`Fp::from_str`](std::str::FromStr::from_str) is preferable. +/// context, [`Fp::from_str`](`ark_std::str::FromStr::from_str`) is preferable. /// /// # Panics /// diff --git a/ff/src/fields/models/fp2.rs b/ff/src/fields/models/fp2.rs index fc269bcd2..4f2fb5800 100644 --- a/ff/src/fields/models/fp2.rs +++ b/ff/src/fields/models/fp2.rs @@ -105,9 +105,8 @@ impl QuadExtConfig for Fp2ParamsWrapper

{ pub type Fp2

= QuadExtField>; impl Fp2

{ - /// In-place multiply both coefficients `c0` and `c1` of an - /// [`Fp2`] element by an element from [`P::Fp`]. The coefficients themselves - /// are elements of [`P::Fp`]. + /// In-place multiply both coefficients `c0` and `c1` of `self` + /// by an element from [`Fp`](`Fp2Config::Fp`). /// /// # Examples /// diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index 42b890334..b16739e27 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -63,9 +63,8 @@ impl CubicExtConfig for Fp3ParamsWrapper

{ pub type Fp3

= CubicExtField>; impl Fp3

{ - /// In-place multiply both coefficients `c0`, `c1`, `c2` of an - /// [`Fp3`] element by an element from [`P::Fp`]. The coefficients themselves - /// are elements of [`P::Fp`]. + /// In-place multiply all coefficients `c0`, `c1`, and `c2` of `self` + /// by an element from [`Fp`](`Fp3Config::Fp`). /// /// # Examples /// From 6f5623af982f358fa6cf44f47f91ed59456c5c1a Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Sat, 15 Jan 2022 12:11:09 -0800 Subject: [PATCH 28/32] Apply suggestions from code review Co-authored-by: Weikeng Chen --- ff/src/fields/models/fp/mod.rs | 13 ++++--------- ff/src/fields/models/fp3.rs | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index b2875c49d..eb6017ea6 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -60,7 +60,7 @@ pub trait FpConfig: crate::FftConfig> { /// Compute the square root of a, if it exists. fn square_root(a: &Fp) -> Option> { // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) - // Actually this is just normal Tonelli-Shanks; since `P::Generator` + // Actually this is just normal Tonelli-Shanks; since [`Self::GENERATOR`] // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` // is also a quadratic non-residue (since `t` is odd). if a.is_zero() { @@ -161,7 +161,7 @@ pub type Fp832

= Fp; impl Fp { /// Construct a new prime element directly from its underlying - /// `BigInteger` data type. + /// [`BigInt`] data type. #[inline] pub const fn new(element: BigInt) -> Self { Self(element, PhantomData) @@ -425,13 +425,8 @@ impl, const N: usize> From for Fp { } else { let upper = (other >> 64) as u64; let lower = ((other << 64) >> 64) as u64; - // This is equivalent to the following, but satisfying the compiler: - // default_int.0[0] = lower; - // default_int.0[1] = upper; - let limbs = [lower, upper]; - for (cur, other) in default_int.0.iter_mut().zip(&limbs) { - *cur = *other; - } + default_int.0[0] = lower; + default_int.0[1] = upper; } Self::from_bigint(default_int).unwrap() } diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index b16739e27..bfdee0e0e 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -8,7 +8,7 @@ pub trait Fp3Config: 'static + Send + Sync + Sized { type Fp: PrimeField + SquareRootField; /// Cubic non-residue in `Self::Fp` used to construct the extension - /// field. That is, `NONRESIDUE` is such that the quadratic polynomial + /// field. That is, `NONRESIDUE` is such that the cubic polynomial /// `f(X) = X^3 - Self::NONRESIDUE` in Fp\[X\] is irreducible in `Self::Fp`. const NONRESIDUE: Self::Fp; From 76b008413bc88d53b99182d7f647af06f752f20b Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Sat, 15 Jan 2022 12:11:40 -0800 Subject: [PATCH 29/32] Update ff/src/fields/mod.rs Co-authored-by: Marcin --- ff/src/fields/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index d9c2dd2cb..f2023905a 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -343,7 +343,7 @@ pub trait PrimeField: Self::from_be_bytes_mod_order(&bytes_copy) } - /// Return QNR^t, and t coprime to 2, and for + /// Return QNR^t, for t coprime to 2, and for /// a given quadratic non-residue. fn qnr_to_t() -> Self { Self::two_adic_root_of_unity() From b366b775b3dbba925c86b5b3c3bde7e9cdb9b95b Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Sat, 15 Jan 2022 12:54:28 -0800 Subject: [PATCH 30/32] Clean up and format --- ec/src/models/bls12/mod.rs | 4 ++-- ec/src/models/bn/g2.rs | 4 ++-- ec/src/models/bn/mod.rs | 8 ++++---- ec/src/models/bw6/g2.rs | 4 ++-- ec/src/models/bw6/mod.rs | 8 ++++---- ff/src/const_helpers.rs | 4 +--- ff/src/fields/models/fp/mod.rs | 4 ++-- poly/src/domain/general.rs | 2 +- poly/src/polynomial/multivariate/mod.rs | 4 ++-- poly/src/polynomial/multivariate/sparse.rs | 2 +- poly/src/polynomial/univariate/mod.rs | 8 ++++---- serialize-derive/src/lib.rs | 18 +++++++++--------- 12 files changed, 34 insertions(+), 36 deletions(-) diff --git a/ec/src/models/bls12/mod.rs b/ec/src/models/bls12/mod.rs index ecdd7fa53..2918c0813 100644 --- a/ec/src/models/bls12/mod.rs +++ b/ec/src/models/bls12/mod.rs @@ -68,12 +68,12 @@ impl Bls12

{ c2.mul_assign_by_fp(&p.y); c1.mul_assign_by_fp(&p.x); f.mul_by_014(&c0, &c1, &c2); - } + }, TwistType::D => { c0.mul_assign_by_fp(&p.y); c1.mul_assign_by_fp(&p.x); f.mul_by_034(&c0, &c1, &c2); - } + }, } } diff --git a/ec/src/models/bn/g2.rs b/ec/src/models/bn/g2.rs index f8e8c91de..6087079de 100644 --- a/ec/src/models/bn/g2.rs +++ b/ec/src/models/bn/g2.rs @@ -92,10 +92,10 @@ impl From> for G2Prepared

{ match bit { 1 => { ell_coeffs.push(addition_step::

(&mut r, &q)); - } + }, -1 => { ell_coeffs.push(addition_step::

(&mut r, &negq)); - } + }, _ => continue, } } diff --git a/ec/src/models/bn/mod.rs b/ec/src/models/bn/mod.rs index f12b0d2af..9c243ab3b 100644 --- a/ec/src/models/bn/mod.rs +++ b/ec/src/models/bn/mod.rs @@ -66,12 +66,12 @@ impl Bn

{ c2.mul_assign_by_fp(&p.y); c1.mul_assign_by_fp(&p.x); f.mul_by_014(&c0, &c1, &c2); - } + }, TwistType::D => { c0.mul_assign_by_fp(&p.y); c1.mul_assign_by_fp(&p.x); f.mul_by_034(&c0, &c1, &c2); - } + }, } } @@ -124,12 +124,12 @@ impl PairingEngine for Bn

{ for &mut (p, ref mut coeffs) in &mut pairs { Self::ell(&mut f, coeffs.next().unwrap(), &p.0); } - } + }, -1 => { for &mut (p, ref mut coeffs) in &mut pairs { Self::ell(&mut f, coeffs.next().unwrap(), &p.0); } - } + }, _ => continue, } } diff --git a/ec/src/models/bw6/g2.rs b/ec/src/models/bw6/g2.rs index 68fbacfbc..ba240f477 100644 --- a/ec/src/models/bw6/g2.rs +++ b/ec/src/models/bw6/g2.rs @@ -112,10 +112,10 @@ impl From> for G2Prepared

{ match bit { 1 => { ell_coeffs_2.push(addition_step::

(&mut r, &q)); - } + }, -1 => { ell_coeffs_2.push(addition_step::

(&mut r, &negq)); - } + }, _ => continue, } } diff --git a/ec/src/models/bw6/mod.rs b/ec/src/models/bw6/mod.rs index 69f52aac3..b4b6e8fa4 100644 --- a/ec/src/models/bw6/mod.rs +++ b/ec/src/models/bw6/mod.rs @@ -58,12 +58,12 @@ impl BW6

{ c2 *= &p.y; c1 *= &p.x; f.mul_by_014(&c0, &c1, &c2); - } + }, TwistType::D => { c0 *= &p.y; c1 *= &p.x; f.mul_by_034(&c0, &c1, &c2); - } + }, } } @@ -274,12 +274,12 @@ impl PairingEngine for BW6

{ for &mut (p, ref mut coeffs) in &mut pairs_2 { Self::ell(&mut f_2, coeffs.next().unwrap(), &p.0); } - } + }, -1 => { for &mut (p, ref mut coeffs) in &mut pairs_2 { Self::ell(&mut f_2, coeffs.next().unwrap(), &p.0); } - } + }, _ => continue, } } diff --git a/ff/src/const_helpers.rs b/ff/src/const_helpers.rs index 5a36fa27b..9f2a98aa0 100644 --- a/ff/src/const_helpers.rs +++ b/ff/src/const_helpers.rs @@ -167,7 +167,7 @@ impl SerBuffer { #[inline(always)] /// Write up to `num_bytes` bytes from `self` to `other`. - /// `num_bytes` is allowed to range from `8 * (N - 1)` to `8 * N + 1`. + /// `num_bytes` is allowed to range from `8 * (N - 1) + 1` to `8 * N + 1`. pub(super) fn write_up_to( &self, mut other: impl Write, @@ -181,7 +181,6 @@ impl SerBuffer { } // for the `N`-th limb, depending on `index`, we can write anywhere from // 1 to all bytes. - // If `index % N == ` let remaining_bytes = num_bytes - (8 * (N - 1)); let write_last_byte = remaining_bytes > 8; let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); @@ -208,7 +207,6 @@ impl SerBuffer { } // for the `N`-th limb, depending on `index`, we can write anywhere from // 1 to all bytes. - // If `index % N == ` let remaining_bytes = num_bytes - (8 * (N - 1)); let write_last_byte = remaining_bytes > 8; let num_last_limb_bytes = ark_std::cmp::min(8, remaining_bytes); diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index eb6017ea6..19ad67eea 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -692,10 +692,10 @@ impl, const N: usize> FromStr for Fp { res.mul_assign(&ten); let digit = Self::from(u64::from(c)); res.add_assign(&digit); - } + }, None => { return Err(()); - } + }, } } if !res.is_less_than_modulus() { diff --git a/poly/src/domain/general.rs b/poly/src/domain/general.rs index ae3a24a7a..744956510 100644 --- a/poly/src/domain/general.rs +++ b/poly/src/domain/general.rs @@ -75,7 +75,7 @@ impl CanonicalSerialize for GeneralEvaluationDomain { GeneralEvaluationDomain::Radix2(domain) => domain.serialize_uncompressed(&mut writer), GeneralEvaluationDomain::MixedRadix(domain) => { domain.serialize_uncompressed(&mut writer) - } + }, } } diff --git a/poly/src/polynomial/multivariate/mod.rs b/poly/src/polynomial/multivariate/mod.rs index ab6a2a28b..04e63c030 100644 --- a/poly/src/polynomial/multivariate/mod.rs +++ b/poly/src/polynomial/multivariate/mod.rs @@ -68,8 +68,8 @@ impl SparseTerm { prev.1 += pow; continue; } - } - _ => {} + }, + _ => {}, }; term_dedup.push((*var, *pow)); } diff --git a/poly/src/polynomial/multivariate/sparse.rs b/poly/src/polynomial/multivariate/sparse.rs index a2dfdbe29..c7fc690da 100644 --- a/poly/src/polynomial/multivariate/sparse.rs +++ b/poly/src/polynomial/multivariate/sparse.rs @@ -146,7 +146,7 @@ impl<'a, 'b, F: Field, T: Term> Add<&'a SparsePolynomial> for &'b SparsePo let other = other_iter.next().unwrap(); let cur = cur_iter.next().unwrap(); (cur.0 + other.0, cur.1.clone()) - } + }, Some(Ordering::Greater) => other_iter.next().unwrap().clone(), None => break, }; diff --git a/poly/src/polynomial/univariate/mod.rs b/poly/src/polynomial/univariate/mod.rs index ae415d29f..d30ce0ac6 100644 --- a/poly/src/polynomial/univariate/mod.rs +++ b/poly/src/polynomial/univariate/mod.rs @@ -147,18 +147,18 @@ impl<'a, F: 'a + FftField> DenseOrSparsePolynomial<'a, F> { SPolynomial(Cow::Borrowed(s)) => { let evals = domain.elements().map(|elem| s.evaluate(&elem)).collect(); Evaluations::from_vec_and_domain(evals, domain) - } + }, SPolynomial(Cow::Owned(s)) => { let evals = domain.elements().map(|elem| s.evaluate(&elem)).collect(); Evaluations::from_vec_and_domain(evals, domain) - } + }, DPolynomial(Cow::Borrowed(d)) => { Evaluations::from_vec_and_domain(domain.fft(&d.coeffs), domain) - } + }, DPolynomial(Cow::Owned(mut d)) => { domain.fft_in_place(&mut d.coeffs); Evaluations::from_vec_and_domain(d.coeffs, domain) - } + }, } } } diff --git a/serialize-derive/src/lib.rs b/serialize-derive/src/lib.rs index b65623f48..fd07f9c25 100644 --- a/serialize-derive/src/lib.rs +++ b/serialize-derive/src/lib.rs @@ -44,7 +44,7 @@ fn impl_serialize_field( ); idents.pop(); } - } + }, _ => { serialize_body .push(quote! { CanonicalSerialize::serialize(&self.#(#idents).*, &mut writer)?; }); @@ -59,7 +59,7 @@ fn impl_serialize_field( uncompressed_size_body.push( quote! { size += CanonicalSerialize::uncompressed_size(&self.#(#idents).*); }, ); - } + }, } } @@ -82,10 +82,10 @@ fn impl_canonical_serialize(ast: &syn::DeriveInput) -> TokenStream { None => { let index = Index::from(i); idents.push(Box::new(index)); - } + }, Some(ref ident) => { idents.push(Box::new(ident.clone())); - } + }, } impl_serialize_field( &mut serialize_body, @@ -97,7 +97,7 @@ fn impl_canonical_serialize(ast: &syn::DeriveInput) -> TokenStream { &field.ty, ); } - } + }, _ => panic!( "Serialize can only be derived for structs, {} is not a struct", name @@ -164,7 +164,7 @@ fn impl_deserialize_field(ty: &Type) -> (TokenStream, TokenStream, TokenStream) quote! { (#(#uncompressed_fields)*), }, quote! { (#(#unchecked_fields)*), }, ) - } + }, _ => ( quote! { CanonicalDeserialize::deserialize(&mut reader)?, }, quote! { CanonicalDeserialize::deserialize_uncompressed(&mut reader)?, }, @@ -197,7 +197,7 @@ fn impl_canonical_deserialize(ast: &syn::DeriveInput) -> TokenStream { compressed_field_cases.push(compressed); uncompressed_field_cases.push(uncompressed); unchecked_field_cases.push(unchecked); - } + }, // struct field without len_type Some(ident) => { let (compressed_field, uncompressed_field, unchecked_field) = @@ -205,7 +205,7 @@ fn impl_canonical_deserialize(ast: &syn::DeriveInput) -> TokenStream { compressed_field_cases.push(quote! { #ident: #compressed_field }); uncompressed_field_cases.push(quote! { #ident: #uncompressed_field }); unchecked_field_cases.push(quote! { #ident: #unchecked_field }); - } + }, } } @@ -242,7 +242,7 @@ fn impl_canonical_deserialize(ast: &syn::DeriveInput) -> TokenStream { }) }); } - } + }, _ => panic!( "Deserialize can only be derived for structs, {} is not a Struct", name From dc52c73cef040fcbc0b644885739b0b21deeb94e Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Sat, 15 Jan 2022 13:42:30 -0800 Subject: [PATCH 31/32] Remove `FftConfig` and move constants to `FftField` --- ff/src/fields/mod.rs | 56 ++++++------------- ff/src/fields/models/fp/mod.rs | 47 ++++++++++------ ff/src/fields/models/fp/montgomery_backend.rs | 17 +++--- ff/src/fields/utils.rs | 2 +- poly/src/domain/general.rs | 6 +- poly/src/domain/mixed_radix.rs | 44 ++++++++------- poly/src/domain/mod.rs | 6 +- poly/src/domain/radix2/mod.rs | 16 +++--- poly/src/domain/utils.rs | 2 +- test-templates/src/fields.rs | 26 ++++----- 10 files changed, 106 insertions(+), 116 deletions(-) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index f2023905a..ff5b6f514 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -173,9 +173,10 @@ pub trait Field: } } -/// A trait that specifies the configuration for a field that supports efficient FFTs. -pub trait FftConfig: 'static + Send + Sync + Sized { - type Field: Field; +/// The interface for fields that are able to be used in FFTs. +pub trait FftField: Field { + /// The generator of the multiplicative group of the field + const GENERATOR: Self; /// Let `N` be the size of the multiplicative group defined by the field. /// Then `TWO_ADICITY` is the two-adicity of `N`, i.e. the integer `s` @@ -183,7 +184,7 @@ pub trait FftConfig: 'static + Send + Sync + Sized { const TWO_ADICITY: u32; /// 2^s root of unity computed by GENERATOR^t - const TWO_ADIC_ROOT_OF_UNITY: Self::Field; + const TWO_ADIC_ROOT_OF_UNITY: Self; /// An integer `b` such that there exists a multiplicative subgroup /// of size `b^k` for some integer `k`. @@ -196,22 +197,7 @@ pub trait FftConfig: 'static + Send + Sync + Sized { /// GENERATOR^((MODULUS-1) / (2^s * /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix /// FFT. - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; -} - -/// The interface for fields that are able to be used in FFTs. -pub trait FftField: Field { - type FftConfig: FftConfig; - - /// Returns the 2^s root of unity. - fn two_adic_root_of_unity() -> Self; - - /// Returns the 2^s * small_subgroup_base^small_subgroup_base_adicity root - /// of unity if a small subgroup is defined. - fn large_subgroup_root_of_unity() -> Option; - - /// Returns the multiplicative generator of `char()` - 1 order. - fn multiplicative_generator() -> Self; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; /// Returns the root of unity of order n, if one exists. /// If no small multiplicative subgroup is defined, this is the 2-adic root @@ -220,24 +206,24 @@ pub trait FftField: Field { /// of order n for the larger subgroup generated by /// `FftConfig::LARGE_SUBGROUP_ROOT_OF_UNITY` /// (for n = 2^i * FftConfig::SMALL_SUBGROUP_BASE^j for some i, j). - fn get_root_of_unity(n: usize) -> Option { + fn get_root_of_unity(n: u64) -> Option { let mut omega: Self; - if let Some(large_subgroup_root_of_unity) = Self::large_subgroup_root_of_unity() { - let q = Self::FftConfig::SMALL_SUBGROUP_BASE.expect( + if let Some(large_subgroup_root_of_unity) = Self::LARGE_SUBGROUP_ROOT_OF_UNITY { + let q = Self::SMALL_SUBGROUP_BASE.expect( "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE", - ) as usize; - let small_subgroup_base_adicity = Self::FftConfig::SMALL_SUBGROUP_BASE_ADICITY.expect( + ) as u64; + let small_subgroup_base_adicity = Self::SMALL_SUBGROUP_BASE_ADICITY.expect( "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE_ADICITY", ); let q_adicity = k_adicity(q, n); - let q_part = q.pow(q_adicity); + let q_part = q.checked_pow(q_adicity)?; let two_adicity = k_adicity(2, n); - let two_part = 1 << two_adicity; + let two_part = 2u64.checked_pow(two_adicity)?; if n != two_part * q_part - || (two_adicity > Self::FftConfig::TWO_ADICITY) + || (two_adicity > Self::TWO_ADICITY) || (q_adicity > small_subgroup_base_adicity) { return None; @@ -248,7 +234,7 @@ pub trait FftField: Field { omega = omega.pow(&[q as u64]); } - for _ in two_adicity..Self::FftConfig::TWO_ADICITY { + for _ in two_adicity..Self::TWO_ADICITY { omega.square_in_place(); } } else { @@ -256,14 +242,14 @@ pub trait FftField: Field { let size = n.next_power_of_two() as u64; let log_size_of_group = ark_std::log2(usize::try_from(size).expect("too large")); - if n != size as usize || log_size_of_group > Self::FftConfig::TWO_ADICITY { + if n != size || log_size_of_group > Self::TWO_ADICITY { return None; } // Compute the generator for the multiplicative subgroup. // It should be 2^(log_size_of_group) root of unity. - omega = Self::two_adic_root_of_unity(); - for _ in log_size_of_group..Self::FftConfig::TWO_ADICITY { + omega = Self::TWO_ADIC_ROOT_OF_UNITY; + for _ in log_size_of_group..Self::TWO_ADICITY { omega.square_in_place(); } } @@ -342,12 +328,6 @@ pub trait PrimeField: bytes_copy.reverse(); Self::from_be_bytes_mod_order(&bytes_copy) } - - /// Return QNR^t, for t coprime to 2, and for - /// a given quadratic non-residue. - fn qnr_to_t() -> Self { - Self::two_adic_root_of_unity() - } } /// The interface for a field that supports an efficient square-root operation. diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 19ad67eea..6d080fae3 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -22,7 +22,7 @@ use crate::{ }; /// A trait that specifies the configuration of a prime field. /// Also specifies how to perform arithmetic on field elements. -pub trait FpConfig: crate::FftConfig> { +pub trait FpConfig: Send + Sync + 'static + Sized { /// The modulus of the field. const MODULUS: crate::BigInt; @@ -39,6 +39,27 @@ pub trait FpConfig: crate::FftConfig> { /// such that, for all elements `f` of the field, `e * f = f`. const ONE: Fp; + /// Let `N` be the size of the multiplicative group defined by the field. + /// Then `TWO_ADICITY` is the two-adicity of `N`, i.e. the integer `s` + /// such that `N = 2^s * t` for some odd integer `t`. + const TWO_ADICITY: u32; + + /// 2^s root of unity computed by GENERATOR^t + const TWO_ADIC_ROOT_OF_UNITY: Fp; + + /// An integer `b` such that there exists a multiplicative subgroup + /// of size `b^k` for some integer `k`. + const SMALL_SUBGROUP_BASE: Option = None; + + /// The integer `k` such that there exists a multiplicative subgroup + /// of size `Self::SMALL_SUBGROUP_BASE^k`. + const SMALL_SUBGROUP_BASE_ADICITY: Option = None; + + /// GENERATOR^((MODULUS-1) / (2^s * + /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix + /// FFT. + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option> = None; + /// Set a += b. fn add_assign(a: &mut Fp, b: &Fp); @@ -69,7 +90,7 @@ pub trait FpConfig: crate::FftConfig> { // Try computing the square root (x at the end of the algorithm) // Check at the end of the algorithm if x was a square root // Begin Tonelli-Shanks - let mut z = Fp::qnr_to_t(); + let mut z = Fp::TWO_ADIC_ROOT_OF_UNITY; let mut w = a.pow(Fp::::TRACE_MINUS_ONE_DIV_TWO); let mut x = w * a; let mut b = x * &w; @@ -344,22 +365,12 @@ impl, const N: usize> PrimeField for Fp { } impl, const N: usize> FftField for Fp { - type FftConfig = P; - - #[inline] - fn two_adic_root_of_unity() -> Self { - P::TWO_ADIC_ROOT_OF_UNITY - } - - #[inline] - fn large_subgroup_root_of_unity() -> Option { - P::LARGE_SUBGROUP_ROOT_OF_UNITY - } - - #[inline] - fn multiplicative_generator() -> Self { - P::GENERATOR - } + const GENERATOR: Self = P::GENERATOR; + const TWO_ADICITY: u32 = P::TWO_ADICITY; + const TWO_ADIC_ROOT_OF_UNITY: Self = P::TWO_ADIC_ROOT_OF_UNITY; + const SMALL_SUBGROUP_BASE: Option = P::SMALL_SUBGROUP_BASE; + const SMALL_SUBGROUP_BASE_ADICITY: Option = P::SMALL_SUBGROUP_BASE_ADICITY; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = P::LARGE_SUBGROUP_ROOT_OF_UNITY; } impl, const N: usize> SquareRootField for Fp { diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 18052c93a..0795b877e 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -1,7 +1,7 @@ use ark_std::{marker::PhantomData, Zero}; use super::{Fp, FpConfig}; -use crate::{biginteger::arithmetic as fa, BigInt, BigInteger, FftConfig}; +use crate::{biginteger::arithmetic as fa, BigInt, BigInteger}; /// A trait that specifies the constants and arithmetic procedures /// for Montgomery arithmetic over the prime field defined by `MODULUS`. @@ -350,15 +350,6 @@ pub use MontFp; pub struct MontBackend(PhantomData); -impl, const N: usize> FftConfig for MontBackend { - type Field = Fp; - const TWO_ADICITY: u32 = Self::MODULUS.two_adic_valuation(); - const TWO_ADIC_ROOT_OF_UNITY: Self::Field = T::TWO_ADIC_ROOT_OF_UNITY; - const SMALL_SUBGROUP_BASE: Option = T::SMALL_SUBGROUP_BASE; - const SMALL_SUBGROUP_BASE_ADICITY: Option = T::SMALL_SUBGROUP_BASE_ADICITY; - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = T::LARGE_SUBGROUP_ROOT_OF_UNITY; -} - impl, const N: usize> FpConfig for MontBackend { /// The modulus of the field. const MODULUS: crate::BigInt = T::MODULUS; @@ -376,6 +367,12 @@ impl, const N: usize> FpConfig for MontBackend { /// such that, for all elements `f` of the field, `e * f = f`. const ONE: Fp = Fp::new(T::R); + const TWO_ADICITY: u32 = Self::MODULUS.two_adic_valuation(); + const TWO_ADIC_ROOT_OF_UNITY: Fp = T::TWO_ADIC_ROOT_OF_UNITY; + const SMALL_SUBGROUP_BASE: Option = T::SMALL_SUBGROUP_BASE; + const SMALL_SUBGROUP_BASE_ADICITY: Option = T::SMALL_SUBGROUP_BASE_ADICITY; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option> = T::LARGE_SUBGROUP_ROOT_OF_UNITY; + fn add_assign(a: &mut Fp, b: &Fp) { T::add_assign(a, b) } diff --git a/ff/src/fields/utils.rs b/ff/src/fields/utils.rs index 340eb4822..e670317b3 100644 --- a/ff/src/fields/utils.rs +++ b/ff/src/fields/utils.rs @@ -1,6 +1,6 @@ /// Calculates the k-adicity of n, i.e., the number of trailing 0s in a base-k /// representation. -pub fn k_adicity(k: usize, mut n: usize) -> u32 { +pub fn k_adicity(k: u64, mut n: u64) -> u32 { let mut r = 0; while n > 1 { if n % k == 0 { diff --git a/poly/src/domain/general.rs b/poly/src/domain/general.rs index 744956510..45993e15e 100644 --- a/poly/src/domain/general.rs +++ b/poly/src/domain/general.rs @@ -10,7 +10,7 @@ pub use crate::domain::utils::Elements; use crate::domain::{ DomainCoeff, EvaluationDomain, MixedRadixEvaluationDomain, Radix2EvaluationDomain, }; -use ark_ff::{FftConfig, FftField}; +use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ io::{Read, Write}, @@ -171,7 +171,7 @@ impl EvaluationDomain for GeneralEvaluationDomain { return Some(GeneralEvaluationDomain::Radix2(domain)); } - if F::FftConfig::SMALL_SUBGROUP_BASE.is_some() { + if F::SMALL_SUBGROUP_BASE.is_some() { return Some(GeneralEvaluationDomain::MixedRadix( MixedRadixEvaluationDomain::new(num_coeffs)?, )); @@ -186,7 +186,7 @@ impl EvaluationDomain for GeneralEvaluationDomain { return Some(domain_size); } - if F::FftConfig::SMALL_SUBGROUP_BASE.is_some() { + if F::SMALL_SUBGROUP_BASE.is_some() { return Some(MixedRadixEvaluationDomain::::compute_size_of_domain( num_coeffs, )?); diff --git a/poly/src/domain/mixed_radix.rs b/poly/src/domain/mixed_radix.rs index 48b8eaa0c..800e51d66 100644 --- a/poly/src/domain/mixed_radix.rs +++ b/poly/src/domain/mixed_radix.rs @@ -14,7 +14,7 @@ use crate::domain::{ utils::{best_fft, bitreverse}, DomainCoeff, EvaluationDomain, }; -use ark_ff::{fields::utils::k_adicity, FftConfig, FftField}; +use ark_ff::{fields::utils::k_adicity, FftField}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ cmp::min, @@ -63,18 +63,18 @@ impl EvaluationDomain for MixedRadixEvaluationDomain { /// Construct a domain that is large enough for evaluations of a polynomial /// having `num_coeffs` coefficients. fn new(num_coeffs: usize) -> Option { - let small_subgroup_base = F::FftConfig::SMALL_SUBGROUP_BASE?; + let small_subgroup_base = F::SMALL_SUBGROUP_BASE?; // Compute the best size of our evaluation domain. - let num_coeffs = best_mixed_domain_size::(num_coeffs); + let num_coeffs = best_mixed_domain_size::(num_coeffs) as u64; // Compute the size of our evaluation domain - let q = usize::try_from(small_subgroup_base).unwrap(); + let q = u64::from(small_subgroup_base); let q_adicity = k_adicity(q, num_coeffs); - let q_part = q.pow(q_adicity); + let q_part = q.checked_pow(q_adicity)?; let two_adicity = k_adicity(2, num_coeffs); - let two_part = 1 << two_adicity; + let two_part = 2u64.checked_pow(two_adicity)?; let size = u64::try_from(num_coeffs).unwrap(); let log_size_of_group = two_adicity; @@ -98,25 +98,25 @@ impl EvaluationDomain for MixedRadixEvaluationDomain { size_inv, group_gen, group_gen_inv: group_gen.inverse()?, - generator_inv: F::multiplicative_generator().inverse()?, + generator_inv: F::GENERATOR.inverse()?, }) } fn compute_size_of_domain(num_coeffs: usize) -> Option { - let small_subgroup_base = F::FftConfig::SMALL_SUBGROUP_BASE?; + let small_subgroup_base = F::SMALL_SUBGROUP_BASE?; // Compute the best size of our evaluation domain. - let num_coeffs = best_mixed_domain_size::(num_coeffs); + let num_coeffs = best_mixed_domain_size::(num_coeffs) as u64; - let q = usize::try_from(small_subgroup_base).unwrap(); + let q = u64::from(small_subgroup_base); let q_adicity = k_adicity(q, num_coeffs); - let q_part = q.pow(q_adicity); + let q_part = q.checked_pow(q_adicity)?; let two_adicity = k_adicity(2, num_coeffs); - let two_part = 1 << two_adicity; + let two_part = 2u64.checked_pow(two_adicity)?; if num_coeffs == q_part * two_part { - Some(num_coeffs) + Some(num_coeffs as usize) } else { None } @@ -290,8 +290,8 @@ fn mixed_radix_fft_permute( fn best_mixed_domain_size(min_size: usize) -> usize { let mut best = usize::max_value(); - let small_subgroup_base_adicity = F::FftConfig::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); - let small_subgroup_base = usize::try_from(F::FftConfig::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); + let small_subgroup_base_adicity = F::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); + let small_subgroup_base = usize::try_from(F::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); for b in 0..=small_subgroup_base_adicity { let mut r = small_subgroup_base.pow(b); @@ -302,7 +302,7 @@ fn best_mixed_domain_size(min_size: usize) -> usize { two_adicity += 1; } - if two_adicity <= F::FftConfig::TWO_ADICITY { + if two_adicity <= F::TWO_ADICITY { best = min(best, r); } } @@ -319,13 +319,15 @@ pub(crate) fn serial_mixed_radix_fft, F: FftField>( // and then splits into q sub-arrays q_adicity many times. let n = a.len(); - let q = usize::try_from(F::FftConfig::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); + let q = usize::try_from(F::SMALL_SUBGROUP_BASE.unwrap()).unwrap(); + let q_u64 = u64::from(F::SMALL_SUBGROUP_BASE.unwrap()); + let n_u64 = n as u64; - let q_adicity = k_adicity(q, n); - let q_part = q.pow(q_adicity); - let two_part = 1 << two_adicity; + let q_adicity = k_adicity(q_u64, n_u64); + let q_part = q_u64.checked_pow(q_adicity).unwrap(); + let two_part = 2u64.checked_pow(two_adicity).unwrap(); - assert_eq!(n, q_part * two_part); + assert_eq!(n_u64, q_part * two_part); let mut m = 1; // invariant: m = 2^{s-1} diff --git a/poly/src/domain/mod.rs b/poly/src/domain/mod.rs index 6ba231866..dabbd865b 100644 --- a/poly/src/domain/mod.rs +++ b/poly/src/domain/mod.rs @@ -143,7 +143,7 @@ pub trait EvaluationDomain: /// in place. #[inline] fn coset_fft_in_place>(&self, coeffs: &mut Vec) { - Self::distribute_powers(coeffs, F::multiplicative_generator()); + Self::distribute_powers(coeffs, F::GENERATOR); self.fft_in_place(coeffs); } @@ -160,7 +160,7 @@ pub trait EvaluationDomain: #[inline] fn coset_ifft_in_place>(&self, evals: &mut Vec) { self.ifft_in_place(evals); - Self::distribute_powers(evals, F::multiplicative_generator().inverse().unwrap()); + Self::distribute_powers(evals, self.generator_inv()); } /// Evaluate all the lagrange polynomials defined by this domain at the @@ -189,7 +189,7 @@ pub trait EvaluationDomain: /// a coset. fn divide_by_vanishing_poly_on_coset_in_place(&self, evals: &mut [F]) { let i = self - .evaluate_vanishing_polynomial(F::multiplicative_generator()) + .evaluate_vanishing_polynomial(F::GENERATOR) .inverse() .unwrap(); diff --git a/poly/src/domain/radix2/mod.rs b/poly/src/domain/radix2/mod.rs index a26f234d6..eda5d5590 100644 --- a/poly/src/domain/radix2/mod.rs +++ b/poly/src/domain/radix2/mod.rs @@ -5,7 +5,7 @@ pub use crate::domain::utils::Elements; use crate::domain::{DomainCoeff, EvaluationDomain}; -use ark_ff::{FftConfig, FftField}; +use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ convert::TryFrom, @@ -58,13 +58,13 @@ impl EvaluationDomain for Radix2EvaluationDomain { let log_size_of_group = size.trailing_zeros(); // libfqfft uses > https://github.com/scipr-lab/libfqfft/blob/e0183b2cef7d4c5deb21a6eaf3fe3b586d738fe0/libfqfft/evaluation_domain/domains/basic_radix2_domain.tcc#L33 - if log_size_of_group > F::FftConfig::TWO_ADICITY { + if log_size_of_group > F::TWO_ADICITY { return None; } // Compute the generator for the multiplicative subgroup. // It should be the 2^(log_size_of_group) root of unity. - let group_gen = F::get_root_of_unity(usize::try_from(size).unwrap())?; + let group_gen = F::get_root_of_unity(size)?; // Check that it is indeed the 2^(log_size_of_group) root of unity. debug_assert_eq!(group_gen.pow([size]), F::one()); let size_as_field_element = F::from(size); @@ -77,13 +77,13 @@ impl EvaluationDomain for Radix2EvaluationDomain { size_inv, group_gen, group_gen_inv: group_gen.inverse()?, - generator_inv: F::multiplicative_generator().inverse()?, + generator_inv: F::GENERATOR.inverse()?, }) } fn compute_size_of_domain(num_coeffs: usize) -> Option { let size = num_coeffs.checked_next_power_of_two()?; - if size.trailing_zeros() > F::FftConfig::TWO_ADICITY { + if size.trailing_zeros() > F::TWO_ADICITY { None } else { Some(size) @@ -362,7 +362,7 @@ mod tests { let poly_evals = domain.fft(&rand_poly.coeffs); let poly_coset_evals = domain.coset_fft(&rand_poly.coeffs); for (i, x) in domain.elements().enumerate() { - let coset_x = Fr::multiplicative_generator() * x; + let coset_x = Fr::GENERATOR * x; assert_eq!(poly_evals[i], rand_poly.evaluate(&x)); assert_eq!(poly_coset_evals[i], rand_poly.evaluate(&coset_x)); @@ -462,7 +462,7 @@ mod tests { } fn serial_radix2_coset_fft(a: &mut [Fr], omega: Fr, log_n: u32) { - let coset_shift = Fr::multiplicative_generator(); + let coset_shift = Fr::GENERATOR; let mut cur_pow = Fr::one(); for coeff in a.iter_mut() { *coeff *= cur_pow; @@ -473,7 +473,7 @@ mod tests { fn serial_radix2_coset_ifft(a: &mut [Fr], omega: Fr, log_n: u32) { serial_radix2_ifft(a, omega, log_n); - let coset_shift = Fr::multiplicative_generator().inverse().unwrap(); + let coset_shift = Fr::GENERATOR.inverse().unwrap(); let mut cur_pow = Fr::one(); for coeff in a.iter_mut() { *coeff *= cur_pow; diff --git a/poly/src/domain/utils.rs b/poly/src/domain/utils.rs index f27f04568..3ea29a7fa 100644 --- a/poly/src/domain/utils.rs +++ b/poly/src/domain/utils.rs @@ -129,7 +129,7 @@ pub(crate) fn parallel_fft, F: FftField>( // These are cosets with generator g^{num_cosets}, and varying shifts. let mut tmp = vec![vec![T::zero(); coset_size]; num_cosets]; let new_omega = omega.pow(&[num_cosets as u64]); - let new_two_adicity = ark_ff::utils::k_adicity(2, coset_size); + let new_two_adicity = ark_ff::utils::k_adicity(2, coset_size as u64); // For each coset, we first build a polynomial of degree |coset size|, // whose evaluations over coset k will agree with the evaluations of a over the coset. diff --git a/test-templates/src/fields.rs b/test-templates/src/fields.rs index 1e78f62e3..5a5e9c947 100644 --- a/test-templates/src/fields.rs +++ b/test-templates/src/fields.rs @@ -1,7 +1,7 @@ #![allow(unused)] #![allow(clippy::eq_op)] use ark_ff::{ - fields::{FftConfig, FftField, Field, LegendreSymbol, PrimeField, SquareRootField}, + fields::{FftField, Field, LegendreSymbol, PrimeField, SquareRootField}, Fp, MontBackend, MontConfig, }; use ark_serialize::{buffer_bit_byte_size, Flags, SWFlags}; @@ -309,28 +309,28 @@ pub fn field_test(a: F, b: F) { pub fn fft_field_test() { assert_eq!( - F::two_adic_root_of_unity().pow([1 << F::FftConfig::TWO_ADICITY]), + F::TWO_ADIC_ROOT_OF_UNITY.pow([1 << F::TWO_ADICITY]), F::one() ); - if let Some(small_subgroup_base) = F::FftConfig::SMALL_SUBGROUP_BASE { - let small_subgroup_base_adicity = F::FftConfig::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); - let large_subgroup_root_of_unity = F::large_subgroup_root_of_unity().unwrap(); - let pow = (1 << F::FftConfig::TWO_ADICITY) - * (small_subgroup_base as u64).pow(small_subgroup_base_adicity); + if let Some(small_subgroup_base) = F::SMALL_SUBGROUP_BASE { + let small_subgroup_base_adicity = F::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); + let large_subgroup_root_of_unity = F::LARGE_SUBGROUP_ROOT_OF_UNITY.unwrap(); + let pow = + (1 << F::TWO_ADICITY) * (small_subgroup_base as u64).pow(small_subgroup_base_adicity); assert_eq!(large_subgroup_root_of_unity.pow([pow]), F::one()); - for i in 0..F::FftConfig::TWO_ADICITY { + for i in 0..F::TWO_ADICITY { for j in 0..small_subgroup_base_adicity { use core::convert::TryFrom; let size = usize::try_from(1 << i as usize).unwrap() * usize::try_from((small_subgroup_base as u64).pow(j)).unwrap(); - let root = F::get_root_of_unity(size).unwrap(); + let root = F::get_root_of_unity(size as u64).unwrap(); assert_eq!(root.pow([size as u64]), F::one()); } } } else { - for i in 0..F::FftConfig::TWO_ADICITY { + for i in 0..F::TWO_ADICITY { let size = 1 << i; let root = F::get_root_of_unity(size).unwrap(); assert_eq!(root.pow([size as u64]), F::one()); @@ -347,6 +347,7 @@ pub fn primefield_test() { } pub fn montgomery_primefield_test, const N: usize>() { + use ark_ff::FpConfig; use num_bigint::BigUint; use num_integer::Integer; let modulus: BigUint = T::MODULUS.into(); @@ -379,9 +380,8 @@ pub fn montgomery_primefield_test, const N: usize>() { trace_minus_one_div_two ); - let two_adic_root_of_unity: BigUint = - Fp::, N>::two_adic_root_of_unity().into(); - let generator: BigUint = Fp::, N>::GENERATOR.into_bigint().into(); + let two_adic_root_of_unity: BigUint = >::TWO_ADIC_ROOT_OF_UNITY.into(); + let generator: BigUint = >::GENERATOR.into_bigint().into(); assert_eq!(two_adic_root_of_unity, generator.modpow(&trace, &modulus)); } From 9ce092a5a3bb28a5f019d758af28e6372acb7a3b Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Sat, 15 Jan 2022 13:43:15 -0800 Subject: [PATCH 32/32] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e745c024f..86d2ac9fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - Add default associated constants to reduce boilerplate. - Rename `Fp*Parameters` to `Fp*Config`. - Add `From`, `From`, and `From` `impl`s for `BigInt`. + - Remove `FftConfig`; move its contents to `FftField`. ### Features