mirror of
https://github.com/logos-storage/proof-aggregation.git
synced 2026-01-02 13:53:13 +00:00
archive recursion experiments and refactor
This commit is contained in:
parent
db9bc823e2
commit
db4653a2a4
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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}};
|
||||
|
||||
@ -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 = <C as GenericConfig<D>>::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)
|
||||
|
||||
@ -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;
|
||||
pub mod uniform;
|
||||
@ -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<ProofWithPublicInputs<F, C, D>> = (0..16).map(|i| inner_proof.clone()).collect();
|
||||
let proofs: Vec<ProofWithPublicInputs<F, C, D>> = (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::<F,D,C,HF, N, M>::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());
|
||||
|
||||
|
||||
5
recursion_experiments/README.md
Normal file
5
recursion_experiments/README.md
Normal file
@ -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.
|
||||
@ -15,7 +15,7 @@ use proof_input::params::Params;
|
||||
/// Benchmark for building, proving, and verifying the Plonky2 tree recursion circuit.
|
||||
fn bench_hybrid_recursion<const N: usize, const M: usize, const K: usize>(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::<N,8,128>(c);
|
||||
bench_hybrid_recursion::<N,4,128>(c);
|
||||
// bench_hybrid_recursion::<N,M,K>(c);
|
||||
bench_hybrid_recursion::<N,4,4>(c);
|
||||
bench_hybrid_recursion::<N,8,8>(c);
|
||||
bench_hybrid_recursion::<N,4,16>(c);
|
||||
bench_hybrid_recursion::<N,8,16>(c);
|
||||
bench_hybrid_recursion::<N,16,16>(c);
|
||||
bench_hybrid_recursion::<N,8,32>(c);
|
||||
bench_hybrid_recursion::<N,16,32>(c);
|
||||
bench_hybrid_recursion::<N,32,32>(c);
|
||||
bench_hybrid_recursion::<N,16,64>(c);
|
||||
bench_hybrid_recursion::<N,32,64>(c);
|
||||
bench_hybrid_recursion::<N,16,128>(c);
|
||||
bench_hybrid_recursion::<4,16,128>(c);
|
||||
}
|
||||
|
||||
/// Criterion benchmark group
|
||||
89
recursion_experiments/benches/uniform_recursion.rs
Normal file
89
recursion_experiments/benches/uniform_recursion.rs
Normal file
@ -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<const N: usize,>(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::<F, D>::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::<F,D>(¶ms.input_params);
|
||||
let samp_circ = SampleCircuit::<F,D,HF>::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::<F>::new();
|
||||
samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?;
|
||||
let inner_data = sampling_builder.build::<C>();
|
||||
let inner_proof = inner_data.prove(pw.clone())?;
|
||||
|
||||
let proofs: Vec<ProofWithPublicInputs<F, C, D>> = (0..N).map(|i| inner_proof.clone()).collect();
|
||||
|
||||
// ------------------- tree --------------------
|
||||
|
||||
let mut tree : Option<TreeRecursion<F, D, C, HF>> = None;
|
||||
|
||||
// Building phase
|
||||
group.bench_function("build tree", |b| {
|
||||
b.iter(|| {
|
||||
tree = Some(TreeRecursion::<F,D,C,HF>::build(inner_data.common.clone()).unwrap());
|
||||
})
|
||||
});
|
||||
|
||||
let mut tree = tree.unwrap();
|
||||
|
||||
let mut proof: Option<ProofWithPublicInputs<F, C, D>> = 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);
|
||||
8
recursion_experiments/recursion/mod.rs
Normal file
8
recursion_experiments/recursion/mod.rs
Normal file
@ -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;
|
||||
139
recursion_experiments/recursion/uniform/leaf.rs
Normal file
139
recursion_experiments/recursion/uniform/leaf.rs
Normal file
@ -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<D> + Poseidon2,
|
||||
const D: usize,
|
||||
C: GenericConfig<D, F = F>,
|
||||
H: AlgebraicHasher<F>,
|
||||
const N: usize,
|
||||
> where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
inner_common_data: CommonCircuitData<F, D>,
|
||||
phantom_data: PhantomData<(C,H)>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LeafTargets <
|
||||
const D: usize,
|
||||
>{
|
||||
pub inner_proof: Vec<ProofWithPublicInputsTarget<D>>,
|
||||
pub verifier_data: VerifierCircuitTarget,
|
||||
}
|
||||
|
||||
impl<
|
||||
F: RichField + Extendable<D> + Poseidon2,
|
||||
const D: usize,
|
||||
C: GenericConfig<D, F = F>,
|
||||
H: AlgebraicHasher<F>,
|
||||
const N: usize,
|
||||
> LeafCircuit<F,D,C,H,N> where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
pub fn new(inner_common_data: CommonCircuitData<F,D>) -> Self {
|
||||
Self{
|
||||
inner_common_data,
|
||||
phantom_data:PhantomData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// build the leaf circuit
|
||||
pub fn build(&self, builder: &mut CircuitBuilder<F, D>) -> Result<LeafTargets<D>> {
|
||||
|
||||
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::<H>(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::<H>(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::<C>(&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<F>,
|
||||
targets: &LeafTargets<D>,
|
||||
inner_proof: &[ProofWithPublicInputs<F, C, D>],
|
||||
verifier_only_data: &VerifierOnlyCircuitData<C, D>,
|
||||
) -> 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<CircuitData<F, C, D>>
|
||||
where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
|
||||
self.build(&mut builder)?;
|
||||
|
||||
let circ_data = builder.build::<C>();
|
||||
|
||||
Ok(circ_data)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
3
recursion_experiments/recursion/uniform/mod.rs
Normal file
3
recursion_experiments/recursion/uniform/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod leaf;
|
||||
pub mod node;
|
||||
pub mod tree;
|
||||
152
recursion_experiments/recursion/uniform/node.rs
Normal file
152
recursion_experiments/recursion/uniform/node.rs
Normal file
@ -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<D> + Poseidon2,
|
||||
const D: usize,
|
||||
C: GenericConfig<D, F = F>,
|
||||
H: AlgebraicHasher<F>,
|
||||
const M: usize,
|
||||
> where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
leaf_common_data: CommonCircuitData<F, D>,
|
||||
phantom_data: PhantomData<(C,H)>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NodeTargets<
|
||||
const D: usize,
|
||||
>{
|
||||
pub leaf_proofs: Vec<ProofWithPublicInputsTarget<D>>,
|
||||
pub verifier_data: VerifierCircuitTarget,
|
||||
}
|
||||
|
||||
impl<
|
||||
F: RichField + Extendable<D> + Poseidon2,
|
||||
const D: usize,
|
||||
C: GenericConfig<D, F = F>,
|
||||
H: AlgebraicHasher<F>,
|
||||
const M: usize,
|
||||
> NodeCircuit<F,D,C,H,M> where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
|
||||
pub fn new(inner_common_data: CommonCircuitData<F,D>) -> Self {
|
||||
Self{
|
||||
leaf_common_data: inner_common_data,
|
||||
phantom_data:PhantomData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// build the leaf circuit
|
||||
pub fn build(&self, builder: &mut CircuitBuilder<F, D>) -> Result<NodeTargets<D>> {
|
||||
|
||||
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::<H>(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::<H>(vd_pub_input);
|
||||
inner_vd_hashes.extend_from_slice(&vd_hash.elements);
|
||||
let vd_hash_all = builder.hash_n_to_hash_no_pad::<H>(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::<C>(&vir_proofs[i], &inner_verifier_data, &inner_common);
|
||||
}
|
||||
|
||||
// let proofs = vec_to_array::<2, ProofWithPublicInputsTarget<D>>(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<F>,
|
||||
targets: &NodeTargets<D>,
|
||||
node_proofs: &[ProofWithPublicInputs<F, C, D>],
|
||||
verifier_only_data: &VerifierOnlyCircuitData<C, D>,
|
||||
) -> 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<CircuitData<F, C, D>>
|
||||
where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
|
||||
self.build(&mut builder)?;
|
||||
|
||||
let circ_data = builder.build::<C>();
|
||||
|
||||
Ok(circ_data)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
252
recursion_experiments/recursion/uniform/tree.rs
Normal file
252
recursion_experiments/recursion/uniform/tree.rs
Normal file
@ -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<D> + Poseidon2,
|
||||
const D: usize,
|
||||
C: GenericConfig<D, F = F>,
|
||||
H: AlgebraicHasher<F>,
|
||||
const N: usize,
|
||||
const M: usize,
|
||||
> where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
leaf: LeafCircuit<F, D, C, H, N>,
|
||||
node: NodeCircuit<F, D, C, H, M>,
|
||||
leaf_circ_data: CircuitData<F, C, D>,
|
||||
node_circ_data: CircuitData<F, C, D>,
|
||||
leaf_targets: LeafTargets<D>,
|
||||
node_targets: NodeTargets<D>,
|
||||
phantom_data: PhantomData<(H)>
|
||||
}
|
||||
|
||||
impl<
|
||||
F: RichField + Extendable<D> + Poseidon2,
|
||||
const D: usize,
|
||||
C: GenericConfig<D, F = F>,
|
||||
H: AlgebraicHasher<F>,
|
||||
const N: usize,
|
||||
const M: usize,
|
||||
> TreeRecursion<F, D, C, H, N, M> where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
|
||||
pub fn build(
|
||||
inner_common_data: CommonCircuitData<F,D>
|
||||
) -> Result<Self> {
|
||||
// build leaf with standard recursion config
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::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::<C>();
|
||||
// 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::<F, D>::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::<C>();
|
||||
// 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<F, C, D>{
|
||||
self.leaf_circ_data.verifier_data()
|
||||
}
|
||||
|
||||
pub fn get_node_verifier_data(&self) -> VerifierCircuitData<F, C, D>{
|
||||
self.node_circ_data.verifier_data()
|
||||
}
|
||||
|
||||
pub fn prove_tree
|
||||
(
|
||||
&mut self,
|
||||
proofs_with_pi: &[ProofWithPublicInputs<F, C, D>],
|
||||
inner_verifier_only_data: &VerifierOnlyCircuitData<C, D>,
|
||||
) -> Result<(ProofWithPublicInputs<F, C, D>)>
|
||||
{
|
||||
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<F, C, D>],
|
||||
inner_verifier_only_data: &VerifierOnlyCircuitData<C, D>,
|
||||
) -> Result<(Vec<ProofWithPublicInputs<F, C, D>>)> {
|
||||
|
||||
let mut leaf_proofs = vec![];
|
||||
|
||||
for proof in proofs_with_pi.chunks(N){
|
||||
let mut pw = PartialWitness::<F>::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<F, C, D>],
|
||||
verifier_only_data: &VerifierOnlyCircuitData<C, D>,
|
||||
) -> Result<(ProofWithPublicInputs<F, C, D>, VerifierOnlyCircuitData<C, D>)> where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
|
||||
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<F, C, D>,
|
||||
inner_public_input: Vec<Vec<F>>,
|
||||
inner_verifier_data: &VerifierCircuitData<F, C, D>) -> 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<F>, inner_public_input: Vec<Vec<F>>, inner_verifier_data: &VerifierCircuitData<F, C, D>) -> 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<F> = 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<F> = pi_chunk.iter()
|
||||
.flat_map(|h| h.elements.iter().cloned())
|
||||
.collect();
|
||||
let mut vd_chunk_f: Vec<F> = 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<F, C, D>) -> HashOut<F>{
|
||||
let mut vd = vec![];
|
||||
let digest: &HashOut<F> = &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<F>;
|
||||
vd.extend_from_slice(&cap_hash.elements);
|
||||
}
|
||||
|
||||
H::hash_no_pad(&vd)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
121
recursion_experiments/recursion/utils/conditional_verifier.rs
Normal file
121
recursion_experiments/recursion/utils/conditional_verifier.rs
Normal file
@ -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<F: RichField + Extendable<D> + Poseidon2, const D: usize ,C: GenericConfig<D, F = F> + 'static>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
condition: BoolTarget,
|
||||
cyclic_proof_with_pis: &ProofWithPublicInputsTarget<D>,
|
||||
verifier_data: &VerifierCircuitTarget,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
{
|
||||
let (dummy_proof_with_pis_target, dummy_verifier_data_target) =
|
||||
dummy_proof_and_vk_no_generator::<F, D, C>(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::<C>(
|
||||
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<F: RichField + Extendable<D> + Poseidon2, const D: usize ,C: GenericConfig<D, F = F> + 'static>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
condition: BoolTarget,
|
||||
proof_with_pis: &ProofWithPublicInputsTarget<D>,
|
||||
inner_verifier_data: &VerifierCircuitTarget,
|
||||
inner_common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
{
|
||||
let (dummy_proof_with_pis_target, dummy_verifier_data_target) =
|
||||
dummy_proof_and_vk_no_generator::<F, D, C>(builder, inner_common_data)?;
|
||||
builder.conditionally_verify_proof::<C>(
|
||||
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<F: RichField + Extendable<D> + Poseidon2, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> CircuitData<F, C, D> {
|
||||
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::<F, D>::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::<C>();
|
||||
assert_eq!(&circuit.common, common_data);
|
||||
circuit
|
||||
}
|
||||
|
||||
pub(crate) fn dummy_proof_and_vk_no_generator<F: RichField + Extendable<D> + Poseidon2, const D: usize ,C: GenericConfig<D, F = F> + 'static> (
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<(ProofWithPublicInputsTarget<D>, VerifierCircuitTarget)>
|
||||
where
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
{
|
||||
let dummy_circuit = dummy_circuit::<F, C, D>(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))
|
||||
}
|
||||
79
recursion_experiments/recursion/utils/dummy_gen.rs
Normal file
79
recursion_experiments/recursion/utils/dummy_gen.rs
Normal file
@ -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<D> + Poseidon2,
|
||||
const D: usize,
|
||||
C: GenericConfig<D, F = F>,
|
||||
> where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
phantom_data: PhantomData<(F,C)>,
|
||||
}
|
||||
|
||||
impl<
|
||||
F: RichField + Extendable<D> + Poseidon2,
|
||||
const D: usize,
|
||||
C: GenericConfig<D, F = F>,
|
||||
> DummyProofGen<F, D, C>
|
||||
where
|
||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
||||
{
|
||||
|
||||
/// Generates a single dummy leaf proof.
|
||||
pub fn gen_dummy_leaf_proof(
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> Result<ProofWithPublicInputs<F, C, D>> {
|
||||
dummy_proof::<F, C, D>(&dummy_circuit::<F, C, D>(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<F, D>,
|
||||
node_verifier_only_data: &VerifierOnlyCircuitData<C, D>,
|
||||
) -> ProofWithPublicInputs<F, C, D> {
|
||||
Self::recursion_base_proof(node_common, HashMap::new())
|
||||
}
|
||||
|
||||
fn recursion_base_proof(
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
mut nonzero_public_inputs: HashMap<usize, F>
|
||||
) -> ProofWithPublicInputs<F, C, D>{
|
||||
dummy_proof::<F, C, D>(
|
||||
&dummy_circuit::<F, C, D>(common_data),
|
||||
nonzero_public_inputs,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Generates an array of `N` dummy leaf proofs.
|
||||
pub fn gen_n_dummy_leaf_proofs<const N: usize>(
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> Result<[ProofWithPublicInputs<F, C, D>; N]> {
|
||||
let dummy_proof = Self::gen_dummy_leaf_proof(common_data)?;
|
||||
let n_dummy_vec = (0..N).map(|_| dummy_proof.clone()).collect::<Vec<_>>();
|
||||
vec_to_array::<N, ProofWithPublicInputs<F, C, D>>(n_dummy_vec)
|
||||
}
|
||||
|
||||
/// Generates an array of `N` dummy node proofs.
|
||||
pub fn gen_n_dummy_node_proofs<const N: usize>(
|
||||
node_common: &CommonCircuitData<F, D>,
|
||||
node_verifier_only_data: &VerifierOnlyCircuitData<C, D>,
|
||||
) -> Result<[ProofWithPublicInputs<F, C, D>; 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<_>>();
|
||||
vec_to_array::<N, ProofWithPublicInputs<F, C, D>>(n_dummy_vec)
|
||||
}
|
||||
}
|
||||
2
recursion_experiments/recursion/utils/mod.rs
Normal file
2
recursion_experiments/recursion/utils/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod dummy_gen;
|
||||
pub mod conditional_verifier;
|
||||
7
recursion_experiments/tests/mod.rs
Normal file
7
recursion_experiments/tests/mod.rs
Normal file
@ -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;
|
||||
67
recursion_experiments/tests/uniform.rs
Normal file
67
recursion_experiments/tests/uniform.rs
Normal file
@ -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::<F, D>::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::<F,D>(¶ms.input_params);
|
||||
let samp_circ = SampleCircuit::<F,D,HF>::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::<F>::new();
|
||||
samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?;
|
||||
let inner_data = sampling_builder.build::<C>();
|
||||
println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits());
|
||||
let inner_proof = inner_data.prove(pw)?;
|
||||
|
||||
let proofs: Vec<ProofWithPublicInputs<F, C, D>> = (0..16).map(|i| inner_proof.clone()).collect();
|
||||
|
||||
// ------------------- tree --------------------
|
||||
const N: usize = 1;
|
||||
const M: usize = 4;
|
||||
|
||||
let mut tree = TreeRecursion::<F,D,C,HF, N, M>::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<Vec<F>> = 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(())
|
||||
}
|
||||
}
|
||||
395
recursion_experiments/tests/uniform_arch.rs
Normal file
395
recursion_experiments/tests/uniform_arch.rs
Normal file
@ -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::<F, D>::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::<F,D>(¶ms.input_params);
|
||||
let samp_circ = SampleCircuit::<F,D,HF>::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::<F>::new();
|
||||
samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?;
|
||||
let inner_data = sampling_builder.build::<C>();
|
||||
println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits());
|
||||
let inner_proof = inner_data.prove(pw)?;
|
||||
|
||||
let proofs: Vec<ProofWithPublicInputs<F, C, D>> = (0..4).map(|i| inner_proof.clone()).collect();
|
||||
|
||||
// ------------------- tree --------------------
|
||||
|
||||
let mut tree = TreeRecursion::<F,D,C,HF>::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::<F, D>::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::<F,D>(¶ms.input_params);
|
||||
let samp_circ = SampleCircuit::<F,D,HF>::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::<F>::new();
|
||||
samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?;
|
||||
let inner_data = sampling_builder.build::<C>();
|
||||
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::<F, D>::new(config.clone());
|
||||
|
||||
let leaf_circ = LeafCircuit::<F,D,C,HF>::new(inner_data.common.clone());
|
||||
let leaf_targ = leaf_circ.build(&mut builder)?;
|
||||
|
||||
// let (proof_targ, vd_targ) = build_proof_ver_circuit::<HF>(&mut builder,&inner_data.common).unwrap();
|
||||
// let leaf_targets = leaf_circuit.build::<C,HF>(&mut builder)?;
|
||||
|
||||
// // add a ConstantGate
|
||||
// builder.add_gate(
|
||||
// ConstantGate::new(config.num_constants),
|
||||
// vec![],
|
||||
// );
|
||||
|
||||
let leaf_data = builder.build::<C>();
|
||||
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::<F>::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::<F, D>::new(config);
|
||||
|
||||
let node_circ = NodeCircuit::<F,D,C,HF>::new(leaf_data.common.clone());
|
||||
let node_targ = node_circ.build(&mut builder)?;
|
||||
|
||||
// let (proof_targ, vd_targ) = build_node_proof_circuit::<HF>(&mut builder,&leaf_data.common).unwrap();
|
||||
// let leaf_targets = leaf_circuit.build::<C,HF>(&mut builder)?;
|
||||
|
||||
let node_data = builder.build::<C>();
|
||||
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::<F>::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::<F>::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::<F, D>::new(config);
|
||||
//
|
||||
// let (proof_targ, vd_targ) = build_node_proof_circuit::<HF>(&mut builder,&node_data.common).unwrap();
|
||||
// // let leaf_targets = leaf_circuit.build::<C,HF>(&mut builder)?;
|
||||
//
|
||||
// let node2_data = builder.build::<C>();
|
||||
// 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::<F>::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::<F>::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::<F, D>::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::<F,D>(¶ms.input_params);
|
||||
let samp_circ = SampleCircuit::<F,D,HF>::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::<F>::new();
|
||||
samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?;
|
||||
let inner_data = sampling_builder.build::<C>();
|
||||
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::<F, D>::new(config.clone());
|
||||
|
||||
let (proof_targ, vd_targ) = build_proof_ver_circuit::<HF>(&mut builder,&inner_data.common).unwrap();
|
||||
// let leaf_targets = leaf_circuit.build::<C,HF>(&mut builder)?;
|
||||
|
||||
// // add a ConstantGate
|
||||
// builder.add_gate(
|
||||
// ConstantGate::new(config.num_constants),
|
||||
// vec![],
|
||||
// );
|
||||
|
||||
let leaf_data = builder.build::<C>();
|
||||
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::<F>::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::<F, D>::new(config);
|
||||
|
||||
let (proof_targ, vd_targ) = build_node_proof_circuit::<HF>(&mut builder,&leaf_data.common).unwrap();
|
||||
// let leaf_targets = leaf_circuit.build::<C,HF>(&mut builder)?;
|
||||
|
||||
let node_data = builder.build::<C>();
|
||||
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::<F>::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::<F, D>::new(config);
|
||||
//
|
||||
// let (proof_targ, vd_targ) = build_node_proof_circuit::<HF>(&mut builder,&node_data.common).unwrap();
|
||||
// // let leaf_targets = leaf_circuit.build::<C,HF>(&mut builder)?;
|
||||
//
|
||||
// let node2_data = builder.build::<C>();
|
||||
// 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::<F>::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::<F>::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<F>,
|
||||
>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<(ProofWithPublicInputsTarget<D>, 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::<H>(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::<C>(&vir_proof,&inner_verifier_data,&common_data);
|
||||
// }
|
||||
// let proof_target_array = vec_to_array::<N,ProofWithPublicInputsTarget<D>>(proof_targets)?;
|
||||
|
||||
Ok(
|
||||
(vir_proof,
|
||||
inner_verifier_data)
|
||||
)
|
||||
}
|
||||
|
||||
/// builds the node circuit
|
||||
pub fn build_node_proof_circuit<
|
||||
H: AlgebraicHasher<F>,
|
||||
>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<(Vec<ProofWithPublicInputsTarget<D>>, 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::<H>(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::<C>(&proof_targets[i],&inner_verifier_data,&common_data);
|
||||
}
|
||||
// let proof_target_array = vec_to_array::<N,ProofWithPublicInputsTarget<D>>(proof_targets)?;
|
||||
|
||||
Ok(
|
||||
(proof_targets,
|
||||
inner_verifier_data)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
@ -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::<F, D>::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::<C>();
|
||||
})
|
||||
});
|
||||
@ -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| {
|
||||
|
||||
@ -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<const N: usize,>(c: &mut Criterion) -> anyhow::Result<()>{
|
||||
fn bench_uniform_recursion<const K: usize,const N: usize,const M: usize,>(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<const N: usize,>(c: &mut Criterion) -> anyhow::Result
|
||||
|
||||
// ------------------- tree --------------------
|
||||
|
||||
let mut tree : Option<TreeRecursion<F, D, C, HF>> = None;
|
||||
let mut tree : Option<TreeRecursion<F, D, C, HF, N, M>> = None;
|
||||
|
||||
// Building phase
|
||||
group.bench_function("build tree", |b| {
|
||||
b.iter(|| {
|
||||
tree = Some(TreeRecursion::<F,D,C,HF>::build(inner_data.common.clone()).unwrap());
|
||||
tree = Some(TreeRecursion::<F,D,C,HF, N, M>::build(inner_data.common.clone()).unwrap());
|
||||
})
|
||||
});
|
||||
|
||||
@ -57,27 +57,31 @@ fn bench_uniform_recursion<const N: usize,>(c: &mut Criterion) -> anyhow::Result
|
||||
|
||||
let proof = proof.unwrap();
|
||||
|
||||
let inner_pi: Vec<Vec<F>> = 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user