arnaucube
arnaucube/NovaPublic Self-hosted repository
Nova/benches/compressed-snark.rs
benches/compressed-snark.rsRaw
  1#![allow(non_snake_case)]
  2
  3use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
  4use core::marker::PhantomData;
  5use criterion::*;
  6use ff::PrimeField;
  7use nova_snark::{
  8  traits::{
  9    circuit::{StepCircuit, TrivialTestCircuit},
 10    Group,
 11  },
 12  CompressedSNARK, PublicParams, RecursiveSNARK,
 13};
 14use std::time::Duration;
 15
 16type G1 = pasta_curves::pallas::Point;
 17type G2 = pasta_curves::vesta::Point;
 18type S1 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G1>;
 19type S2 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G2>;
 20type C1 = NonTrivialTestCircuit<<G1 as Group>::Scalar>;
 21type C2 = TrivialTestCircuit<<G2 as Group>::Scalar>;
 22
 23criterion_group! {
 24name = compressed_snark;
 25config = Criterion::default().warm_up_time(Duration::from_millis(3000));
 26targets = bench_compressed_snark
 27}
 28
 29criterion_main!(compressed_snark);
 30
 31fn bench_compressed_snark(c: &mut Criterion) {
 32  let num_samples = 10;
 33
 34  // we vary the number of constraints in the step circuit
 35  for &log_num_cons_in_step_circuit in [0, 15, 16, 17, 18, 19, 20].iter() {
 36    let num_cons = 1 << log_num_cons_in_step_circuit;
 37
 38    let mut group = c.benchmark_group(format!("RecursiveSNARK-StepCircuitSize-{}", num_cons));
 39    group.sample_size(num_samples);
 40
 41    // Produce public parameters
 42    let pp = PublicParams::<G1, G2, C1, C2>::setup(
 43      NonTrivialTestCircuit::new(num_cons),
 44      TrivialTestCircuit::default(),
 45    );
 46
 47    // produce a recursive SNARK
 48    let num_steps = 3;
 49    let mut recursive_snark: Option<RecursiveSNARK<G1, G2, C1, C2>> = None;
 50
 51    for i in 0..num_steps {
 52      let res = RecursiveSNARK::prove_step(
 53        &pp,
 54        recursive_snark,
 55        NonTrivialTestCircuit::new(num_cons),
 56        TrivialTestCircuit::default(),
 57        <G1 as Group>::Scalar::one(),
 58        <G2 as Group>::Scalar::one(),
 59      );
 60      assert!(res.is_ok());
 61      let recursive_snark_unwrapped = res.unwrap();
 62
 63      // verify the recursive snark at each step of recursion
 64      let res = recursive_snark_unwrapped.verify(
 65        &pp,
 66        i + 1,
 67        <G1 as Group>::Scalar::one(),
 68        <G2 as Group>::Scalar::one(),
 69      );
 70      assert!(res.is_ok());
 71
 72      // set the running variable for the next iteration
 73      recursive_snark = Some(recursive_snark_unwrapped);
 74    }
 75
 76    // Bench time to produce a compressed SNARK
 77    let recursive_snark = recursive_snark.unwrap();
 78    group.bench_function("Prove", |b| {
 79      b.iter(|| {
 80        assert!(CompressedSNARK::<_, _, _, _, S1, S2>::prove(
 81          black_box(&pp),
 82          black_box(&recursive_snark)
 83        )
 84        .is_ok());
 85      })
 86    });
 87    let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark);
 88    assert!(res.is_ok());
 89    let compressed_snark = res.unwrap();
 90
 91    // Benchmark the verification time
 92    group.bench_function("Verify", |b| {
 93      b.iter(|| {
 94        assert!(black_box(&compressed_snark)
 95          .verify(
 96            black_box(&pp),
 97            black_box(num_steps),
 98            black_box(<G1 as Group>::Scalar::one()),
 99            black_box(<G2 as Group>::Scalar::one()),
100          )
101          .is_ok());
102      })
103    });
104
105    group.finish();
106  }
107}
108
109#[derive(Clone, Debug, Default)]
110struct NonTrivialTestCircuit<F: PrimeField> {
111  num_cons: usize,
112  _p: PhantomData<F>,
113}
114
115impl<F> NonTrivialTestCircuit<F>
116where
117  F: PrimeField,
118{
119  pub fn new(num_cons: usize) -> Self {
120    Self {
121      num_cons,
122      _p: Default::default(),
123    }
124  }
125}
126impl<F> StepCircuit<F> for NonTrivialTestCircuit<F>
127where
128  F: PrimeField,
129{
130  fn synthesize<CS: ConstraintSystem<F>>(
131    &self,
132    cs: &mut CS,
133    z: AllocatedNum<F>,
134  ) -> Result<AllocatedNum<F>, SynthesisError> {
135    // Consider a an equation: `x^2 = y`, where `x` and `y` are respectively the input and output.
136    let mut x = z;
137    let mut y = x.clone();
138    for i in 0..self.num_cons {
139      y = x.square(cs.namespace(|| format!("x_sq_{}", i)))?;
140      x = y.clone();
141    }
142    Ok(y)
143  }
144
145  fn compute(&self, z: &F) -> F {
146    let mut x = *z;
147    let mut y = x;
148    for _i in 0..self.num_cons {
149      y = x * x;
150      x = y;
151    }
152    y
153  }
154}