use another sync primitive for dense multiexp

This commit is contained in:
Alex Vlasov 2019-02-11 21:58:23 +03:00
parent b7d59787ed
commit 57a6ce94e8
3 changed files with 48 additions and 25 deletions

@ -2,13 +2,15 @@
extern crate pairing; extern crate pairing;
extern crate rand; extern crate rand;
extern crate bit_vec;
extern crate byteorder;
extern crate ff;
#[cfg(not(feature = "singlecore"))]
extern crate num_cpus; extern crate num_cpus;
extern crate futures; extern crate futures;
extern crate futures_cpupool; extern crate futures_cpupool;
extern crate bit_vec;
extern crate crossbeam; extern crate crossbeam;
extern crate byteorder;
extern crate ff;
pub mod domain; pub mod domain;
pub mod groth16; pub mod groth16;

@ -211,15 +211,21 @@ fn dense_multiexp_inner<G: CurveAffine>(
c: u32, c: u32,
handle_trivial: bool handle_trivial: bool
) -> Result<<G as CurveAffine>::Projective, SynthesisError> ) -> Result<<G as CurveAffine>::Projective, SynthesisError>
{ {
use crossbeam::channel::{unbounded, RecvError};
// Perform this region of the multiexp. We use a different strategy - go over region in parallel, // Perform this region of the multiexp. We use a different strategy - go over region in parallel,
// then over another region, etc. No Arc required // then over another region, etc. No Arc required
let this = { let this = {
let this_region = pool.scope(bases.len(), |scope, chunk| { // let mask = (1u64 << c) - 1u64;
let mut handles = vec![]; let (s, r) = unbounded();
let mut this_acc = <G as CurveAffine>::Projective::zero(); // let this_region =
pool.scope(bases.len(), |scope, chunk| {
// let mut handles = vec![];
// let mut this_acc = <G as CurveAffine>::Projective::zero();
for (base, exp) in bases.chunks(chunk).zip(exponents.chunks(chunk)) { for (base, exp) in bases.chunks(chunk).zip(exponents.chunks(chunk)) {
let handle = scope.spawn(move |_| { let s = s.clone();
// let handle =
scope.spawn(move |_| {
let mut buckets = vec![<G as CurveAffine>::Projective::zero(); (1 << c) - 1]; let mut buckets = vec![<G as CurveAffine>::Projective::zero(); (1 << c) - 1];
// Accumulate the result // Accumulate the result
let mut acc = G::Projective::zero(); let mut acc = G::Projective::zero();
@ -227,6 +233,14 @@ fn dense_multiexp_inner<G: CurveAffine>(
let one = <G::Engine as ScalarEngine>::Fr::one().into_repr(); let one = <G::Engine as ScalarEngine>::Fr::one().into_repr();
for (base, &exp) in base.iter().zip(exp.iter()) { for (base, &exp) in base.iter().zip(exp.iter()) {
// let index = (exp.as_ref()[0] & mask) as usize;
// if index != 0 {
// buckets[index - 1].add_assign_mixed(base);
// }
// exp.shr(c as u32);
if exp != zero { if exp != zero {
if exp == one { if exp == one {
if handle_trivial { if handle_trivial {
@ -251,21 +265,33 @@ fn dense_multiexp_inner<G: CurveAffine>(
} }
// acc contains values over this region // acc contains values over this region
acc s.send(acc).expect("must send result");
// acc
}); });
handles.push(handle); // handles.push(handle);
} }
// wait for all threads to finish // // wait for all threads to finish
for r in handles.into_iter().rev() { // for r in handles.into_iter() {
let thread_result = r.join().unwrap(); // let thread_result = r.join().unwrap();
this_acc.add_assign(&thread_result); // this_acc.add_assign(&thread_result);
} // }
this_acc
// this_acc
}); });
let mut this_region = <G as CurveAffine>::Projective::zero();
loop {
if r.is_empty() {
break;
}
let value = r.recv().expect("must have value");
this_region.add_assign(&value);
}
this_region this_region
}; };
@ -365,14 +391,14 @@ fn test_speed_with_bn256() {
#[test] #[test]
fn test_dense_multiexp() { fn test_dense_multiexp() {
use rand::{self, Rand}; use rand::{XorShiftRng, SeedableRng, Rand, Rng};
use pairing::bn256::Bn256; use pairing::bn256::Bn256;
use num_cpus; use num_cpus;
const SAMPLES: usize = 1 << 22; const SAMPLES: usize = 1 << 22;
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let rng = &mut rand::thread_rng(); let mut v = (0..SAMPLES).map(|_| <Bn256 as ScalarEngine>::Fr::rand(rng).into_repr()).collect::<Vec<_>>();
let v = (0..SAMPLES).map(|_| <Bn256 as ScalarEngine>::Fr::rand(rng).into_repr()).collect::<Vec<_>>();
let g = (0..SAMPLES).map(|_| <Bn256 as Engine>::G1::rand(rng).into_affine()).collect::<Vec<_>>(); let g = (0..SAMPLES).map(|_| <Bn256 as Engine>::G1::rand(rng).into_affine()).collect::<Vec<_>>();
let pool = Worker::new(); let pool = Worker::new();
@ -380,7 +406,7 @@ fn test_dense_multiexp() {
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let dense = dense_multiexp( let dense = dense_multiexp(
&pool, &g, &v).unwrap(); &pool, &g, &mut v.clone()).unwrap();
let duration_ns = start.elapsed().as_nanos() as f64; let duration_ns = start.elapsed().as_nanos() as f64;
println!("{} ns for dense for {} samples", duration_ns, SAMPLES); println!("{} ns for dense for {} samples", duration_ns, SAMPLES);

@ -196,11 +196,6 @@ where
IB::IntoIter: ExactSizeIterator + Clone, IB::IntoIter: ExactSizeIterator + Clone,
IS::IntoIter: ExactSizeIterator, IS::IntoIter: ExactSizeIterator,
{ {
use std::sync::Arc;
use futures::Future;
use ff::PrimeFieldRepr;
use pairing::CurveAffine;
use crate::multicore::Worker; use crate::multicore::Worker;
use crate::multiexp::dense_multiexp; use crate::multiexp::dense_multiexp;