ff: Move pow_vartime back into Field trait

The only places we don't use constant u64 limbs, we use PrimeField::char
instead (except in a single test where we use a field element).
This commit is contained in:
Jack Grigg 2020-05-02 17:57:19 +12:00
parent fb31d09218
commit 15e229509a
13 changed files with 36 additions and 49 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, PowVartime, PrimeField, ScalarEngine}; use ff::{Field, PrimeField, ScalarEngine};
use group::CurveProjective; use group::CurveProjective;
use std::ops::{AddAssign, MulAssign, SubAssign}; use std::ops::{AddAssign, MulAssign, SubAssign};

View File

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

View File

@ -1,6 +1,6 @@
//! Helpers for testing circuit implementations. //! Helpers for testing circuit implementations.
use ff::{Endianness, Field, PowVartime, PrimeField, ScalarEngine}; use ff::{Endianness, Field, PrimeField, ScalarEngine};
use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};

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, PowVartime}; use ff::Field;
use group::{CurveAffine, CurveProjective, Wnaf}; use group::{CurveAffine, CurveProjective, Wnaf};
use pairing::Engine; use pairing::Engine;

View File

@ -1,4 +1,4 @@
use ff::{Field, PowVartime, PrimeField, ScalarEngine}; use ff::{Field, PrimeField, ScalarEngine};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use pairing::{Engine, PairingCurveAffine}; use pairing::{Engine, PairingCurveAffine};

View File

@ -1,4 +1,4 @@
use ff::{Field, PowVartime, PrimeField}; use ff::{Field, PrimeField};
use pairing::Engine; use pairing::Engine;
mod dummy_engine; mod dummy_engine;

View File

@ -76,36 +76,21 @@ pub trait Field:
/// Returns the square root of the field element, if it is /// Returns the square root of the field element, if it is
/// quadratic residue. /// quadratic residue.
fn sqrt(&self) -> CtOption<Self>; fn sqrt(&self) -> CtOption<Self>;
}
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<[L]>>(&self, exp: S) -> Self { fn pow_vartime<S: AsRef<[u64]>>(&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() {
let mut i = Self::ZERO; for i in (0..64).rev() {
while i < Self::LIMB_SIZE {
res = res.square(); res = res.square();
if ((*e >> (Self::LIMB_SIZE - Self::ONE - i)) & Self::ONE) == Self::ONE { if ((*e >> i) & 1) == 1 {
res.mul_assign(self); res.mul_assign(self);
} }
i += Self::ONE;
} }
} }
@ -113,18 +98,6 @@ where
} }
} }
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;
}
/// Helper trait for converting the binary representation of a prime field element into a /// Helper trait for converting the binary representation of a prime field element into a
/// specific endianness. This is useful when you need to act on the bit representation /// specific endianness. This is useful when you need to act on the bit representation
/// of an element generically, as the native binary representation of a prime field is /// of an element generically, as the native binary representation of a prime field is

View File

@ -2,8 +2,6 @@ use super::fq2::Fq2;
use ff::{Field, PrimeField}; use ff::{Field, PrimeField};
use std::ops::{AddAssign, MulAssign, SubAssign}; use std::ops::{AddAssign, MulAssign, SubAssign};
#[cfg(test)]
use ff::PowVartime;
#[cfg(test)] #[cfg(test)]
use std::ops::Neg; use std::ops::Neg;
@ -1644,11 +1642,15 @@ fn test_fq_pow() {
assert_eq!(c, target); assert_eq!(c, target);
} }
use byteorder::ByteOrder;
let mut char_limbs = [0; 6];
byteorder::LittleEndian::read_u64_into(Fq::char().as_ref(), &mut char_limbs);
for _ in 0..1000 { for _ in 0..1000 {
// Exponentiating by the modulus should have no effect in a prime field. // Exponentiating by the modulus should have no effect in a prime field.
let a = Fq::random(&mut rng); let a = Fq::random(&mut rng);
assert_eq!(a, a.pow_vartime(Fq::char())); assert_eq!(a, a.pow_vartime(char_limbs));
} }
} }

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, PowVartime}; use ff::Field;
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};

View File

@ -7,8 +7,6 @@ use std::ops::{AddAssign, MulAssign, SubAssign};
#[PrimeFieldReprEndianness = "little"] #[PrimeFieldReprEndianness = "little"]
pub struct Fr([u64; 4]); 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)]
@ -430,11 +428,15 @@ fn test_fr_pow() {
assert_eq!(c, target); assert_eq!(c, target);
} }
use byteorder::ByteOrder;
let mut char_limbs = [0; 4];
byteorder::LittleEndian::read_u64_into(Fr::char().as_ref(), &mut char_limbs);
for _ in 0..1000 { for _ in 0..1000 {
// Exponentiating by the modulus should have no effect in a prime field. // Exponentiating by the modulus should have no effect in a prime field.
let a = Fr::random(&mut rng); let a = Fr::random(&mut rng);
assert_eq!(a, a.pow_vartime(Fr::char())); assert_eq!(a, a.pow_vartime(char_limbs));
} }
} }

View File

@ -23,7 +23,7 @@ pub use self::fr::{Fr, FrRepr};
use super::{Engine, PairingCurveAffine}; use super::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, PowVartime, ScalarEngine}; use ff::{BitIterator, Field, 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;

View File

@ -1,10 +1,10 @@
use ff::PowVartime; use ff::{Endianness, Field, PrimeField};
use group::{CurveAffine, CurveProjective}; use group::{CurveAffine, CurveProjective};
use rand_core::SeedableRng; use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use std::ops::MulAssign; use std::ops::MulAssign;
use crate::{Engine, Field, PairingCurveAffine, PrimeField}; use crate::{Engine, PairingCurveAffine};
pub fn engine_tests<E: Engine>() { pub fn engine_tests<E: Engine>() {
let mut rng = XorShiftRng::from_seed([ let mut rng = XorShiftRng::from_seed([
@ -130,8 +130,14 @@ fn random_bilinearity_tests<E: Engine>() {
let mut cd = c; let mut cd = c;
cd.mul_assign(&d); cd.mul_assign(&d);
let mut cd = cd.into_repr();
<E::Fr as PrimeField>::ReprEndianness::toggle_little_endian(&mut cd);
let abcd = E::pairing(a, b).pow_vartime(cd.into_repr()); use byteorder::ByteOrder;
let mut cd_limbs = [0; 4];
byteorder::LittleEndian::read_u64_into(cd.as_ref(), &mut cd_limbs);
let abcd = E::pairing(a, b).pow_vartime(cd_limbs);
assert_eq!(acbd, adbc); assert_eq!(acbd, adbc);
assert_eq!(acbd, abcd); assert_eq!(acbd, abcd);

View File

@ -1,5 +1,5 @@
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use ff::{adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField}; use ff::{adc, mac_with_carry, sbb, BitIterator, Field, PrimeField};
use rand_core::RngCore; use rand_core::RngCore;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
@ -1051,11 +1051,15 @@ fn test_fs_pow() {
assert_eq!(c, target); assert_eq!(c, target);
} }
use byteorder::ByteOrder;
let mut char_limbs = [0; 4];
byteorder::LittleEndian::read_u64_into(Fs::char().as_ref(), &mut char_limbs);
for _ in 0..1000 { for _ in 0..1000 {
// Exponentiating by the modulus should have no effect in a prime field. // Exponentiating by the modulus should have no effect in a prime field.
let a = Fs::random(&mut rng); let a = Fs::random(&mut rng);
assert_eq!(a, a.pow_vartime(Fs::char())); assert_eq!(a, a.pow_vartime(char_limbs));
} }
} }