diff --git a/codex-plonky2-circuits/src/recursion/mod.rs b/codex-plonky2-circuits/src/recursion/mod.rs index dbc2d24..d4f1b3b 100644 --- a/codex-plonky2-circuits/src/recursion/mod.rs +++ b/codex-plonky2-circuits/src/recursion/mod.rs @@ -1,8 +1,2 @@ -pub mod cyclic; -pub mod circuits; -pub mod simple; -pub mod tree1; -pub mod tree2; -pub mod hybrid; pub mod utils; pub mod uniform; diff --git a/codex-plonky2-circuits/src/recursion/uniform/leaf.rs b/codex-plonky2-circuits/src/recursion/uniform/leaf.rs index e9c1068..ff1fc49 100644 --- a/codex-plonky2-circuits/src/recursion/uniform/leaf.rs +++ b/codex-plonky2-circuits/src/recursion/uniform/leaf.rs @@ -7,7 +7,7 @@ use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; use plonky2_field::extension::Extendable; use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::recursion::circuits::inner_circuit::InnerCircuit; +// use crate::recursion::circuits::inner_circuit::InnerCircuit; use crate::{error::CircuitError,Result}; /// recursion leaf circuit - verifies N inner proof diff --git a/codex-plonky2-circuits/src/recursion/uniform/node.rs b/codex-plonky2-circuits/src/recursion/uniform/node.rs index 34fdb8f..3ec302c 100644 --- a/codex-plonky2-circuits/src/recursion/uniform/node.rs +++ b/codex-plonky2-circuits/src/recursion/uniform/node.rs @@ -7,7 +7,7 @@ use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; use plonky2_field::extension::Extendable; use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::recursion::circuits::inner_circuit::InnerCircuit; +// use crate::recursion::circuits::inner_circuit::InnerCircuit; use crate::{error::CircuitError,Result}; use crate::circuits::utils::vec_to_array; diff --git a/codex-plonky2-circuits/src/recursion/uniform/tree.rs b/codex-plonky2-circuits/src/recursion/uniform/tree.rs index 5924ccb..f1bf545 100644 --- a/codex-plonky2-circuits/src/recursion/uniform/tree.rs +++ b/codex-plonky2-circuits/src/recursion/uniform/tree.rs @@ -6,7 +6,7 @@ use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::proof::ProofWithPublicInputs; use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::recursion::circuits::inner_circuit::InnerCircuit; +// use crate::recursion::circuits::inner_circuit::InnerCircuit; use plonky2_field::extension::Extendable; use crate::{error::CircuitError, Result}; use crate::recursion::uniform::{leaf::{LeafTargets,LeafCircuit},node::{NodeTargets,NodeCircuit}}; diff --git a/proof-input/src/params.rs b/proof-input/src/params.rs index 5ef4358..ade2ea7 100644 --- a/proof-input/src/params.rs +++ b/proof-input/src/params.rs @@ -10,9 +10,9 @@ use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2Hash; // test types pub const D: usize = 2; -pub type C = PoseidonGoldilocksConfig; +pub type C = Poseidon2GoldilocksConfig; pub type F = >::F; // this is the goldilocks field -pub type HF = PoseidonHash; +pub type HF = Poseidon2Hash; // hardcoded default params for generating proof input const DEFAULT_MAX_DEPTH: usize = 32; // depth of big tree (slot tree depth, includes block tree depth) diff --git a/proof-input/src/recursion/mod.rs b/proof-input/src/recursion/mod.rs index d91a328..6f4d83f 100644 --- a/proof-input/src/recursion/mod.rs +++ b/proof-input/src/recursion/mod.rs @@ -1,7 +1 @@ -pub mod simple_recursion; -pub mod simple_tree; -pub mod cyclic_recursion; -pub mod tree1; -pub mod tree2; -mod hybrid; -mod uniform; \ No newline at end of file +pub mod uniform; \ No newline at end of file diff --git a/proof-input/src/recursion/uniform.rs b/proof-input/src/recursion/uniform.rs index 5acedc9..a845c60 100644 --- a/proof-input/src/recursion/uniform.rs +++ b/proof-input/src/recursion/uniform.rs @@ -35,23 +35,14 @@ mod tests { println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); let inner_proof = inner_data.prove(pw)?; - let proofs: Vec> = (0..16).map(|i| inner_proof.clone()).collect(); + let proofs: Vec> = (0..4).map(|i| inner_proof.clone()).collect(); // ------------------- tree -------------------- const N: usize = 1; - const M: usize = 4; + const M: usize = 2; let mut tree = TreeRecursion::::build(inner_data.common.clone())?; - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&tree.get_leaf_verifier_data().common ).unwrap(); - fs::write("leaf_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&tree.get_node_verifier_data().common ).unwrap(); - fs::write("node_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - let root = tree.prove_tree(&proofs, &inner_data.verifier_only)?; println!("pub input size = {}", root.public_inputs.len()); diff --git a/recursion_experiments/README.md b/recursion_experiments/README.md new file mode 100644 index 0000000..1f2fd4c --- /dev/null +++ b/recursion_experiments/README.md @@ -0,0 +1,5 @@ +Proof Aggregation Experiments +================================ + +In here, we archive the experiments done on various approaches to recursion before setting on the uniform approach. +See [here](../codex-plonky2-circuits/src/recursion) for the best recursion circuit option for our use case that we settled on. diff --git a/workflow/benches/cyclic_recursion.rs b/recursion_experiments/benches/cyclic_recursion.rs similarity index 100% rename from workflow/benches/cyclic_recursion.rs rename to recursion_experiments/benches/cyclic_recursion.rs diff --git a/workflow/benches/hybrid_recursion.rs b/recursion_experiments/benches/hybrid_recursion.rs similarity index 86% rename from workflow/benches/hybrid_recursion.rs rename to recursion_experiments/benches/hybrid_recursion.rs index 5fcd908..960507a 100644 --- a/workflow/benches/hybrid_recursion.rs +++ b/recursion_experiments/benches/hybrid_recursion.rs @@ -15,7 +15,7 @@ use proof_input::params::Params; /// Benchmark for building, proving, and verifying the Plonky2 tree recursion circuit. fn bench_hybrid_recursion(c: &mut Criterion) -> anyhow::Result<()>{ - let mut group = c.benchmark_group(format!("Tree Recursion - Approach 2 Benchmark for N={}",K)); + let mut group = c.benchmark_group(format!("Tree Recursion - Approach 2 Benchmark for N={}, leaf ={}, Node ={}",K, M,N)); //------------ sampling inner circuit ---------------------- // Circuit that does the sampling - default input @@ -77,9 +77,18 @@ fn bench_tree_recursion_approach2(c: &mut Criterion){ const N: usize = 2; // number of child nodes - binary here const M: usize = 64; // number of proofs aggregated in leaves const K: usize = 128; // number of proofs to be aggregated in the tree - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - // bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::(c); + bench_hybrid_recursion::<4,16,128>(c); } /// Criterion benchmark group diff --git a/workflow/benches/simple_recursion.rs b/recursion_experiments/benches/simple_recursion.rs similarity index 100% rename from workflow/benches/simple_recursion.rs rename to recursion_experiments/benches/simple_recursion.rs diff --git a/workflow/benches/simple_recursion_hashed_pi.rs b/recursion_experiments/benches/simple_recursion_hashed_pi.rs similarity index 100% rename from workflow/benches/simple_recursion_hashed_pi.rs rename to recursion_experiments/benches/simple_recursion_hashed_pi.rs diff --git a/workflow/benches/simple_tree_recursion.rs b/recursion_experiments/benches/simple_tree_recursion.rs similarity index 100% rename from workflow/benches/simple_tree_recursion.rs rename to recursion_experiments/benches/simple_tree_recursion.rs diff --git a/workflow/benches/tree_recursion1.rs b/recursion_experiments/benches/tree_recursion1.rs similarity index 100% rename from workflow/benches/tree_recursion1.rs rename to recursion_experiments/benches/tree_recursion1.rs diff --git a/workflow/benches/tree_recursion2.rs b/recursion_experiments/benches/tree_recursion2.rs similarity index 100% rename from workflow/benches/tree_recursion2.rs rename to recursion_experiments/benches/tree_recursion2.rs diff --git a/recursion_experiments/benches/uniform_recursion.rs b/recursion_experiments/benches/uniform_recursion.rs new file mode 100644 index 0000000..417d479 --- /dev/null +++ b/recursion_experiments/benches/uniform_recursion.rs @@ -0,0 +1,89 @@ +use criterion::{Criterion, criterion_group, criterion_main}; +use plonky2::iop::witness::PartialWitness; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::{CircuitConfig}; +use plonky2::plonk::config::GenericConfig; +use plonky2::plonk::proof::ProofWithPublicInputs; +use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit}; +use codex_plonky2_circuits::recursion::uniform::tree::TreeRecursion; +use proof_input::params::{C, D, F,HF}; +use proof_input::gen_input::gen_testing_circuit_input; +use proof_input::params::Params; + +/// Benchmark for building, proving, and verifying the Plonky2 tree recursion circuit. +fn bench_uniform_recursion(c: &mut Criterion) -> anyhow::Result<()>{ + + let mut group = c.benchmark_group(format!("Uniform Tree Recursion Benchmark for N={}",N)); + + //------------ sampling inner circuit ---------------------- + // Circuit that does the sampling - 100 samples + let config = CircuitConfig::standard_recursion_config(); + let mut sampling_builder = CircuitBuilder::::new(config); + let mut params = Params::default(); + params.input_params.n_samples = 100; + params.circuit_params.n_samples = 100; + let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); + let samp_circ = SampleCircuit::::new(params.circuit_params); + 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())?; + + let proofs: Vec> = (0..N).map(|i| inner_proof.clone()).collect(); + + // ------------------- tree -------------------- + + let mut tree : Option> = None; + + // Building phase + group.bench_function("build tree", |b| { + b.iter(|| { + tree = Some(TreeRecursion::::build(inner_data.common.clone()).unwrap()); + }) + }); + + let mut tree = tree.unwrap(); + + let mut proof: Option> = None; + + // Proving Phase + group.bench_function("prove tree", |b| { + b.iter(|| { + proof = Some(tree.prove_tree(&proofs, &inner_data.verifier_only).unwrap()); + }) + }); + + let proof = proof.unwrap(); + + // Verifying Phase + // group.bench_function("verify tree circuit", |b| { + // b.iter(|| { + // verifier_data.verify(proof.clone()).expect("verify fail"); + // }) + // }); + + group.finish(); + Ok(()) +} + +fn bench_uniform_tree_recursion(c: &mut Criterion){ + const N: usize = 2; // number of child nodes - binary here + bench_uniform_recursion::<2>(c).expect("bench failed"); + bench_uniform_recursion::<4>(c).expect("bench failed"); + bench_uniform_recursion::<8>(c).expect("bench failed"); + bench_uniform_recursion::<16>(c).expect("bench failed"); + bench_uniform_recursion::<32>(c).expect("bench failed"); + bench_uniform_recursion::<64>(c).expect("bench failed"); + bench_uniform_recursion::<128>(c).expect("bench failed"); + bench_uniform_recursion::<256>(c).expect("bench failed"); +} + +/// Criterion benchmark group +criterion_group!{ + name = recursion; + config = Criterion::default().sample_size(10); + targets = bench_uniform_tree_recursion +} +criterion_main!(recursion); diff --git a/codex-plonky2-circuits/src/recursion/circuits/inner_circuit.rs b/recursion_experiments/recursion/circuits/inner_circuit.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/circuits/inner_circuit.rs rename to recursion_experiments/recursion/circuits/inner_circuit.rs diff --git a/codex-plonky2-circuits/src/recursion/circuits/leaf_circuit.rs b/recursion_experiments/recursion/circuits/leaf_circuit.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/circuits/leaf_circuit.rs rename to recursion_experiments/recursion/circuits/leaf_circuit.rs diff --git a/codex-plonky2-circuits/src/recursion/circuits/mod.rs b/recursion_experiments/recursion/circuits/mod.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/circuits/mod.rs rename to recursion_experiments/recursion/circuits/mod.rs diff --git a/codex-plonky2-circuits/src/recursion/circuits/sampling_inner_circuit.rs b/recursion_experiments/recursion/circuits/sampling_inner_circuit.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/circuits/sampling_inner_circuit.rs rename to recursion_experiments/recursion/circuits/sampling_inner_circuit.rs diff --git a/codex-plonky2-circuits/src/recursion/cyclic/mod.rs b/recursion_experiments/recursion/cyclic/mod.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/cyclic/mod.rs rename to recursion_experiments/recursion/cyclic/mod.rs diff --git a/codex-plonky2-circuits/src/recursion/hybrid/mod.rs b/recursion_experiments/recursion/hybrid/mod.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/hybrid/mod.rs rename to recursion_experiments/recursion/hybrid/mod.rs diff --git a/codex-plonky2-circuits/src/recursion/hybrid/node_circuit.rs b/recursion_experiments/recursion/hybrid/node_circuit.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/hybrid/node_circuit.rs rename to recursion_experiments/recursion/hybrid/node_circuit.rs diff --git a/codex-plonky2-circuits/src/recursion/hybrid/tree_circuit.rs b/recursion_experiments/recursion/hybrid/tree_circuit.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/hybrid/tree_circuit.rs rename to recursion_experiments/recursion/hybrid/tree_circuit.rs diff --git a/recursion_experiments/recursion/mod.rs b/recursion_experiments/recursion/mod.rs new file mode 100644 index 0000000..dbc2d24 --- /dev/null +++ b/recursion_experiments/recursion/mod.rs @@ -0,0 +1,8 @@ +pub mod cyclic; +pub mod circuits; +pub mod simple; +pub mod tree1; +pub mod tree2; +pub mod hybrid; +pub mod utils; +pub mod uniform; diff --git a/codex-plonky2-circuits/src/recursion/simple/mod.rs b/recursion_experiments/recursion/simple/mod.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/simple/mod.rs rename to recursion_experiments/recursion/simple/mod.rs diff --git a/codex-plonky2-circuits/src/recursion/simple/simple_recursion.rs b/recursion_experiments/recursion/simple/simple_recursion.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/simple/simple_recursion.rs rename to recursion_experiments/recursion/simple/simple_recursion.rs diff --git a/codex-plonky2-circuits/src/recursion/simple/simple_recursion_hashed_pi.rs b/recursion_experiments/recursion/simple/simple_recursion_hashed_pi.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/simple/simple_recursion_hashed_pi.rs rename to recursion_experiments/recursion/simple/simple_recursion_hashed_pi.rs diff --git a/codex-plonky2-circuits/src/recursion/simple/simple_tree_recursion.rs b/recursion_experiments/recursion/simple/simple_tree_recursion.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/simple/simple_tree_recursion.rs rename to recursion_experiments/recursion/simple/simple_tree_recursion.rs diff --git a/codex-plonky2-circuits/src/recursion/tree1/mod.rs b/recursion_experiments/recursion/tree1/mod.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/tree1/mod.rs rename to recursion_experiments/recursion/tree1/mod.rs diff --git a/codex-plonky2-circuits/src/recursion/tree1/node_circuit.rs b/recursion_experiments/recursion/tree1/node_circuit.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/tree1/node_circuit.rs rename to recursion_experiments/recursion/tree1/node_circuit.rs diff --git a/codex-plonky2-circuits/src/recursion/tree1/tree_circuit.rs b/recursion_experiments/recursion/tree1/tree_circuit.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/tree1/tree_circuit.rs rename to recursion_experiments/recursion/tree1/tree_circuit.rs diff --git a/codex-plonky2-circuits/src/recursion/tree2/mod.rs b/recursion_experiments/recursion/tree2/mod.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/tree2/mod.rs rename to recursion_experiments/recursion/tree2/mod.rs diff --git a/codex-plonky2-circuits/src/recursion/tree2/node_circuit.rs b/recursion_experiments/recursion/tree2/node_circuit.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/tree2/node_circuit.rs rename to recursion_experiments/recursion/tree2/node_circuit.rs diff --git a/codex-plonky2-circuits/src/recursion/tree2/tree_circuit.rs b/recursion_experiments/recursion/tree2/tree_circuit.rs similarity index 100% rename from codex-plonky2-circuits/src/recursion/tree2/tree_circuit.rs rename to recursion_experiments/recursion/tree2/tree_circuit.rs diff --git a/recursion_experiments/recursion/uniform/leaf.rs b/recursion_experiments/recursion/uniform/leaf.rs new file mode 100644 index 0000000..e9c1068 --- /dev/null +++ b/recursion_experiments/recursion/uniform/leaf.rs @@ -0,0 +1,139 @@ +use std::marker::PhantomData; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::witness::{PartialWitness, WitnessWrite}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData}; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; +use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; +use plonky2_field::extension::Extendable; +use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; +use crate::recursion::circuits::inner_circuit::InnerCircuit; +use crate::{error::CircuitError,Result}; + +/// recursion leaf circuit - verifies N inner proof +#[derive(Clone, Debug)] +pub struct LeafCircuit< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + H: AlgebraicHasher, + const N: usize, +> where + >::Hasher: AlgebraicHasher +{ + inner_common_data: CommonCircuitData, + phantom_data: PhantomData<(C,H)> +} + +#[derive(Clone, Debug)] +pub struct LeafTargets < + const D: usize, +>{ + pub inner_proof: Vec>, + pub verifier_data: VerifierCircuitTarget, +} + +impl< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + H: AlgebraicHasher, + const N: usize, +> LeafCircuit where + >::Hasher: AlgebraicHasher +{ + pub fn new(inner_common_data: CommonCircuitData) -> Self { + Self{ + inner_common_data, + phantom_data:PhantomData::default(), + } + } + + /// build the leaf circuit + pub fn build(&self, builder: &mut CircuitBuilder) -> Result> { + + let inner_common = self.inner_common_data.clone(); + + // the proof virtual targets + let mut pub_input = vec![]; + let mut vir_proofs = vec![]; + for _i in 0..N { + let vir_proof = builder.add_virtual_proof_with_pis(&inner_common); + let inner_pub_input = vir_proof.public_inputs.clone(); + vir_proofs.push(vir_proof); + pub_input.extend_from_slice(&inner_pub_input); + } + + // hash the public input & make it public + let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(pub_input); + builder.register_public_inputs(&hash_inner_pub_input.elements); + + // virtual target for the verifier data + let inner_verifier_data = builder.add_virtual_verifier_data(inner_common.config.fri_config.cap_height); + + // register verifier data hash as public input. + let mut vd_pub_input = vec![]; + vd_pub_input.extend_from_slice(&inner_verifier_data.circuit_digest.elements); + for i in 0..builder.config.fri_config.num_cap_elements() { + vd_pub_input.extend_from_slice(&inner_verifier_data.constants_sigmas_cap.0[i].elements); + } + let hash_inner_vd_pub_input = builder.hash_n_to_hash_no_pad::(vd_pub_input); + builder.register_public_inputs(&hash_inner_vd_pub_input.elements); + + // verify the proofs in-circuit + for i in 0..N { + builder.verify_proof::(&vir_proofs[i], &inner_verifier_data, &inner_common); + } + + // return targets + let t = LeafTargets { + inner_proof: vir_proofs, + verifier_data: inner_verifier_data, + }; + Ok(t) + + } + + /// assign the leaf targets with given input + pub fn assign_targets( + &self, pw: &mut PartialWitness, + targets: &LeafTargets, + inner_proof: &[ProofWithPublicInputs], + verifier_only_data: &VerifierOnlyCircuitData, + ) -> Result<()> { + assert_eq!(inner_proof.len(), N); + // assign the proofs + for i in 0..N { + pw.set_proof_with_pis_target(&targets.inner_proof[i], &inner_proof[i]) + .map_err(|e| { + CircuitError::ProofTargetAssignmentError("inner-proof".to_string(), e.to_string()) + })?; + } + + // assign the verifier data + pw.set_verifier_data_target(&targets.verifier_data, verifier_only_data) + .map_err(|e| { + CircuitError::VerifierDataTargetAssignmentError(e.to_string()) + })?; + + Ok(()) + } + + /// returns the leaf circuit data + pub fn get_circuit_data (&self) -> Result> + where + >::Hasher: AlgebraicHasher + { + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config.clone()); + + self.build(&mut builder)?; + + let circ_data = builder.build::(); + + Ok(circ_data) + } + +} + + diff --git a/recursion_experiments/recursion/uniform/mod.rs b/recursion_experiments/recursion/uniform/mod.rs new file mode 100644 index 0000000..6daaa29 --- /dev/null +++ b/recursion_experiments/recursion/uniform/mod.rs @@ -0,0 +1,3 @@ +pub mod leaf; +pub mod node; +pub mod tree; \ No newline at end of file diff --git a/recursion_experiments/recursion/uniform/node.rs b/recursion_experiments/recursion/uniform/node.rs new file mode 100644 index 0000000..34fdb8f --- /dev/null +++ b/recursion_experiments/recursion/uniform/node.rs @@ -0,0 +1,152 @@ +use std::marker::PhantomData; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::witness::{PartialWitness, WitnessWrite}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData}; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; +use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; +use plonky2_field::extension::Extendable; +use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; +use crate::recursion::circuits::inner_circuit::InnerCircuit; +use crate::{error::CircuitError,Result}; +use crate::circuits::utils::vec_to_array; + +/// recursion node circuit - verifies 2 leaf proofs +#[derive(Clone, Debug)] +pub struct NodeCircuit< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + H: AlgebraicHasher, + const M: usize, +> where + >::Hasher: AlgebraicHasher +{ + leaf_common_data: CommonCircuitData, + phantom_data: PhantomData<(C,H)> +} + +#[derive(Clone, Debug)] +pub struct NodeTargets< + const D: usize, +>{ + pub leaf_proofs: Vec>, + pub verifier_data: VerifierCircuitTarget, +} + +impl< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + H: AlgebraicHasher, + const M: usize, +> NodeCircuit where + >::Hasher: AlgebraicHasher +{ + + pub fn new(inner_common_data: CommonCircuitData) -> Self { + Self{ + leaf_common_data: inner_common_data, + phantom_data:PhantomData::default(), + } + } + + /// build the leaf circuit + pub fn build(&self, builder: &mut CircuitBuilder) -> Result> { + + let inner_common = self.leaf_common_data.clone(); + + // assert public input is of size 8 - 2 hashout + assert_eq!(inner_common.num_public_inputs, 8); + + // the proof virtual targets - M proofs + let mut vir_proofs = vec![]; + let mut pub_input = vec![]; + let mut inner_vd_hashes = vec![]; + for _i in 0..M { + let vir_proof = builder.add_virtual_proof_with_pis(&inner_common); + let inner_pub_input = vir_proof.public_inputs.clone(); + vir_proofs.push(vir_proof); + pub_input.extend_from_slice(&inner_pub_input[0..4]); + inner_vd_hashes.extend_from_slice(&inner_pub_input[4..8]); + } + + // hash the public input & make it public + let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(pub_input); + builder.register_public_inputs(&hash_inner_pub_input.elements); + + // virtual target for the verifier data + let inner_verifier_data = builder.add_virtual_verifier_data(inner_common.config.fri_config.cap_height); + + // register verifier data hash as public input. H(H_l, H_l, H_n) -> public input + let mut vd_pub_input = vec![]; + vd_pub_input.extend_from_slice(&inner_verifier_data.circuit_digest.elements); + for i in 0..builder.config.fri_config.num_cap_elements() { + vd_pub_input.extend_from_slice(&inner_verifier_data.constants_sigmas_cap.0[i].elements); + } + let vd_hash = builder.hash_n_to_hash_no_pad::(vd_pub_input); + inner_vd_hashes.extend_from_slice(&vd_hash.elements); + let vd_hash_all = builder.hash_n_to_hash_no_pad::(inner_vd_hashes); + builder.register_public_inputs(&vd_hash_all.elements); + + // verify the proofs in-circuit - M proofs + for i in 0..M { + builder.verify_proof::(&vir_proofs[i], &inner_verifier_data, &inner_common); + } + + // let proofs = vec_to_array::<2, ProofWithPublicInputsTarget>(vir_proofs)?; + + // return targets + let t = NodeTargets { + leaf_proofs: vir_proofs, + verifier_data: inner_verifier_data, + }; + Ok(t) + + } + + /// assign the leaf targets with given input + pub fn assign_targets( + &self, pw: &mut PartialWitness, + targets: &NodeTargets, + node_proofs: &[ProofWithPublicInputs], + verifier_only_data: &VerifierOnlyCircuitData, + ) -> Result<()> { + // assert size of proofs vec + assert_eq!(node_proofs.len(), M); + + // assign the proofs + for i in 0..M { + pw.set_proof_with_pis_target(&targets.leaf_proofs[i], &node_proofs[i]) + .map_err(|e| { + CircuitError::ProofTargetAssignmentError("inner-proof".to_string(), e.to_string()) + })?; + } + + // assign the verifier data + pw.set_verifier_data_target(&targets.verifier_data, &verifier_only_data) + .map_err(|e| { + CircuitError::VerifierDataTargetAssignmentError(e.to_string()) + })?; + + Ok(()) + } + + /// returns the leaf circuit data + pub fn get_circuit_data (&self) -> Result> + where + >::Hasher: AlgebraicHasher + { + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config.clone()); + + self.build(&mut builder)?; + + let circ_data = builder.build::(); + + Ok(circ_data) + } + +} + + diff --git a/recursion_experiments/recursion/uniform/tree.rs b/recursion_experiments/recursion/uniform/tree.rs new file mode 100644 index 0000000..5924ccb --- /dev/null +++ b/recursion_experiments/recursion/uniform/tree.rs @@ -0,0 +1,252 @@ +use std::marker::PhantomData; +use plonky2::hash::hash_types::{HashOut, RichField}; +use plonky2::iop::witness::PartialWitness; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitData, VerifierOnlyCircuitData}; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; +use plonky2::plonk::proof::ProofWithPublicInputs; +use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; +use crate::recursion::circuits::inner_circuit::InnerCircuit; +use plonky2_field::extension::Extendable; +use crate::{error::CircuitError, Result}; +use crate::recursion::uniform::{leaf::{LeafTargets,LeafCircuit},node::{NodeTargets,NodeCircuit}}; + +/// tree recursion +pub struct TreeRecursion< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + H: AlgebraicHasher, + const N: usize, + const M: usize, +> where + >::Hasher: AlgebraicHasher +{ + leaf: LeafCircuit, + node: NodeCircuit, + leaf_circ_data: CircuitData, + node_circ_data: CircuitData, + leaf_targets: LeafTargets, + node_targets: NodeTargets, + phantom_data: PhantomData<(H)> +} + +impl< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + H: AlgebraicHasher, + const N: usize, + const M: usize, +> TreeRecursion where + >::Hasher: AlgebraicHasher +{ + + pub fn build( + inner_common_data: CommonCircuitData + ) -> Result { + // build leaf with standard recursion config + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + let leaf = LeafCircuit::<_,D,_,_,N>::new(inner_common_data.clone()); + let leaf_targets = leaf.build(&mut builder)?; + let leaf_circ_data = builder.build::(); + // println!("leaf circuit size = {:?}", leaf_circ_data.common.degree_bits()); + + // build node with standard recursion config + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + let node = NodeCircuit::<_,D,_,_,M>::new(leaf_circ_data.common.clone()); + let node_targets = node.build(&mut builder)?; + let node_circ_data = builder.build::(); + // println!("node circuit size = {:?}", node_circ_data.common.degree_bits()); + + Ok(Self{ + leaf, + node, + leaf_circ_data, + node_circ_data, + leaf_targets, + node_targets, + phantom_data: Default::default(), + }) + } + + pub fn get_leaf_verifier_data(&self) -> VerifierCircuitData{ + self.leaf_circ_data.verifier_data() + } + + pub fn get_node_verifier_data(&self) -> VerifierCircuitData{ + self.node_circ_data.verifier_data() + } + + pub fn prove_tree + ( + &mut self, + proofs_with_pi: &[ProofWithPublicInputs], + inner_verifier_only_data: &VerifierOnlyCircuitData, + ) -> Result<(ProofWithPublicInputs)> + { + if proofs_with_pi.len() % 2 != 0 { + return + Err(CircuitError::RecursionTreeError(format!( + "input proofs must be divisible by {}, got {}", 2, proofs_with_pi.len()) + )) + } + // process leaves + let leaf_proofs = self.get_leaf_proofs( + proofs_with_pi, + inner_verifier_only_data, + )?; + + // process nodes + let (root_proof, vd) = + self.prove(&leaf_proofs,&self.leaf_circ_data.verifier_only)?; + + Ok(root_proof) + } + + fn get_leaf_proofs + ( + &mut self, + proofs_with_pi: &[ProofWithPublicInputs], + inner_verifier_only_data: &VerifierOnlyCircuitData, + ) -> Result<(Vec>)> { + + let mut leaf_proofs = vec![]; + + for proof in proofs_with_pi.chunks(N){ + let mut pw = PartialWitness::::new(); + + self.leaf.assign_targets(&mut pw,&self.leaf_targets,proof,inner_verifier_only_data)?; + let proof = self.leaf_circ_data.prove(pw).unwrap(); + leaf_proofs.push(proof); + } + + Ok(leaf_proofs) + } + + /// generates a proof + fn prove( + &self, + proofs_with_pi: &[ProofWithPublicInputs], + verifier_only_data: &VerifierOnlyCircuitData, + ) -> Result<(ProofWithPublicInputs, VerifierOnlyCircuitData)> where + >::Hasher: AlgebraicHasher + { + + if proofs_with_pi.len() == 1 { + return Ok((proofs_with_pi[0].clone(), verifier_only_data.clone())); + } + + let mut new_proofs = vec![]; + + for chunk in proofs_with_pi.chunks(M) { + + let mut inner_pw = PartialWitness::new(); + + self.node.assign_targets( + &mut inner_pw, + &self.node_targets, + chunk, + verifier_only_data, + )?; + + let proof = self.node_circ_data.prove(inner_pw) + .map_err(|e| CircuitError::ProofGenerationError(e.to_string()))?; + new_proofs.push(proof); + } + + self.prove(&new_proofs, &self.node_circ_data.verifier_only) + } + + pub fn verify_proof_and_public_input( + &self, + proof: ProofWithPublicInputs, + inner_public_input: Vec>, + inner_verifier_data: &VerifierCircuitData) -> Result<()> + { + let public_input = proof.public_inputs.clone(); + self.node_circ_data.verify(proof) + .map_err(|e| CircuitError::InvalidProofError(e.to_string()))?; + self.verify_public_input(public_input, inner_public_input, inner_verifier_data) + } + + pub fn verify_public_input(&self, public_input: Vec, inner_public_input: Vec>, inner_verifier_data: &VerifierCircuitData) -> Result<()>{ + assert_eq!(public_input.len(), 8); + + let given_input_hash = &public_input[0..4]; + let given_vd_hash = &public_input[4..8]; + + let inner_hash = Self::get_hash_of_verifier_data(&inner_verifier_data); + + let leaf_hash = Self::get_hash_of_verifier_data(&self.leaf_circ_data.verifier_data()); + + let node_hash = Self::get_hash_of_verifier_data(&self.node_circ_data.verifier_data()); + + + let mut pub_in_hashes = vec![]; + let mut inner_vd_hashes = vec![]; + for pub_in in inner_public_input.chunks(N){ + let pub_in_flat: Vec = pub_in + .iter() + .flat_map(|v| v.iter().cloned()) + .collect(); + let hash = H::hash_no_pad(&pub_in_flat); + pub_in_hashes.push(hash); + inner_vd_hashes.push(inner_hash.clone()); + } + + let mut level = 0; + while pub_in_hashes.len() > 1 { + let mut next_level_pi_hashes = Vec::new(); + let mut next_level_vd_hashes = Vec::new(); + for (pi_chunk, vd_chunk) in pub_in_hashes.chunks(M).zip(inner_vd_hashes.chunks(M)) { + // collect field elements + let pi_chunk_f: Vec = pi_chunk.iter() + .flat_map(|h| h.elements.iter().cloned()) + .collect(); + let mut vd_chunk_f: Vec = vd_chunk.iter() + .flat_map(|h| h.elements.iter().cloned()) + .collect(); + let hash_n = if level == 0 {leaf_hash} else{node_hash}; + vd_chunk_f.extend_from_slice(&hash_n.elements); + + // Compute Poseidon2 hash of the concatenated chunk + let pi_hash = H::hash_no_pad(&pi_chunk_f); + let vd_hash = H::hash_no_pad(&vd_chunk_f); + next_level_pi_hashes.push(pi_hash); + next_level_vd_hashes.push(vd_hash); + } + pub_in_hashes = next_level_pi_hashes; + inner_vd_hashes = next_level_vd_hashes; + level +=1; + } + + //check expected hash + let expected_pi_hash = pub_in_hashes[0]; + let expected_vd_hash = inner_vd_hashes[0]; + + assert_eq!(given_input_hash, expected_pi_hash.elements); + assert_eq!(given_vd_hash, expected_vd_hash.elements); + Ok(()) + } + + /// helper fn to generate hash of verifier data + fn get_hash_of_verifier_data(verifier_data: &VerifierCircuitData) -> HashOut{ + let mut vd = vec![]; + let digest: &HashOut = &verifier_data.verifier_only.circuit_digest; + let caps = &verifier_data.verifier_only.constants_sigmas_cap; + vd.extend_from_slice(&digest.elements); + for i in 0..verifier_data.common.config.fri_config.num_cap_elements() { + let cap_hash = caps.0[i] as HashOut; + vd.extend_from_slice(&cap_hash.elements); + } + + H::hash_no_pad(&vd) + } + +} + diff --git a/recursion_experiments/recursion/utils/conditional_verifier.rs b/recursion_experiments/recursion/utils/conditional_verifier.rs new file mode 100644 index 0000000..2956e67 --- /dev/null +++ b/recursion_experiments/recursion/utils/conditional_verifier.rs @@ -0,0 +1,121 @@ +use plonky2::gates::noop::NoopGate; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::target::BoolTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::{CircuitData, CommonCircuitData, VerifierCircuitTarget}; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; +use plonky2::plonk::proof::ProofWithPublicInputsTarget; +use plonky2_field::extension::Extendable; +use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; + +/// this takes verifier data (not public) and doesn't check the verifier data for consistency +pub fn conditionally_verify_recursion_proof_or_dummy + Poseidon2, const D: usize ,C: GenericConfig + 'static>( + builder: &mut CircuitBuilder, + condition: BoolTarget, + cyclic_proof_with_pis: &ProofWithPublicInputsTarget, + verifier_data: &VerifierCircuitTarget, + common_data: &CommonCircuitData, +) -> anyhow::Result<()> + where + C::Hasher: AlgebraicHasher, +{ + let (dummy_proof_with_pis_target, dummy_verifier_data_target) = + dummy_proof_and_vk_no_generator::(builder, common_data)?; + + // TODO: make verifier data public + // // Connect previous verifier data to current one. This guarantees that every proof in the cycle uses the same verifier data. + // self.connect_hashes( + // inner_cyclic_pis.circuit_digest, + // verifier_data.circuit_digest, + // ); + // self.connect_merkle_caps( + // &inner_cyclic_pis.constants_sigmas_cap, + // &verifier_data.constants_sigmas_cap, + // ); + + // Verify the cyclic proof if `condition` is set to true, otherwise verify the other proof. + builder.conditionally_verify_proof::( + condition, + cyclic_proof_with_pis, + verifier_data, + &dummy_proof_with_pis_target, + &dummy_verifier_data_target, + common_data, + ); + + // Make sure we have every gate to match `common_data`. + for g in &common_data.gates { + builder.add_gate_to_gate_set(g.clone()); + } + + Ok(()) +} + +/// Conditionally verify a proof with a new generated dummy proof. +pub fn conditionally_verify_proof_or_dummy + Poseidon2, const D: usize ,C: GenericConfig + 'static>( + builder: &mut CircuitBuilder, + condition: BoolTarget, + proof_with_pis: &ProofWithPublicInputsTarget, + inner_verifier_data: &VerifierCircuitTarget, + inner_common_data: &CommonCircuitData, +) -> anyhow::Result<()> + where + C::Hasher: AlgebraicHasher, +{ + let (dummy_proof_with_pis_target, dummy_verifier_data_target) = + dummy_proof_and_vk_no_generator::(builder, inner_common_data)?; + builder.conditionally_verify_proof::( + condition, + proof_with_pis, + inner_verifier_data, + &dummy_proof_with_pis_target, + &dummy_verifier_data_target, + inner_common_data, + ); + Ok(()) +} + +/// Generate a circuit matching a given `CommonCircuitData`. +pub(crate) fn dummy_circuit + Poseidon2, C: GenericConfig, const D: usize>( + common_data: &CommonCircuitData, +) -> CircuitData { + let config = common_data.config.clone(); + assert!( + !common_data.config.zero_knowledge, + "Degree calculation can be off if zero-knowledge is on." + ); + + // Number of `NoopGate`s to add to get a circuit of size `degree` in the end. + // Need to account for public input hashing, a `PublicInputGate` and a `ConstantGate`. + let degree = common_data.degree(); + let num_noop_gate = degree - common_data.num_public_inputs.div_ceil(8) - 2; + + let mut builder = CircuitBuilder::::new(config); + for _ in 0..num_noop_gate { + builder.add_gate(NoopGate, vec![]); + } + for gate in &common_data.gates { + builder.add_gate_to_gate_set(gate.clone()); + } + for _ in 0..common_data.num_public_inputs { + builder.add_virtual_public_input(); + } + + let circuit = builder.build::(); + assert_eq!(&circuit.common, common_data); + circuit +} + +pub(crate) fn dummy_proof_and_vk_no_generator + Poseidon2, const D: usize ,C: GenericConfig + 'static> ( + builder: &mut CircuitBuilder, + common_data: &CommonCircuitData, +) -> anyhow::Result<(ProofWithPublicInputsTarget, VerifierCircuitTarget)> + where + C::Hasher: AlgebraicHasher, +{ + let dummy_circuit = dummy_circuit::(common_data); + let dummy_proof_with_pis_target = builder.add_virtual_proof_with_pis(common_data); + let dummy_verifier_data_target = builder.constant_verifier_data(&dummy_circuit.verifier_only); + + Ok((dummy_proof_with_pis_target, dummy_verifier_data_target)) +} diff --git a/recursion_experiments/recursion/utils/dummy_gen.rs b/recursion_experiments/recursion/utils/dummy_gen.rs new file mode 100644 index 0000000..7b412d6 --- /dev/null +++ b/recursion_experiments/recursion/utils/dummy_gen.rs @@ -0,0 +1,79 @@ +use std::marker::PhantomData; +use plonky2::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; +use plonky2::plonk::proof::{ProofWithPublicInputs}; +use plonky2::recursion::dummy_circuit::{dummy_proof}; +use crate::recursion::utils::conditional_verifier::dummy_circuit; +use hashbrown::HashMap; +use plonky2::hash::hash_types::{ RichField}; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; +use plonky2_field::extension::Extendable; +use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; +use crate::{error::CircuitError, Result}; +use crate::circuits::utils::vec_to_array; + +/// A generator for creating dummy proofs. +pub struct DummyProofGen< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + > where + >::Hasher: AlgebraicHasher +{ + phantom_data: PhantomData<(F,C)>, +} + +impl< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, +> DummyProofGen + where + >::Hasher: AlgebraicHasher +{ + + /// Generates a single dummy leaf proof. + pub fn gen_dummy_leaf_proof( + common_data: &CommonCircuitData, + ) -> Result> { + dummy_proof::(&dummy_circuit::(common_data), HashMap::new()) + .map_err(|e| CircuitError::DummyProofGenerationError(e.to_string())) + } + + /// Generates a single dummy node proof. + pub fn get_dummy_node_proof( + node_common: &CommonCircuitData, + node_verifier_only_data: &VerifierOnlyCircuitData, + ) -> ProofWithPublicInputs { + Self::recursion_base_proof(node_common, HashMap::new()) + } + + fn recursion_base_proof( + common_data: &CommonCircuitData, + mut nonzero_public_inputs: HashMap + ) -> ProofWithPublicInputs{ + dummy_proof::( + &dummy_circuit::(common_data), + nonzero_public_inputs, + ) + .unwrap() + } + + /// Generates an array of `N` dummy leaf proofs. + pub fn gen_n_dummy_leaf_proofs( + common_data: &CommonCircuitData, + ) -> Result<[ProofWithPublicInputs; N]> { + let dummy_proof = Self::gen_dummy_leaf_proof(common_data)?; + let n_dummy_vec = (0..N).map(|_| dummy_proof.clone()).collect::>(); + vec_to_array::>(n_dummy_vec) + } + + /// Generates an array of `N` dummy node proofs. + pub fn gen_n_dummy_node_proofs( + node_common: &CommonCircuitData, + node_verifier_only_data: &VerifierOnlyCircuitData, + ) -> Result<[ProofWithPublicInputs; N]> { + let dummy_proof = Self::get_dummy_node_proof(node_common, node_verifier_only_data); + let n_dummy_vec = (0..N).map(|_| dummy_proof.clone()).collect::>(); + vec_to_array::>(n_dummy_vec) + } +} diff --git a/recursion_experiments/recursion/utils/mod.rs b/recursion_experiments/recursion/utils/mod.rs new file mode 100644 index 0000000..09b3dd3 --- /dev/null +++ b/recursion_experiments/recursion/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod dummy_gen; +pub mod conditional_verifier; diff --git a/proof-input/src/recursion/cyclic_recursion.rs b/recursion_experiments/tests/cyclic_recursion.rs similarity index 100% rename from proof-input/src/recursion/cyclic_recursion.rs rename to recursion_experiments/tests/cyclic_recursion.rs diff --git a/proof-input/src/recursion/hybrid.rs b/recursion_experiments/tests/hybrid.rs similarity index 100% rename from proof-input/src/recursion/hybrid.rs rename to recursion_experiments/tests/hybrid.rs diff --git a/recursion_experiments/tests/mod.rs b/recursion_experiments/tests/mod.rs new file mode 100644 index 0000000..d91a328 --- /dev/null +++ b/recursion_experiments/tests/mod.rs @@ -0,0 +1,7 @@ +pub mod simple_recursion; +pub mod simple_tree; +pub mod cyclic_recursion; +pub mod tree1; +pub mod tree2; +mod hybrid; +mod uniform; \ No newline at end of file diff --git a/proof-input/src/recursion/simple_recursion.rs b/recursion_experiments/tests/simple_recursion.rs similarity index 100% rename from proof-input/src/recursion/simple_recursion.rs rename to recursion_experiments/tests/simple_recursion.rs diff --git a/proof-input/src/recursion/simple_tree.rs b/recursion_experiments/tests/simple_tree.rs similarity index 100% rename from proof-input/src/recursion/simple_tree.rs rename to recursion_experiments/tests/simple_tree.rs diff --git a/proof-input/src/recursion/tree1.rs b/recursion_experiments/tests/tree1.rs similarity index 100% rename from proof-input/src/recursion/tree1.rs rename to recursion_experiments/tests/tree1.rs diff --git a/proof-input/src/recursion/tree2.rs b/recursion_experiments/tests/tree2.rs similarity index 100% rename from proof-input/src/recursion/tree2.rs rename to recursion_experiments/tests/tree2.rs diff --git a/recursion_experiments/tests/uniform.rs b/recursion_experiments/tests/uniform.rs new file mode 100644 index 0000000..5acedc9 --- /dev/null +++ b/recursion_experiments/tests/uniform.rs @@ -0,0 +1,67 @@ +// some tests for approach 2 of the tree recursion + +#[cfg(test)] +mod tests { + use std::fs; + use plonky2::iop::witness::{PartialWitness}; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::{CircuitConfig}; + use plonky2::plonk::config::{ GenericConfig}; + use plonky2::plonk::proof::{ProofWithPublicInputs}; + use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit; + use crate::params::{F, D, C, HF}; + use crate::gen_input::gen_testing_circuit_input; + use crate::params::Params; + use codex_plonky2_circuits::recursion::uniform::{tree::TreeRecursion}; + + #[test] + fn test_uniform_recursion() -> anyhow::Result<()> { + + let config = CircuitConfig::standard_recursion_config(); + let mut sampling_builder = CircuitBuilder::::new(config); + + //------------ sampling inner circuit ---------------------- + // Circuit that does the sampling - 100 samples + let mut params = Params::default(); + params.input_params.n_samples = 100; + params.circuit_params.n_samples = 100; + let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); + let samp_circ = SampleCircuit::::new(params.circuit_params); + 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::(); + println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); + let inner_proof = inner_data.prove(pw)?; + + let proofs: Vec> = (0..16).map(|i| inner_proof.clone()).collect(); + + // ------------------- tree -------------------- + const N: usize = 1; + const M: usize = 4; + + let mut tree = TreeRecursion::::build(inner_data.common.clone())?; + + // serialize circuit into JSON + let common_circuit_data_serialized = serde_json::to_string(&tree.get_leaf_verifier_data().common ).unwrap(); + fs::write("leaf_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + + // serialize circuit into JSON + let common_circuit_data_serialized = serde_json::to_string(&tree.get_node_verifier_data().common ).unwrap(); + fs::write("node_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + + + let root = tree.prove_tree(&proofs, &inner_data.verifier_only)?; + println!("pub input size = {}", root.public_inputs.len()); + + let inner_pi: Vec> = proofs.iter().map(|p| p.public_inputs.clone()).collect(); + + assert!( + tree.verify_proof_and_public_input(root,inner_pi,&inner_data.verifier_data()).is_ok(), + "proof verification failed" + ); + + Ok(()) + } +} \ No newline at end of file diff --git a/recursion_experiments/tests/uniform_arch.rs b/recursion_experiments/tests/uniform_arch.rs new file mode 100644 index 0000000..0c91789 --- /dev/null +++ b/recursion_experiments/tests/uniform_arch.rs @@ -0,0 +1,395 @@ +// some tests for approach 2 of the tree recursion + +#[cfg(test)] +mod tests { + use std::fs; + use std::time::Instant; + use plonky2::gates::constant::ConstantGate; + use plonky2::iop::witness::{PartialWitness, WitnessWrite}; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; + use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher}; + use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; + use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit; + use crate::params::{F, D, C, HF}; + use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; + // use codex_plonky2_circuits::recursion::circuits::inner_circuit::InnerCircuit; + // use codex_plonky2_circuits::recursion::circuits::leaf_circuit::{LeafCircuit}; + // use plonky2_poseidon2::poseidon2_hash::poseidon2::{Poseidon2, Poseidon2Hash}; + use crate::gen_input::gen_testing_circuit_input; + use crate::params::Params; + use codex_plonky2_circuits::recursion::uniform::{leaf::{LeafCircuit,LeafInput,LeafTargets},node::{NodeCircuit,NodeInput,NodeTargets}, tree::TreeRecursion}; + + #[test] + fn test_treeuniform() -> anyhow::Result<()> { + + let config = CircuitConfig::standard_recursion_config(); + let mut sampling_builder = CircuitBuilder::::new(config); + + //------------ sampling inner circuit ---------------------- + // Circuit that does the sampling - default input + let mut params = Params::default(); + params.input_params.n_samples = 100; + params.circuit_params.n_samples = 100; + let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); + let samp_circ = SampleCircuit::::new(params.circuit_params); + 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::(); + println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); + let inner_proof = inner_data.prove(pw)?; + + let proofs: Vec> = (0..4).map(|i| inner_proof.clone()).collect(); + + // ------------------- tree -------------------- + + let mut tree = TreeRecursion::::build(inner_data.common.clone())?; + + let root = tree.prove_tree(&proofs, inner_data.verifier_data())?; + + Ok(()) + } + + #[test] + fn test_2uniform() -> anyhow::Result<()> { + + let config = CircuitConfig::standard_recursion_config(); + let mut sampling_builder = CircuitBuilder::::new(config); + + //------------ sampling inner circuit ---------------------- + // Circuit that does the sampling - default input + let mut params = Params::default(); + params.input_params.n_samples = 100; + params.circuit_params.n_samples = 100; + let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); + let samp_circ = SampleCircuit::::new(params.circuit_params); + 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::(); + println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); + let inner_proof = inner_data.prove(pw)?; + + // serialize circuit into JSON + let common_circuit_data_serialized = serde_json::to_string(&inner_data.common ).unwrap(); + fs::write("circ_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + + + // ------------------- leaf -------------------- + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config.clone()); + + let leaf_circ = LeafCircuit::::new(inner_data.common.clone()); + let leaf_targ = leaf_circ.build(&mut builder)?; + + // let (proof_targ, vd_targ) = build_proof_ver_circuit::(&mut builder,&inner_data.common).unwrap(); + // let leaf_targets = leaf_circuit.build::(&mut builder)?; + + // // add a ConstantGate + // builder.add_gate( + // ConstantGate::new(config.num_constants), + // vec![], + // ); + + let leaf_data = builder.build::(); + println!("leaf circuit size = {:?}", leaf_data.common.degree_bits()); + + // serialize circuit into JSON + let common_circuit_data_serialized = serde_json::to_string(&leaf_data.common ).unwrap(); + fs::write("leaf_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + + // prove + let mut pw = PartialWitness::::new(); + // pw.set_proof_with_pis_target(&proof_targ, &inner_proof)?; + // pw.set_verifier_data_target(&vd_targ,&inner_data.verifier_only)?; + let leaf_in = LeafInput{ + inner_proof: inner_proof.clone(), + verifier_data: inner_data.verifier_data().clone(), + }; + + leaf_circ.assign_targets(&mut pw, &leaf_targ, &leaf_in)?; + + let leaf_proof = leaf_data.prove(pw)?; + + leaf_data.verify(leaf_proof.clone())?; + + // ------------- node1 circuit ------------------ + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + let node_circ = NodeCircuit::::new(leaf_data.common.clone()); + let node_targ = node_circ.build(&mut builder)?; + + // let (proof_targ, vd_targ) = build_node_proof_circuit::(&mut builder,&leaf_data.common).unwrap(); + // let leaf_targets = leaf_circuit.build::(&mut builder)?; + + let node_data = builder.build::(); + println!("node circuit size = {:?}", node_data.common.degree_bits()); + + // serialize circuit into JSON + let common_circuit_data_serialized = serde_json::to_string(&node_data.common ).unwrap(); + fs::write("node_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + + // prove + let mut pw = PartialWitness::::new(); + // pw.set_proof_with_pis_target(&proof_targ[0], &leaf_proof)?; + // pw.set_proof_with_pis_target(&proof_targ[1], &leaf_proof)?; + // pw.set_verifier_data_target(&vd_targ,&leaf_data.verifier_only)?; + + let node_in = NodeInput{ + node_proofs: [leaf_proof.clone(),leaf_proof.clone()], + verifier_data: leaf_data.verifier_data(), + }; + + node_circ.assign_targets(&mut pw, &node_targ,&node_in)?; + + let node_proof = node_data.prove(pw)?; + + node_data.verify(node_proof.clone())?; + + + // ------------- check ---------------- + // prove + let mut pw = PartialWitness::::new(); + + let node_in = NodeInput{ + node_proofs: [node_proof.clone(),node_proof.clone()], + verifier_data: node_data.verifier_data(), + }; + + node_circ.assign_targets(&mut pw, &node_targ,&node_in)?; + + let node2_proof = node_data.prove(pw)?; + + node_data.verify(node2_proof.clone())?; + + + // ------------- node2 circuit ------------------ + // let config = CircuitConfig::standard_recursion_config(); + // let mut builder = CircuitBuilder::::new(config); + // + // let (proof_targ, vd_targ) = build_node_proof_circuit::(&mut builder,&node_data.common).unwrap(); + // // let leaf_targets = leaf_circuit.build::(&mut builder)?; + // + // let node2_data = builder.build::(); + // println!("node2 circuit size = {:?}", node2_data.common.degree_bits()); + // + // // serialize circuit into JSON + // let common_circuit_data_serialized = serde_json::to_string(&node2_data.common ).unwrap(); + // fs::write("node2_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + // + // // prove + // let mut pw = PartialWitness::::new(); + // pw.set_proof_with_pis_target(&proof_targ[0], &leaf_proof)?; + // pw.set_proof_with_pis_target(&proof_targ[1], &leaf_proof)?; + // pw.set_verifier_data_target(&vd_targ,&leaf_data.verifier_only)?; + // + // let node_proof = node2_data.prove(pw)?; + + + // prove node + // let mut pw = PartialWitness::::new(); + // pw.set_proof_with_pis_target(&proof_targ[0], &node_proof)?; + // pw.set_proof_with_pis_target(&proof_targ[1], &node_proof)?; + // pw.set_verifier_data_target(&vd_targ,&node_data.verifier_only)?; + // + // let node2_proof = node_data.prove(pw)?; + + + Ok(()) + } + + #[test] + fn test_uniform_recursion() -> anyhow::Result<()> { + // const N: usize = 2; // binary tree + // const M: usize = 1; // number of proofs in leaves + // const K: usize = 8; + + let config = CircuitConfig::standard_recursion_config(); + let mut sampling_builder = CircuitBuilder::::new(config); + + //------------ sampling inner circuit ---------------------- + // Circuit that does the sampling - default input + let mut params = Params::default(); + params.input_params.n_samples = 100; + params.circuit_params.n_samples = 100; + let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); + let samp_circ = SampleCircuit::::new(params.circuit_params); + 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::(); + println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); + let inner_proof = inner_data.prove(pw)?; + + // serialize circuit into JSON + let common_circuit_data_serialized = serde_json::to_string(&inner_data.common ).unwrap(); + fs::write("circ_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + + + // ------------------- leaf -------------------- + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config.clone()); + + let (proof_targ, vd_targ) = build_proof_ver_circuit::(&mut builder,&inner_data.common).unwrap(); + // let leaf_targets = leaf_circuit.build::(&mut builder)?; + + // // add a ConstantGate + // builder.add_gate( + // ConstantGate::new(config.num_constants), + // vec![], + // ); + + let leaf_data = builder.build::(); + println!("leaf circuit size = {:?}", leaf_data.common.degree_bits()); + + // serialize circuit into JSON + let common_circuit_data_serialized = serde_json::to_string(&leaf_data.common ).unwrap(); + fs::write("leaf_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + + // prove + let mut pw = PartialWitness::::new(); + pw.set_proof_with_pis_target(&proof_targ, &inner_proof)?; + pw.set_verifier_data_target(&vd_targ,&inner_data.verifier_only)?; + + let leaf_proof = leaf_data.prove(pw)?; + + // ------------- node1 circuit ------------------ + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + let (proof_targ, vd_targ) = build_node_proof_circuit::(&mut builder,&leaf_data.common).unwrap(); + // let leaf_targets = leaf_circuit.build::(&mut builder)?; + + let node_data = builder.build::(); + println!("node circuit size = {:?}", node_data.common.degree_bits()); + + // serialize circuit into JSON + let common_circuit_data_serialized = serde_json::to_string(&node_data.common ).unwrap(); + fs::write("node_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + + // prove + let mut pw = PartialWitness::::new(); + pw.set_proof_with_pis_target(&proof_targ[0], &leaf_proof)?; + pw.set_proof_with_pis_target(&proof_targ[1], &leaf_proof)?; + pw.set_verifier_data_target(&vd_targ,&leaf_data.verifier_only)?; + + let node_proof = node_data.prove(pw)?; + + + // ------------- node2 circuit ------------------ + // let config = CircuitConfig::standard_recursion_config(); + // let mut builder = CircuitBuilder::::new(config); + // + // let (proof_targ, vd_targ) = build_node_proof_circuit::(&mut builder,&node_data.common).unwrap(); + // // let leaf_targets = leaf_circuit.build::(&mut builder)?; + // + // let node2_data = builder.build::(); + // println!("node2 circuit size = {:?}", node2_data.common.degree_bits()); + // + // // serialize circuit into JSON + // let common_circuit_data_serialized = serde_json::to_string(&node2_data.common ).unwrap(); + // fs::write("node2_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); + // + // // prove + // let mut pw = PartialWitness::::new(); + // pw.set_proof_with_pis_target(&proof_targ[0], &leaf_proof)?; + // pw.set_proof_with_pis_target(&proof_targ[1], &leaf_proof)?; + // pw.set_verifier_data_target(&vd_targ,&leaf_data.verifier_only)?; + // + // let node_proof = node2_data.prove(pw)?; + + + // prove node + let mut pw = PartialWitness::::new(); + pw.set_proof_with_pis_target(&proof_targ[0], &node_proof)?; + pw.set_proof_with_pis_target(&proof_targ[1], &node_proof)?; + pw.set_verifier_data_target(&vd_targ,&node_data.verifier_only)?; + + let node2_proof = node_data.prove(pw)?; + + + Ok(()) + } + + /// builds the node circuit + pub fn build_proof_ver_circuit< + H: AlgebraicHasher, + >( + builder: &mut CircuitBuilder, + common_data: &CommonCircuitData, + ) -> anyhow::Result<(ProofWithPublicInputsTarget, VerifierCircuitTarget)>{ + + // the proof virtual targets + // let mut proof_targets = vec![]; + let mut inner_pub_input = vec![]; + // for _i in 0..N { + let vir_proof = builder.add_virtual_proof_with_pis(common_data); + // collect the public input + inner_pub_input.extend_from_slice(&vir_proof.public_inputs); + // collect the proof targets + // proof_targets.push(vir_proof); + // } + // hash the public input & make it public + let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(inner_pub_input); + builder.register_public_inputs(&hash_inner_pub_input.elements); + + // virtual target for the verifier data + let inner_verifier_data = builder.add_virtual_verifier_data(common_data.config.fri_config.cap_height); + + // verify the proofs in-circuit + // for i in 0..N { + builder.verify_proof::(&vir_proof,&inner_verifier_data,&common_data); + // } + // let proof_target_array = vec_to_array::>(proof_targets)?; + + Ok( + (vir_proof, + inner_verifier_data) + ) + } + + /// builds the node circuit + pub fn build_node_proof_circuit< + H: AlgebraicHasher, + >( + builder: &mut CircuitBuilder, + common_data: &CommonCircuitData, + ) -> anyhow::Result<(Vec>, VerifierCircuitTarget)>{ + + // the proof virtual targets + let mut proof_targets = vec![]; + let mut inner_pub_input = vec![]; + for _i in 0..2 { + let vir_proof = builder.add_virtual_proof_with_pis(common_data); + // collect the public input + inner_pub_input.extend_from_slice(&vir_proof.public_inputs); + // collect the proof targets + proof_targets.push(vir_proof); + } + // hash the public input & make it public + let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(inner_pub_input); + builder.register_public_inputs(&hash_inner_pub_input.elements); + + // virtual target for the verifier data + let inner_verifier_data = builder.add_virtual_verifier_data(common_data.config.fri_config.cap_height); + + // verify the proofs in-circuit + for i in 0..2 { + builder.verify_proof::(&proof_targets[i],&inner_verifier_data,&common_data); + } + // let proof_target_array = vec_to_array::>(proof_targets)?; + + Ok( + (proof_targets, + inner_verifier_data) + ) + } + +} \ No newline at end of file diff --git a/workflow/Cargo.toml b/workflow/Cargo.toml index 795733c..9c7f1a5 100644 --- a/workflow/Cargo.toml +++ b/workflow/Cargo.toml @@ -46,34 +46,6 @@ harness = false name = "sample_cells" harness = false -[[bench]] -name = "simple_recursion" -harness = false - -[[bench]] -name = "simple_recursion_hashed_pi" -harness = false - -[[bench]] -name = "cyclic_recursion" -harness = false - -[[bench]] -name = "tree_recursion1" -harness = false - -[[bench]] -name = "tree_recursion2" -harness = false - -[[bench]] -name = "simple_tree_recursion" -harness = false - -[[bench]] -name = "hybrid_recursion" -harness = false - [[bench]] name = "uniform_recursion" harness = false \ No newline at end of file diff --git a/workflow/benches/sample_cells.rs b/workflow/benches/sample_cells.rs index 7901ea5..dac23b2 100644 --- a/workflow/benches/sample_cells.rs +++ b/workflow/benches/sample_cells.rs @@ -44,9 +44,10 @@ fn bench_prove_verify(c: &mut Criterion) -> Result<()>{ b.iter(|| { let config = CircuitConfig::standard_recursion_config(); let mut local_builder = CircuitBuilder::::new(config); - let local_targets = targets.clone(); - let mut local_pw = pw.clone(); - circ.sample_slot_assign_witness(&mut local_pw, &local_targets, &circ_input.clone()); + let _targets = circ.sample_slot_circuit_with_public_input(&mut local_builder); + // let local_targets = targets.clone(); + // let mut local_pw = pw.clone(); + // circ.sample_slot_assign_witness(&mut local_pw, &local_targets, &circ_input.clone()); let _data = local_builder.build::(); }) }); @@ -58,14 +59,14 @@ fn bench_prove_verify(c: &mut Criterion) -> Result<()>{ println!("Build time: {:?}", build_duration); println!("Circuit size (degree bits): {:?}", data.common.degree_bits()); - let num_constr: usize = data.common - .gates - .iter() - .map(|gate| gate.0.num_constraints()) - .sum(); - - println!("Number of constraints: {}", num_constr); - println!("Number of gates used: {}", data.common.gates.len()); + // let num_constr: usize = data.common + // .gates + // .iter() + // .map(|gate| gate.0.num_constraints()) + // .sum(); + // + // println!("Number of constraints: {}", num_constr); + // println!("Number of gates used: {}", data.common.gates.len()); // Benchmark the Proving Phase group.bench_function("Prove Circuit", |b| { diff --git a/workflow/benches/uniform_recursion.rs b/workflow/benches/uniform_recursion.rs index 417d479..eb42613 100644 --- a/workflow/benches/uniform_recursion.rs +++ b/workflow/benches/uniform_recursion.rs @@ -11,9 +11,9 @@ use proof_input::gen_input::gen_testing_circuit_input; use proof_input::params::Params; /// Benchmark for building, proving, and verifying the Plonky2 tree recursion circuit. -fn bench_uniform_recursion(c: &mut Criterion) -> anyhow::Result<()>{ +fn bench_uniform_recursion(c: &mut Criterion) -> anyhow::Result<()>{ - let mut group = c.benchmark_group(format!("Uniform Tree Recursion Benchmark for N={}",N)); + let mut group = c.benchmark_group(format!("Uniform Tree Recursion Benchmark for aggregating {} proofs with params: N={}, M={}",K,N,M)); //------------ sampling inner circuit ---------------------- // Circuit that does the sampling - 100 samples @@ -35,12 +35,12 @@ fn bench_uniform_recursion(c: &mut Criterion) -> anyhow::Result // ------------------- tree -------------------- - let mut tree : Option> = None; + let mut tree : Option> = None; // Building phase group.bench_function("build tree", |b| { b.iter(|| { - tree = Some(TreeRecursion::::build(inner_data.common.clone()).unwrap()); + tree = Some(TreeRecursion::::build(inner_data.common.clone()).unwrap()); }) }); @@ -57,27 +57,31 @@ fn bench_uniform_recursion(c: &mut Criterion) -> anyhow::Result let proof = proof.unwrap(); + let inner_pi: Vec> = proofs.iter().map(|p| p.public_inputs.clone()).collect(); + // Verifying Phase - // group.bench_function("verify tree circuit", |b| { - // b.iter(|| { - // verifier_data.verify(proof.clone()).expect("verify fail"); - // }) - // }); + group.bench_function("verify root proof", |b| { + b.iter(|| { + tree.verify_proof_and_public_input(proof.clone(),inner_pi.clone(),&inner_data.verifier_data()) + }) + }); group.finish(); Ok(()) } fn bench_uniform_tree_recursion(c: &mut Criterion){ - const N: usize = 2; // number of child nodes - binary here - bench_uniform_recursion::<2>(c).expect("bench failed"); - bench_uniform_recursion::<4>(c).expect("bench failed"); - bench_uniform_recursion::<8>(c).expect("bench failed"); - bench_uniform_recursion::<16>(c).expect("bench failed"); - bench_uniform_recursion::<32>(c).expect("bench failed"); - bench_uniform_recursion::<64>(c).expect("bench failed"); - bench_uniform_recursion::<128>(c).expect("bench failed"); - bench_uniform_recursion::<256>(c).expect("bench failed"); + const K: usize = 32; // number of inner proofs to aggregate + const N: usize = 1; // number of inner proofs in the leaf + const M: usize = 2; // number of leaf proofs in the node + bench_uniform_recursion::<2, N, M>(c).expect("bench failed"); + bench_uniform_recursion::<4, N, M>(c).expect("bench failed"); + bench_uniform_recursion::<8, N, M>(c).expect("bench failed"); + bench_uniform_recursion::<16, N, M>(c).expect("bench failed"); + bench_uniform_recursion::<32, N, M>(c).expect("bench failed"); + bench_uniform_recursion::<64, N, M>(c).expect("bench failed"); + bench_uniform_recursion::<128, N, M>(c).expect("bench failed"); + bench_uniform_recursion::<256, N, M>(c).expect("bench failed"); } /// Criterion benchmark group