diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 69937ce..5c552e8 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -1,4 +1,4 @@ -use ff::{Field, PowVartime, PrimeField, ScalarEngine, SqrtField}; +use ff::{Field, PowVartime, PrimeField, ScalarEngine}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use pairing::{Engine, PairingCurveAffine}; @@ -217,9 +217,7 @@ impl Field for Fr { fn frobenius_map(&mut self, _: usize) { // identity } -} -impl SqrtField for Fr { fn sqrt(&self) -> CtOption { // Tonelli-Shank's algorithm for q mod 16 = 1 // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 0a7db91..89b4afb 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -163,8 +163,8 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { &modulus, &endianness, limbs, + sqrt_impl, )); - gen.extend(sqrt_impl); // Return the generated impl gen.into() @@ -486,89 +486,84 @@ fn prime_field_constants_and_sqrt( biguint_to_u64_vec((exp(generator.clone(), &t, &modulus) * &r) % modulus, limbs); let generator = biguint_to_u64_vec((generator.clone() * &r) % modulus, limbs); - let sqrt_impl = if (modulus % BigUint::from_str("4").unwrap()) - == BigUint::from_str("3").unwrap() - { - // Addition chain for (r + 1) // 4 - let mod_plus_1_over_4 = pow_fixed::generate( - "e! {self}, - (modulus + BigUint::from_str("1").unwrap()) >> 2, - ); + let sqrt_impl = + if (modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() { + // Addition chain for (r + 1) // 4 + let mod_plus_1_over_4 = pow_fixed::generate( + "e! {self}, + (modulus + BigUint::from_str("1").unwrap()) >> 2, + ); - quote! { - impl ::ff::SqrtField for #name { - fn sqrt(&self) -> ::subtle::CtOption { - use ::subtle::ConstantTimeEq; + quote! { + use ::subtle::ConstantTimeEq; - // Because r = 3 (mod 4) - // sqrt can be done with only one exponentiation, - // via the computation of self^((r + 1) // 4) (mod r) - let sqrt = { - #mod_plus_1_over_4 - }; + // Because r = 3 (mod 4) + // sqrt can be done with only one exponentiation, + // via the computation of self^((r + 1) // 4) (mod r) + let sqrt = { + #mod_plus_1_over_4 + }; - ::subtle::CtOption::new( - sqrt, - (sqrt * &sqrt).ct_eq(self), // Only return Some if it's the square root. - ) - } + ::subtle::CtOption::new( + sqrt, + (sqrt * &sqrt).ct_eq(self), // Only return Some if it's the square root. + ) } - } - } else if (modulus % BigUint::from_str("16").unwrap()) == BigUint::from_str("1").unwrap() { - // Addition chain for (t - 1) // 2 - let t_minus_1_over_2 = pow_fixed::generate("e! {self}, (&t - BigUint::one()) >> 1); + } else if (modulus % BigUint::from_str("16").unwrap()) == BigUint::from_str("1").unwrap() { + // Addition chain for (t - 1) // 2 + let t_minus_1_over_2 = pow_fixed::generate("e! {self}, (&t - BigUint::one()) >> 1); - quote! { - impl ::ff::SqrtField for #name { - fn sqrt(&self) -> ::subtle::CtOption { - // Tonelli-Shank's algorithm for q mod 16 = 1 - // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) - use ::subtle::{ConditionallySelectable, ConstantTimeEq}; + quote! { + // Tonelli-Shank's algorithm for q mod 16 = 1 + // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) + use ::subtle::{ConditionallySelectable, ConstantTimeEq}; - // w = self^((t - 1) // 2) - let w = { - #t_minus_1_over_2 - }; + // w = self^((t - 1) // 2) + let w = { + #t_minus_1_over_2 + }; - let mut v = S; - let mut x = *self * &w; - let mut b = x * &w; + let mut v = S; + let mut x = *self * &w; + let mut b = x * &w; - // Initialize z as the 2^S root of unity. - let mut z = ROOT_OF_UNITY; + // Initialize z as the 2^S root of unity. + let mut z = ROOT_OF_UNITY; - for max_v in (1..=S).rev() { - let mut k = 1; - let mut tmp = b.square(); - let mut j_less_than_v: ::subtle::Choice = 1.into(); + for max_v in (1..=S).rev() { + let mut k = 1; + let mut tmp = b.square(); + let mut j_less_than_v: ::subtle::Choice = 1.into(); - for j in 2..max_v { - let tmp_is_one = tmp.ct_eq(&#name::one()); - let squared = #name::conditional_select(&tmp, &z, tmp_is_one).square(); - tmp = #name::conditional_select(&squared, &tmp, tmp_is_one); - let new_z = #name::conditional_select(&z, &squared, tmp_is_one); - j_less_than_v &= !j.ct_eq(&v); - k = u32::conditional_select(&j, &k, tmp_is_one); - z = #name::conditional_select(&z, &new_z, j_less_than_v); - } - - let result = x * &z; - x = #name::conditional_select(&result, &x, b.ct_eq(&#name::one())); - z = z.square(); - b *= &z; - v = k; + for j in 2..max_v { + let tmp_is_one = tmp.ct_eq(&#name::one()); + let squared = #name::conditional_select(&tmp, &z, tmp_is_one).square(); + tmp = #name::conditional_select(&squared, &tmp, tmp_is_one); + let new_z = #name::conditional_select(&z, &squared, tmp_is_one); + j_less_than_v &= !j.ct_eq(&v); + k = u32::conditional_select(&j, &k, tmp_is_one); + z = #name::conditional_select(&z, &new_z, j_less_than_v); } - ::subtle::CtOption::new( - x, - (x * &x).ct_eq(self), // Only return Some if it's the square root. - ) + let result = x * &z; + x = #name::conditional_select(&result, &x, b.ct_eq(&#name::one())); + z = z.square(); + b *= &z; + v = k; } + + ::subtle::CtOption::new( + x, + (x * &x).ct_eq(self), // Only return Some if it's the square root. + ) } - } - } else { - quote! {} - }; + } else { + syn::Error::new_spanned( + &name, + "ff_derive can't generate a square root function for this field.", + ) + .to_compile_error() + }; // Compute R^2 mod m let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs); @@ -634,6 +629,7 @@ fn prime_field_impl( modulus: &BigUint, endianness: &ReprEndianness, limbs: usize, + sqrt_impl: proc_macro2::TokenStream, ) -> proc_macro2::TokenStream { // Returns r{n} as an ident. fn get_temp(n: usize) -> syn::Ident { @@ -1280,6 +1276,10 @@ fn prime_field_impl( { #squaring_impl } + + fn sqrt(&self) -> ::subtle::CtOption { + #sqrt_impl + } } impl #name { diff --git a/ff/src/lib.rs b/ff/src/lib.rs index bb2994c..e5b09f4 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -75,6 +75,10 @@ pub trait Field: /// Exponentiates this element by a power of the base prime modulus via /// the Frobenius automorphism. fn frobenius_map(&mut self, power: usize); + + /// Returns the square root of the field element, if it is + /// quadratic residue. + fn sqrt(&self) -> CtOption; } pub trait PowVartime: Field @@ -124,13 +128,6 @@ impl PowVartime for T { const LIMB_SIZE: u64 = 64; } -/// This trait represents an element of a field that has a square root operation described for it. -pub trait SqrtField: Field { - /// Returns the square root of the field element, if it is - /// quadratic residue. - fn sqrt(&self) -> CtOption; -} - /// This represents an element of a prime field. pub trait PrimeField: Field + Ord + From + BitAnd + Shr @@ -230,7 +227,7 @@ pub trait PrimeField: /// pairing-friendly curve) can be defined in a subtrait. pub trait ScalarEngine: Sized + 'static + Clone { /// This is the scalar field of the engine's groups. - type Fr: PrimeField + SqrtField; + type Fr: PrimeField; } #[derive(Debug)] diff --git a/group/src/lib.rs b/group/src/lib.rs index 8910494..a330d14 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -1,7 +1,7 @@ // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] -use ff::{PrimeField, ScalarEngine, SqrtField}; +use ff::{Field, PrimeField, ScalarEngine}; use rand::RngCore; use std::error::Error; use std::fmt; @@ -47,8 +47,8 @@ pub trait CurveProjective: + CurveOpsOwned<::Affine> { type Engine: ScalarEngine; - type Scalar: PrimeField + SqrtField; - type Base: SqrtField; + type Scalar: PrimeField; + type Base: Field; type Affine: CurveAffine; /// Returns an element chosen uniformly at random using a user-provided RNG. @@ -105,8 +105,8 @@ pub trait CurveAffine: + Neg { type Engine: ScalarEngine; - type Scalar: PrimeField + SqrtField; - type Base: SqrtField; + type Scalar: PrimeField; + type Base: Field; type Projective: CurveProjective; type Uncompressed: EncodedPoint; type Compressed: EncodedPoint; diff --git a/pairing/benches/bls12_381/fq.rs b/pairing/benches/bls12_381/fq.rs index 3c43fdd..f2a981f 100644 --- a/pairing/benches/bls12_381/fq.rs +++ b/pairing/benches/bls12_381/fq.rs @@ -3,7 +3,7 @@ use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; -use ff::{Field, PrimeField, SqrtField}; +use ff::{Field, PrimeField}; use pairing::bls12_381::*; fn bench_fq_add_assign(c: &mut Criterion) { diff --git a/pairing/benches/bls12_381/fq2.rs b/pairing/benches/bls12_381/fq2.rs index 1eebb92..1402efa 100644 --- a/pairing/benches/bls12_381/fq2.rs +++ b/pairing/benches/bls12_381/fq2.rs @@ -3,7 +3,7 @@ use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; use std::ops::{AddAssign, MulAssign, SubAssign}; -use ff::{Field, SqrtField}; +use ff::Field; use pairing::bls12_381::*; fn bench_fq2_add_assign(c: &mut Criterion) { diff --git a/pairing/benches/bls12_381/fr.rs b/pairing/benches/bls12_381/fr.rs index 33b3901..f3aa749 100644 --- a/pairing/benches/bls12_381/fr.rs +++ b/pairing/benches/bls12_381/fr.rs @@ -3,7 +3,7 @@ use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; -use ff::{Field, PrimeField, SqrtField}; +use ff::{Field, PrimeField}; use pairing::bls12_381::*; fn bench_fr_add_assign(c: &mut Criterion) { diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index ef03797..d70d950 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -754,7 +754,7 @@ pub mod g1 { use super::super::{Bls12, Fq, Fq12, FqRepr, Fr}; use super::g2::G2Affine; use crate::{Engine, PairingCurveAffine}; - use ff::{BitIterator, Field, PrimeField, SqrtField}; + use ff::{BitIterator, Field, PrimeField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; @@ -1054,8 +1054,6 @@ pub mod g1 { #[test] fn g1_generator() { - use crate::SqrtField; - let mut x = Fq::zero(); let mut i = 0; loop { @@ -1366,7 +1364,7 @@ pub mod g2 { use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr}; use super::g1::G1Affine; use crate::{Engine, PairingCurveAffine}; - use ff::{BitIterator, Field, PrimeField, SqrtField}; + use ff::{BitIterator, Field, PrimeField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; @@ -1708,8 +1706,6 @@ pub mod g2 { #[test] fn g2_generator() { - use crate::SqrtField; - let mut x = Fq2::zero(); let mut i = 0; loop { diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index fa236ff..0c2120e 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -1715,8 +1715,6 @@ fn test_fq_pow() { #[test] fn test_fq_sqrt() { - use ff::SqrtField; - let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, @@ -1846,8 +1844,6 @@ fn test_fq_num_bits() { #[test] fn test_fq_root_of_unity() { - use ff::SqrtField; - assert_eq!(Fq::S, 1); assert_eq!(Fq::multiplicative_generator(), Fq::from(2)); assert_eq!( diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs index f8b4853..75b0860 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/pairing/src/bls12_381/fq12.rs @@ -237,6 +237,10 @@ impl Field for Fq12 { c1: t.mul(&self.c1).neg(), }) } + + fn sqrt(&self) -> CtOption { + unimplemented!() + } } #[cfg(test)] diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index dd5b751..ce415ab 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -1,5 +1,5 @@ use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE}; -use ff::{Field, PowVartime, SqrtField}; +use ff::{Field, PowVartime}; use rand_core::RngCore; use std::cmp::Ordering; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; @@ -241,9 +241,7 @@ impl Field for Fq2 { fn frobenius_map(&mut self, power: usize) { self.c1.mul_assign(&FROBENIUS_COEFF_FQ2_C1[power % 2]); } -} -impl SqrtField for Fq2 { /// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET! /// THIS WILL BE REPLACED BY THE bls12_381 CRATE, WHICH IS CONSTANT TIME! fn sqrt(&self) -> CtOption { diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs index b8ac627..2aa73ff 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/pairing/src/bls12_381/fq6.rs @@ -391,6 +391,10 @@ impl Field for Fq6 { tmp }) } + + fn sqrt(&self) -> CtOption { + unimplemented!() + } } #[cfg(test)] diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index 4a153ad..1ffc741 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -495,8 +495,6 @@ fn test_fr_pow() { #[test] fn test_fr_sqrt() { - use ff::SqrtField; - let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, @@ -628,8 +626,6 @@ fn test_fr_num_bits() { #[test] fn test_fr_root_of_unity() { - use ff::SqrtField; - assert_eq!(Fr::S, 32); assert_eq!(Fr::multiplicative_generator(), Fr::from(7)); assert_eq!( diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 0081d81..645c70d 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -20,7 +20,7 @@ pub mod tests; pub mod bls12_381; -use ff::{Field, PrimeField, ScalarEngine, SqrtField}; +use ff::{Field, PrimeField, ScalarEngine}; use group::{CurveAffine, CurveOps, CurveOpsOwned, CurveProjective}; use subtle::CtOption; @@ -61,10 +61,10 @@ pub trait Engine: ScalarEngine { > + From; /// The base field that hosts G1. - type Fq: PrimeField + SqrtField; + type Fq: PrimeField; /// The extension field that hosts G2. - type Fqe: SqrtField; + type Fqe: Field; /// The extension field that hosts the target group of the pairing. type Fqk: Field; diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs index 0288987..0b924ab 100644 --- a/pairing/src/tests/field.rs +++ b/pairing/src/tests/field.rs @@ -1,4 +1,4 @@ -use ff::{Field, PowVartime, PrimeField, SqrtField}; +use ff::{Field, PowVartime, PrimeField}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; @@ -23,7 +23,7 @@ pub fn random_frobenius_tests>(characteristic: C, maxpo } } -pub fn random_sqrt_tests() { +pub fn random_sqrt_tests() { let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index 965b8d8..c4d6c80 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -1,4 +1,4 @@ -use ff::{BitIterator, Field, PrimeField, SqrtField}; +use ff::{BitIterator, Field, PrimeField}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use subtle::CtOption; diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index 5e109d8..38771ba 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -1,5 +1,5 @@ use byteorder::{ByteOrder, LittleEndian}; -use ff::{adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, SqrtField}; +use ff::{adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField}; use rand_core::RngCore; use std::mem; use std::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign}; @@ -541,6 +541,24 @@ impl Field for Fs { ret.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7); ret } + + fn sqrt(&self) -> CtOption { + // Shank's algorithm for s mod 4 = 3 + // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) + + // a1 = self^((s - 3) // 4) + let mut a1 = self.pow_vartime([ + 0xb425c397b5bdcb2du64, + 0x299a0824f3320420, + 0x4199cec0404d0ec0, + 0x39f6d3a994cebea, + ]); + let mut a0 = a1.square(); + a0.mul_assign(self); + a1.mul_assign(self); + + CtOption::new(a1, !a0.ct_eq(&NEGATIVE_ONE)) + } } impl Fs { @@ -673,26 +691,6 @@ impl ToUniform for Fs { } } -impl SqrtField for Fs { - fn sqrt(&self) -> CtOption { - // Shank's algorithm for s mod 4 = 3 - // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) - - // a1 = self^((s - 3) // 4) - let mut a1 = self.pow_vartime([ - 0xb425c397b5bdcb2du64, - 0x299a0824f3320420, - 0x4199cec0404d0ec0, - 0x39f6d3a994cebea, - ]); - let mut a0 = a1.square(); - a0.mul_assign(self); - a1.mul_assign(self); - - CtOption::new(a1, !a0.ct_eq(&NEGATIVE_ONE)) - } -} - #[test] fn test_neg_one() { let o = Fs::one().neg(); diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 06a3810..c940681 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -23,7 +23,7 @@ //! [Jubjub]: https://zips.z.cash/protocol/protocol.pdf#jubjub //! [BLS12-381]: pairing::bls12_381 -use ff::{Field, PrimeField, SqrtField}; +use ff::{Field, PrimeField}; use pairing::Engine; use crate::group_hash::group_hash; @@ -95,7 +95,7 @@ pub trait ToUniform { /// and some pre-computed parameters. pub trait JubjubEngine: Engine { /// The scalar field of the Jubjub curve - type Fs: PrimeField + SqrtField + ToUniform; + type Fs: PrimeField + ToUniform; /// The parameters of Jubjub and the Sapling protocol type Params: JubjubParams; } diff --git a/zcash_primitives/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs index 372f686..4b56802 100644 --- a/zcash_primitives/src/jubjub/montgomery.rs +++ b/zcash_primitives/src/jubjub/montgomery.rs @@ -1,4 +1,4 @@ -use ff::{BitIterator, Field, PrimeField, SqrtField}; +use ff::{BitIterator, Field, PrimeField}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use subtle::CtOption; diff --git a/zcash_primitives/src/jubjub/tests.rs b/zcash_primitives/src/jubjub/tests.rs index fca26b9..595bf7c 100644 --- a/zcash_primitives/src/jubjub/tests.rs +++ b/zcash_primitives/src/jubjub/tests.rs @@ -1,6 +1,6 @@ use super::{edwards, montgomery, JubjubEngine, JubjubParams, PrimeOrder}; -use ff::{Field, PrimeField, SqrtField}; +use ff::{Field, PrimeField}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use rand_core::{RngCore, SeedableRng};