Merge pull request #25 from vacp2p/nova-circom-bench

Nova circom bench
This commit is contained in:
Moudy
2024-03-04 10:07:45 +01:00
committed by GitHub
5 changed files with 255 additions and 23 deletions

View File

@@ -10,20 +10,19 @@ ark-std = { version = "0.3", features = ["print-trace"] }
ff = { version = "0.12.0", features = ["derive"]}
num-bigint = { version = "0.4", features = ["serde", "rand"] }
num-traits = "0.2.15"
#nova-scotia = {git = "https://github.com/oskarth/Nova-Scotia", branch="benchmark-logging"}
#nova-scotia = {path = "../../Nova-Scotia/"}
nova-scotia = { git = "https://github.com/privacy-scaling-explorations/Nova-Scotia", branch = "parallel_nova" }
#nova-scotia = {git = "https://github.com/oskarth/Nova-Scotia.git", branch="feat/r1cs-dual"}
nova-snark = {git = "https://github.com/privacy-scaling-explorations/Nova", branch="parallel_prover_bench"}
#nova-snark = { path = "../../Nova" }
#nova-snark = { version = "0.19.0" }
serde = "1.0"
serde_json = "1.0.85"
sha2 = "0.10.6"
wee_alloc = "0.4.5"
light-poseidon = { version = "*", git = "https://github.com/tyshkor/light-poseidon.git", branch = "hash_vec"}
ark-bn254 = "*"
ark-ff = "*"
ark-ff = "*"
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
[[bench]]
name = "poseidon"
harness = false

View File

@@ -13,4 +13,10 @@ One time:
Then:
`cargo run --example poseidon`
`cargo run --example poseidon`
## Usage
```bash
cargo bench
```

View File

@@ -0,0 +1,148 @@
use core::time::Duration;
use criterion::*;
use nova_scotia::{
circom::reader::load_r1cs, create_public_params, create_recursive_circuit, FileLocation, F1, G2,
};
use nova_snark::traits::Group;
use std::{collections::HashMap, env::current_dir};
criterion_group! {
name = recursive_snark;
config = Criterion::default().warm_up_time(Duration::from_millis(3000));
targets = bench_recursive_snark_proove, bench_recursive_snark_verify
}
criterion_main!(recursive_snark);
fn bench_recursive_snark_proove(c: &mut Criterion) {
let cases = vec![3, 10, 100];
let root = current_dir().unwrap();
// has to be generated by circom before running the code
let circuit_file = root.join("./examples/poseidon/circom/poseidon_test_nova.r1cs");
let r1cs = load_r1cs(&FileLocation::PathBuf(circuit_file));
// has to be generated by circom before running the code
let witness_generator_wasm =
root.join("./examples/poseidon/circom/poseidon_test_nova_js/poseidon_test_nova.wasm");
// Creating public parameters
let pp = create_public_params(r1cs.clone());
for k in cases {
let iteration_count = k;
let step_in_vector = vec![0, 1, 2, 3];
// We don't have any private inputs, so corresponding `HashMap`s are empty, thoough we still need to create and pass them
let mut private_inputs = Vec::new();
for _ in 0..iteration_count {
let private_input = HashMap::new();
private_inputs.push(private_input);
}
let start_public_input = step_in_vector
.into_iter()
.map(|x| F1::from(x))
.collect::<Vec<_>>();
let mut group = c.benchmark_group(format!("Nova-Circom-Poseidon-num-steps-{}", k));
group.sample_size(10);
group.bench_function("Prove", |b| {
b.iter(|| {
// create a recursive SNARK
create_recursive_circuit(
FileLocation::PathBuf(witness_generator_wasm.clone()),
r1cs.clone(),
private_inputs.clone(),
start_public_input.clone(),
&pp,
)
.unwrap();
})
});
group.finish();
}
}
fn bench_recursive_snark_verify(c: &mut Criterion) {
let cases = vec![3, 10, 100];
let root = current_dir().unwrap();
// has to be generated by circom before running the code
let circuit_file = root.join("./examples/poseidon/circom/poseidon_test_nova.r1cs");
let r1cs = load_r1cs(&FileLocation::PathBuf(circuit_file));
// has to be generated by circom before running the code
let witness_generator_wasm =
root.join("./examples/poseidon/circom/poseidon_test_nova_js/poseidon_test_nova.wasm");
let step_in_vector = vec![0, 1, 2, 3];
// Creating public parameters
let pp = create_public_params(r1cs.clone());
println!(
"Number of constraints per step (primary circuit): {}",
pp.num_constraints().0
);
println!(
"Number of constraints per step (secondary circuit): {}",
pp.num_constraints().1
);
println!(
"Number of variables per step (primary circuit): {}",
pp.num_variables().0
);
println!(
"Number of variables per step (secondary circuit): {}",
pp.num_variables().1
);
for k in cases {
let iteration_count = k;
// We don't have any private inputs, so corresponding `HashMap`s are empty, thoough we still need to create and pass them
let mut private_inputs = Vec::new();
for _ in 0..iteration_count {
let private_input = HashMap::new();
private_inputs.push(private_input);
}
let start_public_input = step_in_vector
.clone()
.into_iter()
.map(|x| F1::from(x))
.collect::<Vec<_>>();
// create a recursive SNARK
let recursive_snark = create_recursive_circuit(
FileLocation::PathBuf(witness_generator_wasm.clone()),
r1cs.clone(),
private_inputs.clone(),
start_public_input.clone(),
&pp,
)
.unwrap();
let z0_secondary = vec![<G2 as Group>::Scalar::zero()];
let mut group = c.benchmark_group(format!("Nova-Circom-Poseidon-num-steps-{}", k));
group.sample_size(10);
group.bench_function("Verify", |b| {
b.iter(|| {
let res = recursive_snark.verify(
&pp,
iteration_count,
start_public_input.clone(),
z0_secondary.clone(),
);
assert!(res.is_ok());
})
});
group.finish();
}
}

