From 81b12232fed0d18a78b84d3339839f12dfdc9283 Mon Sep 17 00:00:00 2001
From: iontzialla <iontzialla@gmail.com>
Date: Tue, 14 Jun 2022 15:32:44 -0400
Subject: [PATCH] Add benches (#79)

* add benches

* fix error

* put snark in a black_box when benchmarking verification time

* fix error in benches
---
 Cargo.toml                  |  11 ++++
 benches/compressed-snark.rs | 122 ++++++++++++++++++++++++++++++++++++
 benches/recursive-snark.rs  | 116 ++++++++++++++++++++++++++++++++++
 3 files changed, 249 insertions(+)
 create mode 100644 benches/compressed-snark.rs
 create mode 100644 benches/recursive-snark.rs

diff --git a/Cargo.toml b/Cargo.toml
index f0db640..99e0a0b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,6 +33,17 @@ serde = { version = "1.0", features = ["derive"] }
 bincode = "1.2.1"
 flate2 = "1.0"
 
+[dev-dependencies]
+criterion = "0.3.1"
+
+[[bench]]
+name = "compressed-snark"
+harness = false
+
+[[bench]]
+name = "recursive-snark"
+harness = false
+
 [features]
 default = [ "bellperson/default", "bellperson-nonnative/default", "neptune/default" ]
 wasm = [ "bellperson/wasm", "bellperson-nonnative/wasm", "neptune/wasm" ]
diff --git a/benches/compressed-snark.rs b/benches/compressed-snark.rs
new file mode 100644
index 0000000..bb600fd
--- /dev/null
+++ b/benches/compressed-snark.rs
@@ -0,0 +1,122 @@
+#![allow(non_snake_case)]
+
+extern crate flate2;
+
+//use flate2::{write::ZlibEncoder, Compression};
+use nova_snark::{
+  traits::{Group, StepCircuit},
+  CompressedSNARK, PublicParams, RecursiveSNARK,
+};
+
+type G1 = pasta_curves::pallas::Point;
+type G2 = pasta_curves::vesta::Point;
+
+use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
+use core::marker::PhantomData;
+use criterion::*;
+use ff::PrimeField;
+use std::time::Duration;
+
+fn compressed_snark_benchmark(c: &mut Criterion) {
+  let num_samples = 10;
+  let num_steps = 3;
+  bench_compressed_snark(c, num_samples, num_steps);
+}
+
+fn set_duration() -> Criterion {
+  Criterion::default().warm_up_time(Duration::from_millis(3000))
+}
+
+criterion_group! {
+name = compressed_snark;
+config = set_duration();
+targets = compressed_snark_benchmark
+}
+
+criterion_main!(compressed_snark);
+
+fn bench_compressed_snark(c: &mut Criterion, num_samples: usize, num_steps: usize) {
+  let mut group = c.benchmark_group("CompressedSNARK");
+  group.sample_size(num_samples);
+  // Produce public parameters
+  let pp = PublicParams::<
+    G1,
+    G2,
+    TrivialTestCircuit<<G1 as Group>::Scalar>,
+    TrivialTestCircuit<<G2 as Group>::Scalar>,
+  >::setup(
+    TrivialTestCircuit {
+      _p: Default::default(),
+    },
+    TrivialTestCircuit {
+      _p: Default::default(),
+    },
+  );
+
+  // produce a recursive SNARK
+  let res = RecursiveSNARK::prove(
+    &pp,
+    num_steps,
+    <G1 as Group>::Scalar::zero(),
+    <G2 as Group>::Scalar::zero(),
+  );
+  assert!(res.is_ok());
+  let recursive_snark = res.unwrap();
+  // Bench time to produce a compressed SNARK
+  group.bench_function("Prove", |b| {
+    b.iter(|| {
+      assert!(CompressedSNARK::prove(black_box(&pp), black_box(&recursive_snark)).is_ok());
+    })
+  });
+  let res = CompressedSNARK::prove(&pp, &recursive_snark);
+  assert!(res.is_ok());
+  let compressed_snark = res.unwrap();
+
+  // Output the proof size
+  //let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
+  //bincode::serialize_into(&mut encoder, &compressed_snark).unwrap();
+  //let proof_encoded = encoder.finish().unwrap();
+  //println!(
+  //  "ProofSize: {} B",
+  //  proof_encoded.len(),
+  //);
+
+  // Benchmark the verification time
+  let name = "Verify";
+  group.bench_function(name, |b| {
+    b.iter(|| {
+      assert!(black_box(&compressed_snark)
+        .verify(
+          black_box(&pp),
+          black_box(num_steps),
+          black_box(<G1 as Group>::Scalar::zero()),
+          black_box(<G2 as Group>::Scalar::zero()),
+        )
+        .is_ok());
+    })
+  });
+
+  group.finish();
+}
+
+#[derive(Clone, Debug)]
+struct TrivialTestCircuit<F: PrimeField> {
+  _p: PhantomData<F>,
+}
+
+impl<F> StepCircuit<F> for TrivialTestCircuit<F>
+where
+  F: PrimeField,
+{
+  fn synthesize<CS: ConstraintSystem<F>>(
+    &self,
+    _cs: &mut CS,
+    z: AllocatedNum<F>,
+  ) -> Result<AllocatedNum<F>, SynthesisError> {
+    Ok(z)
+  }
+
+  fn compute(&self, z: &F) -> F {
+    *z
+  }
+}
diff --git a/benches/recursive-snark.rs b/benches/recursive-snark.rs
new file mode 100644
index 0000000..dcda2bf
--- /dev/null
+++ b/benches/recursive-snark.rs
@@ -0,0 +1,116 @@
+#![allow(non_snake_case)]
+
+extern crate flate2;
+
+//use flate2::{write::ZlibEncoder, Compression};
+use nova_snark::{
+  traits::{Group, StepCircuit},
+  PublicParams, RecursiveSNARK,
+};
+
+type G1 = pasta_curves::pallas::Point;
+type G2 = pasta_curves::vesta::Point;
+
+use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
+use core::marker::PhantomData;
+use criterion::*;
+use ff::PrimeField;
+use std::time::Duration;
+
+fn recursive_snark_benchmark(c: &mut Criterion) {
+  let num_samples = 10;
+  for num_steps in 1..10 {
+    bench_recursive_snark(c, num_samples, num_steps);
+  }
+}
+
+fn set_duration() -> Criterion {
+  Criterion::default().warm_up_time(Duration::from_millis(3000))
+}
+
+criterion_group! {
+name = recursive_snark;
+config = set_duration();
+targets = recursive_snark_benchmark
+}
+
+criterion_main!(recursive_snark);
+
+fn bench_recursive_snark(c: &mut Criterion, num_samples: usize, num_steps: usize) {
+  let mut group = c.benchmark_group(format!("RecursiveSNARK-NumSteps-{}", num_steps));
+  group.sample_size(num_samples);
+  // Produce public parameters
+  let pp = PublicParams::<
+    G1,
+    G2,
+    TrivialTestCircuit<<G1 as Group>::Scalar>,
+    TrivialTestCircuit<<G2 as Group>::Scalar>,
+  >::setup(
+    TrivialTestCircuit {
+      _p: Default::default(),
+    },
+    TrivialTestCircuit {
+      _p: Default::default(),
+    },
+  );
+  // Bench time to produce a recursive SNARK
+  group.bench_function("Prove", |b| {
+    b.iter(|| {
+      // produce a recursive SNARK
+      assert!(RecursiveSNARK::prove(
+        black_box(&pp),
+        black_box(num_steps),
+        black_box(<G1 as Group>::Scalar::zero()),
+        black_box(<G2 as Group>::Scalar::zero()),
+      )
+      .is_ok());
+    })
+  });
+  let res = RecursiveSNARK::prove(
+    &pp,
+    num_steps,
+    <G1 as Group>::Scalar::zero(),
+    <G2 as Group>::Scalar::zero(),
+  );
+  assert!(res.is_ok());
+  let recursive_snark = res.unwrap();
+
+  // TODO: Output the proof size
+  // Benchmark the verification time
+  let name = "Verify";
+  group.bench_function(name, |b| {
+    b.iter(|| {
+      assert!(black_box(&recursive_snark)
+        .verify(
+          black_box(&pp),
+          black_box(num_steps),
+          black_box(<G1 as Group>::Scalar::zero()),
+          black_box(<G2 as Group>::Scalar::zero()),
+        )
+        .is_ok());
+    });
+  });
+  group.finish();
+}
+
+#[derive(Clone, Debug)]
+struct TrivialTestCircuit<F: PrimeField> {
+  _p: PhantomData<F>,
+}
+
+impl<F> StepCircuit<F> for TrivialTestCircuit<F>
+where
+  F: PrimeField,
+{
+  fn synthesize<CS: ConstraintSystem<F>>(
+    &self,
+    _cs: &mut CS,
+    z: AllocatedNum<F>,
+  ) -> Result<AllocatedNum<F>, SynthesisError> {
+    Ok(z)
+  }
+
+  fn compute(&self, z: &F) -> F {
+    *z
+  }
+}