From a36784b202be52dad9c53d1d8965c4409dc89116 Mon Sep 17 00:00:00 2001 From: Solomon Date: Mon, 7 Feb 2022 14:13:14 -0800 Subject: [PATCH 01/26] Removed SquareRootField --- ec/src/lib.rs | 12 ++-- ec/src/models/bls12/mod.rs | 4 +- ec/src/models/bn/mod.rs | 4 +- ec/src/models/bw6/mod.rs | 4 +- ec/src/models/mnt4/mod.rs | 6 +- ec/src/models/mnt6/mod.rs | 6 +- ec/src/models/mod.rs | 6 +- ec/src/models/short_weierstrass_jacobian.rs | 2 +- ec/src/models/twisted_edwards_extended.rs | 2 +- ff/src/fields/macros.rs | 56 +++++++++---------- ff/src/fields/mod.rs | 37 ++++++------ ff/src/fields/models/fp3.rs | 4 +- ff/src/fields/models/mod.rs | 2 +- ff/src/fields/models/quadratic_extension.rs | 6 +- ff/src/lib.rs | 2 +- test-curves/src/bls12_381/tests.rs | 2 +- .../src/bn384_small_two_adicity/tests.rs | 2 +- test-templates/src/fields.rs | 6 +- 18 files changed, 79 insertions(+), 84 deletions(-) diff --git a/ec/src/lib.rs b/ec/src/lib.rs index b759009f9..a631c1b5d 100644 --- a/ec/src/lib.rs +++ b/ec/src/lib.rs @@ -21,7 +21,7 @@ extern crate ark_std; use ark_ff::{ bytes::{FromBytes, ToBytes}, - fields::{BitIteratorBE, Field, PrimeField, SquareRootField}, + fields::{BitIteratorBE, Field, PrimeField}, UniformRand, }; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -47,7 +47,7 @@ pub mod wnaf; pub trait PairingEngine: Sized + 'static + Copy + Debug + Sync + Send + Eq + PartialEq { /// This is the scalar field of the G1/G2 groups. - type Fr: PrimeField + SquareRootField; + type Fr: PrimeField; /// The projective representation of an element in G1. type G1Projective: ProjectiveCurve @@ -80,10 +80,10 @@ pub trait PairingEngine: Sized + 'static + Copy + Debug + Sync + Send + Eq + Par type G2Prepared: ToBytes + Default + Clone + Send + Sync + Debug + From; /// The base field that hosts G1. - type Fq: PrimeField + SquareRootField; + type Fq: PrimeField; /// The extension field that hosts G2. - type Fqe: SquareRootField; + type Fqe: Field; /// The extension field that hosts the target group of the pairing. type Fqk: Field; @@ -156,7 +156,7 @@ pub trait ProjectiveCurve: + From<::Affine> { type Parameters: ModelParameters; - type ScalarField: PrimeField + SquareRootField; + type ScalarField: PrimeField; type BaseField: Field; type Affine: AffineCurve< Parameters = Self::Parameters, @@ -256,7 +256,7 @@ pub trait AffineCurve: + From<::Projective> { type Parameters: ModelParameters; - type ScalarField: PrimeField + SquareRootField + Into<::BigInt>; + type ScalarField: PrimeField + Into<::BigInt>; type BaseField: Field; type Projective: ProjectiveCurve< Parameters = Self::Parameters, diff --git a/ec/src/models/bls12/mod.rs b/ec/src/models/bls12/mod.rs index e5b1c50e9..fb6f23629 100644 --- a/ec/src/models/bls12/mod.rs +++ b/ec/src/models/bls12/mod.rs @@ -6,7 +6,7 @@ use ark_ff::fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, fp2::Fp2Parameters, fp6_3over2::Fp6Parameters, - BitIteratorBE, Field, Fp2, PrimeField, SquareRootField, + BitIteratorBE, Field, Fp2, PrimeField, }; use core::marker::PhantomData; use num_traits::{One, Zero}; @@ -33,7 +33,7 @@ pub trait Bls12Parameters: 'static { /// What kind of twist is this? const TWIST_TYPE: TwistType; - type Fp: PrimeField + SquareRootField + Into<::BigInt>; + type Fp: PrimeField + Into<::BigInt>; type Fp2Params: Fp2Parameters; type Fp6Params: Fp6Parameters; type Fp12Params: Fp12Parameters; diff --git a/ec/src/models/bn/mod.rs b/ec/src/models/bn/mod.rs index 7e1751797..e29883828 100644 --- a/ec/src/models/bn/mod.rs +++ b/ec/src/models/bn/mod.rs @@ -6,7 +6,7 @@ use ark_ff::fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, fp2::Fp2Parameters, fp6_3over2::Fp6Parameters, - Field, Fp2, PrimeField, SquareRootField, + Field, Fp2, PrimeField, }; use num_traits::One; @@ -31,7 +31,7 @@ pub trait BnParameters: 'static { const TWIST_TYPE: TwistType; const TWIST_MUL_BY_Q_X: Fp2; const TWIST_MUL_BY_Q_Y: Fp2; - type Fp: PrimeField + SquareRootField + Into<::BigInt>; + type Fp: PrimeField + Into<::BigInt>; type Fp2Params: Fp2Parameters; type Fp6Params: Fp6Parameters; type Fp12Params: Fp12Parameters; diff --git a/ec/src/models/bw6/mod.rs b/ec/src/models/bw6/mod.rs index ff2726e10..c763be683 100644 --- a/ec/src/models/bw6/mod.rs +++ b/ec/src/models/bw6/mod.rs @@ -5,7 +5,7 @@ use crate::{ use ark_ff::fields::{ fp3::Fp3Parameters, fp6_2over3::{Fp6, Fp6Parameters}, - BitIteratorBE, Field, PrimeField, SquareRootField, + BitIteratorBE, Field, PrimeField, }; use num_traits::One; @@ -24,7 +24,7 @@ pub trait BW6Parameters: 'static + Eq + PartialEq { const ATE_LOOP_COUNT_2: &'static [i8]; const ATE_LOOP_COUNT_2_IS_NEGATIVE: bool; const TWIST_TYPE: TwistType; - type Fp: PrimeField + SquareRootField + Into<::BigInt>; + type Fp: PrimeField + Into<::BigInt>; type Fp3Params: Fp3Parameters; type Fp6Params: Fp6Parameters; type G1Parameters: SWModelParameters; diff --git a/ec/src/models/mnt4/mod.rs b/ec/src/models/mnt4/mod.rs index ea73fdcb2..04544dbad 100644 --- a/ec/src/models/mnt4/mod.rs +++ b/ec/src/models/mnt4/mod.rs @@ -5,7 +5,7 @@ use crate::{ use ark_ff::{ fp2::{Fp2, Fp2Parameters}, fp4::{Fp4, Fp4Parameters}, - BitIteratorBE, Field, PrimeField, SquareRootField, + BitIteratorBE, Field, PrimeField, }; use num_traits::{One, Zero}; @@ -30,8 +30,8 @@ pub trait MNT4Parameters: 'static { const FINAL_EXPONENT_LAST_CHUNK_1: ::BigInt; const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool; const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: ::BigInt; - type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fr: PrimeField + SquareRootField + Into<::BigInt>; + type Fp: PrimeField + Into<::BigInt>; + type Fr: PrimeField + Into<::BigInt>; type Fp2Params: Fp2Parameters; type Fp4Params: Fp4Parameters; type G1Parameters: SWModelParameters; diff --git a/ec/src/models/mnt6/mod.rs b/ec/src/models/mnt6/mod.rs index fe1efa8cb..9ad0fb124 100644 --- a/ec/src/models/mnt6/mod.rs +++ b/ec/src/models/mnt6/mod.rs @@ -5,7 +5,7 @@ use crate::{ use ark_ff::{ fp3::{Fp3, Fp3Parameters}, fp6_2over3::{Fp6, Fp6Parameters}, - BitIteratorBE, Field, PrimeField, SquareRootField, + BitIteratorBE, Field, PrimeField, }; use num_traits::{One, Zero}; @@ -30,8 +30,8 @@ pub trait MNT6Parameters: 'static { const FINAL_EXPONENT_LAST_CHUNK_1: ::BigInt; const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool; const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: ::BigInt; - type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fr: PrimeField + SquareRootField + Into<::BigInt>; + type Fp: PrimeField + Into<::BigInt>; + type Fr: PrimeField + Into<::BigInt>; type Fp3Params: Fp3Parameters; type Fp6Params: Fp6Parameters; type G1Parameters: SWModelParameters; diff --git a/ec/src/models/mod.rs b/ec/src/models/mod.rs index 246405b36..d8a399ec0 100644 --- a/ec/src/models/mod.rs +++ b/ec/src/models/mod.rs @@ -1,5 +1,5 @@ use crate::AffineCurve; -use ark_ff::{fields::BitIteratorBE, Field, PrimeField, SquareRootField, Zero}; +use ark_ff::{fields::BitIteratorBE, Field, PrimeField, Zero}; pub mod bls12; pub mod bn; @@ -11,8 +11,8 @@ pub mod twisted_edwards_extended; /// Model parameters for an elliptic curve. pub trait ModelParameters: Send + Sync + Sized + 'static { - type BaseField: Field + SquareRootField; - type ScalarField: PrimeField + SquareRootField + Into<::BigInt>; + type BaseField: Field; + type ScalarField: PrimeField + Into<::BigInt>; const COFACTOR: &'static [u64]; const COFACTOR_INV: Self::ScalarField; diff --git a/ec/src/models/short_weierstrass_jacobian.rs b/ec/src/models/short_weierstrass_jacobian.rs index 0c1918bd6..b00e613d0 100644 --- a/ec/src/models/short_weierstrass_jacobian.rs +++ b/ec/src/models/short_weierstrass_jacobian.rs @@ -12,7 +12,7 @@ use ark_std::{ use ark_ff::{ bytes::{FromBytes, ToBytes}, - fields::{Field, PrimeField, SquareRootField}, + fields::{Field, PrimeField}, ToConstraintField, UniformRand, }; diff --git a/ec/src/models/twisted_edwards_extended.rs b/ec/src/models/twisted_edwards_extended.rs index 8f42fe222..4d23618b9 100644 --- a/ec/src/models/twisted_edwards_extended.rs +++ b/ec/src/models/twisted_edwards_extended.rs @@ -22,7 +22,7 @@ use zeroize::Zeroize; use ark_ff::{ bytes::{FromBytes, ToBytes}, - fields::{Field, PrimeField, SquareRootField}, + fields::{Field, PrimeField}, ToConstraintField, UniformRand, }; diff --git a/ff/src/fields/macros.rs b/ff/src/fields/macros.rs index 4245768f7..3d5293cf5 100644 --- a/ff/src/fields/macros.rs +++ b/ff/src/fields/macros.rs @@ -367,6 +367,33 @@ macro_rules! impl_Fp { } } + #[inline] + fn legendre(&self) -> LegendreSymbol { + use crate::fields::LegendreSymbol::*; + + // s = self^((MODULUS - 1) // 2) + let s = self.pow(P::MODULUS_MINUS_ONE_DIV_TWO); + if s.is_zero() { + Zero + } else if s.is_one() { + QuadraticResidue + } else { + QuadraticNonResidue + } + } + + #[inline] + fn sqrt(&self) -> Option { + sqrt_impl!(Self, P, self) + } + + fn sqrt_in_place(&mut self) -> Option<&mut Self> { + (*self).sqrt().map(|sqrt| { + *self = sqrt; + self + }) + } + #[inline] fn square(&self) -> Self { let mut temp = self.clone(); @@ -486,35 +513,6 @@ macro_rules! impl_Fp { } } - impl SquareRootField for $Fp

