Nova/benches/recursive-snark.rs
benches/recursive-snark.rsRaw
1#![allow(non_snake_case)]
2
3use nova_snark::{
4 traits::{Group, StepCircuit},
5 PublicParams, RecursiveSNARK,
6};
7
8type G1 = pasta_curves::pallas::Point;
9type G2 = pasta_curves::vesta::Point;
10
11#[derive(Clone, Debug)]
12struct TrivialTestCircuit<F: PrimeField> {
13 _p: PhantomData<F>,
14}
15
16impl<F> StepCircuit<F> for TrivialTestCircuit<F>
17where
18 F: PrimeField,
19{
20 fn synthesize<CS: ConstraintSystem<F>>(
21 &self,
22 _cs: &mut CS,
23 z: AllocatedNum<F>,
24 ) -> Result<AllocatedNum<F>, SynthesisError> {
25 Ok(z)
26 }
27
28 fn compute(&self, z: &F) -> F {
29 *z
30 }
31}
32
33type C1 = TrivialTestCircuit<<G1 as Group>::Scalar>;
34type C2 = TrivialTestCircuit<<G2 as Group>::Scalar>;
35
36use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
37use core::marker::PhantomData;
38use criterion::*;
39use ff::PrimeField;
40use std::time::Duration;
41
42fn recursive_snark_benchmark(c: &mut Criterion) {
43 let num_samples = 10;
44 bench_recursive_snark(c, num_samples);
45}
46
47fn set_duration() -> Criterion {
48 Criterion::default().warm_up_time(Duration::from_millis(3000))
49}
50
51criterion_group! {
52name = recursive_snark;
53config = set_duration();
54targets = recursive_snark_benchmark
55}
56
57criterion_main!(recursive_snark);
58
59fn bench_recursive_snark(c: &mut Criterion, num_samples: usize) {
60 let mut group = c.benchmark_group("RecursiveSNARK".to_string());
61 group.sample_size(num_samples);
62
63 // Produce public parameters
64 let pp = PublicParams::<G1, G2, C1, C2>::setup(
65 TrivialTestCircuit {
66 _p: Default::default(),
67 },
68 TrivialTestCircuit {
69 _p: Default::default(),
70 },
71 );
72
73 // Bench time to produce a recursive SNARK;
74 // we execute a certain number of warm-up steps since executing
75 // the first step is cheaper than other steps owing to the presence of
76 // a lot of zeros in the satisfying assignment
77 let num_warmup_steps = 10;
78 let mut recursive_snark: Option<RecursiveSNARK<G1, G2, C1, C2>> = None;
79
80 for i in 0..num_warmup_steps {
81 let res = RecursiveSNARK::prove_step(
82 &pp,
83 recursive_snark,
84 TrivialTestCircuit {
85 _p: Default::default(),
86 },
87 TrivialTestCircuit {
88 _p: Default::default(),
89 },
90 <G1 as Group>::Scalar::one(),
91 <G2 as Group>::Scalar::zero(),
92 );
93 assert!(res.is_ok());
94 let recursive_snark_unwrapped = res.unwrap();
95
96 // verify the recursive snark at each step of recursion
97 let res = recursive_snark_unwrapped.verify(
98 &pp,
99 i + 1,
100 <G1 as Group>::Scalar::one(),
101 <G2 as Group>::Scalar::zero(),
102 );
103 assert!(res.is_ok());
104
105 // set the running variable for the next iteration
106 recursive_snark = Some(recursive_snark_unwrapped);
107 }
108
109 group.bench_function("Prove", |b| {
110 b.iter(|| {
111 // produce a recursive SNARK for a step of the recursion
112 assert!(RecursiveSNARK::prove_step(
113 black_box(&pp),
114 black_box(recursive_snark.clone()),
115 black_box(TrivialTestCircuit {
116 _p: Default::default(),
117 }),
118 black_box(TrivialTestCircuit {
119 _p: Default::default(),
120 }),
121 black_box(<G1 as Group>::Scalar::zero()),
122 black_box(<G2 as Group>::Scalar::zero()),
123 )
124 .is_ok());
125 })
126 });
127
128 let recursive_snark = recursive_snark.unwrap();
129
130 // Benchmark the verification time
131 let name = "Verify";
132 group.bench_function(name, |b| {
133 b.iter(|| {
134 assert!(black_box(&recursive_snark)
135 .verify(
136 black_box(&pp),
137 black_box(num_warmup_steps),
138 black_box(<G1 as Group>::Scalar::zero()),
139 black_box(<G2 as Group>::Scalar::zero()),
140 )
141 .is_ok());
142 });
143 });
144 group.finish();
145}