diff --git a/Cargo.toml b/Cargo.toml index 22e2d429..18576ead 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,9 @@ hex = { version = "0.4", optional = true, default-features = false, features = [ blake2b_simd = "1" rayon = "1.8" unroll = "0.1.5" +blake2 = "0.10.6" +sha2 = "0.10.8" +digest = "0.10.7" [features] default = ["bits"] diff --git a/src/bn256/curve.rs b/src/bn256/curve.rs index 5989c9f6..144c2750 100644 --- a/src/bn256/curve.rs +++ b/src/bn256/curve.rs @@ -11,7 +11,6 @@ use crate::ff::WithSmallOrderMulGroup; use crate::ff::{Field, PrimeField}; use crate::group::Curve; use crate::group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Group, GroupEncoding}; -use crate::hash_to_curve::svdw_hash_to_curve; use crate::{ impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, @@ -39,7 +38,7 @@ new_curve_impl!( G1_A, G1_B, "bn256_g1", - |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z), + |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, G1::default_hash_to_curve_suite()), ); new_curve_impl!( @@ -52,17 +51,26 @@ new_curve_impl!( G2_A, G2_B, "bn256_g2", - |_, _| unimplemented!(), + |domain_prefix| hash_to_curve_g2(domain_prefix), ); -const G1_GENERATOR_X: Fq = Fq::one(); +#[allow(clippy::type_complexity)] +pub(crate) fn hash_to_curve_g2<'a>(domain_prefix: &'a str) -> Box G2 + 'a> { + let suite = G2::default_hash_to_curve_suite(); + Box::new(move |message| { + let r0 = suite.hash_to_curve(domain_prefix, message); + r0.clear_cofactor() + }) +} + +const G1_GENERATOR_X: Fq = Fq::ONE; const G1_GENERATOR_Y: Fq = Fq::from_raw([2, 0, 0, 0]); -const G1_A: Fq = Fq::from_raw([0, 0, 0, 0]); +const G1_A: Fq = Fq::ZERO; const G1_B: Fq = Fq::from_raw([3, 0, 0, 0]); const G2_A: Fq2 = Fq2 { - c0: Fq::from_raw([0, 0, 0, 0]), - c1: Fq::from_raw([0, 0, 0, 0]), + c0: Fq::ZERO, + c1: Fq::ZERO, }; const G2_B: Fq2 = Fq2 { @@ -195,6 +203,26 @@ impl CofactorGroup for G2 { impl G1 { const SVDW_Z: Fq = Fq::ONE; + + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite { + crate::hash_to_curve::Suite::::new( + b"bn256_g1_XMD:SHA-256_SVDW_RO_", + Self::SVDW_Z, + crate::hash_to_curve::Method::SVDW, + ) + } +} + +impl G2 { + const SVDW_Z: Fq2 = Fq2::ONE; + + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite { + crate::hash_to_curve::Suite::::new( + b"bn256_g2_XMD:SHA-256_SVDW_RO_", + Self::SVDW_Z, + crate::hash_to_curve::Method::SVDW, + ) + } } #[cfg(test)] diff --git a/src/bn256/engine.rs b/src/bn256/engine.rs index dd2bedda..6674856b 100644 --- a/src/bn256/engine.rs +++ b/src/bn256/engine.rs @@ -237,10 +237,10 @@ impl G2Prepared { tmp3.square_assign(); tmp3 -= &tmp0; tmp3 -= &tmp2; - tmp3.double_assign(); + tmp3 = tmp3.double(); let mut tmp4 = tmp0; - tmp4.double_assign(); + tmp4 = tmp4.double(); tmp4 += &tmp0; let mut tmp6 = r.x; @@ -265,9 +265,9 @@ impl G2Prepared { r.y -= &r.x; r.y.mul_assign(&tmp4); - tmp2.double_assign(); - tmp2.double_assign(); - tmp2.double_assign(); + tmp2 = tmp2.double(); + tmp2 = tmp2.double(); + tmp2 = tmp2.double(); r.y -= &tmp2; @@ -277,7 +277,7 @@ impl G2Prepared { // tmp3 is the first part of line 12 tmp3 = tmp4; tmp3.mul_assign(&zsquared); - tmp3.double_assign(); + tmp3 = tmp3.double(); tmp3 = tmp3.neg(); // tmp6 is from line 14 @@ -285,15 +285,15 @@ impl G2Prepared { tmp6 -= &tmp0; tmp6 -= &tmp5; - tmp1.double_assign(); - tmp1.double_assign(); + tmp1 = tmp1.double(); + tmp1 = tmp1.double(); tmp6 -= &tmp1; // tmp0 is the first part of line 16 tmp0 = r.z; tmp0.mul_assign(&zsquared); - tmp0.double_assign(); + tmp0 = tmp0.double(); (tmp0, tmp3, tmp6) } @@ -328,8 +328,8 @@ impl G2Prepared { // t4 corresponds to line 6 let mut t4 = t3; - t4.double_assign(); - t4.double_assign(); + t4 = t4.double(); + t4 = t4.double(); // t5 corresponds to line 7 let mut t5 = t4; @@ -373,7 +373,7 @@ impl G2Prepared { // corresponds to line 15 t0 = r.y; t0.mul_assign(&t5); - t0.double_assign(); + t0 = t0.double(); // corresponds to line 12, but assigns to r.y instead of T.y r.y = t8; @@ -389,18 +389,18 @@ impl G2Prepared { t10 -= &ztsquared; // corresponds to line 18 - t9.double_assign(); + t9 = t9.double(); t9 -= &t10; // t10 = 2*Zt from Algo 27, line 19 t10 = r.z; - t10.double_assign(); + t10 = t10.double(); // t1 = first multiplicator of line 21 t6 = t6.neg(); t1 = t6; - t1.double_assign(); + t1 = t1.double(); // t9 corresponds to t9 from Algo 27 (t10, t1, t9) diff --git a/src/bn256/fq.rs b/src/bn256/fq.rs index 8da18bbd..b3e45c34 100644 --- a/src/bn256/fq.rs +++ b/src/bn256/fq.rs @@ -4,33 +4,30 @@ use crate::bn256::assembly::field_arithmetic_asm; use crate::{arithmetic::macx, field_arithmetic, field_specific}; use crate::arithmetic::{adc, bigint_geq, mac, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_bits, field_common, impl_add_binop_specify_output, impl_binops_additive, - impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, -}; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::serde::SerdeObject; use core::convert::TryInto; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -/// This represents an element of $\mathbb{F}_q$ where -/// /// `p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47` /// /// is the base field of the BN254 curve. -// The internal representation of this type is four 64-bit unsigned -// integers in little-endian order. `Fq` values are always in -// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fq(pub(crate) [u64; 4]); #[cfg(feature = "derive_serde")] crate::serialize_deserialize_32_byte_primefield!(Fq); +// Number of 64 bit limbs to represent the field element +pub(super) const NUM_BITS: u32 = 254; + +// Inverter constant +const BYIL: usize = 6; + +// Jabobi constant +const JACOBI_L: usize = 5; + /// Constant representing the modulus /// q = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 const MODULUS: Fq = Fq([ @@ -87,7 +84,8 @@ pub const NEGATIVE_ONE: Fq = Fq([ 0x2259d6b14729c0fa, ]); -const MODULUS_STR: &str = "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"; +pub(crate) const MODULUS_STR: &str = + "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"; /// Obtained with: /// `sage: GF(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47).primitive_element()` @@ -127,23 +125,26 @@ const ZETA: Fq = Fq::from_raw([ 0x30644e72e131a029, ]); +/// Size of the 2-adic sub-group of the field. +const S: u32 = 0; + +use crate::{ + extend_field_legendre, field_bits, impl_add_binop_specify_impl, impl_add_binop_specify_output, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_field, impl_from_u64, impl_from_uniform_bytes, + impl_prime_field, impl_serde_object, impl_sub_binop_specify_output, impl_sum_prod, pow_vartime, +}; impl_binops_additive!(Fq, Fq); impl_binops_multiplicative!(Fq, Fq); -field_common!( - Fq, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); +impl_add_binop_specify_impl!(Fq); +impl_field!(Fq, sparse); +impl_serde_object!(Fq); +impl_prime_field!(Fq, [u8; 32], le); impl_sum_prod!(Fq); -impl_from_u64!(Fq, R2); +extend_field_legendre!(Fq); +impl_from_uniform_bytes!(Fq, 64); +impl_from_uniform_bytes!(Fq, 48); +impl_from_u64!(Fq); #[cfg(not(feature = "asm"))] field_arithmetic!(Fq, MODULUS, INV, sparse); @@ -151,37 +152,14 @@ field_arithmetic!(Fq, MODULUS, INV, sparse); field_arithmetic_asm!(Fq, MODULUS, INV); #[cfg(target_pointer_width = "64")] -field_bits!(Fq, MODULUS); +field_bits!(Fq); #[cfg(not(target_pointer_width = "64"))] -field_bits!(Fq, MODULUS, MODULUS_LIMBS_32); +field_bits!(Fq); impl Fq { pub const fn size() -> usize { 32 } -} - -extend_field_legendre!(Fq); - -impl ff::Field for Fq { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - let mut random_bytes = [0; 64]; - rng.fill_bytes(&mut random_bytes[..]); - - Self::from_uniform_bytes(&random_bytes) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } /// Computes the square root of this element, if it exists. fn sqrt(&self) -> CtOption { @@ -194,92 +172,6 @@ impl ff::Field for Fq { CtOption::new(tmp, tmp.square().ct_eq(self)) } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } -} - -impl ff::PrimeField for Fq { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 254; - const CAPACITY: u32 = 253; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = 0; - - 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 { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq { - /// Converts a 512-bit little endian integer into - /// an `Fq` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - 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()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fq { - const ZETA: Self = ZETA; } #[cfg(test)] @@ -294,70 +186,5 @@ mod test { crate::field_testing_suite!(Fq, "constants", MODULUS_STR); crate::field_testing_suite!(Fq, "sqrt"); crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!( - Fq, - "from_uniform_bytes", - [ - Fq::from_raw([ - 0xd1f334151139642a, - 0xb0f28bcaa90fdb88, - 0x9a13255d88eca613, - 0x02afef300dd32d9a, - ]), - Fq::from_raw([ - 0x03cd906680808fbe, - 0xc28902db5aef5254, - 0x3dbdb406ae292ddf, - 0x276ec249e6b9e195 - ]), - Fq::from_raw([ - 0xb0e07ded189e91f7, - 0x9e3b0caae2b98899, - 0x49e511f19341fdcf, - 0x1ea71260f64b72da - ]), - Fq::from_raw([ - 0x61132be14bb978d4, - 0xe27e09a20808067b, - 0x3842cc8fd1d8406f, - 0x13163c8a13fd550b - ]), - Fq::from_raw([ - 0x04a6495a33d39ac5, - 0xc918e75bb383fae0, - 0x80068784d577b035, - 0x1dd962b86e44e1be - ]), - Fq::from_raw([ - 0x107ffeecf4cb3348, - 0x53a0adb5491a4944, - 0x50028f636ffcb780, - 0x0af7f3aa38015c1d - ]), - Fq::from_raw([ - 0x22513787342eba07, - 0x4fac22ed88770319, - 0x0b7c31082cc92b13, - 0x250e22a8cac6e790 - ]), - Fq::from_raw([ - 0x5954fd7dda014940, - 0x9df859b2124e66fa, - 0xaab48d94eadd9d14, - 0x2a9a75013e3da632 - ]), - Fq::from_raw([ - 0xedd59c88fee718de, - 0x2b034dcfe6de3844, - 0x76b0e2e360488694, - 0x068998ef20d62df1 - ]), - Fq::from_raw([ - 0xac161667911634a4, - 0x296c2f453152552f, - 0x2653625dfaa1cf74, - 0x171abf201a2587d7 - ]), - ] - ); + crate::field_testing_suite!(Fq, "from_uniform_bytes", 64); } diff --git a/src/bn256/fq12.rs b/src/bn256/fq12.rs index b77604d5..e6be6178 100644 --- a/src/bn256/fq12.rs +++ b/src/bn256/fq12.rs @@ -1,7 +1,7 @@ use super::fq::Fq; use super::fq2::Fq2; use super::fq6::Fq6; -use crate::ff::Field; +use crate::{ff::Field, impl_tower2_common}; use core::ops::{Add, Mul, Neg, Sub}; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -9,100 +9,19 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// -GAMMA is a quadratic non-residue in Fp6. Fp12 = Fp6[X]/(X^2 + GAMMA) /// We introduce the variable w such that w^2 = -GAMMA // GAMMA = - v - /// An element of Fq12, represented by c0 + c1 * w. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -pub struct Fq12 { - pub c0: Fq6, - pub c1: Fq6, -} - -impl ConditionallySelectable for Fq12 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fq12 { - c0: Fq6::conditional_select(&a.c0, &b.c0, choice), - c1: Fq6::conditional_select(&a.c1, &b.c1, choice), - } - } -} - -impl ConstantTimeEq for Fq12 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) - } -} - -impl Neg for Fq12 { - type Output = Fq12; - - #[inline] - fn neg(self) -> Fq12 { - -&self - } -} - -impl<'a> Neg for &'a Fq12 { - type Output = Fq12; - - #[inline] - fn neg(self) -> Fq12 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fq12> for &'a Fq12 { - type Output = Fq12; - - #[inline] - fn sub(self, rhs: &'b Fq12) -> Fq12 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fq12> for &'a Fq12 { - type Output = Fq12; - - #[inline] - fn add(self, rhs: &'b Fq12) -> Fq12 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fq12> for &'a Fq12 { - type Output = Fq12; - - #[inline] - fn mul(self, rhs: &'b Fq12) -> Fq12 { - self.mul(rhs) - } -} - use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, impl_sum_prod, }; impl_binops_additive!(Fq12, Fq12); impl_binops_multiplicative!(Fq12, Fq12); +impl_tower2_common!(Fq6, Fq12); +impl_add_binop_specify_impl!(Fq12); impl_sum_prod!(Fq12); impl Fq12 { - #[inline] - pub const fn zero() -> Self { - Fq12 { - c0: Fq6::ZERO, - c1: Fq6::ZERO, - } - } - - #[inline] - pub const fn one() -> Self { - Fq12 { - c0: Fq6::ONE, - c1: Fq6::ZERO, - } - } - pub fn mul_assign(&mut self, other: &Self) { let t0 = self.c0 * other.c0; let mut t1 = self.c1 * other.c1; @@ -134,32 +53,6 @@ impl Fq12 { self.c0 = c0; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0 + other.c0, - c1: self.c1 + other.c1, - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0 - other.c0, - c1: self.c1 - other.c1, - } - } - pub fn mul(&self, other: &Self) -> Self { let mut t = *other; t.mul_assign(self); @@ -172,26 +65,11 @@ impl Fq12 { t } - #[inline(always)] - pub fn neg(&self) -> Self { - Self { - c0: -self.c0, - c1: -self.c1, - } - } - #[inline(always)] pub fn conjugate(&mut self) { self.c1 = -self.c1; } - // pub fn conjugate(&self) -> Self { - // Self { - // c0: self.c0, - // c1: -self.c1, - // } - // } - pub fn frobenius_map(&mut self, power: usize) { self.c0.frobenius_map(power); self.c1.frobenius_map(power); @@ -271,29 +149,29 @@ impl Fq12 { fp4_square(&mut t3, &mut t4, &self.c0.c0, &self.c1.c1); let mut t2 = t3 - self.c0.c0; - t2.double_assign(); + t2 = t2.double(); self.c0.c0 = t2 + t3; t2 = t4 + self.c1.c1; - t2.double_assign(); + t2 = t2.double(); self.c1.c1 = t2 + t4; fp4_square(&mut t3, &mut t4, &self.c1.c0, &self.c0.c2); fp4_square(&mut t5, &mut t6, &self.c0.c1, &self.c1.c2); t2 = t3 - self.c0.c1; - t2.double_assign(); + t2 = t2.double(); self.c0.c1 = t2 + t3; t2 = t4 + self.c1.c2; - t2.double_assign(); + t2 = t2.double(); self.c1.c2 = t2 + t4; t3 = t6; t3.mul_by_nonresidue(); t2 = t3 + self.c1.c0; - t2.double_assign(); + t2 = t2.double(); self.c1.c0 = t2 + t3; t2 = t5 - self.c0.c2; - t2.double_assign(); + t2 = t2.double(); self.c0.c2 = t2 + t5; } } diff --git a/src/bn256/fq2.rs b/src/bn256/fq2.rs index 96e2f000..5c367a04 100644 --- a/src/bn256/fq2.rs +++ b/src/bn256/fq2.rs @@ -10,170 +10,20 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "derive_serde")] use serde::{Deserialize, Serialize}; -/// An element of Fq2, represented by c0 + c1 * u; where u^2 = -1. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fq2 { - pub c0: Fq, - pub c1: Fq, -} - -/// `Fq2` elements are ordered lexicographically. -impl Ord for Fq2 { - #[inline(always)] - fn cmp(&self, other: &Fq2) -> Ordering { - match self.c1.cmp(&other.c1) { - Ordering::Greater => Ordering::Greater, - Ordering::Less => Ordering::Less, - Ordering::Equal => self.c0.cmp(&other.c0), - } - } -} - -impl PartialOrd for Fq2 { - #[inline(always)] - fn partial_cmp(&self, other: &Fq2) -> Option { - Some(self.cmp(other)) - } -} - -impl ConditionallySelectable for Fq2 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fq2 { - c0: Fq::conditional_select(&a.c0, &b.c0, choice), - c1: Fq::conditional_select(&a.c1, &b.c1, choice), - } - } -} - -impl ConstantTimeEq for Fq2 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) - } -} - -impl Default for Fq2 { - #[inline] - fn default() -> Self { - Self::ZERO - } -} - -impl From for [u8; 64] { - fn from(value: Fq2) -> [u8; 64] { - value.to_bytes() - } -} - -impl<'a> From<&'a Fq2> for [u8; 64] { - fn from(value: &'a Fq2) -> [u8; 64] { - value.to_bytes() - } -} - -impl Neg for Fq2 { - type Output = Fq2; - - #[inline] - fn neg(self) -> Fq2 { - -&self - } -} - -impl<'a> Neg for &'a Fq2 { - type Output = Fq2; - - #[inline] - fn neg(self) -> Fq2 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fq2> for &'a Fq2 { - type Output = Fq2; - - #[inline] - fn sub(self, rhs: &'b Fq2) -> Fq2 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fq2> for &'a Fq2 { - type Output = Fq2; - - #[inline] - fn add(self, rhs: &'b Fq2) -> Fq2 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fq2> for &'a Fq2 { - type Output = Fq2; - - #[inline] - fn mul(self, rhs: &'b Fq2) -> Fq2 { - self.mul(rhs) - } -} - use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, impl_sum_prod, impl_tower2, + impl_tower2_common, }; +impl_tower2_common!(Fq, Fq2); +impl_tower2!(Fq, Fq2, ReprFq2); impl_binops_additive!(Fq2, Fq2); impl_binops_multiplicative!(Fq2, Fq2); +impl_add_binop_specify_impl!(Fq2); impl_sum_prod!(Fq2); impl Fq2 { - #[inline] - pub const fn zero() -> Fq2 { - Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - } - } - - #[inline] - pub const fn one() -> Fq2 { - Fq2 { - c0: Fq::one(), - c1: Fq::zero(), - } - } - - pub const fn new(c0: Fq, c1: Fq) -> Self { - Fq2 { c0, c1 } - } - - pub const fn size() -> usize { - 64 - } - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fq`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; 64]) -> CtOption { - let c0 = Fq::from_bytes(bytes[0..32].try_into().unwrap()); - let c1 = Fq::from_bytes(bytes[32..64].try_into().unwrap()); - CtOption::new( - Fq2 { - c0: c0.unwrap(), - c1: c1.unwrap(), - }, - c0.is_some() & c1.is_some(), - ) - } - - /// Converts an element of `Fq` into a byte representation in - /// little-endian byte order. - pub fn to_bytes(&self) -> [u8; 64] { - let mut res = [0u8; 64]; - let c0_bytes = self.c0.to_bytes(); - let c1_bytes = self.c1.to_bytes(); - res[0..32].copy_from_slice(&c0_bytes[..]); - res[32..64].copy_from_slice(&c1_bytes[..]); - res - } - pub fn mul_assign(&mut self, other: &Self) { let mut t0 = self.c0 + self.c1; let mut t1 = self.c0 * other.c0; @@ -197,32 +47,6 @@ impl Fq2 { self.c0 = c0 + ab; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0.add(&other.c0), - c1: self.c1.add(&other.c1), - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0.sub(&other.c0), - c1: self.c1.sub(&other.c1), - } - } - pub fn mul(&self, other: &Self) -> Self { let mut t = *other; t.mul_assign(self); @@ -235,13 +59,6 @@ impl Fq2 { t } - pub fn neg(&self) -> Self { - Self { - c0: self.c0.neg(), - c1: self.c1.neg(), - } - } - // conjugate by negating c1 pub fn conjugate(&mut self) { self.c1 = -self.c1; @@ -260,9 +77,9 @@ impl Fq2 { let t1 = self.c1; // 8*x*i + 8*y - self.double_assign(); - self.double_assign(); - self.double_assign(); + *self = self.double(); + *self = self.double(); + *self = self.double(); // 9*y self.c0 += &t0; @@ -303,38 +120,8 @@ impl Fq2 { t1 = t1.square(); t1 + t0 } -} - -impl Legendre for Fq2 { - fn legendre(&self) -> i64 { - self.norm().legendre() - } -} - -impl Field for Fq2 { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Fq2 { - c0: Fq::random(&mut rng), - c1: Fq::random(&mut rng), - } - } - fn is_zero(&self) -> Choice { - self.c0.is_zero() & self.c1.is_zero() - } - - fn square(&self) -> Self { - self.square() - } - - fn double(&self) -> Self { - self.double() - } - - fn sqrt(&self) -> CtOption { + pub fn sqrt(&self) -> CtOption { // Algorithm 9, https://eprint.iacr.org/2012/685.pdf if self.is_zero().into() { @@ -389,157 +176,14 @@ impl Field for Fq2 { } } } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } - - fn invert(&self) -> CtOption { - self.invert() - } -} - -impl From for Fq2 { - fn from(bit: bool) -> Fq2 { - if bit { - Fq2::ONE - } else { - Fq2::ZERO - } - } } -impl From for Fq2 { - fn from(val: u64) -> Self { - Fq2 { - c0: Fq::from(val), - c1: Fq::zero(), - } - } -} - -// This trait is only implemented to satisfy the requirement of CurveExt -impl PrimeField for Fq2 { - type Repr = Fq2Bytes; - - const MODULUS: &'static str = - "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"; - const MULTIPLICATIVE_GENERATOR: Self = Fq2 { - c0: Fq::from_raw([0x03, 0x0, 0x0, 0x0]), - c1: Fq::ZERO, - }; - const NUM_BITS: u32 = 254; - const CAPACITY: u32 = 253; - const S: u32 = 0; - // TODO: Check that we can just 0 this and forget. - const ROOT_OF_UNITY: Self = Fq2::zero(); - const ROOT_OF_UNITY_INV: Self = Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - }; - const DELTA: Self = Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - }; - const TWO_INV: Self = Fq2 { - c0: Fq::from_raw([ - 0x9e10460b6c3e7ea4, - 0xcbc0b548b438e546, - 0xdc2822db40c0ac2e, - 0x183227397098d014, - ]), - c1: Fq([0, 0, 0, 0]), - }; - - fn from_repr(repr: Self::Repr) -> CtOption { - let c0 = Fq::from_bytes(&repr.0[..32].try_into().unwrap()); - let c1 = Fq::from_bytes(&repr.0[32..].try_into().unwrap()); - // Disallow overflow representation - CtOption::new(Fq2::new(c0.unwrap(), c1.unwrap()), Choice::from(1)) - } - - fn to_repr(&self) -> Self::Repr { - Fq2Bytes(self.to_bytes()) - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr().as_ref()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq2 { - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::new(Fq::from_uniform_bytes(bytes), Fq::zero()) - } -} -#[derive(Clone, Copy, Debug)] -pub struct Fq2Bytes([u8; 64]); - -impl Default for Fq2Bytes { - fn default() -> Self { - Self([0u8; 64]) - } -} - -impl AsMut<[u8]> for Fq2Bytes { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } -} - -impl AsRef<[u8]> for Fq2Bytes { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl crate::serde::SerdeObject for Fq2 { - fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 64); - let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes_unchecked(&bytes[i..i + 32])); - Self { c0, c1 } - } - fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 64 { - return None; - } - let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes(&bytes[i..i + 32])); - c0.zip(c1).map(|(c0, c1)| Self { c0, c1 }) - } - fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(64); - for limb in self.c0.0.iter().chain(self.c1.0.iter()) { - res.extend_from_slice(&limb.to_le_bytes()); - } - res - } - fn read_raw_unchecked(reader: &mut R) -> Self { - let [c0, c1] = [(); 2].map(|_| Fq::read_raw_unchecked(reader)); - Self { c0, c1 } - } - fn read_raw(reader: &mut R) -> std::io::Result { - let c0 = Fq::read_raw(reader)?; - let c1 = Fq::read_raw(reader)?; - Ok(Self { c0, c1 }) - } - fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { - self.c0.write_raw(writer)?; - self.c1.write_raw(writer) - } -} - -impl WithSmallOrderMulGroup<3> for Fq2 { - // Fq::ZETA ^2 - const ZETA: Self = Fq2 { - c0: Fq::from_raw([ - 0x5763473177fffffe, - 0xd4f263f1acdb5c4f, - 0x59e26bcea0d48bac, - 0x0000000000000000, - ]), - c1: Fq::zero(), - }; -} +const ZETA: Fq = Fq::from_raw([ + 0x5763473177fffffe, + 0xd4f263f1acdb5c4f, + 0x59e26bcea0d48bac, + 0x0000000000000000, +]); #[cfg(test)] mod test { diff --git a/src/bn256/fq6.rs b/src/bn256/fq6.rs index de01d6c8..c1ad6ec6 100644 --- a/src/bn256/fq6.rs +++ b/src/bn256/fq6.rs @@ -1,6 +1,6 @@ use super::fq::Fq; use super::fq2::Fq2; -use crate::ff::Field; +use crate::{ff::Field, impl_tower6}; use core::ops::{Add, Mul, Neg, Sub}; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -8,104 +8,19 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// -BETA is a cubic non-residue in Fp2. Fp6 = Fp2[X]/(X^3 + BETA) /// We introduce the variable v such that v^3 = -BETA // BETA = - (u + 9) - /// An element of Fq6, represented by c0 + c1 * v + c2 * v^2. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -pub struct Fq6 { - pub c0: Fq2, - pub c1: Fq2, - pub c2: Fq2, -} - -impl ConditionallySelectable for Fq6 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fq6 { - c0: Fq2::conditional_select(&a.c0, &b.c0, choice), - c1: Fq2::conditional_select(&a.c1, &b.c1, choice), - c2: Fq2::conditional_select(&a.c2, &b.c2, choice), - } - } -} - -impl ConstantTimeEq for Fq6 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) & self.c2.ct_eq(&other.c2) - } -} - -impl Neg for Fq6 { - type Output = Fq6; - - #[inline] - fn neg(self) -> Fq6 { - -&self - } -} - -impl<'a> Neg for &'a Fq6 { - type Output = Fq6; - - #[inline] - fn neg(self) -> Fq6 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fq6> for &'a Fq6 { - type Output = Fq6; - - #[inline] - fn sub(self, rhs: &'b Fq6) -> Fq6 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fq6> for &'a Fq6 { - type Output = Fq6; - - #[inline] - fn add(self, rhs: &'b Fq6) -> Fq6 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fq6> for &'a Fq6 { - type Output = Fq6; - - #[inline] - fn mul(self, rhs: &'b Fq6) -> Fq6 { - self.mul(rhs) - } -} - use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, impl_sum_prod, }; +impl_tower6!(Fq, Fq2, Fq6); impl_binops_additive!(Fq6, Fq6); impl_binops_multiplicative!(Fq6, Fq6); +impl_add_binop_specify_impl!(Fq6); impl_sum_prod!(Fq6); impl Fq6 { - #[inline] - pub const fn zero() -> Self { - Fq6 { - c0: Fq2::ZERO, - c1: Fq2::ZERO, - c2: Fq2::ZERO, - } - } - - #[inline] - pub const fn one() -> Self { - Fq6 { - c0: Fq2::ONE, - c1: Fq2::ZERO, - c2: Fq2::ZERO, - } - } - pub fn mul_assign(&mut self, other: &Self) { let mut a_a = self.c0; let mut b_b = self.c1; @@ -165,7 +80,7 @@ impl Fq6 { let mut ab = self.c0; ab *= &self.c1; let mut s1 = ab; - s1.double_assign(); + s1 = s1.double(); // s2 = (a - b + c)^2 let mut s2 = self.c0; s2 -= &self.c1; @@ -176,7 +91,7 @@ impl Fq6 { bc *= &self.c2; // s3 = 2bc let mut s3 = bc; - s3.double_assign(); + s3 = s3.double(); // s4 = c^2 let mut s4 = self.c2; s4.square_assign(); @@ -200,36 +115,6 @@ impl Fq6 { self.c2 -= &s4; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - c2: self.c2.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - self.c2 = self.c2.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0 + other.c0, - c1: self.c1 + other.c1, - c2: self.c2 + other.c2, - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0 - other.c0, - c1: self.c1 - other.c1, - c2: self.c2 - other.c2, - } - } - pub fn mul(&self, other: &Self) -> Self { let mut t = *other; t.mul_assign(self); @@ -242,14 +127,6 @@ impl Fq6 { t } - pub fn neg(&self) -> Self { - Self { - c0: -self.c0, - c1: -self.c1, - c2: -self.c2, - } - } - pub fn frobenius_map(&mut self, power: usize) { self.c0.frobenius_map(power); self.c1.frobenius_map(power); @@ -390,43 +267,6 @@ impl Fq6 { } } -impl Field for Fq6 { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Fq6 { - c0: Fq2::random(&mut rng), - c1: Fq2::random(&mut rng), - c2: Fq2::random(&mut rng), - } - } - - fn is_zero(&self) -> Choice { - self.c0.is_zero() & self.c1.is_zero() - } - - fn square(&self) -> Self { - self.square() - } - - fn double(&self) -> Self { - self.double() - } - - fn sqrt(&self) -> CtOption { - unimplemented!() - } - - fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { - unimplemented!() - } - - fn invert(&self) -> CtOption { - self.invert() - } -} - pub const FROBENIUS_COEFF_FQ6_C1: [Fq2; 6] = [ // Fq2(u + 9)**(((q^0) - 1) / 3) Fq2 { diff --git a/src/bn256/fr.rs b/src/bn256/fr.rs index 22029e3a..55e6ff72 100644 --- a/src/bn256/fr.rs +++ b/src/bn256/fr.rs @@ -19,13 +19,8 @@ pub use table::FR_TABLE; use crate::impl_from_u64; use crate::arithmetic::{adc, bigint_geq, mac, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_bits, field_common, impl_add_binop_specify_output, impl_binops_additive, - impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, impl_sum_prod, -}; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::serde::SerdeObject; use core::convert::TryInto; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; @@ -37,11 +32,15 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// `r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001` /// /// is the scalar field of the BN254 curve. -// The internal representation of this type is four 64-bit unsigned -// integers in little-endian order. `Fr` values are always in -// Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fr(pub(crate) [u64; 4]); + +// Number of 64 bit limbs to represent the field element +pub(crate) const NUM_BITS: u32 = 254; + +// Inverter constant +const BYIL: usize = 6; + +// Jabobi constant +const JACOBI_L: usize = 5; #[cfg(feature = "derive_serde")] crate::serialize_deserialize_32_byte_primefield!(Fr); @@ -102,8 +101,9 @@ const R3: Fr = Fr([ /// `GENERATOR = 7 mod r` is a generator of the `r - 1` order multiplicative /// subgroup, or in other words a primitive root of the field. -const GENERATOR: Fr = Fr::from_raw([0x07, 0x00, 0x00, 0x00]); +const MULTIPLICATIVE_GENERATOR: Fr = Fr::from_raw([0x07, 0x00, 0x00, 0x00]); +/// Size of the 2-adic sub-group of the field. const S: u32 = 28; /// GENERATOR^t where t * 2^s + 1 = r @@ -117,14 +117,6 @@ const ROOT_OF_UNITY: Fr = Fr::from_raw([ 0x03ddb9f5166d18b7, ]); -/// 1 / 2 mod r -const TWO_INV: Fr = Fr::from_raw([ - 0xa1f0fac9f8000001, - 0x9419f4243cdcb848, - 0xdc2822db40c0ac2e, - 0x183227397098d014, -]); - /// 1 / ROOT_OF_UNITY mod r const ROOT_OF_UNITY_INV: Fr = Fr::from_raw([ 0x0ed3e50a414e6dba, @@ -133,6 +125,14 @@ const ROOT_OF_UNITY_INV: Fr = Fr::from_raw([ 0x048127174daabc26, ]); +/// 1 / 2 mod r +const TWO_INV: Fr = Fr::from_raw([ + 0xa1f0fac9f8000001, + 0x9419f4243cdcb848, + 0xdc2822db40c0ac2e, + 0x183227397098d014, +]); + /// GENERATOR^{2^s} where t * 2^s + 1 = r with t odd. In other words, this is a t root of unity. /// 0x09226b6e22c6f0ca64ec26aad4c86e715b5f898e5e963f25870e56bbe533e9a2 const DELTA: Fr = Fr::from_raw([ @@ -150,26 +150,34 @@ const ZETA: Fr = Fr::from_raw([ 0x30644e72e131a029, ]); +use crate::{ + extend_field_legendre, field_bits, impl_add_binop_specify_impl, impl_add_binop_specify_output, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_field, impl_from_uniform_bytes, impl_prime_field, + impl_serde_object, impl_sub_binop_specify_output, impl_sum_prod, pow_vartime, +}; impl_binops_additive!(Fr, Fr); impl_binops_multiplicative!(Fr, Fr); -field_common!( - Fr, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); +impl_add_binop_specify_impl!(Fr); +impl_field!(Fr, sparse); +impl_serde_object!(Fr); +impl_prime_field!(Fr, [u8; 32], le); impl_sum_prod!(Fr); extend_field_legendre!(Fr); +impl_from_uniform_bytes!(Fr, 64); + +#[cfg(not(feature = "asm"))] +field_arithmetic!(Fr, MODULUS, INV, sparse); +#[cfg(feature = "asm")] +field_arithmetic_asm!(Fr, MODULUS, INV); + +#[cfg(target_pointer_width = "64")] +field_bits!(Fr); +#[cfg(not(target_pointer_width = "64"))] +field_bits!(Fr); #[cfg(not(feature = "bn256-table"))] -impl_from_u64!(Fr, R2); +impl_from_u64!(Fr); #[cfg(feature = "bn256-table")] // A field element is represented in the montgomery form -- this allows for cheap mul_mod operations. // The catch is, if we build an Fr element, regardless of its format, we need to perform one big integer multiplication: @@ -190,54 +198,7 @@ impl From for Fr { } } -#[cfg(not(feature = "asm"))] -field_arithmetic!(Fr, MODULUS, INV, sparse); -#[cfg(feature = "asm")] -field_arithmetic_asm!(Fr, MODULUS, INV); - -#[cfg(target_pointer_width = "64")] -field_bits!(Fr, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits!(Fr, MODULUS, MODULUS_LIMBS_32); - impl Fr { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fr { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - fn sqrt(&self) -> CtOption { /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd. const T_MINUS1_OVER2: [u64; 4] = [ @@ -248,90 +209,11 @@ impl ff::Field for Fr { ]; ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -impl ff::PrimeField for Fr { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 254; - const CAPACITY: u32 = 253; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Fr([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 { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fr { - /// Converts a 512-bit little endian integer into - /// an `Fr` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - 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()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fr { - const ZETA: Self = ZETA; } #[cfg(test)] mod test { + use super::*; crate::field_testing_suite!(Fr, "field_arithmetic"); crate::field_testing_suite!(Fr, "conversion"); @@ -342,84 +224,5 @@ mod test { crate::field_testing_suite!(Fr, "constants", MODULUS_STR); crate::field_testing_suite!(Fr, "sqrt"); crate::field_testing_suite!(Fr, "zeta"); - crate::field_testing_suite!( - Fr, - "from_uniform_bytes", - [ - Fr::from_raw([ - 0x2ca6366467811a07, - 0x22727e3db430ed7e, - 0xbdb79bcb97d9e250, - 0x2cee6d1152d1d7b0 - ]), - Fr::from_raw([ - 0x6ec33f1a3af8cb2d, - 0x2c8f3330e85dab4b, - 0xfeeff4ae1b019172, - 0x095cd2a455dd67b6 - ]), - Fr::from_raw([ - 0x4741eee9c02c9f33, - 0xfc0111dd8aeb7e7a, - 0xb1d79e2a22d4ab08, - 0x0cb7168893a7bbda - ]), - Fr::from_raw([ - 0xc2ff8410555287f8, - 0x0927fbea8c6049c8, - 0xc0edccc8e4d3efe4, - 0x1d724b76911436c4 - ]), - Fr::from_raw([ - 0xdef98bc8d4db6e5b, - 0x42f0ea50590d557e, - 0x1f311a3b8114fd9a, - 0x0487c555645c67b1 - ]), - Fr::from_raw([ - 0x8ad4879b05ceb610, - 0x2e4e9a46537c84b0, - 0x5cfa7c43c9dfcfa1, - 0x0b6b2a4d122d0bb6 - ]), - Fr::from_raw([ - 0xe7f11ee016df7fe7, - 0x6419da89bd8aef3d, - 0x3511f5d293af95c8, - 0x10379c1d4d49593a - ]), - Fr::from_raw([ - 0xd63080c8aa3ecd37, - 0x19c20f30b56fe458, - 0xc9dbbcb3aa780e06, - 0x28a4e2b8273762c6 - ]), - Fr::from_raw([ - 0xecea51b521eac0b8, - 0x65fff58a5881c562, - 0x603ac7d1e06ef3af, - 0x1e0c2c51226eecea - ]), - Fr::from_raw([ - 0xe6ec4779b8bd6516, - 0x0d5411f3cb9504ae, - 0xff706ec73df8e92a, - 0x2c56d60b3e351e56 - ]), - ] - ); - - #[test] - fn bench_fr_from_u16() { - use ark_std::{end_timer, start_timer}; - - let repeat = 10000000; - let mut rng = ark_std::test_rng(); - let base = (0..repeat).map(|_| (rng.next_u32() % (1 << 16)) as u64); - - let timer = start_timer!(|| format!("generate {repeat} Bn256 scalar field elements")); - let _res: Vec<_> = base.map(Fr::from).collect(); - - end_timer!(timer); - } + crate::field_testing_suite!(Fr, "from_uniform_bytes", 64); } diff --git a/src/bn256/mod.rs b/src/bn256/mod.rs index 58186c15..3530b765 100644 --- a/src/bn256/mod.rs +++ b/src/bn256/mod.rs @@ -16,53 +16,3 @@ pub use fq12::*; pub use fq2::*; pub use fq6::*; pub use fr::*; - -#[cfg(test)] -mod test { - use super::G1 as Bn256Point; - use group::GroupEncoding; - use pasta_curves::arithmetic::CurveExt; - use rand_core::{RngCore, SeedableRng}; - - #[test] - fn test_consistent_hash_to_curve() { - // The goal of this test is to generate test vectors to ensure that the ASM implementation - // matches the rust implementation. - let num_vecs = 10; - - // Test vectors generated with rust implementation. - let expected_results = [ - "e0c5a6834e0329b4f8bdc91144b3e687ac9d810a8e899415267db9cfbf61e91e", - "7052a20bee99cbe054fdd8b2e336db3ed3e9a265229e44ab8197c5eabdef2b0b", - "2f058acc133957074ac79e9b9b1867a0cf3d13df7aa7de7f48e9a6be7d96aaad", - "b2ff44a25693b811f35e33feb3e99ad9ba0d06425a3ffd5e79cef63d20143314", - "ab2f6d71d2fde51546d8a5782aa9f707e585b84644470f0c876784dbebd30c95", - "6a4e0e30f37a8d1b92b8cf08df3735a36b4937ee455a9dc5f9283a13530db184", - "f1c69be8c5f5f9e28b0e9f76ab77651a7dcaaae371fbba66450cbcee0ed5b1ab", - "e86267c2e3355d7a6f664a0ea71374406337d452a3f9a294a0594df53c08df21", - "03cf55ca983ecd8a2e2baae18d979d97d688a978d829701c66a14d7c4da58ea2", - "5302c2cfe3c909e9378d08c951bb33d0813818a1baf734379aac8aaa47f38f0d", - ]; - - let mut seeded_rng = rand_chacha::ChaChaRng::seed_from_u64(0u64); - let uniform_bytes = std::iter::from_fn(|| { - let mut bytes = [0u8; 32]; - seeded_rng.fill_bytes(&mut bytes); - Some(bytes) - }) - .take(num_vecs) - .collect::>(); - let hash = Bn256Point::hash_to_curve("from_uniform_bytes"); - for i in 0..num_vecs { - let p = hash(&uniform_bytes[i]); - let expected_result = hex::decode(expected_results[i]).unwrap(); - assert_eq!( - p.to_bytes().as_ref(), - &expected_result[..], - "hash_to_curve_print failed, expected: {}, got: {}", - expected_results[i], - hex::encode(p.to_bytes().as_ref()) - ); - } - } -} diff --git a/src/derive/curve.rs b/src/derive/curve.rs index 2449752a..1f1deaf1 100644 --- a/src/derive/curve.rs +++ b/src/derive/curve.rs @@ -122,9 +122,9 @@ macro_rules! new_curve_impl { #[allow(non_upper_case_globals)] const [< $name _COMPRESSED_SIZE >]: usize = if $spare_bits == 0 { - $base::size() + 1 + $base::SIZE + 1 } else { - $base::size() + $base::SIZE }; #[derive(Copy, Clone, PartialEq, Eq)] @@ -220,8 +220,8 @@ macro_rules! new_curve_impl { tmp[[< $name _FLAG_BYTE_INDEX>]] &= ![< $name _FLAG_BITS >]; // Get x-coordinate - let mut xbytes = [0u8; $base::size()]; - xbytes.copy_from_slice(&tmp[..$base::size()]); + let mut xbytes = [0u8; $base::SIZE]; + xbytes.copy_from_slice(&tmp[..$base::SIZE]); @@ -281,7 +281,7 @@ macro_rules! new_curve_impl { let mut res = [0; [< $name _COMPRESSED_SIZE >]]; let x_bytes = $base::conditional_select(&self.x, &$base::zero(), self.is_identity()).to_bytes(); - res[..$base::size()].copy_from_slice(&x_bytes); + res[..$base::SIZE].copy_from_slice(&x_bytes); // Set identity flag if necessary. res[ [< $name _FLAG_BYTE_INDEX>]] |= u8::conditional_select(&0u8, &IDENTITY_MASK, self.is_identity()); @@ -343,7 +343,7 @@ macro_rules! new_curve_impl { paste::paste! { #[derive(Copy, Clone)] - pub struct [< $name Uncompressed >]([u8; 2*$base::size()]); + pub struct [< $name Uncompressed >]([u8; 2*$base::SIZE]); impl std::fmt::Debug for [< $name Uncompressed >] { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0[..].fmt(f) @@ -352,7 +352,7 @@ macro_rules! new_curve_impl { impl Default for [< $name Uncompressed >] { fn default() -> Self { - [< $name Uncompressed >]([0; 2*$base::size() ]) + [< $name Uncompressed >]([0; 2*$base::SIZE ]) } } @@ -393,8 +393,8 @@ macro_rules! new_curve_impl { fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption { let mut bytes = bytes.0; - let flag_idx_x = $base::size() -1; - let flag_idx_y = 2* $base::size() -1; + let flag_idx_x = $base::SIZE -1; + let flag_idx_y = 2* $base::SIZE -1; // In the uncompressed format, the spare bits in both coordinates must be 0. let mut any_flag_set = Choice::from(0u8); @@ -418,14 +418,14 @@ macro_rules! new_curve_impl { // Get x, y coordinates. - let mut repr = [0u8; $base::size()]; + let mut repr = [0u8; $base::SIZE]; let x = { - repr.copy_from_slice(&bytes[0..$base::size()]); + repr.copy_from_slice(&bytes[0..$base::SIZE]); $base::from_bytes(&repr) }; let y = { - repr.copy_from_slice(&bytes[$base::size()..2*$base::size()]); + repr.copy_from_slice(&bytes[$base::SIZE..2*$base::SIZE]); $base::from_bytes(&repr) }; @@ -451,8 +451,6 @@ macro_rules! new_curve_impl { is_identity, ); - eprintln!("Is the point valid? {:?}", is_valid); - CtOption::new( p, is_valid @@ -462,12 +460,12 @@ macro_rules! new_curve_impl { } fn to_uncompressed(&self) -> Self::Uncompressed { - let mut res = [0; 2*$base::size()]; + let mut res = [0; 2*$base::SIZE]; - res[0..$base::size()].copy_from_slice( + res[0..$base::SIZE].copy_from_slice( &$base::conditional_select(&self.x, &$base::zero(), self.is_identity()).to_bytes()[..], ); - res[$base::size().. 2*$base::size()].copy_from_slice( + res[$base::SIZE.. 2*$base::SIZE].copy_from_slice( &$base::conditional_select(&self.y, &$base::zero(), self.is_identity()).to_bytes()[..], ); @@ -724,7 +722,7 @@ macro_rules! new_curve_impl { #[allow(clippy::redundant_closure_call)] fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box Self + 'a> { - $hash_to_curve($curve_id, domain_prefix) + $hash_to_curve(domain_prefix) } fn is_on_curve(&self) -> Choice { @@ -916,17 +914,17 @@ macro_rules! new_curve_impl { impl $crate::serde::SerdeObject for $name { fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 3 * $base::size()); + debug_assert_eq!(bytes.len(), 3 * $base::SIZE); let [x, y, z] = [0, 1, 2] - .map(|i| $base::from_raw_bytes_unchecked(&bytes[i * $base::size()..(i + 1) * $base::size()])); + .map(|i| $base::from_raw_bytes_unchecked(&bytes[i * $base::SIZE..(i + 1) * $base::SIZE])); Self { x, y, z } } fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 3 * $base::size() { + if bytes.len() != 3 * $base::SIZE { return None; } let [x, y, z] = - [0, 1, 2].map(|i| $base::from_raw_bytes(&bytes[i * $base::size()..(i + 1) * $base::size()])); + [0, 1, 2].map(|i| $base::from_raw_bytes(&bytes[i * $base::SIZE..(i + 1) * $base::SIZE])); x.zip(y).zip(z).and_then(|((x, y), z)| { let res = Self { x, y, z }; // Check that the point is on the curve. @@ -934,7 +932,7 @@ macro_rules! new_curve_impl { }) } fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(3 * $base::size()); + let mut res = Vec::with_capacity(3 * $base::SIZE); Self::write_raw(self, &mut res).unwrap(); res } @@ -1018,16 +1016,16 @@ macro_rules! new_curve_impl { impl $crate::serde::SerdeObject for $name_affine { fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 2 * $base::size()); + debug_assert_eq!(bytes.len(), 2 * $base::SIZE); let [x, y] = - [0, $base::size()].map(|i| $base::from_raw_bytes_unchecked(&bytes[i..i + $base::size()])); + [0, $base::SIZE].map(|i| $base::from_raw_bytes_unchecked(&bytes[i..i + $base::SIZE])); Self { x, y } } fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 2 * $base::size() { + if bytes.len() != 2 * $base::SIZE { return None; } - let [x, y] = [0, $base::size()].map(|i| $base::from_raw_bytes(&bytes[i..i + $base::size()])); + let [x, y] = [0, $base::SIZE].map(|i| $base::from_raw_bytes(&bytes[i..i + $base::SIZE])); x.zip(y).and_then(|(x, y)| { let res = Self { x, y }; // Check that the point is on the curve. @@ -1035,7 +1033,7 @@ macro_rules! new_curve_impl { }) } fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(2 * $base::size()); + let mut res = Vec::with_capacity(2 * $base::SIZE); Self::write_raw(self, &mut res).unwrap(); res } diff --git a/src/derive/field/common.rs b/src/derive/field/common.rs new file mode 100644 index 00000000..10751cab --- /dev/null +++ b/src/derive/field/common.rs @@ -0,0 +1,533 @@ +// #[macro_export] +// macro_rules! assert_const { +// ($constant:ident, $expect:expr) => { +// paste::paste! { +// #[test] +// fn [< test_constant_ $constant:lower >]() { +// let expect = $crate::tests::hex_to_field($expect); +// assert_eq!($constant, expect); +// } +// } +// }; + +// ($constant:expr, $expect:expr, inv) => { +// paste::paste! { +// #[test] +// fn [< test_constant_ $constant:lower >]() { +// let expect = $crate::tests::hex_to_field($expect); +// assert_eq!($constant.invert().unwrap(), expect); +// } +// } +// }; +// } + +#[macro_export] +macro_rules! impl_from_uniform_bytes { + ($field:ident, $size:expr) => { + impl FromUniformBytes<$size> for $field { + fn from_uniform_bytes(bytes: &[u8; $size]) -> Self { + let limbs = (0..($size - 1) / 8 + 1) + .map(|i| u64::from_le_bytes(bytes[i * 8..(i + 1) * 8].try_into().unwrap())) + .collect::>(); + + let lo = (limbs[..NUM_LIMBS]).try_into().unwrap(); + let hi = limbs + .into_iter() + .skip(NUM_LIMBS) + .map(|limb| limb) + .chain(std::iter::repeat(0)) + .take(NUM_LIMBS) + .collect::>(); + + Self::montgomery_form(lo, R2) + Self::montgomery_form(hi.try_into().unwrap(), R3) + } + } + }; +} + +#[macro_export] +macro_rules! pow_vartime { + (dense) => { + fn pow_vartime>(&self, exp: S) -> Self { + let mut res = Self::one(); + let mut found_one = false; + for e in exp.as_ref().iter().rev() { + for i in (0..64).rev() { + if found_one { + res = res.square(); + } + + if ((*e >> i) & 1) == 1 { + found_one = true; + res *= self; + } + } + } + res + } + }; + (sparse) => { + // Uses fallback implementation + }; +} + +#[macro_export] +macro_rules! impl_from_u64 { + ($field:ident) => { + impl From for $field { + fn from(val: u64) -> $field { + let limbs = std::iter::once(val) + .chain(std::iter::repeat(0)) + .take(NUM_LIMBS) + .collect::>() + .try_into() + .unwrap(); + + $field(limbs) * R2 + } + } + }; +} + +#[macro_export] +macro_rules! impl_prime_field { + ( + $field:ident, + $repr:ty, + $endian:tt + ) => { + fn to_repr(el: &$field) -> $repr { + let tmp: [u64; NUM_LIMBS] = (*el).into(); + let mut res = [0; $field::SIZE]; + tmp.iter().enumerate().for_each(|(i, limb)| { + let off = i * 8; + res[off..off + 8].copy_from_slice(&limb.to_le_bytes()); + }); + + res.into() + } + + fn from_repr(repr: $repr) -> CtOption<$field> { + let mut tmp = $field::default(); + let borrow = tmp.0.iter_mut().enumerate().fold(0, |borrow, (i, limb)| { + let off = i * 8; + *limb = u64::from_le_bytes(repr[off..off + 8].try_into().unwrap()); + sbb(*limb, MODULUS.0[i], borrow).1 + }); + + // 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)) + } + + macro_rules! impl_repr { + ($field_inner:ident,$repr_inner:ty, le) => { + fn to_repr(&self) -> $repr { + to_repr(self) + } + + fn from_repr(repr: $repr) -> CtOption { + from_repr(repr) + } + }; + + ($field_inner:ident,$repr_inner:ty, be) => { + fn to_repr(&self) -> $repr { + let mut repr = to_repr(self); + repr.reverse(); + repr + } + + fn from_repr(mut repr: $repr) -> CtOption { + repr.reverse(); + from_repr(repr) + } + }; + } + + impl ff::PrimeField for $field { + type Repr = $repr; + + const MODULUS: &'static str = MODULUS_STR; + const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR; + const TWO_INV: Self = TWO_INV; + const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; + const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; + const DELTA: Self = DELTA; + const NUM_BITS: u32 = NUM_BITS; + const CAPACITY: u32 = Self::NUM_BITS - 1; + const S: u32 = S; + + fn from_u128(v: u128) -> Self { + Self::from_raw( + [v as u64, (v >> 64) as u64] + .into_iter() + .chain(std::iter::repeat(0)) + .take(NUM_LIMBS) + .collect::>() + .try_into() + .unwrap(), + ) + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr()[0] & 1) + } + + impl_repr!($field, $repr, $endian); + } + + impl From<$field> for $repr { + fn from(value: $field) -> $repr { + value.to_repr() + } + } + + impl<'a> From<&'a $field> for $repr { + fn from(value: &'a $field) -> $repr { + value.to_repr() + } + } + + impl WithSmallOrderMulGroup<3> for $field { + const ZETA: Self = ZETA; + } + }; +} + +#[macro_export] +macro_rules! impl_field { + ( + $field:ident, + $field_type:ident + ) => { + // Number of 64 bit limbs to represent the field element + pub(crate) const NUM_LIMBS: usize = ((NUM_BITS - 1) / 64 + 1) as usize; + + // The internal representation of this type is four 64-bit unsigned + // integers in little-endian order. `Fq` values are always in + // Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. + #[derive(Clone, Copy, PartialEq, Eq, Hash, Default)] + pub struct $field(pub(crate) [u64; NUM_LIMBS]); + + /// Bernstein-Yang modular multiplicative inverter created for the modulus equal to + /// the characteristic of the field to invert positive integers in the Montgomery form. + const BYINVERTOR: $crate::ff_ext::inverse::BYInverter = + $crate::ff_ext::inverse::BYInverter::::new(&MODULUS.0, &R2.0); + + impl std::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 ConstantTimeEq for $field { + fn ct_eq(&self, other: &Self) -> Choice { + Choice::from( + self.0 + .iter() + .zip(other.0) + .all(|(a, b)| bool::from(a.ct_eq(&b))) as u8, + ) + } + } + + impl ConditionallySelectable for $field { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + let limbs = (0..NUM_LIMBS) + .map(|i| u64::conditional_select(&a.0[i], &b.0[i], choice)) + .collect::>() + .try_into() + .unwrap(); + $field(limbs) + } + } + + impl core::cmp::PartialOrd for $field { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + 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 ff::Field for $field { + const ZERO: Self = Self::zero(); + const ONE: Self = Self::one(); + + fn random(mut rng: impl RngCore) -> Self { + let mut wide = [0u8; Self::SIZE * 2]; + rng.fill_bytes(&mut wide); + Self::from_uniform_bytes(&wide) + } + + #[must_use] + fn double(&self) -> Self { + self.double() + } + + #[inline(always)] + #[must_use] + fn square(&self) -> Self { + self.square() + } + + fn invert(&self) -> CtOption { + self.invert() + } + + fn sqrt(&self) -> CtOption { + self.sqrt() + } + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + ff::helpers::sqrt_ratio_generic(num, div) + } + + pow_vartime!($field_type); + } + + impl $field { + pub const SIZE: usize = NUM_LIMBS * 8; + + /// Returns zero, the additive identity. + #[inline] + pub const fn zero() -> $field { + $field([0; NUM_LIMBS]) + } + + /// Returns one, the multiplicative identity. + #[inline] + pub const fn one() -> $field { + R + } + + /// Converts from an integer represented in little endian + /// into its (congruent) `$field` representation. + pub const fn from_raw(val: [u64; NUM_LIMBS]) -> Self { + Self::montgomery_form(val, R2) + } + + /// Attempts to convert a little-endian byte representation of + /// a scalar into a `Fr`, failing if the input is not canonical. + pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> CtOption<$field> { + let bytes: ::Repr = (*bytes).into(); + let z = ::from_repr(bytes); + z + } + + /// Converts an element of `Fr` into a byte representation in + /// little-endian byte order. + pub fn to_bytes(&self) -> [u8; Self::SIZE] { + ::to_repr(self).into() + } + + /// Returns the multiplicative inverse of the + /// element. If it is zero, the method fails. + #[inline(always)] + pub fn invert(&self) -> CtOption { + if let Some(inverse) = BYINVERTOR.invert(&self.0) { + CtOption::new(Self(inverse), Choice::from(1)) + } else { + CtOption::new(Self::zero(), Choice::from(0)) + } + } + + // Returns the Jacobi symbol, where the numerator and denominator + // are the element and the characteristic of the field, respectively. + // The Jacobi symbol is applicable to odd moduli + // while the Legendre symbol is applicable to prime moduli. + // They are equivalent for prime moduli. + #[inline(always)] + pub fn jacobi(&self) -> i64 { + $crate::ff_ext::jacobi::jacobi::(&self.0, &MODULUS.0) + } + + // Lexicographic comparison of Montgomery forms. + #[inline(always)] + fn is_less_than(x: &$field, y: &$field) -> bool { + let borrow = + x.0.iter() + .zip(y.0.iter()) + .fold(0, |borrow, (x, y)| sbb(*x, *y, borrow).1); + + borrow >> 63 == 1 + } + } + }; +} + +#[macro_export] +macro_rules! impl_serde_object { + ($field:ident) => { + impl SerdeObject for $field { + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { + debug_assert_eq!(bytes.len(), Self::SIZE); + + let inner = (0..NUM_LIMBS) + .map(|off| { + u64::from_le_bytes(bytes[off * 8..(off + 1) * 8].try_into().unwrap()) + }) + .collect::>(); + Self(inner.try_into().unwrap()) + } + fn from_raw_bytes(bytes: &[u8]) -> Option { + if bytes.len() != Self::SIZE { + return None; + } + let elt = Self::from_raw_bytes_unchecked(bytes); + Self::is_less_than(&elt, &MODULUS).then(|| elt) + } + fn to_raw_bytes(&self) -> Vec { + let mut res = Vec::with_capacity(NUM_LIMBS * 4); + for limb in self.0.iter() { + res.extend_from_slice(&limb.to_le_bytes()); + } + res + } + fn read_raw_unchecked(reader: &mut R) -> Self { + let inner = [(); NUM_LIMBS].map(|_| { + let mut buf = [0; 8]; + reader.read_exact(&mut buf).unwrap(); + u64::from_le_bytes(buf) + }); + Self(inner) + } + fn read_raw(reader: &mut R) -> std::io::Result { + let mut inner = [0u64; NUM_LIMBS]; + for limb in inner.iter_mut() { + let mut buf = [0; 8]; + reader.read_exact(&mut buf)?; + *limb = u64::from_le_bytes(buf); + } + let elt = Self(inner); + Self::is_less_than(&elt, &MODULUS) + .then(|| elt) + .ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "input number is not less than field modulus", + ) + }) + } + fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { + for limb in self.0.iter() { + writer.write_all(&limb.to_le_bytes())?; + } + Ok(()) + } + } + }; +} + +#[macro_export] +macro_rules! field_bits { + // For #[cfg(target_pointer_width = "64")] + ($field:ident) => { + #[cfg(feature = "bits")] + #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] + impl ff::PrimeFieldBits for $field { + type ReprBits = [u64; NUM_LIMBS]; + + fn to_le_bits(&self) -> ff::FieldBits { + let bytes: [u8; Self::SIZE] = self.to_repr().into(); + + let limbs = (0..NUM_LIMBS) + .map(|off| { + u64::from_le_bytes(bytes[off * 8..(off + 1) * 8].try_into().unwrap()) + }) + .collect::>(); + + ff::FieldBits::new(limbs.try_into().unwrap()) + } + + fn char_le_bits() -> ff::FieldBits { + ff::FieldBits::new(MODULUS.0) + } + } + }; + // For #[cfg(not(target_pointer_width = "64"))] + ($field:ident) => { + #[cfg(feature = "bits")] + #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] + impl ff::PrimeFieldBits for $field { + type ReprBits = [u32; NUM_LIMBS * 2]; + + fn to_le_bits(&self) -> ff::FieldBits { + let bytes = self.to_repr(); + + let limbs = (0..NUM_LIMBS * 2) + .map(|off| { + u64::from_le_bytes(bytes[off * 4..(off + 1) * 4].try_into().unwrap()) + }) + .collect::>(); + + ff::FieldBits::new(limbs.try_into().unwrap()) + } + + fn char_le_bits() -> ff::FieldBits { + ff::FieldBits::new(MODULUS_LIMBS_32) + } + } + }; +} + +/// A macro to help define serialization and deserialization for prime field implementations +/// that use 32-byte representations. This assumes the concerned type implements PrimeField +/// (for from_repr, to_repr). +#[macro_export] +macro_rules! serialize_deserialize_32_byte_primefield { + ($type:ty) => { + impl ::serde::Serialize for $type { + fn serialize(&self, serializer: S) -> Result { + let bytes = &self.to_repr(); + if serializer.is_human_readable() { + hex::serde::serialize(bytes, serializer) + } else { + bytes.serialize(serializer) + } + } + } + + use ::serde::de::Error as _; + impl<'de> ::serde::Deserialize<'de> for $type { + fn deserialize>( + deserializer: D, + ) -> Result { + let bytes = if deserializer.is_human_readable() { + ::hex::serde::deserialize(deserializer)? + } else { + <[u8; 32]>::deserialize(deserializer)? + }; + Option::from(Self::from_repr(bytes)).ok_or_else(|| { + D::Error::custom("deserialized bytes don't encode a valid field element") + }) + } + } + }; +} diff --git a/src/derive/field.rs b/src/derive/field/mod.rs similarity index 57% rename from src/derive/field.rs rename to src/derive/field/mod.rs index a6518b02..8dfd13c5 100644 --- a/src/derive/field.rs +++ b/src/derive/field/mod.rs @@ -1,68 +1,14 @@ -#[macro_export] -macro_rules! impl_from_u64 { - ($field:ident, $r2:ident) => { - impl From for $field { - fn from(val: u64) -> $field { - $field([val, 0, 0, 0]) * $r2 - } - } - }; -} +#[macro_use] +pub mod common; +#[macro_use] +pub mod tower; #[macro_export] -macro_rules! field_common { - ( - $field:ident, - $modulus:ident, - $inv:ident, - $modulus_str:ident, - $two_inv:ident, - $root_of_unity_inv:ident, - $delta:ident, - $zeta:ident, - $r:ident, - $r2:ident, - $r3:ident - ) => { - /// Bernstein-Yang modular multiplicative inverter created for the modulus equal to - /// the characteristic of the field to invert positive integers in the Montgomery form. - const BYINVERTOR: $crate::ff_ext::inverse::BYInverter<6> = - $crate::ff_ext::inverse::BYInverter::<6>::new(&$modulus.0, &$r2.0); +macro_rules! field_arithmetic { + ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => { + field_specific!($field, $modulus, $inv, $field_type); 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 - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - #[inline(always)] - pub fn invert(&self) -> CtOption { - if let Some(inverse) = BYINVERTOR.invert(&self.0) { - CtOption::new(Self(inverse), Choice::from(1)) - } else { - CtOption::new(Self::zero(), Choice::from(0)) - } - } - - // Returns the Jacobi symbol, where the numerator and denominator - // are the element and the characteristic of the field, respectively. - // The Jacobi symbol is applicable to odd moduli - // while the Legendre symbol is applicable to prime moduli. - // They are equivalent for prime moduli. - #[inline(always)] - pub fn jacobi(&self) -> i64 { - $crate::ff_ext::jacobi::jacobi::<5>(&self.0, &$modulus.0) - } - const fn montgomery_form(val: [u64; 4], r: $field) -> $field { // Converts a 4 64-bit limb value into its congruent field representation. // If `val` represents a 256 bit value then `r` should be R^2, @@ -147,250 +93,6 @@ macro_rules! field_common { } } - 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 lower_256 = [limbs[0], limbs[1], limbs[2], limbs[3]]; - let upper_256 = [limbs[4], limbs[5], limbs[6], limbs[7]]; - - Self::montgomery_form(lower_256, $r2) + Self::montgomery_form(upper_256, $r3) - } - - /// Converts from an integer represented in little endian - /// into its (congruent) `$field` representation. - pub const fn from_raw(val: [u64; 4]) -> Self { - Self::montgomery_form(val, $r2) - } - - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fr`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<$field> { - ::from_repr(*bytes) - } - - /// Converts an element of `Fr` into a byte representation in - /// little-endian byte order. - pub fn to_bytes(&self) -> [u8; 32] { - ::to_repr(self) - } - - /// Lexicographic comparison of Montgomery forms. - #[inline(always)] - const fn is_less_than(x: &[u64; 4], y: &[u64; 4]) -> bool { - let (_, borrow) = sbb(x[0], y[0], 0); - let (_, borrow) = sbb(x[1], y[1], borrow); - let (_, borrow) = sbb(x[2], y[2], borrow); - let (_, borrow) = sbb(x[3], y[3], borrow); - borrow >> 63 == 1 - } - } - - 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 Default for $field { - #[inline] - fn default() -> Self { - Self::zero() - } - } - - impl From for $field { - fn from(bit: bool) -> $field { - if bit { - $field::one() - } else { - $field::zero() - } - } - } - - 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 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) -> Self { - $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 From<[u64; 4]> for $field { - fn from(digits: [u64; 4]) -> Self { - Self::from_raw(digits) - } - } - - 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 $crate::serde::SerdeObject for $field { - fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 32); - let inner = - [0, 8, 16, 24].map(|i| u64::from_le_bytes(bytes[i..i + 8].try_into().unwrap())); - Self(inner) - } - fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 32 { - return None; - } - let elt = Self::from_raw_bytes_unchecked(bytes); - Self::is_less_than(&elt.0, &$modulus.0).then(|| elt) - } - fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(32); - for limb in self.0.iter() { - res.extend_from_slice(&limb.to_le_bytes()); - } - res - } - fn read_raw_unchecked(reader: &mut R) -> Self { - let inner = [(); 4].map(|_| { - let mut buf = [0; 8]; - reader.read_exact(&mut buf).unwrap(); - u64::from_le_bytes(buf) - }); - Self(inner) - } - fn read_raw(reader: &mut R) -> std::io::Result { - let mut inner = [0u64; 4]; - for limb in inner.iter_mut() { - let mut buf = [0; 8]; - reader.read_exact(&mut buf)?; - *limb = u64::from_le_bytes(buf); - } - let elt = Self(inner); - Self::is_less_than(&elt.0, &$modulus.0) - .then(|| elt) - .ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - "input number is not less than field modulus", - ) - }) - } - fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { - for limb in self.0.iter() { - writer.write_all(&limb.to_le_bytes())?; - } - Ok(()) - } - } - }; -} - -#[macro_export] -macro_rules! field_arithmetic { - ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => { - field_specific!($field, $modulus, $inv, $field_type); - - impl $field { /// Doubles this field element. #[inline] pub const fn double(&self) -> $field { @@ -711,96 +413,3 @@ macro_rules! field_specific { } }; } - -#[macro_export] -macro_rules! field_bits { - // For #[cfg(target_pointer_width = "64")] - ($field:ident, $modulus:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u64; 4]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr(); - - 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()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus.0) - } - } - }; - // For #[cfg(not(target_pointer_width = "64"))] - ($field:ident, $modulus:ident, $modulus_limbs_32:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u32; 8]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr(); - - 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()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus_limbs_32) - } - } - }; -} - -/// A macro to help define serialization and deserialization for prime field implementations -/// that use 32-byte representations. This assumes the concerned type implements PrimeField -/// (for from_repr, to_repr). -#[macro_export] -macro_rules! serialize_deserialize_32_byte_primefield { - ($type:ty) => { - impl ::serde::Serialize for $type { - fn serialize(&self, serializer: S) -> Result { - let bytes = &self.to_repr(); - if serializer.is_human_readable() { - hex::serde::serialize(bytes, serializer) - } else { - bytes.serialize(serializer) - } - } - } - - use ::serde::de::Error as _; - impl<'de> ::serde::Deserialize<'de> for $type { - fn deserialize>( - deserializer: D, - ) -> Result { - let bytes = if deserializer.is_human_readable() { - ::hex::serde::deserialize(deserializer)? - } else { - <[u8; 32]>::deserialize(deserializer)? - }; - Option::from(Self::from_repr(bytes)).ok_or_else(|| { - D::Error::custom("deserialized bytes don't encode a valid field element") - }) - } - } - }; -} diff --git a/src/derive/field/tower.rs b/src/derive/field/tower.rs new file mode 100644 index 00000000..002e3f4a --- /dev/null +++ b/src/derive/field/tower.rs @@ -0,0 +1,465 @@ +#[macro_export] +macro_rules! impl_tower2_common { + ( + $field:ident, + $tower:ident + ) => { + #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] + pub struct $tower { + pub c0: $field, + pub c1: $field, + } + + impl ConditionallySelectable for $tower { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + $tower { + c0: $field::conditional_select(&a.c0, &b.c0, choice), + c1: $field::conditional_select(&a.c1, &b.c1, choice), + } + } + } + + impl ConstantTimeEq for $tower { + fn ct_eq(&self, other: &Self) -> Choice { + self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) + } + } + + impl $tower { + #[inline] + pub const fn zero() -> $tower { + $tower { + c0: $field::ZERO, + c1: $field::ZERO, + } + } + + #[inline] + pub const fn one() -> $tower { + $tower { + c0: $field::ONE, + c1: $field::ZERO, + } + } + + #[inline] + pub const fn new(c0: $field, c1: $field) -> Self { + $tower { c0, c1 } + } + + pub fn double(&self) -> Self { + Self { + c0: self.c0.double(), + c1: self.c1.double(), + } + } + + pub fn add(&self, other: &Self) -> Self { + Self { + c0: self.c0.add(&other.c0), + c1: self.c1.add(&other.c1), + } + } + + pub fn sub(&self, other: &Self) -> Self { + Self { + c0: self.c0.sub(&other.c0), + c1: self.c1.sub(&other.c1), + } + } + + pub fn neg(&self) -> Self { + Self { + c0: self.c0.neg(), + c1: self.c1.neg(), + } + } + } + }; +} + +#[macro_export] +macro_rules! impl_tower2 { + ( + $field:ident, + $tower:ident, + $repr:ident + ) => { + // #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] + // // #[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] + // pub struct $tower { + // pub c0: $field, + // pub c1: $field, + // } + + // impl ConditionallySelectable for $tower { + // fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + // $tower { + // c0: $field::conditional_select(&a.c0, &b.c0, choice), + // c1: $field::conditional_select(&a.c1, &b.c1, choice), + // } + // } + // } + + // impl ConstantTimeEq for $tower { + // fn ct_eq(&self, other: &Self) -> Choice { + // self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) + // } + // } + + /// `$tower` elements are ordered lexicographically. + impl Ord for $tower { + #[inline(always)] + fn cmp(&self, other: &$tower) -> Ordering { + match self.c1.cmp(&other.c1) { + Ordering::Greater => Ordering::Greater, + Ordering::Less => Ordering::Less, + Ordering::Equal => self.c0.cmp(&other.c0), + } + } + } + + impl PartialOrd for $tower { + #[inline(always)] + fn partial_cmp(&self, other: &$tower) -> Option { + Some(self.cmp(other)) + } + } + + impl From<$tower> for [u8; $tower::SIZE] { + fn from(value: $tower) -> [u8; $tower::SIZE] { + value.to_bytes() + } + } + + impl<'a> From<&'a $tower> for [u8; $tower::SIZE] { + fn from(value: &'a $tower) -> [u8; $tower::SIZE] { + value.to_bytes() + } + } + + impl $tower { + pub const SIZE: usize = $field::SIZE * 2; + + /// Attempts to convert a little-endian byte representation of + /// a scalar into a `$field`, failing if the input is not canonical. + pub fn from_bytes(bytes: &[u8; $field::SIZE * 2]) -> CtOption<$tower> { + let c0 = $field::from_bytes(bytes[0..$field::SIZE].try_into().unwrap()); + let c1 = + $field::from_bytes(bytes[$field::SIZE..$field::SIZE * 2].try_into().unwrap()); + CtOption::new( + $tower { + c0: c0.unwrap(), + c1: c1.unwrap(), + }, + c0.is_some() & c1.is_some(), + ) + } + + /// Converts an element of `$field` into a byte representation in + /// little-endian byte order. + #[allow(clippy::wrong_self_convention)] + pub fn to_bytes(&self) -> [u8; $field::SIZE * 2] { + let mut res = [0u8; $field::SIZE * 2]; + let c0_bytes = self.c0.to_bytes(); + let c1_bytes = self.c1.to_bytes(); + res[0..$field::SIZE].copy_from_slice(&c0_bytes[..]); + res[$field::SIZE..$field::SIZE * 2].copy_from_slice(&c1_bytes[..]); + res + } + } + + impl ff::Field for $tower { + const ZERO: Self = Self::zero(); + const ONE: Self = Self::one(); + + fn random(mut rng: impl RngCore) -> Self { + $tower { + c0: $field::random(&mut rng), + c1: $field::random(&mut rng), + } + } + + fn is_zero(&self) -> Choice { + self.c0.is_zero() & self.c1.is_zero() + } + + fn square(&self) -> Self { + self.square() + } + + fn double(&self) -> Self { + self.double() + } + + fn sqrt(&self) -> CtOption { + self.sqrt() + } + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + ff::helpers::sqrt_ratio_generic(num, div) + } + + fn invert(&self) -> CtOption { + self.invert() + } + } + + impl PrimeField for $tower { + type Repr = $repr; + + const MODULUS: &'static str = super::MODULUS_STR; + const MULTIPLICATIVE_GENERATOR: Self = $tower { + c0: $field::MULTIPLICATIVE_GENERATOR, + c1: $field::ZERO, + }; + const NUM_BITS: u32 = $field::NUM_BITS; + const CAPACITY: u32 = $field::NUM_BITS; + const S: u32 = $field::S; + + // TODO: Check that we can just 0 this and forget. + const ROOT_OF_UNITY: Self = $tower::ZERO; + const ROOT_OF_UNITY_INV: Self = $tower::ZERO; + const DELTA: Self = $tower::ZERO; + + const TWO_INV: Self = $tower { + c0: $field::TWO_INV, + c1: $field::ZERO, + }; + + fn from_repr(repr: Self::Repr) -> CtOption { + let c0 = $field::from_bytes(&repr.0[..$field::SIZE].try_into().unwrap()); + let c1 = $field::from_bytes(&repr.0[$field::SIZE..].try_into().unwrap()); + CtOption::new($tower::new(c0.unwrap(), c1.unwrap()), Choice::from(1)) + } + + fn to_repr(&self) -> Self::Repr { + $repr(self.to_bytes()) + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr().as_ref()[0] & 1) + } + } + + impl WithSmallOrderMulGroup<3> for $tower { + // $field::ZETA ^2 + const ZETA: Self = $tower { + c0: ZETA, + c1: $field::ZERO, + }; + } + + impl From for $tower { + fn from(val: u64) -> Self { + $tower { + c0: $field::from(val), + c1: $field::ZERO, + } + } + } + + impl Legendre for $tower { + fn legendre(&self) -> i64 { + self.norm().legendre() + } + } + + #[derive(Clone, Copy, Debug)] + pub struct $repr([u8; $field::SIZE * 2]); + + impl Default for $repr { + fn default() -> Self { + Self([0u8; $field::SIZE * 2]) + } + } + + impl AsMut<[u8]> for $repr { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } + } + + impl AsRef<[u8]> for $repr { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + impl FromUniformBytes<{ $field::SIZE * 2 }> for $tower { + fn from_uniform_bytes(bytes: &[u8; $field::SIZE * 2]) -> Self { + Self::new($field::from_uniform_bytes(bytes), $field::ZERO) + } + } + + impl FromUniformBytes<{ $field::SIZE * 2 * 2 }> for $tower { + fn from_uniform_bytes(bytes: &[u8; $field::SIZE * 2 * 2]) -> Self { + let c0: [u8; $field::SIZE * 2] = bytes[..$field::SIZE * 2].try_into().unwrap(); + let c1: [u8; $field::SIZE * 2] = bytes[$field::SIZE * 2..].try_into().unwrap(); + Self::new( + $field::from_uniform_bytes(&c0), + $field::from_uniform_bytes(&c1), + ) + } + } + + impl $crate::serde::SerdeObject for $tower { + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { + debug_assert_eq!(bytes.len(), $field::SIZE * 2); + let [c0, c1] = [0, $field::SIZE] + .map(|i| $field::from_raw_bytes_unchecked(&bytes[i..i + $field::SIZE])); + Self { c0, c1 } + } + fn from_raw_bytes(bytes: &[u8]) -> Option { + if bytes.len() != $field::SIZE * 2 { + return None; + } + let [c0, c1] = + [0, $field::SIZE].map(|i| $field::from_raw_bytes(&bytes[i..i + $field::SIZE])); + c0.zip(c1).map(|(c0, c1)| Self { c0, c1 }) + } + fn to_raw_bytes(&self) -> Vec { + let mut res = Vec::with_capacity($field::SIZE * 2); + for limb in self.c0.0.iter().chain(self.c1.0.iter()) { + res.extend_from_slice(&limb.to_le_bytes()); + } + res + } + fn read_raw_unchecked(reader: &mut R) -> Self { + let [c0, c1] = [(); 2].map(|_| $field::read_raw_unchecked(reader)); + Self { c0, c1 } + } + fn read_raw(reader: &mut R) -> std::io::Result { + let c0 = $field::read_raw(reader)?; + let c1 = $field::read_raw(reader)?; + Ok(Self { c0, c1 }) + } + fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { + self.c0.write_raw(writer)?; + self.c1.write_raw(writer) + } + } + }; +} + +#[macro_export] +macro_rules! impl_tower6 { + ( + $field:ident, + $tower2:ident, + $tower6:ident + ) => { + #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] + #[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] + pub struct $tower6 { + pub c0: $tower2, + pub c1: $tower2, + pub c2: $tower2, + } + + impl ConditionallySelectable for $tower6 { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + $tower6 { + c0: $tower2::conditional_select(&a.c0, &b.c0, choice), + c1: $tower2::conditional_select(&a.c1, &b.c1, choice), + c2: $tower2::conditional_select(&a.c2, &b.c2, choice), + } + } + } + + impl ConstantTimeEq for $tower6 { + fn ct_eq(&self, other: &Self) -> Choice { + self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) & self.c2.ct_eq(&other.c2) + } + } + + impl $tower6 { + #[inline] + pub const fn zero() -> Self { + $tower6 { + c0: $tower2::ZERO, + c1: $tower2::ZERO, + c2: $tower2::ZERO, + } + } + + #[inline] + pub const fn one() -> Self { + $tower6 { + c0: $tower2::ONE, + c1: $tower2::ZERO, + c2: $tower2::ZERO, + } + } + + pub fn double(&self) -> Self { + Self { + c0: self.c0.double(), + c1: self.c1.double(), + c2: self.c2.double(), + } + } + + pub fn add(&self, other: &Self) -> Self { + Self { + c0: self.c0 + other.c0, + c1: self.c1 + other.c1, + c2: self.c2 + other.c2, + } + } + + pub fn sub(&self, other: &Self) -> Self { + Self { + c0: self.c0 - other.c0, + c1: self.c1 - other.c1, + c2: self.c2 - other.c2, + } + } + + pub fn neg(&self) -> Self { + Self { + c0: -self.c0, + c1: -self.c1, + c2: -self.c2, + } + } + } + + impl Field for $tower6 { + const ZERO: Self = Self::zero(); + const ONE: Self = Self::one(); + + fn random(mut rng: impl RngCore) -> Self { + $tower6 { + c0: $tower2::random(&mut rng), + c1: $tower2::random(&mut rng), + c2: $tower2::random(&mut rng), + } + } + + fn is_zero(&self) -> Choice { + self.c0.is_zero() & self.c1.is_zero() + } + + fn square(&self) -> Self { + self.square() + } + + fn double(&self) -> Self { + self.double() + } + + fn sqrt(&self) -> CtOption { + unimplemented!() + } + + fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { + unimplemented!() + } + + fn invert(&self) -> CtOption { + self.invert() + } + } + }; +} diff --git a/src/derive/mod.rs b/src/derive/mod.rs index 5e5015a1..0674a58c 100644 --- a/src/derive/mod.rs +++ b/src/derive/mod.rs @@ -3,6 +3,56 @@ pub mod curve; #[macro_use] pub mod field; +#[macro_export] +macro_rules! impl_add_binop_specify_impl { + ($field:ident) => { + 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) + } + } + }; +} + #[macro_export] macro_rules! impl_add_binop_specify_output { ($lhs:ident, $rhs:ident, $output:ident) => { @@ -168,14 +218,12 @@ macro_rules! impl_sum_prod { ($f:ident) => { impl> ::core::iter::Sum for $f { fn sum>(iter: I) -> Self { - use ::ff::Field; iter.fold(Self::ZERO, |acc, item| acc + item.borrow()) } } impl> ::core::iter::Product for $f { fn product>(iter: I) -> Self { - use ::ff::Field; iter.fold(Self::ONE, |acc, item| acc * item.borrow()) } } diff --git a/src/grumpkin/curve.rs b/src/grumpkin/curve.rs index dad570da..c493e285 100644 --- a/src/grumpkin/curve.rs +++ b/src/grumpkin/curve.rs @@ -9,7 +9,6 @@ use crate::group::Curve; use crate::group::{prime::PrimeCurveAffine, Group, GroupEncoding}; use crate::grumpkin::Fq; use crate::grumpkin::Fr; -use crate::hash_to_curve::svdw_hash_to_curve; use crate::{ endo, impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, @@ -36,7 +35,7 @@ new_curve_impl!( G1_A, G1_B, "grumpkin_g1", - |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z), + |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, G1::default_hash_to_curve_suite()), ); // Parameters in montgomery form taken from @@ -87,6 +86,14 @@ impl group::cofactor::CofactorGroup for G1 { impl G1 { const SVDW_Z: Fq = Fq::ONE; + + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite { + crate::hash_to_curve::Suite::::new( + b"grumpkin_g1_XMD:SHA-256_SVDW_RO_", + Self::SVDW_Z, + crate::hash_to_curve::Method::SVDW, + ) + } } #[cfg(test)] diff --git a/src/hash_to_curve.rs b/src/hash_to_curve.rs index b4d19b86..993001de 100644 --- a/src/hash_to_curve.rs +++ b/src/hash_to_curve.rs @@ -1,99 +1,211 @@ #![allow(clippy::op_ref)] +use crate::ff_ext::Legendre; +use digest::{core_api::BlockSizeUser, Digest}; use ff::{Field, FromUniformBytes, PrimeField}; use pasta_curves::arithmetic::CurveExt; -use static_assertions::const_assert; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -use crate::{ - ff_ext::Legendre, - secp256k1::{iso_map_secp256k1, IsoSecp256k1, Secp256k1}, -}; - -/// Hashes over a message and writes the output to all of `buf`. -/// Modified from https://github.com/zcash/pasta_curves/blob/7e3fc6a4919f6462a32b79dd226cb2587b7961eb/src/hashtocurve.rs#L11. -fn hash_to_field>( - method: &str, - curve_id: &str, - domain_prefix: &str, +pub enum Method { + SSWU, + SVDW, +} + +pub struct Suite { + domain: Vec, + map_to_curve: Box C>, + _marker: std::marker::PhantomData, +} + +pub(crate) fn expand_message( + domain_prefix: &[u8], + domain: &[u8], message: &[u8], - buf: &mut [F; 2], -) { - assert!(domain_prefix.len() < 256); - assert!((18 + method.len() + curve_id.len() + domain_prefix.len()) < 256); - - // Assume that the field size is 32 bytes and k is 256, where k is defined in - // . - const CHUNKLEN: usize = 64; - const_assert!(CHUNKLEN * 2 < 256); - - // Input block size of BLAKE2b. - const R_IN_BYTES: usize = 128; - - let personal = [0u8; 16]; - let empty_hasher = blake2b_simd::Params::new() - .hash_length(CHUNKLEN) - .personal(&personal) - .to_state(); - - let b_0 = empty_hasher - .clone() - .update(&[0; R_IN_BYTES]) - .update(message) - .update(&[0, (CHUNKLEN * 2) as u8, 0]) - .update(domain_prefix.as_bytes()) - .update(b"-") - .update(curve_id.as_bytes()) - .update(b"_XMD:BLAKE2b_") - .update(method.as_bytes()) - .update(b"_RO_") - .update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8]) - .finalize(); - - let b_1 = empty_hasher - .clone() - .update(b_0.as_array()) - .update(&[1]) - .update(domain_prefix.as_bytes()) - .update(b"-") - .update(curve_id.as_bytes()) - .update(b"_XMD:BLAKE2b_") - .update(method.as_bytes()) - .update(b"_RO_") - .update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8]) - .finalize(); - - let b_2 = { - let mut empty_hasher = empty_hasher; - for (l, r) in b_0.as_array().iter().zip(b_1.as_array().iter()) { - empty_hasher.update(&[*l ^ *r]); + out_len: usize, +) -> Vec { + assert!( + domain_prefix.len() + domain.len() < 256, + "long dst is not supported yet" + ); + assert!(out_len < 256, "larger output length is not supported yet"); + + let mut h = D::new(); + h.update(vec![0; D::block_size()]); + h.update(message); + h.update([0, out_len as u8, 0]); + h.update(domain_prefix); + h.update(domain); + h.update([(domain.len() + domain_prefix.len()) as u8]); + let b_0 = h.finalize(); + + let mut h = D::new(); + h.update(&b_0); + h.update([1]); + h.update(domain_prefix); + h.update(domain); + h.update([(domain.len() + domain_prefix.len()) as u8]); + let mut b_i = h.finalize(); + + let output_size = ::output_size(); + let ell = (out_len + output_size - 1) / output_size; + let mut out = vec![0u8; out_len]; + + for i in 1..ell { + let mut h = D::new(); + b_0.iter() + .zip(b_i.iter()) + .for_each(|(b_0, b_i)| h.update([*b_0 ^ *b_i])); + h.update([1 + i as u8]); + h.update(domain_prefix); + h.update(domain); + h.update([(domain.len() + domain_prefix.len()) as u8]); + + out.iter_mut() + .skip((i - 1) * output_size) + .zip(b_i.iter()) + .for_each(|(out, b_i)| *out = *b_i); + + b_i = h.finalize(); + } + + out.iter_mut() + .skip((ell - 1) * output_size) + .zip(b_i.iter()) + .for_each(|(out, b_i)| *out = *b_i); + + out +} + +#[allow(clippy::type_complexity)] +pub fn hash_to_curve<'a, C, D: Digest + BlockSizeUser + 'a, const L: usize>( + domain_prefix: &'a str, + suite: Suite, +) -> Box C + 'a> +where + C: CurveExt, + C::Base: Legendre, + C::Base: FromUniformBytes, +{ + Box::new(move |message| suite.hash_to_curve(domain_prefix, message)) +} + +impl Suite +where + C::Base: Legendre + FromUniformBytes, +{ + pub(crate) fn new(domain: &[u8], z: C::Base, method: Method) -> Self { + // check minimum target security + // L = ceil((ceil(log2(p)) + k) / 8) + assert!((C::Base::NUM_BITS as usize + 128) / 8 <= L); + + // let shifter = find_shifter(modulus, byte_size); + let map_to_curve: Box C> = match method { + Method::SSWU => Box::new(move |u| sswu_map_to_curve::(u, z)), + Method::SVDW => { + let [c1, c2, c3, c4] = svdw_precomputed_constants::(z); + Box::new(move |u| svdw_map_to_curve::(u, c1, c2, c3, c4, z)) + } + }; + + Self { + map_to_curve, + domain: domain.to_vec(), + _marker: std::marker::PhantomData, } - empty_hasher - .update(&[2]) - .update(domain_prefix.as_bytes()) - .update(b"-") - .update(curve_id.as_bytes()) - .update(b"_XMD:BLAKE2b_") - .update(method.as_bytes()) - .update(b"_RO_") - .update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8]) - .finalize() - }; + } + + pub(crate) fn hash_to_field(&self, domain_prefix: &[u8], message: &[u8]) -> (C::Base, C::Base) { + let out = expand_message::(domain_prefix, &self.domain[..], message, L * 2); + + let u0 = { + let mut out = out[0..L].to_vec(); + out.reverse(); + let out: [u8; L] = out.try_into().unwrap(); + C::Base::from_uniform_bytes(&out) + }; + + let u1 = { + let mut out = out[L..L * 2].to_vec(); + out.reverse(); + let out: [u8; L] = out.try_into().unwrap(); + C::Base::from_uniform_bytes(&out) + }; + + (u0, u1) + } - for (big, buf) in [b_1, b_2].iter().zip(buf.iter_mut()) { - let mut little = [0u8; CHUNKLEN]; - little.copy_from_slice(big.as_array()); - little.reverse(); - *buf = F::from_uniform_bytes(&little); + pub fn hash_to_curve(&self, domain_prefix: &str, message: &[u8]) -> C { + let (u0, u1) = self.hash_to_field(domain_prefix.as_bytes(), message); + (self.map_to_curve)(u0) + (self.map_to_curve)(u1) } } +pub(crate) fn svdw_precomputed_constants(z: C::Base) -> [C::Base; 4] { + let a = C::a(); + let b = C::b(); + let one = C::Base::ONE; + let three = one + one + one; + let four = three + one; + let tmp = three * z.square() + four * a; + + // 1. c1 = g(Z) + let c1 = (z.square() + a) * z + b; + // 2. c2 = -Z / 2 + let c2 = -z * C::Base::TWO_INV; + // 3. c3 = sqrt(-g(Z) * (3 * Z^2 + 4 * A)) # sgn0(c3) MUST equal 0 + let c3 = { + let c3 = (-c1 * tmp).sqrt().unwrap(); + C::Base::conditional_select(&c3, &-c3, c3.is_odd()) + }; + // 4. c4 = -4 * g(Z) / (3 * Z^2 + 4 * A) + let c4 = -four * c1 * tmp.invert().unwrap(); + + [c1, c2, c3, c4] +} + // Implementation of #[allow(clippy::too_many_arguments)] pub(crate) fn sswu_map_to_curve(u: C::Base, z: C::Base) -> C where C: CurveExt, { + // Implement https://datatracker.ietf.org/doc/html/rfc9380#name-sqrt_ratio-for-any-field + // Copied from ff sqrt_ratio_generic substituting F::ROOT_OF_UNITY for input Z + fn sqrt_ratio(num: &F, div: &F, z: &F) -> (Choice, F) { + // General implementation: + // + // a = num * inv0(div) + // = { 0 if div is zero + // { num/div otherwise + // + // b = z * a + // = { 0 if div is zero + // { z*num/div otherwise + + // Since z is non-square, a and b are either both zero (and both square), or + // only one of them is square. We can therefore choose the square root to return + // based on whether a is square, but for the boolean output we need to handle the + // num != 0 && div == 0 case specifically. + + let a = div.invert().unwrap_or(F::ZERO) * num; + let b = a * z; + let sqrt_a = a.sqrt(); + let sqrt_b = b.sqrt(); + + let num_is_zero = num.is_zero(); + let div_is_zero = div.is_zero(); + let is_square = sqrt_a.is_some(); + let is_nonsquare = sqrt_b.is_some(); + assert!(bool::from( + num_is_zero | div_is_zero | (is_square ^ is_nonsquare) + )); + + ( + is_square & (num_is_zero | !div_is_zero), + CtOption::conditional_select(&sqrt_b, &sqrt_a, is_square).unwrap(), + ) + } + let zero = C::Base::ZERO; let one = C::Base::ONE; let a = C::a(); @@ -154,45 +266,6 @@ where C::new_jacobian(x, y, one).unwrap() } -// Implementation of -#[allow(clippy::type_complexity)] -pub(crate) fn sswu_hash_to_curve<'a, C>( - curve_id: &'static str, - domain_prefix: &'a str, - z: C::Base, -) -> Box C + 'a> -where - C: CurveExt, - C::Base: FromUniformBytes<64>, -{ - Box::new(move |message| { - let mut us = [C::Base::ZERO; 2]; - hash_to_field("SSWU", curve_id, domain_prefix, message, &mut us); - - let [q0, q1]: [C; 2] = us.map(|u| sswu_map_to_curve::(u, z)); - - let r = q0 + &q1; - debug_assert!(bool::from(r.is_on_curve())); - r - }) -} - -// Implementation of -#[allow(clippy::type_complexity)] -pub(crate) fn sswu_hash_to_curve_secp256k1<'a>( - _curve_id: &'static str, - domain_prefix: &'a str, -) -> Box Secp256k1 + 'a> { - Box::new(move |message| { - let rp = IsoSecp256k1::hash_to_curve(domain_prefix)(message); - - let r = iso_map_secp256k1(rp); - - debug_assert!(bool::from(r.is_on_curve())); - r - }) -} - #[allow(clippy::too_many_arguments)] pub(crate) fn svdw_map_to_curve( u: C::Base, @@ -284,87 +357,136 @@ where C::new_jacobian(x, y, one).unwrap() } -// Implement https://datatracker.ietf.org/doc/html/rfc9380#name-sqrt_ratio-for-any-field -// Copied from ff sqrt_ratio_generic substituting F::ROOT_OF_UNITY for input Z -fn sqrt_ratio(num: &F, div: &F, z: &F) -> (Choice, F) { - // General implementation: - // - // a = num * inv0(div) - // = { 0 if div is zero - // { num/div otherwise - // - // b = z * a - // = { 0 if div is zero - // { z*num/div otherwise - - // Since z is non-square, a and b are either both zero (and both square), or - // only one of them is square. We can therefore choose the square root to return - // based on whether a is square, but for the boolean output we need to handle the - // num != 0 && div == 0 case specifically. - - let a = div.invert().unwrap_or(F::ZERO) * num; - let b = a * z; - let sqrt_a = a.sqrt(); - let sqrt_b = b.sqrt(); - - let num_is_zero = num.is_zero(); - let div_is_zero = div.is_zero(); - let is_square = sqrt_a.is_some(); - let is_nonsquare = sqrt_b.is_some(); - assert!(bool::from( - num_is_zero | div_is_zero | (is_square ^ is_nonsquare) - )); - - ( - is_square & (num_is_zero | !div_is_zero), - CtOption::conditional_select(&sqrt_b, &sqrt_a, is_square).unwrap(), - ) -} - -/// Implementation of https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#section-6.6.1 -#[allow(clippy::type_complexity)] -pub(crate) fn svdw_hash_to_curve<'a, C>( - curve_id: &'static str, - domain_prefix: &'a str, - z: C::Base, -) -> Box C + 'a> -where - C: CurveExt, - C::Base: FromUniformBytes<64> + Legendre, -{ - let [c1, c2, c3, c4] = svdw_precomputed_constants::(z); - - Box::new(move |message| { - let mut us = [C::Base::ZERO; 2]; - hash_to_field("SVDW", curve_id, domain_prefix, message, &mut us); +#[cfg(test)] +mod test { - let [q0, q1]: [C; 2] = us.map(|u| svdw_map_to_curve(u, c1, c2, c3, c4, z)); + use super::*; + use sha2::Sha256; + use sha2::Sha512; + use std::marker::PhantomData; - let r = q0 + &q1; - debug_assert!(bool::from(r.is_on_curve())); - r - }) -} + #[test] + fn test_expand_message() { + // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#name-expand_message_xmdsha-256-2 -pub(crate) fn svdw_precomputed_constants(z: C::Base) -> [C::Base; 4] { - let a = C::a(); - let b = C::b(); - let one = C::Base::ONE; - let three = one + one + one; - let four = three + one; - let tmp = three * z.square() + four * a; - - // 1. c1 = g(Z) - let c1 = (z.square() + a) * z + b; - // 2. c2 = -Z / 2 - let c2 = -z * C::Base::TWO_INV; - // 3. c3 = sqrt(-g(Z) * (3 * Z^2 + 4 * A)) # sgn0(c3) MUST equal 0 - let c3 = { - let c3 = (-c1 * tmp).sqrt().unwrap(); - C::Base::conditional_select(&c3, &-c3, c3.is_odd()) - }; - // 4. c4 = -4 * g(Z) / (3 * Z^2 + 4 * A) - let c4 = -four * c1 * tmp.invert().unwrap(); + struct Test { + msg: &'static [u8], + expect: Vec, + _marker: PhantomData, + } - [c1, c2, c3, c4] + impl Test { + fn new(msg: &'static [u8], expect: &str) -> Self { + Self { + msg, + expect: crate::tests::hex_to_bytes(expect), + _marker: PhantomData, + } + } + + fn run(&self, domain_prefix: &[u8], domain: &[u8]) { + let outlen = self.expect.len(); + let out = expand_message::(domain_prefix, domain, self.msg, outlen); + assert_eq!(out, self.expect); + } + } + [ + // out len 0x20 + Test::::new( + b"", + "68a985b87eb6b46952128911f2a4412bbc302a9d759667f87f7a21d803f07235", + ), + Test::::new( + b"abc", + "d8ccab23b5985ccea865c6c97b6e5b8350e794e603b4b97902f53a8a0d605615", + ), + Test::::new( + b"abcdef0123456789", + "eff31487c770a893cfb36f912fbfcbff40d5661771ca4b2cb4eafe524333f5c1", + ), + Test::::new( + b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + "b23a1d2b4d97b2ef7785562a7e8bac7eed54ed6e97e29aa51bfe3f12ddad1ff9", + ), + Test::::new( + b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "4623227bcc01293b8c130bf771da8c298dede7383243dc0993d2d94823958c4c", + ), + // out len 0x80 + Test::::new( + b"", + "af84c27ccfd45d41914fdff5df25293e221afc53d8ad2ac06d5e3e29485dadbee0d121587713a3e0dd4d5e69e93eb7cd4f5df4cd103e188cf60cb02edc3edf18eda8576c412b18ffb658e3dd6ec849469b979d444cf7b26911a08e63cf31f9dcc541708d3491184472c2c29bb749d4286b004ceb5ee6b9a7fa5b646c993f0ced", + ), + Test::::new( + b"abc", + "abba86a6129e366fc877aab32fc4ffc70120d8996c88aee2fe4b32d6c7b6437a647e6c3163d40b76a73cf6a5674ef1d890f95b664ee0afa5359a5c4e07985635bbecbac65d747d3d2da7ec2b8221b17b0ca9dc8a1ac1c07ea6a1e60583e2cb00058e77b7b72a298425cd1b941ad4ec65e8afc50303a22c0f99b0509b4c895f40", + ), + Test::::new( + b"abcdef0123456789", + "ef904a29bffc4cf9ee82832451c946ac3c8f8058ae97d8d629831a74c6572bd9ebd0df635cd1f208e2038e760c4994984ce73f0d55ea9f22af83ba4734569d4bc95e18350f740c07eef653cbb9f87910d833751825f0ebefa1abe5420bb52be14cf489b37fe1a72f7de2d10be453b2c9d9eb20c7e3f6edc5a60629178d9478df", + ), + Test::::new( + b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + "80be107d0884f0d881bb460322f0443d38bd222db8bd0b0a5312a6fedb49c1bbd88fd75d8b9a09486c60123dfa1d73c1cc3169761b17476d3c6b7cbbd727acd0e2c942f4dd96ae3da5de368d26b32286e32de7e5a8cb2949f866a0b80c58116b29fa7fabb3ea7d520ee603e0c25bcaf0b9a5e92ec6a1fe4e0391d1cdbce8c68a", + ), + Test::::new( + b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "546aff5444b5b79aa6148bd81728704c32decb73a3ba76e9e75885cad9def1d06d6792f8a7d12794e90efed817d96920d728896a4510864370c207f99bd4a608ea121700ef01ed879745ee3e4ceef777eda6d9e5e38b90c86ea6fb0b36504ba4a45d22e86f6db5dd43d98a294bebb9125d5b794e9d2a81181066eb954966a487", + ), + + ] + .iter() + .for_each(|test| { + test.run(b"QUUX-V01-CS02-with-expander-",b"SHA256-128"); + }); + + [ + // out len 0x20 + Test::::new( + b"", + "6b9a7312411d92f921c6f68ca0b6380730a1a4d982c507211a90964c394179ba", + ), + Test::::new( + b"abc", + "0da749f12fbe5483eb066a5f595055679b976e93abe9be6f0f6318bce7aca8dc", + ), + Test::::new( + b"abcdef0123456789", + "087e45a86e2939ee8b91100af1583c4938e0f5fc6c9db4b107b83346bc967f58", + ), + Test::::new( + b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + "7336234ee9983902440f6bc35b348352013becd88938d2afec44311caf8356b3", + ), + Test::::new( + b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "57b5f7e766d5be68a6bfe1768e3c2b7f1228b3e4b3134956dd73a59b954c66f4", + ), + // out len 0x80 + Test::::new( + b"", + "41b037d1734a5f8df225dd8c7de38f851efdb45c372887be655212d07251b921b052b62eaed99b46f72f2ef4cc96bfaf254ebbbec091e1a3b9e4fb5e5b619d2e0c5414800a1d882b62bb5cd1778f098b8eb6cb399d5d9d18f5d5842cf5d13d7eb00a7cff859b605da678b318bd0e65ebff70bec88c753b159a805d2c89c55961", + ), + Test::::new( + b"abc", + "7f1dddd13c08b543f2e2037b14cefb255b44c83cc397c1786d975653e36a6b11bdd7732d8b38adb4a0edc26a0cef4bb45217135456e58fbca1703cd6032cb1347ee720b87972d63fbf232587043ed2901bce7f22610c0419751c065922b488431851041310ad659e4b23520e1772ab29dcdeb2002222a363f0c2b1c972b3efe1", + ), + Test::::new( + b"abcdef0123456789", + "3f721f208e6199fe903545abc26c837ce59ac6fa45733f1baaf0222f8b7acb0424814fcb5eecf6c1d38f06e9d0a6ccfbf85ae612ab8735dfdf9ce84c372a77c8f9e1c1e952c3a61b7567dd0693016af51d2745822663d0c2367e3f4f0bed827feecc2aaf98c949b5ed0d35c3f1023d64ad1407924288d366ea159f46287e61ac", + ), + Test::::new( + b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + "b799b045a58c8d2b4334cf54b78260b45eec544f9f2fb5bd12fb603eaee70db7317bf807c406e26373922b7b8920fa29142703dd52bdf280084fb7ef69da78afdf80b3586395b433dc66cde048a258e476a561e9deba7060af40adf30c64249ca7ddea79806ee5beb9a1422949471d267b21bc88e688e4014087a0b592b695ed", + ), + Test::::new( + b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "05b0bfef265dcee87654372777b7c44177e2ae4c13a27f103340d9cd11c86cb2426ffcad5bd964080c2aee97f03be1ca18e30a1f14e27bc11ebbd650f305269cc9fb1db08bf90bfc79b42a952b46daf810359e7bc36452684784a64952c343c52e5124cd1f71d474d5197fefc571a92929c9084ffe1112cf5eea5192ebff330b", + ), + ] + .iter() + .for_each(|test| { + test.run(b"QUUX-V01-CS02-with-expander-", b"SHA512-256"); + }); + } } diff --git a/src/pluto_eris/curve.rs b/src/pluto_eris/curve.rs index 7cd68205..bc4cdc8b 100644 --- a/src/pluto_eris/curve.rs +++ b/src/pluto_eris/curve.rs @@ -1,9 +1,8 @@ -use super::fields::{fp::Fp, fp2::Fp2, fq::Fq}; +use super::{fp::Fp, fp2::Fp2, fq::Fq}; use crate::derive::curve::{IDENTITY_MASK, IDENTITY_SHIFT, SIGN_MASK, SIGN_SHIFT}; use crate::ff::WithSmallOrderMulGroup; use crate::ff::{Field, PrimeField}; use crate::group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding}; -use crate::hash_to_curve::svdw_hash_to_curve; use crate::{Coordinates, CurveAffine, CurveExt}; use core::cmp; use core::fmt::Debug; @@ -131,7 +130,7 @@ new_curve_impl!( PLUTO_A, PLUTO_B, "pluto", - |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z), + |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, G1::default_hash_to_curve_suite()), ); impl group::cofactor::CofactorGroup for Eris { @@ -154,6 +153,14 @@ impl G1 { /// Constant Z for the Shallue-van de Woestijne map. /// Computed using https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#svdw-z-code const SVDW_Z: Fp = Fp::ONE; + + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite { + crate::hash_to_curve::Suite::::new( + b"pluto_XMD:SHA-256_SVDW_RO_", + Self::SVDW_Z, + crate::hash_to_curve::Method::SVDW, + ) + } } new_curve_impl!( @@ -166,7 +173,7 @@ new_curve_impl!( ERIS_A, ERIS_B, "eris", - |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, Eris::SVDW_Z), + |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, Eris::default_hash_to_curve_suite()), ); impl CofactorGroup for G2 { @@ -225,6 +232,14 @@ impl Eris { /// Constant Z for the Shallue-van de Woestijne map. /// Computed using https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#svdw-z-code const SVDW_Z: Fq = Fq::ONE; + + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite { + crate::hash_to_curve::Suite::::new( + b"eris_XMD:SHA-256_SVDW_RO_", + Self::SVDW_Z, + crate::hash_to_curve::Method::SVDW, + ) + } } new_curve_impl!( @@ -237,7 +252,7 @@ new_curve_impl!( TRITON_A, TRITON_B, "triton", - |_, _| unimplemented!(), + |_| unimplemented!(), ); #[cfg(test)] diff --git a/src/pluto_eris/engine.rs b/src/pluto_eris/engine.rs index 3b47f878..2d16391d 100644 --- a/src/pluto_eris/engine.rs +++ b/src/pluto_eris/engine.rs @@ -4,11 +4,11 @@ use crate::group::cofactor::CofactorCurveAffine; use crate::group::Group; use crate::pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; use crate::pluto_eris::curve::*; -use crate::pluto_eris::fields::fp::*; -use crate::pluto_eris::fields::fp12::*; -use crate::pluto_eris::fields::fp2::*; -use crate::pluto_eris::fields::fp6::FROBENIUS_COEFF_FP6_C1; -use crate::pluto_eris::fields::fq::*; +use crate::pluto_eris::fp::*; +use crate::pluto_eris::fp12::*; +use crate::pluto_eris::fp2::*; +use crate::pluto_eris::fp6::FROBENIUS_COEFF_FP6_C1; +use crate::pluto_eris::fq::*; use core::borrow::Borrow; use core::iter::Sum; use core::ops::{Add, Mul, MulAssign, Neg, Sub}; @@ -251,10 +251,10 @@ impl G2Prepared { tmp3.square_assign(); tmp3 -= &tmp0; tmp3 -= &tmp2; - tmp3.double_assign(); + tmp3 = tmp3.double(); let mut tmp4 = tmp0; - tmp4.double_assign(); + tmp4 = tmp4.double(); tmp4 += &tmp0; let mut tmp6 = r.x; @@ -279,9 +279,9 @@ impl G2Prepared { r.y -= &r.x; r.y.mul_assign(&tmp4); - tmp2.double_assign(); - tmp2.double_assign(); - tmp2.double_assign(); + tmp2 = tmp2.double(); + tmp2 = tmp2.double(); + tmp2 = tmp2.double(); r.y -= &tmp2; @@ -291,7 +291,7 @@ impl G2Prepared { // tmp3 is the first part of line 12 tmp3 = tmp4; tmp3.mul_assign(&zsquared); - tmp3.double_assign(); + tmp3 = tmp3.double(); tmp3 = tmp3.neg(); // tmp6 is from line 14 @@ -299,15 +299,15 @@ impl G2Prepared { tmp6 -= &tmp0; tmp6 -= &tmp5; - tmp1.double_assign(); - tmp1.double_assign(); + tmp1 = tmp1.double(); + tmp1 = tmp1.double(); tmp6 -= &tmp1; // tmp0 is the first part of line 16 tmp0 = r.z; tmp0.mul_assign(&zsquared); - tmp0.double_assign(); + tmp0 = tmp0.double(); (tmp0, tmp3, tmp6) } @@ -342,8 +342,8 @@ impl G2Prepared { // t4 corresponds to line 6 let mut t4 = t3; - t4.double_assign(); - t4.double_assign(); + t4 = t4.double(); + t4 = t4.double(); // t5 corresponds to line 7 let mut t5 = t4; @@ -387,7 +387,7 @@ impl G2Prepared { // corresponds to line 15 t0 = r.y; t0.mul_assign(&t5); - t0.double_assign(); + t0 = t0.double(); // corresponds to line 12, but assigns to r.y instead of T.y r.y = t8; @@ -403,18 +403,18 @@ impl G2Prepared { t10 -= &ztsquared; // corresponds to line 18 - t9.double_assign(); + t9 = t9.double(); t9 -= &t10; // t10 = 2*Zt from Algo 27, line 19 t10 = r.z; - t10.double_assign(); + t10 = t10.double(); // t1 = first multiplicator of line 21 t6 = t6.neg(); t1 = t6; - t1.double_assign(); + t1 = t1.double(); // t9 corresponds to t9 from Algo 27 (t10, t1, t9) diff --git a/src/pluto_eris/fields/fp.rs b/src/pluto_eris/fields/fp.rs deleted file mode 100644 index a7ff3588..00000000 --- a/src/pluto_eris/fields/fp.rs +++ /dev/null @@ -1,510 +0,0 @@ -use crate::arithmetic::{adc, mac, sbb}; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - extend_field_legendre, field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, - impl_from_u64_7_limbs, -}; -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use std::slice::Iter; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - -#[cfg(feature = "derive_serde")] -use serde::{Deserialize, Serialize}; - -/// This represents an element of $\mathbb{F}_p$ where -/// -/// `p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001` -/// -/// is the base field of the Pluto curve. -/// The internal representation of this type is seven 64-bit unsigned -/// integers in little-endian order which account for the 446 bits required to be represented. -/// `Fp` values are always in Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^448. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fp(pub(crate) [u64; 7]); - -/// Size of `Fp` element in bytes -const SIZE: usize = 56; - -/// Constant representing the modulus -/// p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001 -const MODULUS: Fp = Fp([ - 0x9ffffcd300000001, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 14] = [ - 0x00000001, 0x9ffffcd3, 0x0006b945, 0xa2a7e8c3, 0x8fadffd6, 0xe4a7a5fe, 0xda8a6c7b, 0x443f9a5c, - 0xf439266f, 0xa803ca76, 0x0d7f70e4, 0x0130e000, 0x00002400, 0x24000000, -]; - -// pub const NEGATIVE_ONE: Fp = Fp([]); - -pub(crate) const MODULUS_STR: &str = "0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001"; - -/// INV = -r^{-1} mod 2^64 -/// `0x9ffffcd2ffffffff` -const INV: u64 = 0x9ffffcd2ffffffff; - -/// Let M be the power of `2^64` nearest to `Self::MODULUS_BITS`. Then `R = M % Self::MODULUS`. -/// `R = 2^448 mod p` -/// `0x3ffffffffff03fff7a9dfffa183e9bf67e576bf526ff2f52242c7760637089cbf6a760a123e01218d68a2aaffd0ef18a000163afffffff9` -const R: Fp = Fp([ - 0xa000163afffffff9, - 0x8d68a2aaffd0ef18, - 0xbf6a760a123e0121, - 0x2242c7760637089c, - 0x67e576bf526ff2f5, - 0xf7a9dfffa183e9bf, - 0x03ffffffffff03ff, -]); - -/// `R^2 = 2^896 mod p` -/// `0x1a4b16581f66e3cc8bcb0f20758aec8520b6db3d7481a84c734fd363b575c23e7a42067a8ccd154b4b20c07277ae01f1d9702c6d54dc0598` -const R2: Fp = Fp([ - 0xd9702c6d54dc0598, - 0x4b20c07277ae01f1, - 0x7a42067a8ccd154b, - 0x734fd363b575c23e, - 0x20b6db3d7481a84c, - 0x8bcb0f20758aec85, - 0x1a4b16581f66e3cc, -]); - -/// `R^3 = 2^1792 mod p` -/// `0x1f51e40a048ddc1789010189f4df0ae1f3bc57efac4b3280b25aa8b46a40b225e5446680e4c4ea0449937d6b40e58f05c67afa3fe916dd69` -const R3: Fp = Fp([ - 0xc67afa3fe916dd69, - 0x49937d6b40e58f05, - 0xe5446680e4c4ea04, - 0xb25aa8b46a40b225, - 0xf3bc57efac4b3280, - 0x89010189f4df0ae1, - 0x1f51e40a048ddc17, -]); - -/// `GENERATOR = 10 mod p` is a generator of the `p - 1` order multiplicative -/// subgroup, or in other words a primitive root of the field. -const GENERATOR: Fp = Fp::from_raw([0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - -/// Size of the 2-adic sub-group of the field. -const S: u32 = 32; - -/// GENERATOR^t where t * 2^s + 1 = p -/// with t odd. In other words, this -/// is a 2^s root of unity. -/// `0x2d39f8c5f9adb3f35fe3f4222db17451ddd9602a013af5276bdbe3903ec85fc889232f5c8bc6857060c75e6f399661d6c7b82d31d563091` -const ROOT_OF_UNITY: Fp = Fp::from_raw([ - 0x6c7b82d31d563091, - 0x060c75e6f399661d, - 0x889232f5c8bc6857, - 0x76bdbe3903ec85fc, - 0x1ddd9602a013af52, - 0x35fe3f4222db1745, - 0x02d39f8c5f9adb3f, -]); - -/// 1 / ROOT_OF_UNITY mod p -/// `0x17725d635b00cda4153eb10c7105919d012822bd86c08691803272fbc5c9f8378055eb56ae2d55f9272bf208aad57f666deaead2c693ff66` -const ROOT_OF_UNITY_INV: Fp = Fp::from_raw([ - 0x6deaead2c693ff66, - 0x272bf208aad57f66, - 0x8055eb56ae2d55f9, - 0x803272fbc5c9f837, - 0x012822bd86c08691, - 0x153eb10c7105919d, - 0x17725d635b00cda4, -]); - -/// 1 / 2 mod p -/// `0x12000000000012000098700006bfb8725401e53b7a1c9337a21fcd2e6d45363df253d2ff47d6ffeb5153f46180035ca2cffffe6980000001` -pub(crate) const TWO_INV: Fp = Fp::from_raw([ - 0xcffffe6980000001, - 0x5153f46180035ca2, - 0xf253d2ff47d6ffeb, - 0xa21fcd2e6d45363d, - 0x5401e53b7a1c9337, - 0x0098700006bfb872, - 0x1200000000001200, -]); -/// GENERATOR^{2^s} where t * 2^s + 1 = r with t odd. In other words, this is a t root of unity. -/// `0xeacefc6504d028d42ed23fc8766d5a5f195b456887e1e0021fb760c53233e9170c23749b459b95cc6cbb5faf3754a1e1916b2007775db04` -const DELTA: Fp = Fp::from_raw([ - 0x1916b2007775db04, - 0xc6cbb5faf3754a1e, - 0x70c23749b459b95c, - 0x21fb760c53233e91, - 0xf195b456887e1e00, - 0x42ed23fc8766d5a5, - 0x0eacefc6504d028d, -]); - -/// `ZETA^3 = 1 mod p` where `ZETA^2 != 1 mod p` -/// `0x480000000000360001c950000d7ee0e4a803c956d01c903d720dc8ad8b38dffaf50c100004c37ffffffe` -const ZETA: Fp = Fp::from_raw([ - 0x100004c37ffffffe, - 0xc8ad8b38dffaf50c, - 0xc956d01c903d720d, - 0x50000d7ee0e4a803, - 0x00000000360001c9, - 0x0000000000004800, - 0x0000000000000000, -]); - -/// NEG_ONE ; -1 mod p -pub(crate) const NEG_ONE: Fp = Fp::from_raw([ - 0x9ffffcd300000000, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -impl_binops_additive!(Fp, Fp); -impl_binops_multiplicative!(Fp, Fp); -field_common_7_limbs!( - Fp, - FpRepr, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_sum_prod!(Fp); -impl_from_u64_7_limbs!(Fp, R2); -field_arithmetic_7_limbs!(Fp, MODULUS, INV, sparse); - -#[cfg(target_pointer_width = "64")] -field_bits_7_limbs!(Fp, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits_7_limbs!(Fp, MODULUS, MODULUS_LIMBS_32); - -extend_field_legendre!(Fp); - -impl Fp { - pub const fn size() -> usize { - SIZE - } -} - -impl ff::Field for Fp { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Computes the multiplicative inverse of this element, - /// failing if the element is zero. - fn invert(&self) -> CtOption { - // self^(p - 2) - let tmp = self.pow([ - 0x9ffffcd2ffffffff, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ]); - - CtOption::new(tmp, !self.ct_eq(&Self::zero())) - } - - fn sqrt(&self) -> CtOption { - /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd. - const T_MINUS1_OVER2: [u64; 7] = [ - 0x80035ca2cffffe69, - 0x47d6ffeb5153f461, - 0x6d45363df253d2ff, - 0x7a1c9337a21fcd2e, - 0x06bfb8725401e53b, - 0x0000120000987000, - 0x0000000012000000, - ]; - ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -#[derive(Clone, Copy, Debug)] -/// Canonical little-endian representation of a `Fp` element. -pub struct FpRepr { - pub repr: [u8; SIZE], -} - -impl FpRepr { - /// Returns an iterator over the bytes of the canonical representation of the element. - pub fn iter(&self) -> Iter<'_, u8> { - self.repr.iter() - } -} - -impl Default for FpRepr { - fn default() -> Self { - FpRepr { repr: [0u8; SIZE] } - } -} - -impl AsRef<[u8]> for FpRepr { - fn as_ref(&self) -> &[u8] { - self.repr.as_ref() - } -} - -impl AsMut<[u8]> for FpRepr { - fn as_mut(&mut self) -> &mut [u8] { - self.repr.as_mut() - } -} -impl From<[u8; SIZE]> for FpRepr { - fn from(repr: [u8; SIZE]) -> Self { - Self { repr } - } -} - -impl ff::PrimeField for Fp { - type Repr = FpRepr; - - const NUM_BITS: u32 = 446; - const CAPACITY: u32 = 445; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Self([0, 0, 0, 0, 0, 0, 0]); - let repr = repr.repr; - - 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()); - tmp.0[4] = u64::from_le_bytes(repr[32..40].try_into().unwrap()); - tmp.0[5] = u64::from_le_bytes(repr[40..48].try_into().unwrap()); - tmp.0[6] = u64::from_le_bytes(repr[48..56].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); - let (_, borrow) = sbb(tmp.0[4], MODULUS.0[4], borrow); - let (_, borrow) = sbb(tmp.0[5], MODULUS.0[5], borrow); - let (_, borrow) = sbb(tmp.0[6], MODULUS.0[6], 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 = Self::montgomery_reduce(&[ - self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], 0, 0, 0, - 0, 0, 0, 0, - ]); - - let mut res = [0; SIZE]; - 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[32..40].copy_from_slice(&tmp.0[4].to_le_bytes()); - res[40..48].copy_from_slice(&tmp.0[5].to_le_bytes()); - res[48..56].copy_from_slice(&tmp.0[6].to_le_bytes()); - res.into() - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr().repr[0] & 1) - } -} - -impl FromUniformBytes<64> for Fp { - /// Converts a 512-bit little endian integer into - /// an `Fp` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - 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()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fp { - const ZETA: Self = ZETA; -} - -#[cfg(test)] -mod test { - use super::*; - crate::field_testing_suite!(Fp, "field_arithmetic"); - crate::field_testing_suite!(Fp, "conversion"); - crate::field_testing_suite!(Fp, "serialization"); - crate::field_testing_suite!(Fp, "quadratic_residue"); - crate::field_testing_suite!(Fp, "bits"); - crate::field_testing_suite!(Fp, "serialization_check"); - crate::field_testing_suite!(Fp, "constants", MODULUS_STR); - crate::field_testing_suite!(Fp, "sqrt"); - crate::field_testing_suite!(Fp, "zeta"); - crate::field_testing_suite!( - Fp, - "from_uniform_bytes", - [ - Fp::from_raw([ - 0x93638251ffeffed3, - 0x4d32f4d20020be11, - 0x9c39ee168df390f0, - 0xaeef355d313cce4b, - 0xc97c592ef6030675, - 0xd7bc83d286537318, - 0x01d4a87b24f91154, - ]), - Fp::from_raw([ - 0x63e0a8f1beefc612, - 0xbb28d56dae950a42, - 0x5264111f4a5ea3ad, - 0xbebe71c829f662f7, - 0xa760708568d6060c, - 0x617d8b0cda3f6328, - 0x03096ea964e009c0, - ]), - Fp::from_raw([ - 0xdeaedbda63b3e431, - 0x65892bc45ec174c8, - 0x83ad8d96c18556c7, - 0x3fce5f9d2c537fbe, - 0x001666753a4972d1, - 0x9f7f457a48d6d322, - 0x20b2fadc6bf4004d, - ]), - Fp::from_raw([ - 0x6eea9cbd68b174cf, - 0x63aa4abda18f73e6, - 0x0a6ccc999b1c7864, - 0x0f90b43928625cc2, - 0x55f541b0680af76b, - 0x2045de539849b035, - 0x1d5d7b5f6e8cc333, - ]), - Fp::from_raw([ - 0x673df0f69b71a763, - 0x215a1362cfe53e1e, - 0x7028d2b3766b0f40, - 0x996ac521f57a7f05, - 0x5006663a5c8cea53, - 0xd7ead2b7c71e460d, - 0x0f7c36b781cba9ed, - ]), - Fp::from_raw([ - 0x2eed10e8f00b189d, - 0xe6c79fb4600e94d4, - 0x2a9066b23daac6d4, - 0x476d275780b553fe, - 0xc3f2296317f71051, - 0xb1d2bb5373270c43, - 0x0e18a3597be61302, - ]), - Fp::from_raw([ - 0x7fbbc6b3e494ca68, - 0x2afcc7335152430b, - 0x93d5bd3acbccf3b3, - 0x61a76bb383622b8c, - 0x93efc4d40d7fac4d, - 0x0a791ad7698655a7, - 0x22b10d5c1090eec8, - ]), - Fp::from_raw([ - 0x596eec60211ad67b, - 0xf23f57b9f9db8c07, - 0x33e66f105ffc5e45, - 0xb10ef45226f3ae42, - 0xb98a559ccfc0ba32, - 0x819ba919d0b6e9b5, - 0x20f73876330a90e8, - ]), - Fp::from_raw([ - 0xbade57a48e2d9868, - 0xe61829ffe983fcfc, - 0xd0d080b774c31996, - 0xa1d712ef206b4a2f, - 0x7957f20173071cf6, - 0xf850f49359458652, - 0x17ba9f9aa08b9ee2, - ]), - Fp::from_raw([ - 0xd0239c8282ccc372, - 0xfa20a695ee8f6288, - 0x269f2ef315e029a5, - 0xcc915da35e10b4e6, - 0x8406f6977aadce0f, - 0xd7d5d8bc4497465a, - 0x08ce8bee1323d4f9, - ]), - ] - ); -} diff --git a/src/pluto_eris/fields/fp2.rs b/src/pluto_eris/fields/fp2.rs deleted file mode 100644 index 9bb68782..00000000 --- a/src/pluto_eris/fields/fp2.rs +++ /dev/null @@ -1,649 +0,0 @@ -use super::fp::{Fp, MODULUS_STR}; -use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::ff_ext::Legendre; -use core::convert::TryInto; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use std::cmp::Ordering; -use std::ops::MulAssign; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - -#[cfg(feature = "derive_serde")] -use serde::{Deserialize, Serialize}; - -/// -ALPHA is a quadratic non-residue in Fp. Fp2 = Fp[X]/(X^2 + ALPHA) -/// We introduce the variable u such that u^2 = -ALPHA - -/// U_SQUARE = -5 -/// 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd2fffffffc -const U_SQUARE: Fp = Fp::from_raw([ - 0x9ffffcd2fffffffc, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -const NEG_ONE: Fp2 = Fp2 { - c0: super::fp::NEG_ONE, - c1: Fp::ZERO, -}; - -/// An element of Fp2, represented by c0 + c1 * u. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fp2 { - pub c0: Fp, - pub c1: Fp, -} - -/// `Fp2` elements are ordered lexicographically. -impl Ord for Fp2 { - #[inline(always)] - fn cmp(&self, other: &Fp2) -> Ordering { - match self.c1.cmp(&other.c1) { - Ordering::Greater => Ordering::Greater, - Ordering::Less => Ordering::Less, - Ordering::Equal => self.c0.cmp(&other.c0), - } - } -} - -impl PartialOrd for Fp2 { - #[inline(always)] - fn partial_cmp(&self, other: &Fp2) -> Option { - Some(self.cmp(other)) - } -} - -impl ConditionallySelectable for Fp2 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fp2 { - c0: Fp::conditional_select(&a.c0, &b.c0, choice), - c1: Fp::conditional_select(&a.c1, &b.c1, choice), - } - } -} - -impl ConstantTimeEq for Fp2 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) - } -} - -impl Default for Fp2 { - #[inline] - fn default() -> Self { - Self::ZERO - } -} - -impl From for [u8; 112] { - fn from(value: Fp2) -> [u8; 112] { - value.to_bytes() - } -} - -impl<'a> From<&'a Fp2> for [u8; 112] { - fn from(value: &'a Fp2) -> [u8; 112] { - value.to_bytes() - } -} - -impl Neg for Fp2 { - type Output = Fp2; - - #[inline] - fn neg(self) -> Fp2 { - -&self - } -} - -impl<'a> Neg for &'a Fp2 { - type Output = Fp2; - - #[inline] - fn neg(self) -> Fp2 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fp2> for &'a Fp2 { - type Output = Fp2; - - #[inline] - fn sub(self, rhs: &'b Fp2) -> Fp2 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fp2> for &'a Fp2 { - type Output = Fp2; - - #[inline] - fn add(self, rhs: &'b Fp2) -> Fp2 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fp2> for &'a Fp2 { - type Output = Fp2; - - #[inline] - fn mul(self, rhs: &'b Fp2) -> Fp2 { - self.mul(rhs) - } -} - -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -impl_binops_additive!(Fp2, Fp2); -impl_binops_multiplicative!(Fp2, Fp2); -impl_sum_prod!(Fp2); - -/// Size in bytes of a `Fp2` element. -const SIZE: usize = 112; -/// Size in bytes of a each coefficient of `Fp2`. -const COEF_SIZE: usize = 56; - -impl Fp2 { - /// Returns the zero element. - #[inline] - pub const fn zero() -> Fp2 { - Fp2 { - c0: Fp::zero(), - c1: Fp::zero(), - } - } - - /// Returns the unit. - #[inline] - pub const fn one() -> Fp2 { - Fp2 { - c0: Fp::one(), - c1: Fp::zero(), - } - } - - /// Given its `Fp` coefficients c0, c1. Returns the element of `Fp2`: c0 + c1 * u. - pub const fn new(c0: Fp, c1: Fp) -> Self { - Fp2 { c0, c1 } - } - - /// Returns the size in bytes of a `Fp2` element. - pub const fn size() -> usize { - SIZE - } - - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fp`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; SIZE]) -> CtOption { - let c0 = Fp::from_bytes(bytes[0..COEF_SIZE].try_into().unwrap()); - let c1 = Fp::from_bytes(bytes[COEF_SIZE..SIZE].try_into().unwrap()); - CtOption::new( - Fp2 { - c0: c0.unwrap(), - c1: c1.unwrap(), - }, - c0.is_some() & c1.is_some(), - ) - } - - /// Converts an element of `Fp` into a byte representation in - /// little-endian byte order. - pub fn to_bytes(self) -> [u8; SIZE] { - let mut res = [0u8; SIZE]; - let c0_bytes = self.c0.to_bytes(); - let c1_bytes = self.c1.to_bytes(); - res[0..COEF_SIZE].copy_from_slice(&c0_bytes[..]); - res[COEF_SIZE..SIZE].copy_from_slice(&c1_bytes[..]); - res - } - - // TODO: This is a naive method using 4 multiplications - pub fn mul_assign(&mut self, other: &Self) { - // r0 = s0 * s0 + U_SQUARE * s1 * o1 - // r1 = s0 * o1 - s1 * o0 - - let t0 = self.c0 * other.c0; - let t1 = self.c0 * other.c1; - let t2 = self.c1 * other.c0; - let t3 = self.c1 * other.c1; - - self.c0 = t0 + U_SQUARE * t3; - self.c1 = t1 + t2 - } - - // TODO: This is a naive method using 3 multiplications - pub fn square_assign(&mut self) { - // r0 = s0^2 + U_SQUARE * s1^2 - // r1 = 2* s0s1 - - let ab = self.c0 * self.c1; - let a2 = self.c0 * self.c0; - let b2 = self.c1 * self.c1; - - self.c1 = ab.double(); - self.c0 = a2 + U_SQUARE * b2; - } - - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0.add(&other.c0), - c1: self.c1.add(&other.c1), - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0.sub(&other.c0), - c1: self.c1.sub(&other.c1), - } - } - - pub fn mul(&self, other: &Self) -> Self { - let mut t = *other; - t.mul_assign(self); - t - } - - pub fn square(&self) -> Self { - let mut t = *self; - t.square_assign(); - t - } - - pub fn neg(&self) -> Self { - Self { - c0: self.c0.neg(), - c1: self.c1.neg(), - } - } - - // conjucate by negating c1 - pub fn conjugate(&mut self) { - self.c1 = -self.c1; - } - - pub fn frobenius_map(&mut self, power: usize) { - //TODO Replace with constant time version if needed - if power % 2 != 0 { - self.conjugate() - } - } - - /// Multiply this element by cubic nonresidue: V_CUBE = 57/(u+3) - pub fn mul_by_nonresidue(&mut self) { - // (x + y * u) * 57/(u + 3) - self.mul_assign(&super::fp6::V_CUBE) - } - - pub fn invert(&self) -> CtOption { - let mut t1 = self.c1; - t1 = t1.square(); - t1 *= U_SQUARE; - let mut t0 = self.c0; - t0 = t0.square(); - //t0 = c0^2 - U_SQUARE c1^2 - t0 -= &t1; - t0.invert().map(|t| { - let mut tmp = Fp2 { - c0: self.c0, - c1: self.c1, - }; - tmp.c0 *= &t; - tmp.c1 *= &t; - tmp.c1 = -tmp.c1; - - tmp - }) - } - - /// Norm of Fp2 as extension field in u over Fp - fn norm(&self) -> Fp { - // norm = self * self.conjugate() - let t0 = self.c0.square(); - let t1 = self.c1.square() * U_SQUARE; - t1 - t0 - } -} - -impl Legendre for Fp2 { - fn legendre(&self) -> i64 { - self.norm().legendre() - } -} - -impl Field for Fp2 { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Fp2 { - c0: Fp::random(&mut rng), - c1: Fp::random(&mut rng), - } - } - - fn is_zero(&self) -> Choice { - self.c0.is_zero() & self.c1.is_zero() - } - - fn square(&self) -> Self { - self.square() - } - - fn double(&self) -> Self { - self.double() - } - - fn sqrt(&self) -> CtOption { - // Algorithm 10, https://eprint.iacr.org/2012/685.pdf - - // Aux elements. Described in PRECOMPUTATION of Algorithm 10. - // As element of Fp2: E = 0 + U * - // 0x13e275a1fa6a13af7a82a3d83bc9e63a667c70cf991a36e603b21f15823a404a021848271d63f0875d232408689b4c6c67153f9701e19938 - const E: Fp2 = Fp2 { - c0: Fp::ZERO, - c1: Fp::from_raw([ - 0x67153f9701e19938, - 0x5d232408689b4c6c, - 0x021848271d63f087, - 0x03b21f15823a404a, - 0x667c70cf991a36e6, - 0x7a82a3d83bc9e63a, - 0x13e275a1fa6a13af, - ]), - }; - - // As element of Fp2: f = 5 + 0 * U - // 0x5 - const F: Fp2 = Fp2 { - c0: Fp::from_raw([0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), - c1: Fp::ZERO, - }; - - // Algorithm (not constant time) - let b = self.pow_vartime([ - // (p-1)/4 = - // 0x900000000000900004c3800035fdc392a00f29dbd0e499bd10fe69736a29b1ef929e97fa3eb7ff5a8a9fa30c001ae5167ffff34c0000000 - 0x67ffff34c0000000, - 0xa8a9fa30c001ae51, - 0xf929e97fa3eb7ff5, - 0xd10fe69736a29b1e, - 0x2a00f29dbd0e499b, - 0x004c3800035fdc39, - 0x0900000000000900, - ]); - - let b_2 = b.square(); - let mut b_2_q = b_2; - b_2_q.frobenius_map(1); - - let a0 = b_2_q * b_2; - if a0 == NEG_ONE { - CtOption::new(a0, Choice::from(0)) - } else { - let mut x = b; - x.frobenius_map(1); - if x * b == Fp2::ONE { - let x0 = (b_2 * self).c0.sqrt().unwrap(); - x.c0.mul_assign(x0); - x.c1.mul_assign(x0); - CtOption::new(x, Choice::from(1)) - } else { - let x0 = (self * b_2 * F).sqrt().unwrap(); - x *= x0 * E; - CtOption::new(x, Choice::from(1)) - } - } - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } - - fn invert(&self) -> CtOption { - self.invert() - } -} - -impl From for Fp2 { - fn from(bit: bool) -> Fp2 { - if bit { - Fp2::ONE - } else { - Fp2::ZERO - } - } -} - -impl From for Fp2 { - fn from(val: u64) -> Self { - Fp2 { - c0: Fp::from(val), - c1: Fp::zero(), - } - } -} - -// This trait is only implemented to satisfy the requirement of CurveExt -impl PrimeField for Fp2 { - type Repr = Fp2Bytes; - - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = Fp2 { - c0: Fp::MULTIPLICATIVE_GENERATOR, - c1: Fp::ZERO, - }; - const NUM_BITS: u32 = 446; - const CAPACITY: u32 = 445; - const S: u32 = 0; - - // TODO: Check that we can just 0 this and forget. - const ROOT_OF_UNITY: Self = Fp2::zero(); - const ROOT_OF_UNITY_INV: Self = Fp2 { - c0: Fp::zero(), - c1: Fp::zero(), - }; - const DELTA: Self = Fp2 { - c0: Fp::zero(), - c1: Fp::zero(), - }; - const TWO_INV: Self = Fp2 { - c0: Fp::TWO_INV, - c1: Fp::zero(), - }; - - fn from_repr(repr: Self::Repr) -> CtOption { - let c0 = Fp::from_bytes(&repr.0[..COEF_SIZE].try_into().unwrap()); - let c1 = Fp::from_bytes(&repr.0[COEF_SIZE..].try_into().unwrap()); - // Disallow overflow representation - CtOption::new(Fp2::new(c0.unwrap(), c1.unwrap()), Choice::from(1)) - } - - fn to_repr(&self) -> Self::Repr { - Fp2Bytes(self.to_bytes()) - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr().as_ref()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fp2 { - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::new(Fp::from_uniform_bytes(bytes), Fp::zero()) - } -} -#[derive(Clone, Copy, Debug)] -/// Canonical little-endian representation of a `Fp2` element. -/// First half of the bytes represent `c0`, the second half represent `c1`. -pub struct Fp2Bytes([u8; SIZE]); - -impl Default for Fp2Bytes { - fn default() -> Self { - Self([0u8; SIZE]) - } -} - -impl AsMut<[u8]> for Fp2Bytes { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } -} - -impl AsRef<[u8]> for Fp2Bytes { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl crate::serde::SerdeObject for Fp2 { - fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 112); - let [c0, c1] = [0, 56].map(|i| Fp::from_raw_bytes_unchecked(&bytes[i..i + 56])); - Self { c0, c1 } - } - fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != SIZE { - return None; - } - let [c0, c1] = [0, COEF_SIZE].map(|i| Fp::from_raw_bytes(&bytes[i..i + COEF_SIZE])); - c0.zip(c1).map(|(c0, c1)| Self { c0, c1 }) - } - fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(SIZE); - for limb in self.c0.0.iter().chain(self.c1.0.iter()) { - res.extend_from_slice(&limb.to_le_bytes()); - } - res - } - fn read_raw_unchecked(reader: &mut R) -> Self { - let [c0, c1] = [(); 2].map(|_| Fp::read_raw_unchecked(reader)); - Self { c0, c1 } - } - fn read_raw(reader: &mut R) -> std::io::Result { - let c0 = Fp::read_raw(reader)?; - let c1 = Fp::read_raw(reader)?; - Ok(Self { c0, c1 }) - } - fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { - self.c0.write_raw(writer)?; - self.c1.write_raw(writer) - } -} - -impl WithSmallOrderMulGroup<3> for Fp2 { - const ZETA: Self = Fp2 { - // 0x24000000000024000130e0000d7f28e4a803ca76be3924a5f43f8cddf9a5c4781b50d5e1ff708dc8d9fa5d8a200bc4398ffff80f80000002 - c0: Fp::from_raw([ - 0x8ffff80f80000002, - 0xd9fa5d8a200bc439, - 0x1b50d5e1ff708dc8, - 0xf43f8cddf9a5c478, - 0xa803ca76be3924a5, - 0x0130e0000d7f28e4, - 0x2400000000002400, - ]), - c1: Fp::zero(), - }; -} - -#[cfg(test)] -mod test { - use super::*; - crate::field_testing_suite!(Fp2, "field_arithmetic"); - crate::field_testing_suite!(Fp2, "conversion"); - crate::field_testing_suite!(Fp2, "serialization"); - crate::field_testing_suite!(Fp2, "quadratic_residue"); - crate::field_testing_suite!(Fp2, "sqrt"); - crate::field_testing_suite!(Fp2, "zeta", Fp); - // extension field-specific - crate::field_testing_suite!(Fp2, "f2_tests", Fp); - crate::field_testing_suite!( - Fp2, - "frobenius", - // Frobenius endomorphism power parameter for extension field - // ϕ: E → E - // (x, y) ↦ (x^p, y^p) - // p: modulus of base field (Here, Fp::MODULUS) - [ - 0x9ffffcd300000001, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ] - ); - - #[test] - fn test_fp2_squaring() { - // u + 1 - let mut a = Fp2 { - c0: Fp::one(), - c1: Fp::one(), - }; - // (u + 1) ^2 = 1 + u^2 + 2u = -4 + 2u - a.square_assign(); - let minus_4 = -Fp::from(4u64); - assert_eq!( - a, - Fp2 { - c0: minus_4, - c1: Fp::one() + Fp::one(), - } - ); - - // u - let mut a = Fp2 { - c0: Fp::zero(), - c1: Fp::one(), - }; - // u^2 - a.square_assign(); - assert_eq!( - a, - Fp2 { - c0: U_SQUARE, - c1: Fp::zero(), - } - ); - } - - #[test] - fn test_fp2_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - let nqr = crate::pluto_eris::fields::fp6::V_CUBE; - for _ in 0..1000 { - let mut a = Fp2::random(&mut rng); - let mut b = a; - a.mul_by_nonresidue(); - b.mul_assign(&nqr); - - assert_eq!(a, b); - } - } -} diff --git a/src/pluto_eris/fields/fq.rs b/src/pluto_eris/fields/fq.rs deleted file mode 100644 index 782ca241..00000000 --- a/src/pluto_eris/fields/fq.rs +++ /dev/null @@ -1,501 +0,0 @@ -use crate::arithmetic::{adc, mac, sbb}; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - extend_field_legendre, field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, - impl_from_u64_7_limbs, -}; -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use std::slice::Iter; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - -#[cfg(feature = "derive_serde")] -use serde::{Deserialize, Serialize}; - -/// This represents an element of $\mathbb{F}_q$ where -/// -/// `q = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001` -/// -/// is the scalar field of the Pluto curve (and the base field of the Eris curve). -/// The internal representation of this type is seven 64-bit unsigned -/// integers in little-endian order which account for the 446 bits required to be represented. -/// `Fq` values are always in Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^448. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fq(pub(crate) [u64; 7]); - -/// Size of `Fq` element in bytes -const SIZE: usize = 56; - -/// Constant representing the modulus -/// `p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001` -const MODULUS: Fq = Fq([ - 0x1ffffcd300000001, - 0x9ca7e85d60050af4, - 0xe4a775fe8e177fd6, - 0x443f9a5c7a8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 14] = [ - 0x00000001, 0x1ffffcd3, 0x60050af4, 0x9ca7e85d, 0x8e177fd6, 0xe4a775fe, 0x7a8a6c7b, 0x443f9a5c, - 0xf439266f, 0xa803ca76, 0x0d7f70e4, 0x0130e000, 0x00002400, 0x24000000, -]; - -const MODULUS_STR: &str = "0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001"; - -/// INV = -(q^{-1} mod 2^64) mod 2^64 -/// `0x1ffffcd2ffffffff` -const INV: u64 = 0x1ffffcd2ffffffff; - -/// Let M be the power of `2^64` nearest to `Self::MODULUS_BITS`. Then `R = M % Self::MODULUS`. -/// `R = 2^448 mod q` -/// `0x3ffffffffff03fff7a9dfffa183e9bf67e576bf526ff2f52242c778a637089cbf6bc60a1d5b8121b768a5725fdcb3532000163afffffff9` -const R: Fq = Fq([ - 0x2000163afffffff9, - 0xb768a5725fdcb353, - 0xbf6bc60a1d5b8121, - 0x2242c778a637089c, - 0x67e576bf526ff2f5, - 0xf7a9dfffa183e9bf, - 0x3ffffffffff03ff, -]); - -/// `R^2 = 2^896 mod q` -/// `0x50d7c998f46144ee436895a5a630ff544d51e923f64695651da4da1c97f716419bd905e6e4ff6c2bc64e865fe4552ad740808c831022522` -const R2: Fq = Fq([ - 0x740808c831022522, - 0xbc64e865fe4552ad, - 0x19bd905e6e4ff6c2, - 0x51da4da1c97f7164, - 0x44d51e923f646956, - 0xe436895a5a630ff5, - 0x050d7c998f46144e, -]); - -/// `R^3 = 2^1792 mod q` -/// `0x2f2c41fb476072baa10b8225e69f7de3b2c1031e6d01279e65191fab1f6ce25295c3c8bd6945406c89b51b218477a6f7252704d7495b38a` -const R3: Fq = Fq([ - 0x7252704d7495b38a, - 0xc89b51b218477a6f, - 0x295c3c8bd6945406, - 0xe65191fab1f6ce25, - 0x3b2c1031e6d01279, - 0xaa10b8225e69f7de, - 0x02f2c41fb476072b, -]); - -/// `GENERATOR = 7 mod q` is a generator of the `q - 1` order multiplicative -/// subgroup, or in other words a primitive root of the field. -const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - -/// Size of the 2-adic sub-group of the field. -const S: u32 = 32; - -/// GENERATOR^t where t * 2^s + 1 = q -/// with t odd. In other words, this is a 2^s root of unity. -/// `0x0a5e6f78289fd24b1c64c90821c44cdce9ba1b3e90f2e88957f869667f6dfdbdbce6bb9ed38a8c2382fa11e3d3810fcc3c7bb406ec7bce04` - -const ROOT_OF_UNITY: Fq = Fq::from_raw([ - 0x3c7bb406ec7bce04, - 0x82fa11e3d3810fcc, - 0xbce6bb9ed38a8c23, - 0x57f869667f6dfdbd, - 0xe9ba1b3e90f2e889, - 0x1c64c90821c44cdc, - 0x0a5e6f78289fd24b, -]); - -/// 1 / ROOT_OF_UNITY mod q -/// `0x1a8c636e293fe9928f85aa6ec68f950ebb57e3f0502dd05667c990c1c2f57128c77768be1824fd3f60869f410287a1879ec16a35ca69b6fb` - -const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([ - 0x9ec16a35ca69b6fb, - 0x60869f410287a187, - 0xc77768be1824fd3f, - 0x67c990c1c2f57128, - 0xbb57e3f0502dd056, - 0x8f85aa6ec68f950e, - 0x1a8c636e293fe992, -]); - -/// 1 / 2 mod q -/// `0x12000000000012000098700006bfb8725401e53b7a1c9337a21fcd2e3d45363df253baff470bbfeb4e53f42eb002857a0ffffe6980000001` -const TWO_INV: Fq = Fq::from_raw([ - 0x0ffffe6980000001, - 0x4e53f42eb002857a, - 0xf253baff470bbfeb, - 0xa21fcd2e3d45363d, - 0x5401e53b7a1c9337, - 0x0098700006bfb872, - 0x1200000000001200, -]); - -/// GENERATOR^{2^s} where t * 2^s + 1 = q with t odd. In other words, this is a t root of unity. -/// 0x657946fe07116ceca983fe28713a2b257ab7a7866c95121e727f3776c3e84cb0a14f6a7f83f8cdaeadb479c657bdf2de4589640faf72e67 -const DELTA: Fq = Fq::from_raw([ - 0xe4589640faf72e67, - 0xeadb479c657bdf2d, - 0x0a14f6a7f83f8cda, - 0xe727f3776c3e84cb, - 0x57ab7a7866c95121, - 0xca983fe28713a2b2, - 0x657946fe07116ce, -]); - -/// `ZETA^3 = 1 mod q` where `ZETA^2 != 1 mod q` -/// `0x9000000000006c000392a0001afee1c9500792ae3039253e641ba35817a29ffaf50be000032cfffffffe` - -const ZETA: Fq = Fq::from_raw([ - 0xe000032cfffffffe, - 0xa35817a29ffaf50b, - 0x92ae3039253e641b, - 0xa0001afee1c95007, - 0x000000006c000392, - 0x0000000000009000, - 0x0000000000000000, -]); - -impl_binops_additive!(Fq, Fq); -impl_binops_multiplicative!(Fq, Fq); -field_common_7_limbs!( - Fq, - FqRepr, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_sum_prod!(Fq); -impl_from_u64_7_limbs!(Fq, R2); -field_arithmetic_7_limbs!(Fq, MODULUS, INV, sparse); - -#[cfg(target_pointer_width = "64")] -field_bits_7_limbs!(Fq, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits_7_limbs!(Fq, MODULUS, MODULUS_LIMBS_32); - -extend_field_legendre!(Fq); - -impl Fq { - /// Return field element size in bytes. - pub const fn size() -> usize { - SIZE - } -} - -impl ff::Field for Fq { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Computes the multiplicative inverse of this element, - /// failing if the element is zero. - fn invert(&self) -> CtOption { - // self^(q - 2) - let tmp = self.pow_vartime([ - 0x1ffffcd2ffffffff, - 0x9ca7e85d60050af4, - 0xe4a775fe8e177fd6, - 0x443f9a5c7a8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ]); - - CtOption::new(tmp, !self.ct_eq(&Self::zero())) - } - - fn sqrt(&self) -> CtOption { - /// `(t - 1) // 2` where t * 2^s + 1 = q with t odd. - const T_MINUS1_OVER2: [u64; 7] = [ - 0xb002857a0ffffe69, - 0x470bbfeb4e53f42e, - 0x3d45363df253baff, - 0x7a1c9337a21fcd2e, - 0x06bfb8725401e53b, - 0x0000120000987000, - 0x0000000012000000, - ]; - ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -#[derive(Clone, Copy, Debug)] -/// Canonical little-endian representation of a `Fq` element. -pub struct FqRepr { - pub repr: [u8; SIZE], -} - -impl FqRepr { - /// Returns an iterator over the bytes of the canonical representation of the element. - pub fn iter(&self) -> Iter<'_, u8> { - self.repr.iter() - } -} - -impl Default for FqRepr { - fn default() -> Self { - FqRepr { repr: [0u8; SIZE] } - } -} - -impl AsRef<[u8]> for FqRepr { - fn as_ref(&self) -> &[u8] { - self.repr.as_ref() - } -} - -impl AsMut<[u8]> for FqRepr { - fn as_mut(&mut self) -> &mut [u8] { - self.repr.as_mut() - } -} -impl From<[u8; SIZE]> for FqRepr { - fn from(repr: [u8; SIZE]) -> Self { - Self { repr } - } -} - -impl ff::PrimeField for Fq { - type Repr = FqRepr; - - const NUM_BITS: u32 = 446; - const CAPACITY: u32 = 445; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Self([0, 0, 0, 0, 0, 0, 0]); - let repr = repr.repr; - - 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()); - tmp.0[4] = u64::from_le_bytes(repr[32..40].try_into().unwrap()); - tmp.0[5] = u64::from_le_bytes(repr[40..48].try_into().unwrap()); - tmp.0[6] = u64::from_le_bytes(repr[48..56].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); - let (_, borrow) = sbb(tmp.0[4], MODULUS.0[4], borrow); - let (_, borrow) = sbb(tmp.0[5], MODULUS.0[5], borrow); - let (_, borrow) = sbb(tmp.0[6], MODULUS.0[6], 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 = Self::montgomery_reduce(&[ - self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], 0, 0, 0, - 0, 0, 0, 0, - ]); - - let mut res = [0; SIZE]; - 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[32..40].copy_from_slice(&tmp.0[4].to_le_bytes()); - res[40..48].copy_from_slice(&tmp.0[5].to_le_bytes()); - res[48..56].copy_from_slice(&tmp.0[6].to_le_bytes()); - res.into() - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr().repr[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq { - /// Converts a 512-bit little endian integer into - /// an `Fq` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - 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()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fq { - const ZETA: Self = ZETA; -} - -#[cfg(test)] -mod test { - use super::*; - crate::field_testing_suite!(Fq, "field_arithmetic"); - crate::field_testing_suite!(Fq, "conversion"); - crate::field_testing_suite!(Fq, "serialization"); - crate::field_testing_suite!(Fq, "quadratic_residue"); - crate::field_testing_suite!(Fq, "bits"); - crate::field_testing_suite!(Fq, "serialization_check"); - crate::field_testing_suite!(Fq, "constants", MODULUS_STR); - crate::field_testing_suite!(Fq, "sqrt"); - crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!( - Fq, - "from_uniform_bytes", - [ - Fq::from_raw([ - 0x93638251ffeffed3, - 0xb17ab6ae332352b4, - 0xbf2731af91057325, - 0x7b700ef5a22260d0, - 0xc97c59318d325250, - 0xd7bc83d286537318, - 0x01d4a87b24f91154, - ]), - Fq::from_raw([ - 0x63e0a8f1beefc612, - 0x080f69572a9ddaae, - 0xb9ff1cf0e1f7c067, - 0xd8d8bf5b522bc48b, - 0xa7607085c7065359, - 0x617d8b0cda3f6328, - 0x03096ea964e009c0, - ]), - Fq::from_raw([ - 0x5eaedbda63b3e431, - 0x90ebbfa6f11a9266, - 0x4528cf4d506c9f9b, - 0x8c6ac679e9ac3856, - 0x001666755d9c2c57, - 0x9f7f457a48d6d322, - 0x20b2fadc6bf4004d, - ]), - Fq::from_raw([ - 0xeeea9cbd68b174cf, - 0x84af9e4ce5a781a5, - 0x3578772b5b482647, - 0x6b202eb54b7df723, - 0x55f541b1436b7660, - 0x2045de539849b035, - 0x1d5d7b5f6e8cc333, - ]), - Fq::from_raw([ - 0xe73df0f69b71a763, - 0xbccfb84010979d9d, - 0x1ce3c87be8bf3247, - 0x695fde61877cb617, - 0x5006663bd0944209, - 0xd7ead2b7c71e460d, - 0x0f7c36b781cba9ed, - ]), - Fq::from_raw([ - 0xaeed10e8f00b189d, - 0x5190807038915743, - 0x90b840c0a13b0307, - 0x20fa8cc52c3a9a28, - 0xc3f229646be29c1d, - 0xb1d2bb5373270c43, - 0x0e18a3597be61302, - ]), - Fq::from_raw([ - 0xffbbc6b3e494ca68, - 0x30d4a100158c1751, - 0x0328dae560dff403, - 0x1495c3ce50cce340, - 0x93efc4d4d6ea0079, - 0x0a791ad7698655a7, - 0x22b10d5c1090eec8, - ]), - Fq::from_raw([ - 0xd96eec60211ad67b, - 0x4d081a969b3d8488, - 0x57c9b5abbeec4cf0, - 0x13ced15637e4b0eb, - 0xb98a559f49b0071c, - 0x819ba919d0b6e9b5, - 0x20f73876330a90e8, - ]), - Fq::from_raw([ - 0xbade57a48e2d9868, - 0xc688e43e21f9d2fc, - 0x848a82da9e1d75dc, - 0xae5f4536b9d60aa7, - 0x7957f2028c96467b, - 0xf850f49359458652, - 0x17ba9f9aa08b9ee2, - ]), - Fq::from_raw([ - 0xd0239c8282ccc372, - 0x4a777ad0b66181ea, - 0x53737d5f19e61bfc, - 0x5340b579fe7c4c83, - 0x8406f69a0f89f90a, - 0xd7d5d8bc4497465a, - 0x08ce8bee1323d4f9, - ]), - ] - ); -} diff --git a/src/pluto_eris/fields/mod.rs b/src/pluto_eris/fields/mod.rs deleted file mode 100644 index 2ed86a6b..00000000 --- a/src/pluto_eris/fields/mod.rs +++ /dev/null @@ -1,856 +0,0 @@ -pub mod fp; -pub mod fp12; -pub mod fp2; -pub mod fp6; -pub mod fq; - -#[macro_export] -macro_rules! impl_from_u64_7_limbs { - ($field:ident, $r2:ident) => { - impl From for $field { - fn from(val: u64) -> $field { - $field([val, 0, 0, 0, 0, 0, 0]) * $r2 - } - } - }; -} - -#[macro_export] -macro_rules! field_common_7_limbs { - ( - $field:ident, - $field_repr:ident, - $modulus:ident, - $inv:ident, - $modulus_str:ident, - $two_inv:ident, - $root_of_unity_inv:ident, - $delta:ident, - $zeta:ident, - $r:ident, - $r2:ident, - $r3:ident - ) => { - impl $field { - /// Returns zero, the additive identity. - #[inline] - pub const fn zero() -> $field { - $field([0, 0, 0, 0, 0, 0, 0]) - } - - /// Returns one, the multiplicative identity. - #[inline] - pub const fn one() -> $field { - $r - } - - // Returns the Jacobi symbol, where the numerator and denominator - // are the element and the characteristic of the field, respectively. - // The Jacobi symbol is applicable to odd moduli - // while the Legendre symbol is applicable to prime moduli. - // They are equivalent for prime moduli. - #[inline(always)] - pub fn jacobi(&self) -> i64 { - $crate::ff_ext::jacobi::jacobi::<8>(&self.0, &$modulus.0) - } - - 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], limbs[4], limbs[5], limbs[6], - ]); - let d1 = $field([limbs[7], 0u64, 0u64, 0u64, 0u64, 0u64, 0u64]); - // Convert to Montgomery form - d0 * $r2 + d1 * $r3 - } - - /// Converts from an integer represented in little endian - /// into its (congruent) `$field` representation. - pub const fn from_raw(val: [u64; 7]) -> Self { - #[cfg(feature = "asm")] - { - let (r0, carry) = mac(0, val[0], $r2.0[0], 0); - let (r1, carry) = mac(0, val[0], $r2.0[1], carry); - let (r2, carry) = mac(0, val[0], $r2.0[2], carry); - let (r3, carry) = mac(0, val[0], $r2.0[3], carry); - let (r4, carry) = mac(0, val[0], $r2.0[4], carry); - let (r5, carry) = mac(0, val[0], $r2.0[5], carry); - let (r6, r7) = mac(0, val[0], $r2.0[6], carry); - - let (r1, carry) = mac(r1, val[1], $r2.0[0], 0); - let (r2, carry) = mac(r2, val[1], $r2.0[1], carry); - let (r3, carry) = mac(r3, val[1], $r2.0[2], carry); - let (r4, carry) = mac(r4, val[1], $r2.0[3], carry); - let (r5, carry) = mac(r5, val[1], $r2.0[4], carry); - let (r6, carry) = mac(r6, val[1], $r2.0[5], carry); - let (r7, r8) = mac(r7, val[1], $r2.0[6], carry); - - let (r2, carry) = mac(r2, val[2], $r2.0[0], 0); - let (r3, carry) = mac(r3, val[2], $r2.0[1], carry); - let (r4, carry) = mac(r4, val[2], $r2.0[2], carry); - let (r5, carry) = mac(r5, val[2], $r2.0[3], carry); - let (r6, carry) = mac(r6, val[2], $r2.0[4], carry); - let (r7, carry) = mac(r7, val[2], $r2.0[5], carry); - let (r8, r9) = mac(r8, val[2], $r2.0[6], carry); - - let (r3, carry) = mac(r3, val[3], $r2.0[0], 0); - let (r4, carry) = mac(r4, val[3], $r2.0[1], carry); - let (r5, carry) = mac(r5, val[3], $r2.0[2], carry); - let (r6, carry) = mac(r6, val[3], $r2.0[3], carry); - let (r7, carry) = mac(r7, val[3], $r2.0[4], carry); - let (r8, carry) = mac(r8, val[3], $r2.0[5], carry); - let (r9, r10) = mac(r9, val[3], $r2.0[6], carry); - - let (r4, carry) = mac(r4, val[4], $r2.0[0], 0); - let (r5, carry) = mac(r5, val[4], $r2.0[1], carry); - let (r6, carry) = mac(r6, val[4], $r2.0[2], carry); - let (r7, carry) = mac(r7, val[4], $r2.0[3], carry); - let (r8, carry) = mac(r8, val[4], $r2.0[4], carry); - let (r9, carry) = mac(r9, val[4], $r2.0[5], carry); - let (r10, r11) = mac(r10, val[4], $r2.0[6], carry); - - let (r5, carry) = mac(r5, val[5], $r2.0[0], 0); - let (r6, carry) = mac(r6, val[5], $r2.0[1], carry); - let (r7, carry) = mac(r7, val[5], $r2.0[2], carry); - let (r8, carry) = mac(r8, val[5], $r2.0[3], carry); - let (r9, carry) = mac(r9, val[5], $r2.0[4], carry); - let (r10, carry) = mac(r10, val[5], $r2.0[5], carry); - let (r11, r12) = mac(r11, val[5], $r2.0[6], carry); - - let (r6, carry) = mac(r6, val[6], $r2.0[0], 0); - let (r7, carry) = mac(r7, val[6], $r2.0[1], carry); - let (r8, carry) = mac(r8, val[6], $r2.0[2], carry); - let (r9, carry) = mac(r9, val[6], $r2.0[3], carry); - let (r10, carry) = mac(r10, val[6], $r2.0[4], carry); - let (r11, carry) = mac(r11, val[6], $r2.0[5], carry); - let (r12, r13) = mac(r12, val[6], $r2.0[6], carry); - - // Montgomery reduction - 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, carry) = mac(r4, k, $modulus.0[4], carry); - let (r5, carry) = mac(r5, k, $modulus.0[5], carry); - let (r6, carry) = mac(r6, k, $modulus.0[6], carry); - let (r7, carry2) = adc(r7, 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, carry) = mac(r5, k, $modulus.0[4], carry); - let (r6, carry) = mac(r6, k, $modulus.0[5], carry); - let (r7, carry) = mac(r7, k, $modulus.0[6], carry); - let (r8, carry2) = adc(r8, 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, carry) = mac(r6, k, $modulus.0[4], carry); - let (r7, carry) = mac(r7, k, $modulus.0[5], carry); - let (r8, carry) = mac(r8, k, $modulus.0[6], carry); - let (r9, carry2) = adc(r9, 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, carry) = mac(r7, k, $modulus.0[4], carry); - let (r8, carry) = mac(r8, k, $modulus.0[5], carry); - let (r9, carry) = mac(r9, k, $modulus.0[6], carry); - let (r10, carry2) = adc(r10, carry2, carry); - - let k = r4.wrapping_mul($inv); - let (_, carry) = mac(r4, k, $modulus.0[0], 0); - let (r5, carry) = mac(r5, k, $modulus.0[1], carry); - let (r6, carry) = mac(r6, k, $modulus.0[2], carry); - let (r7, carry) = mac(r7, k, $modulus.0[3], carry); - let (r8, carry) = mac(r8, k, $modulus.0[4], carry); - let (r9, carry) = mac(r9, k, $modulus.0[5], carry); - let (r10, carry) = mac(r10, k, $modulus.0[6], carry); - let (r11, carry2) = adc(r11, carry2, carry); - - let k = r5.wrapping_mul($inv); - let (_, carry) = mac(r5, k, $modulus.0[0], 0); - let (r6, carry) = mac(r6, k, $modulus.0[1], carry); - let (r7, carry) = mac(r7, k, $modulus.0[2], carry); - let (r8, carry) = mac(r8, k, $modulus.0[3], carry); - let (r9, carry) = mac(r9, k, $modulus.0[4], carry); - let (r10, carry) = mac(r10, k, $modulus.0[5], carry); - let (r11, carry) = mac(r11, k, $modulus.0[6], carry); - let (r12, carry2) = adc(r12, carry2, carry); - - let k = r6.wrapping_mul($inv); - let (_, carry) = mac(r6, k, $modulus.0[0], 0); - let (r7, carry) = mac(r7, k, $modulus.0[1], carry); - let (r8, carry) = mac(r8, k, $modulus.0[2], carry); - let (r9, carry) = mac(r9, k, $modulus.0[3], carry); - let (r10, carry) = mac(r10, k, $modulus.0[4], carry); - let (r11, carry) = mac(r11, k, $modulus.0[5], carry); - let (r12, carry) = mac(r12, k, $modulus.0[6], carry); - let (r13, carry2) = adc(r13, carry2, carry); - - // Result may be within MODULUS of the correct value - let (d0, borrow) = sbb(r7, $modulus.0[0], 0); - let (d1, borrow) = sbb(r8, $modulus.0[1], borrow); - let (d2, borrow) = sbb(r9, $modulus.0[2], borrow); - let (d3, borrow) = sbb(r10, $modulus.0[3], borrow); - let (d4, borrow) = sbb(r11, $modulus.0[4], borrow); - let (d5, borrow) = sbb(r12, $modulus.0[5], borrow); - let (d6, borrow) = sbb(r13, $modulus.0[6], borrow); - let (_, borrow) = sbb(carry2, 0, borrow); - 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, carry) = adc(d3, $modulus.0[3] & borrow, carry); - let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); - let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); - let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); - - $field([d0, d1, d2, d3, d4, d5, d6]) - } - #[cfg(not(feature = "asm"))] - { - (&$field(val)).mul(&$r2) - } - } - - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fr`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; 56]) -> CtOption<$field> { - ::from_repr($field_repr { repr: *bytes }) - } - - /// Converts an element of `Fr` into a byte representation in - /// little-endian byte order. - pub fn to_bytes(&self) -> [u8; 56] { - ::to_repr(self).repr - } - - /// Lexicographic comparison of Montgomery forms. - #[inline(always)] - const fn is_less_than(x: &[u64; 7], y: &[u64; 7]) -> bool { - let (_, borrow) = sbb(x[0], y[0], 0); - let (_, borrow) = sbb(x[1], y[1], borrow); - let (_, borrow) = sbb(x[2], y[2], borrow); - let (_, borrow) = sbb(x[3], y[3], borrow); - let (_, borrow) = sbb(x[4], y[4], borrow); - let (_, borrow) = sbb(x[5], y[5], borrow); - let (_, borrow) = sbb(x[6], y[6], borrow); - borrow >> 63 == 1 - } - } - - 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 Default for $field { - #[inline] - fn default() -> Self { - Self::zero() - } - } - - impl From for $field { - fn from(bit: bool) -> $field { - if bit { - $field::one() - } else { - $field::zero() - } - } - } - - 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]) - & self.0[4].ct_eq(&other.0[4]) - & self.0[5].ct_eq(&other.0[5]) - & self.0[6].ct_eq(&other.0[6]) - } - } - - 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) -> Self { - $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), - u64::conditional_select(&a.0[4], &b.0[4], choice), - u64::conditional_select(&a.0[5], &b.0[5], choice), - u64::conditional_select(&a.0[6], &b.0[6], 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 From<$field> for [u8; 56] { - fn from(value: $field) -> [u8; 56] { - value.to_repr().repr - } - } - - impl<'a> From<&'a $field> for [u8; 56] { - fn from(value: &'a $field) -> [u8; 56] { - value.to_repr().repr - } - } - - impl $crate::serde::SerdeObject for $field { - fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 56); - let inner = [0, 8, 16, 24, 32, 40, 48] - .map(|i| u64::from_le_bytes(bytes[i..i + 8].try_into().unwrap())); - Self(inner) - } - fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 56 { - return None; - } - let elt = Self::from_raw_bytes_unchecked(bytes); - Self::is_less_than(&elt.0, &$modulus.0).then(|| elt) - } - fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(56); - for limb in self.0.iter() { - res.extend_from_slice(&limb.to_le_bytes()); - } - res - } - fn read_raw_unchecked(reader: &mut R) -> Self { - let inner = [(); 7].map(|_| { - let mut buf = [0; 8]; - reader.read_exact(&mut buf).unwrap(); - u64::from_le_bytes(buf) - }); - Self(inner) - } - fn read_raw(reader: &mut R) -> std::io::Result { - let mut inner = [0u64; 7]; - for limb in inner.iter_mut() { - let mut buf = [0; 8]; - reader.read_exact(&mut buf)?; - *limb = u64::from_le_bytes(buf); - } - let elt = Self(inner); - Self::is_less_than(&elt.0, &$modulus.0) - .then(|| elt) - .ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - "input number is not less than field modulus", - ) - }) - } - fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { - for limb in self.0.iter() { - writer.write_all(&limb.to_le_bytes())?; - } - Ok(()) - } - } - }; -} - -#[macro_export] -macro_rules! field_arithmetic_7_limbs { - ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => { - $crate::field_specific_7_limbs!($field, $modulus, $inv, $field_type); - impl $field { - /// Doubles this field element. - #[inline] - pub const fn double(&self) -> $field { - self.add(self) - } - - /// 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, carry) = mac(0, self.0[0], self.0[3], carry); - let (r4, carry) = mac(0, self.0[0], self.0[4], carry); - let (r5, carry) = mac(0, self.0[0], self.0[5], carry); - let (r6, r7) = mac(0, self.0[0], self.0[6], carry); - - let (r3, carry) = mac(r3, self.0[1], self.0[2], 0); - let (r4, carry) = mac(r4, self.0[1], self.0[3], carry); - let (r5, carry) = mac(r5, self.0[1], self.0[4], carry); - let (r6, carry) = mac(r6, self.0[1], self.0[5], carry); - let (r7, r8) = mac(r7, self.0[1], self.0[6], carry); - - let (r5, carry) = mac(r5, self.0[2], self.0[3], 0); - let (r6, carry) = mac(r6, self.0[2], self.0[4], carry); - let (r7, carry) = mac(r7, self.0[2], self.0[5], carry); - let (r8, r9) = mac(r8, self.0[2], self.0[6], carry); - - let (r7, carry) = mac(r7, self.0[3], self.0[4], 0); - let (r8, carry) = mac(r8, self.0[3], self.0[5], carry); - let (r9, r10) = mac(r9, self.0[3], self.0[6], carry); - - let (r9, carry) = mac(r9, self.0[4], self.0[5], 0); - let (r10, r11) = mac(r10, self.0[4], self.0[6], carry); - - let (r11, r12) = mac(r11, self.0[5], self.0[6], 0); - - let r13 = r12 >> 63; - let r12 = (r12 << 1) | (r11 >> 63); - let r11 = (r11 << 1) | (r10 >> 63); - let r10 = (r10 << 1) | (r9 >> 63); - let r9 = (r9 << 1) | (r8 >> 63); - let r8 = (r8 << 1) | (r7 >> 63); - let r7 = (r7 << 1) | (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, carry) = adc(0, r7, carry); - let (r8, carry) = mac(r8, self.0[4], self.0[4], carry); - let (r9, carry) = adc(0, r9, carry); - let (r10, carry) = mac(r10, self.0[5], self.0[5], carry); - let (r11, carry) = adc(0, r11, carry); - let (r12, carry) = mac(r12, self.0[6], self.0[6], carry); - let (r13, _) = adc(0, r13, carry); - - $field::montgomery_reduce(&[ - r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, - ]) - } - - /// 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, carry) = mac(0, self.0[0], rhs.0[3], carry); - let (r4, carry) = mac(0, self.0[0], rhs.0[4], carry); - let (r5, carry) = mac(0, self.0[0], rhs.0[5], carry); - let (r6, r7) = mac(0, self.0[0], rhs.0[6], 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, carry) = mac(r4, self.0[1], rhs.0[3], carry); - let (r5, carry) = mac(r5, self.0[1], rhs.0[4], carry); - let (r6, carry) = mac(r6, self.0[1], rhs.0[5], carry); - let (r7, r8) = mac(r7, self.0[1], rhs.0[6], 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, carry) = mac(r5, self.0[2], rhs.0[3], carry); - let (r6, carry) = mac(r6, self.0[2], rhs.0[4], carry); - let (r7, carry) = mac(r7, self.0[2], rhs.0[5], carry); - let (r8, r9) = mac(r8, self.0[2], rhs.0[6], 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, carry) = mac(r6, self.0[3], rhs.0[3], carry); - let (r7, carry) = mac(r7, self.0[3], rhs.0[4], carry); - let (r8, carry) = mac(r8, self.0[3], rhs.0[5], carry); - let (r9, r10) = mac(r9, self.0[3], rhs.0[6], carry); - - let (r4, carry) = mac(r4, self.0[4], rhs.0[0], 0); - let (r5, carry) = mac(r5, self.0[4], rhs.0[1], carry); - let (r6, carry) = mac(r6, self.0[4], rhs.0[2], carry); - let (r7, carry) = mac(r7, self.0[4], rhs.0[3], carry); - let (r8, carry) = mac(r8, self.0[4], rhs.0[4], carry); - let (r9, carry) = mac(r9, self.0[4], rhs.0[5], carry); - let (r10, r11) = mac(r10, self.0[4], rhs.0[6], carry); - - let (r5, carry) = mac(r5, self.0[5], rhs.0[0], 0); - let (r6, carry) = mac(r6, self.0[5], rhs.0[1], carry); - let (r7, carry) = mac(r7, self.0[5], rhs.0[2], carry); - let (r8, carry) = mac(r8, self.0[5], rhs.0[3], carry); - let (r9, carry) = mac(r9, self.0[5], rhs.0[4], carry); - let (r10, carry) = mac(r10, self.0[5], rhs.0[5], carry); - let (r11, r12) = mac(r11, self.0[5], rhs.0[6], carry); - - let (r6, carry) = mac(r6, self.0[6], rhs.0[0], 0); - let (r7, carry) = mac(r7, self.0[6], rhs.0[1], carry); - let (r8, carry) = mac(r8, self.0[6], rhs.0[2], carry); - let (r9, carry) = mac(r9, self.0[6], rhs.0[3], carry); - let (r10, carry) = mac(r10, self.0[6], rhs.0[4], carry); - let (r11, carry) = mac(r11, self.0[6], rhs.0[5], carry); - let (r12, r13) = mac(r12, self.0[6], rhs.0[6], carry); - - $field::montgomery_reduce(&[ - r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, - ]) - } - - /// 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); - let (d4, borrow) = sbb(self.0[4], rhs.0[4], borrow); - let (d5, borrow) = sbb(self.0[5], rhs.0[5], borrow); - let (d6, borrow) = sbb(self.0[6], rhs.0[6], 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, carry) = adc(d3, $modulus.0[3] & borrow, carry); - let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); - let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); - let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); - - $field([d0, d1, d2, d3, d4, d5, d6]) - } - - /// 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, borrow) = sbb($modulus.0[3], self.0[3], borrow); - let (d4, borrow) = sbb($modulus.0[4], self.0[4], borrow); - let (d5, borrow) = sbb($modulus.0[5], self.0[5], borrow); - let (d6, _) = sbb($modulus.0[6], self.0[6], 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] - | self.0[4] - | self.0[5] - | self.0[6]) - == 0) as u64) - .wrapping_sub(1); - - $field([ - d0 & mask, - d1 & mask, - d2 & mask, - d3 & mask, - d4 & mask, - d5 & mask, - d6 & mask, - ]) - } - } - }; -} - -#[macro_export] -macro_rules! field_specific_7_limbs { - ($field:ident, $modulus:ident, $inv:ident, sparse) => { - impl $field { - /// 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, carry) = adc(self.0[3], rhs.0[3], carry); - let (d4, carry) = adc(self.0[4], rhs.0[4], carry); - let (d5, carry) = adc(self.0[5], rhs.0[5], carry); - let (d6, _) = adc(self.0[6], rhs.0[6], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - (&$field([d0, d1, d2, d3, d4, d5, d6])).sub(&$modulus) - } - - #[inline(always)] - pub(crate) const fn montgomery_reduce(r: &[u64; 14]) -> $field { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r[0].wrapping_mul($inv); - let (_, carry) = mac(r[0], k, $modulus.0[0], 0); - let (r1, carry) = mac(r[1], k, $modulus.0[1], carry); - let (r2, carry) = mac(r[2], k, $modulus.0[2], carry); - let (r3, carry) = mac(r[3], k, $modulus.0[3], carry); - let (r4, carry) = mac(r[4], k, $modulus.0[4], carry); - let (r5, carry) = mac(r[5], k, $modulus.0[5], carry); - let (r6, carry) = mac(r[6], k, $modulus.0[6], carry); - let (r7, carry2) = adc(r[7], 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, carry) = mac(r5, k, $modulus.0[4], carry); - let (r6, carry) = mac(r6, k, $modulus.0[5], carry); - let (r7, carry) = mac(r7, k, $modulus.0[6], carry); - let (r8, carry2) = adc(r[8], 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, carry) = mac(r6, k, $modulus.0[4], carry); - let (r7, carry) = mac(r7, k, $modulus.0[5], carry); - let (r8, carry) = mac(r8, k, $modulus.0[6], carry); - let (r9, carry2) = adc(r[9], 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, carry) = mac(r7, k, $modulus.0[4], carry); - let (r8, carry) = mac(r8, k, $modulus.0[5], carry); - let (r9, carry) = mac(r9, k, $modulus.0[6], carry); - let (r10, carry2) = adc(r[10], carry2, carry); - - let k = r4.wrapping_mul($inv); - let (_, carry) = mac(r4, k, $modulus.0[0], 0); - let (r5, carry) = mac(r5, k, $modulus.0[1], carry); - let (r6, carry) = mac(r6, k, $modulus.0[2], carry); - let (r7, carry) = mac(r7, k, $modulus.0[3], carry); - let (r8, carry) = mac(r8, k, $modulus.0[4], carry); - let (r9, carry) = mac(r9, k, $modulus.0[5], carry); - let (r10, carry) = mac(r10, k, $modulus.0[6], carry); - let (r11, carry2) = adc(r[11], carry2, carry); - - let k = r5.wrapping_mul($inv); - let (_, carry) = mac(r5, k, $modulus.0[0], 0); - let (r6, carry) = mac(r6, k, $modulus.0[1], carry); - let (r7, carry) = mac(r7, k, $modulus.0[2], carry); - let (r8, carry) = mac(r8, k, $modulus.0[3], carry); - let (r9, carry) = mac(r9, k, $modulus.0[4], carry); - let (r10, carry) = mac(r10, k, $modulus.0[5], carry); - let (r11, carry) = mac(r11, k, $modulus.0[6], carry); - let (r12, carry2) = adc(r[12], carry2, carry); - - let k = r6.wrapping_mul($inv); - let (_, carry) = mac(r6, k, $modulus.0[0], 0); - let (r7, carry) = mac(r7, k, $modulus.0[1], carry); - let (r8, carry) = mac(r8, k, $modulus.0[2], carry); - let (r9, carry) = mac(r9, k, $modulus.0[3], carry); - let (r10, carry) = mac(r10, k, $modulus.0[4], carry); - let (r11, carry) = mac(r11, k, $modulus.0[5], carry); - let (r12, carry) = mac(r12, k, $modulus.0[6], carry); - let (r13, _) = adc(r[13], carry2, carry); - // Result may be within MODULUS of the correct value - (&$field([r7, r8, r9, r10, r11, r12, r13])).sub(&$modulus) - } - } - }; - ($field:ident, $modulus:ident, $inv:ident, dense) => { - impl $field { - /// 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, carry) = adc(self.0[3], rhs.0[3], carry); - let (d4, carry) = adc(self.0[4], rhs.0[4], carry); - let (d5, carry) = adc(self.0[5], rhs.0[5], carry); - let (d6, carry) = adc(self.0[6], rhs.0[6], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - let (d0, borrow) = sbb(d0, $modulus.0[0], 0); - let (d1, borrow) = sbb(d1, $modulus.0[1], borrow); - let (d2, borrow) = sbb(d2, $modulus.0[2], borrow); - let (d3, borrow) = sbb(d3, $modulus.0[3], borrow); - let (d4, borrow) = sbb(d4, $modulus.0[4], borrow); - let (d5, borrow) = sbb(d5, $modulus.0[5], borrow); - let (_, borrow) = sbb(carry, 0, borrow); - - 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, carry) = adc(d3, $modulus.0[3] & borrow, carry); - let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); - let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); - let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); - - $field([d0, d1, d2, d3, d4, d5, d6]) - } - } - }; -} - -#[macro_export] -macro_rules! field_bits_7_limbs { - // For #[cfg(target_pointer_width = "64")] - ($field:ident, $modulus:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u64; 7]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr().repr; - - 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()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus.0) - } - } - }; - // For #[cfg(not(target_pointer_width = "64"))] - ($field:ident, $modulus:ident, $modulus_limbs_32:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u32; 14]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr().repr; - - 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()), - u32::from_le_bytes(bytes[32..36].try_into().unwrap()), - u32::from_le_bytes(bytes[36..40].try_into().unwrap()), - u32::from_le_bytes(bytes[40..44].try_into().unwrap()), - u32::from_le_bytes(bytes[44..48].try_into().unwrap()), - u32::from_le_bytes(bytes[48..52].try_into().unwrap()), - u32::from_le_bytes(bytes[52..56].try_into().unwrap()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus_limbs_32) - } - } - }; -} diff --git a/src/pluto_eris/fp.rs b/src/pluto_eris/fp.rs new file mode 100644 index 00000000..f383496f --- /dev/null +++ b/src/pluto_eris/fp.rs @@ -0,0 +1,288 @@ +use crate::arithmetic::{adc, mac, sbb}; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::serde::SerdeObject; +use core::convert::TryInto; +use core::fmt; +use core::ops::{Add, Mul, Neg, Sub}; +use rand::RngCore; +use std::slice::Iter; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[cfg(feature = "derive_serde")] +use serde::{Deserialize, Serialize}; + +/// This represents an element of $\mathbb{F}_p$ where +/// +/// `p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001` +/// +/// is the base field of the Pluto curve. + +// Number of 64 bit limbs to represent the field element +pub(crate) const NUM_BITS: u32 = 446; + +// Inverter constant +const BYIL: usize = 9; + +// Jabobi constant +const JACOBI_L: usize = 8; + +/// Constant representing the modulus +/// p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001 +const MODULUS: Fp = Fp([ + 0x9ffffcd300000001, + 0xa2a7e8c30006b945, + 0xe4a7a5fe8fadffd6, + 0x443f9a5cda8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, +]); + +/// The modulus as u32 limbs. +#[cfg(not(target_pointer_width = "64"))] +const MODULUS_LIMBS_32: [u32; 14] = [ + 0x00000001, 0x9ffffcd3, 0x0006b945, 0xa2a7e8c3, 0x8fadffd6, 0xe4a7a5fe, 0xda8a6c7b, 0x443f9a5c, + 0xf439266f, 0xa803ca76, 0x0d7f70e4, 0x0130e000, 0x00002400, 0x24000000, +]; + +// pub const NEGATIVE_ONE: Fp = Fp([]); + +pub(crate) const MODULUS_STR: &str = "0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001"; + +/// INV = -r^{-1} mod 2^64 +/// `0x9ffffcd2ffffffff` +const INV: u64 = 0x9ffffcd2ffffffff; + +/// Let M be the power of `2^64` nearest to `Self::MODULUS_BITS`. Then `R = M % Self::MODULUS`. +/// `R = 2^448 mod p` +/// `0x3ffffffffff03fff7a9dfffa183e9bf67e576bf526ff2f52242c7760637089cbf6a760a123e01218d68a2aaffd0ef18a000163afffffff9` +const R: Fp = Fp([ + 0xa000163afffffff9, + 0x8d68a2aaffd0ef18, + 0xbf6a760a123e0121, + 0x2242c7760637089c, + 0x67e576bf526ff2f5, + 0xf7a9dfffa183e9bf, + 0x03ffffffffff03ff, +]); + +/// `R^2 = 2^896 mod p` +/// `0x1a4b16581f66e3cc8bcb0f20758aec8520b6db3d7481a84c734fd363b575c23e7a42067a8ccd154b4b20c07277ae01f1d9702c6d54dc0598` +const R2: Fp = Fp([ + 0xd9702c6d54dc0598, + 0x4b20c07277ae01f1, + 0x7a42067a8ccd154b, + 0x734fd363b575c23e, + 0x20b6db3d7481a84c, + 0x8bcb0f20758aec85, + 0x1a4b16581f66e3cc, +]); + +/// `R^3 = 2^1792 mod p` +/// `0x1f51e40a048ddc1789010189f4df0ae1f3bc57efac4b3280b25aa8b46a40b225e5446680e4c4ea0449937d6b40e58f05c67afa3fe916dd69` +const R3: Fp = Fp([ + 0xc67afa3fe916dd69, + 0x49937d6b40e58f05, + 0xe5446680e4c4ea04, + 0xb25aa8b46a40b225, + 0xf3bc57efac4b3280, + 0x89010189f4df0ae1, + 0x1f51e40a048ddc17, +]); + +/// `GENERATOR = 10 mod p` is a generator of the `p - 1` order multiplicative +/// subgroup, or in other words a primitive root of the field. +const MULTIPLICATIVE_GENERATOR: Fp = Fp::from_raw([0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); + +/// Size of the 2-adic sub-group of the field. +const S: u32 = 32; + +/// GENERATOR^t where t * 2^s + 1 = p +/// with t odd. In other words, this +/// is a 2^s root of unity. +/// `0x2d39f8c5f9adb3f35fe3f4222db17451ddd9602a013af5276bdbe3903ec85fc889232f5c8bc6857060c75e6f399661d6c7b82d31d563091` +const ROOT_OF_UNITY: Fp = Fp::from_raw([ + 0x6c7b82d31d563091, + 0x060c75e6f399661d, + 0x889232f5c8bc6857, + 0x76bdbe3903ec85fc, + 0x1ddd9602a013af52, + 0x35fe3f4222db1745, + 0x02d39f8c5f9adb3f, +]); + +/// 1 / ROOT_OF_UNITY mod p +/// `0x17725d635b00cda4153eb10c7105919d012822bd86c08691803272fbc5c9f8378055eb56ae2d55f9272bf208aad57f666deaead2c693ff66` +const ROOT_OF_UNITY_INV: Fp = Fp::from_raw([ + 0x6deaead2c693ff66, + 0x272bf208aad57f66, + 0x8055eb56ae2d55f9, + 0x803272fbc5c9f837, + 0x012822bd86c08691, + 0x153eb10c7105919d, + 0x17725d635b00cda4, +]); + +/// 1 / 2 mod p +/// `0x12000000000012000098700006bfb8725401e53b7a1c9337a21fcd2e6d45363df253d2ff47d6ffeb5153f46180035ca2cffffe6980000001` +pub(crate) const TWO_INV: Fp = Fp::from_raw([ + 0xcffffe6980000001, + 0x5153f46180035ca2, + 0xf253d2ff47d6ffeb, + 0xa21fcd2e6d45363d, + 0x5401e53b7a1c9337, + 0x0098700006bfb872, + 0x1200000000001200, +]); +/// GENERATOR^{2^s} where t * 2^s + 1 = r with t odd. In other words, this is a t root of unity. +/// `0xeacefc6504d028d42ed23fc8766d5a5f195b456887e1e0021fb760c53233e9170c23749b459b95cc6cbb5faf3754a1e1916b2007775db04` +const DELTA: Fp = Fp::from_raw([ + 0x1916b2007775db04, + 0xc6cbb5faf3754a1e, + 0x70c23749b459b95c, + 0x21fb760c53233e91, + 0xf195b456887e1e00, + 0x42ed23fc8766d5a5, + 0x0eacefc6504d028d, +]); + +/// `ZETA^3 = 1 mod p` where `ZETA^2 != 1 mod p` +/// `0x480000000000360001c950000d7ee0e4a803c956d01c903d720dc8ad8b38dffaf50c100004c37ffffffe` +const ZETA: Fp = Fp::from_raw([ + 0x100004c37ffffffe, + 0xc8ad8b38dffaf50c, + 0xc956d01c903d720d, + 0x50000d7ee0e4a803, + 0x00000000360001c9, + 0x0000000000004800, + 0x0000000000000000, +]); + +/// NEG_ONE ; -1 mod p +pub(crate) const NEG_ONE: Fp = Fp::from_raw([ + 0x9ffffcd300000000, + 0xa2a7e8c30006b945, + 0xe4a7a5fe8fadffd6, + 0x443f9a5cda8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, +]); + +use crate::{ + extend_field_legendre, field_arithmetic_7_limbs, field_bits, impl_add_binop_specify_impl, + impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, + impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_field, impl_from_u64, + impl_from_uniform_bytes, impl_prime_field, impl_serde_object, impl_sub_binop_specify_output, + impl_sum_prod, pow_vartime, +}; +impl_binops_additive!(Fp, Fp); +impl_binops_multiplicative!(Fp, Fp); +impl_add_binop_specify_impl!(Fp); +impl_field!(Fp, sparse); +impl_serde_object!(Fp); +impl_prime_field!(Fp, ReprFp, le); +impl_sum_prod!(Fp); +extend_field_legendre!(Fp); +impl_from_u64!(Fp); +impl_from_uniform_bytes!(Fp, 64); +impl_from_uniform_bytes!(Fp, 72); +impl_from_uniform_bytes!(Fp, 112); + +field_arithmetic_7_limbs!(Fp, MODULUS, INV, sparse); + +#[cfg(target_pointer_width = "64")] +field_bits!(Fp); +#[cfg(not(target_pointer_width = "64"))] +field_bits!(Fp); + +impl Fp { + fn sqrt(&self) -> CtOption { + /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd. + const T_MINUS1_OVER2: [u64; 7] = [ + 0x80035ca2cffffe69, + 0x47d6ffeb5153f461, + 0x6d45363df253d2ff, + 0x7a1c9337a21fcd2e, + 0x06bfb8725401e53b, + 0x0000120000987000, + 0x0000000012000000, + ]; + ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) + } +} + +#[derive(Clone, Copy, Debug)] +/// Canonical little-endian representation of a `Fp` element. +pub struct ReprFp { + pub repr: [u8; Fp::SIZE], +} + +impl ReprFp { + /// Returns an iterator over the bytes of the canonical representation of the element. + pub fn iter(&self) -> Iter<'_, u8> { + self.repr.iter() + } +} + +impl Default for ReprFp { + fn default() -> Self { + ReprFp { + repr: [0u8; Fp::SIZE], + } + } +} + +impl AsRef<[u8]> for ReprFp { + fn as_ref(&self) -> &[u8] { + self.repr.as_ref() + } +} + +impl AsMut<[u8]> for ReprFp { + fn as_mut(&mut self) -> &mut [u8] { + self.repr.as_mut() + } +} +impl From<[u8; Fp::SIZE]> for ReprFp { + fn from(repr: [u8; Fp::SIZE]) -> Self { + Self { repr } + } +} + +impl From for [u8; Fp::SIZE] { + fn from(repr: ReprFp) -> Self { + repr.repr + } +} + +impl core::ops::Index for ReprFp { + type Output = u8; + + fn index(&self, index: usize) -> &Self::Output { + &self.repr[index] + } +} + +impl core::ops::Index> for ReprFp { + type Output = [u8]; + + fn index(&self, index: core::ops::Range) -> &Self::Output { + &self.repr[index] + } +} + +#[cfg(test)] +mod test { + use super::*; + crate::field_testing_suite!(Fp, "field_arithmetic"); + crate::field_testing_suite!(Fp, "conversion"); + crate::field_testing_suite!(Fp, "serialization"); + crate::field_testing_suite!(Fp, "quadratic_residue"); + crate::field_testing_suite!(Fp, "bits"); + crate::field_testing_suite!(Fp, "serialization_check"); + crate::field_testing_suite!(Fp, "constants", MODULUS_STR); + crate::field_testing_suite!(Fp, "sqrt"); + crate::field_testing_suite!(Fp, "zeta"); + crate::field_testing_suite!(Fp, "from_uniform_bytes", 64); +} diff --git a/src/pluto_eris/fields/fp12.rs b/src/pluto_eris/fp12.rs similarity index 83% rename from src/pluto_eris/fields/fp12.rs rename to src/pluto_eris/fp12.rs index b6e08a8c..95a98e50 100644 --- a/src/pluto_eris/fields/fp12.rs +++ b/src/pluto_eris/fp12.rs @@ -1,7 +1,7 @@ use super::fp::Fp; use super::fp2::Fp2; use super::fp6::Fp6; -use crate::ff::Field; +use crate::{ff::Field, impl_tower2_common}; use core::ops::{Add, Mul, Neg, Sub}; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -9,98 +9,18 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// -GAMMA is a quadratic non-residue in Fp6. Fp12 = Fp6[X]/(X^2 + GAMMA) /// We introduce the variable w such that w^2 = -GAMMA /// GAMMA = - v -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -pub struct Fp12 { - c0: Fp6, - c1: Fp6, -} - -impl ConditionallySelectable for Fp12 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fp12 { - c0: Fp6::conditional_select(&a.c0, &b.c0, choice), - c1: Fp6::conditional_select(&a.c1, &b.c1, choice), - } - } -} - -impl ConstantTimeEq for Fp12 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) - } -} - -impl Neg for Fp12 { - type Output = Fp12; - - #[inline] - fn neg(self) -> Fp12 { - -&self - } -} - -impl<'a> Neg for &'a Fp12 { - type Output = Fp12; - - #[inline] - fn neg(self) -> Fp12 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fp12> for &'a Fp12 { - type Output = Fp12; - - #[inline] - fn sub(self, rhs: &'b Fp12) -> Fp12 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fp12> for &'a Fp12 { - type Output = Fp12; - - #[inline] - fn add(self, rhs: &'b Fp12) -> Fp12 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fp12> for &'a Fp12 { - type Output = Fp12; - - #[inline] - fn mul(self, rhs: &'b Fp12) -> Fp12 { - self.mul(rhs) - } -} - use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, impl_sum_prod, }; impl_binops_additive!(Fp12, Fp12); impl_binops_multiplicative!(Fp12, Fp12); +impl_tower2_common!(Fp6, Fp12); +impl_add_binop_specify_impl!(Fp12); impl_sum_prod!(Fp12); impl Fp12 { - #[inline] - pub const fn zero() -> Self { - Fp12 { - c0: Fp6::ZERO, - c1: Fp6::ZERO, - } - } - - #[inline] - pub const fn one() -> Self { - Fp12 { - c0: Fp6::ONE, - c1: Fp6::ZERO, - } - } - pub fn mul_assign(&mut self, other: &Self) { let t0 = self.c0 * other.c0; let mut t1 = self.c1 * other.c1; @@ -132,32 +52,6 @@ impl Fp12 { self.c0 = c0; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0 + other.c0, - c1: self.c1 + other.c1, - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0 - other.c0, - c1: self.c1 - other.c1, - } - } - pub fn mul(&self, other: &Self) -> Self { let mut t = *other; t.mul_assign(self); @@ -170,14 +64,6 @@ impl Fp12 { t } - #[inline(always)] - pub fn neg(&self) -> Self { - Self { - c0: -self.c0, - c1: -self.c1, - } - } - #[inline(always)] pub fn conjugate(&mut self) { self.c1 = -self.c1; @@ -262,29 +148,29 @@ impl Fp12 { fp4_square(&mut t3, &mut t4, &self.c0.c0, &self.c1.c1); let mut t2 = t3 - self.c0.c0; - t2.double_assign(); + t2 = t2.double(); self.c0.c0 = t2 + t3; t2 = t4 + self.c1.c1; - t2.double_assign(); + t2 = t2.double(); self.c1.c1 = t2 + t4; fp4_square(&mut t3, &mut t4, &self.c1.c0, &self.c0.c2); fp4_square(&mut t5, &mut t6, &self.c0.c1, &self.c1.c2); t2 = t3 - self.c0.c1; - t2.double_assign(); + t2 = t2.double(); self.c0.c1 = t2 + t3; t2 = t4 + self.c1.c2; - t2.double_assign(); + t2 = t2.double(); self.c1.c2 = t2 + t4; t3 = t6; t3.mul_by_nonresidue(); t2 = t3 + self.c1.c0; - t2.double_assign(); + t2 = t2.double(); self.c1.c0 = t2 + t3; t2 = t5 - self.c0.c2; - t2.double_assign(); + t2 = t2.double(); self.c0.c2 = t2 + t5; } } diff --git a/src/pluto_eris/fp2.rs b/src/pluto_eris/fp2.rs new file mode 100644 index 00000000..efb7dcba --- /dev/null +++ b/src/pluto_eris/fp2.rs @@ -0,0 +1,291 @@ +use super::fp::Fp; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::ff_ext::Legendre; +use core::convert::TryInto; +use core::ops::{Add, Mul, Neg, Sub}; +use rand::RngCore; +use std::cmp::Ordering; +use std::ops::MulAssign; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[cfg(feature = "derive_serde")] +use serde::{Deserialize, Serialize}; + +use crate::{ + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, impl_sum_prod, impl_tower2, + impl_tower2_common, +}; +impl_tower2_common!(Fp, Fp2); +impl_tower2!(Fp, Fp2, ReprFp2); +impl_binops_additive!(Fp2, Fp2); +impl_binops_multiplicative!(Fp2, Fp2); +impl_add_binop_specify_impl!(Fp2); +impl_sum_prod!(Fp2); + +/// -ALPHA is a quadratic non-residue in Fp. Fp2 = Fp[X]/(X^2 + ALPHA) +/// We introduce the variable u such that u^2 = -ALPHA + +/// U_SQUARE = -5 +/// 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd2fffffffc +const U_SQUARE: Fp = Fp::from_raw([ + 0x9ffffcd2fffffffc, + 0xa2a7e8c30006b945, + 0xe4a7a5fe8fadffd6, + 0x443f9a5cda8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, +]); + +const NEG_ONE: Fp2 = Fp2 { + c0: super::fp::NEG_ONE, + c1: Fp::ZERO, +}; + +// /// Size in bytes of a `Fp2` element. +// const SIZE: usize = 112; +// /// Size in bytes of a each coefficient of `Fp2`. +// const COEF_SIZE: usize = 56; + +impl Fp2 { + // TODO: This is a naive method using 4 multiplications + pub fn mul_assign(&mut self, other: &Self) { + // r0 = s0 * s0 + U_SQUARE * s1 * o1 + // r1 = s0 * o1 - s1 * o0 + + let t0 = self.c0 * other.c0; + let t1 = self.c0 * other.c1; + let t2 = self.c1 * other.c0; + let t3 = self.c1 * other.c1; + + self.c0 = t0 + U_SQUARE * t3; + self.c1 = t1 + t2 + } + + // TODO: This is a naive method using 3 multiplications + pub fn square_assign(&mut self) { + // r0 = s0^2 + U_SQUARE * s1^2 + // r1 = 2* s0s1 + + let ab = self.c0 * self.c1; + let a2 = self.c0 * self.c0; + let b2 = self.c1 * self.c1; + + self.c1 = ab.double(); + self.c0 = a2 + U_SQUARE * b2; + } + + pub fn mul(&self, other: &Self) -> Self { + let mut t = *other; + t.mul_assign(self); + t + } + + pub fn square(&self) -> Self { + let mut t = *self; + t.square_assign(); + t + } + + // conjucate by negating c1 + pub fn conjugate(&mut self) { + self.c1 = -self.c1; + } + + pub fn frobenius_map(&mut self, power: usize) { + //TODO Replace with constant time version if needed + if power % 2 != 0 { + self.conjugate() + } + } + + /// Multiply this element by cubic nonresidue: V_CUBE = 57/(u+3) + pub fn mul_by_nonresidue(&mut self) { + // (x + y * u) * 57/(u + 3) + self.mul_assign(&super::fp6::V_CUBE) + } + + pub fn invert(&self) -> CtOption { + let mut t1 = self.c1; + t1 = t1.square(); + t1 *= U_SQUARE; + let mut t0 = self.c0; + t0 = t0.square(); + //t0 = c0^2 - U_SQUARE c1^2 + t0 -= &t1; + t0.invert().map(|t| { + let mut tmp = Fp2 { + c0: self.c0, + c1: self.c1, + }; + tmp.c0 *= &t; + tmp.c1 *= &t; + tmp.c1 = -tmp.c1; + + tmp + }) + } + + /// Norm of Fp2 as extension field in u over Fp + fn norm(&self) -> Fp { + // norm = self * self.conjugate() + let t0 = self.c0.square(); + let t1 = self.c1.square() * U_SQUARE; + t1 - t0 + } + + fn sqrt(&self) -> CtOption { + // Algorithm 10, https://eprint.iacr.org/2012/685.pdf + + // Aux elements. Described in PRECOMPUTATION of Algorithm 10. + // As element of Fp2: E = 0 + U * + // 0x13e275a1fa6a13af7a82a3d83bc9e63a667c70cf991a36e603b21f15823a404a021848271d63f0875d232408689b4c6c67153f9701e19938 + const E: Fp2 = Fp2 { + c0: Fp::ZERO, + c1: Fp::from_raw([ + 0x67153f9701e19938, + 0x5d232408689b4c6c, + 0x021848271d63f087, + 0x03b21f15823a404a, + 0x667c70cf991a36e6, + 0x7a82a3d83bc9e63a, + 0x13e275a1fa6a13af, + ]), + }; + + // As element of Fp2: f = 5 + 0 * U + // 0x5 + const F: Fp2 = Fp2 { + c0: Fp::from_raw([0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), + c1: Fp::ZERO, + }; + + // Algorithm (not constant time) + let b = self.pow_vartime([ + // (p-1)/4 = + // 0x900000000000900004c3800035fdc392a00f29dbd0e499bd10fe69736a29b1ef929e97fa3eb7ff5a8a9fa30c001ae5167ffff34c0000000 + 0x67ffff34c0000000, + 0xa8a9fa30c001ae51, + 0xf929e97fa3eb7ff5, + 0xd10fe69736a29b1e, + 0x2a00f29dbd0e499b, + 0x004c3800035fdc39, + 0x0900000000000900, + ]); + + let b_2 = b.square(); + let mut b_2_q = b_2; + b_2_q.frobenius_map(1); + + let a0 = b_2_q * b_2; + if a0 == NEG_ONE { + CtOption::new(a0, Choice::from(0)) + } else { + let mut x = b; + x.frobenius_map(1); + if x * b == Fp2::ONE { + let x0 = (b_2 * self).c0.sqrt().unwrap(); + x.c0.mul_assign(x0); + x.c1.mul_assign(x0); + CtOption::new(x, Choice::from(1)) + } else { + let x0 = (self * b_2 * F).sqrt().unwrap(); + x *= x0 * E; + CtOption::new(x, Choice::from(1)) + } + } + } +} + +const ZETA: Fp = Fp::from_raw([ + 0x8ffff80f80000002, + 0xd9fa5d8a200bc439, + 0x1b50d5e1ff708dc8, + 0xf43f8cddf9a5c478, + 0xa803ca76be3924a5, + 0x0130e0000d7f28e4, + 0x2400000000002400, +]); + +#[cfg(test)] +mod test { + use super::*; + crate::field_testing_suite!(Fp2, "field_arithmetic"); + crate::field_testing_suite!(Fp2, "conversion"); + crate::field_testing_suite!(Fp2, "serialization"); + crate::field_testing_suite!(Fp2, "quadratic_residue"); + crate::field_testing_suite!(Fp2, "sqrt"); + crate::field_testing_suite!(Fp2, "zeta", Fp); + // extension field-specific + crate::field_testing_suite!(Fp2, "f2_tests", Fp); + crate::field_testing_suite!( + Fp2, + "frobenius", + // Frobenius endomorphism power parameter for extension field + // ϕ: E → E + // (x, y) ↦ (x^p, y^p) + // p: modulus of base field (Here, Fp::MODULUS) + [ + 0x9ffffcd300000001, + 0xa2a7e8c30006b945, + 0xe4a7a5fe8fadffd6, + 0x443f9a5cda8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, + ] + ); + + #[test] + fn test_fp2_squaring() { + // u + 1 + let mut a = Fp2 { + c0: Fp::one(), + c1: Fp::one(), + }; + // (u + 1) ^2 = 1 + u^2 + 2u = -4 + 2u + a.square_assign(); + let minus_4 = -Fp::from(4u64); + assert_eq!( + a, + Fp2 { + c0: minus_4, + c1: Fp::one() + Fp::one(), + } + ); + + // u + let mut a = Fp2 { + c0: Fp::zero(), + c1: Fp::one(), + }; + // u^2 + a.square_assign(); + assert_eq!( + a, + Fp2 { + c0: U_SQUARE, + c1: Fp::zero(), + } + ); + } + + #[test] + fn test_fp2_mul_nonresidue() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + let nqr = crate::pluto_eris::fp6::V_CUBE; + for _ in 0..1000 { + let mut a = Fp2::random(&mut rng); + let mut b = a; + a.mul_by_nonresidue(); + b.mul_assign(&nqr); + + assert_eq!(a, b); + } + } +} diff --git a/src/pluto_eris/fields/fp6.rs b/src/pluto_eris/fp6.rs similarity index 80% rename from src/pluto_eris/fields/fp6.rs rename to src/pluto_eris/fp6.rs index 2e298eca..a354c138 100644 --- a/src/pluto_eris/fields/fp6.rs +++ b/src/pluto_eris/fp6.rs @@ -8,6 +8,16 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// -BETA is a cubic non-residue in Fp2. Fp6 = Fp2[X]/(X^3 + BETA) /// We introduce the variable v such that v^3 = -BETA /// BETA = - 57/(z+3) +use crate::{ + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, impl_sum_prod, impl_tower6, +}; +impl_tower6!(Fp, Fp2, Fp6); +impl_binops_additive!(Fp6, Fp6); +impl_binops_multiplicative!(Fp6, Fp6); +impl_add_binop_specify_impl!(Fp6); +impl_sum_prod!(Fp6); /// V_CUBE = 57/(u+3) pub(crate) const V_CUBE: Fp2 = Fp2 { @@ -33,103 +43,7 @@ pub(crate) const V_CUBE: Fp2 = Fp2 { ]), }; -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -/// The `Fp6` element c0 + c1 * v + c2 * v3 -pub struct Fp6 { - pub c0: Fp2, - pub c1: Fp2, - pub c2: Fp2, -} - -impl ConditionallySelectable for Fp6 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fp6 { - c0: Fp2::conditional_select(&a.c0, &b.c0, choice), - c1: Fp2::conditional_select(&a.c1, &b.c1, choice), - c2: Fp2::conditional_select(&a.c2, &b.c2, choice), - } - } -} - -impl ConstantTimeEq for Fp6 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) & self.c2.ct_eq(&other.c2) - } -} - -impl Neg for Fp6 { - type Output = Fp6; - - #[inline] - fn neg(self) -> Fp6 { - -&self - } -} - -impl<'a> Neg for &'a Fp6 { - type Output = Fp6; - - #[inline] - fn neg(self) -> Fp6 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fp6> for &'a Fp6 { - type Output = Fp6; - - #[inline] - fn sub(self, rhs: &'b Fp6) -> Fp6 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fp6> for &'a Fp6 { - type Output = Fp6; - - #[inline] - fn add(self, rhs: &'b Fp6) -> Fp6 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fp6> for &'a Fp6 { - type Output = Fp6; - - #[inline] - fn mul(self, rhs: &'b Fp6) -> Fp6 { - self.mul(rhs) - } -} - -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -impl_binops_additive!(Fp6, Fp6); -impl_binops_multiplicative!(Fp6, Fp6); -impl_sum_prod!(Fp6); - impl Fp6 { - #[inline] - pub const fn zero() -> Self { - Fp6 { - c0: Fp2::ZERO, - c1: Fp2::ZERO, - c2: Fp2::ZERO, - } - } - - #[inline] - pub const fn one() -> Self { - Fp6 { - c0: Fp2::ONE, - c1: Fp2::ZERO, - c2: Fp2::ZERO, - } - } - pub fn mul_assign(&mut self, other: &Self) { let mut a_a = self.c0; let mut b_b = self.c1; @@ -188,8 +102,8 @@ impl Fp6 { // s1 = 2ab let mut ab = self.c0; ab *= &self.c1; - let mut s1 = ab; - s1.double_assign(); + let s1 = ab; + let s1 = s1.double(); // s2 = (a - b + c)^2 let mut s2 = self.c0; s2 -= &self.c1; @@ -199,8 +113,8 @@ impl Fp6 { let mut bc = self.c1; bc *= &self.c2; // s3 = 2bc - let mut s3 = bc; - s3.double_assign(); + let s3 = bc; + let s3 = s3.double(); // s4 = c^2 let mut s4 = self.c2; s4.square_assign(); @@ -225,36 +139,6 @@ impl Fp6 { self.c2 -= &s4; } - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - c2: self.c2.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - self.c2 = self.c2.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0 + other.c0, - c1: self.c1 + other.c1, - c2: self.c2 + other.c2, - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0 - other.c0, - c1: self.c1 - other.c1, - c2: self.c2 - other.c2, - } - } - pub fn mul(&self, other: &Self) -> Self { let mut t = *other; t.mul_assign(self); @@ -267,14 +151,6 @@ impl Fp6 { t } - pub fn neg(&self) -> Self { - Self { - c0: -self.c0, - c1: -self.c1, - c2: -self.c2, - } - } - pub fn frobenius_map(&mut self, power: usize) { self.c0.frobenius_map(power); self.c1.frobenius_map(power); @@ -415,43 +291,6 @@ impl Fp6 { } } -impl Field for Fp6 { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Fp6 { - c0: Fp2::random(&mut rng), - c1: Fp2::random(&mut rng), - c2: Fp2::random(&mut rng), - } - } - - fn is_zero(&self) -> Choice { - self.c0.is_zero() & self.c1.is_zero() - } - - fn square(&self) -> Self { - self.square() - } - - fn double(&self) -> Self { - self.double() - } - - fn sqrt(&self) -> CtOption { - unimplemented!() - } - - fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { - unimplemented!() - } - - fn invert(&self) -> CtOption { - self.invert() - } -} - /// Fp2 coefficients for the efficient computation of Frobenius Endomorphism in Fp6. pub(crate) const FROBENIUS_COEFF_FP6_C1: [Fp2; 6] = [ // Fp2(v^3)**(((p^0) - 1) / 3) diff --git a/src/pluto_eris/fq.rs b/src/pluto_eris/fq.rs new file mode 100644 index 00000000..a66ca398 --- /dev/null +++ b/src/pluto_eris/fq.rs @@ -0,0 +1,278 @@ +use crate::arithmetic::{adc, mac, sbb}; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::serde::SerdeObject; +use core::convert::TryInto; +use core::fmt; +use core::ops::{Add, Mul, Neg, Sub}; +use rand::RngCore; +use std::slice::Iter; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[cfg(feature = "derive_serde")] +use serde::{Deserialize, Serialize}; + +/// This represents an element of $\mathbb{F}_q$ where +/// +/// `q = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001` +/// + +// Number of 64 bit limbs to represent the field element +pub(crate) const NUM_BITS: u32 = 446; + +// Inverter constant +const BYIL: usize = 9; + +// Jabobi constant +const JACOBI_L: usize = 8; + +/// Constant representing the modulus +/// `p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001` +const MODULUS: Fq = Fq([ + 0x1ffffcd300000001, + 0x9ca7e85d60050af4, + 0xe4a775fe8e177fd6, + 0x443f9a5c7a8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, +]); + +/// The modulus as u32 limbs. +#[cfg(not(target_pointer_width = "64"))] +const MODULUS_LIMBS_32: [u32; 14] = [ + 0x00000001, 0x1ffffcd3, 0x60050af4, 0x9ca7e85d, 0x8e177fd6, 0xe4a775fe, 0x7a8a6c7b, 0x443f9a5c, + 0xf439266f, 0xa803ca76, 0x0d7f70e4, 0x0130e000, 0x00002400, 0x24000000, +]; + +const MODULUS_STR: &str = "0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001"; + +/// INV = -(q^{-1} mod 2^64) mod 2^64 +/// `0x1ffffcd2ffffffff` +const INV: u64 = 0x1ffffcd2ffffffff; + +/// Let M be the power of `2^64` nearest to `Self::MODULUS_BITS`. Then `R = M % Self::MODULUS`. +/// `R = 2^448 mod q` +/// `0x3ffffffffff03fff7a9dfffa183e9bf67e576bf526ff2f52242c778a637089cbf6bc60a1d5b8121b768a5725fdcb3532000163afffffff9` +const R: Fq = Fq([ + 0x2000163afffffff9, + 0xb768a5725fdcb353, + 0xbf6bc60a1d5b8121, + 0x2242c778a637089c, + 0x67e576bf526ff2f5, + 0xf7a9dfffa183e9bf, + 0x3ffffffffff03ff, +]); + +/// `R^2 = 2^896 mod q` +/// `0x50d7c998f46144ee436895a5a630ff544d51e923f64695651da4da1c97f716419bd905e6e4ff6c2bc64e865fe4552ad740808c831022522` +const R2: Fq = Fq([ + 0x740808c831022522, + 0xbc64e865fe4552ad, + 0x19bd905e6e4ff6c2, + 0x51da4da1c97f7164, + 0x44d51e923f646956, + 0xe436895a5a630ff5, + 0x050d7c998f46144e, +]); + +/// `R^3 = 2^1792 mod q` +/// `0x2f2c41fb476072baa10b8225e69f7de3b2c1031e6d01279e65191fab1f6ce25295c3c8bd6945406c89b51b218477a6f7252704d7495b38a` +const R3: Fq = Fq([ + 0x7252704d7495b38a, + 0xc89b51b218477a6f, + 0x295c3c8bd6945406, + 0xe65191fab1f6ce25, + 0x3b2c1031e6d01279, + 0xaa10b8225e69f7de, + 0x02f2c41fb476072b, +]); + +/// `GENERATOR = 7 mod q` is a generator of the `q - 1` order multiplicative +/// subgroup, or in other words a primitive root of the field. +const MULTIPLICATIVE_GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); + +/// Size of the 2-adic sub-group of the field. +const S: u32 = 32; + +/// GENERATOR^t where t * 2^s + 1 = q +/// with t odd. In other words, this is a 2^s root of unity. +/// `0x0a5e6f78289fd24b1c64c90821c44cdce9ba1b3e90f2e88957f869667f6dfdbdbce6bb9ed38a8c2382fa11e3d3810fcc3c7bb406ec7bce04` + +const ROOT_OF_UNITY: Fq = Fq::from_raw([ + 0x3c7bb406ec7bce04, + 0x82fa11e3d3810fcc, + 0xbce6bb9ed38a8c23, + 0x57f869667f6dfdbd, + 0xe9ba1b3e90f2e889, + 0x1c64c90821c44cdc, + 0x0a5e6f78289fd24b, +]); + +/// 1 / ROOT_OF_UNITY mod q +/// `0x1a8c636e293fe9928f85aa6ec68f950ebb57e3f0502dd05667c990c1c2f57128c77768be1824fd3f60869f410287a1879ec16a35ca69b6fb` + +const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([ + 0x9ec16a35ca69b6fb, + 0x60869f410287a187, + 0xc77768be1824fd3f, + 0x67c990c1c2f57128, + 0xbb57e3f0502dd056, + 0x8f85aa6ec68f950e, + 0x1a8c636e293fe992, +]); + +/// 1 / 2 mod q +/// `0x12000000000012000098700006bfb8725401e53b7a1c9337a21fcd2e3d45363df253baff470bbfeb4e53f42eb002857a0ffffe6980000001` +const TWO_INV: Fq = Fq::from_raw([ + 0x0ffffe6980000001, + 0x4e53f42eb002857a, + 0xf253baff470bbfeb, + 0xa21fcd2e3d45363d, + 0x5401e53b7a1c9337, + 0x0098700006bfb872, + 0x1200000000001200, +]); + +/// GENERATOR^{2^s} where t * 2^s + 1 = q with t odd. In other words, this is a t root of unity. +/// 0x657946fe07116ceca983fe28713a2b257ab7a7866c95121e727f3776c3e84cb0a14f6a7f83f8cdaeadb479c657bdf2de4589640faf72e67 +const DELTA: Fq = Fq::from_raw([ + 0xe4589640faf72e67, + 0xeadb479c657bdf2d, + 0x0a14f6a7f83f8cda, + 0xe727f3776c3e84cb, + 0x57ab7a7866c95121, + 0xca983fe28713a2b2, + 0x657946fe07116ce, +]); + +/// `ZETA^3 = 1 mod q` where `ZETA^2 != 1 mod q` +/// `0x9000000000006c000392a0001afee1c9500792ae3039253e641ba35817a29ffaf50be000032cfffffffe` + +const ZETA: Fq = Fq::from_raw([ + 0xe000032cfffffffe, + 0xa35817a29ffaf50b, + 0x92ae3039253e641b, + 0xa0001afee1c95007, + 0x000000006c000392, + 0x0000000000009000, + 0x0000000000000000, +]); + +use crate::{ + extend_field_legendre, field_arithmetic_7_limbs, field_bits, impl_add_binop_specify_impl, + impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, + impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_field, impl_from_u64, + impl_from_uniform_bytes, impl_prime_field, impl_serde_object, impl_sub_binop_specify_output, + impl_sum_prod, pow_vartime, +}; +impl_binops_additive!(Fq, Fq); +impl_binops_multiplicative!(Fq, Fq); +impl_add_binop_specify_impl!(Fq); +impl_field!(Fq, sparse); +impl_serde_object!(Fq); +impl_prime_field!(Fq, ReprFq, le); +impl_sum_prod!(Fq); +extend_field_legendre!(Fq); +impl_from_u64!(Fq); +impl_from_uniform_bytes!(Fq, 64); +impl_from_uniform_bytes!(Fq, 72); +impl_from_uniform_bytes!(Fq, 112); + +field_arithmetic_7_limbs!(Fq, MODULUS, INV, sparse); + +#[cfg(target_pointer_width = "64")] +field_bits!(Fq); +#[cfg(not(target_pointer_width = "64"))] +field_bits!(Fq); + +impl Fq { + fn sqrt(&self) -> CtOption { + /// `(t - 1) // 2` where t * 2^s + 1 = q with t odd. + const T_MINUS1_OVER2: [u64; 7] = [ + 0xb002857a0ffffe69, + 0x470bbfeb4e53f42e, + 0x3d45363df253baff, + 0x7a1c9337a21fcd2e, + 0x06bfb8725401e53b, + 0x0000120000987000, + 0x0000000012000000, + ]; + ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) + } +} + +#[derive(Clone, Copy, Debug)] +/// Canonical little-endian representation of a `Fq` element. +pub struct ReprFq { + pub repr: [u8; Fq::SIZE], +} + +impl ReprFq { + /// Returns an iterator over the bytes of the canonical representation of the element. + pub fn iter(&self) -> Iter<'_, u8> { + self.repr.iter() + } +} + +impl Default for ReprFq { + fn default() -> Self { + ReprFq { + repr: [0u8; Fq::SIZE], + } + } +} + +impl AsRef<[u8]> for ReprFq { + fn as_ref(&self) -> &[u8] { + self.repr.as_ref() + } +} + +impl AsMut<[u8]> for ReprFq { + fn as_mut(&mut self) -> &mut [u8] { + self.repr.as_mut() + } +} +impl From<[u8; Fq::SIZE]> for ReprFq { + fn from(repr: [u8; Fq::SIZE]) -> Self { + Self { repr } + } +} + +impl From for [u8; Fq::SIZE] { + fn from(repr: ReprFq) -> Self { + repr.repr + } +} + +impl core::ops::Index for ReprFq { + type Output = u8; + + fn index(&self, index: usize) -> &Self::Output { + &self.repr[index] + } +} + +impl core::ops::Index> for ReprFq { + type Output = [u8]; + + fn index(&self, index: core::ops::Range) -> &Self::Output { + &self.repr[index] + } +} + +#[cfg(test)] +mod test { + use super::*; + crate::field_testing_suite!(Fq, "field_arithmetic"); + crate::field_testing_suite!(Fq, "conversion"); + crate::field_testing_suite!(Fq, "serialization"); + crate::field_testing_suite!(Fq, "quadratic_residue"); + crate::field_testing_suite!(Fq, "bits"); + crate::field_testing_suite!(Fq, "serialization_check"); + crate::field_testing_suite!(Fq, "constants", MODULUS_STR); + crate::field_testing_suite!(Fq, "sqrt"); + crate::field_testing_suite!(Fq, "zeta"); + // crate::field_testing_suite!(Fq, "from_uniform_bytes", 64, 72); + crate::field_testing_suite!(Fq, "from_uniform_bytes", 64); +} diff --git a/src/pluto_eris/mod.rs b/src/pluto_eris/mod.rs index 72118ca3..c7391bac 100644 --- a/src/pluto_eris/mod.rs +++ b/src/pluto_eris/mod.rs @@ -7,9 +7,512 @@ //! Pairing constants derivation: https://github.com/John-Gong-Math/pluto_eris/blob/main/pluto_pairing.ipynb mod curve; mod engine; -mod fields; +mod fp; +mod fp12; +mod fp2; +mod fp6; +mod fq; pub use curve::*; pub use engine::*; -pub use fields::fp::*; -pub use fields::fq::*; +pub use fp::*; +pub use fq::*; + +#[macro_export] +macro_rules! field_arithmetic_7_limbs { + ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => { + impl From<$field> for [u64; NUM_LIMBS] { + fn from(elt: $field) -> [u64; NUM_LIMBS] { + $field::montgomery_reduce(&[ + elt.0[0], elt.0[1], elt.0[2], elt.0[3], elt.0[4], elt.0[5], elt.0[6], 0, 0, 0, + 0, 0, 0, 0, + ]) + .0 + } + } + + $crate::field_specific_7_limbs!($field, $modulus, $inv, $field_type); + impl $field { + const fn montgomery_form(val: [u64; NUM_LIMBS], r: $field) -> $field { + let (r0, carry) = mac(0, val[0], r.0[0], 0); + let (r1, carry) = mac(0, val[0], r.0[1], carry); + let (r2, carry) = mac(0, val[0], r.0[2], carry); + let (r3, carry) = mac(0, val[0], r.0[3], carry); + let (r4, carry) = mac(0, val[0], r.0[4], carry); + let (r5, carry) = mac(0, val[0], r.0[5], carry); + let (r6, r7) = mac(0, val[0], r.0[6], carry); + + let (r1, carry) = mac(r1, val[1], r.0[0], 0); + let (r2, carry) = mac(r2, val[1], r.0[1], carry); + let (r3, carry) = mac(r3, val[1], r.0[2], carry); + let (r4, carry) = mac(r4, val[1], r.0[3], carry); + let (r5, carry) = mac(r5, val[1], r.0[4], carry); + let (r6, carry) = mac(r6, val[1], r.0[5], carry); + let (r7, r8) = mac(r7, val[1], r.0[6], carry); + + let (r2, carry) = mac(r2, val[2], r.0[0], 0); + let (r3, carry) = mac(r3, val[2], r.0[1], carry); + let (r4, carry) = mac(r4, val[2], r.0[2], carry); + let (r5, carry) = mac(r5, val[2], r.0[3], carry); + let (r6, carry) = mac(r6, val[2], r.0[4], carry); + let (r7, carry) = mac(r7, val[2], r.0[5], carry); + let (r8, r9) = mac(r8, val[2], r.0[6], carry); + + let (r3, carry) = mac(r3, val[3], r.0[0], 0); + let (r4, carry) = mac(r4, val[3], r.0[1], carry); + let (r5, carry) = mac(r5, val[3], r.0[2], carry); + let (r6, carry) = mac(r6, val[3], r.0[3], carry); + let (r7, carry) = mac(r7, val[3], r.0[4], carry); + let (r8, carry) = mac(r8, val[3], r.0[5], carry); + let (r9, r10) = mac(r9, val[3], r.0[6], carry); + + let (r4, carry) = mac(r4, val[4], r.0[0], 0); + let (r5, carry) = mac(r5, val[4], r.0[1], carry); + let (r6, carry) = mac(r6, val[4], r.0[2], carry); + let (r7, carry) = mac(r7, val[4], r.0[3], carry); + let (r8, carry) = mac(r8, val[4], r.0[4], carry); + let (r9, carry) = mac(r9, val[4], r.0[5], carry); + let (r10, r11) = mac(r10, val[4], r.0[6], carry); + + let (r5, carry) = mac(r5, val[5], r.0[0], 0); + let (r6, carry) = mac(r6, val[5], r.0[1], carry); + let (r7, carry) = mac(r7, val[5], r.0[2], carry); + let (r8, carry) = mac(r8, val[5], r.0[3], carry); + let (r9, carry) = mac(r9, val[5], r.0[4], carry); + let (r10, carry) = mac(r10, val[5], r.0[5], carry); + let (r11, r12) = mac(r11, val[5], r.0[6], carry); + + let (r6, carry) = mac(r6, val[6], r.0[0], 0); + let (r7, carry) = mac(r7, val[6], r.0[1], carry); + let (r8, carry) = mac(r8, val[6], r.0[2], carry); + let (r9, carry) = mac(r9, val[6], r.0[3], carry); + let (r10, carry) = mac(r10, val[6], r.0[4], carry); + let (r11, carry) = mac(r11, val[6], r.0[5], carry); + let (r12, r13) = mac(r12, val[6], r.0[6], carry); + + // Montgomery reduction + 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, carry) = mac(r4, k, MODULUS.0[4], carry); + let (r5, carry) = mac(r5, k, MODULUS.0[5], carry); + let (r6, carry) = mac(r6, k, MODULUS.0[6], carry); + let (r7, carry2) = adc(r7, 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, carry) = mac(r5, k, MODULUS.0[4], carry); + let (r6, carry) = mac(r6, k, MODULUS.0[5], carry); + let (r7, carry) = mac(r7, k, MODULUS.0[6], carry); + let (r8, carry2) = adc(r8, 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, carry) = mac(r6, k, MODULUS.0[4], carry); + let (r7, carry) = mac(r7, k, MODULUS.0[5], carry); + let (r8, carry) = mac(r8, k, MODULUS.0[6], carry); + let (r9, carry2) = adc(r9, 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, carry) = mac(r7, k, MODULUS.0[4], carry); + let (r8, carry) = mac(r8, k, MODULUS.0[5], carry); + let (r9, carry) = mac(r9, k, MODULUS.0[6], carry); + let (r10, carry2) = adc(r10, carry2, carry); + + let k = r4.wrapping_mul(INV); + let (_, carry) = mac(r4, k, MODULUS.0[0], 0); + let (r5, carry) = mac(r5, k, MODULUS.0[1], carry); + let (r6, carry) = mac(r6, k, MODULUS.0[2], carry); + let (r7, carry) = mac(r7, k, MODULUS.0[3], carry); + let (r8, carry) = mac(r8, k, MODULUS.0[4], carry); + let (r9, carry) = mac(r9, k, MODULUS.0[5], carry); + let (r10, carry) = mac(r10, k, MODULUS.0[6], carry); + let (r11, carry2) = adc(r11, carry2, carry); + + let k = r5.wrapping_mul(INV); + let (_, carry) = mac(r5, k, MODULUS.0[0], 0); + let (r6, carry) = mac(r6, k, MODULUS.0[1], carry); + let (r7, carry) = mac(r7, k, MODULUS.0[2], carry); + let (r8, carry) = mac(r8, k, MODULUS.0[3], carry); + let (r9, carry) = mac(r9, k, MODULUS.0[4], carry); + let (r10, carry) = mac(r10, k, MODULUS.0[5], carry); + let (r11, carry) = mac(r11, k, MODULUS.0[6], carry); + let (r12, carry2) = adc(r12, carry2, carry); + + let k = r6.wrapping_mul(INV); + let (_, carry) = mac(r6, k, MODULUS.0[0], 0); + let (r7, carry) = mac(r7, k, MODULUS.0[1], carry); + let (r8, carry) = mac(r8, k, MODULUS.0[2], carry); + let (r9, carry) = mac(r9, k, MODULUS.0[3], carry); + let (r10, carry) = mac(r10, k, MODULUS.0[4], carry); + let (r11, carry) = mac(r11, k, MODULUS.0[5], carry); + let (r12, carry) = mac(r12, k, MODULUS.0[6], carry); + let (r13, carry2) = adc(r13, carry2, carry); + + // Result may be within MODULUS of the correct value + let (d0, borrow) = sbb(r7, MODULUS.0[0], 0); + let (d1, borrow) = sbb(r8, MODULUS.0[1], borrow); + let (d2, borrow) = sbb(r9, MODULUS.0[2], borrow); + let (d3, borrow) = sbb(r10, MODULUS.0[3], borrow); + let (d4, borrow) = sbb(r11, MODULUS.0[4], borrow); + let (d5, borrow) = sbb(r12, MODULUS.0[5], borrow); + let (d6, borrow) = sbb(r13, MODULUS.0[6], borrow); + let (_, borrow) = sbb(carry2, 0, borrow); + 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, carry) = adc(d3, MODULUS.0[3] & borrow, carry); + let (d4, carry) = adc(d4, MODULUS.0[4] & borrow, carry); + let (d5, carry) = adc(d5, MODULUS.0[5] & borrow, carry); + let (d6, _) = adc(d6, MODULUS.0[6] & borrow, carry); + + $field([d0, d1, d2, d3, d4, d5, d6]) + } + + /// Doubles this field element. + #[inline] + pub const fn double(&self) -> $field { + self.add(self) + } + + /// 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, carry) = mac(0, self.0[0], self.0[3], carry); + let (r4, carry) = mac(0, self.0[0], self.0[4], carry); + let (r5, carry) = mac(0, self.0[0], self.0[5], carry); + let (r6, r7) = mac(0, self.0[0], self.0[6], carry); + + let (r3, carry) = mac(r3, self.0[1], self.0[2], 0); + let (r4, carry) = mac(r4, self.0[1], self.0[3], carry); + let (r5, carry) = mac(r5, self.0[1], self.0[4], carry); + let (r6, carry) = mac(r6, self.0[1], self.0[5], carry); + let (r7, r8) = mac(r7, self.0[1], self.0[6], carry); + + let (r5, carry) = mac(r5, self.0[2], self.0[3], 0); + let (r6, carry) = mac(r6, self.0[2], self.0[4], carry); + let (r7, carry) = mac(r7, self.0[2], self.0[5], carry); + let (r8, r9) = mac(r8, self.0[2], self.0[6], carry); + + let (r7, carry) = mac(r7, self.0[3], self.0[4], 0); + let (r8, carry) = mac(r8, self.0[3], self.0[5], carry); + let (r9, r10) = mac(r9, self.0[3], self.0[6], carry); + + let (r9, carry) = mac(r9, self.0[4], self.0[5], 0); + let (r10, r11) = mac(r10, self.0[4], self.0[6], carry); + + let (r11, r12) = mac(r11, self.0[5], self.0[6], 0); + + let r13 = r12 >> 63; + let r12 = (r12 << 1) | (r11 >> 63); + let r11 = (r11 << 1) | (r10 >> 63); + let r10 = (r10 << 1) | (r9 >> 63); + let r9 = (r9 << 1) | (r8 >> 63); + let r8 = (r8 << 1) | (r7 >> 63); + let r7 = (r7 << 1) | (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, carry) = adc(0, r7, carry); + let (r8, carry) = mac(r8, self.0[4], self.0[4], carry); + let (r9, carry) = adc(0, r9, carry); + let (r10, carry) = mac(r10, self.0[5], self.0[5], carry); + let (r11, carry) = adc(0, r11, carry); + let (r12, carry) = mac(r12, self.0[6], self.0[6], carry); + let (r13, _) = adc(0, r13, carry); + + $field::montgomery_reduce(&[ + r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, + ]) + } + + /// 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, carry) = mac(0, self.0[0], rhs.0[3], carry); + let (r4, carry) = mac(0, self.0[0], rhs.0[4], carry); + let (r5, carry) = mac(0, self.0[0], rhs.0[5], carry); + let (r6, r7) = mac(0, self.0[0], rhs.0[6], 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, carry) = mac(r4, self.0[1], rhs.0[3], carry); + let (r5, carry) = mac(r5, self.0[1], rhs.0[4], carry); + let (r6, carry) = mac(r6, self.0[1], rhs.0[5], carry); + let (r7, r8) = mac(r7, self.0[1], rhs.0[6], 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, carry) = mac(r5, self.0[2], rhs.0[3], carry); + let (r6, carry) = mac(r6, self.0[2], rhs.0[4], carry); + let (r7, carry) = mac(r7, self.0[2], rhs.0[5], carry); + let (r8, r9) = mac(r8, self.0[2], rhs.0[6], 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, carry) = mac(r6, self.0[3], rhs.0[3], carry); + let (r7, carry) = mac(r7, self.0[3], rhs.0[4], carry); + let (r8, carry) = mac(r8, self.0[3], rhs.0[5], carry); + let (r9, r10) = mac(r9, self.0[3], rhs.0[6], carry); + + let (r4, carry) = mac(r4, self.0[4], rhs.0[0], 0); + let (r5, carry) = mac(r5, self.0[4], rhs.0[1], carry); + let (r6, carry) = mac(r6, self.0[4], rhs.0[2], carry); + let (r7, carry) = mac(r7, self.0[4], rhs.0[3], carry); + let (r8, carry) = mac(r8, self.0[4], rhs.0[4], carry); + let (r9, carry) = mac(r9, self.0[4], rhs.0[5], carry); + let (r10, r11) = mac(r10, self.0[4], rhs.0[6], carry); + + let (r5, carry) = mac(r5, self.0[5], rhs.0[0], 0); + let (r6, carry) = mac(r6, self.0[5], rhs.0[1], carry); + let (r7, carry) = mac(r7, self.0[5], rhs.0[2], carry); + let (r8, carry) = mac(r8, self.0[5], rhs.0[3], carry); + let (r9, carry) = mac(r9, self.0[5], rhs.0[4], carry); + let (r10, carry) = mac(r10, self.0[5], rhs.0[5], carry); + let (r11, r12) = mac(r11, self.0[5], rhs.0[6], carry); + + let (r6, carry) = mac(r6, self.0[6], rhs.0[0], 0); + let (r7, carry) = mac(r7, self.0[6], rhs.0[1], carry); + let (r8, carry) = mac(r8, self.0[6], rhs.0[2], carry); + let (r9, carry) = mac(r9, self.0[6], rhs.0[3], carry); + let (r10, carry) = mac(r10, self.0[6], rhs.0[4], carry); + let (r11, carry) = mac(r11, self.0[6], rhs.0[5], carry); + let (r12, r13) = mac(r12, self.0[6], rhs.0[6], carry); + + $field::montgomery_reduce(&[ + r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, + ]) + } + + /// 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); + let (d4, borrow) = sbb(self.0[4], rhs.0[4], borrow); + let (d5, borrow) = sbb(self.0[5], rhs.0[5], borrow); + let (d6, borrow) = sbb(self.0[6], rhs.0[6], 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, carry) = adc(d3, $modulus.0[3] & borrow, carry); + let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); + let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); + let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); + + $field([d0, d1, d2, d3, d4, d5, d6]) + } + + /// 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, borrow) = sbb($modulus.0[3], self.0[3], borrow); + let (d4, borrow) = sbb($modulus.0[4], self.0[4], borrow); + let (d5, borrow) = sbb($modulus.0[5], self.0[5], borrow); + let (d6, _) = sbb($modulus.0[6], self.0[6], 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] + | self.0[4] + | self.0[5] + | self.0[6]) + == 0) as u64) + .wrapping_sub(1); + + $field([ + d0 & mask, + d1 & mask, + d2 & mask, + d3 & mask, + d4 & mask, + d5 & mask, + d6 & mask, + ]) + } + } + }; +} + +#[macro_export] +macro_rules! field_specific_7_limbs { + ($field:ident, $modulus:ident, $inv:ident, sparse) => { + impl $field { + /// 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, carry) = adc(self.0[3], rhs.0[3], carry); + let (d4, carry) = adc(self.0[4], rhs.0[4], carry); + let (d5, carry) = adc(self.0[5], rhs.0[5], carry); + let (d6, _) = adc(self.0[6], rhs.0[6], carry); + + // Attempt to subtract the modulus, to ensure the value + // is smaller than the modulus. + (&$field([d0, d1, d2, d3, d4, d5, d6])).sub(&$modulus) + } + + #[inline(always)] + pub(crate) const fn montgomery_reduce(r: &[u64; 14]) -> $field { + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + + let k = r[0].wrapping_mul($inv); + let (_, carry) = mac(r[0], k, $modulus.0[0], 0); + let (r1, carry) = mac(r[1], k, $modulus.0[1], carry); + let (r2, carry) = mac(r[2], k, $modulus.0[2], carry); + let (r3, carry) = mac(r[3], k, $modulus.0[3], carry); + let (r4, carry) = mac(r[4], k, $modulus.0[4], carry); + let (r5, carry) = mac(r[5], k, $modulus.0[5], carry); + let (r6, carry) = mac(r[6], k, $modulus.0[6], carry); + let (r7, carry2) = adc(r[7], 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, carry) = mac(r5, k, $modulus.0[4], carry); + let (r6, carry) = mac(r6, k, $modulus.0[5], carry); + let (r7, carry) = mac(r7, k, $modulus.0[6], carry); + let (r8, carry2) = adc(r[8], 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, carry) = mac(r6, k, $modulus.0[4], carry); + let (r7, carry) = mac(r7, k, $modulus.0[5], carry); + let (r8, carry) = mac(r8, k, $modulus.0[6], carry); + let (r9, carry2) = adc(r[9], 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, carry) = mac(r7, k, $modulus.0[4], carry); + let (r8, carry) = mac(r8, k, $modulus.0[5], carry); + let (r9, carry) = mac(r9, k, $modulus.0[6], carry); + let (r10, carry2) = adc(r[10], carry2, carry); + + let k = r4.wrapping_mul($inv); + let (_, carry) = mac(r4, k, $modulus.0[0], 0); + let (r5, carry) = mac(r5, k, $modulus.0[1], carry); + let (r6, carry) = mac(r6, k, $modulus.0[2], carry); + let (r7, carry) = mac(r7, k, $modulus.0[3], carry); + let (r8, carry) = mac(r8, k, $modulus.0[4], carry); + let (r9, carry) = mac(r9, k, $modulus.0[5], carry); + let (r10, carry) = mac(r10, k, $modulus.0[6], carry); + let (r11, carry2) = adc(r[11], carry2, carry); + + let k = r5.wrapping_mul($inv); + let (_, carry) = mac(r5, k, $modulus.0[0], 0); + let (r6, carry) = mac(r6, k, $modulus.0[1], carry); + let (r7, carry) = mac(r7, k, $modulus.0[2], carry); + let (r8, carry) = mac(r8, k, $modulus.0[3], carry); + let (r9, carry) = mac(r9, k, $modulus.0[4], carry); + let (r10, carry) = mac(r10, k, $modulus.0[5], carry); + let (r11, carry) = mac(r11, k, $modulus.0[6], carry); + let (r12, carry2) = adc(r[12], carry2, carry); + + let k = r6.wrapping_mul($inv); + let (_, carry) = mac(r6, k, $modulus.0[0], 0); + let (r7, carry) = mac(r7, k, $modulus.0[1], carry); + let (r8, carry) = mac(r8, k, $modulus.0[2], carry); + let (r9, carry) = mac(r9, k, $modulus.0[3], carry); + let (r10, carry) = mac(r10, k, $modulus.0[4], carry); + let (r11, carry) = mac(r11, k, $modulus.0[5], carry); + let (r12, carry) = mac(r12, k, $modulus.0[6], carry); + let (r13, _) = adc(r[13], carry2, carry); + // Result may be within MODULUS of the correct value + (&$field([r7, r8, r9, r10, r11, r12, r13])).sub(&$modulus) + } + } + }; + ($field:ident, $modulus:ident, $inv:ident, dense) => { + impl $field { + /// 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, carry) = adc(self.0[3], rhs.0[3], carry); + let (d4, carry) = adc(self.0[4], rhs.0[4], carry); + let (d5, carry) = adc(self.0[5], rhs.0[5], carry); + let (d6, carry) = adc(self.0[6], rhs.0[6], carry); + + // Attempt to subtract the modulus, to ensure the value + // is smaller than the modulus. + let (d0, borrow) = sbb(d0, $modulus.0[0], 0); + let (d1, borrow) = sbb(d1, $modulus.0[1], borrow); + let (d2, borrow) = sbb(d2, $modulus.0[2], borrow); + let (d3, borrow) = sbb(d3, $modulus.0[3], borrow); + let (d4, borrow) = sbb(d4, $modulus.0[4], borrow); + let (d5, borrow) = sbb(d5, $modulus.0[5], borrow); + let (_, borrow) = sbb(carry, 0, borrow); + + 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, carry) = adc(d3, $modulus.0[3] & borrow, carry); + let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); + let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); + let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); + + $field([d0, d1, d2, d3, d4, d5, d6]) + } + } + }; +} diff --git a/src/secp256k1/curve.rs b/src/secp256k1/curve.rs index d4cdd659..ff872adc 100644 --- a/src/secp256k1/curve.rs +++ b/src/secp256k1/curve.rs @@ -2,7 +2,6 @@ use crate::derive::curve::{IDENTITY_MASK, IDENTITY_SHIFT, SIGN_MASK, SIGN_SHIFT} use crate::ff::WithSmallOrderMulGroup; use crate::ff::{Field, PrimeField}; use crate::group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding}; -use crate::hash_to_curve::{sswu_hash_to_curve, sswu_hash_to_curve_secp256k1}; use crate::secp256k1::Fp; use crate::secp256k1::Fq; use crate::{Coordinates, CurveAffine, CurveExt}; @@ -10,6 +9,7 @@ use core::cmp; use core::fmt::Debug; use core::iter::Sum; use core::ops::{Add, Mul, Neg, Sub}; +use group::cofactor::CofactorGroup; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -65,7 +65,7 @@ new_curve_impl!( SECP_A, SECP_B, "secp256k1", - |curve_id, domain_prefix| sswu_hash_to_curve_secp256k1(curve_id, domain_prefix), + |domain_prefix| hash_to_curve(domain_prefix), ); impl Secp256k1 { @@ -80,6 +80,15 @@ impl Secp256k1 { ]); } +#[allow(clippy::type_complexity)] +pub(crate) fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box Secp256k1 + 'a> { + Box::new(move |message| { + let r0 = IsoSecp256k1::hash_to_curve(domain_prefix)(message); + let r1 = iso_map_secp256k1(r0); + r1.clear_cofactor() + }) +} + // Simplified SWU for AB == 0 // // E': y'^2 = x'^3 + A' * x' + B', where @@ -133,7 +142,7 @@ new_curve_impl!( ISO_SECP_A, ISO_SECP_B, "secp256k1", - |curve_id, domain_prefix| sswu_hash_to_curve(curve_id, domain_prefix, IsoSecp256k1::SSWU_Z), + |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, IsoSecp256k1::default_hash_to_curve_suite()), ); impl IsoSecp256k1 { @@ -146,6 +155,15 @@ impl IsoSecp256k1 { 0xffffffffffffffff, 0xffffffffffffffff, ]); + + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite + { + crate::hash_to_curve::Suite::::new( + b"secp256k1_XMD:SHA-256_SSWU_RO_", + Self::SSWU_Z, + crate::hash_to_curve::Method::SSWU, + ) + } } /// 3-Isogeny Map for Secp256k1 @@ -284,4 +302,66 @@ mod test { SECP_GENERATOR_Y, Fq::MODULUS ); + + #[test] + fn test_hash_to_curve() { + struct Test { + msg: &'static [u8], + expect: C, + } + + impl Test { + fn new(msg: &'static [u8], expect: C) -> Self { + Self { msg, expect } + } + + fn run(&self, domain_prefix: &str) { + // default + let r0 = C::CurveExt::hash_to_curve(domain_prefix)(self.msg); + assert_eq!(r0.to_affine(), self.expect); + } + } + + let tests = [ + Test::::new( + b"", + crate::tests::point_from_hex( + "c1cae290e291aee617ebaef1be6d73861479c48b841eaba9b7b5852ddfeb1346", + "64fa678e07ae116126f08b022a94af6de15985c996c3a91b64c406a960e51067", + ), + ), + Test::::new( + b"abc", + crate::tests::point_from_hex( + "3377e01eab42db296b512293120c6cee72b6ecf9f9205760bd9ff11fb3cb2c4b", + "7f95890f33efebd1044d382a01b1bee0900fb6116f94688d487c6c7b9c8371f6", + ), + ), + Test::::new( + b"abcdef0123456789", + crate::tests::point_from_hex( + "bac54083f293f1fe08e4a70137260aa90783a5cb84d3f35848b324d0674b0e3a", + "4436476085d4c3c4508b60fcf4389c40176adce756b398bdee27bca19758d828", + ), + ), + Test::::new( + b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + crate::tests::point_from_hex( + "e2167bc785333a37aa562f021f1e881defb853839babf52a7f72b102e41890e9", + "f2401dd95cc35867ffed4f367cd564763719fbc6a53e969fb8496a1e6685d873", + ), + ), // + Test::::new( + b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + crate::tests::point_from_hex( + "e3c8d35aaaf0b9b647e88a0a0a7ee5d5bed5ad38238152e4e6fd8c1f8cb7c998", + "8446eeb6181bf12f56a9d24e262221cc2f0c4725c7e3803024b5888ee5823aa6", + ), + ), + ]; + + tests.iter().for_each(|test| { + test.run("QUUX-V01-CS02-with-"); + }); + } } diff --git a/src/secp256k1/fp.rs b/src/secp256k1/fp.rs index 415017fa..419e4ca2 100644 --- a/src/secp256k1/fp.rs +++ b/src/secp256k1/fp.rs @@ -1,11 +1,6 @@ use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output, - impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, -}; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::serde::SerdeObject; use core::convert::TryInto; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; @@ -17,11 +12,15 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// `p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f` /// /// is the base field of the secp256k1 curve. -// The internal representation of this type is four 64-bit unsigned -// integers in little-endian order. `Fp` values are always in -// Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fp(pub(crate) [u64; 4]); + +// Number of 64 bit limbs to represent the field element +pub(crate) const NUM_BITS: u32 = 256; + +// Inverter constant +const BYIL: usize = 6; + +// Jabobi constant +const JACOBI_L: usize = 5; #[cfg(feature = "derive_serde")] crate::serialize_deserialize_32_byte_primefield!(Fp); @@ -39,6 +38,9 @@ const MODULUS: Fp = Fp([ /// It's derived with SageMath with: `GF(MODULUS).primitive_element()`. const MULTIPLICATIVE_GENERATOR: Fp = Fp::from_raw([0x03, 0x00, 0x00, 0x00]); +/// Size of the 2-adic sub-group of the field. +const S: u32 = 1; + /// The modulus as u32 limbs. #[cfg(not(target_pointer_width = "64"))] const MODULUS_LIMBS_32: [u32; 8] = [ @@ -111,62 +113,33 @@ const ROOT_OF_UNITY_INV: Fp = Fp([ 0xffffffffffffffffu64, ]); +use crate::{ + extend_field_legendre, field_arithmetic, field_bits, field_specific, + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_field, impl_from_u64, impl_from_uniform_bytes, + impl_prime_field, impl_serde_object, impl_sub_binop_specify_output, impl_sum_prod, pow_vartime, +}; impl_binops_additive!(Fp, Fp); impl_binops_multiplicative!(Fp, Fp); -field_common!( - Fp, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_from_u64!(Fp, R2); -field_arithmetic!(Fp, MODULUS, INV, dense); +impl_add_binop_specify_impl!(Fp); +impl_field!(Fp, dense); +impl_serde_object!(Fp); +impl_prime_field!(Fp, [u8; 32], le); impl_sum_prod!(Fp); +extend_field_legendre!(Fp); +impl_from_uniform_bytes!(Fp, 64); +impl_from_uniform_bytes!(Fp, 48); +impl_from_u64!(Fp); + +field_arithmetic!(Fp, MODULUS, INV, dense); #[cfg(target_pointer_width = "64")] -field_bits!(Fp, MODULUS); +field_bits!(Fp); #[cfg(not(target_pointer_width = "64"))] -field_bits!(Fp, MODULUS, MODULUS_LIMBS_32); +field_bits!(Fp); impl Fp { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fp { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - /// Computes the square root of this element, if it exists. fn sqrt(&self) -> CtOption { let tmp = self.pow([ @@ -178,118 +151,8 @@ impl ff::Field for Fp { CtOption::new(tmp, tmp.square().ct_eq(self)) } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - - fn pow_vartime>(&self, exp: S) -> Self { - let mut res = Self::one(); - let mut found_one = false; - for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { - if found_one { - res = res.square(); - } - - if ((*e >> i) & 1) == 1 { - found_one = true; - res *= self; - } - } - } - res - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -impl ff::PrimeField for Fp { - type Repr = [u8; 32]; - - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR; - const TWO_INV: Self = TWO_INV; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const DELTA: Self = DELTA; - const NUM_BITS: u32 = 256; - const CAPACITY: u32 = 255; - const S: u32 = 1; - - 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 { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn from_u128(v: u128) -> Self { - Self::from_raw([v as u64, (v >> 64) as u64, 0, 0]) - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } } -impl FromUniformBytes<64> for Fp { - /// Converts a 512-bit little endian integer into - /// an `Fp` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - 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()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fp { - const ZETA: Self = ZETA; -} - -extend_field_legendre!(Fp); - #[cfg(test)] mod test { use super::*; @@ -302,4 +165,5 @@ mod test { crate::field_testing_suite!(Fp, "constants", MODULUS_STR); crate::field_testing_suite!(Fp, "sqrt"); crate::field_testing_suite!(Fp, "zeta"); + crate::field_testing_suite!(Fp, "from_uniform_bytes", 48, 64); } diff --git a/src/secp256k1/fq.rs b/src/secp256k1/fq.rs index ba7351ca..23fd633d 100644 --- a/src/secp256k1/fq.rs +++ b/src/secp256k1/fq.rs @@ -1,12 +1,6 @@ use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output, - impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, -}; -use core::convert::TryInto; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::serde::SerdeObject; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; use rand::RngCore; @@ -17,11 +11,15 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// `q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141` /// /// is the scalar field of the secp256k1 curve. -// The internal representation of this type is four 64-bit unsigned -// integers in little-endian order. `Fq` values are always in -// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fq(pub(crate) [u64; 4]); + +// Number of 64 bit limbs to represent the field element +pub(crate) const NUM_BITS: u32 = 256; + +// Inverter constant +const BYIL: usize = 6; + +// Jabobi constant +const JACOBI_L: usize = 5; #[cfg(feature = "derive_serde")] crate::serialize_deserialize_32_byte_primefield!(Fq); @@ -79,7 +77,10 @@ const R3: Fq = Fq([ /// `GENERATOR = 7 mod r` is a generator of the `q - 1` order multiplicative /// subgroup, or in other words a primitive root of the field. /// It's derived with SageMath with: `GF(MODULUS).primitive_element()`. -const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00]); +const MULTIPLICATIVE_GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00]); + +/// Size of the 2-adic sub-group of the field. +const S: u32 = 6; /// GENERATOR^t where t * 2^s + 1 = r with t odd. In other words, this is a 2^s root of unity. /// `0xc1dc060e7a91986df9879a3fbc483a898bdeab680756045992f4b5402b052f2` @@ -106,13 +107,6 @@ const TWO_INV: Fq = Fq::from_raw([ 0x7fffffffffffffff, ]); -const ZETA: Fq = Fq::from_raw([ - 0xdf02967c1b23bd72, - 0x122e22ea20816678, - 0xa5261c028812645a, - 0x5363ad4cc05c30e0, -]); - /// Generator of the t-order multiplicative subgroup. /// Computed by exponentiating Self::MULTIPLICATIVE_GENERATOR by 2^s, where s is Self::S. /// `0x0000000000000000000cbc21fe4561c8d63b78e780e1341e199417c8c0bb7601` @@ -123,180 +117,70 @@ const DELTA: Fq = Fq([ 0x1900960de4b7929c, ]); +const ZETA: Fq = Fq::from_raw([ + 0xdf02967c1b23bd72, + 0x122e22ea20816678, + 0xa5261c028812645a, + 0x5363ad4cc05c30e0, +]); + +use crate::{ + extend_field_legendre, field_arithmetic, field_bits, field_specific, + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_field, impl_from_u64, impl_from_uniform_bytes, + impl_prime_field, impl_serde_object, impl_sub_binop_specify_output, impl_sum_prod, pow_vartime, +}; impl_binops_additive!(Fq, Fq); impl_binops_multiplicative!(Fq, Fq); -field_common!( - Fq, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_from_u64!(Fq, R2); -field_arithmetic!(Fq, MODULUS, INV, dense); +impl_add_binop_specify_impl!(Fq); +impl_field!(Fq, dense); +impl_serde_object!(Fq); +impl_prime_field!(Fq, [u8; 32], le); impl_sum_prod!(Fq); +extend_field_legendre!(Fq); +impl_from_uniform_bytes!(Fq, 64); +impl_from_uniform_bytes!(Fq, 48); +impl_from_u64!(Fq); + +// fn pow_vartime>(&self, exp: S) -> Self { +// let mut res = Self::one(); +// let mut found_one = false; +// for e in exp.as_ref().iter().rev() { +// for i in (0..64).rev() { +// if found_one { +// res = res.square(); +// } + +// if ((*e >> i) & 1) == 1 { +// found_one = true; +// res *= self; +// } +// } +// } +// res +// } + +field_arithmetic!(Fq, MODULUS, INV, dense); #[cfg(target_pointer_width = "64")] -field_bits!(Fq, MODULUS); +field_bits!(Fq); #[cfg(not(target_pointer_width = "64"))] -field_bits!(Fq, MODULUS, MODULUS_LIMBS_32); +field_bits!(Fq); impl Fq { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fq { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - - fn pow_vartime>(&self, exp: S) -> Self { - let mut res = Self::one(); - let mut found_one = false; - for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { - if found_one { - res = res.square(); - } - - if ((*e >> i) & 1) == 1 { - found_one = true; - res *= self; - } - } - } - res - } - fn sqrt(&self) -> CtOption { - let tm1d2 = [ + let t = [ 0x777fa4bd19a06c82, 0xfd755db9cd5e9140, 0xffffffffffffffff, 0x01ffffffffffffff, ]; - ff::helpers::sqrt_tonelli_shanks(self, tm1d2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -impl ff::PrimeField for Fq { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 256; - const CAPACITY: u32 = 255; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = 6; - - 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 { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq { - /// Converts a 512-bit little endian integer into - /// an `Fq` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - 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()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) + ff::helpers::sqrt_tonelli_shanks(self, t) } } -impl WithSmallOrderMulGroup<3> for Fq { - const ZETA: Self = ZETA; -} - -extend_field_legendre!(Fq); - #[cfg(test)] mod test { use super::*; @@ -309,4 +193,5 @@ mod test { crate::field_testing_suite!(Fq, "constants", MODULUS_STR); crate::field_testing_suite!(Fq, "sqrt"); crate::field_testing_suite!(Fq, "zeta"); + crate::field_testing_suite!(Fq, "from_uniform_bytes", 48, 64); } diff --git a/src/secp256r1/curve.rs b/src/secp256r1/curve.rs index c1e2fb0f..db2bc9cb 100644 --- a/src/secp256r1/curve.rs +++ b/src/secp256r1/curve.rs @@ -2,7 +2,6 @@ use crate::derive::curve::{IDENTITY_MASK, IDENTITY_SHIFT, SIGN_MASK, SIGN_SHIFT} use crate::ff::WithSmallOrderMulGroup; use crate::ff::{Field, PrimeField}; use crate::group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding}; -use crate::hash_to_curve::sswu_hash_to_curve; use crate::secp256r1::Fp; use crate::secp256r1::Fq; use crate::{Coordinates, CurveAffine, CurveExt}; @@ -76,19 +75,27 @@ new_curve_impl!( SECP_A, SECP_B, "secp256r1", - |curve_id, domain_prefix| sswu_hash_to_curve(curve_id, domain_prefix, Secp256r1::SSVDW_Z), + |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, Secp256r1::default_hash_to_curve_suite()), ); impl Secp256r1 { // Optimal Z with: // 0xffffffff00000001000000000000000000000000fffffffffffffffffffffff5 // Z = -10 (reference: ) - const SSVDW_Z: Fp = Fp::from_raw([ + const SSWU_Z: Fp = Fp::from_raw([ 0xfffffffffffffff5, 0x00000000ffffffff, 0x0000000000000000, 0xffffffff00000001, ]); + + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite { + crate::hash_to_curve::Suite::::new( + b"P256_XMD:SHA-256_SSWU_RO_", + Self::SSWU_Z, + crate::hash_to_curve::Method::SSWU, + ) + } } #[cfg(test)] @@ -107,4 +114,66 @@ mod test { SECP_GENERATOR_Y, Fq::MODULUS ); + + #[test] + fn test_hash_to_curve() { + struct Test { + msg: &'static [u8], + expect: C, + } + + impl Test { + fn new(msg: &'static [u8], expect: C) -> Self { + Self { msg, expect } + } + + fn run(&self, domain_prefix: &str) { + // default + let r0 = C::CurveExt::hash_to_curve(domain_prefix)(self.msg); + assert_eq!(r0.to_affine(), self.expect); + } + } + + let tests = [ + Test::::new( + b"", + crate::tests::point_from_hex( + "2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91c44247d3e4", + "8a7a74985cc5c776cdfe4b1f19884970453912e9d31528c060be9ab5c43e8415", + ), + ), + Test::::new( + b"abc", + crate::tests::point_from_hex( + "0bb8b87485551aa43ed54f009230450b492fead5f1cc91658775dac4a3388a0f", + "5c41b3d0731a27a7b14bc0bf0ccded2d8751f83493404c84a88e71ffd424212e", + ), + ), + Test::::new( + b"abcdef0123456789", + crate::tests::point_from_hex( + "65038ac8f2b1def042a5df0b33b1f4eca6bff7cb0f9c6c1526811864e544ed80", + "cad44d40a656e7aff4002a8de287abc8ae0482b5ae825822bb870d6df9b56ca3", + ), + ), + Test::::new( + b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + crate::tests::point_from_hex( + "4be61ee205094282ba8a2042bcb48d88dfbb609301c49aa8b078533dc65a0b5d", + "98f8df449a072c4721d241a3b1236d3caccba603f916ca680f4539d2bfb3c29e", + ), + ), // + Test::::new( + b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + crate::tests::point_from_hex( + "457ae2981f70ca85d8e24c308b14db22f3e3862c5ea0f652ca38b5e49cd64bc5", + "ecb9f0eadc9aeed232dabc53235368c1394c78de05dd96893eefa62b0f4757dc", + ), + ), + ]; + + tests.iter().for_each(|test| { + test.run("QUUX-V01-CS02-with-"); + }); + } } diff --git a/src/secp256r1/fp.rs b/src/secp256r1/fp.rs index bce80808..bdd8ce7a 100644 --- a/src/secp256r1/fp.rs +++ b/src/secp256r1/fp.rs @@ -1,11 +1,6 @@ use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output, - impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, -}; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::serde::SerdeObject; use core::convert::TryInto; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; @@ -17,11 +12,15 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// `p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff /// /// is the base field of the secp256r1 curve. -// The internal representation of this type is four 64-bit unsigned -// integers in little-endian order. `Fp` values are always in -// Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fp(pub(crate) [u64; 4]); + +// Number of 64 bit limbs to represent the field element +pub(crate) const NUM_BITS: u32 = 256; + +// Inverter constant +const BYIL: usize = 6; + +// Jabobi constant +const JACOBI_L: usize = 5; #[cfg(feature = "derive_serde")] crate::serialize_deserialize_32_byte_primefield!(Fp); @@ -39,6 +38,9 @@ const MODULUS: Fp = Fp([ /// It's derived with SageMath with: `GF(MODULUS).primitive_element()`. const MULTIPLICATIVE_GENERATOR: Fp = Fp::from_raw([0x06, 0x00, 0x00, 0x00]); +/// Size of the 2-adic sub-group of the field. +const S: u32 = 1; + /// The modulus as u32 limbs. #[cfg(not(target_pointer_width = "64"))] const MODULUS_LIMBS_32: [u32; 8] = [ @@ -129,62 +131,33 @@ const ROOT_OF_UNITY_INV: Fp = Fp::from_raw([ 0xffffffff00000001, ]); +use crate::{ + extend_field_legendre, field_arithmetic, field_bits, field_specific, + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_field, impl_from_u64, impl_from_uniform_bytes, + impl_prime_field, impl_serde_object, impl_sub_binop_specify_output, impl_sum_prod, pow_vartime, +}; impl_binops_additive!(Fp, Fp); impl_binops_multiplicative!(Fp, Fp); -field_common!( - Fp, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_from_u64!(Fp, R2); -field_arithmetic!(Fp, MODULUS, INV, dense); +impl_add_binop_specify_impl!(Fp); +impl_field!(Fp, dense); +impl_serde_object!(Fp); +impl_prime_field!(Fp, [u8; 32], le); impl_sum_prod!(Fp); +extend_field_legendre!(Fp); +impl_from_uniform_bytes!(Fp, 64); +impl_from_uniform_bytes!(Fp, 48); +impl_from_u64!(Fp); + +field_arithmetic!(Fp, MODULUS, INV, dense); #[cfg(target_pointer_width = "64")] -field_bits!(Fp, MODULUS); +field_bits!(Fp); #[cfg(not(target_pointer_width = "64"))] -field_bits!(Fp, MODULUS, MODULUS_LIMBS_32); +field_bits!(Fp); impl Fp { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fp { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - /// Computes the square root of this element, if it exists. fn sqrt(&self) -> CtOption { let tmp = self.pow([ @@ -196,118 +169,8 @@ impl ff::Field for Fp { CtOption::new(tmp, tmp.square().ct_eq(self)) } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - - fn pow_vartime>(&self, exp: S) -> Self { - let mut res = Self::one(); - let mut found_one = false; - for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { - if found_one { - res = res.square(); - } - - if ((*e >> i) & 1) == 1 { - found_one = true; - res *= self; - } - } - } - res - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -impl ff::PrimeField for Fp { - type Repr = [u8; 32]; - - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR; - const TWO_INV: Self = TWO_INV; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const DELTA: Self = DELTA; - const NUM_BITS: u32 = 256; - const CAPACITY: u32 = 255; - const S: u32 = 1; - - 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 { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn from_u128(v: u128) -> Self { - Self::from_raw([v as u64, (v >> 64) as u64, 0, 0]) - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } } -impl FromUniformBytes<64> for Fp { - /// Converts a 512-bit little endian integer into - /// an `Fp` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - 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()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fp { - const ZETA: Self = ZETA; -} - -extend_field_legendre!(Fp); - #[cfg(test)] mod test { use super::*; @@ -320,4 +183,5 @@ mod test { crate::field_testing_suite!(Fp, "constants", MODULUS_STR); crate::field_testing_suite!(Fp, "sqrt"); crate::field_testing_suite!(Fp, "zeta"); + crate::field_testing_suite!(Fp, "from_uniform_bytes", 48, 64); } diff --git a/src/secp256r1/fq.rs b/src/secp256r1/fq.rs index c6f1dd86..245a8080 100644 --- a/src/secp256r1/fq.rs +++ b/src/secp256r1/fq.rs @@ -1,6 +1,6 @@ use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb}; -use crate::extend_field_legendre; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; +use crate::serde::SerdeObject; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; use rand::RngCore; @@ -11,11 +11,15 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// `q = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551` /// /// is the scalar field of the secp256r1 curve. -// The internal representation of this type is four 64-bit unsigned -// integers in little-endian order. `Fq` values are always in -// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Fq(pub(crate) [u64; 4]); + +// Number of 64 bit limbs to represent the field element +pub(crate) const NUM_BITS: u32 = 256; + +// Inverter constant +const BYIL: usize = 6; + +// Jabobi constant +const JACOBI_L: usize = 5; #[cfg(feature = "derive_serde")] crate::serialize_deserialize_32_byte_primefield!(Fq); @@ -78,7 +82,10 @@ const R3: Fq = Fq([ /// `GENERATOR = 7 mod r` is a generator of the `q - 1` order multiplicative /// subgroup, or in other words a primitive root of the field. /// It's derived with SageMath with: `GF(MODULUS).primitive_element()`. -const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00]); +const MULTIPLICATIVE_GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00]); + +/// Size of the 2-adic sub-group of the field. +const S: u32 = 4; /// GENERATOR^t where t * 2^s + 1 = r with t odd. In other words, this is a 2^s root of unity. /// `ffc97f062a770992ba807ace842a3dfc1546cad004378daf0592d7fbb41e6602` @@ -118,185 +125,44 @@ const ZETA: Fq = Fq::from_raw([ const DELTA: Fq = Fq::from_raw([0x1e39a5057d81, 0, 0, 0]); use crate::{ - field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output, - impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod, + extend_field_legendre, field_arithmetic, field_bits, field_specific, + impl_add_binop_specify_impl, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_field, impl_from_u64, impl_from_uniform_bytes, + impl_prime_field, impl_serde_object, impl_sub_binop_specify_output, impl_sum_prod, pow_vartime, }; impl_binops_additive!(Fq, Fq); impl_binops_multiplicative!(Fq, Fq); -field_common!( - Fq, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_from_u64!(Fq, R2); -field_arithmetic!(Fq, MODULUS, INV, dense); +impl_add_binop_specify_impl!(Fq); +impl_field!(Fq, dense); +impl_serde_object!(Fq); +impl_prime_field!(Fq, [u8; 32], le); impl_sum_prod!(Fq); +extend_field_legendre!(Fq); +impl_from_uniform_bytes!(Fq, 64); +impl_from_uniform_bytes!(Fq, 48); +impl_from_u64!(Fq); +field_arithmetic!(Fq, MODULUS, INV, dense); #[cfg(target_pointer_width = "64")] -field_bits!(Fq, MODULUS); +field_bits!(Fq); #[cfg(not(target_pointer_width = "64"))] -field_bits!(Fq, MODULUS, MODULUS_LIMBS_32); +field_bits!(Fq); impl Fq { - pub const fn size() -> usize { - 32 - } -} - -impl ff::Field for Fq { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Returns the multiplicative inverse of the - /// element. If it is zero, the method fails. - fn invert(&self) -> CtOption { - self.invert() - } - - fn pow_vartime>(&self, exp: S) -> Self { - let mut res = Self::one(); - let mut found_one = false; - for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { - if found_one { - res = res.square(); - } - - if ((*e >> i) & 1) == 1 { - found_one = true; - res *= self; - } - } - } - res - } - fn sqrt(&self) -> CtOption { // 7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a - let tm1d2 = [ + let t = [ 0x279dce5617e3192a, 0xfde737d56d38bcf4, 0x07ffffffffffffff, 0x7fffffff8000000, ]; - ff::helpers::sqrt_tonelli_shanks(self, tm1d2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) + ff::helpers::sqrt_tonelli_shanks(self, t) } } -impl ff::PrimeField for Fq { - type Repr = [u8; 32]; - - const NUM_BITS: u32 = 256; - const CAPACITY: u32 = 255; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = 4; - - 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 { - let tmp: [u64; 4] = (*self).into(); - let mut res = [0; 32]; - res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); - - res - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr()[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq { - /// Converts a 512-bit little endian integer into - /// an `Fq` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - 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()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fq { - const ZETA: Self = ZETA; -} - -extend_field_legendre!(Fq); - #[cfg(test)] mod test { use super::*; @@ -308,4 +174,5 @@ mod test { crate::field_testing_suite!(Fq, "constants", MODULUS_STR); crate::field_testing_suite!(Fq, "sqrt"); crate::field_testing_suite!(Fq, "zeta"); + crate::field_testing_suite!(Fq, "from_uniform_bytes", 64); } diff --git a/src/secq256k1/curve.rs b/src/secq256k1/curve.rs index 6a7b0f33..1356d86e 100644 --- a/src/secq256k1/curve.rs +++ b/src/secq256k1/curve.rs @@ -3,7 +3,6 @@ use crate::ff::WithSmallOrderMulGroup; use crate::ff::{Field, PrimeField}; use crate::group::Curve; use crate::group::{prime::PrimeCurveAffine, Group, GroupEncoding}; -use crate::hash_to_curve::svdw_hash_to_curve; use crate::secp256k1::{Fp, Fq}; use crate::{ impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, @@ -48,7 +47,7 @@ new_curve_impl!( SECQ_A, SECQ_B, "secq256k1", - |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, Secq256k1::SVDW_Z), + |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, Secq256k1::default_hash_to_curve_suite()), ); impl group::cofactor::CofactorGroup for Secq256k1 { @@ -69,6 +68,14 @@ impl group::cofactor::CofactorGroup for Secq256k1 { impl Secq256k1 { const SVDW_Z: Fq = Fq::ONE; + + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite { + crate::hash_to_curve::Suite::::new( + b"secq256k1_XMD:SHA-256_SWDW_RO_", + Self::SVDW_Z, + crate::hash_to_curve::Method::SVDW, + ) + } } #[cfg(test)] diff --git a/src/tests/curve.rs b/src/tests/curve.rs index b89863cf..5cbf6dbb 100644 --- a/src/tests/curve.rs +++ b/src/tests/curve.rs @@ -235,20 +235,20 @@ macro_rules! curve_testing_suite { ($c: ident) => { assert!(bool::from( $c::from_bytes(&$c::identity().to_bytes()) - .unwrap() - .is_identity() + .unwrap() + .is_identity() )); assert!(bool::from( <$c as CurveExt>::AffineExt::from_uncompressed(&<$c as CurveExt>::AffineExt::identity().to_uncompressed()) - .unwrap() - .is_identity() + .unwrap() + .is_identity() )); assert!(bool::from( <$c as CurveExt>::AffineExt::from_bytes(&<$c as CurveExt>::AffineExt::identity().to_bytes()) - .unwrap() - .is_identity() + .unwrap() + .is_identity() )); for _ in 0..100 { @@ -343,10 +343,10 @@ macro_rules! curve_testing_suite { } } - use crate::ff::Field; - use crate::group::prime::PrimeCurveAffine; - use crate::{group::GroupEncoding, serde::SerdeObject}; - use crate::{CurveAffine, CurveExt}; + use $crate::ff::Field; + use $crate::group::prime::PrimeCurveAffine; + use $crate::{group::GroupEncoding, serde::SerdeObject}; + use $crate::{CurveAffine, CurveExt}; use rand_core::OsRng; @@ -506,8 +506,8 @@ macro_rules! curve_testing_suite { ($curve: ident, "svdw_map_to_curve", ($precomputed_constants: expr, $test_vector: expr)) => { #[test] fn test_map_to_curve() { - use crate::ff_ext::Legendre; - use crate::{hash_to_curve, CurveAffine, CurveExt}; + use $crate::ff_ext::Legendre; + use $crate::{hash_to_curve, CurveAffine, CurveExt}; use ff::PrimeField; use num_bigint::BigUint; use num_traits::Num; diff --git a/src/tests/field.rs b/src/tests/field.rs index 95c91ed2..ac7ceea8 100644 --- a/src/tests/field.rs +++ b/src/tests/field.rs @@ -1,3 +1,6 @@ +use ff::{FromUniformBytes, PrimeField}; +use rand::RngCore; + #[macro_export] macro_rules! field_testing_suite { ($field: ident, "field_arithmetic") => { @@ -280,7 +283,7 @@ macro_rules! field_testing_suite { #[test] fn test_serialization() { - use crate::serde::SerdeObject; + use $crate::serde::SerdeObject; random_serialization_test!($field); #[cfg(feature = "derive_serde")] random_serde_test!($field); @@ -290,7 +293,7 @@ macro_rules! field_testing_suite { ($field: ident, "quadratic_residue") => { #[test] fn test_quadratic_residue() { - use crate::ff_ext::Legendre; + use $crate::ff_ext::Legendre; use ff::Field; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; @@ -344,12 +347,12 @@ macro_rules! field_testing_suite { #[test] fn test_serialization_check() { - use crate::serde::SerdeObject; + use $crate::serde::SerdeObject; let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); - const LIMBS: usize = $field::size() / 8; + const LIMBS: usize = $field::SIZE / 8; // failure check for _ in 0..1000000 { let rand_word = [(); LIMBS].map(|_| rng.next_u64()); @@ -392,7 +395,7 @@ macro_rules! field_testing_suite { ($field: ident, "sqrt") => { #[test] fn test_sqrt() { - use crate::ff_ext::Legendre; + use $crate::ff_ext::Legendre; use rand_core::OsRng; let v = ($field::TWO_INV).square().sqrt().unwrap(); @@ -449,25 +452,13 @@ macro_rules! field_testing_suite { } }; - ($field: ident, "from_uniform_bytes", $test_vectors: expr) => { + ($field: ident, "from_uniform_bytes", $($L:expr),* $(,)?) => { + #[test] fn test_from_uniform_bytes() { - const N_VECS: usize = 10; - assert!($test_vectors.len() == N_VECS); - - let mut seeded_rng = XorShiftRng::seed_from_u64(0u64); - let uniform_bytes = std::iter::from_fn(|| { - let mut bytes = [0u8; 64]; - seeded_rng.fill_bytes(&mut bytes); - Some(bytes) - }) - .take(N_VECS) - .collect::>(); - - for i in 0..N_VECS { - let q = $field::from_uniform_bytes(&uniform_bytes[i]); - assert_eq!($test_vectors[i], q); - } + $( + $crate::tests::field::run_test_from_uniform_bytes::<$field, $L>(); + )* } }; @@ -733,3 +724,26 @@ macro_rules! field_testing_suite { } }; } + +pub(crate) fn run_test_from_uniform_bytes() +where + F: FromUniformBytes, +{ + use num_bigint::BigUint; + use rand_core::OsRng; + + let mut uniform_bytes = [0u8; L]; + OsRng.fill_bytes(&mut uniform_bytes[..]); + + let e0 = { + let e0 = BigUint::from_bytes_le(&uniform_bytes); + let e0 = e0 % crate::tests::modulus::(); + let bytes = e0.to_bytes_le(); + let mut e0 = F::Repr::default(); + e0.as_mut()[..bytes.len()].copy_from_slice(&bytes); + F::from_repr(e0).unwrap() + }; + + let e1 = F::from_uniform_bytes(&uniform_bytes); + assert_eq!(e0, e1); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index f773c8d7..c06f4228 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,2 +1,36 @@ +use ff::PrimeField; +use num_bigint::BigUint; +use pasta_curves::arithmetic::CurveAffine; + pub mod curve; pub mod field; + +pub(crate) fn hex_to_bytes(hex: &str) -> Vec { + let bytes = hex.as_bytes().to_vec(); + bytes + .chunks(2) + .map(|chunk| u8::from_str_radix(std::str::from_utf8(chunk).unwrap(), 16).unwrap()) + .collect() +} + +pub(crate) fn hex_to_field(hex: &str) -> F { + let mut bytes = hex_to_bytes(hex); + bytes.reverse(); + let mut repr = F::Repr::default(); + repr.as_mut()[..bytes.len()].copy_from_slice(&bytes); + F::from_repr(repr).unwrap() +} + +pub(crate) fn point_from_hex(x: &str, y: &str) -> C { + let x = crate::tests::hex_to_field(x); + let y = crate::tests::hex_to_field(y); + C::from_xy(x, y).unwrap() +} + +pub(crate) fn fe_to_big(fe: &F) -> BigUint { + BigUint::from_bytes_le(fe.to_repr().as_ref()) +} + +pub(crate) fn modulus() -> BigUint { + fe_to_big(&-F::ONE) + 1usize +}