{ - #[inline] - fn legendre(&self) -> LegendreSymbol { - use crate::fields::LegendreSymbol::*; - - // s = self^((MODULUS - 1) // 2) - let s = self.pow(P::MODULUS_MINUS_ONE_DIV_TWO); - if s.is_zero() { - Zero - } else if s.is_one() { - QuadraticResidue - } else { - QuadraticNonResidue - } - } - - #[inline] - fn sqrt(&self) -> Option { - sqrt_impl!(Self, P, self) - } - - fn sqrt_in_place(&mut self) -> Option<&mut Self> { - (*self).sqrt().map(|sqrt| { - *self = sqrt; - self - }) - } - } - /// Note that this implementation of `Ord` compares field elements viewing /// them as integers in the range 0, 1, ..., P::MODULUS - 1. However, other /// implementations of `PrimeField` might choose a different ordering, and diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index bc6df82de..0d3356a49 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -150,6 +150,19 @@ pub trait Field: /// random field elements from a hash-function or RNG output. fn from_random_bytes_with_flags(bytes: &[u8]) -> Option<(Self, F)>; + /// Returns a `LegendreSymbol`, which indicates whether this field element + /// is 1 : a quadratic residue + /// 0 : equal to 0 + /// -1 : a quadratic non-residue + fn legendre(&self) -> LegendreSymbol; + + /// Returns the square root of self, if it exists. + #[must_use] + fn sqrt(&self) -> Option; + + /// Sets `self` to be the square root of `self`, if it exists. + fn sqrt_in_place(&mut self) -> Option<&mut Self>; + /// Returns `self * self`. #[must_use] fn square(&self) -> Self; @@ -432,22 +445,6 @@ pub trait PrimeField: } } -/// The interface for a field that supports an efficient square-root operation. -pub trait SquareRootField: Field { - /// Returns a `LegendreSymbol`, which indicates whether this field element - /// is 1 : a quadratic residue - /// 0 : equal to 0 - /// -1 : a quadratic non-residue - fn legendre(&self) -> LegendreSymbol; - - /// Returns the square root of self, if it exists. - #[must_use] - fn sqrt(&self) -> Option; - - /// Sets `self` to be the square root of `self`, if it exists. - fn sqrt_in_place(&mut self) -> Option<&mut Self>; -} - /// Indication of the field element's quadratic residuosity /// /// # Examples @@ -455,7 +452,7 @@ pub trait SquareRootField: Field { /// # use ark_std::test_rng; /// # use ark_test_curves::bls12_381::Fq as Fp; /// # use ark_std::UniformRand; -/// # use ark_ff::{LegendreSymbol, Field, SquareRootField}; +/// # use ark_ff::{LegendreSymbol, Field}; /// let a: Fp = Fp::rand(&mut test_rng()); /// let b = a.square(); /// assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); @@ -475,7 +472,7 @@ impl LegendreSymbol { /// # use ark_std::test_rng; /// # use ark_test_curves::bls12_381::Fq as Fp; /// # use ark_std::UniformRand; - /// # use ark_ff::{LegendreSymbol, Field, SquareRootField}; + /// # use ark_ff::{LegendreSymbol, Field}; /// let a: Fp = Fp::rand(&mut test_rng()); /// let b: Fp = a.square(); /// assert!(!b.legendre().is_zero()); @@ -489,7 +486,7 @@ impl LegendreSymbol { /// # Examples /// ``` /// # use ark_test_curves::bls12_381::{Fq, Fq2Parameters}; - /// # use ark_ff::{LegendreSymbol, SquareRootField}; + /// # use ark_ff::LegendreSymbol; /// # use ark_ff::Fp2Parameters; /// let a: Fq = Fq2Parameters::NONRESIDUE; /// assert!(a.legendre().is_qnr()); @@ -504,7 +501,7 @@ impl LegendreSymbol { /// # use ark_std::test_rng; /// # use ark_test_curves::bls12_381::Fq as Fp; /// # use ark_std::UniformRand; - /// # use ark_ff::{LegendreSymbol, Field, SquareRootField}; + /// # use ark_ff::{LegendreSymbol, Field}; /// let a: Fp = Fp::rand(&mut test_rng()); /// let b: Fp = a.square(); /// assert!(b.legendre().is_qr()); diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index 809bfa111..0a1bd5339 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -3,7 +3,7 @@ use crate::fields::*; use core::marker::PhantomData; pub trait Fp3Parameters: 'static + Send + Sync { - type Fp: PrimeField + SquareRootField; + type Fp: PrimeField; const NONRESIDUE: Self::Fp; @@ -71,7 +71,7 @@ impl Fp3

{ } } -impl SquareRootField for Fp3

{ +impl Field for Fp3

{ /// Returns the Legendre symbol. fn legendre(&self) -> LegendreSymbol { self.norm().legendre() diff --git a/ff/src/fields/models/mod.rs b/ff/src/fields/models/mod.rs index 4f70b4fe4..a11cab1de 100644 --- a/ff/src/fields/models/mod.rs +++ b/ff/src/fields/models/mod.rs @@ -14,7 +14,7 @@ use crate::{ BigInteger384, BigInteger448, BigInteger64, BigInteger768, BigInteger832, }, bytes::{FromBytes, ToBytes}, - fields::{FftField, Field, FpParameters, LegendreSymbol, PrimeField, SquareRootField}, + fields::{FftField, Field, FpParameters, LegendreSymbol, PrimeField}, }; use ark_serialize::*; diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 1888297a7..30f25d638 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -21,7 +21,7 @@ use ark_std::rand::{ use crate::{ biginteger::BigInteger, bytes::{FromBytes, ToBytes}, - fields::{Field, LegendreSymbol, PrimeField, SquareRootField}, + fields::{Field, LegendreSymbol, PrimeField}, ToConstraintField, UniformRand, }; @@ -369,9 +369,9 @@ impl Field for QuadExtField

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

+impl<'a, P: QuadExtParameters> Field for QuadExtField

where - P::BaseField: SquareRootField + From, + P::BaseField: Field + From, { fn legendre(&self) -> LegendreSymbol { // The LegendreSymbol in a field of order q for an element x can be diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 3c088a184..b4b375b29 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -41,7 +41,7 @@ pub use ark_std::vec; pub mod prelude { pub use crate::biginteger::BigInteger; - pub use crate::fields::{Field, FpParameters, PrimeField, SquareRootField}; + pub use crate::fields::{Field, FpParameters, PrimeField}; pub use ark_std::UniformRand; diff --git a/test-curves/src/bls12_381/tests.rs b/test-curves/src/bls12_381/tests.rs index 338770c27..504af3b49 100644 --- a/test-curves/src/bls12_381/tests.rs +++ b/test-curves/src/bls12_381/tests.rs @@ -1,6 +1,6 @@ #![allow(unused_imports)] use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; -use ark_ff::{Field, One, SquareRootField, UniformRand, Zero}; +use ark_ff::{Field, One, UniformRand, Zero}; use crate::bls12_381::{g1, Fq, Fq2, Fq6, FqParameters, Fr, G1Affine, G1Projective}; use ark_algebra_test_templates::{ diff --git a/test-curves/src/bn384_small_two_adicity/tests.rs b/test-curves/src/bn384_small_two_adicity/tests.rs index 32c6438bd..9b4cc36af 100644 --- a/test-curves/src/bn384_small_two_adicity/tests.rs +++ b/test-curves/src/bn384_small_two_adicity/tests.rs @@ -1,6 +1,6 @@ #![allow(unused_imports)] use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; -use ark_ff::{Field, One, SquareRootField, UniformRand, Zero}; +use ark_ff::{Field, One, UniformRand, Zero}; use ark_std::{rand::Rng, test_rng}; use crate::bn384_small_two_adicity::{g1, Fq, FqParameters, Fr, G1Affine, G1Projective}; diff --git a/test-templates/src/fields.rs b/test-templates/src/fields.rs index be0003c28..85d5538dc 100644 --- a/test-templates/src/fields.rs +++ b/test-templates/src/fields.rs @@ -1,6 +1,6 @@ #![allow(unused)] #![allow(clippy::eq_op)] -use ark_ff::fields::{FftField, FftParameters, Field, LegendreSymbol, PrimeField, SquareRootField}; +use ark_ff::fields::{FftField, FftParameters, Field, LegendreSymbol, PrimeField}; use ark_serialize::{buffer_bit_byte_size, Flags, SWFlags}; use ark_std::{io::Cursor, rand::Rng}; @@ -187,7 +187,7 @@ fn random_field_tests() { } } -fn random_sqrt_tests() { +fn random_sqrt_tests() { let mut rng = ark_std::test_rng(); for _ in 0..ITERATIONS { @@ -343,7 +343,7 @@ pub fn primefield_test() { fft_field_test::(); } -pub fn sqrt_field_test(elem: F) { +pub fn sqrt_field_test(elem: F) { let square = elem.square(); let sqrt = square.sqrt().unwrap(); assert!(sqrt == elem || sqrt == -elem); From bf84185356609b532910933900615e5e047d0480 Mon Sep 17 00:00:00 2001 From: Solomon Date: Mon, 7 Feb 2022 15:01:34 -0800 Subject: [PATCH 02/26] Merge cleanup --- ec/src/models/bn/mod.rs | 12 - ec/src/models/bw6/mod.rs | 12 - ff/src/fields/macros.rs | 744 ----------------------------------- test-templates/src/fields.rs | 6 +- 4 files changed, 1 insertion(+), 773 deletions(-) delete mode 100644 ff/src/fields/macros.rs diff --git a/ec/src/models/bn/mod.rs b/ec/src/models/bn/mod.rs index 6b7bc6d1a..c61a5a05c 100644 --- a/ec/src/models/bn/mod.rs +++ b/ec/src/models/bn/mod.rs @@ -4,15 +4,9 @@ use crate::{ }; use ark_ff::fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, -<<<<<<< HEAD fp2::Fp2Parameters, fp6_3over2::Fp6Parameters, Field, Fp2, PrimeField, -======= - fp2::Fp2Config, - fp6_3over2::Fp6Config, - Field, Fp2, PrimeField, SquareRootField, ->>>>>>> master }; use num_traits::One; @@ -37,15 +31,9 @@ pub trait BnParameters: 'static { const TWIST_TYPE: TwistType; const TWIST_MUL_BY_Q_X: Fp2; const TWIST_MUL_BY_Q_Y: Fp2; -<<<<<<< HEAD type Fp: PrimeField + Into<::BigInt>; type Fp2Params: Fp2Parameters; type Fp6Params: Fp6Parameters; -======= - type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fp2Params: Fp2Config; - type Fp6Params: Fp6Config; ->>>>>>> master type Fp12Params: Fp12Parameters; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< diff --git a/ec/src/models/bw6/mod.rs b/ec/src/models/bw6/mod.rs index 17afe4092..3dc001d7f 100644 --- a/ec/src/models/bw6/mod.rs +++ b/ec/src/models/bw6/mod.rs @@ -3,15 +3,9 @@ use crate::{ PairingEngine, }; use ark_ff::fields::{ -<<<<<<< HEAD fp3::Fp3Parameters, fp6_2over3::{Fp6, Fp6Parameters}, BitIteratorBE, Field, PrimeField, -======= - fp3::Fp3Config, - fp6_2over3::{Fp6, Fp6Config}, - BitIteratorBE, Field, PrimeField, SquareRootField, ->>>>>>> master }; use num_traits::One; @@ -30,15 +24,9 @@ pub trait BW6Parameters: 'static + Eq + PartialEq { const ATE_LOOP_COUNT_2: &'static [i8]; const ATE_LOOP_COUNT_2_IS_NEGATIVE: bool; const TWIST_TYPE: TwistType; -<<<<<<< HEAD type Fp: PrimeField + Into<::BigInt>; type Fp3Params: Fp3Parameters; type Fp6Params: Fp6Parameters; -======= - type Fp: PrimeField + SquareRootField + Into<::BigInt>; - type Fp3Params: Fp3Config; - type Fp6Params: Fp6Config; ->>>>>>> master type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Self::Fp, diff --git a/ff/src/fields/macros.rs b/ff/src/fields/macros.rs deleted file mode 100644 index 3d5293cf5..000000000 --- a/ff/src/fields/macros.rs +++ /dev/null @@ -1,744 +0,0 @@ -macro_rules! impl_prime_field_serializer { - ($field: ident, $params: ident, $byte_size: expr) => { - impl CanonicalSerializeWithFlags for $field

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

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

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

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

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

, - ); - - impl

$Fp

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

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

ark_std::fmt::Debug for $Fp

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

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

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

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

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

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

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

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

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

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

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

(P::GENERATOR, PhantomData) - } - } - - /// Note that this implementation of `Ord` compares field elements viewing - /// them as integers in the range 0, 1, ..., P::MODULUS - 1. However, other - /// implementations of `PrimeField` might choose a different ordering, and - /// as such, users should use this `Ord` for applications where - /// any ordering suffices (like in a BTreeMap), and not in applications - /// where a particular ordering is required. - impl Ord for $Fp

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

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

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

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

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

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

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

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

> for $Fp

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

> for $Fp

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

> for $Fp

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

> for $Fp

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

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

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

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

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

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

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

{ - $Fp::

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

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

) -> Self { - other.into_repr().into() - } - } - } -} diff --git a/test-templates/src/fields.rs b/test-templates/src/fields.rs index 547a210dc..9b7c89621 100644 --- a/test-templates/src/fields.rs +++ b/test-templates/src/fields.rs @@ -1,13 +1,9 @@ #![allow(unused)] #![allow(clippy::eq_op)] -<<<<<<< HEAD -use ark_ff::fields::{FftField, FftParameters, Field, LegendreSymbol, PrimeField}; -======= use ark_ff::{ - fields::{FftField, Field, LegendreSymbol, PrimeField, SquareRootField}, + fields::{FftField, Field, LegendreSymbol, PrimeField}, Fp, MontBackend, MontConfig, }; ->>>>>>> master use ark_serialize::{buffer_bit_byte_size, Flags, SWFlags}; use ark_std::{io::Cursor, rand::Rng}; From 08dc4d649beed6f44fa65ee188b871c95d961460 Mon Sep 17 00:00:00 2001 From: Solomon Date: Mon, 7 Feb 2022 18:46:25 -0800 Subject: [PATCH 03/26] Reverted changes to track master --- ec/src/models/bls12/mod.rs | 8 ++++---- ec/src/models/bn/mod.rs | 8 ++++---- ec/src/models/bw6/mod.rs | 8 ++++---- ec/src/models/mnt4/mod.rs | 8 ++++---- ec/src/models/mnt6/mod.rs | 8 ++++---- ff/src/fields/models/fp3.rs | 7 ++++--- ff/src/fields/models/quadratic_extension.rs | 2 +- ff/src/lib.rs | 2 +- 8 files changed, 26 insertions(+), 25 deletions(-) diff --git a/ec/src/models/bls12/mod.rs b/ec/src/models/bls12/mod.rs index f51d559db..25b046c81 100644 --- a/ec/src/models/bls12/mod.rs +++ b/ec/src/models/bls12/mod.rs @@ -4,8 +4,8 @@ use crate::{ }; use ark_ff::fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, - fp2::Fp2Parameters, - fp6_3over2::Fp6Parameters, + fp2::Fp2Config, + fp6_3over2::Fp6Config, BitIteratorBE, Field, Fp2, PrimeField, }; use core::marker::PhantomData; @@ -34,8 +34,8 @@ pub trait Bls12Parameters: 'static { const TWIST_TYPE: TwistType; type Fp: PrimeField + Into<::BigInt>; - type Fp2Params: Fp2Parameters; - type Fp6Params: Fp6Parameters; + type Fp2Params: Fp2Config; + type Fp6Params: Fp6Config; type Fp12Params: Fp12Parameters; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< diff --git a/ec/src/models/bn/mod.rs b/ec/src/models/bn/mod.rs index c61a5a05c..c303641f6 100644 --- a/ec/src/models/bn/mod.rs +++ b/ec/src/models/bn/mod.rs @@ -4,8 +4,8 @@ use crate::{ }; use ark_ff::fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, - fp2::Fp2Parameters, - fp6_3over2::Fp6Parameters, + fp2::Fp2Config, + fp6_3over2::Fp6Config, Field, Fp2, PrimeField, }; use num_traits::One; @@ -32,8 +32,8 @@ pub trait BnParameters: 'static { const TWIST_MUL_BY_Q_X: Fp2; const TWIST_MUL_BY_Q_Y: Fp2; type Fp: PrimeField + Into<::BigInt>; - type Fp2Params: Fp2Parameters; - type Fp6Params: Fp6Parameters; + type Fp2Params: Fp2Config; + type Fp6Params: Fp6Config; type Fp12Params: Fp12Parameters; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< diff --git a/ec/src/models/bw6/mod.rs b/ec/src/models/bw6/mod.rs index 3dc001d7f..45189d7f3 100644 --- a/ec/src/models/bw6/mod.rs +++ b/ec/src/models/bw6/mod.rs @@ -3,8 +3,8 @@ use crate::{ PairingEngine, }; use ark_ff::fields::{ - fp3::Fp3Parameters, - fp6_2over3::{Fp6, Fp6Parameters}, + fp3::Fp3Config, + fp6_2over3::{Fp6, Fp6Config}, BitIteratorBE, Field, PrimeField, }; use num_traits::One; @@ -25,8 +25,8 @@ pub trait BW6Parameters: 'static + Eq + PartialEq { const ATE_LOOP_COUNT_2_IS_NEGATIVE: bool; const TWIST_TYPE: TwistType; type Fp: PrimeField + Into<::BigInt>; - type Fp3Params: Fp3Parameters; - type Fp6Params: Fp6Parameters; + type Fp3Params: Fp3Config; + type Fp6Params: Fp6Config; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Self::Fp, diff --git a/ec/src/models/mnt4/mod.rs b/ec/src/models/mnt4/mod.rs index 04544dbad..c5a5d2cdc 100644 --- a/ec/src/models/mnt4/mod.rs +++ b/ec/src/models/mnt4/mod.rs @@ -3,8 +3,8 @@ use crate::{ PairingEngine, }; use ark_ff::{ - fp2::{Fp2, Fp2Parameters}, - fp4::{Fp4, Fp4Parameters}, + fp2::{Fp2, Fp2Config}, + fp4::{Fp4, Fp4Config}, BitIteratorBE, Field, PrimeField, }; use num_traits::{One, Zero}; @@ -32,8 +32,8 @@ pub trait MNT4Parameters: 'static { const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: ::BigInt; type Fp: PrimeField + Into<::BigInt>; type Fr: PrimeField + Into<::BigInt>; - type Fp2Params: Fp2Parameters; - type Fp4Params: Fp4Parameters; + type Fp2Params: Fp2Config; + type Fp4Params: Fp4Config; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Fp2, diff --git a/ec/src/models/mnt6/mod.rs b/ec/src/models/mnt6/mod.rs index 9ad0fb124..8bb200b40 100644 --- a/ec/src/models/mnt6/mod.rs +++ b/ec/src/models/mnt6/mod.rs @@ -3,8 +3,8 @@ use crate::{ PairingEngine, }; use ark_ff::{ - fp3::{Fp3, Fp3Parameters}, - fp6_2over3::{Fp6, Fp6Parameters}, + fp3::{Fp3, Fp3Config}, + fp6_2over3::{Fp6, Fp6Config}, BitIteratorBE, Field, PrimeField, }; use num_traits::{One, Zero}; @@ -32,8 +32,8 @@ pub trait MNT6Parameters: 'static { const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: ::BigInt; type Fp: PrimeField + Into<::BigInt>; type Fr: PrimeField + Into<::BigInt>; - type Fp3Params: Fp3Parameters; - type Fp6Params: Fp6Parameters; + type Fp3Params: Fp3Config; + type Fp6Params: Fp6Config; type G1Parameters: SWModelParameters; type G2Parameters: SWModelParameters< BaseField = Fp3, diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index 683ffeba6..eb1cf959c 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -2,9 +2,10 @@ use super::cubic_extension::*; use crate::fields::*; use core::marker::PhantomData; -pub trait Fp3Parameters: 'static + Send + Sync { +/// Trait that specifies constants and methods for defining degree-three extension fields. +pub trait Fp3Config: 'static + Send + Sync + Sized { + /// Base prime field underlying this extension. type Fp: PrimeField; - /// Cubic non-residue in `Self::Fp` used to construct the extension /// field. That is, `NONRESIDUE` is such that the cubic polynomial /// `f(X) = X^3 - Self::NONRESIDUE` in Fp\[X\] is irreducible in `Self::Fp`. @@ -98,7 +99,7 @@ impl Fp3

