Merge pull request #223 from str4d/remove-primefieldrepr

Remove ff::PrimeFieldRepr
This commit is contained in:
str4d 2020-05-01 08:59:41 +12:00 committed by GitHub
commit b02cf3b467
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 2303 additions and 3752 deletions

View File

@ -11,7 +11,7 @@
//! [`EvaluationDomain`]: crate::domain::EvaluationDomain //! [`EvaluationDomain`]: crate::domain::EvaluationDomain
//! [Groth16]: https://eprint.iacr.org/2016/260 //! [Groth16]: https://eprint.iacr.org/2016/260
use ff::{Field, PrimeField, ScalarEngine}; use ff::{Field, PowVartime, PrimeField, ScalarEngine};
use group::CurveProjective; use group::CurveProjective;
use std::ops::{AddAssign, MulAssign, SubAssign}; use std::ops::{AddAssign, MulAssign, SubAssign};

View File

@ -313,12 +313,12 @@ pub fn field_into_allocated_bits_le<E: ScalarEngine, CS: ConstraintSystem<E>, F:
// Deconstruct in big-endian bit order // Deconstruct in big-endian bit order
let values = match value { let values = match value {
Some(ref value) => { Some(ref value) => {
let mut field_char = BitIterator::new(F::char()); let mut field_char = BitIterator::<u8, _>::new(F::char());
let mut tmp = Vec::with_capacity(F::NUM_BITS as usize); let mut tmp = Vec::with_capacity(F::NUM_BITS as usize);
let mut found_one = false; let mut found_one = false;
for b in BitIterator::new(value.into_repr()) { for b in BitIterator::<u8, _>::new(value.into_repr()) {
// Skip leading bits // Skip leading bits
found_one |= field_char.next().unwrap(); found_one |= field_char.next().unwrap();
if !found_one { if !found_one {

View File

@ -1,4 +1,4 @@
use ff::{Field, PrimeField, ScalarEngine}; use ff::{PowVartime, PrimeField, ScalarEngine};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};

View File

@ -1,6 +1,6 @@
//! Gadgets representing numbers in the scalar field of the underlying curve. //! 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 std::ops::{AddAssign, MulAssign};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
@ -103,9 +103,8 @@ impl<E: ScalarEngine> AllocatedNum<E> {
// We want to ensure that the bit representation of a is // We want to ensure that the bit representation of a is
// less than or equal to r - 1. // 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::<u8, _>::new(e.into_repr()));
let mut b = E::Fr::char(); let b = (-E::Fr::one()).into_repr();
b.sub_noborrow(&1.into());
let mut result = vec![]; let mut result = vec![];
@ -115,7 +114,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
let mut found_one = false; let mut found_one = false;
let mut i = 0; let mut i = 0;
for b in BitIterator::new(b) { for b in BitIterator::<u8, _>::new(b) {
let a_bit = a.as_mut().map(|e| e.next().unwrap()); let a_bit = a.as_mut().map(|e| e.next().unwrap());
// Skip over unset bits at the beginning // Skip over unset bits at the beginning
@ -558,7 +557,7 @@ mod test {
assert!(cs.is_satisfied()); assert!(cs.is_satisfied());
for (b, a) in BitIterator::new(r.into_repr()) for (b, a) in BitIterator::<u8, _>::new(r.into_repr())
.skip(1) .skip(1)
.zip(bits.iter().rev()) .zip(bits.iter().rev())
{ {

View File

@ -1,6 +1,6 @@
//! Helpers for testing circuit implementations. //! Helpers for testing circuit implementations.
use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; use ff::{Field, PowVartime, PrimeField, ScalarEngine};
use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
@ -106,7 +106,12 @@ fn hash_lc<E: ScalarEngine>(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); h.update(&buf);
} }

View File

@ -2,7 +2,7 @@ use rand_core::RngCore;
use std::ops::{AddAssign, MulAssign}; use std::ops::{AddAssign, MulAssign};
use std::sync::Arc; use std::sync::Arc;
use ff::{Field, PrimeField}; use ff::{Field, PowVartime};
use group::{CurveAffine, CurveProjective, Wnaf}; use group::{CurveAffine, CurveProjective, Wnaf};
use pairing::Engine; use pairing::Engine;
@ -273,7 +273,7 @@ where
exp.mul_assign(&coeff); exp.mul_assign(&coeff);
// Exponentiate // Exponentiate
*h = g1_wnaf.scalar(exp.into_repr()); *h = g1_wnaf.scalar(&exp);
} }
// Batch normalize // Batch normalize
@ -376,14 +376,14 @@ where
// Compute A query (in G1) // Compute A query (in G1)
if !at.is_zero() { if !at.is_zero() {
*a = g1_wnaf.scalar(at.into_repr()); *a = g1_wnaf.scalar(&at);
} }
// Compute B query (in G1/G2) // Compute B query (in G1/G2)
if !bt.is_zero() { if !bt.is_zero() {
let bt_repr = bt.into_repr(); ();
*b_g1 = g1_wnaf.scalar(bt_repr); *b_g1 = g1_wnaf.scalar(&bt);
*b_g2 = g2_wnaf.scalar(bt_repr); *b_g2 = g2_wnaf.scalar(&bt);
} }
at.mul_assign(&beta); at.mul_assign(&beta);
@ -394,7 +394,7 @@ where
e.add_assign(&ct); e.add_assign(&ct);
e.mul_assign(inv); e.mul_assign(inv);
*ext = g1_wnaf.scalar(e.into_repr()); *ext = g1_wnaf.scalar(&e);
} }
// Batch normalize // Batch normalize

View File

@ -4,7 +4,7 @@ use std::sync::Arc;
use futures::Future; use futures::Future;
use ff::{Field, PrimeField}; use ff::Field;
use group::{CurveAffine, CurveProjective}; use group::{CurveAffine, CurveProjective};
use pairing::Engine; use pairing::Engine;
@ -229,26 +229,14 @@ where
let a_len = a.len() - 1; let a_len = a.len() - 1;
a.truncate(a_len); a.truncate(a_len);
// TODO: parallelize if it's even helpful // TODO: parallelize if it's even helpful
let a = Arc::new(a.into_iter().map(|s| s.0.into_repr()).collect::<Vec<_>>()); let a = Arc::new(a.into_iter().map(|s| s.0).collect::<Vec<_>>());
multiexp(&worker, params.get_h(a.len())?, FullDensity, a) multiexp(&worker, params.get_h(a.len())?, FullDensity, a)
}; };
// TODO: parallelize if it's even helpful // TODO: parallelize if it's even helpful
let input_assignment = Arc::new( let input_assignment = Arc::new(prover.input_assignment);
prover let aux_assignment = Arc::new(prover.aux_assignment);
.input_assignment
.into_iter()
.map(|s| s.into_repr())
.collect::<Vec<_>>(),
);
let aux_assignment = Arc::new(
prover
.aux_assignment
.into_iter()
.map(|s| s.into_repr())
.collect::<Vec<_>>(),
);
let l = multiexp( let l = multiexp(
&worker, &worker,

View File

@ -1,4 +1,4 @@
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField}; use ff::{Field, PowVartime, PrimeField, ScalarEngine, SqrtField};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use pairing::{Engine, PairingCurveAffine}; use pairing::{Engine, PairingCurveAffine};
@ -6,7 +6,7 @@ use rand_core::RngCore;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
use std::num::Wrapping; 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}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
const MODULUS_R: Wrapping<u32> = Wrapping(64513); const MODULUS_R: Wrapping<u32> = Wrapping(64513);
@ -32,6 +32,12 @@ impl fmt::Display for Fr {
} }
} }
impl From<u64> for Fr {
fn from(v: u64) -> Fr {
Fr(Wrapping((v % MODULUS_R.0 as u64) as u32))
}
}
impl ConditionallySelectable for Fr { impl ConditionallySelectable for Fr {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fr(Wrapping(u32::conditional_select( Fr(Wrapping(u32::conditional_select(
@ -42,6 +48,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<Ordering> {
Some(self.cmp(other))
}
}
impl Neg for Fr { impl Neg for Fr {
type Output = Self; type Output = Self;
@ -143,6 +161,23 @@ impl MulAssign for Fr {
} }
} }
impl BitAnd<u64> for Fr {
type Output = u64;
fn bitand(self, rhs: u64) -> u64 {
(self.0).0 as u64 & rhs
}
}
impl Shr<u32> for Fr {
type Output = Fr;
fn shr(mut self, rhs: u32) -> Fr {
self.0 = Wrapping((self.0).0 >> rhs);
self
}
}
impl Field for Fr { impl Field for Fr {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self { fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Fr(Wrapping(rng.next_u32()) % MODULUS_R) Fr(Wrapping(rng.next_u32()) % MODULUS_R)
@ -190,9 +225,9 @@ impl SqrtField for Fr {
// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
let mut c = Fr::root_of_unity(); let mut c = Fr::root_of_unity();
// r = self^((t + 1) // 2) // r = self^((t + 1) // 2)
let mut r = self.pow_vartime([32]); let mut r = self.pow_vartime([32u64]);
// t = self^t // t = self^t
let mut t = self.pow_vartime([63]); let mut t = self.pow_vartime([63u64]);
let mut m = Fr::S; let mut m = Fr::S;
while t != <Fr as Field>::one() { while t != <Fr as Field>::one() {
@ -222,86 +257,35 @@ impl SqrtField for Fr {
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct FrRepr([u64; 1]); pub struct FrRepr([u8; 8]);
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<Ordering> {
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<u64> for FrRepr {
fn from(v: u64) -> FrRepr {
FrRepr([v])
}
}
impl From<Fr> for FrRepr { impl From<Fr> for FrRepr {
fn from(v: Fr) -> FrRepr { fn from(v: Fr) -> FrRepr {
FrRepr([(v.0).0 as u64]) FrRepr::from(&v)
} }
} }
impl AsMut<[u64]> for FrRepr { impl<'a> From<&'a Fr> for FrRepr {
fn as_mut(&mut self) -> &mut [u64] { 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[..] &mut self.0[..]
} }
} }
impl AsRef<[u64]> for FrRepr { impl AsRef<[u8]> for FrRepr {
fn as_ref(&self) -> &[u64] { fn as_ref(&self) -> &[u8] {
&self.0[..] &self.0[..]
} }
} }
impl Default for FrRepr { impl Default for FrRepr {
fn default() -> FrRepr { fn default() -> FrRepr {
FrRepr::from(0u64) FrRepr([0; 8])
}
}
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;
} }
} }
@ -312,11 +296,12 @@ impl PrimeField for Fr {
const CAPACITY: u32 = 15; const CAPACITY: u32 = 15;
const S: u32 = 10; const S: u32 = 10;
fn from_repr(repr: FrRepr) -> Result<Self, PrimeFieldDecodingError> { fn from_repr(repr: FrRepr) -> Option<Self> {
if repr.0[0] >= (MODULUS_R.0 as u64) { let v = u64::from_le_bytes(repr.0);
Err(PrimeFieldDecodingError::NotInField) if v >= (MODULUS_R.0 as u64) {
None
} else { } else {
Ok(Fr(Wrapping(repr.0[0] as u32))) Some(Fr(Wrapping(v as u32)))
} }
} }
@ -324,6 +309,10 @@ impl PrimeField for Fr {
FrRepr::from(*self) FrRepr::from(*self)
} }
fn is_odd(&self) -> bool {
(self.0).0 % 2 != 0
}
fn char() -> FrRepr { fn char() -> FrRepr {
Fr(MODULUS_R).into() Fr(MODULUS_R).into()
} }
@ -423,7 +412,7 @@ impl CurveProjective for Fr {
*self *self
} }
fn recommended_wnaf_for_scalar(_: <Self::Scalar as PrimeField>::Repr) -> usize { fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize {
3 3
} }

View File

@ -1,4 +1,4 @@
use ff::{Field, PrimeField}; use ff::{Field, PowVartime, PrimeField};
use pairing::Engine; use pairing::Engine;
mod dummy_engine; mod dummy_engine;
@ -127,22 +127,22 @@ fn test_xordemo() {
let mut root_of_unity = Fr::root_of_unity(); let mut root_of_unity = Fr::root_of_unity();
// We expect this to be a 2^10 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. // Let's turn it into a 2^3 root of unity.
root_of_unity = root_of_unity.pow_vartime(&[1 << 7]); root_of_unity = root_of_unity.pow_vartime(&[1u64 << 7]);
assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1 << 3])); assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1u64 << 3]));
assert_eq!(Fr::from_str("20201").unwrap(), root_of_unity); assert_eq!(Fr::from_str("20201").unwrap(), root_of_unity);
// Let's compute all the points in our evaluation domain. // Let's compute all the points in our evaluation domain.
let mut points = Vec::with_capacity(8); 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])); points.push(root_of_unity.pow_vartime(&[i]));
} }
// Let's compute t(tau) = (tau - p_0)(tau - p_1)... // Let's compute t(tau) = (tau - p_0)(tau - p_1)...
// = tau^8 - 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()); t_at_tau.sub_assign(&Fr::one());
{ {
let mut tmp = Fr::one(); let mut tmp = Fr::one();

View File

@ -1,6 +1,6 @@
use super::multicore::Worker; use super::multicore::Worker;
use bit_vec::{self, BitVec}; use bit_vec::{self, BitVec};
use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; use ff::{Field, PrimeField, ScalarEngine};
use futures::Future; use futures::Future;
use group::{CurveAffine, CurveProjective}; use group::{CurveAffine, CurveProjective};
use std::io; use std::io;
@ -154,7 +154,7 @@ fn multiexp_inner<Q, D, G, S>(
pool: &Worker, pool: &Worker,
bases: S, bases: S,
density_map: D, density_map: D,
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>, exponents: Arc<Vec<<G::Engine as ScalarEngine>::Fr>>,
mut skip: u32, mut skip: u32,
c: u32, c: u32,
handle_trivial: bool, handle_trivial: bool,
@ -181,13 +181,12 @@ where
// Create space for the buckets // Create space for the buckets
let mut buckets = vec![G::zero(); (1 << c) - 1]; let mut buckets = vec![G::zero(); (1 << c) - 1];
let zero = <G::Engine as ScalarEngine>::Fr::zero().into_repr(); let one = <G::Engine as ScalarEngine>::Fr::one();
let one = <G::Engine as ScalarEngine>::Fr::one().into_repr();
// Sort the bases into buckets // Sort the bases into buckets
for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) { for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) {
if density { if density {
if exp == zero { if exp.is_zero() {
bases.skip(1)?; bases.skip(1)?;
} else if exp == one { } else if exp == one {
if handle_trivial { if handle_trivial {
@ -196,9 +195,8 @@ where
bases.skip(1)?; bases.skip(1)?;
} }
} else { } else {
let mut exp = exp; let exp = exp >> skip;
exp.shr(skip); let exp = exp & ((1 << c) - 1);
let exp = exp.as_ref()[0] % (1 << c);
if exp != 0 { if exp != 0 {
(&mut buckets[(exp - 1) as usize]) (&mut buckets[(exp - 1) as usize])
@ -261,7 +259,7 @@ pub fn multiexp<Q, D, G, S>(
pool: &Worker, pool: &Worker,
bases: S, bases: S,
density_map: D, density_map: D,
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>, exponents: Arc<Vec<<G::Engine as ScalarEngine>::Fr>>,
) -> Box<dyn Future<Item = G, Error = SynthesisError>> ) -> Box<dyn Future<Item = G, Error = SynthesisError>>
where where
for<'a> &'a Q: QueryDensity, for<'a> &'a Q: QueryDensity,
@ -290,14 +288,14 @@ where
fn test_with_bls12() { fn test_with_bls12() {
fn naive_multiexp<G: CurveProjective>( fn naive_multiexp<G: CurveProjective>(
bases: Arc<Vec<<G as CurveProjective>::Affine>>, bases: Arc<Vec<<G as CurveProjective>::Affine>>,
exponents: Arc<Vec<<G::Scalar as PrimeField>::Repr>>, exponents: Arc<Vec<G::Scalar>>,
) -> G { ) -> G {
assert_eq!(bases.len(), exponents.len()); assert_eq!(bases.len(), exponents.len());
let mut acc = G::zero(); let mut acc = G::zero();
for (base, exp) in bases.iter().zip(exponents.iter()) { 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 acc
@ -311,7 +309,7 @@ fn test_with_bls12() {
let rng = &mut rand::thread_rng(); let rng = &mut rand::thread_rng();
let v = Arc::new( let v = Arc::new(
(0..SAMPLES) (0..SAMPLES)
.map(|_| <Bls12 as ScalarEngine>::Fr::random(rng).into_repr()) .map(|_| <Bls12 as ScalarEngine>::Fr::random(rng))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); );
let g = Arc::new( let g = Arc::new(

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,10 @@ extern crate std;
#[cfg(feature = "derive")] #[cfg(feature = "derive")]
pub use ff_derive::*; pub use ff_derive::*;
use core::convert::TryFrom;
use core::fmt; use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use core::marker::PhantomData;
use core::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign};
use rand_core::RngCore; use rand_core::RngCore;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
@ -73,21 +75,36 @@ pub trait Field:
/// Exponentiates this element by a power of the base prime modulus via /// Exponentiates this element by a power of the base prime modulus via
/// the Frobenius automorphism. /// the Frobenius automorphism.
fn frobenius_map(&mut self, power: usize); fn frobenius_map(&mut self, power: usize);
}
pub trait PowVartime<L>: Field
where
L: Copy + PartialEq + PartialOrd + AddAssign,
L: BitAnd<Output = L>,
L: Shr<Output = L>,
L: Sub<Output = L>,
{
const ZERO: L;
const ONE: L;
const LIMB_SIZE: L;
/// Exponentiates `self` by `exp`, where `exp` is a little-endian order /// Exponentiates `self` by `exp`, where `exp` is a little-endian order
/// integer exponent. /// integer exponent.
/// ///
/// **This operation is variable time with respect to the exponent.** If the /// **This operation is variable time with respect to the exponent.** If the
/// exponent is fixed, this operation is effectively constant time. /// exponent is fixed, this operation is effectively constant time.
fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self { fn pow_vartime<S: AsRef<[L]>>(&self, exp: S) -> Self {
let mut res = Self::one(); let mut res = Self::one();
for e in exp.as_ref().iter().rev() { 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(); res = res.square();
if ((*e >> i) & 1) == 1 { if ((*e >> (Self::LIMB_SIZE - Self::ONE - i)) & Self::ONE) == Self::ONE {
res.mul_assign(self); res.mul_assign(self);
} }
i += Self::ONE;
} }
} }
@ -95,6 +112,18 @@ pub trait Field:
} }
} }
impl<T: Field> PowVartime<u8> for T {
const ZERO: u8 = 0;
const ONE: u8 = 1;
const LIMB_SIZE: u8 = 8;
}
impl<T: Field> PowVartime<u64> 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. /// This trait represents an element of a field that has a square root operation described for it.
pub trait SqrtField: Field { pub trait SqrtField: Field {
/// Returns the square root of the field element, if it is /// Returns the square root of the field element, if it is
@ -102,137 +131,13 @@ pub trait SqrtField: Field {
fn sqrt(&self) -> CtOption<Self>; fn sqrt(&self) -> CtOption<Self>;
} }
/// 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<u64>
{
/// 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<W: Write>(&self, mut writer: W) -> io::Result<()> {
use byteorder::{BigEndian, WriteBytesExt};
for digit in self.as_ref().iter().rev() {
writer.write_u64::<BigEndian>(*digit)?;
}
Ok(())
}
/// Reads a big endian integer into this representation.
#[cfg(feature = "std")]
fn read_be<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
use byteorder::{BigEndian, ReadBytesExt};
for digit in self.as_mut().iter_mut().rev() {
*digit = reader.read_u64::<BigEndian>()?;
}
Ok(())
}
/// Writes this `PrimeFieldRepr` as a little endian integer.
#[cfg(feature = "std")]
fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
use byteorder::{LittleEndian, WriteBytesExt};
for digit in self.as_ref().iter() {
writer.write_u64::<LittleEndian>(*digit)?;
}
Ok(())
}
/// Reads a little endian integer into this representation.
#[cfg(feature = "std")]
fn read_le<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
use byteorder::{LittleEndian, ReadBytesExt};
for digit in self.as_mut().iter_mut() {
*digit = reader.read_u64::<LittleEndian>()?;
}
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. /// This represents an element of a prime field.
pub trait PrimeField: Field { pub trait PrimeField:
/// The prime field can be converted back and forth into this biginteger Field + Ord + From<u64> + BitAnd<u64, Output = u64> + Shr<u32, Output = Self>
{
/// The prime field can be converted back and forth into this binary
/// representation. /// representation.
type Repr: PrimeFieldRepr + From<Self>; type Repr: Default + AsRef<[u8]> + AsMut<[u8]> + From<Self> + for<'r> From<&'r Self>;
/// Interpret a string of numbers as a (congruent) prime field element. /// Interpret a string of numbers as a (congruent) prime field element.
/// Does not accept unnecessary leading zeroes or a blank string. /// Does not accept unnecessary leading zeroes or a blank string.
@ -247,7 +152,7 @@ pub trait PrimeField: Field {
let mut res = Self::zero(); 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; let mut first_digit = true;
@ -263,7 +168,7 @@ pub trait PrimeField: Field {
} }
res.mul_assign(&ten); 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 => { None => {
return None; return None;
@ -274,13 +179,31 @@ pub trait PrimeField: Field {
Some(res) Some(res)
} }
/// Convert this prime field element into a biginteger representation. /// Attempts to convert a byte representation of a field element into an element of
fn from_repr(_: Self::Repr) -> Result<Self, PrimeFieldDecodingError>; /// 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<Self>;
/// Convert a biginteger representation into a prime field element, if /// Converts an element of the prime field into the standard byte representation for
/// the number is an element of the field. /// 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; 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. /// Returns the field characteristic; the modulus.
fn char() -> Self::Repr; fn char() -> Self::Repr;
@ -311,20 +234,25 @@ pub trait ScalarEngine: Sized + 'static + Clone {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct BitIterator<E> { pub struct BitIterator<T, E: AsRef<[T]>> {
t: E, t: E,
n: usize, n: usize,
_limb: PhantomData<T>,
} }
impl<E: AsRef<[u64]>> BitIterator<E> { impl<E: AsRef<[u64]>> BitIterator<u64, E> {
pub fn new(t: E) -> Self { pub fn new(t: E) -> Self {
let n = t.as_ref().len() * 64; let n = t.as_ref().len() * 64;
BitIterator { t, n } BitIterator {
t,
n,
_limb: PhantomData::default(),
}
} }
} }
impl<E: AsRef<[u64]>> Iterator for BitIterator<E> { impl<E: AsRef<[u64]>> Iterator for BitIterator<u64, E> {
type Item = bool; type Item = bool;
fn next(&mut self) -> Option<bool> { fn next(&mut self) -> Option<bool> {
@ -340,9 +268,37 @@ impl<E: AsRef<[u64]>> Iterator for BitIterator<E> {
} }
} }
impl<E: AsRef<[u8]>> BitIterator<u8, E> {
pub fn new(t: E) -> Self {
let n = t.as_ref().len() * 8;
BitIterator {
t,
n,
_limb: PhantomData::default(),
}
}
}
impl<E: AsRef<[u8]>> Iterator for BitIterator<u8, E> {
type Item = bool;
fn next(&mut self) -> Option<bool> {
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] #[test]
fn test_bit_iterator() { fn test_bit_iterator() {
let mut a = BitIterator::new([0xa953_d79b_83f6_ab59, 0x6dea_2059_e200_bd39]); let mut a = BitIterator::<u64, _>::new([0xa953_d79b_83f6_ab59, 0x6dea_2059_e200_bd39]);
let expected = "01101101111010100010000001011001111000100000000010111101001110011010100101010011110101111001101110000011111101101010101101011001"; let expected = "01101101111010100010000001011001111000100000000010111101001110011010100101010011110101111001101110000011111101101010101101011001";
for e in expected.chars() { for e in expected.chars() {
@ -353,7 +309,7 @@ fn test_bit_iterator() {
let expected = "1010010101111110101010000101101011101000011101110101001000011001100100100011011010001011011011010001011011101100110100111011010010110001000011110100110001100110011101101000101100011100100100100100001010011101010111110011101011000011101000111011011101011001"; let expected = "1010010101111110101010000101101011101000011101110101001000011001100100100011011010001011011011010001011011101100110100111011010010110001000011110100110001100110011101101000101100011100100100100100001010011101010111110011101011000011101000111011011101011001";
let mut a = BitIterator::new([ let mut a = BitIterator::<u64, _>::new([
0x429d_5f3a_c3a3_b759, 0x429d_5f3a_c3a3_b759,
0xb10f_4c66_768b_1c92, 0xb10f_4c66_768b_1c92,
0x9236_8b6d_16ec_d3b4, 0x9236_8b6d_16ec_d3b4,

View File

@ -15,6 +15,7 @@ repository = "https://github.com/ebfull/group"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
byteorder = { version = "1", default-features = false }
ff = { version = "0.6", path = "../ff" } ff = { version = "0.6", path = "../ff" }
rand = "0.7" rand = "0.7"
rand_xorshift = "0.2" rand_xorshift = "0.2"

View File

@ -1,7 +1,7 @@
// Catch documentation errors caused by code changes. // Catch documentation errors caused by code changes.
#![deny(intra_doc_link_resolution_failure)] #![deny(intra_doc_link_resolution_failure)]
use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField}; use ff::{PrimeField, ScalarEngine, SqrtField};
use rand::RngCore; use rand::RngCore;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
@ -82,7 +82,7 @@ pub trait CurveProjective:
/// Recommends a wNAF window table size given a scalar. Always returns a number /// Recommends a wNAF window table size given a scalar. Always returns a number
/// between 2 and 22, inclusive. /// between 2 and 22, inclusive.
fn recommended_wnaf_for_scalar(scalar: <Self::Scalar as PrimeField>::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 /// 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. /// 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. /// The element is not part of the r-order subgroup.
NotInSubgroup, NotInSubgroup,
/// One of the coordinates could not be decoded /// 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 /// The compression mode of the encoded element was not as expected
UnexpectedCompressionMode, UnexpectedCompressionMode,
/// The encoding contained bits that should not have been set /// The encoding contained bits that should not have been set
@ -202,8 +202,8 @@ impl Error for GroupDecodingError {
impl fmt::Display for GroupDecodingError { impl fmt::Display for GroupDecodingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match *self { match *self {
GroupDecodingError::CoordinateDecodingError(description, ref err) => { GroupDecodingError::CoordinateDecodingError(description) => {
write!(f, "{} decoding error: {}", description, err) write!(f, "{} decoding error", description)
} }
_ => write!(f, "{}", self.description()), _ => write!(f, "{}", self.description()),
} }

View File

@ -85,12 +85,12 @@ fn random_wnaf_tests<G: CurveProjective>() {
for w in 2..14 { for w in 2..14 {
for _ in 0..100 { for _ in 0..100 {
let g = G::random(&mut rng); 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; let mut g1 = g;
g1.mul_assign(s); g1.mul_assign(s);
wnaf_table(&mut table, g, w); 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); let g2 = wnaf_exp(&table, &wnaf);
assert_eq!(g1, g2); assert_eq!(g1, g2);
@ -103,17 +103,17 @@ fn random_wnaf_tests<G: CurveProjective>() {
for _ in 0..100 { for _ in 0..100 {
let g = G::random(&mut rng); 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; let mut g1 = g;
g1.mul_assign(s); g1.mul_assign(s);
let g2 = { let g2 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
wnaf.base(g, 1).scalar(s) wnaf.base(g, 1).scalar(&s)
}; };
let g3 = { let g3 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
wnaf.scalar(s).base(g) wnaf.scalar(&s).base(g)
}; };
let g4 = { let g4 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
@ -121,11 +121,11 @@ fn random_wnaf_tests<G: CurveProjective>() {
only_compiles_if_send(&shared); only_compiles_if_send(&shared);
shared.scalar(s) shared.scalar(&s)
}; };
let g5 = { let g5 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
let mut shared = wnaf.scalar(s).shared(); let mut shared = wnaf.scalar(&s).shared();
only_compiles_if_send(&shared); only_compiles_if_send(&shared);
@ -137,40 +137,40 @@ fn random_wnaf_tests<G: CurveProjective>() {
{ {
// Populate the vectors. // Populate the vectors.
wnaf.base(G::random(&mut rng), 1) 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 g7 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
{ {
// Populate the vectors. // Populate the vectors.
wnaf.base(G::random(&mut rng), 1) 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 g8 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
{ {
// Populate the vectors. // Populate the vectors.
wnaf.base(G::random(&mut rng), 1) 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(); let mut shared = wnaf.base(g, 1).shared();
only_compiles_if_send(&shared); only_compiles_if_send(&shared);
shared.scalar(s) shared.scalar(&s)
}; };
let g9 = { let g9 = {
let mut wnaf = Wnaf::new(); let mut wnaf = Wnaf::new();
{ {
// Populate the vectors. // Populate the vectors.
wnaf.base(G::random(&mut rng), 1) 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); only_compiles_if_send(&shared);

View File

@ -1,4 +1,6 @@
use ff::{PrimeField, PrimeFieldRepr}; use byteorder::{ByteOrder, LittleEndian};
use ff::PrimeField;
use std::iter;
use super::CurveProjective; use super::CurveProjective;
@ -16,31 +18,60 @@ pub(crate) fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, wi
} }
} }
/// Replaces the contents of `wnaf` with the w-NAF representation of a scalar. /// Replaces the contents of `wnaf` with the w-NAF representation of a little-endian
pub(crate) fn wnaf_form<S: PrimeFieldRepr>(wnaf: &mut Vec<i64>, mut c: S, window: usize) { /// scalar.
pub(crate) fn wnaf_form<S: AsRef<[u8]>>(wnaf: &mut Vec<i64>, 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); wnaf.truncate(0);
while !c.is_zero() { let bit_len = c.as_ref().len() * 8;
let mut u; let u64_len = (bit_len + 1) / 64;
if c.is_odd() {
u = (c.as_ref()[0] % (1 << (window + 1))) as i64;
if u > (1 << window) { let mut c_u64 = vec![0u64; u64_len + 1];
u -= 1 << (window + 1); LittleEndian::read_u64_into(c.as_ref(), &mut c_u64[0..u64_len]);
}
if u > 0 { let width = 1u64 << window;
c.sub_noborrow(&S::from(u as u64)); let window_mask = width - 1;
} else {
c.add_nocarry(&S::from((-u) as u64)); 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 { } 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,13 +143,13 @@ impl<G: CurveProjective> Wnaf<(), Vec<G>, Vec<i64>> {
/// exponentiations with `.base(..)`. /// exponentiations with `.base(..)`.
pub fn scalar( pub fn scalar(
&mut self, &mut self,
scalar: <<G as CurveProjective>::Scalar as PrimeField>::Repr, scalar: &<G as CurveProjective>::Scalar,
) -> Wnaf<usize, &mut Vec<G>, &[i64]> { ) -> Wnaf<usize, &mut Vec<G>, &[i64]> {
// Compute the appropriate window size for the scalar. // 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. // 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 // Return a Wnaf object that mutably borrows the base storage location, but
// immutably borrows the computed wNAF form scalar location. // immutably borrows the computed wNAF form scalar location.
@ -168,14 +199,11 @@ impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> { impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> {
/// Performs exponentiation given a scalar. /// Performs exponentiation given a scalar.
pub fn scalar<G: CurveProjective>( pub fn scalar<G: CurveProjective>(&mut self, scalar: &<G as CurveProjective>::Scalar) -> G
&mut self,
scalar: <<G as CurveProjective>::Scalar as PrimeField>::Repr,
) -> G
where where
B: AsRef<[G]>, 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()) wnaf_exp(self.base.as_ref(), self.scalar.as_mut())
} }
} }

View File

@ -3,140 +3,9 @@ use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; use ff::{Field, PrimeField, SqrtField};
use pairing::bls12_381::*; 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<FqRepr> = (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<FqRepr> = (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<FqRepr> = (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) { fn bench_fq_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000; const SAMPLES: usize = 1000;
@ -328,11 +197,6 @@ fn bench_fq_from_repr(c: &mut Criterion) {
criterion_group!( criterion_group!(
benches, 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_add_assign,
bench_fq_sub_assign, bench_fq_sub_assign,
bench_fq_mul_assign, bench_fq_mul_assign,

View File

@ -3,140 +3,9 @@ use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; use ff::{Field, PrimeField, SqrtField};
use pairing::bls12_381::*; 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<FrRepr> = (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<FrRepr> = (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<FrRepr> = (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) { fn bench_fr_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000; const SAMPLES: usize = 1000;
@ -328,11 +197,6 @@ fn bench_fr_from_repr(c: &mut Criterion) {
criterion_group!( criterion_group!(
benches, 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_add_assign,
bench_fr_sub_assign, bench_fr_sub_assign,
bench_fr_mul_assign, bench_fr_mul_assign,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE}; use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
use ff::{Field, SqrtField}; use ff::{Field, PowVartime, SqrtField};
use rand_core::RngCore; use rand_core::RngCore;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
@ -254,7 +254,7 @@ impl SqrtField for Fq2 {
} else { } else {
// a1 = self^((q - 3) / 4) // a1 = self^((q - 3) / 4)
let mut a1 = self.pow_vartime([ let mut a1 = self.pow_vartime([
0xee7fbfffffffeaaa, 0xee7fbfffffffeaaau64,
0x7aaffffac54ffff, 0x7aaffffac54ffff,
0xd9cc34a83dac3d89, 0xd9cc34a83dac3d89,
0xd91dd2e13ce144af, 0xd91dd2e13ce144af,
@ -286,7 +286,7 @@ impl SqrtField for Fq2 {
alpha.add_assign(&Fq2::one()); alpha.add_assign(&Fq2::one());
// alpha = alpha^((q - 1) / 2) // alpha = alpha^((q - 1) / 2)
alpha = alpha.pow_vartime([ alpha = alpha.pow_vartime([
0xdcff7fffffffd555, 0xdcff7fffffffd555u64,
0xf55ffff58a9ffff, 0xf55ffff58a9ffff,
0xb39869507b587b12, 0xb39869507b587b12,
0xb23ba5c279c2895f, 0xb23ba5c279c2895f,
@ -302,6 +302,11 @@ impl SqrtField for Fq2 {
} }
} }
#[cfg(test)]
use super::fq::FqRepr;
#[cfg(test)]
use ff::PrimeField;
#[test] #[test]
fn test_fq2_ordering() { fn test_fq2_ordering() {
let mut a = Fq2 { let mut a = Fq2 {
@ -353,9 +358,6 @@ fn test_fq2_basics() {
#[test] #[test]
fn test_fq2_squaring() { fn test_fq2_squaring() {
use super::fq::FqRepr;
use ff::PrimeField;
let a = Fq2 { let a = Fq2 {
c0: Fq::one(), c0: Fq::one(),
c1: Fq::one(), c1: Fq::one(),
@ -364,7 +366,7 @@ fn test_fq2_squaring() {
a.square(), a.square(),
Fq2 { Fq2 {
c0: Fq::zero(), c0: Fq::zero(),
c1: Fq::from_repr(FqRepr::from(2)).unwrap(), c1: Fq::from(2),
} }
); // 2u ); // 2u
@ -381,21 +383,17 @@ fn test_fq2_squaring() {
let a = Fq2 { let a = Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x9c2c6309bbf8b598, 0x07, 0x08, 0x0c, 0x5f, 0xa1, 0xd8, 0xe0, 0x42, 0x41, 0xb7, 0x6d, 0xcc, 0x1c, 0x3f,
0x4eef5c946536f602, 0xbe, 0x5e, 0xf7, 0xf2, 0x95, 0xa9, 0x4e, 0x58, 0xae, 0x7c, 0x90, 0xe3, 0x4a, 0xab,
0x90e34aab6fb6a6bd, 0x6f, 0xb6, 0xa6, 0xbd, 0x4e, 0xef, 0x5c, 0x94, 0x65, 0x36, 0xf6, 0x02, 0x9c, 0x2c,
0xf7f295a94e58ae7c, 0x63, 0x09, 0xbb, 0xf8, 0xb5, 0x98,
0x41b76dcc1c3fbe5e,
0x7080c5fa1d8e042,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x38f473b3c870a4ab, 0x10, 0xd1, 0x61, 0x5e, 0x75, 0x25, 0x0a, 0x21, 0xfc, 0x58, 0xa7, 0xb7, 0xbe, 0x81,
0x6ad3291177c8c7e5, 0x54, 0x07, 0xbf, 0xb9, 0x90, 0x20, 0x60, 0x41, 0x37, 0xa0, 0xda, 0xc5, 0xa4, 0xc9,
0xdac5a4c911a4353e, 0x11, 0xa4, 0x35, 0x3e, 0x6a, 0xd3, 0x29, 0x11, 0x77, 0xc8, 0xc7, 0xe5, 0x38, 0xf4,
0xbfb99020604137a0, 0x73, 0xb3, 0xc8, 0x70, 0xa4, 0xab,
0xfc58a7b7be815407,
0x10d1615e75250a21,
])) ]))
.unwrap(), .unwrap(),
}; };
@ -403,21 +401,17 @@ fn test_fq2_squaring() {
a.square(), a.square(),
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0xf262c28c538bcf68, 0x07, 0xea, 0xc8, 0x13, 0x69, 0xc4, 0x33, 0x61, 0x4c, 0xf1, 0x7b, 0x58, 0x93, 0xc3,
0xb9f2a66eae1073ba, 0xd3, 0x27, 0xcb, 0x67, 0x41, 0x57, 0x61, 0x8d, 0xa1, 0x76, 0x0d, 0xc4, 0x6a, 0xb8,
0xdc46ab8fad67ae0, 0xfa, 0xd6, 0x7a, 0xe0, 0xb9, 0xf2, 0xa6, 0x6e, 0xae, 0x10, 0x73, 0xba, 0xf2, 0x62,
0xcb674157618da176, 0xc2, 0x8c, 0x53, 0x8b, 0xcf, 0x68,
0x4cf17b5893c3d327,
0x7eac81369c43361
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0xc1579cf58e980cf8, 0x15, 0x42, 0xa6, 0x1c, 0x8a, 0x8d, 0xb9, 0x94, 0x73, 0x9c, 0x98, 0x30, 0x42, 0x77,
0xa23eb7e12dd54d98, 0x9a, 0x65, 0x38, 0xd0, 0xd7, 0x27, 0x5a, 0x96, 0x89, 0xe1, 0xe7, 0x51, 0x38, 0xbc,
0xe75138bce4cec7aa, 0xe4, 0xce, 0xc7, 0xaa, 0xa2, 0x3e, 0xb7, 0xe1, 0x2d, 0xd5, 0x4d, 0x98, 0xc1, 0x57,
0x38d0d7275a9689e1, 0x9c, 0xf5, 0x8e, 0x98, 0x0c, 0xf8,
0x739c983042779a65,
0x1542a61c8a8db994
])) ]))
.unwrap(), .unwrap(),
} }
@ -431,41 +425,33 @@ fn test_fq2_mul() {
let mut a = Fq2 { let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x85c9f989e1461f03, 0x05, 0x1d, 0x3f, 0x92, 0x53, 0xe2, 0x51, 0x6f, 0x1c, 0x20, 0x2d, 0x8e, 0xd9, 0x7a,
0xa2e33c333449a1d6, 0xfb, 0x45, 0x9e, 0xe5, 0x3e, 0x7e, 0x84, 0xd7, 0x53, 0x2e, 0x41, 0xe4, 0x61, 0x15,
0x41e461154a7354a3, 0x4a, 0x73, 0x54, 0xa3, 0xa2, 0xe3, 0x3c, 0x33, 0x34, 0x49, 0xa1, 0xd6, 0x85, 0xc9,
0x9ee53e7e84d7532e, 0xf9, 0x89, 0xe1, 0x46, 0x1f, 0x03,
0x1c202d8ed97afb45,
0x51d3f9253e2516f,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0xa7348a8b511aedcf, 0x18, 0x0c, 0x3e, 0xe4, 0x66, 0x56, 0xb0, 0x08, 0x7a, 0x5e, 0x1e, 0xcb, 0x67, 0x6d,
0x143c215d8176b319, 0x65, 0xf9, 0x09, 0x53, 0x3e, 0x4a, 0x9a, 0x51, 0x58, 0xbe, 0x4c, 0xc4, 0x80, 0x81,
0x4cc48081c09b8903, 0xc0, 0x9b, 0x89, 0x03, 0x14, 0x3c, 0x21, 0x5d, 0x81, 0x76, 0xb3, 0x19, 0xa7, 0x34,
0x9533e4a9a5158be, 0x8a, 0x8b, 0x51, 0x1a, 0xed, 0xcf,
0x7a5e1ecb676d65f9,
0x180c3ee46656b008,
])) ]))
.unwrap(), .unwrap(),
}; };
a.mul_assign(&Fq2 { a.mul_assign(&Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0xe21f9169805f537e, 0x02, 0xc9, 0x3a, 0x72, 0xeb, 0x8a, 0xf8, 0x3e, 0x06, 0xc9, 0x11, 0x02, 0x92, 0xbf,
0xfc87e62e179c285d, 0xa4, 0x09, 0xcd, 0x46, 0x0f, 0x9f, 0x0c, 0x23, 0xe4, 0x30, 0x27, 0xec, 0xe1, 0x75,
0x27ece175be07a531, 0xbe, 0x07, 0xa5, 0x31, 0xfc, 0x87, 0xe6, 0x2e, 0x17, 0x9c, 0x28, 0x5d, 0xe2, 0x1f,
0xcd460f9f0c23e430, 0x91, 0x69, 0x80, 0x5f, 0x53, 0x7e,
0x6c9110292bfa409,
0x2c93a72eb8af83e,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x4b1c3f936d8992d4, 0x19, 0xe1, 0x73, 0x34, 0xd4, 0xe9, 0x35, 0x58, 0x63, 0x4c, 0xd3, 0xc6, 0xc5, 0x65,
0x1d2a72916dba4c8a, 0x09, 0x6d, 0x57, 0xa0, 0x6d, 0x31, 0x35, 0xa7, 0x52, 0xae, 0x88, 0x71, 0xc5, 0x08,
0x8871c508658d1e5f, 0x65, 0x8d, 0x1e, 0x5f, 0x1d, 0x2a, 0x72, 0x91, 0x6d, 0xba, 0x4c, 0x8a, 0x4b, 0x1c,
0x57a06d3135a752ae, 0x3f, 0x93, 0x6d, 0x89, 0x92, 0xd4,
0x634cd3c6c565096d,
0x19e17334d4e93558,
])) ]))
.unwrap(), .unwrap(),
}); });
@ -473,21 +459,17 @@ fn test_fq2_mul() {
a, a,
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x95b5127e6360c7e4, 0x17, 0x51, 0xaf, 0xbe, 0x16, 0x6e, 0x53, 0x99, 0x53, 0x10, 0xa2, 0x02, 0xd9, 0x2f,
0xde29c31a19a6937e, 0x99, 0x63, 0x55, 0x11, 0xfe, 0x4d, 0x84, 0xee, 0x5f, 0x78, 0xf6, 0x1a, 0x96, 0xda,
0xf61a96dacf5a39bc, 0xcf, 0x5a, 0x39, 0xbc, 0xde, 0x29, 0xc3, 0x1a, 0x19, 0xa6, 0x93, 0x7e, 0x95, 0xb5,
0x5511fe4d84ee5f78, 0x12, 0x7e, 0x63, 0x60, 0xc7, 0xe4,
0x5310a202d92f9963,
0x1751afbe166e5399
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x84af0e1bd630117a, 0x01, 0xef, 0x1a, 0x36, 0xc2, 0x01, 0x58, 0x9d, 0x33, 0xa9, 0xac, 0x82, 0xce, 0x4c,
0x6c63cd4da2c2aa7, 0x50, 0x83, 0xc9, 0x75, 0x10, 0x65, 0x79, 0xc2, 0x75, 0xee, 0x5b, 0xa6, 0xe5, 0x43,
0x5ba6e5430e883d40, 0x0e, 0x88, 0x3d, 0x40, 0x06, 0xc6, 0x3c, 0xd4, 0xda, 0x2c, 0x2a, 0xa7, 0x84, 0xaf,
0xc975106579c275ee, 0x0e, 0x1b, 0xd6, 0x30, 0x11, 0x7a,
0x33a9ac82ce4c5083,
0x1ef1a36c201589d
])) ]))
.unwrap(), .unwrap(),
} }
@ -503,21 +485,17 @@ fn test_fq2_invert() {
let a = Fq2 { let a = Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x85c9f989e1461f03, 0x05, 0x1d, 0x3f, 0x92, 0x53, 0xe2, 0x51, 0x6f, 0x1c, 0x20, 0x2d, 0x8e, 0xd9, 0x7a,
0xa2e33c333449a1d6, 0xfb, 0x45, 0x9e, 0xe5, 0x3e, 0x7e, 0x84, 0xd7, 0x53, 0x2e, 0x41, 0xe4, 0x61, 0x15,
0x41e461154a7354a3, 0x4a, 0x73, 0x54, 0xa3, 0xa2, 0xe3, 0x3c, 0x33, 0x34, 0x49, 0xa1, 0xd6, 0x85, 0xc9,
0x9ee53e7e84d7532e, 0xf9, 0x89, 0xe1, 0x46, 0x1f, 0x03,
0x1c202d8ed97afb45,
0x51d3f9253e2516f,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0xa7348a8b511aedcf, 0x18, 0x0c, 0x3e, 0xe4, 0x66, 0x56, 0xb0, 0x08, 0x7a, 0x5e, 0x1e, 0xcb, 0x67, 0x6d,
0x143c215d8176b319, 0x65, 0xf9, 0x09, 0x53, 0x3e, 0x4a, 0x9a, 0x51, 0x58, 0xbe, 0x4c, 0xc4, 0x80, 0x81,
0x4cc48081c09b8903, 0xc0, 0x9b, 0x89, 0x03, 0x14, 0x3c, 0x21, 0x5d, 0x81, 0x76, 0xb3, 0x19, 0xa7, 0x34,
0x9533e4a9a5158be, 0x8a, 0x8b, 0x51, 0x1a, 0xed, 0xcf,
0x7a5e1ecb676d65f9,
0x180c3ee46656b008,
])) ]))
.unwrap(), .unwrap(),
}; };
@ -526,21 +504,17 @@ fn test_fq2_invert() {
a, a,
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x70300f9bcb9e594, 0x13, 0x51, 0xef, 0x01, 0x94, 0x1b, 0x70, 0xc4, 0xa6, 0xc3, 0xd8, 0xf9, 0x58, 0x6f,
0xe5ecda5fdafddbb2, 0x26, 0x36, 0xdf, 0xba, 0x70, 0x32, 0x93, 0x94, 0x1c, 0x30, 0x64, 0xbe, 0xf6, 0x17,
0x64bef617d2915a8f, 0xd2, 0x91, 0x5a, 0x8f, 0xe5, 0xec, 0xda, 0x5f, 0xda, 0xfd, 0xdb, 0xb2, 0x07, 0x03,
0xdfba703293941c30, 0x00, 0xf9, 0xbc, 0xb9, 0xe5, 0x94,
0xa6c3d8f9586f2636,
0x1351ef01941b70c4
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x8c39fd76a8312cb4, 0x10, 0x3b, 0xdf, 0x24, 0x1a, 0xfb, 0x00, 0x19, 0xdf, 0x4e, 0x54, 0xf0, 0xd3, 0xef,
0x15d7b6b95defbff0, 0x15, 0xa6, 0xcb, 0xf6, 0x51, 0xa0, 0xf3, 0x67, 0xaf, 0xb2, 0x94, 0x71, 0x43, 0xf8,
0x947143f89faedee9, 0x9f, 0xae, 0xde, 0xe9, 0x15, 0xd7, 0xb6, 0xb9, 0x5d, 0xef, 0xbf, 0xf0, 0x8c, 0x39,
0xcbf651a0f367afb2, 0xfd, 0x76, 0xa8, 0x31, 0x2c, 0xb4,
0xdf4e54f0d3ef15a6,
0x103bdf241afb0019
])) ]))
.unwrap(), .unwrap(),
} }
@ -554,41 +528,33 @@ fn test_fq2_addition() {
let mut a = Fq2 { let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7, 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x11e59ea221a3b6d2, 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0x8b1a52e0a90f59ed, 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0xb966ce3bc2108b13, 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db, 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0x946ae52d684fa7ed, 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xbe203411c66fb3a5, 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xb3f8afc0ee248cad, 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
])) ]))
.unwrap(), .unwrap(),
}; };
a.add_assign(&Fq2 { a.add_assign(&Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x619a02d78dc70ef2, 0x13, 0xce, 0x43, 0x3f, 0xa2, 0x60, 0x27, 0xf5, 0x98, 0x6a, 0x4a, 0x62, 0xfa, 0x82,
0xb93adfc9119e33e8, 0xa4, 0x9d, 0x3b, 0x88, 0x89, 0x9a, 0x42, 0xa6, 0x31, 0x8f, 0x4b, 0xf0, 0xb9, 0x9a,
0x4bf0b99a9f0dca12, 0x9f, 0x0d, 0xca, 0x12, 0xb9, 0x3a, 0xdf, 0xc9, 0x11, 0x9e, 0x33, 0xe8, 0x61, 0x9a,
0x3b88899a42a6318f, 0x02, 0xd7, 0x8d, 0xc7, 0x0e, 0xf2,
0x986a4a62fa82a49d,
0x13ce433fa26027f5,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x66323bf80b58b9b9, 0x11, 0xd6, 0xe2, 0x0e, 0x98, 0x6c, 0x20, 0x85, 0x4c, 0x8c, 0x18, 0x00, 0xeb, 0x10,
0xa1379b6facf6e596, 0x45, 0x66, 0x22, 0x36, 0xf5, 0x52, 0x46, 0xd0, 0xd4, 0x4d, 0x40, 0x2a, 0xef, 0x1f,
0x402aef1fb797e32f, 0xb7, 0x97, 0xe3, 0x2f, 0xa1, 0x37, 0x9b, 0x6f, 0xac, 0xf6, 0xe5, 0x96, 0x66, 0x32,
0x2236f55246d0d44d, 0x3b, 0xf8, 0x0b, 0x58, 0xb9, 0xb9,
0x4c8c1800eb104566,
0x11d6e20e986c2085,
])) ]))
.unwrap(), .unwrap(),
}); });
@ -596,21 +562,17 @@ fn test_fq2_addition() {
a, a,
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x8e9a7adaf6eb0eb9, 0x14, 0xc7, 0x15, 0xd5, 0x55, 0x3f, 0x01, 0xd2, 0x65, 0x30, 0x94, 0x27, 0xb3, 0xd5,
0xcb207e6b3341eaba, 0xd0, 0x90, 0xf4, 0xef, 0x57, 0xd6, 0x04, 0xb6, 0xbc, 0xa2, 0xd7, 0x0b, 0x0c, 0x7b,
0xd70b0c7b481d23ff, 0x48, 0x1d, 0x23, 0xff, 0xcb, 0x20, 0x7e, 0x6b, 0x33, 0x41, 0xea, 0xba, 0x8e, 0x9a,
0xf4ef57d604b6bca2, 0x7a, 0xda, 0xf6, 0xeb, 0x0e, 0xb9,
0x65309427b3d5d090,
0x14c715d5553f01d2
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0xfdb032e7d9079a94, 0x13, 0x03, 0xf3, 0x46, 0x51, 0x12, 0xc8, 0xbc, 0x9a, 0xd2, 0x65, 0xeb, 0x46, 0xe0,
0x35a2809d15468d83, 0x19, 0x84, 0xd6, 0x2f, 0xa5, 0x13, 0x34, 0xf5, 0x60, 0xfa, 0xfe, 0x4b, 0x23, 0x31,
0xfe4b23317e0796d5, 0x7e, 0x07, 0x96, 0xd5, 0x35, 0xa2, 0x80, 0x9d, 0x15, 0x46, 0x8d, 0x83, 0xfd, 0xb0,
0xd62fa51334f560fa, 0x32, 0xe7, 0xd9, 0x07, 0x9a, 0x94,
0x9ad265eb46e01984,
0x1303f3465112c8bc
])) ]))
.unwrap(), .unwrap(),
} }
@ -624,41 +586,33 @@ fn test_fq2_subtraction() {
let mut a = Fq2 { let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7, 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x11e59ea221a3b6d2, 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0x8b1a52e0a90f59ed, 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0xb966ce3bc2108b13, 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db, 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0x946ae52d684fa7ed, 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xbe203411c66fb3a5, 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xb3f8afc0ee248cad, 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
])) ]))
.unwrap(), .unwrap(),
}; };
a.sub_assign(&Fq2 { a.sub_assign(&Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x619a02d78dc70ef2, 0x13, 0xce, 0x43, 0x3f, 0xa2, 0x60, 0x27, 0xf5, 0x98, 0x6a, 0x4a, 0x62, 0xfa, 0x82,
0xb93adfc9119e33e8, 0xa4, 0x9d, 0x3b, 0x88, 0x89, 0x9a, 0x42, 0xa6, 0x31, 0x8f, 0x4b, 0xf0, 0xb9, 0x9a,
0x4bf0b99a9f0dca12, 0x9f, 0x0d, 0xca, 0x12, 0xb9, 0x3a, 0xdf, 0xc9, 0x11, 0x9e, 0x33, 0xe8, 0x61, 0x9a,
0x3b88899a42a6318f, 0x02, 0xd7, 0x8d, 0xc7, 0x0e, 0xf2,
0x986a4a62fa82a49d,
0x13ce433fa26027f5,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x66323bf80b58b9b9, 0x11, 0xd6, 0xe2, 0x0e, 0x98, 0x6c, 0x20, 0x85, 0x4c, 0x8c, 0x18, 0x00, 0xeb, 0x10,
0xa1379b6facf6e596, 0x45, 0x66, 0x22, 0x36, 0xf5, 0x52, 0x46, 0xd0, 0xd4, 0x4d, 0x40, 0x2a, 0xef, 0x1f,
0x402aef1fb797e32f, 0xb7, 0x97, 0xe3, 0x2f, 0xa1, 0x37, 0x9b, 0x6f, 0xac, 0xf6, 0xe5, 0x96, 0x66, 0x32,
0x2236f55246d0d44d, 0x3b, 0xf8, 0x0b, 0x58, 0xb9, 0xb9,
0x4c8c1800eb104566,
0x11d6e20e986c2085,
])) ]))
.unwrap(), .unwrap(),
}); });
@ -666,21 +620,17 @@ fn test_fq2_subtraction() {
a, a,
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x8565752bdb5c9b80, 0x07, 0x2b, 0xa1, 0x40, 0x49, 0xfe, 0x98, 0x81, 0x7f, 0x77, 0xa7, 0x18, 0x02, 0x1c,
0x7756bed7c15982e9, 0x34, 0x2d, 0xe2, 0x55, 0x90, 0x26, 0x72, 0xef, 0x6c, 0x43, 0xa6, 0x5a, 0x6b, 0xe7,
0xa65a6be700b285fe, 0x00, 0xb2, 0x85, 0xfe, 0x77, 0x56, 0xbe, 0xd7, 0xc1, 0x59, 0x82, 0xe9, 0x85, 0x65,
0xe255902672ef6c43, 0x75, 0x2b, 0xdb, 0x5c, 0x9b, 0x80,
0x7f77a718021c342d,
0x72ba14049fe9881
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0xeb4abaf7c255d1cd, 0x09, 0x57, 0x41, 0x13, 0x59, 0xba, 0x6e, 0x4c, 0x4c, 0xd5, 0xdd, 0x9f, 0xb4, 0x0b,
0x11df49bc6cacc256, 0x3b, 0x8f, 0xf6, 0x39, 0x05, 0xf3, 0x9a, 0xd8, 0xcb, 0x1f, 0xe5, 0x26, 0x17, 0x93,
0xe52617930588c69a, 0x05, 0x88, 0xc6, 0x9a, 0x11, 0xdf, 0x49, 0xbc, 0x6c, 0xac, 0xc2, 0x56, 0xeb, 0x4a,
0xf63905f39ad8cb1f, 0xba, 0xf7, 0xc2, 0x55, 0xd1, 0xcd,
0x4cd5dd9fb40b3b8f,
0x957411359ba6e4c
])) ]))
.unwrap(), .unwrap(),
} }
@ -694,21 +644,17 @@ fn test_fq2_negation() {
let a = Fq2 { let a = Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7, 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x11e59ea221a3b6d2, 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0x8b1a52e0a90f59ed, 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0xb966ce3bc2108b13, 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db, 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0x946ae52d684fa7ed, 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xbe203411c66fb3a5, 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xb3f8afc0ee248cad, 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
])) ]))
.unwrap(), .unwrap(),
} }
@ -717,21 +663,17 @@ fn test_fq2_negation() {
a, a,
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x8cfe87fc96dbaae4, 0x19, 0x08, 0x3f, 0x54, 0x86, 0xa1, 0x0c, 0xbd, 0x7e, 0x55, 0x5d, 0xf1, 0x89, 0xf8,
0xcc6615c8fb0492d, 0x80, 0xe3, 0xab, 0x10, 0x7d, 0x49, 0x31, 0x74, 0x87, 0xab, 0xdc, 0x16, 0x7f, 0xc0,
0xdc167fc04da19c37, 0x4d, 0xa1, 0x9c, 0x37, 0x0c, 0xc6, 0x61, 0x5c, 0x8f, 0xb0, 0x49, 0x2d, 0x8c, 0xfe,
0xab107d49317487ab, 0x87, 0xfc, 0x96, 0xdb, 0xaa, 0xe4,
0x7e555df189f880e3,
0x19083f5486a10cbd
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x228109103250c9d0, 0x18, 0xd4, 0x00, 0xb2, 0x80, 0xd9, 0x3e, 0x62, 0xfc, 0xd5, 0x59, 0xcb, 0xe7, 0x7b,
0x8a411ad149045812, 0xd8, 0xb8, 0xb0, 0x7e, 0x9b, 0xc4, 0x05, 0x60, 0x86, 0x11, 0xa9, 0x10, 0x9e, 0x8f,
0xa9109e8f3041427e, 0x30, 0x41, 0x42, 0x7e, 0x8a, 0x41, 0x1a, 0xd1, 0x49, 0x04, 0x58, 0x12, 0x22, 0x81,
0xb07e9bc405608611, 0x09, 0x10, 0x32, 0x50, 0xc9, 0xd0,
0xfcd559cbe77bd8b8,
0x18d400b280d93e62
])) ]))
.unwrap(), .unwrap(),
} }
@ -745,21 +687,17 @@ fn test_fq2_doubling() {
let a = Fq2 { let a = Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7, 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x11e59ea221a3b6d2, 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0x8b1a52e0a90f59ed, 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0xb966ce3bc2108b13, 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db, 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0x946ae52d684fa7ed, 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xbe203411c66fb3a5, 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xb3f8afc0ee248cad, 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
])) ]))
.unwrap(), .unwrap(),
}; };
@ -767,21 +705,17 @@ fn test_fq2_doubling() {
a.double(), a.double(),
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x5a00f006d247ff8e, 0x01, 0xf1, 0xa5, 0x2b, 0x65, 0xbd, 0xb3, 0xb9, 0x99, 0x8c, 0x93, 0x89, 0x72, 0xa6,
0x23cb3d4443476da4, 0x57, 0xe7, 0x72, 0xcd, 0x9c, 0x77, 0x84, 0x21, 0x16, 0x27, 0x16, 0x34, 0xa5, 0xc1,
0x1634a5c1521eb3da, 0x52, 0x1e, 0xb3, 0xda, 0x23, 0xcb, 0x3d, 0x44, 0x43, 0x47, 0x6d, 0xa4, 0x5a, 0x00,
0x72cd9c7784211627, 0xf0, 0x06, 0xd2, 0x47, 0xff, 0x8e,
0x998c938972a657e7,
0x1f1a52b65bdb3b9
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x2efbeddf9b5dc1b6, 0x02, 0x5a, 0x22, 0x6f, 0x71, 0x4d, 0x50, 0x6e, 0x9c, 0x8c, 0x9b, 0xd4, 0xb7, 0x9f,
0x28d5ca5ad09f4fdb, 0xa8, 0x3d, 0x67, 0xf1, 0x5f, 0x81, 0xdc, 0x49, 0x19, 0x5b, 0x7c, 0x40, 0x68, 0x23,
0x7c4068238cdf674b, 0x8c, 0xdf, 0x67, 0x4b, 0x28, 0xd5, 0xca, 0x5a, 0xd0, 0x9f, 0x4f, 0xdb, 0x2e, 0xfb,
0x67f15f81dc49195b, 0xed, 0xdf, 0x9b, 0x5d, 0xc1, 0xb6,
0x9c8c9bd4b79fa83d,
0x25a226f714d506e
])) ]))
.unwrap(), .unwrap(),
} }
@ -795,21 +729,17 @@ fn test_fq2_frobenius_map() {
let mut a = Fq2 { let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7, 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x11e59ea221a3b6d2, 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0x8b1a52e0a90f59ed, 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0xb966ce3bc2108b13, 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db, 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0x946ae52d684fa7ed, 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xbe203411c66fb3a5, 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xb3f8afc0ee248cad, 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
])) ]))
.unwrap(), .unwrap(),
}; };
@ -818,21 +748,17 @@ fn test_fq2_frobenius_map() {
a, a,
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7, 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x11e59ea221a3b6d2, 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0x8b1a52e0a90f59ed, 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0xb966ce3bc2108b13, 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db, 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0x946ae52d684fa7ed, 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xbe203411c66fb3a5, 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xb3f8afc0ee248cad, 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837
])) ]))
.unwrap(), .unwrap(),
} }
@ -842,21 +768,17 @@ fn test_fq2_frobenius_map() {
a, a,
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7, 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x11e59ea221a3b6d2, 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0x8b1a52e0a90f59ed, 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0xb966ce3bc2108b13, 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x228109103250c9d0, 0x18, 0xd4, 0x00, 0xb2, 0x80, 0xd9, 0x3e, 0x62, 0xfc, 0xd5, 0x59, 0xcb, 0xe7, 0x7b,
0x8a411ad149045812, 0xd8, 0xb8, 0xb0, 0x7e, 0x9b, 0xc4, 0x05, 0x60, 0x86, 0x11, 0xa9, 0x10, 0x9e, 0x8f,
0xa9109e8f3041427e, 0x30, 0x41, 0x42, 0x7e, 0x8a, 0x41, 0x1a, 0xd1, 0x49, 0x04, 0x58, 0x12, 0x22, 0x81,
0xb07e9bc405608611, 0x09, 0x10, 0x32, 0x50, 0xc9, 0xd0,
0xfcd559cbe77bd8b8,
0x18d400b280d93e62
])) ]))
.unwrap(), .unwrap(),
} }
@ -866,21 +788,17 @@ fn test_fq2_frobenius_map() {
a, a,
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7, 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x11e59ea221a3b6d2, 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0x8b1a52e0a90f59ed, 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0xb966ce3bc2108b13, 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db, 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0x946ae52d684fa7ed, 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xbe203411c66fb3a5, 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xb3f8afc0ee248cad, 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837
])) ]))
.unwrap(), .unwrap(),
} }
@ -890,21 +808,17 @@ fn test_fq2_frobenius_map() {
a, a,
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7, 0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x11e59ea221a3b6d2, 0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0x8b1a52e0a90f59ed, 0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0xb966ce3bc2108b13, 0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db, 0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0x946ae52d684fa7ed, 0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xbe203411c66fb3a5, 0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xb3f8afc0ee248cad, 0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837
])) ]))
.unwrap(), .unwrap(),
} }
@ -919,21 +833,17 @@ fn test_fq2_sqrt() {
assert_eq!( assert_eq!(
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x476b4c309720e227, 0x07, 0xca, 0x7d, 0xa1, 0xf1, 0x36, 0x06, 0xac, 0x1e, 0x58, 0xb2, 0x15, 0x9d, 0xfe,
0x34c2d04faffdab6, 0x10, 0xe2, 0xdb, 0x4a, 0x11, 0x6b, 0x5b, 0xf7, 0x4a, 0xa1, 0xa5, 0x7e, 0x6f, 0xc1,
0xa57e6fc1bab51fd9, 0xba, 0xb5, 0x1f, 0xd9, 0x03, 0x4c, 0x2d, 0x04, 0xfa, 0xff, 0xda, 0xb6, 0x47, 0x6b,
0xdb4a116b5bf74aa1, 0x4c, 0x30, 0x97, 0x20, 0xe2, 0x27,
0x1e58b2159dfe10e2,
0x7ca7da1f13606ac
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0xfa8de88b7516d2c3, 0x0e, 0xc9, 0x23, 0x36, 0x65, 0x0e, 0x49, 0xd5, 0x08, 0xee, 0x53, 0x94, 0xd7, 0x7a,
0x371a75ed14f41629, 0xfb, 0x3d, 0x21, 0x26, 0x11, 0xbc, 0xa4, 0xe9, 0x91, 0x21, 0x4c, 0xec, 0x2d, 0xca,
0x4cec2dca577a3eb6, 0x57, 0x7a, 0x3e, 0xb6, 0x37, 0x1a, 0x75, 0xed, 0x14, 0xf4, 0x16, 0x29, 0xfa, 0x8d,
0x212611bca4e99121, 0xe8, 0x8b, 0x75, 0x16, 0xd2, 0xc3,
0x8ee5394d77afb3d,
0xec92336650e49d5
])) ]))
.unwrap(), .unwrap(),
} }
@ -941,21 +851,17 @@ fn test_fq2_sqrt() {
.unwrap(), .unwrap(),
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0x40b299b2704258c5, 0x10, 0xf6, 0x96, 0x3b, 0xba, 0xd2, 0xeb, 0xc5, 0x88, 0x1b, 0x3e, 0x01, 0xb6, 0x11,
0x6ef7de92e8c68b63, 0xc0, 0x70, 0x8d, 0x7f, 0x1f, 0x72, 0x3d, 0x02, 0xc1, 0xd3, 0x6d, 0x2d, 0xdb, 0xe5,
0x6d2ddbe552203e82, 0x52, 0x20, 0x3e, 0x82, 0x6e, 0xf7, 0xde, 0x92, 0xe8, 0xc6, 0x8b, 0x63, 0x40, 0xb2,
0x8d7f1f723d02c1d3, 0x99, 0xb2, 0x70, 0x42, 0x58, 0xc5,
0x881b3e01b611c070,
0x10f6963bbad2ebc5
])) ]))
.unwrap(), .unwrap(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0xc099534fc209e752, 0x08, 0xd7, 0xcf, 0xff, 0x94, 0x21, 0x63, 0x30, 0xa4, 0xc9, 0x3b, 0x08, 0x10, 0x5d,
0x7670594665676447, 0x71, 0xa9, 0x6b, 0x85, 0x2a, 0xea, 0xf2, 0xaf, 0xcb, 0x1b, 0x28, 0xa2, 0x0f, 0xae,
0x28a20faed211efe7, 0xd2, 0x11, 0xef, 0xe7, 0x76, 0x70, 0x59, 0x46, 0x65, 0x67, 0x64, 0x47, 0xc0, 0x99,
0x6b852aeaf2afcb1b, 0x53, 0x4f, 0xc2, 0x09, 0xe7, 0x52,
0xa4c93b08105d71a9,
0x8d7cfff94216330
])) ]))
.unwrap(), .unwrap(),
} }
@ -964,12 +870,10 @@ fn test_fq2_sqrt() {
assert_eq!( assert_eq!(
Fq2 { Fq2 {
c0: Fq::from_repr(FqRepr([ c0: Fq::from_repr(FqRepr([
0xb9f78429d1517a6b, 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b,
0x1eabfffeb153ffff, 0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0,
0x6730d2a0f6b0f624, 0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xf7,
0x64774b84f38512bf, 0x84, 0x29, 0xd1, 0x51, 0x7a, 0x6b,
0x4b1ba7b6434bacd7,
0x1a0111ea397fe69a
])) ]))
.unwrap(), .unwrap(),
c1: Fq::zero(), c1: Fq::zero(),
@ -979,12 +883,10 @@ fn test_fq2_sqrt() {
Fq2 { Fq2 {
c0: Fq::zero(), c0: Fq::zero(),
c1: Fq::from_repr(FqRepr([ c1: Fq::from_repr(FqRepr([
0xb9fefffffd4357a3, 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b,
0x1eabfffeb153ffff, 0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0,
0x6730d2a0f6b0f624, 0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe,
0x64774b84f38512bf, 0xff, 0xff, 0xfd, 0x43, 0x57, 0xa3,
0x4b1ba7b6434bacd7,
0x1a0111ea397fe69a
])) ]))
.unwrap(), .unwrap(),
} }

View File

@ -1,11 +1,14 @@
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; use ff::{Field, PrimeField};
use std::ops::{AddAssign, MulAssign, SubAssign}; use std::ops::{AddAssign, MulAssign, SubAssign};
#[derive(PrimeField)] #[derive(PrimeField)]
#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] #[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
#[PrimeFieldGenerator = "7"] #[PrimeFieldGenerator = "7"]
pub struct Fr(FrRepr); #[PrimeFieldReprEndianness = "little"]
pub struct Fr([u64; 4]);
#[cfg(test)]
use ff::PowVartime;
#[cfg(test)] #[cfg(test)]
use rand_core::SeedableRng; use rand_core::SeedableRng;
#[cfg(test)] #[cfg(test)]
@ -13,373 +16,26 @@ use rand_xorshift::XorShiftRng;
#[cfg(test)] #[cfg(test)]
use std::ops::Neg; 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] #[test]
fn test_fr_is_valid() { fn test_fr_is_valid() {
let mut a = Fr(MODULUS); let mut a = MODULUS_LIMBS;
assert!(!a.is_valid()); assert!(!a.is_valid());
a.0.sub_noborrow(&FrRepr::from(1)); a.sub_noborrow(&Fr([1, 0, 0, 0]));
assert!(a.is_valid()); assert!(a.is_valid());
assert!(Fr(FrRepr::from(0)).is_valid()); assert!(Fr::from(0).is_valid());
assert!(Fr(FrRepr([ assert!(Fr([
0xffffffff00000000, 0xffffffff00000000,
0x53bda402fffe5bfe, 0x53bda402fffe5bfe,
0x3339d80809a1d805, 0x3339d80809a1d805,
0x73eda753299d7d48 0x73eda753299d7d48
])) ])
.is_valid()); .is_valid());
assert!(!Fr(FrRepr([ assert!(!Fr([
0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff 0xffffffffffffffff
])) ])
.is_valid()); .is_valid());
let mut rng = XorShiftRng::from_seed([ let mut rng = XorShiftRng::from_seed([
@ -397,85 +53,85 @@ fn test_fr_is_valid() {
fn test_fr_add_assign() { fn test_fr_add_assign() {
{ {
// Random number // Random number
let mut tmp = Fr(FrRepr([ let mut tmp = Fr([
0x437ce7616d580765, 0x437ce7616d580765,
0xd42d1ccb29d1235b, 0xd42d1ccb29d1235b,
0xed8f753821bd1423, 0xed8f753821bd1423,
0x4eede1c9c89528ca, 0x4eede1c9c89528ca,
])); ]);
assert!(tmp.is_valid()); assert!(tmp.is_valid());
// Test that adding zero has no effect. // Test that adding zero has no effect.
tmp.add_assign(&Fr(FrRepr::from(0))); tmp.add_assign(&Fr([0, 0, 0, 0]));
assert_eq!( assert_eq!(
tmp, tmp,
Fr(FrRepr([ Fr([
0x437ce7616d580765, 0x437ce7616d580765,
0xd42d1ccb29d1235b, 0xd42d1ccb29d1235b,
0xed8f753821bd1423, 0xed8f753821bd1423,
0x4eede1c9c89528ca 0x4eede1c9c89528ca
])) ])
); );
// Add one and test for the result. // Add one and test for the result.
tmp.add_assign(&Fr(FrRepr::from(1))); tmp.add_assign(&Fr([1, 0, 0, 0]));
assert_eq!( assert_eq!(
tmp, tmp,
Fr(FrRepr([ Fr([
0x437ce7616d580766, 0x437ce7616d580766,
0xd42d1ccb29d1235b, 0xd42d1ccb29d1235b,
0xed8f753821bd1423, 0xed8f753821bd1423,
0x4eede1c9c89528ca 0x4eede1c9c89528ca
])) ])
); );
// Add another random number that exercises the reduction. // Add another random number that exercises the reduction.
tmp.add_assign(&Fr(FrRepr([ tmp.add_assign(&Fr([
0x946f435944f7dc79, 0x946f435944f7dc79,
0xb55e7ee6533a9b9b, 0xb55e7ee6533a9b9b,
0x1e43b84c2f6194ca, 0x1e43b84c2f6194ca,
0x58717ab525463496, 0x58717ab525463496,
]))); ]));
assert_eq!( assert_eq!(
tmp, tmp,
Fr(FrRepr([ Fr([
0xd7ec2abbb24fe3de, 0xd7ec2abbb24fe3de,
0x35cdf7ae7d0d62f7, 0x35cdf7ae7d0d62f7,
0xd899557c477cd0e9, 0xd899557c477cd0e9,
0x3371b52bc43de018 0x3371b52bc43de018
])) ])
); );
// Add one to (r - 1) and test for the result. // Add one to (r - 1) and test for the result.
tmp = Fr(FrRepr([ tmp = Fr([
0xffffffff00000000, 0xffffffff00000000,
0x53bda402fffe5bfe, 0x53bda402fffe5bfe,
0x3339d80809a1d805, 0x3339d80809a1d805,
0x73eda753299d7d48, 0x73eda753299d7d48,
])); ]);
tmp.add_assign(&Fr(FrRepr::from(1))); tmp.add_assign(&Fr([1, 0, 0, 0]));
assert!(tmp.0.is_zero()); assert!(tmp.is_zero());
// Add a random number to another one such that the result is r - 1 // Add a random number to another one such that the result is r - 1
tmp = Fr(FrRepr([ tmp = Fr([
0xade5adacdccb6190, 0xade5adacdccb6190,
0xaa21ee0f27db3ccd, 0xaa21ee0f27db3ccd,
0x2550f4704ae39086, 0x2550f4704ae39086,
0x591d1902e7c5ba27, 0x591d1902e7c5ba27,
])); ]);
tmp.add_assign(&Fr(FrRepr([ tmp.add_assign(&Fr([
0x521a525223349e70, 0x521a525223349e70,
0xa99bb5f3d8231f31, 0xa99bb5f3d8231f31,
0xde8e397bebe477e, 0xde8e397bebe477e,
0x1ad08e5041d7c321, 0x1ad08e5041d7c321,
]))); ]));
assert_eq!( assert_eq!(
tmp, tmp,
Fr(FrRepr([ Fr([
0xffffffff00000000, 0xffffffff00000000,
0x53bda402fffe5bfe, 0x53bda402fffe5bfe,
0x3339d80809a1d805, 0x3339d80809a1d805,
0x73eda753299d7d48 0x73eda753299d7d48
])) ])
); );
// Add one to the result and test for it. // Add one to the result and test for it.
tmp.add_assign(&Fr(FrRepr::from(1))); tmp.add_assign(&Fr([1, 0, 0, 0]));
assert!(tmp.0.is_zero()); assert!(tmp.is_zero());
} }
// Test associativity // Test associativity
@ -509,71 +165,71 @@ fn test_fr_add_assign() {
fn test_fr_sub_assign() { fn test_fr_sub_assign() {
{ {
// Test arbitrary subtraction that tests reduction. // Test arbitrary subtraction that tests reduction.
let mut tmp = Fr(FrRepr([ let mut tmp = Fr([
0x6a68c64b6f735a2b, 0x6a68c64b6f735a2b,
0xd5f4d143fe0a1972, 0xd5f4d143fe0a1972,
0x37c17f3829267c62, 0x37c17f3829267c62,
0xa2f37391f30915c, 0xa2f37391f30915c,
])); ]);
tmp.sub_assign(&Fr(FrRepr([ tmp.sub_assign(&Fr([
0xade5adacdccb6190, 0xade5adacdccb6190,
0xaa21ee0f27db3ccd, 0xaa21ee0f27db3ccd,
0x2550f4704ae39086, 0x2550f4704ae39086,
0x591d1902e7c5ba27, 0x591d1902e7c5ba27,
]))); ]));
assert_eq!( assert_eq!(
tmp, tmp,
Fr(FrRepr([ Fr([
0xbc83189d92a7f89c, 0xbc83189d92a7f89c,
0x7f908737d62d38a3, 0x7f908737d62d38a3,
0x45aa62cfe7e4c3e1, 0x45aa62cfe7e4c3e1,
0x24ffc5896108547d 0x24ffc5896108547d
])) ])
); );
// Test the opposite subtraction which doesn't test reduction. // Test the opposite subtraction which doesn't test reduction.
tmp = Fr(FrRepr([ tmp = Fr([
0xade5adacdccb6190, 0xade5adacdccb6190,
0xaa21ee0f27db3ccd, 0xaa21ee0f27db3ccd,
0x2550f4704ae39086, 0x2550f4704ae39086,
0x591d1902e7c5ba27, 0x591d1902e7c5ba27,
])); ]);
tmp.sub_assign(&Fr(FrRepr([ tmp.sub_assign(&Fr([
0x6a68c64b6f735a2b, 0x6a68c64b6f735a2b,
0xd5f4d143fe0a1972, 0xd5f4d143fe0a1972,
0x37c17f3829267c62, 0x37c17f3829267c62,
0xa2f37391f30915c, 0xa2f37391f30915c,
]))); ]));
assert_eq!( assert_eq!(
tmp, tmp,
Fr(FrRepr([ Fr([
0x437ce7616d580765, 0x437ce7616d580765,
0xd42d1ccb29d1235b, 0xd42d1ccb29d1235b,
0xed8f753821bd1423, 0xed8f753821bd1423,
0x4eede1c9c89528ca 0x4eede1c9c89528ca
])) ])
); );
// Test for sensible results with zero // Test for sensible results with zero
tmp = Fr(FrRepr::from(0)); tmp = Fr::from(0);
tmp.sub_assign(&Fr(FrRepr::from(0))); tmp.sub_assign(&Fr::from(0));
assert!(tmp.is_zero()); assert!(tmp.is_zero());
tmp = Fr(FrRepr([ tmp = Fr([
0x437ce7616d580765, 0x437ce7616d580765,
0xd42d1ccb29d1235b, 0xd42d1ccb29d1235b,
0xed8f753821bd1423, 0xed8f753821bd1423,
0x4eede1c9c89528ca, 0x4eede1c9c89528ca,
])); ]);
tmp.sub_assign(&Fr(FrRepr::from(0))); tmp.sub_assign(&Fr::from(0));
assert_eq!( assert_eq!(
tmp, tmp,
Fr(FrRepr([ Fr([
0x437ce7616d580765, 0x437ce7616d580765,
0xd42d1ccb29d1235b, 0xd42d1ccb29d1235b,
0xed8f753821bd1423, 0xed8f753821bd1423,
0x4eede1c9c89528ca 0x4eede1c9c89528ca
])) ])
); );
} }
@ -600,25 +256,25 @@ fn test_fr_sub_assign() {
#[test] #[test]
fn test_fr_mul_assign() { fn test_fr_mul_assign() {
let mut tmp = Fr(FrRepr([ let mut tmp = Fr([
0x6b7e9b8faeefc81a, 0x6b7e9b8faeefc81a,
0xe30a8463f348ba42, 0xe30a8463f348ba42,
0xeff3cb67a8279c9c, 0xeff3cb67a8279c9c,
0x3d303651bd7c774d, 0x3d303651bd7c774d,
])); ]);
tmp.mul_assign(&Fr(FrRepr([ tmp.mul_assign(&Fr([
0x13ae28e3bc35ebeb, 0x13ae28e3bc35ebeb,
0xa10f4488075cae2c, 0xa10f4488075cae2c,
0x8160e95a853c3b5d, 0x8160e95a853c3b5d,
0x5ae3f03b561a841d, 0x5ae3f03b561a841d,
]))); ]));
assert!( assert!(
tmp == Fr(FrRepr([ tmp == Fr([
0x23717213ce710f71, 0x23717213ce710f71,
0xdbee1fe53a16e1af, 0xdbee1fe53a16e1af,
0xf565d3e1c2a48000, 0xf565d3e1c2a48000,
0x4426507ee75df9d7 0x4426507ee75df9d7
])) ])
); );
let mut rng = XorShiftRng::from_seed([ let mut rng = XorShiftRng::from_seed([
@ -667,22 +323,76 @@ fn test_fr_mul_assign() {
} }
} }
#[test]
fn test_fr_shr() {
let mut a = Fr::from_repr(FrRepr([
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([
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([
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([
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([
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([
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] #[test]
fn test_fr_squaring() { fn test_fr_squaring() {
let a = Fr(FrRepr([ let a = Fr([
0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff, 0xffffffffffffffff,
0x73eda753299d7d47, 0x73eda753299d7d47,
])); ]);
assert!(a.is_valid()); assert!(a.is_valid());
assert_eq!( assert_eq!(
a.square(), a.square(),
Fr::from_repr(FrRepr([ Fr::from_repr(FrRepr([
0xc0d698e7bde077b8, 0xb8, 0x77, 0xe0, 0xbd, 0xe7, 0x98, 0xd6, 0xc0, 0xc2, 0x6e, 0xe7, 0x79, 0x05, 0x31,
0xb79a310579e76ec2, 0x9a, 0xb7, 0x5f, 0x4e, 0xaf, 0xa9, 0xd0, 0xa8, 0x1d, 0xac, 0x97, 0x3e, 0xf2, 0x9b,
0xac1da8d0a9af4e5f, 0xc4, 0x29, 0xf6, 0x13,
0x13f629c49bf23e97
])) ]))
.unwrap() .unwrap()
); );
@ -763,7 +473,7 @@ fn test_fr_pow() {
0xe5, 0xe5,
]); ]);
for i in 0..1000 { for i in 0u64..1000 {
// Exponentiate by various small numbers and ensure it consists with repeated // Exponentiate by various small numbers and ensure it consists with repeated
// multiplication. // multiplication.
let a = Fr::random(&mut rng); let a = Fr::random(&mut rng);
@ -820,42 +530,38 @@ fn test_fr_sqrt() {
fn test_fr_from_into_repr() { fn test_fr_from_into_repr() {
// r + 1 should not be in the field // r + 1 should not be in the field
assert!(Fr::from_repr(FrRepr([ assert!(Fr::from_repr(FrRepr([
0xffffffff00000002, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0x02, 0xa4, 0xbd,
0x53bda402fffe5bfe, 0x53, 0x05, 0xd8, 0xa1, 0x09, 0x08, 0xd8, 0x39, 0x33, 0x48, 0x7d, 0x9d, 0x29, 0x53, 0xa7,
0x3339d80809a1d805, 0xed, 0x73,
0x73eda753299d7d48
])) ]))
.is_err()); .is_none());
// r should not be in the field // 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. // Multiply some arbitrary representations to see if the result is as expected.
let a = FrRepr([ let a = FrRepr([
0x25ebe3a3ad3c0c6a, 0x6a, 0x0c, 0x3c, 0xad, 0xa3, 0xe3, 0xeb, 0x25, 0x7c, 0x81, 0x2e, 0x09, 0x9d, 0xe3, 0x90,
0x6990e39d092e817c, 0x69, 0x8e, 0x65, 0xf5, 0x42, 0x0d, 0x90, 0x1f, 0x94, 0xe0, 0x71, 0x8a, 0xb3, 0x03, 0xa1,
0x941f900d42f5658e, 0xf8, 0x44,
0x44f8a103b38a71e0,
]); ]);
let mut a_fr = Fr::from_repr(a).unwrap(); let mut a_fr = Fr::from_repr(a).unwrap();
let b = FrRepr([ let b = FrRepr([
0x264e9454885e2475, 0x75, 0x24, 0x5e, 0x88, 0x54, 0x94, 0x4e, 0x26, 0x70, 0x83, 0x30, 0xb0, 0x6b, 0x74, 0xf7,
0x46f7746bb0308370, 0x46, 0xf9, 0x11, 0x74, 0x34, 0xf5, 0x3e, 0x68, 0x04, 0x92, 0x44, 0x8d, 0x20, 0x7f, 0x8d,
0x4683ef5347411f9, 0x83, 0x58,
0x58838d7f208d4492,
]); ]);
let b_fr = Fr::from_repr(b).unwrap(); let b_fr = Fr::from_repr(b).unwrap();
let c = FrRepr([ let c = FrRepr([
0x48a09ab93cfc740d, 0x0d, 0x74, 0xfc, 0x3c, 0xb9, 0x9a, 0xa0, 0x48, 0x71, 0xa6, 0xc7, 0xbf, 0x0f, 0x60, 0xa6,
0x3a6600fbfc7a671, 0x03, 0x67, 0xd7, 0x01, 0x75, 0x01, 0x67, 0x85, 0x83, 0x12, 0x55, 0x74, 0x77, 0xda, 0xd6,
0x838567017501d767, 0x61, 0x71,
0x7161d6da77745512,
]); ]);
a_fr.mul_assign(&b_fr); a_fr.mul_assign(&b_fr);
assert_eq!(a_fr.into_repr(), c); assert_eq!(a_fr.into_repr(), c);
// Zero should be in the field. // 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([ let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
@ -874,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] #[test]
fn test_fr_display() { fn test_fr_display() {
assert_eq!( assert_eq!(
format!( format!(
"{}", "{}",
Fr::from_repr(FrRepr([ Fr::from_repr(FrRepr([
0xc3cae746a3b5ecc7, 0xc7, 0xec, 0xb5, 0xa3, 0x46, 0xe7, 0xca, 0xc3, 0xee, 0x5a, 0x5b, 0x3f, 0xeb, 0xc8,
0x185ec8eb3f5b5aee, 0x5e, 0x18, 0x99, 0xdd, 0xb9, 0xe4, 0xff, 0x99, 0x44, 0x68, 0xaa, 0x8f, 0xb6, 0xaf,
0x684499ffe4b9dd99, 0xa7, 0xbb, 0xc9, 0x07,
0x7c9bba7afb68faa
])) ]))
.unwrap() .unwrap()
), ),
@ -937,10 +598,9 @@ fn test_fr_display() {
format!( format!(
"{}", "{}",
Fr::from_repr(FrRepr([ Fr::from_repr(FrRepr([
0x44c71298ff198106, 0x06, 0x81, 0x19, 0xff, 0x98, 0x12, 0xc7, 0x44, 0x6a, 0x9b, 0xf7, 0x7d, 0x81, 0x10,
0xb0ad10817df79b6a, 0xad, 0xb0, 0x2b, 0x13, 0x74, 0x2b, 0x0a, 0xa8, 0x34, 0xd0, 0x19, 0x07, 0xf5, 0x36,
0xd034a80a2b74132b, 0x13, 0x9a, 0xcf, 0x41,
0x41cf9a1336f50719
])) ]))
.unwrap() .unwrap()
), ),
@ -948,6 +608,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] #[test]
fn test_fr_num_bits() { fn test_fr_num_bits() {
assert_eq!(Fr::NUM_BITS, 255); assert_eq!(Fr::NUM_BITS, 255);
@ -959,20 +631,17 @@ fn test_fr_root_of_unity() {
use ff::SqrtField; use ff::SqrtField;
assert_eq!(Fr::S, 32); assert_eq!(Fr::S, 32);
assert_eq!( assert_eq!(Fr::multiplicative_generator(), Fr::from(7));
Fr::multiplicative_generator(),
Fr::from_repr(FrRepr::from(7)).unwrap()
);
assert_eq!( assert_eq!(
Fr::multiplicative_generator().pow_vartime([ Fr::multiplicative_generator().pow_vartime([
0xfffe5bfeffffffff, 0xfffe5bfeffffffffu64,
0x9a1d80553bda402, 0x9a1d80553bda402,
0x299d7d483339d808, 0x299d7d483339d808,
0x73eda753 0x73eda753
]), ]),
Fr::root_of_unity() 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())); assert!(bool::from(Fr::multiplicative_generator().sqrt().is_none()));
} }

View File

@ -23,7 +23,7 @@ pub use self::fr::{Fr, FrRepr};
use super::{Engine, PairingCurveAffine}; use super::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, ScalarEngine}; use ff::{BitIterator, Field, PowVartime, ScalarEngine};
use group::CurveAffine; use group::CurveAffine;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption; use subtle::CtOption;
@ -82,7 +82,7 @@ impl Engine for Bls12 {
let mut f = Fq12::one(); let mut f = Fq12::one();
let mut found_one = false; let mut found_one = false;
for i in BitIterator::new(&[BLS_X >> 1]) { for i in BitIterator::<u64, _>::new(&[BLS_X >> 1]) {
if !found_one { if !found_one {
found_one = i; found_one = i;
continue; continue;
@ -324,7 +324,7 @@ impl G2Prepared {
let mut r: G2 = q.into(); let mut r: G2 = q.into();
let mut found_one = false; let mut found_one = false;
for i in BitIterator::new([BLS_X >> 1]) { for i in BitIterator::<u64, _>::new([BLS_X >> 1]) {
if !found_one { if !found_one {
found_one = i; found_one = i;
continue; continue;

View File

@ -1,4 +1,4 @@
use ff::PrimeFieldRepr; use ff::PrimeField;
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use super::*; 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; 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"); assert_eq!(coordinate, "x coordinate");
} else { } else {
panic!("should have rejected the point") panic!("should have rejected the point")
@ -162,9 +164,9 @@ fn test_g1_uncompressed_invalid_vectors() {
{ {
let mut o = o; 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"); assert_eq!(coordinate, "y coordinate");
} else { } else {
panic!("should have rejected the point") panic!("should have rejected the point")
@ -175,7 +177,7 @@ fn test_g1_uncompressed_invalid_vectors() {
let m = Fq::zero().into_repr(); let m = Fq::zero().into_repr();
let mut o = o; 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() { if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
// :) // :)
@ -191,15 +193,15 @@ fn test_g1_uncompressed_invalid_vectors() {
loop { loop {
let mut x3b = x.square(); let mut x3b = x.square();
x3b.mul_assign(&x); 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(); let y = x3b.sqrt();
if y.is_some().into() { if y.is_some().into() {
let y = y.unwrap(); let y = y.unwrap();
// We know this is on the curve, but it's likely not going to be in the correct subgroup. // 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()[..48].copy_from_slice(x.into_repr().as_ref());
y.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); o.as_mut()[48..].copy_from_slice(y.into_repr().as_ref());
if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
break; 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; 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)"); assert_eq!(coordinate, "x coordinate (c1)");
} else { } else {
panic!("should have rejected the point") panic!("should have rejected the point")
@ -278,9 +282,9 @@ fn test_g2_uncompressed_invalid_vectors() {
{ {
let mut o = o; 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)"); assert_eq!(coordinate, "x coordinate (c0)");
} else { } else {
panic!("should have rejected the point") panic!("should have rejected the point")
@ -289,9 +293,9 @@ fn test_g2_uncompressed_invalid_vectors() {
{ {
let mut o = o; 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)"); assert_eq!(coordinate, "y coordinate (c1)");
} else { } else {
panic!("should have rejected the point") panic!("should have rejected the point")
@ -300,9 +304,9 @@ fn test_g2_uncompressed_invalid_vectors() {
{ {
let mut o = o; 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)"); assert_eq!(coordinate, "y coordinate (c0)");
} else { } else {
panic!("should have rejected the point") panic!("should have rejected the point")
@ -313,8 +317,8 @@ fn test_g2_uncompressed_invalid_vectors() {
let m = Fq::zero().into_repr(); let m = Fq::zero().into_repr();
let mut o = o; let mut o = o;
m.write_be(&mut o.as_mut()[0..]).unwrap(); o.as_mut()[..48].copy_from_slice(m.as_ref());
m.write_be(&mut o.as_mut()[48..]).unwrap(); o.as_mut()[48..96].copy_from_slice(m.as_ref());
if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
// :) // :)
@ -331,8 +335,8 @@ fn test_g2_uncompressed_invalid_vectors() {
let mut x3b = x.square(); let mut x3b = x.square();
x3b.mul_assign(&x); x3b.mul_assign(&x);
x3b.add_assign(&Fq2 { x3b.add_assign(&Fq2 {
c0: Fq::from_repr(FqRepr::from(4)).unwrap(), c0: Fq::from(4),
c1: Fq::from_repr(FqRepr::from(4)).unwrap(), c1: Fq::from(4),
}); // TODO: perhaps expose coeff_b through API? }); // TODO: perhaps expose coeff_b through API?
let y = x3b.sqrt(); let y = x3b.sqrt();
@ -340,10 +344,10 @@ fn test_g2_uncompressed_invalid_vectors() {
let y = y.unwrap(); let y = y.unwrap();
// We know this is on the curve, but it's likely not going to be in the correct subgroup. // 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(); o.as_mut()[..48].copy_from_slice(x.c1.into_repr().as_ref());
x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); o.as_mut()[48..96].copy_from_slice(x.c0.into_repr().as_ref());
y.c1.into_repr().write_be(&mut o.as_mut()[96..]).unwrap(); o.as_mut()[96..144].copy_from_slice(y.c1.into_repr().as_ref());
y.c0.into_repr().write_be(&mut o.as_mut()[144..]).unwrap(); o.as_mut()[144..].copy_from_slice(y.c0.into_repr().as_ref());
if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
break; 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; 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; 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"); assert_eq!(coordinate, "x coordinate");
} else { } else {
panic!("should have rejected the point") panic!("should have rejected the point")
@ -428,12 +434,12 @@ fn test_g1_compressed_invalid_vectors() {
loop { loop {
let mut x3b = x.square(); let mut x3b = x.square();
x3b.mul_assign(&x); 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() { if x3b.sqrt().is_some().into() {
x.add_assign(&Fq::one()); x.add_assign(&Fq::one());
} else { } 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; o.as_mut()[0] |= 0b1000_0000;
if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
@ -452,11 +458,11 @@ fn test_g1_compressed_invalid_vectors() {
loop { loop {
let mut x3b = x.square(); let mut x3b = x.square();
x3b.mul_assign(&x); 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() { 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. // 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; o.as_mut()[0] |= 0b1000_0000;
if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { 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; 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; 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)"); assert_eq!(coordinate, "x coordinate (c1)");
} else { } else {
panic!("should have rejected the point") panic!("should have rejected the point")
@ -537,10 +545,10 @@ fn test_g2_compressed_invalid_vectors() {
{ {
let mut o = o; 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; 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)"); assert_eq!(coordinate, "x coordinate (c0)");
} else { } else {
panic!("should have rejected the point") panic!("should have rejected the point")
@ -558,15 +566,15 @@ fn test_g2_compressed_invalid_vectors() {
let mut x3b = x.square(); let mut x3b = x.square();
x3b.mul_assign(&x); x3b.mul_assign(&x);
x3b.add_assign(&Fq2 { x3b.add_assign(&Fq2 {
c0: Fq::from_repr(FqRepr::from(4)).unwrap(), c0: Fq::from(4),
c1: Fq::from_repr(FqRepr::from(4)).unwrap(), c1: Fq::from(4),
}); // TODO: perhaps expose coeff_b through API? }); // TODO: perhaps expose coeff_b through API?
if x3b.sqrt().is_some().into() { if x3b.sqrt().is_some().into() {
x.add_assign(&Fq2::one()); x.add_assign(&Fq2::one());
} else { } else {
x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); o.as_mut()[..48].copy_from_slice(x.c1.into_repr().as_ref());
x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); o.as_mut()[48..].copy_from_slice(x.c0.into_repr().as_ref());
o.as_mut()[0] |= 0b1000_0000; o.as_mut()[0] |= 0b1000_0000;
if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
@ -589,14 +597,14 @@ fn test_g2_compressed_invalid_vectors() {
let mut x3b = x.square(); let mut x3b = x.square();
x3b.mul_assign(&x); x3b.mul_assign(&x);
x3b.add_assign(&Fq2 { x3b.add_assign(&Fq2 {
c0: Fq::from_repr(FqRepr::from(4)).unwrap(), c0: Fq::from(4),
c1: Fq::from_repr(FqRepr::from(4)).unwrap(), c1: Fq::from(4),
}); // TODO: perhaps expose coeff_b through API? }); // TODO: perhaps expose coeff_b through API?
if x3b.sqrt().is_some().into() { 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. // 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(); o.as_mut()[..48].copy_from_slice(x.c1.into_repr().as_ref());
x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); o.as_mut()[48..].copy_from_slice(x.c0.into_repr().as_ref());
o.as_mut()[0] |= 0b1000_0000; o.as_mut()[0] |= 0b1000_0000;
if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {

View File

@ -1,3 +1,4 @@
use ff::PowVartime;
use group::{CurveAffine, CurveProjective}; use group::{CurveAffine, CurveProjective};
use rand_core::SeedableRng; use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;

View File

@ -1,8 +1,8 @@
use ff::{Field, PrimeField, SqrtField}; use ff::{Field, PowVartime, PrimeField, SqrtField};
use rand_core::{RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
pub fn random_frobenius_tests<F: Field, C: AsRef<[u64]>>(characteristic: C, maxpower: usize) { pub fn random_frobenius_tests<F: Field, C: AsRef<[u8]>>(characteristic: C, maxpower: usize) {
let mut rng = XorShiftRng::from_seed([ let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5, 0xe5,
@ -119,7 +119,7 @@ pub fn from_str_tests<F: PrimeField>() {
let n = rng.next_u64(); let n = rng.next_u64();
let a = F::from_str(&format!("{}", n)).unwrap(); 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); assert_eq!(a, b);
} }

View File

@ -1,10 +1,9 @@
use ff::{PrimeField, PrimeFieldRepr}; use ff::PrimeField;
use rand_core::SeedableRng; use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
pub fn random_repr_tests<P: PrimeField>() { pub fn random_repr_tests<P: PrimeField>() {
random_encoding_tests::<P>(); random_encoding_tests::<P>();
random_shl_tests::<P>();
random_shr_tests::<P>(); random_shr_tests::<P>();
} }
@ -15,71 +14,12 @@ fn random_encoding_tests<P: PrimeField>() {
]); ]);
for _ in 0..1000 { for _ in 0..1000 {
let r = P::random(&mut rng).into_repr(); let r = P::random(&mut rng);
// Big endian let v = r.into_repr();
{ let rdecoded = P::from_repr(v).unwrap();
let mut rdecoded = <P as PrimeField>::Repr::default();
let mut v: Vec<u8> = vec![]; assert_eq!(r, rdecoded);
r.write_be(&mut v).unwrap();
rdecoded.read_be(&v[0..]).unwrap();
assert_eq!(r, rdecoded);
}
// Little endian
{
let mut rdecoded = <P as PrimeField>::Repr::default();
let mut v: Vec<u8> = vec![];
r.write_le(&mut v).unwrap();
rdecoded.read_le(&v[0..]).unwrap();
assert_eq!(r, rdecoded);
}
{
let mut rdecoded_le = <P as PrimeField>::Repr::default();
let mut rdecoded_be_flip = <P as PrimeField>::Repr::default();
let mut v: Vec<u8> = 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<u8> = v.into_iter().rev().collect();
rdecoded_be_flip.read_be(&v[..]).unwrap();
assert_eq!(rdecoded_le, rdecoded_be_flip);
}
}
}
fn random_shl_tests<P: PrimeField>() {
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);
}
} }
} }
@ -90,19 +30,22 @@ fn random_shr_tests<P: PrimeField>() {
]); ]);
for _ in 0..100 { 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() { for shift in 0..P::NUM_BITS {
let mut r1 = r; let r1 = r >> shift;
let mut r2 = r;
// Doubling the shifted element inserts zeros on the right; re-shifting should
// undo the doubling.
let mut r2 = r1;
for _ in 0..shift { for _ in 0..shift {
r1.div2(); r2 = r2.double();
} }
r2 = r2 >> shift;
r2.shr(shift);
assert_eq!(r1, r2); assert_eq!(r1, r2);
} }
assert_eq!(r >> P::NUM_BITS, P::zero());
} }
} }

View File

@ -1,6 +1,6 @@
//! Generated code for handling light client protobuf structs. //! Generated code for handling light client protobuf structs.
use ff::{PrimeField, PrimeFieldRepr}; use ff::PrimeField;
use pairing::bls12_381::{Bls12, Fr, FrRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr};
use zcash_primitives::{ use zcash_primitives::{
block::{BlockHash, BlockHeader}, block::{BlockHash, BlockHeader},
@ -67,8 +67,8 @@ impl compact_formats::CompactOutput {
/// [`CompactOutput.cmu`]: #structfield.cmu /// [`CompactOutput.cmu`]: #structfield.cmu
pub fn cmu(&self) -> Result<Fr, ()> { pub fn cmu(&self) -> Result<Fr, ()> {
let mut repr = FrRepr::default(); let mut repr = FrRepr::default();
repr.read_le(&self.cmu[..]).map_err(|_| ())?; repr.as_mut().copy_from_slice(&self.cmu[..]);
Fr::from_repr(repr).map_err(|_| ()) Fr::from_repr(repr).ok_or(())
} }
/// Returns the ephemeral public key for this output. /// Returns the ephemeral public key for this output.

View File

@ -183,7 +183,7 @@ pub fn scan_block(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ff::{Field, PrimeField, PrimeFieldRepr}; use ff::{Field, PrimeField};
use pairing::bls12_381::{Bls12, Fr}; use pairing::bls12_381::{Bls12, Fr};
use rand_core::{OsRng, RngCore}; use rand_core::{OsRng, RngCore};
use zcash_primitives::{ use zcash_primitives::{
@ -207,9 +207,7 @@ mod tests {
}; };
let fake_cmu = { let fake_cmu = {
let fake_cmu = Fr::random(rng); let fake_cmu = Fr::random(rng);
let mut bytes = vec![]; fake_cmu.into_repr().as_ref().to_owned()
fake_cmu.into_repr().write_le(&mut bytes).unwrap();
bytes
}; };
let fake_epk = { let fake_epk = {
let mut buffer = vec![0; 64]; let mut buffer = vec![0; 64];
@ -264,8 +262,7 @@ mod tests {
Memo::default(), Memo::default(),
&mut rng, &mut rng,
); );
let mut cmu = vec![]; let cmu = note.cm(&JUBJUB).into_repr().as_ref().to_owned();
note.cm(&JUBJUB).into_repr().write_le(&mut cmu).unwrap();
let mut epk = vec![]; let mut epk = vec![];
encryptor.epk().write(&mut epk).unwrap(); encryptor.epk().write(&mut epk).unwrap();
let enc_ciphertext = encryptor.encrypt_note_plaintext(); let enc_ciphertext = encryptor.encrypt_note_plaintext();

View File

@ -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 std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption; use subtle::CtOption;
@ -83,15 +83,15 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
} }
impl<E: JubjubEngine> Point<E, Unknown> { impl<E: JubjubEngine> Point<E, Unknown> {
pub fn read<R: Read>(reader: R, params: &E::Params) -> io::Result<Self> { pub fn read<R: Read>(mut reader: R, params: &E::Params) -> io::Result<Self> {
let mut y_repr = <E::Fr as PrimeField>::Repr::default(); let mut y_repr = <E::Fr as PrimeField>::Repr::default();
y_repr.read_le(reader)?; reader.read_exact(y_repr.as_mut())?;
let x_sign = (y_repr.as_ref()[3] >> 63) == 1; let x_sign = (y_repr.as_ref()[31] >> 7) == 1;
y_repr.as_mut()[3] &= 0x7fffffffffffffff; y_repr.as_mut()[31] &= 0x7f;
match E::Fr::from_repr(y_repr) { match E::Fr::from_repr(y_repr) {
Ok(y) => { Some(y) => {
let p = Self::get_for_y(y, x_sign, params); let p = Self::get_for_y(y, x_sign, params);
if bool::from(p.is_some()) { if bool::from(p.is_some()) {
Ok(p.unwrap()) Ok(p.unwrap())
@ -99,7 +99,7 @@ impl<E: JubjubEngine> Point<E, Unknown> {
Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")) Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve"))
} }
} }
Err(_) => Err(io::Error::new( None => Err(io::Error::new(
io::ErrorKind::InvalidInput, io::ErrorKind::InvalidInput,
"y is not in field", "y is not in field",
)), )),
@ -127,7 +127,7 @@ impl<E: JubjubEngine> Point<E, Unknown> {
tmp1.mul_assign(&tmp2); tmp1.mul_assign(&tmp2);
tmp1.sqrt().map(|mut x| { tmp1.sqrt().map(|mut x| {
if x.into_repr().is_odd() != sign { if x.is_odd() != sign {
x = x.neg(); x = x.neg();
} }
@ -167,18 +167,17 @@ impl<E: JubjubEngine> Point<E, Unknown> {
} }
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> { impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
pub fn write<W: Write>(&self, writer: W) -> io::Result<()> { pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
let (x, y) = self.to_xy(); let (x, y) = self.to_xy();
assert_eq!(E::Fr::NUM_BITS, 255); assert_eq!(E::Fr::NUM_BITS, 255);
let x_repr = x.into_repr();
let mut y_repr = y.into_repr(); let mut y_repr = y.into_repr();
if x_repr.is_odd() { 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 /// Convert from a Montgomery point
@ -468,7 +467,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
let mut res = Self::zero(); let mut res = Self::zero();
for b in BitIterator::new(scalar.into()) { for b in BitIterator::<u8, _>::new(scalar.into()) {
res = res.double(params); res = res.double(params);
if b { if b {

File diff suppressed because it is too large Load Diff

View File

@ -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 std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption; use subtle::CtOption;
@ -60,7 +60,7 @@ impl<E: JubjubEngine> Point<E, Unknown> {
rhs.add_assign(&x2); rhs.add_assign(&x2);
rhs.sqrt().map(|mut y| { rhs.sqrt().map(|mut y| {
if y.into_repr().is_odd() != sign { if y.is_odd() != sign {
y = y.neg(); y = y.neg();
} }
@ -304,7 +304,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
let mut res = Self::zero(); let mut res = Self::zero();
for b in BitIterator::new(scalar.into()) { for b in BitIterator::<u8, _>::new(scalar.into()) {
res = res.double(params); res = res.double(params);
if b { if b {

View File

@ -1,6 +1,6 @@
use super::{edwards, montgomery, JubjubEngine, JubjubParams, PrimeOrder}; 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 std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use rand_core::{RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};
@ -237,7 +237,7 @@ fn test_get_for<E: JubjubEngine>(params: &E::Params) {
let p = edwards::Point::<E, _>::get_for_y(y, sign, params); let p = edwards::Point::<E, _>::get_for_y(y, sign, params);
if bool::from(p.is_some()) { if bool::from(p.is_some()) {
let mut p = p.unwrap(); 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(); p = p.negate();
assert!(edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap() == p); assert!(edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap() == p);
} }
@ -370,32 +370,26 @@ fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
// Check that the number of windows per generator // Check that the number of windows per generator
// in the Pedersen hash does not allow for collisions // 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(); let max = (-E::Fs::one()) >> 1;
{
max.sub_noborrow(&E::Fs::one().into_repr());
max.div2();
}
let mut pacc = E::Fs::zero().into_repr(); let mut pacc = E::Fs::zero();
let mut nacc = E::Fs::char(); let mut nacc = E::Fs::zero();
for _ in 0..params.pedersen_hash_chunks_per_generator() { for _ in 0..params.pedersen_hash_chunks_per_generator() {
// tmp = cur * 4 // tmp = cur * 4
let mut tmp = cur; let tmp = cur.double().double();
tmp.mul2();
tmp.mul2();
pacc.add_nocarry(&tmp); pacc += &tmp;
nacc.sub_noborrow(&tmp); nacc -= &tmp; // The first subtraction wraps intentionally.
assert!(pacc < max); assert!(pacc < max);
assert!(pacc < nacc); assert!(pacc < nacc);
// cur = cur * 16 // cur = cur * 16
for _ in 0..4 { for _ in 0..4 {
cur.mul2(); cur = cur.double();
} }
} }
} }

View File

@ -9,7 +9,7 @@ use crate::{
primitives::{ProofGenerationKey, ViewingKey}, primitives::{ProofGenerationKey, ViewingKey},
}; };
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
use ff::{PrimeField, PrimeFieldRepr}; use ff::PrimeField;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
pub const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed"; pub const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed";
@ -71,14 +71,14 @@ impl<E: JubjubEngine> ExpandedSpendingKey<E> {
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> { pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
let mut ask_repr = <E::Fs as PrimeField>::Repr::default(); let mut ask_repr = <E::Fs as PrimeField>::Repr::default();
ask_repr.read_le(&mut reader)?; reader.read_exact(ask_repr.as_mut())?;
let ask = E::Fs::from_repr(ask_repr) 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 = <E::Fs as PrimeField>::Repr::default(); let mut nsk_repr = <E::Fs as PrimeField>::Repr::default();
nsk_repr.read_le(&mut reader)?; reader.read_exact(nsk_repr.as_mut())?;
let nsk = E::Fs::from_repr(nsk_repr) 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]; let mut ovk = [0; 32];
reader.read_exact(&mut ovk)?; reader.read_exact(&mut ovk)?;
@ -91,8 +91,8 @@ impl<E: JubjubEngine> ExpandedSpendingKey<E> {
} }
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> { pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
self.ask.into_repr().write_le(&mut writer)?; writer.write_all(self.ask.into_repr().as_ref())?;
self.nsk.into_repr().write_le(&mut writer)?; writer.write_all(self.nsk.into_repr().as_ref())?;
writer.write_all(&self.ovk.0)?; writer.write_all(&self.ovk.0)?;
Ok(()) Ok(())

View File

@ -511,9 +511,9 @@ mod tests {
use super::{CommitmentTree, Hashable, IncrementalWitness, MerklePath, PathFiller}; use super::{CommitmentTree, Hashable, IncrementalWitness, MerklePath, PathFiller};
use crate::sapling::Node; use crate::sapling::Node;
use ff::PrimeFieldRepr;
use hex; use hex;
use pairing::bls12_381::FrRepr; use pairing::bls12_381::FrRepr;
use std::convert::TryInto;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
const HEX_EMPTY_ROOTS: [&str; 33] = [ const HEX_EMPTY_ROOTS: [&str; 33] = [
@ -1016,9 +1016,7 @@ mod tests {
let mut paths_i = 0; let mut paths_i = 0;
let mut witness_ser_i = 0; let mut witness_ser_i = 0;
for i in 0..16 { for i in 0..16 {
let mut cm = FrRepr::default(); let cm = FrRepr(hex::decode(commitments[i]).unwrap()[..].try_into().unwrap());
cm.read_le(&hex::decode(commitments[i]).unwrap()[..])
.expect("length is 32 bytes");
let cm = Node::new(cm); let cm = Node::new(cm);

View File

@ -11,9 +11,10 @@ use crate::{
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf};
use ff::{PrimeField, PrimeFieldRepr}; use ff::PrimeField;
use pairing::bls12_381::{Bls12, Fr}; use pairing::bls12_381::{Bls12, Fr};
use rand_core::{CryptoRng, RngCore}; use rand_core::{CryptoRng, RngCore};
use std::convert::TryInto;
use std::fmt; use std::fmt;
use std::str; use std::str;
@ -192,7 +193,7 @@ fn prf_ock(
let mut ock_input = [0u8; 128]; let mut ock_input = [0u8; 128];
ock_input[0..32].copy_from_slice(&ovk.0); ock_input[0..32].copy_from_slice(&ovk.0);
cv.write(&mut ock_input[32..64]).unwrap(); 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(); epk.write(&mut ock_input[96..128]).unwrap();
Blake2bParams::new() Blake2bParams::new()
@ -302,11 +303,7 @@ impl SaplingNoteEncryption {
(&mut input[12..20]) (&mut input[12..20])
.write_u64::<LittleEndian>(self.note.value) .write_u64::<LittleEndian>(self.note.value)
.unwrap(); .unwrap();
self.note input[20..COMPACT_NOTE_SIZE].copy_from_slice(self.note.r.into_repr().as_ref());
.r
.into_repr()
.write_le(&mut input[20..COMPACT_NOTE_SIZE])
.unwrap();
input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&self.memo.0); input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&self.memo.0);
let mut output = [0u8; ENC_CIPHERTEXT_SIZE]; let mut output = [0u8; ENC_CIPHERTEXT_SIZE];
@ -330,10 +327,7 @@ impl SaplingNoteEncryption {
let mut input = [0u8; OUT_PLAINTEXT_SIZE]; let mut input = [0u8; OUT_PLAINTEXT_SIZE];
self.note.pk_d.write(&mut input[0..32]).unwrap(); self.note.pk_d.write(&mut input[0..32]).unwrap();
self.esk input[32..OUT_PLAINTEXT_SIZE].copy_from_slice(self.esk.into_repr().as_ref());
.into_repr()
.write_le(&mut input[32..OUT_PLAINTEXT_SIZE])
.unwrap();
let mut output = [0u8; OUT_CIPHERTEXT_SIZE]; let mut output = [0u8; OUT_CIPHERTEXT_SIZE];
assert_eq!( assert_eq!(
@ -363,9 +357,11 @@ fn parse_note_plaintext_without_memo(
let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?; let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?;
let mut rcm = FsRepr::default(); let rcm = Fs::from_repr(FsRepr(
rcm.read_le(&plaintext[20..COMPACT_NOTE_SIZE]).ok()?; plaintext[20..COMPACT_NOTE_SIZE]
let rcm = Fs::from_repr(rcm).ok()?; .try_into()
.expect("slice is the correct length"),
))?;
let diversifier = Diversifier(d); let diversifier = Diversifier(d);
let pk_d = diversifier let pk_d = diversifier
@ -483,9 +479,11 @@ pub fn try_sapling_output_recovery(
.ok()? .ok()?
.as_prime_order(&JUBJUB)?; .as_prime_order(&JUBJUB)?;
let mut esk = FsRepr::default(); let esk = Fs::from_repr(FsRepr(
esk.read_le(&op[32..OUT_PLAINTEXT_SIZE]).ok()?; op[32..OUT_PLAINTEXT_SIZE]
let esk = Fs::from_repr(esk).ok()?; .try_into()
.expect("slice is the correct length"),
))?;
let shared_secret = sapling_ka_agree(&esk, &pk_d); let shared_secret = sapling_ka_agree(&esk, &pk_d);
let key = kdf_sapling(shared_secret, &epk); let key = kdf_sapling(shared_secret, &epk);
@ -515,9 +513,11 @@ pub fn try_sapling_output_recovery(
let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?; let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?;
let mut rcm = FsRepr::default(); let rcm = Fs::from_repr(FsRepr(
rcm.read_le(&plaintext[20..COMPACT_NOTE_SIZE]).ok()?; plaintext[20..COMPACT_NOTE_SIZE]
let rcm = Fs::from_repr(rcm).ok()?; .try_into()
.expect("slice is the correct length"),
))?;
let mut memo = [0u8; 512]; let mut memo = [0u8; 512];
memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]); memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]);
@ -554,10 +554,11 @@ mod tests {
primitives::{Diversifier, PaymentAddress, ValueCommitment}, primitives::{Diversifier, PaymentAddress, ValueCommitment},
}; };
use crypto_api_chachapoly::ChachaPolyIetf; use crypto_api_chachapoly::ChachaPolyIetf;
use ff::{Field, PrimeField, PrimeFieldRepr}; use ff::{Field, PrimeField};
use pairing::bls12_381::{Bls12, Fr, FrRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr};
use rand_core::OsRng; use rand_core::OsRng;
use rand_core::{CryptoRng, RngCore}; use rand_core::{CryptoRng, RngCore};
use std::convert::TryInto;
use std::str::FromStr; use std::str::FromStr;
use super::{ use super::{
@ -791,9 +792,7 @@ mod tests {
.as_prime_order(&JUBJUB) .as_prime_order(&JUBJUB)
.unwrap(); .unwrap();
let mut esk = FsRepr::default(); let esk = Fs::from_repr(FsRepr(op[32..OUT_PLAINTEXT_SIZE].try_into().unwrap())).unwrap();
esk.read_le(&op[32..OUT_PLAINTEXT_SIZE]).unwrap();
let esk = Fs::from_repr(esk).unwrap();
let shared_secret = sapling_ka_agree(&esk, &pk_d); let shared_secret = sapling_ka_agree(&esk, &pk_d);
let key = kdf_sapling(shared_secret, &epk); let key = kdf_sapling(shared_secret, &epk);
@ -1292,17 +1291,13 @@ mod tests {
macro_rules! read_fr { macro_rules! read_fr {
($field:expr) => {{ ($field:expr) => {{
let mut repr = FrRepr::default(); Fr::from_repr(FrRepr($field[..].try_into().unwrap())).unwrap()
repr.read_le(&$field[..]).unwrap();
Fr::from_repr(repr).unwrap()
}}; }};
} }
macro_rules! read_fs { macro_rules! read_fs {
($field:expr) => {{ ($field:expr) => {{
let mut repr = FsRepr::default(); Fs::from_repr(FsRepr($field[..].try_into().unwrap())).unwrap()
repr.read_le(&$field[..]).unwrap();
Fs::from_repr(repr).unwrap()
}}; }};
} }

View File

@ -1,7 +1,7 @@
//! Implementation of the Pedersen hash function used in Sapling. //! Implementation of the Pedersen hash function used in Sapling.
use crate::jubjub::*; use crate::jubjub::*;
use ff::{Field, PrimeField, PrimeFieldRepr}; use ff::Field;
use std::ops::{AddAssign, Neg}; use std::ops::{AddAssign, Neg};
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -88,16 +88,14 @@ where
let window = JubjubBls12::pedersen_hash_exp_window_size(); let window = JubjubBls12::pedersen_hash_exp_window_size();
let window_mask = (1 << window) - 1; let window_mask = (1 << window) - 1;
let mut acc = acc.into_repr();
let mut tmp = edwards::Point::zero(); let mut tmp = edwards::Point::zero();
while !acc.is_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); tmp = tmp.add(&table[0][i], params);
acc.shr(window); acc = acc >> window;
table = &table[1..]; table = &table[1..];
} }

View File

@ -1,6 +1,6 @@
//! Structs for core Zcash primitives. //! Structs for core Zcash primitives.
use ff::{Field, PrimeField, PrimeFieldRepr}; use ff::{Field, PrimeField};
use crate::constants; use crate::constants;
@ -24,7 +24,7 @@ impl<E: JubjubEngine> ValueCommitment<E> {
pub fn cm(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder> { pub fn cm(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
params params
.generator(FixedGenerators::ValueCommitmentValue) .generator(FixedGenerators::ValueCommitmentValue)
.mul(self.value, params) .mul(E::Fs::from(self.value), params)
.add( .add(
&params &params
.generator(FixedGenerators::ValueCommitmentRandomness) .generator(FixedGenerators::ValueCommitmentRandomness)
@ -86,7 +86,7 @@ impl<E: JubjubEngine> ViewingKey<E> {
h[31] &= 0b0000_0111; h[31] &= 0b0000_0111;
let mut e = <E::Fs as PrimeField>::Repr::default(); let mut e = <E::Fs as PrimeField>::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") E::Fs::from_repr(e).expect("should be a valid scalar")
} }
@ -291,7 +291,7 @@ impl<E: JubjubEngine> Note<E> {
let rho = self.cm_full_point(params).add( let rho = self.cm_full_point(params).add(
&params &params
.generator(FixedGenerators::NullifierPosition) .generator(FixedGenerators::NullifierPosition)
.mul(position, params), .mul(E::Fs::from(position), params),
params, params,
); );

View File

@ -4,23 +4,23 @@
//! [RedJubjub]: https://zips.z.cash/protocol/protocol.pdf#concretereddsa //! [RedJubjub]: https://zips.z.cash/protocol/protocol.pdf#concretereddsa
use crate::jubjub::{edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown}; use crate::jubjub::{edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown};
use ff::{Field, PrimeField, PrimeFieldRepr}; use ff::{Field, PrimeField};
use rand_core::RngCore; use rand_core::RngCore;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
use std::ops::{AddAssign, MulAssign, Neg}; use std::ops::{AddAssign, MulAssign, Neg};
use crate::util::hash_to_scalar; use crate::util::hash_to_scalar;
fn read_scalar<E: JubjubEngine, R: Read>(reader: R) -> io::Result<E::Fs> { fn read_scalar<E: JubjubEngine, R: Read>(mut reader: R) -> io::Result<E::Fs> {
let mut s_repr = <E::Fs as PrimeField>::Repr::default(); let mut s_repr = <E::Fs as PrimeField>::Repr::default();
s_repr.read_le(reader)?; reader.read_exact(s_repr.as_mut())?;
E::Fs::from_repr(s_repr) 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<E: JubjubEngine, W: Write>(s: &E::Fs, writer: W) -> io::Result<()> { fn write_scalar<E: JubjubEngine, W: Write>(s: &E::Fs, mut writer: W) -> io::Result<()> {
s.into_repr().write_le(writer) writer.write_all(s.into_repr().as_ref())
} }
fn h_star<E: JubjubEngine>(a: &[u8], b: &[u8]) -> E::Fs { fn h_star<E: JubjubEngine>(a: &[u8], b: &[u8]) -> E::Fs {

View File

@ -5,7 +5,7 @@ use crate::{
pedersen_hash::{pedersen_hash, Personalization}, pedersen_hash::{pedersen_hash, Personalization},
primitives::Note, primitives::Note,
}; };
use ff::{BitIterator, PrimeField, PrimeFieldRepr}; use ff::{BitIterator, PrimeField};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use pairing::bls12_381::{Bls12, Fr, FrRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr};
use rand_core::{CryptoRng, RngCore}; 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 { pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr {
let lhs = { let lhs = {
let mut tmp = [false; 256]; 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::<u8, _>::new(lhs)) {
*a = b; *a = b;
} }
tmp tmp
@ -29,7 +29,7 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr {
let rhs = { let rhs = {
let mut tmp = [false; 256]; 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::<u8, _>::new(rhs)) {
*a = b; *a = b;
} }
tmp tmp
@ -62,13 +62,13 @@ impl Node {
impl Hashable for Node { impl Hashable for Node {
fn read<R: Read>(mut reader: R) -> io::Result<Self> { fn read<R: Read>(mut reader: R) -> io::Result<Self> {
let mut repr = FrRepr::default(); let mut repr = FrRepr([0; 32]);
repr.read_le(&mut reader)?; reader.read_exact(&mut repr.0)?;
Ok(Node::new(repr)) Ok(Node::new(repr))
} }
fn write<W: Write>(&self, mut writer: W) -> io::Result<()> { fn write<W: 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 { fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self {

View File

@ -2,7 +2,7 @@
use crate::jubjub::{edwards, Unknown}; use crate::jubjub::{edwards, Unknown};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use ff::{PrimeField, PrimeFieldRepr}; use ff::PrimeField;
use pairing::bls12_381::{Bls12, Fr, FrRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr};
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
@ -138,9 +138,10 @@ impl SpendDescription {
// Consensus rule (§7.3): Canonical encoding is enforced here // Consensus rule (§7.3): Canonical encoding is enforced here
let anchor = { let anchor = {
let mut f = FrRepr::default(); let mut f = FrRepr([0; 32]);
f.read_le(&mut reader)?; reader.read_exact(&mut f.0)?;
Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))? Fr::from_repr(f)
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "anchor not in field"))?
}; };
let mut nullifier = [0; 32]; let mut nullifier = [0; 32];
@ -175,7 +176,7 @@ impl SpendDescription {
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> { pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
self.cv.write(&mut writer)?; 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)?; writer.write_all(&self.nullifier)?;
self.rk.write(&mut writer)?; self.rk.write(&mut writer)?;
writer.write_all(&self.zkproof)?; writer.write_all(&self.zkproof)?;
@ -218,9 +219,10 @@ impl OutputDescription {
// Consensus rule (§7.4): Canonical encoding is enforced here // Consensus rule (§7.4): Canonical encoding is enforced here
let cmu = { let cmu = {
let mut f = FrRepr::default(); let mut f = FrRepr([0; 32]);
f.read_le(&mut reader)?; reader.read_exact(&mut f.0)?;
Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))? Fr::from_repr(f)
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "cmu not in field"))?
}; };
// Consensus rules (§4.5): // Consensus rules (§4.5):
@ -252,7 +254,7 @@ impl OutputDescription {
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> { pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
self.cv.write(&mut writer)?; 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)?; self.ephemeral_key.write(&mut writer)?;
writer.write_all(&self.enc_ciphertext)?; writer.write_all(&self.enc_ciphertext)?;
writer.write_all(&self.out_ciphertext)?; writer.write_all(&self.out_ciphertext)?;

View File

@ -1,6 +1,6 @@
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
use byteorder::{LittleEndian, WriteBytesExt}; use byteorder::{LittleEndian, WriteBytesExt};
use ff::{PrimeField, PrimeFieldRepr}; use ff::PrimeField;
use super::{ use super::{
components::{Amount, TxOut}, 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); let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384);
for s_spend in &tx.shielded_spends { for s_spend in &tx.shielded_spends {
s_spend.cv.write(&mut data).unwrap(); 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); data.extend_from_slice(&s_spend.nullifier);
s_spend.rk.write(&mut data).unwrap(); s_spend.rk.write(&mut data).unwrap();
data.extend_from_slice(&s_spend.zkproof); data.extend_from_slice(&s_spend.zkproof);

View File

@ -453,7 +453,7 @@ impl ExtendedFullViewingKey {
mod tests { mod tests {
use super::*; use super::*;
use ff::{PrimeField, PrimeFieldRepr}; use ff::PrimeField;
#[test] #[test]
fn derive_nonhardened_child() { fn derive_nonhardened_child() {
@ -1014,11 +1014,8 @@ mod tests {
let xsk = &xsks[j]; let xsk = &xsks[j];
let tv = &test_vectors[j]; let tv = &test_vectors[j];
let mut buf = [0; 32]; assert_eq!(xsk.expsk.ask.into_repr().as_ref(), tv.ask.unwrap());
xsk.expsk.ask.into_repr().write_le(&mut buf[..]).unwrap(); assert_eq!(xsk.expsk.nsk.into_repr().as_ref(), tv.nsk.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.ovk.0, tv.ovk); assert_eq!(xsk.expsk.ovk.0, tv.ovk);
assert_eq!(xsk.dk.0, tv.dk); assert_eq!(xsk.dk.0, tv.dk);
@ -1043,13 +1040,7 @@ mod tests {
assert_eq!(xfvk.dk.0, tv.dk); assert_eq!(xfvk.dk.0, tv.dk);
assert_eq!(xfvk.chain_code.0, tv.c); assert_eq!(xfvk.chain_code.0, tv.c);
xfvk.fvk assert_eq!(xfvk.fvk.vk.ivk().into_repr().as_ref(), tv.ivk);
.vk
.ivk()
.into_repr()
.write_le(&mut buf[..])
.unwrap();
assert_eq!(buf, tv.ivk);
let mut ser = vec![]; let mut ser = vec![];
xfvk.write(&mut ser).unwrap(); xfvk.write(&mut ser).unwrap();

View File

@ -769,7 +769,7 @@ mod test {
let q = p.mul(s, params); let q = p.mul(s, params);
let (x1, y1) = q.to_xy(); let (x1, y1) = q.to_xy();
let mut s_bits = BitIterator::new(s.into_repr()).collect::<Vec<_>>(); let mut s_bits = BitIterator::<u8, _>::new(s.into_repr()).collect::<Vec<_>>();
s_bits.reverse(); s_bits.reverse();
s_bits.truncate(Fs::NUM_BITS as usize); s_bits.truncate(Fs::NUM_BITS as usize);
@ -822,7 +822,7 @@ mod test {
y: num_y0, y: num_y0,
}; };
let mut s_bits = BitIterator::new(s.into_repr()).collect::<Vec<_>>(); let mut s_bits = BitIterator::<u8, _>::new(s.into_repr()).collect::<Vec<_>>();
s_bits.reverse(); s_bits.reverse();
s_bits.truncate(Fs::NUM_BITS as usize); s_bits.truncate(Fs::NUM_BITS as usize);

View File

@ -1,6 +1,6 @@
//! The Sapling circuits. //! The Sapling circuits.
use ff::{Field, PrimeField, PrimeFieldRepr}; use ff::{Field, PrimeField};
use bellman::{Circuit, ConstraintSystem, SynthesisError}; use bellman::{Circuit, ConstraintSystem, SynthesisError};
@ -478,7 +478,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
// Witness the sign bit // Witness the sign bit
let sign_bit = boolean::Boolean::from(boolean::AllocatedBit::alloc( let sign_bit = boolean::Boolean::from(boolean::AllocatedBit::alloc(
cs.namespace(|| "pk_d bit of x"), 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 // Extend the note with pk_d representation
@ -615,8 +615,8 @@ fn test_input_circuit_with_bls12_381() {
::std::mem::swap(&mut lhs, &mut rhs); ::std::mem::swap(&mut lhs, &mut rhs);
} }
let mut lhs: Vec<bool> = BitIterator::new(lhs.into_repr()).collect(); let mut lhs: Vec<bool> = BitIterator::<u8, _>::new(lhs.into_repr()).collect();
let mut rhs: Vec<bool> = BitIterator::new(rhs.into_repr()).collect(); let mut rhs: Vec<bool> = BitIterator::<u8, _>::new(rhs.into_repr()).collect();
lhs.reverse(); lhs.reverse();
rhs.reverse(); rhs.reverse();
@ -799,8 +799,8 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() {
::std::mem::swap(&mut lhs, &mut rhs); ::std::mem::swap(&mut lhs, &mut rhs);
} }
let mut lhs: Vec<bool> = BitIterator::new(lhs.into_repr()).collect(); let mut lhs: Vec<bool> = BitIterator::<u8, _>::new(lhs.into_repr()).collect();
let mut rhs: Vec<bool> = BitIterator::new(rhs.into_repr()).collect(); let mut rhs: Vec<bool> = BitIterator::<u8, _>::new(rhs.into_repr()).collect();
lhs.reverse(); lhs.reverse();
rhs.reverse(); rhs.reverse();

View File

@ -2,7 +2,7 @@
use pairing::bls12_381::Bls12; use pairing::bls12_381::Bls12;
use zcash_primitives::jubjub::{ use zcash_primitives::jubjub::{
edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown, edwards, fs::Fs, FixedGenerators, JubjubBls12, JubjubParams, Unknown,
}; };
use zcash_primitives::transaction::components::Amount; use zcash_primitives::transaction::components::Amount;
@ -30,7 +30,7 @@ fn compute_value_balance(
// Compute it in the exponent // Compute it in the exponent
let mut value_balance = params let mut value_balance = params
.generator(FixedGenerators::ValueCommitmentValue) .generator(FixedGenerators::ValueCommitmentValue)
.mul(FsRepr::from(abs), params); .mul(Fs::from(abs), params);
// Negate if necessary // Negate if necessary
if is_negative { if is_negative {