group: Add scalar multiplication bounds to Group
The Scalar associated type is moved from CurveProjective to Group.
This commit is contained in:
parent
0df950dc0d
commit
ec88778258
|
@ -221,7 +221,7 @@ impl<G: CurveProjective, E: ScalarEngine<Fr = G::Scalar>> Group<E> for Point<G>
|
||||||
Point(G::identity())
|
Point(G::identity())
|
||||||
}
|
}
|
||||||
fn group_mul_assign(&mut self, by: &G::Scalar) {
|
fn group_mul_assign(&mut self, by: &G::Scalar) {
|
||||||
self.0.mul_assign(by.to_repr());
|
self.0.mul_assign(by);
|
||||||
}
|
}
|
||||||
fn group_add_assign(&mut self, other: &Self) {
|
fn group_add_assign(&mut self, other: &Self) {
|
||||||
self.0.add_assign(&other.0);
|
self.0.add_assign(&other.0);
|
||||||
|
|
|
@ -317,7 +317,7 @@ where
|
||||||
let mut a_answer = a_inputs.wait()?;
|
let mut a_answer = a_inputs.wait()?;
|
||||||
AddAssign::<&E::G1>::add_assign(&mut a_answer, &a_aux.wait()?);
|
AddAssign::<&E::G1>::add_assign(&mut a_answer, &a_aux.wait()?);
|
||||||
AddAssign::<&E::G1>::add_assign(&mut g_a, &a_answer);
|
AddAssign::<&E::G1>::add_assign(&mut g_a, &a_answer);
|
||||||
a_answer.mul_assign(s);
|
MulAssign::<E::Fr>::mul_assign(&mut a_answer, s);
|
||||||
AddAssign::<&E::G1>::add_assign(&mut g_c, &a_answer);
|
AddAssign::<&E::G1>::add_assign(&mut g_c, &a_answer);
|
||||||
|
|
||||||
let mut b1_answer: E::G1 = b_g1_inputs.wait()?;
|
let mut b1_answer: E::G1 = b_g1_inputs.wait()?;
|
||||||
|
@ -326,7 +326,7 @@ where
|
||||||
AddAssign::<&E::G2>::add_assign(&mut b2_answer, &b_g2_aux.wait()?);
|
AddAssign::<&E::G2>::add_assign(&mut b2_answer, &b_g2_aux.wait()?);
|
||||||
|
|
||||||
AddAssign::<&E::G2>::add_assign(&mut g_b, &b2_answer);
|
AddAssign::<&E::G2>::add_assign(&mut g_b, &b2_answer);
|
||||||
b1_answer.mul_assign(r);
|
MulAssign::<E::Fr>::mul_assign(&mut b1_answer, r);
|
||||||
AddAssign::<&E::G1>::add_assign(&mut g_c, &b1_answer);
|
AddAssign::<&E::G1>::add_assign(&mut g_c, &b1_answer);
|
||||||
AddAssign::<&E::G1>::add_assign(&mut g_c, &h.wait()?);
|
AddAssign::<&E::G1>::add_assign(&mut g_c, &h.wait()?);
|
||||||
AddAssign::<&E::G1>::add_assign(&mut g_c, &l.wait()?);
|
AddAssign::<&E::G1>::add_assign(&mut g_c, &l.wait()?);
|
||||||
|
|
|
@ -367,6 +367,7 @@ impl Engine for DummyEngine {
|
||||||
|
|
||||||
impl Group for Fr {
|
impl Group for Fr {
|
||||||
type Subgroup = Fr;
|
type Subgroup = Fr;
|
||||||
|
type Scalar = Fr;
|
||||||
|
|
||||||
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
|
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
|
||||||
<Fr as Field>::random(rng)
|
<Fr as Field>::random(rng)
|
||||||
|
@ -394,7 +395,6 @@ impl PrimeGroup for Fr {}
|
||||||
impl CurveProjective for Fr {
|
impl CurveProjective for Fr {
|
||||||
type Affine = Fr;
|
type Affine = Fr;
|
||||||
type Base = Fr;
|
type Base = Fr;
|
||||||
type Scalar = Fr;
|
|
||||||
|
|
||||||
fn batch_normalization(_: &mut [Self]) {}
|
fn batch_normalization(_: &mut [Self]) {}
|
||||||
|
|
||||||
|
@ -402,12 +402,6 @@ impl CurveProjective for Fr {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S) {
|
|
||||||
let tmp = Fr::from_repr(other.into()).unwrap();
|
|
||||||
|
|
||||||
MulAssign::mul_assign(self, &tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_affine(&self) -> Fr {
|
fn into_affine(&self) -> Fr {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use rand::RngCore;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
|
|
||||||
pub mod tests;
|
pub mod tests;
|
||||||
|
|
||||||
|
@ -28,6 +28,20 @@ impl<T, Rhs, Output> GroupOps<Rhs, Output> for T where
|
||||||
pub trait GroupOpsOwned<Rhs = Self, Output = Self>: for<'r> GroupOps<&'r Rhs, Output> {}
|
pub trait GroupOpsOwned<Rhs = Self, Output = Self>: for<'r> GroupOps<&'r Rhs, Output> {}
|
||||||
impl<T, Rhs, Output> GroupOpsOwned<Rhs, Output> for T where T: for<'r> GroupOps<&'r Rhs, Output> {}
|
impl<T, Rhs, Output> GroupOpsOwned<Rhs, Output> for T where T: for<'r> GroupOps<&'r Rhs, Output> {}
|
||||||
|
|
||||||
|
/// A helper trait for types implementing group scalar multiplication.
|
||||||
|
pub trait ScalarMul<Rhs, Output = Self>: Mul<Rhs, Output = Output> + MulAssign<Rhs> {}
|
||||||
|
|
||||||
|
impl<T, Rhs, Output> ScalarMul<Rhs, Output> for T where T: Mul<Rhs, Output = Output> + MulAssign<Rhs>
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// A helper trait for references implementing group scalar multiplication.
|
||||||
|
///
|
||||||
|
/// This trait, in combination with `ScalarMul`, is necessary to address type constraint
|
||||||
|
/// issues in `pairing::Engine` (specifically, to ensure that [`ff::ScalarEngine::Fr`] is
|
||||||
|
/// correctly constrained to implement these traits required by [`Group::Scalar`]).
|
||||||
|
pub trait ScalarMulOwned<Rhs, Output = Self>: for<'r> ScalarMul<&'r Rhs, Output> {}
|
||||||
|
impl<T, Rhs, Output> ScalarMulOwned<Rhs, Output> for T where T: for<'r> ScalarMul<&'r Rhs, Output> {}
|
||||||
|
|
||||||
/// This trait represents an element of a cryptographic group.
|
/// This trait represents an element of a cryptographic group.
|
||||||
pub trait Group:
|
pub trait Group:
|
||||||
Clone
|
Clone
|
||||||
|
@ -46,11 +60,16 @@ pub trait Group:
|
||||||
+ GroupOpsOwned
|
+ GroupOpsOwned
|
||||||
+ GroupOps<<Self as Group>::Subgroup>
|
+ GroupOps<<Self as Group>::Subgroup>
|
||||||
+ GroupOpsOwned<<Self as Group>::Subgroup>
|
+ GroupOpsOwned<<Self as Group>::Subgroup>
|
||||||
|
+ ScalarMul<<Self as Group>::Scalar>
|
||||||
|
+ ScalarMulOwned<<Self as Group>::Scalar>
|
||||||
{
|
{
|
||||||
/// The large prime-order subgroup in which cryptographic operations are performed.
|
/// The large prime-order subgroup in which cryptographic operations are performed.
|
||||||
/// If `Self` implements `PrimeGroup`, then `Self::Subgroup` may be `Self`.
|
/// If `Self` implements `PrimeGroup`, then `Self::Subgroup` may be `Self`.
|
||||||
type Subgroup: PrimeGroup;
|
type Subgroup: PrimeGroup;
|
||||||
|
|
||||||
|
/// Scalars modulo the order of [`Group::Subgroup`].
|
||||||
|
type Scalar: PrimeField;
|
||||||
|
|
||||||
/// Returns an element chosen uniformly at random using a user-provided RNG.
|
/// Returns an element chosen uniformly at random using a user-provided RNG.
|
||||||
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self;
|
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self;
|
||||||
|
|
||||||
|
@ -78,7 +97,6 @@ pub trait CurveProjective:
|
||||||
+ GroupOps<<Self as CurveProjective>::Affine>
|
+ GroupOps<<Self as CurveProjective>::Affine>
|
||||||
+ GroupOpsOwned<<Self as CurveProjective>::Affine>
|
+ GroupOpsOwned<<Self as CurveProjective>::Affine>
|
||||||
{
|
{
|
||||||
type Scalar: PrimeField;
|
|
||||||
type Base: Field;
|
type Base: Field;
|
||||||
type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>;
|
type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>;
|
||||||
|
|
||||||
|
@ -90,9 +108,6 @@ pub trait CurveProjective:
|
||||||
/// cheap affine conversion is possible.
|
/// cheap affine conversion is possible.
|
||||||
fn is_normalized(&self) -> bool;
|
fn is_normalized(&self) -> bool;
|
||||||
|
|
||||||
/// Performs scalar multiplication of this element.
|
|
||||||
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S);
|
|
||||||
|
|
||||||
/// Converts this element into its affine representation.
|
/// Converts this element into its affine representation.
|
||||||
fn into_affine(&self) -> Self::Affine;
|
fn into_affine(&self) -> Self::Affine;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use super::CurveProjective;
|
use super::{CurveProjective, Group};
|
||||||
|
|
||||||
/// Replaces the contents of `table` with a w-NAF window table for the given window size.
|
/// Replaces the contents of `table` with a w-NAF window table for the given window size.
|
||||||
pub(crate) fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, window: usize) {
|
pub(crate) fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, window: usize) {
|
||||||
|
@ -140,10 +140,7 @@ impl<G: CurveProjective> Wnaf<(), Vec<G>, Vec<i64>> {
|
||||||
|
|
||||||
/// Given a scalar, compute its wNAF representation and return a `Wnaf` object that can perform
|
/// Given a scalar, compute its wNAF representation and return a `Wnaf` object that can perform
|
||||||
/// exponentiations with `.base(..)`.
|
/// exponentiations with `.base(..)`.
|
||||||
pub fn scalar(
|
pub fn scalar(&mut self, scalar: &<G as Group>::Scalar) -> Wnaf<usize, &mut Vec<G>, &[i64]> {
|
||||||
&mut self,
|
|
||||||
scalar: &<G as CurveProjective>::Scalar,
|
|
||||||
) -> Wnaf<usize, &mut Vec<G>, &[i64]> {
|
|
||||||
// Compute the appropriate window size for the scalar.
|
// Compute the appropriate window size for the scalar.
|
||||||
let window_size = G::recommended_wnaf_for_scalar(&scalar);
|
let window_size = G::recommended_wnaf_for_scalar(&scalar);
|
||||||
|
|
||||||
|
@ -198,7 +195,7 @@ impl<B, S: AsRef<[i64]>> Wnaf<usize, B, S> {
|
||||||
|
|
||||||
impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> {
|
impl<B, S: AsMut<Vec<i64>>> Wnaf<usize, B, S> {
|
||||||
/// Performs exponentiation given a scalar.
|
/// Performs exponentiation given a scalar.
|
||||||
pub fn scalar<G: CurveProjective>(&mut self, scalar: &<G as CurveProjective>::Scalar) -> G
|
pub fn scalar<G: CurveProjective>(&mut self, scalar: &<G as Group>::Scalar) -> G
|
||||||
where
|
where
|
||||||
B: AsRef<[G]>,
|
B: AsRef<[G]>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub(crate) mod g1 {
|
||||||
use std::ops::AddAssign;
|
use std::ops::AddAssign;
|
||||||
|
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
use group::{CurveProjective, Group};
|
use group::Group;
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
|
|
||||||
fn bench_g1_mul_assign(c: &mut Criterion) {
|
fn bench_g1_mul_assign(c: &mut Criterion) {
|
||||||
|
@ -24,7 +24,7 @@ pub(crate) mod g1 {
|
||||||
c.bench_function("G1::mul_assign", |b| {
|
c.bench_function("G1::mul_assign", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut tmp = v[count].0;
|
let mut tmp = v[count].0;
|
||||||
tmp.mul_assign(v[count].1);
|
tmp *= v[count].1;
|
||||||
count = (count + 1) % SAMPLES;
|
count = (count + 1) % SAMPLES;
|
||||||
tmp
|
tmp
|
||||||
})
|
})
|
||||||
|
@ -92,7 +92,7 @@ pub(crate) mod g2 {
|
||||||
use std::ops::AddAssign;
|
use std::ops::AddAssign;
|
||||||
|
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
use group::{CurveProjective, Group};
|
use group::Group;
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
|
|
||||||
fn bench_g2_mul_assign(c: &mut Criterion) {
|
fn bench_g2_mul_assign(c: &mut Criterion) {
|
||||||
|
@ -111,7 +111,7 @@ pub(crate) mod g2 {
|
||||||
c.bench_function("G2::mul_assign", |b| {
|
c.bench_function("G2::mul_assign", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut tmp = v[count].0;
|
let mut tmp = v[count].0;
|
||||||
tmp.mul_assign(v[count].1);
|
tmp *= v[count].1;
|
||||||
count = (count + 1) % SAMPLES;
|
count = (count + 1) % SAMPLES;
|
||||||
tmp
|
tmp
|
||||||
})
|
})
|
||||||
|
|
|
@ -520,8 +520,55 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::Mul<<$projective as Group>::Scalar> for $projective {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(mut self, other: <$projective as Group>::Scalar) -> Self {
|
||||||
|
self.mul_assign(&other);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::Mul<&'r <$projective as Group>::Scalar> for $projective {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(mut self, other: &'r <$projective as Group>::Scalar) -> Self {
|
||||||
|
self.mul_assign(other);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::MulAssign<<$projective as Group>::Scalar> for $projective {
|
||||||
|
fn mul_assign(&mut self, other: <$projective as Group>::Scalar) {
|
||||||
|
self.mul_assign(&other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> ::std::ops::MulAssign<&'r <$projective as Group>::Scalar> for $projective {
|
||||||
|
fn mul_assign(&mut self, other: &'r <$projective as Group>::Scalar) {
|
||||||
|
let mut res = Self::identity();
|
||||||
|
|
||||||
|
let mut found_one = false;
|
||||||
|
|
||||||
|
for i in BitIterator::<u8, _>::new(other.to_repr()) {
|
||||||
|
if found_one {
|
||||||
|
res = res.double();
|
||||||
|
} else {
|
||||||
|
found_one = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if i {
|
||||||
|
res.add_assign(&*self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*self = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Group for $projective {
|
impl Group for $projective {
|
||||||
type Subgroup = Self;
|
type Subgroup = Self;
|
||||||
|
type Scalar = $scalarfield;
|
||||||
|
|
||||||
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
|
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
|
||||||
loop {
|
loop {
|
||||||
|
@ -611,7 +658,6 @@ macro_rules! curve_impl {
|
||||||
impl PrimeGroup for $projective {}
|
impl PrimeGroup for $projective {}
|
||||||
|
|
||||||
impl CurveProjective for $projective {
|
impl CurveProjective for $projective {
|
||||||
type Scalar = $scalarfield;
|
|
||||||
type Base = $basefield;
|
type Base = $basefield;
|
||||||
type Affine = $affine;
|
type Affine = $affine;
|
||||||
|
|
||||||
|
@ -672,26 +718,6 @@ macro_rules! curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S) {
|
|
||||||
let mut res = Self::identity();
|
|
||||||
|
|
||||||
let mut found_one = false;
|
|
||||||
|
|
||||||
for i in BitIterator::<u8, _>::new(other.into()) {
|
|
||||||
if found_one {
|
|
||||||
res = res.double();
|
|
||||||
} else {
|
|
||||||
found_one = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if i {
|
|
||||||
res.add_assign(&*self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*self = res;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_affine(&self) -> $affine {
|
fn into_affine(&self) -> $affine {
|
||||||
(*self).into()
|
(*self).into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub mod tests;
|
||||||
pub mod bls12_381;
|
pub mod bls12_381;
|
||||||
|
|
||||||
use ff::{Field, PrimeField, ScalarEngine};
|
use ff::{Field, PrimeField, ScalarEngine};
|
||||||
use group::{CurveAffine, CurveProjective, GroupOps, GroupOpsOwned};
|
use group::{CurveAffine, CurveProjective, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned};
|
||||||
use subtle::CtOption;
|
use subtle::CtOption;
|
||||||
|
|
||||||
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
||||||
|
@ -32,7 +32,9 @@ pub trait Engine: ScalarEngine {
|
||||||
type G1: CurveProjective<Base = Self::Fq, Scalar = Self::Fr, Affine = Self::G1Affine>
|
type G1: CurveProjective<Base = Self::Fq, Scalar = Self::Fr, Affine = Self::G1Affine>
|
||||||
+ From<Self::G1Affine>
|
+ From<Self::G1Affine>
|
||||||
+ GroupOps<Self::G1Affine>
|
+ GroupOps<Self::G1Affine>
|
||||||
+ GroupOpsOwned<Self::G1Affine>;
|
+ GroupOpsOwned<Self::G1Affine>
|
||||||
|
+ ScalarMul<Self::Fr>
|
||||||
|
+ ScalarMulOwned<Self::Fr>;
|
||||||
|
|
||||||
/// The affine representation of an element in G1.
|
/// The affine representation of an element in G1.
|
||||||
type G1Affine: PairingCurveAffine<
|
type G1Affine: PairingCurveAffine<
|
||||||
|
@ -47,7 +49,9 @@ pub trait Engine: ScalarEngine {
|
||||||
type G2: CurveProjective<Base = Self::Fqe, Scalar = Self::Fr, Affine = Self::G2Affine>
|
type G2: CurveProjective<Base = Self::Fqe, Scalar = Self::Fr, Affine = Self::G2Affine>
|
||||||
+ From<Self::G2Affine>
|
+ From<Self::G2Affine>
|
||||||
+ GroupOps<Self::G2Affine>
|
+ GroupOps<Self::G2Affine>
|
||||||
+ GroupOpsOwned<Self::G2Affine>;
|
+ GroupOpsOwned<Self::G2Affine>
|
||||||
|
+ ScalarMul<Self::Fr>
|
||||||
|
+ ScalarMulOwned<Self::Fr>;
|
||||||
|
|
||||||
/// The affine representation of an element in G2.
|
/// The affine representation of an element in G2.
|
||||||
type G2Affine: PairingCurveAffine<
|
type G2Affine: PairingCurveAffine<
|
||||||
|
|
|
@ -114,23 +114,21 @@ fn random_bilinearity_tests<E: Engine>() {
|
||||||
let d = E::Fr::random(&mut rng);
|
let d = E::Fr::random(&mut rng);
|
||||||
|
|
||||||
let mut ac = a;
|
let mut ac = a;
|
||||||
ac.mul_assign(c);
|
MulAssign::<&E::Fr>::mul_assign(&mut ac, &c);
|
||||||
|
|
||||||
let mut ad = a;
|
let mut ad = a;
|
||||||
ad.mul_assign(d);
|
MulAssign::<&E::Fr>::mul_assign(&mut ad, &d);
|
||||||
|
|
||||||
let mut bc = b;
|
let mut bc = b;
|
||||||
bc.mul_assign(c);
|
MulAssign::<&E::Fr>::mul_assign(&mut bc, &c);
|
||||||
|
|
||||||
let mut bd = b;
|
let mut bd = b;
|
||||||
bd.mul_assign(d);
|
MulAssign::<&E::Fr>::mul_assign(&mut bd, &d);
|
||||||
|
|
||||||
let acbd = E::pairing(ac, bd);
|
let acbd = E::pairing(ac, bd);
|
||||||
let adbc = E::pairing(ad, bc);
|
let adbc = E::pairing(ad, bc);
|
||||||
|
|
||||||
let mut cd = c;
|
let mut cd = (c * &d).to_repr();
|
||||||
cd.mul_assign(&d);
|
|
||||||
let mut cd = cd.to_repr();
|
|
||||||
<E::Fr as PrimeField>::ReprEndianness::toggle_little_endian(&mut cd);
|
<E::Fr as PrimeField>::ReprEndianness::toggle_little_endian(&mut cd);
|
||||||
|
|
||||||
use byteorder::ByteOrder;
|
use byteorder::ByteOrder;
|
||||||
|
|
Loading…
Reference in New Issue