Skip to content

Commit

Permalink
Batch inversion & normalization (#345)
Browse files Browse the repository at this point in the history
* fix: use ff batch inversion

* fix: use batch normalization in HyperKZG
  • Loading branch information
huitseeker authored Feb 25, 2024
1 parent afb9486 commit 6089294
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 63 deletions.
19 changes: 10 additions & 9 deletions src/provider/hyperkzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
};
use core::marker::PhantomData;
use ff::{Field, PrimeFieldBits};
use group::{Curve, Group as _};
use group::{prime::PrimeCurveAffine as _, Curve, Group as _};
use itertools::Itertools as _;
use pairing::{Engine, MillerLoopResult, MultiMillerLoop};
use rayon::prelude::*;
Expand Down Expand Up @@ -241,14 +241,15 @@ where

// We do not need to commit to the first polynomial as it is already committed.
// Compute commitments in parallel
let comms: Vec<E::G1Affine> = (1..polys.len())
.into_par_iter()
.map(|i| {
<NE::CE as CommitmentEngineTrait<NE>>::commit(ck, &polys[i])
.comm
.to_affine()
})
.collect();
let comms = {
let mut comms = vec![E::G1Affine::identity(); polys.len() - 1];
let comms_proj: Vec<E::G1> = (1..polys.len())
.into_par_iter()
.map(|i| <NE::CE as CommitmentEngineTrait<NE>>::commit(ck, &polys[i]).comm)
.collect();
Curve::batch_normalize(&comms_proj, &mut comms);
comms
};

