mirror of
https://github.com/codex-storage/proof-aggregation.git
synced 2025-02-09 13:23:45 +00:00
add simple tree recursion
This commit is contained in:
parent
4bb1b74293
commit
64bc34b218
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[workspace]
|
||||
members = ["codex-plonky2-circuits","plonky2_poseidon2","proof-input","workflow"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = { version = "1.0.89", default-features = false}
|
||||
unroll = { version = "0.1.5", default-features = false }
|
||||
plonky2 = { version = "1.0.0", default-features = false }
|
||||
plonky2_field = { version = "1.0.0", default-features = false }
|
||||
plonky2_maybe_rayon = { version = "0.2.0", default-features = false }
|
||||
itertools = { version = "0.12.1", default-features = false }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
homepage = "https://github.com/codex-storage/proof-aggregation"
|
||||
repository = "https://github.com/codex-storage/proof-aggregation"
|
||||
keywords = ["cryptography", "SNARK", "plonky2", "Codex"]
|
||||
categories = ["cryptography"]
|
@ -3,20 +3,20 @@ name = "codex-plonky2-circuits"
|
||||
description = "Codex storage proofs circuits for Plonky2"
|
||||
authors = ["Mohammed Alghazwi <m.ghazwi@gmail.com>"]
|
||||
readme = "README.md"
|
||||
version = "0.1.0"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.89" }
|
||||
unroll = { version = "0.1.5", default-features = false }
|
||||
serde = { version = "1.0.210" , features = ["rc"] }
|
||||
serde_json = { version = "1.0" }
|
||||
plonky2 = { version = "1.0.0" }
|
||||
plonky2_field = { version = "1.0.0", default-features = false }
|
||||
anyhow = { workplace = true }
|
||||
unroll = { workplace = true }
|
||||
serde = { workplace = true }
|
||||
serde_json = { workplace = true }
|
||||
plonky2 = { workplace = true }
|
||||
plonky2_field = { workplace = true }
|
||||
plonky2_poseidon2 = { path = "../plonky2_poseidon2" }
|
||||
itertools = { version = "0.12.1", default-features = false }
|
||||
plonky2_maybe_rayon = { version = "0.2.0", default-features = false }
|
||||
rand = "0.8.5"
|
||||
itertools = { workplace = true }
|
||||
plonky2_maybe_rayon = { workplace = true }
|
||||
hashbrown = "0.14.5"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.5.1", default-features = false }
|
||||
|
BIN
codex-plonky2-circuits/inner_circ_data.bin
Normal file
BIN
codex-plonky2-circuits/inner_circ_data.bin
Normal file
Binary file not shown.
BIN
codex-plonky2-circuits/outer_circ_data.bin
Normal file
BIN
codex-plonky2-circuits/outer_circ_data.bin
Normal file
Binary file not shown.
@ -4,4 +4,3 @@ pub mod utils;
|
||||
pub mod params;
|
||||
pub mod keyed_compress;
|
||||
pub mod sponge;
|
||||
pub mod recursion;
|
@ -1,60 +0,0 @@
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{VerifierCircuitData, VerifierCircuitTarget};
|
||||
use plonky2::plonk::config::GenericConfig;
|
||||
use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget};
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||
use plonky2_poseidon2::config::Poseidon2GoldilocksConfig;
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||
|
||||
// recursion param
|
||||
|
||||
pub type F = GoldilocksField;
|
||||
pub const D: usize = 2;
|
||||
pub type C = Poseidon2GoldilocksConfig;
|
||||
pub type Plonky2Proof = ProofWithPublicInputs<F, C, D>;
|
||||
|
||||
/// aggregate sampling proofs
|
||||
pub fn aggregate_sampling_proofs<
|
||||
>(
|
||||
proofs_with_pi: Vec<Plonky2Proof>,
|
||||
verifier_data: &VerifierCircuitData<F, C, D>,
|
||||
builder: &mut CircuitBuilder::<F, D>,
|
||||
pw: &mut PartialWitness<F>,
|
||||
){
|
||||
// assert the number of proofs equals D
|
||||
assert_eq!(proofs_with_pi.len(), D, "Number of proofs to aggregate is not supported");
|
||||
|
||||
// the proof virtual targets
|
||||
let mut proof_targets = vec![];
|
||||
for i in 0..D {
|
||||
let vir_proof = builder.add_virtual_proof_with_pis(&verifier_data.common);
|
||||
proof_targets.push(vir_proof);
|
||||
}
|
||||
// assign the proofs with public input
|
||||
for i in 0..D{
|
||||
pw.set_proof_with_pis_target(&proof_targets[i],&proofs_with_pi[i]);
|
||||
}
|
||||
|
||||
let vd_target = VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder
|
||||
.add_virtual_cap(verifier_data.common.config.fri_config.cap_height),
|
||||
circuit_digest: builder.add_virtual_hash(),
|
||||
};
|
||||
pw.set_cap_target(
|
||||
&vd_target.constants_sigmas_cap,
|
||||
&verifier_data.verifier_only.constants_sigmas_cap,
|
||||
);
|
||||
pw.set_hash_target(
|
||||
vd_target.circuit_digest,
|
||||
verifier_data.verifier_only.circuit_digest,
|
||||
);
|
||||
|
||||
// verify the proofs in-circuit
|
||||
for i in 0..D {
|
||||
builder.verify_proof::<C>(&proof_targets[i],&vd_target,&verifier_data.common);
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
use std::{fs, io};
|
||||
use std::path::Path;
|
||||
use plonky2::hash::hash_types::{HashOutTarget, NUM_HASH_OUT_ELTS, RichField};
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2_field::extension::Extendable;
|
||||
@ -82,4 +84,9 @@ pub fn add_assign_hash_out_target<
|
||||
for i in 0..NUM_HASH_OUT_ELTS {
|
||||
mut_hot.elements[i] = (builder.add(mut_hot.elements[i], hot.elements[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the contents of the specified file and returns them as a vector of bytes using `std::fs::read`.
|
||||
pub fn read_bytes_from_file<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
||||
fs::read(path)
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
pub mod circuits;
|
||||
pub mod merkle_tree;
|
||||
pub mod recursion;
|
||||
|
8
codex-plonky2-circuits/src/recursion/mod.rs
Normal file
8
codex-plonky2-circuits/src/recursion/mod.rs
Normal file
@ -0,0 +1,8 @@
|
||||
pub mod structs;
|
||||
pub mod traits;
|
||||
pub mod simple_recursion;
|
||||
pub mod simple_recursion2;
|
||||
pub mod tree_recursion;
|
||||
pub mod params;
|
||||
pub mod sampling;
|
||||
|
22
codex-plonky2-circuits/src/recursion/params.rs
Normal file
22
codex-plonky2-circuits/src/recursion/params.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use plonky2::plonk::proof::ProofWithPublicInputs;
|
||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||
use plonky2_poseidon2::config::Poseidon2GoldilocksConfig;
|
||||
|
||||
// recursion param
|
||||
pub type F = GoldilocksField;
|
||||
pub const D: usize = 2;
|
||||
pub type C = Poseidon2GoldilocksConfig;
|
||||
pub type Plonky2Proof = ProofWithPublicInputs<F, C, D>;
|
||||
|
||||
|
||||
pub struct RecursionTreeParams{
|
||||
pub tree_width: usize,
|
||||
}
|
||||
|
||||
impl RecursionTreeParams {
|
||||
pub fn new(tree_width: usize) -> Self{
|
||||
Self{
|
||||
tree_width
|
||||
}
|
||||
}
|
||||
}
|
28
codex-plonky2-circuits/src/recursion/sampling.rs
Normal file
28
codex-plonky2-circuits/src/recursion/sampling.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use plonky2::iop::target::BoolTarget;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::circuits::params::CircuitParams;
|
||||
use crate::circuits::sample_cells::{SampleCircuit, SampleCircuitInput, SampleTargets};
|
||||
use crate::recursion::params::{D, F};
|
||||
use crate::recursion::traits::InnerCircuit;
|
||||
|
||||
pub struct SamplingRecursion {}
|
||||
|
||||
impl InnerCircuit for SamplingRecursion{
|
||||
type Targets = SampleTargets;
|
||||
type Input = SampleCircuitInput<F, D>;
|
||||
|
||||
/// build the circuit
|
||||
/// TODO: this build the circuit with default circuit params -> make it generic
|
||||
fn build(builder: &mut CircuitBuilder<F, D>) -> anyhow::Result<Self::Targets> {
|
||||
let circ = SampleCircuit::new(CircuitParams::default());
|
||||
Ok(circ.sample_slot_circuit(builder))
|
||||
}
|
||||
|
||||
fn assign_targets(pw: &mut PartialWitness<F>, targets: &Self::Targets, input: &Self::Input) -> anyhow::Result<()> {
|
||||
let circ = SampleCircuit::<F,D>::new(CircuitParams::default());
|
||||
// circ.sample_slot_assign_witness(pw,targets,input);
|
||||
todo!()
|
||||
// Ok(())
|
||||
}
|
||||
}
|
167
codex-plonky2-circuits/src/recursion/simple_recursion.rs
Normal file
167
codex-plonky2-circuits/src/recursion/simple_recursion.rs
Normal file
@ -0,0 +1,167 @@
|
||||
use plonky2::hash::hash_types::{HashOut, HashOutTarget, RichField};
|
||||
use plonky2::iop::target::Target;
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, VerifierCircuitData, VerifierCircuitTarget};
|
||||
use plonky2::plonk::config::GenericConfig;
|
||||
use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget};
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||
use plonky2_poseidon2::config::Poseidon2GoldilocksConfig;
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||
use plonky2_poseidon2::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer};
|
||||
use crate::circuits::utils::read_bytes_from_file;
|
||||
use crate::recursion::params::{F,C,D,Plonky2Proof};
|
||||
|
||||
/// aggregate sampling proofs
|
||||
pub fn aggregate_sampling_proofs<
|
||||
>(
|
||||
proofs_with_pi: &Vec<Plonky2Proof>,
|
||||
verifier_data: &VerifierCircuitData<F, C, D>,
|
||||
builder: &mut CircuitBuilder::<F, D>,
|
||||
pw: &mut PartialWitness<F>,
|
||||
)-> anyhow::Result<()>{
|
||||
// the proof virtual targets
|
||||
let mut proof_targets = vec![];
|
||||
let mut inner_entropy_targets = vec![];
|
||||
let num_pub_input = proofs_with_pi[0].public_inputs.len(); // assuming num of public input is the same for all proofs
|
||||
for i in 0..proofs_with_pi.len() {
|
||||
let vir_proof = builder.add_virtual_proof_with_pis(&verifier_data.common);
|
||||
// register the inner public input as public input
|
||||
// only register the slot index and dataset root, entropy later
|
||||
// assuming public input are ordered:
|
||||
// [slot_root (1 element), dataset_root (4 element), entropy (4 element)]
|
||||
for j in 0..(num_pub_input-4){
|
||||
builder.register_public_input(vir_proof.public_inputs[j]);
|
||||
}
|
||||
// collect entropy targets
|
||||
let mut entropy_i = vec![];
|
||||
for k in (num_pub_input-4)..num_pub_input{
|
||||
entropy_i.push(vir_proof.public_inputs[k])
|
||||
}
|
||||
inner_entropy_targets.push(entropy_i);
|
||||
proof_targets.push(vir_proof);
|
||||
}
|
||||
// assign the proofs with public input
|
||||
for i in 0..proofs_with_pi.len(){
|
||||
pw.set_proof_with_pis_target(&proof_targets[i],&proofs_with_pi[i])?;
|
||||
}
|
||||
// virtual target for the verifier data
|
||||
let inner_verifier_data = builder.add_virtual_verifier_data(verifier_data.common.config.fri_config.cap_height);
|
||||
|
||||
// assign the verifier data
|
||||
pw.set_cap_target(
|
||||
&inner_verifier_data.constants_sigmas_cap,
|
||||
&verifier_data.verifier_only.constants_sigmas_cap,
|
||||
)?;
|
||||
pw.set_hash_target(inner_verifier_data.circuit_digest, verifier_data.verifier_only.circuit_digest)?;
|
||||
|
||||
// verify the proofs in-circuit
|
||||
for i in 0..proofs_with_pi.len() {
|
||||
builder.verify_proof::<C>(&proof_targets[i],&inner_verifier_data,&verifier_data.common);
|
||||
}
|
||||
|
||||
// register entropy as public input
|
||||
let outer_entropy_target = builder.add_virtual_hash_public_input();
|
||||
let entropy_as_hash = HashOut::from_vec(
|
||||
[
|
||||
proofs_with_pi[0].public_inputs[num_pub_input-4],
|
||||
proofs_with_pi[0].public_inputs[num_pub_input-3],
|
||||
proofs_with_pi[0].public_inputs[num_pub_input-2],
|
||||
proofs_with_pi[0].public_inputs[num_pub_input-1]
|
||||
].to_vec()
|
||||
); // entropy is last 4 elements
|
||||
pw.set_hash_target(outer_entropy_target, entropy_as_hash)?;
|
||||
// connect the public input of the recursion circuit to the inner proofs
|
||||
for i in 0..proofs_with_pi.len() {
|
||||
for j in 0..4 {
|
||||
builder.connect(inner_entropy_targets[i][j], outer_entropy_target.elements[j]);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// recursion tree width or the number of proofs in each node in the tree
|
||||
const RECURSION_TREE_WIDTH: usize = 2;
|
||||
|
||||
/// aggregate sampling proofs in tree like structure
|
||||
/// uses the const params: `RECURSION_TREE_WIDTH`
|
||||
pub fn aggregate_sampling_proofs_tree(
|
||||
proofs_with_pi: &[ProofWithPublicInputs<F, C, D>],
|
||||
data: CircuitData<F, C, D>,
|
||||
) -> anyhow::Result<(ProofWithPublicInputs<F, C, D>, CircuitData<F, C, D>)> {
|
||||
// base case: if only one proof remains, return it
|
||||
if proofs_with_pi.len() == 1 {
|
||||
return Ok((proofs_with_pi[0].clone(), data));
|
||||
}
|
||||
|
||||
let mut new_proofs = vec![];
|
||||
let mut new_circuit_data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// group proofs according to the tree's width
|
||||
for chunk in proofs_with_pi.chunks(RECURSION_TREE_WIDTH) {
|
||||
let proofs_chunk = chunk.to_vec();
|
||||
|
||||
// Build an inner-circuit to verify and aggregate the proofs in the chunk
|
||||
let inner_config = CircuitConfig::standard_recursion_config();
|
||||
let mut inner_builder = CircuitBuilder::<F, D>::new(inner_config);
|
||||
let mut inner_pw = PartialWitness::new();
|
||||
|
||||
// aggregate proofs
|
||||
aggregate_sampling_proofs(
|
||||
&proofs_chunk,
|
||||
&data.verifier_data(),
|
||||
&mut inner_builder,
|
||||
&mut inner_pw,
|
||||
)?;
|
||||
|
||||
// Build the inner-circuit
|
||||
// this causes major delay - we can load it but better if we split build and prove
|
||||
let inner_data = inner_builder.build::<C>();
|
||||
|
||||
// Prove the inner-circuit
|
||||
let proof = inner_data.prove(inner_pw)?;
|
||||
new_proofs.push(proof);
|
||||
new_circuit_data = Some(inner_data);
|
||||
}
|
||||
|
||||
// Recursively aggregate the new proofs
|
||||
aggregate_sampling_proofs_tree(&new_proofs, new_circuit_data.unwrap())
|
||||
}
|
||||
|
||||
/// same as above but takes `VerifierCircuitData`
|
||||
pub fn aggregate_sampling_proofs_tree2(
|
||||
proofs_with_pi: &[ProofWithPublicInputs<F, C, D>],
|
||||
vd: VerifierCircuitData<F, C, D>
|
||||
) -> anyhow::Result<(ProofWithPublicInputs<F, C, D>, VerifierCircuitData<F, C, D>)> {
|
||||
if proofs_with_pi.len() == 1 {
|
||||
return Ok((proofs_with_pi[0].clone(), vd));
|
||||
}
|
||||
|
||||
let mut new_proofs = vec![];
|
||||
let mut new_circuit_data: Option<VerifierCircuitData<F, C, D>> = None;
|
||||
|
||||
for chunk in proofs_with_pi.chunks(RECURSION_TREE_WIDTH) {
|
||||
let proofs_chunk = chunk.to_vec();
|
||||
|
||||
let inner_config = CircuitConfig::standard_recursion_config();
|
||||
let mut inner_builder = CircuitBuilder::<F, D>::new(inner_config);
|
||||
let mut inner_pw = PartialWitness::new();
|
||||
|
||||
aggregate_sampling_proofs(
|
||||
&proofs_chunk,
|
||||
&vd,
|
||||
&mut inner_builder,
|
||||
&mut inner_pw,
|
||||
)?;
|
||||
|
||||
let inner_data = inner_builder.build::<C>();
|
||||
|
||||
let proof = inner_data.prove(inner_pw)?;
|
||||
new_proofs.push(proof);
|
||||
new_circuit_data = Some(inner_data.verifier_data());
|
||||
}
|
||||
|
||||
aggregate_sampling_proofs_tree2(&new_proofs, new_circuit_data.unwrap())
|
||||
}
|
135
codex-plonky2-circuits/src/recursion/simple_recursion2.rs
Normal file
135
codex-plonky2-circuits/src/recursion/simple_recursion2.rs
Normal file
@ -0,0 +1,135 @@
|
||||
use plonky2::hash::hash_types::{HashOut, HashOutTarget, RichField};
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{VerifierCircuitData, VerifierCircuitTarget};
|
||||
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::params::RecursionTreeParams;
|
||||
|
||||
pub struct SimpleRecursionCircuit<
|
||||
F: RichField + Extendable<D> + Poseidon2,
|
||||
C: GenericConfig<D, F = F>,
|
||||
const D: usize,
|
||||
>{
|
||||
pub recursion_tree_params: RecursionTreeParams,
|
||||
pub verifier_data: VerifierCircuitData<F, C, D>
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SimpleRecursionTargets<
|
||||
const D: usize,
|
||||
> {
|
||||
pub proofs_with_pi: Vec<ProofWithPublicInputsTarget<D>>,
|
||||
pub verifier_data: VerifierCircuitTarget,
|
||||
pub entropy: HashOutTarget,
|
||||
}
|
||||
|
||||
pub struct SimpleRecursionInput<
|
||||
F: RichField + Extendable<D> + Poseidon2,
|
||||
C: GenericConfig<D, F = F>,
|
||||
const D: usize,
|
||||
>{
|
||||
pub proofs: Vec<ProofWithPublicInputs<F, C, D>>,
|
||||
pub verifier_data: VerifierCircuitData<F, C, D>,
|
||||
pub entropy: HashOut<F>,
|
||||
}
|
||||
|
||||
impl<
|
||||
F: RichField + Extendable<D> + Poseidon2,
|
||||
C: GenericConfig<D, F = F>,
|
||||
const D: usize,
|
||||
> SimpleRecursionCircuit<F,C,D> where
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
{
|
||||
|
||||
pub fn new(
|
||||
recursion_tree_params: RecursionTreeParams,
|
||||
verifier_data: VerifierCircuitData<F, C, D>
|
||||
)->Self{
|
||||
Self{
|
||||
recursion_tree_params,
|
||||
verifier_data,
|
||||
}
|
||||
}
|
||||
|
||||
/// contains the circuit logic and returns the witness & public input targets
|
||||
pub fn build_circuit(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder::<F, D>,
|
||||
) -> SimpleRecursionTargets<D> {
|
||||
// the proof virtual targets
|
||||
let mut proof_targets = vec![];
|
||||
let mut inner_entropy_targets = vec![];
|
||||
|
||||
for i in 0..self.recursion_tree_params.tree_width {
|
||||
let vir_proof = builder.add_virtual_proof_with_pis(&self.verifier_data.common);
|
||||
// register the inner public input as public input
|
||||
// only register the slot index and dataset root, entropy later
|
||||
// assuming public input are ordered:
|
||||
// [slot_root (1 element), dataset_root (4 element), entropy (4 element)]
|
||||
let num_pub_input = vir_proof.public_inputs.len();
|
||||
for j in 0..(num_pub_input-4){
|
||||
builder.register_public_input(vir_proof.public_inputs[j]);
|
||||
}
|
||||
// collect entropy targets
|
||||
let mut entropy_i = vec![];
|
||||
for k in (num_pub_input-4)..num_pub_input{
|
||||
entropy_i.push(vir_proof.public_inputs[k])
|
||||
}
|
||||
inner_entropy_targets.push(entropy_i);
|
||||
proof_targets.push(vir_proof);
|
||||
}
|
||||
// virtual target for the verifier data
|
||||
let inner_verifier_data = builder.add_virtual_verifier_data(self.verifier_data.common.config.fri_config.cap_height);
|
||||
|
||||
// verify the proofs in-circuit
|
||||
for i in 0..self.recursion_tree_params.tree_width {
|
||||
builder.verify_proof::<C>(&proof_targets[i],&inner_verifier_data,&self.verifier_data.common);
|
||||
}
|
||||
|
||||
// register entropy as public input
|
||||
let outer_entropy_target = builder.add_virtual_hash_public_input();
|
||||
|
||||
// connect the public input of the recursion circuit to the inner proofs
|
||||
for i in 0..self.recursion_tree_params.tree_width {
|
||||
for j in 0..4 {
|
||||
builder.connect(inner_entropy_targets[i][j], outer_entropy_target.elements[j]);
|
||||
}
|
||||
}
|
||||
// return targets
|
||||
SimpleRecursionTargets {
|
||||
proofs_with_pi: proof_targets,
|
||||
verifier_data: inner_verifier_data,
|
||||
entropy: outer_entropy_target,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// assign the targets
|
||||
pub fn assign_witness(
|
||||
&self,
|
||||
pw: &mut PartialWitness<F>,
|
||||
targets: &SimpleRecursionTargets<D>,
|
||||
witnesses: SimpleRecursionInput<F, C, D>,
|
||||
) -> anyhow::Result<()>{
|
||||
// assign the proofs with public input
|
||||
for i in 0..self.recursion_tree_params.tree_width{
|
||||
pw.set_proof_with_pis_target(&targets.proofs_with_pi[i],&witnesses.proofs[i])?;
|
||||
}
|
||||
|
||||
// assign the verifier data
|
||||
pw.set_cap_target(
|
||||
&targets.verifier_data.constants_sigmas_cap,
|
||||
&witnesses.verifier_data.verifier_only.constants_sigmas_cap,
|
||||
)?;
|
||||
pw.set_hash_target(targets.verifier_data.circuit_digest, witnesses.verifier_data.verifier_only.circuit_digest)?;
|
||||
|
||||
// set the entropy hash target
|
||||
pw.set_hash_target(targets.entropy, witnesses.entropy)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
}
|
||||
}
|
0
codex-plonky2-circuits/src/recursion/structs.rs
Normal file
0
codex-plonky2-circuits/src/recursion/structs.rs
Normal file
25
codex-plonky2-circuits/src/recursion/traits.rs
Normal file
25
codex-plonky2-circuits/src/recursion/traits.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use plonky2::iop::target::BoolTarget;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::recursion::params::{F,C,D};
|
||||
|
||||
/// InnerCircuit is the trait used to define the logic of the circuit and assign witnesses
|
||||
/// to that circuit instance.
|
||||
pub trait InnerCircuit<
|
||||
// TODO: make it generic for F and D ?
|
||||
> {
|
||||
type Targets;
|
||||
type Input;
|
||||
|
||||
/// build the circuit logic and return targets to be assigned later
|
||||
fn build(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
) -> anyhow::Result<Self::Targets>;
|
||||
|
||||
/// assign the actual witness values for the current instance of the circuit.
|
||||
fn assign_targets(
|
||||
pw: &mut PartialWitness<F>,
|
||||
targets: &Self::Targets,
|
||||
input: &Self::Input,
|
||||
) -> anyhow::Result<()>;
|
||||
}
|
69
codex-plonky2-circuits/src/recursion/tree_recursion.rs
Normal file
69
codex-plonky2-circuits/src/recursion/tree_recursion.rs
Normal file
@ -0,0 +1,69 @@
|
||||
use hashbrown::HashMap;
|
||||
use plonky2::hash::hash_types::{HashOut, HashOutTarget, RichField};
|
||||
use plonky2::iop::target::Target;
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{CircuitData, VerifierCircuitData, VerifierCircuitTarget};
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
|
||||
use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget};
|
||||
use plonky2::recursion::dummy_circuit::cyclic_base_proof;
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||
use crate::recursion::params::RecursionTreeParams;
|
||||
use crate::recursion::params::{F,D,C,Plonky2Proof};
|
||||
use crate::recursion::traits::InnerCircuit;
|
||||
|
||||
pub struct RecursionCircuit<
|
||||
I: InnerCircuit,
|
||||
>{
|
||||
pub recursion_tree_params: RecursionTreeParams,
|
||||
pub inner_circuit_targets: Vec<I::Targets>,
|
||||
pub proof_targets: Vec<ProofWithPublicInputsTarget<D>>,
|
||||
pub verifier_data_targets: VerifierCircuitTarget,
|
||||
pub verifier_data: VerifierCircuitData<F, C, D>,
|
||||
pub condition_targets: Vec<Target>,
|
||||
}
|
||||
|
||||
pub struct RecursionCircuitInput<
|
||||
I: InnerCircuit,
|
||||
>{
|
||||
pub inner_circuit_input: Vec<I::Targets>,
|
||||
pub proofs: Plonky2Proof,
|
||||
pub conditions: Vec<F>
|
||||
}
|
||||
|
||||
impl<
|
||||
I: InnerCircuit,
|
||||
> RecursionCircuit<I> {
|
||||
|
||||
pub fn build_circuit(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder::<F, D>,
|
||||
) -> Self {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn get_circuit_data() -> CircuitData<F, C, D>{
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn get_dummy_proof(circuit_data: CircuitData<F, C, D>) -> Plonky2Proof {
|
||||
let verifier_data = circuit_data.verifier_data();
|
||||
let dummy_proof_with_pis = cyclic_base_proof(
|
||||
&circuit_data.common,
|
||||
&verifier_data.verifier_only,
|
||||
HashMap::new(),
|
||||
);
|
||||
dummy_proof_with_pis
|
||||
}
|
||||
|
||||
pub fn assign_witness(
|
||||
&self,
|
||||
pw: &mut PartialWitness<F>,
|
||||
witnesses: RecursionCircuitInput<I>
|
||||
)-> anyhow::Result<()>{
|
||||
todo!()
|
||||
// Ok(())
|
||||
|
||||
}
|
||||
}
|
@ -7,12 +7,12 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.89" }
|
||||
unroll = { version = "0.1.5", default-features = false }
|
||||
serde = { version = "1.0.210" , features = ["rc"] }
|
||||
serde_json = { version = "1.0" }
|
||||
plonky2 = { version = "1.0.0", default-features = true}
|
||||
plonky2_field = { version = "1.0.0", default-features = false }
|
||||
anyhow = { workspace = true }
|
||||
unroll = { workspace = true }
|
||||
plonky2 = { workspace = true }
|
||||
plonky2_field = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
log = { version = "0.4.20", default-features = false }
|
||||
jemallocator = "0.5.4"
|
||||
|
||||
|
@ -7,10 +7,11 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
anyhow = "1.0"
|
||||
plonky2 = { version = "1.0.0" }
|
||||
plonky2_field = { version = "1.0.0", default-features = false }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
plonky2 = { workspace = true }
|
||||
plonky2_field = { workspace = true }
|
||||
# --- local ---
|
||||
plonky2_poseidon2 = { path = "../plonky2_poseidon2" }
|
||||
codex-plonky2-circuits = { path = "../codex-plonky2-circuits" }
|
BIN
proof-input/inner_circ_data.bin
Normal file
BIN
proof-input/inner_circ_data.bin
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
proof-input/outer_circ_data.bin
Normal file
BIN
proof-input/outer_circ_data.bin
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -7,11 +7,13 @@ use codex_plonky2_circuits::circuits::params::{CircuitParams, HF};
|
||||
use crate::params::TestParams;
|
||||
use crate::utils::{bits_le_padded_to_usize, calculate_cell_index_bits, ceiling_log2, usize_to_bits_le};
|
||||
use codex_plonky2_circuits::merkle_tree::merkle_safe::{MerkleProof, MerkleTree};
|
||||
use codex_plonky2_circuits::circuits::sample_cells::{Cell, MerklePath, SampleCircuit, SampleCircuitInput};
|
||||
use codex_plonky2_circuits::circuits::sample_cells::{Cell, MerklePath, SampleCircuit, SampleCircuitInput, SampleTargets};
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData};
|
||||
use plonky2::plonk::proof::ProofWithPublicInputs;
|
||||
use crate::sponge::{hash_bytes_no_padding, hash_n_with_padding};
|
||||
use crate::params::{C, D, F};
|
||||
|
||||
/// generates circuit input (SampleCircuitInput) from fake data for testing
|
||||
/// which can be later stored into json see json.rs
|
||||
@ -386,6 +388,54 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
// build the sampling circuit
|
||||
// returns the proof and verifier ci
|
||||
pub fn build_circuit(n_samples: usize, slot_index: usize) -> anyhow::Result<(CircuitData<F, C, D>, PartialWitness<F>)>{
|
||||
let (data, pw, _) = build_circuit_with_targets(n_samples, slot_index).unwrap();
|
||||
|
||||
Ok((data, pw))
|
||||
}
|
||||
|
||||
// build the sampling circuit ,
|
||||
// returns the proof and verifier ci and targets
|
||||
pub fn build_circuit_with_targets(n_samples: usize, slot_index: usize) -> anyhow::Result<(CircuitData<F, C, D>, PartialWitness<F>, SampleTargets)>{
|
||||
// get input
|
||||
let mut params = TestParams::default();
|
||||
params.n_samples = n_samples;
|
||||
params.testing_slot_index = slot_index;
|
||||
let circ_input = gen_testing_circuit_input::<F,D>(¶ms);
|
||||
|
||||
// Create the circuit
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let mut circuit_params = CircuitParams::default();
|
||||
circuit_params.n_samples = n_samples;
|
||||
|
||||
// build the circuit
|
||||
let circ = SampleCircuit::new(circuit_params.clone());
|
||||
let mut targets = circ.sample_slot_circuit(&mut builder);
|
||||
|
||||
// Create a PartialWitness and assign
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
// assign a witness
|
||||
circ.sample_slot_assign_witness(&mut pw, &mut targets, circ_input);
|
||||
|
||||
// Build the circuit
|
||||
let data = builder.build::<C>();
|
||||
|
||||
Ok((data, pw, targets))
|
||||
}
|
||||
|
||||
// prove the circuit
|
||||
pub fn prove_circuit(data: &CircuitData<F, C, D>, pw: &PartialWitness<F>) -> anyhow::Result<ProofWithPublicInputs<F, C, D>>{
|
||||
// Prove the circuit with the assigned witness
|
||||
let proof_with_pis = data.prove(pw.clone())?;
|
||||
|
||||
Ok(proof_with_pis)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::Instant;
|
||||
@ -395,48 +445,14 @@ mod tests {
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use codex_plonky2_circuits::circuits::params::CircuitParams;
|
||||
use codex_plonky2_circuits::circuits::recursion::aggregate_sampling_proofs;
|
||||
use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit;
|
||||
use codex_plonky2_circuits::recursion::simple_recursion::{aggregate_sampling_proofs, aggregate_sampling_proofs_tree, aggregate_sampling_proofs_tree2};
|
||||
use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit, SampleTargets};
|
||||
use codex_plonky2_circuits::recursion::params::RecursionTreeParams;
|
||||
use plonky2::plonk::proof::ProofWithPublicInputs;
|
||||
use crate::params::{C, D, F};
|
||||
|
||||
// build the sampling circuit and prove,
|
||||
// returns the proof and verifier ci
|
||||
pub fn build_circuit(n_samples: usize) -> anyhow::Result<(CircuitData<F, C, D>, PartialWitness<F>)>{
|
||||
// get input
|
||||
let mut params = TestParams::default();
|
||||
params.n_samples = n_samples;
|
||||
let circ_input = gen_testing_circuit_input::<F,D>(¶ms);
|
||||
|
||||
// Create the circuit
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let mut circuit_params = CircuitParams::default();
|
||||
circuit_params.n_samples = n_samples;
|
||||
|
||||
// build the circuit
|
||||
let circ = SampleCircuit::new(circuit_params.clone());
|
||||
let mut targets = circ.sample_slot_circuit(&mut builder);
|
||||
|
||||
// Create a PartialWitness and assign
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
// assign a witness
|
||||
circ.sample_slot_assign_witness(&mut pw, &mut targets, circ_input);
|
||||
|
||||
// Build the circuit
|
||||
let data = builder.build::<C>();
|
||||
|
||||
Ok((data, pw))
|
||||
}
|
||||
|
||||
pub fn prove_circuit(data: &CircuitData<F, C, D>, pw: &PartialWitness<F>) -> anyhow::Result<ProofWithPublicInputs<F, C, D>>{
|
||||
// Prove the circuit with the assigned witness
|
||||
let proof_with_pis = data.prove(pw.clone())?;
|
||||
|
||||
Ok(proof_with_pis)
|
||||
}
|
||||
use plonky2_poseidon2::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer};
|
||||
use crate::json::write_bytes_to_file;
|
||||
use codex_plonky2_circuits::recursion::simple_recursion2::{SimpleRecursionCircuit, SimpleRecursionInput};
|
||||
// use crate::params::{C, D, F};
|
||||
|
||||
// Test sample cells (non-circuit)
|
||||
#[test]
|
||||
@ -495,12 +511,20 @@ mod tests {
|
||||
fn test_recursion() -> anyhow::Result<()> {
|
||||
// number of samples in each proof
|
||||
let n_samples = 10;
|
||||
// build the circuit
|
||||
let (data, pw) = build_circuit(n_samples)?;
|
||||
// number of inner proofs:
|
||||
let n_inner = 4;
|
||||
|
||||
let mut data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..D{
|
||||
proofs_with_pi.push(prove_circuit(&data, &pw)?);
|
||||
for i in 0..n_inner{
|
||||
// build the circuit
|
||||
let (data_i, pw) = build_circuit(n_samples, i)?;
|
||||
// prove
|
||||
proofs_with_pi.push(prove_circuit(&data_i, &pw)?);
|
||||
data = Some(data_i);
|
||||
|
||||
}
|
||||
|
||||
println!("num of public inputs inner proof = {}", proofs_with_pi[0].public_inputs.len());
|
||||
@ -511,7 +535,7 @@ mod tests {
|
||||
// Create a PartialWitness
|
||||
let mut pw_agg = PartialWitness::new();
|
||||
// aggregate proofs
|
||||
aggregate_sampling_proofs(proofs_with_pi, &data.verifier_data(), &mut builder, &mut pw_agg);
|
||||
aggregate_sampling_proofs(&proofs_with_pi, &data.unwrap().verifier_data(), &mut builder, &mut pw_agg)?;
|
||||
|
||||
let data_agg = builder.build::<C>();
|
||||
|
||||
@ -531,4 +555,121 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Test tree recursion
|
||||
#[test]
|
||||
fn test_tree_recursion() -> anyhow::Result<()> {
|
||||
// number of samples in each proof
|
||||
let n_samples = 10;
|
||||
// number of inner proofs:
|
||||
let n_inner = 4;
|
||||
let mut data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..n_inner{
|
||||
// build the circuit
|
||||
let (data_i, pw) = build_circuit(n_samples, i)?;
|
||||
proofs_with_pi.push(prove_circuit(&data_i, &pw)?);
|
||||
data = Some(data_i);
|
||||
}
|
||||
|
||||
let data = data.unwrap();
|
||||
println!("inner circuit size = {:?}", data.common.degree_bits());
|
||||
let gate_serializer = DefaultGateSerializer;
|
||||
let generator_serializer =DefaultGeneratorSerializer::<C, D>::default();
|
||||
let data_bytes = data.to_bytes(&gate_serializer, &generator_serializer).unwrap();
|
||||
println!("inner proof circuit data size = {} bytes", data_bytes.len());
|
||||
let file_path = "inner_circ_data.bin";
|
||||
// Write data to the file
|
||||
write_bytes_to_file(data_bytes, file_path).unwrap();
|
||||
println!("Data written to {}", file_path);
|
||||
|
||||
let start_time = Instant::now();
|
||||
let (proof, vd_agg) = aggregate_sampling_proofs_tree(&proofs_with_pi, data)?;
|
||||
println!("prove_time = {:?}", start_time.elapsed());
|
||||
println!("num of public inputs = {}", proof.public_inputs.len());
|
||||
println!("agg pub input = {:?}", proof.public_inputs);
|
||||
|
||||
println!("outer circuit size = {:?}", vd_agg.common.degree_bits());
|
||||
// let gate_serializer = DefaultGateSerializer;
|
||||
// let generator_serializer =DefaultGeneratorSerializer::<C, D>::default();
|
||||
let outer_data_bytes = vd_agg.to_bytes(&gate_serializer, &generator_serializer).unwrap();
|
||||
println!("outer proof circuit data size = {} bytes", outer_data_bytes.len());
|
||||
let file_path = "outer_circ_data.bin";
|
||||
// Write data to the file
|
||||
write_bytes_to_file(outer_data_bytes, file_path).unwrap();
|
||||
println!("Data written to {}", file_path);
|
||||
|
||||
// Verify the proof
|
||||
let verifier_data = vd_agg.verifier_data();
|
||||
assert!(
|
||||
verifier_data.verify(proof).is_ok(),
|
||||
"Merkle proof verification failed"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// test the tree recursion
|
||||
#[test]
|
||||
pub fn test_tree_recursion2()-> anyhow::Result<()>{
|
||||
// number of samples in each proof
|
||||
let n_samples = 10;
|
||||
// number of inner proofs:
|
||||
let n_inner = 4;
|
||||
let mut data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..n_inner{
|
||||
// build the circuit
|
||||
let (data_i, pw) = build_circuit(n_samples, i)?;
|
||||
proofs_with_pi.push(prove_circuit(&data_i, &pw)?);
|
||||
data = Some(data_i);
|
||||
}
|
||||
let data = data.unwrap();
|
||||
|
||||
let rt_params = RecursionTreeParams::new(n_inner);
|
||||
|
||||
let rec_circuit = SimpleRecursionCircuit::new(rt_params, data.verifier_data());
|
||||
|
||||
// Create the circuit
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
// Create a PartialWitness
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
let targets = rec_circuit.build_circuit(&mut builder);
|
||||
|
||||
let start = Instant::now();
|
||||
let agg_data = builder.build::<C>();
|
||||
println!("build time = {:?}", start.elapsed());
|
||||
println!("circuit size = {:?}", data.common.degree_bits());
|
||||
|
||||
let mut default_entropy = HashOut::ZERO;
|
||||
default_entropy.elements[0] = F::from_canonical_u64(1234567);
|
||||
|
||||
let w = SimpleRecursionInput{
|
||||
proofs: proofs_with_pi,
|
||||
verifier_data: data.verifier_data(),
|
||||
entropy: default_entropy,
|
||||
};
|
||||
|
||||
rec_circuit.assign_witness(&mut pw,&targets,w)?;
|
||||
|
||||
let start = Instant::now();
|
||||
let proof = agg_data.prove(pw)?;
|
||||
println!("prove time = {:?}", start.elapsed());
|
||||
|
||||
// Verify the proof
|
||||
let verifier_data = agg_data.verifier_data();
|
||||
assert!(
|
||||
verifier_data.verify(proof).is_ok(),
|
||||
"Merkle proof verification failed"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,11 +7,13 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
anyhow = "1.0"
|
||||
plonky2 = { version = "1.0.0" }
|
||||
plonky2_field = { version = "1.0.0", default-features = false }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
plonky2 = { workspace = true }
|
||||
plonky2_field = { workspace = true }
|
||||
|
||||
# --- local ---
|
||||
plonky2_poseidon2 = { path = "../plonky2_poseidon2" }
|
||||
codex-plonky2-circuits = { path = "../codex-plonky2-circuits" }
|
||||
proof-input = { path = "../proof-input" }
|
||||
@ -42,4 +44,12 @@ harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "sample_cells"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "recursion"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "tree_recursion"
|
||||
harness = false
|
85
workflow/benches/recursion.rs
Normal file
85
workflow/benches/recursion.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use anyhow::Result;
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData};
|
||||
use plonky2::plonk::config::GenericConfig;
|
||||
use codex_plonky2_circuits::recursion::simple_recursion::aggregate_sampling_proofs;
|
||||
use proof_input::params::{D, C, F, Params, TestParams};
|
||||
use proof_input::gen_input::{build_circuit, prove_circuit};
|
||||
|
||||
/// Benchmark for building, proving, and verifying the Plonky2 recursion circuit.
|
||||
fn bench_recursion(c: &mut Criterion) {
|
||||
// num of inner proofs
|
||||
let num_of_inner_proofs = 4;
|
||||
// number of samples in each proof
|
||||
let n_samples = 10;
|
||||
|
||||
let mut data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..num_of_inner_proofs{
|
||||
// build the circuit
|
||||
let (data_i, pw) = build_circuit(n_samples, 3).unwrap();
|
||||
proofs_with_pi.push(prove_circuit(&data_i, &pw).unwrap());
|
||||
data = Some(data_i);
|
||||
}
|
||||
|
||||
// Create the circuit
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
// Create a PartialWitness
|
||||
let mut pw_agg = PartialWitness::new();
|
||||
// aggregate proofs
|
||||
let data = data.unwrap();
|
||||
let vd = data.verifier_data();
|
||||
aggregate_sampling_proofs(&proofs_with_pi.clone(), &vd, &mut builder, &mut pw_agg);
|
||||
|
||||
let mut group = c.benchmark_group("bench recursion");
|
||||
|
||||
group.bench_function("Build Circuit", |b| {
|
||||
b.iter(|| {
|
||||
// Create the circuit
|
||||
let local_config = CircuitConfig::standard_recursion_config();
|
||||
let mut local_builder = CircuitBuilder::<F, D>::new(local_config);
|
||||
// Create a PartialWitness
|
||||
let mut local_pw_agg = PartialWitness::new();
|
||||
// aggregate proofs
|
||||
aggregate_sampling_proofs(&proofs_with_pi.clone(), &vd, &mut local_builder, &mut local_pw_agg);
|
||||
let _data = local_builder.build::<C>();
|
||||
})
|
||||
});
|
||||
|
||||
let agg_data = builder.build::<C>();
|
||||
println!("Circuit size (degree bits): {:?}", agg_data.common.degree_bits());
|
||||
println!("Number of gates used: {}", agg_data.common.gates.len());
|
||||
|
||||
group.bench_function("Prove Circuit", |b| {
|
||||
b.iter(|| {
|
||||
let local_pw = pw_agg.clone();
|
||||
agg_data.prove(local_pw).expect("Failed to prove circuit")
|
||||
})
|
||||
});
|
||||
|
||||
let agg_proof_with_pis = agg_data.prove(pw_agg.clone()).expect("Failed to prove circuit");
|
||||
let agg_verifier_data = agg_data.verifier_data();
|
||||
|
||||
println!("Proof size: {} bytes", agg_proof_with_pis.to_bytes().len());
|
||||
|
||||
group.bench_function("Verify Proof", |b| {
|
||||
b.iter(|| {
|
||||
agg_verifier_data.verify(agg_proof_with_pis.clone()).expect("Failed to verify proof");
|
||||
})
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
/// Criterion benchmark group
|
||||
criterion_group!{
|
||||
name = recursion;
|
||||
config = Criterion::default().sample_size(10);
|
||||
targets = bench_recursion
|
||||
}
|
||||
criterion_main!(recursion);
|
59
workflow/benches/tree_recursion.rs
Normal file
59
workflow/benches/tree_recursion.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use anyhow::Result;
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, VerifierCircuitData};
|
||||
use plonky2::plonk::config::GenericConfig;
|
||||
use codex_plonky2_circuits::recursion::simple_recursion::{aggregate_sampling_proofs_tree, aggregate_sampling_proofs_tree2};
|
||||
use plonky2::plonk::proof::ProofWithPublicInputs;
|
||||
use proof_input::params::{D, C, F, Params, TestParams};
|
||||
use proof_input::gen_input::{build_circuit, prove_circuit};
|
||||
|
||||
/// Benchmark for building, proving, and verifying the Plonky2 recursion circuit.
|
||||
fn bench_tree_recursion(c: &mut Criterion) {
|
||||
// num of inner proofs
|
||||
let num_of_inner_proofs = 4;
|
||||
// number of samples in each proof
|
||||
let n_samples = 10;
|
||||
|
||||
let (data, pw) = build_circuit(n_samples, 3).unwrap();
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..num_of_inner_proofs{
|
||||
proofs_with_pi.push(prove_circuit(&data, &pw).unwrap());
|
||||
}
|
||||
let vd = data.verifier_data();
|
||||
|
||||
let mut group = c.benchmark_group("bench simple tree recursion");
|
||||
let mut agg_proof_with_pis: Option<ProofWithPublicInputs<F, C, D>> = None;
|
||||
let mut agg_vd: Option<VerifierCircuitData<F, C, D>> = None;
|
||||
|
||||
// Benchmark the Circuit Building Phase
|
||||
group.bench_function("build & prove Circuit", |b| {
|
||||
b.iter(|| {
|
||||
let (agg_p, agg_d) = aggregate_sampling_proofs_tree2(&proofs_with_pi, vd.clone()).unwrap();
|
||||
agg_proof_with_pis = Some(agg_p);
|
||||
agg_vd = Some(agg_d);
|
||||
})
|
||||
});
|
||||
|
||||
let proof = agg_proof_with_pis.unwrap();
|
||||
println!("Proof size: {} bytes", proof.to_bytes().len());
|
||||
|
||||
// Benchmark the Verifying Phase
|
||||
let loc_vd = agg_vd.unwrap();
|
||||
group.bench_function("Verify Proof", |b| {
|
||||
b.iter(|| {
|
||||
loc_vd.clone().verify(proof.clone()).expect("Failed to verify proof");
|
||||
})
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
/// Criterion benchmark group
|
||||
criterion_group!{
|
||||
name = recursion;
|
||||
config = Criterion::default().sample_size(10);
|
||||
targets = bench_tree_recursion
|
||||
}
|
||||
criterion_main!(recursion);
|
Loading…
x
Reference in New Issue
Block a user