Skip to content

Commit

Permalink
reduce HyperNova proving time, reduce computation in Nova&Mova comput…
Browse files Browse the repository at this point in the history
…e_T method (#183)

* reduce ~65% proving time in HyperNova by removing the not-needed cs.finalize calls

* update compute_T (Nova & Mova) using Mova optimized approach from Mova's section 5.2 (https://eprint.iacr.org/2024/1220.pdf)
  • Loading branch information
arnaucube authored Dec 17, 2024
1 parent 83d1383 commit 659b909
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 25 deletions.
7 changes: 6 additions & 1 deletion benches/hypernova.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use criterion::*;
use pprof::criterion::{Output, PProfProfiler};

use ark_bn254::{constraints::GVar as bn_GVar, Fr as bn_Fr, G1Projective as bn_G};
use ark_grumpkin::{constraints::GVar as grumpkin_GVar, Projective as grumpkin_G};
Expand Down Expand Up @@ -79,5 +80,9 @@ fn bench_hypernova_ivc(c: &mut Criterion) {
}
}

criterion_group!(benches, bench_hypernova_ivc);
criterion_group! {
name = benches;
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
targets = bench_hypernova_ivc
}
criterion_main!(benches);
7 changes: 6 additions & 1 deletion benches/protogalaxy.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use criterion::*;
use pprof::criterion::{Output, PProfProfiler};

use ark_bn254::{constraints::GVar as bn_GVar, Fr as bn_Fr, G1Projective as bn_G};
use ark_grumpkin::{constraints::GVar as grumpkin_GVar, Projective as grumpkin_G};
Expand Down Expand Up @@ -73,5 +74,9 @@ fn bench_protogalaxy_ivc(c: &mut Criterion) {
}
}

criterion_group!(benches, bench_protogalaxy_ivc);
criterion_group! {
name = benches;
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
targets = bench_protogalaxy_ivc
}
criterion_main!(benches);
12 changes: 10 additions & 2 deletions folding-schemes/src/folding/hypernova/circuits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,11 @@ where
Ok(ccs)
}

/// Returns the cs (ConstraintSystem) and the CCS out of the AugmentedFCircuit
/// Returns the cs (ConstraintSystem) and the CCS out of the AugmentedFCircuit.
/// Notice that in order to be able to internally call the `extract_r1cs` function, this method
/// calls the `cs.finalize` method which consumes a noticeable portion of the time. If the CCS
/// is not needed, directly generate the ConstraintSystem without calling the `finalize` method
/// will save computing time.
#[allow(clippy::type_complexity)]
pub fn compute_cs_ccs(
&self,
Expand Down Expand Up @@ -1429,7 +1433,11 @@ mod tests {
cf_U_i = cf_U_i1;
}

let (cs, _) = augmented_f_circuit.compute_cs_ccs()?;
let cs = ConstraintSystem::<Fr>::new_ref();
augmented_f_circuit
.clone()
.generate_constraints(cs.clone())?;
let cs = cs.into_inner().ok_or(Error::NoInnerConstraintSystem)?;
assert!(cs.is_satisfied()?);

let (r1cs_w_i1, r1cs_x_i1) = extract_w_x::<Fr>(&cs); // includes 1 and public inputs
Expand Down
11 changes: 8 additions & 3 deletions folding-schemes/src/folding/hypernova/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ark_crypto_primitives::sponge::{
use ark_ec::CurveGroup;
use ark_ff::{BigInteger, PrimeField};
use ark_r1cs_std::prelude::CurveVar;
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError};
use ark_std::{fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero};

Expand Down Expand Up @@ -427,15 +428,17 @@ where
cf_cmT: None,
};

let (cs, _) = augmented_f_circuit.compute_cs_ccs()?;
let cs = ConstraintSystem::<C1::ScalarField>::new_ref();
augmented_f_circuit.generate_constraints(cs.clone())?;
let cs = cs.into_inner().ok_or(Error::NoInnerConstraintSystem)?;

#[cfg(test)]
assert!(cs.is_satisfied()?);

let (r1cs_w_i1, r1cs_x_i1) = extract_w_x::<C1::ScalarField>(&cs); // includes 1 and public inputs

#[cfg(test)]
assert_eq!(r1cs_x_i1[0], augmented_f_circuit.x.unwrap());
assert_eq!(r1cs_x_i1[0], u_i1_x);

let r1cs_z = [
vec![C1::ScalarField::one()],
Expand Down Expand Up @@ -932,7 +935,9 @@ where
self.cf_U_i = cf_U_i1;
}

let (cs, _) = augmented_f_circuit.compute_cs_ccs()?;
let cs = ConstraintSystem::<C1::ScalarField>::new_ref();
augmented_f_circuit.generate_constraints(cs.clone())?;
let cs = cs.into_inner().ok_or(Error::NoInnerConstraintSystem)?;

