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<::Scalar>, + TrivialTestCircuit<::Scalar>, + >::setup( + TrivialTestCircuit { + _p: Default::default(), + }, + TrivialTestCircuit { + _p: Default::default(), + }, + ); + + // produce a recursive SNARK + let res = RecursiveSNARK::prove( + &pp, + num_steps, + ::Scalar::zero(), + ::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(::Scalar::zero()), + black_box(::Scalar::zero()), + ) + .is_ok()); + }) + }); + + group.finish(); +} + +#[derive(Clone, Debug)] +struct TrivialTestCircuit { + _p: PhantomData, +} + +impl StepCircuit for TrivialTestCircuit +where + F: PrimeField, +{ + fn synthesize>( + &self, + _cs: &mut CS, + z: AllocatedNum, + ) -> Result, 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<::Scalar>, + TrivialTestCircuit<::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(::Scalar::zero()), + black_box(::Scalar::zero()), + ) + .is_ok()); + }) + }); + let res = RecursiveSNARK::prove( + &pp, + num_steps, + ::Scalar::zero(), + ::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(::Scalar::zero()), + black_box(::Scalar::zero()), + ) + .is_ok()); + }); + }); + group.finish(); +} + +#[derive(Clone, Debug)] +struct TrivialTestCircuit { + _p: PhantomData, +} + +impl StepCircuit for TrivialTestCircuit +where + F: PrimeField, +{ + fn synthesize>( + &self, + _cs: &mut CS, + z: AllocatedNum, + ) -> Result, SynthesisError> { + Ok(z) + } + + fn compute(&self, z: &F) -> F { + *z + } +}