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.
This commit is contained in:
Jack Grigg 2020-06-06 11:29:26 +12:00
parent a105ad675a
commit ad96a38750
6 changed files with 40 additions and 25 deletions

View File

@ -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<E, C, R>(
) -> Result<Parameters<E>, SynthesisError>
where
E: Engine,
E::G1: WnafGroup,
E::G2: WnafGroup,
C: Circuit<E::Fr>,
R: RngCore,
{
@ -165,6 +167,8 @@ pub fn generate_parameters<E, C>(
) -> Result<Parameters<E>, SynthesisError>
where
E: Engine,
E::G1: WnafGroup,
E::G2: WnafGroup,
C: Circuit<E::Fr>,
{
let mut assembly = KeypairAssembly {

View File

@ -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
}

View File

@ -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<Rhs = Self, Output = Self>:
@ -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 {

View File

@ -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<G: CofactorCurve>() {
random_doubling_tests::<G>();
random_negation_tests::<G>();
random_transformation_tests::<G>();
random_wnaf_tests::<G>();
random_compressed_encoding_tests::<G>();
}
fn random_wnaf_tests<G: CofactorCurve>() {
pub fn random_wnaf_tests<G: WnafGroup>() {
use crate::wnaf::*;
let mut rng = XorShiftRng::from_seed([

View File

@ -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<G: CofactorCurve>(table: &mut Vec<G>, mut base: G, window: usize) {
pub(crate) fn wnaf_table<G: Group>(table: &mut Vec<G>, mut base: G, window: usize) {
table.truncate(0);
table.reserve(1 << (window - 1));
@ -78,7 +89,7 @@ pub(crate) fn wnaf_form<S: AsRef<[u8]>>(wnaf: &mut Vec<i64>, 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<G: CofactorCurve>(table: &[G], wnaf: &[i64]) -> G {
pub(crate) fn wnaf_exp<G: Group>(table: &[G], wnaf: &[i64]) -> G {
let mut result = G::identity();
let mut found_one = false;
@ -110,7 +121,7 @@ pub struct Wnaf<W, B, S> {
window_size: W,
}
impl<G: CofactorCurve> Wnaf<(), Vec<G>, Vec<i64>> {
impl<G: Group> Wnaf<(), Vec<G>, Vec<i64>> {
/// Construct a new wNAF context without allocating.
pub fn new() -> Self {
Wnaf {
@ -119,7 +130,9 @@ impl<G: CofactorCurve> Wnaf<(), Vec<G>, Vec<i64>> {
window_size: (),
}
}
}
impl<G: WnafGroup> Wnaf<(), Vec<G>, Vec<i64>> {
/// 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<usize, &[G], &mut Vec<i64>> {
@ -157,7 +170,7 @@ impl<G: CofactorCurve> Wnaf<(), Vec<G>, Vec<i64>> {
}
}
impl<'a, G: CofactorCurve> Wnaf<usize, &'a [G], &'a mut Vec<i64>> {
impl<'a, G: Group> Wnaf<usize, &'a [G], &'a mut Vec<i64>> {
/// 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<usize, &'a [G], Vec<i64>> {
@ -169,7 +182,7 @@ impl<'a, G: CofactorCurve> Wnaf<usize, &'a [G], &'a mut Vec<i64>> {
}
}
impl<'a, G: CofactorCurve> Wnaf<usize, &'a mut Vec<G>, &'a [i64]> {
impl<'a, G: Group> Wnaf<usize, &'a mut Vec<G>, &'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<usize, &'a mut Vec<G>, &'a [i64]> {
impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
/// Performs exponentiation given a base.
pub fn base<G: CofactorCurve>(&mut self, base: G) -> G
pub fn base<G: Group>(&mut self, base: G) -> G
where
B: AsMut<Vec<G>>,
{
@ -195,7 +208,7 @@ impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> {
/// Performs exponentiation given a scalar.
pub fn scalar<G: CofactorCurve>(&mut self, scalar: &<G as Group>::Scalar) -> G
pub fn scalar<G: Group>(&mut self, scalar: &<G as Group>::Scalar) -> G
where
B: AsRef<[G]>,
{

View File

@ -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(
<Self::Scalar as PrimeField>::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::<G1>();
random_wnaf_tests::<G1>();
random_uncompressed_encoding_tests::<G1>();
}
}
@ -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::<G2>();
random_wnaf_tests::<G2>();
random_uncompressed_encoding_tests::<G2>();
}
}