Skip to content

Commit

Permalink
fix: use yastl for thread pools instead of rayon (filecoin-project#204)
Browse files Browse the repository at this point in the history
* fix: use yastl for thread pools instead of rayon
  • Loading branch information
dignifiedquire authored Aug 10, 2021
1 parent 149e12b commit ff3d582
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 354 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ paired = { version = "0.22.0", optional = true }
rust-gpu-tools = { version = "0.4.0", optional = true }
ff-cl-gen = { version = "0.3.0", optional = true }
fs2 = { version = "0.4.3", optional = true }
yastl = "0.1.2"

[dev-dependencies]
hex-literal = "0.3"
Expand Down
14 changes: 7 additions & 7 deletions src/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
let minv = self.minv;

for v in self.coeffs.chunks_mut(chunk) {
scope.spawn(move |_| {
scope.execute(move || {
for v in v {
v.group_mul_assign(&minv);
}
Expand All @@ -118,7 +118,7 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) {
worker.scope(self.coeffs.len(), |scope, chunk| {
for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() {
scope.spawn(move |_| {
scope.execute(move || {
let mut u = g.pow(&[(i * chunk) as u64]);
for v in v.iter_mut() {
v.group_mul_assign(&u);
Expand Down Expand Up @@ -170,7 +170,7 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {

worker.scope(self.coeffs.len(), |scope, chunk| {
for v in self.coeffs.chunks_mut(chunk) {
scope.spawn(move |_| {
scope.execute(move || {
for v in v {
v.group_mul_assign(&i);
}
Expand All @@ -189,7 +189,7 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
.chunks_mut(chunk)
.zip(other.coeffs.chunks(chunk))
{
scope.spawn(move |_| {
scope.execute(move || {
for (a, b) in a.iter_mut().zip(b.iter()) {
a.group_mul_assign(&b.0);
}
Expand All @@ -208,7 +208,7 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
.chunks_mut(chunk)
.zip(other.coeffs.chunks(chunk))
{
scope.spawn(move |_| {
scope.execute(move || {
for (a, b) in a.iter_mut().zip(b.iter()) {
a.group_sub_assign(&b);
}
Expand Down Expand Up @@ -392,7 +392,7 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
let a = &*a;

for (j, tmp) in tmp.iter_mut().enumerate() {
scope.spawn(move |_scope| {
scope.execute(move || {
// Shuffle into a sub-FFT
let omega_j = omega.pow(&[j as u64]);
let omega_step = omega.pow(&[(j as u64) << log_new_n]);
Expand Down Expand Up @@ -420,7 +420,7 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
let tmp = &tmp;

for (idx, a) in a.chunks_mut(chunk).enumerate() {
scope.spawn(move |_scope| {
scope.execute(move || {
let mut idx = idx * chunk;
let mask = (1 << log_cpus) - 1;
for a in a {
Expand Down
2 changes: 1 addition & 1 deletion src/gpu/multiexp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ where

let mut acc = <G as CurveAffine>::Projective::zero();

let results = crate::multicore::THREAD_POOL.install(|| {
let results = crate::multicore::RAYON_THREAD_POOL.install(|| {
if n > 0 {
bases
.par_chunks(chunk_size)
Expand Down
12 changes: 6 additions & 6 deletions src/groth16/aggregate/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ macro_rules! try_par {
$(
let mut $name = None;
)+
rayon::scope(|s| {
crate::multicore::THREAD_POOL.scoped(|s| {
$(
let $name = &mut $name;
s.spawn(move |_| {
s.execute(move || {
*$name = Some($f);
});)+
});
Expand All @@ -21,10 +21,10 @@ macro_rules! par {
$(
let mut $name = None;
)+
rayon::scope(|s| {
crate::multicore::THREAD_POOL.scoped(|s| {
$(
let $name = &mut $name;
s.spawn(move |_| {
s.execute(move || {
*$name = Some($f);
});)+
});
Expand All @@ -38,11 +38,11 @@ macro_rules! par {
let mut $name1 = None;
let mut $name2 = None;
)+
rayon::scope(|s| {
crate::multicore::THREAD_POOL.scoped(|s| {
$(
let $name1 = &mut $name1;
let $name2 = &mut $name2;
s.spawn(move |_| {
s.execute(move || {
let (a, b) = $f;
*$name1 = Some(a);
*$name2 = Some(b);
Expand Down
39 changes: 11 additions & 28 deletions src/groth16/aggregate/srs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,39 +267,22 @@ pub fn setup_fake_srs<E: Engine, R: rand::RngCore>(rng: &mut R, size: usize) ->
let g = E::G1::one();
let h = E::G2::one();

let mut g_alpha_powers = Vec::new();
let mut g_beta_powers = Vec::new();
let mut h_alpha_powers = Vec::new();
let mut h_beta_powers = Vec::new();
rayon::scope(|s| {
let alpha = &alpha;
let h = &h;
let g = &g;
let beta = &beta;
let g_alpha_powers = &mut g_alpha_powers;
s.spawn(move |_| {
*g_alpha_powers = structured_generators_scalar_power(2 * size, g, alpha);
});
let g_beta_powers = &mut g_beta_powers;
s.spawn(move |_| {
*g_beta_powers = structured_generators_scalar_power(2 * size, g, beta);
});

let h_alpha_powers = &mut h_alpha_powers;
s.spawn(move |_| {
*h_alpha_powers = structured_generators_scalar_power(2 * size, h, alpha);
});

let h_beta_powers = &mut h_beta_powers;
s.spawn(move |_| {
*h_beta_powers = structured_generators_scalar_power(2 * size, h, beta);
});
});
let alpha = &alpha;
let h = &h;
let g = &g;
let beta = &beta;
par! {
let g_alpha_powers = structured_generators_scalar_power(2 * size, g, alpha),
let g_beta_powers = structured_generators_scalar_power(2 * size, g, beta),
let h_alpha_powers = structured_generators_scalar_power(2 * size, h, alpha),
let h_beta_powers = structured_generators_scalar_power(2 * size, h, beta)
};

debug_assert!(h_alpha_powers[0] == E::G2::one().into_affine());
debug_assert!(h_beta_powers[0] == E::G2::one().into_affine());
debug_assert!(g_alpha_powers[0] == E::G1::one().into_affine());
debug_assert!(g_beta_powers[0] == E::G1::one().into_affine());

GenericSRS {
g_alpha_powers,
g_beta_powers,
Expand Down
220 changes: 108 additions & 112 deletions src/groth16/aggregate/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,118 +73,114 @@ pub fn verify_aggregate_proof<E: Engine + std::fmt::Debug, R: rand::RngCore + Se
let pairing_checks = PairingChecks::new(rng);
let pairing_checks_copy = &pairing_checks;

rayon::scope(move |_s| {
// 1.Check TIPA proof ab
// 2.Check TIPA proof c
// s.spawn(move |_| {
let now = Instant::now();
verify_tipp_mipp::<E, R>(
ip_verifier_srs,
proof,
&r, // we give the extra r as it's not part of the proof itself - it is simply used on top for the groth16 aggregation
pairing_checks_copy,
&hcom,
);
debug!("TIPP took {} ms", now.elapsed().as_millis(),);
// });

// Check aggregate pairing product equation
// SUM of a geometric progression
// SUM a^i = (1 - a^n) / (1 - a) = -(1-a^n)/-(1-a)
// = (a^n - 1) / (a - 1)
info!("checking aggregate pairing");
let mut r_sum = r.pow(&[public_inputs.len() as u64]);
r_sum.sub_assign(&E::Fr::one());
let b = sub!(*r, &E::Fr::one()).inverse().unwrap();
r_sum.mul_assign(&b);

// The following parts 3 4 5 are independently computing the parts of the Groth16
// verification equation
// NOTE From this point on, we are only checking *one* pairing check (the Groth16
// verification equation) so we don't need to randomize as all other checks are being
// randomized already. When merging all pairing checks together, this will be the only one
// non-randomized.
//
let (r_vec_sender, r_vec_receiver) = bounded(1);
// s.spawn(move |_| {
let now = Instant::now();
r_vec_sender
.send(structured_scalar_power(public_inputs.len(), &*r))
.unwrap();
let elapsed = now.elapsed().as_millis();
debug!("generation of r vector: {}ms", elapsed);
// });

par! {
// 3. Compute left part of the final pairing equation
let left = {
let mut alpha_g1_r_sum = pvk.alpha_g1;
alpha_g1_r_sum.mul_assign(r_sum);

E::miller_loop(&[(&alpha_g1_r_sum.into_affine().prepare(), &pvk.beta_g2)])
},
// 4. Compute right part of the final pairing equation
let right = {
E::miller_loop(&[(
// e(c^r vector form, h^delta)
// let agg_c = inner_product::multiexponentiation::<E::G1Affine>(&c, r_vec)
&proof.agg_c.into_affine().prepare(),
&pvk.delta_g2,
)])
},
// 5. compute the middle part of the final pairing equation, the one
// with the public inputs
let middle = {
// We want to compute MUL(i:0 -> l) S_i ^ (SUM(j:0 -> n) ai,j * r^j)
// this table keeps tracks of incremental computation of each i-th
// exponent to later multiply with S_i
// The index of the table is i, which is an index of the public
// input element
// We incrementally build the r vector and the table
// NOTE: in this version it's not r^2j but simply r^j

let l = public_inputs[0].len();
let mut g_ic = pvk.ic_projective[0];
g_ic.mul_assign(r_sum);

let powers = r_vec_receiver.recv().unwrap();

let now = Instant::now();
// now we do the multi exponentiation
let getter = |i: usize| -> <E::Fr as PrimeField>::Repr {
// i denotes the column of the public input, and j denotes which public input
let mut c = public_inputs[0][i];
for j in 1..public_inputs.len() {
let mut ai = public_inputs[j][i];
ai.mul_assign(&powers[j]);
c.add_assign(&ai);
}
c.into_repr()
};

let totsi = par_multiscalar::<_, E::G1Affine>(
&ScalarList::Getter(getter, l),
&pvk.multiscalar.at_point(1),
std::mem::size_of::<<E::Fr as PrimeField>::Repr>() * 8,
);

g_ic.add_assign(&totsi);

let ml = E::miller_loop(&[(&g_ic.into_affine().prepare(), &pvk.gamma_g2)]);
let elapsed = now.elapsed().as_millis();
debug!("table generation: {}ms", elapsed);

ml
}
};

pairing_checks_copy.merge_nonrandom(
vec![left, middle, right],
// final value ip_ab is what we want to compare in the groth16
// aggregated equation A * B
proof.ip_ab,
);
});
// 1.Check TIPA proof ab
// 2.Check TIPA proof c
// s.spawn(move |_| {
let now = Instant::now();
verify_tipp_mipp::<E, R>(
ip_verifier_srs,
proof,
&r, // we give the extra r as it's not part of the proof itself - it is simply used on top for the groth16 aggregation
pairing_checks_copy,
&hcom,
);
debug!("TIPP took {} ms", now.elapsed().as_millis(),);

// Check aggregate pairing product equation
// SUM of a geometric progression
// SUM a^i = (1 - a^n) / (1 - a) = -(1-a^n)/-(1-a)
// = (a^n - 1) / (a - 1)
info!("checking aggregate pairing");
let mut r_sum = r.pow(&[public_inputs.len() as u64]);
r_sum.sub_assign(&E::Fr::one());
let b = sub!(*r, &E::Fr::one()).inverse().unwrap();
r_sum.mul_assign(&b);

// The following parts 3 4 5 are independently computing the parts of the Groth16
// verification equation
// NOTE From this point on, we are only checking *one* pairing check (the Groth16
// verification equation) so we don't need to randomize as all other checks are being
// randomized already. When merging all pairing checks together, this will be the only one
// non-randomized.
//
let (r_vec_sender, r_vec_receiver) = bounded(1);

let now = Instant::now();
r_vec_sender
.send(structured_scalar_power(public_inputs.len(), &*r))
.unwrap();
let elapsed = now.elapsed().as_millis();
debug!("generation of r vector: {}ms", elapsed);

par! {
// 3. Compute left part of the final pairing equation
let left = {
let mut alpha_g1_r_sum = pvk.alpha_g1;
alpha_g1_r_sum.mul_assign(r_sum);

E::miller_loop(&[(&alpha_g1_r_sum.into_affine().prepare(), &pvk.beta_g2)])
},
// 4. Compute right part of the final pairing equation
let right = {
E::miller_loop(&[(
// e(c^r vector form, h^delta)
// let agg_c = inner_product::multiexponentiation::<E::G1Affine>(&c, r_vec)
&proof.agg_c.into_affine().prepare(),
&pvk.delta_g2,
)])
},
// 5. compute the middle part of the final pairing equation, the one
// with the public inputs
let middle = {
// We want to compute MUL(i:0 -> l) S_i ^ (SUM(j:0 -> n) ai,j * r^j)
// this table keeps tracks of incremental computation of each i-th
// exponent to later multiply with S_i
// The index of the table is i, which is an index of the public
// input element
// We incrementally build the r vector and the table
// NOTE: in this version it's not r^2j but simply r^j

let l = public_inputs[0].len();
let mut g_ic = pvk.ic_projective[0];
g_ic.mul_assign(r_sum);

let powers = r_vec_receiver.recv().unwrap();

let now = Instant::now();
// now we do the multi exponentiation
let getter = |i: usize| -> <E::Fr as PrimeField>::Repr {
// i denotes the column of the public input, and j denotes which public input
let mut c = public_inputs[0][i];
for j in 1..public_inputs.len() {
let mut ai = public_inputs[j][i];
ai.mul_assign(&powers[j]);
c.add_assign(&ai);
}
c.into_repr()
};

let totsi = par_multiscalar::<_, E::G1Affine>(
&ScalarList::Getter(getter, l),
&pvk.multiscalar.at_point(1),
std::mem::size_of::<<E::Fr as PrimeField>::Repr>() * 8,
);

g_ic.add_assign(&totsi);

let ml = E::miller_loop(&[(&g_ic.into_affine().prepare(), &pvk.gamma_g2)]);
let elapsed = now.elapsed().as_millis();
debug!("table generation: {}ms", elapsed);

ml
}
};

pairing_checks_copy.merge_nonrandom(
vec![left, middle, right],
// final value ip_ab is what we want to compare in the groth16
// aggregated equation A * B
proof.ip_ab,
);

let res = pairing_checks.verify();
info!("aggregate verify done");
Expand Down
Loading

0 comments on commit ff3d582

Please sign in to comment.