ff: Move pow_vartime into a trait that is generic over the limb size

The trait is implemented by default for u8 and u64, allowing pow_vartime
to be used with both the byte encoding and limb representation of field
elements.
This commit is contained in:
Jack Grigg 2020-03-27 22:35:55 +13:00
parent 69c60530d4
commit b6457a905b
14 changed files with 89 additions and 55 deletions

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@ use rand_core::RngCore;
use std::ops::{AddAssign, MulAssign};
use std::sync::Arc;
use ff::Field;
use ff::{Field, PowVartime};
use group::{CurveAffine, CurveProjective, Wnaf};
use pairing::Engine;

View File

@ -1,4 +1,6 @@
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField};
use ff::{
Field, PowVartime, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField,
};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use pairing::{Engine, PairingCurveAffine};
@ -190,9 +192,9 @@ impl SqrtField for Fr {
// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
let mut c = Fr::root_of_unity();
// r = self^((t + 1) // 2)
let mut r = self.pow_vartime([32]);
let mut r = self.pow_vartime([32u64]);
// t = self^t
let mut t = self.pow_vartime([63]);
let mut t = self.pow_vartime([63u64]);
let mut m = Fr::S;
while t != <Fr as Field>::one() {

View File

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

View File

@ -13,7 +13,7 @@ extern crate std;
pub use ff_derive::*;
use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use core::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign};
use rand_core::RngCore;
#[cfg(feature = "std")]
use std::io::{self, Read, Write};
@ -73,21 +73,36 @@ pub trait Field:
/// Exponentiates this element by a power of the base prime modulus via
/// the Frobenius automorphism.
fn frobenius_map(&mut self, power: usize);
}
pub trait PowVartime<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
/// integer exponent.
///
/// **This operation is variable time with respect to the exponent.** If the
/// exponent is fixed, this operation is effectively constant time.
fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
fn pow_vartime<S: AsRef<[L]>>(&self, exp: S) -> Self {
let mut res = Self::one();
for e in exp.as_ref().iter().rev() {
for i in (0..64).rev() {
let mut i = Self::ZERO;
while i < Self::LIMB_SIZE {
res = res.square();
if ((*e >> i) & 1) == 1 {
if ((*e >> (Self::LIMB_SIZE - Self::ONE - i)) & Self::ONE) == Self::ONE {
res.mul_assign(self);
}
i += Self::ONE;
}
}
@ -95,6 +110,18 @@ pub trait Field:
}
}
impl<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.
pub trait SqrtField: Field {
/// Returns the square root of the field element, if it is

View File

@ -2,6 +2,8 @@ use super::fq2::Fq2;
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
use std::ops::{AddAssign, MulAssign, SubAssign};
#[cfg(test)]
use ff::PowVartime;
#[cfg(test)]
use std::ops::Neg;
@ -466,7 +468,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ2_C1[1],
nqr.pow_vartime([
0xdcff7fffffffd555,
0xdcff7fffffffd555u64,
0xf55ffff58a9ffff,
0xb39869507b587b12,
0xb23ba5c279c2895f,
@ -484,7 +486,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[1],
nqr.pow_vartime([
0x9354ffffffffe38e,
0x9354ffffffffe38eu64,
0xa395554e5c6aaaa,
0xcd104635a790520c,
0xcc27c3d6fbd7063f,
@ -495,7 +497,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[2],
nqr.pow_vartime([
0xb78e0000097b2f68,
0xb78e0000097b2f68u64,
0xd44f23b47cbd64e3,
0x5cb9668120b069a9,
0xccea85f9bf7b3d16,
@ -512,7 +514,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[3],
nqr.pow_vartime([
0xdbc6fcd6f35b9e06,
0xdbc6fcd6f35b9e06u64,
0x997dead10becd6aa,
0x9dbbd24c17206460,
0x72b97acc6057c45e,
@ -535,7 +537,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[4],
nqr.pow_vartime([
0x4649add3c71c6d90,
0x4649add3c71c6d90u64,
0x43caa6528972a865,
0xcda8445bbaaa0fbb,
0xc93dea665662aa66,
@ -564,7 +566,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[5],
nqr.pow_vartime([
0xf896f792732eb2be,
0xf896f792732eb2beu64,
0x49c86a6d1dc593a1,
0xe5b31e94581f91c3,
0xe3da5cc0a6b20d7f,
@ -601,7 +603,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[1],
nqr.pow_vartime([
0x26a9ffffffffc71c,
0x26a9ffffffffc71cu64,
0x1472aaa9cb8d5555,
0x9a208c6b4f20a418,
0x984f87adf7ae0c7f,
@ -612,7 +614,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[2],
nqr.pow_vartime([
0x6f1c000012f65ed0,
0x6f1c000012f65ed0u64,
0xa89e4768f97ac9c7,
0xb972cd024160d353,
0x99d50bf37ef67a2c,
@ -629,7 +631,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[3],
nqr.pow_vartime([
0xb78df9ade6b73c0c,
0xb78df9ade6b73c0cu64,
0x32fbd5a217d9ad55,
0x3b77a4982e40c8c1,
0xe572f598c0af88bd,
@ -652,7 +654,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[4],
nqr.pow_vartime([
0x8c935ba78e38db20,
0x8c935ba78e38db20u64,
0x87954ca512e550ca,
0x9b5088b775541f76,
0x927bd4ccacc554cd,
@ -681,7 +683,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[5],
nqr.pow_vartime([
0xf12def24e65d657c,
0xf12def24e65d657cu64,
0x9390d4da3b8b2743,
0xcb663d28b03f2386,
0xc7b4b9814d641aff,
@ -718,7 +720,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[1],
nqr.pow_vartime([
0x49aa7ffffffff1c7,
0x49aa7ffffffff1c7u64,
0x51caaaa72e35555,
0xe688231ad3c82906,
0xe613e1eb7deb831f,
@ -729,7 +731,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[2],
nqr.pow_vartime([
0xdbc7000004bd97b4,
0xdbc7000004bd97b4u64,
0xea2791da3e5eb271,
0x2e5cb340905834d4,
0xe67542fcdfbd9e8b,
@ -746,7 +748,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[3],
nqr.pow_vartime(vec![
0x6de37e6b79adcf03,
0x6de37e6b79adcf03u64,
0x4cbef56885f66b55,
0x4edde9260b903230,
0x395cbd66302be22f,
@ -769,7 +771,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[4],
nqr.pow_vartime(vec![
0xa324d6e9e38e36c8,
0xa324d6e9e38e36c8u64,
0xa1e5532944b95432,
0x66d4222ddd5507dd,
0xe49ef5332b315533,
@ -798,7 +800,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[5],
nqr.pow_vartime(vec![
0xfc4b7bc93997595f,
0xfc4b7bc93997595fu64,
0xa4e435368ee2c9d0,
0xf2d98f4a2c0fc8e1,
0xf1ed2e60535906bf,
@ -833,7 +835,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[6],
nqr.pow_vartime(vec![
0x21219610a012ba3c,
0x21219610a012ba3cu64,
0xa5c19ad35375325,
0x4e9df1e497674396,
0xfb05b717c991c6ef,
@ -874,7 +876,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[7],
nqr.pow_vartime(vec![
0x742754a1f22fdb,
0x742754a1f22fdbu64,
0x2a1955c2dec3a702,
0x9747b28c796d134e,
0xc113a0411f59db79,
@ -921,7 +923,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[8],
nqr.pow_vartime(vec![
0x802f5720d0b25710,
0x802f5720d0b25710u64,
0x6714f0a258b85c7c,
0x31394c90afdf16e,
0xe9d2b0c64f957b19,
@ -974,7 +976,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[9],
nqr.pow_vartime(vec![
0x4af4accf7de0b977,
0x4af4accf7de0b977u64,
0x742485e21805b4ee,
0xee388fbc4ac36dec,
0x1e199da57ad178a,
@ -1033,7 +1035,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[10],
nqr.pow_vartime(vec![
0xe5953a4f96cdda44,
0xe5953a4f96cdda44u64,
0x336b2d734cbc32bb,
0x3f79bfe3cd7410e,
0x267ae19aaa0f0332,
@ -1098,7 +1100,7 @@ fn test_frob_coeffs() {
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[11],
nqr.pow_vartime(vec![
0x107db680942de533,
0x107db680942de533u64,
0x6262b24d2052393b,
0x6136df824159ebc,
0xedb052c9970c5deb,
@ -2029,7 +2031,7 @@ fn test_fq_pow() {
0xe5,
]);
for i in 0..1000 {
for i in 0u64..1000 {
// Exponentiate by various small numbers and ensure it consists with repeated
// multiplication.
let a = Fq::random(&mut rng);
@ -2197,7 +2199,7 @@ fn test_fq_root_of_unity() {
);
assert_eq!(
Fq::multiplicative_generator().pow_vartime([
0xdcff7fffffffd555,
0xdcff7fffffffd555u64,
0xf55ffff58a9ffff,
0xb39869507b587b12,
0xb23ba5c279c2895f,
@ -2206,7 +2208,7 @@ fn test_fq_root_of_unity() {
]),
Fq::root_of_unity()
);
assert_eq!(Fq::root_of_unity().pow_vartime([1 << Fq::S]), Fq::one());
assert_eq!(Fq::root_of_unity().pow_vartime([1u64 << Fq::S]), Fq::one());
assert!(bool::from(Fq::multiplicative_generator().sqrt().is_none()));
}

View File

@ -1,5 +1,5 @@
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
use ff::{Field, SqrtField};
use ff::{Field, PowVartime, SqrtField};
use rand_core::RngCore;
use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
@ -254,7 +254,7 @@ impl SqrtField for Fq2 {
} else {
// a1 = self^((q - 3) / 4)
let mut a1 = self.pow_vartime([
0xee7fbfffffffeaaa,
0xee7fbfffffffeaaau64,
0x7aaffffac54ffff,
0xd9cc34a83dac3d89,
0xd91dd2e13ce144af,
@ -286,7 +286,7 @@ impl SqrtField for Fq2 {
alpha.add_assign(&Fq2::one());
// alpha = alpha^((q - 1) / 2)
alpha = alpha.pow_vartime([
0xdcff7fffffffd555,
0xdcff7fffffffd555u64,
0xf55ffff58a9ffff,
0xb39869507b587b12,
0xb23ba5c279c2895f,

View File

@ -6,6 +6,8 @@ use std::ops::{AddAssign, MulAssign, SubAssign};
#[PrimeFieldGenerator = "7"]
pub struct Fr(FrRepr);
#[cfg(test)]
use ff::PowVartime;
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]
@ -763,7 +765,7 @@ fn test_fr_pow() {
0xe5,
]);
for i in 0..1000 {
for i in 0u64..1000 {
// Exponentiate by various small numbers and ensure it consists with repeated
// multiplication.
let a = Fr::random(&mut rng);
@ -965,14 +967,14 @@ fn test_fr_root_of_unity() {
);
assert_eq!(
Fr::multiplicative_generator().pow_vartime([
0xfffe5bfeffffffff,
0xfffe5bfeffffffffu64,
0x9a1d80553bda402,
0x299d7d483339d808,
0x73eda753
]),
Fr::root_of_unity()
);
assert_eq!(Fr::root_of_unity().pow_vartime([1 << Fr::S]), Fr::one());
assert_eq!(Fr::root_of_unity().pow_vartime([1u64 << Fr::S]), Fr::one());
assert!(bool::from(Fr::multiplicative_generator().sqrt().is_none()));
}

View File

@ -23,7 +23,7 @@ pub use self::fr::{Fr, FrRepr};
use super::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, ScalarEngine};
use ff::{BitIterator, Field, PowVartime, ScalarEngine};
use group::CurveAffine;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption;

View File

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

View File

@ -1,4 +1,4 @@
use ff::{Field, PrimeField, SqrtField};
use ff::{Field, PowVartime, PrimeField, SqrtField};
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;

View File

@ -1,6 +1,6 @@
use byteorder::{ByteOrder, LittleEndian};
use ff::{
adc, mac_with_carry, sbb, BitIterator, Field, PrimeField, PrimeFieldDecodingError,
adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, PrimeFieldDecodingError,
PrimeFieldRepr, SqrtField,
};
use rand_core::RngCore;
@ -745,7 +745,7 @@ impl SqrtField for Fs {
// a1 = self^((s - 3) // 4)
let mut a1 = self.pow_vartime([
0xb425c397b5bdcb2d,
0xb425c397b5bdcb2du64,
0x299a0824f3320420,
0x4199cec0404d0ec0,
0x39f6d3a994cebea,
@ -1491,7 +1491,7 @@ fn test_fs_pow() {
0xe5,
]);
for i in 0..1000 {
for i in 0u64..1000 {
// Exponentiate by various small numbers and ensure it consists with repeated
// multiplication.
let a = Fs::random(&mut rng);
@ -1689,13 +1689,13 @@ fn test_fs_root_of_unity() {
);
assert_eq!(
Fs::multiplicative_generator().pow_vartime([
0x684b872f6b7b965b,
0x684b872f6b7b965bu64,
0x53341049e6640841,
0x83339d80809a1d80,
0x73eda753299d7d4
]),
Fs::root_of_unity()
);
assert_eq!(Fs::root_of_unity().pow_vartime([1 << Fs::S]), Fs::one());
assert_eq!(Fs::root_of_unity().pow_vartime([1u64 << Fs::S]), Fs::one());
assert!(bool::from(Fs::multiplicative_generator().sqrt().is_none()));
}