From a101da56abf25a5b5de09756a8c063f0e50a6510 Mon Sep 17 00:00:00 2001 From: M Alghazwi Date: Mon, 6 Jan 2025 14:14:56 +0100 Subject: [PATCH] add benchmark impl for tree recursion approach2 --- workflow/Cargo.toml | 8 +- .../{recursion.rs => simple_recursion.rs} | 1 + workflow/benches/tree_recursion.rs | 90 ----------- workflow/benches/tree_recursion_approach1.rs | 87 ++++++++++ workflow/benches/tree_recursion_approach2.rs | 152 ++++++++++++++++++ 5 files changed, 246 insertions(+), 92 deletions(-) rename workflow/benches/{recursion.rs => simple_recursion.rs} (98%) delete mode 100644 workflow/benches/tree_recursion.rs create mode 100644 workflow/benches/tree_recursion_approach1.rs create mode 100644 workflow/benches/tree_recursion_approach2.rs diff --git a/workflow/Cargo.toml b/workflow/Cargo.toml index b7aebc1..ed517fa 100644 --- a/workflow/Cargo.toml +++ b/workflow/Cargo.toml @@ -47,11 +47,15 @@ name = "sample_cells" harness = false [[bench]] -name = "recursion" +name = "simple_recursion" harness = false [[bench]] -name = "tree_recursion" +name = "tree_recursion_approach1" +harness = false + +[[bench]] +name = "tree_recursion_approach2" harness = false [[bench]] diff --git a/workflow/benches/recursion.rs b/workflow/benches/simple_recursion.rs similarity index 98% rename from workflow/benches/recursion.rs rename to workflow/benches/simple_recursion.rs index f4266c9..1c6990f 100644 --- a/workflow/benches/recursion.rs +++ b/workflow/benches/simple_recursion.rs @@ -9,6 +9,7 @@ use proof_input::params::{D, C, F, Params, TestParams}; use proof_input::gen_input::{build_circuit, prove_circuit}; /// Benchmark for building, proving, and verifying the Plonky2 recursion circuit. +/// Simple recursion approach - verify N proofs in-circuit fn bench_recursion(c: &mut Criterion) { // num of inner proofs let num_of_inner_proofs = 4; diff --git a/workflow/benches/tree_recursion.rs b/workflow/benches/tree_recursion.rs deleted file mode 100644 index 677a26c..0000000 --- a/workflow/benches/tree_recursion.rs +++ /dev/null @@ -1,90 +0,0 @@ -use criterion::{Criterion, criterion_group, criterion_main}; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData}; -use plonky2::plonk::config::GenericConfig; -use plonky2::plonk::proof::ProofWithPublicInputs; -use codex_plonky2_circuits::circuits::sample_cells::SampleCircuitInput; -use codex_plonky2_circuits::recursion::sampling_inner_circuit::SamplingRecursion; -use codex_plonky2_circuits::recursion::tree_recursion::{NodeCircuit, TreeRecursion}; -use proof_input::params::{C, D, F, TestParams}; -use proof_input::gen_input::gen_testing_circuit_input; - -fn get_m_default_circ_input() -> [SampleCircuitInput; M]{ - let mut params = TestParams::default(); - params.n_samples = 10; - let one_circ_input = gen_testing_circuit_input::(¶ms); - let circ_input: [SampleCircuitInput; M] = (0..M) - .map(|_| one_circ_input.clone()) - .collect::>() - .try_into().unwrap(); - circ_input -} - -/// Benchmark for building, proving, and verifying the Plonky2 tree recursion circuit. -fn bench_tree_recursion(c: &mut Criterion) { - - const M: usize = 1; - const N: usize = 2; - - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - // Circuit that does the sampling - let inner_sampling_circuit = SamplingRecursion::default(); - - let mut cyclic_circ = NodeCircuit::<_,M,N>::new(inner_sampling_circuit); - let mut tree_circ = TreeRecursion::new(cyclic_circ); - let circ_input = get_m_default_circ_input::(); - - // // get proofs - // let mut proofs_with_pi = vec![]; - // for i in 0..num_of_inner_proofs{ - // proofs_with_pi.push(prove_circuit(&data, &pw).unwrap()); - // } - // let vd = data.verifier_data(); - - let mut group = c.benchmark_group("bench simple tree recursion"); - let mut agg_proof_with_pis: Option> = None; - let mut agg_vd: Option> = None; - - // Benchmark the Circuit Building Phase - group.bench_function("build", |b| { - b.iter(|| { - let mut cyclic_circ = NodeCircuit::<_,M,N>::new(inner_sampling_circuit.clone()); - let mut tree_circ = TreeRecursion::new(cyclic_circ); - tree_circ.build(); - }) - }); - - // let proof = agg_proof_with_pis.unwrap(); - // println!("Proof size: {} bytes", proof.to_bytes().len()); - - let mut proof: Option> = None; - - // Benchmark the Circuit prove Phase - group.bench_function("prove", |b| { - b.iter(|| { - proof = Some(tree_circ.prove(&circ_input,None, true).unwrap()); - }) - }); - - // let proof = tree_circ.prove(&circ_input,None, true)?; - - // Benchmark the Verifying Phase - let loc_vd = agg_vd.unwrap(); - group.bench_function("Verify Proof", |b| { - b.iter(|| { - tree_circ.verify_proof(proof.unwrap()).expect("Failed to verify proof"); - }) - }); - - group.finish(); -} - -/// Criterion benchmark group -criterion_group!{ - name = recursion; - config = Criterion::default().sample_size(3); - targets = bench_tree_recursion -} -criterion_main!(recursion); diff --git a/workflow/benches/tree_recursion_approach1.rs b/workflow/benches/tree_recursion_approach1.rs new file mode 100644 index 0000000..cc0a763 --- /dev/null +++ b/workflow/benches/tree_recursion_approach1.rs @@ -0,0 +1,87 @@ +use anyhow::anyhow; +use criterion::{Criterion, criterion_group, criterion_main}; +use plonky2::plonk::config::GenericConfig; +use plonky2::plonk::proof::ProofWithPublicInputs; +use codex_plonky2_circuits::recursion::sampling_inner_circuit::SamplingRecursion; +use codex_plonky2_circuits::recursion::tree_recursion::{NodeCircuit, TreeRecursion}; +use codex_plonky2_circuits::recursion::params::{C, D, F}; +use proof_input::gen_input::get_m_default_circ_input; + + +/// Benchmark for building, proving, and verifying the approach1 Plonky2 tree recursion circuit. +fn bench_tree_recursion(c: &mut Criterion) { + + let mut group = c.benchmark_group("bench tree recursion - approach 1"); + + let inner_sampling_circuit = SamplingRecursion::default(); + + let node_circ = NodeCircuit::<_,M,N>::new(inner_sampling_circuit); + let mut tree_circ = TreeRecursion::new(node_circ); + let circ_input = get_m_default_circ_input::(); + + // Building Phase + group.bench_function("build", |b| { + b.iter(|| { + tree_circ.build(); + }) + }); + + let mut proof: Option> = None; + + // prove Phase + group.bench_function("prove with leaf only", |b| { + b.iter(|| { + proof = Some(tree_circ.prove(&circ_input,None, true).unwrap()); + }) + }); + + // Verifying Phase for proof with leaf + group.bench_function("Verify proof with only leaf", |b| { + b.iter(|| { + tree_circ.verify_proof(proof.clone().unwrap()).expect("Failed to verify proof"); + }) + }); + + // make N node proofs + let node_proofs: [ProofWithPublicInputs; N] = (0..N) + .map(|_| { + proof.clone().unwrap() + }) + .collect::>() + .try_into() + .map_err(|_| anyhow!("Expected exactly M inner circuits")).unwrap(); + + // prove Phase for node leaf and node proofs + group.bench_function("prove with leaf and node", |b| { + b.iter(|| { + proof = Some(tree_circ.prove(&circ_input,Some(node_proofs.clone()), true).unwrap()); + }) + }); + + // Verifying Phase for node leaf and node proofs + group.bench_function("Verify Proof with leaf and node proofs", |b| { + b.iter(|| { + tree_circ.verify_proof(proof.clone().unwrap()).expect("Failed to verify proof"); + }) + }); + + // print circuit size + let tree_common_data = tree_circ.node_circ.cyclic_circuit_data.unwrap().common; + println!("Circuit size (degree bits): {:?}", tree_common_data.degree_bits() ); + + group.finish(); +} + +fn bench_tree_recursion_approach1(c: &mut Criterion){ + const M: usize = 1; + const N: usize = 2; + bench_tree_recursion::(c); +} + +/// Criterion benchmark group +criterion_group!{ + name = recursion; + config = Criterion::default().sample_size(10); + targets = bench_tree_recursion_approach1 +} +criterion_main!(recursion); diff --git a/workflow/benches/tree_recursion_approach2.rs b/workflow/benches/tree_recursion_approach2.rs new file mode 100644 index 0000000..4aa3d40 --- /dev/null +++ b/workflow/benches/tree_recursion_approach2.rs @@ -0,0 +1,152 @@ +use criterion::{Criterion, criterion_group, criterion_main}; +use plonky2::iop::witness::PartialWitness; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData}; +use plonky2::plonk::config::GenericConfig; +use plonky2::plonk::proof::ProofWithPublicInputs; +use codex_plonky2_circuits::circuits::params::CircuitParams; +use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit, SampleCircuitInput}; +use codex_plonky2_circuits::recursion::leaf_circuit::{LeafCircuit, LeafInput}; +use codex_plonky2_circuits::recursion::sampling_inner_circuit::SamplingRecursion; +use codex_plonky2_circuits::recursion::tree_recursion2::{NodeCircuit, TreeRecursion}; +use codex_plonky2_circuits::recursion::params::{C, D, F}; +use proof_input::gen_input::gen_testing_circuit_input; +use proof_input::params::TestParams; + + +/// Benchmark for building, proving, and verifying the Plonky2 tree recursion circuit. +fn bench_tree_recursion(c: &mut Criterion){ + + let mut group = c.benchmark_group("bench tree recursion - approach 2"); + + //------------ sampling inner circuit ---------------------- + // Circuit that does the sampling - default input + let config = CircuitConfig::standard_recursion_config(); + let mut sampling_builder = CircuitBuilder::::new(config); + let mut params = TestParams::default(); + let one_circ_input = gen_testing_circuit_input::(¶ms); + let samp_circ = SampleCircuit::::new(CircuitParams::default()); + let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder); + // get generate a sampling proof + let mut pw = PartialWitness::::new(); + samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input); + let inner_data = sampling_builder.build::(); + let inner_proof = inner_data.prove(pw.clone()).unwrap(); + + // Building Phase + group.bench_function("build inner circuit", |b| { + b.iter(|| { + let config = CircuitConfig::standard_recursion_config(); + let mut sampling_builder = CircuitBuilder::::new(config); + let _inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder); + sampling_builder.build::(); + }) + }); + + // Proving Phase + group.bench_function("prove inner circuit", |b| { + b.iter(|| { + let _inner_proof = inner_data.prove(pw.clone()); + }) + }); + + println!("inner circuit - Circuit size (degree bits): {:?}", inner_data.common.degree_bits() ); + println!("inner proof - num of public input = {}", inner_proof.public_inputs.len()); + + // ------------------- leaf -------------------- + // leaf circuit that verifies the sampling proof + let inner_circ = SamplingRecursion::default(); + let leaf_circuit = LeafCircuit::new(inner_circ); + + let leaf_in = LeafInput{ + inner_proof, + verifier_data: inner_data.verifier_data(), + }; + let config = CircuitConfig::standard_recursion_config(); + let mut leaf_builder = CircuitBuilder::::new(config); + let leaf_targets = leaf_circuit.build(&mut leaf_builder).unwrap(); + let leaf_circ_data = leaf_builder.build::(); + + // Building Phase + group.bench_function("build leaf circuit", |b| { + b.iter(|| { + let config = CircuitConfig::standard_recursion_config(); + let mut leaf_builder = CircuitBuilder::::new(config); + let _leaf_targets = leaf_circuit.build(&mut leaf_builder).unwrap(); + let _leaf_circ_data = leaf_builder.build::(); + }) + }); + + let mut pw = PartialWitness::::new(); + leaf_circuit.assign_targets(&mut pw, &leaf_targets, &leaf_in); + let leaf_proof = leaf_circ_data.prove(pw.clone()).unwrap(); + + // Proving Phase + group.bench_function("prove leaf circuit", |b| { + b.iter(|| { + let _leaf_proof = leaf_circ_data.prove(pw.clone()); + }) + }); + + println!("leaf circuit - Circuit size (degree bits): {:?}", leaf_circ_data.common.degree_bits() ); + println!("leaf proof - num of public input = {}", leaf_proof.public_inputs.len()); + + // ------------- Node/tree circuit ------------------ + // node circuit that verifies leafs or itself + + let mut tree = TreeRecursion::::build().unwrap(); + + // Building phase + group.bench_function("build tree circuit", |b| { + b.iter(|| { + let _tree = TreeRecursion::::build(); + }) + }); + + + let leaf_proofs: Vec> = (0..N) + .map(|_| { + leaf_proof.clone() + }) + .collect::>(); + + let tree_root_proof = tree.prove_tree(leaf_proofs.clone()).unwrap(); + + // Proving Phase + group.bench_function("prove tree circuit", |b| { + b.iter(|| { + let _tree_root_proof = tree.prove_tree(leaf_proofs.clone()); + }) + }); + + println!("tree circuit - Circuit size (degree bits): {:?}", tree.node.node_data.node_circuit_data.common.degree_bits()); + println!("tree circuit - num of public input = {}", tree_root_proof.public_inputs.len()); + + assert!( + tree.verify_proof(tree_root_proof.clone()).is_ok(), + "proof verification failed" + ); + + // Verifying Phase + group.bench_function("verify tree circuit", |b| { + b.iter(|| { + tree.verify_proof(tree_root_proof.clone()).expect("verify fail"); + }) + }); + + + group.finish(); +} + +fn bench_tree_recursion_approach2(c: &mut Criterion){ + const N: usize = 2; + bench_tree_recursion::(c); +} + +/// Criterion benchmark group +criterion_group!{ + name = recursion; + config = Criterion::default().sample_size(10); + targets = bench_tree_recursion_approach2 +} +criterion_main!(recursion);