Add batchexp utility function to Engine.

This commit is contained in:
Sean Bowe 2017-05-16 16:41:31 -06:00
parent 33dd0de661
commit 97d58c7954
3 changed files with 72 additions and 1 deletions

@ -1025,6 +1025,37 @@ impl Engine for Bls381 {
f f
} }
fn batchexp<G: Curve<Self>, S: AsRef<[Self::Fr]>>(&self, g: &mut [G::Affine], scalars: S, coeff: Option<&Self::Fr>)
{
use crossbeam;
use num_cpus;
assert_eq!(g.len(), scalars.as_ref().len());
let chunk = (g.len() / num_cpus::get()) + 1;
crossbeam::scope(|scope| {
for (g, s) in g.chunks_mut(chunk).zip(scalars.as_ref().chunks(chunk)) {
scope.spawn(move || {
let mut table = WindowTable::new();
for (g, s) in g.iter_mut().zip(s.iter()) {
let mut s = *s;
match coeff {
Some(coeff) => {
s.mul_assign(self, coeff);
},
_ => {}
};
let mut newg = g.to_jacobian(self);
opt_exp(self, &mut newg, s.into_repr(self), &mut table);
*g = newg.to_affine(self);
}
});
}
});
}
fn batch_baseexp<G: Curve<Self>, S: AsRef<[Self::Fr]>>(&self, table: &WindowTable<Self, G, Vec<G>>, s: S) -> Vec<G::Affine> fn batch_baseexp<G: Curve<Self>, S: AsRef<[Self::Fr]>>(&self, table: &WindowTable<Self, G, Vec<G>>, s: S) -> Vec<G::Affine>
{ {
use crossbeam; use crossbeam;

@ -44,6 +44,8 @@ pub trait Engine: Sized + Clone + Send + Sync
/// Perform multi-exponentiation. g and s must have the same length. /// Perform multi-exponentiation. g and s must have the same length.
fn multiexp<G: Curve<Self>>(&self, g: &[G::Affine], s: &[Self::Fr]) -> Result<G, ()>; fn multiexp<G: Curve<Self>>(&self, g: &[G::Affine], s: &[Self::Fr]) -> Result<G, ()>;
fn batch_baseexp<G: Curve<Self>, S: AsRef<[Self::Fr]>>(&self, table: &WindowTable<Self, G, Vec<G>>, scalars: S) -> Vec<G::Affine>; fn batch_baseexp<G: Curve<Self>, S: AsRef<[Self::Fr]>>(&self, table: &WindowTable<Self, G, Vec<G>>, scalars: S) -> Vec<G::Affine>;
fn batchexp<G: Curve<Self>, S: AsRef<[Self::Fr]>>(&self, g: &mut [G::Affine], scalars: S, coeff: Option<&Self::Fr>);
} }
pub trait Group<E: Engine>: Copy + Send + Sync + Sized pub trait Group<E: Engine>: Copy + Send + Sync + Sized

@ -1,9 +1,44 @@
use super::{Engine, Curve, CurveAffine, Field, PrimeField}; use super::{Engine, Curve, CurveAffine, Field, PrimeField};
use rand; use rand::{self, Rng};
mod fields; mod fields;
mod curves; mod curves;
fn test_batchexp<E: Engine, G: Curve<E>>(e: &E) {
let rng = &mut rand::thread_rng();
fn test_batchexp_case<E: Engine, G: Curve<E>, R: Rng>(e: &E, rng: &mut R, amount: usize, coeff: Option<&E::Fr>)
{
let mut g: Vec<G::Affine> = (0..amount).map(|_| G::random(e, rng).to_affine(e)).collect();
let mut s: Vec<E::Fr> = (0..amount).map(|_| E::Fr::random(e, rng)).collect();
let mut g_batch = g.clone();
e.batchexp::<G, _>(&mut g_batch, &s, coeff);
for (g, s) in g.iter_mut().zip(s.iter_mut()) {
match coeff {
Some(coeff) => {
s.mul_assign(e, &coeff);
},
_ => {}
}
*g = g.mul(e, s).to_affine(e);
}
assert_eq!(g_batch, g);
}
for amt in 10..100 {
if amt % 2 == 0 {
let coeff = &E::Fr::random(e, rng);
test_batchexp_case::<E, G, _>(e, rng, amt, Some(coeff));
} else {
test_batchexp_case::<E, G, _>(e, rng, amt, None);
}
}
}
fn test_multiexp<E: Engine, G: Curve<E>>(e: &E) { fn test_multiexp<E: Engine, G: Curve<E>>(e: &E) {
fn naiveexp<E: Engine, G: Curve<E>>(e: &E, g: &[G::Affine], s: &[E::Fr]) -> G fn naiveexp<E: Engine, G: Curve<E>>(e: &E, g: &[G::Affine], s: &[E::Fr]) -> G
{ {
@ -120,6 +155,9 @@ pub fn test_engine<E: Engine>() {
test_frobenius(&engine); test_frobenius(&engine);
test_multiexp::<E, E::G1>(&engine); test_multiexp::<E, E::G1>(&engine);
test_multiexp::<E, E::G2>(&engine); test_multiexp::<E, E::G2>(&engine);
test_batchexp::<E, E::G1>(&engine);
test_batchexp::<E, E::G2>(&engine);
} }
fn test_frobenius<E: Engine>(e: &E) { fn test_frobenius<E: Engine>(e: &E) {