// Phase 2
// We do not need to add x to the transcript, because in our context x was obtained from the transcript.
Expand Down
27 changes: 2 additions & 25 deletions src/provider/ipa_pc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::{
digest::SimpleDigestible,
errors::{NovaError, PCSError},
provider::{pedersen::CommitmentKeyExtTrait, traits::DlogGroup},
provider::{pedersen::CommitmentKeyExtTrait, traits::DlogGroup, util::field::batch_invert},
spartan::polys::eq::EqPolynomial,
traits::{
commitment::{CommitmentEngineTrait, CommitmentTrait},
Expand Down Expand Up @@ -304,29 +304,6 @@ where

let P = U.comm_a_vec + CE::<E>::commit(&ck_c, &[U.c]);

let batch_invert = |v: &[E::Scalar]| -> Result<Vec<E::Scalar>, NovaError> {
let mut products = vec![E::Scalar::ZERO; v.len()];
let mut acc = E::Scalar::ONE;

for i in 0..v.len() {
products[i] = acc;
acc *= v[i];
}

// return error if acc is zero
acc = Option::from(acc.invert()).ok_or(NovaError::InternalError)?;

// compute the inverse once for all entries
let mut inv = vec![E::Scalar::ZERO; v.len()];
for i in (0..v.len()).rev() {
let tmp = acc * v[i];
inv[i] = products[i] * acc;
acc = tmp;
}

Ok(inv)
};

// compute a vector of public coins using self.L_vec and self.R_vec
let r = (0..self.L_vec.len())
.map(|i| {
Expand All @@ -341,7 +318,7 @@ where
.into_par_iter()
.map(|i| r[i] * r[i])
.collect();
let r_inverse = batch_invert(&r)?;
let r_inverse = batch_invert(r.clone())?;
let r_inverse_square: Vec<E::Scalar> = (0..self.L_vec.len())
.into_par_iter()
.map(|i| r_inverse[i] * r_inverse[i])
Expand Down
22 changes: 22 additions & 0 deletions src/provider/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,28 @@ pub mod msm {
}
}

pub mod field {
use crate::errors::NovaError;
use ff::{BatchInverter, Field};

#[inline]
pub fn batch_invert<F: Field>(mut v: Vec<F>) -> Result<Vec<F>, NovaError> {
// we only allocate the scratch space if every element of v is nonzero
let mut scratch_space = v
.iter()
.map(|x| {
if !x.is_zero_vartime() {
Ok(*x)
} else {
Err(NovaError::InternalError)
}
})
.collect::<Result<Vec<_>, _>>()?;
let _ = BatchInverter::invert_with_external_scratch(&mut v, &mut scratch_space[..]);
Ok(v)
}
}

pub mod iterators {
use ff::Field;
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
Expand Down
32 changes: 3 additions & 29 deletions src/spartan/sumcheck/engine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use ff::Field;
use rayon::prelude::*;

use crate::provider::util::field::batch_invert;
use crate::spartan::math::Math;
use crate::spartan::polys::{
eq::EqPolynomial, masked_eq::MaskedEqPolynomial, multilinear::MultilinearPolynomial,
Expand Down Expand Up @@ -191,33 +192,6 @@ impl<E: Engine> MemorySumcheckInstance<E> {
|| hash_func_vec(mem_col, addr_col, L_col),
);

let batch_invert = |v: &[E::Scalar]| -> Result<Vec<E::Scalar>, NovaError> {
let mut products = vec![E::Scalar::ZERO; v.len()];
let mut acc = E::Scalar::ONE;

for i in 0..v.len() {
products[i] = acc;
acc *= v[i];
}

// we can compute an inversion only if acc is non-zero
if acc == E::Scalar::ZERO {
return Err(NovaError::InternalError);
}

// compute the inverse once for all entries
acc = acc.invert().unwrap();

let mut inv = vec![E::Scalar::ZERO; v.len()];
for i in 0..v.len() {
let tmp = acc * v[v.len() - 1 - i];
inv[v.len() - 1 - i] = products[v.len() - 1 - i] * acc;
acc = tmp;
}

Ok(inv)
};

// compute vectors TS[i]/(T[i] + r) and 1/(W[i] + r)
let helper = |T: &[E::Scalar],
W: &[E::Scalar],
Expand All @@ -234,15 +208,15 @@ impl<E: Engine> MemorySumcheckInstance<E> {
|| {
rayon::join(
|| {
let inv = batch_invert(&T.par_iter().map(|e| *e + *r).collect::<Vec<_>>())?;
let inv = batch_invert(T.par_iter().map(|e| *e + *r).collect::<Vec<_>>())?;

// compute inv[i] * TS[i] in parallel
Ok(
zip_with!((inv.into_par_iter(), TS.par_iter()), |e1, e2| e1 * *e2)
.collect::<Vec<_>>(),
)
},
|| batch_invert(&W.par_iter().map(|e| *e + *r).collect::<Vec<_>>()),
|| batch_invert(W.par_iter().map(|e| *e + *r).collect::<Vec<_>>()),
)
},
|| {
Expand Down

1 comment on commit 6089294

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Table of Contents

Overview

This benchmark report shows the Arecibo GPU benchmarks.
NVIDIA L4
Intel(R) Xeon(R) CPU @ 2.20GHz
32 vCPUs
125 GB RAM
Workflow run: https://github.com/lurk-lab/arecibo/actions/runs/8037209930

Benchmark Results

RecursiveSNARK-NIVC-2

ref=afb9486 ref=6089294
Prove-NumCons-6540 44.45 ms (✅ 1.00x) 44.35 ms (✅ 1.00x faster)
Verify-NumCons-6540 34.11 ms (✅ 1.00x) 34.12 ms (✅ 1.00x slower)
Prove-NumCons-1028888 328.10 ms (✅ 1.00x) 319.46 ms (✅ 1.03x faster)
Verify-NumCons-1028888 250.22 ms (✅ 1.00x) 250.92 ms (✅ 1.00x slower)

CompressedSNARK-NIVC-Commitments-2

ref=afb9486 ref=6089294
Prove-NumCons-6540 10.61 s (✅ 1.00x) 10.67 s (✅ 1.01x slower)
Verify-NumCons-6540 50.95 ms (✅ 1.00x) 50.50 ms (✅ 1.01x faster)
Prove-NumCons-1028888 53.14 s (✅ 1.00x) 52.25 s (✅ 1.02x faster)
Verify-NumCons-1028888 50.87 ms (✅ 1.00x) 50.78 ms (✅ 1.00x faster)

Made with criterion-table

Please sign in to comment.