From 6e53cf3c4cd818d0502a4024370665b5ac5cb9f9 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 26 Mar 2020 19:00:46 +1300 Subject: [PATCH 01/10] group: Take scalar by reference in CurveProjective::recommended_wnaf_for_scalar --- bellman/src/groth16/tests/dummy_engine.rs | 2 +- group/src/lib.rs | 2 +- group/src/wnaf.rs | 2 +- pairing/src/bls12_381/ec.rs | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 6c011c3ea..21322d86a 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -423,7 +423,7 @@ impl CurveProjective for Fr { *self } - fn recommended_wnaf_for_scalar(_: ::Repr) -> usize { + fn recommended_wnaf_for_scalar(_: &::Repr) -> usize { 3 } diff --git a/group/src/lib.rs b/group/src/lib.rs index 34c8ac208..3dd9bbd21 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -82,7 +82,7 @@ pub trait CurveProjective: /// Recommends a wNAF window table size given a scalar. Always returns a number /// between 2 and 22, inclusive. - fn recommended_wnaf_for_scalar(scalar: ::Repr) -> usize; + fn recommended_wnaf_for_scalar(scalar: &::Repr) -> usize; /// Recommends a wNAF window size given the number of scalars you intend to multiply /// a base by. Always returns a number between 2 and 22, inclusive. diff --git a/group/src/wnaf.rs b/group/src/wnaf.rs index 381cd106b..70f880b8a 100644 --- a/group/src/wnaf.rs +++ b/group/src/wnaf.rs @@ -115,7 +115,7 @@ impl Wnaf<(), Vec, Vec> { scalar: <::Scalar as PrimeField>::Repr, ) -> Wnaf, &[i64]> { // Compute the appropriate window size for the scalar. - let window_size = G::recommended_wnaf_for_scalar(scalar); + let window_size = G::recommended_wnaf_for_scalar(&scalar); // Compute the wNAF form of the scalar. wnaf_form(&mut self.scalar, scalar, window_size); diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index a87fe11f8..2dae1ea0e 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -674,7 +674,7 @@ macro_rules! curve_impl { (*self).into() } - fn recommended_wnaf_for_scalar(scalar: ::Repr) -> usize { + fn recommended_wnaf_for_scalar(scalar: &::Repr) -> usize { Self::empirical_recommended_wnaf_for_scalar(scalar) } @@ -1014,7 +1014,7 @@ pub mod g1 { } impl G1 { - fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> usize { + fn empirical_recommended_wnaf_for_scalar(scalar: &FrRepr) -> usize { let num_bits = scalar.num_bits() as usize; if num_bits >= 130 { @@ -1733,7 +1733,7 @@ pub mod g2 { } impl G2 { - fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> usize { + fn empirical_recommended_wnaf_for_scalar(scalar: &FrRepr) -> usize { let num_bits = scalar.num_bits() as usize; if num_bits >= 103 { From 69c60530d41fc17c2ea52a42135c7b90901c6182 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 26 Mar 2020 19:23:29 +1300 Subject: [PATCH 02/10] group: Rewrite wNAF to remove dependency on ff::PrimeFieldRepr Adapted from Scalar::non_adjacent_form in curve25519-dalek. --- bellman/src/groth16/generator.rs | 14 +++--- group/Cargo.toml | 1 + group/src/tests/mod.rs | 30 ++++++------ group/src/wnaf.rs | 81 ++++++++++++++++++++++---------- 4 files changed, 78 insertions(+), 48 deletions(-) diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index d99383555..02efc21bd 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -2,7 +2,7 @@ use rand_core::RngCore; use std::ops::{AddAssign, MulAssign}; use std::sync::Arc; -use ff::{Field, PrimeField}; +use ff::Field; use group::{CurveAffine, CurveProjective, Wnaf}; use pairing::Engine; @@ -273,7 +273,7 @@ where exp.mul_assign(&coeff); // Exponentiate - *h = g1_wnaf.scalar(exp.into_repr()); + *h = g1_wnaf.scalar(&exp); } // Batch normalize @@ -376,14 +376,14 @@ where // Compute A query (in G1) if !at.is_zero() { - *a = g1_wnaf.scalar(at.into_repr()); + *a = g1_wnaf.scalar(&at); } // Compute B query (in G1/G2) if !bt.is_zero() { - let bt_repr = bt.into_repr(); - *b_g1 = g1_wnaf.scalar(bt_repr); - *b_g2 = g2_wnaf.scalar(bt_repr); + (); + *b_g1 = g1_wnaf.scalar(&bt); + *b_g2 = g2_wnaf.scalar(&bt); } at.mul_assign(&beta); @@ -394,7 +394,7 @@ where e.add_assign(&ct); e.mul_assign(inv); - *ext = g1_wnaf.scalar(e.into_repr()); + *ext = g1_wnaf.scalar(&e); } // Batch normalize diff --git a/group/Cargo.toml b/group/Cargo.toml index 9b8fe5f76..b68c2fe6b 100644 --- a/group/Cargo.toml +++ b/group/Cargo.toml @@ -15,6 +15,7 @@ repository = "https://github.com/ebfull/group" edition = "2018" [dependencies] +byteorder = { version = "1", default-features = false } ff = { version = "0.6", path = "../ff" } rand = "0.7" rand_xorshift = "0.2" diff --git a/group/src/tests/mod.rs b/group/src/tests/mod.rs index c53ba762f..66a76c096 100644 --- a/group/src/tests/mod.rs +++ b/group/src/tests/mod.rs @@ -85,12 +85,12 @@ fn random_wnaf_tests() { for w in 2..14 { for _ in 0..100 { let g = G::random(&mut rng); - let s = G::Scalar::random(&mut rng).into_repr(); + let s = G::Scalar::random(&mut rng); let mut g1 = g; g1.mul_assign(s); wnaf_table(&mut table, g, w); - wnaf_form(&mut wnaf, s, w); + wnaf_form(&mut wnaf, s.into_repr(), w); let g2 = wnaf_exp(&table, &wnaf); assert_eq!(g1, g2); @@ -103,17 +103,17 @@ fn random_wnaf_tests() { for _ in 0..100 { let g = G::random(&mut rng); - let s = G::Scalar::random(&mut rng).into_repr(); + let s = G::Scalar::random(&mut rng); let mut g1 = g; g1.mul_assign(s); let g2 = { let mut wnaf = Wnaf::new(); - wnaf.base(g, 1).scalar(s) + wnaf.base(g, 1).scalar(&s) }; let g3 = { let mut wnaf = Wnaf::new(); - wnaf.scalar(s).base(g) + wnaf.scalar(&s).base(g) }; let g4 = { let mut wnaf = Wnaf::new(); @@ -121,11 +121,11 @@ fn random_wnaf_tests() { only_compiles_if_send(&shared); - shared.scalar(s) + shared.scalar(&s) }; let g5 = { let mut wnaf = Wnaf::new(); - let mut shared = wnaf.scalar(s).shared(); + let mut shared = wnaf.scalar(&s).shared(); only_compiles_if_send(&shared); @@ -137,40 +137,40 @@ fn random_wnaf_tests() { { // Populate the vectors. wnaf.base(G::random(&mut rng), 1) - .scalar(G::Scalar::random(&mut rng).into_repr()); + .scalar(&G::Scalar::random(&mut rng)); } - wnaf.base(g, 1).scalar(s) + wnaf.base(g, 1).scalar(&s) }; let g7 = { let mut wnaf = Wnaf::new(); { // Populate the vectors. wnaf.base(G::random(&mut rng), 1) - .scalar(G::Scalar::random(&mut rng).into_repr()); + .scalar(&G::Scalar::random(&mut rng)); } - wnaf.scalar(s).base(g) + wnaf.scalar(&s).base(g) }; let g8 = { let mut wnaf = Wnaf::new(); { // Populate the vectors. wnaf.base(G::random(&mut rng), 1) - .scalar(G::Scalar::random(&mut rng).into_repr()); + .scalar(&G::Scalar::random(&mut rng)); } let mut shared = wnaf.base(g, 1).shared(); only_compiles_if_send(&shared); - shared.scalar(s) + shared.scalar(&s) }; let g9 = { let mut wnaf = Wnaf::new(); { // Populate the vectors. wnaf.base(G::random(&mut rng), 1) - .scalar(G::Scalar::random(&mut rng).into_repr()); + .scalar(&G::Scalar::random(&mut rng)); } - let mut shared = wnaf.scalar(s).shared(); + let mut shared = wnaf.scalar(&s).shared(); only_compiles_if_send(&shared); diff --git a/group/src/wnaf.rs b/group/src/wnaf.rs index 70f880b8a..200110157 100644 --- a/group/src/wnaf.rs +++ b/group/src/wnaf.rs @@ -1,4 +1,5 @@ -use ff::{PrimeField, PrimeFieldRepr}; +use ff::PrimeField; +use std::iter; use super::CurveProjective; @@ -16,31 +17,60 @@ pub(crate) fn wnaf_table(table: &mut Vec, mut base: G, wi } } -/// Replaces the contents of `wnaf` with the w-NAF representation of a scalar. -pub(crate) fn wnaf_form(wnaf: &mut Vec, mut c: S, window: usize) { +/// Replaces the contents of `wnaf` with the w-NAF representation of a little-endian +/// scalar. +pub(crate) fn wnaf_form>(wnaf: &mut Vec, c: S, window: usize) { + // Required by the NAF definition + debug_assert!(window >= 2); + // Required so that the NAF digits fit in i64 + debug_assert!(window <= 64); + wnaf.truncate(0); - while !c.is_zero() { - let mut u; - if c.is_odd() { - u = (c.as_ref()[0] % (1 << (window + 1))) as i64; + let u64_len = c.as_ref().len(); + let bit_len = u64_len * 64; - if u > (1 << window) { - u -= 1 << (window + 1); - } + let mut c_u64 = vec![0u64; u64_len + 1]; + c_u64[0..u64_len].copy_from_slice(c.as_ref()); - if u > 0 { - c.sub_noborrow(&S::from(u as u64)); - } else { - c.add_nocarry(&S::from((-u) as u64)); - } + let width = 1u64 << window; + let window_mask = width - 1; + + let mut pos = 0; + let mut carry = 0; + while pos < bit_len { + // Construct a buffer of bits of the scalar, starting at bit `pos` + let u64_idx = pos / 64; + let bit_idx = pos % 64; + let bit_buf = if bit_idx + window < 64 { + // This window's bits are contained in a single u64 + c_u64[u64_idx] >> bit_idx } else { - u = 0; + // Combine the current u64's bits with the bits from the next u64 + (c_u64[u64_idx] >> bit_idx) | (c_u64[u64_idx + 1] << (64 - bit_idx)) + }; + + // Add the carry into the current window + let window_val = carry + (bit_buf & window_mask); + + if window_val & 1 == 0 { + // If the window value is even, preserve the carry and emit 0. + // Why is the carry preserved? + // If carry == 0 and window_val & 1 == 0, then the next carry should be 0 + // If carry == 1 and window_val & 1 == 0, then bit_buf & 1 == 1 so the next carry should be 1 + wnaf.push(0); + pos += 1; + } else { + wnaf.push(if window_val < width / 2 { + carry = 0; + window_val as i64 + } else { + carry = 1; + (window_val as i64).wrapping_sub(width as i64) + }); + wnaf.extend(iter::repeat(0).take(window - 1)); + pos += window; } - - wnaf.push(u); - - c.div2(); } } @@ -112,8 +142,10 @@ impl Wnaf<(), Vec, Vec> { /// exponentiations with `.base(..)`. pub fn scalar( &mut self, - scalar: <::Scalar as PrimeField>::Repr, + scalar: &::Scalar, ) -> Wnaf, &[i64]> { + let scalar = scalar.into_repr(); + // Compute the appropriate window size for the scalar. let window_size = G::recommended_wnaf_for_scalar(&scalar); @@ -168,14 +200,11 @@ impl> Wnaf { impl>> Wnaf { /// Performs exponentiation given a scalar. - pub fn scalar( - &mut self, - scalar: <::Scalar as PrimeField>::Repr, - ) -> G + pub fn scalar(&mut self, scalar: &::Scalar) -> G where B: AsRef<[G]>, { - wnaf_form(self.scalar.as_mut(), scalar, self.window_size); + wnaf_form(self.scalar.as_mut(), scalar.into_repr(), self.window_size); wnaf_exp(self.base.as_ref(), self.scalar.as_mut()) } } From b6457a905b23b78e30890ab7a2bf6d3b43c20e13 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 27 Mar 2020 22:35:55 +1300 Subject: [PATCH 03/10] ff: Move pow_vartime into a trait that is generic over the limb size The trait is implemented by default for u8 and u64, allowing pow_vartime to be used with both the byte encoding and limb representation of field elements. --- bellman/src/domain.rs | 2 +- bellman/src/gadgets/multieq.rs | 2 +- bellman/src/gadgets/test/mod.rs | 2 +- bellman/src/groth16/generator.rs | 2 +- bellman/src/groth16/tests/dummy_engine.rs | 8 ++-- bellman/src/groth16/tests/mod.rs | 12 +++--- ff/src/lib.rs | 35 +++++++++++++-- pairing/src/bls12_381/fq.rs | 52 ++++++++++++----------- pairing/src/bls12_381/fq2.rs | 6 +-- pairing/src/bls12_381/fr.rs | 8 ++-- pairing/src/bls12_381/mod.rs | 2 +- pairing/src/tests/engine.rs | 1 + pairing/src/tests/field.rs | 2 +- zcash_primitives/src/jubjub/fs.rs | 10 ++--- 14 files changed, 89 insertions(+), 55 deletions(-) diff --git a/bellman/src/domain.rs b/bellman/src/domain.rs index 0e9192e44..f1c25922f 100644 --- a/bellman/src/domain.rs +++ b/bellman/src/domain.rs @@ -11,7 +11,7 @@ //! [`EvaluationDomain`]: crate::domain::EvaluationDomain //! [Groth16]: https://eprint.iacr.org/2016/260 -use ff::{Field, PrimeField, ScalarEngine}; +use ff::{Field, PowVartime, PrimeField, ScalarEngine}; use group::CurveProjective; use std::ops::{AddAssign, MulAssign, SubAssign}; diff --git a/bellman/src/gadgets/multieq.rs b/bellman/src/gadgets/multieq.rs index 37b2d9429..890eb7c6e 100644 --- a/bellman/src/gadgets/multieq.rs +++ b/bellman/src/gadgets/multieq.rs @@ -1,4 +1,4 @@ -use ff::{Field, PrimeField, ScalarEngine}; +use ff::{PowVartime, PrimeField, ScalarEngine}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; diff --git a/bellman/src/gadgets/test/mod.rs b/bellman/src/gadgets/test/mod.rs index 0a37cd16f..a803accae 100644 --- a/bellman/src/gadgets/test/mod.rs +++ b/bellman/src/gadgets/test/mod.rs @@ -1,6 +1,6 @@ //! Helpers for testing circuit implementations. -use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; +use ff::{Field, PowVartime, PrimeField, PrimeFieldRepr, ScalarEngine}; use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index 02efc21bd..1d8699229 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -2,7 +2,7 @@ use rand_core::RngCore; use std::ops::{AddAssign, MulAssign}; use std::sync::Arc; -use ff::Field; +use ff::{Field, PowVartime}; use group::{CurveAffine, CurveProjective, Wnaf}; use pairing::Engine; diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 21322d86a..4693aaa1a 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -1,4 +1,6 @@ -use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField}; +use ff::{ + Field, PowVartime, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField, +}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use pairing::{Engine, PairingCurveAffine}; @@ -190,9 +192,9 @@ impl SqrtField for Fr { // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) let mut c = Fr::root_of_unity(); // r = self^((t + 1) // 2) - let mut r = self.pow_vartime([32]); + let mut r = self.pow_vartime([32u64]); // t = self^t - let mut t = self.pow_vartime([63]); + let mut t = self.pow_vartime([63u64]); let mut m = Fr::S; while t != ::one() { diff --git a/bellman/src/groth16/tests/mod.rs b/bellman/src/groth16/tests/mod.rs index 5c2f02dbb..2914bf2c0 100644 --- a/bellman/src/groth16/tests/mod.rs +++ b/bellman/src/groth16/tests/mod.rs @@ -1,4 +1,4 @@ -use ff::{Field, PrimeField}; +use ff::{Field, PowVartime, PrimeField}; use pairing::Engine; mod dummy_engine; @@ -127,22 +127,22 @@ fn test_xordemo() { let mut root_of_unity = Fr::root_of_unity(); // We expect this to be a 2^10 root of unity - assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1 << 10])); + assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1u64 << 10])); // Let's turn it into a 2^3 root of unity. - root_of_unity = root_of_unity.pow_vartime(&[1 << 7]); - assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1 << 3])); + root_of_unity = root_of_unity.pow_vartime(&[1u64 << 7]); + assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1u64 << 3])); assert_eq!(Fr::from_str("20201").unwrap(), root_of_unity); // Let's compute all the points in our evaluation domain. let mut points = Vec::with_capacity(8); - for i in 0..8 { + for i in 0u64..8 { points.push(root_of_unity.pow_vartime(&[i])); } // Let's compute t(tau) = (tau - p_0)(tau - p_1)... // = tau^8 - 1 - let mut t_at_tau = tau.pow_vartime(&[8]); + let mut t_at_tau = tau.pow_vartime(&[8u64]); t_at_tau.sub_assign(&Fr::one()); { let mut tmp = Fr::one(); diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 65c32b2d6..e3cb8b474 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -13,7 +13,7 @@ extern crate std; pub use ff_derive::*; use core::fmt; -use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use core::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign}; use rand_core::RngCore; #[cfg(feature = "std")] use std::io::{self, Read, Write}; @@ -73,21 +73,36 @@ 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); +} + +pub trait PowVartime: Field +where + L: Copy + PartialEq + PartialOrd + AddAssign, + L: BitAnd, + L: Shr, + L: Sub, +{ + const ZERO: L; + const ONE: L; + const LIMB_SIZE: L; /// Exponentiates `self` by `exp`, where `exp` is a little-endian order /// integer exponent. /// /// **This operation is variable time with respect to the exponent.** If the /// exponent is fixed, this operation is effectively constant time. - fn pow_vartime>(&self, exp: S) -> Self { + fn pow_vartime>(&self, exp: S) -> Self { let mut res = Self::one(); for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { + let mut i = Self::ZERO; + while i < Self::LIMB_SIZE { res = res.square(); - if ((*e >> i) & 1) == 1 { + if ((*e >> (Self::LIMB_SIZE - Self::ONE - i)) & Self::ONE) == Self::ONE { res.mul_assign(self); } + + i += Self::ONE; } } @@ -95,6 +110,18 @@ pub trait Field: } } +impl PowVartime for T { + const ZERO: u8 = 0; + const ONE: u8 = 1; + const LIMB_SIZE: u8 = 8; +} + +impl PowVartime for T { + const ZERO: u64 = 0; + const ONE: u64 = 1; + 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 diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index 57d653264..2f7b15d16 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -2,6 +2,8 @@ use super::fq2::Fq2; use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; use std::ops::{AddAssign, MulAssign, SubAssign}; +#[cfg(test)] +use ff::PowVartime; #[cfg(test)] use std::ops::Neg; @@ -466,7 +468,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ2_C1[1], nqr.pow_vartime([ - 0xdcff7fffffffd555, + 0xdcff7fffffffd555u64, 0xf55ffff58a9ffff, 0xb39869507b587b12, 0xb23ba5c279c2895f, @@ -484,7 +486,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[1], nqr.pow_vartime([ - 0x9354ffffffffe38e, + 0x9354ffffffffe38eu64, 0xa395554e5c6aaaa, 0xcd104635a790520c, 0xcc27c3d6fbd7063f, @@ -495,7 +497,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[2], nqr.pow_vartime([ - 0xb78e0000097b2f68, + 0xb78e0000097b2f68u64, 0xd44f23b47cbd64e3, 0x5cb9668120b069a9, 0xccea85f9bf7b3d16, @@ -512,7 +514,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[3], nqr.pow_vartime([ - 0xdbc6fcd6f35b9e06, + 0xdbc6fcd6f35b9e06u64, 0x997dead10becd6aa, 0x9dbbd24c17206460, 0x72b97acc6057c45e, @@ -535,7 +537,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[4], nqr.pow_vartime([ - 0x4649add3c71c6d90, + 0x4649add3c71c6d90u64, 0x43caa6528972a865, 0xcda8445bbaaa0fbb, 0xc93dea665662aa66, @@ -564,7 +566,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[5], nqr.pow_vartime([ - 0xf896f792732eb2be, + 0xf896f792732eb2beu64, 0x49c86a6d1dc593a1, 0xe5b31e94581f91c3, 0xe3da5cc0a6b20d7f, @@ -601,7 +603,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[1], nqr.pow_vartime([ - 0x26a9ffffffffc71c, + 0x26a9ffffffffc71cu64, 0x1472aaa9cb8d5555, 0x9a208c6b4f20a418, 0x984f87adf7ae0c7f, @@ -612,7 +614,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[2], nqr.pow_vartime([ - 0x6f1c000012f65ed0, + 0x6f1c000012f65ed0u64, 0xa89e4768f97ac9c7, 0xb972cd024160d353, 0x99d50bf37ef67a2c, @@ -629,7 +631,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[3], nqr.pow_vartime([ - 0xb78df9ade6b73c0c, + 0xb78df9ade6b73c0cu64, 0x32fbd5a217d9ad55, 0x3b77a4982e40c8c1, 0xe572f598c0af88bd, @@ -652,7 +654,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[4], nqr.pow_vartime([ - 0x8c935ba78e38db20, + 0x8c935ba78e38db20u64, 0x87954ca512e550ca, 0x9b5088b775541f76, 0x927bd4ccacc554cd, @@ -681,7 +683,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[5], nqr.pow_vartime([ - 0xf12def24e65d657c, + 0xf12def24e65d657cu64, 0x9390d4da3b8b2743, 0xcb663d28b03f2386, 0xc7b4b9814d641aff, @@ -718,7 +720,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[1], nqr.pow_vartime([ - 0x49aa7ffffffff1c7, + 0x49aa7ffffffff1c7u64, 0x51caaaa72e35555, 0xe688231ad3c82906, 0xe613e1eb7deb831f, @@ -729,7 +731,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[2], nqr.pow_vartime([ - 0xdbc7000004bd97b4, + 0xdbc7000004bd97b4u64, 0xea2791da3e5eb271, 0x2e5cb340905834d4, 0xe67542fcdfbd9e8b, @@ -746,7 +748,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[3], nqr.pow_vartime(vec![ - 0x6de37e6b79adcf03, + 0x6de37e6b79adcf03u64, 0x4cbef56885f66b55, 0x4edde9260b903230, 0x395cbd66302be22f, @@ -769,7 +771,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[4], nqr.pow_vartime(vec![ - 0xa324d6e9e38e36c8, + 0xa324d6e9e38e36c8u64, 0xa1e5532944b95432, 0x66d4222ddd5507dd, 0xe49ef5332b315533, @@ -798,7 +800,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[5], nqr.pow_vartime(vec![ - 0xfc4b7bc93997595f, + 0xfc4b7bc93997595fu64, 0xa4e435368ee2c9d0, 0xf2d98f4a2c0fc8e1, 0xf1ed2e60535906bf, @@ -833,7 +835,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[6], nqr.pow_vartime(vec![ - 0x21219610a012ba3c, + 0x21219610a012ba3cu64, 0xa5c19ad35375325, 0x4e9df1e497674396, 0xfb05b717c991c6ef, @@ -874,7 +876,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[7], nqr.pow_vartime(vec![ - 0x742754a1f22fdb, + 0x742754a1f22fdbu64, 0x2a1955c2dec3a702, 0x9747b28c796d134e, 0xc113a0411f59db79, @@ -921,7 +923,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[8], nqr.pow_vartime(vec![ - 0x802f5720d0b25710, + 0x802f5720d0b25710u64, 0x6714f0a258b85c7c, 0x31394c90afdf16e, 0xe9d2b0c64f957b19, @@ -974,7 +976,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[9], nqr.pow_vartime(vec![ - 0x4af4accf7de0b977, + 0x4af4accf7de0b977u64, 0x742485e21805b4ee, 0xee388fbc4ac36dec, 0x1e199da57ad178a, @@ -1033,7 +1035,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[10], nqr.pow_vartime(vec![ - 0xe5953a4f96cdda44, + 0xe5953a4f96cdda44u64, 0x336b2d734cbc32bb, 0x3f79bfe3cd7410e, 0x267ae19aaa0f0332, @@ -1098,7 +1100,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[11], nqr.pow_vartime(vec![ - 0x107db680942de533, + 0x107db680942de533u64, 0x6262b24d2052393b, 0x6136df824159ebc, 0xedb052c9970c5deb, @@ -2029,7 +2031,7 @@ fn test_fq_pow() { 0xe5, ]); - for i in 0..1000 { + for i in 0u64..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. let a = Fq::random(&mut rng); @@ -2197,7 +2199,7 @@ fn test_fq_root_of_unity() { ); assert_eq!( Fq::multiplicative_generator().pow_vartime([ - 0xdcff7fffffffd555, + 0xdcff7fffffffd555u64, 0xf55ffff58a9ffff, 0xb39869507b587b12, 0xb23ba5c279c2895f, @@ -2206,7 +2208,7 @@ fn test_fq_root_of_unity() { ]), Fq::root_of_unity() ); - assert_eq!(Fq::root_of_unity().pow_vartime([1 << Fq::S]), Fq::one()); + assert_eq!(Fq::root_of_unity().pow_vartime([1u64 << Fq::S]), Fq::one()); assert!(bool::from(Fq::multiplicative_generator().sqrt().is_none())); } diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index 0cd88e7d7..e0955f08f 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, SqrtField}; +use ff::{Field, PowVartime, SqrtField}; use rand_core::RngCore; use std::cmp::Ordering; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; @@ -254,7 +254,7 @@ impl SqrtField for Fq2 { } else { // a1 = self^((q - 3) / 4) let mut a1 = self.pow_vartime([ - 0xee7fbfffffffeaaa, + 0xee7fbfffffffeaaau64, 0x7aaffffac54ffff, 0xd9cc34a83dac3d89, 0xd91dd2e13ce144af, @@ -286,7 +286,7 @@ impl SqrtField for Fq2 { alpha.add_assign(&Fq2::one()); // alpha = alpha^((q - 1) / 2) alpha = alpha.pow_vartime([ - 0xdcff7fffffffd555, + 0xdcff7fffffffd555u64, 0xf55ffff58a9ffff, 0xb39869507b587b12, 0xb23ba5c279c2895f, diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index 4c30e49cb..f520d303e 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -6,6 +6,8 @@ use std::ops::{AddAssign, MulAssign, SubAssign}; #[PrimeFieldGenerator = "7"] pub struct Fr(FrRepr); +#[cfg(test)] +use ff::PowVartime; #[cfg(test)] use rand_core::SeedableRng; #[cfg(test)] @@ -763,7 +765,7 @@ fn test_fr_pow() { 0xe5, ]); - for i in 0..1000 { + for i in 0u64..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. let a = Fr::random(&mut rng); @@ -965,14 +967,14 @@ fn test_fr_root_of_unity() { ); assert_eq!( Fr::multiplicative_generator().pow_vartime([ - 0xfffe5bfeffffffff, + 0xfffe5bfeffffffffu64, 0x9a1d80553bda402, 0x299d7d483339d808, 0x73eda753 ]), Fr::root_of_unity() ); - assert_eq!(Fr::root_of_unity().pow_vartime([1 << Fr::S]), Fr::one()); + assert_eq!(Fr::root_of_unity().pow_vartime([1u64 << Fr::S]), Fr::one()); assert!(bool::from(Fr::multiplicative_generator().sqrt().is_none())); } diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs index 80848e12d..afa3aaf0e 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/pairing/src/bls12_381/mod.rs @@ -23,7 +23,7 @@ pub use self::fr::{Fr, FrRepr}; use super::{Engine, PairingCurveAffine}; -use ff::{BitIterator, Field, ScalarEngine}; +use ff::{BitIterator, Field, PowVartime, ScalarEngine}; use group::CurveAffine; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use subtle::CtOption; diff --git a/pairing/src/tests/engine.rs b/pairing/src/tests/engine.rs index 0776e5d4b..c65816de1 100644 --- a/pairing/src/tests/engine.rs +++ b/pairing/src/tests/engine.rs @@ -1,3 +1,4 @@ +use ff::PowVartime; use group::{CurveAffine, CurveProjective}; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs index 7ddb36534..a1f72b84b 100644 --- a/pairing/src/tests/field.rs +++ b/pairing/src/tests/field.rs @@ -1,4 +1,4 @@ -use ff::{Field, PrimeField, SqrtField}; +use ff::{Field, PowVartime, PrimeField, SqrtField}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index ef1ccbea4..6e902cbd3 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -1,6 +1,6 @@ use byteorder::{ByteOrder, LittleEndian}; use ff::{ - adc, mac_with_carry, sbb, BitIterator, Field, PrimeField, PrimeFieldDecodingError, + adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField, }; use rand_core::RngCore; @@ -745,7 +745,7 @@ impl SqrtField for Fs { // a1 = self^((s - 3) // 4) let mut a1 = self.pow_vartime([ - 0xb425c397b5bdcb2d, + 0xb425c397b5bdcb2du64, 0x299a0824f3320420, 0x4199cec0404d0ec0, 0x39f6d3a994cebea, @@ -1491,7 +1491,7 @@ fn test_fs_pow() { 0xe5, ]); - for i in 0..1000 { + for i in 0u64..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. let a = Fs::random(&mut rng); @@ -1689,13 +1689,13 @@ fn test_fs_root_of_unity() { ); assert_eq!( Fs::multiplicative_generator().pow_vartime([ - 0x684b872f6b7b965b, + 0x684b872f6b7b965bu64, 0x53341049e6640841, 0x83339d80809a1d80, 0x73eda753299d7d4 ]), Fs::root_of_unity() ); - assert_eq!(Fs::root_of_unity().pow_vartime([1 << Fs::S]), Fs::one()); + assert_eq!(Fs::root_of_unity().pow_vartime([1u64 << Fs::S]), Fs::one()); assert!(bool::from(Fs::multiplicative_generator().sqrt().is_none())); } From fd79de5408997899f9d183f92f01baf49a9a406f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 27 Mar 2020 23:19:58 +1300 Subject: [PATCH 04/10] ff: Add PrimeField: From constraint --- bellman/src/groth16/tests/dummy_engine.rs | 6 ++++++ ff/ff_derive/src/lib.rs | 9 +++++++++ ff/src/lib.rs | 6 +++--- pairing/src/bls12_381/fq.rs | 13 ++++--------- pairing/src/bls12_381/fq2.rs | 2 +- pairing/src/bls12_381/fr.rs | 7 ++----- pairing/src/bls12_381/tests/mod.rs | 18 +++++++++--------- pairing/src/tests/field.rs | 2 +- zcash_primitives/src/jubjub/fs.rs | 16 +++++++++++----- zcash_primitives/src/primitives.rs | 4 ++-- zcash_proofs/src/sapling/mod.rs | 4 ++-- 11 files changed, 50 insertions(+), 37 deletions(-) diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 4693aaa1a..2ef9798c8 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -34,6 +34,12 @@ impl fmt::Display for Fr { } } +impl From for Fr { + fn from(v: u64) -> Fr { + Fr(Wrapping((v % MODULUS_R.0 as u64) as u32)) + } +} + impl ConditionallySelectable for Fr { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Fr(Wrapping(u32::conditional_select( diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 121c296dc..9a8a74462 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -853,6 +853,15 @@ fn prime_field_impl( } } + impl From for #name { + #[inline(always)] + fn from(val: u64) -> #name { + let mut raw = [0u64; #limbs]; + raw[0] = val; + #name(#repr(raw)) * #name(R2) + } + } + impl From<#name> for #repr { fn from(e: #name) -> #repr { e.into_repr() diff --git a/ff/src/lib.rs b/ff/src/lib.rs index e3cb8b474..8bb8ffabc 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -256,7 +256,7 @@ impl fmt::Display for PrimeFieldDecodingError { } /// This represents an element of a prime field. -pub trait PrimeField: Field { +pub trait PrimeField: Field + From { /// The prime field can be converted back and forth into this biginteger /// representation. type Repr: PrimeFieldRepr + From; @@ -274,7 +274,7 @@ pub trait PrimeField: Field { let mut res = Self::zero(); - let ten = Self::from_repr(Self::Repr::from(10)).unwrap(); + let ten = Self::from(10); let mut first_digit = true; @@ -290,7 +290,7 @@ pub trait PrimeField: Field { } res.mul_assign(&ten); - res.add_assign(&Self::from_repr(Self::Repr::from(u64::from(c))).unwrap()); + res.add_assign(&Self::from(u64::from(c))); } None => { return None; diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index 2f7b15d16..5a8f17307 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -456,7 +456,7 @@ pub struct Fq(FqRepr); #[test] fn test_b_coeff() { - assert_eq!(Fq::from_repr(FqRepr::from(4)).unwrap(), B_COEFF); + assert_eq!(Fq::from(4), B_COEFF); } #[test] @@ -1586,7 +1586,7 @@ fn test_fq_is_valid() { assert!(!a.is_valid()); a.0.sub_noborrow(&FqRepr::from(1)); assert!(a.is_valid()); - assert!(Fq(FqRepr::from(0)).is_valid()); + assert!(Fq::from(0).is_valid()); assert!(Fq(FqRepr([ 0xdf4671abd14dab3e, 0xe2dc0c9f534fbd33, @@ -2193,10 +2193,7 @@ fn test_fq_root_of_unity() { use ff::SqrtField; assert_eq!(Fq::S, 1); - assert_eq!( - Fq::multiplicative_generator(), - Fq::from_repr(FqRepr::from(2)).unwrap() - ); + assert_eq!(Fq::multiplicative_generator(), Fq::from(2)); assert_eq!( Fq::multiplicative_generator().pow_vartime([ 0xdcff7fffffffd555u64, @@ -2225,9 +2222,7 @@ fn test_fq_ordering() { // FqRepr's ordering is well-tested, but we still need to make sure the Fq // elements aren't being compared in Montgomery form. for i in 0..100 { - assert!( - Fq::from_repr(FqRepr::from(i + 1)).unwrap() > Fq::from_repr(FqRepr::from(i)).unwrap() - ); + assert!(Fq::from(i + 1) > Fq::from(i)); } } diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index e0955f08f..6e6230736 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -364,7 +364,7 @@ fn test_fq2_squaring() { a.square(), Fq2 { c0: Fq::zero(), - c1: Fq::from_repr(FqRepr::from(2)).unwrap(), + c1: Fq::from(2), } ); // 2u diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index f520d303e..028287d20 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -368,7 +368,7 @@ fn test_fr_is_valid() { assert!(!a.is_valid()); a.0.sub_noborrow(&FrRepr::from(1)); assert!(a.is_valid()); - assert!(Fr(FrRepr::from(0)).is_valid()); + assert!(Fr::from(0).is_valid()); assert!(Fr(FrRepr([ 0xffffffff00000000, 0x53bda402fffe5bfe, @@ -961,10 +961,7 @@ fn test_fr_root_of_unity() { use ff::SqrtField; assert_eq!(Fr::S, 32); - assert_eq!( - Fr::multiplicative_generator(), - Fr::from_repr(FrRepr::from(7)).unwrap() - ); + assert_eq!(Fr::multiplicative_generator(), Fr::from(7)); assert_eq!( Fr::multiplicative_generator().pow_vartime([ 0xfffe5bfeffffffffu64, diff --git a/pairing/src/bls12_381/tests/mod.rs b/pairing/src/bls12_381/tests/mod.rs index 9c5b2c93f..f79961cdb 100644 --- a/pairing/src/bls12_381/tests/mod.rs +++ b/pairing/src/bls12_381/tests/mod.rs @@ -191,7 +191,7 @@ fn test_g1_uncompressed_invalid_vectors() { loop { let mut x3b = x.square(); x3b.mul_assign(&x); - x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API? + x3b.add_assign(&Fq::from(4)); // TODO: perhaps expose coeff_b through API? let y = x3b.sqrt(); if y.is_some().into() { @@ -331,8 +331,8 @@ fn test_g2_uncompressed_invalid_vectors() { let mut x3b = x.square(); x3b.mul_assign(&x); x3b.add_assign(&Fq2 { - c0: Fq::from_repr(FqRepr::from(4)).unwrap(), - c1: Fq::from_repr(FqRepr::from(4)).unwrap(), + c0: Fq::from(4), + c1: Fq::from(4), }); // TODO: perhaps expose coeff_b through API? let y = x3b.sqrt(); @@ -428,7 +428,7 @@ fn test_g1_compressed_invalid_vectors() { loop { let mut x3b = x.square(); x3b.mul_assign(&x); - x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API? + x3b.add_assign(&Fq::from(4)); // TODO: perhaps expose coeff_b through API? if x3b.sqrt().is_some().into() { x.add_assign(&Fq::one()); @@ -452,7 +452,7 @@ fn test_g1_compressed_invalid_vectors() { loop { let mut x3b = x.square(); x3b.mul_assign(&x); - x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API? + x3b.add_assign(&Fq::from(4)); // TODO: perhaps expose coeff_b through API? if x3b.sqrt().is_some().into() { // We know this is on the curve, but it's likely not going to be in the correct subgroup. @@ -558,8 +558,8 @@ fn test_g2_compressed_invalid_vectors() { let mut x3b = x.square(); x3b.mul_assign(&x); x3b.add_assign(&Fq2 { - c0: Fq::from_repr(FqRepr::from(4)).unwrap(), - c1: Fq::from_repr(FqRepr::from(4)).unwrap(), + c0: Fq::from(4), + c1: Fq::from(4), }); // TODO: perhaps expose coeff_b through API? if x3b.sqrt().is_some().into() { @@ -589,8 +589,8 @@ fn test_g2_compressed_invalid_vectors() { let mut x3b = x.square(); x3b.mul_assign(&x); x3b.add_assign(&Fq2 { - c0: Fq::from_repr(FqRepr::from(4)).unwrap(), - c1: Fq::from_repr(FqRepr::from(4)).unwrap(), + c0: Fq::from(4), + c1: Fq::from(4), }); // TODO: perhaps expose coeff_b through API? if x3b.sqrt().is_some().into() { diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs index a1f72b84b..64242322e 100644 --- a/pairing/src/tests/field.rs +++ b/pairing/src/tests/field.rs @@ -119,7 +119,7 @@ pub fn from_str_tests() { let n = rng.next_u64(); let a = F::from_str(&format!("{}", n)).unwrap(); - let b = F::from_repr(n.into()).unwrap(); + let b = F::from(n); assert_eq!(a, b); } diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index 6e902cbd3..466d4c5ea 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -278,6 +278,15 @@ impl ::std::fmt::Display for Fs { } } +impl From for Fs { + #[inline(always)] + fn from(val: u64) -> Fs { + let mut raw = [0u64; 4]; + raw[0] = val; + Fs(FsRepr(raw)) * Fs(R2) + } +} + impl From for FsRepr { fn from(e: Fs) -> FsRepr { e.into_repr() @@ -514,7 +523,7 @@ impl Field for Fs { #[inline] fn zero() -> Self { - Fs(FsRepr::from(0)) + Fs::from(0) } #[inline] @@ -1683,10 +1692,7 @@ fn test_fs_num_bits() { #[test] fn test_fs_root_of_unity() { assert_eq!(Fs::S, 1); - assert_eq!( - Fs::multiplicative_generator(), - Fs::from_repr(FsRepr::from(6)).unwrap() - ); + assert_eq!(Fs::multiplicative_generator(), Fs::from(6)); assert_eq!( Fs::multiplicative_generator().pow_vartime([ 0x684b872f6b7b965bu64, diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index af4fa3ad0..6e01a1052 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -24,7 +24,7 @@ impl ValueCommitment { pub fn cm(&self, params: &E::Params) -> edwards::Point { params .generator(FixedGenerators::ValueCommitmentValue) - .mul(self.value, params) + .mul(E::Fs::from(self.value), params) .add( ¶ms .generator(FixedGenerators::ValueCommitmentRandomness) @@ -291,7 +291,7 @@ impl Note { let rho = self.cm_full_point(params).add( ¶ms .generator(FixedGenerators::NullifierPosition) - .mul(position, params), + .mul(E::Fs::from(position), params), params, ); diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs index 60ffd9bde..cd3757874 100644 --- a/zcash_proofs/src/sapling/mod.rs +++ b/zcash_proofs/src/sapling/mod.rs @@ -2,7 +2,7 @@ use pairing::bls12_381::Bls12; use zcash_primitives::jubjub::{ - edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown, + edwards, fs::Fs, FixedGenerators, JubjubBls12, JubjubParams, Unknown, }; use zcash_primitives::transaction::components::Amount; @@ -30,7 +30,7 @@ fn compute_value_balance( // Compute it in the exponent let mut value_balance = params .generator(FixedGenerators::ValueCommitmentValue) - .mul(FsRepr::from(abs), params); + .mul(Fs::from(abs), params); // Negate if necessary if is_negative { From 232f0a50b8c95a32fc2dc557179b5cd7f257cf45 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 28 Mar 2020 12:02:32 +1300 Subject: [PATCH 05/10] ff: Rework BitIterator to work with both u8 and u64 limb sizes This enables BitIterator to be used with both the byte encoding and limb representation of scalars. --- bellman/src/gadgets/boolean.rs | 4 +- bellman/src/gadgets/num.rs | 8 ++-- ff/src/lib.rs | 46 ++++++++++++++++++++--- pairing/src/bls12_381/ec.rs | 27 +++++++++---- pairing/src/bls12_381/mod.rs | 4 +- zcash_primitives/src/jubjub/edwards.rs | 2 +- zcash_primitives/src/jubjub/fs.rs | 7 +--- zcash_primitives/src/jubjub/montgomery.rs | 2 +- zcash_primitives/src/sapling.rs | 4 +- zcash_proofs/src/circuit/ecc.rs | 4 +- zcash_proofs/src/circuit/sapling.rs | 8 ++-- 11 files changed, 80 insertions(+), 36 deletions(-) diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs index d3c882d11..f11768164 100644 --- a/bellman/src/gadgets/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -313,12 +313,12 @@ pub fn field_into_allocated_bits_le, F: // Deconstruct in big-endian bit order let values = match value { Some(ref value) => { - let mut field_char = BitIterator::new(F::char()); + let mut field_char = BitIterator::::new(F::char()); let mut tmp = Vec::with_capacity(F::NUM_BITS as usize); let mut found_one = false; - for b in BitIterator::new(value.into_repr()) { + for b in BitIterator::::new(value.into_repr()) { // Skip leading bits found_one |= field_char.next().unwrap(); if !found_one { diff --git a/bellman/src/gadgets/num.rs b/bellman/src/gadgets/num.rs index e460d201c..f8ce6d32d 100644 --- a/bellman/src/gadgets/num.rs +++ b/bellman/src/gadgets/num.rs @@ -103,7 +103,9 @@ impl AllocatedNum { // We want to ensure that the bit representation of a is // less than or equal to r - 1. - let mut a = self.value.map(|e| BitIterator::new(e.into_repr())); + let mut a = self + .value + .map(|e| BitIterator::::new(e.into_repr())); let mut b = E::Fr::char(); b.sub_noborrow(&1.into()); @@ -115,7 +117,7 @@ impl AllocatedNum { let mut found_one = false; let mut i = 0; - for b in BitIterator::new(b) { + for b in BitIterator::::new(b) { let a_bit = a.as_mut().map(|e| e.next().unwrap()); // Skip over unset bits at the beginning @@ -558,7 +560,7 @@ mod test { assert!(cs.is_satisfied()); - for (b, a) in BitIterator::new(r.into_repr()) + for (b, a) in BitIterator::::new(r.into_repr()) .skip(1) .zip(bits.iter().rev()) { diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 8bb8ffabc..e91210fc9 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -13,6 +13,7 @@ extern crate std; pub use ff_derive::*; use core::fmt; +use core::marker::PhantomData; use core::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign}; use rand_core::RngCore; #[cfg(feature = "std")] @@ -338,20 +339,25 @@ pub trait ScalarEngine: Sized + 'static + Clone { } #[derive(Debug)] -pub struct BitIterator { +pub struct BitIterator> { t: E, n: usize, + _limb: PhantomData, } -impl> BitIterator { +impl> BitIterator { pub fn new(t: E) -> Self { let n = t.as_ref().len() * 64; - BitIterator { t, n } + BitIterator { + t, + n, + _limb: PhantomData::default(), + } } } -impl> Iterator for BitIterator { +impl> Iterator for BitIterator { type Item = bool; fn next(&mut self) -> Option { @@ -367,9 +373,37 @@ impl> Iterator for BitIterator { } } +impl> BitIterator { + pub fn new(t: E) -> Self { + let n = t.as_ref().len() * 8; + + BitIterator { + t, + n, + _limb: PhantomData::default(), + } + } +} + +impl> Iterator for BitIterator { + type Item = bool; + + fn next(&mut self) -> Option { + if self.n == 0 { + None + } else { + self.n -= 1; + let part = self.n / 8; + let bit = self.n - (8 * part); + + Some(self.t.as_ref()[part] & (1 << bit) > 0) + } + } +} + #[test] fn test_bit_iterator() { - let mut a = BitIterator::new([0xa953_d79b_83f6_ab59, 0x6dea_2059_e200_bd39]); + let mut a = BitIterator::::new([0xa953_d79b_83f6_ab59, 0x6dea_2059_e200_bd39]); let expected = "01101101111010100010000001011001111000100000000010111101001110011010100101010011110101111001101110000011111101101010101101011001"; for e in expected.chars() { @@ -380,7 +414,7 @@ fn test_bit_iterator() { let expected = "1010010101111110101010000101101011101000011101110101001000011001100100100011011010001011011011010001011011101100110100111011010010110001000011110100110001100110011101101000101100011100100100100100001010011101010111110011101011000011101000111011011101011001"; - let mut a = BitIterator::new([ + let mut a = BitIterator::::new([ 0x429d_5f3a_c3a3_b759, 0xb10f_4c66_768b_1c92, 0x9236_8b6d_16ec_d3b4, diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index 2dae1ea0e..42bd91e20 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -81,7 +81,18 @@ macro_rules! curve_impl { } impl $affine { - fn mul_bits>(&self, bits: BitIterator) -> $projective { + fn mul_bits_u64>(&self, bits: BitIterator) -> $projective { + let mut res = $projective::zero(); + for i in bits { + res.double(); + if i { + res.add_assign(self) + } + } + res + } + + fn mul_bits_u8>(&self, bits: BitIterator) -> $projective { let mut res = $projective::zero(); for i in bits { res.double(); @@ -172,8 +183,8 @@ macro_rules! curve_impl { } fn mul::Repr>>(&self, by: S) -> $projective { - let bits = BitIterator::new(by.into()); - self.mul_bits(bits) + let bits = BitIterator::::new(by.into()); + self.mul_bits_u64(bits) } fn into_projective(&self) -> $projective { @@ -655,7 +666,7 @@ macro_rules! curve_impl { let mut found_one = false; - for i in BitIterator::new(other.into()) { + for i in BitIterator::::new(other.into()) { if found_one { res.double(); } else { @@ -992,8 +1003,8 @@ pub mod g1 { impl G1Affine { fn scale_by_cofactor(&self) -> G1 { // G1 cofactor = (x - 1)^2 / 3 = 76329603384216526031706109802092473003 - let cofactor = BitIterator::new([0x8c00aaab0000aaab, 0x396c8c005555e156]); - self.mul_bits(cofactor) + let cofactor = BitIterator::::new([0x8c00aaab0000aaab, 0x396c8c005555e156]); + self.mul_bits_u64(cofactor) } fn get_generator() -> Self { @@ -1714,7 +1725,7 @@ pub mod g2 { fn scale_by_cofactor(&self) -> G2 { // G2 cofactor = (x^8 - 4 x^7 + 5 x^6) - (4 x^4 + 6 x^3 - 4 x^2 - 4 x + 13) // 9 // 0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5 - let cofactor = BitIterator::new([ + let cofactor = BitIterator::::new([ 0xcf1c38e31c7238e5, 0x1616ec6e786f0c70, 0x21537e293a6691ae, @@ -1724,7 +1735,7 @@ pub mod g2 { 0x91d50792876a202, 0x5d543a95414e7f1, ]); - self.mul_bits(cofactor) + self.mul_bits_u64(cofactor) } fn perform_pairing(&self, other: &G1Affine) -> Fq12 { diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs index afa3aaf0e..0f1805321 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/pairing/src/bls12_381/mod.rs @@ -82,7 +82,7 @@ impl Engine for Bls12 { let mut f = Fq12::one(); let mut found_one = false; - for i in BitIterator::new(&[BLS_X >> 1]) { + for i in BitIterator::::new(&[BLS_X >> 1]) { if !found_one { found_one = i; continue; @@ -324,7 +324,7 @@ impl G2Prepared { let mut r: G2 = q.into(); let mut found_one = false; - for i in BitIterator::new([BLS_X >> 1]) { + for i in BitIterator::::new([BLS_X >> 1]) { if !found_one { found_one = i; continue; diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index 1b3ebc0b6..549d44140 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -468,7 +468,7 @@ impl Point { let mut res = Self::zero(); - for b in BitIterator::new(scalar.into()) { + for b in BitIterator::::new(scalar.into()) { res = res.double(params); if b { diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index 466d4c5ea..e163adc37 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -1,4 +1,3 @@ -use byteorder::{ByteOrder, LittleEndian}; use ff::{ adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField, @@ -721,7 +720,7 @@ impl Fs { self.reduce(); } - fn mul_bits>(&self, bits: BitIterator) -> Self { + fn mul_bits>(&self, bits: BitIterator) -> Self { let mut res = Self::zero(); for bit in bits { res = res.double(); @@ -741,9 +740,7 @@ impl ToUniform for Fs { /// Random Oracle output. fn to_uniform(digest: &[u8]) -> Self { assert_eq!(digest.len(), 64); - let mut repr: [u64; 8] = [0; 8]; - LittleEndian::read_u64_into(digest, &mut repr); - Self::one().mul_bits(BitIterator::new(repr)) + Self::one().mul_bits(BitIterator::::new(digest)) } } diff --git a/zcash_primitives/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs index 9cad803e8..efdb29dcd 100644 --- a/zcash_primitives/src/jubjub/montgomery.rs +++ b/zcash_primitives/src/jubjub/montgomery.rs @@ -304,7 +304,7 @@ impl Point { let mut res = Self::zero(); - for b in BitIterator::new(scalar.into()) { + for b in BitIterator::::new(scalar.into()) { res = res.double(params); if b { diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index da8b8384f..ecf5cd400 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -21,7 +21,7 @@ pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { let lhs = { let mut tmp = [false; 256]; - for (a, b) in tmp.iter_mut().rev().zip(BitIterator::new(lhs)) { + for (a, b) in tmp.iter_mut().rev().zip(BitIterator::::new(lhs)) { *a = b; } tmp @@ -29,7 +29,7 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { let rhs = { let mut tmp = [false; 256]; - for (a, b) in tmp.iter_mut().rev().zip(BitIterator::new(rhs)) { + for (a, b) in tmp.iter_mut().rev().zip(BitIterator::::new(rhs)) { *a = b; } tmp diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index 05baf8b60..01ed2d436 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -769,7 +769,7 @@ mod test { let q = p.mul(s, params); let (x1, y1) = q.to_xy(); - let mut s_bits = BitIterator::new(s.into_repr()).collect::>(); + let mut s_bits = BitIterator::::new(s.into_repr()).collect::>(); s_bits.reverse(); s_bits.truncate(Fs::NUM_BITS as usize); @@ -822,7 +822,7 @@ mod test { y: num_y0, }; - let mut s_bits = BitIterator::new(s.into_repr()).collect::>(); + let mut s_bits = BitIterator::::new(s.into_repr()).collect::>(); s_bits.reverse(); s_bits.truncate(Fs::NUM_BITS as usize); diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index 9782a4f96..c3ddde9c6 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -615,8 +615,8 @@ fn test_input_circuit_with_bls12_381() { ::std::mem::swap(&mut lhs, &mut rhs); } - let mut lhs: Vec = BitIterator::new(lhs.into_repr()).collect(); - let mut rhs: Vec = BitIterator::new(rhs.into_repr()).collect(); + let mut lhs: Vec = BitIterator::::new(lhs.into_repr()).collect(); + let mut rhs: Vec = BitIterator::::new(rhs.into_repr()).collect(); lhs.reverse(); rhs.reverse(); @@ -799,8 +799,8 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() { ::std::mem::swap(&mut lhs, &mut rhs); } - let mut lhs: Vec = BitIterator::new(lhs.into_repr()).collect(); - let mut rhs: Vec = BitIterator::new(rhs.into_repr()).collect(); + let mut lhs: Vec = BitIterator::::new(lhs.into_repr()).collect(); + let mut rhs: Vec = BitIterator::::new(rhs.into_repr()).collect(); lhs.reverse(); rhs.reverse(); From 1fdca393bb1eeeabbdd46215a5281e93bd7a95d6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 21 Apr 2020 19:05:19 +1200 Subject: [PATCH 06/10] ff: PrimeField::{is_even, is_odd} --- bellman/src/groth16/tests/dummy_engine.rs | 4 ++++ ff/ff_derive/src/lib.rs | 5 +++++ ff/src/lib.rs | 9 +++++++++ pairing/src/bls12_381/fq.rs | 12 ++++++++++++ pairing/src/bls12_381/fr.rs | 12 ++++++++++++ zcash_primitives/src/jubjub/edwards.rs | 5 ++--- zcash_primitives/src/jubjub/fs.rs | 5 +++++ zcash_primitives/src/jubjub/montgomery.rs | 4 ++-- zcash_primitives/src/jubjub/tests.rs | 2 +- zcash_proofs/src/circuit/sapling.rs | 4 ++-- 10 files changed, 54 insertions(+), 8 deletions(-) diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 2ef9798c8..91f6993d9 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -332,6 +332,10 @@ impl PrimeField for Fr { FrRepr::from(*self) } + fn is_odd(&self) -> bool { + (self.0).0 % 2 != 0 + } + fn char() -> FrRepr { Fr(MODULUS_R).into() } diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 9a8a74462..17ad39917 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -1029,6 +1029,11 @@ fn prime_field_impl( r.0 } + #[inline(always)] + fn is_odd(&self) -> bool { + self.into_repr().is_odd() + } + fn char() -> #repr { MODULUS } diff --git a/ff/src/lib.rs b/ff/src/lib.rs index e91210fc9..b2f4d3af6 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -309,6 +309,15 @@ pub trait PrimeField: Field + From { /// the number is an element of the field. fn into_repr(&self) -> Self::Repr; + /// Returns true iff this element is odd. + fn is_odd(&self) -> bool; + + /// Returns true iff this element is even. + #[inline(always)] + fn is_even(&self) -> bool { + !self.is_odd() + } + /// Returns the field characteristic; the modulus. fn char() -> Self::Repr; diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index 5a8f17307..8e5d66028 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -2182,6 +2182,18 @@ fn test_fq_display() { ); } +#[test] +fn test_fq_is_odd() { + assert!(!Fq::from(0).is_odd()); + assert!(Fq::from(0).is_even()); + assert!(Fq::from(1).is_odd()); + assert!(!Fq::from(1).is_even()); + assert!(!Fq::from(324834872).is_odd()); + assert!(Fq::from(324834872).is_even()); + assert!(Fq::from(324834873).is_odd()); + assert!(!Fq::from(324834873).is_even()); +} + #[test] fn test_fq_num_bits() { assert_eq!(Fq::NUM_BITS, 381); diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index 028287d20..cc02d220e 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -950,6 +950,18 @@ fn test_fr_display() { ); } +#[test] +fn test_fr_is_odd() { + assert!(!Fr::from(0).is_odd()); + assert!(Fr::from(0).is_even()); + assert!(Fr::from(1).is_odd()); + assert!(!Fr::from(1).is_even()); + assert!(!Fr::from(324834872).is_odd()); + assert!(Fr::from(324834872).is_even()); + assert!(Fr::from(324834873).is_odd()); + assert!(!Fr::from(324834873).is_even()); +} + #[test] fn test_fr_num_bits() { assert_eq!(Fr::NUM_BITS, 255); diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index 549d44140..cbe4d0be0 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -127,7 +127,7 @@ impl Point { tmp1.mul_assign(&tmp2); tmp1.sqrt().map(|mut x| { - if x.into_repr().is_odd() != sign { + if x.is_odd() != sign { x = x.neg(); } @@ -172,9 +172,8 @@ impl Point { assert_eq!(E::Fr::NUM_BITS, 255); - let x_repr = x.into_repr(); let mut y_repr = y.into_repr(); - if x_repr.is_odd() { + if x.is_odd() { y_repr.as_mut()[3] |= 0x8000000000000000u64; } diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index e163adc37..e4bea138d 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -481,6 +481,11 @@ impl PrimeField for Fs { r.0 } + #[inline(always)] + fn is_odd(&self) -> bool { + self.into_repr().is_odd() + } + fn char() -> FsRepr { MODULUS } diff --git a/zcash_primitives/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs index efdb29dcd..0992637fe 100644 --- a/zcash_primitives/src/jubjub/montgomery.rs +++ b/zcash_primitives/src/jubjub/montgomery.rs @@ -1,4 +1,4 @@ -use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; +use ff::{BitIterator, Field, PrimeField, SqrtField}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use subtle::CtOption; @@ -60,7 +60,7 @@ impl Point { rhs.add_assign(&x2); rhs.sqrt().map(|mut y| { - if y.into_repr().is_odd() != sign { + if y.is_odd() != sign { y = y.neg(); } diff --git a/zcash_primitives/src/jubjub/tests.rs b/zcash_primitives/src/jubjub/tests.rs index 84b3a9649..6f66c4446 100644 --- a/zcash_primitives/src/jubjub/tests.rs +++ b/zcash_primitives/src/jubjub/tests.rs @@ -237,7 +237,7 @@ fn test_get_for(params: &E::Params) { let p = edwards::Point::::get_for_y(y, sign, params); if bool::from(p.is_some()) { let mut p = p.unwrap(); - assert!(p.to_xy().0.into_repr().is_odd() == sign); + assert!(p.to_xy().0.is_odd() == sign); p = p.negate(); assert!(edwards::Point::::get_for_y(y, !sign, params).unwrap() == p); } diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index c3ddde9c6..7d1fbbabd 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -1,6 +1,6 @@ //! The Sapling circuits. -use ff::{Field, PrimeField, PrimeFieldRepr}; +use ff::{Field, PrimeField}; use bellman::{Circuit, ConstraintSystem, SynthesisError}; @@ -478,7 +478,7 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { // Witness the sign bit let sign_bit = boolean::Boolean::from(boolean::AllocatedBit::alloc( cs.namespace(|| "pk_d bit of x"), - pk_d.map(|e| e.0.into_repr().is_odd()), + pk_d.map(|e| e.0.is_odd()), )?); // Extend the note with pk_d representation From 08500ee71275e7b6127e7b512c0763b058acf714 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 22 Apr 2020 10:45:51 +1200 Subject: [PATCH 07/10] ff: PrimeField: BitAnd + Shr --- bellman/src/groth16/tests/dummy_engine.rs | 19 +++- ff/ff_derive/src/lib.rs | 73 +++++++++++-- ff/src/lib.rs | 4 +- pairing/src/bls12_381/fq.rs | 73 +++++++++++++ pairing/src/bls12_381/fr.rs | 61 +++++++++++ zcash_primitives/src/jubjub/fs.rs | 127 +++++++++++++++++++++- zcash_primitives/src/pedersen_hash.rs | 8 +- 7 files changed, 348 insertions(+), 17 deletions(-) diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 91f6993d9..86e7b182e 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -8,7 +8,7 @@ use rand_core::RngCore; use std::cmp::Ordering; use std::fmt; use std::num::Wrapping; -use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use std::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; const MODULUS_R: Wrapping = Wrapping(64513); @@ -151,6 +151,23 @@ impl MulAssign for Fr { } } +impl BitAnd for Fr { + type Output = u64; + + fn bitand(self, rhs: u64) -> u64 { + (self.0).0 as u64 & rhs + } +} + +impl Shr for Fr { + type Output = Fr; + + fn shr(mut self, rhs: u32) -> Fr { + self.0 = Wrapping((self.0).0 >> rhs); + self + } +} + impl Field for Fr { fn random(rng: &mut R) -> Self { Fr(Wrapping(rng.next_u32()) % MODULUS_R) diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 17ad39917..f5439c535 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -785,14 +785,19 @@ fn prime_field_impl( proc_macro2::Punct::new('&', proc_macro2::Spacing::Alone), ); - // (self.0).0[0], (self.0).0[1], ..., 0, 0, 0, 0, ... - let mut into_repr_params = proc_macro2::TokenStream::new(); - into_repr_params.append_separated( - (0..limbs) - .map(|i| quote! { (self.0).0[#i] }) - .chain((0..limbs).map(|_| quote! {0})), - proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), - ); + fn mont_reduce_params(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream { + // a.0[0], a.0[1], ..., 0, 0, 0, 0, ... + let mut mont_reduce_params = proc_macro2::TokenStream::new(); + mont_reduce_params.append_separated( + (0..limbs) + .map(|i| quote! { (#a.0).0[#i] }) + .chain((0..limbs).map(|_| quote! {0})), + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), + ); + mont_reduce_params + } + + let mont_reduce_self_params = mont_reduce_params(quote! {self}, limbs); let top_limb_index = limbs - 1; @@ -1006,6 +1011,56 @@ fn prime_field_impl( } } + impl ::core::ops::BitAnd for #name { + type Output = u64; + + #[inline(always)] + fn bitand(mut self, rhs: u64) -> u64 { + self.mont_reduce( + #mont_reduce_self_params + ); + + (self.0).0[0] & rhs + } + } + + impl ::core::ops::Shr for #name { + type Output = #name; + + #[inline(always)] + fn shr(mut self, mut n: u32) -> #name { + if n as usize >= 64 * #limbs { + return Self::from(0); + } + + // Convert from Montgomery to native representation. + self.mont_reduce( + #mont_reduce_self_params + ); + + while n >= 64 { + let mut t = 0; + for i in (self.0).0.iter_mut().rev() { + ::core::mem::swap(&mut t, i); + } + n -= 64; + } + + if n > 0 { + let mut t = 0; + for i in (self.0).0.iter_mut().rev() { + let t2 = *i << (64 - n); + *i >>= n; + *i |= t; + t = t2; + } + } + + // Convert back to Montgomery representation + self * #name(R2) + } + } + impl ::ff::PrimeField for #name { type Repr = #repr; @@ -1023,7 +1078,7 @@ fn prime_field_impl( fn into_repr(&self) -> #repr { let mut r = *self; r.mont_reduce( - #into_repr_params + #mont_reduce_self_params ); r.0 diff --git a/ff/src/lib.rs b/ff/src/lib.rs index b2f4d3af6..78fbc5c37 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -257,7 +257,9 @@ impl fmt::Display for PrimeFieldDecodingError { } /// This represents an element of a prime field. -pub trait PrimeField: Field + From { +pub trait PrimeField: + Field + From + BitAnd + Shr +{ /// The prime field can be converted back and forth into this biginteger /// representation. type Repr: PrimeFieldRepr + From; diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index 8e5d66028..f9caf5e95 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -1931,6 +1931,79 @@ fn test_fq_mul_assign() { } } +#[test] +fn test_fq_shr() { + let mut a = Fq::from_repr(FqRepr([ + 0xaa5cdd6172847ffd, + 0x43242c06aed55287, + 0x9ddd5b312f3dd104, + 0xc5541fd48046b7e7, + 0x16080cf4071e0b05, + 0x1225f2901aea514e, + ])) + .unwrap(); + a = a >> 0; + assert_eq!( + a.into_repr(), + FqRepr([ + 0xaa5cdd6172847ffd, + 0x43242c06aed55287, + 0x9ddd5b312f3dd104, + 0xc5541fd48046b7e7, + 0x16080cf4071e0b05, + 0x1225f2901aea514e, + ]) + ); + a = a >> 1; + assert_eq!( + a.into_repr(), + FqRepr([ + 0xd52e6eb0b9423ffe, + 0x21921603576aa943, + 0xceeead98979ee882, + 0xe2aa0fea40235bf3, + 0x0b04067a038f0582, + 0x0912f9480d7528a7, + ]) + ); + a = a >> 50; + assert_eq!( + a.into_repr(), + FqRepr([ + 0x8580d5daaa50f54b, + 0xab6625e7ba208864, + 0x83fa9008d6fcf3bb, + 0x019e80e3c160b8aa, + 0xbe52035d4a29c2c1, + 0x0000000000000244, + ]) + ); + a = a >> 130; + assert_eq!( + a.into_repr(), + FqRepr([ + 0xa0fea40235bf3cee, + 0x4067a038f0582e2a, + 0x2f9480d7528a70b0, + 0x0000000000000091, + 0x0000000000000000, + 0x0000000000000000, + ]) + ); + a = a >> 64; + assert_eq!( + a.into_repr(), + FqRepr([ + 0x4067a038f0582e2a, + 0x2f9480d7528a70b0, + 0x0000000000000091, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + ]) + ); +} + #[test] fn test_fq_squaring() { let a = Fq(FqRepr([ diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index cc02d220e..6bfb17520 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -669,6 +669,67 @@ fn test_fr_mul_assign() { } } +#[test] +fn test_fr_shr() { + let mut a = Fr::from_repr(FrRepr([ + 0xb33fbaec482a283f, + 0x997de0d3a88cb3df, + 0x9af62d2a9a0e5525, + 0x36003ab08de70da1, + ])) + .unwrap(); + a = a >> 0; + assert_eq!( + a.into_repr(), + FrRepr([ + 0xb33fbaec482a283f, + 0x997de0d3a88cb3df, + 0x9af62d2a9a0e5525, + 0x36003ab08de70da1, + ]) + ); + a = a >> 1; + assert_eq!( + a.into_repr(), + FrRepr([ + 0xd99fdd762415141f, + 0xccbef069d44659ef, + 0xcd7b16954d072a92, + 0x1b001d5846f386d0, + ]) + ); + a = a >> 50; + assert_eq!( + a.into_repr(), + FrRepr([ + 0xbc1a7511967bf667, + 0xc5a55341caa4b32f, + 0x075611bce1b4335e, + 0x00000000000006c0, + ]) + ); + a = a >> 130; + assert_eq!( + a.into_repr(), + FrRepr([ + 0x01d5846f386d0cd7, + 0x00000000000001b0, + 0x0000000000000000, + 0x0000000000000000, + ]) + ); + a = a >> 64; + assert_eq!( + a.into_repr(), + FrRepr([ + 0x00000000000001b0, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + ]) + ); +} + #[test] fn test_fr_squaring() { let a = Fr(FrRepr([ diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index e4bea138d..81d7089b4 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -3,7 +3,8 @@ use ff::{ PrimeFieldRepr, SqrtField, }; use rand_core::RngCore; -use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use std::mem; +use std::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use super::ToUniform; @@ -452,6 +453,69 @@ impl MulAssign for Fs { } } +impl BitAnd for Fs { + type Output = u64; + + #[inline(always)] + fn bitand(mut self, rhs: u64) -> u64 { + self.mont_reduce( + (self.0).0[0], + (self.0).0[1], + (self.0).0[2], + (self.0).0[3], + 0, + 0, + 0, + 0, + ); + (self.0).0[0] & rhs + } +} + +impl Shr for Fs { + type Output = Self; + + #[inline(always)] + fn shr(mut self, mut n: u32) -> Self { + if n as usize >= 64 * 4 { + return Self::from(0); + } + + // Convert from Montgomery to native representation. + self.mont_reduce( + (self.0).0[0], + (self.0).0[1], + (self.0).0[2], + (self.0).0[3], + 0, + 0, + 0, + 0, + ); + + while n >= 64 { + let mut t = 0; + for i in (self.0).0.iter_mut().rev() { + mem::swap(&mut t, i); + } + n -= 64; + } + + if n > 0 { + let mut t = 0; + for i in (self.0).0.iter_mut().rev() { + let t2 = *i << (64 - n); + *i >>= n; + *i |= t; + t = t2; + } + } + + // Convert back to Montgomery representation + self * Fs(R2) + } +} + impl PrimeField for Fs { type Repr = FsRepr; @@ -1400,6 +1464,67 @@ fn test_fs_mul_assign() { } } +#[test] +fn test_fs_shr() { + let mut a = Fs::from_repr(FsRepr([ + 0xb33fbaec482a283f, + 0x997de0d3a88cb3df, + 0x9af62d2a9a0e5525, + 0x06003ab08de70da1, + ])) + .unwrap(); + a = a >> 0; + assert_eq!( + a.into_repr(), + FsRepr([ + 0xb33fbaec482a283f, + 0x997de0d3a88cb3df, + 0x9af62d2a9a0e5525, + 0x06003ab08de70da1, + ]) + ); + a = a >> 1; + assert_eq!( + a.into_repr(), + FsRepr([ + 0xd99fdd762415141f, + 0xccbef069d44659ef, + 0xcd7b16954d072a92, + 0x03001d5846f386d0, + ]) + ); + a = a >> 50; + assert_eq!( + a.into_repr(), + FsRepr([ + 0xbc1a7511967bf667, + 0xc5a55341caa4b32f, + 0x075611bce1b4335e, + 0x00000000000000c0, + ]) + ); + a = a >> 130; + assert_eq!( + a.into_repr(), + FsRepr([ + 0x01d5846f386d0cd7, + 0x0000000000000030, + 0x0000000000000000, + 0x0000000000000000, + ]) + ); + a = a >> 64; + assert_eq!( + a.into_repr(), + FsRepr([ + 0x0000000000000030, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + ]) + ); +} + #[test] fn test_fr_squaring() { let a = Fs(FsRepr([ diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index ea182a5ac..afd8a7325 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -1,7 +1,7 @@ //! Implementation of the Pedersen hash function used in Sapling. use crate::jubjub::*; -use ff::{Field, PrimeField, PrimeFieldRepr}; +use ff::Field; use std::ops::{AddAssign, Neg}; #[derive(Copy, Clone)] @@ -88,16 +88,14 @@ where let window = JubjubBls12::pedersen_hash_exp_window_size(); let window_mask = (1 << window) - 1; - let mut acc = acc.into_repr(); - let mut tmp = edwards::Point::zero(); while !acc.is_zero() { - let i = (acc.as_ref()[0] & window_mask) as usize; + let i = (acc & window_mask) as usize; tmp = tmp.add(&table[0][i], params); - acc.shr(window); + acc = acc >> window; table = &table[1..]; } From 1a40cfd39c0db51313c2de50c344e1bdd905c9a6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 22 Apr 2020 18:58:36 +1200 Subject: [PATCH 08/10] zcash_primitives: Make jubjub::Fs::invert constant time --- zcash_primitives/src/jubjub/fs.rs | 68 +++++++------------------------ 1 file changed, 15 insertions(+), 53 deletions(-) diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index 81d7089b4..f3af2b1ce 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -617,61 +617,23 @@ impl Field for Fs { ret } - /// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET! - /// THIS WILL BE REPLACED BY THE jubjub CRATE, WHICH IS CONSTANT TIME! fn invert(&self) -> CtOption { - if self.is_zero() { - CtOption::new(Self::zero(), Choice::from(0)) - } else { - // Guajardo Kumar Paar Pelzl - // Efficient Software-Implementation of Finite Fields with Applications to Cryptography - // Algorithm 16 (BEA for Inversion in Fp) + // We need to find b such that b * a ≡ 1 mod p. As we are in a prime + // field, we can apply Fermat's Little Theorem: + // + // a^p ≡ a mod p + // a^(p-1) ≡ 1 mod p + // a^(p-2) * a ≡ 1 mod p + // + // Thus inversion can be implemented with a single exponentiation. + let inverse = self.pow_vartime(&[ + 0xd097_0e5e_d6f7_2cb5u64, + 0xa668_2093_ccc8_1082, + 0x0667_3b01_0134_3b00, + 0x0e7d_b4ea_6533_afa9, + ]); - let one = FsRepr::from(1); - - let mut u = self.0; - let mut v = MODULUS; - let mut b = Fs(R2); // 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(&MODULUS); - b.0.div2(); - } - } - - while v.is_even() { - v.div2(); - - if c.0.is_even() { - c.0.div2(); - } else { - c.0.add_nocarry(&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 { - CtOption::new(b, Choice::from(1)) - } else { - CtOption::new(c, Choice::from(1)) - } - } + CtOption::new(inverse, Choice::from(if self.is_zero() { 0 } else { 1 })) } #[inline(always)] From 1fe3e3784cf9c9f1ec4da0210c6095b56fb3447a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 23 Apr 2020 16:30:36 +1200 Subject: [PATCH 09/10] ff: Add Ord bound to PrimeField --- bellman/src/groth16/tests/dummy_engine.rs | 12 ++++++++++++ ff/src/lib.rs | 2 +- zcash_primitives/src/jubjub/fs.rs | 14 +++++++++++++ zcash_primitives/src/jubjub/tests.rs | 24 +++++++++-------------- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 86e7b182e..6d3ae73f0 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -50,6 +50,18 @@ impl ConditionallySelectable for Fr { } } +impl Ord for Fr { + fn cmp(&self, other: &Fr) -> Ordering { + (self.0).0.cmp(&(other.0).0) + } +} + +impl PartialOrd for Fr { + fn partial_cmp(&self, other: &Fr) -> Option { + Some(self.cmp(other)) + } +} + impl Neg for Fr { type Output = Self; diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 78fbc5c37..9a4028be9 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -258,7 +258,7 @@ impl fmt::Display for PrimeFieldDecodingError { /// This represents an element of a prime field. pub trait PrimeField: - Field + From + BitAnd + Shr + Field + Ord + From + BitAnd + Shr { /// The prime field can be converted back and forth into this biginteger /// representation. diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index f3af2b1ce..85c3df4ce 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -272,6 +272,20 @@ impl ConstantTimeEq for Fs { } } +impl Ord for Fs { + #[inline(always)] + fn cmp(&self, other: &Fs) -> ::std::cmp::Ordering { + self.into_repr().cmp(&other.into_repr()) + } +} + +impl PartialOrd for Fs { + #[inline(always)] + fn partial_cmp(&self, other: &Fs) -> Option<::std::cmp::Ordering> { + Some(self.cmp(other)) + } +} + impl ::std::fmt::Display for Fs { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "Fs({})", self.into_repr()) diff --git a/zcash_primitives/src/jubjub/tests.rs b/zcash_primitives/src/jubjub/tests.rs index 6f66c4446..fca26b916 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, PrimeFieldRepr, SqrtField}; +use ff::{Field, PrimeField, SqrtField}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use rand_core::{RngCore, SeedableRng}; @@ -370,32 +370,26 @@ fn test_jubjub_params(params: &E::Params) { // Check that the number of windows per generator // in the Pedersen hash does not allow for collisions - let mut cur = E::Fs::one().into_repr(); + let mut cur = E::Fs::one(); - let mut max = E::Fs::char(); - { - max.sub_noborrow(&E::Fs::one().into_repr()); - max.div2(); - } + let max = (-E::Fs::one()) >> 1; - let mut pacc = E::Fs::zero().into_repr(); - let mut nacc = E::Fs::char(); + let mut pacc = E::Fs::zero(); + let mut nacc = E::Fs::zero(); for _ in 0..params.pedersen_hash_chunks_per_generator() { // tmp = cur * 4 - let mut tmp = cur; - tmp.mul2(); - tmp.mul2(); + let tmp = cur.double().double(); - pacc.add_nocarry(&tmp); - nacc.sub_noborrow(&tmp); + pacc += &tmp; + nacc -= &tmp; // The first subtraction wraps intentionally. assert!(pacc < max); assert!(pacc < nacc); // cur = cur * 16 for _ in 0..4 { - cur.mul2(); + cur = cur.double(); } } } From 49f119fb033dac88165028b7117e3d23e9f469a8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 23 Apr 2020 17:32:04 +1200 Subject: [PATCH 10/10] ff: Remove PrimeFieldRepr trait The ff::PrimeField::Repr associated type now has the minimal necessary bounds, which can be satisfied by a newtype around a byte array. --- bellman/src/gadgets/boolean.rs | 4 +- bellman/src/gadgets/num.rs | 13 +- bellman/src/gadgets/test/mod.rs | 9 +- bellman/src/groth16/prover.rs | 20 +- bellman/src/groth16/tests/dummy_engine.rs | 92 +- bellman/src/multiexp.rs | 22 +- ff/ff_derive/src/lib.rs | 642 ++++++---- ff/src/lib.rs | 148 +-- group/src/lib.rs | 10 +- group/src/wnaf.rs | 13 +- pairing/benches/bls12_381/fq.rs | 138 +-- pairing/benches/bls12_381/fr.rs | 138 +-- pairing/src/bls12_381/ec.rs | 697 +++++------ pairing/src/bls12_381/fq.rs | 866 ++++---------- pairing/src/bls12_381/fq2.rs | 508 ++++---- pairing/src/bls12_381/fr.rs | 607 ++-------- pairing/src/bls12_381/tests/mod.rs | 84 +- pairing/src/tests/field.rs | 2 +- pairing/src/tests/repr.rs | 87 +- zcash_client_backend/src/proto/mod.rs | 6 +- zcash_client_backend/src/welding_rig.rs | 9 +- zcash_primitives/src/jubjub/edwards.rs | 22 +- zcash_primitives/src/jubjub/fs.rs | 1044 +++++------------ zcash_primitives/src/jubjub/montgomery.rs | 2 +- zcash_primitives/src/keys.rs | 14 +- zcash_primitives/src/merkle_tree.rs | 6 +- zcash_primitives/src/note_encryption.rs | 55 +- zcash_primitives/src/primitives.rs | 4 +- zcash_primitives/src/redjubjub.rs | 12 +- zcash_primitives/src/sapling.rs | 12 +- .../src/transaction/components.rs | 20 +- zcash_primitives/src/transaction/sighash.rs | 4 +- zcash_primitives/src/zip32.rs | 17 +- zcash_proofs/src/circuit/ecc.rs | 4 +- zcash_proofs/src/circuit/sapling.rs | 8 +- 35 files changed, 1705 insertions(+), 3634 deletions(-) diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs index f11768164..2ccad51a7 100644 --- a/bellman/src/gadgets/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -313,12 +313,12 @@ pub fn field_into_allocated_bits_le, F: // Deconstruct in big-endian bit order let values = match value { Some(ref value) => { - let mut field_char = BitIterator::::new(F::char()); + let mut field_char = BitIterator::::new(F::char()); let mut tmp = Vec::with_capacity(F::NUM_BITS as usize); let mut found_one = false; - for b in BitIterator::::new(value.into_repr()) { + for b in BitIterator::::new(value.into_repr()) { // Skip leading bits found_one |= field_char.next().unwrap(); if !found_one { diff --git a/bellman/src/gadgets/num.rs b/bellman/src/gadgets/num.rs index f8ce6d32d..8f736636d 100644 --- a/bellman/src/gadgets/num.rs +++ b/bellman/src/gadgets/num.rs @@ -1,6 +1,6 @@ //! Gadgets representing numbers in the scalar field of the underlying curve. -use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, ScalarEngine}; +use ff::{BitIterator, Field, PrimeField, ScalarEngine}; use std::ops::{AddAssign, MulAssign}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; @@ -103,11 +103,8 @@ impl AllocatedNum { // We want to ensure that the bit representation of a is // less than or equal to r - 1. - let mut a = self - .value - .map(|e| BitIterator::::new(e.into_repr())); - let mut b = E::Fr::char(); - b.sub_noborrow(&1.into()); + let mut a = self.value.map(|e| BitIterator::::new(e.into_repr())); + let b = (-E::Fr::one()).into_repr(); let mut result = vec![]; @@ -117,7 +114,7 @@ impl AllocatedNum { let mut found_one = false; let mut i = 0; - for b in BitIterator::::new(b) { + for b in BitIterator::::new(b) { let a_bit = a.as_mut().map(|e| e.next().unwrap()); // Skip over unset bits at the beginning @@ -560,7 +557,7 @@ mod test { assert!(cs.is_satisfied()); - for (b, a) in BitIterator::::new(r.into_repr()) + for (b, a) in BitIterator::::new(r.into_repr()) .skip(1) .zip(bits.iter().rev()) { diff --git a/bellman/src/gadgets/test/mod.rs b/bellman/src/gadgets/test/mod.rs index a803accae..b08290749 100644 --- a/bellman/src/gadgets/test/mod.rs +++ b/bellman/src/gadgets/test/mod.rs @@ -1,6 +1,6 @@ //! Helpers for testing circuit implementations. -use ff::{Field, PowVartime, PrimeField, PrimeFieldRepr, ScalarEngine}; +use ff::{Field, PowVartime, PrimeField, ScalarEngine}; use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; @@ -106,7 +106,12 @@ fn hash_lc(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) { } } - coeff.into_repr().write_be(&mut buf[9..]).unwrap(); + // BLS12-381's Fr is canonically serialized in little-endian, but the hasher + // writes its coefficients in big endian. For now, we flip the endianness + // manually, which is not necessarily correct for circuits using other curves. + // TODO: Fix this in a standalone commit, and document the no-op change. + let coeff_be: Vec<_> = coeff.into_repr().as_ref().iter().cloned().rev().collect(); + buf[9..].copy_from_slice(&coeff_be[..]); h.update(&buf); } diff --git a/bellman/src/groth16/prover.rs b/bellman/src/groth16/prover.rs index c31b4db97..34abbb4ea 100644 --- a/bellman/src/groth16/prover.rs +++ b/bellman/src/groth16/prover.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use futures::Future; -use ff::{Field, PrimeField}; +use ff::Field; use group::{CurveAffine, CurveProjective}; use pairing::Engine; @@ -229,26 +229,14 @@ where let a_len = a.len() - 1; a.truncate(a_len); // TODO: parallelize if it's even helpful - let a = Arc::new(a.into_iter().map(|s| s.0.into_repr()).collect::>()); + let a = Arc::new(a.into_iter().map(|s| s.0).collect::>()); multiexp(&worker, params.get_h(a.len())?, FullDensity, a) }; // TODO: parallelize if it's even helpful - let input_assignment = Arc::new( - prover - .input_assignment - .into_iter() - .map(|s| s.into_repr()) - .collect::>(), - ); - let aux_assignment = Arc::new( - prover - .aux_assignment - .into_iter() - .map(|s| s.into_repr()) - .collect::>(), - ); + let input_assignment = Arc::new(prover.input_assignment); + let aux_assignment = Arc::new(prover.aux_assignment); let l = multiexp( &worker, diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 6d3ae73f0..69937ce9c 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -1,6 +1,4 @@ -use ff::{ - Field, PowVartime, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField, -}; +use ff::{Field, PowVartime, PrimeField, ScalarEngine, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use pairing::{Engine, PairingCurveAffine}; @@ -259,86 +257,35 @@ impl SqrtField for Fr { } #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct FrRepr([u64; 1]); - -impl Ord for FrRepr { - fn cmp(&self, other: &FrRepr) -> Ordering { - (self.0)[0].cmp(&(other.0)[0]) - } -} - -impl PartialOrd for FrRepr { - fn partial_cmp(&self, other: &FrRepr) -> Option { - Some(self.cmp(other)) - } -} - -impl fmt::Display for FrRepr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(f, "{}", (self.0)[0]) - } -} - -impl From for FrRepr { - fn from(v: u64) -> FrRepr { - FrRepr([v]) - } -} +pub struct FrRepr([u8; 8]); impl From for FrRepr { fn from(v: Fr) -> FrRepr { - FrRepr([(v.0).0 as u64]) + FrRepr::from(&v) } } -impl AsMut<[u64]> for FrRepr { - fn as_mut(&mut self) -> &mut [u64] { +impl<'a> From<&'a Fr> for FrRepr { + fn from(v: &'a Fr) -> FrRepr { + FrRepr(((v.0).0 as u64).to_le_bytes()) + } +} + +impl AsMut<[u8]> for FrRepr { + fn as_mut(&mut self) -> &mut [u8] { &mut self.0[..] } } -impl AsRef<[u64]> for FrRepr { - fn as_ref(&self) -> &[u64] { +impl AsRef<[u8]> for FrRepr { + fn as_ref(&self) -> &[u8] { &self.0[..] } } impl Default for FrRepr { fn default() -> FrRepr { - FrRepr::from(0u64) - } -} - -impl PrimeFieldRepr for FrRepr { - fn sub_noborrow(&mut self, other: &Self) { - self.0[0] = self.0[0].wrapping_sub(other.0[0]); - } - fn add_nocarry(&mut self, other: &Self) { - self.0[0] = self.0[0].wrapping_add(other.0[0]); - } - fn num_bits(&self) -> u32 { - 64 - self.0[0].leading_zeros() - } - fn is_zero(&self) -> bool { - self.0[0] == 0 - } - fn is_odd(&self) -> bool { - !self.is_even() - } - fn is_even(&self) -> bool { - self.0[0] % 2 == 0 - } - fn div2(&mut self) { - self.shr(1) - } - fn shr(&mut self, amt: u32) { - self.0[0] >>= amt; - } - fn mul2(&mut self) { - self.shl(1) - } - fn shl(&mut self, amt: u32) { - self.0[0] <<= amt; + FrRepr([0; 8]) } } @@ -349,11 +296,12 @@ impl PrimeField for Fr { const CAPACITY: u32 = 15; const S: u32 = 10; - fn from_repr(repr: FrRepr) -> Result { - if repr.0[0] >= (MODULUS_R.0 as u64) { - Err(PrimeFieldDecodingError::NotInField) + fn from_repr(repr: FrRepr) -> Option { + let v = u64::from_le_bytes(repr.0); + if v >= (MODULUS_R.0 as u64) { + None } else { - Ok(Fr(Wrapping(repr.0[0] as u32))) + Some(Fr(Wrapping(v as u32))) } } @@ -464,7 +412,7 @@ impl CurveProjective for Fr { *self } - fn recommended_wnaf_for_scalar(_: &::Repr) -> usize { + fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize { 3 } diff --git a/bellman/src/multiexp.rs b/bellman/src/multiexp.rs index 0bc61ba14..18f48bd46 100644 --- a/bellman/src/multiexp.rs +++ b/bellman/src/multiexp.rs @@ -1,6 +1,6 @@ use super::multicore::Worker; use bit_vec::{self, BitVec}; -use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; +use ff::{Field, PrimeField, ScalarEngine}; use futures::Future; use group::{CurveAffine, CurveProjective}; use std::io; @@ -154,7 +154,7 @@ fn multiexp_inner( pool: &Worker, bases: S, density_map: D, - exponents: Arc::Fr as PrimeField>::Repr>>, + exponents: Arc::Fr>>, mut skip: u32, c: u32, handle_trivial: bool, @@ -181,13 +181,12 @@ where // Create space for the buckets let mut buckets = vec![G::zero(); (1 << c) - 1]; - let zero = ::Fr::zero().into_repr(); - let one = ::Fr::one().into_repr(); + let one = ::Fr::one(); // Sort the bases into buckets for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) { if density { - if exp == zero { + if exp.is_zero() { bases.skip(1)?; } else if exp == one { if handle_trivial { @@ -196,9 +195,8 @@ where bases.skip(1)?; } } else { - let mut exp = exp; - exp.shr(skip); - let exp = exp.as_ref()[0] % (1 << c); + let exp = exp >> skip; + let exp = exp & ((1 << c) - 1); if exp != 0 { (&mut buckets[(exp - 1) as usize]) @@ -261,7 +259,7 @@ pub fn multiexp( pool: &Worker, bases: S, density_map: D, - exponents: Arc::Fr as PrimeField>::Repr>>, + exponents: Arc::Fr>>, ) -> Box> where for<'a> &'a Q: QueryDensity, @@ -290,14 +288,14 @@ where fn test_with_bls12() { fn naive_multiexp( bases: Arc::Affine>>, - exponents: Arc::Repr>>, + exponents: Arc>, ) -> G { assert_eq!(bases.len(), exponents.len()); let mut acc = G::zero(); for (base, exp) in bases.iter().zip(exponents.iter()) { - AddAssign::<&G>::add_assign(&mut acc, &base.mul(*exp)); + AddAssign::<&G>::add_assign(&mut acc, &base.mul(exp.into_repr())); } acc @@ -311,7 +309,7 @@ fn test_with_bls12() { let rng = &mut rand::thread_rng(); let v = Arc::new( (0..SAMPLES) - .map(|_| ::Fr::random(rng).into_repr()) + .map(|_| ::Fr::random(rng)) .collect::>(), ); let g = Arc::new( diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index f5439c535..0a7db91a8 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -8,19 +8,105 @@ use num_integer::Integer; use num_traits::{One, ToPrimitive, Zero}; use quote::quote; use quote::TokenStreamExt; +use std::iter; use std::str::FromStr; mod pow_fixed; -#[proc_macro_derive(PrimeField, attributes(PrimeFieldModulus, PrimeFieldGenerator))] +enum ReprEndianness { + Big, + Little, +} + +impl FromStr for ReprEndianness { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "big" => Ok(ReprEndianness::Big), + "little" => Ok(ReprEndianness::Little), + _ => Err(()), + } + } +} + +impl ReprEndianness { + fn from_repr(&self, name: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream { + let read_repr = match self { + ReprEndianness::Big => quote! { + ::byteorder::BigEndian::read_u64_into(r.as_ref(), &mut inner[..]); + inner.reverse(); + }, + ReprEndianness::Little => quote! { + ::byteorder::LittleEndian::read_u64_into(r.as_ref(), &mut inner[..]); + }, + }; + + quote! { + use ::byteorder::ByteOrder; + + let r = { + let mut inner = [0u64; #limbs]; + #read_repr + #name(inner) + }; + + if r.is_valid() { + Some(r * R2) + } else { + None + } + } + } + + fn into_repr( + &self, + repr: &syn::Ident, + mont_reduce_self_params: &proc_macro2::TokenStream, + limbs: usize, + ) -> proc_macro2::TokenStream { + let bytes = limbs * 8; + + let write_repr = match self { + ReprEndianness::Big => quote! { + r.0.reverse(); + ::byteorder::BigEndian::write_u64_into(&r.0, &mut repr[..]); + }, + ReprEndianness::Little => quote! { + ::byteorder::LittleEndian::write_u64_into(&r.0, &mut repr[..]); + }, + }; + + quote! { + use ::byteorder::ByteOrder; + + let mut r = *self; + r.mont_reduce( + #mont_reduce_self_params + ); + + let mut repr = [0u8; #bytes]; + #write_repr + #repr(repr) + } + } + + fn iter_be(&self) -> proc_macro2::TokenStream { + match self { + ReprEndianness::Big => quote! {self.0.iter()}, + ReprEndianness::Little => quote! {self.0.iter().rev()}, + } + } +} + +#[proc_macro_derive( + PrimeField, + attributes(PrimeFieldModulus, PrimeFieldGenerator, PrimeFieldReprEndianness) +)] pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { // Parse the type definition let ast: syn::DeriveInput = syn::parse(input).unwrap(); - // The struct we're deriving for is a wrapper around a "Repr" type we must construct. - let repr_ident = fetch_wrapped_ident(&ast.data) - .expect("PrimeField derive only operates over tuple structs of a single item"); - // We're given the modulus p of the prime field let modulus: BigUint = fetch_attr("PrimeFieldModulus", &ast.attrs) .expect("Please supply a PrimeFieldModulus attribute") @@ -29,11 +115,18 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { // We may be provided with a generator of p - 1 order. It is required that this generator be quadratic // nonresidue. + // TODO: Compute this ourselves. let generator: BigUint = fetch_attr("PrimeFieldGenerator", &ast.attrs) .expect("Please supply a PrimeFieldGenerator attribute") .parse() .expect("PrimeFieldGenerator should be a number"); + // Field element representations may be in little-endian or big-endian. + let endianness = fetch_attr("PrimeFieldReprEndianness", &ast.attrs) + .expect("Please supply a PrimeFieldReprEndianness attribute") + .parse() + .expect("PrimeFieldReprEndianness should be 'big' or 'little'"); + // The arithmetic in this library only works if the modulus*2 is smaller than the backing // representation. Compute the number of limbs we need. let mut limbs = 1; @@ -46,34 +139,146 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } } + // The struct we're deriving for must be a wrapper around `pub [u64; limbs]`. + if let Some(err) = validate_struct(&ast, limbs) { + return err.into(); + } + + // Generate the identifier for the "Repr" type we must construct. + let repr_ident = syn::Ident::new( + &format!("{}Repr", ast.ident), + proc_macro2::Span::call_site(), + ); + let mut gen = proc_macro2::TokenStream::new(); let (constants_impl, sqrt_impl) = prime_field_constants_and_sqrt(&ast.ident, &repr_ident, &modulus, limbs, generator); gen.extend(constants_impl); - gen.extend(prime_field_repr_impl(&repr_ident, limbs)); - gen.extend(prime_field_impl(&ast.ident, &repr_ident, &modulus, limbs)); + gen.extend(prime_field_repr_impl(&repr_ident, &endianness, limbs * 8)); + gen.extend(prime_field_impl( + &ast.ident, + &repr_ident, + &modulus, + &endianness, + limbs, + )); gen.extend(sqrt_impl); // Return the generated impl gen.into() } -/// Fetches the ident being wrapped by the type we're deriving. -fn fetch_wrapped_ident(body: &syn::Data) -> Option { - if let syn::Data::Struct(ref variant_data) = body { - if let syn::Fields::Unnamed(ref fields) = variant_data.fields { - if fields.unnamed.len() == 1 { - if let syn::Type::Path(ref path) = fields.unnamed[0].ty { - if path.path.segments.len() == 1 { - return Some(path.path.segments[0].ident.clone()); - } - } - } +/// Checks that `body` contains `pub [u64; limbs]`. +fn validate_struct(ast: &syn::DeriveInput, limbs: usize) -> Option { + // The body should be a struct. + let variant_data = match &ast.data { + syn::Data::Struct(x) => x, + _ => { + return Some( + syn::Error::new_spanned(ast, "PrimeField derive only works for structs.") + .to_compile_error(), + ) } }; + // The struct should contain a single unnamed field. + let fields = match &variant_data.fields { + syn::Fields::Unnamed(x) if x.unnamed.len() == 1 => x, + _ => { + return Some( + syn::Error::new_spanned( + &ast.ident, + format!( + "The struct must contain an array of limbs. Change this to `{}([u64; {}])`", + ast.ident, limbs, + ), + ) + .to_compile_error(), + ) + } + }; + let field = &fields.unnamed[0]; + + // The field should be an array. + let arr = match &field.ty { + syn::Type::Array(x) => x, + _ => { + return Some( + syn::Error::new_spanned( + field, + format!( + "The inner field must be an array of limbs. Change this to `[u64; {}]`", + limbs, + ), + ) + .to_compile_error(), + ) + } + }; + + // The array's element type should be `u64`. + if match arr.elem.as_ref() { + syn::Type::Path(path) => path + .path + .get_ident() + .map(|x| x.to_string() != "u64") + .unwrap_or(true), + _ => true, + } { + return Some( + syn::Error::new_spanned( + arr, + format!( + "PrimeField derive requires 64-bit limbs. Change this to `[u64; {}]", + limbs + ), + ) + .to_compile_error(), + ); + } + + // The array's length should be a literal int equal to `limbs`. + let lit_int = match match &arr.len { + syn::Expr::Lit(expr_lit) => match &expr_lit.lit { + syn::Lit::Int(lit_int) => Some(lit_int), + _ => None, + }, + _ => None, + } { + Some(x) => x, + _ => { + return Some( + syn::Error::new_spanned( + arr, + format!("To derive PrimeField, change this to `[u64; {}]`.", limbs), + ) + .to_compile_error(), + ) + } + }; + if lit_int.base10_digits() != limbs.to_string() { + return Some( + syn::Error::new_spanned( + lit_int, + format!("The given modulus requires {} limbs.", limbs), + ) + .to_compile_error(), + ); + } + + // The field should not be public. + match &field.vis { + syn::Visibility::Inherited => (), + _ => { + return Some( + syn::Error::new_spanned(&field.vis, "Field must not be public.").to_compile_error(), + ) + } + } + + // Valid! None } @@ -102,18 +307,49 @@ fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option { None } -// Implement PrimeFieldRepr for the wrapped ident `repr` with `limbs` limbs. -fn prime_field_repr_impl(repr: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream { +// Implement the wrapped ident `repr` with `bytes` bytes. +fn prime_field_repr_impl( + repr: &syn::Ident, + endianness: &ReprEndianness, + bytes: usize, +) -> proc_macro2::TokenStream { + let repr_iter_be = endianness.iter_be(); + quote! { - #[derive(Copy, Clone, PartialEq, Eq, Default)] - pub struct #repr(pub [u64; #limbs]); + #[derive(Copy, Clone)] + pub struct #repr(pub [u8; #bytes]); + + impl ::subtle::ConstantTimeEq for #repr { + fn ct_eq(&self, other: &#repr) -> ::subtle::Choice { + self.0 + .iter() + .zip(other.0.iter()) + .map(|(a, b)| a.ct_eq(b)) + .fold(1.into(), |acc, x| acc & x) + } + } + + impl ::core::cmp::PartialEq for #repr { + fn eq(&self, other: &#repr) -> bool { + use ::subtle::ConstantTimeEq; + self.ct_eq(other).into() + } + } + + impl ::core::cmp::Eq for #repr { } + + impl ::core::default::Default for #repr { + fn default() -> #repr { + #repr([0u8; #bytes]) + } + } impl ::core::fmt::Debug for #repr { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "0x")?; - for i in self.0.iter().rev() { - write!(f, "{:016x}", *i)?; + for i in #repr_iter_be { + write!(f, "{:02x}", *i)?; } Ok(()) @@ -123,183 +359,27 @@ fn prime_field_repr_impl(repr: &syn::Ident, limbs: usize) -> proc_macro2::TokenS impl ::core::fmt::Display for #repr { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "0x")?; - for i in self.0.iter().rev() { - write!(f, "{:016x}", *i)?; + for i in #repr_iter_be { + write!(f, "{:02x}", *i)?; } Ok(()) } } - impl AsRef<[u64]> for #repr { + impl AsRef<[u8]> for #repr { #[inline(always)] - fn as_ref(&self) -> &[u64] { + fn as_ref(&self) -> &[u8] { &self.0 } } - impl AsMut<[u64]> for #repr { + impl AsMut<[u8]> for #repr { #[inline(always)] - fn as_mut(&mut self) -> &mut [u64] { + fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } } - - impl From for #repr { - #[inline(always)] - fn from(val: u64) -> #repr { - use core::default::Default; - - let mut repr = Self::default(); - repr.0[0] = val; - repr - } - } - - impl Ord for #repr { - #[inline(always)] - fn cmp(&self, other: &#repr) -> ::core::cmp::Ordering { - for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { - if a < b { - return ::core::cmp::Ordering::Less - } else if a > b { - return ::core::cmp::Ordering::Greater - } - } - - ::core::cmp::Ordering::Equal - } - } - - impl PartialOrd for #repr { - #[inline(always)] - fn partial_cmp(&self, other: &#repr) -> Option<::core::cmp::Ordering> { - Some(self.cmp(other)) - } - } - - impl ::ff::PrimeFieldRepr for #repr { - #[inline(always)] - fn is_odd(&self) -> bool { - self.0[0] & 1 == 1 - } - - #[inline(always)] - fn is_even(&self) -> bool { - !self.is_odd() - } - - #[inline(always)] - fn is_zero(&self) -> bool { - self.0.iter().all(|&e| e == 0) - } - - #[inline(always)] - fn shr(&mut self, mut n: u32) { - if n as usize >= 64 * #limbs { - *self = Self::from(0); - return; - } - - while n >= 64 { - let mut t = 0; - for i in self.0.iter_mut().rev() { - ::core::mem::swap(&mut t, i); - } - n -= 64; - } - - if n > 0 { - let mut t = 0; - for i in self.0.iter_mut().rev() { - let t2 = *i << (64 - n); - *i >>= n; - *i |= t; - t = t2; - } - } - } - - #[inline(always)] - fn div2(&mut self) { - let mut t = 0; - for i in self.0.iter_mut().rev() { - let t2 = *i << 63; - *i >>= 1; - *i |= t; - t = t2; - } - } - - #[inline(always)] - fn mul2(&mut self) { - let mut last = 0; - for i in &mut self.0 { - let tmp = *i >> 63; - *i <<= 1; - *i |= last; - last = tmp; - } - } - - #[inline(always)] - fn shl(&mut self, mut n: u32) { - if n as usize >= 64 * #limbs { - *self = Self::from(0); - return; - } - - while n >= 64 { - let mut t = 0; - for i in &mut self.0 { - ::core::mem::swap(&mut t, i); - } - n -= 64; - } - - if n > 0 { - let mut t = 0; - for i in &mut self.0 { - let t2 = *i >> (64 - n); - *i <<= n; - *i |= t; - t = t2; - } - } - } - - #[inline(always)] - fn num_bits(&self) -> u32 { - let mut ret = (#limbs as u32) * 64; - for i in self.0.iter().rev() { - let leading = i.leading_zeros(); - ret -= leading; - if leading != 64 { - break; - } - } - - ret - } - - #[inline(always)] - fn add_nocarry(&mut self, other: &#repr) { - let mut carry = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = ::ff::adc(*a, *b, &mut carry); - } - } - - #[inline(always)] - fn sub_noborrow(&mut self, other: &#repr) { - let mut borrow = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = ::ff::sbb(*a, *b, &mut borrow); - } - } - } } } @@ -455,7 +535,7 @@ fn prime_field_constants_and_sqrt( let mut b = x * &w; // Initialize z as the 2^S root of unity. - let mut z = #name(ROOT_OF_UNITY); + let mut z = ROOT_OF_UNITY; for max_v in (1..=S).rev() { let mut k = 1; @@ -494,6 +574,11 @@ fn prime_field_constants_and_sqrt( let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs); let r = biguint_to_u64_vec(r, limbs); + let modulus_repr = { + let mut buf = modulus.to_bytes_le(); + buf.extend(iter::repeat(0).take((limbs * 8) - buf.len())); + buf + }; let modulus = biguint_to_real_u64_vec(modulus.clone(), limbs); // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1 @@ -507,7 +592,10 @@ fn prime_field_constants_and_sqrt( ( quote! { /// This is the modulus m of the prime field - const MODULUS: #repr = #repr([#(#modulus,)*]); + const MODULUS: #repr = #repr([#(#modulus_repr,)*]); + + /// This is the modulus m of the prime field in limb form + const MODULUS_LIMBS: #name = #name([#(#modulus,)*]); /// The number of bits needed to represent the modulus. const MODULUS_BITS: u32 = #modulus_num_bits; @@ -517,23 +605,23 @@ fn prime_field_constants_and_sqrt( const REPR_SHAVE_BITS: u32 = #repr_shave_bits; /// 2^{limbs*64} mod m - const R: #repr = #repr(#r); + const R: #name = #name(#r); /// 2^{limbs*64*2} mod m - const R2: #repr = #repr(#r2); + const R2: #name = #name(#r2); /// -(m^{-1} mod m) mod m const INV: u64 = #inv; /// Multiplicative generator of `MODULUS` - 1 order, also quadratic /// nonresidue. - const GENERATOR: #repr = #repr(#generator); + const GENERATOR: #name = #name(#generator); /// 2^s * t = MODULUS - 1 with t odd const S: u32 = #s; /// 2^s root of unity computed by GENERATOR^t - const ROOT_OF_UNITY: #repr = #repr(#root_of_unity); + const ROOT_OF_UNITY: #name = #name(#root_of_unity); }, sqrt_impl, ) @@ -544,6 +632,7 @@ fn prime_field_impl( name: &syn::Ident, repr: &syn::Ident, modulus: &BigUint, + endianness: &ReprEndianness, limbs: usize, ) -> proc_macro2::TokenStream { // Returns r{n} as an ident. @@ -575,14 +664,14 @@ fn prime_field_impl( gen.extend(quote! { let k = #temp.wrapping_mul(INV); let mut carry = 0; - ::ff::mac_with_carry(#temp, k, MODULUS.0[0], &mut carry); + ::ff::mac_with_carry(#temp, k, MODULUS_LIMBS.0[0], &mut carry); }); } for j in 1..limbs { let temp = get_temp(i + j); gen.extend(quote! { - #temp = ::ff::mac_with_carry(#temp, k, MODULUS.0[#j], &mut carry); + #temp = ::ff::mac_with_carry(#temp, k, MODULUS_LIMBS.0[#j], &mut carry); }); } @@ -609,7 +698,7 @@ fn prime_field_impl( let temp = get_temp(limbs + i); gen.extend(quote! { - (self.0).0[#i] = #temp; + self.0[#i] = #temp; }); } @@ -628,11 +717,11 @@ fn prime_field_impl( let temp = get_temp(i + j); if i == 0 { gen.extend(quote! { - let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#j], &mut carry); + let #temp = ::ff::mac_with_carry(0, #a.0[#i], #a.0[#j], &mut carry); }); } else { - gen.extend(quote!{ - let #temp = ::ff::mac_with_carry(#temp, (#a.0).0[#i], (#a.0).0[#j], &mut carry); + gen.extend(quote! { + let #temp = ::ff::mac_with_carry(#temp, #a.0[#i], #a.0[#j], &mut carry); }); } } @@ -672,11 +761,11 @@ fn prime_field_impl( let temp1 = get_temp(i * 2 + 1); if i == 0 { gen.extend(quote! { - let #temp0 = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#i], &mut carry); + let #temp0 = ::ff::mac_with_carry(0, #a.0[#i], #a.0[#i], &mut carry); }); } else { - gen.extend(quote!{ - let #temp0 = ::ff::mac_with_carry(#temp0, (#a.0).0[#i], (#a.0).0[#i], &mut carry); + gen.extend(quote! { + let #temp0 = ::ff::mac_with_carry(#temp0, #a.0[#i], #a.0[#i], &mut carry); }); } @@ -717,11 +806,11 @@ fn prime_field_impl( if i == 0 { gen.extend(quote! { - let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#b.0).0[#j], &mut carry); + let #temp = ::ff::mac_with_carry(0, #a.0[#i], #b.0[#j], &mut carry); }); } else { - gen.extend(quote!{ - let #temp = ::ff::mac_with_carry(#temp, (#a.0).0[#i], (#b.0).0[#j], &mut carry); + gen.extend(quote! { + let #temp = ::ff::mac_with_carry(#temp, #a.0[#i], #b.0[#j], &mut carry); }); } } @@ -778,10 +867,10 @@ fn prime_field_impl( let invert_impl = inv_impl(quote! {self}, name, modulus); let montgomery_impl = mont_impl(limbs); - // (self.0).0[0].ct_eq(&(other.0).0[0]) & (self.0).0[1].ct_eq(&(other.0).0[1]) & ... + // self.0[0].ct_eq(&other.0[0]) & self.0[1].ct_eq(&other.0[1]) & ... let mut ct_eq_impl = proc_macro2::TokenStream::new(); ct_eq_impl.append_separated( - (0..limbs).map(|i| quote! { (self.0).0[#i].ct_eq(&(other.0).0[#i]) }), + (0..limbs).map(|i| quote! { self.0[#i].ct_eq(&other.0[#i]) }), proc_macro2::Punct::new('&', proc_macro2::Spacing::Alone), ); @@ -790,7 +879,7 @@ fn prime_field_impl( let mut mont_reduce_params = proc_macro2::TokenStream::new(); mont_reduce_params.append_separated( (0..limbs) - .map(|i| quote! { (#a.0).0[#i] }) + .map(|i| quote! { #a.0[#i] }) .chain((0..limbs).map(|_| quote! {0})), proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), ); @@ -798,6 +887,10 @@ fn prime_field_impl( } let mont_reduce_self_params = mont_reduce_params(quote! {self}, limbs); + let mont_reduce_other_params = mont_reduce_params(quote! {other}, limbs); + + let from_repr_impl = endianness.from_repr(name, limbs); + let into_repr_impl = endianness.into_repr(repr, &mont_reduce_self_params, limbs); let top_limb_index = limbs - 1; @@ -818,13 +911,14 @@ fn prime_field_impl( impl ::subtle::ConstantTimeEq for #name { fn ct_eq(&self, other: &#name) -> ::subtle::Choice { - #ct_eq_impl + self.into_repr().ct_eq(&other.into_repr()) } } impl ::core::cmp::PartialEq for #name { fn eq(&self, other: &#name) -> bool { - self.0 == other.0 + use ::subtle::ConstantTimeEq; + self.ct_eq(other).into() } } @@ -841,7 +935,17 @@ fn prime_field_impl( impl Ord for #name { #[inline(always)] fn cmp(&self, other: &#name) -> ::core::cmp::Ordering { - self.into_repr().cmp(&other.into_repr()) + let mut a = *self; + a.mont_reduce( + #mont_reduce_self_params + ); + + let mut b = *other; + b.mont_reduce( + #mont_reduce_other_params + ); + + a.cmp_native(&b) } } @@ -863,7 +967,7 @@ fn prime_field_impl( fn from(val: u64) -> #name { let mut raw = [0u64; #limbs]; raw[0] = val; - #name(#repr(raw)) * #name(R2) + #name(raw) * R2 } } @@ -873,13 +977,19 @@ fn prime_field_impl( } } + impl<'a> From<&'a #name> for #repr { + fn from(e: &'a #name) -> #repr { + e.into_repr() + } + } + impl ::subtle::ConditionallySelectable for #name { fn conditional_select(a: &#name, b: &#name, choice: ::subtle::Choice) -> #name { let mut res = [0u64; #limbs]; for i in 0..#limbs { - res[i] = u64::conditional_select(&(a.0).0[i], &(b.0).0[i], choice); + res[i] = u64::conditional_select(&a.0[i], &b.0[i], choice); } - #name(#repr(res)) + #name(res) } } @@ -890,9 +1000,9 @@ fn prime_field_impl( fn neg(self) -> #name { let mut ret = self; if !ret.is_zero() { - let mut tmp = MODULUS; - tmp.sub_noborrow(&ret.0); - ret.0 = tmp; + let mut tmp = MODULUS_LIMBS; + tmp.sub_noborrow(&ret); + ret = tmp; } ret } @@ -922,7 +1032,7 @@ fn prime_field_impl( #[inline] fn add_assign(&mut self, other: &#name) { // This cannot exceed the backing capacity. - self.0.add_nocarry(&other.0); + self.add_nocarry(other); // However, it may need to be reduced. self.reduce(); @@ -960,11 +1070,11 @@ fn prime_field_impl( #[inline] fn sub_assign(&mut self, other: &#name) { // If `other` is larger than `self`, we'll need to add the modulus to self first. - if other.0 > self.0 { - self.0.add_nocarry(&MODULUS); + if other.cmp_native(self) == ::core::cmp::Ordering::Greater { + self.add_nocarry(&MODULUS_LIMBS); } - self.0.sub_noborrow(&other.0); + self.sub_noborrow(other); } } @@ -1020,7 +1130,7 @@ fn prime_field_impl( #mont_reduce_self_params ); - (self.0).0[0] & rhs + self.0[0] & rhs } } @@ -1040,7 +1150,7 @@ fn prime_field_impl( while n >= 64 { let mut t = 0; - for i in (self.0).0.iter_mut().rev() { + for i in self.0.iter_mut().rev() { ::core::mem::swap(&mut t, i); } n -= 64; @@ -1048,7 +1158,7 @@ fn prime_field_impl( if n > 0 { let mut t = 0; - for i in (self.0).0.iter_mut().rev() { + for i in self.0.iter_mut().rev() { let t2 = *i << (64 - n); *i >>= n; *i |= t; @@ -1057,39 +1167,32 @@ fn prime_field_impl( } // Convert back to Montgomery representation - self * #name(R2) + self * R2 } } impl ::ff::PrimeField for #name { type Repr = #repr; - fn from_repr(r: #repr) -> Result<#name, PrimeFieldDecodingError> { - let mut r = #name(r); - if r.is_valid() { - r.mul_assign(&#name(R2)); - - Ok(r) - } else { - Err(PrimeFieldDecodingError::NotInField) - } + fn from_repr(r: #repr) -> Option<#name> { + #from_repr_impl } fn into_repr(&self) -> #repr { + #into_repr_impl + } + + #[inline(always)] + fn is_odd(&self) -> bool { let mut r = *self; r.mont_reduce( #mont_reduce_self_params ); - r.0 + r.0[0] & 1 == 1 } - #[inline(always)] - fn is_odd(&self) -> bool { - self.into_repr().is_odd() - } - - fn char() -> #repr { + fn char() -> Self::Repr { MODULUS } @@ -1098,13 +1201,13 @@ fn prime_field_impl( const CAPACITY: u32 = Self::NUM_BITS - 1; fn multiplicative_generator() -> Self { - #name(GENERATOR) + GENERATOR } const S: u32 = S; fn root_of_unity() -> Self { - #name(ROOT_OF_UNITY) + ROOT_OF_UNITY } } @@ -1117,7 +1220,7 @@ fn prime_field_impl( for i in 0..#limbs { repr[i] = rng.next_u64(); } - #name(#repr(repr)) + #name(repr) }; // Mask away the unused most-significant bits. @@ -1131,17 +1234,17 @@ fn prime_field_impl( #[inline] fn zero() -> Self { - #name(#repr::from(0)) + #name([0; #limbs]) } #[inline] fn one() -> Self { - #name(R) + R } #[inline] fn is_zero(&self) -> bool { - self.0.is_zero() + self.0.iter().all(|&e| e == 0) } #[inline] @@ -1149,7 +1252,13 @@ fn prime_field_impl( let mut ret = *self; // This cannot exceed the backing capacity. - ret.0.mul2(); + let mut last = 0; + for i in &mut ret.0 { + let tmp = *i >> 63; + *i <<= 1; + *i |= last; + last = tmp; + } // However, it may need to be reduced. ret.reduce(); @@ -1174,11 +1283,46 @@ fn prime_field_impl( } impl #name { + /// Compares two elements in native representation. This is only used + /// internally. + #[inline(always)] + fn cmp_native(&self, other: &#name) -> ::core::cmp::Ordering { + for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { + if a < b { + return ::core::cmp::Ordering::Less + } else if a > b { + return ::core::cmp::Ordering::Greater + } + } + + ::core::cmp::Ordering::Equal + } + /// Determines if the element is really in the field. This is only used /// internally. #[inline(always)] fn is_valid(&self) -> bool { - self.0 < MODULUS + // The Ord impl calls `reduce`, which in turn calls `is_valid`, so we use + // this internal function to eliminate the cycle. + self.cmp_native(&MODULUS_LIMBS) == ::core::cmp::Ordering::Less + } + + #[inline(always)] + fn add_nocarry(&mut self, other: &#name) { + let mut carry = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + *a = ::ff::adc(*a, *b, &mut carry); + } + } + + #[inline(always)] + fn sub_noborrow(&mut self, other: &#name) { + let mut borrow = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + *a = ::ff::sbb(*a, *b, &mut borrow); + } } /// Subtracts the modulus from this element if this element is not in the @@ -1186,7 +1330,7 @@ fn prime_field_impl( #[inline(always)] fn reduce(&mut self) { if !self.is_valid() { - self.0.sub_noborrow(&MODULUS); + self.sub_noborrow(&MODULUS_LIMBS); } } diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 9a4028be9..bb2994cde 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -12,6 +12,7 @@ extern crate std; #[cfg(feature = "derive")] pub use ff_derive::*; +use core::convert::TryFrom; use core::fmt; use core::marker::PhantomData; use core::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign}; @@ -130,139 +131,13 @@ pub trait SqrtField: Field { fn sqrt(&self) -> CtOption; } -/// This trait represents a wrapper around a biginteger which can encode any element of a particular -/// prime field. It is a smart wrapper around a sequence of `u64` limbs, least-significant digit -/// first. -pub trait PrimeFieldRepr: - Sized - + Copy - + Clone - + Eq - + Ord - + Send - + Sync - + Default - + fmt::Debug - + fmt::Display - + 'static - + AsRef<[u64]> - + AsMut<[u64]> - + From -{ - /// Subtract another represetation from this one. - fn sub_noborrow(&mut self, other: &Self); - - /// Add another representation to this one. - fn add_nocarry(&mut self, other: &Self); - - /// Compute the number of bits needed to encode this number. Always a - /// multiple of 64. - fn num_bits(&self) -> u32; - - /// Returns true iff this number is zero. - fn is_zero(&self) -> bool; - - /// Returns true iff this number is odd. - fn is_odd(&self) -> bool; - - /// Returns true iff this number is even. - fn is_even(&self) -> bool; - - /// Performs a rightwise bitshift of this number, effectively dividing - /// it by 2. - fn div2(&mut self); - - /// Performs a rightwise bitshift of this number by some amount. - fn shr(&mut self, amt: u32); - - /// Performs a leftwise bitshift of this number, effectively multiplying - /// it by 2. Overflow is ignored. - fn mul2(&mut self); - - /// Performs a leftwise bitshift of this number by some amount. - fn shl(&mut self, amt: u32); - - /// Writes this `PrimeFieldRepr` as a big endian integer. - #[cfg(feature = "std")] - fn write_be(&self, mut writer: W) -> io::Result<()> { - use byteorder::{BigEndian, WriteBytesExt}; - - for digit in self.as_ref().iter().rev() { - writer.write_u64::(*digit)?; - } - - Ok(()) - } - - /// Reads a big endian integer into this representation. - #[cfg(feature = "std")] - fn read_be(&mut self, mut reader: R) -> io::Result<()> { - use byteorder::{BigEndian, ReadBytesExt}; - - for digit in self.as_mut().iter_mut().rev() { - *digit = reader.read_u64::()?; - } - - Ok(()) - } - - /// Writes this `PrimeFieldRepr` as a little endian integer. - #[cfg(feature = "std")] - fn write_le(&self, mut writer: W) -> io::Result<()> { - use byteorder::{LittleEndian, WriteBytesExt}; - - for digit in self.as_ref().iter() { - writer.write_u64::(*digit)?; - } - - Ok(()) - } - - /// Reads a little endian integer into this representation. - #[cfg(feature = "std")] - fn read_le(&mut self, mut reader: R) -> io::Result<()> { - use byteorder::{LittleEndian, ReadBytesExt}; - - for digit in self.as_mut().iter_mut() { - *digit = reader.read_u64::()?; - } - - Ok(()) - } -} - -/// An error that may occur when trying to interpret a `PrimeFieldRepr` as a -/// `PrimeField` element. -#[derive(Debug)] -pub enum PrimeFieldDecodingError { - /// The encoded value is not in the field - NotInField, -} - -#[cfg(feature = "std")] -impl std::error::Error for PrimeFieldDecodingError { - fn description(&self) -> &str { - match *self { - PrimeFieldDecodingError::NotInField => "not an element of the field", - } - } -} - -impl fmt::Display for PrimeFieldDecodingError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - match *self { - PrimeFieldDecodingError::NotInField => write!(f, "not an element of the field"), - } - } -} - /// This represents an element of a prime field. pub trait PrimeField: Field + Ord + From + BitAnd + Shr { - /// The prime field can be converted back and forth into this biginteger + /// The prime field can be converted back and forth into this binary /// representation. - type Repr: PrimeFieldRepr + From; + type Repr: Default + AsRef<[u8]> + AsMut<[u8]> + From + for<'r> From<&'r Self>; /// Interpret a string of numbers as a (congruent) prime field element. /// Does not accept unnecessary leading zeroes or a blank string. @@ -304,11 +179,20 @@ pub trait PrimeField: Some(res) } - /// Convert this prime field element into a biginteger representation. - fn from_repr(_: Self::Repr) -> Result; + /// Attempts to convert a byte representation of a field element into an element of + /// this prime field, failing if the input is not canonical (is not smaller than the + /// field's modulus). + /// + /// The byte representation is interpreted with the same endianness as is returned + /// by [`PrimeField::into_repr`]. + fn from_repr(_: Self::Repr) -> Option; - /// Convert a biginteger representation into a prime field element, if - /// the number is an element of the field. + /// Converts an element of the prime field into the standard byte representation for + /// this field. + /// + /// Endianness of the byte representation is defined by the field implementation. + /// Callers should assume that it is the standard endianness used to represent encoded + /// elements of this particular field. fn into_repr(&self) -> Self::Repr; /// Returns true iff this element is odd. diff --git a/group/src/lib.rs b/group/src/lib.rs index 3dd9bbd21..89104945d 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, PrimeFieldDecodingError, ScalarEngine, SqrtField}; +use ff::{PrimeField, ScalarEngine, SqrtField}; use rand::RngCore; use std::error::Error; use std::fmt; @@ -82,7 +82,7 @@ pub trait CurveProjective: /// Recommends a wNAF window table size given a scalar. Always returns a number /// between 2 and 22, inclusive. - fn recommended_wnaf_for_scalar(scalar: &::Repr) -> usize; + fn recommended_wnaf_for_scalar(scalar: &Self::Scalar) -> usize; /// Recommends a wNAF window size given the number of scalars you intend to multiply /// a base by. Always returns a number between 2 and 22, inclusive. @@ -178,7 +178,7 @@ pub enum GroupDecodingError { /// The element is not part of the r-order subgroup. NotInSubgroup, /// One of the coordinates could not be decoded - CoordinateDecodingError(&'static str, PrimeFieldDecodingError), + CoordinateDecodingError(&'static str), /// The compression mode of the encoded element was not as expected UnexpectedCompressionMode, /// The encoding contained bits that should not have been set @@ -202,8 +202,8 @@ impl Error for GroupDecodingError { impl fmt::Display for GroupDecodingError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { - GroupDecodingError::CoordinateDecodingError(description, ref err) => { - write!(f, "{} decoding error: {}", description, err) + GroupDecodingError::CoordinateDecodingError(description) => { + write!(f, "{} decoding error", description) } _ => write!(f, "{}", self.description()), } diff --git a/group/src/wnaf.rs b/group/src/wnaf.rs index 200110157..261b301d2 100644 --- a/group/src/wnaf.rs +++ b/group/src/wnaf.rs @@ -1,3 +1,4 @@ +use byteorder::{ByteOrder, LittleEndian}; use ff::PrimeField; use std::iter; @@ -19,7 +20,7 @@ pub(crate) fn wnaf_table(table: &mut Vec, mut base: G, wi /// Replaces the contents of `wnaf` with the w-NAF representation of a little-endian /// scalar. -pub(crate) fn wnaf_form>(wnaf: &mut Vec, c: S, window: usize) { +pub(crate) fn wnaf_form>(wnaf: &mut Vec, c: S, window: usize) { // Required by the NAF definition debug_assert!(window >= 2); // Required so that the NAF digits fit in i64 @@ -27,11 +28,11 @@ pub(crate) fn wnaf_form>(wnaf: &mut Vec, c: S, window: usiz wnaf.truncate(0); - let u64_len = c.as_ref().len(); - let bit_len = u64_len * 64; + let bit_len = c.as_ref().len() * 8; + let u64_len = (bit_len + 1) / 64; let mut c_u64 = vec![0u64; u64_len + 1]; - c_u64[0..u64_len].copy_from_slice(c.as_ref()); + LittleEndian::read_u64_into(c.as_ref(), &mut c_u64[0..u64_len]); let width = 1u64 << window; let window_mask = width - 1; @@ -144,13 +145,11 @@ impl Wnaf<(), Vec, Vec> { &mut self, scalar: &::Scalar, ) -> Wnaf, &[i64]> { - let scalar = scalar.into_repr(); - // Compute the appropriate window size for the scalar. let window_size = G::recommended_wnaf_for_scalar(&scalar); // Compute the wNAF form of the scalar. - wnaf_form(&mut self.scalar, scalar, window_size); + wnaf_form(&mut self.scalar, scalar.into_repr(), window_size); // Return a Wnaf object that mutably borrows the base storage location, but // immutably borrows the computed wNAF form scalar location. diff --git a/pairing/benches/bls12_381/fq.rs b/pairing/benches/bls12_381/fq.rs index 244c161bc..3c43fdd1f 100644 --- a/pairing/benches/bls12_381/fq.rs +++ b/pairing/benches/bls12_381/fq.rs @@ -3,140 +3,9 @@ use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; -use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; +use ff::{Field, PrimeField, SqrtField}; use pairing::bls12_381::*; -fn bench_fq_repr_add_nocarry(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) - .map(|_| { - let mut tmp1 = Fq::random(&mut rng).into_repr(); - let mut tmp2 = Fq::random(&mut rng).into_repr(); - // Shave a few bits off to avoid overflow. - for _ in 0..3 { - tmp1.div2(); - tmp2.div2(); - } - (tmp1, tmp2) - }) - .collect(); - - let mut count = 0; - c.bench_function("FqRepr::add_nocarry", |b| { - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_nocarry(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - -fn bench_fq_repr_sub_noborrow(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) - .map(|_| { - let tmp1 = Fq::random(&mut rng).into_repr(); - let mut tmp2 = tmp1; - // Ensure tmp2 is smaller than tmp1. - for _ in 0..10 { - tmp2.div2(); - } - (tmp1, tmp2) - }) - .collect(); - - let mut count = 0; - c.bench_function("FqRepr::sub_noborrow", |b| { - b.iter(|| { - let mut tmp = v[count].0; - tmp.sub_noborrow(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - -fn bench_fq_repr_num_bits(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec = (0..SAMPLES) - .map(|_| Fq::random(&mut rng).into_repr()) - .collect(); - - let mut count = 0; - c.bench_function("FqRepr::num_bits", |b| { - b.iter(|| { - let tmp = v[count].num_bits(); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - -fn bench_fq_repr_mul2(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec = (0..SAMPLES) - .map(|_| Fq::random(&mut rng).into_repr()) - .collect(); - - let mut count = 0; - c.bench_function("FqRepr::mul2", |b| { - b.iter(|| { - let mut tmp = v[count]; - tmp.mul2(); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - -fn bench_fq_repr_div2(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec = (0..SAMPLES) - .map(|_| Fq::random(&mut rng).into_repr()) - .collect(); - - let mut count = 0; - c.bench_function("FqRepr::div2", |b| { - b.iter(|| { - let mut tmp = v[count]; - tmp.div2(); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - fn bench_fq_add_assign(c: &mut Criterion) { const SAMPLES: usize = 1000; @@ -328,11 +197,6 @@ fn bench_fq_from_repr(c: &mut Criterion) { criterion_group!( benches, - bench_fq_repr_add_nocarry, - bench_fq_repr_sub_noborrow, - bench_fq_repr_num_bits, - bench_fq_repr_mul2, - bench_fq_repr_div2, bench_fq_add_assign, bench_fq_sub_assign, bench_fq_mul_assign, diff --git a/pairing/benches/bls12_381/fr.rs b/pairing/benches/bls12_381/fr.rs index d2dbc4c21..33b3901e1 100644 --- a/pairing/benches/bls12_381/fr.rs +++ b/pairing/benches/bls12_381/fr.rs @@ -3,140 +3,9 @@ use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; -use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; +use ff::{Field, PrimeField, SqrtField}; use pairing::bls12_381::*; -fn bench_fr_repr_add_nocarry(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) - .map(|_| { - let mut tmp1 = Fr::random(&mut rng).into_repr(); - let mut tmp2 = Fr::random(&mut rng).into_repr(); - // Shave a few bits off to avoid overflow. - for _ in 0..3 { - tmp1.div2(); - tmp2.div2(); - } - (tmp1, tmp2) - }) - .collect(); - - let mut count = 0; - c.bench_function("FrRepr::add_nocarry", |b| { - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_nocarry(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - -fn bench_fr_repr_sub_noborrow(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) - .map(|_| { - let tmp1 = Fr::random(&mut rng).into_repr(); - let mut tmp2 = tmp1; - // Ensure tmp2 is smaller than tmp1. - for _ in 0..10 { - tmp2.div2(); - } - (tmp1, tmp2) - }) - .collect(); - - let mut count = 0; - c.bench_function("FrRepr::sub_noborrow", |b| { - b.iter(|| { - let mut tmp = v[count].0; - tmp.sub_noborrow(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - -fn bench_fr_repr_num_bits(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec = (0..SAMPLES) - .map(|_| Fr::random(&mut rng).into_repr()) - .collect(); - - let mut count = 0; - c.bench_function("FrRepr::num_bits", |b| { - b.iter(|| { - let tmp = v[count].num_bits(); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - -fn bench_fr_repr_mul2(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec = (0..SAMPLES) - .map(|_| Fr::random(&mut rng).into_repr()) - .collect(); - - let mut count = 0; - c.bench_function("FrRepr::mul2", |b| { - b.iter(|| { - let mut tmp = v[count]; - tmp.mul2(); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - -fn bench_fr_repr_div2(c: &mut Criterion) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let v: Vec = (0..SAMPLES) - .map(|_| Fr::random(&mut rng).into_repr()) - .collect(); - - let mut count = 0; - c.bench_function("FrRepr::div2", |b| { - b.iter(|| { - let mut tmp = v[count]; - tmp.div2(); - count = (count + 1) % SAMPLES; - tmp - }) - }); -} - fn bench_fr_add_assign(c: &mut Criterion) { const SAMPLES: usize = 1000; @@ -328,11 +197,6 @@ fn bench_fr_from_repr(c: &mut Criterion) { criterion_group!( benches, - bench_fr_repr_add_nocarry, - bench_fr_repr_sub_noborrow, - bench_fr_repr_num_bits, - bench_fr_repr_mul2, - bench_fr_repr_div2, bench_fr_add_assign, bench_fr_sub_assign, bench_fr_mul_assign, diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index 42bd91e20..ef0379778 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -183,8 +183,8 @@ macro_rules! curve_impl { } fn mul::Repr>>(&self, by: S) -> $projective { - let bits = BitIterator::::new(by.into()); - self.mul_bits_u64(bits) + let bits = BitIterator::::new(by.into()); + self.mul_bits_u8(bits) } fn into_projective(&self) -> $projective { @@ -666,7 +666,7 @@ macro_rules! curve_impl { let mut found_one = false; - for i in BitIterator::::new(other.into()) { + for i in BitIterator::::new(other.into()) { if found_one { res.double(); } else { @@ -685,8 +685,10 @@ macro_rules! curve_impl { (*self).into() } - fn recommended_wnaf_for_scalar(scalar: &::Repr) -> usize { - Self::empirical_recommended_wnaf_for_scalar(scalar) + fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize { + Self::empirical_recommended_wnaf_for_scalar( + ::NUM_BITS as usize, + ) } fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize { @@ -749,10 +751,10 @@ macro_rules! curve_impl { } pub mod g1 { - use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr}; + use super::super::{Bls12, Fq, Fq12, FqRepr, Fr}; use super::g2::G2Affine; use crate::{Engine, PairingCurveAffine}; - use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; + use ff::{BitIterator, Field, PrimeField, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; @@ -842,22 +844,21 @@ pub mod g1 { // Unset the three most significant bits. copy[0] &= 0x1f; - let mut x = FqRepr([0; 6]); - let mut y = FqRepr([0; 6]); - - { - let mut reader = ©[..]; - - x.read_be(&mut reader).unwrap(); - y.read_be(&mut reader).unwrap(); + fn copy_segment(s: &[u8], start: usize) -> [u8; 48] { + let mut ret = [0; 48]; + ret.copy_from_slice(&s[start..start + 48]); + ret } + let x = FqRepr(copy_segment(©, 0)); + let y = FqRepr(copy_segment(©, 48)); + Ok(G1Affine { - x: Fq::from_repr(x).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate", e) + x: Fq::from_repr(x).ok_or_else(|| { + GroupDecodingError::CoordinateDecodingError("x coordinate") })?, - y: Fq::from_repr(y).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("y coordinate", e) + y: Fq::from_repr(y).ok_or_else(|| { + GroupDecodingError::CoordinateDecodingError("y coordinate") })?, infinity: false, }) @@ -871,10 +872,8 @@ pub mod g1 { // is at infinity. res.0[0] |= 1 << 6; } else { - let mut writer = &mut res.0[..]; - - affine.x.into_repr().write_be(&mut writer).unwrap(); - affine.y.into_repr().write_be(&mut writer).unwrap(); + res.0[..48].copy_from_slice(&affine.x.into_repr().0); + res.0[48..].copy_from_slice(&affine.y.into_repr().0); } res @@ -950,17 +949,9 @@ pub mod g1 { // Unset the three most significant bits. copy[0] &= 0x1f; - let mut x = FqRepr([0; 6]); - - { - let mut reader = ©[..]; - - x.read_be(&mut reader).unwrap(); - } - // Interpret as Fq element. - let x = Fq::from_repr(x) - .map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate", e))?; + let x = Fq::from_repr(FqRepr(copy)) + .ok_or_else(|| GroupDecodingError::CoordinateDecodingError("x coordinate"))?; let ret = G1Affine::get_point_from_x(x, greatest); if ret.is_some().into() { @@ -978,11 +969,7 @@ pub mod g1 { // is at infinity. res.0[0] |= 1 << 6; } else { - { - let mut writer = &mut res.0[..]; - - affine.x.into_repr().write_be(&mut writer).unwrap(); - } + res.0 = affine.x.into_repr().0; let negy = affine.y.neg(); @@ -1025,9 +1012,7 @@ pub mod g1 { } impl G1 { - fn empirical_recommended_wnaf_for_scalar(scalar: &FrRepr) -> usize { - let num_bits = scalar.num_bits() as usize; - + fn empirical_recommended_wnaf_for_scalar(num_bits: usize) -> usize { if num_bits >= 130 { 4 } else if num_bits >= 34 { @@ -1082,13 +1067,11 @@ pub mod g1 { let y = rhs.sqrt(); if y.is_some().into() { let y = y.unwrap(); - let yrepr = y.into_repr(); let negy = y.neg(); - let negyrepr = negy.into_repr(); let p = G1Affine { x, - y: if yrepr < negyrepr { y } else { negy }, + y: if y < negy { y } else { negy }, infinity: false, }; assert!(!p.is_in_correct_subgroup_assuming_on_curve()); @@ -1116,21 +1099,17 @@ pub mod g1 { { let p = G1Affine { x: Fq::from_repr(FqRepr([ - 0xc58d887b66c035dc, - 0x10cbfd301d553822, - 0xaf23e064f1131ee5, - 0x9fe83b1b4a5d648d, - 0xf583cc5a508f6a40, - 0xc3ad2aefde0bb13, + 0x0c, 0x3a, 0xd2, 0xae, 0xfd, 0xe0, 0xbb, 0x13, 0xf5, 0x83, 0xcc, 0x5a, 0x50, + 0x8f, 0x6a, 0x40, 0x9f, 0xe8, 0x3b, 0x1b, 0x4a, 0x5d, 0x64, 0x8d, 0xaf, 0x23, + 0xe0, 0x64, 0xf1, 0x13, 0x1e, 0xe5, 0x10, 0xcb, 0xfd, 0x30, 0x1d, 0x55, 0x38, + 0x22, 0xc5, 0x8d, 0x88, 0x7b, 0x66, 0xc0, 0x35, 0xdc, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0x60aa6f9552f03aae, - 0xecd01d5181300d35, - 0x8af1cdb8aa8ce167, - 0xe760f57922998c9d, - 0x953703f5795a39e5, - 0xfe3ae0922df702c, + 0x0f, 0xe3, 0xae, 0x09, 0x22, 0xdf, 0x70, 0x2c, 0x95, 0x37, 0x03, 0xf5, 0x79, + 0x5a, 0x39, 0xe5, 0xe7, 0x60, 0xf5, 0x79, 0x22, 0x99, 0x8c, 0x9d, 0x8a, 0xf1, + 0xcd, 0xb8, 0xaa, 0x8c, 0xe1, 0x67, 0xec, 0xd0, 0x1d, 0x51, 0x81, 0x30, 0x0d, + 0x35, 0x60, 0xaa, 0x6f, 0x95, 0x52, 0xf0, 0x3a, 0xae, ])) .unwrap(), infinity: false, @@ -1143,21 +1122,17 @@ pub mod g1 { { let p = G1Affine { x: Fq::from_repr(FqRepr([ - 0xee6adf83511e15f5, - 0x92ddd328f27a4ba6, - 0xe305bd1ac65adba7, - 0xea034ee2928b30a8, - 0xbd8833dc7c79a7f7, - 0xe45c9f0c0438675, + 0x0e, 0x45, 0xc9, 0xf0, 0xc0, 0x43, 0x86, 0x75, 0xbd, 0x88, 0x33, 0xdc, 0x7c, + 0x79, 0xa7, 0xf7, 0xea, 0x03, 0x4e, 0xe2, 0x92, 0x8b, 0x30, 0xa8, 0xe3, 0x05, + 0xbd, 0x1a, 0xc6, 0x5a, 0xdb, 0xa7, 0x92, 0xdd, 0xd3, 0x28, 0xf2, 0x7a, 0x4b, + 0xa6, 0xee, 0x6a, 0xdf, 0x83, 0x51, 0x1e, 0x15, 0xf5, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0x3b450eb1ab7b5dad, - 0xa65cb81e975e8675, - 0xaa548682b21726e5, - 0x753ddf21a2601d20, - 0x532d0b640bd3ff8b, - 0x118d2c543f031102, + 0x11, 0x8d, 0x2c, 0x54, 0x3f, 0x03, 0x11, 0x02, 0x53, 0x2d, 0x0b, 0x64, 0x0b, + 0xd3, 0xff, 0x8b, 0x75, 0x3d, 0xdf, 0x21, 0xa2, 0x60, 0x1d, 0x20, 0xaa, 0x54, + 0x86, 0x82, 0xb2, 0x17, 0x26, 0xe5, 0xa6, 0x5c, 0xb8, 0x1e, 0x97, 0x5e, 0x86, + 0x75, 0x3b, 0x45, 0x0e, 0xb1, 0xab, 0x7b, 0x5d, 0xad, ])) .unwrap(), infinity: false, @@ -1171,21 +1146,17 @@ pub mod g1 { { let p = G1Affine { x: Fq::from_repr(FqRepr([ - 0x76e1c971c6db8fe8, - 0xe37e1a610eff2f79, - 0x88ae9c499f46f0c0, - 0xf35de9ce0d6b4e84, - 0x265bddd23d1dec54, - 0x12a8778088458308, + 0x12, 0xa8, 0x77, 0x80, 0x88, 0x45, 0x83, 0x08, 0x26, 0x5b, 0xdd, 0xd2, 0x3d, + 0x1d, 0xec, 0x54, 0xf3, 0x5d, 0xe9, 0xce, 0x0d, 0x6b, 0x4e, 0x84, 0x88, 0xae, + 0x9c, 0x49, 0x9f, 0x46, 0xf0, 0xc0, 0xe3, 0x7e, 0x1a, 0x61, 0x0e, 0xff, 0x2f, + 0x79, 0x76, 0xe1, 0xc9, 0x71, 0xc6, 0xdb, 0x8f, 0xe8, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0x8a22defa0d526256, - 0xc57ca55456fcb9ae, - 0x1ba194e89bab2610, - 0x921beef89d4f29df, - 0x5b6fda44ad85fa78, - 0xed74ab9f302cbe0, + 0x0e, 0xd7, 0x4a, 0xb9, 0xf3, 0x02, 0xcb, 0xe0, 0x5b, 0x6f, 0xda, 0x44, 0xad, + 0x85, 0xfa, 0x78, 0x92, 0x1b, 0xee, 0xf8, 0x9d, 0x4f, 0x29, 0xdf, 0x1b, 0xa1, + 0x94, 0xe8, 0x9b, 0xab, 0x26, 0x10, 0xc5, 0x7c, 0xa5, 0x54, 0x56, 0xfc, 0xb9, + 0xae, 0x8a, 0x22, 0xde, 0xfa, 0x0d, 0x52, 0x62, 0x56, ])) .unwrap(), infinity: false, @@ -1199,21 +1170,17 @@ pub mod g1 { fn test_g1_addition_correctness() { let mut p = G1 { x: Fq::from_repr(FqRepr([ - 0x47fd1f891d6e8bbf, - 0x79a3b0448f31a2aa, - 0x81f3339e5f9968f, - 0x485e77d50a5df10d, - 0x4c6fcac4b55fd479, - 0x86ed4d9906fb064, + 0x08, 0x6e, 0xd4, 0xd9, 0x90, 0x6f, 0xb0, 0x64, 0x4c, 0x6f, 0xca, 0xc4, 0xb5, 0x5f, + 0xd4, 0x79, 0x48, 0x5e, 0x77, 0xd5, 0x0a, 0x5d, 0xf1, 0x0d, 0x08, 0x1f, 0x33, 0x39, + 0xe5, 0xf9, 0x96, 0x8f, 0x79, 0xa3, 0xb0, 0x44, 0x8f, 0x31, 0xa2, 0xaa, 0x47, 0xfd, + 0x1f, 0x89, 0x1d, 0x6e, 0x8b, 0xbf, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0xd25ee6461538c65, - 0x9f3bbb2ecd3719b9, - 0xa06fd3f1e540910d, - 0xcefca68333c35288, - 0x570c8005f8573fa6, - 0x152ca696fe034442, + 0x15, 0x2c, 0xa6, 0x96, 0xfe, 0x03, 0x44, 0x42, 0x57, 0x0c, 0x80, 0x05, 0xf8, 0x57, + 0x3f, 0xa6, 0xce, 0xfc, 0xa6, 0x83, 0x33, 0xc3, 0x52, 0x88, 0xa0, 0x6f, 0xd3, 0xf1, + 0xe5, 0x40, 0x91, 0x0d, 0x9f, 0x3b, 0xbb, 0x2e, 0xcd, 0x37, 0x19, 0xb9, 0x0d, 0x25, + 0xee, 0x64, 0x61, 0x53, 0x8c, 0x65, ])) .unwrap(), z: Fq::one(), @@ -1221,21 +1188,17 @@ pub mod g1 { p.add_assign(&G1 { x: Fq::from_repr(FqRepr([ - 0xeec78f3096213cbf, - 0xa12beb1fea1056e6, - 0xc286c0211c40dd54, - 0x5f44314ec5e3fb03, - 0x24e8538737c6e675, - 0x8abd623a594fba8, + 0x08, 0xab, 0xd6, 0x23, 0xa5, 0x94, 0xfb, 0xa8, 0x24, 0xe8, 0x53, 0x87, 0x37, 0xc6, + 0xe6, 0x75, 0x5f, 0x44, 0x31, 0x4e, 0xc5, 0xe3, 0xfb, 0x03, 0xc2, 0x86, 0xc0, 0x21, + 0x1c, 0x40, 0xdd, 0x54, 0xa1, 0x2b, 0xeb, 0x1f, 0xea, 0x10, 0x56, 0xe6, 0xee, 0xc7, + 0x8f, 0x30, 0x96, 0x21, 0x3c, 0xbf, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0x6b0528f088bb7044, - 0x2fdeb5c82917ff9e, - 0x9a5181f2fac226ad, - 0xd65104c6f95a872a, - 0x1f2998a5a9c61253, - 0xe74846154a9e44, + 0x00, 0xe7, 0x48, 0x46, 0x15, 0x4a, 0x9e, 0x44, 0x1f, 0x29, 0x98, 0xa5, 0xa9, 0xc6, + 0x12, 0x53, 0xd6, 0x51, 0x04, 0xc6, 0xf9, 0x5a, 0x87, 0x2a, 0x9a, 0x51, 0x81, 0xf2, + 0xfa, 0xc2, 0x26, 0xad, 0x2f, 0xde, 0xb5, 0xc8, 0x29, 0x17, 0xff, 0x9e, 0x6b, 0x05, + 0x28, 0xf0, 0x88, 0xbb, 0x70, 0x44, ])) .unwrap(), z: Fq::one(), @@ -1247,21 +1210,17 @@ pub mod g1 { p, G1Affine { x: Fq::from_repr(FqRepr([ - 0x6dd3098f22235df, - 0xe865d221c8090260, - 0xeb96bb99fa50779f, - 0xc4f9a52a428e23bb, - 0xd178b28dd4f407ef, - 0x17fb8905e9183c69 + 0x17, 0xfb, 0x89, 0x05, 0xe9, 0x18, 0x3c, 0x69, 0xd1, 0x78, 0xb2, 0x8d, 0xd4, + 0xf4, 0x07, 0xef, 0xc4, 0xf9, 0xa5, 0x2a, 0x42, 0x8e, 0x23, 0xbb, 0xeb, 0x96, + 0xbb, 0x99, 0xfa, 0x50, 0x77, 0x9f, 0xe8, 0x65, 0xd2, 0x21, 0xc8, 0x09, 0x02, + 0x60, 0x06, 0xdd, 0x30, 0x98, 0xf2, 0x22, 0x35, 0xdf, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0xd0de9d65292b7710, - 0xf6a05f2bcf1d9ca7, - 0x1040e27012f20b64, - 0xeec8d1a5b7466c58, - 0x4bc362649dce6376, - 0x430cbdc5455b00a + 0x04, 0x30, 0xcb, 0xdc, 0x54, 0x55, 0xb0, 0x0a, 0x4b, 0xc3, 0x62, 0x64, 0x9d, + 0xce, 0x63, 0x76, 0xee, 0xc8, 0xd1, 0xa5, 0xb7, 0x46, 0x6c, 0x58, 0x10, 0x40, + 0xe2, 0x70, 0x12, 0xf2, 0x0b, 0x64, 0xf6, 0xa0, 0x5f, 0x2b, 0xcf, 0x1d, 0x9c, + 0xa7, 0xd0, 0xde, 0x9d, 0x65, 0x29, 0x2b, 0x77, 0x10, ])) .unwrap(), infinity: false, @@ -1273,21 +1232,17 @@ pub mod g1 { fn test_g1_doubling_correctness() { let mut p = G1 { x: Fq::from_repr(FqRepr([ - 0x47fd1f891d6e8bbf, - 0x79a3b0448f31a2aa, - 0x81f3339e5f9968f, - 0x485e77d50a5df10d, - 0x4c6fcac4b55fd479, - 0x86ed4d9906fb064, + 0x08, 0x6e, 0xd4, 0xd9, 0x90, 0x6f, 0xb0, 0x64, 0x4c, 0x6f, 0xca, 0xc4, 0xb5, 0x5f, + 0xd4, 0x79, 0x48, 0x5e, 0x77, 0xd5, 0x0a, 0x5d, 0xf1, 0x0d, 0x08, 0x1f, 0x33, 0x39, + 0xe5, 0xf9, 0x96, 0x8f, 0x79, 0xa3, 0xb0, 0x44, 0x8f, 0x31, 0xa2, 0xaa, 0x47, 0xfd, + 0x1f, 0x89, 0x1d, 0x6e, 0x8b, 0xbf, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0xd25ee6461538c65, - 0x9f3bbb2ecd3719b9, - 0xa06fd3f1e540910d, - 0xcefca68333c35288, - 0x570c8005f8573fa6, - 0x152ca696fe034442, + 0x15, 0x2c, 0xa6, 0x96, 0xfe, 0x03, 0x44, 0x42, 0x57, 0x0c, 0x80, 0x05, 0xf8, 0x57, + 0x3f, 0xa6, 0xce, 0xfc, 0xa6, 0x83, 0x33, 0xc3, 0x52, 0x88, 0xa0, 0x6f, 0xd3, 0xf1, + 0xe5, 0x40, 0x91, 0x0d, 0x9f, 0x3b, 0xbb, 0x2e, 0xcd, 0x37, 0x19, 0xb9, 0x0d, 0x25, + 0xee, 0x64, 0x61, 0x53, 0x8c, 0x65, ])) .unwrap(), z: Fq::one(), @@ -1301,21 +1256,17 @@ pub mod g1 { p, G1Affine { x: Fq::from_repr(FqRepr([ - 0xf939ddfe0ead7018, - 0x3b03942e732aecb, - 0xce0e9c38fdb11851, - 0x4b914c16687dcde0, - 0x66c8baf177d20533, - 0xaf960cff3d83833 + 0x0a, 0xf9, 0x60, 0xcf, 0xf3, 0xd8, 0x38, 0x33, 0x66, 0xc8, 0xba, 0xf1, 0x77, + 0xd2, 0x05, 0x33, 0x4b, 0x91, 0x4c, 0x16, 0x68, 0x7d, 0xcd, 0xe0, 0xce, 0x0e, + 0x9c, 0x38, 0xfd, 0xb1, 0x18, 0x51, 0x03, 0xb0, 0x39, 0x42, 0xe7, 0x32, 0xae, + 0xcb, 0xf9, 0x39, 0xdd, 0xfe, 0x0e, 0xad, 0x70, 0x18, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0x3f0675695f5177a8, - 0x2b6d82ae178a1ba0, - 0x9096380dd8e51b11, - 0x1771a65b60572f4e, - 0x8b547c1313b27555, - 0x135075589a687b1e + 0x13, 0x50, 0x75, 0x58, 0x9a, 0x68, 0x7b, 0x1e, 0x8b, 0x54, 0x7c, 0x13, 0x13, + 0xb2, 0x75, 0x55, 0x17, 0x71, 0xa6, 0x5b, 0x60, 0x57, 0x2f, 0x4e, 0x90, 0x96, + 0x38, 0x0d, 0xd8, 0xe5, 0x1b, 0x11, 0x2b, 0x6d, 0x82, 0xae, 0x17, 0x8a, 0x1b, + 0xa0, 0x3f, 0x06, 0x75, 0x69, 0x5f, 0x51, 0x77, 0xa8, ])) .unwrap(), infinity: false, @@ -1334,21 +1285,17 @@ pub mod g1 { let a = G1Affine { x: Fq::from_repr(FqRepr([ - 0xea431f2cc38fc94d, - 0x3ad2354a07f5472b, - 0xfe669f133f16c26a, - 0x71ffa8021531705, - 0x7418d484386d267, - 0xd5108d8ff1fbd6, + 0x00, 0xd5, 0x10, 0x8d, 0x8f, 0xf1, 0xfb, 0xd6, 0x07, 0x41, 0x8d, 0x48, 0x43, 0x86, + 0xd2, 0x67, 0x07, 0x1f, 0xfa, 0x80, 0x21, 0x53, 0x17, 0x05, 0xfe, 0x66, 0x9f, 0x13, + 0x3f, 0x16, 0xc2, 0x6a, 0x3a, 0xd2, 0x35, 0x4a, 0x07, 0xf5, 0x47, 0x2b, 0xea, 0x43, + 0x1f, 0x2c, 0xc3, 0x8f, 0xc9, 0x4d, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0xa776ccbfe9981766, - 0x255632964ff40f4a, - 0xc09744e650b00499, - 0x520f74773e74c8c3, - 0x484c8fc982008f0, - 0xee2c3d922008cc6, + 0x0e, 0xe2, 0xc3, 0xd9, 0x22, 0x00, 0x8c, 0xc6, 0x04, 0x84, 0xc8, 0xfc, 0x98, 0x20, + 0x08, 0xf0, 0x52, 0x0f, 0x74, 0x77, 0x3e, 0x74, 0xc8, 0xc3, 0xc0, 0x97, 0x44, 0xe6, + 0x50, 0xb0, 0x04, 0x99, 0x25, 0x56, 0x32, 0x96, 0x4f, 0xf4, 0x0f, 0x4a, 0xa7, 0x76, + 0xcc, 0xbf, 0xe9, 0x98, 0x17, 0x66, ])) .unwrap(), infinity: false, @@ -1356,21 +1303,17 @@ pub mod g1 { let b = G1Affine { x: Fq::from_repr(FqRepr([ - 0xe06cdb156b6356b6, - 0xd9040b2d75448ad9, - 0xe702f14bb0e2aca5, - 0xc6e05201e5f83991, - 0xf7c75910816f207c, - 0x18d4043e78103106, + 0x18, 0xd4, 0x04, 0x3e, 0x78, 0x10, 0x31, 0x06, 0xf7, 0xc7, 0x59, 0x10, 0x81, 0x6f, + 0x20, 0x7c, 0xc6, 0xe0, 0x52, 0x01, 0xe5, 0xf8, 0x39, 0x91, 0xe7, 0x02, 0xf1, 0x4b, + 0xb0, 0xe2, 0xac, 0xa5, 0xd9, 0x04, 0x0b, 0x2d, 0x75, 0x44, 0x8a, 0xd9, 0xe0, 0x6c, + 0xdb, 0x15, 0x6b, 0x63, 0x56, 0xb6, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0xa776ccbfe9981766, - 0x255632964ff40f4a, - 0xc09744e650b00499, - 0x520f74773e74c8c3, - 0x484c8fc982008f0, - 0xee2c3d922008cc6, + 0x0e, 0xe2, 0xc3, 0xd9, 0x22, 0x00, 0x8c, 0xc6, 0x04, 0x84, 0xc8, 0xfc, 0x98, 0x20, + 0x08, 0xf0, 0x52, 0x0f, 0x74, 0x77, 0x3e, 0x74, 0xc8, 0xc3, 0xc0, 0x97, 0x44, 0xe6, + 0x50, 0xb0, 0x04, 0x99, 0x25, 0x56, 0x32, 0x96, 0x4f, 0xf4, 0x0f, 0x4a, 0xa7, 0x76, + 0xcc, 0xbf, 0xe9, 0x98, 0x17, 0x66, ])) .unwrap(), infinity: false, @@ -1381,21 +1324,17 @@ pub mod g1 { // y = 1711275103908443722918766889652776216989264073722543507596490456144926139887096946237734327757134898380852225872709 let c = G1Affine { x: Fq::from_repr(FqRepr([ - 0xef4f05bdd10c8aa8, - 0xad5bf87341a2df9, - 0x81c7424206b78714, - 0x9676ff02ec39c227, - 0x4c12c15d7e55b9f3, - 0x57fd1e317db9bd, + 0x00, 0x57, 0xfd, 0x1e, 0x31, 0x7d, 0xb9, 0xbd, 0x4c, 0x12, 0xc1, 0x5d, 0x7e, 0x55, + 0xb9, 0xf3, 0x96, 0x76, 0xff, 0x02, 0xec, 0x39, 0xc2, 0x27, 0x81, 0xc7, 0x42, 0x42, + 0x06, 0xb7, 0x87, 0x14, 0x0a, 0xd5, 0xbf, 0x87, 0x34, 0x1a, 0x2d, 0xf9, 0xef, 0x4f, + 0x05, 0xbd, 0xd1, 0x0c, 0x8a, 0xa8, ])) .unwrap(), y: Fq::from_repr(FqRepr([ - 0x1288334016679345, - 0xf955cd68615ff0b5, - 0xa6998dbaa600f18a, - 0x1267d70db51049fb, - 0x4696deb9ab2ba3e7, - 0xb1e4e11177f59d4, + 0x0b, 0x1e, 0x4e, 0x11, 0x17, 0x7f, 0x59, 0xd4, 0x46, 0x96, 0xde, 0xb9, 0xab, 0x2b, + 0xa3, 0xe7, 0x12, 0x67, 0xd7, 0x0d, 0xb5, 0x10, 0x49, 0xfb, 0xa6, 0x99, 0x8d, 0xba, + 0xa6, 0x00, 0xf1, 0x8a, 0xf9, 0x55, 0xcd, 0x68, 0x61, 0x5f, 0xf0, 0xb5, 0x12, 0x88, + 0x33, 0x40, 0x16, 0x67, 0x93, 0x45, ])) .unwrap(), infinity: false, @@ -1424,10 +1363,10 @@ pub mod g1 { } pub mod g2 { - use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr}; + use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr}; use super::g1::G1Affine; use crate::{Engine, PairingCurveAffine}; - use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; + use ff::{BitIterator, Field, PrimeField, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; @@ -1517,35 +1456,32 @@ pub mod g2 { // Unset the three most significant bits. copy[0] &= 0x1f; - let mut x_c0 = FqRepr([0; 6]); - let mut x_c1 = FqRepr([0; 6]); - let mut y_c0 = FqRepr([0; 6]); - let mut y_c1 = FqRepr([0; 6]); - - { - let mut reader = ©[..]; - - x_c1.read_be(&mut reader).unwrap(); - x_c0.read_be(&mut reader).unwrap(); - y_c1.read_be(&mut reader).unwrap(); - y_c0.read_be(&mut reader).unwrap(); + fn copy_segment(s: &[u8], start: usize) -> [u8; 48] { + let mut ret = [0; 48]; + ret.copy_from_slice(&s[start..start + 48]); + ret } + let x_c1 = FqRepr(copy_segment(©, 0)); + let x_c0 = FqRepr(copy_segment(©, 48)); + let y_c1 = FqRepr(copy_segment(©, 96)); + let y_c0 = FqRepr(copy_segment(©, 144)); + Ok(G2Affine { x: Fq2 { - c0: Fq::from_repr(x_c0).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e) + c0: Fq::from_repr(x_c0).ok_or_else(|| { + GroupDecodingError::CoordinateDecodingError("x coordinate (c0)") })?, - c1: Fq::from_repr(x_c1).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e) + c1: Fq::from_repr(x_c1).ok_or_else(|| { + GroupDecodingError::CoordinateDecodingError("x coordinate (c1)") })?, }, y: Fq2 { - c0: Fq::from_repr(y_c0).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("y coordinate (c0)", e) + c0: Fq::from_repr(y_c0).ok_or_else(|| { + GroupDecodingError::CoordinateDecodingError("y coordinate (c0)") })?, - c1: Fq::from_repr(y_c1).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("y coordinate (c1)", e) + c1: Fq::from_repr(y_c1).ok_or_else(|| { + GroupDecodingError::CoordinateDecodingError("y coordinate (c1)") })?, }, infinity: false, @@ -1560,12 +1496,10 @@ pub mod g2 { // is at infinity. res.0[0] |= 1 << 6; } else { - let mut writer = &mut res.0[..]; - - affine.x.c1.into_repr().write_be(&mut writer).unwrap(); - affine.x.c0.into_repr().write_be(&mut writer).unwrap(); - affine.y.c1.into_repr().write_be(&mut writer).unwrap(); - affine.y.c0.into_repr().write_be(&mut writer).unwrap(); + res.0[0..48].copy_from_slice(&affine.x.c1.into_repr().0); + res.0[48..96].copy_from_slice(&affine.x.c0.into_repr().0); + res.0[96..144].copy_from_slice(&affine.y.c1.into_repr().0); + res.0[144..192].copy_from_slice(&affine.y.c0.into_repr().0); } res @@ -1641,23 +1575,22 @@ pub mod g2 { // Unset the three most significant bits. copy[0] &= 0x1f; - let mut x_c1 = FqRepr([0; 6]); - let mut x_c0 = FqRepr([0; 6]); - - { - let mut reader = ©[..]; - - x_c1.read_be(&mut reader).unwrap(); - x_c0.read_be(&mut reader).unwrap(); + fn copy_segment(s: &[u8], start: usize) -> [u8; 48] { + let mut ret = [0; 48]; + ret.copy_from_slice(&s[start..start + 48]); + ret } + let x_c1 = FqRepr(copy_segment(©, 0)); + let x_c0 = FqRepr(copy_segment(©, 48)); + // Interpret as Fq element. let x = Fq2 { - c0: Fq::from_repr(x_c0).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e) + c0: Fq::from_repr(x_c0).ok_or_else(|| { + GroupDecodingError::CoordinateDecodingError("x coordinate (c0)") })?, - c1: Fq::from_repr(x_c1).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e) + c1: Fq::from_repr(x_c1).ok_or_else(|| { + GroupDecodingError::CoordinateDecodingError("x coordinate (c1)") })?, }; @@ -1677,12 +1610,8 @@ pub mod g2 { // is at infinity. res.0[0] |= 1 << 6; } else { - { - let mut writer = &mut res.0[..]; - - affine.x.c1.into_repr().write_be(&mut writer).unwrap(); - affine.x.c0.into_repr().write_be(&mut writer).unwrap(); - } + res.0[..48].copy_from_slice(&affine.x.c1.into_repr().0); + res.0[48..].copy_from_slice(&affine.x.c0.into_repr().0); let negy = affine.y.neg(); @@ -1744,9 +1673,7 @@ pub mod g2 { } impl G2 { - fn empirical_recommended_wnaf_for_scalar(scalar: &FrRepr) -> usize { - let num_bits = scalar.num_bits() as usize; - + fn empirical_recommended_wnaf_for_scalar(num_bits: usize) -> usize { if num_bits >= 103 { 4 } else if num_bits >= 37 { @@ -1827,41 +1754,33 @@ pub mod g2 { let p = G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ - 0xa757072d9fa35ba9, - 0xae3fb2fb418f6e8a, - 0xc1598ec46faa0c7c, - 0x7a17a004747e3dbe, - 0xcc65406a7c2e5a73, - 0x10b8c03d64db4d0c, + 0x10, 0xb8, 0xc0, 0x3d, 0x64, 0xdb, 0x4d, 0x0c, 0xcc, 0x65, 0x40, 0x6a, + 0x7c, 0x2e, 0x5a, 0x73, 0x7a, 0x17, 0xa0, 0x04, 0x74, 0x7e, 0x3d, 0xbe, + 0xc1, 0x59, 0x8e, 0xc4, 0x6f, 0xaa, 0x0c, 0x7c, 0xae, 0x3f, 0xb2, 0xfb, + 0x41, 0x8f, 0x6e, 0x8a, 0xa7, 0x57, 0x07, 0x2d, 0x9f, 0xa3, 0x5b, 0xa9, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xd30e70fe2f029778, - 0xda30772df0f5212e, - 0x5b47a9ff9a233a50, - 0xfb777e5b9b568608, - 0x789bac1fec71a2b9, - 0x1342f02e2da54405, + 0x13, 0x42, 0xf0, 0x2e, 0x2d, 0xa5, 0x44, 0x05, 0x78, 0x9b, 0xac, 0x1f, + 0xec, 0x71, 0xa2, 0xb9, 0xfb, 0x77, 0x7e, 0x5b, 0x9b, 0x56, 0x86, 0x08, + 0x5b, 0x47, 0xa9, 0xff, 0x9a, 0x23, 0x3a, 0x50, 0xda, 0x30, 0x77, 0x2d, + 0xf0, 0xf5, 0x21, 0x2e, 0xd3, 0x0e, 0x70, 0xfe, 0x2f, 0x02, 0x97, 0x78, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ - 0xfe0812043de54dca, - 0xe455171a3d47a646, - 0xa493f36bc20be98a, - 0x663015d9410eb608, - 0x78e82a79d829a544, - 0x40a00545bb3c1e, + 0x00, 0x40, 0xa0, 0x05, 0x45, 0xbb, 0x3c, 0x1e, 0x78, 0xe8, 0x2a, 0x79, + 0xd8, 0x29, 0xa5, 0x44, 0x66, 0x30, 0x15, 0xd9, 0x41, 0x0e, 0xb6, 0x08, + 0xa4, 0x93, 0xf3, 0x6b, 0xc2, 0x0b, 0xe9, 0x8a, 0xe4, 0x55, 0x17, 0x1a, + 0x3d, 0x47, 0xa6, 0x46, 0xfe, 0x08, 0x12, 0x04, 0x3d, 0xe5, 0x4d, 0xca, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x4709802348e79377, - 0xb5ac4dc9204bcfbd, - 0xda361c97d02f42b2, - 0x15008b1dc399e8df, - 0x68128fd0548a3829, - 0x16a613db5c873aaa, + 0x16, 0xa6, 0x13, 0xdb, 0x5c, 0x87, 0x3a, 0xaa, 0x68, 0x12, 0x8f, 0xd0, + 0x54, 0x8a, 0x38, 0x29, 0x15, 0x00, 0x8b, 0x1d, 0xc3, 0x99, 0xe8, 0xdf, + 0xda, 0x36, 0x1c, 0x97, 0xd0, 0x2f, 0x42, 0xb2, 0xb5, 0xac, 0x4d, 0xc9, + 0x20, 0x4b, 0xcf, 0xbd, 0x47, 0x09, 0x80, 0x23, 0x48, 0xe7, 0x93, 0x77, ])) .unwrap(), }, @@ -1876,41 +1795,33 @@ pub mod g2 { let p = G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ - 0xf4fdfe95a705f917, - 0xc2914df688233238, - 0x37c6b12cca35a34b, - 0x41abba710d6c692c, - 0xffcc4b2b62ce8484, - 0x6993ec01b8934ed, + 0x06, 0x99, 0x3e, 0xc0, 0x1b, 0x89, 0x34, 0xed, 0xff, 0xcc, 0x4b, 0x2b, + 0x62, 0xce, 0x84, 0x84, 0x41, 0xab, 0xba, 0x71, 0x0d, 0x6c, 0x69, 0x2c, + 0x37, 0xc6, 0xb1, 0x2c, 0xca, 0x35, 0xa3, 0x4b, 0xc2, 0x91, 0x4d, 0xf6, + 0x88, 0x23, 0x32, 0x38, 0xf4, 0xfd, 0xfe, 0x95, 0xa7, 0x05, 0xf9, 0x17, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xb94e92d5f874e26, - 0x44516408bc115d95, - 0xe93946b290caa591, - 0xa5a0c2b7131f3555, - 0x83800965822367e7, - 0x10cf1d3ad8d90bfa, + 0x10, 0xcf, 0x1d, 0x3a, 0xd8, 0xd9, 0x0b, 0xfa, 0x83, 0x80, 0x09, 0x65, + 0x82, 0x23, 0x67, 0xe7, 0xa5, 0xa0, 0xc2, 0xb7, 0x13, 0x1f, 0x35, 0x55, + 0xe9, 0x39, 0x46, 0xb2, 0x90, 0xca, 0xa5, 0x91, 0x44, 0x51, 0x64, 0x08, + 0xbc, 0x11, 0x5d, 0x95, 0x0b, 0x94, 0xe9, 0x2d, 0x5f, 0x87, 0x4e, 0x26, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ - 0xbf00334c79701d97, - 0x4fe714f9ff204f9a, - 0xab70b28002f3d825, - 0x5a9171720e73eb51, - 0x38eb4fd8d658adb7, - 0xb649051bbc1164d, + 0x0b, 0x64, 0x90, 0x51, 0xbb, 0xc1, 0x16, 0x4d, 0x38, 0xeb, 0x4f, 0xd8, + 0xd6, 0x58, 0xad, 0xb7, 0x5a, 0x91, 0x71, 0x72, 0x0e, 0x73, 0xeb, 0x51, + 0xab, 0x70, 0xb2, 0x80, 0x02, 0xf3, 0xd8, 0x25, 0x4f, 0xe7, 0x14, 0xf9, + 0xff, 0x20, 0x4f, 0x9a, 0xbf, 0x00, 0x33, 0x4c, 0x79, 0x70, 0x1d, 0x97, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x9225814253d7df75, - 0xc196c2513477f887, - 0xe05e2fbd15a804e0, - 0x55f2b8efad953e04, - 0x7379345eda55265e, - 0x377f2e6208fd4cb, + 0x03, 0x77, 0xf2, 0xe6, 0x20, 0x8f, 0xd4, 0xcb, 0x73, 0x79, 0x34, 0x5e, + 0xda, 0x55, 0x26, 0x5e, 0x55, 0xf2, 0xb8, 0xef, 0xad, 0x95, 0x3e, 0x04, + 0xe0, 0x5e, 0x2f, 0xbd, 0x15, 0xa8, 0x04, 0xe0, 0xc1, 0x96, 0xc2, 0x51, + 0x34, 0x77, 0xf8, 0x87, 0x92, 0x25, 0x81, 0x42, 0x53, 0xd7, 0xdf, 0x75, ])) .unwrap(), }, @@ -1926,41 +1837,33 @@ pub mod g2 { let p = G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ - 0x262cea73ea1906c, - 0x2f08540770fabd6, - 0x4ceb92d0a76057be, - 0x2199bc19c48c393d, - 0x4a151b732a6075bf, - 0x17762a3b9108c4a7, + 0x17, 0x76, 0x2a, 0x3b, 0x91, 0x08, 0xc4, 0xa7, 0x4a, 0x15, 0x1b, 0x73, + 0x2a, 0x60, 0x75, 0xbf, 0x21, 0x99, 0xbc, 0x19, 0xc4, 0x8c, 0x39, 0x3d, + 0x4c, 0xeb, 0x92, 0xd0, 0xa7, 0x60, 0x57, 0xbe, 0x02, 0xf0, 0x85, 0x40, + 0x77, 0x0f, 0xab, 0xd6, 0x02, 0x62, 0xce, 0xa7, 0x3e, 0xa1, 0x90, 0x6c, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x26f461e944bbd3d1, - 0x298f3189a9cf6ed6, - 0x74328ad8bc2aa150, - 0x7e147f3f9e6e241, - 0x72a9b63583963fff, - 0x158b0083c000462, + 0x01, 0x58, 0xb0, 0x08, 0x3c, 0x00, 0x04, 0x62, 0x72, 0xa9, 0xb6, 0x35, + 0x83, 0x96, 0x3f, 0xff, 0x07, 0xe1, 0x47, 0xf3, 0xf9, 0xe6, 0xe2, 0x41, + 0x74, 0x32, 0x8a, 0xd8, 0xbc, 0x2a, 0xa1, 0x50, 0x29, 0x8f, 0x31, 0x89, + 0xa9, 0xcf, 0x6e, 0xd6, 0x26, 0xf4, 0x61, 0xe9, 0x44, 0xbb, 0xd3, 0xd1, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ - 0x91fb0b225ecf103b, - 0x55d42edc1dc46ba0, - 0x43939b11997b1943, - 0x68cad19430706b4d, - 0x3ccfb97b924dcea8, - 0x1660f93434588f8d, + 0x16, 0x60, 0xf9, 0x34, 0x34, 0x58, 0x8f, 0x8d, 0x3c, 0xcf, 0xb9, 0x7b, + 0x92, 0x4d, 0xce, 0xa8, 0x68, 0xca, 0xd1, 0x94, 0x30, 0x70, 0x6b, 0x4d, + 0x43, 0x93, 0x9b, 0x11, 0x99, 0x7b, 0x19, 0x43, 0x55, 0xd4, 0x2e, 0xdc, + 0x1d, 0xc4, 0x6b, 0xa0, 0x91, 0xfb, 0x0b, 0x22, 0x5e, 0xcf, 0x10, 0x3b, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xaaed3985b6dcb9c7, - 0xc1e985d6d898d9f4, - 0x618bd2ac3271ac42, - 0x3940a2dbb914b529, - 0xbeb88137cf34f3e7, - 0x1699ee577c61b694, + 0x16, 0x99, 0xee, 0x57, 0x7c, 0x61, 0xb6, 0x94, 0xbe, 0xb8, 0x81, 0x37, + 0xcf, 0x34, 0xf3, 0xe7, 0x39, 0x40, 0xa2, 0xdb, 0xb9, 0x14, 0xb5, 0x29, + 0x61, 0x8b, 0xd2, 0xac, 0x32, 0x71, 0xac, 0x42, 0xc1, 0xe9, 0x85, 0xd6, + 0xd8, 0x98, 0xd9, 0xf4, 0xaa, 0xed, 0x39, 0x85, 0xb6, 0xdc, 0xb9, 0xc7, ])) .unwrap(), }, @@ -1976,41 +1879,33 @@ pub mod g2 { let mut p = G2 { x: Fq2 { c0: Fq::from_repr(FqRepr([ - 0x6c994cc1e303094e, - 0xf034642d2c9e85bd, - 0x275094f1352123a9, - 0x72556c999f3707ac, - 0x4617f2e6774e9711, - 0x100b2fe5bffe030b, + 0x10, 0x0b, 0x2f, 0xe5, 0xbf, 0xfe, 0x03, 0x0b, 0x46, 0x17, 0xf2, 0xe6, 0x77, + 0x4e, 0x97, 0x11, 0x72, 0x55, 0x6c, 0x99, 0x9f, 0x37, 0x07, 0xac, 0x27, 0x50, + 0x94, 0xf1, 0x35, 0x21, 0x23, 0xa9, 0xf0, 0x34, 0x64, 0x2d, 0x2c, 0x9e, 0x85, + 0xbd, 0x6c, 0x99, 0x4c, 0xc1, 0xe3, 0x03, 0x09, 0x4e, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x7a33555977ec608, - 0xe23039d1fe9c0881, - 0x19ce4678aed4fcb5, - 0x4637c4f417667e2e, - 0x93ebe7c3e41f6acc, - 0xde884f89a9a371b, + 0x0d, 0xe8, 0x84, 0xf8, 0x9a, 0x9a, 0x37, 0x1b, 0x93, 0xeb, 0xe7, 0xc3, 0xe4, + 0x1f, 0x6a, 0xcc, 0x46, 0x37, 0xc4, 0xf4, 0x17, 0x66, 0x7e, 0x2e, 0x19, 0xce, + 0x46, 0x78, 0xae, 0xd4, 0xfc, 0xb5, 0xe2, 0x30, 0x39, 0xd1, 0xfe, 0x9c, 0x08, + 0x81, 0x07, 0xa3, 0x35, 0x55, 0x97, 0x7e, 0xc6, 0x08, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ - 0xe073119472e1eb62, - 0x44fb3391fe3c9c30, - 0xaa9b066d74694006, - 0x25fd427b4122f231, - 0xd83112aace35cae, - 0x191b2432407cbb7f, + 0x19, 0x1b, 0x24, 0x32, 0x40, 0x7c, 0xbb, 0x7f, 0x0d, 0x83, 0x11, 0x2a, 0xac, + 0xe3, 0x5c, 0xae, 0x25, 0xfd, 0x42, 0x7b, 0x41, 0x22, 0xf2, 0x31, 0xaa, 0x9b, + 0x06, 0x6d, 0x74, 0x69, 0x40, 0x06, 0x44, 0xfb, 0x33, 0x91, 0xfe, 0x3c, 0x9c, + 0x30, 0xe0, 0x73, 0x11, 0x94, 0x72, 0xe1, 0xeb, 0x62, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xf68ae82fe97662f5, - 0xe986057068b50b7d, - 0x96c30f0411590b48, - 0x9eaa6d19de569196, - 0xf6a03d31e2ec2183, - 0x3bdafaf7ca9b39b, + 0x03, 0xbd, 0xaf, 0xaf, 0x7c, 0xa9, 0xb3, 0x9b, 0xf6, 0xa0, 0x3d, 0x31, 0xe2, + 0xec, 0x21, 0x83, 0x9e, 0xaa, 0x6d, 0x19, 0xde, 0x56, 0x91, 0x96, 0x96, 0xc3, + 0x0f, 0x04, 0x11, 0x59, 0x0b, 0x48, 0xe9, 0x86, 0x05, 0x70, 0x68, 0xb5, 0x0b, + 0x7d, 0xf6, 0x8a, 0xe8, 0x2f, 0xe9, 0x76, 0x62, 0xf5, ])) .unwrap(), }, @@ -2020,41 +1915,33 @@ pub mod g2 { p.add_assign(&G2 { x: Fq2 { c0: Fq::from_repr(FqRepr([ - 0xa8c763d25910bdd3, - 0x408777b30ca3add4, - 0x6115fcc12e2769e, - 0x8e73a96b329ad190, - 0x27c546f75ee1f3ab, - 0xa33d27add5e7e82, + 0x0a, 0x33, 0xd2, 0x7a, 0xdd, 0x5e, 0x7e, 0x82, 0x27, 0xc5, 0x46, 0xf7, 0x5e, + 0xe1, 0xf3, 0xab, 0x8e, 0x73, 0xa9, 0x6b, 0x32, 0x9a, 0xd1, 0x90, 0x06, 0x11, + 0x5f, 0xcc, 0x12, 0xe2, 0x76, 0x9e, 0x40, 0x87, 0x77, 0xb3, 0x0c, 0xa3, 0xad, + 0xd4, 0xa8, 0xc7, 0x63, 0xd2, 0x59, 0x10, 0xbd, 0xd3, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x93b1ebcd54870dfe, - 0xf1578300e1342e11, - 0x8270dca3a912407b, - 0x2089faf462438296, - 0x828e5848cd48ea66, - 0x141ecbac1deb038b, + 0x14, 0x1e, 0xcb, 0xac, 0x1d, 0xeb, 0x03, 0x8b, 0x82, 0x8e, 0x58, 0x48, 0xcd, + 0x48, 0xea, 0x66, 0x20, 0x89, 0xfa, 0xf4, 0x62, 0x43, 0x82, 0x96, 0x82, 0x70, + 0xdc, 0xa3, 0xa9, 0x12, 0x40, 0x7b, 0xf1, 0x57, 0x83, 0x00, 0xe1, 0x34, 0x2e, + 0x11, 0x93, 0xb1, 0xeb, 0xcd, 0x54, 0x87, 0x0d, 0xfe, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ - 0xf5d2c28857229c3f, - 0x8c1574228757ca23, - 0xe8d8102175f5dc19, - 0x2767032fc37cc31d, - 0xd5ee2aba84fd10fe, - 0x16576ccd3dd0a4e8, + 0x16, 0x57, 0x6c, 0xcd, 0x3d, 0xd0, 0xa4, 0xe8, 0xd5, 0xee, 0x2a, 0xba, 0x84, + 0xfd, 0x10, 0xfe, 0x27, 0x67, 0x03, 0x2f, 0xc3, 0x7c, 0xc3, 0x1d, 0xe8, 0xd8, + 0x10, 0x21, 0x75, 0xf5, 0xdc, 0x19, 0x8c, 0x15, 0x74, 0x22, 0x87, 0x57, 0xca, + 0x23, 0xf5, 0xd2, 0xc2, 0x88, 0x57, 0x22, 0x9c, 0x3f, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x4da9b6f6a96d1dd2, - 0x9657f7da77f1650e, - 0xbc150712f9ffe6da, - 0x31898db63f87363a, - 0xabab040ddbd097cc, - 0x11ad236b9ba02990, + 0x11, 0xad, 0x23, 0x6b, 0x9b, 0xa0, 0x29, 0x90, 0xab, 0xab, 0x04, 0x0d, 0xdb, + 0xd0, 0x97, 0xcc, 0x31, 0x89, 0x8d, 0xb6, 0x3f, 0x87, 0x36, 0x3a, 0xbc, 0x15, + 0x07, 0x12, 0xf9, 0xff, 0xe6, 0xda, 0x96, 0x57, 0xf7, 0xda, 0x77, 0xf1, 0x65, + 0x0e, 0x4d, 0xa9, 0xb6, 0xf6, 0xa9, 0x6d, 0x1d, 0xd2, ])) .unwrap(), }, @@ -2068,41 +1955,33 @@ pub mod g2 { G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ - 0xcde7ee8a3f2ac8af, - 0xfc642eb35975b069, - 0xa7de72b7dd0e64b7, - 0xf1273e6406eef9cc, - 0xababd760ff05cb92, - 0xd7c20456617e89 + 0x00, 0xd7, 0xc2, 0x04, 0x56, 0x61, 0x7e, 0x89, 0xab, 0xab, 0xd7, 0x60, + 0xff, 0x05, 0xcb, 0x92, 0xf1, 0x27, 0x3e, 0x64, 0x06, 0xee, 0xf9, 0xcc, + 0xa7, 0xde, 0x72, 0xb7, 0xdd, 0x0e, 0x64, 0xb7, 0xfc, 0x64, 0x2e, 0xb3, + 0x59, 0x75, 0xb0, 0x69, 0xcd, 0xe7, 0xee, 0x8a, 0x3f, 0x2a, 0xc8, 0xaf, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xd1a50b8572cbd2b8, - 0x238f0ac6119d07df, - 0x4dbe924fe5fd6ac2, - 0x8b203284c51edf6b, - 0xc8a0b730bbb21f5e, - 0x1a3b59d29a31274 + 0x01, 0xa3, 0xb5, 0x9d, 0x29, 0xa3, 0x12, 0x74, 0xc8, 0xa0, 0xb7, 0x30, + 0xbb, 0xb2, 0x1f, 0x5e, 0x8b, 0x20, 0x32, 0x84, 0xc5, 0x1e, 0xdf, 0x6b, + 0x4d, 0xbe, 0x92, 0x4f, 0xe5, 0xfd, 0x6a, 0xc2, 0x23, 0x8f, 0x0a, 0xc6, + 0x11, 0x9d, 0x07, 0xdf, 0xd1, 0xa5, 0x0b, 0x85, 0x72, 0xcb, 0xd2, 0xb8, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ - 0x9e709e78a8eaa4c9, - 0xd30921c93ec342f4, - 0x6d1ef332486f5e34, - 0x64528ab3863633dc, - 0x159384333d7cba97, - 0x4cb84741f3cafe8 + 0x04, 0xcb, 0x84, 0x74, 0x1f, 0x3c, 0xaf, 0xe8, 0x15, 0x93, 0x84, 0x33, + 0x3d, 0x7c, 0xba, 0x97, 0x64, 0x52, 0x8a, 0xb3, 0x86, 0x36, 0x33, 0xdc, + 0x6d, 0x1e, 0xf3, 0x32, 0x48, 0x6f, 0x5e, 0x34, 0xd3, 0x09, 0x21, 0xc9, + 0x3e, 0xc3, 0x42, 0xf4, 0x9e, 0x70, 0x9e, 0x78, 0xa8, 0xea, 0xa4, 0xc9, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x242af0dc3640e1a4, - 0xe90a73ad65c66919, - 0x2bd7ca7f4346f9ec, - 0x38528f92b689644d, - 0xb6884deec59fb21f, - 0x3c075d3ec52ba90 + 0x03, 0xc0, 0x75, 0xd3, 0xec, 0x52, 0xba, 0x90, 0xb6, 0x88, 0x4d, 0xee, + 0xc5, 0x9f, 0xb2, 0x1f, 0x38, 0x52, 0x8f, 0x92, 0xb6, 0x89, 0x64, 0x4d, + 0x2b, 0xd7, 0xca, 0x7f, 0x43, 0x46, 0xf9, 0xec, 0xe9, 0x0a, 0x73, 0xad, + 0x65, 0xc6, 0x69, 0x19, 0x24, 0x2a, 0xf0, 0xdc, 0x36, 0x40, 0xe1, 0xa4, ])) .unwrap(), }, @@ -2116,41 +1995,33 @@ pub mod g2 { let mut p = G2 { x: Fq2 { c0: Fq::from_repr(FqRepr([ - 0x6c994cc1e303094e, - 0xf034642d2c9e85bd, - 0x275094f1352123a9, - 0x72556c999f3707ac, - 0x4617f2e6774e9711, - 0x100b2fe5bffe030b, + 0x10, 0x0b, 0x2f, 0xe5, 0xbf, 0xfe, 0x03, 0x0b, 0x46, 0x17, 0xf2, 0xe6, 0x77, + 0x4e, 0x97, 0x11, 0x72, 0x55, 0x6c, 0x99, 0x9f, 0x37, 0x07, 0xac, 0x27, 0x50, + 0x94, 0xf1, 0x35, 0x21, 0x23, 0xa9, 0xf0, 0x34, 0x64, 0x2d, 0x2c, 0x9e, 0x85, + 0xbd, 0x6c, 0x99, 0x4c, 0xc1, 0xe3, 0x03, 0x09, 0x4e, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x7a33555977ec608, - 0xe23039d1fe9c0881, - 0x19ce4678aed4fcb5, - 0x4637c4f417667e2e, - 0x93ebe7c3e41f6acc, - 0xde884f89a9a371b, + 0x0d, 0xe8, 0x84, 0xf8, 0x9a, 0x9a, 0x37, 0x1b, 0x93, 0xeb, 0xe7, 0xc3, 0xe4, + 0x1f, 0x6a, 0xcc, 0x46, 0x37, 0xc4, 0xf4, 0x17, 0x66, 0x7e, 0x2e, 0x19, 0xce, + 0x46, 0x78, 0xae, 0xd4, 0xfc, 0xb5, 0xe2, 0x30, 0x39, 0xd1, 0xfe, 0x9c, 0x08, + 0x81, 0x07, 0xa3, 0x35, 0x55, 0x97, 0x7e, 0xc6, 0x08, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ - 0xe073119472e1eb62, - 0x44fb3391fe3c9c30, - 0xaa9b066d74694006, - 0x25fd427b4122f231, - 0xd83112aace35cae, - 0x191b2432407cbb7f, + 0x19, 0x1b, 0x24, 0x32, 0x40, 0x7c, 0xbb, 0x7f, 0x0d, 0x83, 0x11, 0x2a, 0xac, + 0xe3, 0x5c, 0xae, 0x25, 0xfd, 0x42, 0x7b, 0x41, 0x22, 0xf2, 0x31, 0xaa, 0x9b, + 0x06, 0x6d, 0x74, 0x69, 0x40, 0x06, 0x44, 0xfb, 0x33, 0x91, 0xfe, 0x3c, 0x9c, + 0x30, 0xe0, 0x73, 0x11, 0x94, 0x72, 0xe1, 0xeb, 0x62, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xf68ae82fe97662f5, - 0xe986057068b50b7d, - 0x96c30f0411590b48, - 0x9eaa6d19de569196, - 0xf6a03d31e2ec2183, - 0x3bdafaf7ca9b39b, + 0x03, 0xbd, 0xaf, 0xaf, 0x7c, 0xa9, 0xb3, 0x9b, 0xf6, 0xa0, 0x3d, 0x31, 0xe2, + 0xec, 0x21, 0x83, 0x9e, 0xaa, 0x6d, 0x19, 0xde, 0x56, 0x91, 0x96, 0x96, 0xc3, + 0x0f, 0x04, 0x11, 0x59, 0x0b, 0x48, 0xe9, 0x86, 0x05, 0x70, 0x68, 0xb5, 0x0b, + 0x7d, 0xf6, 0x8a, 0xe8, 0x2f, 0xe9, 0x76, 0x62, 0xf5, ])) .unwrap(), }, @@ -2166,41 +2037,33 @@ pub mod g2 { G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ - 0x91ccb1292727c404, - 0x91a6cb182438fad7, - 0x116aee59434de902, - 0xbcedcfce1e52d986, - 0x9755d4a3926e9862, - 0x18bab73760fd8024 + 0x18, 0xba, 0xb7, 0x37, 0x60, 0xfd, 0x80, 0x24, 0x97, 0x55, 0xd4, 0xa3, + 0x92, 0x6e, 0x98, 0x62, 0xbc, 0xed, 0xcf, 0xce, 0x1e, 0x52, 0xd9, 0x86, + 0x11, 0x6a, 0xee, 0x59, 0x43, 0x4d, 0xe9, 0x02, 0x91, 0xa6, 0xcb, 0x18, + 0x24, 0x38, 0xfa, 0xd7, 0x91, 0xcc, 0xb1, 0x29, 0x27, 0x27, 0xc4, 0x04, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x4e7c5e0a2ae5b99e, - 0x96e582a27f028961, - 0xc74d1cf4ef2d5926, - 0xeb0cf5e610ef4fe7, - 0x7b4c2bae8db6e70b, - 0xf136e43909fca0 + 0x00, 0xf1, 0x36, 0xe4, 0x39, 0x09, 0xfc, 0xa0, 0x7b, 0x4c, 0x2b, 0xae, + 0x8d, 0xb6, 0xe7, 0x0b, 0xeb, 0x0c, 0xf5, 0xe6, 0x10, 0xef, 0x4f, 0xe7, + 0xc7, 0x4d, 0x1c, 0xf4, 0xef, 0x2d, 0x59, 0x26, 0x96, 0xe5, 0x82, 0xa2, + 0x7f, 0x02, 0x89, 0x61, 0x4e, 0x7c, 0x5e, 0x0a, 0x2a, 0xe5, 0xb9, 0x9e, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ - 0x954d4466ab13e58, - 0x3ee42eec614cf890, - 0x853bb1d28877577e, - 0xa5a2a51f7fde787b, - 0x8b92866bc6384188, - 0x81a53fe531d64ef + 0x08, 0x1a, 0x53, 0xfe, 0x53, 0x1d, 0x64, 0xef, 0x8b, 0x92, 0x86, 0x6b, + 0xc6, 0x38, 0x41, 0x88, 0xa5, 0xa2, 0xa5, 0x1f, 0x7f, 0xde, 0x78, 0x7b, + 0x85, 0x3b, 0xb1, 0xd2, 0x88, 0x77, 0x57, 0x7e, 0x3e, 0xe4, 0x2e, 0xec, + 0x61, 0x4c, 0xf8, 0x90, 0x09, 0x54, 0xd4, 0x46, 0x6a, 0xb1, 0x3e, 0x58, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x4c5d607666239b34, - 0xeddb5f48304d14b3, - 0x337167ee6e8e3cb6, - 0xb271f52f12ead742, - 0x244e6c2015c83348, - 0x19e2deae6eb9b441 + 0x19, 0xe2, 0xde, 0xae, 0x6e, 0xb9, 0xb4, 0x41, 0x24, 0x4e, 0x6c, 0x20, + 0x15, 0xc8, 0x33, 0x48, 0xb2, 0x71, 0xf5, 0x2f, 0x12, 0xea, 0xd7, 0x42, + 0x33, 0x71, 0x67, 0xee, 0x6e, 0x8e, 0x3c, 0xb6, 0xed, 0xdb, 0x5f, 0x48, + 0x30, 0x4d, 0x14, 0xb3, 0x4c, 0x5d, 0x60, 0x76, 0x66, 0x23, 0x9b, 0x34, ])) .unwrap(), }, diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index f9caf5e95..fa236ff9c 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -1,5 +1,5 @@ use super::fq2::Fq2; -use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; +use ff::{Field, PrimeField}; use std::ops::{AddAssign, MulAssign, SubAssign}; #[cfg(test)] @@ -8,14 +8,14 @@ use ff::PowVartime; use std::ops::Neg; // B coefficient of BLS12-381 curve, 4. -pub const B_COEFF: Fq = Fq(FqRepr([ +pub const B_COEFF: Fq = Fq([ 0xaa270000000cfff3, 0x53cc0032fc34000a, 0x478fe97a6b0a807f, 0xb1d37ebee6ba24d7, 0x8ec9733bbf78ab2f, 0x9d645513d83de7e, -])); +]); // The generators of G1/G2 are computed by finding the lexicographically smallest valid x coordinate, // and its lexicographically smallest y coordinate and multiplying it by the cofactor such that the @@ -24,228 +24,228 @@ pub const B_COEFF: Fq = Fq(FqRepr([ // Generator of G1 // x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 // y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 -pub const G1_GENERATOR_X: Fq = Fq(FqRepr([ +pub const G1_GENERATOR_X: Fq = Fq([ 0x5cb38790fd530c16, 0x7817fc679976fff5, 0x154f95c7143ba1c1, 0xf0ae6acdf3d0e747, 0xedce6ecc21dbf440, 0x120177419e0bfb75, -])); -pub const G1_GENERATOR_Y: Fq = Fq(FqRepr([ +]); +pub const G1_GENERATOR_Y: Fq = Fq([ 0xbaac93d50ce72271, 0x8c22631a7918fd8e, 0xdd595f13570725ce, 0x51ac582950405194, 0xe1c8c3fad0059c0, 0xbbc3efc5008a26a, -])); +]); // Generator of G2 // x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160 // y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905 -pub const G2_GENERATOR_X_C0: Fq = Fq(FqRepr([ +pub const G2_GENERATOR_X_C0: Fq = Fq([ 0xf5f28fa202940a10, 0xb3f5fb2687b4961a, 0xa1a893b53e2ae580, 0x9894999d1a3caee9, 0x6f67b7631863366b, 0x58191924350bcd7, -])); -pub const G2_GENERATOR_X_C1: Fq = Fq(FqRepr([ +]); +pub const G2_GENERATOR_X_C1: Fq = Fq([ 0xa5a9c0759e23f606, 0xaaa0c59dbccd60c3, 0x3bb17e18e2867806, 0x1b1ab6cc8541b367, 0xc2b6ed0ef2158547, 0x11922a097360edf3, -])); -pub const G2_GENERATOR_Y_C0: Fq = Fq(FqRepr([ +]); +pub const G2_GENERATOR_Y_C0: Fq = Fq([ 0x4c730af860494c4a, 0x597cfa1f5e369c5a, 0xe7e6856caa0a635a, 0xbbefb5e96e0d495f, 0x7d3a975f0ef25a2, 0x83fd8e7e80dae5, -])); -pub const G2_GENERATOR_Y_C1: Fq = Fq(FqRepr([ +]); +pub const G2_GENERATOR_Y_C1: Fq = Fq([ 0xadc0fc92df64b05d, 0x18aa270a2b1461dc, 0x86adac6a3be4eba0, 0x79495c4ec93da33a, 0xe7175850a43ccaed, 0xb2bc2a163de1bf2, -])); +]); // Coefficients for the Frobenius automorphism. pub const FROBENIUS_COEFF_FQ2_C1: [Fq; 2] = [ // Fq(-1)**(((q^0) - 1) / 2) - Fq(FqRepr([ + Fq([ 0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493, - ])), + ]), // Fq(-1)**(((q^1) - 1) / 2) - Fq(FqRepr([ + Fq([ 0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x7e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x40ab3263eff0206, - ])), + ]), ]; pub const FROBENIUS_COEFF_FQ6_C1: [Fq2; 6] = [ // Fq2(u + 1)**(((q^0) - 1) / 3) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((q^1) - 1) / 3) Fq2 { - c0: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - c1: Fq(FqRepr([ + c0: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), + c1: Fq([ 0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x3f97d6e83d050d2, 0x18f0206554638741, - ])), + ]), }, // Fq2(u + 1)**(((q^2) - 1) / 3) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x51ba4ab241b6160, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((q^3) - 1) / 3) Fq2 { - c0: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - c1: Fq(FqRepr([ + c0: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), + c1: Fq([ 0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493, - ])), + ]), }, // Fq2(u + 1)**(((q^4) - 1) / 3) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x3f97d6e83d050d2, 0x18f0206554638741, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((q^5) - 1) / 3) Fq2 { - c0: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - c1: Fq(FqRepr([ + c0: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), + c1: Fq([ 0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x51ba4ab241b6160, - ])), + ]), }, ]; pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [ // Fq2(u + 1)**(((2q^0) - 2) / 3) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((2q^1) - 2) / 3) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x890dc9e4867545c3, 0x2af322533285a5d5, 0x50880866309b7e2c, 0xa20d1b8c7e881024, 0x14e4f04fe2db9068, 0x14e56d3f1564853a, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((2q^2) - 2) / 3) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x3f97d6e83d050d2, 0x18f0206554638741, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((2q^3) - 2) / 3) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x7e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x40ab3263eff0206, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((2q^4) - 2) / 3) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x51ba4ab241b6160, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((2q^5) - 2) / 3) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0xecfb361b798dba3a, 0xc100ddb891865a2c, 0xec08ff1232bda8e, 0xd5c13cc6f1ca4721, 0x47222a47bf7b5c04, 0x110f184e51c5f59, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, ]; @@ -253,206 +253,207 @@ pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [ pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [ // Fq2(u + 1)**(((q^0) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((q^1) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x7089552b319d465, 0xc6695f92b50a8313, 0x97e83cccd117228f, 0xa35baecab2dc29ee, 0x1ce393ea5daace4d, 0x8f2220fb0fb66eb, - ])), - c1: Fq(FqRepr([ + ]), + c1: Fq([ 0xb2f66aad4ce5d646, 0x5842a06bfc497cec, 0xcf4895d42599d394, 0xc11b9cba40a8e8d0, 0x2e3813cbe5a0de89, 0x110eefda88847faf, - ])), + ]), }, // Fq2(u + 1)**(((q^2) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0xecfb361b798dba3a, 0xc100ddb891865a2c, 0xec08ff1232bda8e, 0xd5c13cc6f1ca4721, 0x47222a47bf7b5c04, 0x110f184e51c5f59, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((q^3) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0xbd592fc7d825ec8, - ])), - c1: Fq(FqRepr([ + ]), + c1: Fq([ 0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0xe2b7eedbbfd87d2, - ])), + ]), }, // Fq2(u + 1)**(((q^4) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x51ba4ab241b6160, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((q^5) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x3726c30af242c66c, 0x7c2ac1aad1b6fe70, 0xa04007fbba4b14a2, 0xef517c3266341429, 0x95ba654ed2226b, 0x2e370eccc86f7dd, - ])), - c1: Fq(FqRepr([ + ]), + c1: Fq([ 0x82d83cf50dbce43f, 0xa2813e53df9d018f, 0xc6f0caa53c65e181, 0x7525cf528d50fe95, 0x4a85ed50f4798a6b, 0x171da0fd6cf8eebd, - ])), + ]), }, // Fq2(u + 1)**(((q^6) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x7e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x40ab3263eff0206, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((q^7) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0xb2f66aad4ce5d646, 0x5842a06bfc497cec, 0xcf4895d42599d394, 0xc11b9cba40a8e8d0, 0x2e3813cbe5a0de89, 0x110eefda88847faf, - ])), - c1: Fq(FqRepr([ + ]), + c1: Fq([ 0x7089552b319d465, 0xc6695f92b50a8313, 0x97e83cccd117228f, 0xa35baecab2dc29ee, 0x1ce393ea5daace4d, 0x8f2220fb0fb66eb, - ])), + ]), }, // Fq2(u + 1)**(((q^8) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x3f97d6e83d050d2, 0x18f0206554638741, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((q^9) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0xe2b7eedbbfd87d2, - ])), - c1: Fq(FqRepr([ + ]), + c1: Fq([ 0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0xbd592fc7d825ec8, - ])), + ]), }, // Fq2(u + 1)**(((q^10) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x890dc9e4867545c3, 0x2af322533285a5d5, 0x50880866309b7e2c, 0xa20d1b8c7e881024, 0x14e4f04fe2db9068, 0x14e56d3f1564853a, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]), }, // Fq2(u + 1)**(((q^11) - 1) / 6) Fq2 { - c0: Fq(FqRepr([ + c0: Fq([ 0x82d83cf50dbce43f, 0xa2813e53df9d018f, 0xc6f0caa53c65e181, 0x7525cf528d50fe95, 0x4a85ed50f4798a6b, 0x171da0fd6cf8eebd, - ])), - c1: Fq(FqRepr([ + ]), + c1: Fq([ 0x3726c30af242c66c, 0x7c2ac1aad1b6fe70, 0xa04007fbba4b14a2, 0xef517c3266341429, 0x95ba654ed2226b, 0x2e370eccc86f7dd, - ])), + ]), }, ]; // -((2**384) mod q) mod q -pub const NEGATIVE_ONE: Fq = Fq(FqRepr([ +pub const NEGATIVE_ONE: Fq = Fq([ 0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x7e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x40ab3263eff0206, -])); +]); #[derive(PrimeField)] #[PrimeFieldModulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"] #[PrimeFieldGenerator = "2"] -pub struct Fq(FqRepr); +#[PrimeFieldReprEndianness = "big"] +pub struct Fq([u64; 6]); #[test] fn test_b_coeff() { @@ -1182,428 +1183,30 @@ use rand_core::SeedableRng; #[cfg(test)] use rand_xorshift::XorShiftRng; -#[test] -fn test_fq_repr_ordering() { - use std::cmp::Ordering; - - fn assert_equality(a: FqRepr, b: FqRepr) { - assert_eq!(a, b); - assert!(a.cmp(&b) == Ordering::Equal); - } - - fn assert_lt(a: FqRepr, b: FqRepr) { - assert!(a < b); - assert!(b > a); - } - - assert_equality( - FqRepr([9999, 9999, 9999, 9999, 9999, 9999]), - FqRepr([9999, 9999, 9999, 9999, 9999, 9999]), - ); - assert_equality( - FqRepr([9999, 9998, 9999, 9999, 9999, 9999]), - FqRepr([9999, 9998, 9999, 9999, 9999, 9999]), - ); - assert_equality( - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - ); - assert_lt( - FqRepr([9999, 9999, 9999, 9997, 9999, 9998]), - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - ); - assert_lt( - FqRepr([9999, 9999, 9999, 9997, 9998, 9999]), - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - ); - assert_lt( - FqRepr([9, 9999, 9999, 9997, 9998, 9999]), - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - ); -} - -#[test] -fn test_fq_repr_from() { - assert_eq!(FqRepr::from(100), FqRepr([100, 0, 0, 0, 0, 0])); -} - -#[test] -fn test_fq_repr_is_odd() { - assert!(!FqRepr::from(0).is_odd()); - assert!(FqRepr::from(0).is_even()); - assert!(FqRepr::from(1).is_odd()); - assert!(!FqRepr::from(1).is_even()); - assert!(!FqRepr::from(324834872).is_odd()); - assert!(FqRepr::from(324834872).is_even()); - assert!(FqRepr::from(324834873).is_odd()); - assert!(!FqRepr::from(324834873).is_even()); -} - -#[test] -fn test_fq_repr_is_zero() { - assert!(FqRepr::from(0).is_zero()); - assert!(!FqRepr::from(1).is_zero()); - assert!(!FqRepr([0, 0, 0, 0, 1, 0]).is_zero()); -} - -#[test] -fn test_fq_repr_div2() { - let mut a = FqRepr([ - 0x8b0ad39f8dd7482a, - 0x147221c9a7178b69, - 0x54764cb08d8a6aa0, - 0x8519d708e1d83041, - 0x41f82777bd13fdb, - 0xf43944578f9b771b, - ]); - a.div2(); - assert_eq!( - a, - FqRepr([ - 0xc58569cfc6eba415, - 0xa3910e4d38bc5b4, - 0xaa3b265846c53550, - 0xc28ceb8470ec1820, - 0x820fc13bbde89fed, - 0x7a1ca22bc7cdbb8d - ]) - ); - for _ in 0..10 { - a.div2(); - } - assert_eq!( - a, - FqRepr([ - 0x6d31615a73f1bae9, - 0x54028e443934e2f1, - 0x82a8ec99611b14d, - 0xfb70a33ae11c3b06, - 0xe36083f04eef7a27, - 0x1e87288af1f36e - ]) - ); - for _ in 0..300 { - a.div2(); - } - assert_eq!(a, FqRepr([0x7288af1f36ee3608, 0x1e8, 0x0, 0x0, 0x0, 0x0])); - for _ in 0..50 { - a.div2(); - } - assert_eq!(a, FqRepr([0x7a1ca2, 0x0, 0x0, 0x0, 0x0, 0x0])); - for _ in 0..22 { - a.div2(); - } - assert_eq!(a, FqRepr([0x1, 0x0, 0x0, 0x0, 0x0, 0x0])); - a.div2(); - assert!(a.is_zero()); -} - -#[test] -fn test_fq_repr_shr() { - let mut a = FqRepr([ - 0xaa5cdd6172847ffd, - 0x43242c06aed55287, - 0x9ddd5b312f3dd104, - 0xc5541fd48046b7e7, - 0x16080cf4071e0b05, - 0x1225f2901aea514e, - ]); - a.shr(0); - assert_eq!( - a, - FqRepr([ - 0xaa5cdd6172847ffd, - 0x43242c06aed55287, - 0x9ddd5b312f3dd104, - 0xc5541fd48046b7e7, - 0x16080cf4071e0b05, - 0x1225f2901aea514e - ]) - ); - a.shr(1); - assert_eq!( - a, - FqRepr([ - 0xd52e6eb0b9423ffe, - 0x21921603576aa943, - 0xceeead98979ee882, - 0xe2aa0fea40235bf3, - 0xb04067a038f0582, - 0x912f9480d7528a7 - ]) - ); - a.shr(50); - assert_eq!( - a, - FqRepr([ - 0x8580d5daaa50f54b, - 0xab6625e7ba208864, - 0x83fa9008d6fcf3bb, - 0x19e80e3c160b8aa, - 0xbe52035d4a29c2c1, - 0x244 - ]) - ); - a.shr(130); - assert_eq!( - a, - FqRepr([ - 0xa0fea40235bf3cee, - 0x4067a038f0582e2a, - 0x2f9480d7528a70b0, - 0x91, - 0x0, - 0x0 - ]) - ); - a.shr(64); - assert_eq!( - a, - FqRepr([0x4067a038f0582e2a, 0x2f9480d7528a70b0, 0x91, 0x0, 0x0, 0x0]) - ); -} - -#[test] -fn test_fq_repr_mul2() { - let mut a = FqRepr::from(23712937547); - a.mul2(); - assert_eq!(a, FqRepr([0xb0acd6c96, 0x0, 0x0, 0x0, 0x0, 0x0])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!( - a, - FqRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0, 0x0, 0x0]) - ); - for _ in 0..300 { - a.mul2(); - } - assert_eq!(a, FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0xcd6c960000000000])); - for _ in 0..17 { - a.mul2(); - } - assert_eq!(a, FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x2c00000000000000])); - for _ in 0..6 { - a.mul2(); - } - assert!(a.is_zero()); -} - -#[test] -fn test_fq_repr_num_bits() { - let mut a = FqRepr::from(0); - assert_eq!(0, a.num_bits()); - a = FqRepr::from(1); - for i in 1..385 { - assert_eq!(i, a.num_bits()); - a.mul2(); - } - assert_eq!(0, a.num_bits()); -} - -#[test] -fn test_fq_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let mut t = FqRepr([ - 0x827a4a08041ebd9, - 0x3c239f3dcc8f0d6b, - 0x9ab46a912d555364, - 0x196936b17b43910b, - 0xad0eb3948a5c34fd, - 0xd56f7b5ab8b5ce8, - ]); - t.sub_noborrow(&FqRepr([ - 0xc7867917187ca02b, - 0x5d75679d4911ffef, - 0x8c5b3e48b1a71c15, - 0x6a427ae846fd66aa, - 0x7a37e7265ee1eaf9, - 0x7c0577a26f59d5, - ])); - assert!( - t == FqRepr([ - 0x40a12b8967c54bae, - 0xdeae37a0837d0d7b, - 0xe592c487bae374e, - 0xaf26bbc934462a61, - 0x32d6cc6e2b7a4a03, - 0xcdaf23e091c0313 - ]) - ); - - for _ in 0..1000 { - let mut a = Fq::random(&mut rng).into_repr(); - a.0[5] >>= 30; - let mut b = a; - for _ in 0..10 { - b.mul2(); - } - let mut c = b; - for _ in 0..10 { - c.mul2(); - } - - assert!(a < b); - assert!(b < c); - - let mut csub_ba = c; - csub_ba.sub_noborrow(&b); - csub_ba.sub_noborrow(&a); - - let mut csub_ab = c; - csub_ab.sub_noborrow(&a); - csub_ab.sub_noborrow(&b); - - assert_eq!(csub_ab, csub_ba); - } - - // Subtracting q+1 from q should produce -1 (mod 2**384) - let mut qplusone = FqRepr([ - 0xb9feffffffffaaab, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ]); - qplusone.sub_noborrow(&FqRepr([ - 0xb9feffffffffaaac, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ])); - assert_eq!( - qplusone, - FqRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ]) - ); -} - -#[test] -fn test_fq_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let mut t = FqRepr([ - 0x827a4a08041ebd9, - 0x3c239f3dcc8f0d6b, - 0x9ab46a912d555364, - 0x196936b17b43910b, - 0xad0eb3948a5c34fd, - 0xd56f7b5ab8b5ce8, - ]); - t.add_nocarry(&FqRepr([ - 0xc7867917187ca02b, - 0x5d75679d4911ffef, - 0x8c5b3e48b1a71c15, - 0x6a427ae846fd66aa, - 0x7a37e7265ee1eaf9, - 0x7c0577a26f59d5, - ])); - assert!( - t == FqRepr([ - 0xcfae1db798be8c04, - 0x999906db15a10d5a, - 0x270fa8d9defc6f79, - 0x83abb199c240f7b6, - 0x27469abae93e1ff6, - 0xdd2fd2d4dfab6be - ]) - ); - - // Test for the associativity of addition. - for _ in 0..1000 { - let mut a = Fq::random(&mut rng).into_repr(); - let mut b = Fq::random(&mut rng).into_repr(); - let mut c = Fq::random(&mut rng).into_repr(); - - // Unset the first few bits, so that overflow won't occur. - a.0[5] >>= 3; - b.0[5] >>= 3; - c.0[5] >>= 3; - - let mut abc = a; - abc.add_nocarry(&b); - abc.add_nocarry(&c); - - let mut acb = a; - acb.add_nocarry(&c); - acb.add_nocarry(&b); - - let mut bac = b; - bac.add_nocarry(&a); - bac.add_nocarry(&c); - - let mut bca = b; - bca.add_nocarry(&c); - bca.add_nocarry(&a); - - let mut cab = c; - cab.add_nocarry(&a); - cab.add_nocarry(&b); - - let mut cba = c; - cba.add_nocarry(&b); - cba.add_nocarry(&a); - - assert_eq!(abc, acb); - assert_eq!(abc, bac); - assert_eq!(abc, bca); - assert_eq!(abc, cab); - assert_eq!(abc, cba); - } - - // Adding 1 to (2^384 - 1) should produce zero - let mut x = FqRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - ]); - x.add_nocarry(&FqRepr::from(1)); - assert!(x.is_zero()); -} - #[test] fn test_fq_is_valid() { - let mut a = Fq(MODULUS); + let mut a = MODULUS_LIMBS; assert!(!a.is_valid()); - a.0.sub_noborrow(&FqRepr::from(1)); + a.sub_noborrow(&Fq([1, 0, 0, 0, 0, 0])); assert!(a.is_valid()); assert!(Fq::from(0).is_valid()); - assert!(Fq(FqRepr([ + assert!(Fq([ 0xdf4671abd14dab3e, 0xe2dc0c9f534fbd33, 0x31ca6c880cc444a6, 0x257a67e70ef33359, 0xf9b29e493f899b36, 0x17c8be1800b9f059 - ])) + ]) .is_valid()); - assert!(!Fq(FqRepr([ + assert!(!Fq([ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff - ])) + ]) .is_valid()); let mut rng = XorShiftRng::from_seed([ @@ -1621,103 +1224,103 @@ fn test_fq_is_valid() { fn test_fq_add_assign() { { // Random number - let mut tmp = Fq(FqRepr([ + let mut tmp = Fq([ 0x624434821df92b69, 0x503260c04fd2e2ea, 0xd9df726e0d16e8ce, 0xfbcb39adfd5dfaeb, 0x86b8a22b0c88b112, 0x165a2ed809e4201b, - ])); + ]); assert!(tmp.is_valid()); // Test that adding zero has no effect. - tmp.add_assign(&Fq(FqRepr::from(0))); + tmp.add_assign(&Fq([0, 0, 0, 0, 0, 0])); assert_eq!( tmp, - Fq(FqRepr([ + Fq([ 0x624434821df92b69, 0x503260c04fd2e2ea, 0xd9df726e0d16e8ce, 0xfbcb39adfd5dfaeb, 0x86b8a22b0c88b112, 0x165a2ed809e4201b - ])) + ]) ); // Add one and test for the result. - tmp.add_assign(&Fq(FqRepr::from(1))); + tmp.add_assign(&Fq([1, 0, 0, 0, 0, 0])); assert_eq!( tmp, - Fq(FqRepr([ + Fq([ 0x624434821df92b6a, 0x503260c04fd2e2ea, 0xd9df726e0d16e8ce, 0xfbcb39adfd5dfaeb, 0x86b8a22b0c88b112, 0x165a2ed809e4201b - ])) + ]) ); // Add another random number that exercises the reduction. - tmp.add_assign(&Fq(FqRepr([ + tmp.add_assign(&Fq([ 0x374d8f8ea7a648d8, 0xe318bb0ebb8bfa9b, 0x613d996f0a95b400, 0x9fac233cb7e4fef1, 0x67e47552d253c52, 0x5c31b227edf25da, - ]))); + ])); assert_eq!( tmp, - Fq(FqRepr([ + Fq([ 0xdf92c410c59fc997, 0x149f1bd05a0add85, 0xd3ec393c20fba6ab, 0x37001165c1bde71d, 0x421b41c9f662408e, 0x21c38104f435f5b - ])) + ]) ); // Add one to (q - 1) and test for the result. - tmp = Fq(FqRepr([ + tmp = Fq([ 0xb9feffffffffaaaa, 0x1eabfffeb153ffff, 0x6730d2a0f6b0f624, 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a, - ])); - tmp.add_assign(&Fq(FqRepr::from(1))); - assert!(tmp.0.is_zero()); + ]); + tmp.add_assign(&Fq([1, 0, 0, 0, 0, 0])); + assert!(tmp.is_zero()); // Add a random number to another one such that the result is q - 1 - tmp = Fq(FqRepr([ + tmp = Fq([ 0x531221a410efc95b, 0x72819306027e9717, 0x5ecefb937068b746, 0x97de59cd6feaefd7, 0xdc35c51158644588, 0xb2d176c04f2100, - ])); - tmp.add_assign(&Fq(FqRepr([ + ]); + tmp.add_assign(&Fq([ 0x66ecde5bef0fe14f, 0xac2a6cf8aed568e8, 0x861d70d86483edd, 0xcc98f1b7839a22e8, 0x6ee5e2a4eae7674e, 0x194e40737930c599, - ]))); + ])); assert_eq!( tmp, - Fq(FqRepr([ + Fq([ 0xb9feffffffffaaaa, 0x1eabfffeb153ffff, 0x6730d2a0f6b0f624, 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a - ])) + ]) ); // Add one to the result and test for it. - tmp.add_assign(&Fq(FqRepr::from(1))); - assert!(tmp.0.is_zero()); + tmp.add_assign(&Fq([1, 0, 0, 0, 0, 0])); + assert!(tmp.is_zero()); } // Test associativity @@ -1751,87 +1354,87 @@ fn test_fq_add_assign() { fn test_fq_sub_assign() { { // Test arbitrary subtraction that tests reduction. - let mut tmp = Fq(FqRepr([ + let mut tmp = Fq([ 0x531221a410efc95b, 0x72819306027e9717, 0x5ecefb937068b746, 0x97de59cd6feaefd7, 0xdc35c51158644588, 0xb2d176c04f2100, - ])); - tmp.sub_assign(&Fq(FqRepr([ + ]); + tmp.sub_assign(&Fq([ 0x98910d20877e4ada, 0x940c983013f4b8ba, 0xf677dc9b8345ba33, 0xbef2ce6b7f577eba, 0xe1ae288ac3222c44, 0x5968bb602790806, - ]))); + ])); assert_eq!( tmp, - Fq(FqRepr([ + Fq([ 0x748014838971292c, 0xfd20fad49fddde5c, 0xcf87f198e3d3f336, 0x3d62d6e6e41883db, 0x45a3443cd88dc61b, 0x151d57aaf755ff94 - ])) + ]) ); // Test the opposite subtraction which doesn't test reduction. - tmp = Fq(FqRepr([ + tmp = Fq([ 0x98910d20877e4ada, 0x940c983013f4b8ba, 0xf677dc9b8345ba33, 0xbef2ce6b7f577eba, 0xe1ae288ac3222c44, 0x5968bb602790806, - ])); - tmp.sub_assign(&Fq(FqRepr([ + ]); + tmp.sub_assign(&Fq([ 0x531221a410efc95b, 0x72819306027e9717, 0x5ecefb937068b746, 0x97de59cd6feaefd7, 0xdc35c51158644588, 0xb2d176c04f2100, - ]))); + ])); assert_eq!( tmp, - Fq(FqRepr([ + Fq([ 0x457eeb7c768e817f, 0x218b052a117621a3, 0x97a8e10812dd02ed, 0x2714749e0f6c8ee3, 0x57863796abde6bc, 0x4e3ba3f4229e706 - ])) + ]) ); // Test for sensible results with zero - tmp = Fq(FqRepr::from(0)); - tmp.sub_assign(&Fq(FqRepr::from(0))); + tmp = Fq::zero(); + tmp.sub_assign(&Fq::zero()); assert!(tmp.is_zero()); - tmp = Fq(FqRepr([ + tmp = Fq([ 0x98910d20877e4ada, 0x940c983013f4b8ba, 0xf677dc9b8345ba33, 0xbef2ce6b7f577eba, 0xe1ae288ac3222c44, 0x5968bb602790806, - ])); - tmp.sub_assign(&Fq(FqRepr::from(0))); + ]); + tmp.sub_assign(&Fq::zero()); assert_eq!( tmp, - Fq(FqRepr([ + Fq([ 0x98910d20877e4ada, 0x940c983013f4b8ba, 0xf677dc9b8345ba33, 0xbef2ce6b7f577eba, 0xe1ae288ac3222c44, 0x5968bb602790806 - ])) + ]) ); } @@ -1858,31 +1461,31 @@ fn test_fq_sub_assign() { #[test] fn test_fq_mul_assign() { - let mut tmp = Fq(FqRepr([ + let mut tmp = Fq([ 0xcc6200000020aa8a, 0x422800801dd8001a, 0x7f4f5e619041c62c, 0x8a55171ac70ed2ba, 0x3f69cc3a3d07d58b, 0xb972455fd09b8ef, - ])); - tmp.mul_assign(&Fq(FqRepr([ + ]); + tmp.mul_assign(&Fq([ 0x329300000030ffcf, 0x633c00c02cc40028, 0xbef70d925862a942, 0x4f7fa2a82a963c17, 0xdf1eb2575b8bc051, 0x1162b680fb8e9566, - ]))); + ])); assert!( - tmp == Fq(FqRepr([ + tmp == Fq([ 0x9dc4000001ebfe14, 0x2850078997b00193, 0xa8197f1abb4d7bf, 0xc0309573f4bfe871, 0xf48d0923ffaf7620, 0x11d4b58c7a926e66 - ])) + ]) ); let mut rng = XorShiftRng::from_seed([ @@ -1934,96 +1537,82 @@ fn test_fq_mul_assign() { #[test] fn test_fq_shr() { let mut a = Fq::from_repr(FqRepr([ - 0xaa5cdd6172847ffd, - 0x43242c06aed55287, - 0x9ddd5b312f3dd104, - 0xc5541fd48046b7e7, - 0x16080cf4071e0b05, - 0x1225f2901aea514e, + 0x12, 0x25, 0xf2, 0x90, 0x1a, 0xea, 0x51, 0x4e, 0x16, 0x08, 0x0c, 0xf4, 0x07, 0x1e, 0x0b, + 0x05, 0xc5, 0x54, 0x1f, 0xd4, 0x80, 0x46, 0xb7, 0xe7, 0x9d, 0xdd, 0x5b, 0x31, 0x2f, 0x3d, + 0xd1, 0x04, 0x43, 0x24, 0x2c, 0x06, 0xae, 0xd5, 0x52, 0x87, 0xaa, 0x5c, 0xdd, 0x61, 0x72, + 0x84, 0x7f, 0xfd, ])) .unwrap(); a = a >> 0; assert_eq!( a.into_repr(), FqRepr([ - 0xaa5cdd6172847ffd, - 0x43242c06aed55287, - 0x9ddd5b312f3dd104, - 0xc5541fd48046b7e7, - 0x16080cf4071e0b05, - 0x1225f2901aea514e, + 0x12, 0x25, 0xf2, 0x90, 0x1a, 0xea, 0x51, 0x4e, 0x16, 0x08, 0x0c, 0xf4, 0x07, 0x1e, + 0x0b, 0x05, 0xc5, 0x54, 0x1f, 0xd4, 0x80, 0x46, 0xb7, 0xe7, 0x9d, 0xdd, 0x5b, 0x31, + 0x2f, 0x3d, 0xd1, 0x04, 0x43, 0x24, 0x2c, 0x06, 0xae, 0xd5, 0x52, 0x87, 0xaa, 0x5c, + 0xdd, 0x61, 0x72, 0x84, 0x7f, 0xfd, ]) ); a = a >> 1; assert_eq!( a.into_repr(), FqRepr([ - 0xd52e6eb0b9423ffe, - 0x21921603576aa943, - 0xceeead98979ee882, - 0xe2aa0fea40235bf3, - 0x0b04067a038f0582, - 0x0912f9480d7528a7, + 0x09, 0x12, 0xf9, 0x48, 0x0d, 0x75, 0x28, 0xa7, 0x0b, 0x04, 0x06, 0x7a, 0x03, 0x8f, + 0x05, 0x82, 0xe2, 0xaa, 0x0f, 0xea, 0x40, 0x23, 0x5b, 0xf3, 0xce, 0xee, 0xad, 0x98, + 0x97, 0x9e, 0xe8, 0x82, 0x21, 0x92, 0x16, 0x03, 0x57, 0x6a, 0xa9, 0x43, 0xd5, 0x2e, + 0x6e, 0xb0, 0xb9, 0x42, 0x3f, 0xfe, ]) ); a = a >> 50; assert_eq!( a.into_repr(), FqRepr([ - 0x8580d5daaa50f54b, - 0xab6625e7ba208864, - 0x83fa9008d6fcf3bb, - 0x019e80e3c160b8aa, - 0xbe52035d4a29c2c1, - 0x0000000000000244, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x44, 0xbe, 0x52, 0x03, 0x5d, 0x4a, 0x29, + 0xc2, 0xc1, 0x01, 0x9e, 0x80, 0xe3, 0xc1, 0x60, 0xb8, 0xaa, 0x83, 0xfa, 0x90, 0x08, + 0xd6, 0xfc, 0xf3, 0xbb, 0xab, 0x66, 0x25, 0xe7, 0xba, 0x20, 0x88, 0x64, 0x85, 0x80, + 0xd5, 0xda, 0xaa, 0x50, 0xf5, 0x4b, ]) ); a = a >> 130; assert_eq!( a.into_repr(), FqRepr([ - 0xa0fea40235bf3cee, - 0x4067a038f0582e2a, - 0x2f9480d7528a70b0, - 0x0000000000000091, - 0x0000000000000000, - 0x0000000000000000, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x2f, 0x94, 0x80, 0xd7, + 0x52, 0x8a, 0x70, 0xb0, 0x40, 0x67, 0xa0, 0x38, 0xf0, 0x58, 0x2e, 0x2a, 0xa0, 0xfe, + 0xa4, 0x02, 0x35, 0xbf, 0x3c, 0xee, ]) ); a = a >> 64; assert_eq!( a.into_repr(), FqRepr([ - 0x4067a038f0582e2a, - 0x2f9480d7528a70b0, - 0x0000000000000091, - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000000, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x91, 0x2f, 0x94, 0x80, 0xd7, 0x52, 0x8a, 0x70, 0xb0, 0x40, 0x67, + 0xa0, 0x38, 0xf0, 0x58, 0x2e, 0x2a, ]) ); } #[test] fn test_fq_squaring() { - let a = Fq(FqRepr([ + let a = Fq([ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x19ffffffffffffff, - ])); + ]); assert!(a.is_valid()); assert_eq!( a.square(), Fq::from_repr(FqRepr([ - 0x1cfb28fe7dfbbb86, - 0x24cbe1731577a59, - 0xcce1d4edc120e66e, - 0xdc05c659b4e15b27, - 0x79361e5a802c6a23, - 0x24bcbe5d51b9a6f + 0x02, 0x4b, 0xcb, 0xe5, 0xd5, 0x1b, 0x9a, 0x6f, 0x79, 0x36, 0x1e, 0x5a, 0x80, 0x2c, + 0x6a, 0x23, 0xdc, 0x05, 0xc6, 0x59, 0xb4, 0xe1, 0x5b, 0x27, 0xcc, 0xe1, 0xd4, 0xed, + 0xc1, 0x20, 0xe6, 0x6e, 0x02, 0x4c, 0xbe, 0x17, 0x31, 0x57, 0x7a, 0x59, 0x1c, 0xfb, + 0x28, 0xfe, 0x7d, 0xfb, 0xbb, 0x86, ])) .unwrap() ); @@ -2161,50 +1750,42 @@ fn test_fq_sqrt() { fn test_fq_from_into_repr() { // q + 1 should not be in the field assert!(Fq::from_repr(FqRepr([ - 0xb9feffffffffaaac, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a + 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, + 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, + 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xaa, 0xac, ])) - .is_err()); + .is_none()); // q should not be in the field - assert!(Fq::from_repr(Fq::char()).is_err()); + assert!(Fq::from_repr(Fq::char()).is_none()); // Multiply some arbitrary representations to see if the result is as expected. let a = FqRepr([ - 0x4a49dad4ff6cde2d, - 0xac62a82a8f51cd50, - 0x2b1f41ab9f36d640, - 0x908a387f480735f1, - 0xae30740c08a875d7, - 0x6c80918a365ef78, + 0x06, 0xc8, 0x09, 0x18, 0xa3, 0x65, 0xef, 0x78, 0xae, 0x30, 0x74, 0x0c, 0x08, 0xa8, 0x75, + 0xd7, 0x90, 0x8a, 0x38, 0x7f, 0x48, 0x07, 0x35, 0xf1, 0x2b, 0x1f, 0x41, 0xab, 0x9f, 0x36, + 0xd6, 0x40, 0xac, 0x62, 0xa8, 0x2a, 0x8f, 0x51, 0xcd, 0x50, 0x4a, 0x49, 0xda, 0xd4, 0xff, + 0x6c, 0xde, 0x2d, ]); let mut a_fq = Fq::from_repr(a).unwrap(); let b = FqRepr([ - 0xbba57917c32f0cf0, - 0xe7f878cf87f05e5d, - 0x9498b4292fd27459, - 0xd59fd94ee4572cfa, - 0x1f607186d5bb0059, - 0xb13955f5ac7f6a3, + 0x0b, 0x13, 0x95, 0x5f, 0x5a, 0xc7, 0xf6, 0xa3, 0x1f, 0x60, 0x71, 0x86, 0xd5, 0xbb, 0x00, + 0x59, 0xd5, 0x9f, 0xd9, 0x4e, 0xe4, 0x57, 0x2c, 0xfa, 0x94, 0x98, 0xb4, 0x29, 0x2f, 0xd2, + 0x74, 0x59, 0xe7, 0xf8, 0x78, 0xcf, 0x87, 0xf0, 0x5e, 0x5d, 0xbb, 0xa5, 0x79, 0x17, 0xc3, + 0x2f, 0x0c, 0xf0, ]); let b_fq = Fq::from_repr(b).unwrap(); let c = FqRepr([ - 0xf5f70713b717914c, - 0x355ea5ac64cbbab1, - 0xce60dd43417ec960, - 0xf16b9d77b0ad7d10, - 0xa44c204c1de7cdb7, - 0x1684487772bc9a5a, + 0x16, 0x84, 0x48, 0x77, 0x72, 0xbc, 0x9a, 0x5a, 0xa4, 0x4c, 0x20, 0x4c, 0x1d, 0xe7, 0xcd, + 0xb7, 0xf1, 0x6b, 0x9d, 0x77, 0xb0, 0xad, 0x7d, 0x10, 0xce, 0x60, 0xdd, 0x43, 0x41, 0x7e, + 0xc9, 0x60, 0x35, 0x5e, 0xa5, 0xac, 0x64, 0xcb, 0xba, 0xb1, 0xf5, 0xf7, 0x07, 0x13, 0xb7, + 0x17, 0x91, 0x4c, ]); a_fq.mul_assign(&b_fq); assert_eq!(a_fq.into_repr(), c); // Zero should be in the field. - assert!(Fq::from_repr(FqRepr::from(0)).unwrap().is_zero()); + assert!(Fq::from_repr(FqRepr([0; 48])).unwrap().is_zero()); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -2223,34 +1804,24 @@ fn test_fq_from_into_repr() { } } -#[test] -fn test_fq_repr_display() { - assert_eq!( - format!("{}", FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])), - "0x1947f0d5f4fe325ab1d4aad87651e694676cc4eef4c46f2cb38d35b3f677958539a8f184f3535c7ba956babf9301ea24".to_string() - ); - assert_eq!( - format!("{}", FqRepr([0xb4171485fd8622dd, 0x864229a6edec7ec5, 0xc57f7bdcf8dfb707, 0x6db7ff0ecea4584a, 0xf8d8578c4a57132d, 0x6eb66d42d9fcaaa])), - "0x06eb66d42d9fcaaaf8d8578c4a57132d6db7ff0ecea4584ac57f7bdcf8dfb707864229a6edec7ec5b4171485fd8622dd".to_string() - ); - assert_eq!( - format!("{}", FqRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])), - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() - ); - assert_eq!( - format!("{}", FqRepr([0, 0, 0, 0, 0, 0])), - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".to_string() - ); -} - #[test] fn test_fq_display() { assert_eq!( - format!("{}", Fq::from_repr(FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])).unwrap()), + format!("{}", Fq::from_repr(FqRepr([ + 0x19, 0x47, 0xf0, 0xd5, 0xf4, 0xfe, 0x32, 0x5a, 0xb1, 0xd4, 0xaa, 0xd8, 0x76, 0x51, + 0xe6, 0x94, 0x67, 0x6c, 0xc4, 0xee, 0xf4, 0xc4, 0x6f, 0x2c, 0xb3, 0x8d, 0x35, 0xb3, + 0xf6, 0x77, 0x95, 0x85, 0x39, 0xa8, 0xf1, 0x84, 0xf3, 0x53, 0x5c, 0x7b, 0xa9, 0x56, + 0xba, 0xbf, 0x93, 0x01, 0xea, 0x24, + ])).unwrap()), "Fq(0x1947f0d5f4fe325ab1d4aad87651e694676cc4eef4c46f2cb38d35b3f677958539a8f184f3535c7ba956babf9301ea24)".to_string() ); assert_eq!( - format!("{}", Fq::from_repr(FqRepr([0xe28e79396ac2bbf8, 0x413f6f7f06ea87eb, 0xa4b62af4a792a689, 0xb7f89f88f59c1dc5, 0x9a551859b1e43a9a, 0x6c9f5a1060de974])).unwrap()), + format!("{}", Fq::from_repr(FqRepr([ + 0x06, 0xc9, 0xf5, 0xa1, 0x06, 0x0d, 0xe9, 0x74, 0x9a, 0x55, 0x18, 0x59, 0xb1, 0xe4, + 0x3a, 0x9a, 0xb7, 0xf8, 0x9f, 0x88, 0xf5, 0x9c, 0x1d, 0xc5, 0xa4, 0xb6, 0x2a, 0xf4, + 0xa7, 0x92, 0xa6, 0x89, 0x41, 0x3f, 0x6f, 0x7f, 0x06, 0xea, 0x87, 0xeb, 0xe2, 0x8e, + 0x79, 0x39, 0x6a, 0xc2, 0xbb, 0xf8, + ])).unwrap()), "Fq(0x06c9f5a1060de9749a551859b1e43a9ab7f89f88f59c1dc5a4b62af4a792a689413f6f7f06ea87ebe28e79396ac2bbf8)".to_string() ); } @@ -2304,8 +1875,7 @@ fn fq_field_tests() { #[test] fn test_fq_ordering() { - // FqRepr's ordering is well-tested, but we still need to make sure the Fq - // elements aren't being compared in Montgomery form. + // We need to make sure the Fq elements aren't being compared in Montgomery form. for i in 0..100 { assert!(Fq::from(i + 1) > Fq::from(i)); } diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index 6e6230736..dd5b751f6 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -302,6 +302,11 @@ impl SqrtField for Fq2 { } } +#[cfg(test)] +use super::fq::FqRepr; +#[cfg(test)] +use ff::PrimeField; + #[test] fn test_fq2_ordering() { let mut a = Fq2 { @@ -353,9 +358,6 @@ fn test_fq2_basics() { #[test] fn test_fq2_squaring() { - use super::fq::FqRepr; - use ff::PrimeField; - let a = Fq2 { c0: Fq::one(), c1: Fq::one(), @@ -381,21 +383,17 @@ fn test_fq2_squaring() { let a = Fq2 { c0: Fq::from_repr(FqRepr([ - 0x9c2c6309bbf8b598, - 0x4eef5c946536f602, - 0x90e34aab6fb6a6bd, - 0xf7f295a94e58ae7c, - 0x41b76dcc1c3fbe5e, - 0x7080c5fa1d8e042, + 0x07, 0x08, 0x0c, 0x5f, 0xa1, 0xd8, 0xe0, 0x42, 0x41, 0xb7, 0x6d, 0xcc, 0x1c, 0x3f, + 0xbe, 0x5e, 0xf7, 0xf2, 0x95, 0xa9, 0x4e, 0x58, 0xae, 0x7c, 0x90, 0xe3, 0x4a, 0xab, + 0x6f, 0xb6, 0xa6, 0xbd, 0x4e, 0xef, 0x5c, 0x94, 0x65, 0x36, 0xf6, 0x02, 0x9c, 0x2c, + 0x63, 0x09, 0xbb, 0xf8, 0xb5, 0x98, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x38f473b3c870a4ab, - 0x6ad3291177c8c7e5, - 0xdac5a4c911a4353e, - 0xbfb99020604137a0, - 0xfc58a7b7be815407, - 0x10d1615e75250a21, + 0x10, 0xd1, 0x61, 0x5e, 0x75, 0x25, 0x0a, 0x21, 0xfc, 0x58, 0xa7, 0xb7, 0xbe, 0x81, + 0x54, 0x07, 0xbf, 0xb9, 0x90, 0x20, 0x60, 0x41, 0x37, 0xa0, 0xda, 0xc5, 0xa4, 0xc9, + 0x11, 0xa4, 0x35, 0x3e, 0x6a, 0xd3, 0x29, 0x11, 0x77, 0xc8, 0xc7, 0xe5, 0x38, 0xf4, + 0x73, 0xb3, 0xc8, 0x70, 0xa4, 0xab, ])) .unwrap(), }; @@ -403,21 +401,17 @@ fn test_fq2_squaring() { a.square(), Fq2 { c0: Fq::from_repr(FqRepr([ - 0xf262c28c538bcf68, - 0xb9f2a66eae1073ba, - 0xdc46ab8fad67ae0, - 0xcb674157618da176, - 0x4cf17b5893c3d327, - 0x7eac81369c43361 + 0x07, 0xea, 0xc8, 0x13, 0x69, 0xc4, 0x33, 0x61, 0x4c, 0xf1, 0x7b, 0x58, 0x93, 0xc3, + 0xd3, 0x27, 0xcb, 0x67, 0x41, 0x57, 0x61, 0x8d, 0xa1, 0x76, 0x0d, 0xc4, 0x6a, 0xb8, + 0xfa, 0xd6, 0x7a, 0xe0, 0xb9, 0xf2, 0xa6, 0x6e, 0xae, 0x10, 0x73, 0xba, 0xf2, 0x62, + 0xc2, 0x8c, 0x53, 0x8b, 0xcf, 0x68, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xc1579cf58e980cf8, - 0xa23eb7e12dd54d98, - 0xe75138bce4cec7aa, - 0x38d0d7275a9689e1, - 0x739c983042779a65, - 0x1542a61c8a8db994 + 0x15, 0x42, 0xa6, 0x1c, 0x8a, 0x8d, 0xb9, 0x94, 0x73, 0x9c, 0x98, 0x30, 0x42, 0x77, + 0x9a, 0x65, 0x38, 0xd0, 0xd7, 0x27, 0x5a, 0x96, 0x89, 0xe1, 0xe7, 0x51, 0x38, 0xbc, + 0xe4, 0xce, 0xc7, 0xaa, 0xa2, 0x3e, 0xb7, 0xe1, 0x2d, 0xd5, 0x4d, 0x98, 0xc1, 0x57, + 0x9c, 0xf5, 0x8e, 0x98, 0x0c, 0xf8, ])) .unwrap(), } @@ -431,41 +425,33 @@ fn test_fq2_mul() { let mut a = Fq2 { c0: Fq::from_repr(FqRepr([ - 0x85c9f989e1461f03, - 0xa2e33c333449a1d6, - 0x41e461154a7354a3, - 0x9ee53e7e84d7532e, - 0x1c202d8ed97afb45, - 0x51d3f9253e2516f, + 0x05, 0x1d, 0x3f, 0x92, 0x53, 0xe2, 0x51, 0x6f, 0x1c, 0x20, 0x2d, 0x8e, 0xd9, 0x7a, + 0xfb, 0x45, 0x9e, 0xe5, 0x3e, 0x7e, 0x84, 0xd7, 0x53, 0x2e, 0x41, 0xe4, 0x61, 0x15, + 0x4a, 0x73, 0x54, 0xa3, 0xa2, 0xe3, 0x3c, 0x33, 0x34, 0x49, 0xa1, 0xd6, 0x85, 0xc9, + 0xf9, 0x89, 0xe1, 0x46, 0x1f, 0x03, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xa7348a8b511aedcf, - 0x143c215d8176b319, - 0x4cc48081c09b8903, - 0x9533e4a9a5158be, - 0x7a5e1ecb676d65f9, - 0x180c3ee46656b008, + 0x18, 0x0c, 0x3e, 0xe4, 0x66, 0x56, 0xb0, 0x08, 0x7a, 0x5e, 0x1e, 0xcb, 0x67, 0x6d, + 0x65, 0xf9, 0x09, 0x53, 0x3e, 0x4a, 0x9a, 0x51, 0x58, 0xbe, 0x4c, 0xc4, 0x80, 0x81, + 0xc0, 0x9b, 0x89, 0x03, 0x14, 0x3c, 0x21, 0x5d, 0x81, 0x76, 0xb3, 0x19, 0xa7, 0x34, + 0x8a, 0x8b, 0x51, 0x1a, 0xed, 0xcf, ])) .unwrap(), }; a.mul_assign(&Fq2 { c0: Fq::from_repr(FqRepr([ - 0xe21f9169805f537e, - 0xfc87e62e179c285d, - 0x27ece175be07a531, - 0xcd460f9f0c23e430, - 0x6c9110292bfa409, - 0x2c93a72eb8af83e, + 0x02, 0xc9, 0x3a, 0x72, 0xeb, 0x8a, 0xf8, 0x3e, 0x06, 0xc9, 0x11, 0x02, 0x92, 0xbf, + 0xa4, 0x09, 0xcd, 0x46, 0x0f, 0x9f, 0x0c, 0x23, 0xe4, 0x30, 0x27, 0xec, 0xe1, 0x75, + 0xbe, 0x07, 0xa5, 0x31, 0xfc, 0x87, 0xe6, 0x2e, 0x17, 0x9c, 0x28, 0x5d, 0xe2, 0x1f, + 0x91, 0x69, 0x80, 0x5f, 0x53, 0x7e, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x4b1c3f936d8992d4, - 0x1d2a72916dba4c8a, - 0x8871c508658d1e5f, - 0x57a06d3135a752ae, - 0x634cd3c6c565096d, - 0x19e17334d4e93558, + 0x19, 0xe1, 0x73, 0x34, 0xd4, 0xe9, 0x35, 0x58, 0x63, 0x4c, 0xd3, 0xc6, 0xc5, 0x65, + 0x09, 0x6d, 0x57, 0xa0, 0x6d, 0x31, 0x35, 0xa7, 0x52, 0xae, 0x88, 0x71, 0xc5, 0x08, + 0x65, 0x8d, 0x1e, 0x5f, 0x1d, 0x2a, 0x72, 0x91, 0x6d, 0xba, 0x4c, 0x8a, 0x4b, 0x1c, + 0x3f, 0x93, 0x6d, 0x89, 0x92, 0xd4, ])) .unwrap(), }); @@ -473,21 +459,17 @@ fn test_fq2_mul() { a, Fq2 { c0: Fq::from_repr(FqRepr([ - 0x95b5127e6360c7e4, - 0xde29c31a19a6937e, - 0xf61a96dacf5a39bc, - 0x5511fe4d84ee5f78, - 0x5310a202d92f9963, - 0x1751afbe166e5399 + 0x17, 0x51, 0xaf, 0xbe, 0x16, 0x6e, 0x53, 0x99, 0x53, 0x10, 0xa2, 0x02, 0xd9, 0x2f, + 0x99, 0x63, 0x55, 0x11, 0xfe, 0x4d, 0x84, 0xee, 0x5f, 0x78, 0xf6, 0x1a, 0x96, 0xda, + 0xcf, 0x5a, 0x39, 0xbc, 0xde, 0x29, 0xc3, 0x1a, 0x19, 0xa6, 0x93, 0x7e, 0x95, 0xb5, + 0x12, 0x7e, 0x63, 0x60, 0xc7, 0xe4, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x84af0e1bd630117a, - 0x6c63cd4da2c2aa7, - 0x5ba6e5430e883d40, - 0xc975106579c275ee, - 0x33a9ac82ce4c5083, - 0x1ef1a36c201589d + 0x01, 0xef, 0x1a, 0x36, 0xc2, 0x01, 0x58, 0x9d, 0x33, 0xa9, 0xac, 0x82, 0xce, 0x4c, + 0x50, 0x83, 0xc9, 0x75, 0x10, 0x65, 0x79, 0xc2, 0x75, 0xee, 0x5b, 0xa6, 0xe5, 0x43, + 0x0e, 0x88, 0x3d, 0x40, 0x06, 0xc6, 0x3c, 0xd4, 0xda, 0x2c, 0x2a, 0xa7, 0x84, 0xaf, + 0x0e, 0x1b, 0xd6, 0x30, 0x11, 0x7a, ])) .unwrap(), } @@ -503,21 +485,17 @@ fn test_fq2_invert() { let a = Fq2 { c0: Fq::from_repr(FqRepr([ - 0x85c9f989e1461f03, - 0xa2e33c333449a1d6, - 0x41e461154a7354a3, - 0x9ee53e7e84d7532e, - 0x1c202d8ed97afb45, - 0x51d3f9253e2516f, + 0x05, 0x1d, 0x3f, 0x92, 0x53, 0xe2, 0x51, 0x6f, 0x1c, 0x20, 0x2d, 0x8e, 0xd9, 0x7a, + 0xfb, 0x45, 0x9e, 0xe5, 0x3e, 0x7e, 0x84, 0xd7, 0x53, 0x2e, 0x41, 0xe4, 0x61, 0x15, + 0x4a, 0x73, 0x54, 0xa3, 0xa2, 0xe3, 0x3c, 0x33, 0x34, 0x49, 0xa1, 0xd6, 0x85, 0xc9, + 0xf9, 0x89, 0xe1, 0x46, 0x1f, 0x03, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xa7348a8b511aedcf, - 0x143c215d8176b319, - 0x4cc48081c09b8903, - 0x9533e4a9a5158be, - 0x7a5e1ecb676d65f9, - 0x180c3ee46656b008, + 0x18, 0x0c, 0x3e, 0xe4, 0x66, 0x56, 0xb0, 0x08, 0x7a, 0x5e, 0x1e, 0xcb, 0x67, 0x6d, + 0x65, 0xf9, 0x09, 0x53, 0x3e, 0x4a, 0x9a, 0x51, 0x58, 0xbe, 0x4c, 0xc4, 0x80, 0x81, + 0xc0, 0x9b, 0x89, 0x03, 0x14, 0x3c, 0x21, 0x5d, 0x81, 0x76, 0xb3, 0x19, 0xa7, 0x34, + 0x8a, 0x8b, 0x51, 0x1a, 0xed, 0xcf, ])) .unwrap(), }; @@ -526,21 +504,17 @@ fn test_fq2_invert() { a, Fq2 { c0: Fq::from_repr(FqRepr([ - 0x70300f9bcb9e594, - 0xe5ecda5fdafddbb2, - 0x64bef617d2915a8f, - 0xdfba703293941c30, - 0xa6c3d8f9586f2636, - 0x1351ef01941b70c4 + 0x13, 0x51, 0xef, 0x01, 0x94, 0x1b, 0x70, 0xc4, 0xa6, 0xc3, 0xd8, 0xf9, 0x58, 0x6f, + 0x26, 0x36, 0xdf, 0xba, 0x70, 0x32, 0x93, 0x94, 0x1c, 0x30, 0x64, 0xbe, 0xf6, 0x17, + 0xd2, 0x91, 0x5a, 0x8f, 0xe5, 0xec, 0xda, 0x5f, 0xda, 0xfd, 0xdb, 0xb2, 0x07, 0x03, + 0x00, 0xf9, 0xbc, 0xb9, 0xe5, 0x94, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x8c39fd76a8312cb4, - 0x15d7b6b95defbff0, - 0x947143f89faedee9, - 0xcbf651a0f367afb2, - 0xdf4e54f0d3ef15a6, - 0x103bdf241afb0019 + 0x10, 0x3b, 0xdf, 0x24, 0x1a, 0xfb, 0x00, 0x19, 0xdf, 0x4e, 0x54, 0xf0, 0xd3, 0xef, + 0x15, 0xa6, 0xcb, 0xf6, 0x51, 0xa0, 0xf3, 0x67, 0xaf, 0xb2, 0x94, 0x71, 0x43, 0xf8, + 0x9f, 0xae, 0xde, 0xe9, 0x15, 0xd7, 0xb6, 0xb9, 0x5d, 0xef, 0xbf, 0xf0, 0x8c, 0x39, + 0xfd, 0x76, 0xa8, 0x31, 0x2c, 0xb4, ])) .unwrap(), } @@ -554,41 +528,33 @@ fn test_fq2_addition() { let mut a = Fq2 { c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, + 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53, + 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0, + 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00, + 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, + 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf, + 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11, + 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d, + 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb, ])) .unwrap(), }; a.add_assign(&Fq2 { c0: Fq::from_repr(FqRepr([ - 0x619a02d78dc70ef2, - 0xb93adfc9119e33e8, - 0x4bf0b99a9f0dca12, - 0x3b88899a42a6318f, - 0x986a4a62fa82a49d, - 0x13ce433fa26027f5, + 0x13, 0xce, 0x43, 0x3f, 0xa2, 0x60, 0x27, 0xf5, 0x98, 0x6a, 0x4a, 0x62, 0xfa, 0x82, + 0xa4, 0x9d, 0x3b, 0x88, 0x89, 0x9a, 0x42, 0xa6, 0x31, 0x8f, 0x4b, 0xf0, 0xb9, 0x9a, + 0x9f, 0x0d, 0xca, 0x12, 0xb9, 0x3a, 0xdf, 0xc9, 0x11, 0x9e, 0x33, 0xe8, 0x61, 0x9a, + 0x02, 0xd7, 0x8d, 0xc7, 0x0e, 0xf2, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x66323bf80b58b9b9, - 0xa1379b6facf6e596, - 0x402aef1fb797e32f, - 0x2236f55246d0d44d, - 0x4c8c1800eb104566, - 0x11d6e20e986c2085, + 0x11, 0xd6, 0xe2, 0x0e, 0x98, 0x6c, 0x20, 0x85, 0x4c, 0x8c, 0x18, 0x00, 0xeb, 0x10, + 0x45, 0x66, 0x22, 0x36, 0xf5, 0x52, 0x46, 0xd0, 0xd4, 0x4d, 0x40, 0x2a, 0xef, 0x1f, + 0xb7, 0x97, 0xe3, 0x2f, 0xa1, 0x37, 0x9b, 0x6f, 0xac, 0xf6, 0xe5, 0x96, 0x66, 0x32, + 0x3b, 0xf8, 0x0b, 0x58, 0xb9, 0xb9, ])) .unwrap(), }); @@ -596,21 +562,17 @@ fn test_fq2_addition() { a, Fq2 { c0: Fq::from_repr(FqRepr([ - 0x8e9a7adaf6eb0eb9, - 0xcb207e6b3341eaba, - 0xd70b0c7b481d23ff, - 0xf4ef57d604b6bca2, - 0x65309427b3d5d090, - 0x14c715d5553f01d2 + 0x14, 0xc7, 0x15, 0xd5, 0x55, 0x3f, 0x01, 0xd2, 0x65, 0x30, 0x94, 0x27, 0xb3, 0xd5, + 0xd0, 0x90, 0xf4, 0xef, 0x57, 0xd6, 0x04, 0xb6, 0xbc, 0xa2, 0xd7, 0x0b, 0x0c, 0x7b, + 0x48, 0x1d, 0x23, 0xff, 0xcb, 0x20, 0x7e, 0x6b, 0x33, 0x41, 0xea, 0xba, 0x8e, 0x9a, + 0x7a, 0xda, 0xf6, 0xeb, 0x0e, 0xb9, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xfdb032e7d9079a94, - 0x35a2809d15468d83, - 0xfe4b23317e0796d5, - 0xd62fa51334f560fa, - 0x9ad265eb46e01984, - 0x1303f3465112c8bc + 0x13, 0x03, 0xf3, 0x46, 0x51, 0x12, 0xc8, 0xbc, 0x9a, 0xd2, 0x65, 0xeb, 0x46, 0xe0, + 0x19, 0x84, 0xd6, 0x2f, 0xa5, 0x13, 0x34, 0xf5, 0x60, 0xfa, 0xfe, 0x4b, 0x23, 0x31, + 0x7e, 0x07, 0x96, 0xd5, 0x35, 0xa2, 0x80, 0x9d, 0x15, 0x46, 0x8d, 0x83, 0xfd, 0xb0, + 0x32, 0xe7, 0xd9, 0x07, 0x9a, 0x94, ])) .unwrap(), } @@ -624,41 +586,33 @@ fn test_fq2_subtraction() { let mut a = Fq2 { c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, + 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53, + 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0, + 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00, + 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, + 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf, + 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11, + 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d, + 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb, ])) .unwrap(), }; a.sub_assign(&Fq2 { c0: Fq::from_repr(FqRepr([ - 0x619a02d78dc70ef2, - 0xb93adfc9119e33e8, - 0x4bf0b99a9f0dca12, - 0x3b88899a42a6318f, - 0x986a4a62fa82a49d, - 0x13ce433fa26027f5, + 0x13, 0xce, 0x43, 0x3f, 0xa2, 0x60, 0x27, 0xf5, 0x98, 0x6a, 0x4a, 0x62, 0xfa, 0x82, + 0xa4, 0x9d, 0x3b, 0x88, 0x89, 0x9a, 0x42, 0xa6, 0x31, 0x8f, 0x4b, 0xf0, 0xb9, 0x9a, + 0x9f, 0x0d, 0xca, 0x12, 0xb9, 0x3a, 0xdf, 0xc9, 0x11, 0x9e, 0x33, 0xe8, 0x61, 0x9a, + 0x02, 0xd7, 0x8d, 0xc7, 0x0e, 0xf2, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x66323bf80b58b9b9, - 0xa1379b6facf6e596, - 0x402aef1fb797e32f, - 0x2236f55246d0d44d, - 0x4c8c1800eb104566, - 0x11d6e20e986c2085, + 0x11, 0xd6, 0xe2, 0x0e, 0x98, 0x6c, 0x20, 0x85, 0x4c, 0x8c, 0x18, 0x00, 0xeb, 0x10, + 0x45, 0x66, 0x22, 0x36, 0xf5, 0x52, 0x46, 0xd0, 0xd4, 0x4d, 0x40, 0x2a, 0xef, 0x1f, + 0xb7, 0x97, 0xe3, 0x2f, 0xa1, 0x37, 0x9b, 0x6f, 0xac, 0xf6, 0xe5, 0x96, 0x66, 0x32, + 0x3b, 0xf8, 0x0b, 0x58, 0xb9, 0xb9, ])) .unwrap(), }); @@ -666,21 +620,17 @@ fn test_fq2_subtraction() { a, Fq2 { c0: Fq::from_repr(FqRepr([ - 0x8565752bdb5c9b80, - 0x7756bed7c15982e9, - 0xa65a6be700b285fe, - 0xe255902672ef6c43, - 0x7f77a718021c342d, - 0x72ba14049fe9881 + 0x07, 0x2b, 0xa1, 0x40, 0x49, 0xfe, 0x98, 0x81, 0x7f, 0x77, 0xa7, 0x18, 0x02, 0x1c, + 0x34, 0x2d, 0xe2, 0x55, 0x90, 0x26, 0x72, 0xef, 0x6c, 0x43, 0xa6, 0x5a, 0x6b, 0xe7, + 0x00, 0xb2, 0x85, 0xfe, 0x77, 0x56, 0xbe, 0xd7, 0xc1, 0x59, 0x82, 0xe9, 0x85, 0x65, + 0x75, 0x2b, 0xdb, 0x5c, 0x9b, 0x80, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xeb4abaf7c255d1cd, - 0x11df49bc6cacc256, - 0xe52617930588c69a, - 0xf63905f39ad8cb1f, - 0x4cd5dd9fb40b3b8f, - 0x957411359ba6e4c + 0x09, 0x57, 0x41, 0x13, 0x59, 0xba, 0x6e, 0x4c, 0x4c, 0xd5, 0xdd, 0x9f, 0xb4, 0x0b, + 0x3b, 0x8f, 0xf6, 0x39, 0x05, 0xf3, 0x9a, 0xd8, 0xcb, 0x1f, 0xe5, 0x26, 0x17, 0x93, + 0x05, 0x88, 0xc6, 0x9a, 0x11, 0xdf, 0x49, 0xbc, 0x6c, 0xac, 0xc2, 0x56, 0xeb, 0x4a, + 0xba, 0xf7, 0xc2, 0x55, 0xd1, 0xcd, ])) .unwrap(), } @@ -694,21 +644,17 @@ fn test_fq2_negation() { let a = Fq2 { c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, + 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53, + 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0, + 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00, + 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, + 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf, + 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11, + 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d, + 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb, ])) .unwrap(), } @@ -717,21 +663,17 @@ fn test_fq2_negation() { a, Fq2 { c0: Fq::from_repr(FqRepr([ - 0x8cfe87fc96dbaae4, - 0xcc6615c8fb0492d, - 0xdc167fc04da19c37, - 0xab107d49317487ab, - 0x7e555df189f880e3, - 0x19083f5486a10cbd + 0x19, 0x08, 0x3f, 0x54, 0x86, 0xa1, 0x0c, 0xbd, 0x7e, 0x55, 0x5d, 0xf1, 0x89, 0xf8, + 0x80, 0xe3, 0xab, 0x10, 0x7d, 0x49, 0x31, 0x74, 0x87, 0xab, 0xdc, 0x16, 0x7f, 0xc0, + 0x4d, 0xa1, 0x9c, 0x37, 0x0c, 0xc6, 0x61, 0x5c, 0x8f, 0xb0, 0x49, 0x2d, 0x8c, 0xfe, + 0x87, 0xfc, 0x96, 0xdb, 0xaa, 0xe4, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x228109103250c9d0, - 0x8a411ad149045812, - 0xa9109e8f3041427e, - 0xb07e9bc405608611, - 0xfcd559cbe77bd8b8, - 0x18d400b280d93e62 + 0x18, 0xd4, 0x00, 0xb2, 0x80, 0xd9, 0x3e, 0x62, 0xfc, 0xd5, 0x59, 0xcb, 0xe7, 0x7b, + 0xd8, 0xb8, 0xb0, 0x7e, 0x9b, 0xc4, 0x05, 0x60, 0x86, 0x11, 0xa9, 0x10, 0x9e, 0x8f, + 0x30, 0x41, 0x42, 0x7e, 0x8a, 0x41, 0x1a, 0xd1, 0x49, 0x04, 0x58, 0x12, 0x22, 0x81, + 0x09, 0x10, 0x32, 0x50, 0xc9, 0xd0, ])) .unwrap(), } @@ -745,21 +687,17 @@ fn test_fq2_doubling() { let a = Fq2 { c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, + 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53, + 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0, + 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00, + 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, + 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf, + 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11, + 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d, + 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb, ])) .unwrap(), }; @@ -767,21 +705,17 @@ fn test_fq2_doubling() { a.double(), Fq2 { c0: Fq::from_repr(FqRepr([ - 0x5a00f006d247ff8e, - 0x23cb3d4443476da4, - 0x1634a5c1521eb3da, - 0x72cd9c7784211627, - 0x998c938972a657e7, - 0x1f1a52b65bdb3b9 + 0x01, 0xf1, 0xa5, 0x2b, 0x65, 0xbd, 0xb3, 0xb9, 0x99, 0x8c, 0x93, 0x89, 0x72, 0xa6, + 0x57, 0xe7, 0x72, 0xcd, 0x9c, 0x77, 0x84, 0x21, 0x16, 0x27, 0x16, 0x34, 0xa5, 0xc1, + 0x52, 0x1e, 0xb3, 0xda, 0x23, 0xcb, 0x3d, 0x44, 0x43, 0x47, 0x6d, 0xa4, 0x5a, 0x00, + 0xf0, 0x06, 0xd2, 0x47, 0xff, 0x8e, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x2efbeddf9b5dc1b6, - 0x28d5ca5ad09f4fdb, - 0x7c4068238cdf674b, - 0x67f15f81dc49195b, - 0x9c8c9bd4b79fa83d, - 0x25a226f714d506e + 0x02, 0x5a, 0x22, 0x6f, 0x71, 0x4d, 0x50, 0x6e, 0x9c, 0x8c, 0x9b, 0xd4, 0xb7, 0x9f, + 0xa8, 0x3d, 0x67, 0xf1, 0x5f, 0x81, 0xdc, 0x49, 0x19, 0x5b, 0x7c, 0x40, 0x68, 0x23, + 0x8c, 0xdf, 0x67, 0x4b, 0x28, 0xd5, 0xca, 0x5a, 0xd0, 0x9f, 0x4f, 0xdb, 0x2e, 0xfb, + 0xed, 0xdf, 0x9b, 0x5d, 0xc1, 0xb6, ])) .unwrap(), } @@ -795,21 +729,17 @@ fn test_fq2_frobenius_map() { let mut a = Fq2 { c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, + 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53, + 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0, + 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00, + 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, + 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf, + 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11, + 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d, + 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb, ])) .unwrap(), }; @@ -818,21 +748,17 @@ fn test_fq2_frobenius_map() { a, Fq2 { c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc + 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53, + 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0, + 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00, + 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837 + 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf, + 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11, + 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d, + 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb, ])) .unwrap(), } @@ -842,21 +768,17 @@ fn test_fq2_frobenius_map() { a, Fq2 { c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc + 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53, + 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0, + 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00, + 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x228109103250c9d0, - 0x8a411ad149045812, - 0xa9109e8f3041427e, - 0xb07e9bc405608611, - 0xfcd559cbe77bd8b8, - 0x18d400b280d93e62 + 0x18, 0xd4, 0x00, 0xb2, 0x80, 0xd9, 0x3e, 0x62, 0xfc, 0xd5, 0x59, 0xcb, 0xe7, 0x7b, + 0xd8, 0xb8, 0xb0, 0x7e, 0x9b, 0xc4, 0x05, 0x60, 0x86, 0x11, 0xa9, 0x10, 0x9e, 0x8f, + 0x30, 0x41, 0x42, 0x7e, 0x8a, 0x41, 0x1a, 0xd1, 0x49, 0x04, 0x58, 0x12, 0x22, 0x81, + 0x09, 0x10, 0x32, 0x50, 0xc9, 0xd0, ])) .unwrap(), } @@ -866,21 +788,17 @@ fn test_fq2_frobenius_map() { a, Fq2 { c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc + 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53, + 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0, + 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00, + 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837 + 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf, + 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11, + 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d, + 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb, ])) .unwrap(), } @@ -890,21 +808,17 @@ fn test_fq2_frobenius_map() { a, Fq2 { c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc + 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53, + 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0, + 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00, + 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837 + 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf, + 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11, + 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d, + 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb, ])) .unwrap(), } @@ -919,21 +833,17 @@ fn test_fq2_sqrt() { assert_eq!( Fq2 { c0: Fq::from_repr(FqRepr([ - 0x476b4c309720e227, - 0x34c2d04faffdab6, - 0xa57e6fc1bab51fd9, - 0xdb4a116b5bf74aa1, - 0x1e58b2159dfe10e2, - 0x7ca7da1f13606ac + 0x07, 0xca, 0x7d, 0xa1, 0xf1, 0x36, 0x06, 0xac, 0x1e, 0x58, 0xb2, 0x15, 0x9d, 0xfe, + 0x10, 0xe2, 0xdb, 0x4a, 0x11, 0x6b, 0x5b, 0xf7, 0x4a, 0xa1, 0xa5, 0x7e, 0x6f, 0xc1, + 0xba, 0xb5, 0x1f, 0xd9, 0x03, 0x4c, 0x2d, 0x04, 0xfa, 0xff, 0xda, 0xb6, 0x47, 0x6b, + 0x4c, 0x30, 0x97, 0x20, 0xe2, 0x27, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xfa8de88b7516d2c3, - 0x371a75ed14f41629, - 0x4cec2dca577a3eb6, - 0x212611bca4e99121, - 0x8ee5394d77afb3d, - 0xec92336650e49d5 + 0x0e, 0xc9, 0x23, 0x36, 0x65, 0x0e, 0x49, 0xd5, 0x08, 0xee, 0x53, 0x94, 0xd7, 0x7a, + 0xfb, 0x3d, 0x21, 0x26, 0x11, 0xbc, 0xa4, 0xe9, 0x91, 0x21, 0x4c, 0xec, 0x2d, 0xca, + 0x57, 0x7a, 0x3e, 0xb6, 0x37, 0x1a, 0x75, 0xed, 0x14, 0xf4, 0x16, 0x29, 0xfa, 0x8d, + 0xe8, 0x8b, 0x75, 0x16, 0xd2, 0xc3, ])) .unwrap(), } @@ -941,21 +851,17 @@ fn test_fq2_sqrt() { .unwrap(), Fq2 { c0: Fq::from_repr(FqRepr([ - 0x40b299b2704258c5, - 0x6ef7de92e8c68b63, - 0x6d2ddbe552203e82, - 0x8d7f1f723d02c1d3, - 0x881b3e01b611c070, - 0x10f6963bbad2ebc5 + 0x10, 0xf6, 0x96, 0x3b, 0xba, 0xd2, 0xeb, 0xc5, 0x88, 0x1b, 0x3e, 0x01, 0xb6, 0x11, + 0xc0, 0x70, 0x8d, 0x7f, 0x1f, 0x72, 0x3d, 0x02, 0xc1, 0xd3, 0x6d, 0x2d, 0xdb, 0xe5, + 0x52, 0x20, 0x3e, 0x82, 0x6e, 0xf7, 0xde, 0x92, 0xe8, 0xc6, 0x8b, 0x63, 0x40, 0xb2, + 0x99, 0xb2, 0x70, 0x42, 0x58, 0xc5, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ - 0xc099534fc209e752, - 0x7670594665676447, - 0x28a20faed211efe7, - 0x6b852aeaf2afcb1b, - 0xa4c93b08105d71a9, - 0x8d7cfff94216330 + 0x08, 0xd7, 0xcf, 0xff, 0x94, 0x21, 0x63, 0x30, 0xa4, 0xc9, 0x3b, 0x08, 0x10, 0x5d, + 0x71, 0xa9, 0x6b, 0x85, 0x2a, 0xea, 0xf2, 0xaf, 0xcb, 0x1b, 0x28, 0xa2, 0x0f, 0xae, + 0xd2, 0x11, 0xef, 0xe7, 0x76, 0x70, 0x59, 0x46, 0x65, 0x67, 0x64, 0x47, 0xc0, 0x99, + 0x53, 0x4f, 0xc2, 0x09, 0xe7, 0x52, ])) .unwrap(), } @@ -964,12 +870,10 @@ fn test_fq2_sqrt() { assert_eq!( Fq2 { c0: Fq::from_repr(FqRepr([ - 0xb9f78429d1517a6b, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a + 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, + 0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, + 0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xf7, + 0x84, 0x29, 0xd1, 0x51, 0x7a, 0x6b, ])) .unwrap(), c1: Fq::zero(), @@ -979,12 +883,10 @@ fn test_fq2_sqrt() { Fq2 { c0: Fq::zero(), c1: Fq::from_repr(FqRepr([ - 0xb9fefffffd4357a3, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a + 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, + 0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, + 0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, + 0xff, 0xff, 0xfd, 0x43, 0x57, 0xa3, ])) .unwrap(), } diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index 6bfb17520..4a153ad32 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -1,10 +1,11 @@ -use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; +use ff::{Field, PrimeField}; use std::ops::{AddAssign, MulAssign, SubAssign}; #[derive(PrimeField)] #[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] #[PrimeFieldGenerator = "7"] -pub struct Fr(FrRepr); +#[PrimeFieldReprEndianness = "little"] +pub struct Fr([u64; 4]); #[cfg(test)] use ff::PowVartime; @@ -15,373 +16,26 @@ use rand_xorshift::XorShiftRng; #[cfg(test)] use std::ops::Neg; -#[test] -fn test_fr_repr_ordering() { - fn assert_equality(a: FrRepr, b: FrRepr) { - assert_eq!(a, b); - assert!(a.cmp(&b) == ::std::cmp::Ordering::Equal); - } - - fn assert_lt(a: FrRepr, b: FrRepr) { - assert!(a < b); - assert!(b > a); - } - - assert_equality( - FrRepr([9999, 9999, 9999, 9999]), - FrRepr([9999, 9999, 9999, 9999]), - ); - assert_equality( - FrRepr([9999, 9998, 9999, 9999]), - FrRepr([9999, 9998, 9999, 9999]), - ); - assert_equality( - FrRepr([9999, 9999, 9999, 9997]), - FrRepr([9999, 9999, 9999, 9997]), - ); - assert_lt( - FrRepr([9999, 9997, 9999, 9998]), - FrRepr([9999, 9997, 9999, 9999]), - ); - assert_lt( - FrRepr([9999, 9997, 9998, 9999]), - FrRepr([9999, 9997, 9999, 9999]), - ); - assert_lt( - FrRepr([9, 9999, 9999, 9997]), - FrRepr([9999, 9999, 9999, 9997]), - ); -} - -#[test] -fn test_fr_repr_from() { - assert_eq!(FrRepr::from(100), FrRepr([100, 0, 0, 0])); -} - -#[test] -fn test_fr_repr_is_odd() { - assert!(!FrRepr::from(0).is_odd()); - assert!(FrRepr::from(0).is_even()); - assert!(FrRepr::from(1).is_odd()); - assert!(!FrRepr::from(1).is_even()); - assert!(!FrRepr::from(324834872).is_odd()); - assert!(FrRepr::from(324834872).is_even()); - assert!(FrRepr::from(324834873).is_odd()); - assert!(!FrRepr::from(324834873).is_even()); -} - -#[test] -fn test_fr_repr_is_zero() { - assert!(FrRepr::from(0).is_zero()); - assert!(!FrRepr::from(1).is_zero()); - assert!(!FrRepr([0, 0, 1, 0]).is_zero()); -} - -#[test] -fn test_fr_repr_div2() { - let mut a = FrRepr([ - 0xbd2920b19c972321, - 0x174ed0466a3be37e, - 0xd468d5e3b551f0b5, - 0xcb67c072733beefc, - ]); - a.div2(); - assert_eq!( - a, - FrRepr([ - 0x5e949058ce4b9190, - 0x8ba76823351df1bf, - 0x6a346af1daa8f85a, - 0x65b3e039399df77e - ]) - ); - for _ in 0..10 { - a.div2(); - } - assert_eq!( - a, - FrRepr([ - 0x6fd7a524163392e4, - 0x16a2e9da08cd477c, - 0xdf9a8d1abc76aa3e, - 0x196cf80e4e677d - ]) - ); - for _ in 0..200 { - a.div2(); - } - assert_eq!(a, FrRepr([0x196cf80e4e67, 0x0, 0x0, 0x0])); - for _ in 0..40 { - a.div2(); - } - assert_eq!(a, FrRepr([0x19, 0x0, 0x0, 0x0])); - for _ in 0..4 { - a.div2(); - } - assert_eq!(a, FrRepr([0x1, 0x0, 0x0, 0x0])); - a.div2(); - assert!(a.is_zero()); -} - -#[test] -fn test_fr_repr_shr() { - let mut a = FrRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x36003ab08de70da1, - ]); - a.shr(0); - assert_eq!( - a, - FrRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x36003ab08de70da1 - ]) - ); - a.shr(1); - assert_eq!( - a, - FrRepr([ - 0xd99fdd762415141f, - 0xccbef069d44659ef, - 0xcd7b16954d072a92, - 0x1b001d5846f386d0 - ]) - ); - a.shr(50); - assert_eq!( - a, - FrRepr([ - 0xbc1a7511967bf667, - 0xc5a55341caa4b32f, - 0x75611bce1b4335e, - 0x6c0 - ]) - ); - a.shr(130); - assert_eq!(a, FrRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0])); - a.shr(64); - assert_eq!(a, FrRepr([0x1b0, 0x0, 0x0, 0x0])); -} - -#[test] -fn test_fr_repr_mul2() { - let mut a = FrRepr::from(23712937547); - a.mul2(); - assert_eq!(a, FrRepr([0xb0acd6c96, 0x0, 0x0, 0x0])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FrRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0])); - for _ in 0..128 { - a.mul2(); - } - assert_eq!(a, FrRepr([0x0, 0x0, 0x6000000000000000, 0xb0acd6c9])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FrRepr([0x0, 0x0, 0x0, 0x9600000000000000])); - for _ in 0..7 { - a.mul2(); - } - assert!(a.is_zero()); -} - -#[test] -fn test_fr_repr_num_bits() { - let mut a = FrRepr::from(0); - assert_eq!(0, a.num_bits()); - a = FrRepr::from(1); - for i in 1..257 { - assert_eq!(i, a.num_bits()); - a.mul2(); - } - assert_eq!(0, a.num_bits()); -} - -#[test] -fn test_fr_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let mut t = FrRepr([ - 0x8e62a7e85264e2c3, - 0xb23d34c1941d3ca, - 0x5976930b7502dd15, - 0x600f3fb517bf5495, - ]); - t.sub_noborrow(&FrRepr([ - 0xd64f669809cbc6a4, - 0xfa76cb9d90cf7637, - 0xfefb0df9038d43b3, - 0x298a30c744b31acf, - ])); - assert!( - t == FrRepr([ - 0xb813415048991c1f, - 0x10ad07ae88725d92, - 0x5a7b851271759961, - 0x36850eedd30c39c5 - ]) - ); - - for _ in 0..1000 { - let mut a = Fr::random(&mut rng).into_repr(); - a.0[3] >>= 30; - let mut b = a; - for _ in 0..10 { - b.mul2(); - } - let mut c = b; - for _ in 0..10 { - c.mul2(); - } - - assert!(a < b); - assert!(b < c); - - let mut csub_ba = c; - csub_ba.sub_noborrow(&b); - csub_ba.sub_noborrow(&a); - - let mut csub_ab = c; - csub_ab.sub_noborrow(&a); - csub_ab.sub_noborrow(&b); - - assert_eq!(csub_ab, csub_ba); - } - - // Subtracting r+1 from r should produce -1 (mod 2**256) - let mut qplusone = FrRepr([ - 0xffffffff00000001, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ]); - qplusone.sub_noborrow(&FrRepr([ - 0xffffffff00000002, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ])); - assert_eq!( - qplusone, - FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ]) - ); -} - -#[test] -fn test_fr_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let mut t = FrRepr([ - 0xd64f669809cbc6a4, - 0xfa76cb9d90cf7637, - 0xfefb0df9038d43b3, - 0x298a30c744b31acf, - ]); - t.add_nocarry(&FrRepr([ - 0x8e62a7e85264e2c3, - 0xb23d34c1941d3ca, - 0x5976930b7502dd15, - 0x600f3fb517bf5495, - ])); - assert_eq!( - t, - FrRepr([ - 0x64b20e805c30a967, - 0x59a9ee9aa114a02, - 0x5871a104789020c9, - 0x8999707c5c726f65 - ]) - ); - - // Test for the associativity of addition. - for _ in 0..1000 { - let mut a = Fr::random(&mut rng).into_repr(); - let mut b = Fr::random(&mut rng).into_repr(); - let mut c = Fr::random(&mut rng).into_repr(); - - // Unset the first few bits, so that overflow won't occur. - a.0[3] >>= 3; - b.0[3] >>= 3; - c.0[3] >>= 3; - - let mut abc = a; - abc.add_nocarry(&b); - abc.add_nocarry(&c); - - let mut acb = a; - acb.add_nocarry(&c); - acb.add_nocarry(&b); - - let mut bac = b; - bac.add_nocarry(&a); - bac.add_nocarry(&c); - - let mut bca = b; - bca.add_nocarry(&c); - bca.add_nocarry(&a); - - let mut cab = c; - cab.add_nocarry(&a); - cab.add_nocarry(&b); - - let mut cba = c; - cba.add_nocarry(&b); - cba.add_nocarry(&a); - - assert_eq!(abc, acb); - assert_eq!(abc, bac); - assert_eq!(abc, bca); - assert_eq!(abc, cab); - assert_eq!(abc, cba); - } - - // Adding 1 to (2^256 - 1) should produce zero - let mut x = FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - ]); - x.add_nocarry(&FrRepr::from(1)); - assert!(x.is_zero()); -} - #[test] fn test_fr_is_valid() { - let mut a = Fr(MODULUS); + let mut a = MODULUS_LIMBS; assert!(!a.is_valid()); - a.0.sub_noborrow(&FrRepr::from(1)); + a.sub_noborrow(&Fr([1, 0, 0, 0])); assert!(a.is_valid()); assert!(Fr::from(0).is_valid()); - assert!(Fr(FrRepr([ + assert!(Fr([ 0xffffffff00000000, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48 - ])) + ]) .is_valid()); - assert!(!Fr(FrRepr([ + assert!(!Fr([ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff - ])) + ]) .is_valid()); let mut rng = XorShiftRng::from_seed([ @@ -399,85 +53,85 @@ fn test_fr_is_valid() { fn test_fr_add_assign() { { // Random number - let mut tmp = Fr(FrRepr([ + let mut tmp = Fr([ 0x437ce7616d580765, 0xd42d1ccb29d1235b, 0xed8f753821bd1423, 0x4eede1c9c89528ca, - ])); + ]); assert!(tmp.is_valid()); // Test that adding zero has no effect. - tmp.add_assign(&Fr(FrRepr::from(0))); + tmp.add_assign(&Fr([0, 0, 0, 0])); assert_eq!( tmp, - Fr(FrRepr([ + Fr([ 0x437ce7616d580765, 0xd42d1ccb29d1235b, 0xed8f753821bd1423, 0x4eede1c9c89528ca - ])) + ]) ); // Add one and test for the result. - tmp.add_assign(&Fr(FrRepr::from(1))); + tmp.add_assign(&Fr([1, 0, 0, 0])); assert_eq!( tmp, - Fr(FrRepr([ + Fr([ 0x437ce7616d580766, 0xd42d1ccb29d1235b, 0xed8f753821bd1423, 0x4eede1c9c89528ca - ])) + ]) ); // Add another random number that exercises the reduction. - tmp.add_assign(&Fr(FrRepr([ + tmp.add_assign(&Fr([ 0x946f435944f7dc79, 0xb55e7ee6533a9b9b, 0x1e43b84c2f6194ca, 0x58717ab525463496, - ]))); + ])); assert_eq!( tmp, - Fr(FrRepr([ + Fr([ 0xd7ec2abbb24fe3de, 0x35cdf7ae7d0d62f7, 0xd899557c477cd0e9, 0x3371b52bc43de018 - ])) + ]) ); // Add one to (r - 1) and test for the result. - tmp = Fr(FrRepr([ + tmp = Fr([ 0xffffffff00000000, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48, - ])); - tmp.add_assign(&Fr(FrRepr::from(1))); - assert!(tmp.0.is_zero()); + ]); + tmp.add_assign(&Fr([1, 0, 0, 0])); + assert!(tmp.is_zero()); // Add a random number to another one such that the result is r - 1 - tmp = Fr(FrRepr([ + tmp = Fr([ 0xade5adacdccb6190, 0xaa21ee0f27db3ccd, 0x2550f4704ae39086, 0x591d1902e7c5ba27, - ])); - tmp.add_assign(&Fr(FrRepr([ + ]); + tmp.add_assign(&Fr([ 0x521a525223349e70, 0xa99bb5f3d8231f31, 0xde8e397bebe477e, 0x1ad08e5041d7c321, - ]))); + ])); assert_eq!( tmp, - Fr(FrRepr([ + Fr([ 0xffffffff00000000, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48 - ])) + ]) ); // Add one to the result and test for it. - tmp.add_assign(&Fr(FrRepr::from(1))); - assert!(tmp.0.is_zero()); + tmp.add_assign(&Fr([1, 0, 0, 0])); + assert!(tmp.is_zero()); } // Test associativity @@ -511,71 +165,71 @@ fn test_fr_add_assign() { fn test_fr_sub_assign() { { // Test arbitrary subtraction that tests reduction. - let mut tmp = Fr(FrRepr([ + let mut tmp = Fr([ 0x6a68c64b6f735a2b, 0xd5f4d143fe0a1972, 0x37c17f3829267c62, 0xa2f37391f30915c, - ])); - tmp.sub_assign(&Fr(FrRepr([ + ]); + tmp.sub_assign(&Fr([ 0xade5adacdccb6190, 0xaa21ee0f27db3ccd, 0x2550f4704ae39086, 0x591d1902e7c5ba27, - ]))); + ])); assert_eq!( tmp, - Fr(FrRepr([ + Fr([ 0xbc83189d92a7f89c, 0x7f908737d62d38a3, 0x45aa62cfe7e4c3e1, 0x24ffc5896108547d - ])) + ]) ); // Test the opposite subtraction which doesn't test reduction. - tmp = Fr(FrRepr([ + tmp = Fr([ 0xade5adacdccb6190, 0xaa21ee0f27db3ccd, 0x2550f4704ae39086, 0x591d1902e7c5ba27, - ])); - tmp.sub_assign(&Fr(FrRepr([ + ]); + tmp.sub_assign(&Fr([ 0x6a68c64b6f735a2b, 0xd5f4d143fe0a1972, 0x37c17f3829267c62, 0xa2f37391f30915c, - ]))); + ])); assert_eq!( tmp, - Fr(FrRepr([ + Fr([ 0x437ce7616d580765, 0xd42d1ccb29d1235b, 0xed8f753821bd1423, 0x4eede1c9c89528ca - ])) + ]) ); // Test for sensible results with zero - tmp = Fr(FrRepr::from(0)); - tmp.sub_assign(&Fr(FrRepr::from(0))); + tmp = Fr::from(0); + tmp.sub_assign(&Fr::from(0)); assert!(tmp.is_zero()); - tmp = Fr(FrRepr([ + tmp = Fr([ 0x437ce7616d580765, 0xd42d1ccb29d1235b, 0xed8f753821bd1423, 0x4eede1c9c89528ca, - ])); - tmp.sub_assign(&Fr(FrRepr::from(0))); + ]); + tmp.sub_assign(&Fr::from(0)); assert_eq!( tmp, - Fr(FrRepr([ + Fr([ 0x437ce7616d580765, 0xd42d1ccb29d1235b, 0xed8f753821bd1423, 0x4eede1c9c89528ca - ])) + ]) ); } @@ -602,25 +256,25 @@ fn test_fr_sub_assign() { #[test] fn test_fr_mul_assign() { - let mut tmp = Fr(FrRepr([ + let mut tmp = Fr([ 0x6b7e9b8faeefc81a, 0xe30a8463f348ba42, 0xeff3cb67a8279c9c, 0x3d303651bd7c774d, - ])); - tmp.mul_assign(&Fr(FrRepr([ + ]); + tmp.mul_assign(&Fr([ 0x13ae28e3bc35ebeb, 0xa10f4488075cae2c, 0x8160e95a853c3b5d, 0x5ae3f03b561a841d, - ]))); + ])); assert!( - tmp == Fr(FrRepr([ + tmp == Fr([ 0x23717213ce710f71, 0xdbee1fe53a16e1af, 0xf565d3e1c2a48000, 0x4426507ee75df9d7 - ])) + ]) ); let mut rng = XorShiftRng::from_seed([ @@ -672,80 +326,73 @@ fn test_fr_mul_assign() { #[test] fn test_fr_shr() { let mut a = Fr::from_repr(FrRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x36003ab08de70da1, + 0x3f, 0x28, 0x2a, 0x48, 0xec, 0xba, 0x3f, 0xb3, 0xdf, 0xb3, 0x8c, 0xa8, 0xd3, 0xe0, 0x7d, + 0x99, 0x25, 0x55, 0x0e, 0x9a, 0x2a, 0x2d, 0xf6, 0x9a, 0xa1, 0x0d, 0xe7, 0x8d, 0xb0, 0x3a, + 0x00, 0x36, ])) .unwrap(); a = a >> 0; assert_eq!( a.into_repr(), FrRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x36003ab08de70da1, + 0x3f, 0x28, 0x2a, 0x48, 0xec, 0xba, 0x3f, 0xb3, 0xdf, 0xb3, 0x8c, 0xa8, 0xd3, 0xe0, + 0x7d, 0x99, 0x25, 0x55, 0x0e, 0x9a, 0x2a, 0x2d, 0xf6, 0x9a, 0xa1, 0x0d, 0xe7, 0x8d, + 0xb0, 0x3a, 0x00, 0x36, ]) ); a = a >> 1; assert_eq!( a.into_repr(), FrRepr([ - 0xd99fdd762415141f, - 0xccbef069d44659ef, - 0xcd7b16954d072a92, - 0x1b001d5846f386d0, + 0x1f, 0x14, 0x15, 0x24, 0x76, 0xdd, 0x9f, 0xd9, 0xef, 0x59, 0x46, 0xd4, 0x69, 0xf0, + 0xbe, 0xcc, 0x92, 0x2a, 0x07, 0x4d, 0x95, 0x16, 0x7b, 0xcd, 0xd0, 0x86, 0xf3, 0x46, + 0x58, 0x1d, 0x00, 0x1b, ]) ); a = a >> 50; assert_eq!( a.into_repr(), FrRepr([ - 0xbc1a7511967bf667, - 0xc5a55341caa4b32f, - 0x075611bce1b4335e, - 0x00000000000006c0, + 0x67, 0xf6, 0x7b, 0x96, 0x11, 0x75, 0x1a, 0xbc, 0x2f, 0xb3, 0xa4, 0xca, 0x41, 0x53, + 0xa5, 0xc5, 0x5e, 0x33, 0xb4, 0xe1, 0xbc, 0x11, 0x56, 0x07, 0xc0, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ]) ); a = a >> 130; assert_eq!( a.into_repr(), FrRepr([ - 0x01d5846f386d0cd7, - 0x00000000000001b0, - 0x0000000000000000, - 0x0000000000000000, + 0xd7, 0x0c, 0x6d, 0x38, 0x6f, 0x84, 0xd5, 0x01, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ]) ); a = a >> 64; assert_eq!( a.into_repr(), FrRepr([ - 0x00000000000001b0, - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000000, + 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ]) ); } #[test] fn test_fr_squaring() { - let a = Fr(FrRepr([ + let a = Fr([ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x73eda753299d7d47, - ])); + ]); assert!(a.is_valid()); assert_eq!( a.square(), Fr::from_repr(FrRepr([ - 0xc0d698e7bde077b8, - 0xb79a310579e76ec2, - 0xac1da8d0a9af4e5f, - 0x13f629c49bf23e97 + 0xb8, 0x77, 0xe0, 0xbd, 0xe7, 0x98, 0xd6, 0xc0, 0xc2, 0x6e, 0xe7, 0x79, 0x05, 0x31, + 0x9a, 0xb7, 0x5f, 0x4e, 0xaf, 0xa9, 0xd0, 0xa8, 0x1d, 0xac, 0x97, 0x3e, 0xf2, 0x9b, + 0xc4, 0x29, 0xf6, 0x13, ])) .unwrap() ); @@ -883,42 +530,38 @@ fn test_fr_sqrt() { fn test_fr_from_into_repr() { // r + 1 should not be in the field assert!(Fr::from_repr(FrRepr([ - 0xffffffff00000002, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48 + 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0x02, 0xa4, 0xbd, + 0x53, 0x05, 0xd8, 0xa1, 0x09, 0x08, 0xd8, 0x39, 0x33, 0x48, 0x7d, 0x9d, 0x29, 0x53, 0xa7, + 0xed, 0x73, ])) - .is_err()); + .is_none()); // r should not be in the field - assert!(Fr::from_repr(Fr::char()).is_err()); + assert!(Fr::from_repr(Fr::char()).is_none()); // Multiply some arbitrary representations to see if the result is as expected. let a = FrRepr([ - 0x25ebe3a3ad3c0c6a, - 0x6990e39d092e817c, - 0x941f900d42f5658e, - 0x44f8a103b38a71e0, + 0x6a, 0x0c, 0x3c, 0xad, 0xa3, 0xe3, 0xeb, 0x25, 0x7c, 0x81, 0x2e, 0x09, 0x9d, 0xe3, 0x90, + 0x69, 0x8e, 0x65, 0xf5, 0x42, 0x0d, 0x90, 0x1f, 0x94, 0xe0, 0x71, 0x8a, 0xb3, 0x03, 0xa1, + 0xf8, 0x44, ]); let mut a_fr = Fr::from_repr(a).unwrap(); let b = FrRepr([ - 0x264e9454885e2475, - 0x46f7746bb0308370, - 0x4683ef5347411f9, - 0x58838d7f208d4492, + 0x75, 0x24, 0x5e, 0x88, 0x54, 0x94, 0x4e, 0x26, 0x70, 0x83, 0x30, 0xb0, 0x6b, 0x74, 0xf7, + 0x46, 0xf9, 0x11, 0x74, 0x34, 0xf5, 0x3e, 0x68, 0x04, 0x92, 0x44, 0x8d, 0x20, 0x7f, 0x8d, + 0x83, 0x58, ]); let b_fr = Fr::from_repr(b).unwrap(); let c = FrRepr([ - 0x48a09ab93cfc740d, - 0x3a6600fbfc7a671, - 0x838567017501d767, - 0x7161d6da77745512, + 0x0d, 0x74, 0xfc, 0x3c, 0xb9, 0x9a, 0xa0, 0x48, 0x71, 0xa6, 0xc7, 0xbf, 0x0f, 0x60, 0xa6, + 0x03, 0x67, 0xd7, 0x01, 0x75, 0x01, 0x67, 0x85, 0x83, 0x12, 0x55, 0x74, 0x77, 0xda, 0xd6, + 0x61, 0x71, ]); a_fr.mul_assign(&b_fr); assert_eq!(a_fr.into_repr(), c); // Zero should be in the field. - assert!(Fr::from_repr(FrRepr::from(0)).unwrap().is_zero()); + assert!(Fr::from_repr(FrRepr([0; 32])).unwrap().is_zero()); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -937,60 +580,15 @@ fn test_fr_from_into_repr() { } } -#[test] -fn test_fr_repr_display() { - assert_eq!( - format!( - "{}", - FrRepr([ - 0x2829c242fa826143, - 0x1f32cf4dd4330917, - 0x932e4e479d168cd9, - 0x513c77587f563f64 - ]) - ), - "0x513c77587f563f64932e4e479d168cd91f32cf4dd43309172829c242fa826143".to_string() - ); - assert_eq!( - format!( - "{}", - FrRepr([ - 0x25ebe3a3ad3c0c6a, - 0x6990e39d092e817c, - 0x941f900d42f5658e, - 0x44f8a103b38a71e0 - ]) - ), - "0x44f8a103b38a71e0941f900d42f5658e6990e39d092e817c25ebe3a3ad3c0c6a".to_string() - ); - assert_eq!( - format!( - "{}", - FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ]) - ), - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() - ); - assert_eq!( - format!("{}", FrRepr([0, 0, 0, 0])), - "0x0000000000000000000000000000000000000000000000000000000000000000".to_string() - ); -} - #[test] fn test_fr_display() { assert_eq!( format!( "{}", Fr::from_repr(FrRepr([ - 0xc3cae746a3b5ecc7, - 0x185ec8eb3f5b5aee, - 0x684499ffe4b9dd99, - 0x7c9bba7afb68faa + 0xc7, 0xec, 0xb5, 0xa3, 0x46, 0xe7, 0xca, 0xc3, 0xee, 0x5a, 0x5b, 0x3f, 0xeb, 0xc8, + 0x5e, 0x18, 0x99, 0xdd, 0xb9, 0xe4, 0xff, 0x99, 0x44, 0x68, 0xaa, 0x8f, 0xb6, 0xaf, + 0xa7, 0xbb, 0xc9, 0x07, ])) .unwrap() ), @@ -1000,10 +598,9 @@ fn test_fr_display() { format!( "{}", Fr::from_repr(FrRepr([ - 0x44c71298ff198106, - 0xb0ad10817df79b6a, - 0xd034a80a2b74132b, - 0x41cf9a1336f50719 + 0x06, 0x81, 0x19, 0xff, 0x98, 0x12, 0xc7, 0x44, 0x6a, 0x9b, 0xf7, 0x7d, 0x81, 0x10, + 0xad, 0xb0, 0x2b, 0x13, 0x74, 0x2b, 0x0a, 0xa8, 0x34, 0xd0, 0x19, 0x07, 0xf5, 0x36, + 0x13, 0x9a, 0xcf, 0x41, ])) .unwrap() ), diff --git a/pairing/src/bls12_381/tests/mod.rs b/pairing/src/bls12_381/tests/mod.rs index f79961cdb..6d9252e83 100644 --- a/pairing/src/bls12_381/tests/mod.rs +++ b/pairing/src/bls12_381/tests/mod.rs @@ -1,4 +1,4 @@ -use ff::PrimeFieldRepr; +use ff::PrimeField; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use super::*; @@ -147,13 +147,15 @@ fn test_g1_uncompressed_invalid_vectors() { } } - let m = Fq::char(); + // PrimeField::char() returns the modulus in its little-endian byte representation, + // but Fq field elements use big-endian encoding, so flip the endianness. + let m: Vec<_> = Fq::char().as_ref().iter().cloned().rev().collect(); { let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut()[..48].copy_from_slice(&m[..]); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { assert_eq!(coordinate, "x coordinate"); } else { panic!("should have rejected the point") @@ -162,9 +164,9 @@ fn test_g1_uncompressed_invalid_vectors() { { let mut o = o; - m.write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[48..].copy_from_slice(&m[..]); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { assert_eq!(coordinate, "y coordinate"); } else { panic!("should have rejected the point") @@ -175,7 +177,7 @@ fn test_g1_uncompressed_invalid_vectors() { let m = Fq::zero().into_repr(); let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut()[..48].copy_from_slice(m.as_ref()); if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { // :) @@ -198,8 +200,8 @@ fn test_g1_uncompressed_invalid_vectors() { let y = y.unwrap(); // We know this is on the curve, but it's likely not going to be in the correct subgroup. - x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - y.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[..48].copy_from_slice(x.into_repr().as_ref()); + o.as_mut()[48..].copy_from_slice(y.into_repr().as_ref()); if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { break; @@ -263,13 +265,15 @@ fn test_g2_uncompressed_invalid_vectors() { } } - let m = Fq::char(); + // PrimeField::char() returns the modulus in its little-endian byte representation, + // but Fq field elements use big-endian encoding, so flip the endianness. + let m: Vec<_> = Fq::char().as_ref().iter().cloned().rev().collect(); { let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut()[..48].copy_from_slice(&m[..]); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { assert_eq!(coordinate, "x coordinate (c1)"); } else { panic!("should have rejected the point") @@ -278,9 +282,9 @@ fn test_g2_uncompressed_invalid_vectors() { { let mut o = o; - m.write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[48..96].copy_from_slice(&m[..]); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { assert_eq!(coordinate, "x coordinate (c0)"); } else { panic!("should have rejected the point") @@ -289,9 +293,9 @@ fn test_g2_uncompressed_invalid_vectors() { { let mut o = o; - m.write_be(&mut o.as_mut()[96..]).unwrap(); + o.as_mut()[96..144].copy_from_slice(&m[..]); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { assert_eq!(coordinate, "y coordinate (c1)"); } else { panic!("should have rejected the point") @@ -300,9 +304,9 @@ fn test_g2_uncompressed_invalid_vectors() { { let mut o = o; - m.write_be(&mut o.as_mut()[144..]).unwrap(); + o.as_mut()[144..].copy_from_slice(&m[..]); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { assert_eq!(coordinate, "y coordinate (c0)"); } else { panic!("should have rejected the point") @@ -313,8 +317,8 @@ fn test_g2_uncompressed_invalid_vectors() { let m = Fq::zero().into_repr(); let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); - m.write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[..48].copy_from_slice(m.as_ref()); + o.as_mut()[48..96].copy_from_slice(m.as_ref()); if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { // :) @@ -340,10 +344,10 @@ fn test_g2_uncompressed_invalid_vectors() { let y = y.unwrap(); // We know this is on the curve, but it's likely not going to be in the correct subgroup. - x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); - y.c1.into_repr().write_be(&mut o.as_mut()[96..]).unwrap(); - y.c0.into_repr().write_be(&mut o.as_mut()[144..]).unwrap(); + o.as_mut()[..48].copy_from_slice(x.c1.into_repr().as_ref()); + o.as_mut()[48..96].copy_from_slice(x.c0.into_repr().as_ref()); + o.as_mut()[96..144].copy_from_slice(y.c1.into_repr().as_ref()); + o.as_mut()[144..].copy_from_slice(y.c0.into_repr().as_ref()); if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { break; @@ -407,14 +411,16 @@ fn test_g1_compressed_invalid_vectors() { } } - let m = Fq::char(); + // PrimeField::char() returns the modulus in its little-endian byte representation, + // but Fq field elements use big-endian encoding, so flip the endianness. + let m: Vec<_> = Fq::char().as_ref().iter().cloned().rev().collect(); { let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut()[..48].copy_from_slice(&m[..]); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { assert_eq!(coordinate, "x coordinate"); } else { panic!("should have rejected the point") @@ -433,7 +439,7 @@ fn test_g1_compressed_invalid_vectors() { if x3b.sqrt().is_some().into() { x.add_assign(&Fq::one()); } else { - x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut().copy_from_slice(x.into_repr().as_ref()); o.as_mut()[0] |= 0b1000_0000; if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { @@ -456,7 +462,7 @@ fn test_g1_compressed_invalid_vectors() { if x3b.sqrt().is_some().into() { // We know this is on the curve, but it's likely not going to be in the correct subgroup. - x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut().copy_from_slice(x.into_repr().as_ref()); o.as_mut()[0] |= 0b1000_0000; if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { @@ -521,14 +527,16 @@ fn test_g2_compressed_invalid_vectors() { } } - let m = Fq::char(); + // PrimeField::char() returns the modulus in its little-endian byte representation, + // but Fq field elements use big-endian encoding, so flip the endianness. + let m: Vec<_> = Fq::char().as_ref().iter().cloned().rev().collect(); { let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut()[..48].copy_from_slice(&m[..]); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { assert_eq!(coordinate, "x coordinate (c1)"); } else { panic!("should have rejected the point") @@ -537,10 +545,10 @@ fn test_g2_compressed_invalid_vectors() { { let mut o = o; - m.write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[48..96].copy_from_slice(&m[..]); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { assert_eq!(coordinate, "x coordinate (c0)"); } else { panic!("should have rejected the point") @@ -565,8 +573,8 @@ fn test_g2_compressed_invalid_vectors() { if x3b.sqrt().is_some().into() { x.add_assign(&Fq2::one()); } else { - x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[..48].copy_from_slice(x.c1.into_repr().as_ref()); + o.as_mut()[48..].copy_from_slice(x.c0.into_repr().as_ref()); o.as_mut()[0] |= 0b1000_0000; if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { @@ -595,8 +603,8 @@ fn test_g2_compressed_invalid_vectors() { if x3b.sqrt().is_some().into() { // We know this is on the curve, but it's likely not going to be in the correct subgroup. - x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[..48].copy_from_slice(x.c1.into_repr().as_ref()); + o.as_mut()[48..].copy_from_slice(x.c0.into_repr().as_ref()); o.as_mut()[0] |= 0b1000_0000; if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs index 64242322e..0288987ee 100644 --- a/pairing/src/tests/field.rs +++ b/pairing/src/tests/field.rs @@ -2,7 +2,7 @@ use ff::{Field, PowVartime, PrimeField, SqrtField}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; -pub fn random_frobenius_tests>(characteristic: C, maxpower: usize) { +pub fn random_frobenius_tests>(characteristic: C, maxpower: usize) { 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/pairing/src/tests/repr.rs b/pairing/src/tests/repr.rs index cde3ab3bc..7bc44e9ea 100644 --- a/pairing/src/tests/repr.rs +++ b/pairing/src/tests/repr.rs @@ -1,10 +1,9 @@ -use ff::{PrimeField, PrimeFieldRepr}; +use ff::PrimeField; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; pub fn random_repr_tests() { random_encoding_tests::

(); - random_shl_tests::

(); random_shr_tests::

(); } @@ -15,71 +14,12 @@ fn random_encoding_tests() { ]); for _ in 0..1000 { - let r = P::random(&mut rng).into_repr(); + let r = P::random(&mut rng); - // Big endian - { - let mut rdecoded =

::Repr::default(); + let v = r.into_repr(); + let rdecoded = P::from_repr(v).unwrap(); - let mut v: Vec = vec![]; - r.write_be(&mut v).unwrap(); - rdecoded.read_be(&v[0..]).unwrap(); - - assert_eq!(r, rdecoded); - } - - // Little endian - { - let mut rdecoded =

::Repr::default(); - - let mut v: Vec = vec![]; - r.write_le(&mut v).unwrap(); - rdecoded.read_le(&v[0..]).unwrap(); - - assert_eq!(r, rdecoded); - } - - { - let mut rdecoded_le =

::Repr::default(); - let mut rdecoded_be_flip =

::Repr::default(); - - let mut v: Vec = vec![]; - r.write_le(&mut v).unwrap(); - - // This reads in little-endian, so we are done. - rdecoded_le.read_le(&v[..]).unwrap(); - - // This reads in big-endian, so we perform a swap of the - // bytes beforehand. - let v: Vec = v.into_iter().rev().collect(); - rdecoded_be_flip.read_be(&v[..]).unwrap(); - - assert_eq!(rdecoded_le, rdecoded_be_flip); - } - } -} - -fn random_shl_tests() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..100 { - let r = P::random(&mut rng).into_repr(); - - for shift in 0..=r.num_bits() { - let mut r1 = r; - let mut r2 = r; - - for _ in 0..shift { - r1.mul2(); - } - - r2.shl(shift); - - assert_eq!(r1, r2); - } + assert_eq!(r, rdecoded); } } @@ -90,19 +30,22 @@ fn random_shr_tests() { ]); for _ in 0..100 { - let r = P::random(&mut rng).into_repr(); + let r = P::random(&mut rng); - for shift in 0..=r.num_bits() { - let mut r1 = r; - let mut r2 = r; + for shift in 0..P::NUM_BITS { + let r1 = r >> shift; + // Doubling the shifted element inserts zeros on the right; re-shifting should + // undo the doubling. + let mut r2 = r1; for _ in 0..shift { - r1.div2(); + r2 = r2.double(); } - - r2.shr(shift); + r2 = r2 >> shift; assert_eq!(r1, r2); } + + assert_eq!(r >> P::NUM_BITS, P::zero()); } } diff --git a/zcash_client_backend/src/proto/mod.rs b/zcash_client_backend/src/proto/mod.rs index 0ab1b6d51..0872fbb8d 100644 --- a/zcash_client_backend/src/proto/mod.rs +++ b/zcash_client_backend/src/proto/mod.rs @@ -1,6 +1,6 @@ //! Generated code for handling light client protobuf structs. -use ff::{PrimeField, PrimeFieldRepr}; +use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use zcash_primitives::{ block::{BlockHash, BlockHeader}, @@ -67,8 +67,8 @@ impl compact_formats::CompactOutput { /// [`CompactOutput.cmu`]: #structfield.cmu pub fn cmu(&self) -> Result { let mut repr = FrRepr::default(); - repr.read_le(&self.cmu[..]).map_err(|_| ())?; - Fr::from_repr(repr).map_err(|_| ()) + repr.as_mut().copy_from_slice(&self.cmu[..]); + Fr::from_repr(repr).ok_or(()) } /// Returns the ephemeral public key for this output. diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 14939d763..d1f9bcd4d 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -183,7 +183,7 @@ pub fn scan_block( #[cfg(test)] mod tests { - use ff::{Field, PrimeField, PrimeFieldRepr}; + use ff::{Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{OsRng, RngCore}; use zcash_primitives::{ @@ -207,9 +207,7 @@ mod tests { }; let fake_cmu = { let fake_cmu = Fr::random(rng); - let mut bytes = vec![]; - fake_cmu.into_repr().write_le(&mut bytes).unwrap(); - bytes + fake_cmu.into_repr().as_ref().to_owned() }; let fake_epk = { let mut buffer = vec![0; 64]; @@ -264,8 +262,7 @@ mod tests { Memo::default(), &mut rng, ); - let mut cmu = vec![]; - note.cm(&JUBJUB).into_repr().write_le(&mut cmu).unwrap(); + let cmu = note.cm(&JUBJUB).into_repr().as_ref().to_owned(); let mut epk = vec![]; encryptor.epk().write(&mut epk).unwrap(); let enc_ciphertext = encryptor.encrypt_note_plaintext(); diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index cbe4d0be0..965b8d86d 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -1,4 +1,4 @@ -use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; +use ff::{BitIterator, Field, PrimeField, SqrtField}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use subtle::CtOption; @@ -83,15 +83,15 @@ impl PartialEq for Point { } impl Point { - pub fn read(reader: R, params: &E::Params) -> io::Result { + pub fn read(mut reader: R, params: &E::Params) -> io::Result { let mut y_repr = ::Repr::default(); - y_repr.read_le(reader)?; + reader.read_exact(y_repr.as_mut())?; - let x_sign = (y_repr.as_ref()[3] >> 63) == 1; - y_repr.as_mut()[3] &= 0x7fffffffffffffff; + let x_sign = (y_repr.as_ref()[31] >> 7) == 1; + y_repr.as_mut()[31] &= 0x7f; match E::Fr::from_repr(y_repr) { - Ok(y) => { + Some(y) => { let p = Self::get_for_y(y, x_sign, params); if bool::from(p.is_some()) { Ok(p.unwrap()) @@ -99,7 +99,7 @@ impl Point { Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")) } } - Err(_) => Err(io::Error::new( + None => Err(io::Error::new( io::ErrorKind::InvalidInput, "y is not in field", )), @@ -167,17 +167,17 @@ impl Point { } impl Point { - pub fn write(&self, writer: W) -> io::Result<()> { + pub fn write(&self, mut writer: W) -> io::Result<()> { let (x, y) = self.to_xy(); assert_eq!(E::Fr::NUM_BITS, 255); let mut y_repr = y.into_repr(); if x.is_odd() { - y_repr.as_mut()[3] |= 0x8000000000000000u64; + y_repr.as_mut()[31] |= 0x80; } - y_repr.write_le(writer) + writer.write_all(y_repr.as_ref()) } /// Convert from a Montgomery point @@ -467,7 +467,7 @@ impl Point { let mut res = Self::zero(); - for b in BitIterator::::new(scalar.into()) { + for b in BitIterator::::new(scalar.into()) { res = res.double(params); if b { diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index 85c3df4ce..5e109d8d5 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -1,7 +1,5 @@ -use ff::{ - adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, PrimeFieldDecodingError, - PrimeFieldRepr, SqrtField, -}; +use byteorder::{ByteOrder, LittleEndian}; +use ff::{adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, SqrtField}; use rand_core::RngCore; use std::mem; use std::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign}; @@ -11,6 +9,11 @@ use super::ToUniform; // s = 6554484396890773809930967563523245729705921265872317281365359162392183254199 const MODULUS: FsRepr = FsRepr([ + 0xb7, 0x2c, 0xf7, 0xd6, 0x5e, 0x0e, 0x97, 0xd0, 0x82, 0x10, 0xc8, 0xcc, 0x93, 0x20, 0x68, 0xa6, + 0x00, 0x3b, 0x34, 0x01, 0x01, 0x3b, 0x67, 0x06, 0xa9, 0xaf, 0x33, 0x65, 0xea, 0xb4, 0x7d, 0x0e, +]); + +const MODULUS_LIMBS: Fs = Fs([ 0xd0970e5ed6f72cb7, 0xa6682093ccc81082, 0x6673b0101343b00, @@ -25,7 +28,7 @@ const MODULUS_BITS: u32 = 252; const REPR_SHAVE_BITS: u32 = 4; // R = 2**256 % s -const R: FsRepr = FsRepr([ +const R: Fs = Fs([ 0x25f80bb3b99607d9, 0xf315d62f66b6e750, 0x932514eeeb8814f4, @@ -33,7 +36,7 @@ const R: FsRepr = FsRepr([ ]); // R2 = R^2 % s -const R2: FsRepr = FsRepr([ +const R2: Fs = Fs([ 0x67719aa495e57731, 0x51b0cef09ce3fc26, 0x69dab7fac026e9a5, @@ -44,7 +47,7 @@ const R2: FsRepr = FsRepr([ const INV: u64 = 0x1ba3a358ef788ef9; // GENERATOR = 6 (multiplicative generator of r-1 order, that is also quadratic nonresidue) -const GENERATOR: FsRepr = FsRepr([ +const GENERATOR: Fs = Fs([ 0x720b1b19d49ea8f1, 0xbf4aa36101f13a58, 0x5fa8cc968193ccbb, @@ -55,7 +58,7 @@ const GENERATOR: FsRepr = FsRepr([ const S: u32 = 1; // 2^S root of unity computed by GENERATOR^t -const ROOT_OF_UNITY: FsRepr = FsRepr([ +const ROOT_OF_UNITY: Fs = Fs([ 0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, @@ -63,199 +66,45 @@ const ROOT_OF_UNITY: FsRepr = FsRepr([ ]); // -((2**256) mod s) mod s -const NEGATIVE_ONE: Fs = Fs(FsRepr([ +const NEGATIVE_ONE: Fs = Fs([ 0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, 0x4d6b87b1da259e2, -])); +]); /// This is the underlying representation of an element of `Fs`. #[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] -pub struct FsRepr(pub [u64; 4]); +pub struct FsRepr(pub [u8; 32]); impl ::std::fmt::Display for FsRepr { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "0x")?; for i in self.0.iter().rev() { - write!(f, "{:016x}", *i)?; + write!(f, "{:02x}", *i)?; } Ok(()) } } -impl AsRef<[u64]> for FsRepr { +impl AsRef<[u8]> for FsRepr { #[inline(always)] - fn as_ref(&self) -> &[u64] { + fn as_ref(&self) -> &[u8] { &self.0 } } -impl AsMut<[u64]> for FsRepr { +impl AsMut<[u8]> for FsRepr { #[inline(always)] - fn as_mut(&mut self) -> &mut [u64] { + fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } } -impl From for FsRepr { - #[inline(always)] - fn from(val: u64) -> FsRepr { - let mut repr = Self::default(); - repr.0[0] = val; - repr - } -} - -impl Ord for FsRepr { - #[inline(always)] - fn cmp(&self, other: &FsRepr) -> ::std::cmp::Ordering { - for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { - if a < b { - return ::std::cmp::Ordering::Less; - } else if a > b { - return ::std::cmp::Ordering::Greater; - } - } - - ::std::cmp::Ordering::Equal - } -} - -impl PartialOrd for FsRepr { - #[inline(always)] - fn partial_cmp(&self, other: &FsRepr) -> Option<::std::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl PrimeFieldRepr for FsRepr { - #[inline(always)] - fn is_odd(&self) -> bool { - self.0[0] & 1 == 1 - } - - #[inline(always)] - fn is_even(&self) -> bool { - !self.is_odd() - } - - #[inline(always)] - fn is_zero(&self) -> bool { - self.0.iter().all(|&e| e == 0) - } - - #[inline(always)] - fn shr(&mut self, mut n: u32) { - if n >= 64 * 4 { - *self = Self::from(0); - return; - } - - while n >= 64 { - let mut t = 0; - for i in self.0.iter_mut().rev() { - ::std::mem::swap(&mut t, i); - } - n -= 64; - } - - if n > 0 { - let mut t = 0; - for i in self.0.iter_mut().rev() { - let t2 = *i << (64 - n); - *i >>= n; - *i |= t; - t = t2; - } - } - } - - #[inline(always)] - fn div2(&mut self) { - let mut t = 0; - for i in self.0.iter_mut().rev() { - let t2 = *i << 63; - *i >>= 1; - *i |= t; - t = t2; - } - } - - #[inline(always)] - fn mul2(&mut self) { - let mut last = 0; - for i in &mut self.0 { - let tmp = *i >> 63; - *i <<= 1; - *i |= last; - last = tmp; - } - } - - #[inline(always)] - fn shl(&mut self, mut n: u32) { - if n >= 64 * 4 { - *self = Self::from(0); - return; - } - - while n >= 64 { - let mut t = 0; - for i in &mut self.0 { - ::std::mem::swap(&mut t, i); - } - n -= 64; - } - - if n > 0 { - let mut t = 0; - for i in &mut self.0 { - let t2 = *i >> (64 - n); - *i <<= n; - *i |= t; - t = t2; - } - } - } - - #[inline(always)] - fn num_bits(&self) -> u32 { - let mut ret = (4 as u32) * 64; - for i in self.0.iter().rev() { - let leading = i.leading_zeros(); - ret -= leading; - if leading != 64 { - break; - } - } - - ret - } - - #[inline(always)] - fn add_nocarry(&mut self, other: &FsRepr) { - let mut carry = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = adc(*a, *b, &mut carry); - } - } - - #[inline(always)] - fn sub_noborrow(&mut self, other: &FsRepr) { - let mut borrow = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = sbb(*a, *b, &mut borrow); - } - } -} - /// This is an element of the scalar field of the Jubjub curve. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Fs(FsRepr); +pub struct Fs([u64; 4]); impl Default for Fs { fn default() -> Self { @@ -265,17 +114,23 @@ impl Default for Fs { impl ConstantTimeEq for Fs { fn ct_eq(&self, other: &Fs) -> Choice { - (self.0).0[0].ct_eq(&(other.0).0[0]) - & (self.0).0[1].ct_eq(&(other.0).0[1]) - & (self.0).0[2].ct_eq(&(other.0).0[2]) - & (self.0).0[3].ct_eq(&(other.0).0[3]) + self.0[0].ct_eq(&other.0[0]) + & self.0[1].ct_eq(&other.0[1]) + & self.0[2].ct_eq(&other.0[2]) + & self.0[3].ct_eq(&other.0[3]) } } impl Ord for Fs { #[inline(always)] fn cmp(&self, other: &Fs) -> ::std::cmp::Ordering { - self.into_repr().cmp(&other.into_repr()) + let mut a = *self; + a.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); + + let mut b = *other; + b.mont_reduce(other.0[0], other.0[1], other.0[2], other.0[3], 0, 0, 0, 0); + + a.cmp_native(&b) } } @@ -297,7 +152,7 @@ impl From for Fs { fn from(val: u64) -> Fs { let mut raw = [0u64; 4]; raw[0] = val; - Fs(FsRepr(raw)) * Fs(R2) + Fs(raw) * R2 } } @@ -307,14 +162,20 @@ impl From for FsRepr { } } +impl<'a> From<&'a Fs> for FsRepr { + fn from(e: &'a Fs) -> FsRepr { + e.into_repr() + } +} + impl ConditionallySelectable for Fs { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fs(FsRepr([ - u64::conditional_select(&(a.0).0[0], &(b.0).0[0], choice), - u64::conditional_select(&(a.0).0[1], &(b.0).0[1], choice), - u64::conditional_select(&(a.0).0[2], &(b.0).0[2], choice), - u64::conditional_select(&(a.0).0[3], &(b.0).0[3], choice), - ])) + Fs([ + u64::conditional_select(&a.0[0], &b.0[0], choice), + u64::conditional_select(&a.0[1], &b.0[1], choice), + u64::conditional_select(&a.0[2], &b.0[2], choice), + u64::conditional_select(&a.0[3], &b.0[3], choice), + ]) } } @@ -324,9 +185,9 @@ impl Neg for Fs { #[inline] fn neg(mut self) -> Self { if !self.is_zero() { - let mut tmp = MODULUS; - tmp.sub_noborrow(&self.0); - self.0 = tmp; + let mut tmp = MODULUS_LIMBS; + tmp.sub_noborrow(&self); + self = tmp; } self } @@ -356,7 +217,7 @@ impl<'r> AddAssign<&'r Fs> for Fs { #[inline] fn add_assign(&mut self, other: &Self) { // This cannot exceed the backing capacity. - self.0.add_nocarry(&other.0); + self.add_nocarry(&other); // However, it may need to be reduced. self.reduce(); @@ -394,11 +255,11 @@ impl<'r> SubAssign<&'r Fs> for Fs { #[inline] fn sub_assign(&mut self, other: &Self) { // If `other` is larger than `self`, we'll need to add the modulus to self first. - if other.0 > self.0 { - self.0.add_nocarry(&MODULUS); + if other.cmp_native(self) == ::core::cmp::Ordering::Greater { + self.add_nocarry(&MODULUS_LIMBS); } - self.0.sub_noborrow(&other.0); + self.sub_noborrow(&other); } } @@ -433,28 +294,28 @@ impl<'r> MulAssign<&'r Fs> for Fs { #[inline] fn mul_assign(&mut self, other: &Self) { let mut carry = 0; - let r0 = mac_with_carry(0, (self.0).0[0], (other.0).0[0], &mut carry); - let r1 = mac_with_carry(0, (self.0).0[0], (other.0).0[1], &mut carry); - let r2 = mac_with_carry(0, (self.0).0[0], (other.0).0[2], &mut carry); - let r3 = mac_with_carry(0, (self.0).0[0], (other.0).0[3], &mut carry); + let r0 = mac_with_carry(0, self.0[0], other.0[0], &mut carry); + let r1 = mac_with_carry(0, self.0[0], other.0[1], &mut carry); + let r2 = mac_with_carry(0, self.0[0], other.0[2], &mut carry); + let r3 = mac_with_carry(0, self.0[0], other.0[3], &mut carry); let r4 = carry; let mut carry = 0; - let r1 = mac_with_carry(r1, (self.0).0[1], (other.0).0[0], &mut carry); - let r2 = mac_with_carry(r2, (self.0).0[1], (other.0).0[1], &mut carry); - let r3 = mac_with_carry(r3, (self.0).0[1], (other.0).0[2], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[1], (other.0).0[3], &mut carry); + let r1 = mac_with_carry(r1, self.0[1], other.0[0], &mut carry); + let r2 = mac_with_carry(r2, self.0[1], other.0[1], &mut carry); + let r3 = mac_with_carry(r3, self.0[1], other.0[2], &mut carry); + let r4 = mac_with_carry(r4, self.0[1], other.0[3], &mut carry); let r5 = carry; let mut carry = 0; - let r2 = mac_with_carry(r2, (self.0).0[2], (other.0).0[0], &mut carry); - let r3 = mac_with_carry(r3, (self.0).0[2], (other.0).0[1], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[2], (other.0).0[2], &mut carry); - let r5 = mac_with_carry(r5, (self.0).0[2], (other.0).0[3], &mut carry); + let r2 = mac_with_carry(r2, self.0[2], other.0[0], &mut carry); + let r3 = mac_with_carry(r3, self.0[2], other.0[1], &mut carry); + let r4 = mac_with_carry(r4, self.0[2], other.0[2], &mut carry); + let r5 = mac_with_carry(r5, self.0[2], other.0[3], &mut carry); let r6 = carry; let mut carry = 0; - let r3 = mac_with_carry(r3, (self.0).0[3], (other.0).0[0], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[3], (other.0).0[1], &mut carry); - let r5 = mac_with_carry(r5, (self.0).0[3], (other.0).0[2], &mut carry); - let r6 = mac_with_carry(r6, (self.0).0[3], (other.0).0[3], &mut carry); + let r3 = mac_with_carry(r3, self.0[3], other.0[0], &mut carry); + let r4 = mac_with_carry(r4, self.0[3], other.0[1], &mut carry); + let r5 = mac_with_carry(r5, self.0[3], other.0[2], &mut carry); + let r6 = mac_with_carry(r6, self.0[3], other.0[3], &mut carry); let r7 = carry; self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7); } @@ -472,17 +333,8 @@ impl BitAnd for Fs { #[inline(always)] fn bitand(mut self, rhs: u64) -> u64 { - self.mont_reduce( - (self.0).0[0], - (self.0).0[1], - (self.0).0[2], - (self.0).0[3], - 0, - 0, - 0, - 0, - ); - (self.0).0[0] & rhs + self.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); + self.0[0] & rhs } } @@ -496,20 +348,11 @@ impl Shr for Fs { } // Convert from Montgomery to native representation. - self.mont_reduce( - (self.0).0[0], - (self.0).0[1], - (self.0).0[2], - (self.0).0[3], - 0, - 0, - 0, - 0, - ); + self.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); while n >= 64 { let mut t = 0; - for i in (self.0).0.iter_mut().rev() { + for i in self.0.iter_mut().rev() { mem::swap(&mut t, i); } n -= 64; @@ -517,7 +360,7 @@ impl Shr for Fs { if n > 0 { let mut t = 0; - for i in (self.0).0.iter_mut().rev() { + for i in self.0.iter_mut().rev() { let t2 = *i << (64 - n); *i >>= n; *i |= t; @@ -526,42 +369,42 @@ impl Shr for Fs { } // Convert back to Montgomery representation - self * Fs(R2) + self * R2 } } impl PrimeField for Fs { type Repr = FsRepr; - fn from_repr(r: FsRepr) -> Result { - let mut r = Fs(r); - if r.is_valid() { - r.mul_assign(&Fs(R2)); + fn from_repr(r: FsRepr) -> Option { + let r = { + let mut inner = [0; 4]; + LittleEndian::read_u64_into(r.as_ref(), &mut inner[..]); + Fs(inner) + }; - Ok(r) + if r.is_valid() { + Some(r * &R2) } else { - Err(PrimeFieldDecodingError::NotInField) + None } } fn into_repr(&self) -> FsRepr { let mut r = *self; - r.mont_reduce( - (self.0).0[0], - (self.0).0[1], - (self.0).0[2], - (self.0).0[3], - 0, - 0, - 0, - 0, - ); - r.0 + r.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); + + let mut repr = [0; 32]; + LittleEndian::write_u64_into(&r.0, &mut repr[..]); + FsRepr(repr) } #[inline(always)] fn is_odd(&self) -> bool { - self.into_repr().is_odd() + let mut r = *self; + r.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); + + r.0[0] & 1 == 1 } fn char() -> FsRepr { @@ -573,13 +416,13 @@ impl PrimeField for Fs { const CAPACITY: u32 = Self::NUM_BITS - 1; fn multiplicative_generator() -> Self { - Fs(GENERATOR) + GENERATOR } const S: u32 = S; fn root_of_unity() -> Self { - Fs(ROOT_OF_UNITY) + ROOT_OF_UNITY } } @@ -591,7 +434,7 @@ impl Field for Fs { for limb in &mut repr { *limb = rng.next_u64(); } - Fs(FsRepr(repr)) + Fs(repr) }; // Mask away the unused most-significant bits. @@ -610,12 +453,12 @@ impl Field for Fs { #[inline] fn one() -> Self { - Fs(R) + R } #[inline] fn is_zero(&self) -> bool { - self.0.is_zero() + self.0.iter().all(|&e| e == 0) } #[inline] @@ -623,7 +466,13 @@ impl Field for Fs { let mut ret = *self; // This cannot exceed the backing capacity. - ret.0.mul2(); + let mut last = 0; + for i in &mut ret.0 { + let tmp = *i >> 63; + *i <<= 1; + *i |= last; + last = tmp; + } // However, it may need to be reduced. ret.reduce(); @@ -658,16 +507,16 @@ impl Field for Fs { #[inline] fn square(&self) -> Self { let mut carry = 0; - let r1 = mac_with_carry(0, (self.0).0[0], (self.0).0[1], &mut carry); - let r2 = mac_with_carry(0, (self.0).0[0], (self.0).0[2], &mut carry); - let r3 = mac_with_carry(0, (self.0).0[0], (self.0).0[3], &mut carry); + let r1 = mac_with_carry(0, self.0[0], self.0[1], &mut carry); + let r2 = mac_with_carry(0, self.0[0], self.0[2], &mut carry); + let r3 = mac_with_carry(0, self.0[0], self.0[3], &mut carry); let r4 = carry; let mut carry = 0; - let r3 = mac_with_carry(r3, (self.0).0[1], (self.0).0[2], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[1], (self.0).0[3], &mut carry); + let r3 = mac_with_carry(r3, self.0[1], self.0[2], &mut carry); + let r4 = mac_with_carry(r4, self.0[1], self.0[3], &mut carry); let r5 = carry; let mut carry = 0; - let r5 = mac_with_carry(r5, (self.0).0[2], (self.0).0[3], &mut carry); + let r5 = mac_with_carry(r5, self.0[2], self.0[3], &mut carry); let r6 = carry; let r7 = r6 >> 63; @@ -679,13 +528,13 @@ impl Field for Fs { let r1 = r1 << 1; let mut carry = 0; - let r0 = mac_with_carry(0, (self.0).0[0], (self.0).0[0], &mut carry); + let r0 = mac_with_carry(0, self.0[0], self.0[0], &mut carry); let r1 = adc(r1, 0, &mut carry); - let r2 = mac_with_carry(r2, (self.0).0[1], (self.0).0[1], &mut carry); + let r2 = mac_with_carry(r2, self.0[1], self.0[1], &mut carry); let r3 = adc(r3, 0, &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[2], (self.0).0[2], &mut carry); + let r4 = mac_with_carry(r4, self.0[2], self.0[2], &mut carry); let r5 = adc(r5, 0, &mut carry); - let r6 = mac_with_carry(r6, (self.0).0[3], (self.0).0[3], &mut carry); + let r6 = mac_with_carry(r6, self.0[3], self.0[3], &mut carry); let r7 = adc(r7, 0, &mut carry); let mut ret = *self; @@ -695,11 +544,46 @@ impl Field for Fs { } impl Fs { + /// Compares two elements in native representation. This is only used + /// internally. + #[inline(always)] + fn cmp_native(&self, other: &Fs) -> ::std::cmp::Ordering { + for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { + if a < b { + return ::std::cmp::Ordering::Less; + } else if a > b { + return ::std::cmp::Ordering::Greater; + } + } + + ::std::cmp::Ordering::Equal + } + /// Determines if the element is really in the field. This is only used /// internally. #[inline(always)] fn is_valid(&self) -> bool { - self.0 < MODULUS + // The Ord impl calls `reduce`, which in turn calls `is_valid`, so we use + // this internal function to eliminate the cycle. + self.cmp_native(&MODULUS_LIMBS) == ::core::cmp::Ordering::Less + } + + #[inline(always)] + fn add_nocarry(&mut self, other: &Fs) { + let mut carry = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + *a = adc(*a, *b, &mut carry); + } + } + + #[inline(always)] + fn sub_noborrow(&mut self, other: &Fs) { + let mut borrow = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + *a = sbb(*a, *b, &mut borrow); + } } /// Subtracts the modulus from this element if this element is not in the @@ -707,7 +591,7 @@ impl Fs { #[inline(always)] fn reduce(&mut self) { if !self.is_valid() { - self.0.sub_noborrow(&MODULUS); + self.sub_noborrow(&MODULUS_LIMBS); } } @@ -729,39 +613,39 @@ impl Fs { let k = r0.wrapping_mul(INV); let mut carry = 0; - mac_with_carry(r0, k, MODULUS.0[0], &mut carry); - r1 = mac_with_carry(r1, k, MODULUS.0[1], &mut carry); - r2 = mac_with_carry(r2, k, MODULUS.0[2], &mut carry); - r3 = mac_with_carry(r3, k, MODULUS.0[3], &mut carry); + mac_with_carry(r0, k, MODULUS_LIMBS.0[0], &mut carry); + r1 = mac_with_carry(r1, k, MODULUS_LIMBS.0[1], &mut carry); + r2 = mac_with_carry(r2, k, MODULUS_LIMBS.0[2], &mut carry); + r3 = mac_with_carry(r3, k, MODULUS_LIMBS.0[3], &mut carry); r4 = adc(r4, 0, &mut carry); let carry2 = carry; let k = r1.wrapping_mul(INV); let mut carry = 0; - mac_with_carry(r1, k, MODULUS.0[0], &mut carry); - r2 = mac_with_carry(r2, k, MODULUS.0[1], &mut carry); - r3 = mac_with_carry(r3, k, MODULUS.0[2], &mut carry); - r4 = mac_with_carry(r4, k, MODULUS.0[3], &mut carry); + mac_with_carry(r1, k, MODULUS_LIMBS.0[0], &mut carry); + r2 = mac_with_carry(r2, k, MODULUS_LIMBS.0[1], &mut carry); + r3 = mac_with_carry(r3, k, MODULUS_LIMBS.0[2], &mut carry); + r4 = mac_with_carry(r4, k, MODULUS_LIMBS.0[3], &mut carry); r5 = adc(r5, carry2, &mut carry); let carry2 = carry; let k = r2.wrapping_mul(INV); let mut carry = 0; - mac_with_carry(r2, k, MODULUS.0[0], &mut carry); - r3 = mac_with_carry(r3, k, MODULUS.0[1], &mut carry); - r4 = mac_with_carry(r4, k, MODULUS.0[2], &mut carry); - r5 = mac_with_carry(r5, k, MODULUS.0[3], &mut carry); + mac_with_carry(r2, k, MODULUS_LIMBS.0[0], &mut carry); + r3 = mac_with_carry(r3, k, MODULUS_LIMBS.0[1], &mut carry); + r4 = mac_with_carry(r4, k, MODULUS_LIMBS.0[2], &mut carry); + r5 = mac_with_carry(r5, k, MODULUS_LIMBS.0[3], &mut carry); r6 = adc(r6, carry2, &mut carry); let carry2 = carry; let k = r3.wrapping_mul(INV); let mut carry = 0; - mac_with_carry(r3, k, MODULUS.0[0], &mut carry); - r4 = mac_with_carry(r4, k, MODULUS.0[1], &mut carry); - r5 = mac_with_carry(r5, k, MODULUS.0[2], &mut carry); - r6 = mac_with_carry(r6, k, MODULUS.0[3], &mut carry); + mac_with_carry(r3, k, MODULUS_LIMBS.0[0], &mut carry); + r4 = mac_with_carry(r4, k, MODULUS_LIMBS.0[1], &mut carry); + r5 = mac_with_carry(r5, k, MODULUS_LIMBS.0[2], &mut carry); + r6 = mac_with_carry(r6, k, MODULUS_LIMBS.0[3], &mut carry); r7 = adc(r7, carry2, &mut carry); - (self.0).0[0] = r4; - (self.0).0[1] = r5; - (self.0).0[2] = r6; - (self.0).0[3] = r7; + self.0[0] = r4; + self.0[1] = r5; + self.0[2] = r6; + self.0[3] = r7; self.reduce(); } @@ -821,340 +705,26 @@ use rand_core::SeedableRng; #[cfg(test)] use rand_xorshift::XorShiftRng; -#[test] -fn test_fs_repr_ordering() { - fn assert_equality(a: FsRepr, b: FsRepr) { - assert_eq!(a, b); - assert!(a.cmp(&b) == ::std::cmp::Ordering::Equal); - } - - fn assert_lt(a: FsRepr, b: FsRepr) { - assert!(a < b); - assert!(b > a); - } - - assert_equality( - FsRepr([9999, 9999, 9999, 9999]), - FsRepr([9999, 9999, 9999, 9999]), - ); - assert_equality( - FsRepr([9999, 9998, 9999, 9999]), - FsRepr([9999, 9998, 9999, 9999]), - ); - assert_equality( - FsRepr([9999, 9999, 9999, 9997]), - FsRepr([9999, 9999, 9999, 9997]), - ); - assert_lt( - FsRepr([9999, 9997, 9999, 9998]), - FsRepr([9999, 9997, 9999, 9999]), - ); - assert_lt( - FsRepr([9999, 9997, 9998, 9999]), - FsRepr([9999, 9997, 9999, 9999]), - ); - assert_lt( - FsRepr([9, 9999, 9999, 9997]), - FsRepr([9999, 9999, 9999, 9997]), - ); -} - -#[test] -fn test_fs_repr_from() { - assert_eq!(FsRepr::from(100), FsRepr([100, 0, 0, 0])); -} - -#[test] -fn test_fs_repr_is_odd() { - assert!(!FsRepr::from(0).is_odd()); - assert!(FsRepr::from(0).is_even()); - assert!(FsRepr::from(1).is_odd()); - assert!(!FsRepr::from(1).is_even()); - assert!(!FsRepr::from(324834872).is_odd()); - assert!(FsRepr::from(324834872).is_even()); - assert!(FsRepr::from(324834873).is_odd()); - assert!(!FsRepr::from(324834873).is_even()); -} - -#[test] -fn test_fs_repr_is_zero() { - assert!(FsRepr::from(0).is_zero()); - assert!(!FsRepr::from(1).is_zero()); - assert!(!FsRepr([0, 0, 1, 0]).is_zero()); -} - -#[test] -fn test_fs_repr_div2() { - let mut a = FsRepr([ - 0xbd2920b19c972321, - 0x174ed0466a3be37e, - 0xd468d5e3b551f0b5, - 0xcb67c072733beefc, - ]); - a.div2(); - assert_eq!( - a, - FsRepr([ - 0x5e949058ce4b9190, - 0x8ba76823351df1bf, - 0x6a346af1daa8f85a, - 0x65b3e039399df77e - ]) - ); - for _ in 0..10 { - a.div2(); - } - assert_eq!( - a, - FsRepr([ - 0x6fd7a524163392e4, - 0x16a2e9da08cd477c, - 0xdf9a8d1abc76aa3e, - 0x196cf80e4e677d - ]) - ); - for _ in 0..200 { - a.div2(); - } - assert_eq!(a, FsRepr([0x196cf80e4e67, 0x0, 0x0, 0x0])); - for _ in 0..40 { - a.div2(); - } - assert_eq!(a, FsRepr([0x19, 0x0, 0x0, 0x0])); - for _ in 0..4 { - a.div2(); - } - assert_eq!(a, FsRepr([0x1, 0x0, 0x0, 0x0])); - a.div2(); - assert!(a.is_zero()); -} - -#[test] -fn test_fs_repr_shr() { - let mut a = FsRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x36003ab08de70da1, - ]); - a.shr(0); - assert_eq!( - a, - FsRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x36003ab08de70da1 - ]) - ); - a.shr(1); - assert_eq!( - a, - FsRepr([ - 0xd99fdd762415141f, - 0xccbef069d44659ef, - 0xcd7b16954d072a92, - 0x1b001d5846f386d0 - ]) - ); - a.shr(50); - assert_eq!( - a, - FsRepr([ - 0xbc1a7511967bf667, - 0xc5a55341caa4b32f, - 0x75611bce1b4335e, - 0x6c0 - ]) - ); - a.shr(130); - assert_eq!(a, FsRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0])); - a.shr(64); - assert_eq!(a, FsRepr([0x1b0, 0x0, 0x0, 0x0])); -} - -#[test] -fn test_fs_repr_mul2() { - let mut a = FsRepr::from(23712937547); - a.mul2(); - assert_eq!(a, FsRepr([0xb0acd6c96, 0x0, 0x0, 0x0])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FsRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0])); - for _ in 0..128 { - a.mul2(); - } - assert_eq!(a, FsRepr([0x0, 0x0, 0x6000000000000000, 0xb0acd6c9])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FsRepr([0x0, 0x0, 0x0, 0x9600000000000000])); - for _ in 0..7 { - a.mul2(); - } - assert!(a.is_zero()); -} - -#[test] -fn test_fs_repr_num_bits() { - let mut a = FsRepr::from(0); - assert_eq!(0, a.num_bits()); - a = FsRepr::from(1); - for i in 1..257 { - assert_eq!(i, a.num_bits()); - a.mul2(); - } - assert_eq!(0, a.num_bits()); -} - -#[test] -fn test_fs_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let mut t = FsRepr([ - 0x8e62a7e85264e2c3, - 0xb23d34c1941d3ca, - 0x5976930b7502dd15, - 0x600f3fb517bf5495, - ]); - t.sub_noborrow(&FsRepr([ - 0xd64f669809cbc6a4, - 0xfa76cb9d90cf7637, - 0xfefb0df9038d43b3, - 0x298a30c744b31acf, - ])); - assert!( - t == FsRepr([ - 0xb813415048991c1f, - 0x10ad07ae88725d92, - 0x5a7b851271759961, - 0x36850eedd30c39c5 - ]) - ); - - for _ in 0..1000 { - let mut a = Fs::random(&mut rng).into_repr(); - a.0[3] >>= 30; - let mut b = a; - for _ in 0..10 { - b.mul2(); - } - let mut c = b; - for _ in 0..10 { - c.mul2(); - } - - assert!(a < b); - assert!(b < c); - - let mut csub_ba = c; - csub_ba.sub_noborrow(&b); - csub_ba.sub_noborrow(&a); - - let mut csub_ab = c; - csub_ab.sub_noborrow(&a); - csub_ab.sub_noborrow(&b); - - assert_eq!(csub_ab, csub_ba); - } -} - -#[test] -fn test_fr_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let mut t = FsRepr([ - 0xd64f669809cbc6a4, - 0xfa76cb9d90cf7637, - 0xfefb0df9038d43b3, - 0x298a30c744b31acf, - ]); - t.add_nocarry(&FsRepr([ - 0x8e62a7e85264e2c3, - 0xb23d34c1941d3ca, - 0x5976930b7502dd15, - 0x600f3fb517bf5495, - ])); - assert_eq!( - t, - FsRepr([ - 0x64b20e805c30a967, - 0x59a9ee9aa114a02, - 0x5871a104789020c9, - 0x8999707c5c726f65 - ]) - ); - - // Test for the associativity of addition. - for _ in 0..1000 { - let mut a = Fs::random(&mut rng).into_repr(); - let mut b = Fs::random(&mut rng).into_repr(); - let mut c = Fs::random(&mut rng).into_repr(); - - // Unset the first few bits, so that overflow won't occur. - a.0[3] >>= 3; - b.0[3] >>= 3; - c.0[3] >>= 3; - - let mut abc = a; - abc.add_nocarry(&b); - abc.add_nocarry(&c); - - let mut acb = a; - acb.add_nocarry(&c); - acb.add_nocarry(&b); - - let mut bac = b; - bac.add_nocarry(&a); - bac.add_nocarry(&c); - - let mut bca = b; - bca.add_nocarry(&c); - bca.add_nocarry(&a); - - let mut cab = c; - cab.add_nocarry(&a); - cab.add_nocarry(&b); - - let mut cba = c; - cba.add_nocarry(&b); - cba.add_nocarry(&a); - - assert_eq!(abc, acb); - assert_eq!(abc, bac); - assert_eq!(abc, bca); - assert_eq!(abc, cab); - assert_eq!(abc, cba); - } -} - #[test] fn test_fs_is_valid() { - let mut a = Fs(MODULUS); + let mut a = MODULUS_LIMBS; assert!(!a.is_valid()); - a.0.sub_noborrow(&FsRepr::from(1)); + a.sub_noborrow(&Fs([1, 0, 0, 0])); assert!(a.is_valid()); - assert!(Fs(FsRepr::from(0)).is_valid()); - assert!(Fs(FsRepr([ + assert!(Fs::zero().is_valid()); + assert!(Fs([ 0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9 - ])) + ]) .is_valid()); - assert!(!Fs(FsRepr([ + assert!(!Fs([ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff - ])) + ]) .is_valid()); let mut rng = XorShiftRng::from_seed([ @@ -1178,77 +748,77 @@ fn test_fs_add_assign() { .unwrap(); assert!(tmp.is_valid()); // Test that adding zero has no effect. - tmp.add_assign(&Fs(FsRepr::from(0))); + tmp.add_assign(&Fs::zero()); assert_eq!( tmp, - Fs(FsRepr([ + Fs([ 0x8e6bfff4722d6e67, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162 - ])) + ]) ); // Add one and test for the result. - tmp.add_assign(&Fs(FsRepr::from(1))); + tmp.add_assign(&Fs([1, 0, 0, 0])); assert_eq!( tmp, - Fs(FsRepr([ + Fs([ 0x8e6bfff4722d6e68, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162 - ])) + ]) ); // Add another random number that exercises the reduction. - tmp.add_assign(&Fs(FsRepr([ + tmp.add_assign(&Fs([ 0xb634d07bc42d4a70, 0xf724f0c008411f5f, 0x456d4053d865af34, 0x24ce814e8c63027, - ]))); + ])); assert_eq!( tmp, - Fs(FsRepr([ + Fs([ 0x44a0d070365ab8d8, 0x4d68cb1c91616459, 0xd9d3350659f7c99e, 0x4ac5d4227a3a189 - ])) + ]) ); // Add one to (s - 1) and test for the result. - tmp = Fs(FsRepr([ + tmp = Fs([ 0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9, - ])); - tmp.add_assign(&Fs(FsRepr::from(1))); - assert!(tmp.0.is_zero()); + ]); + tmp.add_assign(&Fs([1, 0, 0, 0])); + assert!(tmp.is_zero()); // Add a random number to another one such that the result is s - 1 - tmp = Fs(FsRepr([ + tmp = Fs([ 0xa11fda5950ce3636, 0x922e0dbccfe0ca0e, 0xacebb6e215b82d4a, 0x97ffb8cdc3aee93, - ])); - tmp.add_assign(&Fs(FsRepr([ + ]); + tmp.add_assign(&Fs([ 0x2f7734058628f680, 0x143a12d6fce74674, 0x597b841eeb7c0db6, 0x4fdb95d88f8c115, - ]))); + ])); assert_eq!( tmp, - Fs(FsRepr([ + Fs([ 0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9 - ])) + ]) ); // Add one to the result and test for it. - tmp.add_assign(&Fs(FsRepr::from(1))); - assert!(tmp.0.is_zero()); + tmp.add_assign(&Fs([1, 0, 0, 0])); + assert!(tmp.is_zero()); } // Test associativity @@ -1282,71 +852,71 @@ fn test_fs_add_assign() { fn test_fs_sub_assign() { { // Test arbitrary subtraction that tests reduction. - let mut tmp = Fs(FsRepr([ + let mut tmp = Fs([ 0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2, - ])); - tmp.sub_assign(&Fs(FsRepr([ + ]); + tmp.sub_assign(&Fs([ 0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679, - ]))); + ])); assert_eq!( tmp, - Fs(FsRepr([ + Fs([ 0x97c015841f9b79f6, 0xe7fcb121eb6ffc49, 0xb8c050814de2a3c1, 0x943c0589dcafa21 - ])) + ]) ); // Test the opposite subtraction which doesn't test reduction. - tmp = Fs(FsRepr([ + tmp = Fs([ 0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679, - ])); - tmp.sub_assign(&Fs(FsRepr([ + ]); + tmp.sub_assign(&Fs([ 0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2, - ]))); + ])); assert_eq!( tmp, - Fs(FsRepr([ + Fs([ 0x38d6f8dab75bb2c1, 0xbe6b6f71e1581439, 0x4da6ea7fb351973e, 0x539f491c768b587 - ])) + ]) ); // Test for sensible results with zero - tmp = Fs(FsRepr::from(0)); - tmp.sub_assign(&Fs(FsRepr::from(0))); + tmp = Fs::zero(); + tmp.sub_assign(&Fs::from(0)); assert!(tmp.is_zero()); - tmp = Fs(FsRepr([ + tmp = Fs([ 0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230, - ])); - tmp.sub_assign(&Fs(FsRepr::from(0))); + ]); + tmp.sub_assign(&Fs::from(0)); assert_eq!( tmp, - Fs(FsRepr([ + Fs([ 0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230 - ])) + ]) ); } @@ -1373,25 +943,25 @@ fn test_fs_sub_assign() { #[test] fn test_fs_mul_assign() { - let mut tmp = Fs(FsRepr([ + let mut tmp = Fs([ 0xb433b01287f71744, 0x4eafb86728c4d108, 0xfdd52c14b9dfbe65, 0x2ff1f3434821118, - ])); - tmp.mul_assign(&Fs(FsRepr([ + ]); + tmp.mul_assign(&Fs([ 0xdae00fc63c9fa90f, 0x5a5ed89b96ce21ce, 0x913cd26101bd6f58, 0x3f0822831697fe9, - ]))); + ])); assert!( - tmp == Fs(FsRepr([ + tmp == Fs([ 0xb68ecb61d54d2992, 0x5ff95874defce6a6, 0x3590eb053894657d, 0x53823a118515933 - ])) + ]) ); let mut rng = XorShiftRng::from_seed([ @@ -1443,80 +1013,73 @@ fn test_fs_mul_assign() { #[test] fn test_fs_shr() { let mut a = Fs::from_repr(FsRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x06003ab08de70da1, + 0x3f, 0x28, 0x2a, 0x48, 0xec, 0xba, 0x3f, 0xb3, 0xdf, 0xb3, 0x8c, 0xa8, 0xd3, 0xe0, 0x7d, + 0x99, 0x25, 0x55, 0x0e, 0x9a, 0x2a, 0x2d, 0xf6, 0x9a, 0xa1, 0x0d, 0xe7, 0x8d, 0xb0, 0x3a, + 0x00, 0x06, ])) .unwrap(); a = a >> 0; assert_eq!( a.into_repr(), FsRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x06003ab08de70da1, + 0x3f, 0x28, 0x2a, 0x48, 0xec, 0xba, 0x3f, 0xb3, 0xdf, 0xb3, 0x8c, 0xa8, 0xd3, 0xe0, + 0x7d, 0x99, 0x25, 0x55, 0x0e, 0x9a, 0x2a, 0x2d, 0xf6, 0x9a, 0xa1, 0x0d, 0xe7, 0x8d, + 0xb0, 0x3a, 0x00, 0x06, ]) ); a = a >> 1; assert_eq!( a.into_repr(), FsRepr([ - 0xd99fdd762415141f, - 0xccbef069d44659ef, - 0xcd7b16954d072a92, - 0x03001d5846f386d0, + 0x1f, 0x14, 0x15, 0x24, 0x76, 0xdd, 0x9f, 0xd9, 0xef, 0x59, 0x46, 0xd4, 0x69, 0xf0, + 0xbe, 0xcc, 0x92, 0x2a, 0x07, 0x4d, 0x95, 0x16, 0x7b, 0xcd, 0xd0, 0x86, 0xf3, 0x46, + 0x58, 0x1d, 0x00, 0x03, ]) ); a = a >> 50; assert_eq!( a.into_repr(), FsRepr([ - 0xbc1a7511967bf667, - 0xc5a55341caa4b32f, - 0x075611bce1b4335e, - 0x00000000000000c0, + 0x67, 0xf6, 0x7b, 0x96, 0x11, 0x75, 0x1a, 0xbc, 0x2f, 0xb3, 0xa4, 0xca, 0x41, 0x53, + 0xa5, 0xc5, 0x5e, 0x33, 0xb4, 0xe1, 0xbc, 0x11, 0x56, 0x07, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ]) ); a = a >> 130; assert_eq!( a.into_repr(), FsRepr([ - 0x01d5846f386d0cd7, - 0x0000000000000030, - 0x0000000000000000, - 0x0000000000000000, + 0xd7, 0x0c, 0x6d, 0x38, 0x6f, 0x84, 0xd5, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ]) ); a = a >> 64; assert_eq!( a.into_repr(), FsRepr([ - 0x0000000000000030, - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000000, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ]) ); } #[test] -fn test_fr_squaring() { - let a = Fs(FsRepr([ +fn test_fs_squaring() { + let a = Fs([ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xe7db4ea6533afa8, - ])); + ]); assert!(a.is_valid()); assert_eq!( a.square(), Fs::from_repr(FsRepr([ - 0x12c7f55cbc52fbaa, - 0xdedc98a0b5e6ce9e, - 0xad2892726a5396a, - 0x9fe82af8fee77b3 + 0xaa, 0xfb, 0x52, 0xbc, 0x5c, 0xf5, 0xc7, 0x12, 0x9e, 0xce, 0xe6, 0xb5, 0xa0, 0x98, + 0xdc, 0xde, 0x6a, 0x39, 0xa5, 0x26, 0x27, 0x89, 0xd2, 0x0a, 0xb3, 0x77, 0xee, 0x8f, + 0xaf, 0x82, 0xfe, 0x09, ])) .unwrap() ); @@ -1658,42 +1221,39 @@ fn test_fs_sqrt() { fn test_fs_from_into_repr() { // r + 1 should not be in the field assert!(Fs::from_repr(FsRepr([ - 0xd0970e5ed6f72cb8, - 0xa6682093ccc81082, - 0x6673b0101343b00, - 0xe7db4ea6533afa9 + 0xb8, 0x2c, 0xf7, 0xd6, 0x5e, 0x0e, 0x97, 0xd0, 0x82, 0x10, 0xc8, 0xcc, 0x93, 0x20, 0x68, + 0xa6, 0x00, 0x3b, 0x34, 0x01, 0x01, 0x3b, 0x67, 0x06, 0xa9, 0xaf, 0x33, 0x65, 0xea, 0xb4, + 0x7d, 0x0e, ])) - .is_err()); + .is_none()); // r should not be in the field - assert!(Fs::from_repr(Fs::char()).is_err()); + assert!(Fs::from_repr(Fs::char()).is_none()); // Multiply some arbitrary representations to see if the result is as expected. - let a = FsRepr([ - 0x5f2d0c05d0337b71, - 0xa1df2b0f8a20479, - 0xad73785e71bb863, - 0x504a00480c9acec, - ]); - let mut a_fs = Fs::from_repr(a).unwrap(); - let b = FsRepr([ - 0x66356ff51e477562, - 0x60a92ab55cf7603, - 0x8e4273c7364dd192, - 0x36df8844a344dc5, - ]); - let b_fs = Fs::from_repr(b).unwrap(); - let c = FsRepr([ - 0x7eef61708f4f2868, - 0x747a7e6cf52946fb, - 0x83dd75d7c9120017, - 0x762f5177f0f3df7, - ]); + let mut a_fs = Fs::from_repr(FsRepr([ + 0x71, 0x7b, 0x33, 0xd0, 0x05, 0x0c, 0x2d, 0x5f, 0x79, 0x04, 0xa2, 0xf8, 0xb0, 0xf2, 0x1d, + 0x0a, 0x63, 0xb8, 0x1b, 0xe7, 0x85, 0x37, 0xd7, 0x0a, 0xec, 0xac, 0xc9, 0x80, 0x04, 0xa0, + 0x04, 0x05, + ])) + .unwrap(); + let b_fs = Fs::from_repr(FsRepr([ + 0x62, 0x75, 0x47, 0x1e, 0xf5, 0x6f, 0x35, 0x66, 0x03, 0x76, 0xcf, 0x55, 0xab, 0x92, 0x0a, + 0x06, 0x92, 0xd1, 0x4d, 0x36, 0xc7, 0x73, 0x42, 0x8e, 0xc5, 0x4d, 0x34, 0x4a, 0x84, 0xf8, + 0x6d, 0x03, + ])) + .unwrap(); + let c_fs = Fs::from_repr(FsRepr([ + 0x68, 0x28, 0x4f, 0x8f, 0x70, 0x61, 0xef, 0x7e, 0xfb, 0x46, 0x29, 0xf5, 0x6c, 0x7e, 0x7a, + 0x74, 0x17, 0x00, 0x12, 0xc9, 0xd7, 0x75, 0xdd, 0x83, 0xf7, 0x3d, 0x0f, 0x7f, 0x17, 0xf5, + 0x62, 0x07, + ])) + .unwrap(); a_fs.mul_assign(&b_fs); - assert_eq!(a_fs.into_repr(), c); + assert_eq!(a_fs, c_fs); // Zero should be in the field. - assert!(Fs::from_repr(FsRepr::from(0)).unwrap().is_zero()); + assert!(Fs::from_repr(FsRepr::default()).unwrap().is_zero()); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -1712,60 +1272,15 @@ fn test_fs_from_into_repr() { } } -#[test] -fn test_fs_repr_display() { - assert_eq!( - format!( - "{}", - FsRepr([ - 0xa296db59787359df, - 0x8d3e33077430d318, - 0xd1abf5c606102eb7, - 0xcbc33ee28108f0 - ]) - ), - "0x00cbc33ee28108f0d1abf5c606102eb78d3e33077430d318a296db59787359df".to_string() - ); - assert_eq!( - format!( - "{}", - FsRepr([ - 0x14cb03535054a620, - 0x312aa2bf2d1dff52, - 0x970fe98746ab9361, - 0xc1e18acf82711e6 - ]) - ), - "0x0c1e18acf82711e6970fe98746ab9361312aa2bf2d1dff5214cb03535054a620".to_string() - ); - assert_eq!( - format!( - "{}", - FsRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ]) - ), - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() - ); - assert_eq!( - format!("{}", FsRepr([0, 0, 0, 0])), - "0x0000000000000000000000000000000000000000000000000000000000000000".to_string() - ); -} - #[test] fn test_fs_display() { assert_eq!( format!( "{}", Fs::from_repr(FsRepr([ - 0x5528efb9998a01a3, - 0x5bd2add5cb357089, - 0xc061fa6adb491f98, - 0x70db9d143db03d9 + 0xa3, 0x01, 0x8a, 0x99, 0xb9, 0xef, 0x28, 0x55, 0x89, 0x70, 0x35, 0xcb, 0xd5, 0xad, + 0xd2, 0x5b, 0x98, 0x1f, 0x49, 0xdb, 0x6a, 0xfa, 0x61, 0xc0, 0xd9, 0x03, 0xdb, 0x43, + 0xd1, 0xb9, 0x0d, 0x07, ])) .unwrap() ), @@ -1775,10 +1290,9 @@ fn test_fs_display() { format!( "{}", Fs::from_repr(FsRepr([ - 0xd674745e2717999e, - 0xbeb1f52d3e96f338, - 0x9c7ae147549482b9, - 0x999706024530d22 + 0x9e, 0x99, 0x17, 0x27, 0x5e, 0x74, 0x74, 0xd6, 0x38, 0xf3, 0x96, 0x3e, 0x2d, 0xf5, + 0xb1, 0xbe, 0xb9, 0x82, 0x94, 0x54, 0x47, 0xe1, 0x7a, 0x9c, 0x22, 0x0d, 0x53, 0x24, + 0x60, 0x70, 0x99, 0x09, ])) .unwrap() ), diff --git a/zcash_primitives/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs index 0992637fe..372f686ee 100644 --- a/zcash_primitives/src/jubjub/montgomery.rs +++ b/zcash_primitives/src/jubjub/montgomery.rs @@ -304,7 +304,7 @@ impl Point { let mut res = Self::zero(); - for b in BitIterator::::new(scalar.into()) { + for b in BitIterator::::new(scalar.into()) { res = res.double(params); if b { diff --git a/zcash_primitives/src/keys.rs b/zcash_primitives/src/keys.rs index 76914baaa..2f067a2e4 100644 --- a/zcash_primitives/src/keys.rs +++ b/zcash_primitives/src/keys.rs @@ -9,7 +9,7 @@ use crate::{ primitives::{ProofGenerationKey, ViewingKey}, }; use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; -use ff::{PrimeField, PrimeFieldRepr}; +use ff::PrimeField; use std::io::{self, Read, Write}; pub const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed"; @@ -71,14 +71,14 @@ impl ExpandedSpendingKey { pub fn read(mut reader: R) -> io::Result { let mut ask_repr = ::Repr::default(); - ask_repr.read_le(&mut reader)?; + reader.read_exact(ask_repr.as_mut())?; let ask = E::Fs::from_repr(ask_repr) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "ask not in field"))?; let mut nsk_repr = ::Repr::default(); - nsk_repr.read_le(&mut reader)?; + reader.read_exact(nsk_repr.as_mut())?; let nsk = E::Fs::from_repr(nsk_repr) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "nsk not in field"))?; let mut ovk = [0; 32]; reader.read_exact(&mut ovk)?; @@ -91,8 +91,8 @@ impl ExpandedSpendingKey { } pub fn write(&self, mut writer: W) -> io::Result<()> { - self.ask.into_repr().write_le(&mut writer)?; - self.nsk.into_repr().write_le(&mut writer)?; + writer.write_all(self.ask.into_repr().as_ref())?; + writer.write_all(self.nsk.into_repr().as_ref())?; writer.write_all(&self.ovk.0)?; Ok(()) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 53600e5f3..a3fc1fca7 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -511,9 +511,9 @@ mod tests { use super::{CommitmentTree, Hashable, IncrementalWitness, MerklePath, PathFiller}; use crate::sapling::Node; - use ff::PrimeFieldRepr; use hex; use pairing::bls12_381::FrRepr; + use std::convert::TryInto; use std::io::{self, Read, Write}; const HEX_EMPTY_ROOTS: [&str; 33] = [ @@ -1016,9 +1016,7 @@ mod tests { let mut paths_i = 0; let mut witness_ser_i = 0; for i in 0..16 { - let mut cm = FrRepr::default(); - cm.read_le(&hex::decode(commitments[i]).unwrap()[..]) - .expect("length is 32 bytes"); + let cm = FrRepr(hex::decode(commitments[i]).unwrap()[..].try_into().unwrap()); let cm = Node::new(cm); diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 747bd8d8c..539ee643f 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -11,9 +11,10 @@ use crate::{ use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; -use ff::{PrimeField, PrimeFieldRepr}; +use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{CryptoRng, RngCore}; +use std::convert::TryInto; use std::fmt; use std::str; @@ -192,7 +193,7 @@ fn prf_ock( let mut ock_input = [0u8; 128]; ock_input[0..32].copy_from_slice(&ovk.0); cv.write(&mut ock_input[32..64]).unwrap(); - cmu.into_repr().write_le(&mut ock_input[64..96]).unwrap(); + ock_input[64..96].copy_from_slice(cmu.into_repr().as_ref()); epk.write(&mut ock_input[96..128]).unwrap(); Blake2bParams::new() @@ -302,11 +303,7 @@ impl SaplingNoteEncryption { (&mut input[12..20]) .write_u64::(self.note.value) .unwrap(); - self.note - .r - .into_repr() - .write_le(&mut input[20..COMPACT_NOTE_SIZE]) - .unwrap(); + input[20..COMPACT_NOTE_SIZE].copy_from_slice(self.note.r.into_repr().as_ref()); input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&self.memo.0); let mut output = [0u8; ENC_CIPHERTEXT_SIZE]; @@ -330,10 +327,7 @@ impl SaplingNoteEncryption { let mut input = [0u8; OUT_PLAINTEXT_SIZE]; self.note.pk_d.write(&mut input[0..32]).unwrap(); - self.esk - .into_repr() - .write_le(&mut input[32..OUT_PLAINTEXT_SIZE]) - .unwrap(); + input[32..OUT_PLAINTEXT_SIZE].copy_from_slice(self.esk.into_repr().as_ref()); let mut output = [0u8; OUT_CIPHERTEXT_SIZE]; assert_eq!( @@ -363,9 +357,11 @@ fn parse_note_plaintext_without_memo( let v = (&plaintext[12..20]).read_u64::().ok()?; - let mut rcm = FsRepr::default(); - rcm.read_le(&plaintext[20..COMPACT_NOTE_SIZE]).ok()?; - let rcm = Fs::from_repr(rcm).ok()?; + let rcm = Fs::from_repr(FsRepr( + plaintext[20..COMPACT_NOTE_SIZE] + .try_into() + .expect("slice is the correct length"), + ))?; let diversifier = Diversifier(d); let pk_d = diversifier @@ -483,9 +479,11 @@ pub fn try_sapling_output_recovery( .ok()? .as_prime_order(&JUBJUB)?; - let mut esk = FsRepr::default(); - esk.read_le(&op[32..OUT_PLAINTEXT_SIZE]).ok()?; - let esk = Fs::from_repr(esk).ok()?; + let esk = Fs::from_repr(FsRepr( + op[32..OUT_PLAINTEXT_SIZE] + .try_into() + .expect("slice is the correct length"), + ))?; let shared_secret = sapling_ka_agree(&esk, &pk_d); let key = kdf_sapling(shared_secret, &epk); @@ -515,9 +513,11 @@ pub fn try_sapling_output_recovery( let v = (&plaintext[12..20]).read_u64::().ok()?; - let mut rcm = FsRepr::default(); - rcm.read_le(&plaintext[20..COMPACT_NOTE_SIZE]).ok()?; - let rcm = Fs::from_repr(rcm).ok()?; + let rcm = Fs::from_repr(FsRepr( + plaintext[20..COMPACT_NOTE_SIZE] + .try_into() + .expect("slice is the correct length"), + ))?; let mut memo = [0u8; 512]; memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]); @@ -554,10 +554,11 @@ mod tests { primitives::{Diversifier, PaymentAddress, ValueCommitment}, }; use crypto_api_chachapoly::ChachaPolyIetf; - use ff::{Field, PrimeField, PrimeFieldRepr}; + use ff::{Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand_core::OsRng; use rand_core::{CryptoRng, RngCore}; + use std::convert::TryInto; use std::str::FromStr; use super::{ @@ -791,9 +792,7 @@ mod tests { .as_prime_order(&JUBJUB) .unwrap(); - let mut esk = FsRepr::default(); - esk.read_le(&op[32..OUT_PLAINTEXT_SIZE]).unwrap(); - let esk = Fs::from_repr(esk).unwrap(); + let esk = Fs::from_repr(FsRepr(op[32..OUT_PLAINTEXT_SIZE].try_into().unwrap())).unwrap(); let shared_secret = sapling_ka_agree(&esk, &pk_d); let key = kdf_sapling(shared_secret, &epk); @@ -1292,17 +1291,13 @@ mod tests { macro_rules! read_fr { ($field:expr) => {{ - let mut repr = FrRepr::default(); - repr.read_le(&$field[..]).unwrap(); - Fr::from_repr(repr).unwrap() + Fr::from_repr(FrRepr($field[..].try_into().unwrap())).unwrap() }}; } macro_rules! read_fs { ($field:expr) => {{ - let mut repr = FsRepr::default(); - repr.read_le(&$field[..]).unwrap(); - Fs::from_repr(repr).unwrap() + Fs::from_repr(FsRepr($field[..].try_into().unwrap())).unwrap() }}; } diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 6e01a1052..cd06a60a9 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -1,6 +1,6 @@ //! Structs for core Zcash primitives. -use ff::{Field, PrimeField, PrimeFieldRepr}; +use ff::{Field, PrimeField}; use crate::constants; @@ -86,7 +86,7 @@ impl ViewingKey { h[31] &= 0b0000_0111; let mut e = ::Repr::default(); - e.read_le(&h[..]).unwrap(); + e.as_mut().copy_from_slice(&h[..]); E::Fs::from_repr(e).expect("should be a valid scalar") } diff --git a/zcash_primitives/src/redjubjub.rs b/zcash_primitives/src/redjubjub.rs index fcc3900f6..c816ddfdd 100644 --- a/zcash_primitives/src/redjubjub.rs +++ b/zcash_primitives/src/redjubjub.rs @@ -4,23 +4,23 @@ //! [RedJubjub]: https://zips.z.cash/protocol/protocol.pdf#concretereddsa use crate::jubjub::{edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown}; -use ff::{Field, PrimeField, PrimeFieldRepr}; +use ff::{Field, PrimeField}; use rand_core::RngCore; use std::io::{self, Read, Write}; use std::ops::{AddAssign, MulAssign, Neg}; use crate::util::hash_to_scalar; -fn read_scalar(reader: R) -> io::Result { +fn read_scalar(mut reader: R) -> io::Result { let mut s_repr = ::Repr::default(); - s_repr.read_le(reader)?; + reader.read_exact(s_repr.as_mut())?; E::Fs::from_repr(s_repr) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "scalar is not in field")) + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "scalar is not in field")) } -fn write_scalar(s: &E::Fs, writer: W) -> io::Result<()> { - s.into_repr().write_le(writer) +fn write_scalar(s: &E::Fs, mut writer: W) -> io::Result<()> { + writer.write_all(s.into_repr().as_ref()) } fn h_star(a: &[u8], b: &[u8]) -> E::Fs { diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index ecf5cd400..4582fe663 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -5,7 +5,7 @@ use crate::{ pedersen_hash::{pedersen_hash, Personalization}, primitives::Note, }; -use ff::{BitIterator, PrimeField, PrimeFieldRepr}; +use ff::{BitIterator, PrimeField}; use lazy_static::lazy_static; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand_core::{CryptoRng, RngCore}; @@ -21,7 +21,7 @@ pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { let lhs = { let mut tmp = [false; 256]; - for (a, b) in tmp.iter_mut().rev().zip(BitIterator::::new(lhs)) { + for (a, b) in tmp.iter_mut().rev().zip(BitIterator::::new(lhs)) { *a = b; } tmp @@ -29,7 +29,7 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { let rhs = { let mut tmp = [false; 256]; - for (a, b) in tmp.iter_mut().rev().zip(BitIterator::::new(rhs)) { + for (a, b) in tmp.iter_mut().rev().zip(BitIterator::::new(rhs)) { *a = b; } tmp @@ -62,13 +62,13 @@ impl Node { impl Hashable for Node { fn read(mut reader: R) -> io::Result { - let mut repr = FrRepr::default(); - repr.read_le(&mut reader)?; + let mut repr = FrRepr([0; 32]); + reader.read_exact(&mut repr.0)?; Ok(Node::new(repr)) } fn write(&self, mut writer: W) -> io::Result<()> { - self.repr.write_le(&mut writer) + writer.write_all(self.repr.as_ref()) } fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self { diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index dfc54fdc6..d53ee7f15 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -2,7 +2,7 @@ use crate::jubjub::{edwards, Unknown}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use ff::{PrimeField, PrimeFieldRepr}; +use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use std::io::{self, Read, Write}; @@ -138,9 +138,10 @@ impl SpendDescription { // Consensus rule (§7.3): Canonical encoding is enforced here let anchor = { - let mut f = FrRepr::default(); - f.read_le(&mut reader)?; - Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))? + let mut f = FrRepr([0; 32]); + reader.read_exact(&mut f.0)?; + Fr::from_repr(f) + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "anchor not in field"))? }; let mut nullifier = [0; 32]; @@ -175,7 +176,7 @@ impl SpendDescription { pub fn write(&self, mut writer: W) -> io::Result<()> { self.cv.write(&mut writer)?; - self.anchor.into_repr().write_le(&mut writer)?; + writer.write_all(self.anchor.into_repr().as_ref())?; writer.write_all(&self.nullifier)?; self.rk.write(&mut writer)?; writer.write_all(&self.zkproof)?; @@ -218,9 +219,10 @@ impl OutputDescription { // Consensus rule (§7.4): Canonical encoding is enforced here let cmu = { - let mut f = FrRepr::default(); - f.read_le(&mut reader)?; - Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))? + let mut f = FrRepr([0; 32]); + reader.read_exact(&mut f.0)?; + Fr::from_repr(f) + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "cmu not in field"))? }; // Consensus rules (§4.5): @@ -252,7 +254,7 @@ impl OutputDescription { pub fn write(&self, mut writer: W) -> io::Result<()> { self.cv.write(&mut writer)?; - self.cmu.into_repr().write_le(&mut writer)?; + writer.write_all(self.cmu.into_repr().as_ref())?; self.ephemeral_key.write(&mut writer)?; writer.write_all(&self.enc_ciphertext)?; writer.write_all(&self.out_ciphertext)?; diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index 4319f4175..c77c2d0a1 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -1,6 +1,6 @@ use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use byteorder::{LittleEndian, WriteBytesExt}; -use ff::{PrimeField, PrimeFieldRepr}; +use ff::PrimeField; use super::{ components::{Amount, TxOut}, @@ -128,7 +128,7 @@ fn shielded_spends_hash(tx: &TransactionData) -> Blake2bHash { let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384); for s_spend in &tx.shielded_spends { s_spend.cv.write(&mut data).unwrap(); - s_spend.anchor.into_repr().write_le(&mut data).unwrap(); + data.extend_from_slice(s_spend.anchor.into_repr().as_ref()); data.extend_from_slice(&s_spend.nullifier); s_spend.rk.write(&mut data).unwrap(); data.extend_from_slice(&s_spend.zkproof); diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index e34767b46..a02457f64 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -453,7 +453,7 @@ impl ExtendedFullViewingKey { mod tests { use super::*; - use ff::{PrimeField, PrimeFieldRepr}; + use ff::PrimeField; #[test] fn derive_nonhardened_child() { @@ -1014,11 +1014,8 @@ mod tests { let xsk = &xsks[j]; let tv = &test_vectors[j]; - let mut buf = [0; 32]; - xsk.expsk.ask.into_repr().write_le(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.ask.unwrap()); - xsk.expsk.nsk.into_repr().write_le(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.nsk.unwrap()); + assert_eq!(xsk.expsk.ask.into_repr().as_ref(), tv.ask.unwrap()); + assert_eq!(xsk.expsk.nsk.into_repr().as_ref(), tv.nsk.unwrap()); assert_eq!(xsk.expsk.ovk.0, tv.ovk); assert_eq!(xsk.dk.0, tv.dk); @@ -1043,13 +1040,7 @@ mod tests { assert_eq!(xfvk.dk.0, tv.dk); assert_eq!(xfvk.chain_code.0, tv.c); - xfvk.fvk - .vk - .ivk() - .into_repr() - .write_le(&mut buf[..]) - .unwrap(); - assert_eq!(buf, tv.ivk); + assert_eq!(xfvk.fvk.vk.ivk().into_repr().as_ref(), tv.ivk); let mut ser = vec![]; xfvk.write(&mut ser).unwrap(); diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index 01ed2d436..59eb7614f 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -769,7 +769,7 @@ mod test { let q = p.mul(s, params); let (x1, y1) = q.to_xy(); - let mut s_bits = BitIterator::::new(s.into_repr()).collect::>(); + let mut s_bits = BitIterator::::new(s.into_repr()).collect::>(); s_bits.reverse(); s_bits.truncate(Fs::NUM_BITS as usize); @@ -822,7 +822,7 @@ mod test { y: num_y0, }; - let mut s_bits = BitIterator::::new(s.into_repr()).collect::>(); + let mut s_bits = BitIterator::::new(s.into_repr()).collect::>(); s_bits.reverse(); s_bits.truncate(Fs::NUM_BITS as usize); diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index 7d1fbbabd..5e6c05f1b 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -615,8 +615,8 @@ fn test_input_circuit_with_bls12_381() { ::std::mem::swap(&mut lhs, &mut rhs); } - let mut lhs: Vec = BitIterator::::new(lhs.into_repr()).collect(); - let mut rhs: Vec = BitIterator::::new(rhs.into_repr()).collect(); + let mut lhs: Vec = BitIterator::::new(lhs.into_repr()).collect(); + let mut rhs: Vec = BitIterator::::new(rhs.into_repr()).collect(); lhs.reverse(); rhs.reverse(); @@ -799,8 +799,8 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() { ::std::mem::swap(&mut lhs, &mut rhs); } - let mut lhs: Vec = BitIterator::::new(lhs.into_repr()).collect(); - let mut rhs: Vec = BitIterator::::new(rhs.into_repr()).collect(); + let mut lhs: Vec = BitIterator::::new(lhs.into_repr()).collect(); + let mut rhs: Vec = BitIterator::::new(rhs.into_repr()).collect(); lhs.reverse(); rhs.reverse();