From ad96a38750b1f23c18765403f3b3faa26bd23d31 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 6 Jun 2020 11:29:26 +1200 Subject: [PATCH] group: Make Wnaf generic over Group Wnaf was originally generic over CurveProjective; in the prior refactor commit, we renamed this to CofactorCurve. But w-NAF only requires scalar multiplication, which is provided by the Group trait, so we relax the bounds on Wnaf to enable it to be used with any group. We move the generic w-NAF helper methods from the Curve trait to a new WnafGroup extension trait, to keep the w-NAF API surface self-contained, and not expose it to users who aren't using it. --- bellman/src/groth16/generator.rs | 6 ++++- bellman/src/groth16/tests/dummy_engine.rs | 4 +++- group/src/lib.rs | 10 +------- group/src/tests/mod.rs | 4 ++-- group/src/wnaf.rs | 29 ++++++++++++++++------- pairing/src/bls12_381/ec.rs | 12 ++++++---- 6 files changed, 40 insertions(+), 25 deletions(-) diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index 084e7a376..d04ed6c0a 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -3,7 +3,7 @@ use std::ops::{AddAssign, MulAssign}; use std::sync::Arc; use ff::{Field, PrimeField}; -use group::{cofactor::CofactorCurveAffine, Curve, Group, Wnaf}; +use group::{cofactor::CofactorCurveAffine, Curve, Group, Wnaf, WnafGroup}; use pairing::Engine; use super::{Parameters, VerifyingKey}; @@ -22,6 +22,8 @@ pub fn generate_random_parameters( ) -> Result, SynthesisError> where E: Engine, + E::G1: WnafGroup, + E::G2: WnafGroup, C: Circuit, R: RngCore, { @@ -165,6 +167,8 @@ pub fn generate_parameters( ) -> Result, SynthesisError> where E: Engine, + E::G1: WnafGroup, + E::G2: WnafGroup, C: Circuit, { let mut assembly = KeypairAssembly { diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 17e0043a1..8f11fe154 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -2,7 +2,7 @@ use ff::{Field, PrimeField}; use group::{ cofactor::{CofactorCurve, CofactorCurveAffine, CofactorGroup}, prime::PrimeGroup, - Curve, Group, GroupEncoding, UncompressedEncoding, + Curve, Group, GroupEncoding, UncompressedEncoding, WnafGroup, }; use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; @@ -414,7 +414,9 @@ impl Curve for Fr { fn to_affine(&self) -> Fr { *self } +} +impl WnafGroup for Fr { fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize { 3 } diff --git a/group/src/lib.rs b/group/src/lib.rs index 9696df42d..57914f820 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -13,7 +13,7 @@ pub mod prime; pub mod tests; mod wnaf; -pub use self::wnaf::Wnaf; +pub use self::wnaf::{Wnaf, WnafGroup}; /// A helper trait for types with a group operation. pub trait GroupOps: @@ -98,14 +98,6 @@ pub trait Curve: /// Converts this element into its affine representation. fn to_affine(&self) -> Self::AffineRepr; - - /// Recommends a wNAF window table size given a scalar. Always returns a number - /// between 2 and 22, inclusive. - fn recommended_wnaf_for_scalar(scalar: &Self::Scalar) -> usize; - - /// Recommends a wNAF window size given the number of scalars you intend to multiply - /// a base by. Always returns a number between 2 and 22, inclusive. - fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize; } pub trait GroupEncoding: Sized { diff --git a/group/src/tests/mod.rs b/group/src/tests/mod.rs index 50ba58135..be383b167 100644 --- a/group/src/tests/mod.rs +++ b/group/src/tests/mod.rs @@ -5,6 +5,7 @@ use std::ops::{Mul, Neg}; use crate::{ cofactor::{CofactorCurve, CofactorCurveAffine}, + wnaf::WnafGroup, GroupEncoding, UncompressedEncoding, }; @@ -64,11 +65,10 @@ pub fn curve_tests() { random_doubling_tests::(); random_negation_tests::(); random_transformation_tests::(); - random_wnaf_tests::(); random_compressed_encoding_tests::(); } -fn random_wnaf_tests() { +pub fn random_wnaf_tests() { use crate::wnaf::*; let mut rng = XorShiftRng::from_seed([ diff --git a/group/src/wnaf.rs b/group/src/wnaf.rs index 98573b4ad..20651d437 100644 --- a/group/src/wnaf.rs +++ b/group/src/wnaf.rs @@ -2,10 +2,21 @@ use byteorder::{ByteOrder, LittleEndian}; use ff::PrimeField; use std::iter; -use super::{cofactor::CofactorCurve, Group}; +use super::Group; + +/// Extension trait on a [`Group`] that provides helpers used by [`Wnaf`]. +pub trait WnafGroup: Group { + /// Recommends a wNAF window table size given a scalar. Always returns a number + /// between 2 and 22, inclusive. + fn recommended_wnaf_for_scalar(scalar: &Self::Scalar) -> usize; + + /// Recommends a wNAF window size given the number of scalars you intend to multiply + /// a base by. Always returns a number between 2 and 22, inclusive. + fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize; +} /// Replaces the contents of `table` with a w-NAF window table for the given window size. -pub(crate) fn wnaf_table(table: &mut Vec, mut base: G, window: usize) { +pub(crate) fn wnaf_table(table: &mut Vec, mut base: G, window: usize) { table.truncate(0); table.reserve(1 << (window - 1)); @@ -78,7 +89,7 @@ pub(crate) fn wnaf_form>(wnaf: &mut Vec, c: S, window: usize /// /// This function must be provided a `table` and `wnaf` that were constructed with /// the same window size; otherwise, it may panic or produce invalid results. -pub(crate) fn wnaf_exp(table: &[G], wnaf: &[i64]) -> G { +pub(crate) fn wnaf_exp(table: &[G], wnaf: &[i64]) -> G { let mut result = G::identity(); let mut found_one = false; @@ -110,7 +121,7 @@ pub struct Wnaf { window_size: W, } -impl Wnaf<(), Vec, Vec> { +impl Wnaf<(), Vec, Vec> { /// Construct a new wNAF context without allocating. pub fn new() -> Self { Wnaf { @@ -119,7 +130,9 @@ impl Wnaf<(), Vec, Vec> { window_size: (), } } +} +impl Wnaf<(), Vec, Vec> { /// Given a base and a number of scalars, compute a window table and return a `Wnaf` object that /// can perform exponentiations with `.scalar(..)`. pub fn base(&mut self, base: G, num_scalars: usize) -> Wnaf> { @@ -157,7 +170,7 @@ impl Wnaf<(), Vec, Vec> { } } -impl<'a, G: CofactorCurve> Wnaf> { +impl<'a, G: Group> Wnaf> { /// Constructs new space for the scalar representation while borrowing /// the computed window table, for sending the window table across threads. pub fn shared(&self) -> Wnaf> { @@ -169,7 +182,7 @@ impl<'a, G: CofactorCurve> Wnaf> { } } -impl<'a, G: CofactorCurve> Wnaf, &'a [i64]> { +impl<'a, G: Group> Wnaf, &'a [i64]> { /// Constructs new space for the window table while borrowing /// the computed scalar representation, for sending the scalar representation /// across threads. @@ -184,7 +197,7 @@ impl<'a, G: CofactorCurve> Wnaf, &'a [i64]> { impl> Wnaf { /// Performs exponentiation given a base. - pub fn base(&mut self, base: G) -> G + pub fn base(&mut self, base: G) -> G where B: AsMut>, { @@ -195,7 +208,7 @@ impl> Wnaf { impl>> Wnaf { /// Performs exponentiation given a scalar. - pub fn scalar(&mut self, scalar: &::Scalar) -> G + pub fn scalar(&mut self, scalar: &::Scalar) -> G where B: AsRef<[G]>, { diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index bf4d96240..487455844 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -1092,7 +1092,9 @@ macro_rules! curve_impl { fn to_affine(&self) -> $affine { (*self).into() } + } + impl WnafGroup for $projective { fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize { Self::empirical_recommended_wnaf_for_scalar( ::NUM_BITS as usize, @@ -1210,7 +1212,7 @@ pub mod g1 { use group::{ cofactor::{CofactorCurve, CofactorCurveAffine, CofactorGroup}, prime::PrimeGroup, - Curve, Group, GroupEncoding, UncompressedEncoding, + Curve, Group, GroupEncoding, UncompressedEncoding, WnafGroup, }; use rand_core::RngCore; use std::fmt; @@ -1778,8 +1780,9 @@ pub mod g1 { #[test] fn g1_curve_tests() { - use group::tests::{curve_tests, random_uncompressed_encoding_tests}; + use group::tests::{curve_tests, random_uncompressed_encoding_tests, random_wnaf_tests}; curve_tests::(); + random_wnaf_tests::(); random_uncompressed_encoding_tests::(); } } @@ -1792,7 +1795,7 @@ pub mod g2 { use group::{ cofactor::{CofactorCurve, CofactorCurveAffine, CofactorGroup}, prime::PrimeGroup, - Curve, Group, GroupEncoding, UncompressedEncoding, + Curve, Group, GroupEncoding, UncompressedEncoding, WnafGroup, }; use rand_core::RngCore; use std::fmt; @@ -2484,8 +2487,9 @@ pub mod g2 { #[test] fn g2_curve_tests() { - use group::tests::{curve_tests, random_uncompressed_encoding_tests}; + use group::tests::{curve_tests, random_uncompressed_encoding_tests, random_wnaf_tests}; curve_tests::(); + random_wnaf_tests::(); random_uncompressed_encoding_tests::(); } }