From b6457a905b23b78e30890ab7a2bf6d3b43c20e13 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 27 Mar 2020 22:35:55 +1300 Subject: [PATCH] ff: Move pow_vartime into a trait that is generic over the limb size The trait is implemented by default for u8 and u64, allowing pow_vartime to be used with both the byte encoding and limb representation of field elements. --- bellman/src/domain.rs | 2 +- bellman/src/gadgets/multieq.rs | 2 +- bellman/src/gadgets/test/mod.rs | 2 +- bellman/src/groth16/generator.rs | 2 +- bellman/src/groth16/tests/dummy_engine.rs | 8 ++-- bellman/src/groth16/tests/mod.rs | 12 +++--- ff/src/lib.rs | 35 +++++++++++++-- pairing/src/bls12_381/fq.rs | 52 ++++++++++++----------- pairing/src/bls12_381/fq2.rs | 6 +-- pairing/src/bls12_381/fr.rs | 8 ++-- pairing/src/bls12_381/mod.rs | 2 +- pairing/src/tests/engine.rs | 1 + pairing/src/tests/field.rs | 2 +- zcash_primitives/src/jubjub/fs.rs | 10 ++--- 14 files changed, 89 insertions(+), 55 deletions(-) diff --git a/bellman/src/domain.rs b/bellman/src/domain.rs index 0e9192e44..f1c25922f 100644 --- a/bellman/src/domain.rs +++ b/bellman/src/domain.rs @@ -11,7 +11,7 @@ //! [`EvaluationDomain`]: crate::domain::EvaluationDomain //! [Groth16]: https://eprint.iacr.org/2016/260 -use ff::{Field, PrimeField, ScalarEngine}; +use ff::{Field, PowVartime, PrimeField, ScalarEngine}; use group::CurveProjective; use std::ops::{AddAssign, MulAssign, SubAssign}; diff --git a/bellman/src/gadgets/multieq.rs b/bellman/src/gadgets/multieq.rs index 37b2d9429..890eb7c6e 100644 --- a/bellman/src/gadgets/multieq.rs +++ b/bellman/src/gadgets/multieq.rs @@ -1,4 +1,4 @@ -use ff::{Field, PrimeField, ScalarEngine}; +use ff::{PowVartime, PrimeField, ScalarEngine}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; diff --git a/bellman/src/gadgets/test/mod.rs b/bellman/src/gadgets/test/mod.rs index 0a37cd16f..a803accae 100644 --- a/bellman/src/gadgets/test/mod.rs +++ b/bellman/src/gadgets/test/mod.rs @@ -1,6 +1,6 @@ //! Helpers for testing circuit implementations. -use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; +use ff::{Field, PowVartime, PrimeField, PrimeFieldRepr, ScalarEngine}; use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index 02efc21bd..1d8699229 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -2,7 +2,7 @@ use rand_core::RngCore; use std::ops::{AddAssign, MulAssign}; use std::sync::Arc; -use ff::Field; +use ff::{Field, PowVartime}; use group::{CurveAffine, CurveProjective, Wnaf}; use pairing::Engine; diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 21322d86a..4693aaa1a 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -1,4 +1,6 @@ -use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField}; +use ff::{ + Field, PowVartime, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField, +}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use pairing::{Engine, PairingCurveAffine}; @@ -190,9 +192,9 @@ impl SqrtField for Fr { // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) let mut c = Fr::root_of_unity(); // r = self^((t + 1) // 2) - let mut r = self.pow_vartime([32]); + let mut r = self.pow_vartime([32u64]); // t = self^t - let mut t = self.pow_vartime([63]); + let mut t = self.pow_vartime([63u64]); let mut m = Fr::S; while t != ::one() { diff --git a/bellman/src/groth16/tests/mod.rs b/bellman/src/groth16/tests/mod.rs index 5c2f02dbb..2914bf2c0 100644 --- a/bellman/src/groth16/tests/mod.rs +++ b/bellman/src/groth16/tests/mod.rs @@ -1,4 +1,4 @@ -use ff::{Field, PrimeField}; +use ff::{Field, PowVartime, PrimeField}; use pairing::Engine; mod dummy_engine; @@ -127,22 +127,22 @@ fn test_xordemo() { let mut root_of_unity = Fr::root_of_unity(); // We expect this to be a 2^10 root of unity - assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1 << 10])); + assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1u64 << 10])); // Let's turn it into a 2^3 root of unity. - root_of_unity = root_of_unity.pow_vartime(&[1 << 7]); - assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1 << 3])); + root_of_unity = root_of_unity.pow_vartime(&[1u64 << 7]); + assert_eq!(Fr::one(), root_of_unity.pow_vartime(&[1u64 << 3])); assert_eq!(Fr::from_str("20201").unwrap(), root_of_unity); // Let's compute all the points in our evaluation domain. let mut points = Vec::with_capacity(8); - for i in 0..8 { + for i in 0u64..8 { points.push(root_of_unity.pow_vartime(&[i])); } // Let's compute t(tau) = (tau - p_0)(tau - p_1)... // = tau^8 - 1 - let mut t_at_tau = tau.pow_vartime(&[8]); + let mut t_at_tau = tau.pow_vartime(&[8u64]); t_at_tau.sub_assign(&Fr::one()); { let mut tmp = Fr::one(); diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 65c32b2d6..e3cb8b474 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -13,7 +13,7 @@ extern crate std; pub use ff_derive::*; use core::fmt; -use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use core::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign}; use rand_core::RngCore; #[cfg(feature = "std")] use std::io::{self, Read, Write}; @@ -73,21 +73,36 @@ pub trait Field: /// Exponentiates this element by a power of the base prime modulus via /// the Frobenius automorphism. fn frobenius_map(&mut self, power: usize); +} + +pub trait PowVartime: Field +where + L: Copy + PartialEq + PartialOrd + AddAssign, + L: BitAnd, + L: Shr, + L: Sub, +{ + const ZERO: L; + const ONE: L; + const LIMB_SIZE: L; /// Exponentiates `self` by `exp`, where `exp` is a little-endian order /// integer exponent. /// /// **This operation is variable time with respect to the exponent.** If the /// exponent is fixed, this operation is effectively constant time. - fn pow_vartime>(&self, exp: S) -> Self { + fn pow_vartime>(&self, exp: S) -> Self { let mut res = Self::one(); for e in exp.as_ref().iter().rev() { - for i in (0..64).rev() { + let mut i = Self::ZERO; + while i < Self::LIMB_SIZE { res = res.square(); - if ((*e >> i) & 1) == 1 { + if ((*e >> (Self::LIMB_SIZE - Self::ONE - i)) & Self::ONE) == Self::ONE { res.mul_assign(self); } + + i += Self::ONE; } } @@ -95,6 +110,18 @@ pub trait Field: } } +impl PowVartime for T { + const ZERO: u8 = 0; + const ONE: u8 = 1; + const LIMB_SIZE: u8 = 8; +} + +impl PowVartime for T { + const ZERO: u64 = 0; + const ONE: u64 = 1; + const LIMB_SIZE: u64 = 64; +} + /// This trait represents an element of a field that has a square root operation described for it. pub trait SqrtField: Field { /// Returns the square root of the field element, if it is diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index 57d653264..2f7b15d16 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -2,6 +2,8 @@ use super::fq2::Fq2; use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; use std::ops::{AddAssign, MulAssign, SubAssign}; +#[cfg(test)] +use ff::PowVartime; #[cfg(test)] use std::ops::Neg; @@ -466,7 +468,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ2_C1[1], nqr.pow_vartime([ - 0xdcff7fffffffd555, + 0xdcff7fffffffd555u64, 0xf55ffff58a9ffff, 0xb39869507b587b12, 0xb23ba5c279c2895f, @@ -484,7 +486,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[1], nqr.pow_vartime([ - 0x9354ffffffffe38e, + 0x9354ffffffffe38eu64, 0xa395554e5c6aaaa, 0xcd104635a790520c, 0xcc27c3d6fbd7063f, @@ -495,7 +497,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[2], nqr.pow_vartime([ - 0xb78e0000097b2f68, + 0xb78e0000097b2f68u64, 0xd44f23b47cbd64e3, 0x5cb9668120b069a9, 0xccea85f9bf7b3d16, @@ -512,7 +514,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[3], nqr.pow_vartime([ - 0xdbc6fcd6f35b9e06, + 0xdbc6fcd6f35b9e06u64, 0x997dead10becd6aa, 0x9dbbd24c17206460, 0x72b97acc6057c45e, @@ -535,7 +537,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[4], nqr.pow_vartime([ - 0x4649add3c71c6d90, + 0x4649add3c71c6d90u64, 0x43caa6528972a865, 0xcda8445bbaaa0fbb, 0xc93dea665662aa66, @@ -564,7 +566,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C1[5], nqr.pow_vartime([ - 0xf896f792732eb2be, + 0xf896f792732eb2beu64, 0x49c86a6d1dc593a1, 0xe5b31e94581f91c3, 0xe3da5cc0a6b20d7f, @@ -601,7 +603,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[1], nqr.pow_vartime([ - 0x26a9ffffffffc71c, + 0x26a9ffffffffc71cu64, 0x1472aaa9cb8d5555, 0x9a208c6b4f20a418, 0x984f87adf7ae0c7f, @@ -612,7 +614,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[2], nqr.pow_vartime([ - 0x6f1c000012f65ed0, + 0x6f1c000012f65ed0u64, 0xa89e4768f97ac9c7, 0xb972cd024160d353, 0x99d50bf37ef67a2c, @@ -629,7 +631,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[3], nqr.pow_vartime([ - 0xb78df9ade6b73c0c, + 0xb78df9ade6b73c0cu64, 0x32fbd5a217d9ad55, 0x3b77a4982e40c8c1, 0xe572f598c0af88bd, @@ -652,7 +654,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[4], nqr.pow_vartime([ - 0x8c935ba78e38db20, + 0x8c935ba78e38db20u64, 0x87954ca512e550ca, 0x9b5088b775541f76, 0x927bd4ccacc554cd, @@ -681,7 +683,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ6_C2[5], nqr.pow_vartime([ - 0xf12def24e65d657c, + 0xf12def24e65d657cu64, 0x9390d4da3b8b2743, 0xcb663d28b03f2386, 0xc7b4b9814d641aff, @@ -718,7 +720,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[1], nqr.pow_vartime([ - 0x49aa7ffffffff1c7, + 0x49aa7ffffffff1c7u64, 0x51caaaa72e35555, 0xe688231ad3c82906, 0xe613e1eb7deb831f, @@ -729,7 +731,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[2], nqr.pow_vartime([ - 0xdbc7000004bd97b4, + 0xdbc7000004bd97b4u64, 0xea2791da3e5eb271, 0x2e5cb340905834d4, 0xe67542fcdfbd9e8b, @@ -746,7 +748,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[3], nqr.pow_vartime(vec![ - 0x6de37e6b79adcf03, + 0x6de37e6b79adcf03u64, 0x4cbef56885f66b55, 0x4edde9260b903230, 0x395cbd66302be22f, @@ -769,7 +771,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[4], nqr.pow_vartime(vec![ - 0xa324d6e9e38e36c8, + 0xa324d6e9e38e36c8u64, 0xa1e5532944b95432, 0x66d4222ddd5507dd, 0xe49ef5332b315533, @@ -798,7 +800,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[5], nqr.pow_vartime(vec![ - 0xfc4b7bc93997595f, + 0xfc4b7bc93997595fu64, 0xa4e435368ee2c9d0, 0xf2d98f4a2c0fc8e1, 0xf1ed2e60535906bf, @@ -833,7 +835,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[6], nqr.pow_vartime(vec![ - 0x21219610a012ba3c, + 0x21219610a012ba3cu64, 0xa5c19ad35375325, 0x4e9df1e497674396, 0xfb05b717c991c6ef, @@ -874,7 +876,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[7], nqr.pow_vartime(vec![ - 0x742754a1f22fdb, + 0x742754a1f22fdbu64, 0x2a1955c2dec3a702, 0x9747b28c796d134e, 0xc113a0411f59db79, @@ -921,7 +923,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[8], nqr.pow_vartime(vec![ - 0x802f5720d0b25710, + 0x802f5720d0b25710u64, 0x6714f0a258b85c7c, 0x31394c90afdf16e, 0xe9d2b0c64f957b19, @@ -974,7 +976,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[9], nqr.pow_vartime(vec![ - 0x4af4accf7de0b977, + 0x4af4accf7de0b977u64, 0x742485e21805b4ee, 0xee388fbc4ac36dec, 0x1e199da57ad178a, @@ -1033,7 +1035,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[10], nqr.pow_vartime(vec![ - 0xe5953a4f96cdda44, + 0xe5953a4f96cdda44u64, 0x336b2d734cbc32bb, 0x3f79bfe3cd7410e, 0x267ae19aaa0f0332, @@ -1098,7 +1100,7 @@ fn test_frob_coeffs() { assert_eq!( FROBENIUS_COEFF_FQ12_C1[11], nqr.pow_vartime(vec![ - 0x107db680942de533, + 0x107db680942de533u64, 0x6262b24d2052393b, 0x6136df824159ebc, 0xedb052c9970c5deb, @@ -2029,7 +2031,7 @@ fn test_fq_pow() { 0xe5, ]); - for i in 0..1000 { + for i in 0u64..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. let a = Fq::random(&mut rng); @@ -2197,7 +2199,7 @@ fn test_fq_root_of_unity() { ); assert_eq!( Fq::multiplicative_generator().pow_vartime([ - 0xdcff7fffffffd555, + 0xdcff7fffffffd555u64, 0xf55ffff58a9ffff, 0xb39869507b587b12, 0xb23ba5c279c2895f, @@ -2206,7 +2208,7 @@ fn test_fq_root_of_unity() { ]), Fq::root_of_unity() ); - assert_eq!(Fq::root_of_unity().pow_vartime([1 << Fq::S]), Fq::one()); + assert_eq!(Fq::root_of_unity().pow_vartime([1u64 << Fq::S]), Fq::one()); assert!(bool::from(Fq::multiplicative_generator().sqrt().is_none())); } diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index 0cd88e7d7..e0955f08f 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -1,5 +1,5 @@ use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE}; -use ff::{Field, SqrtField}; +use ff::{Field, PowVartime, SqrtField}; use rand_core::RngCore; use std::cmp::Ordering; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; @@ -254,7 +254,7 @@ impl SqrtField for Fq2 { } else { // a1 = self^((q - 3) / 4) let mut a1 = self.pow_vartime([ - 0xee7fbfffffffeaaa, + 0xee7fbfffffffeaaau64, 0x7aaffffac54ffff, 0xd9cc34a83dac3d89, 0xd91dd2e13ce144af, @@ -286,7 +286,7 @@ impl SqrtField for Fq2 { alpha.add_assign(&Fq2::one()); // alpha = alpha^((q - 1) / 2) alpha = alpha.pow_vartime([ - 0xdcff7fffffffd555, + 0xdcff7fffffffd555u64, 0xf55ffff58a9ffff, 0xb39869507b587b12, 0xb23ba5c279c2895f, diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index 4c30e49cb..f520d303e 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -6,6 +6,8 @@ use std::ops::{AddAssign, MulAssign, SubAssign}; #[PrimeFieldGenerator = "7"] pub struct Fr(FrRepr); +#[cfg(test)] +use ff::PowVartime; #[cfg(test)] use rand_core::SeedableRng; #[cfg(test)] @@ -763,7 +765,7 @@ fn test_fr_pow() { 0xe5, ]); - for i in 0..1000 { + for i in 0u64..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. let a = Fr::random(&mut rng); @@ -965,14 +967,14 @@ fn test_fr_root_of_unity() { ); assert_eq!( Fr::multiplicative_generator().pow_vartime([ - 0xfffe5bfeffffffff, + 0xfffe5bfeffffffffu64, 0x9a1d80553bda402, 0x299d7d483339d808, 0x73eda753 ]), Fr::root_of_unity() ); - assert_eq!(Fr::root_of_unity().pow_vartime([1 << Fr::S]), Fr::one()); + assert_eq!(Fr::root_of_unity().pow_vartime([1u64 << Fr::S]), Fr::one()); assert!(bool::from(Fr::multiplicative_generator().sqrt().is_none())); } diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs index 80848e12d..afa3aaf0e 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/pairing/src/bls12_381/mod.rs @@ -23,7 +23,7 @@ pub use self::fr::{Fr, FrRepr}; use super::{Engine, PairingCurveAffine}; -use ff::{BitIterator, Field, ScalarEngine}; +use ff::{BitIterator, Field, PowVartime, ScalarEngine}; use group::CurveAffine; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use subtle::CtOption; diff --git a/pairing/src/tests/engine.rs b/pairing/src/tests/engine.rs index 0776e5d4b..c65816de1 100644 --- a/pairing/src/tests/engine.rs +++ b/pairing/src/tests/engine.rs @@ -1,3 +1,4 @@ +use ff::PowVartime; use group::{CurveAffine, CurveProjective}; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs index 7ddb36534..a1f72b84b 100644 --- a/pairing/src/tests/field.rs +++ b/pairing/src/tests/field.rs @@ -1,4 +1,4 @@ -use ff::{Field, PrimeField, SqrtField}; +use ff::{Field, PowVartime, PrimeField, SqrtField}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index ef1ccbea4..6e902cbd3 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -1,6 +1,6 @@ use byteorder::{ByteOrder, LittleEndian}; use ff::{ - adc, mac_with_carry, sbb, BitIterator, Field, PrimeField, PrimeFieldDecodingError, + adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField, }; use rand_core::RngCore; @@ -745,7 +745,7 @@ impl SqrtField for Fs { // a1 = self^((s - 3) // 4) let mut a1 = self.pow_vartime([ - 0xb425c397b5bdcb2d, + 0xb425c397b5bdcb2du64, 0x299a0824f3320420, 0x4199cec0404d0ec0, 0x39f6d3a994cebea, @@ -1491,7 +1491,7 @@ fn test_fs_pow() { 0xe5, ]); - for i in 0..1000 { + for i in 0u64..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. let a = Fs::random(&mut rng); @@ -1689,13 +1689,13 @@ fn test_fs_root_of_unity() { ); assert_eq!( Fs::multiplicative_generator().pow_vartime([ - 0x684b872f6b7b965b, + 0x684b872f6b7b965bu64, 0x53341049e6640841, 0x83339d80809a1d80, 0x73eda753299d7d4 ]), Fs::root_of_unity() ); - assert_eq!(Fs::root_of_unity().pow_vartime([1 << Fs::S]), Fs::one()); + assert_eq!(Fs::root_of_unity().pow_vartime([1u64 << Fs::S]), Fs::one()); assert!(bool::from(Fs::multiplicative_generator().sqrt().is_none())); }