View File

@@ -21,10 +21,10 @@ extern crate wee_alloc;
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
/// Creates a recursive SNARK, that proves the recursive (cyclic) calculation, of 4 values using Poseidon hashing function
///
///
/// Panic
///
/// Code panics in case needed `poseidon_test_nova.r1cs` and/or `poseidon_test_nova.wasm` do no exist at specified paths
///
/// Code panics in case needed `poseidon_test_nova.r1cs` and/or `poseidon_test_nova.wasm` do no exist at specified paths
fn recursive_hashing(depth: usize) {
println! {"Using recursive depth: {:?} times depth_per_fold in circuit (default 10 or 100, check yourself! :D)", depth};

View File

@@ -1,14 +1,93 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
use ark_std::{end_timer, start_timer};
#[cfg(test)]
mod tests {
use super::*;
use std::{collections::HashMap, env, env::current_dir, time::Instant};
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
use nova_scotia::{
circom::{circuit::CircomCircuit, reader::load_r1cs},
create_public_params, create_recursive_circuit, FileLocation, F1, G1, G2, S1, S2,
};
// Ignore create_recursive_circuit
use nova_snark::{
traits::{circuit::TrivialTestCircuit, Group},
CompressedSNARK, RecursiveSNARK,
};
extern crate wee_alloc;
// NOTE: Supposedly this helps against segfaults, but seems intermittent
// Consider trying jemallocator (?)
// Alternatively, just run larger benchmarks on a server (with C++ version)
//
// Use `wee_alloc` as the global allocator.
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
type C1 = CircomCircuit<<G1 as Group>::Scalar>;
type C2 = TrivialTestCircuit<<G2 as Group>::Scalar>;
/// Creates a recursive SNARK, that proves the recursive (cyclic) calculation, of 4 values using Poseidon hashing function
///
/// Panic
///
/// Code panics in case needed `poseidon_test_nova.r1cs` and/or `poseidon_test_nova.wasm` do no exist at specified paths
pub fn recursive_hashing_proove(depth: usize) -> RecursiveSNARK<G1, G2, C1, C2> {
println! {"Using recursive depth: {:?} times depth_per_fold in circuit (default 10 or 100, check yourself! :D)", depth};
let iteration_count = depth;
let root = current_dir().unwrap();
// has to be generated by circom before running the code
let circuit_file = root.join("./examples/poseidon/circom/poseidon_test_nova.r1cs");
let r1cs = load_r1cs(&FileLocation::PathBuf(circuit_file));
// has to be generated by circom before running the code
let witness_generator_wasm =
root.join("./examples/poseidon/circom/poseidon_test_nova_js/poseidon_test_nova.wasm");
let step_in_vector = vec![0, 1, 2, 3];
// We don't have any private inputs, so corresponding `HashMap`s are empty, thoough we still need to create and pass them
let mut private_inputs = Vec::new();
for _ in 0..iteration_count {
let private_input = HashMap::new();
private_inputs.push(private_input);
}
let start_public_input = step_in_vector
.into_iter()
.map(|x| F1::from(x))
.collect::<Vec<_>>();
// Creating public parameters
let pp = create_public_params(r1cs.clone());
println!(
"Number of constraints per step (primary circuit): {}",
pp.num_constraints().0
);
println!(
"Number of constraints per step (secondary circuit): {}",
pp.num_constraints().1
);
println!(
"Number of variables per step (primary circuit): {}",
pp.num_variables().0
);
println!(
"Number of variables per step (secondary circuit): {}",
pp.num_variables().1
);
// create a recursive SNARK
let recursive_snark = create_recursive_circuit(
FileLocation::PathBuf(witness_generator_wasm),
r1cs,
private_inputs,
start_public_input.clone(),
&pp,
)
.unwrap();
recursive_snark
}