#[cfg(test)]
assert!(cs.is_satisfied()?);
Expand Down
2 changes: 1 addition & 1 deletion folding-schemes/src/folding/nova/nifs/mova.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ where
// compute the cross terms
let z1: Vec<C::ScalarField> = [vec![U_i.u], U_i.x.to_vec(), W_i.W.to_vec()].concat();
let z2: Vec<C::ScalarField> = [vec![u_i.u], u_i.x.to_vec(), w_i.W.to_vec()].concat();
let T = NovaNIFS::<C, CS, T, H>::compute_T(r1cs, U_i.u, u_i.u, &z1, &z2)?;
let T = NovaNIFS::<C, CS, T, H>::compute_T(r1cs, U_i.u, u_i.u, &z1, &z2, &W_i.E, &w_i.E)?;

let n_vars: usize = log2(W_i.E.len()) as usize;
if log2(T.len()) as usize != n_vars {
Expand Down
32 changes: 15 additions & 17 deletions folding-schemes/src/folding/nova/nifs/nova.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ where
// compute the cross terms
let z1: Vec<C::ScalarField> = [vec![U_i.u], U_i.x.to_vec(), W_i.W.to_vec()].concat();
let z2: Vec<C::ScalarField> = [vec![u_i.u], u_i.x.to_vec(), w_i.W.to_vec()].concat();
let T = Self::compute_T(r1cs, U_i.u, u_i.u, &z1, &z2)?;
let T = Self::compute_T(r1cs, U_i.u, u_i.u, &z1, &z2, &W_i.E, &w_i.E)?;

// use r_T=0 since we don't need hiding property for cm(T)
let cmT = CS::commit(cs_prover_params, &T, &C::ScalarField::zero())?;
Expand Down Expand Up @@ -207,30 +207,28 @@ impl<C: CurveGroup, CS: CommitmentScheme<C, H>, T: Transcript<C::ScalarField>, c
where
C::ScalarField: Absorb,
{
/// compute_T: compute cross-terms T
/// compute_T: compute cross-terms T. We use the approach described in
/// [Mova](https://eprint.iacr.org/2024/1220.pdf)'s section 5.2.
pub fn compute_T(
r1cs: &R1CS<C::ScalarField>,
u1: C::ScalarField,
u2: C::ScalarField,
z1: &[C::ScalarField],
z2: &[C::ScalarField],
E1: &[C::ScalarField],
E2: &[C::ScalarField],
) -> Result<Vec<C::ScalarField>, Error> {
let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
let z = vec_add(z1, z2)?;

// this is parallelizable (for the future)
let Az1 = mat_vec_mul(&A, z1)?;
let Bz1 = mat_vec_mul(&B, z1)?;
let Cz1 = mat_vec_mul(&C, z1)?;
let Az2 = mat_vec_mul(&A, z2)?;
let Bz2 = mat_vec_mul(&B, z2)?;
let Cz2 = mat_vec_mul(&C, z2)?;

let Az1_Bz2 = hadamard(&Az1, &Bz2)?;
let Az2_Bz1 = hadamard(&Az2, &Bz1)?;
let u1Cz2 = vec_scalar_mul(&Cz2, &u1);
let u2Cz1 = vec_scalar_mul(&Cz1, &u2);

vec_sub(&vec_sub(&vec_add(&Az1_Bz2, &Az2_Bz1)?, &u1Cz2)?, &u2Cz1)
let Az = mat_vec_mul(&r1cs.A, &z)?;
let Bz = mat_vec_mul(&r1cs.B, &z)?;
let Cz = mat_vec_mul(&r1cs.C, &z)?;
let u = u1 + u2;
let uCz = vec_scalar_mul(&Cz, &u);
let AzBz = hadamard(&Az, &Bz)?;
let lhs = vec_sub(&AzBz, &uCz)?;
vec_sub(&vec_sub(&lhs, E1)?, E2)
}

pub fn compute_cyclefold_cmT(
Expand All @@ -248,7 +246,7 @@ where
let z2: Vec<C::ScalarField> = [vec![ci2.u], ci2.x.to_vec(), w2.W.to_vec()].concat();

// compute cross terms
let T = Self::compute_T(r1cs, ci1.u, ci2.u, &z1, &z2)?;
let T = Self::compute_T(r1cs, ci1.u, ci2.u, &z1, &z2, &w1.E, &w2.E)?;
// use r_T=0 since we don't need hiding property for cm(T)
let cmT = CS::commit(cs_prover_params, &T, &C::ScalarField::zero())?;
Ok((T, cmT))
Expand Down

0 comments on commit 659b909

Please sign in to comment.