{ } } -impl Field for Fp3

{ +impl Field for Fp3

{ /// Returns the Legendre symbol. fn legendre(&self) -> LegendreSymbol { self.norm().legendre() diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 9d1a5c548..2f974f2bd 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -387,7 +387,7 @@ impl Field for QuadExtField

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

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

where P::BaseField: Field + From, { diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 293140857..002d74a11 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -42,7 +42,7 @@ pub use ark_std::vec; pub mod prelude { pub use crate::biginteger::BigInteger; - pub use crate::fields::{Field, FpParameters, PrimeField}; + pub use crate::fields::{Field, PrimeField}; pub use ark_std::UniformRand; From a518c6784d5c03950cc1455ce85eabd4bd25fb08 Mon Sep 17 00:00:00 2001 From: Solomon Date: Mon, 7 Feb 2022 18:47:37 -0800 Subject: [PATCH 04/26] Added Tonelli-Shanks and Shanks sqrt algorithms for cubic extension fields --- ff/src/fields/models/cubic_extension.rs | 91 ++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 247ae0b13..271c89d20 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -263,6 +263,10 @@ impl Field for CubicExtField

{ self } + fn sqrt(&self) -> Option { + tonelli_shanks(self) + } + fn inverse(&self) -> Option { if self.is_zero() { None @@ -314,8 +318,93 @@ impl Field for CubicExtField

{ } } +fn tonelli_shanks(f: &CubicExtField

) -> Option> { + // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) + // Actually this is just normal Tonelli-Shanks; since `P::Generator` + // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` + // is also a quadratic non-residue (since `t` is odd). + if f.is_zero() { + return Some(CubicExtField::zero()); + } + // Try computing the square root (x at the end of the algorithm) + // Check at the end of the algorithm if x was a square root + // Begin Tonelli-Shanks + let mut z = CubicExtField::qnr_to_t(); + let mut w = f.pow(P::TRACE_MINUS_ONE_DIV_TWO); + let mut x = w * f; + let mut b = x * &w; + + let mut v = P::TWO_ADICITY as usize; + + while !b.is_one() { + let mut k = 0usize; + + let mut b2k = b; + while !b2k.is_one() { + // invariant: b2k = b^(2^k) after entering this loop + b2k.square_in_place(); + k += 1; + } + + if k == (P::TWO_ADICITY as usize) { + // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, + // which means that no square root exists. + return None; + } + let j = v - k; + w = z; + for _ in 1..j { + w.square_in_place(); + } + + z = w.square(); + b *= &z; + x *= &w; + v = k; + } + // Is x the square root? If so, return it. + if (x.square() == *f) { + return Some(x); + } else { + // Consistency check that if no square root is found, + // it is because none exists. + #[cfg(debug_assertions)] + { + use crate::fields::LegendreSymbol::*; + if (f.legendre() != QuadraticNonResidue) { + panic!("Input has a square root per its legendre symbol, but it was not found") + } + } + None + } +} + +fn shanks(f: &CubicExtField

) -> Option> { + // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) + // Using decomposition of (q-3)/ 4 = alpha + p[p(alpha) + (3a + 2)]*sum_i^((m-3)/2) p^{2i} + + // t1 = f^alpha + let t1 = f.pow(\alpha); + // t2 = f^p + let t2 = f.frobenius(1); + // t3 = f^((p^2)alpha) * f^(3p(alpha) + 2p) + let t3 = t2.frobenius(1).pow(alpha) * (t2.pow(3).pow(alpha) + t2.square()); + let mut r = CubicExtField::one(); + let n = (CubicExtField::extension_degree() - 3)/2; + for i in 1..(n+1) { + r *= t3.frobenius(2 * i); + + let mut a_1 = t1 * r; + let mut x = a_1 * f; + let mut a_0 = a_1 * x; + if (a_0 == -CubicExtField::one()) { + return None; + } + x +} + /// `CubicExtField` elements are ordered lexicographically. -impl Ord for CubicExtField

{ +impl Ord for CubicExtField

-> { #[inline(always)] fn cmp(&self, other: &Self) -> Ordering { let c2_cmp = self.c2.cmp(&other.c2); From df8d67cef4f83e3528bda13ca227f2471e9e20c8 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Mon, 7 Feb 2022 18:54:45 -0800 Subject: [PATCH 05/26] Apply suggestions from code review --- ff/src/fields/models/cubic_extension.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 271c89d20..f68c2b73f 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -371,7 +371,7 @@ fn tonelli_shanks(f: &CubicExtField

) -> Option(f: &CubicExtField

) -> Option> { // Using decomposition of (q-3)/ 4 = alpha + p[p(alpha) + (3a + 2)]*sum_i^((m-3)/2) p^{2i} // t1 = f^alpha - let t1 = f.pow(\alpha); + let t1 = f.pow(alpha); // t2 = f^p let t2 = f.frobenius(1); // t3 = f^((p^2)alpha) * f^(3p(alpha) + 2p) @@ -404,7 +404,7 @@ fn shanks(f: &CubicExtField

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

-> { +impl Ord for CubicExtField

{ #[inline(always)] fn cmp(&self, other: &Self) -> Ordering { let c2_cmp = self.c2.cmp(&other.c2); From d9136e5282a4e6ef58d1521b1f6ee0b5c1f1d5c9 Mon Sep 17 00:00:00 2001 From: Solomon Date: Tue, 29 Mar 2022 13:40:34 -0700 Subject: [PATCH 06/26] WIP: Drafted square root algorithms for cubic extensions --- ff/src/fields/mod.rs | 2 +- ff/src/fields/models/cubic_extension.rs | 111 ++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index ac3931e1b..efaf9ddd9 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -84,7 +84,7 @@ pub trait Field: + From { type BasePrimeField: PrimeField; - + const SqrtPrecomp: SqrtPrecomputation; /// Returns the characteristic of the field, /// in little-endian representation. fn characteristic() -> &'static [u64] { diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 271c89d20..ec666791d 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -38,6 +38,7 @@ pub trait CubicExtConfig: 'static + Send + Sync { /// Frobenius endomorphism. type FrobCoeff: Field; + const PRECOMP : SqrtPrecomputation; /// The degree of the extension over the base prime field. const DEGREE_OVER_BASE_PRIME_FIELD: usize; @@ -183,6 +184,7 @@ impl One for CubicExtField

{ } impl Field for CubicExtField

{ + const SqrtPrecomp: SqrtPrecomputation = P::PRECOMP; type BasePrimeField = P::BasePrimeField; fn extension_degree() -> u64 { @@ -318,7 +320,33 @@ impl Field for CubicExtField

{ } } -fn tonelli_shanks(f: &CubicExtField

) -> Option> { +public enum SqrtPrecomputation { + ThreeModFour, + FiveModEight{TRACE: F::BigInt}, + NineModSixteen{TRACE: F::BigInt, d: F::BigInt, e: F::BigInt, c: F::BigInt}, + OneModSixteen{TRACE: F::BigInt, TRACE_MINUS_ONE_DIV_TWO: F::BigInt}, +} + +impl SqrtPrecomputation { + fn sqrt(&self) -> Option { + match self { + SqrtPrecomputation::ThreeModFour => { + shanks(self) + }, + SqrtPrecomputation::FiveModEight{TRACE: F::BigInt} => { + atkin(self, TRACE) + }, + SqrtPrecomputation::NineModSixteen{TRACE: F::BigInt, d: F::BigInt, e: F::BigInt, c: F::BigInt} => { + kong(self, TRACE, d, e, c) + }, + SqrtPrecomputation::OneModSixteen{TRACE: F::BigInt, TRACE_MINUS_ONE_DIV_TWO: F::BigInt} => { + tonelli_shanks(self, TRACE, TRACE_MINUS_ONE_DIV_TWO) + } + } + } +} + +fn tonelli_shanks(f: &CubicExtField

, TRACE: F::BigInt, TRACE_MINUS_ONE_DIV_TWO: F::BigInt) -> Option> { // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) // Actually this is just normal Tonelli-Shanks; since `P::Generator` // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` @@ -330,7 +358,7 @@ fn tonelli_shanks(f: &CubicExtField

) -> Option(f: &CubicExtField

) -> Option> { // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) // Using decomposition of (q-3)/ 4 = alpha + p[p(alpha) + (3a + 2)]*sum_i^((m-3)/2) p^{2i} + // alpha = (p - 3) / 4; + let alpha = (f.characteristic() - 3) / 4; // t1 = f^alpha - let t1 = f.pow(\alpha); + let t1 = f.pow(alpha); // t2 = f^p - let t2 = f.frobenius(1); + let t2 = f.frobenius_map(1); // t3 = f^((p^2)alpha) * f^(3p(alpha) + 2p) - let t3 = t2.frobenius(1).pow(alpha) * (t2.pow(3).pow(alpha) + t2.square()); + let t3 = t2.frobenius_map(1).pow(alpha) * (t2.pow(3).pow(alpha) + t2.square()); let mut r = CubicExtField::one(); let n = (CubicExtField::extension_degree() - 3)/2; for i in 1..(n+1) { - r *= t3.frobenius(2 * i); + r *= t3.frobenius_map(2 * i); let mut a_1 = t1 * r; - let mut x = a_1 * f; - let mut a_0 = a_1 * x; + let mut a_0 = a_1 * a_1 * f; + if (a_0 == -CubicExtField::one()) { + return None; + } + x +} + +fn atkin(f: &CubicExtField

, TRACE: F::BigInt) -> Option> { + // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 3) + // Using decomposition of (q-5)/ 8 = alpha + p[p(alpha) + (5a + 3)]*sum_i^((m-3)/2) p^{2i} + // Precomputation + let t = TRACE; + // alpha = (p - 5) / 8 + let alpha = (f.characteristic() - 5) / 8; + // t1 = f^alpha + let t1 = f.pow(alpha); + // t2 = f^p + let t2 = f.frobenius_map(1); + // t3 = f^((p^2)alpha) * f^(5p(alpha) + 3p) + let t3 = t2.frobenius_map(1).pow(alpha) * (t2.pow(5).pow(alpha) + t2.pow(3)); + let mut r = CubicExtField::one(); + let n = (CubicExtField::extension_degree() - 3)/2; + for i in 1..(n+1) { + r *= t3.frobenius_map(2 * i); + let mut a_1 = t1 * r; + let mut a_0 = a_1 * a_1 * f; + a_0 *= a_0; if (a_0 == -CubicExtField::one()) { return None; } + let b = t * a_1; + let i = 2 * b * f * b; + let x = a * b * (i - 1); x } +fn kong(f: &CubicExtField

, TRACE: F::BigInt, d: F::BigInt, e: F::BigInt, c: F::BigInt) -> Option> { + // https://eprint.iacr.org/2012/685.pdf (page 11, algorithm 4) + // Using decomposition of (q-9)/16 = alpha + p[p(alpha) + (9a + 5)]*sum_i^((m-3)/2) p^{2i} + // Precomputation + let t = TRACE; + // alpha = (p - 9) / 16 + let alpha = (f.characteristic() - 9) / 16; + // t1 = f^alpha + let t1 = f.pow(alpha); + // t2 = f^p + let t2 = f.frobenius_map(1); + // t3 = f^((p^2)alpha) * f^(9p(alpha) + 5p) + let t3 = t2.frobenius_map(1).pow(alpha) * (t2.pow(9).pow(alpha) + t2.pow(5)); + let mut r = CubicExtField::one(); + let n = (CubicExtField::extension_degree() - 3)/2; + for i in 1..(n+1) { + r *= t3.frobenius_map(2 * i); + let mut a_1 = t1 * r; + let mut a_0 = a_1 * a_1 * f; + a_0 = a_0.pow(4); + if (a_0 == -CubicExtField::one()) { + return None; + } + let b = t * a_1; + let i = 2 * b * f * b; + let r = i * i; + if (r == -CubicExtField::one()) { + let x = a * b * (i - 1); + return x; + } else { + let u = b * d; + let i = 2 * u * u * e * f; + let x = u * c * f * (i - 1); + return x; + } +} + /// `CubicExtField` elements are ordered lexicographically. impl Ord for CubicExtField

-> { #[inline(always)] From 547542608536a7bfdbd68a66b022069d5ae5becb Mon Sep 17 00:00:00 2001 From: Solomon Date: Tue, 29 Mar 2022 15:24:03 -0700 Subject: [PATCH 07/26] Small fix --- ff/src/fields/models/cubic_extension.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index cb69fbc69..b9ccbb4d9 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -266,7 +266,7 @@ impl Field for CubicExtField

{ } fn sqrt(&self) -> Option { - tonelli_shanks(self) + self.SqrtPrecomp.sqrt() } fn inverse(&self) -> Option { From 4374ec7e22d264bc724d8b0c2fa21a7f853de603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Wed, 25 May 2022 13:21:52 +0200 Subject: [PATCH 08/26] Remove old imports Fix --- ec/src/hashing/curve_maps/swu/mod.rs | 2 +- ec/src/hashing/tests/mod.rs | 4 ++-- ec/src/models/mod.rs | 1 - ff/src/fields/mod.rs | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ec/src/hashing/curve_maps/swu/mod.rs b/ec/src/hashing/curve_maps/swu/mod.rs index 78c886965..5d950e1a5 100644 --- a/ec/src/hashing/curve_maps/swu/mod.rs +++ b/ec/src/hashing/curve_maps/swu/mod.rs @@ -1,5 +1,5 @@ use crate::models::SWModelParameters; -use ark_ff::{BigInteger, Field, One, PrimeField, SquareRootField, Zero}; +use ark_ff::{BigInteger, Field, One, PrimeField, Zero}; use ark_std::string::ToString; use core::marker::PhantomData; diff --git a/ec/src/hashing/tests/mod.rs b/ec/src/hashing/tests/mod.rs index 8f9326daf..884f887e4 100644 --- a/ec/src/hashing/tests/mod.rs +++ b/ec/src/hashing/tests/mod.rs @@ -11,10 +11,10 @@ use crate::{ short_weierstrass_jacobian::GroupAffine, ModelParameters, }; +use ark_ff::Field; use ark_ff::field_hashers::DefaultFieldHasher; use ark_ff::{biginteger::BigInteger64, fields::Fp64, BigInt, MontBackend, MontFp}; -use ark_ff::SquareRootField; use ark_std::vec::Vec; use ark_test_curves::bls12_381::{Fq, Fq2, Fq6}; use hashbrown::HashMap; @@ -118,7 +118,7 @@ fn test_field_division() { /// Check that the hashing parameters are sane: zeta should be a non-square #[test] fn checking_the_hashing_parameters() { - assert!(SquareRootField::legendre(&TestSWUMapToCurveParams::ZETA).is_qr() == false); + assert!(Field::legendre(&TestSWUMapToCurveParams::ZETA).is_qr() == false); } /// The point of the test is to get a simple SWU compatible curve and make diff --git a/ec/src/models/mod.rs b/ec/src/models/mod.rs index 00b418a46..e9a828666 100644 --- a/ec/src/models/mod.rs +++ b/ec/src/models/mod.rs @@ -1,4 +1,3 @@ -use crate::AffineCurve; use crate::ProjectiveCurve; use ark_ff::{Field, PrimeField, Zero}; diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index d422ac84b..eba7205e0 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -392,7 +392,7 @@ impl LegendreSymbol { /// /// # Examples /// ``` - /// # use ark_test_curves::{Fp2Config, LegendreSymbol, bls12_381::{Fq, Fq2Config}}; + /// # use ark_test_curves::{Fp2Config, Field, LegendreSymbol, bls12_381::{Fq, Fq2Config}}; /// let a: Fq = Fq2Config::NONRESIDUE; /// assert!(a.legendre().is_qnr()); /// ``` From ba4f0cd42b09a7918d850d8ed07fb2967972a9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Wed, 25 May 2022 10:12:04 +0200 Subject: [PATCH 09/26] As a first step, use Tonelli-Shanks for cubic sqrt --- ff/src/fields/mod.rs | 2 - ff/src/fields/models/cubic_extension.rs | 199 ++------------------ ff/src/fields/models/fp/mod.rs | 58 +++--- ff/src/fields/models/fp3.rs | 20 -- ff/src/fields/models/quadratic_extension.rs | 77 ++++---- 5 files changed, 81 insertions(+), 275 deletions(-) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index eba7205e0..d492a344b 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -87,8 +87,6 @@ pub trait Field: { type BasePrimeField: PrimeField; - const SqrtPrecomp: SqrtPrecomputation; - type BasePrimeFieldIter: Iterator; /// Returns the characteristic of the field, diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 7696ba21a..1fcd6e1b7 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -22,7 +22,7 @@ use ark_std::rand::{ use crate::{ bytes::{FromBytes, ToBytes}, fields::{Field, PrimeField}, - ToConstraintField, UniformRand, + ToConstraintField, UniformRand, LegendreSymbol, }; /// Defines a Cubic extension field from a cubic non-residue. @@ -39,7 +39,6 @@ pub trait CubicExtConfig: 'static + Send + Sync { /// Frobenius endomorphism. type FrobCoeff: Field; - const PRECOMP : SqrtPrecomputation; /// The degree of the extension over the base prime field. const DEGREE_OVER_BASE_PRIME_FIELD: usize; @@ -186,7 +185,6 @@ impl One for CubicExtField

{ type BaseFieldIter

= <

::BaseField as Field>::BasePrimeFieldIter; impl Field for CubicExtField

{ - const SqrtPrecomp: SqrtPrecomputation = P::PRECOMP; type BasePrimeField = P::BasePrimeField; type BasePrimeFieldIter = Chain, Chain, BaseFieldIter

>>; @@ -276,8 +274,22 @@ impl Field for CubicExtField

{ self } + /// Returns the Legendre symbol. + fn legendre(&self) -> LegendreSymbol { + self.norm().legendre() + } + + /// Returns the square root of self, if it exists. fn sqrt(&self) -> Option { - self.SqrtPrecomp.sqrt() + sqrt_impl!(Self, P, self) + } + + /// Sets `self` to be the square root of `self`, if it exists. + fn sqrt_in_place(&mut self) -> Option<&mut Self> { + (*self).sqrt().map(|sqrt| { + *self = sqrt; + self + }) } fn inverse(&self) -> Option { @@ -330,185 +342,6 @@ impl Field for CubicExtField

{ P::mul_base_field_by_frob_coeff(&mut self.c1, &mut self.c2, power); } } - -pub enum SqrtPrecomputation { - ThreeModFour, - FiveModEight{TRACE: F::BigInt}, - NineModSixteen{TRACE: F::BigInt, d: F::BigInt, e: F::BigInt, c: F::BigInt}, - OneModSixteen{TRACE: F::BigInt, TRACE_MINUS_ONE_DIV_TWO: F::BigInt}, -} - -impl SqrtPrecomputation { - fn sqrt(&self) -> Option { - match self { - SqrtPrecomputation::ThreeModFour => { - shanks(self) - }, - SqrtPrecomputation::FiveModEight{TRACE: F::BigInt} => { - atkin(self, TRACE) - }, - SqrtPrecomputation::NineModSixteen{TRACE: F::BigInt, d: F::BigInt, e: F::BigInt, c: F::BigInt} => { - kong(self, TRACE, d, e, c) - }, - SqrtPrecomputation::OneModSixteen{TRACE: F::BigInt, TRACE_MINUS_ONE_DIV_TWO: F::BigInt} => { - tonelli_shanks(self, TRACE, TRACE_MINUS_ONE_DIV_TWO) - } - } - } -} - -fn tonelli_shanks(f: &CubicExtField

, TRACE: F::BigInt, TRACE_MINUS_ONE_DIV_TWO: F::BigInt) -> Option> { - // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) - // Actually this is just normal Tonelli-Shanks; since `P::Generator` - // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` - // is also a quadratic non-residue (since `t` is odd). - if f.is_zero() { - return Some(CubicExtField::zero()); - } - // Try computing the square root (x at the end of the algorithm) - // Check at the end of the algorithm if x was a square root - // Begin Tonelli-Shanks - let mut z = CubicExtField::qnr_to_t(); - let mut w = f.pow(TRACE_MINUS_ONE_DIV_TWO); - let mut x = w * f; - let mut b = x * &w; - - let mut v = P::TWO_ADICITY as usize; - - while !b.is_one() { - let mut k = 0usize; - - let mut b2k = b; - while !b2k.is_one() { - // invariant: b2k = b^(2^k) after entering this loop - b2k.square_in_place(); - k += 1; - } - - if k == (P::TWO_ADICITY as usize) { - // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, - // which means that no square root exists. - return None; - } - let j = v - k; - w = z; - for _ in 1..j { - w.square_in_place(); - } - - z = w.square(); - b *= &z; - x *= &w; - v = k; - } - // Is x the square root? If so, return it. - if (x.square() == *f) { - return Some(x); - } else { - // Consistency check that if no square root is found, - // it is because none exists. - #[cfg(debug_assertions)] - { - use crate::fields::LegendreSymbol::*; - if f.legendre() != QuadraticNonResidue { - panic!("Input has a square root per its legendre symbol, but it was not found") - } - } - None - } -} - -fn shanks(f: &CubicExtField

) -> Option> { - // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) - // Using decomposition of (q-3)/ 4 = alpha + p[p(alpha) + (3a + 2)]*sum_i^((m-3)/2) p^{2i} - - // alpha = (p - 3) / 4; - let alpha = (f.characteristic() - 3) / 4; - // t1 = f^alpha - let t1 = f.pow(alpha); - // t2 = f^p - let t2 = f.frobenius_map(1); - // t3 = f^((p^2)alpha) * f^(3p(alpha) + 2p) - let t3 = t2.frobenius_map(1).pow(alpha) * (t2.pow(3).pow(alpha) + t2.square()); - let mut r = CubicExtField::one(); - let n = (CubicExtField::extension_degree() - 3)/2; - for i in 1..(n+1) { - r *= t3.frobenius_map(2 * i); - - let mut a_1 = t1 * r; - let mut a_0 = a_1 * a_1 * f; - if (a_0 == -CubicExtField::one()) { - return None; - } - x -} - -fn atkin(f: &CubicExtField

, TRACE: F::BigInt) -> Option> { - // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 3) - // Using decomposition of (q-5)/ 8 = alpha + p[p(alpha) + (5a + 3)]*sum_i^((m-3)/2) p^{2i} - // Precomputation - let t = TRACE; - // alpha = (p - 5) / 8 - let alpha = (f.characteristic() - 5) / 8; - // t1 = f^alpha - let t1 = f.pow(alpha); - // t2 = f^p - let t2 = f.frobenius_map(1); - // t3 = f^((p^2)alpha) * f^(5p(alpha) + 3p) - let t3 = t2.frobenius_map(1).pow(alpha) * (t2.pow(5).pow(alpha) + t2.pow(3)); - let mut r = CubicExtField::one(); - let n = (CubicExtField::extension_degree() - 3)/2; - for i in 1..(n+1) { - r *= t3.frobenius_map(2 * i); - let mut a_1 = t1 * r; - let mut a_0 = a_1 * a_1 * f; - a_0 *= a_0; - if (a_0 == -CubicExtField::one()) { - return None; - } - let b = t * a_1; - let i = 2 * b * f * b; - let x = a * b * (i - 1); - x -} - -fn kong(f: &CubicExtField

, TRACE: F::BigInt, d: F::BigInt, e: F::BigInt, c: F::BigInt) -> Option> { - // https://eprint.iacr.org/2012/685.pdf (page 11, algorithm 4) - // Using decomposition of (q-9)/16 = alpha + p[p(alpha) + (9a + 5)]*sum_i^((m-3)/2) p^{2i} - // Precomputation - let t = TRACE; - // alpha = (p - 9) / 16 - let alpha = (f.characteristic() - 9) / 16; - // t1 = f^alpha - let t1 = f.pow(alpha); - // t2 = f^p - let t2 = f.frobenius_map(1); - // t3 = f^((p^2)alpha) * f^(9p(alpha) + 5p) - let t3 = t2.frobenius_map(1).pow(alpha) * (t2.pow(9).pow(alpha) + t2.pow(5)); - let mut r = CubicExtField::one(); - let n = (CubicExtField::extension_degree() - 3)/2; - for i in 1..(n+1) { - r *= t3.frobenius_map(2 * i); - let mut a_1 = t1 * r; - let mut a_0 = a_1 * a_1 * f; - a_0 = a_0.pow(4); - if (a_0 == -CubicExtField::one()) { - return None; - } - let b = t * a_1; - let i = 2 * b * f * b; - let r = i * i; - if (r == -CubicExtField::one()) { - let x = a * b * (i - 1); - return x; - } else { - let u = b * d; - let i = 2 * u * u * e * f; - let x = u * c * f * (i - 1); - return x; - } -} - /// `CubicExtField` elements are ordered lexicographically. impl Ord for CubicExtField

{ #[inline(always)] diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 54509d0a9..20892173c 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -20,7 +20,7 @@ mod montgomery_backend; pub use montgomery_backend::*; use crate::{ - BigInt, BigInteger, FftField, Field, FromBytes, LegendreSymbol, PrimeField, SquareRootField, + BigInt, BigInteger, FftField, Field, FromBytes, LegendreSymbol, PrimeField, ToBytes, }; /// A trait that specifies the configuration of a prime field. @@ -351,36 +351,7 @@ impl, const N: usize> Field for Fp { /// The Frobenius map has no effect in a prime field. #[inline] fn frobenius_map(&mut self, _: usize) {} -} - -impl, const N: usize> PrimeField for Fp { - type BigInt = BigInt; - const MODULUS: Self::BigInt = P::MODULUS; - const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt = P::MODULUS.divide_by_2_round_down(); - const MODULUS_BIT_SIZE: u32 = P::MODULUS.const_num_bits(); - const TRACE: Self::BigInt = P::MODULUS.two_adic_coefficient(); - const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt = Self::TRACE.divide_by_2_round_down(); - - #[inline] - fn from_bigint(r: BigInt) -> Option { - P::from_bigint(r) - } - - fn into_bigint(&self) -> BigInt { - P::into_bigint(*self) - } -} - -impl, const N: usize> FftField for Fp { - const GENERATOR: Self = P::GENERATOR; - const TWO_ADICITY: u32 = P::TWO_ADICITY; - const TWO_ADIC_ROOT_OF_UNITY: Self = P::TWO_ADIC_ROOT_OF_UNITY; - const SMALL_SUBGROUP_BASE: Option = P::SMALL_SUBGROUP_BASE; - const SMALL_SUBGROUP_BASE_ADICITY: Option = P::SMALL_SUBGROUP_BASE_ADICITY; - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = P::LARGE_SUBGROUP_ROOT_OF_UNITY; -} -impl, const N: usize> SquareRootField for Fp { #[inline] fn legendre(&self) -> LegendreSymbol { use crate::fields::LegendreSymbol::*; @@ -409,6 +380,33 @@ impl, const N: usize> SquareRootField for Fp { } } +impl, const N: usize> PrimeField for Fp { + type BigInt = BigInt; + const MODULUS: Self::BigInt = P::MODULUS; + const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt = P::MODULUS.divide_by_2_round_down(); + const MODULUS_BIT_SIZE: u32 = P::MODULUS.const_num_bits(); + const TRACE: Self::BigInt = P::MODULUS.two_adic_coefficient(); + const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt = Self::TRACE.divide_by_2_round_down(); + + #[inline] + fn from_bigint(r: BigInt) -> Option { + P::from_bigint(r) + } + + fn into_bigint(&self) -> BigInt { + P::into_bigint(*self) + } +} + +impl, const N: usize> FftField for Fp { + const GENERATOR: Self = P::GENERATOR; + const TWO_ADICITY: u32 = P::TWO_ADICITY; + const TWO_ADIC_ROOT_OF_UNITY: Self = P::TWO_ADIC_ROOT_OF_UNITY; + const SMALL_SUBGROUP_BASE: Option = P::SMALL_SUBGROUP_BASE; + const SMALL_SUBGROUP_BASE_ADICITY: Option = P::SMALL_SUBGROUP_BASE_ADICITY; + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = P::LARGE_SUBGROUP_ROOT_OF_UNITY; +} + /// Note that this implementation of `Ord` compares field elements viewing /// them as integers in the range 0, 1, ..., P::MODULUS - 1. However, other /// implementations of `PrimeField` might choose a different ordering, and diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index 0daa55293..e07f38cb6 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -98,23 +98,3 @@ impl Fp3

{ P::QUADRATIC_NONRESIDUE_TO_T } } - -impl Field for Fp3

{ - /// Returns the Legendre symbol. - fn legendre(&self) -> LegendreSymbol { - self.norm().legendre() - } - - /// Returns the square root of self, if it exists. - fn sqrt(&self) -> Option { - sqrt_impl!(Self, P, self) - } - - /// Sets `self` to be the square root of `self`, if it exists. - fn sqrt_in_place(&mut self) -> Option<&mut Self> { - (*self).sqrt().map(|sqrt| { - *self = sqrt; - self - }) - } -} diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 2e3bc8869..c6b120e65 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -251,7 +251,10 @@ impl One for QuadExtField

{ } type BaseFieldIter

= <

::BaseField as Field>::BasePrimeFieldIter; -impl Field for QuadExtField

{ +impl Field for QuadExtField

+// where +// P::BaseField: From, +{ type BasePrimeField = P::BasePrimeField; type BasePrimeFieldIter = Chain, BaseFieldIter

>; @@ -363,44 +366,6 @@ impl Field for QuadExtField

{ } } - fn inverse(&self) -> Option { - if self.is_zero() { - None - } else { - // Guide to Pairing-based Cryptography, Algorithm 5.19. - // v1 = c1.square() - let v1 = self.c1.square(); - // v0 = c0.square() - beta * v1 - let v0 = P::sub_and_mul_base_field_by_nonresidue(&self.c0.square(), &v1); - - v0.inverse().map(|v1| { - let c0 = self.c0 * &v1; - let c1 = -(self.c1 * &v1); - Self::new(c0, c1) - }) - } - } - - fn inverse_in_place(&mut self) -> Option<&mut Self> { - if let Some(inverse) = self.inverse() { - *self = inverse; - Some(self) - } else { - None - } - } - - fn frobenius_map(&mut self, power: usize) { - self.c0.frobenius_map(power); - self.c1.frobenius_map(power); - P::mul_base_field_by_frob_coeff(&mut self.c1, power); - } -} - -impl<'a, P: QuadExtConfig> Field for QuadExtField

-where - P::BaseField: Field + From, -{ fn legendre(&self) -> LegendreSymbol { // The LegendreSymbol in a field of order q for an element x can be // computed as x^((q-1)/2). @@ -446,7 +411,7 @@ where two_inv.div2(); let two_inv = P::BasePrimeField::from(two_inv); - let two_inv = P::BaseField::from(two_inv); + let two_inv = P::BaseField::from_base_prime_field_elems(&[two_inv]).unwrap(); alpha.sqrt().and_then(|alpha| { let mut delta = (alpha + &self.c0) * &two_inv; @@ -481,6 +446,38 @@ where self }) } + fn inverse(&self) -> Option { + if self.is_zero() { + None + } else { + // Guide to Pairing-based Cryptography, Algorithm 5.19. + // v1 = c1.square() + let v1 = self.c1.square(); + // v0 = c0.square() - beta * v1 + let v0 = P::sub_and_mul_base_field_by_nonresidue(&self.c0.square(), &v1); + + v0.inverse().map(|v1| { + let c0 = self.c0 * &v1; + let c1 = -(self.c1 * &v1); + Self::new(c0, c1) + }) + } + } + + fn inverse_in_place(&mut self) -> Option<&mut Self> { + if let Some(inverse) = self.inverse() { + *self = inverse; + Some(self) + } else { + None + } + } + + fn frobenius_map(&mut self, power: usize) { + self.c0.frobenius_map(power); + self.c1.frobenius_map(power); + P::mul_base_field_by_frob_coeff(&mut self.c1, power); + } } /// `QuadExtField` elements are ordered lexicographically. From cff8e61ba819b52e51d266d1dcba0e8f0715302c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Wed, 25 May 2022 13:27:55 +0200 Subject: [PATCH 10/26] Expose attributes on CubicExtField - `TWO_ADICITY` - `TRACE_MINUS_ONE_DIV_TWO` - `QUADRATIC_NONRESIDUE_TO_T` needed to compute sqrt in cubic extensions --- ff/src/fields/arithmetic.rs | 2 +- ff/src/fields/models/cubic_extension.rs | 8 +++++++- ff/src/fields/models/fp3.rs | 9 +++------ ff/src/fields/models/fp6_3over2.rs | 9 +++++++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index 985322595..3504f14d5 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -10,7 +10,7 @@ macro_rules! sqrt_impl { // Try computing the square root (x at the end of the algorithm) // Check at the end of the algorithm if x was a square root // Begin Tonelli-Shanks - let mut z = $Self::qnr_to_t(); + let mut z = $P::QUADRATIC_NONRESIDUE_TO_T; let mut w = $self.pow($P::TRACE_MINUS_ONE_DIV_TWO); let mut x = w * $self; let mut b = x * &w; diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 1fcd6e1b7..7c6e6505c 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -26,7 +26,7 @@ use crate::{ }; /// Defines a Cubic extension field from a cubic non-residue. -pub trait CubicExtConfig: 'static + Send + Sync { +pub trait CubicExtConfig: 'static + Send + Sync + Sized { /// The prime field that this cubic extension is eventually an extension of. type BasePrimeField: PrimeField; /// The base field that this field is a cubic extension of. @@ -42,6 +42,12 @@ pub trait CubicExtConfig: 'static + Send + Sync { /// The degree of the extension over the base prime field. const DEGREE_OVER_BASE_PRIME_FIELD: usize; + /// p^3 - 1 = 2^s * t, where t is odd. + const TWO_ADICITY: u32; + const TRACE_MINUS_ONE_DIV_TWO: &'static [u64]; + /// t-th power of a quadratic nonresidue in Fp3. + const QUADRATIC_NONRESIDUE_TO_T: CubicExtField; + /// The cubic non-residue used to construct the extension. const NONRESIDUE: Self::BaseField; diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index e07f38cb6..b6feebe41 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -40,6 +40,9 @@ impl CubicExtConfig for Fp3ConfigWrapper

{ const DEGREE_OVER_BASE_PRIME_FIELD: usize = 3; const NONRESIDUE: Self::BaseField = P::NONRESIDUE; + const TWO_ADICITY: u32 = P::TWO_ADICITY; + const TRACE_MINUS_ONE_DIV_TWO: &'static [u64] = P::TRACE_MINUS_ONE_DIV_TWO; + const QUADRATIC_NONRESIDUE_TO_T: CubicExtField = P::QUADRATIC_NONRESIDUE_TO_T; const FROBENIUS_COEFF_C1: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP3_C1; const FROBENIUS_COEFF_C2: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP3_C2; @@ -91,10 +94,4 @@ impl Fp3

{ self.c1.mul_assign(value); self.c2.mul_assign(value); } - - /// Returns the value of QNR^T. - #[inline] - pub fn qnr_to_t() -> Self { - P::QUADRATIC_NONRESIDUE_TO_T - } } diff --git a/ff/src/fields/models/fp6_3over2.rs b/ff/src/fields/models/fp6_3over2.rs index ccbb407b5..434e411a4 100644 --- a/ff/src/fields/models/fp6_3over2.rs +++ b/ff/src/fields/models/fp6_3over2.rs @@ -11,6 +11,12 @@ pub trait Fp6Config: 'static + Send + Sync + Copy { const FROBENIUS_COEFF_FP6_C1: &'static [Fp2]; const FROBENIUS_COEFF_FP6_C2: &'static [Fp2]; + /// p^3 - 1 = 2^s * t, where t is odd. + const TWO_ADICITY: u32; + const TRACE_MINUS_ONE_DIV_TWO: &'static [u64]; + /// t-th power of a quadratic nonresidue in Fp3. + const QUADRATIC_NONRESIDUE_TO_T: Fp6; + #[inline(always)] fn mul_fp2_by_nonresidue(fe: &Fp2) -> Fp2 { Self::NONRESIDUE * fe @@ -27,6 +33,9 @@ impl CubicExtConfig for Fp6ConfigWrapper

{ const DEGREE_OVER_BASE_PRIME_FIELD: usize = 6; const NONRESIDUE: Self::BaseField = P::NONRESIDUE; + const TWO_ADICITY: u32 = P::TWO_ADICITY; + const TRACE_MINUS_ONE_DIV_TWO: &'static [u64] = P::TRACE_MINUS_ONE_DIV_TWO; + const QUADRATIC_NONRESIDUE_TO_T: CubicExtField = P::QUADRATIC_NONRESIDUE_TO_T; const FROBENIUS_COEFF_C1: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP6_C1; const FROBENIUS_COEFF_C2: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP6_C2; From 69a4c3b4f8776544832c808d0ba04f06385ebbc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Wed, 13 Jul 2022 16:43:52 +0200 Subject: [PATCH 11/26] re-introduce SQRT_PRECOMP --- ff/src/fields/arithmetic.rs | 13 ++++++---- ff/src/fields/mod.rs | 27 +++++++++++++++++++++ ff/src/fields/models/cubic_extension.rs | 19 +++++++++------ ff/src/fields/models/fp/mod.rs | 7 +++--- ff/src/fields/models/fp3.rs | 10 +++++--- ff/src/fields/models/fp6_3over2.rs | 11 ++------- ff/src/fields/models/quadratic_extension.rs | 4 ++- 7 files changed, 60 insertions(+), 31 deletions(-) diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index 3504f14d5..a5eaf75d1 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -1,5 +1,5 @@ macro_rules! sqrt_impl { - ($Self:ident, $P:tt, $self:expr) => {{ + ($Self:ident, $self:expr, $two_adicity:tt, $trace:tt, $quad:tt) => {{ // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) // Actually this is just normal Tonelli-Shanks; since `P::Generator` // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` @@ -10,12 +10,15 @@ macro_rules! sqrt_impl { // Try computing the square root (x at the end of the algorithm) // Check at the end of the algorithm if x was a square root // Begin Tonelli-Shanks - let mut z = $P::QUADRATIC_NONRESIDUE_TO_T; - let mut w = $self.pow($P::TRACE_MINUS_ONE_DIV_TWO); + // let mut z = $P::QUADRATIC_NONRESIDUE_TO_T; + let mut z = *$quad; + // let mut w = $self.pow($P::TRACE_MINUS_ONE_DIV_TWO); + let mut w = $self.pow($trace); let mut x = w * $self; let mut b = x * &w; - let mut v = $P::TWO_ADICITY as usize; + // let mut v = $P::TWO_ADICITY as usize; + let mut v = *$two_adicity as usize; while !b.is_one() { let mut k = 0usize; @@ -27,7 +30,7 @@ macro_rules! sqrt_impl { k += 1; } - if k == ($P::TWO_ADICITY as usize) { + if k == (*$two_adicity as usize) { // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, // which means that no square root exists. return None; diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index d492a344b..b44cad5b8 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -87,6 +87,8 @@ pub trait Field: { type BasePrimeField: PrimeField; + const SQRT_PRECOMP: Option>; + type BasePrimeFieldIter: Iterator; /// Returns the characteristic of the field, @@ -414,6 +416,31 @@ impl LegendreSymbol { } } +pub enum SqrtPrecomputation { + // Tonelli-Shanks algorithm works for all elements, no matter what the modulus is. + TonelliShanks(u32, &'static [u64], F), +} + +impl SqrtPrecomputation { + fn sqrt(&self, elem: &F) -> Option { + match self { + SqrtPrecomputation::TonelliShanks( + two_adicity, + trace_minus_one_div_two, + quad_non_residue_to_t, + ) => { + sqrt_impl!( + F, + elem, + two_adicity, + trace_minus_one_div_two, + quad_non_residue_to_t + ) + }, + } + } +} + /// Iterates over a slice of `u64` in *big-endian* order. #[derive(Debug)] pub struct BitIteratorBE> { diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 7c6e6505c..7a74d9cd5 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -22,7 +22,7 @@ use ark_std::rand::{ use crate::{ bytes::{FromBytes, ToBytes}, fields::{Field, PrimeField}, - ToConstraintField, UniformRand, LegendreSymbol, + LegendreSymbol, SqrtPrecomputation, ToConstraintField, UniformRand, }; /// Defines a Cubic extension field from a cubic non-residue. @@ -39,15 +39,11 @@ pub trait CubicExtConfig: 'static + Send + Sync + Sized { /// Frobenius endomorphism. type FrobCoeff: Field; + const PRECOMP: Option>>; + /// The degree of the extension over the base prime field. const DEGREE_OVER_BASE_PRIME_FIELD: usize; - /// p^3 - 1 = 2^s * t, where t is odd. - const TWO_ADICITY: u32; - const TRACE_MINUS_ONE_DIV_TWO: &'static [u64]; - /// t-th power of a quadratic nonresidue in Fp3. - const QUADRATIC_NONRESIDUE_TO_T: CubicExtField; - /// The cubic non-residue used to construct the extension. const NONRESIDUE: Self::BaseField; @@ -192,6 +188,7 @@ impl One for CubicExtField

{ type BaseFieldIter

= <

::BaseField as Field>::BasePrimeFieldIter; impl Field for CubicExtField

{ type BasePrimeField = P::BasePrimeField; + const SQRT_PRECOMP: Option> = P::PRECOMP; type BasePrimeFieldIter = Chain, Chain, BaseFieldIter

>>; fn extension_degree() -> u64 { @@ -287,7 +284,12 @@ impl Field for CubicExtField

{ /// Returns the square root of self, if it exists. fn sqrt(&self) -> Option { - sqrt_impl!(Self, P, self) + // sqrt computation needs certain params to be defined, like + // `TRACE_MINUS_ONE_DIV_TWO` + match Self::SQRT_PRECOMP { + Some(tv) => tv.sqrt(self), + None => unimplemented!(), + } } /// Sets `self` to be the square root of `self`, if it exists. @@ -348,6 +350,7 @@ impl Field for CubicExtField

{ P::mul_base_field_by_frob_coeff(&mut self.c1, &mut self.c2, power); } } + /// `CubicExtField` elements are ordered lexicographically. impl Ord for CubicExtField

{ #[inline(always)] diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 20892173c..5d1433586 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -19,10 +19,7 @@ use ark_std::{ mod montgomery_backend; pub use montgomery_backend::*; -use crate::{ - BigInt, BigInteger, FftField, Field, FromBytes, LegendreSymbol, PrimeField, - ToBytes, -}; +use crate::{BigInt, BigInteger, FftField, Field, FromBytes, LegendreSymbol, PrimeField, ToBytes}; /// A trait that specifies the configuration of a prime field. /// Also specifies how to perform arithmetic on field elements. pub trait FpConfig: Send + Sync + 'static + Sized { @@ -244,6 +241,8 @@ impl, const N: usize> Field for Fp { type BasePrimeField = Self; type BasePrimeFieldIter = iter::Once; + const SQRT_PRECOMP: Option> = None; + fn extension_degree() -> u64 { 1 } diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index b6feebe41..eb84de69f 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -40,10 +40,12 @@ impl CubicExtConfig for Fp3ConfigWrapper

{ const DEGREE_OVER_BASE_PRIME_FIELD: usize = 3; const NONRESIDUE: Self::BaseField = P::NONRESIDUE; - const TWO_ADICITY: u32 = P::TWO_ADICITY; - const TRACE_MINUS_ONE_DIV_TWO: &'static [u64] = P::TRACE_MINUS_ONE_DIV_TWO; - const QUADRATIC_NONRESIDUE_TO_T: CubicExtField = P::QUADRATIC_NONRESIDUE_TO_T; - + const PRECOMP: Option>> = + Some(SqrtPrecomputation::TonelliShanks( + P::TWO_ADICITY, + P::TRACE_MINUS_ONE_DIV_TWO, + P::QUADRATIC_NONRESIDUE_TO_T, + )); const FROBENIUS_COEFF_C1: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP3_C1; const FROBENIUS_COEFF_C2: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP3_C2; diff --git a/ff/src/fields/models/fp6_3over2.rs b/ff/src/fields/models/fp6_3over2.rs index 434e411a4..4154bd3a9 100644 --- a/ff/src/fields/models/fp6_3over2.rs +++ b/ff/src/fields/models/fp6_3over2.rs @@ -11,12 +11,6 @@ pub trait Fp6Config: 'static + Send + Sync + Copy { const FROBENIUS_COEFF_FP6_C1: &'static [Fp2]; const FROBENIUS_COEFF_FP6_C2: &'static [Fp2]; - /// p^3 - 1 = 2^s * t, where t is odd. - const TWO_ADICITY: u32; - const TRACE_MINUS_ONE_DIV_TWO: &'static [u64]; - /// t-th power of a quadratic nonresidue in Fp3. - const QUADRATIC_NONRESIDUE_TO_T: Fp6; - #[inline(always)] fn mul_fp2_by_nonresidue(fe: &Fp2) -> Fp2 { Self::NONRESIDUE * fe @@ -30,12 +24,11 @@ impl CubicExtConfig for Fp6ConfigWrapper

{ type BaseField = Fp2; type FrobCoeff = Fp2; + const PRECOMP: Option>> = None; + const DEGREE_OVER_BASE_PRIME_FIELD: usize = 6; const NONRESIDUE: Self::BaseField = P::NONRESIDUE; - const TWO_ADICITY: u32 = P::TWO_ADICITY; - const TRACE_MINUS_ONE_DIV_TWO: &'static [u64] = P::TRACE_MINUS_ONE_DIV_TWO; - const QUADRATIC_NONRESIDUE_TO_T: CubicExtField = P::QUADRATIC_NONRESIDUE_TO_T; const FROBENIUS_COEFF_C1: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP6_C1; const FROBENIUS_COEFF_C2: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP6_C2; diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index c6b120e65..a04fc6577 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -23,7 +23,7 @@ use crate::{ biginteger::BigInteger, bytes::{FromBytes, ToBytes}, fields::{Field, LegendreSymbol, PrimeField}, - ToConstraintField, UniformRand, + SqrtPrecomputation, ToConstraintField, UniformRand, }; /// Defines a Quadratic extension field from a quadratic non-residue. @@ -257,6 +257,8 @@ impl Field for QuadExtField

{ type BasePrimeField = P::BasePrimeField; + const SQRT_PRECOMP: Option> = None; + type BasePrimeFieldIter = Chain, BaseFieldIter

>; fn extension_degree() -> u64 { From b6713e91279c915b9c80b4bd5dea641414aa6df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Wed, 13 Jul 2022 17:12:57 +0200 Subject: [PATCH 12/26] Call `sqrt_impl` macro from FpConfig square_root --- ff/src/fields/arithmetic.rs | 8 ++--- ff/src/fields/models/fp/mod.rs | 66 +++++----------------------------- 2 files changed, 11 insertions(+), 63 deletions(-) diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index a5eaf75d1..193a08436 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -1,5 +1,5 @@ macro_rules! sqrt_impl { - ($Self:ident, $self:expr, $two_adicity:tt, $trace:tt, $quad:tt) => {{ + ($Self:ident, $self:expr, $two_adicity:expr, $trace_minus_one_div_two:expr, $quadratic_nonresidue:expr) => {{ // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) // Actually this is just normal Tonelli-Shanks; since `P::Generator` // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` @@ -10,10 +10,8 @@ macro_rules! sqrt_impl { // Try computing the square root (x at the end of the algorithm) // Check at the end of the algorithm if x was a square root // Begin Tonelli-Shanks - // let mut z = $P::QUADRATIC_NONRESIDUE_TO_T; - let mut z = *$quad; - // let mut w = $self.pow($P::TRACE_MINUS_ONE_DIV_TWO); - let mut w = $self.pow($trace); + let mut z = *$quadratic_nonresidue; + let mut w = $self.pow($trace_minus_one_div_two); let mut x = w * $self; let mut b = x * &w; diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 5d1433586..e88099fc4 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -79,65 +79,15 @@ pub trait FpConfig: Send + Sync + 'static + Sized { fn inverse(a: &Fp) -> Option>; /// Compute the square root of a, if it exists. + #[allow(unused_parens)] fn square_root(a: &Fp) -> Option> { - // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) - // Actually this is just normal Tonelli-Shanks; since [`Self::GENERATOR`] - // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` - // is also a quadratic non-residue (since `t` is odd). - if a.is_zero() { - return Some(Fp::zero()); - } - // Try computing the square root (x at the end of the algorithm) - // Check at the end of the algorithm if x was a square root - // Begin Tonelli-Shanks - let mut z = Fp::TWO_ADIC_ROOT_OF_UNITY; - let mut w = a.pow(Fp::::TRACE_MINUS_ONE_DIV_TWO); - let mut x = w * a; - let mut b = x * &w; - - let mut v = Self::TWO_ADICITY as usize; - - while !b.is_one() { - let mut k = 0usize; - - let mut b2k = b; - while !b2k.is_one() { - // invariant: b2k = b^(2^k) after entering this loop - b2k.square_in_place(); - k += 1; - } - - if k == (Self::TWO_ADICITY as usize) { - // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, - // which means that no square root exists. - return None; - } - let j = v - k; - w = z; - for _ in 1..j { - w.square_in_place(); - } - - z = w.square(); - b *= &z; - x *= &w; - v = k; - } - // Is x the square root? If so, return it. - if x.square() == *a { - return Some(x); - } else { - // Consistency check that if no square root is found, - // it is because none exists. - #[cfg(debug_assertions)] - { - use crate::fields::LegendreSymbol::*; - if a.legendre() != QuadraticNonResidue { - panic!("Input has a square root per its Legendre symbol, but it was not found") - } - } - None - } + sqrt_impl!( + Fp, + a, + (&Self::TWO_ADICITY), + (Fp::::TRACE_MINUS_ONE_DIV_TWO), + (&Self::TWO_ADIC_ROOT_OF_UNITY) + ) } /// Construct a field element from an integer in the range `0..(Self::MODULUS - 1)`. From 08cf0bdac69ae073f91b1c76464e0facbb1c1a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Wed, 13 Jul 2022 17:44:17 +0200 Subject: [PATCH 13/26] Test sqrt on Fq6_3over2 should panic with `not implemented` --- test-templates/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-templates/src/lib.rs b/test-templates/src/lib.rs index 068461f3e..08dc89a03 100644 --- a/test-templates/src/lib.rs +++ b/test-templates/src/lib.rs @@ -279,6 +279,14 @@ macro_rules! generate_field_test { frobenius_test::(Fq::characteristic(), 13); } + #[test] + #[should_panic(expected = "not implemented")] + fn test_fq6_sqrt() { + let mut rng = ark_std::test_rng(); + let g: Fq6 = UniformRand::rand(&mut rng); + sqrt_field_test(g); + } + generate_field_test!($($tail)*); }; From 36446a6c5e4e8ac5d47e6eeada124c2d519447ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Wed, 13 Jul 2022 17:44:33 +0200 Subject: [PATCH 14/26] sqrt on Fp3 should still work --- test-curves/src/mnt6_753/mod.rs | 3 +++ test-curves/src/mnt6_753/tests.rs | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 test-curves/src/mnt6_753/tests.rs diff --git a/test-curves/src/mnt6_753/mod.rs b/test-curves/src/mnt6_753/mod.rs index 8b1820844..d8171d56f 100644 --- a/test-curves/src/mnt6_753/mod.rs +++ b/test-curves/src/mnt6_753/mod.rs @@ -6,3 +6,6 @@ pub use self::fq::*; pub mod fq3; pub use self::fq3::*; + +#[cfg(test)] +mod tests; diff --git a/test-curves/src/mnt6_753/tests.rs b/test-curves/src/mnt6_753/tests.rs new file mode 100644 index 000000000..c30c9d606 --- /dev/null +++ b/test-curves/src/mnt6_753/tests.rs @@ -0,0 +1,15 @@ +#![allow(unused_imports)] +use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{Field, One, UniformRand, Zero}; + +use crate::mnt6_753::{Fq, Fq3,FqConfig, Fr, FrConfig}; +use ark_algebra_test_templates::{ + curves::*, fields::*, generate_field_test, generate_g1_test, groups::*, msm::*, +}; +use ark_std::{ + ops::{AddAssign, MulAssign, SubAssign}, + rand::Rng, + test_rng, +}; + +generate_field_test!(mnt6_753; fq3; ); From 28d5df66d8c387b3715fb95138102629363111b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Thu, 14 Jul 2022 19:15:43 +0200 Subject: [PATCH 15/26] Mark SqrtPrecomputation enum as non-exhaustive Likely to add more variants in the future --- ff/src/fields/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index 4fb6a6bb6..71cbd8d2f 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -485,6 +485,7 @@ impl LegendreSymbol { } } +#[non_exhaustive] pub enum SqrtPrecomputation { // Tonelli-Shanks algorithm works for all elements, no matter what the modulus is. TonelliShanks(u32, &'static [u64], F), From 90c9b29c9a9c243d102b86682f960b50c34a05e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Thu, 14 Jul 2022 19:27:44 +0200 Subject: [PATCH 16/26] Delegate sqrt precom definition to config --- ff/src/fields/models/fp6_3over2.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ff/src/fields/models/fp6_3over2.rs b/ff/src/fields/models/fp6_3over2.rs index 00359e5ab..af5657f03 100644 --- a/ff/src/fields/models/fp6_3over2.rs +++ b/ff/src/fields/models/fp6_3over2.rs @@ -7,6 +7,8 @@ pub trait Fp6Config: 'static + Send + Sync + Copy { const NONRESIDUE: Fp2; + const PRECOMP: Option>> = None; + /// Coefficients for the Frobenius automorphism. const FROBENIUS_COEFF_FP6_C1: &'static [Fp2]; const FROBENIUS_COEFF_FP6_C2: &'static [Fp2]; @@ -24,7 +26,7 @@ impl CubicExtConfig for Fp6ConfigWrapper

{ type BaseField = Fp2; type FrobCoeff = Fp2; - const PRECOMP: Option>> = None; + const PRECOMP: Option>> = P::PRECOMP; const DEGREE_OVER_BASE_PRIME_FIELD: usize = 6; From cb32939b0324ce71121890271bfb5d8f71aa8f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Thu, 14 Jul 2022 19:29:03 +0200 Subject: [PATCH 17/26] Rename PRECOMP -> SQRT_PRECOMP --- ff/src/fields/models/cubic_extension.rs | 4 ++-- ff/src/fields/models/fp3.rs | 2 +- ff/src/fields/models/fp6_3over2.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index b4a803d72..6a7b11720 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -38,7 +38,7 @@ pub trait CubicExtConfig: 'static + Send + Sync + Sized { /// Frobenius endomorphism. type FrobCoeff: Field; - const PRECOMP: Option>>; + const SQRT_PRECOMP: Option>>; /// The degree of the extension over the base prime field. const DEGREE_OVER_BASE_PRIME_FIELD: usize; @@ -165,7 +165,7 @@ impl One for CubicExtField

{ type BaseFieldIter

= <

::BaseField as Field>::BasePrimeFieldIter; impl Field for CubicExtField

{ type BasePrimeField = P::BasePrimeField; - const SQRT_PRECOMP: Option> = P::PRECOMP; + const SQRT_PRECOMP: Option> = P::SQRT_PRECOMP; type BasePrimeFieldIter = Chain, Chain, BaseFieldIter

>>; const ZERO: Self = Self::new(P::BaseField::ZERO, P::BaseField::ZERO, P::BaseField::ZERO); diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index e8794022e..e255487a0 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -40,7 +40,7 @@ impl CubicExtConfig for Fp3ConfigWrapper

{ const DEGREE_OVER_BASE_PRIME_FIELD: usize = 3; const NONRESIDUE: Self::BaseField = P::NONRESIDUE; - const PRECOMP: Option>> = + const SQRT_PRECOMP: Option>> = Some(SqrtPrecomputation::TonelliShanks( P::TWO_ADICITY, P::TRACE_MINUS_ONE_DIV_TWO, diff --git a/ff/src/fields/models/fp6_3over2.rs b/ff/src/fields/models/fp6_3over2.rs index af5657f03..7913001b5 100644 --- a/ff/src/fields/models/fp6_3over2.rs +++ b/ff/src/fields/models/fp6_3over2.rs @@ -7,7 +7,7 @@ pub trait Fp6Config: 'static + Send + Sync + Copy { const NONRESIDUE: Fp2; - const PRECOMP: Option>> = None; + const SQRT_PRECOMP: Option>> = None; /// Coefficients for the Frobenius automorphism. const FROBENIUS_COEFF_FP6_C1: &'static [Fp2]; @@ -26,7 +26,7 @@ impl CubicExtConfig for Fp6ConfigWrapper

{ type BaseField = Fp2; type FrobCoeff = Fp2; - const PRECOMP: Option>> = P::PRECOMP; + const SQRT_PRECOMP: Option>> = P::SQRT_PRECOMP; const DEGREE_OVER_BASE_PRIME_FIELD: usize = 6; From 1341215a259588ccba9e949690f0b535d3d22558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Thu, 14 Jul 2022 19:42:05 +0200 Subject: [PATCH 18/26] Call `from_base_prime_field` instead --- ff/src/fields/models/quadratic_extension.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index aa97721ec..e1168ef6d 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -432,7 +432,7 @@ impl Field for QuadExtField

{ two_inv.div2(); let two_inv = P::BasePrimeField::from(two_inv); - let two_inv = P::BaseField::from_base_prime_field_elems(&[two_inv]).unwrap(); + let two_inv = P::BaseField::from_base_prime_field(two_inv); alpha.sqrt().and_then(|alpha| { let mut delta = (alpha + &self.c0) * &two_inv; From 5976eedb766240b1952023849a627281778f77c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Thu, 14 Jul 2022 19:43:47 +0200 Subject: [PATCH 19/26] Remove old code --- ff/src/fields/arithmetic.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index 193a08436..239eae32a 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -15,7 +15,6 @@ macro_rules! sqrt_impl { let mut x = w * $self; let mut b = x * &w; - // let mut v = $P::TWO_ADICITY as usize; let mut v = *$two_adicity as usize; while !b.is_one() { From 40be9d00da6fe3736dd54745ce775296b2a03582 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Thu, 14 Jul 2022 10:50:17 -0700 Subject: [PATCH 20/26] Add default impl of sqrt --- ff/src/fields/mod.rs | 14 ++++++++++++-- ff/src/fields/models/cubic_extension.rs | 18 ------------------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index 64620c268..eb06afd62 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -198,10 +198,20 @@ pub trait Field: /// Returns the square root of self, if it exists. #[must_use] - fn sqrt(&self) -> Option; + fn sqrt(&self) -> Option { + match Self::SQRT_PRECOMP { + Some(tv) => tv.sqrt(self), + None => unimplemented!(), + } + } /// Sets `self` to be the square root of `self`, if it exists. - fn sqrt_in_place(&mut self) -> Option<&mut Self>; + fn sqrt_in_place(&mut self) -> Option<&mut Self> { + (*self).sqrt().map(|sqrt| { + *self = sqrt; + self + }) + } /// Returns `self * self`. #[must_use] diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index e90606f7c..10ea45a84 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -259,24 +259,6 @@ impl Field for CubicExtField

{ self.norm().legendre() } - /// Returns the square root of self, if it exists. - fn sqrt(&self) -> Option { - // sqrt computation needs certain params to be defined, like - // `TRACE_MINUS_ONE_DIV_TWO` - match Self::SQRT_PRECOMP { - Some(tv) => tv.sqrt(self), - None => unimplemented!(), - } - } - - /// Sets `self` to be the square root of `self`, if it exists. - fn sqrt_in_place(&mut self) -> Option<&mut Self> { - (*self).sqrt().map(|sqrt| { - *self = sqrt; - self - }) - } - fn inverse(&self) -> Option { if self.is_zero() { None From 287cf8d738e5e423d42ae59c86d6e305040989e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Thu, 14 Jul 2022 21:50:58 +0200 Subject: [PATCH 21/26] Delegate SQRT_PRECOMP to FpConfig --- ff/src/fields/mod.rs | 2 +- ff/src/fields/models/fp/mod.rs | 35 +++++++++------------------------- ff/src/fields/models/fp3.rs | 2 +- 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index eb06afd62..d65112a6f 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -508,7 +508,7 @@ impl LegendreSymbol { #[non_exhaustive] pub enum SqrtPrecomputation { // Tonelli-Shanks algorithm works for all elements, no matter what the modulus is. - TonelliShanks(u32, &'static [u64], F), + TonelliShanks(u32, &'static dyn AsRef<[u64]>, F), } impl SqrtPrecomputation { diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index e930c5846..1b8930f1a 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -18,7 +18,7 @@ use ark_std::{ mod montgomery_backend; pub use montgomery_backend::*; -use crate::{BigInt, BigInteger, FftField, Field, LegendreSymbol, PrimeField}; +use crate::{BigInt, BigInteger, FftField, Field, LegendreSymbol, PrimeField, SqrtPrecomputation}; /// A trait that specifies the configuration of a prime field. /// Also specifies how to perform arithmetic on field elements. pub trait FpConfig: Send + Sync + 'static + Sized { @@ -59,6 +59,13 @@ pub trait FpConfig: Send + Sync + 'static + Sized { /// FFT. const LARGE_SUBGROUP_ROOT_OF_UNITY: Option> = None; + const SQRT_PRECOMP: Option>> = + Some(SqrtPrecomputation::TonelliShanks( + Self::TWO_ADICITY, + &Fp::::TRACE_MINUS_ONE_DIV_TWO, + Self::TWO_ADIC_ROOT_OF_UNITY, + )); + /// Set a += b. fn add_assign(a: &mut Fp, b: &Fp); @@ -77,18 +84,6 @@ pub trait FpConfig: Send + Sync + 'static + Sized { /// Compute a^{-1} if `a` is not zero. fn inverse(a: &Fp) -> Option>; - /// Compute the square root of a, if it exists. - #[allow(unused_parens)] - fn square_root(a: &Fp) -> Option> { - sqrt_impl!( - Fp, - a, - (&Self::TWO_ADICITY), - (Fp::::TRACE_MINUS_ONE_DIV_TWO), - (&Self::TWO_ADIC_ROOT_OF_UNITY) - ) - } - /// Construct a field element from an integer in the range /// `0..(Self::MODULUS - 1)`. Returns `None` if the integer is outside /// this range. @@ -183,7 +178,7 @@ impl, const N: usize> Field for Fp { type BasePrimeField = Self; type BasePrimeFieldIter = iter::Once; - const SQRT_PRECOMP: Option> = None; + const SQRT_PRECOMP: Option> = P::SQRT_PRECOMP; const ZERO: Self = P::ZERO; const ONE: Self = P::ONE; @@ -313,18 +308,6 @@ impl, const N: usize> Field for Fp { QuadraticNonResidue } } - - #[inline] - fn sqrt(&self) -> Option { - P::square_root(self) - } - - fn sqrt_in_place(&mut self) -> Option<&mut Self> { - (*self).sqrt().map(|sqrt| { - *self = sqrt; - self - }) - } } impl, const N: usize> PrimeField for Fp { diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index e255487a0..d908c1e3f 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -43,7 +43,7 @@ impl CubicExtConfig for Fp3ConfigWrapper

{ const SQRT_PRECOMP: Option>> = Some(SqrtPrecomputation::TonelliShanks( P::TWO_ADICITY, - P::TRACE_MINUS_ONE_DIV_TWO, + &P::TRACE_MINUS_ONE_DIV_TWO, P::QUADRATIC_NONRESIDUE_TO_T, )); const FROBENIUS_COEFF_C1: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP3_C1; From bbb88837e2ee9587af0e625c572e99c2db2cb418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Thu, 14 Jul 2022 22:01:08 +0200 Subject: [PATCH 22/26] Add comments and sort definitions --- ff/src/fields/mod.rs | 5 +++-- ff/src/fields/models/cubic_extension.rs | 5 ++++- ff/src/fields/models/fp/mod.rs | 3 +++ ff/src/fields/models/fp3.rs | 2 ++ ff/src/fields/models/fp6_3over2.rs | 1 + ff/src/fields/models/quadratic_extension.rs | 4 ++-- 6 files changed, 15 insertions(+), 5 deletions(-) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index d65112a6f..3c0193720 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -131,10 +131,11 @@ pub trait Field: { type BasePrimeField: PrimeField; - const SQRT_PRECOMP: Option>; - type BasePrimeFieldIter: Iterator; + /// Determines the algorithm for computing square roots. + const SQRT_PRECOMP: Option>; + /// The additive identity of the field. const ZERO: Self; /// The multiplicative identity of the field. diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 10ea45a84..fcfaaadd3 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -38,6 +38,7 @@ pub trait CubicExtConfig: 'static + Send + Sync + Sized { /// Frobenius endomorphism. type FrobCoeff: Field; + /// Determines the algorithm for computing square roots. const SQRT_PRECOMP: Option>>; /// The degree of the extension over the base prime field. @@ -157,8 +158,10 @@ impl One for CubicExtField

{ type BaseFieldIter

= <

::BaseField as Field>::BasePrimeFieldIter; impl Field for CubicExtField

{ type BasePrimeField = P::BasePrimeField; - const SQRT_PRECOMP: Option> = P::SQRT_PRECOMP; type BasePrimeFieldIter = Chain, Chain, BaseFieldIter

>>; + + const SQRT_PRECOMP: Option> = P::SQRT_PRECOMP; + const ZERO: Self = Self::new(P::BaseField::ZERO, P::BaseField::ZERO, P::BaseField::ZERO); const ONE: Self = Self::new(P::BaseField::ONE, P::BaseField::ZERO, P::BaseField::ZERO); diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 1b8930f1a..3ecd8d061 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -59,6 +59,9 @@ pub trait FpConfig: Send + Sync + 'static + Sized { /// FFT. const LARGE_SUBGROUP_ROOT_OF_UNITY: Option> = None; + /// Determines the algorithm for computing square roots. + /// Currently uses the generic Tonelli-Shanks, + /// which works for every modulus. const SQRT_PRECOMP: Option>> = Some(SqrtPrecomputation::TonelliShanks( Self::TWO_ADICITY, diff --git a/ff/src/fields/models/fp3.rs b/ff/src/fields/models/fp3.rs index d908c1e3f..f3dad8620 100644 --- a/ff/src/fields/models/fp3.rs +++ b/ff/src/fields/models/fp3.rs @@ -40,12 +40,14 @@ impl CubicExtConfig for Fp3ConfigWrapper

{ const DEGREE_OVER_BASE_PRIME_FIELD: usize = 3; const NONRESIDUE: Self::BaseField = P::NONRESIDUE; + const SQRT_PRECOMP: Option>> = Some(SqrtPrecomputation::TonelliShanks( P::TWO_ADICITY, &P::TRACE_MINUS_ONE_DIV_TWO, P::QUADRATIC_NONRESIDUE_TO_T, )); + const FROBENIUS_COEFF_C1: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP3_C1; const FROBENIUS_COEFF_C2: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP3_C2; diff --git a/ff/src/fields/models/fp6_3over2.rs b/ff/src/fields/models/fp6_3over2.rs index 7913001b5..8240b6a52 100644 --- a/ff/src/fields/models/fp6_3over2.rs +++ b/ff/src/fields/models/fp6_3over2.rs @@ -7,6 +7,7 @@ pub trait Fp6Config: 'static + Send + Sync + Copy { const NONRESIDUE: Fp2; + /// Determines the algorithm for computing square roots. const SQRT_PRECOMP: Option>> = None; /// Coefficients for the Frobenius automorphism. diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index e1168ef6d..33c5d3f46 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -235,10 +235,10 @@ type BaseFieldIter

= <

::BaseField as Field>::BasePrimeFie impl Field for QuadExtField

{ type BasePrimeField = P::BasePrimeField; - const SQRT_PRECOMP: Option> = None; - type BasePrimeFieldIter = Chain, BaseFieldIter

>; + const SQRT_PRECOMP: Option> = None; + const ZERO: Self = Self::new(P::BaseField::ZERO, P::BaseField::ZERO); const ONE: Self = Self::new(P::BaseField::ONE, P::BaseField::ZERO); From 5cd329cf2377bcebc836d353f21234f09b272419 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Thu, 14 Jul 2022 13:56:32 -0700 Subject: [PATCH 23/26] Move `SQRT_PRECOMP` to `MontConfig` --- ff/src/fields/models/fp/mod.rs | 11 +++-------- ff/src/fields/models/fp/montgomery_backend.rs | 12 +++++++++++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 3ecd8d061..87674cbd5 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -59,15 +59,10 @@ pub trait FpConfig: Send + Sync + 'static + Sized { /// FFT. const LARGE_SUBGROUP_ROOT_OF_UNITY: Option> = None; - /// Determines the algorithm for computing square roots. + /// Precomputed material for use when computing square roots. /// Currently uses the generic Tonelli-Shanks, /// which works for every modulus. - const SQRT_PRECOMP: Option>> = - Some(SqrtPrecomputation::TonelliShanks( - Self::TWO_ADICITY, - &Fp::::TRACE_MINUS_ONE_DIV_TWO, - Self::TWO_ADIC_ROOT_OF_UNITY, - )); + const SQRT_PRECOMP: Option>>; /// Set a += b. fn add_assign(a: &mut Fp, b: &Fp); @@ -181,7 +176,7 @@ impl, const N: usize> Field for Fp { type BasePrimeField = Self; type BasePrimeFieldIter = iter::Once; - const SQRT_PRECOMP: Option> = P::SQRT_PRECOMP; + const SQRT_PRECOMP: Option> = P::SQRT_PRECOMP; const ZERO: Self = P::ZERO; const ONE: Self = P::ONE; diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index d339676a8..f10239a3c 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -1,7 +1,7 @@ use ark_std::{marker::PhantomData, Zero}; use super::{Fp, FpConfig}; -use crate::{biginteger::arithmetic as fa, BigInt, BigInteger}; +use crate::{biginteger::arithmetic as fa, BigInt, BigInteger, PrimeField, SqrtPrecomputation}; use ark_ff_macros::unroll_for_loops; /// A trait that specifies the constants and arithmetic procedures @@ -55,6 +55,15 @@ pub trait MontConfig: 'static + Sync + Send + Sized { /// Used for mixed-radix FFT. const LARGE_SUBGROUP_ROOT_OF_UNITY: Option, N>> = None; + /// Precomputed material for use when computing square roots. + /// The default is to use the standard Tonelli-Shanks algorithm. + const SQRT_PRECOMP: Option, N>>> = + Some(SqrtPrecomputation::TonelliShanks( + >::TWO_ADICITY, + &, N>>::TRACE_MINUS_ONE_DIV_TWO, + Self::TWO_ADIC_ROOT_OF_UNITY, + )); + /// Set a += b; fn add_assign(a: &mut Fp, N>, b: &Fp, N>) { // This cannot exceed the backing capacity. @@ -385,6 +394,7 @@ impl, const N: usize> FpConfig for MontBackend { const SMALL_SUBGROUP_BASE: Option = T::SMALL_SUBGROUP_BASE; const SMALL_SUBGROUP_BASE_ADICITY: Option = T::SMALL_SUBGROUP_BASE_ADICITY; const LARGE_SUBGROUP_ROOT_OF_UNITY: Option> = T::LARGE_SUBGROUP_ROOT_OF_UNITY; + const SQRT_PRECOMP: Option>> = T::SQRT_PRECOMP; fn add_assign(a: &mut Fp, b: &Fp) { T::add_assign(a, b) From d2434f3887d2e593d19d76b719225f5f18ee6310 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Thu, 14 Jul 2022 14:08:49 -0700 Subject: [PATCH 24/26] Remove `sqrt_impl` macro --- ff/src/fields/arithmetic.rs | 63 ---------------------------------- ff/src/fields/mod.rs | 68 ++++++++++++++++++++++++++++++------- 2 files changed, 56 insertions(+), 75 deletions(-) diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index 239eae32a..3e02dd0db 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -1,66 +1,3 @@ -macro_rules! sqrt_impl { - ($Self:ident, $self:expr, $two_adicity:expr, $trace_minus_one_div_two:expr, $quadratic_nonresidue:expr) => {{ - // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) - // Actually this is just normal Tonelli-Shanks; since `P::Generator` - // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` - // is also a quadratic non-residue (since `t` is odd). - if $self.is_zero() { - return Some($Self::zero()); - } - // Try computing the square root (x at the end of the algorithm) - // Check at the end of the algorithm if x was a square root - // Begin Tonelli-Shanks - let mut z = *$quadratic_nonresidue; - let mut w = $self.pow($trace_minus_one_div_two); - let mut x = w * $self; - let mut b = x * &w; - - let mut v = *$two_adicity as usize; - - while !b.is_one() { - let mut k = 0usize; - - let mut b2k = b; - while !b2k.is_one() { - // invariant: b2k = b^(2^k) after entering this loop - b2k.square_in_place(); - k += 1; - } - - if k == (*$two_adicity as usize) { - // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, - // which means that no square root exists. - return None; - } - let j = v - k; - w = z; - for _ in 1..j { - w.square_in_place(); - } - - z = w.square(); - b *= &z; - x *= &w; - v = k; - } - // Is x the square root? If so, return it. - if (x.square() == *$self) { - return Some(x); - } else { - // Consistency check that if no square root is found, - // it is because none exists. - #[cfg(debug_assertions)] - { - use crate::fields::LegendreSymbol::*; - if ($self.legendre() != QuadraticNonResidue) { - panic!("Input has a square root per its legendre symbol, but it was not found") - } - } - None - } - }}; -} - // Implements AddAssign on Self by deferring to an implementation on &Self #[macro_export] macro_rules! impl_additive_ops_from_ref { diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index 3c0193720..86e2dcac2 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -515,18 +515,62 @@ pub enum SqrtPrecomputation { impl SqrtPrecomputation { fn sqrt(&self, elem: &F) -> Option { match self { - SqrtPrecomputation::TonelliShanks( - two_adicity, - trace_minus_one_div_two, - quad_non_residue_to_t, - ) => { - sqrt_impl!( - F, - elem, - two_adicity, - trace_minus_one_div_two, - quad_non_residue_to_t - ) + SqrtPrecomputation::TonelliShanks(two_adicity, trace_minus_one_div_two, qnr_to_t) => { + // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) + // Actually this is just normal Tonelli-Shanks; since `P::Generator` + // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` + // is also a quadratic non-residue (since `t` is odd). + if elem.is_zero() { + return Some(F::zero()); + } + // Try computing the square root (x at the end of the algorithm) + // Check at the end of the algorithm if x was a square root + // Begin Tonelli-Shanks + let mut z = *qnr_to_t; + let mut w = elem.pow(trace_minus_one_div_two); + let mut x = w * elem; + let mut b = x * &w; + + let mut v = *two_adicity as usize; + + while !b.is_one() { + let mut k = 0usize; + + let mut b2k = b; + while !b2k.is_one() { + // invariant: b2k = b^(2^k) after entering this loop + b2k.square_in_place(); + k += 1; + } + + if k == (*two_adicity as usize) { + // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, + // which means that no square root exists. + return None; + } + let j = v - k; + w = z; + for _ in 1..j { + w.square_in_place(); + } + + z = w.square(); + b *= &z; + x *= &w; + v = k; + } + // Is x the square root? If so, return it. + if x.square() == *elem { + return Some(x); + } else { + // Consistency check that if no square root is found, + // it is because none exists. + debug_assert!(!matches!( + elem.legendre(), + LegendreSymbol::QuadraticResidue + )); + None + } }, } } From 63982ec31243f8216424361212072c47772f6c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20G=C3=B3rny?= Date: Thu, 14 Jul 2022 23:24:18 +0200 Subject: [PATCH 25/26] fmt --- ff/src/fields/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index 86e2dcac2..5b240a122 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -565,10 +565,7 @@ impl SqrtPrecomputation { } else { // Consistency check that if no square root is found, // it is because none exists. - debug_assert!(!matches!( - elem.legendre(), - LegendreSymbol::QuadraticResidue - )); + debug_assert!(!matches!(elem.legendre(), LegendreSymbol::QuadraticResidue)); None } }, From ef0262dbe9346c9568651c9d97fe0f93b3d09ad2 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Thu, 14 Jul 2022 14:37:32 -0700 Subject: [PATCH 26/26] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6614c0ea..c65028352 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ - [\#408](https://github.com/arkworks-rs/algebra/pull/408) (`ark-ff`) Change the output of `Display` formatting for BigInt & Fp from hex to decimal. - [\#412](https://github.com/arkworks-rs/algebra/pull/412) (`ark-poly`) Rename UV/MVPolynomial to DenseUV/MVPolynomial. - [\#417](https://github.com/arkworks-rs/algebra/pull/417) (`ark-ff`) Remove `ToBytes` and `FromBytes`. +- [\#422](https://github.com/arkworks-rs/algebra/pull/422) (`ark-ff`) Remove `SquareRootField`, and move functionality to `Field` - [\#425](https://github.com/arkworks-rs/algebra/pull/425) (`ark-ec`) Refactor `VariableBase` struct to `VariableBaseMSM` trait and implement it for `GroupProjective`. - [\#438](https://github.com/arkworks-rs/algebra/pull/438) (`ark-ec`) Rename modules, structs, and traits related to `ec`. - `short_weierstrass_jacobian` → `short_weierstrass`