diff --git a/src/fields.rs b/src/fields.rs index ccad57a..01be0c1 100644 --- a/src/fields.rs +++ b/src/fields.rs @@ -1,6 +1,7 @@ //! This module contains implementations for the two finite fields of the Pallas //! and Vesta curves. +mod common; mod fp; mod fq; diff --git a/src/fields/common.rs b/src/fields/common.rs new file mode 100644 index 0000000..0676139 --- /dev/null +++ b/src/fields/common.rs @@ -0,0 +1,488 @@ +macro_rules! field_operation { + ($field:ident, $modulus:ident, $inv:ident, $r:ident, $r2:ident, $r3:ident, $s:ident, $g:ident, $root_of_unity:ident, $modulus_limbs_32:ident) => { + impl fmt::Debug for $field { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let tmp = self.to_repr(); + write!(f, "0x")?; + for &b in tmp.iter().rev() { + write!(f, "{:02x}", b)?; + } + Ok(()) + } + } + + impl From for $field { + fn from(bit: bool) -> $field { + if bit { + $field::one() + } else { + $field::zero() + } + } + } + + impl From for $field { + fn from(val: u64) -> $field { + $field([val, 0, 0, 0]) * $r2 + } + } + + impl ConstantTimeEq for $field { + fn ct_eq(&self, other: &Self) -> Choice { + self.0[0].ct_eq(&other.0[0]) + & self.0[1].ct_eq(&other.0[1]) + & self.0[2].ct_eq(&other.0[2]) + & self.0[3].ct_eq(&other.0[3]) + } + } + + impl PartialEq for $field { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).unwrap_u8() == 1 + } + } + + impl core::cmp::Ord for $field { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + let left = self.to_repr(); + let right = other.to_repr(); + left.iter() + .zip(right.iter()) + .rev() + .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) { + core::cmp::Ordering::Equal => None, + res => Some(res), + }) + .unwrap_or(core::cmp::Ordering::Equal) + } + } + + impl core::cmp::PartialOrd for $field { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + impl ConditionallySelectable for $field { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> $field { + $field([ + u64::conditional_select(&a.0[0], &b.0[0], choice), + u64::conditional_select(&a.0[1], &b.0[1], choice), + u64::conditional_select(&a.0[2], &b.0[2], choice), + u64::conditional_select(&a.0[3], &b.0[3], choice), + ]) + } + } + + impl<'a> Neg for &'a $field { + type Output = $field; + + #[inline] + fn neg(self) -> $field { + self.neg() + } + } + + impl Neg for $field { + type Output = $field; + + #[inline] + fn neg(self) -> $field { + -&self + } + } + + impl<'a, 'b> Sub<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn sub(self, rhs: &'b $field) -> $field { + self.sub(rhs) + } + } + + impl<'a, 'b> Add<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn add(self, rhs: &'b $field) -> $field { + self.add(rhs) + } + } + + impl<'a, 'b> Mul<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn mul(self, rhs: &'b $field) -> $field { + self.mul(rhs) + } + } + + impl Default for $field { + #[inline] + fn default() -> Self { + Self::zero() + } + } + + impl $field { + /// Returns zero, the additive identity. + #[inline] + pub const fn zero() -> $field { + $field([0, 0, 0, 0]) + } + + /// Returns one, the multiplicative identity. + #[inline] + pub const fn one() -> $field { + $r + } + + /// Doubles this field element. + #[inline] + pub const fn double(&self) -> $field { + let r1 = self.0[0] << 1; + + let c = self.0[0] >> 63; + let tmp = self.0[1] << 1; + let r2 = tmp | c; + + let c = self.0[1] >> 63; + let tmp = self.0[2] << 1; + let r3 = tmp | c; + + let c = self.0[2] >> 63; + let tmp = self.0[3] << 1; + let r4 = tmp | c; + + (&$field([r1, r2, r3, r4])).sub(&$modulus) + } + + fn from_u512(limbs: [u64; 8]) -> $field { + // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits + // with the higher bits multiplied by 2^256. Thus, we perform two reductions + // + // 1. the lower bits are multiplied by R^2, as normal + // 2. the upper bits are multiplied by R^2 * 2^256 = R^3 + // + // and computing their sum in the field. It remains to see that arbitrary 256-bit + // numbers can be placed into Montgomery form safely using the reduction. The + // reduction works so long as the product is less than R=2^256 multiplied by + // the modulus. This holds because for any `c` smaller than the modulus, we have + // that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the + // reduction always works so long as `c` is in the field; in this case it is either the + // constant `R2` or `R3`. + let d0 = $field([limbs[0], limbs[1], limbs[2], limbs[3]]); + let d1 = $field([limbs[4], limbs[5], limbs[6], limbs[7]]); + // Convert to Montgomery form + d0 * $r2 + d1 * $r3 + } + + /// Converts from an integer represented in little endian + /// into its (congruent) `Fp` representation. + pub const fn from_raw(val: [u64; 4]) -> $field { + (&$field(val)).mul(&$r2) + } + + /// Squares this element. + #[inline] + pub const fn square(&self) -> $field { + let (r1, carry) = mac(0, self.0[0], self.0[1], 0); + let (r2, carry) = mac(0, self.0[0], self.0[2], carry); + let (r3, r4) = mac(0, self.0[0], self.0[3], carry); + + let (r3, carry) = mac(r3, self.0[1], self.0[2], 0); + let (r4, r5) = mac(r4, self.0[1], self.0[3], carry); + + let (r5, r6) = mac(r5, self.0[2], self.0[3], 0); + + let r7 = r6 >> 63; + let r6 = (r6 << 1) | (r5 >> 63); + let r5 = (r5 << 1) | (r4 >> 63); + let r4 = (r4 << 1) | (r3 >> 63); + let r3 = (r3 << 1) | (r2 >> 63); + let r2 = (r2 << 1) | (r1 >> 63); + let r1 = r1 << 1; + + let (r0, carry) = mac(0, self.0[0], self.0[0], 0); + let (r1, carry) = adc(0, r1, carry); + let (r2, carry) = mac(r2, self.0[1], self.0[1], carry); + let (r3, carry) = adc(0, r3, carry); + let (r4, carry) = mac(r4, self.0[2], self.0[2], carry); + let (r5, carry) = adc(0, r5, carry); + let (r6, carry) = mac(r6, self.0[3], self.0[3], carry); + let (r7, _) = adc(0, r7, carry); + + $field::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) + } + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + const fn montgomery_reduce( + r0: u64, + r1: u64, + r2: u64, + r3: u64, + r4: u64, + r5: u64, + r6: u64, + r7: u64, + ) -> $field { + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + + let k = r0.wrapping_mul($inv); + let (_, carry) = mac(r0, k, $modulus.0[0], 0); + let (r1, carry) = mac(r1, k, $modulus.0[1], carry); + let (r2, carry) = mac(r2, k, $modulus.0[2], carry); + let (r3, carry) = mac(r3, k, $modulus.0[3], carry); + let (r4, carry2) = adc(r4, 0, carry); + + let k = r1.wrapping_mul(INV); + let (_, carry) = mac(r1, k, $modulus.0[0], 0); + let (r2, carry) = mac(r2, k, $modulus.0[1], carry); + let (r3, carry) = mac(r3, k, $modulus.0[2], carry); + let (r4, carry) = mac(r4, k, $modulus.0[3], carry); + let (r5, carry2) = adc(r5, carry2, carry); + + let k = r2.wrapping_mul(INV); + let (_, carry) = mac(r2, k, $modulus.0[0], 0); + let (r3, carry) = mac(r3, k, $modulus.0[1], carry); + let (r4, carry) = mac(r4, k, $modulus.0[2], carry); + let (r5, carry) = mac(r5, k, $modulus.0[3], carry); + let (r6, carry2) = adc(r6, carry2, carry); + + let k = r3.wrapping_mul(INV); + let (_, carry) = mac(r3, k, $modulus.0[0], 0); + let (r4, carry) = mac(r4, k, $modulus.0[1], carry); + let (r5, carry) = mac(r5, k, $modulus.0[2], carry); + let (r6, carry) = mac(r6, k, $modulus.0[3], carry); + let (r7, _) = adc(r7, carry2, carry); + + // Result may be within MODULUS of the correct value + (&$field([r4, r5, r6, r7])).sub(&$modulus) + } + + /// Multiplies `rhs` by `self`, returning the result. + #[inline] + pub const fn mul(&self, rhs: &Self) -> $field { + // Schoolbook multiplication + + let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0); + let (r1, carry) = mac(0, self.0[0], rhs.0[1], carry); + let (r2, carry) = mac(0, self.0[0], rhs.0[2], carry); + let (r3, r4) = mac(0, self.0[0], rhs.0[3], carry); + + let (r1, carry) = mac(r1, self.0[1], rhs.0[0], 0); + let (r2, carry) = mac(r2, self.0[1], rhs.0[1], carry); + let (r3, carry) = mac(r3, self.0[1], rhs.0[2], carry); + let (r4, r5) = mac(r4, self.0[1], rhs.0[3], carry); + + let (r2, carry) = mac(r2, self.0[2], rhs.0[0], 0); + let (r3, carry) = mac(r3, self.0[2], rhs.0[1], carry); + let (r4, carry) = mac(r4, self.0[2], rhs.0[2], carry); + let (r5, r6) = mac(r5, self.0[2], rhs.0[3], carry); + + let (r3, carry) = mac(r3, self.0[3], rhs.0[0], 0); + let (r4, carry) = mac(r4, self.0[3], rhs.0[1], carry); + let (r5, carry) = mac(r5, self.0[3], rhs.0[2], carry); + let (r6, r7) = mac(r6, self.0[3], rhs.0[3], carry); + + $field::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) + } + + /// Subtracts `rhs` from `self`, returning the result. + #[inline] + pub const fn sub(&self, rhs: &$field) -> $field { + let (d0, borrow) = sbb(self.0[0], rhs.0[0], 0); + let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); + let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); + let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow); + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. + let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); + let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); + let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); + let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry); + + $field([d0, d1, d2, d3]) + } + + /// Adds `rhs` to `self`, returning the result. + #[inline] + pub const fn add(&self, rhs: &$field) -> $field { + let (d0, carry) = adc(self.0[0], rhs.0[0], 0); + let (d1, carry) = adc(self.0[1], rhs.0[1], carry); + let (d2, carry) = adc(self.0[2], rhs.0[2], carry); + let (d3, _) = adc(self.0[3], rhs.0[3], carry); + + // Attempt to subtract the modulus, to ensure the value + // is smaller than the modulus. + (&$field([d0, d1, d2, d3])).sub(&$modulus) + } + + /// Negates `self`. + #[inline] + pub const fn neg(&self) -> $field { + // Subtract `self` from `MODULUS` to negate. Ignore the final + // borrow because it cannot underflow; self is guaranteed to + // be in the field. + let (d0, borrow) = sbb($modulus.0[0], self.0[0], 0); + let (d1, borrow) = sbb($modulus.0[1], self.0[1], borrow); + let (d2, borrow) = sbb($modulus.0[2], self.0[2], borrow); + let (d3, _) = sbb($modulus.0[3], self.0[3], borrow); + + // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is + // zero if `self` was zero, and `u64::max_value()` if self was nonzero. + let mask = + (((self.0[0] | self.0[1] | self.0[2] | self.0[3]) == 0) as u64).wrapping_sub(1); + + $field([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) + } + } + + impl From<$field> for [u8; 32] { + fn from(value: $field) -> [u8; 32] { + value.to_repr() + } + } + + impl<'a> From<&'a $field> for [u8; 32] { + fn from(value: &'a $field) -> [u8; 32] { + value.to_repr() + } + } + + impl Group for $field { + type Scalar = $field; + + fn group_zero() -> Self { + Self::zero() + } + fn group_add(&mut self, rhs: &Self) { + *self += *rhs; + } + fn group_sub(&mut self, rhs: &Self) { + *self -= *rhs; + } + fn group_scale(&mut self, by: &Self::Scalar) { + *self *= *by; + } + } + + impl ff::PrimeField for $field { + type Repr = [u8; 32]; + + const NUM_BITS: u32 = 255; + const CAPACITY: u32 = 254; + const S: u32 = $s; + + fn from_repr(repr: Self::Repr) -> CtOption<$field> { + let mut tmp = $field([0, 0, 0, 0]); + + tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); + tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); + tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); + tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); + + // Try to subtract the modulus + let (_, borrow) = sbb(tmp.0[0], $modulus.0[0], 0); + let (_, borrow) = sbb(tmp.0[1], $modulus.0[1], borrow); + let (_, borrow) = sbb(tmp.0[2], $modulus.0[2], borrow); + let (_, borrow) = sbb(tmp.0[3], $modulus.0[3], borrow); + + // If the element is smaller than MODULUS then the + // subtraction will underflow, producing a borrow value + // of 0xffff...ffff. Otherwise, it'll be zero. + let is_some = (borrow as u8) & 1; + + // Convert to Montgomery form by computing + // (a.R^0 * R^2) / R = a.R + tmp *= &R2; + + CtOption::new(tmp, Choice::from(is_some)) + } + + fn to_repr(&self) -> Self::Repr { + // Turn into canonical form by computing + // (a.R) / R = a + let tmp = $field::montgomery_reduce( + self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0, + ); + + let mut res = [0; 32]; + res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); + res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); + res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); + res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); + + res + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr()[0] & 1) + } + + fn multiplicative_generator() -> $field { + $g + } + + fn root_of_unity() -> $field { + $root_of_unity + } + } + + #[cfg(all(feature = "bits", not(target_pointer_width = "64")))] + type ReprBits = [u32; 8]; + + #[cfg(all(feature = "bits", target_pointer_width = "64"))] + type ReprBits = [u64; 4]; + + #[cfg(feature = "bits")] + impl PrimeFieldBits for $field { + type ReprBits = ReprBits; + + fn to_le_bits(&self) -> FieldBits { + let bytes = self.to_repr(); + + #[cfg(not(target_pointer_width = "64"))] + let limbs = [ + u32::from_le_bytes(bytes[0..4].try_into().unwrap()), + u32::from_le_bytes(bytes[4..8].try_into().unwrap()), + u32::from_le_bytes(bytes[8..12].try_into().unwrap()), + u32::from_le_bytes(bytes[12..16].try_into().unwrap()), + u32::from_le_bytes(bytes[16..20].try_into().unwrap()), + u32::from_le_bytes(bytes[20..24].try_into().unwrap()), + u32::from_le_bytes(bytes[24..28].try_into().unwrap()), + u32::from_le_bytes(bytes[28..32].try_into().unwrap()), + ]; + + #[cfg(target_pointer_width = "64")] + let limbs = [ + u64::from_le_bytes(bytes[0..8].try_into().unwrap()), + u64::from_le_bytes(bytes[8..16].try_into().unwrap()), + u64::from_le_bytes(bytes[16..24].try_into().unwrap()), + u64::from_le_bytes(bytes[24..32].try_into().unwrap()), + ]; + + FieldBits::new(limbs) + } + + fn char_le_bits() -> FieldBits { + #[cfg(not(target_pointer_width = "64"))] + { + FieldBits::new($modulus_limbs_32) + } + + #[cfg(target_pointer_width = "64")] + FieldBits::new($modulus.0) + } + } + }; +} + +pub(crate) use field_operation; diff --git a/src/fields/fp.rs b/src/fields/fp.rs index bf46141..4f4907d 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -13,6 +13,8 @@ use ff::{FieldBits, PrimeFieldBits}; use crate::arithmetic::{adc, mac, sbb, FieldExt, Group, SqrtRatio}; +use crate::fields::common::field_operation; + #[cfg(feature = "sqrt-table")] use crate::arithmetic::SqrtTables; @@ -28,81 +30,6 @@ use crate::arithmetic::SqrtTables; #[repr(transparent)] pub struct Fp(pub(crate) [u64; 4]); -impl fmt::Debug for Fp { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let tmp = self.to_repr(); - write!(f, "0x")?; - for &b in tmp.iter().rev() { - write!(f, "{:02x}", b)?; - } - Ok(()) - } -} - -impl From for Fp { - fn from(bit: bool) -> Fp { - if bit { - Fp::one() - } else { - Fp::zero() - } - } -} - -impl From for Fp { - fn from(val: u64) -> Fp { - Fp([val, 0, 0, 0]) * R2 - } -} - -impl ConstantTimeEq for Fp { - fn ct_eq(&self, other: &Self) -> Choice { - self.0[0].ct_eq(&other.0[0]) - & self.0[1].ct_eq(&other.0[1]) - & self.0[2].ct_eq(&other.0[2]) - & self.0[3].ct_eq(&other.0[3]) - } -} - -impl PartialEq for Fp { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.ct_eq(other).unwrap_u8() == 1 - } -} - -impl core::cmp::Ord for Fp { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let left = self.to_repr(); - let right = other.to_repr(); - left.iter() - .zip(right.iter()) - .rev() - .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) { - core::cmp::Ordering::Equal => None, - res => Some(res), - }) - .unwrap_or(core::cmp::Ordering::Equal) - } -} - -impl core::cmp::PartialOrd for Fp { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl ConditionallySelectable for Fp { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fp([ - u64::conditional_select(&a.0[0], &b.0[0], choice), - u64::conditional_select(&a.0[1], &b.0[1], choice), - u64::conditional_select(&a.0[2], &b.0[2], choice), - u64::conditional_select(&a.0[3], &b.0[3], choice), - ]) - } -} - /// Constant representing the modulus /// p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 const MODULUS: Fp = Fp([ @@ -125,51 +52,6 @@ const MODULUS_LIMBS_32: [u32; 8] = [ 0x4000_0000, ]; -impl<'a> Neg for &'a Fp { - type Output = Fp; - - #[inline] - fn neg(self) -> Fp { - self.neg() - } -} - -impl Neg for Fp { - type Output = Fp; - - #[inline] - fn neg(self) -> Fp { - -&self - } -} - -impl<'a, 'b> Sub<&'b Fp> for &'a Fp { - type Output = Fp; - - #[inline] - fn sub(self, rhs: &'b Fp) -> Fp { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fp> for &'a Fp { - type Output = Fp; - - #[inline] - fn add(self, rhs: &'b Fp) -> Fp { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fp> for &'a Fp { - type Output = Fp; - - #[inline] - fn mul(self, rhs: &'b Fp) -> Fp { - self.mul(rhs) - } -} - impl_binops_additive!(Fp, Fp); impl_binops_multiplicative!(Fp, Fp); @@ -239,258 +121,18 @@ const T_MINUS1_OVER2: [u64; 4] = [ 0x0000_0000_2000_0000, ]; -impl Default for Fp { - #[inline] - fn default() -> Self { - Self::zero() - } -} - -impl Fp { - /// Returns zero, the additive identity. - #[inline] - pub const fn zero() -> Fp { - Fp([0, 0, 0, 0]) - } - - /// Returns one, the multiplicative identity. - #[inline] - pub const fn one() -> Fp { - R - } - - /// Doubles this field element. - #[inline] - pub const fn double(&self) -> Fp { - let r1 = self.0[0] << 1; - - let c = self.0[0] >> 63; - let tmp = self.0[1] << 1; - let r2 = tmp | c; - - let c = self.0[1] >> 63; - let tmp = self.0[2] << 1; - let r3 = tmp | c; - - let c = self.0[2] >> 63; - let tmp = self.0[3] << 1; - let r4 = tmp | c; - - (&Fp([r1, r2, r3, r4])).sub(&MODULUS) - } - - fn from_u512(limbs: [u64; 8]) -> Fp { - // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits - // with the higher bits multiplied by 2^256. Thus, we perform two reductions - // - // 1. the lower bits are multiplied by R^2, as normal - // 2. the upper bits are multiplied by R^2 * 2^256 = R^3 - // - // and computing their sum in the field. It remains to see that arbitrary 256-bit - // numbers can be placed into Montgomery form safely using the reduction. The - // reduction works so long as the product is less than R=2^256 multiplied by - // the modulus. This holds because for any `c` smaller than the modulus, we have - // that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the - // reduction always works so long as `c` is in the field; in this case it is either the - // constant `R2` or `R3`. - let d0 = Fp([limbs[0], limbs[1], limbs[2], limbs[3]]); - let d1 = Fp([limbs[4], limbs[5], limbs[6], limbs[7]]); - // Convert to Montgomery form - d0 * R2 + d1 * R3 - } - - /// Converts from an integer represented in little endian - /// into its (congruent) `Fp` representation. - pub const fn from_raw(val: [u64; 4]) -> Self { - (&Fp(val)).mul(&R2) - } - - /// Squares this element. - #[inline] - pub const fn square(&self) -> Fp { - let (r1, carry) = mac(0, self.0[0], self.0[1], 0); - let (r2, carry) = mac(0, self.0[0], self.0[2], carry); - let (r3, r4) = mac(0, self.0[0], self.0[3], carry); - - let (r3, carry) = mac(r3, self.0[1], self.0[2], 0); - let (r4, r5) = mac(r4, self.0[1], self.0[3], carry); - - let (r5, r6) = mac(r5, self.0[2], self.0[3], 0); - - let r7 = r6 >> 63; - let r6 = (r6 << 1) | (r5 >> 63); - let r5 = (r5 << 1) | (r4 >> 63); - let r4 = (r4 << 1) | (r3 >> 63); - let r3 = (r3 << 1) | (r2 >> 63); - let r2 = (r2 << 1) | (r1 >> 63); - let r1 = r1 << 1; - - let (r0, carry) = mac(0, self.0[0], self.0[0], 0); - let (r1, carry) = adc(0, r1, carry); - let (r2, carry) = mac(r2, self.0[1], self.0[1], carry); - let (r3, carry) = adc(0, r3, carry); - let (r4, carry) = mac(r4, self.0[2], self.0[2], carry); - let (r5, carry) = adc(0, r5, carry); - let (r6, carry) = mac(r6, self.0[3], self.0[3], carry); - let (r7, _) = adc(0, r7, carry); - - Fp::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) - } - - #[allow(clippy::too_many_arguments)] - #[inline(always)] - const fn montgomery_reduce( - r0: u64, - r1: u64, - r2: u64, - r3: u64, - r4: u64, - r5: u64, - r6: u64, - r7: u64, - ) -> Self { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r0.wrapping_mul(INV); - let (_, carry) = mac(r0, k, MODULUS.0[0], 0); - let (r1, carry) = mac(r1, k, MODULUS.0[1], carry); - let (r2, carry) = mac(r2, k, MODULUS.0[2], carry); - let (r3, carry) = mac(r3, k, MODULUS.0[3], carry); - let (r4, carry2) = adc(r4, 0, carry); - - let k = r1.wrapping_mul(INV); - let (_, carry) = mac(r1, k, MODULUS.0[0], 0); - let (r2, carry) = mac(r2, k, MODULUS.0[1], carry); - let (r3, carry) = mac(r3, k, MODULUS.0[2], carry); - let (r4, carry) = mac(r4, k, MODULUS.0[3], carry); - let (r5, carry2) = adc(r5, carry2, carry); - - let k = r2.wrapping_mul(INV); - let (_, carry) = mac(r2, k, MODULUS.0[0], 0); - let (r3, carry) = mac(r3, k, MODULUS.0[1], carry); - let (r4, carry) = mac(r4, k, MODULUS.0[2], carry); - let (r5, carry) = mac(r5, k, MODULUS.0[3], carry); - let (r6, carry2) = adc(r6, carry2, carry); - - let k = r3.wrapping_mul(INV); - let (_, carry) = mac(r3, k, MODULUS.0[0], 0); - let (r4, carry) = mac(r4, k, MODULUS.0[1], carry); - let (r5, carry) = mac(r5, k, MODULUS.0[2], carry); - let (r6, carry) = mac(r6, k, MODULUS.0[3], carry); - let (r7, _) = adc(r7, carry2, carry); - - // Result may be within MODULUS of the correct value - (&Fp([r4, r5, r6, r7])).sub(&MODULUS) - } - - /// Multiplies `rhs` by `self`, returning the result. - #[inline] - pub const fn mul(&self, rhs: &Self) -> Self { - // Schoolbook multiplication - - let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0); - let (r1, carry) = mac(0, self.0[0], rhs.0[1], carry); - let (r2, carry) = mac(0, self.0[0], rhs.0[2], carry); - let (r3, r4) = mac(0, self.0[0], rhs.0[3], carry); - - let (r1, carry) = mac(r1, self.0[1], rhs.0[0], 0); - let (r2, carry) = mac(r2, self.0[1], rhs.0[1], carry); - let (r3, carry) = mac(r3, self.0[1], rhs.0[2], carry); - let (r4, r5) = mac(r4, self.0[1], rhs.0[3], carry); - - let (r2, carry) = mac(r2, self.0[2], rhs.0[0], 0); - let (r3, carry) = mac(r3, self.0[2], rhs.0[1], carry); - let (r4, carry) = mac(r4, self.0[2], rhs.0[2], carry); - let (r5, r6) = mac(r5, self.0[2], rhs.0[3], carry); - - let (r3, carry) = mac(r3, self.0[3], rhs.0[0], 0); - let (r4, carry) = mac(r4, self.0[3], rhs.0[1], carry); - let (r5, carry) = mac(r5, self.0[3], rhs.0[2], carry); - let (r6, r7) = mac(r6, self.0[3], rhs.0[3], carry); - - Fp::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) - } - - /// Subtracts `rhs` from `self`, returning the result. - #[inline] - pub const fn sub(&self, rhs: &Self) -> Self { - let (d0, borrow) = sbb(self.0[0], rhs.0[0], 0); - let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); - let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); - let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow); - - // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise - // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. - let (d0, carry) = adc(d0, MODULUS.0[0] & borrow, 0); - let (d1, carry) = adc(d1, MODULUS.0[1] & borrow, carry); - let (d2, carry) = adc(d2, MODULUS.0[2] & borrow, carry); - let (d3, _) = adc(d3, MODULUS.0[3] & borrow, carry); - - Fp([d0, d1, d2, d3]) - } - - /// Adds `rhs` to `self`, returning the result. - #[inline] - pub const fn add(&self, rhs: &Self) -> Self { - let (d0, carry) = adc(self.0[0], rhs.0[0], 0); - let (d1, carry) = adc(self.0[1], rhs.0[1], carry); - let (d2, carry) = adc(self.0[2], rhs.0[2], carry); - let (d3, _) = adc(self.0[3], rhs.0[3], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - (&Fp([d0, d1, d2, d3])).sub(&MODULUS) - } - - /// Negates `self`. - #[inline] - pub const fn neg(&self) -> Self { - // Subtract `self` from `MODULUS` to negate. Ignore the final - // borrow because it cannot underflow; self is guaranteed to - // be in the field. - let (d0, borrow) = sbb(MODULUS.0[0], self.0[0], 0); - let (d1, borrow) = sbb(MODULUS.0[1], self.0[1], borrow); - let (d2, borrow) = sbb(MODULUS.0[2], self.0[2], borrow); - let (d3, _) = sbb(MODULUS.0[3], self.0[3], borrow); - - // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is - // zero if `self` was zero, and `u64::max_value()` if self was nonzero. - let mask = (((self.0[0] | self.0[1] | self.0[2] | self.0[3]) == 0) as u64).wrapping_sub(1); - - Fp([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) - } -} - -impl From for [u8; 32] { - fn from(value: Fp) -> [u8; 32] { - value.to_repr() - } -} - -impl<'a> From<&'a Fp> for [u8; 32] { - fn from(value: &'a Fp) -> [u8; 32] { - value.to_repr() - } -} - -impl Group for Fp { - type Scalar = Fp; - - fn group_zero() -> Self { - Self::zero() - } - fn group_add(&mut self, rhs: &Self) { - *self += *rhs; - } - fn group_sub(&mut self, rhs: &Self) { - *self -= *rhs; - } - fn group_scale(&mut self, by: &Self::Scalar) { - *self *= *by; - } -} +field_operation!( + Fp, + MODULUS, + INV, + R, + R2, + R3, + S, + GENERATOR, + ROOT_OF_UNITY, + MODULUS_LIMBS_32 +); impl ff::Field for Fp { fn random(mut rng: impl RngCore) -> Self { @@ -567,114 +209,6 @@ impl ff::Field for Fp { } } -impl ff::PrimeField for Fp { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 255; - const CAPACITY: u32 = 254; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Fp([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = Fp::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); - - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } - - fn multiplicative_generator() -> Self { - GENERATOR - } - - fn root_of_unity() -> Self { - ROOT_OF_UNITY - } -} - -#[cfg(all(feature = "bits", not(target_pointer_width = "64")))] -type ReprBits = [u32; 8]; - -#[cfg(all(feature = "bits", target_pointer_width = "64"))] -type ReprBits = [u64; 4]; - -#[cfg(feature = "bits")] -#[cfg_attr(docsrs, doc(cfg(feature = "bits")))] -impl PrimeFieldBits for Fp { - type ReprBits = ReprBits; - - fn to_le_bits(&self) -> FieldBits { - let bytes = self.to_repr(); - - #[cfg(not(target_pointer_width = "64"))] - let limbs = [ - u32::from_le_bytes(bytes[0..4].try_into().unwrap()), - u32::from_le_bytes(bytes[4..8].try_into().unwrap()), - u32::from_le_bytes(bytes[8..12].try_into().unwrap()), - u32::from_le_bytes(bytes[12..16].try_into().unwrap()), - u32::from_le_bytes(bytes[16..20].try_into().unwrap()), - u32::from_le_bytes(bytes[20..24].try_into().unwrap()), - u32::from_le_bytes(bytes[24..28].try_into().unwrap()), - u32::from_le_bytes(bytes[28..32].try_into().unwrap()), - ]; - - #[cfg(target_pointer_width = "64")] - let limbs = [ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - ]; - - FieldBits::new(limbs) - } - - fn char_le_bits() -> FieldBits { - #[cfg(not(target_pointer_width = "64"))] - { - FieldBits::new(MODULUS_LIMBS_32) - } - - #[cfg(target_pointer_width = "64")] - FieldBits::new(MODULUS.0) - } -} - #[cfg(feature = "sqrt-table")] lazy_static! { // The perfect hash parameters are found by `squareroottab.sage` in zcash/pasta. diff --git a/src/fields/fq.rs b/src/fields/fq.rs index d872295..2381afe 100644 --- a/src/fields/fq.rs +++ b/src/fields/fq.rs @@ -13,6 +13,8 @@ use ff::{FieldBits, PrimeFieldBits}; use crate::arithmetic::{adc, mac, sbb, FieldExt, Group, SqrtRatio}; +use crate::fields::common::field_operation; + #[cfg(feature = "sqrt-table")] use crate::arithmetic::SqrtTables; @@ -28,81 +30,6 @@ use crate::arithmetic::SqrtTables; #[repr(transparent)] pub struct Fq(pub(crate) [u64; 4]); -impl fmt::Debug for Fq { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let tmp = self.to_repr(); - write!(f, "0x")?; - for &b in tmp.iter().rev() { - write!(f, "{:02x}", b)?; - } - Ok(()) - } -} - -impl From for Fq { - fn from(bit: bool) -> Fq { - if bit { - Fq::one() - } else { - Fq::zero() - } - } -} - -impl From for Fq { - fn from(val: u64) -> Fq { - Fq([val, 0, 0, 0]) * R2 - } -} - -impl ConstantTimeEq for Fq { - fn ct_eq(&self, other: &Self) -> Choice { - self.0[0].ct_eq(&other.0[0]) - & self.0[1].ct_eq(&other.0[1]) - & self.0[2].ct_eq(&other.0[2]) - & self.0[3].ct_eq(&other.0[3]) - } -} - -impl PartialEq for Fq { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.ct_eq(other).unwrap_u8() == 1 - } -} - -impl core::cmp::Ord for Fq { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let left = self.to_repr(); - let right = other.to_repr(); - left.iter() - .zip(right.iter()) - .rev() - .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) { - core::cmp::Ordering::Equal => None, - res => Some(res), - }) - .unwrap_or(core::cmp::Ordering::Equal) - } -} - -impl core::cmp::PartialOrd for Fq { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl ConditionallySelectable for Fq { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fq([ - u64::conditional_select(&a.0[0], &b.0[0], choice), - u64::conditional_select(&a.0[1], &b.0[1], choice), - u64::conditional_select(&a.0[2], &b.0[2], choice), - u64::conditional_select(&a.0[3], &b.0[3], choice), - ]) - } -} - /// Constant representing the modulus /// q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 const MODULUS: Fq = Fq([ @@ -125,51 +52,6 @@ const MODULUS_LIMBS_32: [u32; 8] = [ 0x4000_0000, ]; -impl<'a> Neg for &'a Fq { - type Output = Fq; - - #[inline] - fn neg(self) -> Fq { - self.neg() - } -} - -impl Neg for Fq { - type Output = Fq; - - #[inline] - fn neg(self) -> Fq { - -&self - } -} - -impl<'a, 'b> Sub<&'b Fq> for &'a Fq { - type Output = Fq; - - #[inline] - fn sub(self, rhs: &'b Fq) -> Fq { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fq> for &'a Fq { - type Output = Fq; - - #[inline] - fn add(self, rhs: &'b Fq) -> Fq { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fq> for &'a Fq { - type Output = Fq; - - #[inline] - fn mul(self, rhs: &'b Fq) -> Fq { - self.mul(rhs) - } -} - impl_binops_additive!(Fq, Fq); impl_binops_multiplicative!(Fq, Fq); @@ -239,258 +121,18 @@ const T_MINUS1_OVER2: [u64; 4] = [ 0x0000_0000_2000_0000, ]; -impl Default for Fq { - #[inline] - fn default() -> Self { - Self::zero() - } -} - -impl Fq { - /// Returns zero, the additive identity. - #[inline] - pub const fn zero() -> Fq { - Fq([0, 0, 0, 0]) - } - - /// Returns one, the multiplicative identity. - #[inline] - pub const fn one() -> Fq { - R - } - - /// Doubles this field element. - #[inline] - pub const fn double(&self) -> Fq { - let r1 = self.0[0] << 1; - - let c = self.0[0] >> 63; - let tmp = self.0[1] << 1; - let r2 = tmp | c; - - let c = self.0[1] >> 63; - let tmp = self.0[2] << 1; - let r3 = tmp | c; - - let c = self.0[2] >> 63; - let tmp = self.0[3] << 1; - let r4 = tmp | c; - - (&Fq([r1, r2, r3, r4])).sub(&MODULUS) - } - - fn from_u512(limbs: [u64; 8]) -> Fq { - // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits - // with the higher bits multiplied by 2^256. Thus, we perform two reductions - // - // 1. the lower bits are multiplied by R^2, as normal - // 2. the upper bits are multiplied by R^2 * 2^256 = R^3 - // - // and computing their sum in the field. It remains to see that arbitrary 256-bit - // numbers can be placed into Montgomery form safely using the reduction. The - // reduction works so long as the product is less than R=2^256 multiplied by - // the modulus. This holds because for any `c` smaller than the modulus, we have - // that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the - // reduction always works so long as `c` is in the field; in this case it is either the - // constant `R2` or `R3`. - let d0 = Fq([limbs[0], limbs[1], limbs[2], limbs[3]]); - let d1 = Fq([limbs[4], limbs[5], limbs[6], limbs[7]]); - // Convert to Montgomery form - d0 * R2 + d1 * R3 - } - - /// Converts from an integer represented in little endian - /// into its (congruent) `Fq` representation. - pub const fn from_raw(val: [u64; 4]) -> Self { - (&Fq(val)).mul(&R2) - } - - /// Squares this element. - #[inline] - pub const fn square(&self) -> Fq { - let (r1, carry) = mac(0, self.0[0], self.0[1], 0); - let (r2, carry) = mac(0, self.0[0], self.0[2], carry); - let (r3, r4) = mac(0, self.0[0], self.0[3], carry); - - let (r3, carry) = mac(r3, self.0[1], self.0[2], 0); - let (r4, r5) = mac(r4, self.0[1], self.0[3], carry); - - let (r5, r6) = mac(r5, self.0[2], self.0[3], 0); - - let r7 = r6 >> 63; - let r6 = (r6 << 1) | (r5 >> 63); - let r5 = (r5 << 1) | (r4 >> 63); - let r4 = (r4 << 1) | (r3 >> 63); - let r3 = (r3 << 1) | (r2 >> 63); - let r2 = (r2 << 1) | (r1 >> 63); - let r1 = r1 << 1; - - let (r0, carry) = mac(0, self.0[0], self.0[0], 0); - let (r1, carry) = adc(0, r1, carry); - let (r2, carry) = mac(r2, self.0[1], self.0[1], carry); - let (r3, carry) = adc(0, r3, carry); - let (r4, carry) = mac(r4, self.0[2], self.0[2], carry); - let (r5, carry) = adc(0, r5, carry); - let (r6, carry) = mac(r6, self.0[3], self.0[3], carry); - let (r7, _) = adc(0, r7, carry); - - Fq::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) - } - - #[allow(clippy::too_many_arguments)] - #[inline(always)] - const fn montgomery_reduce( - r0: u64, - r1: u64, - r2: u64, - r3: u64, - r4: u64, - r5: u64, - r6: u64, - r7: u64, - ) -> Self { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r0.wrapping_mul(INV); - let (_, carry) = mac(r0, k, MODULUS.0[0], 0); - let (r1, carry) = mac(r1, k, MODULUS.0[1], carry); - let (r2, carry) = mac(r2, k, MODULUS.0[2], carry); - let (r3, carry) = mac(r3, k, MODULUS.0[3], carry); - let (r4, carry2) = adc(r4, 0, carry); - - let k = r1.wrapping_mul(INV); - let (_, carry) = mac(r1, k, MODULUS.0[0], 0); - let (r2, carry) = mac(r2, k, MODULUS.0[1], carry); - let (r3, carry) = mac(r3, k, MODULUS.0[2], carry); - let (r4, carry) = mac(r4, k, MODULUS.0[3], carry); - let (r5, carry2) = adc(r5, carry2, carry); - - let k = r2.wrapping_mul(INV); - let (_, carry) = mac(r2, k, MODULUS.0[0], 0); - let (r3, carry) = mac(r3, k, MODULUS.0[1], carry); - let (r4, carry) = mac(r4, k, MODULUS.0[2], carry); - let (r5, carry) = mac(r5, k, MODULUS.0[3], carry); - let (r6, carry2) = adc(r6, carry2, carry); - - let k = r3.wrapping_mul(INV); - let (_, carry) = mac(r3, k, MODULUS.0[0], 0); - let (r4, carry) = mac(r4, k, MODULUS.0[1], carry); - let (r5, carry) = mac(r5, k, MODULUS.0[2], carry); - let (r6, carry) = mac(r6, k, MODULUS.0[3], carry); - let (r7, _) = adc(r7, carry2, carry); - - // Result may be within MODULUS of the correct value - (&Fq([r4, r5, r6, r7])).sub(&MODULUS) - } - - /// Multiplies `rhs` by `self`, returning the result. - #[inline] - pub const fn mul(&self, rhs: &Self) -> Self { - // Schoolbook multiplication - - let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0); - let (r1, carry) = mac(0, self.0[0], rhs.0[1], carry); - let (r2, carry) = mac(0, self.0[0], rhs.0[2], carry); - let (r3, r4) = mac(0, self.0[0], rhs.0[3], carry); - - let (r1, carry) = mac(r1, self.0[1], rhs.0[0], 0); - let (r2, carry) = mac(r2, self.0[1], rhs.0[1], carry); - let (r3, carry) = mac(r3, self.0[1], rhs.0[2], carry); - let (r4, r5) = mac(r4, self.0[1], rhs.0[3], carry); - - let (r2, carry) = mac(r2, self.0[2], rhs.0[0], 0); - let (r3, carry) = mac(r3, self.0[2], rhs.0[1], carry); - let (r4, carry) = mac(r4, self.0[2], rhs.0[2], carry); - let (r5, r6) = mac(r5, self.0[2], rhs.0[3], carry); - - let (r3, carry) = mac(r3, self.0[3], rhs.0[0], 0); - let (r4, carry) = mac(r4, self.0[3], rhs.0[1], carry); - let (r5, carry) = mac(r5, self.0[3], rhs.0[2], carry); - let (r6, r7) = mac(r6, self.0[3], rhs.0[3], carry); - - Fq::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) - } - - /// Subtracts `rhs` from `self`, returning the result. - #[inline] - pub const fn sub(&self, rhs: &Self) -> Self { - let (d0, borrow) = sbb(self.0[0], rhs.0[0], 0); - let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); - let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); - let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow); - - // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise - // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. - let (d0, carry) = adc(d0, MODULUS.0[0] & borrow, 0); - let (d1, carry) = adc(d1, MODULUS.0[1] & borrow, carry); - let (d2, carry) = adc(d2, MODULUS.0[2] & borrow, carry); - let (d3, _) = adc(d3, MODULUS.0[3] & borrow, carry); - - Fq([d0, d1, d2, d3]) - } - - /// Adds `rhs` to `self`, returning the result. - #[inline] - pub const fn add(&self, rhs: &Self) -> Self { - let (d0, carry) = adc(self.0[0], rhs.0[0], 0); - let (d1, carry) = adc(self.0[1], rhs.0[1], carry); - let (d2, carry) = adc(self.0[2], rhs.0[2], carry); - let (d3, _) = adc(self.0[3], rhs.0[3], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - (&Fq([d0, d1, d2, d3])).sub(&MODULUS) - } - - /// Negates `self`. - #[inline] - pub const fn neg(&self) -> Self { - // Subtract `self` from `MODULUS` to negate. Ignore the final - // borrow because it cannot underflow; self is guaranteed to - // be in the field. - let (d0, borrow) = sbb(MODULUS.0[0], self.0[0], 0); - let (d1, borrow) = sbb(MODULUS.0[1], self.0[1], borrow); - let (d2, borrow) = sbb(MODULUS.0[2], self.0[2], borrow); - let (d3, _) = sbb(MODULUS.0[3], self.0[3], borrow); - - // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is - // zero if `self` was zero, and `u64::max_value()` if self was nonzero. - let mask = (((self.0[0] | self.0[1] | self.0[2] | self.0[3]) == 0) as u64).wrapping_sub(1); - - Fq([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) - } -} - -impl From for [u8; 32] { - fn from(value: Fq) -> [u8; 32] { - value.to_repr() - } -} - -impl<'a> From<&'a Fq> for [u8; 32] { - fn from(value: &'a Fq) -> [u8; 32] { - value.to_repr() - } -} - -impl Group for Fq { - type Scalar = Fq; - - fn group_zero() -> Self { - Self::zero() - } - fn group_add(&mut self, rhs: &Self) { - *self += *rhs; - } - fn group_sub(&mut self, rhs: &Self) { - *self -= *rhs; - } - fn group_scale(&mut self, by: &Self::Scalar) { - *self *= *by; - } -} +field_operation!( + Fq, + MODULUS, + INV, + R, + R2, + R3, + S, + GENERATOR, + ROOT_OF_UNITY, + MODULUS_LIMBS_32 +); impl ff::Field for Fq { fn random(mut rng: impl RngCore) -> Self { @@ -567,113 +209,6 @@ impl ff::Field for Fq { } } -impl ff::PrimeField for Fq { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 255; - const CAPACITY: u32 = 254; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Fq([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = Fq::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); - - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } - - fn multiplicative_generator() -> Self { - GENERATOR - } - - fn root_of_unity() -> Self { - ROOT_OF_UNITY - } -} - -#[cfg(all(feature = "bits", not(target_pointer_width = "64")))] -type ReprBits = [u32; 8]; - -#[cfg(all(feature = "bits", target_pointer_width = "64"))] -type ReprBits = [u64; 4]; - -#[cfg(feature = "bits")] -impl PrimeFieldBits for Fq { - type ReprBits = ReprBits; - - fn to_le_bits(&self) -> FieldBits { - let bytes = self.to_repr(); - - #[cfg(not(target_pointer_width = "64"))] - let limbs = [ - u32::from_le_bytes(bytes[0..4].try_into().unwrap()), - u32::from_le_bytes(bytes[4..8].try_into().unwrap()), - u32::from_le_bytes(bytes[8..12].try_into().unwrap()), - u32::from_le_bytes(bytes[12..16].try_into().unwrap()), - u32::from_le_bytes(bytes[16..20].try_into().unwrap()), - u32::from_le_bytes(bytes[20..24].try_into().unwrap()), - u32::from_le_bytes(bytes[24..28].try_into().unwrap()), - u32::from_le_bytes(bytes[28..32].try_into().unwrap()), - ]; - - #[cfg(target_pointer_width = "64")] - let limbs = [ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - ]; - - FieldBits::new(limbs) - } - - fn char_le_bits() -> FieldBits { - #[cfg(not(target_pointer_width = "64"))] - { - FieldBits::new(MODULUS_LIMBS_32) - } - - #[cfg(target_pointer_width = "64")] - FieldBits::new(MODULUS.0) - } -} - #[cfg(feature = "sqrt-table")] lazy_static! { // The perfect hash parameters are found by `squareroottab.sage` in zcash/pasta.