From 06ae6ffd30caae39aa3873376f21eb05ed68bc47 Mon Sep 17 00:00:00 2001 From: M Alghazwi Date: Fri, 20 Jun 2025 18:33:29 +0200 Subject: [PATCH] remove old experiments --- Cargo.toml | 1 - goldibear_experiments/.gitignore | 13 - goldibear_experiments/README.md | 5 - .../codex-plonky2-circuits/.gitignore | 13 - .../codex-plonky2-circuits/Cargo.toml | 24 -- .../src/circuits/keyed_compress.rs | 34 -- .../src/circuits/merkle_circuit.rs | 166 ------- .../src/circuits/mod.rs | 6 - .../src/circuits/params.rs | 64 --- .../src/circuits/sample_cells.rs | 404 ------------------ .../src/circuits/sponge.rs | 185 -------- .../src/circuits/utils.rs | 144 ------- .../codex-plonky2-circuits/src/error.rs | 71 --- .../codex-plonky2-circuits/src/lib.rs | 4 - goldibear_experiments/proof-input/.gitignore | 13 - goldibear_experiments/proof-input/Cargo.toml | 21 - .../proof-input/benches/sample_cells.rs | 103 ----- .../proof-input/src/data_structs.rs | 257 ----------- .../proof-input/src/gen_input.rs | 234 ---------- goldibear_experiments/proof-input/src/lib.rs | 7 - .../src/merkle_tree/key_compress.rs | 27 -- .../src/merkle_tree/merkle_safe.rs | 247 ----------- .../proof-input/src/merkle_tree/mod.rs | 2 - .../proof-input/src/params.rs | 224 ---------- .../proof-input/src/sponge.rs | 292 ------------- .../proof-input/src/utils.rs | 103 ----- recursion_experiments/README.md | 5 - .../benches/cyclic_recursion.rs | 80 ---- .../benches/hybrid_recursion.rs | 100 ----- .../benches/simple_recursion.rs | 112 ----- .../benches/simple_recursion_hashed_pi.rs | 111 ----- .../benches/simple_tree_recursion.rs | 68 --- .../benches/tree_recursion1.rs | 161 ------- .../benches/tree_recursion2.rs | 206 --------- .../benches/uniform_recursion.rs | 89 ---- .../recursion/circuits/inner_circuit.rs | 45 -- .../recursion/circuits/leaf_circuit.rs | 155 ------- .../recursion/circuits/mod.rs | 3 - .../circuits/sampling_inner_circuit.rs | 89 ---- recursion_experiments/recursion/cyclic/mod.rs | 265 ------------ recursion_experiments/recursion/hybrid/mod.rs | 2 - .../recursion/hybrid/node_circuit.rs | 104 ----- .../recursion/hybrid/tree_circuit.rs | 152 ------- recursion_experiments/recursion/mod.rs | 8 - recursion_experiments/recursion/simple/mod.rs | 3 - .../recursion/simple/simple_recursion.rs | 156 ------- .../simple/simple_recursion_hashed_pi.rs | 132 ------ .../recursion/simple/simple_tree_recursion.rs | 119 ------ recursion_experiments/recursion/tree1/mod.rs | 2 - .../recursion/tree1/node_circuit.rs | 259 ----------- .../recursion/tree1/tree_circuit.rs | 154 ------- recursion_experiments/recursion/tree2/mod.rs | 2 - .../recursion/tree2/node_circuit.rs | 289 ------------- .../recursion/tree2/tree_circuit.rs | 168 -------- .../recursion/uniform/leaf.rs | 139 ------ .../recursion/uniform/mod.rs | 3 - .../recursion/uniform/node.rs | 152 ------- .../recursion/uniform/tree.rs | 252 ----------- .../recursion/utils/conditional_verifier.rs | 121 ------ .../recursion/utils/dummy_gen.rs | 79 ---- recursion_experiments/recursion/utils/mod.rs | 2 - .../tests/cyclic_recursion.rs | 104 ----- recursion_experiments/tests/hybrid.rs | 124 ------ recursion_experiments/tests/mod.rs | 7 - .../tests/simple_recursion.rs | 162 ------- recursion_experiments/tests/simple_tree.rs | 64 --- recursion_experiments/tests/tree1.rs | 165 ------- recursion_experiments/tests/tree2.rs | 198 --------- recursion_experiments/tests/uniform.rs | 67 --- recursion_experiments/tests/uniform_arch.rs | 395 ----------------- 70 files changed, 7737 deletions(-) delete mode 100644 goldibear_experiments/.gitignore delete mode 100644 goldibear_experiments/README.md delete mode 100644 goldibear_experiments/codex-plonky2-circuits/.gitignore delete mode 100644 goldibear_experiments/codex-plonky2-circuits/Cargo.toml delete mode 100644 goldibear_experiments/codex-plonky2-circuits/src/circuits/keyed_compress.rs delete mode 100644 goldibear_experiments/codex-plonky2-circuits/src/circuits/merkle_circuit.rs delete mode 100644 goldibear_experiments/codex-plonky2-circuits/src/circuits/mod.rs delete mode 100644 goldibear_experiments/codex-plonky2-circuits/src/circuits/params.rs delete mode 100644 goldibear_experiments/codex-plonky2-circuits/src/circuits/sample_cells.rs delete mode 100644 goldibear_experiments/codex-plonky2-circuits/src/circuits/sponge.rs delete mode 100644 goldibear_experiments/codex-plonky2-circuits/src/circuits/utils.rs delete mode 100644 goldibear_experiments/codex-plonky2-circuits/src/error.rs delete mode 100644 goldibear_experiments/codex-plonky2-circuits/src/lib.rs delete mode 100644 goldibear_experiments/proof-input/.gitignore delete mode 100644 goldibear_experiments/proof-input/Cargo.toml delete mode 100644 goldibear_experiments/proof-input/benches/sample_cells.rs delete mode 100644 goldibear_experiments/proof-input/src/data_structs.rs delete mode 100644 goldibear_experiments/proof-input/src/gen_input.rs delete mode 100644 goldibear_experiments/proof-input/src/lib.rs delete mode 100644 goldibear_experiments/proof-input/src/merkle_tree/key_compress.rs delete mode 100644 goldibear_experiments/proof-input/src/merkle_tree/merkle_safe.rs delete mode 100644 goldibear_experiments/proof-input/src/merkle_tree/mod.rs delete mode 100644 goldibear_experiments/proof-input/src/params.rs delete mode 100644 goldibear_experiments/proof-input/src/sponge.rs delete mode 100644 goldibear_experiments/proof-input/src/utils.rs delete mode 100644 recursion_experiments/README.md delete mode 100644 recursion_experiments/benches/cyclic_recursion.rs delete mode 100644 recursion_experiments/benches/hybrid_recursion.rs delete mode 100644 recursion_experiments/benches/simple_recursion.rs delete mode 100644 recursion_experiments/benches/simple_recursion_hashed_pi.rs delete mode 100644 recursion_experiments/benches/simple_tree_recursion.rs delete mode 100644 recursion_experiments/benches/tree_recursion1.rs delete mode 100644 recursion_experiments/benches/tree_recursion2.rs delete mode 100644 recursion_experiments/benches/uniform_recursion.rs delete mode 100644 recursion_experiments/recursion/circuits/inner_circuit.rs delete mode 100644 recursion_experiments/recursion/circuits/leaf_circuit.rs delete mode 100644 recursion_experiments/recursion/circuits/mod.rs delete mode 100644 recursion_experiments/recursion/circuits/sampling_inner_circuit.rs delete mode 100644 recursion_experiments/recursion/cyclic/mod.rs delete mode 100644 recursion_experiments/recursion/hybrid/mod.rs delete mode 100644 recursion_experiments/recursion/hybrid/node_circuit.rs delete mode 100644 recursion_experiments/recursion/hybrid/tree_circuit.rs delete mode 100644 recursion_experiments/recursion/mod.rs delete mode 100644 recursion_experiments/recursion/simple/mod.rs delete mode 100644 recursion_experiments/recursion/simple/simple_recursion.rs delete mode 100644 recursion_experiments/recursion/simple/simple_recursion_hashed_pi.rs delete mode 100644 recursion_experiments/recursion/simple/simple_tree_recursion.rs delete mode 100644 recursion_experiments/recursion/tree1/mod.rs delete mode 100644 recursion_experiments/recursion/tree1/node_circuit.rs delete mode 100644 recursion_experiments/recursion/tree1/tree_circuit.rs delete mode 100644 recursion_experiments/recursion/tree2/mod.rs delete mode 100644 recursion_experiments/recursion/tree2/node_circuit.rs delete mode 100644 recursion_experiments/recursion/tree2/tree_circuit.rs delete mode 100644 recursion_experiments/recursion/uniform/leaf.rs delete mode 100644 recursion_experiments/recursion/uniform/mod.rs delete mode 100644 recursion_experiments/recursion/uniform/node.rs delete mode 100644 recursion_experiments/recursion/uniform/tree.rs delete mode 100644 recursion_experiments/recursion/utils/conditional_verifier.rs delete mode 100644 recursion_experiments/recursion/utils/dummy_gen.rs delete mode 100644 recursion_experiments/recursion/utils/mod.rs delete mode 100644 recursion_experiments/tests/cyclic_recursion.rs delete mode 100644 recursion_experiments/tests/hybrid.rs delete mode 100644 recursion_experiments/tests/mod.rs delete mode 100644 recursion_experiments/tests/simple_recursion.rs delete mode 100644 recursion_experiments/tests/simple_tree.rs delete mode 100644 recursion_experiments/tests/tree1.rs delete mode 100644 recursion_experiments/tests/tree2.rs delete mode 100644 recursion_experiments/tests/uniform.rs delete mode 100644 recursion_experiments/tests/uniform_arch.rs diff --git a/Cargo.toml b/Cargo.toml index a94bfce..f7f6f51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = ["codex-plonky2-circuits","plonky2_poseidon2","proof-input","workflow"] -exclude = ["goldibear_experiments"] resolver = "2" [workspace.dependencies] diff --git a/goldibear_experiments/.gitignore b/goldibear_experiments/.gitignore deleted file mode 100644 index a3547b9..0000000 --- a/goldibear_experiments/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -#IDE Related -.idea - -# Cargo build -/target -Cargo.lock - -# Profile-guided optimization -/tmp -pgo-data.profdata - -# MacOS nuisances -.DS_Store diff --git a/goldibear_experiments/README.md b/goldibear_experiments/README.md deleted file mode 100644 index 382a2c0..0000000 --- a/goldibear_experiments/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Plonky2 Goldibear Experiments -================================ - -Few experiments done to test the [Plonky2_Goldibear](https://github.com/telosnetwork/plonky2_goldibear/tree/main). -The storage circuits are adapted for that version of plonky2 and tested. diff --git a/goldibear_experiments/codex-plonky2-circuits/.gitignore b/goldibear_experiments/codex-plonky2-circuits/.gitignore deleted file mode 100644 index a3547b9..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -#IDE Related -.idea - -# Cargo build -/target -Cargo.lock - -# Profile-guided optimization -/tmp -pgo-data.profdata - -# MacOS nuisances -.DS_Store diff --git a/goldibear_experiments/codex-plonky2-circuits/Cargo.toml b/goldibear_experiments/codex-plonky2-circuits/Cargo.toml deleted file mode 100644 index 871bbc9..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "codex-plonky2-circuits" -description = "Codex storage proofs circuits for Plonky2" -authors = ["Mohammed Alghazwi "] -readme = "README.md" -version = "1.0.0" -edition = "2021" - -[dependencies] -anyhow = { version = "1.0.89"} -unroll = { version = "0.1.5"} -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -plonky2 = { git = "https://github.com/telosnetwork/plonky2_goldibear.git"} -plonky2_field = { git = "https://github.com/telosnetwork/plonky2_goldibear.git" } -thiserror = "2.0.10" -itertools = { version = "0.12.1"} -plonky2_maybe_rayon = { git = "https://github.com/telosnetwork/plonky2_goldibear.git" } -hashbrown = "0.14.5" - -[dev-dependencies] -criterion = { version = "0.5.1", default-features = false } -tynm = { version = "0.1.6", default-features = false } - diff --git a/goldibear_experiments/codex-plonky2-circuits/src/circuits/keyed_compress.rs b/goldibear_experiments/codex-plonky2-circuits/src/circuits/keyed_compress.rs deleted file mode 100644 index e762fd7..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/src/circuits/keyed_compress.rs +++ /dev/null @@ -1,34 +0,0 @@ -use plonky2::hash::hash_types::{ HashOutTarget, RichField}; -use plonky2::hash::hashing::PlonkyPermutation; -use plonky2::iop::target::Target; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::config::AlgebraicHasher; -use plonky2_field::types::HasExtension; -use crate::circuits::params::NUM_HASH_OUT_ELTS; - -/// Compression function which takes two 256 bit inputs (HashOutTarget) and key Target -/// and returns a 256 bit output (HashOutTarget / 4 Targets). -pub fn key_compress_circuit< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher, ->( - builder: &mut CircuitBuilder, - x: HashOutTarget, - y: HashOutTarget, - key: Target, -) -> HashOutTarget { - let zero = builder.zero(); - let mut state = H::AlgebraicPermutation::new(core::iter::repeat(zero)); - - state.set_from_slice(&x.elements, 0); - state.set_from_slice(&y.elements, NUM_HASH_OUT_ELTS); - state.set_elt(key, NUM_HASH_OUT_ELTS*2); - - state = builder.permute::(state); - - HashOutTarget { - elements: state.squeeze()[..NUM_HASH_OUT_ELTS].try_into().unwrap(), - } -} - diff --git a/goldibear_experiments/codex-plonky2-circuits/src/circuits/merkle_circuit.rs b/goldibear_experiments/codex-plonky2-circuits/src/circuits/merkle_circuit.rs deleted file mode 100644 index 325b993..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/src/circuits/merkle_circuit.rs +++ /dev/null @@ -1,166 +0,0 @@ -// Plonky2 Circuit implementation of "safe" merkle tree -// consistent with the one in codex: -// https://github.com/codex-storage/codex-storage-proofs-circuits/blob/master/circuit/codex/merkle.circom - -use plonky2::{ - hash::hash_types::{HashOutTarget, RichField, }, - iop::target::BoolTarget, - plonk::circuit_builder::CircuitBuilder, -}; -use std::marker::PhantomData; -use plonky2::plonk::config::AlgebraicHasher; -use plonky2_field::types::HasExtension; -use crate::circuits::keyed_compress::key_compress_circuit; -use crate::circuits::params::NUM_HASH_OUT_ELTS; -use crate::circuits::utils::{add_assign_hash_out_target, mul_hash_out_target}; -use crate::Result; -use crate::error::CircuitError; - -// Constants for the keys used in compression -pub const KEY_NONE: u64 = 0x0; -pub const KEY_BOTTOM_LAYER: u64 = 0x1; -pub const KEY_ODD: u64 = 0x2; -pub const KEY_ODD_AND_BOTTOM_LAYER: u64 = 0x3; - -/// Merkle tree targets representing the input to the circuit -#[derive(Clone)] -pub struct MerkleTreeTargets{ - pub leaf: HashOutTarget, - pub path_bits: Vec, - pub last_bits: Vec, - pub mask_bits: Vec, - pub merkle_path: MerkleProofTarget, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MerkleProofTarget { - /// The Merkle digest of each sibling subtree, staying from the bottommost layer. - pub path: Vec>, -} - -/// Merkle tree circuit contains the functions for -/// building, proving and verifying the circuit. -#[derive(Clone)] -pub struct MerkleTreeCircuit< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher, -> { - pub phantom_data: PhantomData<(F,H)>, -} - -impl< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher, -> MerkleTreeCircuit { - - - pub fn new() -> Self{ - Self{ - phantom_data: Default::default(), - } - } - - /// Reconstructs the Merkle root from a leaf and Merkle path using a “mask” approach. - /// - /// # input - /// - /// * `builder` - A circuit builder. - /// * `targets` - The Merkle targets. - /// * `max_depth` - The maximum depth of the tree. - /// - /// # Returns - /// - /// A `HashOutTarget` representing the reconstructed Merkle root in-circuit. - /// - pub fn reconstruct_merkle_root_circuit_with_mask( - builder: &mut CircuitBuilder, - targets: &mut MerkleTreeTargets, - max_depth: usize, - ) -> Result> { - let mut state: Vec> = Vec::with_capacity(max_depth+1); - state.push(targets.leaf); - let zero = builder.zero(); - let one = builder.one(); - let two = builder.two(); - - // --- Basic checks on input sizes. - let path_len = targets.path_bits.len(); - let proof_len = targets.merkle_path.path.len(); - let mask_len = targets.mask_bits.len(); - let last_len = targets.last_bits.len(); - - if path_len != proof_len { - return Err(CircuitError::PathBitsLengthMismatch(path_len, proof_len)); - } - - if mask_len != path_len + 1 { - return Err(CircuitError::MaskBitsLengthMismatch(mask_len, path_len+1)); - } - - if last_len != path_len { - return Err(CircuitError::LastBitsLengthMismatch(last_len, path_len)); - } - - if path_len != max_depth { - return Err(CircuitError::PathBitsMaxDepthMismatch(path_len, max_depth)); - } - - // compute is_last - let mut is_last = vec![BoolTarget::new_unsafe(zero); max_depth + 1]; - is_last[max_depth] = BoolTarget::new_unsafe(one); // set isLast[max_depth] to 1 (true) - for i in (0..max_depth).rev() { - let eq_out = builder.is_equal(targets.path_bits[i].target , targets.last_bits[i].target); - is_last[i] = builder.and( is_last[i + 1] , eq_out); - } - - let mut i: usize = 0; - for (&bit, &sibling) in targets.path_bits.iter().zip(&targets.merkle_path.path) { - - // logic: we add KEY_BOTTOM_LAYER if i == 0, otherwise KEY_NONE. - let bottom_key_val = if i == 0 { - KEY_BOTTOM_LAYER - } else { - KEY_NONE - }; - let bottom = builder.constant(F::from_canonical_u64(bottom_key_val)); - - // compute: odd = isLast[i] * (1-pathBits[i]); - // compute: key = bottom + 2*odd - let mut odd = builder.sub(one, targets.path_bits[i].target); - odd = builder.mul(is_last[i].target, odd); - odd = builder.mul(two, odd); - let key = builder.add(bottom,odd); - - // select left and right based on path_bit - let mut left = vec![]; - let mut right = vec![]; - for j in 0..NUM_HASH_OUT_ELTS { - left.push( builder.select(bit, sibling.elements[j], state[i].elements[j])); - right.push( builder.select(bit, state[i].elements[j], sibling.elements[j])); - } - - // Compress them with a keyed-hash function - let combined_hash = key_compress_circuit:: - (builder, - HashOutTarget::from_vec(left), - HashOutTarget::from_vec(right), - key); - state.push(combined_hash); - - i += 1; - } - - // select the right layer using the mask bits - let mut reconstructed_root = HashOutTarget::from_vec([builder.zero();4].to_vec()); - for k in 0..max_depth { - let diff = builder.sub(targets.mask_bits[k].target, targets.mask_bits[k+1].target); - let mul_result = mul_hash_out_target(builder,&diff,&mut state[k+1]); - add_assign_hash_out_target(builder,&mut reconstructed_root, &mul_result); - } - - Ok(reconstructed_root) - - } -} diff --git a/goldibear_experiments/codex-plonky2-circuits/src/circuits/mod.rs b/goldibear_experiments/codex-plonky2-circuits/src/circuits/mod.rs deleted file mode 100644 index d074992..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/src/circuits/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod merkle_circuit; -pub mod sample_cells; -pub mod utils; -pub mod params; -pub mod keyed_compress; -pub mod sponge; diff --git a/goldibear_experiments/codex-plonky2-circuits/src/circuits/params.rs b/goldibear_experiments/codex-plonky2-circuits/src/circuits/params.rs deleted file mode 100644 index f68503f..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/src/circuits/params.rs +++ /dev/null @@ -1,64 +0,0 @@ -// global params for the circuits - -use anyhow::{Context, Result}; -use std::env; -use plonky2::hash::hash_types::GOLDILOCKS_NUM_HASH_OUT_ELTS; - -/// params used for the circuits -/// should be defined prior to building the circuit -#[derive(Clone, Debug)] -pub struct CircuitParams{ - pub max_depth: usize, - pub max_log2_n_slots: usize, - pub block_tree_depth: usize, - pub n_field_elems_per_cell: usize, - pub n_samples: usize, -} - -impl CircuitParams { - /// Creates a new `CircuitParams` struct from environment. - /// - /// - `MAX_DEPTH`:The maximum slot depth - /// - `MAX_LOG2_N_SLOTS`:The maximum log2 number of slots - /// - `BLOCK_TREE_DEPTH`:The block tree depth - /// - `N_FIELD_ELEMS_PER_CELL`: The number of field elements per cell - /// - `N_SAMPLES`: number of samples - /// - /// Returns an error if any environment variable is missing or fails to parse. - pub fn from_env() -> Result { - let max_depth = env::var("MAX_DEPTH") - .context("MAX_DEPTH is not set")? - .parse::() - .context("MAX_DEPTH must be a valid usize")?; - - let max_log2_n_slots = env::var("MAX_LOG2_N_SLOTS") - .context("MAX_LOG2_N_SLOTS is not set")? - .parse::() - .context("MAX_LOG2_N_SLOTS must be a valid usize")?; - - let block_tree_depth = env::var("BLOCK_TREE_DEPTH") - .context("BLOCK_TREE_DEPTH is not set")? - .parse::() - .context("BLOCK_TREE_DEPTH must be a valid usize")?; - - let n_field_elems_per_cell = env::var("N_FIELD_ELEMS_PER_CELL") - .context("N_FIELD_ELEMS_PER_CELL is not set")? - .parse::() - .context("N_FIELD_ELEMS_PER_CELL must be a valid usize")?; - - let n_samples = env::var("N_SAMPLES") - .context("N_SAMPLES is not set")? - .parse::() - .context("N_SAMPLES must be a valid usize")?; - - Ok(CircuitParams { - max_depth, - max_log2_n_slots, - block_tree_depth, - n_field_elems_per_cell, - n_samples, - }) - } -} - -pub const NUM_HASH_OUT_ELTS: usize = GOLDILOCKS_NUM_HASH_OUT_ELTS; diff --git a/goldibear_experiments/codex-plonky2-circuits/src/circuits/sample_cells.rs b/goldibear_experiments/codex-plonky2-circuits/src/circuits/sample_cells.rs deleted file mode 100644 index b573e76..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/src/circuits/sample_cells.rs +++ /dev/null @@ -1,404 +0,0 @@ -// Sample cells -// consistent with: -// https://github.com/codex-storage/codex-storage-proofs-circuits/blob/master/circuit/codex/sample_cells.circom -// circuit consists of: -// - reconstruct the dataset merkle root using the slot root as leaf -// - samples multiple cells by calling the sample_cells - -use std::marker::PhantomData; - -use plonky2::{ - hash::{ - hash_types::{HashOut, HashOutTarget, RichField}, - hashing::PlonkyPermutation, - }, - iop::{ - target::{BoolTarget, Target}, - witness::{PartialWitness, WitnessWrite}, - }, - plonk::circuit_builder::CircuitBuilder, -}; -use plonky2::plonk::config::AlgebraicHasher; -use plonky2_field::types::HasExtension; - -use crate::{ - circuits::{ - merkle_circuit::{MerkleProofTarget, MerkleTreeCircuit, MerkleTreeTargets}, - params::{CircuitParams, NUM_HASH_OUT_ELTS}, - sponge::{hash_n_no_padding, hash_n_with_padding}, - utils::{assign_hash_out_targets, ceiling_log2}, - }, - Result, - error::CircuitError, -}; - -/// circuit for sampling a slot in a dataset merkle tree -#[derive(Clone, Debug)] -pub struct SampleCircuit< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher, -> { - params: CircuitParams, - phantom_data: PhantomData<(F,H)>, -} - -impl< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher, -> SampleCircuit { - pub fn new(params: CircuitParams) -> Self{ - Self{ - params, - phantom_data: Default::default(), - } - } -} - -/// struct of input to the circuit as targets -/// used to build the circuit and can be assigned after building -#[derive(Clone, Debug)] -pub struct SampleTargets { - - pub entropy: HashOutTarget, // public input - pub dataset_root: HashOutTarget, // public input - pub slot_index: Target, // public input - - pub slot_root: HashOutTarget, - pub n_cells_per_slot: Target, - pub n_slots_per_dataset: Target, - - pub slot_proof: MerkleProofTarget, - - pub cell_data: Vec, - pub merkle_paths: Vec, -} - -/// circuit input as field elements -#[derive(Clone, Debug, PartialEq)] -pub struct SampleCircuitInput< - F: RichField + HasExtension, - const D: usize, ->{ - pub entropy: HashOut, // public input - pub dataset_root: HashOut, // public input - pub slot_index: F, // public input - - pub slot_root: HashOut, - pub n_cells_per_slot: F, - pub n_slots_per_dataset: F, - - pub slot_proof: Vec>, - - pub cell_data: Vec>, - pub merkle_paths: Vec>, - -} - -/// merkle path from leaf to root as vec of HashOut (4 Goldilocks field elems) -#[derive(Clone, Debug, PartialEq)] -pub struct MerklePath< - F: RichField + HasExtension, - const D: usize, -> { - pub path: Vec> -} - -/// a vec of cell targets -#[derive(Clone, Debug, PartialEq)] -pub struct CellTarget { - pub data: Vec -} - -/// cell data as field elements -#[derive(Clone, Debug, PartialEq)] -pub struct Cell< - F: RichField + HasExtension, - const D: usize, -> { - pub data: Vec, -} - -//------- circuit impl -------- -impl< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher, -> SampleCircuit { - - /// samples and registers the public input - pub fn sample_slot_circuit_with_public_input( - &self, - builder: &mut CircuitBuilder, - ) -> Result { - let targets = self.sample_slot_circuit(builder)?; - let mut pub_targets = vec![]; - pub_targets.push(targets.slot_index); - pub_targets.extend_from_slice(&targets.dataset_root.elements); - pub_targets.extend_from_slice(&targets.entropy.elements); - builder.register_public_inputs(&pub_targets); - Ok(targets) - } - - /// in-circuit sampling - /// WARNING: no public input are registered when calling this function - pub fn sample_slot_circuit( - &self, - builder: &mut CircuitBuilder::, - ) -> Result { - // circuit params - let CircuitParams { - max_depth, - max_log2_n_slots, - block_tree_depth, - n_field_elems_per_cell, - n_samples, - } = self.params; - - // constants - let zero = builder.zero(); - let one = builder.one(); - - // ***** prove slot root is in dataset tree ********* - - // Create virtual target for slot root and index - let slot_root = builder.add_virtual_hash(); - let slot_index = builder.add_virtual_target();// public input - // let slot_index = builder.add_virtual_public_input();// public input - - // dataset path bits (binary decomposition of leaf_index) - let d_path_bits = builder.split_le(slot_index,max_log2_n_slots); - - // create virtual target for n_slots_per_dataset - let n_slots_per_dataset = builder.add_virtual_target(); - - // dataset last bits and mask bits - let (d_last_bits, d_mask_bits) = - ceiling_log2(builder, n_slots_per_dataset, max_log2_n_slots); - - // dataset Merkle path (sibling hashes from leaf to root) - let d_merkle_path = MerkleProofTarget { - path: (0..max_log2_n_slots).map(|_| builder.add_virtual_hash()).collect(), - }; - - // create MerkleTreeTargets struct - let mut d_targets = MerkleTreeTargets{ - leaf: slot_root, - path_bits: d_path_bits, - last_bits: d_last_bits, - mask_bits: d_mask_bits, - merkle_path: d_merkle_path, - }; - - // dataset reconstructed root - let d_reconstructed_root = - MerkleTreeCircuit::::reconstruct_merkle_root_circuit_with_mask(builder, &mut d_targets, max_log2_n_slots)?; - - // expected Merkle root - let d_expected_root = builder.add_virtual_hash(); // public input - // let d_expected_root = builder.add_virtual_hash_public_input(); // public input - - // check equality with expected root - for i in 0..NUM_HASH_OUT_ELTS { - builder.connect(d_expected_root.elements[i], d_reconstructed_root.elements[i]); - } - - //*********** do the sampling ************ - - let mut data_targets =vec![]; - let mut slot_sample_proofs = vec![]; - let entropy_target = builder.add_virtual_hash(); // public input - // let entropy_target = builder.add_virtual_hash_public_input(); // public input - - // virtual target for n_cells_per_slot - let n_cells_per_slot = builder.add_virtual_target(); - - // calculate last index = n_cells_per_slot-1 - let slot_last_index = builder.sub(n_cells_per_slot, one); - - // create the mask bits - // TODO: re-use this for block and slot trees - let mask_bits = builder.split_le(slot_last_index,max_depth); - - // last and mask bits for block tree - let mut b_last_bits = builder.split_le(slot_last_index,max_depth); - let mut b_mask_bits = builder.split_le(slot_last_index,max_depth); - - // last and mask bits for the slot tree - let mut s_last_bits = b_last_bits.split_off(block_tree_depth); - let mut s_mask_bits = b_mask_bits.split_off(block_tree_depth); - - // pad mask bits with 0 - b_mask_bits.push(BoolTarget::new_unsafe(zero.clone())); - s_mask_bits.push(BoolTarget::new_unsafe(zero.clone())); - - for i in 0..n_samples{ - // cell data targets - let mut data_i = (0..n_field_elems_per_cell).map(|_| builder.add_virtual_target()).collect::>(); - // hash the cell data - let mut hash_inputs:Vec= Vec::new(); - hash_inputs.extend_from_slice(&data_i); - // let data_i_hash = builder.hash_n_to_hash_no_pad::(hash_inputs); - let data_i_hash = hash_n_no_padding::(builder, hash_inputs)?; - // make the counter into hash digest - let ctr_target = builder.constant(F::from_canonical_u64((i+1) as u64)); - let mut ctr = builder.add_virtual_hash(); - for i in 0..ctr.elements.len() { - if i==0 { - ctr.elements[i] = ctr_target; - }else{ - ctr.elements[i] = zero.clone(); - } - } - // paths for block and slot - let mut b_path_bits = self.calculate_cell_index_bits(builder, &entropy_target, &d_targets.leaf, &ctr, mask_bits.clone())?; - let mut s_path_bits = b_path_bits.split_off(block_tree_depth); - - let mut b_merkle_path = MerkleProofTarget { - path: (0..block_tree_depth).map(|_| builder.add_virtual_hash()).collect(), - }; - - let mut s_merkle_path = MerkleProofTarget { - path: (0..(max_depth - block_tree_depth)).map(|_| builder.add_virtual_hash()).collect(), - }; - - let mut block_targets = MerkleTreeTargets { - leaf: data_i_hash, - path_bits:b_path_bits, - last_bits: b_last_bits.clone(), - mask_bits: b_mask_bits.clone(), - merkle_path: b_merkle_path, - }; - - // reconstruct block root - let b_root = MerkleTreeCircuit::::reconstruct_merkle_root_circuit_with_mask(builder, &mut block_targets, block_tree_depth)?; - - let mut slot_targets = MerkleTreeTargets { - leaf: b_root, - path_bits:s_path_bits, - last_bits:s_last_bits.clone(), - mask_bits:s_mask_bits.clone(), - merkle_path:s_merkle_path, - }; - - // reconstruct slot root with block root as leaf - let slot_reconstructed_root = MerkleTreeCircuit::::reconstruct_merkle_root_circuit_with_mask(builder, &mut slot_targets, max_depth-block_tree_depth)?; - - // check equality with expected root - for i in 0..NUM_HASH_OUT_ELTS { - builder.connect( d_targets.leaf.elements[i], slot_reconstructed_root.elements[i]); - } - - // combine block and slot path to get the full path so we can assign it later. - let mut slot_sample_proof_target = MerkleProofTarget{ - path: block_targets.merkle_path.path, - }; - slot_sample_proof_target.path.extend_from_slice(&slot_targets.merkle_path.path); - - let cell_i = CellTarget{ - data: data_i - }; - data_targets.push(cell_i); - slot_sample_proofs.push(slot_sample_proof_target); - - } - - let st = SampleTargets { - entropy: entropy_target, - dataset_root: d_expected_root, - slot_index, - slot_root: d_targets.leaf, - n_cells_per_slot, - n_slots_per_dataset, - slot_proof: d_targets.merkle_path, - cell_data: data_targets, - merkle_paths: slot_sample_proofs, - }; - - Ok(st) - } - - /// calculate the cell index = H( entropy | slotRoot | counter ) `mod` nCells - pub fn calculate_cell_index_bits(&self, builder: &mut CircuitBuilder, entropy: &HashOutTarget, slot_root: &HashOutTarget, ctr: &HashOutTarget, mask_bits: Vec) -> Result> { - let mut hash_inputs:Vec= Vec::new(); - hash_inputs.extend_from_slice(&entropy.elements); - hash_inputs.extend_from_slice(&slot_root.elements); - hash_inputs.extend_from_slice(&ctr.elements); - - let hash_out = hash_n_with_padding::(builder, hash_inputs)?; - let cell_index_bits = builder.low_bits(hash_out.elements[0], self.params.max_depth, true); - - let mut masked_cell_index_bits = vec![]; - - // extract the lowest 32 bits using the bit mask - for i in 0..self.params.max_depth{ - masked_cell_index_bits.push(BoolTarget::new_unsafe(builder.mul(mask_bits[i].target, cell_index_bits[i].target))); - } - - Ok(masked_cell_index_bits) - } - - /// helper method to assign the targets in the circuit to actual field elems - pub fn sample_slot_assign_witness( - &self, - pw: &mut PartialWitness, - targets: &SampleTargets, - witnesses: &SampleCircuitInput, - ) -> Result<()>{ - // circuit params - let CircuitParams { - max_depth, - n_field_elems_per_cell, - n_samples, - .. - } = self.params; - - // assign n_cells_per_slot - pw.set_target(targets.n_cells_per_slot, witnesses.n_cells_per_slot) - ; - - // assign n_slots_per_dataset - pw.set_target(targets.n_slots_per_dataset, witnesses.n_slots_per_dataset) - ; - - // assign dataset proof - for (i, sibling_hash) in witnesses.slot_proof.iter().enumerate() { - pw.set_hash_target(targets.slot_proof.path[i], *sibling_hash) - ; - } - // assign slot index - pw.set_target(targets.slot_index, witnesses.slot_index) - ; - - // assign the expected Merkle root of dataset to the target - pw.set_hash_target(targets.dataset_root, witnesses.dataset_root) - ; - - // assign the sampled slot - pw.set_hash_target(targets.slot_root, witnesses.slot_root) - ; - - // assign entropy - assign_hash_out_targets(pw, &targets.entropy, &witnesses.entropy)?; - - // do the sample N times - for i in 0..n_samples { - // assign cell data - let leaf = witnesses.cell_data[i].data.clone(); - for j in 0..n_field_elems_per_cell{ - pw.set_target(targets.cell_data[i].data[j], leaf[j]) - ; - } - // assign proof for that cell - let cell_proof = witnesses.merkle_paths[i].path.clone(); - for k in 0..max_depth { - pw.set_hash_target(targets.merkle_paths[i].path[k], cell_proof[k]) - ; - } - } - - Ok(()) - } - -} diff --git a/goldibear_experiments/codex-plonky2-circuits/src/circuits/sponge.rs b/goldibear_experiments/codex-plonky2-circuits/src/circuits/sponge.rs deleted file mode 100644 index 6209de6..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/src/circuits/sponge.rs +++ /dev/null @@ -1,185 +0,0 @@ -use plonky2::hash::hash_types::{HashOutTarget, RichField}; -use plonky2::hash::hashing::PlonkyPermutation; -use plonky2::iop::target::Target; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::config::AlgebraicHasher; -use plonky2_field::types::HasExtension; -use crate::error::CircuitError; -use crate::Result; -use crate::circuits::params::NUM_HASH_OUT_ELTS; - -/// hash n targets (field elements) into hash digest / HashOutTarget (4 Goldilocks field elements) -/// this function uses the 10* padding -pub fn hash_n_with_padding< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher ->( - builder: &mut CircuitBuilder, - inputs: Vec, -) -> Result> { - Ok( - HashOutTarget::from_vec( - hash_n_to_m_with_padding::(builder, inputs, NUM_HASH_OUT_ELTS)? - ) - ) -} - -pub fn hash_n_to_m_with_padding< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher ->( - builder: &mut CircuitBuilder, - inputs: Vec, - num_outputs: usize, -) -> Result> { - let rate = H::AlgebraicPermutation::RATE; - let width = H::AlgebraicPermutation::WIDTH; // rate + capacity - let zero = builder.zero(); - let one = builder.one(); - let mut state = H::AlgebraicPermutation::new(core::iter::repeat(zero).take(width)); - - // Set the domain separator at index 8 - let dom_sep_value = rate as u64 + 256 * 12 + 65536 * 63; - let dom_sep = builder.constant(F::from_canonical_u64(dom_sep_value)); - state.set_elt(dom_sep, 8); - - let n = inputs.len(); - let num_chunks = (n + rate) / rate; // 10* padding - let mut input_iter = inputs.iter(); - - // Process the first (num_chunks - 1) chunks - for _ in 0..(num_chunks - 1) { - let mut chunk = Vec::with_capacity(rate); - for _ in 0..rate { - if let Some(&input) = input_iter.next() { - chunk.push(input); - } else { - // should not happen here - return Err(CircuitError::InsufficientInputs(rate,chunk.len())); - } - } - // Add the chunk to the state - for j in 0..rate { - state.set_elt(builder.add(state.as_ref()[j], chunk[j]), j); - } - // Apply permutation - state = builder.permute::(state); - } - - // Process the last chunk with 10* padding - let rem = num_chunks * rate - n; // 0 < rem <= rate - let ofs = rate - rem; // Offset where padding starts - - let mut last_chunk = Vec::with_capacity(rate); - for _ in 0..ofs { - if let Some(&input) = input_iter.next() { - last_chunk.push(input); - } else { - last_chunk.push(zero); // Pad zeros if no more inputs - } - } - - // Add the '1' padding bit - last_chunk.push(one); - - // Pad zeros to reach the full rate - while last_chunk.len() < rate { - last_chunk.push(zero); - } - - // Add the last chunk to the state - for j in 0..rate { - state.set_elt(builder.add(state.as_ref()[j], last_chunk[j]), j); - } - // Apply permutation - state = builder.permute::(state); - - // Squeeze until we have the desired number of outputs - let mut outputs = Vec::with_capacity(num_outputs); - loop { - for &s in state.squeeze() { - outputs.push(s); - if outputs.len() == num_outputs { - return Ok(outputs); - } - } - state = builder.permute::(state); - } -} - -/// hash n targets (field elements) into hash digest / HashOutTarget (4 Goldilocks field elements) -/// this function uses doesn't pad and expects input to be divisible by rate -/// rate is fixed at 8 for now. -pub fn hash_n_no_padding< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher ->( - builder: &mut CircuitBuilder, - inputs: Vec, -) -> Result> { - Ok( - HashOutTarget::from_vec( - hash_n_to_m_no_padding::(builder, inputs, NUM_HASH_OUT_ELTS)? - ) - ) -} - -pub fn hash_n_to_m_no_padding< - F: RichField + HasExtension, - const D: usize, - H: AlgebraicHasher ->( - builder: &mut CircuitBuilder, - inputs: Vec, - num_outputs: usize, -) -> Result> { - let rate = H::AlgebraicPermutation::RATE; - let width = H::AlgebraicPermutation::WIDTH; // rate + capacity - let zero = builder.zero(); - let mut state = H::AlgebraicPermutation::new(core::iter::repeat(zero).take(width)); - - // Set the domain separator at index 8 - let dom_sep_value = rate as u64 + 256 * 12 + 65536 * 8; - let dom_sep = builder.constant(F::from_canonical_u64(dom_sep_value)); - state.set_elt(dom_sep, 8); - - let n = inputs.len(); - if n % rate != 0 { - return Err(CircuitError::SpongeInputLengthMismatch(n, rate)); - } - let num_chunks = n / rate; // 10* padding - let mut input_iter = inputs.iter(); - - // Process all chunks - for _ in 0..num_chunks { - let mut chunk = Vec::with_capacity(rate); - for _ in 0..rate { - if let Some(&input) = input_iter.next() { - chunk.push(input); - } else { - // should not happen here - return Err(CircuitError::InsufficientInputs(rate,chunk.len())); - } - } - // Add the chunk to the state - for j in 0..rate { - state.set_elt(builder.add(state.as_ref()[j], chunk[j]), j); - } - // Apply permutation - state = builder.permute::(state); - } - // Squeeze until we have the desired number of outputs - let mut outputs = Vec::with_capacity(num_outputs); - loop { - for &s in state.squeeze() { - outputs.push(s); - if outputs.len() == num_outputs { - return Ok(outputs); - } - } - state = builder.permute::(state); - } -} \ No newline at end of file diff --git a/goldibear_experiments/codex-plonky2-circuits/src/circuits/utils.rs b/goldibear_experiments/codex-plonky2-circuits/src/circuits/utils.rs deleted file mode 100644 index 6ada72e..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/src/circuits/utils.rs +++ /dev/null @@ -1,144 +0,0 @@ -use std::{fs, io}; -use std::path::Path; -use itertools::Itertools; -use plonky2::hash::hash_types::{HashOut, HashOutTarget, RichField}; -use plonky2::iop::witness::{PartialWitness, WitnessWrite}; -use plonky2::iop::target::{BoolTarget, Target}; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2_field::types::HasExtension; -use crate::Result; -use crate::error::CircuitError; -use crate::circuits::params::NUM_HASH_OUT_ELTS; - -// --------- helper functions --------- - -/// computes the `last_index` (the binary decomposition of `inp-1`) and the `mask_bits` -pub fn ceiling_log2< - F: RichField + HasExtension, - const D: usize, ->( - builder: &mut CircuitBuilder, - inp: Target, - n: usize, -) -> (Vec, Vec){ - let one = builder.one(); - let zero = builder.zero(); - let last_index = builder.sub(inp, one.clone()); - let last_bits = builder.split_le(last_index,n); - - let mut aux: Vec = vec![BoolTarget::new_unsafe(zero.clone()); n + 1]; - aux[n] = BoolTarget::new_unsafe(one.clone()); - let mut mask: Vec = vec![BoolTarget::new_unsafe(zero.clone()); n + 1]; - for i in (0..n).rev(){ - let diff = builder.sub(one.clone(), last_bits[i].target); - let aux_i = builder.mul( aux[i+1].target, diff); - aux[i] = BoolTarget::new_unsafe(aux_i); - mask[i] = BoolTarget::new_unsafe(builder.sub(one.clone(), aux[i].target)); - } - - (last_bits, mask) -} - -/// assign a vec of bool values to a vec of BoolTargets -pub fn assign_bool_targets< - F: RichField + HasExtension, - const D: usize, ->( - pw: &mut PartialWitness, - bool_targets: &Vec, - bools: Vec, -) -> Result<()>{ - if bools.len() > bool_targets.len() { - return Err(CircuitError::AssignmentLengthMismatch ( - bool_targets.len(), - bools.len(), - ) - ); - } - for (i, bit) in bools.iter().enumerate() { - pw.set_bool_target(bool_targets[i], *bit); - } - Ok(()) -} - -/// assign a vec of field elems to hash out target elements -/// TODO: change to HashOut -pub fn assign_hash_out_targets< - F: RichField + HasExtension, - const D: usize, ->( - pw: &mut PartialWitness, - hash_out_elements_targets: &HashOutTarget, - hash_out_elements: &HashOut, -) -> Result<()>{ - - // Assign each field element to its corresponding target - for (j, (&target, &element)) in hash_out_elements_targets.elements.iter().zip(hash_out_elements.elements.iter()).enumerate() { - pw.set_target(target, element) - } - - Ok(()) -} - -/// helper fn to multiply a HashOutTarget by a Target -pub fn mul_hash_out_target< - F: RichField + HasExtension, - const D: usize, ->(builder: &mut CircuitBuilder, t: &Target, hash_target: &mut HashOutTarget) -> HashOutTarget { - let mut mul_elements = vec![]; - for i in 0..NUM_HASH_OUT_ELTS { - mul_elements.push(builder.mul(hash_target.elements[i], *t)); - } - HashOutTarget::from_vec(mul_elements) -} - -/// helper fn to add AND assign a HashOutTarget (hot) to a mutable HashOutTarget (mut_hot) -pub fn add_assign_hash_out_target< - F: RichField + HasExtension, - const D: usize, ->(builder: &mut CircuitBuilder, mut_hot: &mut HashOutTarget, hot: &HashOutTarget) { - 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>(path: P) -> io::Result> { - fs::read(path) -} - -/// select hash helper method -/// Computes `if b { h0 } else { h1 }`. -pub fn select_hash< - F: RichField + HasExtension, - const D: usize, ->( - builder: &mut CircuitBuilder, - b: BoolTarget, - h0: HashOutTarget, - h1: HashOutTarget, -) -> HashOutTarget { - HashOutTarget { - elements: core::array::from_fn(|i| builder.select(b, h0.elements[i], h1.elements[i])), - } -} - -/// Converts a Vec into a fixed-size array [T; N], returning an error if the lengths don't match. -pub fn vec_to_array(vec: Vec) -> Result<[T; N]> { - vec.try_into().map_err(|v: Vec| CircuitError::ArrayLengthMismatchError(format!( - "Expected exactly {} elements, got {}", - N, - v.len() - ))) -} - -/// Computes `if b { v0 } else { v1 }`. -pub fn select_vec< - F: RichField + HasExtension, - const D: usize, ->(builder: &mut CircuitBuilder, b: BoolTarget, v0: &[Target], v1: &[Target]) -> Vec { - v0.iter() - .zip_eq(v1) - .map(|(t0, t1)| builder.select(b, *t0, *t1)) - .collect() -} diff --git a/goldibear_experiments/codex-plonky2-circuits/src/error.rs b/goldibear_experiments/codex-plonky2-circuits/src/error.rs deleted file mode 100644 index 74ba35c..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/src/error.rs +++ /dev/null @@ -1,71 +0,0 @@ -use thiserror::Error; - -/// Custom error types for the Circuits. -#[derive(Error, Debug)] -pub enum CircuitError { - #[error("Path bits length mismatch: expected {0}, found {1}")] - PathBitsLengthMismatch(usize, usize), - - #[error("Mask bits length mismatch: expected {0}, found {1}")] - MaskBitsLengthMismatch(usize, usize), - - #[error("Last bits length mismatch: expected {0}, found {1}")] - LastBitsLengthMismatch(usize, usize), - - #[error("Path bits and max depth mismatch: path bits length {0}, max depth {1}")] - PathBitsMaxDepthMismatch(usize, usize), - - #[error("Insufficient input elements for chunk; expected {0}, found {1}")] - InsufficientInputs (usize, usize), - - #[error("Sponge: Input length ({0}) must be divisible by rate ({1}) for no padding")] - SpongeInputLengthMismatch(usize, usize), - - #[error("Assignment length mismatch: expected at least {0}, found {1}")] - AssignmentLengthMismatch(usize, usize), - - #[error("Failed to assign Target at index {0}: {1}")] - ArrayTargetAssignmentError(usize, String), - - #[error("Failed to assign Target {0}: {1}")] - TargetAssignmentError(String, String), - - #[error("Failed to assign BoolTarget at index {0}: {1}")] - ArrayBoolTargetAssignmentError(usize, String), - - #[error("Failed to assign BoolTarget {0}: {1}")] - BoolTargetAssignmentError(String, String), - - #[error("Failed to assign HashTarget {0}: {1}")] - HashTargetAssignmentError(String, String), - - #[error("Failed to assign ProofTarget {0}: {1}")] - ProofTargetAssignmentError(String, String), - - #[error("Failed to assign VerifierDataTarget {0}")] - VerifierDataTargetAssignmentError(String), - - #[error("Array Length Mismatch Error {0}")] - ArrayLengthMismatchError(String), - - #[error("Proof Verification Failed {0}")] - InvalidProofError(String), - - #[error("Proof Generation Failed {0}")] - ProofGenerationError(String), - - #[error("Error in Recursion Tree: {0}")] - RecursionTreeError(String), - - #[error("Dummy Proof Generation Error: {0}")] - DummyProofGenerationError(String), - - #[error("Conditional Verification Error: {0}")] - ConditionalVerificationError(String), - - #[error("Recursive Proof VerifierData Check Failed: {0}")] - RecursiveProofVerifierDataCheckError(String), - - #[error("Expected Option {0} to contain value")] - OptionError(String), -} \ No newline at end of file diff --git a/goldibear_experiments/codex-plonky2-circuits/src/lib.rs b/goldibear_experiments/codex-plonky2-circuits/src/lib.rs deleted file mode 100644 index 2975e39..0000000 --- a/goldibear_experiments/codex-plonky2-circuits/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod circuits; -pub mod error; - -pub type Result = core::result::Result; diff --git a/goldibear_experiments/proof-input/.gitignore b/goldibear_experiments/proof-input/.gitignore deleted file mode 100644 index a3547b9..0000000 --- a/goldibear_experiments/proof-input/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -#IDE Related -.idea - -# Cargo build -/target -Cargo.lock - -# Profile-guided optimization -/tmp -pgo-data.profdata - -# MacOS nuisances -.DS_Store diff --git a/goldibear_experiments/proof-input/Cargo.toml b/goldibear_experiments/proof-input/Cargo.toml deleted file mode 100644 index 96c0a3e..0000000 --- a/goldibear_experiments/proof-input/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "proof-input" -description = "proof input generation library" -authors = ["Mohammed Alghazwi "] -version = "0.1.0" -edition = "2021" - -[dependencies] -clap = { version = "4.0", features = ["derive"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -anyhow = { version = "1.0.89"} -plonky2 = { git = "https://github.com/telosnetwork/plonky2_goldibear.git"} -plonky2_field = { git = "https://github.com/telosnetwork/plonky2_goldibear.git"} -# --- local --- -codex-plonky2-circuits = { path = "../codex-plonky2-circuits" } -criterion = "0.5.1" - -[[bench]] -name = "sample_cells" -harness = false \ No newline at end of file diff --git a/goldibear_experiments/proof-input/benches/sample_cells.rs b/goldibear_experiments/proof-input/benches/sample_cells.rs deleted file mode 100644 index cb8d146..0000000 --- a/goldibear_experiments/proof-input/benches/sample_cells.rs +++ /dev/null @@ -1,103 +0,0 @@ -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; -use plonky2::plonk::config::GenericConfig; - -use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit; -use proof_input::gen_input::gen_testing_circuit_input; -use proof_input::params::{D, C, F, HF, Params}; -use codex_plonky2_circuits::circuits::params::NUM_HASH_OUT_ELTS; - -/// Benchmark for building, proving, and verifying the Plonky2 circuit. -fn bench_prove_verify(c: &mut Criterion) -> Result<()>{ - - let n_samples = 100; - // get default parameters - let params = Params::default(); - let mut test_params = params.input_params; - test_params.n_samples = n_samples; - - let mut circuit_params = params.circuit_params; - circuit_params.n_samples = n_samples; - - // gen the circuit input - let circ_input = gen_testing_circuit_input::(&test_params); - - // Create the circuit configuration - let config = CircuitConfig::standard_recursion_config_gl(); - let mut builder = CircuitBuilder::::new(config); - - // Initialize the SampleCircuit with the parameters - let circ = SampleCircuit::::new(circuit_params.clone()); - let targets = circ.sample_slot_circuit_with_public_input(&mut builder)?; - - // Create a PartialWitness and assign the circuit input - let mut pw = PartialWitness::new(); - circ.sample_slot_assign_witness(&mut pw, &targets, &circ_input.clone()); - - // Benchmark Group: Separate benchmarks for building, proving, and verifying - let mut group = c.benchmark_group("Sampling Circuit Benchmark"); - - // Benchmark the Circuit Building Phase - group.bench_function("Build Circuit", |b| { - b.iter(|| { - let config = CircuitConfig::standard_recursion_config_gl(); - let mut local_builder = CircuitBuilder::::new(config); - let _targets = circ.sample_slot_circuit_with_public_input(&mut local_builder); - let _data = local_builder.build::(); - }) - }); - - // Build the circuit once for proving and verifying benchmarks - let build_start = std::time::Instant::now(); - let data = builder.build::(); - let build_duration = build_start.elapsed(); - 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()); - - // Benchmark the Proving Phase - group.bench_function("Prove Circuit", |b| { - b.iter(|| { - let local_pw = pw.clone(); - data.prove(local_pw).expect("Failed to prove circuit") - }) - }); - - // Generate the proof once for verification benchmarking - let prove_start = std::time::Instant::now(); - let proof_with_pis = data.prove(pw.clone()).expect("Failed to prove circuit"); - let prove_duration = prove_start.elapsed(); - println!("prove time: {:?}", prove_duration); - let verifier_data = data.verifier_data(); - - println!("Proof size: {} bytes", proof_with_pis.to_bytes().len()); - - // Benchmark the Verifying Phase - group.bench_function("Verify Proof", |b| { - b.iter(|| { - verifier_data.verify(proof_with_pis.clone()).expect("Failed to verify proof"); - }) - }); - - group.finish(); - Ok(()) -} - -/// Criterion benchmark group -criterion_group!{ - name = prove_verify_benches; - config = Criterion::default().sample_size(10); - targets = bench_prove_verify -} -criterion_main!(prove_verify_benches); diff --git a/goldibear_experiments/proof-input/src/data_structs.rs b/goldibear_experiments/proof-input/src/data_structs.rs deleted file mode 100644 index d01f230..0000000 --- a/goldibear_experiments/proof-input/src/data_structs.rs +++ /dev/null @@ -1,257 +0,0 @@ -// Data structure used to generate the proof input - -use plonky2::hash::hash_types::{HashOut, RichField}; -use codex_plonky2_circuits::circuits::sample_cells::Cell; -use plonky2_field::types::{HasExtension, Sample}; -use crate::merkle_tree::merkle_safe::{MerkleProof, MerkleTree}; -use crate::params::{InputParams, HF}; -use crate::sponge::hash_bytes_no_padding; -use crate::utils::{bits_le_padded_to_usize, calculate_cell_index_bits, usize_to_bits_le}; -use codex_plonky2_circuits::circuits::params::NUM_HASH_OUT_ELTS; - -// ----------------- slot tree ----------------- -#[derive(Clone)] -pub struct SlotTree< - F: RichField + HasExtension, - const D: usize, -> { - pub tree: MerkleTree, // slot tree - pub block_trees: Vec>, // vec of block trees - pub cell_data: Vec>, // cell data as field elements - pub params: InputParams, // parameters -} - -impl< - F: RichField + HasExtension, - const D: usize, -> SlotTree { - /// Create a slot tree with fake data, for testing only - pub fn new_default(params: &InputParams) -> Self { - // generate fake cell data - let cell_data = (0..params.n_cells) - .map(|_| new_random_cell(params)) - .collect::>(); - Self::new(cell_data, params.clone()) - } - - /// Create a new slot tree with the supplied cell data and parameters - pub fn new(cells: Vec>, params: InputParams) -> Self { - let leaves: Vec> = cells - .iter() - .map(|element| hash_bytes_no_padding::(&element.data)) - .collect(); - let zero = HashOut { - elements: [F::zero(); 4], - }; - let n_blocks = params.n_blocks_test(); - let n_cells_in_blocks = params.n_cells_in_blocks(); - - let block_trees = (0..n_blocks) - .map(|i| { - let start = i * n_cells_in_blocks; - let end = (i + 1) * n_cells_in_blocks; - Self::get_block_tree(&leaves[start..end].to_vec()) - }) - .collect::>(); - let block_roots = block_trees - .iter() - .map(|t| t.root().unwrap()) - .collect::>(); - let slot_tree = MerkleTree::::new(&block_roots, zero).unwrap(); - Self { - tree: slot_tree, - block_trees, - cell_data: cells, - params, - } - } - - /// Generates a proof for the given leaf index - /// The path in the proof is a combined block and slot path to make up the full path - pub fn get_proof(&self, index: usize) -> MerkleProof { - let block_index = index / self.params.n_cells_in_blocks(); - let leaf_index = index % self.params.n_cells_in_blocks(); - let block_proof = self.block_trees[block_index].get_proof(leaf_index).unwrap(); - let slot_proof = self.tree.get_proof(block_index).unwrap(); - - // Combine the paths from the block and slot proofs - let mut combined_path = block_proof.path.clone(); - combined_path.extend(slot_proof.path.clone()); - - MerkleProof:: { - index, - path: combined_path, - nleaves: self.cell_data.len(), - zero: block_proof.zero.clone(), - } - } - - fn get_block_tree(leaves: &Vec>) -> MerkleTree { - let zero = HashOut { - elements: [F::zero(); 4], - }; - // Build the Merkle tree - let block_tree = MerkleTree::::new(leaves, zero).unwrap(); - block_tree - } -} - -// -------------- Dataset Tree ------------- -/// Dataset tree containing all slot trees -#[derive(Clone)] -pub struct DatasetTree< - F: RichField + HasExtension, - const D: usize, -> { - pub tree: MerkleTree, // dataset tree - pub slot_trees: Vec>, // vec of slot trees - pub params: InputParams, // parameters -} - -/// Dataset Merkle proof struct, containing the dataset proof and sampled proofs. -#[derive(Clone)] -pub struct DatasetProof< - F: RichField + HasExtension, - const D: usize, -> { - pub slot_index: F, - pub entropy: HashOut, - pub dataset_proof: MerkleProof, // proof for dataset level tree - pub slot_proofs: Vec>, // proofs for sampled slot - pub cell_data: Vec>, -} - -impl< - F: RichField + HasExtension, - const D: usize, -> DatasetTree { - /// Dataset tree with fake data, for testing only - pub fn new_default(params: &InputParams) -> Self { - let mut slot_trees = vec![]; - let n_slots = 1 << params.dataset_depth_test(); - for _ in 0..n_slots { - slot_trees.push(SlotTree::::new_default(params)); - } - Self::new(slot_trees, params.clone()) - } - - /// Create data for only the specified slot index in params - pub fn new_for_testing(params: &InputParams) -> Self { - let mut slot_trees = vec![]; - // let n_slots = 1 << params.dataset_depth(); - let n_slots = params.n_slots; - // zero hash - let zero = HashOut { - elements: [F::zero(); 4], - }; - let zero_slot = SlotTree:: { - tree: MerkleTree::::new(&[zero.clone()], zero.clone()).unwrap(), - block_trees: vec![], - cell_data: vec![], - params: params.clone(), - }; - for i in 0..n_slots { - if i == params.testing_slot_index { - slot_trees.push(SlotTree::::new_default(params)); - } else { - slot_trees.push(zero_slot.clone()); - } - } - // get the roots of slot trees - let slot_roots = slot_trees - .iter() - .map(|t| t.tree.root().unwrap()) - .collect::>(); - let dataset_tree = MerkleTree::::new(&slot_roots, zero).unwrap(); - Self { - tree: dataset_tree, - slot_trees, - params: params.clone(), - } - } - - /// Same as default but with supplied slot trees - pub fn new(slot_trees: Vec>, params: InputParams) -> Self { - // get the roots of slot trees - let slot_roots = slot_trees - .iter() - .map(|t| t.tree.root().unwrap()) - .collect::>(); - // zero hash - let zero = HashOut { - elements: [F::zero(); 4], - }; - let dataset_tree = MerkleTree::::new(&slot_roots, zero).unwrap(); - Self { - tree: dataset_tree, - slot_trees, - params, - } - } - - /// Generates a proof for the given slot index - /// Also takes entropy so it can use it to sample the slot - /// note: proofs are padded based on the params in self - pub fn sample_slot(&self, index: usize, entropy: usize) -> DatasetProof { - let mut dataset_proof = self.tree.get_proof(index).unwrap(); - Self::pad_proof(&mut dataset_proof, self.params.dataset_max_depth()); - - let slot = &self.slot_trees[index]; - let slot_root = slot.tree.root().unwrap(); - let mut slot_proofs = vec![]; - let mut cell_data = vec![]; - let entropy_field = F::from_canonical_u64(entropy as u64); - let mut entropy_as_digest = HashOut::::zero(); - entropy_as_digest.elements[0] = entropy_field; - - // get the index for cell from H(slot_root|counter|entropy) - let mask_bits = usize_to_bits_le(self.params.n_cells-1, self.params.max_depth+1); - for i in 0..self.params.n_samples { - let cell_index_bits = calculate_cell_index_bits( - &entropy_as_digest.elements.to_vec(), - slot_root, - i + 1, - self.params.max_depth, - mask_bits.clone() - ); - let cell_index = bits_le_padded_to_usize(&cell_index_bits); - let mut s_proof = slot.get_proof(cell_index); - Self::pad_proof(&mut s_proof, self.params.max_depth); - slot_proofs.push(s_proof); - let data_i = slot.cell_data[cell_index].data.clone(); - let cell_i = Cell::{ - data: data_i - }; - cell_data.push(cell_i); - } - - DatasetProof { - slot_index: F::from_canonical_u64(index as u64), - entropy: entropy_as_digest, - dataset_proof, - slot_proofs, - cell_data, - } - } - /// pad the proof with 0s until max_depth - pub fn pad_proof(merkle_proof: &mut MerkleProof, max_depth: usize){ - for i in merkle_proof.path.len()..max_depth{ - merkle_proof.path.push(HashOut::::zero()); - } - } -} - -// ------------ helper functions ------------- - -/// Create a new cell with random data, using the parameters from `Params` -pub fn new_random_cell< - F: RichField + HasExtension, - const D: usize, ->(params: &InputParams) -> Cell { - let data = (0..params.n_field_elems_per_cell()) - .map(|_| F::rand()) - .collect::>(); - Cell:: { - data, - } -} diff --git a/goldibear_experiments/proof-input/src/gen_input.rs b/goldibear_experiments/proof-input/src/gen_input.rs deleted file mode 100644 index 149f9e0..0000000 --- a/goldibear_experiments/proof-input/src/gen_input.rs +++ /dev/null @@ -1,234 +0,0 @@ -use plonky2::hash::hash_types::RichField; -use plonky2::plonk::config::{GenericConfig, Hasher}; -use crate::params::{Params,InputParams}; -use crate::utils::{bits_le_padded_to_usize, calculate_cell_index_bits, ceiling_log2, usize_to_bits_le}; -use crate::merkle_tree::merkle_safe::MerkleProof; -use codex_plonky2_circuits::circuits::sample_cells::{MerklePath, SampleCircuit, SampleCircuitInput, SampleTargets}; -use plonky2::iop::witness::PartialWitness; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData}; -use plonky2::plonk::proof::ProofWithPublicInputs; -use codex_plonky2_circuits::circuits::params::CircuitParams; -use plonky2_field::types::HasExtension; -use crate::data_structs::DatasetTree; -use crate::sponge::hash_bytes_no_padding; -use crate::params::{C, D, F, HF}; -use codex_plonky2_circuits::circuits::params::NUM_HASH_OUT_ELTS; - -/// generates circuit input (SampleCircuitInput) from fake data for testing -/// which can be later stored into json see json.rs -pub fn gen_testing_circuit_input< - F: RichField + HasExtension, - const D: usize, ->(params: &InputParams) -> SampleCircuitInput{ - let dataset_t = DatasetTree::::new_for_testing(¶ms); - - let slot_index = params.testing_slot_index; // samples the specified slot - let entropy = params.entropy; // Use the entropy from Params - - let proof = dataset_t.sample_slot(slot_index, entropy); - let slot_root = dataset_t.slot_trees[slot_index].tree.root().unwrap(); - - let mut slot_paths = vec![]; - for i in 0..params.n_samples { - let path = proof.slot_proofs[i].path.clone(); - let mp = MerklePath::{ - path, - }; - slot_paths.push(mp); - } - - SampleCircuitInput:: { - entropy: proof.entropy, - dataset_root: dataset_t.tree.root().unwrap(), - slot_index: proof.slot_index.clone(), - slot_root, - n_cells_per_slot: F::from_canonical_usize(params.n_cells), - n_slots_per_dataset: F::from_canonical_usize(params.n_slots), - slot_proof: proof.dataset_proof.path.clone(), - cell_data: proof.cell_data.clone(), - merkle_paths: slot_paths, - } -} - -/// verifies the given circuit input. -/// this is non circuit version for sanity check -pub fn verify_circuit_input< - F: RichField + HasExtension, - const D: usize, ->(circ_input: SampleCircuitInput, params: &InputParams) -> bool{ - let slot_index = circ_input.slot_index.as_canonical_u64(); - let slot_root = circ_input.slot_root.clone(); - // check dataset level proof - let slot_proof = circ_input.slot_proof.clone(); - let dataset_path_bits = usize_to_bits_le(slot_index as usize, params.dataset_max_depth()); - let (dataset_last_bits, dataset_mask_bits) = ceiling_log2(params.n_slots, params.dataset_max_depth()); - let reconstructed_slot_root = MerkleProof::::reconstruct_root2( - slot_root, - dataset_path_bits, - dataset_last_bits, - slot_proof, - dataset_mask_bits, - params.max_slots.trailing_zeros() as usize, - ).unwrap(); - // assert reconstructed equals dataset root - assert_eq!(reconstructed_slot_root, circ_input.dataset_root.clone()); - - // check each sampled cell - // get the index for cell from H(slot_root|counter|entropy) - let mask_bits = usize_to_bits_le(params.n_cells -1, params.max_depth); - for i in 0..params.n_samples { - let cell_index_bits = calculate_cell_index_bits( - &circ_input.entropy.elements.to_vec(), - slot_root, - i + 1, - params.max_depth, - mask_bits.clone(), - ); - - let cell_index = bits_le_padded_to_usize(&cell_index_bits); - - let s_res = verify_cell_proof(&circ_input, ¶ms, cell_index, i); - if s_res.unwrap() == false { - println!("call {} is false", i); - return false; - } - } - true -} - -/// Verify the given proof for slot tree, checks equality with the given root -pub fn verify_cell_proof< - F: RichField + HasExtension, - const D: usize, ->(circ_input: &SampleCircuitInput, params: &InputParams, cell_index: usize, ctr: usize) -> anyhow::Result { - let mut block_path_bits = usize_to_bits_le(cell_index, params.max_depth); - let last_index = params.n_cells - 1; - let mut block_last_bits = usize_to_bits_le(last_index, params.max_depth); - - let split_point = params.bot_depth(); - - let slot_last_bits = block_last_bits.split_off(split_point); - let slot_path_bits = block_path_bits.split_off(split_point); - - // pub type HP = >::Permutation; - let leaf_hash = hash_bytes_no_padding::(&circ_input.cell_data[ctr].data); - - let mut block_path = circ_input.merkle_paths[ctr].path.clone(); - let slot_path = block_path.split_off(split_point); - - let mut block_mask_bits = usize_to_bits_le(last_index, params.max_depth+1); - let mut slot_mask_bits = block_mask_bits.split_off(split_point); - - block_mask_bits.push(false); - slot_mask_bits.push(false); - - let block_res = MerkleProof::::reconstruct_root2( - leaf_hash, - block_path_bits.clone(), - block_last_bits.clone(), - block_path, - block_mask_bits, - params.bot_depth(), - ); - let reconstructed_root = MerkleProof::::reconstruct_root2( - block_res.unwrap(), - slot_path_bits, - slot_last_bits, - slot_path, - slot_mask_bits, - params.max_depth - params.bot_depth(), - ); - - Ok(reconstructed_root.unwrap() == circ_input.slot_root) -} - - -/// returns exactly M default circuit input -pub fn get_m_default_circ_input() -> [SampleCircuitInput; M]{ - let params = Params::default().input_params; - // let one_circ_input = gen_testing_circuit_input::(¶ms); - // let circ_input: [SampleCircuitInput; M] = (0..M) - // .map(|_| one_circ_input.clone()) - // .collect::>() - // .try_into().unwrap(); - // circ_input - get_m_circ_input::(params) -} - -/// returns exactly M default circuit input -pub fn get_m_circ_input(params: InputParams) -> [SampleCircuitInput; M]{ - // let params = Params::default().input_params; - let one_circ_input = gen_testing_circuit_input::(¶ms); - let circ_input: [SampleCircuitInput; M] = (0..M) - .map(|_| one_circ_input.clone()) - .collect::>() - .try_into().unwrap(); - circ_input -} - -#[cfg(test)] -mod tests { - use std::time::Instant; - use super::*; - use plonky2::plonk::circuit_data::CircuitConfig; - use plonky2::iop::witness::PartialWitness; - use plonky2::plonk::circuit_builder::CircuitBuilder; - use codex_plonky2_circuits::circuits::params::CircuitParams; - use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit; - // use crate::params::{C, D, F}; - - // Test sample cells (non-circuit) - #[test] - fn test_gen_verify_proof(){ - let params = Params::default().input_params; - let w = gen_testing_circuit_input::(¶ms); - assert!(verify_circuit_input::(w, ¶ms)); - } - - // Test sample cells in-circuit for a selected slot - #[test] - fn test_proof_in_circuit() -> anyhow::Result<()> { - // get input - let mut params = Params::default(); - let mut input_params = params.input_params; - input_params.n_samples = 10; - let circ_input = gen_testing_circuit_input::(&input_params); - - // Create the circuit - let config = CircuitConfig::standard_recursion_config_gl(); - let mut builder = CircuitBuilder::::new(config); - - let mut circuit_params = params.circuit_params; - circuit_params.n_samples = 10; - - // build the circuit - let circ = SampleCircuit::::new(circuit_params.clone()); - let mut targets = circ.sample_slot_circuit_with_public_input(&mut builder)?; - - // Create a PartialWitness and assign - let mut pw = PartialWitness::new(); - - // assign a witness - circ.sample_slot_assign_witness(&mut pw, &targets, &circ_input)?; - - // Build the circuit - let data = builder.build::(); - println!("circuit size = {:?}", data.common.degree_bits()); - - // Prove the circuit with the assigned witness - let start_time = Instant::now(); - let proof_with_pis = data.prove(pw)?; - println!("prove_time = {:?}", start_time.elapsed()); - - // Verify the proof - let verifier_data = data.verifier_data(); - assert!( - verifier_data.verify(proof_with_pis).is_ok(), - "Merkle proof verification failed" - ); - - Ok(()) - } - -} diff --git a/goldibear_experiments/proof-input/src/lib.rs b/goldibear_experiments/proof-input/src/lib.rs deleted file mode 100644 index a71ed0e..0000000 --- a/goldibear_experiments/proof-input/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ - -pub mod gen_input; -pub mod params; -pub mod utils; -pub mod sponge; -pub mod merkle_tree; -pub mod data_structs; diff --git a/goldibear_experiments/proof-input/src/merkle_tree/key_compress.rs b/goldibear_experiments/proof-input/src/merkle_tree/key_compress.rs deleted file mode 100644 index 2205461..0000000 --- a/goldibear_experiments/proof-input/src/merkle_tree/key_compress.rs +++ /dev/null @@ -1,27 +0,0 @@ -use plonky2::hash::hash_types::{HashOut, RichField}; -use plonky2::hash::hashing::PlonkyPermutation; -use plonky2::plonk::config::Hasher; -use codex_plonky2_circuits::circuits::params::NUM_HASH_OUT_ELTS; -use plonky2_field::types::HasExtension; - -/// Compression function which takes two 256 bit inputs (HashOut) and u64 key (which is converted to field element in the function) -/// and returns a 256 bit output (HashOut / 4 Goldilocks field elems). -pub fn key_compress< - F: RichField + HasExtension, - const D: usize, - H:Hasher ->(x: HashOut, y: HashOut, key: u64) -> HashOut { - - let key_field = F::from_canonical_u64(key); - - let mut perm = H::Permutation::new(core::iter::repeat(F::zero())); - perm.set_from_slice(&x.elements, 0); - perm.set_from_slice(&y.elements, NUM_HASH_OUT_ELTS); - perm.set_elt(key_field,NUM_HASH_OUT_ELTS*2); - - perm.permute(); - - HashOut { - elements: perm.squeeze()[..NUM_HASH_OUT_ELTS].try_into().unwrap(), - } -} \ No newline at end of file diff --git a/goldibear_experiments/proof-input/src/merkle_tree/merkle_safe.rs b/goldibear_experiments/proof-input/src/merkle_tree/merkle_safe.rs deleted file mode 100644 index 057fa31..0000000 --- a/goldibear_experiments/proof-input/src/merkle_tree/merkle_safe.rs +++ /dev/null @@ -1,247 +0,0 @@ -// Implementation of "safe" merkle tree -// consistent with the one in codex: -// https://github.com/codex-storage/nim-codex/blob/master/codex/merkletree/merkletree.nim - -use anyhow::{ensure, Result}; -// use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::hash::hash_types::{HashOut, RichField}; -// use plonky2::hash::poseidon::PoseidonHash; -use plonky2::plonk::config::Hasher; -use std::ops::Shr; -use plonky2_field::types::{ HasExtension}; -use crate::merkle_tree::key_compress::key_compress; -use crate::params::HF; -use codex_plonky2_circuits::circuits::params::NUM_HASH_OUT_ELTS; - -// Constants for the keys used in compression -pub const KEY_NONE: u64 = 0x0; -pub const KEY_BOTTOM_LAYER: u64 = 0x1; -pub const KEY_ODD: u64 = 0x2; -pub const KEY_ODD_AND_BOTTOM_LAYER: u64 = 0x3; - -/// Merkle tree struct, containing the layers, compression function, and zero hash. -#[derive(Clone)] -pub struct MerkleTree< - F: RichField + HasExtension, - const D: usize, -> { - pub layers: Vec>>, - pub zero: HashOut, -} - -impl< - F: RichField + HasExtension, - const D: usize, -> MerkleTree { - /// Constructs a new Merkle tree from the given leaves. - pub fn new( - leaves: &[HashOut], - zero: HashOut, - ) -> Result { - let layers = merkle_tree_worker::(leaves, zero, true)?; - Ok(Self { - layers, - zero, - }) - } - - /// Returns the depth of the Merkle tree. - pub fn depth(&self) -> usize { - self.layers.len() - 1 - } - - /// Returns the number of leaves in the Merkle tree. - pub fn leaves_count(&self) -> usize { - self.layers[0].len() - } - - /// Returns the root hash of the Merkle tree. - pub fn root(&self) -> Result> { - let last_layer = self.layers.last().ok_or_else(|| anyhow::anyhow!("Empty tree"))?; - ensure!(last_layer.len() == 1, "Invalid Merkle tree"); - Ok(last_layer[0]) - } - - /// Generates a Merkle proof for a given leaf index. - pub fn get_proof(&self, index: usize) -> Result> { - let depth = self.depth(); - let nleaves = self.leaves_count(); - - ensure!(index < nleaves, "Index out of bounds"); - - let mut path = Vec::with_capacity(depth); - let mut k = index; - let mut m = nleaves; - - for i in 0..depth { - let j = k ^ 1; - let sibling = if j < m { - self.layers[i][j] - } else { - self.zero - }; - path.push(sibling); - k = k >> 1; - m = (m + 1) >> 1; - } - - Ok(MerkleProof { - index, - path, - nleaves, - zero: self.zero, - }) - } -} - -/// Build the Merkle tree layers. -fn merkle_tree_worker< - F: RichField + HasExtension, - const D: usize, ->( - xs: &[HashOut], - zero: HashOut, - is_bottom_layer: bool, -) -> Result>>> { - let m = xs.len(); - if !is_bottom_layer && m == 1 { - return Ok(vec![xs.to_vec()]); - } - - let halfn = m / 2; - let n = 2 * halfn; - let is_odd = n != m; - - let mut ys = Vec::with_capacity(halfn + if is_odd { 1 } else { 0 }); - - for i in 0..halfn { - let key = if is_bottom_layer { KEY_BOTTOM_LAYER } else { KEY_NONE }; - let h = key_compress::(xs[2 * i], xs[2 * i + 1], key); - ys.push(h); - } - - if is_odd { - let key = if is_bottom_layer { - KEY_ODD_AND_BOTTOM_LAYER - } else { - KEY_ODD - }; - let h = key_compress::(xs[n], zero, key); - ys.push(h); - } - - let mut layers = vec![xs.to_vec()]; - let mut upper_layers = merkle_tree_worker::(&ys, zero, false)?; - layers.append(&mut upper_layers); - - Ok(layers) -} - -/// Merkle proof struct, containing the index, path, and other necessary data. -#[derive(Clone)] -pub struct MerkleProof< - F: RichField + HasExtension, - const D: usize, -> { - pub index: usize, // Index of the leaf - pub path: Vec>, // Sibling hashes from the leaf to the root - pub nleaves: usize, // Total number of leaves - pub zero: HashOut, -} - -impl< - F: RichField + HasExtension, - const D: usize, -> MerkleProof { - /// Reconstructs the root hash from the proof and the given leaf. - pub fn reconstruct_root(&self, leaf: HashOut) -> Result> { - let mut m = self.nleaves; - let mut j = self.index; - let mut h = leaf; - let mut bottom_flag = KEY_BOTTOM_LAYER; - - for p in &self.path { - let odd_index = (j & 1) != 0; - if odd_index { - // The index of the child is odd - h = key_compress::(*p, h, bottom_flag); - } else { - if j == m - 1 { - // Single child -> so odd node - h = key_compress::(h, *p, bottom_flag + 2); - } else { - // Even node - h = key_compress::(h, *p, bottom_flag); - } - } - bottom_flag = KEY_NONE; - j = j.shr(1); - m = (m + 1).shr(1); - } - - Ok(h) - } - - /// reconstruct the root using path_bits and last_bits in similar way as the circuit - /// this is used for testing - sanity check - pub fn reconstruct_root2(leaf: HashOut, path_bits: Vec, last_bits:Vec, path: Vec>, mask_bits:Vec, depth: usize) -> Result> { - let is_last = compute_is_last(path_bits.clone(),last_bits); - - let mut h = vec![]; - h.push(leaf); - let mut i = 0; - - for p in &path { - let bottom = if(i==0){ - KEY_BOTTOM_LAYER - }else{ - KEY_NONE - }; - - let odd = (is_last[i] as usize) * (1-(path_bits[i] as usize)); - - let key = bottom + (2 * (odd as u64)); - let odd_index = path_bits[i]; - if odd_index { - h.push(key_compress::(*p, h[i], key)); - } else { - h.push(key_compress::(h[i], *p, key)); - } - i += 1; - } - - let mut reconstructed_root = HashOut::::zero(); - for k in 0..depth{ - let diff = (mask_bits[k] as u64) - (mask_bits[k+1] as u64); - let mul_res: Vec = h[k+1].elements.iter().map(|e| e.mul(F::from_canonical_u64(diff))).collect(); - reconstructed_root = HashOut::::from_vec( - mul_res.iter().zip(reconstructed_root.elements).map(|(e1,e2)| e1.add(e2)).collect() - ); - } - - Ok(reconstructed_root) - } - - /// Verifies the proof against a given root and leaf. - pub fn verify(&self, leaf: HashOut, root: HashOut) -> Result { - let reconstructed_root = self.reconstruct_root(leaf)?; - Ok(reconstructed_root == root) - } -} - -///helper function to compute is_last -fn compute_is_last(path_bits: Vec, last_bits: Vec) -> Vec { - let max_depth = path_bits.len(); - - // Initialize isLast vector - let mut is_last = vec![false; max_depth + 1]; - is_last[max_depth] = true; // Set isLast[max_depth] to 1 (true) - - // Iterate over eq and isLast in reverse order - for i in (0..max_depth).rev() { - let eq_out = path_bits[i] == last_bits[i]; // eq[i].out - is_last[i] = is_last[i + 1] && eq_out; // isLast[i] = isLast[i+1] * eq[i].out - } - - is_last -} diff --git a/goldibear_experiments/proof-input/src/merkle_tree/mod.rs b/goldibear_experiments/proof-input/src/merkle_tree/mod.rs deleted file mode 100644 index 878f3ed..0000000 --- a/goldibear_experiments/proof-input/src/merkle_tree/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod merkle_safe; -pub mod key_compress; diff --git a/goldibear_experiments/proof-input/src/params.rs b/goldibear_experiments/proof-input/src/params.rs deleted file mode 100644 index 81aa68d..0000000 --- a/goldibear_experiments/proof-input/src/params.rs +++ /dev/null @@ -1,224 +0,0 @@ -// params for generating input for proof circuit - -use plonky2::hash::poseidon_goldilocks::Poseidon64Hash; -use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; -use std::env; -use anyhow::{Result, Context}; -use codex_plonky2_circuits::circuits::params::{CircuitParams, NUM_HASH_OUT_ELTS}; - -// test types -pub const D: usize = 2; -pub type C = PoseidonGoldilocksConfig; -pub type F = >::F; // this is the goldilocks field -pub type HF = Poseidon64Hash; - -// hardcoded default params for generating proof input -const DEFAULT_MAX_DEPTH: usize = 32; // depth of big tree (slot tree depth, includes block tree depth) -const DEFAULT_MAX_SLOTS: usize = 256; // maximum number of slots -const DEFAULT_CELL_SIZE: usize = 2048; // cell size in bytes -const DEFAULT_BLOCK_SIZE: usize = 65536; // block size in bytes -const DEFAULT_N_SAMPLES: usize = 5; // number of samples to prove - -const DEFAULT_ENTROPY: usize = 1234567; // external randomness -const DEFAULT_SEED: usize = 12345; // seed for creating fake data TODO: not used now - -const DEFAULT_N_SLOTS: usize = 11; // number of slots in the dataset -const DEFAULT_SLOT_INDEX: usize = 3; // the index of the slot to be sampled -const DEFAULT_N_CELLS: usize = 512; // number of cells in each slot - -/// Params struct -#[derive(Clone)] -pub struct Params { - pub circuit_params: CircuitParams, - pub input_params: InputParams, -} - -/// test params -#[derive(Clone)] -pub struct InputParams{ - pub max_depth: usize, - pub max_slots: usize, - pub cell_size: usize, - pub block_size: usize, - pub n_samples: usize, - pub entropy: usize, - pub seed: usize, - pub n_slots: usize, - pub testing_slot_index: usize, - pub n_cells: usize, -} - -/// Implement the Default trait for Params using the hardcoded constants -impl Default for Params { - fn default() -> Self { - let input_params = InputParams { - max_depth: DEFAULT_MAX_DEPTH, - max_slots: DEFAULT_MAX_SLOTS, - cell_size: DEFAULT_CELL_SIZE, - block_size: DEFAULT_BLOCK_SIZE, - n_samples: DEFAULT_N_SAMPLES, - entropy: DEFAULT_ENTROPY, - seed: DEFAULT_SEED, - n_slots: DEFAULT_N_SLOTS, - testing_slot_index: DEFAULT_SLOT_INDEX, - n_cells: DEFAULT_N_CELLS, - }; - let circuit_params = input_params.get_circuit_params(); - - Params{ - circuit_params, - input_params, - } - } -} - -/// Implement a new function to create Params with custom values -impl InputParams { - // GOLDILOCKS_F_SIZE - pub fn goldilocks_f_size(&self) -> usize { - 64 - } - - // N_FIELD_ELEMS_PER_CELL - pub fn n_field_elems_per_cell(&self) -> usize { - (self.cell_size + 62) / 62 * 8 - } - - // BOT_DEPTH - pub fn bot_depth(&self) -> usize { - log2(self.block_size / self.cell_size) - } - - // N_CELLS_IN_BLOCKS - pub fn n_cells_in_blocks(&self) -> usize { - 1 << self.bot_depth() - } - - // N_BLOCKS - pub fn n_blocks(&self) -> usize { - 1 << (self.max_depth - self.bot_depth()) - } - - // Depth of test input - pub fn depth_test(&self) -> usize { - self.n_cells.trailing_zeros() as usize - } - - // N_BLOCKS for the test input - pub fn n_blocks_test(&self) -> usize { - 1 << (self.depth_test() - self.bot_depth()) - } - - // DATASET_DEPTH - pub fn dataset_max_depth(&self) -> usize { - ceiling_log2(self.max_slots) - } - - // DATASET_DEPTH for test - pub fn dataset_depth_test(&self) -> usize { - ceiling_log2(self.n_slots) - } - - pub fn get_circuit_params(&self) -> CircuitParams{ - CircuitParams{ - max_depth: self.max_depth, - max_log2_n_slots: self.dataset_max_depth(), - block_tree_depth: self.bot_depth(), - n_field_elems_per_cell: self.n_field_elems_per_cell(), - n_samples:self.n_samples, - } - } -} - -pub fn log2(x: usize) -> usize { - assert!(x.is_power_of_two(), "Input must be a power of 2."); - x.trailing_zeros() as usize -} - -pub fn ceiling_log2(x: usize) -> usize { - if x <= 1 { - return 0; - } - usize::BITS as usize - x.saturating_sub(1).leading_zeros() as usize -} - -/// load test params from env -impl InputParams { - pub fn from_env() -> Result { - let max_depth = env::var("MAXDEPTH") - .context("MAXDEPTH not set")? - .parse::() - .context("Invalid MAXDEPTH")?; - - let max_slots = env::var("MAXSLOTS") - .context("MAXSLOTS not set")? - .parse::() - .context("Invalid MAXSLOTS")?; - - let cell_size = env::var("CELLSIZE") - .context("CELLSIZE not set")? - .parse::() - .context("Invalid CELLSIZE")?; - - let block_size = env::var("BLOCKSIZE") - .context("BLOCKSIZE not set")? - .parse::() - .context("Invalid BLOCKSIZE")?; - - let n_samples = env::var("NSAMPLES") - .context("NSAMPLES not set")? - .parse::() - .context("Invalid NSAMPLES")?; - - let entropy = env::var("ENTROPY") - .context("ENTROPY not set")? - .parse::() - .context("Invalid ENTROPY")?; - - let seed = env::var("SEED") - .context("SEED not set")? - .parse::() - .context("Invalid SEED")?; - - let n_slots = env::var("NSLOTS") - .context("NSLOTS not set")? - .parse::() - .context("Invalid NSLOTS")?; - - let testing_slot_index = env::var("SLOTINDEX") - .context("SLOTINDEX not set")? - .parse::() - .context("Invalid SLOTINDEX")?; - - let n_cells = env::var("NCELLS") - .context("NCELLS not set")? - .parse::() - .context("Invalid NCELLS")?; - - Ok(InputParams { - max_depth, - max_slots, - cell_size, - block_size, - n_samples, - entropy, - seed, - n_slots, - testing_slot_index, - n_cells, - }) - } -} - -/// load params from env -impl Params { - pub fn from_env() -> Result { - let input_params = InputParams::from_env()?; - let circuit_params = input_params.get_circuit_params(); - - Ok(Params{ - circuit_params, - input_params, - }) - } -} \ No newline at end of file diff --git a/goldibear_experiments/proof-input/src/sponge.rs b/goldibear_experiments/proof-input/src/sponge.rs deleted file mode 100644 index 83192a3..0000000 --- a/goldibear_experiments/proof-input/src/sponge.rs +++ /dev/null @@ -1,292 +0,0 @@ -use plonky2::hash::hash_types::{HashOut, RichField}; -use plonky2::plonk::config::Hasher; -use plonky2::hash::hashing::PlonkyPermutation; -use plonky2_field::types::{HasExtension}; -use codex_plonky2_circuits::circuits::params::NUM_HASH_OUT_ELTS; - -/// sponge function similar to the in-circuit one -/// used here for testing / sanity check -pub fn hash_n_with_padding< - F: RichField + HasExtension, - const D: usize, - H: Hasher ->( - inputs: &[F], -) -> HashOut{ - HashOut::::from_vec(hash_n_to_m_with_padding::(inputs, NUM_HASH_OUT_ELTS)) -} - -pub fn hash_n_to_m_with_padding< - F: RichField + HasExtension, - const D: usize, - P: PlonkyPermutation ->( - inputs: &[F], - num_outputs: usize, -) -> Vec { - let rate = P::RATE; - let width = P::WIDTH; // rate + capacity - let zero = F::zero(); - let one = F::one(); - let mut perm = P::new(core::iter::repeat(zero).take(width)); - - // Set the domain separator at index 8 - let domsep_value = F::from_canonical_u64(rate as u64 + 256 * 12 + 65536 * 63); - perm.set_elt(domsep_value, 8); - - let N = inputs.len(); - let num_chunks = (N + rate) / rate; // Calculate number of chunks with 10* padding - let mut input_iter = inputs.iter(); - - // Process all chunks except the last one - for _ in 0..(num_chunks - 1) { - let mut chunk = Vec::with_capacity(rate); - for _ in 0..rate { - if let Some(&input) = input_iter.next() { - chunk.push(input); - } else { - // should not happen here - panic!("Insufficient input elements for chunk; expected more elements."); - } - } - // Add the chunk to the state - for j in 0..rate { - perm.set_elt(perm.as_ref()[j] + chunk[j],j); - } - // Apply permutation - perm.permute(); - } - - // Process the last chunk with 10* padding - let rem = num_chunks * rate - N; // Number of padding elements (0 < rem <= rate) - let ofs = rate - rem; // Offset where padding starts - - let mut last_chunk = Vec::with_capacity(rate); - // Absorb remaining inputs - for _ in 0..ofs { - if let Some(&input) = input_iter.next() { - last_chunk.push(input); - } else { - last_chunk.push(zero); - } - } - // Add the '1' padding bit - last_chunk.push(one); - // Pad with zeros to reach the full rate - while last_chunk.len() < rate { - last_chunk.push(zero); - } - - // Add the last chunk to the state - for j in 0..rate { - perm.set_elt(perm.as_ref()[j] + last_chunk[j],j); - } - // Apply permutation - perm.permute(); - - // Squeeze outputs until we have the desired number - let mut outputs = Vec::with_capacity(num_outputs); - loop { - for &item in perm.squeeze() { - outputs.push(item); - if outputs.len() == num_outputs { - return outputs; - } - } - perm.permute(); - } -} - -/// sponge function for bytes with no padding -/// expects the input to be divisible by rate -/// note: rate is fixed at 8 for now -/// used here for testing / sanity check -pub fn hash_bytes_no_padding< - F: RichField + HasExtension, - const D: usize, - H: Hasher ->( - inputs: &[F], -) -> HashOut{ - HashOut::::from_vec(hash_bytes_to_m_no_padding::(inputs, NUM_HASH_OUT_ELTS)) -} - -pub fn hash_bytes_to_m_no_padding< - F: RichField + HasExtension, - const D: usize, - P: PlonkyPermutation ->( - inputs: &[F], - num_outputs: usize, -) -> Vec { - let rate = P::RATE; - let width = P::WIDTH; // rate + capacity - let zero = F::zero(); - let one = F::one(); - let mut perm = P::new(core::iter::repeat(zero).take(width)); - - // Set the domain separator at index 8 - let domsep_value = F::from_canonical_u64(rate as u64 + 256 * 12 + 65536 * 8); - perm.set_elt(domsep_value, 8); - - let n = inputs.len(); - assert_eq!(n % rate, 0, "Input length ({}) must be divisible by rate ({})", n, rate); - let num_chunks = n / rate; // Calculate number of chunks - let mut input_iter = inputs.iter(); - - // Process all chunks - for _ in 0..num_chunks { - let mut chunk = Vec::with_capacity(rate); - for _ in 0..rate { - if let Some(&input) = input_iter.next() { - chunk.push(input); - } else { - // should not happen here - panic!("Insufficient input elements for chunk; expected more elements."); - } - } - // Add the chunk to the state - for j in 0..rate { - perm.set_elt(perm.as_ref()[j] + chunk[j],j); - } - // Apply permutation - perm.permute(); - } - - // Squeeze outputs until we have the desired number - let mut outputs = Vec::with_capacity(num_outputs); - loop { - for &item in perm.squeeze() { - outputs.push(item); - if outputs.len() == num_outputs { - return outputs; - } - } - perm.permute(); - } -} - -// #[cfg(test)] -// mod tests { -// use crate::sponge::hash_n_with_padding; -// use crate::params::{D, F, HF}; -// -// -// #[test] -// fn test_sponge_hash_rate_8() { -// -// struct TestCase { -// n: usize, -// digest: [u64; 4], -// } -// -// let test_cases: Vec = vec![ -// TestCase { n: 0, digest: [0x509f3a747e4a6fca, 0xd6f21d91afb92eb3, 0xf65ef4075dcfb169, 0xbceaf22e0cd21b3d] }, -// TestCase { n: 1, digest: [0xfa286adad207c7ea, 0x97d864ff2e89415e, 0xcf002b28585bd945, 0x95ec163fbdd0792e] }, -// TestCase { n: 2, digest: [0xe4b779622cbb574f, 0x1fe4b1bc9a0c9fc7, 0x40051ada5252de9b, 0xb351345b1894a59f] }, -// TestCase { n: 3, digest: [0x133a5a2fd0cae006, 0x072a7769ca9a550d, 0x92134dad95d394c6, 0x22234de7d7270aab] }, -// TestCase { n: 4, digest: [0x78269e830f2a824a, 0x76f8b00469a8fa81, 0x6793369b1d75ebf5, 0xfba1a89dc21d9b30] }, -// TestCase { n: 5, digest: [0x263994efd2cd5c57, 0x7c37a93fd48fc98b, 0xa081b26a68767d13, 0x16af92d6e1e4d7f8] }, -// TestCase { n: 6, digest: [0x0b0b0f1d64f8d58c, 0x2946089b2eb949fc, 0xf68bcf08b69a95e7, 0x814d6eb4b2df848c] }, -// TestCase { n: 7, digest: [0xae0c900a194ee051, 0x4555257fba7a500b, 0x1713fd448cc82c3a, 0xaf8f2e895e2136f3] }, -// TestCase { n: 8, digest: [0x100351f04fc470b7, 0x79d3c3c416087158, 0x113bb1c70a6e84ee, 0x3eab2507cdc254d3] }, -// TestCase { n: 9, digest: [0xbab284d7f11855d6, 0xe1b53d108f308a1c, 0x971fea7184337830, 0x6d674ae321cfb9ba] }, -// TestCase { n: 10, digest: [0x68c00dbe0ed03a8f, 0xab5ba3617eb6f76b, 0x5d735bb89418cc0b, 0xff4101076f3f3c70] }, -// TestCase { n: 11, digest: [0xaecce2fa7de4f97d, 0x07cee3dc720812e0, 0x4155bf667391a9e8, 0xbf8a49a12f40e746] }, -// TestCase { n: 12, digest: [0xd3f43f06fc7affd2, 0xee9a8ac5ef44071a, 0xe00ec9e7f468d0e2, 0x944e34913a974233] }, -// TestCase { n: 13, digest: [0xcd50fe6ab5e3de54, 0x9b2093adaeac949c, 0xa176a2a9e2c82787, 0xd35f0635a1ec333f] }, -// TestCase { n: 14, digest: [0x8f5188d26ca0368c, 0x0116bf587e5cc970, 0x30654ee52a3c66d8, 0xe8ded60382c44b04] }, -// TestCase { n: 15, digest: [0xc7f020f910327951, 0x13a468945463870d, 0xbcf8ca584edb30f3, 0x7e7234f0b8954e7e] }, -// TestCase { n: 16, digest: [0xf8a9aef7392048e7, 0x6124715a2c5343eb, 0x1b7f17ebec4a5b13, 0xdf61d868051dad75] }, -// TestCase { n: 17, digest: [0x44d1fb6822c7f3fa, 0x2623cc2240022e42, 0xc90ce9259c9e1160, 0x7a42bc611acacc12] }, -// TestCase { n: 18, digest: [0x85dab5b06ef2d176, 0x24a587b13a4e3b30, 0xf547a00373299873, 0xb298a6ef846d64a1] }, -// TestCase { n: 19, digest: [0x7cc060a3f2a74260, 0xa07dc76e73335eb0, 0xf8ed9acbcf8a242e, 0xd32eaf3150005e49] }, -// TestCase { n: 20, digest: [0x3e961c84e53106f9, 0x63d9a807f9cfd88c, 0x7031e8834a17821a, 0xf2e1c79698798fa9] }, -// TestCase { n: 21, digest: [0x8a0ab00081c9828f, 0xa5f7aadaf3af046e, 0xada8b4c6220b3420, 0x80ebc8c91a65518c] }, -// TestCase { n: 22, digest: [0x39505fc00f052122, 0xb13edc24a35665c7, 0xa7b164fffe37ec64, 0x8f7eeb42c068e19f] }, -// TestCase { n: 23, digest: [0x1f49d6f25f39522b, 0x879377d8df727784, 0x00f1461600d09cdd, 0xd2c7946a44e1aa66] }, -// TestCase { n: 24, digest: [0x1c6f7a68537f7dc7, 0x64e6e09714dc0854, 0x9abfed111e51bd96, 0x65061b2bc484ed8b] }, -// TestCase { n: 25, digest: [0x95fd5cc6bc02ab29, 0xe2e3c96d9b1b8b5d, 0xadcf491caa16549e, 0x97d91e370da3c0b4] }, -// TestCase { n: 26, digest: [0x7599c5052ba67767, 0x3fe4a05f44e96ed6, 0xbbfe6874aa53808c, 0xd6771e162cc9f0ff] }, -// TestCase { n: 27, digest: [0xdff28121d822093c, 0x7313ea03b57bb436, 0x10ed29b28a77d8c3, 0x6ee304be541fe36f] }, -// TestCase { n: 28, digest: [0xce2b7f232b504b48, 0x02c638c398c12cb0, 0x4f1d416215377a86, 0x2d43ff6c5dd88f8c] }, -// TestCase { n: 29, digest: [0xa60cb008de647e9a, 0x502e2e740f68e2d1, 0xe983eb54e4052013, 0xe76e59c5e5dbcca2] }, -// TestCase { n: 30, digest: [0x7735e3ac5e08fa00, 0x211a86449207c30d, 0x9d80ddd40e7760b2, 0xe60f32f28597a188] }, -// TestCase { n: 31, digest: [0x6fab3f12496f0691, 0x5116ad81bedd7d84, 0xaa8a7713a80b323b, 0xce6d94533fc40b88] }, -// TestCase { n: 32, digest: [0xce51cdbd641d57c0, 0xf638202a88ee7f9c, 0x26c291ecc5162b45, 0x04a0a62b949c236f] }, -// TestCase { n: 33, digest: [0x923391e4a4cde9e2, 0xdcb3acccba80597d, 0x247bb4b67044a0e1, 0x65bbac92e096d1ec] }, -// TestCase { n: 34, digest: [0x1550d0234ae35f05, 0x16f4d1708923d4f1, 0x232319cb4090ea4e, 0x8354e1aed093070c] }, -// TestCase { n: 35, digest: [0xc7dd24e6db4ea70f, 0x80bc3d2aac952cb1, 0xabbd1a878bc50565, 0xf1ebc3b8d513c591] }, -// TestCase { n: 36, digest: [0xba9c4b1ce906efb1, 0xa332d0daccc62979, 0xfb658fcad0b5fbbd, 0x62d21407f34a35ee] }, -// TestCase { n: 37, digest: [0xcb2973d44f2b589d, 0x01708b32c4556317, 0x3ad51597c12b8564, 0x28d3a5d7de72cfd5] }, -// TestCase { n: 38, digest: [0x1dcf1f4ab7338296, 0xb88c661141b5aabb, 0x7e546b6e9b31bc90, 0xf26f7e6ffabb4e69] }, -// TestCase { n: 39, digest: [0x2e139ff910c0f410, 0xba3d2c0a92ec3845, 0x2860e475933a7108, 0x8f2a6c6d13bedc7a] }, -// TestCase { n: 40, digest: [0xc18a53c17c360ef4, 0x5e56ea9228988c68, 0xee0bd138436e996d, 0x06afd46a753f8257] }, -// TestCase { n: 41, digest: [0x2c992403c5277dc5, 0xba8770bc3a54b043, 0x51b882882a7b7864, 0xf75e179a53e7948e] }, -// TestCase { n: 42, digest: [0xde855183965741c3, 0x93520eac77a8f98d, 0x6412ae8cf0522d78, 0x9db49c6b455a83b4] }, -// TestCase { n: 43, digest: [0x552e357ddb7e1ef6, 0x5fa779e9c7373b56, 0x18f7c445e27e5dcf, 0x2664ecee5e7bc6c2] }, -// TestCase { n: 44, digest: [0x37b8a716c87e5489, 0x1201fcd31e407152, 0x0979d7887c42e1ca, 0x902e8b2bf748b356] }, -// TestCase { n: 45, digest: [0xa48bdd1d464960ed, 0x8e92c1af0cf258bc, 0x7c5b447524b92ba9, 0xac63902e613e4ef0] }, -// TestCase { n: 46, digest: [0x542e62f9317fe11d, 0xc23ba113a3f3c810, 0x2bda30c42a89cc7e, 0x35616e9f1a00aa8f] }, -// TestCase { n: 47, digest: [0x1c9194a0acfa97d7, 0x60d536ac106dd774, 0x8855b4a40e110080, 0xc2c408114e8c20d6] }, -// TestCase { n: 48, digest: [0x0e90b1cc3ac49e0c, 0x1b73aa8e0decbf88, 0x0ca9ef7070e0513f, 0x25cfb975571b6139] }, -// TestCase { n: 49, digest: [0xba6d6f7aa664f2e7, 0x4b9af896093937b9, 0x115b9aeb6c5f563e, 0x41cb5f42c6d3b115] }, -// TestCase { n: 50, digest: [0xdc3bdc491154caf6, 0xb95159bae61b2035, 0x98bd384fb3d0100b, 0xd70226f2b71ea465] }, -// TestCase { n: 51, digest: [0x57f31da51bcd2eab, 0x4a3b3945a8662b5c, 0x44dffaa325530b19, 0x47f4e41c2c1474cf] }, -// TestCase { n: 52, digest: [0xc3f518f6cf3b43bf, 0x1214790ff48554e4, 0x99c1eabc61b218fd, 0xf90b03954d7937f8] }, -// TestCase { n: 53, digest: [0x6357b3cdcbc1283a, 0x6acc0c2d5aac9261, 0xdf11e7ad14d432d1, 0x2242b26bdcc8a380] }, -// TestCase { n: 54, digest: [0x1946dc4471f8c502, 0x6be7d72499e0b4a5, 0x6e11de349239ff90, 0xfca78044256b8b54] }, -// TestCase { n: 55, digest: [0x302b38fb3df623dd, 0x69b362f7932fd7af, 0x2b47156f9135508b, 0xfe6c574f0a102e92] }, -// TestCase { n: 56, digest: [0xfdc9bd08a0416122, 0x063ebf4767fc7914, 0x330f36279d94050e, 0x79c61f80746893ec] }, -// TestCase { n: 57, digest: [0x7b5d8384b67af5c0, 0xa705e0163fa4d839, 0x1e203432e872104e, 0xe0e7699f20a291f4] }, -// TestCase { n: 58, digest: [0xb0aa74a52fe04366, 0x194b0d4afcdc03d9, 0x5134dc604b5d9f2a, 0x53c6bf9d5a1d502b] }, -// TestCase { n: 59, digest: [0xd5c8258f6fc80e2b, 0x82bac373eb051b48, 0x5ef620241420462d, 0x58635db0134fb97a] }, -// TestCase { n: 60, digest: [0x42ebb974ac5dd0ef, 0x676d0c6b3dde78c3, 0x14ed5eda2c9cb9de, 0x0f78a26badaa447c] }, -// TestCase { n: 61, digest: [0x2b3ca7711db999d5, 0xb74bd29abcb6179a, 0x8ba196525e6adb25, 0x86cb9464ae269a43] }, -// TestCase { n: 62, digest: [0x3d0e61a2ca7a65a2, 0x31f77852d41a6c8d, 0x2e4ceaa39763a53d, 0x5232ff5a3d78755e] }, -// TestCase { n: 63, digest: [0xb2ed789e88c1f525, 0x1592c1a1eafd2a9b, 0x98700c512f8c9a5d, 0xf96837b5d99a4eb4] }, -// TestCase { n: 64, digest: [0xe4b7d14e11de2fa9, 0xe81afff2cee68e14, 0xc58abb080bf37dd3, 0x36ae8b2196b5ae88] }, -// TestCase { n: 65, digest: [0xa1df9ff199c41d63, 0xd02c067d3d12edc1, 0xc9b598130fa60794, 0x5afe82d34c3fc8fa] }, -// TestCase { n: 66, digest: [0x0bc0094a1f07256d, 0x33c5b4c2a171d5bd, 0x1f38f1b1dc92aa54, 0x4610d21f276faa11] }, -// TestCase { n: 67, digest: [0x8072f00df8f7e44f, 0x42f0c2b8fe81d8a0, 0x2b5caf9e7c0ff611, 0x92b0b3a4a4bebe1a] }, -// TestCase { n: 68, digest: [0x6539f06fab064b57, 0xdb298b91f6c4f44f, 0x5d8f8eec6b7e8c86, 0x848a447123f39006] }, -// TestCase { n: 69, digest: [0x87f32efc9eaa65f6, 0xc5699d4ab6443852, 0x61008286bc651f4a, 0xcbcf714354843da3] }, -// TestCase { n: 70, digest: [0xffb8ad2258107315, 0xf7d6a58eb54f2745, 0xaecf888211821114, 0x7e0ea33b4d56976e] }, -// TestCase { n: 71, digest: [0xa9e5b6d70f67db2b, 0x072fd05840040322, 0x40ffcc86e3909dec, 0x3d80f61616a9e6d7] }, -// TestCase { n: 72, digest: [0xa77dd95d9ff4d7b8, 0x3a0e0502f74c091a, 0x1fa83de1e7dc716d, 0xe01ae447cc3a0e40] }, -// TestCase { n: 73, digest: [0xc4a29dc875a308eb, 0xd2ed0da7aab24b0c, 0x4c2aaaed0bc4f059, 0xaea772c635ea901a] }, -// TestCase { n: 74, digest: [0xaad59bf06c151ecf, 0x5e0f45e55df36692, 0x4798afb8b944a01e, 0xd7152cd819bbd7f8] }, -// TestCase { n: 75, digest: [0x89ae5b2b35ba07c7, 0x129f4ff59afaa1a3, 0x4275f3f797112650, 0xea3b4baaf7190a19] }, -// TestCase { n: 76, digest: [0xab068e43be297604, 0x17bd1c3cf4afec96, 0xaa84a8098dba4516, 0xa6e487ceafb02c49] }, -// TestCase { n: 77, digest: [0x2c85080ef895bb4a, 0xbd280690a789c124, 0xca4f8423b50de8a5, 0xec809bb8c30de95b] }, -// TestCase { n: 78, digest: [0x51c3d13543e4922b, 0xff9c11d5b93268db, 0xd9cf911cc5326948, 0x4b7bb11eafe7fd44] }, -// TestCase { n: 79, digest: [0xb435274d75678586, 0x8600e7f2db687493, 0x282873a3600a38da, 0x727791507d1b600e] }, -// TestCase { n: 80, digest: [0x23ae45602324f628, 0x0dc16b33f43209c5, 0x2455376f83b1aeff, 0xd5470f22ec2113bc] }, -// ]; -// -// for test_case in test_cases { -// let n = test_case.n; -// let expected_digest = test_case.digest; -// -// // Generate inputs -// let inputs: Vec = (0..n) -// .map(|i| F::from_canonical_u64(i as u64 + 1)) -// .collect(); -// -// // Call the sponge function -// let output = hash_n_with_padding::(&inputs); -// -// // Compare the outputs -// for (i, &out_elem) in output.elements.iter().enumerate() { -// let expected_elem = F::from_canonical_u64(expected_digest[i]); -// assert_eq!( -// out_elem, -// expected_elem, -// "Mismatch at test case n={}, output element {}", -// n, -// i -// ); -// } -// } -// } -// } diff --git a/goldibear_experiments/proof-input/src/utils.rs b/goldibear_experiments/proof-input/src/utils.rs deleted file mode 100644 index 0e63dbb..0000000 --- a/goldibear_experiments/proof-input/src/utils.rs +++ /dev/null @@ -1,103 +0,0 @@ -use plonky2::hash::hash_types::{HashOut, RichField}; -use crate::params::HF; -use plonky2::hash::hashing::PlonkyPermutation; -use plonky2_field::types::HasExtension; -use crate::sponge::hash_n_with_padding; -use codex_plonky2_circuits::circuits::params::NUM_HASH_OUT_ELTS; - -// --------- helper functions --------- - -/// Converts an index to a vector of bits (LSB first) no padding. -pub fn usize_to_bits_le(index: usize, bit_length: usize) -> Vec { - // Assert that the index can fit within the given bit length. - assert!( - index < (1 << bit_length), - "Index ({}) does not fit in {} bits", - index, - bit_length - ); - - let mut bits = Vec::with_capacity(bit_length); - for i in 0..bit_length { - bits.push(((index >> i) & 1) == 1); - } - - // No padding - bits -} - -/// returns the first bit_length bits of index -pub fn low_bits(index: usize, bit_length: usize) -> Vec { - - let mut bits = Vec::with_capacity(bit_length); - - for i in 0..bit_length { - // get the i-th bit and push its bool value - bits.push(((index >> i) & 1) == 1); - } - - bits -} - -/// calculate the sampled cell index from entropy, slot root, and counter -/// this is the non-circuit version for testing -pub fn calculate_cell_index_bits< - F: RichField + HasExtension, - const D: usize ->(entropy: &Vec, slot_root: HashOut, ctr: usize, depth: usize, mask_bits: Vec) -> Vec { - let ctr_field = F::from_canonical_u64(ctr as u64); - let mut ctr_as_digest = HashOut::::zero(); - ctr_as_digest.elements[0] = ctr_field; - let mut hash_inputs = Vec::new(); - hash_inputs.extend_from_slice(&entropy); - hash_inputs.extend_from_slice(&slot_root.elements); - hash_inputs.extend_from_slice(&ctr_as_digest.elements); - let hash_output = hash_n_with_padding::(&hash_inputs); - let cell_index_bytes = hash_output.elements[0].as_canonical_u64(); - - let cell_index_bits = low_bits(cell_index_bytes as usize, depth); - - let mut masked_cell_index_bits = vec![]; - - for i in 0..depth{ - masked_cell_index_bits.push(cell_index_bits[i] && mask_bits[i]); - } - - masked_cell_index_bits -} - -/// Converts a vector of bits (LSB first) into an index (usize). -pub fn bits_le_padded_to_usize(bits: &[bool]) -> usize { - bits.iter().enumerate().fold(0usize, |acc, (i, &bit)| { - if bit { - acc | (1 << i) - } else { - acc - } - }) -} - -/// computes the `last_index` (the binary decomposition of `inp-1`) and the `mask_bits` -pub fn ceiling_log2( - inp: usize, - n: usize, -) -> (Vec, Vec) { - // Handle the case when inp is 0 - let last_index = if inp == 0 { panic!("input to ceiling_log2 is 0") } else { inp - 1 }; - let last_bits = usize_to_bits_le(last_index, n); - - // Initialize aux, all false - let mut aux = vec![false; n+1]; - aux[n] = true; // aux[n] = 1 - - // Initialize mask vector - let mut mask = vec![false; n+1]; - - // Compute aux and mask bits - for i in (0..n).rev() { - aux[i] = aux[i + 1] && !last_bits[i]; - mask[i] = !aux[i]; - } - - (last_bits, mask) -} diff --git a/recursion_experiments/README.md b/recursion_experiments/README.md deleted file mode 100644 index 1f2fd4c..0000000 --- a/recursion_experiments/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Proof Aggregation Experiments -================================ - -In here, we archive the experiments done on various approaches to recursion before setting on the uniform approach. -See [here](../codex-plonky2-circuits/src/recursion) for the best recursion circuit option for our use case that we settled on. diff --git a/recursion_experiments/benches/cyclic_recursion.rs b/recursion_experiments/benches/cyclic_recursion.rs deleted file mode 100644 index 1902155..0000000 --- a/recursion_experiments/benches/cyclic_recursion.rs +++ /dev/null @@ -1,80 +0,0 @@ -use criterion::{Criterion, criterion_group, criterion_main}; -use plonky2::plonk::config::GenericConfig; -use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; -use codex_plonky2_circuits::recursion::cyclic::CyclicCircuit; -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_cyclic_recursion(c: &mut Criterion) -> anyhow::Result<()>{ - - let mut group = c.benchmark_group(format!("Cyclic Recursion Benchmark for N={}",N)); - - // number of samples in each proof - let n_samples = 10; - - let mut params = Params::default(); - let mut input_params = params.input_params; - input_params.n_samples = n_samples; - let mut circuit_params = params.circuit_params; - circuit_params.n_samples = n_samples; - let inner_sampling_circuit = SamplingRecursion::::new(circuit_params); - let mut circ_inputs = vec![]; - for _i in 0..N { - circ_inputs.push(gen_testing_circuit_input::(&input_params)); - } - - let mut cyclic_circ = CyclicCircuit::::build_circuit::(inner_sampling_circuit.clone())?; - - // Building Phase - group.bench_function("build cyclic circuit", |b| { - b.iter(|| { - let _cyclic_circ = CyclicCircuit::::build_circuit::(inner_sampling_circuit.clone()); - - }) - }); - println!("cyclic circuit size = {:?}", cyclic_circ.cyclic_circuit_data.common.degree_bits()); - - let proof = cyclic_circ.prove_n_layers(circ_inputs.clone())?; - - // Proving Phase - group.bench_function("prove cyclic circuit", |b| { - b.iter(|| { - let _proof = cyclic_circ.prove_n_layers(circ_inputs.clone()); - }) - }); - println!("Proof size: {} bytes", proof.to_bytes().len()); - println!("num of pi = {}", proof.public_inputs.len()); - - // Verifying Phase - group.bench_function("verify cyclic circuit proof", |b| { - b.iter(|| { - cyclic_circ.verify_latest_proof(); - }) - }); - - assert!( - cyclic_circ.verify_latest_proof().is_ok(), - "proof verification failed" - ); - - group.finish(); - Ok(()) -} - -fn bench_recursion(c: &mut Criterion){ - const N: usize = 2; // number of proofs to be aggregated - bench_cyclic_recursion::<4>(c); - bench_cyclic_recursion::<8>(c); - bench_cyclic_recursion::<16>(c); -} - -/// Criterion benchmark group -criterion_group!{ - name = recursion; - config = Criterion::default().sample_size(10); - targets = bench_recursion -} -criterion_main!(recursion); diff --git a/recursion_experiments/benches/hybrid_recursion.rs b/recursion_experiments/benches/hybrid_recursion.rs deleted file mode 100644 index 960507a..0000000 --- a/recursion_experiments/benches/hybrid_recursion.rs +++ /dev/null @@ -1,100 +0,0 @@ -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::circuits::leaf_circuit::LeafCircuit; -use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; -use codex_plonky2_circuits::recursion::hybrid::tree_circuit::HybridTreeRecursion; -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_hybrid_recursion(c: &mut Criterion) -> anyhow::Result<()>{ - - 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 - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - let mut params = Params::default(); - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input); - let inner_data = sampling_builder.build::(); - let inner_proof = inner_data.prove(pw.clone())?; - - // ------------------- leaf -------------------- - let inner_circ = SamplingRecursion::::new(Params::default().circuit_params); - let leaf_circuit = LeafCircuit::::new(inner_circ); - - - // ------------- Node/tree circuit ------------------ - // node circuit that verifies leafs or itself - - let mut tree = HybridTreeRecursion::::new(leaf_circuit); - - // prepare input - let input_proofs: Vec> = (0..K) - .map(|_| { - inner_proof.clone() - }) - .collect::>(); - - // Building phase - group.bench_function("prove tree", |b| { - b.iter(|| { - let _ = tree.prove_tree::(&input_proofs, inner_data.verifier_data()); - - }) - }); - - let (tree_root_proof, verifier_data) = tree.prove_tree::(&input_proofs, inner_data.verifier_data())?; - - println!("tree circuit - num of public input = {}", tree_root_proof.public_inputs.len()); - println!("Proof size: {} bytes", tree_root_proof.to_bytes().len()); - - // Verifying Phase - group.bench_function("verify tree circuit", |b| { - b.iter(|| { - verifier_data.verify(tree_root_proof.clone()).expect("verify fail"); - }) - }); - - - group.finish(); - Ok(()) -} - -fn bench_tree_recursion_approach2(c: &mut Criterion){ - const N: usize = 2; // number of child nodes - binary here - const M: usize = 64; // number of proofs aggregated in leaves - const K: usize = 128; // number of proofs to be aggregated in the tree - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::(c); - bench_hybrid_recursion::<4,16,128>(c); -} - -/// Criterion benchmark group -criterion_group!{ - name = recursion; - config = Criterion::default().sample_size(10); - targets = bench_tree_recursion_approach2 -} -criterion_main!(recursion); diff --git a/recursion_experiments/benches/simple_recursion.rs b/recursion_experiments/benches/simple_recursion.rs deleted file mode 100644 index 4a28f6a..0000000 --- a/recursion_experiments/benches/simple_recursion.rs +++ /dev/null @@ -1,112 +0,0 @@ -use anyhow::Result; -use criterion::{criterion_group, criterion_main, Criterion}; -use plonky2::hash::hash_types::HashOut; -use plonky2::iop::witness::PartialWitness; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig}; -use plonky2::plonk::config::GenericConfig; -use plonky2_field::types::Field; -use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; -use codex_plonky2_circuits::recursion::simple::simple_recursion::{SimpleRecursionCircuit, SimpleRecursionInput}; -use proof_input::params::{D, C, F, HF, Params}; -use proof_input::gen_input::{build_circuit, prove_circuit}; - -/// Benchmark for building, proving, and verifying the Plonky2 recursion circuit. -/// Simple recursion approach - verify N proofs in-circuit -fn bench_simple_recursion(c: &mut Criterion) -> Result<()>{ - let mut group = c.benchmark_group(format!("Simple Recursion Benchmark for N ={}", N_INNER)); - - // number of samples in each proof - let n_samples = 10; - // params - let mut circ_params = Params::default().circuit_params; - circ_params.n_samples = n_samples; - - let (data, pw) = build_circuit(n_samples, 3)?; - let proof = prove_circuit(&data, &pw)?; - - // get proofs - let mut proofs_with_pi = (0..N_INNER).map(|i| proof.clone()).collect::>(); - - println!("inner circuit size = {:?}", data.common.degree_bits()); - - // careful here, the sampling recursion is the default so proofs should be for circuit - // with default params - let sampling_inner_circ = SamplingRecursion::::new(circ_params); - let rec_circuit = SimpleRecursionCircuit::::new(sampling_inner_circ); - - group.bench_function("Build Circuit", |b| { - b.iter(|| { - // Create the circuit - let local_config = CircuitConfig::standard_recursion_config(); - let mut local_builder = CircuitBuilder::::new(local_config); - // aggregate proofs - let _loc_targets = rec_circuit.build_circuit(&mut local_builder).unwrap(); - let _agg_data = local_builder.build::(); - }) - }); - - - // Create the circuit - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - // Create a PartialWitness - let mut pw = PartialWitness::new(); - - let targets = rec_circuit.build_circuit(&mut builder)?; - let agg_data = builder.build::(); - - println!("agg circuit size = {:?}", agg_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)?; - - group.bench_function("Prove Circuit", |b| { - b.iter(|| { - let local_pw = pw.clone(); - agg_data.prove(local_pw).expect("Failed to prove circuit") - }) - }); - - let proof = agg_data.prove(pw)?; - println!("Proof size: {} bytes", proof.to_bytes().len()); - println!("public input count = {:?}", proof.public_inputs.len()); - - // Verify the proof - let verifier_data = agg_data.verifier_data(); - group.bench_function("Verify Proof", |b| { - b.iter(|| { - verifier_data.clone().verify(proof.clone()).expect("Failed to verify proof"); - }) - }); - - assert!( - verifier_data.verify(proof).is_ok(), - "proof verification failed" - ); - - group.finish(); - Ok(()) -} - -fn bench_multiple_n(c: &mut Criterion){ - bench_simple_recursion::<32>(c); - bench_simple_recursion::<64>(c); - bench_simple_recursion::<128>(c); -} - -/// Criterion benchmark group -criterion_group!{ - name = recursion; - config = Criterion::default().sample_size(10); - targets = bench_multiple_n -} -criterion_main!(recursion); diff --git a/recursion_experiments/benches/simple_recursion_hashed_pi.rs b/recursion_experiments/benches/simple_recursion_hashed_pi.rs deleted file mode 100644 index d1715fe..0000000 --- a/recursion_experiments/benches/simple_recursion_hashed_pi.rs +++ /dev/null @@ -1,111 +0,0 @@ -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}; -use plonky2::plonk::config::GenericConfig; -use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; -use codex_plonky2_circuits::recursion::simple::simple_recursion_hashed_pi::{SimpleRecursionCircuitHashedPI, SimpleRecursionInputHashedPI}; -use proof_input::params::{D, C, F, HF, Params}; -use proof_input::gen_input::{build_circuit, prove_circuit}; - -/// Benchmark for building, proving, and verifying the Plonky2 recursion circuit. -/// Simple recursion approach - verify N proofs in-circuit -fn bench_recursion(c: &mut Criterion) -> Result<()>{ - let mut group = c.benchmark_group(format!("Simple Recursion With Hashed Public Input Benchmark for N={}",N_INNER)); - - // number of samples in each proof - let n_samples = 50; - // params - let mut circ_params = Params::default().circuit_params; - circ_params.n_samples = n_samples; - - let (data, pw) = build_circuit(n_samples, 3)?; - let proof = prove_circuit(&data, &pw)?; - - // get proofs - let mut proofs_with_pi = (0..N_INNER).map(|i| proof.clone()).collect::>(); - - println!("inner circuit size = {:?}", data.common.degree_bits()); - - // careful here, the sampling recursion is the default so proofs should be for circuit - // with default params - let sampling_inner_circ = SamplingRecursion::::new(circ_params); - let rec_circuit = SimpleRecursionCircuitHashedPI::::new(sampling_inner_circ); - - group.bench_function("Build Circuit", |b| { - b.iter(|| { - // Create the circuit - let local_config = CircuitConfig::standard_recursion_config(); - let mut local_builder = CircuitBuilder::::new(local_config); - // aggregate proofs - let _loc_targets = rec_circuit.build_circuit::(&mut local_builder).unwrap(); - let _agg_data = local_builder.build::(); - }) - }); - - - // Create the circuit - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - // Create a PartialWitness - let mut pw = PartialWitness::new(); - - let targets = rec_circuit.build_circuit::(&mut builder)?; - let agg_data = builder.build::(); - - println!("agg circuit size = {:?}", agg_data.common.degree_bits()); - - let w = SimpleRecursionInputHashedPI{ - proofs: proofs_with_pi, - verifier_data: data.verifier_data(), - }; - - rec_circuit.assign_witness(&mut pw,&targets,w)?; - - group.bench_function("Prove Circuit", |b| { - b.iter(|| { - let local_pw = pw.clone(); - agg_data.prove(local_pw).expect("Failed to prove circuit") - }) - }); - - let proof = agg_data.prove(pw)?; - println!("Proof size: {} bytes", proof.to_bytes().len()); - println!("public input count = {:?}", proof.public_inputs.len()); - - // Verify the proof - let verifier_data = agg_data.verifier_data(); - group.bench_function("Verify Proof", |b| { - b.iter(|| { - verifier_data.clone().verify(proof.clone()).expect("Failed to verify proof"); - }) - }); - - assert!( - verifier_data.verify(proof).is_ok(), - "proof verification failed" - ); - - group.finish(); - Ok(()) -} - -fn bench_multiple_n(c: &mut Criterion){ - bench_recursion::<4>(c); - bench_recursion::<8>(c); - bench_recursion::<16>(c); - bench_recursion::<32>(c); - bench_recursion::<64>(c); - bench_recursion::<128>(c); -// bench_recursion::<256>(c); -} - - -/// Criterion benchmark group -criterion_group!{ - name = recursion; - config = Criterion::default().sample_size(10); - targets = bench_multiple_n -} -criterion_main!(recursion); diff --git a/recursion_experiments/benches/simple_tree_recursion.rs b/recursion_experiments/benches/simple_tree_recursion.rs deleted file mode 100644 index 193cd39..0000000 --- a/recursion_experiments/benches/simple_tree_recursion.rs +++ /dev/null @@ -1,68 +0,0 @@ -use criterion::{Criterion, criterion_group, criterion_main}; -use plonky2::plonk::circuit_data::VerifierCircuitData; -use plonky2::plonk::config::GenericConfig; -use plonky2::plonk::proof::ProofWithPublicInputs; -use codex_plonky2_circuits::recursion::simple::simple_tree_recursion::aggregate_sampling_proofs_tree; -use proof_input::params::{C, D, F, HF, Params}; -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) -> anyhow::Result<()>{ - - let mut group = c.benchmark_group(format!("Simple Tree Recursion Benchmark for N={}",N_INNER)); - - // number of samples in each proof - let n_samples = 10; - // params - let mut circ_params = Params::default().circuit_params; - circ_params.n_samples = n_samples; - - let (data, pw) = build_circuit(n_samples, 3)?; - let proof = prove_circuit(&data, &pw)?; - - // get proofs - let proofs_with_pi = (0..N_INNER).map(|i| proof.clone()).collect::>(); - - println!("inner circuit size = {:?}", data.common.degree_bits()); - - - let mut agg_proof_with_pis: Option> = None; - let mut agg_vd: Option> = None; - - // Benchmark the Circuit Building Phase - group.bench_function("build & prove Circuit", |b| { - b.iter(|| { - let (proof, vd_agg) = aggregate_sampling_proofs_tree::(&proofs_with_pi, data.verifier_data()).unwrap(); - agg_proof_with_pis = Some(proof); - agg_vd = Some(vd_agg); - }) - }); - - 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(); - Ok(()) -} - -fn bench_multiple_n(c: &mut Criterion){ - bench_tree_recursion::<4>(c); - bench_tree_recursion::<8>(c); - bench_tree_recursion::<16>(c); -} - -/// Criterion benchmark group -criterion_group!{ - name = recursion; - config = Criterion::default().sample_size(10); - targets = bench_multiple_n -} -criterion_main!(recursion); diff --git a/recursion_experiments/benches/tree_recursion1.rs b/recursion_experiments/benches/tree_recursion1.rs deleted file mode 100644 index efa6a6a..0000000 --- a/recursion_experiments/benches/tree_recursion1.rs +++ /dev/null @@ -1,161 +0,0 @@ -use anyhow::{anyhow, Result}; -use criterion::{Criterion, criterion_group, criterion_main}; -use plonky2::plonk::config::GenericConfig; -use plonky2::plonk::proof::ProofWithPublicInputs; -use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; -use codex_plonky2_circuits::recursion::tree1::{tree_circuit::TreeRecursion}; -use proof_input::params::{C, D, F, HF, Params}; -use proof_input::gen_input::{get_m_circ_input}; - - -/// Benchmark for building, proving, and verifying the approach1 Plonky2 tree recursion circuit. -fn bench_node_recursion(c: &mut Criterion) -> Result<()>{ - - let mut group = c.benchmark_group("Tree Recursion - Approach 1 Benchmark"); - - // number of samples in each proof - let n_samples = 5; - // params - let mut circ_params = Params::default().circuit_params; - circ_params.n_samples = n_samples; - let mut input_params = Params::default().input_params; - input_params.n_samples = n_samples; - - let inner_sampling_circuit = SamplingRecursion::::new(circ_params); - - let circ_input = get_m_circ_input::(input_params); - - // Building Phase - group.bench_function("build", |b| { - b.iter(|| { - let _tree_circ = TreeRecursion::::build::(inner_sampling_circuit.clone()); - }) - }); - - let mut tree_circ = TreeRecursion::::build::(inner_sampling_circuit)?; - println!("tree circuit size = {:?}", tree_circ.node_circ.cyclic_circuit_data.common.degree_bits()); - - // prove Phase - group.bench_function("prove with leaf only", |b| { - b.iter(|| { - let _proof = tree_circ.prove(&circ_input,None, true); - }) - }); - - let proof = tree_circ.prove(&circ_input,None, true)?; - println!("Proof size: {} bytes", proof.to_bytes().len()); - println!("num of pi = {}", proof.public_inputs.len()); - - // make N node proofs - let node_proofs: [ProofWithPublicInputs; N] = (0..N) - .map(|_| { - proof.clone() - }) - .collect::>() - .try_into() - .map_err(|_| anyhow!("Expected exactly M inner circuits")).unwrap(); - - // prove Phase for node leaf and node proofs - group.bench_function("prove with leaf and node", |b| { - b.iter(|| { - let _proof = tree_circ.prove(&circ_input,Some(node_proofs.clone()), true); - }) - }); - - // Verifying Phase for node leaf and node proofs - group.bench_function("Verify Proof with leaf and node proofs", |b| { - b.iter(|| { - tree_circ.verify_proof(proof.clone()).expect("Failed to verify proof"); - }) - }); - - assert!( - tree_circ.verify_proof(proof).is_ok(), - "proof verification failed" - ); - - group.finish(); - Ok(()) -} - -fn bench_tree_recursion(c: &mut Criterion) -> Result<()>{ - let mut group = c.benchmark_group(format!("bench tree recursion - approach 1 for N={}",TOTAL_INPUT)); - - // number of samples in each proof - let n_samples = 5; - // params - let mut circ_params = Params::default().circuit_params; - circ_params.n_samples = n_samples; - let mut input_params = Params::default().input_params; - input_params.n_samples = n_samples; - - let inner_sampling_circuit = SamplingRecursion::::new(circ_params); - - let circ_input = get_m_circ_input::(input_params).to_vec(); - - // Building Phase - group.bench_function("build", |b| { - b.iter(|| { - let _tree_circ = TreeRecursion::::build::(inner_sampling_circuit.clone()).unwrap(); - }) - }); - - let mut tree_circ = TreeRecursion::::build::(inner_sampling_circuit)?; - println!("tree circuit size = {:?}", tree_circ.node_circ.cyclic_circuit_data.common.degree_bits()); - - // prove Phase - group.bench_function("prove tree", |b| { - b.iter(|| { - let _proof = tree_circ.prove_tree(circ_input.clone(),DEPTH).unwrap(); - }) - }); - - let proof = tree_circ.prove_tree(circ_input,DEPTH)?; - println!("Proof size: {} bytes", proof.to_bytes().len()); - println!("num of pi = {}", proof.public_inputs.len()); - - // Verifying Phase for node leaf and node proofs - group.bench_function("Verify final proof", |b| { - b.iter(|| { - tree_circ.verify_proof(proof.clone()).expect("Failed to verify proof"); - }) - }); - - assert!( - tree_circ.verify_proof(proof).is_ok(), - "proof verification failed" - ); - - group.finish(); - Ok(()) -} - -fn bench_tree_recursion_approach1(c: &mut Criterion){ - const M: usize = 1; - const N: usize = 2; - bench_node_recursion::(c); -} - -fn bench_multiple_params(c: &mut Criterion){ - const M: usize = 1; - const N: usize = 2; - const DEPTH1: usize = 2; - const TOTAL_INPUT1: usize = (N.pow(DEPTH1 as u32) - 1) / (N - 1); - const DEPTH2: usize = 3; - const TOTAL_INPUT2: usize = (N.pow(DEPTH2 as u32) - 1) / (N - 1); - const DEPTH3: usize = 4; - const TOTAL_INPUT3: usize = (N.pow(DEPTH3 as u32) - 1) / (N - 1); - - bench_tree_recursion::(c); - bench_tree_recursion::(c); - bench_tree_recursion::(c); -} - - -/// Criterion benchmark group -criterion_group!{ - name = recursion; - config = Criterion::default().sample_size(10); - targets = bench_multiple_params -} -criterion_main!(recursion); diff --git a/recursion_experiments/benches/tree_recursion2.rs b/recursion_experiments/benches/tree_recursion2.rs deleted file mode 100644 index 52c6738..0000000 --- a/recursion_experiments/benches/tree_recursion2.rs +++ /dev/null @@ -1,206 +0,0 @@ -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::circuits::utils::vec_to_array; -use codex_plonky2_circuits::recursion::circuits::leaf_circuit::{LeafCircuit, LeafInput}; -use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; -use codex_plonky2_circuits::recursion::tree2::{tree_circuit::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_leaf(c: &mut Criterion) -> anyhow::Result<()>{ - - let mut group = c.benchmark_group(format!("Tree Recursion - Approach 2 Benchmark for N={}",K)); - - //------------ sampling inner circuit ---------------------- - // Circuit that does the sampling - default input - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - let mut params = Params::default(); - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input); - let inner_data = sampling_builder.build::(); - let inner_proof = inner_data.prove(pw.clone())?; - - // Building Phase - group.bench_function("build inner circuit", |b| { - b.iter(|| { - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - let _inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder); - sampling_builder.build::(); - }) - }); - - // Proving Phase - group.bench_function("prove inner circuit", |b| { - b.iter(|| { - let _inner_proof = inner_data.prove(pw.clone()); - }) - }); - - println!("inner circuit - Circuit size (degree bits): {:?}", inner_data.common.degree_bits() ); - println!("inner proof - num of public input = {}", inner_proof.public_inputs.len()); - - // ------------------- leaf -------------------- - // leaf circuit that verifies the sampling proof - let inner_circ = SamplingRecursion::::new(Params::default().circuit_params); - let leaf_circuit = LeafCircuit::::new(inner_circ); - - let leafs: Vec> = (0..M).map(|i| inner_proof.clone()).collect::>(); - let leafs_arr = vec_to_array::>(leafs)?; - - let leaf_in = LeafInput::{ - inner_proof: leafs_arr, - verifier_data: inner_data.verifier_data(), - }; - let config = CircuitConfig::standard_recursion_config(); - let mut leaf_builder = CircuitBuilder::::new(config); - let leaf_targets = leaf_circuit.build::(&mut leaf_builder)?; - let leaf_circ_data = leaf_builder.build::(); - - // Building Phase - group.bench_function("build leaf circuit", |b| { - b.iter(|| { - let config = CircuitConfig::standard_recursion_config(); - let mut leaf_builder = CircuitBuilder::::new(config); - let _leaf_targets = leaf_circuit.build::(&mut leaf_builder).unwrap(); - let _leaf_circ_data = leaf_builder.build::(); - }) - }); - - let mut pw = PartialWitness::::new(); - leaf_circuit.assign_targets::(&mut pw, &leaf_targets, &leaf_in)?; - let leaf_proof = leaf_circ_data.prove(pw.clone())?; - - // Proving Phase - group.bench_function("prove leaf circuit", |b| { - b.iter(|| { - let _leaf_proof = leaf_circ_data.prove(pw.clone()); - }) - }); - - println!("leaf circuit - Circuit size (degree bits): {:?}", leaf_circ_data.common.degree_bits() ); - println!("leaf proof - num of public input = {}", leaf_proof.public_inputs.len()); - - - group.finish(); - Ok(()) -} - -/// Benchmark for building, proving, and verifying the Plonky2 tree recursion circuit. -fn bench_tree_recursion(c: &mut Criterion) -> anyhow::Result<()>{ - - let mut group = c.benchmark_group(format!("Tree Recursion - Approach 2 Benchmark for N={}",K)); - - //------------ sampling inner circuit ---------------------- - // Circuit that does the sampling - default input - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - let mut params = Params::default(); - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input); - let inner_data = sampling_builder.build::(); - let inner_proof = inner_data.prove(pw.clone())?; - - // ------------------- leaf -------------------- - // leaf circuit that verifies the sampling proof - let inner_circ = SamplingRecursion::::new(Params::default().circuit_params); - let leaf_circuit = LeafCircuit::::new(inner_circ); - - let leafs: Vec> = (0..M).map(|i| inner_proof.clone()).collect::>(); - let leafs_arr = vec_to_array::>(leafs)?; - - let leaf_in = LeafInput::{ - inner_proof: leafs_arr, - verifier_data: inner_data.verifier_data(), - }; - let config = CircuitConfig::standard_recursion_config(); - let mut leaf_builder = CircuitBuilder::::new(config); - let leaf_targets = leaf_circuit.build::(&mut leaf_builder)?; - let leaf_circ_data = leaf_builder.build::(); - - let mut pw = PartialWitness::::new(); - leaf_circuit.assign_targets::(&mut pw, &leaf_targets, &leaf_in)?; - let leaf_proof = leaf_circ_data.prove(pw.clone())?; - - - // ------------- Node/tree circuit ------------------ - // node circuit that verifies leafs or itself - - let mut tree = TreeRecursion::::build::<_,HF, M>(leaf_circuit.clone())?; - - // Building phase - group.bench_function("build tree circuit", |b| { - b.iter(|| { - let _tree = TreeRecursion::::build::<_,HF, M>(leaf_circuit.clone()); - }) - }); - - - let leaf_proofs: Vec> = (0..K) - .map(|_| { - leaf_proof.clone() - }) - .collect::>(); - - let tree_root_proof = tree.prove_tree(leaf_proofs.clone()).unwrap(); - - // Proving Phase - group.bench_function("prove tree circuit", |b| { - b.iter(|| { - let _tree_root_proof = tree.prove_tree(leaf_proofs.clone()); - }) - }); - - println!("tree circuit - Circuit size (degree bits): {:?}", tree.node.node_data.node_circuit_data.common.degree_bits()); - println!("tree circuit - num of public input = {}", tree_root_proof.public_inputs.len()); - - assert!( - tree.verify_proof(tree_root_proof.clone(), N==K).is_ok(), - "proof verification failed" - ); - - // Verifying Phase - group.bench_function("verify tree circuit", |b| { - b.iter(|| { - tree.verify_proof(tree_root_proof.clone(), N==K).expect("verify fail"); - }) - }); - - - group.finish(); - Ok(()) -} - -fn bench_tree_recursion_approach2(c: &mut Criterion){ - const M:usize = 1; // number of inner proofs in each leaf - const N: usize = 2; // number of child nodes - const K: usize = 4; // number of proofs to be aggregated in the tree - bench_tree_recursion::(c); - // bench_tree_recursion::(c); - // bench_leaf::<2,N,8>(c); -} - -/// Criterion benchmark group -criterion_group!{ - name = recursion; - config = Criterion::default().sample_size(10); - targets = bench_tree_recursion_approach2 -} -criterion_main!(recursion); diff --git a/recursion_experiments/benches/uniform_recursion.rs b/recursion_experiments/benches/uniform_recursion.rs deleted file mode 100644 index 417d479..0000000 --- a/recursion_experiments/benches/uniform_recursion.rs +++ /dev/null @@ -1,89 +0,0 @@ -use criterion::{Criterion, criterion_group, criterion_main}; -use plonky2::iop::witness::PartialWitness; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig}; -use plonky2::plonk::config::GenericConfig; -use plonky2::plonk::proof::ProofWithPublicInputs; -use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit}; -use codex_plonky2_circuits::recursion::uniform::tree::TreeRecursion; -use proof_input::params::{C, D, F,HF}; -use proof_input::gen_input::gen_testing_circuit_input; -use proof_input::params::Params; - -/// Benchmark for building, proving, and verifying the Plonky2 tree recursion circuit. -fn bench_uniform_recursion(c: &mut Criterion) -> anyhow::Result<()>{ - - let mut group = c.benchmark_group(format!("Uniform Tree Recursion Benchmark for N={}",N)); - - //------------ sampling inner circuit ---------------------- - // Circuit that does the sampling - 100 samples - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - let mut params = Params::default(); - params.input_params.n_samples = 100; - params.circuit_params.n_samples = 100; - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?; - let inner_data = sampling_builder.build::(); - let inner_proof = inner_data.prove(pw.clone())?; - - let proofs: Vec> = (0..N).map(|i| inner_proof.clone()).collect(); - - // ------------------- tree -------------------- - - let mut tree : Option> = None; - - // Building phase - group.bench_function("build tree", |b| { - b.iter(|| { - tree = Some(TreeRecursion::::build(inner_data.common.clone()).unwrap()); - }) - }); - - let mut tree = tree.unwrap(); - - let mut proof: Option> = None; - - // Proving Phase - group.bench_function("prove tree", |b| { - b.iter(|| { - proof = Some(tree.prove_tree(&proofs, &inner_data.verifier_only).unwrap()); - }) - }); - - let proof = proof.unwrap(); - - // Verifying Phase - // group.bench_function("verify tree circuit", |b| { - // b.iter(|| { - // verifier_data.verify(proof.clone()).expect("verify fail"); - // }) - // }); - - group.finish(); - Ok(()) -} - -fn bench_uniform_tree_recursion(c: &mut Criterion){ - const N: usize = 2; // number of child nodes - binary here - bench_uniform_recursion::<2>(c).expect("bench failed"); - bench_uniform_recursion::<4>(c).expect("bench failed"); - bench_uniform_recursion::<8>(c).expect("bench failed"); - bench_uniform_recursion::<16>(c).expect("bench failed"); - bench_uniform_recursion::<32>(c).expect("bench failed"); - bench_uniform_recursion::<64>(c).expect("bench failed"); - bench_uniform_recursion::<128>(c).expect("bench failed"); - bench_uniform_recursion::<256>(c).expect("bench failed"); -} - -/// Criterion benchmark group -criterion_group!{ - name = recursion; - config = Criterion::default().sample_size(10); - targets = bench_uniform_tree_recursion -} -criterion_main!(recursion); diff --git a/recursion_experiments/recursion/circuits/inner_circuit.rs b/recursion_experiments/recursion/circuits/inner_circuit.rs deleted file mode 100644 index 1eb5c3f..0000000 --- a/recursion_experiments/recursion/circuits/inner_circuit.rs +++ /dev/null @@ -1,45 +0,0 @@ -use plonky2::hash::hash_types::RichField; -use plonky2::iop::target::Target; -use plonky2::iop::witness::PartialWitness; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::CommonCircuitData; -use plonky2_field::extension::Extendable; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::Result; - -/// InnerCircuit is the trait used to define the logic of the circuit and assign witnesses -/// to that circuit instance. -pub trait InnerCircuit< - F: RichField + Extendable + Poseidon2, - const D: usize, -> { - type Targets; - type Input:Clone; - - /// build the circuit logic and return targets to be assigned later - /// based on register_pi, registers the public input or not. - fn build( - &self, - builder: &mut CircuitBuilder, - register_pi: bool - ) -> Result; - - /// assign the actual witness values for the current instance of the circuit. - fn assign_targets( - &self, - pw: &mut PartialWitness, - targets: &Self::Targets, - input: &Self::Input, - ) -> Result<()>; - - /// from the set of the targets, return only the targets which are public - /// TODO: this can probably be replaced with enum for Public/Private targets - fn get_pub_input_targets( - targets: &Self::Targets, - ) -> Vec; - - /// get the common data for the inner-circuit - fn get_common_data( - &self - ) -> Result<(CommonCircuitData)>; -} diff --git a/recursion_experiments/recursion/circuits/leaf_circuit.rs b/recursion_experiments/recursion/circuits/leaf_circuit.rs deleted file mode 100644 index 0a2e4ef..0000000 --- a/recursion_experiments/recursion/circuits/leaf_circuit.rs +++ /dev/null @@ -1,155 +0,0 @@ -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, 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::circuits::inner_circuit::InnerCircuit; -use crate::{error::CircuitError,Result}; -use crate::circuits::utils::vec_to_array; - -/// recursion leaf circuit for the recursion tree circuit -#[derive(Clone, Debug)] -pub struct LeafCircuit< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const M: usize, -> { - pub inner_circ: I, - phantom_data: PhantomData -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const M: usize, -> LeafCircuit { - pub fn new(inner_circ: I) -> Self { - Self{ - inner_circ, - phantom_data:PhantomData::default(), - } - } -} -#[derive(Clone, Debug)] -pub struct LeafTargets < - const D: usize, - const M: usize ->{ - pub inner_proof: [ProofWithPublicInputsTarget; M], - pub verifier_data: VerifierCircuitTarget, -} -#[derive(Clone, Debug)] -pub struct LeafInput< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - const M: usize, ->{ - pub inner_proof: [ProofWithPublicInputs; M], - pub verifier_data: VerifierCircuitData -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const M: usize, -> LeafCircuit{ - - /// build the leaf circuit - pub fn build< - C: GenericConfig, - H: AlgebraicHasher, - >(&self, builder: &mut CircuitBuilder) -> Result> - where - >::Hasher: AlgebraicHasher - { - - let common = self.inner_circ.get_common_data()?; - - // the proof virtual targets - only one for now - let mut vir_proofs = vec![]; - let mut pub_input = vec![]; - for _i in 0..M { - let vir_proof = builder.add_virtual_proof_with_pis(&common); - let inner_pub_input = vir_proof.public_inputs.clone(); - vir_proofs.push(vir_proof); - pub_input.extend_from_slice(&inner_pub_input); - } - - // hash the public input & make it public - let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(pub_input); - builder.register_public_inputs(&hash_inner_pub_input.elements); - - // virtual target for the verifier data - let inner_verifier_data = builder.add_virtual_verifier_data(common.config.fri_config.cap_height); - - // verify the proofs in-circuit (only one now) - for i in 0..M { - builder.verify_proof::(&vir_proofs[i], &inner_verifier_data, &common); - } - - let proofs = vec_to_array::>(vir_proofs)?; - - // return targets - let t = LeafTargets { - inner_proof: proofs, - verifier_data: inner_verifier_data, - }; - Ok(t) - - } - - /// assign the leaf targets with given input - pub fn assign_targets< - C: GenericConfig, - H: AlgebraicHasher, - >(&self, pw: &mut PartialWitness, targets: &LeafTargets, input: &LeafInput) -> Result<()> - where - >::Hasher: AlgebraicHasher - { - // assign the proofs - for i in 0..M { - pw.set_proof_with_pis_target(&targets.inner_proof[i], &input.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, &input.verifier_data.verifier_only) - .map_err(|e| { - CircuitError::VerifierDataTargetAssignmentError(e.to_string()) - })?; - - Ok(()) - } - - /// returns the leaf circuit data - /// TODO: make generic recursion config - pub fn get_circuit_data< - C: GenericConfig, - H: AlgebraicHasher, - >(&self) -> Result> - where - >::Hasher: AlgebraicHasher - { - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - - self.build::(&mut builder)?; - - let circ_data = builder.build::(); - - Ok(circ_data) - } - -} - - diff --git a/recursion_experiments/recursion/circuits/mod.rs b/recursion_experiments/recursion/circuits/mod.rs deleted file mode 100644 index 9c7c554..0000000 --- a/recursion_experiments/recursion/circuits/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod inner_circuit; -pub mod sampling_inner_circuit; -pub mod leaf_circuit; diff --git a/recursion_experiments/recursion/circuits/sampling_inner_circuit.rs b/recursion_experiments/recursion/circuits/sampling_inner_circuit.rs deleted file mode 100644 index ab40189..0000000 --- a/recursion_experiments/recursion/circuits/sampling_inner_circuit.rs +++ /dev/null @@ -1,89 +0,0 @@ -use std::marker::PhantomData; -use plonky2::hash::hash_types::RichField; -use plonky2::iop::target::Target; -use plonky2::iop::witness::PartialWitness; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2_field::extension::Extendable; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::circuits::params::CircuitParams; -use crate::circuits::sample_cells::{SampleCircuit, SampleCircuitInput, SampleTargets}; -use crate::recursion::circuits::inner_circuit::InnerCircuit; -use crate::Result; - -/// recursion Inner circuit for the sampling circuit -#[derive(Clone, Debug)] -pub struct SamplingRecursion< - F: RichField + Extendable + Poseidon2, - const D: usize, - H: AlgebraicHasher, - C: GenericConfig, -> { - pub sampling_circ: SampleCircuit, - phantom_data: PhantomData, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - H: AlgebraicHasher, - C: GenericConfig, -> SamplingRecursion { - pub fn new(circ_params:CircuitParams) -> Self { - Self{ - sampling_circ: SampleCircuit::new(circ_params), - phantom_data: PhantomData::default(), - } - } -} - - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - H: AlgebraicHasher, - C: GenericConfig, -> InnerCircuit for SamplingRecursion { - type Targets = SampleTargets; - type Input = SampleCircuitInput; - - /// build the circuit - fn build(&self, builder: &mut CircuitBuilder, register_pi: bool) -> Result { - if register_pi{ - self.sampling_circ.sample_slot_circuit_with_public_input(builder) - }else { - self.sampling_circ.sample_slot_circuit(builder) - } - } - - fn assign_targets(&self, pw: &mut PartialWitness, targets: &Self::Targets, input: &Self::Input) -> Result<()> { - self.sampling_circ.sample_slot_assign_witness(pw, targets, input) - } - - /// returns the public input specific for this circuit which are: - /// `[slot_index, dataset_root, entropy]` - fn get_pub_input_targets(targets: &Self::Targets) -> Vec { - let mut pub_targets = vec![]; - pub_targets.push(targets.slot_index.clone()); - pub_targets.extend_from_slice(&targets.dataset_root.elements); - pub_targets.extend_from_slice(&targets.entropy.elements); - - pub_targets - } - - /// return the common circuit data for the sampling circuit - /// uses the `standard_recursion_config` - /// TODO: make it generic for any config - fn get_common_data(&self) -> Result<(CommonCircuitData)> { - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - // build the inner circuit - self.sampling_circ.sample_slot_circuit_with_public_input(&mut builder)?; - - let circ_data = builder.build::(); - - Ok(circ_data.common) - } -} \ No newline at end of file diff --git a/recursion_experiments/recursion/cyclic/mod.rs b/recursion_experiments/recursion/cyclic/mod.rs deleted file mode 100644 index 25be599..0000000 --- a/recursion_experiments/recursion/cyclic/mod.rs +++ /dev/null @@ -1,265 +0,0 @@ -// Cyclic approach to recursion where at each cycle you verify previous proof -// and run the inner circuit -> resulting in one proof that again can be fed -// into another cyclic circle. - -use plonky2::hash::hash_types::{HashOutTarget, RichField}; -use plonky2::iop::target::{BoolTarget}; -use plonky2::iop::witness::{PartialWitness, WitnessWrite}; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitTarget}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::recursion::circuits::inner_circuit::InnerCircuit; -use plonky2::gates::noop::NoopGate; -use plonky2_field::extension::Extendable; -use crate::circuits::utils::select_hash; -use crate::error::CircuitError; -use crate::recursion::utils::conditional_verifier::{dummy_circuit}; -use crate::recursion::utils::dummy_gen::DummyProofGen; -use crate::Result; - -/// cyclic circuit struct -/// contains necessary data -/// note: only keeps track of latest proof not all proofs. -pub struct CyclicCircuit< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - C: GenericConfig, ->{ - pub layer: usize, - pub circ: I, - pub cyclic_target: CyclicCircuitTargets, - pub cyclic_circuit_data: CircuitData, - pub common_data: CommonCircuitData, - pub latest_proof: Option>, -} - -/// targets need to be assigned for the cyclic circuit -#[derive(Clone)] -pub struct CyclicCircuitTargets< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, ->{ - pub inner_targets: I::Targets, - pub condition: BoolTarget, - pub inner_cyclic_proof_with_pis: ProofWithPublicInputsTarget, - pub verifier_data: VerifierCircuitTarget, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - C: GenericConfig + 'static, -> CyclicCircuit where - >::Hasher: AlgebraicHasher -{ - - /// builds the cyclic recursion circuit using any inner circuit I - /// return the circuit data - pub fn build_circuit< - H: AlgebraicHasher, - >( - // &mut self, - inner_circuit: I - ) -> Result<(Self)>{ - - // builder with standard recursion config - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - //build the inner circuit - let inner_t = inner_circuit.build(& mut builder, false)?; - - // common data for recursion - let mut common_data = Self::common_data_for_cyclic_recursion(); - // the hash of the public input - let pub_input_hash = builder.add_virtual_hash_public_input(); - // verifier data for inner proofs - // TODO: make verifier data public - // let verifier_data_target = builder.add_verifier_data_public_inputs(); - let verifier_data_target = builder.add_virtual_verifier_data(builder.config.fri_config.cap_height); - // common data should have same num of public input as inner proofs - common_data.num_public_inputs = builder.num_public_inputs(); - - // condition - let condition = builder.add_virtual_bool_target_safe(); - - // inner proof with public input - let inner_cyclic_proof_with_pis = builder.add_virtual_proof_with_pis(&common_data); - // get the hash of the pub input - let inner_cyclic_pis = &inner_cyclic_proof_with_pis.public_inputs; - let inner_pub_input_hash = HashOutTarget::from_vec(inner_cyclic_pis[0..4].to_vec()); - // now hash the current public input - let outer_pis = I::get_pub_input_targets(&inner_t); - let outer_pi_hash = builder.hash_n_to_hash_no_pad::(outer_pis); - let zero_hash = HashOutTarget::from_vec([builder.zero(); 4].to_vec()); - // if leaf pad with zeros - let inner_pi_hash_or_zero_hash = select_hash(&mut builder, condition, inner_pub_input_hash, zero_hash); - // hash current public input with previous hash - let mut hash_input = vec![]; - hash_input.extend_from_slice(&outer_pi_hash.elements); - hash_input.extend_from_slice(&inner_pi_hash_or_zero_hash.elements); - let outer_pi_hash = builder.hash_n_to_hash_no_pad::(hash_input); - // connect this up one to `pub_input_hash` - builder.connect_hashes(pub_input_hash,outer_pi_hash); - - // verify proof in-circuit - builder.verify_proof::(&inner_cyclic_proof_with_pis, &verifier_data_target, &common_data); - - // build the cyclic circuit - let cyclic_circuit_data = builder.build::(); - - // assign targets - let cyc_t = CyclicCircuitTargets::{ - inner_targets: inner_t, - condition, - inner_cyclic_proof_with_pis, - verifier_data: verifier_data_target - }; - - Ok( - Self{ - layer: 0, - circ: inner_circuit, - cyclic_target: cyc_t, - cyclic_circuit_data, - common_data, - latest_proof: None, - } - ) - } - - /// generates a proof with only one recursion layer - /// takes circuit input - pub fn prove_one_layer( - &mut self, - circ_input: &I::Input, - ) -> Result>{ - - let circ_data = &self.cyclic_circuit_data; - let cyc_targets = &self.cyclic_target; - let common_data = &self.common_data; - - // assign targets - let mut pw = PartialWitness::new(); - self.circ.assign_targets(&mut pw,&cyc_targets.inner_targets,&circ_input)?; - - // if leaf add dummy proof - if self.layer == 0 { - pw.set_bool_target(cyc_targets.condition, false) - .map_err(|e| - CircuitError::BoolTargetAssignmentError("condition".to_string(),e.to_string()), - )?; - pw.set_proof_with_pis_target::( - &cyc_targets.inner_cyclic_proof_with_pis, - &DummyProofGen::::get_dummy_node_proof( - common_data, - &circ_data.verifier_only, - ), - ).map_err(|e| - CircuitError::ProofTargetAssignmentError("cyclic proof".to_string(),e.to_string()), - )?; - // assign verifier data - let dummy_ver = dummy_circuit::(common_data).verifier_only; - pw.set_verifier_data_target(&cyc_targets.verifier_data, &dummy_ver) - .map_err(|e| CircuitError::VerifierDataTargetAssignmentError(e.to_string()))?; - }else{ // else add last proof - pw.set_bool_target(cyc_targets.condition, true) - .map_err(|e| - CircuitError::BoolTargetAssignmentError("condition".to_string(),e.to_string()), - )?; - - let last_proof = self.latest_proof - .as_ref() - .ok_or_else(|| CircuitError::OptionError("cyclic proof".to_string()))? - .clone(); - - pw.set_proof_with_pis_target(&cyc_targets.inner_cyclic_proof_with_pis, &last_proof) - .map_err(|e| - CircuitError::ProofTargetAssignmentError("cyclic proof".to_string(),e.to_string()), - )?; - // assign verifier data - pw.set_verifier_data_target(&cyc_targets.verifier_data, &circ_data.verifier_only) - .map_err(|e| CircuitError::VerifierDataTargetAssignmentError(e.to_string()))?; - } - - // prove - let proof = circ_data.prove(pw).map_err( - |e| CircuitError::InvalidProofError(e.to_string()) - )?; - - self.latest_proof = Some(proof.clone()); - self.layer = self.layer + 1; - Ok(proof) - } - - /// prove n recursive layers - /// the function takes - /// - circ_input: vector of n inputs - pub fn prove_n_layers( - &mut self, - circ_input: Vec, - ) -> Result>{ - - for i in 0..circ_input.len() { - self.prove_one_layer(&circ_input[i])?; - } - - let latest_proofs = self.latest_proof.clone().ok_or(CircuitError::OptionError("proof not found".to_string()))?; - - Ok(latest_proofs) - } - - /// verifies the latest proof generated - pub fn verify_latest_proof( - &mut self, - ) -> Result<()>{ - - let proof = self.latest_proof - .as_ref() - .ok_or_else(|| CircuitError::OptionError("cyclic proof".to_string()))? - .clone(); - - // TODO: check that the correct verifier data is consistent - - self.cyclic_circuit_data.verify(proof).map_err( - |e| CircuitError::InvalidProofError(e.to_string()) - )?; - - Ok(()) - } - - /// Generates `CommonCircuitData` usable for recursion. - pub fn common_data_for_cyclic_recursion() -> CommonCircuitData - { - // layer 1 - let config = CircuitConfig::standard_recursion_config(); - let builder = CircuitBuilder::::new(config); - let data = builder.build::(); - // layer 2 - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - let proof = builder.add_virtual_proof_with_pis(&data.common); - let verifier_data = - builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); - builder.verify_proof::(&proof, &verifier_data, &data.common); - let data = builder.build::(); - // layer 3 - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - let proof = builder.add_virtual_proof_with_pis(&data.common); - let verifier_data = - builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); - builder.verify_proof::(&proof, &verifier_data, &data.common); - // pad with noop gates - while builder.num_gates() < 1 << 12 { - builder.add_gate(NoopGate, vec![]); - } - builder.build::().common - } -} - diff --git a/recursion_experiments/recursion/hybrid/mod.rs b/recursion_experiments/recursion/hybrid/mod.rs deleted file mode 100644 index 26bc7e1..0000000 --- a/recursion_experiments/recursion/hybrid/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod node_circuit; -pub mod tree_circuit; \ No newline at end of file diff --git a/recursion_experiments/recursion/hybrid/node_circuit.rs b/recursion_experiments/recursion/hybrid/node_circuit.rs deleted file mode 100644 index 0d41668..0000000 --- a/recursion_experiments/recursion/hybrid/node_circuit.rs +++ /dev/null @@ -1,104 +0,0 @@ -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::{CommonCircuitData, VerifierCircuitData, VerifierCircuitTarget}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use plonky2_field::extension::Extendable; -use crate::circuits::utils::{vec_to_array}; -use crate::{error::CircuitError, Result}; - -/// Node circuit struct -/// contains necessary data -/// N: number of proofs verified in-circuit (so num of child nodes) -pub struct NodeCircuit< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - const N: usize, ->{ - phantom_data: PhantomData<(F,C)> -} - -/// Node circuit targets -/// assumes that all proofs use the same verifier data -#[derive(Clone, Debug)] -pub struct NodeCircuitTargets< - const D: usize, - const N: usize, ->{ - pub proof_targets: [ProofWithPublicInputsTarget; N], - pub verifier_data_target: VerifierCircuitTarget, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig + 'static, - const N: usize, -> NodeCircuit - where - >::Hasher: AlgebraicHasher -{ - - /// builds the node circuit - pub fn build_circuit< - H: AlgebraicHasher, - >( - builder: &mut CircuitBuilder, - common_data: &CommonCircuitData, - ) -> Result<(NodeCircuitTargets)>{ - - // the proof virtual targets - let mut proof_targets = vec![]; - let mut inner_pub_input = vec![]; - for _i in 0..N { - let vir_proof = builder.add_virtual_proof_with_pis(common_data); - // collect the public input - inner_pub_input.extend_from_slice(&vir_proof.public_inputs); - // collect the proof targets - proof_targets.push(vir_proof); - } - // hash the public input & make it public - let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(inner_pub_input); - builder.register_public_inputs(&hash_inner_pub_input.elements); - - // virtual target for the verifier data - let inner_verifier_data = builder.add_virtual_verifier_data(common_data.config.fri_config.cap_height); - - // verify the proofs in-circuit - for i in 0..N { - builder.verify_proof::(&proof_targets[i],&inner_verifier_data,&common_data); - } - let proof_target_array = vec_to_array::>(proof_targets)?; - - Ok(NodeCircuitTargets{ - proof_targets: proof_target_array, - verifier_data_target: inner_verifier_data, - }) - } - - /// assigns the targets for the Node circuit - pub fn assign_targets( - node_targets: NodeCircuitTargets, - proofs_with_pi: &[ProofWithPublicInputs; N], - verifier_data: &VerifierCircuitData, - pw: &mut PartialWitness, - ) -> Result<()>{ - for i in 0..N{ - pw.set_proof_with_pis_target(&node_targets.proof_targets[i],&proofs_with_pi[i]) - .map_err(|e| { - CircuitError::ProofTargetAssignmentError(format!("proof {}", i), e.to_string()) - })?; - } - // assign the verifier data - pw.set_verifier_data_target(&node_targets.verifier_data_target, &verifier_data.verifier_only) - .map_err(|e| { - CircuitError::VerifierDataTargetAssignmentError(e.to_string()) - })?; - - Ok(()) - } -} \ No newline at end of file diff --git a/recursion_experiments/recursion/hybrid/tree_circuit.rs b/recursion_experiments/recursion/hybrid/tree_circuit.rs deleted file mode 100644 index 7a38564..0000000 --- a/recursion_experiments/recursion/hybrid/tree_circuit.rs +++ /dev/null @@ -1,152 +0,0 @@ -use plonky2::hash::hash_types::RichField; -use plonky2::iop::witness::PartialWitness; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, VerifierCircuitData}; -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::circuits::utils::vec_to_array; -use crate::recursion::circuits::leaf_circuit::{LeafCircuit, LeafInput}; -use crate::recursion::hybrid::node_circuit::{NodeCircuit, NodeCircuitTargets}; - -/// Hybrid tree recursion - combines simple and tree recursion -/// - N: number of leaf proofs to verify in the node circuit -/// - M: number of inner proofs to verify in the leaf circuit -pub struct HybridTreeRecursion< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const N: usize, - const M: usize, -> { - pub leaf: LeafCircuit, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const N: usize, - const M: usize, -> HybridTreeRecursion -{ - - pub fn new( - leaf: LeafCircuit - ) -> Self { - Self{ - leaf, - } - } - - pub fn prove_tree< - C: GenericConfig + 'static, - H: AlgebraicHasher, - >( - &mut self, - proofs_with_pi: &[ProofWithPublicInputs], - inner_verifier_data: VerifierCircuitData, - ) -> Result<(ProofWithPublicInputs, VerifierCircuitData)> where - >::Hasher: AlgebraicHasher - { - // process leaves - let (leaf_proofs, leaf_data) = self.get_leaf_proofs::( - proofs_with_pi, - inner_verifier_data, - )?; - - // process nodes - let (root_proof, last_verifier_data) = - self.prove::(&leaf_proofs,leaf_data.verifier_data(), None, None, 0)?; - - Ok((root_proof, last_verifier_data)) - } - - - fn get_leaf_proofs< - C: GenericConfig + 'static, - H: AlgebraicHasher, - >( - &mut self, - proofs_with_pi: &[ProofWithPublicInputs], - inner_verifier_data: VerifierCircuitData, - ) -> Result<(Vec>, CircuitData)> where - >::Hasher: AlgebraicHasher{ - // builder with standard recursion config - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - let leaf_targets = self.leaf.build::(&mut builder)?; - let leaf_data = builder.build::(); - println!("leaf circuit size = {:?}", leaf_data.common.degree_bits()); - - let mut leaf_proofs = vec![]; - - for chunk in proofs_with_pi.chunks(M){ - let mut pw = PartialWitness::::new(); - let chunk_arr = vec_to_array::>(chunk.to_vec())?; - let leaf_in = LeafInput{ - inner_proof: chunk_arr, - verifier_data: inner_verifier_data.clone(), - }; - self.leaf.assign_targets::(&mut pw,&leaf_targets,&leaf_in)?; - let proof = leaf_data.prove(pw).unwrap(); - leaf_proofs.push(proof); - } - - Ok((leaf_proofs, leaf_data)) - } - - /// generates a proof - only one node - /// takes N proofs - fn prove< - C: GenericConfig + 'static, - H: AlgebraicHasher, - >( - &mut self, - proofs_with_pi: &[ProofWithPublicInputs], - verifier_data: VerifierCircuitData, - node_target_options: Option>, - node_data_option: Option>, - layer: usize, - ) -> Result<(ProofWithPublicInputs, VerifierCircuitData)> where - >::Hasher: AlgebraicHasher - { - - if proofs_with_pi.len() == 1 { - return Ok((proofs_with_pi[0].clone(), verifier_data)); - } - - let mut new_proofs = vec![]; - - let (node_data, node_targets) = if layer<2 { - let node_config = CircuitConfig::standard_recursion_config(); - let mut node_builder = CircuitBuilder::::new(node_config); - let targets = NodeCircuit::::build_circuit::(&mut node_builder, &verifier_data.common)?; - let data = node_builder.build::(); - (data, targets) - }else{ - (node_data_option.unwrap(), node_target_options.unwrap()) - }; - - for chunk in proofs_with_pi.chunks(N) { - - let chunk_arr = vec_to_array::>(chunk.to_vec())?; - - let mut inner_pw = PartialWitness::new(); - - NodeCircuit::::assign_targets(node_targets.clone(),&chunk_arr,&verifier_data, &mut inner_pw)?; - - let proof = node_data.prove(inner_pw) - .map_err(|e| CircuitError::ProofGenerationError(e.to_string()))?; - new_proofs.push(proof); - } - - self.prove::(&new_proofs, node_data.verifier_data(), Some(node_targets),Some(node_data), layer+1) - } - -} - diff --git a/recursion_experiments/recursion/mod.rs b/recursion_experiments/recursion/mod.rs deleted file mode 100644 index dbc2d24..0000000 --- a/recursion_experiments/recursion/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod cyclic; -pub mod circuits; -pub mod simple; -pub mod tree1; -pub mod tree2; -pub mod hybrid; -pub mod utils; -pub mod uniform; diff --git a/recursion_experiments/recursion/simple/mod.rs b/recursion_experiments/recursion/simple/mod.rs deleted file mode 100644 index 224ff24..0000000 --- a/recursion_experiments/recursion/simple/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod simple_recursion; -pub mod simple_recursion_hashed_pi; -pub mod simple_tree_recursion; diff --git a/recursion_experiments/recursion/simple/simple_recursion.rs b/recursion_experiments/recursion/simple/simple_recursion.rs deleted file mode 100644 index 4e0cc1b..0000000 --- a/recursion_experiments/recursion/simple/simple_recursion.rs +++ /dev/null @@ -1,156 +0,0 @@ -// the simple aggregation approach is verifying N proofs in-circuit and generating one final proof - -use std::marker::PhantomData; -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::error::CircuitError; -use crate::recursion::circuits::inner_circuit::InnerCircuit; -use crate::Result; - -// ---------------------- Simple recursion Approach 1 --------------------------- -// The simple approach here separates the build (setting the targets) and assigning the witness. -// the public input of the inner-proofs is the public input of the final proof except that -// the entropy is expected to be the same therefore only one entropy public input is in the final proof - -pub struct SimpleRecursionCircuit< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const N: usize, - C: GenericConfig, -> { - pub inner_circuit: I, - phantom_data: PhantomData<(F,C)> -} - -#[derive(Clone)] -pub struct SimpleRecursionTargets< - const D: usize, -> { - pub proofs_with_pi: Vec>, - pub verifier_data: VerifierCircuitTarget, - pub entropy: HashOutTarget, -} - -pub struct SimpleRecursionInput< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, ->{ - pub proofs: Vec>, - pub verifier_data: VerifierCircuitData, - pub entropy: HashOut, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const N: usize, - C: GenericConfig, -> SimpleRecursionCircuit where - >::Hasher: AlgebraicHasher, -{ - - pub fn new( - inner_circuit: I, - )->Self{ - Self{ - inner_circuit, - phantom_data: PhantomData::default(), - } - } - - /// contains the circuit logic and returns the witness & public input targets - pub fn build_circuit< - >( - &self, - builder: &mut CircuitBuilder, - ) -> Result>{ - // the proof virtual targets - let mut proof_targets = vec![]; - let mut inner_entropy_targets = vec![]; - let inner_common = self.inner_circuit.get_common_data()?; - - for _ in 0..N { - let vir_proof = builder.add_virtual_proof_with_pis(&inner_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(inner_common.config.fri_config.cap_height); - - // verify the proofs in-circuit - for i in 0..N { - builder.verify_proof::(&proof_targets[i],&inner_verifier_data,&inner_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..N { - for j in 0..4 { - builder.connect(inner_entropy_targets[i][j], outer_entropy_target.elements[j]); - } - } - // return targets - let srt = SimpleRecursionTargets { - proofs_with_pi: proof_targets, - verifier_data: inner_verifier_data, - entropy: outer_entropy_target, - }; - Ok(srt) - } - - /// assign the targets - pub fn assign_witness< - >( - &self, - pw: &mut PartialWitness, - targets: &SimpleRecursionTargets, - witnesses: SimpleRecursionInput, - ) -> Result<()>{ - // assign the proofs with public input - for i in 0..N{ - pw.set_proof_with_pis_target(&targets.proofs_with_pi[i],&witnesses.proofs[i]) - .map_err(|e| { - CircuitError::ProofTargetAssignmentError(format!("proof {}", i), e.to_string()) - })?; - } - - // assign the verifier data - pw.set_verifier_data_target(&targets.verifier_data, &witnesses.verifier_data.verifier_only) - .map_err(|e| { - CircuitError::VerifierDataTargetAssignmentError(e.to_string()) - })?; - - // set the entropy hash target - pw.set_hash_target(targets.entropy, witnesses.entropy) - .map_err(|e| { - CircuitError::HashTargetAssignmentError("entropy".to_string(), e.to_string()) - })?; - - Ok(()) - - } -} \ No newline at end of file diff --git a/recursion_experiments/recursion/simple/simple_recursion_hashed_pi.rs b/recursion_experiments/recursion/simple/simple_recursion_hashed_pi.rs deleted file mode 100644 index adf29a0..0000000 --- a/recursion_experiments/recursion/simple/simple_recursion_hashed_pi.rs +++ /dev/null @@ -1,132 +0,0 @@ -// the simple aggregation approach is verifying N proofs in-circuit and generating one final proof - -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::{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::error::CircuitError; -use crate::recursion::circuits::inner_circuit::InnerCircuit; -use crate::Result; - -// ---------------------- Simple recursion Approach 2 --------------------------- -// The simple approach here separates the build (setting the targets) and assigning the witness. -// ** the Hash of public input of the inner-proofs is the public input of the final proof ** - -pub struct SimpleRecursionCircuitHashedPI< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const N: usize, - C: GenericConfig, -> { - pub inner_circuit: I, - phantom_data: PhantomData<(F,C)> -} - -#[derive(Clone)] -pub struct SimpleRecursionTargetsHashedPI< - const D: usize, -> { - pub proofs_with_pi: Vec>, - pub verifier_data: VerifierCircuitTarget, -} - -pub struct SimpleRecursionInputHashedPI< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, ->{ - pub proofs: Vec>, - pub verifier_data: VerifierCircuitData, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const N: usize, - C: GenericConfig, -> SimpleRecursionCircuitHashedPI where - >::Hasher: AlgebraicHasher, -{ - - pub fn new( - inner_circuit: I, - )->Self{ - Self{ - inner_circuit, - phantom_data: PhantomData::default(), - } - } - - /// contains the circuit logic and returns the witness & public input targets - pub fn build_circuit< - H: AlgebraicHasher, - >( - &self, - builder: &mut CircuitBuilder, - ) -> Result>{ - // the proof virtual targets - let mut proof_targets = vec![]; - let mut inner_pub_input = vec![]; - let inner_common = self.inner_circuit.get_common_data()?; - - for _i in 0..N { - let vir_proof = builder.add_virtual_proof_with_pis(&inner_common); - // collect the public input - inner_pub_input.extend_from_slice(&vir_proof.public_inputs); - // collect the proof targets - proof_targets.push(vir_proof); - } - - // hash the public input & make it public - let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(inner_pub_input); - builder.register_public_inputs(&hash_inner_pub_input.elements); - - // virtual target for the verifier data - let inner_verifier_data = builder.add_virtual_verifier_data(inner_common.config.fri_config.cap_height); - - // verify the proofs in-circuit - for i in 0..N { - builder.verify_proof::(&proof_targets[i],&inner_verifier_data,&inner_common); - } - - // return targets - let srt = SimpleRecursionTargetsHashedPI { - proofs_with_pi: proof_targets, - verifier_data: inner_verifier_data, - }; - Ok(srt) - } - - /// assign the targets - pub fn assign_witness< - >( - &self, - pw: &mut PartialWitness, - targets: &SimpleRecursionTargetsHashedPI, - witnesses: SimpleRecursionInputHashedPI, - ) -> Result<()>{ - // assign the proofs with public input - for i in 0..N{ - pw.set_proof_with_pis_target(&targets.proofs_with_pi[i],&witnesses.proofs[i]) - .map_err(|e| { - CircuitError::ProofTargetAssignmentError(format!("proof {}", i), e.to_string()) - })?; - } - - // assign the verifier data - pw.set_verifier_data_target(&targets.verifier_data, &witnesses.verifier_data.verifier_only) - .map_err(|e| { - CircuitError::VerifierDataTargetAssignmentError(e.to_string()) - })?; - - Ok(()) - - } -} \ No newline at end of file diff --git a/recursion_experiments/recursion/simple/simple_tree_recursion.rs b/recursion_experiments/recursion/simple/simple_tree_recursion.rs deleted file mode 100644 index b717777..0000000 --- a/recursion_experiments/recursion/simple/simple_tree_recursion.rs +++ /dev/null @@ -1,119 +0,0 @@ -use plonky2::hash::hash_types::RichField; -use plonky2::plonk::proof::ProofWithPublicInputs; -use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData}; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::iop::witness::{PartialWitness, WitnessWrite}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2_field::extension::Extendable; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::error::CircuitError; -use crate::Result; - -// recursion tree width or the number of proofs in each node in the tree -const RECURSION_TREE_WIDTH: usize = 2; - -/// aggregate sampling proofs -/// This function takes: -/// - N number of proofs (it has to be sampling proofs here) -/// - verifier_data of the sampling circuit -/// - circuit builder -/// - partial witness -/// -/// The function doesn't return anything but sets the targets in the builder and assigns the witness -pub fn aggregate_sampling_proofs< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - H: AlgebraicHasher ->( - proofs_with_pi: &Vec>, - verifier_data: &VerifierCircuitData, - builder: &mut CircuitBuilder, - pw: &mut PartialWitness, -)-> Result<()>where - >::Hasher: AlgebraicHasher -{ - // the proof virtual targets - let mut proof_targets = vec![]; - let mut inner_pub_input = vec![]; - for _i in 0..proofs_with_pi.len() { - let vir_proof = builder.add_virtual_proof_with_pis(&verifier_data.common); - // collect the public input - inner_pub_input.extend_from_slice(&vir_proof.public_inputs); - // collect the proof targets - proof_targets.push(vir_proof); - } - // hash the public input & make it public - let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(inner_pub_input); - builder.register_public_inputs(&hash_inner_pub_input.elements); - // 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]) - .map_err(|e| { - CircuitError::ProofTargetAssignmentError(format!("proof {}", i), e.to_string()) - })?; - } - // 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_verifier_data_target(&inner_verifier_data, &verifier_data.verifier_only) - .map_err(|e| { - CircuitError::VerifierDataTargetAssignmentError(e.to_string()) - })?; - - // verify the proofs in-circuit - for i in 0..proofs_with_pi.len() { - builder.verify_proof::(&proof_targets[i],&inner_verifier_data,&verifier_data.common); - } - - Ok(()) -} - -/// aggregate sampling proofs in tree like structure -/// uses the const params: `RECURSION_TREE_WIDTH` -/// In this tree approach the building is done at each level -> very slow! -/// takes `VerifierCircuitData` -pub fn aggregate_sampling_proofs_tree -< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - H: AlgebraicHasher ->( - proofs_with_pi: &[ProofWithPublicInputs], - vd: VerifierCircuitData -) -> Result<(ProofWithPublicInputs, VerifierCircuitData)> where - >::Hasher: AlgebraicHasher -{ - 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> = 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::::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::(); - - let proof = inner_data.prove(inner_pw) - .map_err(|e| CircuitError::ProofGenerationError(e.to_string()))?; - new_proofs.push(proof); - new_circuit_data = Some(inner_data.verifier_data()); - } - - aggregate_sampling_proofs_tree::(&new_proofs, new_circuit_data.unwrap()) -} diff --git a/recursion_experiments/recursion/tree1/mod.rs b/recursion_experiments/recursion/tree1/mod.rs deleted file mode 100644 index d4d7a1b..0000000 --- a/recursion_experiments/recursion/tree1/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod tree_circuit; -pub mod node_circuit; diff --git a/recursion_experiments/recursion/tree1/node_circuit.rs b/recursion_experiments/recursion/tree1/node_circuit.rs deleted file mode 100644 index e4cf226..0000000 --- a/recursion_experiments/recursion/tree1/node_circuit.rs +++ /dev/null @@ -1,259 +0,0 @@ -use plonky2::hash::hash_types::{HashOutTarget, RichField}; -use plonky2_field::extension::Extendable; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitTarget}; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; -use plonky2::iop::witness::{PartialWitness, WitnessWrite}; -use plonky2::gates::noop::NoopGate; -use plonky2::iop::target::BoolTarget; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::circuits::utils::{select_hash, vec_to_array}; -use crate::{error::CircuitError, Result}; -use crate::recursion::circuits::inner_circuit::InnerCircuit; -use crate::recursion::utils::conditional_verifier::dummy_circuit; -use crate::recursion::utils::dummy_gen::DummyProofGen; - -/// Node circuit struct -/// contains necessary data -/// M: number of inner-circuits to run -/// N: number of proofs verified in-circuit (so num of child nodes) -pub struct NodeCircuit< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const M: usize, - const N: usize, - C: GenericConfig, ->{ - pub circ: I, - pub cyclic_target: NodeCircuitTargets, - pub cyclic_circuit_data: CircuitData, - pub common_data: CommonCircuitData, -} - -/// Node circuit targets -/// assumes that all inner proofs use the same verifier data -#[derive(Clone, Debug)] -pub struct NodeCircuitTargets< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const M: usize, - const N: usize, ->{ - pub inner_targets: [I::Targets; M], - pub condition: BoolTarget, - pub inner_proofs_with_pis: [ProofWithPublicInputsTarget; N], - pub verifier_data: VerifierCircuitTarget, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const M: usize, - const N: usize, - C: GenericConfig + 'static, -> NodeCircuit where - >::Hasher: AlgebraicHasher -{ - - /// builds the cyclic recursion circuit using any inner circuit I - /// return the Node circuit - /// TODO: make generic recursion config - pub fn build_circuit< - H: AlgebraicHasher, - >( - inner_circ: I, - ) -> Result<(Self)>{ - - // builder with standard recursion config - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - //build M inner circuits - let inner_t: [I::Targets; M] = - vec_to_array::( - (0..M) - .map(|_| inner_circ.build(&mut builder, false)) - .collect::>>()? - )?; - - // common data for recursion - let mut common_data = Self::common_data_for_node()?; - - let pub_input_hash = builder.add_virtual_hash_public_input(); - // TODO: make verifier data public - // let verifier_data_target = builder.add_verifier_data_public_inputs(); - let verifier_data_target = builder.add_virtual_verifier_data(builder.config.fri_config.cap_height); - common_data.num_public_inputs = builder.num_public_inputs(); - - // condition - let condition = builder.add_virtual_bool_target_safe(); - - // inner proofs targets - N proof targets - let inner_cyclic_proof_with_pis: [ProofWithPublicInputsTarget; N] = - vec_to_array::>( - (0..N) - .map(|_| builder.add_virtual_proof_with_pis(&common_data)) - .collect::>() - )?; - - // get the public input hash from all inner proof targets - let mut inner_pub_input_hashes = vec![]; - for i in 0..N { - let inner_cyclic_pis = &inner_cyclic_proof_with_pis[i].public_inputs; - inner_pub_input_hashes.extend_from_slice(&inner_cyclic_pis[0..4]); - } - // hash all the inner public input h = H(h_1 | h_2 | ... | h_N) - let inner_pub_input_hash = builder.hash_n_to_hash_no_pad::(inner_pub_input_hashes); - - // get the public input of the inner circuit - let mut outer_pis = vec![]; - for i in 0..M { - outer_pis.push( I::get_pub_input_targets(&inner_t[i])); - } - // hash all the public input -> generate one HashOut at the end - let mut outer_pi_hashes = vec![]; - for i in 0..M { - let hash_res = builder.hash_n_to_hash_no_pad::(outer_pis[i].clone()); - outer_pi_hashes.extend_from_slice(&hash_res.elements) - } - // the final public input hash - let outer_pi_hash = builder.hash_n_to_hash_no_pad::(outer_pi_hashes); - // zero hash for leaves - let zero_hash = HashOutTarget::from_vec([builder.zero(); 4].to_vec()); - // if the inner proofs are dummy then use zero hash for public input - let inner_pi_hash_or_zero_hash = select_hash(&mut builder, condition, inner_pub_input_hash, zero_hash); - - // now hash the public input of the inner proofs and outer proof, so we have one public hash - let mut hash_input = vec![]; - hash_input.extend_from_slice(&outer_pi_hash.elements); - hash_input.extend_from_slice(&inner_pi_hash_or_zero_hash.elements); - let outer_pi_hash = builder.hash_n_to_hash_no_pad::(hash_input); - // connect this up one to `pub_input_hash` - builder.connect_hashes(pub_input_hash,outer_pi_hash); - - // verify all N proofs in-circuit - for i in 0..N { - builder.verify_proof::(&inner_cyclic_proof_with_pis[i], &verifier_data_target, &common_data); - - } - - // build the cyclic circuit - let cyclic_circuit_data = builder.build::(); - - // assign targets - let cyc_t = NodeCircuitTargets::{ - inner_targets: inner_t, - condition, - inner_proofs_with_pis: inner_cyclic_proof_with_pis, - verifier_data: verifier_data_target - }; - - // assign the data - Ok(Self{ - circ: inner_circ, - cyclic_target: cyc_t, - cyclic_circuit_data, - common_data, - }) - } - - /// assigns the targets for the Node circuit - /// takes circuit input - pub fn assign_targets( - &mut self, - circ_input: &[I::Input; M], - proof_options: Option<[ProofWithPublicInputs; N]>, - pw: &mut PartialWitness, - is_leaf: bool, - ) -> Result<()>{ - - let circ_data = &self.cyclic_circuit_data; - let cyc_targets = &self.cyclic_target; - let common_data = &self.common_data; - - for i in 0..M { - self.circ.assign_targets(pw, &cyc_targets.inner_targets[i], &circ_input[i])?; - } - - if is_leaf == true { - pw.set_bool_target(cyc_targets.condition, false) - .map_err(|e| CircuitError::BoolTargetAssignmentError("condition".to_string(),e.to_string()))?; - for i in 0..N { - pw.set_proof_with_pis_target::( - &cyc_targets.inner_proofs_with_pis[i], - &DummyProofGen::::get_dummy_node_proof( - common_data, - &circ_data.verifier_only, - ), - ).map_err(|e| CircuitError::ProofTargetAssignmentError("inner proofs".to_string(),e.to_string()))?; - } - // assign verifier data - let dummy_ver = dummy_circuit::(common_data).verifier_only; - pw.set_verifier_data_target(&cyc_targets.verifier_data, &dummy_ver) - .map_err(|e| CircuitError::VerifierDataTargetAssignmentError(e.to_string()))?; - }else{ - pw.set_bool_target(cyc_targets.condition, true) - .map_err(|e| CircuitError::BoolTargetAssignmentError("condition".to_string(),e.to_string()))?; - - let proofs = proof_options.ok_or(CircuitError::OptionError("inner proof not given".to_string()))?; - for i in 0..N { - pw.set_proof_with_pis_target(&cyc_targets.inner_proofs_with_pis[i], &proofs[i]) - .map_err(|e| CircuitError::ProofTargetAssignmentError("inner proofs".to_string(),e.to_string()))?; - } - // assign verifier data - pw.set_verifier_data_target(&cyc_targets.verifier_data, &circ_data.verifier_only) - .map_err(|e| CircuitError::VerifierDataTargetAssignmentError(e.to_string()))?; - } - - Ok(()) - } - - /// Generates `CommonCircuitData` usable for node recursion. - /// the circuit being built here depends on M and N so must be re-generated - /// if the params change - pub fn common_data_for_node() -> Result> - { - // layer 1 - let config = CircuitConfig::standard_recursion_config(); - let builder = CircuitBuilder::::new(config); - let data = builder.build::(); - - // layer 2 - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - let verifier_data = builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); - // generate and verify N number of proofs - for _ in 0..N { - let proof = builder.add_virtual_proof_with_pis(&data.common); - builder.verify_proof::(&proof, &verifier_data, &data.common); - } - let data = builder.build::(); - - // layer 3 - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - - // add a ConstantGate - builder.add_gate( - plonky2::gates::constant::ConstantGate::new(config.num_constants), - vec![], - ); - - // generate and verify N number of proofs - let verifier_data = builder.add_verifier_data_public_inputs(); - for _ in 0..N { - let proof = builder.add_virtual_proof_with_pis(&data.common); - builder.verify_proof::(&proof, &verifier_data, &data.common); - } - // pad - padding depends on the inner circuit size - while builder.num_gates() < 1 << 13 { - builder.add_gate(NoopGate, vec![]); - } - Ok(builder.build::().common) - } - -} diff --git a/recursion_experiments/recursion/tree1/tree_circuit.rs b/recursion_experiments/recursion/tree1/tree_circuit.rs deleted file mode 100644 index e5fe006..0000000 --- a/recursion_experiments/recursion/tree1/tree_circuit.rs +++ /dev/null @@ -1,154 +0,0 @@ -use std::array::from_fn; -use plonky2::hash::hash_types::RichField; -use plonky2::iop::witness::{PartialWitness}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2::plonk::proof::ProofWithPublicInputs; -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::recursion::tree1::node_circuit::NodeCircuit; - -/// the tree recursion struct simplifies the process -/// of building, proving and verifying -/// the two consts are: -/// - M: number of inner circuits to run -/// - N: number of inner proofs to verify -pub struct TreeRecursion< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const M: usize, - const N: usize, - C: GenericConfig, ->{ - pub node_circ: NodeCircuit -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - I: InnerCircuit, - const M: usize, - const N: usize, - C: GenericConfig + 'static, -> TreeRecursion where - >::Hasher: AlgebraicHasher -{ - - pub fn build< - H: AlgebraicHasher, - >( - inner_circuit: I, - ) -> Result<(Self)>{ - Ok(Self { - node_circ: NodeCircuit:: < F, - D, - I, - M, - N, - C>::build_circuit:: < H>(inner_circuit)? - }) - } - - /// generates a proof - only one node - /// takes M circuit input and N proofs - pub fn prove( - &mut self, - circ_input: &[I::Input; M], - proofs_option: Option<[ProofWithPublicInputs; N]>, - is_leaf: bool, - ) -> Result>{ - - let mut pw = PartialWitness::new(); - self.node_circ.assign_targets( - circ_input, - proofs_option, - &mut pw, - is_leaf, - )?; - - let circ_data = &self.node_circ.cyclic_circuit_data; - - let proof = circ_data.prove(pw) - .map_err(|e| CircuitError::InvalidProofError(e.to_string()))?; - - Ok(proof) - } - - /// prove n in a tree structure recursively - /// the function takes - /// - circ_input: vector of circuit inputs - pub fn prove_tree( - &mut self, - circ_input: Vec, - depth: usize, - ) -> Result>{ - // Total input size check - let total_input = (N.pow(depth as u32) - 1) / (N - 1); - - if circ_input.len() != total_input{ - return Err(CircuitError::RecursionTreeError( - "Invalid input size for tree depth".to_string() - )); - } - - let mut cur_proofs: Vec> = vec![]; - - // Iterate from leaf layer to root - for layer in (0..depth).rev() { - let layer_num_nodes = N.pow(layer as u32); // Number of nodes at this layer - let mut next_proofs = Vec::new(); - - for node_idx in 0..layer_num_nodes { - // Get the inputs for the current node - let node_inputs: [I::Input; M] = from_fn(|i| { - circ_input - .get(node_idx * M + i) - .cloned() - .unwrap_or_else(|| panic!("Index out of bounds at node {node_idx}, input {i}")) - }); - - let proof = if layer == depth - 1 { - // Leaf layer: no child proofs - self.prove(&node_inputs, None, true)? - } else { - // Non-leaf layer: collect child proofs - let proofs_array: [ProofWithPublicInputs; N] = cur_proofs - .drain(..N) - .collect::>() - .try_into() - .map_err(|_| CircuitError::ArrayLengthMismatchError("Incorrect number of proofs for node".to_string()))?; - self.prove(&node_inputs, Some(proofs_array), false)? - }; - next_proofs.push(proof); - } - cur_proofs = next_proofs; - } - - // Check that exactly one proof remains - if cur_proofs.len() != 1 { - return Err(CircuitError::RecursionTreeError( - format!("Expected exactly 1 final proof, found {}", - cur_proofs.len()) - )); - } - - Ok(cur_proofs.remove(0)) - } - - /// verifies the proof generated - pub fn verify_proof( - &self, - proof: ProofWithPublicInputs - ) -> Result<()>{ - - let circ_data = &self.node_circ.cyclic_circuit_data; - - // TODO: check verifier_data - - circ_data.verify(proof).map_err(|e|CircuitError::InvalidProofError(e.to_string()))?; - - Ok(()) - } -} diff --git a/recursion_experiments/recursion/tree2/mod.rs b/recursion_experiments/recursion/tree2/mod.rs deleted file mode 100644 index f81ad84..0000000 --- a/recursion_experiments/recursion/tree2/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod node_circuit; -pub mod tree_circuit; diff --git a/recursion_experiments/recursion/tree2/node_circuit.rs b/recursion_experiments/recursion/tree2/node_circuit.rs deleted file mode 100644 index 85f1b6e..0000000 --- a/recursion_experiments/recursion/tree2/node_circuit.rs +++ /dev/null @@ -1,289 +0,0 @@ -use plonky2::gates::constant::ConstantGate; -use plonky2::gates::noop::NoopGate; -use plonky2::hash::hash_types::RichField; -use plonky2::iop::target::BoolTarget; -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_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::recursion::circuits::inner_circuit::InnerCircuit; -use plonky2_field::extension::Extendable; -use crate::circuits::utils::{select_vec, vec_to_array}; -use crate::{error::CircuitError, Result}; -use crate::recursion::circuits::leaf_circuit::LeafCircuit; - -/// Node circuit struct -/// contains necessary data -/// N: number of proofs verified in-circuit (so num of child nodes) -pub struct NodeCircuit< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - const N: usize, ->{ - pub node_targets: NodeCircuitTargets, - pub node_data: NodeData, -} - -/// Node circuit targets -/// assumes that all leaf proofs use the same verifier data -#[derive(Clone, Debug)] -pub struct NodeCircuitTargets< - const D: usize, - const N: usize, ->{ - pub leaf_proofs: [ProofWithPublicInputsTarget; N], - pub condition: BoolTarget, - pub node_proofs: [ProofWithPublicInputsTarget; N], - pub leaf_verifier_data: VerifierCircuitTarget, - pub node_verifier_data: VerifierCircuitTarget, -} - -/// Node common data and verifier data -#[derive(Debug)] -pub struct NodeData< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, ->{ - pub node_circuit_data: CircuitData, - pub inner_node_common_data: CommonCircuitData, - pub leaf_circuit_data: CircuitData, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig + 'static, - const N: usize, -> NodeCircuit - where - >::Hasher: AlgebraicHasher -{ - - /// builds the node circuit - /// the circuit data and targets are stored in the node struct - /// TODO: make generic recursion config - pub fn build_circuit< - I: InnerCircuit, - H: AlgebraicHasher, - const M: usize, - >( - leaf_circuit: LeafCircuit - ) -> Result>{ - - // builder with standard recursion config - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - // circuit data for leaf - let leaf_circ_data = leaf_circuit.get_circuit_data::()?; - - // common data for leaf - let leaf_common = leaf_circ_data.common.clone(); - - // virtual proofs for leaf proofs - let mut leaf_proofs = vec![]; - for _i in 0..N { - let vir_proof = builder.add_virtual_proof_with_pis(&leaf_common); - leaf_proofs.push(vir_proof); - } - - // get the public input hash from all inner proof targets - let mut leaf_pub_input_hashes = vec![]; - for i in 0..N { - let inner_cyclic_pis = &leaf_proofs[i].public_inputs; - leaf_pub_input_hashes.extend_from_slice(&inner_cyclic_pis[0..4]); - } - - // leaf verifier data - // TODO: make verifier data public - let leaf_verifier_data = builder.add_virtual_verifier_data(leaf_common.config.fri_config.cap_height); - - // condition - let condition = builder.add_virtual_bool_target_safe(); - - // verify leaf proofs in-circuit if it is a leaf node, - // meaning that we are on bottom layer of the tree - for i in 0..N{ - builder.verify_proof::(&leaf_proofs[i], &leaf_verifier_data, &leaf_common); - - } - - // common data for recursion - let mut common_data = Self::get_common_data_for_node()?; - // public input hash. defined here so that is public_input[0..4] - let pub_input_hash = builder.add_virtual_hash_public_input(); - // TODO: make verifier data public - // let _verifier_data_target = builder.add_verifier_data_public_inputs(); - let verifier_data_target = builder.add_virtual_verifier_data(builder.config.fri_config.cap_height); - common_data.num_public_inputs = builder.num_public_inputs(); - - let inner_cyclic_proof_with_pis: [ProofWithPublicInputsTarget; N] = - vec_to_array::>( - (0..N) - .map(|_| builder.add_virtual_proof_with_pis(&common_data)) - .collect::>() - )?; - - // get the public input hash from all inner proof targets - let mut inner_pub_input_hashes = vec![]; - for i in 0..N { - let inner_cyclic_pis = &inner_cyclic_proof_with_pis[i].public_inputs; - inner_pub_input_hashes.extend_from_slice(&inner_cyclic_pis[0..4]); - } - - // select the public input - either leaf or node - let pub_input_to_be_hashed = select_vec(&mut builder, condition, &leaf_pub_input_hashes ,&inner_pub_input_hashes); - // hash all the node public input h = H(h_1 | h_2 | ... | h_N) - let node_hash_or_leaf_hash= builder.hash_n_to_hash_no_pad::(pub_input_to_be_hashed); - - builder.connect_hashes(pub_input_hash,node_hash_or_leaf_hash); - - // verify all N proofs in-circuit - for i in 0..N { - builder.verify_proof::(&inner_cyclic_proof_with_pis[i], &verifier_data_target, &common_data); - - } - - // build the node circuit - let node_circuit_data = builder.build::(); - - // collect the leaf proofs - let leaf_proofs: [ProofWithPublicInputsTarget; N] = - vec_to_array::>( - (0..N).map(|i| { - leaf_proofs[i].clone() - }).collect::>() - )?; - - // store targets - let node_targets = NodeCircuitTargets::{ - leaf_proofs, - condition, - node_proofs: inner_cyclic_proof_with_pis, - leaf_verifier_data, - node_verifier_data: verifier_data_target - }; - - let node_data = NodeData{ - node_circuit_data, - inner_node_common_data: common_data, - leaf_circuit_data: leaf_circ_data, - }; - - let node = NodeCircuit{ - node_targets, - node_data, - }; - - Ok(node) - } - - /// assigns the targets for the Node circuit - takes - /// - either leaf or circuit proofs - /// - leaf circuit data - /// - partial witness - /// - bool value, true if leaf node, otherwise false. - pub fn assign_targets( - node_targets: NodeCircuitTargets, - leaf_proofs: [ProofWithPublicInputs; N], - node_proofs: [ProofWithPublicInputs; N], - leaf_verifier_only_data: &VerifierOnlyCircuitData, - node_verifier_only_data: &VerifierOnlyCircuitData, - pw: &mut PartialWitness, - is_leaf: bool, - ) -> Result<()>{ - - if is_leaf == true { - let dummy_node = node_proofs; - // assign the condition - pw.set_bool_target(node_targets.condition, true) - .map_err(|e| CircuitError::BoolTargetAssignmentError("condition".to_string(),e.to_string()))?; - for i in 0..N { - // assign the node proofs with dummy - pw.set_proof_with_pis_target::( - &node_targets.node_proofs[i], - &dummy_node[i], - ).map_err(|e| CircuitError::ProofTargetAssignmentError("dummy node proofs".to_string(),e.to_string()))?; - // assign the leaf proof with real proofs - pw.set_proof_with_pis_target( - &node_targets.leaf_proofs[i], - &leaf_proofs[i] - ).map_err(|e| CircuitError::ProofTargetAssignmentError("leaf proofs".to_string(),e.to_string()))?; - } - }else{ - // assign the condition - pw.set_bool_target(node_targets.condition, false) - .map_err(|e| CircuitError::BoolTargetAssignmentError("condition".to_string(),e.to_string()))?; - - // dummy leaf - let dummy_leaf = leaf_proofs; - for i in 0..N { - // assign the node proofs - pw.set_proof_with_pis_target(&node_targets.node_proofs[i], &node_proofs[i]) - .map_err(|e| CircuitError::ProofTargetAssignmentError("node proofs".to_string(),e.to_string()))?; - - // assign leaf proofs with dummy - pw.set_proof_with_pis_target::( - &node_targets.leaf_proofs[i], - &dummy_leaf[i], - ).map_err(|e| CircuitError::ProofTargetAssignmentError("dummy leaf proofs".to_string(),e.to_string()))?; - } - } - // assign the verifier data - pw.set_verifier_data_target(&node_targets.leaf_verifier_data, leaf_verifier_only_data) - .map_err(|e| CircuitError::VerifierDataTargetAssignmentError(e.to_string()))?; - pw.set_verifier_data_target(&node_targets.node_verifier_data, node_verifier_only_data) - .map_err(|e| CircuitError::VerifierDataTargetAssignmentError(e.to_string()))?; - - Ok(()) - } - - /// Generates `CommonCircuitData` usable for node recursion. - /// the circuit being built here depends on M and N so must be re-generated - /// if the params change - pub fn get_common_data_for_node() -> Result> - { - // layer 1 - let config = CircuitConfig::standard_recursion_config(); - let builder = CircuitBuilder::::new(config); - let data = builder.build::(); - - // layer 2 - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - let verifier_data = builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); - // generate and verify N number of proofs - for _ in 0..1 { - let proof = builder.add_virtual_proof_with_pis(&data.common); - builder.verify_proof::(&proof, &verifier_data, &data.common); - } - let data = builder.build::(); - - // layer 3 - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - - // add a ConstantGate - builder.add_gate( - ConstantGate::new(config.num_constants), - vec![], - ); - - // generate and verify N number of proofs - let verifier_data = builder.add_verifier_data_public_inputs(); - for _ in 0..N { - let proof = builder.add_virtual_proof_with_pis(&data.common); - builder.verify_proof::(&proof, &verifier_data, &data.common); - } - // pad. - while builder.num_gates() < 1 << 12 { - builder.add_gate(NoopGate, vec![]); - } - Ok(builder.build::().common) - } - -} \ No newline at end of file diff --git a/recursion_experiments/recursion/tree2/tree_circuit.rs b/recursion_experiments/recursion/tree2/tree_circuit.rs deleted file mode 100644 index d6b878d..0000000 --- a/recursion_experiments/recursion/tree2/tree_circuit.rs +++ /dev/null @@ -1,168 +0,0 @@ -use plonky2::hash::hash_types::RichField; -use plonky2::iop::witness::{PartialWitness}; -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::recursion::utils::dummy_gen::DummyProofGen; -use crate::{error::CircuitError, Result}; -use crate::circuits::utils::vec_to_array; -use crate::recursion::circuits::leaf_circuit::LeafCircuit; -use crate::recursion::tree2::node_circuit::NodeCircuit; - -/// the tree recursion struct simplifies the process -/// of building, proving and verifying -/// - N: number of inner proofs to verify in the node circuit -pub struct TreeRecursion< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig + 'static, - const N: usize, -> where - >::Hasher: AlgebraicHasher -{ - pub node: NodeCircuit -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig + 'static, - const N: usize, -> TreeRecursion where - >::Hasher: AlgebraicHasher -{ - - - - pub fn build< - I: InnerCircuit, - H: AlgebraicHasher, - const M: usize, - >( - leaf_circuit: LeafCircuit - ) -> Result{ - Ok( - Self{ - node: NodeCircuit::::build_circuit::(leaf_circuit)?, - } - ) - } - - /// generates a proof - only one node - /// takes N proofs - pub fn prove( - &mut self, - leaf_proofs: [ProofWithPublicInputs; N], - node_proofs: [ProofWithPublicInputs; N], - is_leaf: bool, - ) -> Result>{ - - let mut pw = PartialWitness::new(); - - NodeCircuit::assign_targets( - self.node.node_targets.clone(), - leaf_proofs, - node_proofs, - &self.node.node_data.leaf_circuit_data.verifier_only, - &self.node.node_data.node_circuit_data.verifier_only, - &mut pw, - is_leaf, - )?; - - let proof = self.node.node_data.node_circuit_data.prove(pw) - .map_err(|e| CircuitError::ProofGenerationError(e.to_string()))?; - Ok(proof) - } - - /// prove n leaf proofs in a tree structure - /// the function uses circuit data from self takes - /// - leaf_proofs: vector of circuit inputs - /// NOTE: Expects the number of leaf proofs to be divisible by N, e.g. by 2 if binary tree - pub fn prove_tree( - &mut self, - leaf_proofs: Vec>, - ) -> Result> { - // 1. Check the total number of leaf_proofs is divisible by N - if leaf_proofs.len() % N != 0 { - return - Err(CircuitError::RecursionTreeError(format!( - "input proofs must be divisible by {}, got {}", N, leaf_proofs.len()) - )) - } - - // 2. Prepare the dummy proofs - let dummy_node_proofs = DummyProofGen::::gen_n_dummy_node_proofs( - &self.node.node_data.inner_node_common_data, - &self.node.node_data.node_circuit_data.verifier_only, - )?; - - let dummy_leaf_proofs = DummyProofGen::::gen_n_dummy_leaf_proofs( - &self.node.node_data.leaf_circuit_data.common - )?; - - // 3. Work through levels of proofs until only one remains - let mut current_level_proofs = leaf_proofs; - - // Keep reducing until we’re left with 1 proof - let mut level: usize = 0; - while current_level_proofs.len() >= N { - let mut next_level_proofs = Vec::new(); - - // Process in chunks of N - for chunk in current_level_proofs.chunks_exact(N) { - // Convert the chunk slice into a fixed-size array - let chunk_array: [ProofWithPublicInputs; N] = - vec_to_array::>(chunk.to_vec())?; - - // Decide leaf or node based on level - // assumes the first chunk is the leaf - let (leaf_chunk, node_chunk, is_leaf) = if level == 0 { - (chunk_array, dummy_node_proofs.clone(), true) - } else { - (dummy_leaf_proofs.clone(), chunk_array, false) - }; - - let node = self.prove( - leaf_chunk, - node_chunk, - is_leaf, - )?; - - next_level_proofs.push(node); - } - - current_level_proofs = next_level_proofs; - level = level + 1; - } - - // 4. Check that exactly one proof remains - if current_level_proofs.len() != 1 { - return Err(CircuitError::RecursionTreeError( - format!("Expected exactly 1 final proof, found {}", - current_level_proofs.len()) - )); - } - - // 5. Return the final root proof - Ok(current_level_proofs.remove(0)) - } - - /// verifies the proof generated - /// TODO: separate prover from verifier. - pub fn verify_proof( - &self, - proof: ProofWithPublicInputs, - is_leaf: bool, - ) -> Result<()>{ - - // TODO: if !is_leaf check verifier data - - self.node.node_data.node_circuit_data.verify(proof) - .map_err(|e| CircuitError::InvalidProofError(e.to_string()))?; - - Ok(()) - } -} - diff --git a/recursion_experiments/recursion/uniform/leaf.rs b/recursion_experiments/recursion/uniform/leaf.rs deleted file mode 100644 index e9c1068..0000000 --- a/recursion_experiments/recursion/uniform/leaf.rs +++ /dev/null @@ -1,139 +0,0 @@ -use std::marker::PhantomData; -use plonky2::hash::hash_types::RichField; -use plonky2::iop::witness::{PartialWitness, WitnessWrite}; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; -use plonky2_field::extension::Extendable; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::recursion::circuits::inner_circuit::InnerCircuit; -use crate::{error::CircuitError,Result}; - -/// recursion leaf circuit - verifies N inner proof -#[derive(Clone, Debug)] -pub struct LeafCircuit< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - H: AlgebraicHasher, - const N: usize, -> where - >::Hasher: AlgebraicHasher -{ - inner_common_data: CommonCircuitData, - phantom_data: PhantomData<(C,H)> -} - -#[derive(Clone, Debug)] -pub struct LeafTargets < - const D: usize, ->{ - pub inner_proof: Vec>, - pub verifier_data: VerifierCircuitTarget, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - H: AlgebraicHasher, - const N: usize, -> LeafCircuit where - >::Hasher: AlgebraicHasher -{ - pub fn new(inner_common_data: CommonCircuitData) -> Self { - Self{ - inner_common_data, - phantom_data:PhantomData::default(), - } - } - - /// build the leaf circuit - pub fn build(&self, builder: &mut CircuitBuilder) -> Result> { - - let inner_common = self.inner_common_data.clone(); - - // the proof virtual targets - let mut pub_input = vec![]; - let mut vir_proofs = vec![]; - for _i in 0..N { - let vir_proof = builder.add_virtual_proof_with_pis(&inner_common); - let inner_pub_input = vir_proof.public_inputs.clone(); - vir_proofs.push(vir_proof); - pub_input.extend_from_slice(&inner_pub_input); - } - - // hash the public input & make it public - let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(pub_input); - builder.register_public_inputs(&hash_inner_pub_input.elements); - - // virtual target for the verifier data - let inner_verifier_data = builder.add_virtual_verifier_data(inner_common.config.fri_config.cap_height); - - // register verifier data hash as public input. - let mut vd_pub_input = vec![]; - vd_pub_input.extend_from_slice(&inner_verifier_data.circuit_digest.elements); - for i in 0..builder.config.fri_config.num_cap_elements() { - vd_pub_input.extend_from_slice(&inner_verifier_data.constants_sigmas_cap.0[i].elements); - } - let hash_inner_vd_pub_input = builder.hash_n_to_hash_no_pad::(vd_pub_input); - builder.register_public_inputs(&hash_inner_vd_pub_input.elements); - - // verify the proofs in-circuit - for i in 0..N { - builder.verify_proof::(&vir_proofs[i], &inner_verifier_data, &inner_common); - } - - // return targets - let t = LeafTargets { - inner_proof: vir_proofs, - verifier_data: inner_verifier_data, - }; - Ok(t) - - } - - /// assign the leaf targets with given input - pub fn assign_targets( - &self, pw: &mut PartialWitness, - targets: &LeafTargets, - inner_proof: &[ProofWithPublicInputs], - verifier_only_data: &VerifierOnlyCircuitData, - ) -> Result<()> { - assert_eq!(inner_proof.len(), N); - // assign the proofs - for i in 0..N { - pw.set_proof_with_pis_target(&targets.inner_proof[i], &inner_proof[i]) - .map_err(|e| { - CircuitError::ProofTargetAssignmentError("inner-proof".to_string(), e.to_string()) - })?; - } - - // assign the verifier data - pw.set_verifier_data_target(&targets.verifier_data, verifier_only_data) - .map_err(|e| { - CircuitError::VerifierDataTargetAssignmentError(e.to_string()) - })?; - - Ok(()) - } - - /// returns the leaf circuit data - pub fn get_circuit_data (&self) -> Result> - where - >::Hasher: AlgebraicHasher - { - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - - self.build(&mut builder)?; - - let circ_data = builder.build::(); - - Ok(circ_data) - } - -} - - diff --git a/recursion_experiments/recursion/uniform/mod.rs b/recursion_experiments/recursion/uniform/mod.rs deleted file mode 100644 index 6daaa29..0000000 --- a/recursion_experiments/recursion/uniform/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod leaf; -pub mod node; -pub mod tree; \ No newline at end of file diff --git a/recursion_experiments/recursion/uniform/node.rs b/recursion_experiments/recursion/uniform/node.rs deleted file mode 100644 index 34fdb8f..0000000 --- a/recursion_experiments/recursion/uniform/node.rs +++ /dev/null @@ -1,152 +0,0 @@ -use std::marker::PhantomData; -use plonky2::hash::hash_types::RichField; -use plonky2::iop::witness::{PartialWitness, WitnessWrite}; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; -use plonky2_field::extension::Extendable; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::recursion::circuits::inner_circuit::InnerCircuit; -use crate::{error::CircuitError,Result}; -use crate::circuits::utils::vec_to_array; - -/// recursion node circuit - verifies 2 leaf proofs -#[derive(Clone, Debug)] -pub struct NodeCircuit< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - H: AlgebraicHasher, - const M: usize, -> where - >::Hasher: AlgebraicHasher -{ - leaf_common_data: CommonCircuitData, - phantom_data: PhantomData<(C,H)> -} - -#[derive(Clone, Debug)] -pub struct NodeTargets< - const D: usize, ->{ - pub leaf_proofs: Vec>, - pub verifier_data: VerifierCircuitTarget, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - H: AlgebraicHasher, - const M: usize, -> NodeCircuit where - >::Hasher: AlgebraicHasher -{ - - pub fn new(inner_common_data: CommonCircuitData) -> Self { - Self{ - leaf_common_data: inner_common_data, - phantom_data:PhantomData::default(), - } - } - - /// build the leaf circuit - pub fn build(&self, builder: &mut CircuitBuilder) -> Result> { - - let inner_common = self.leaf_common_data.clone(); - - // assert public input is of size 8 - 2 hashout - assert_eq!(inner_common.num_public_inputs, 8); - - // the proof virtual targets - M proofs - let mut vir_proofs = vec![]; - let mut pub_input = vec![]; - let mut inner_vd_hashes = vec![]; - for _i in 0..M { - let vir_proof = builder.add_virtual_proof_with_pis(&inner_common); - let inner_pub_input = vir_proof.public_inputs.clone(); - vir_proofs.push(vir_proof); - pub_input.extend_from_slice(&inner_pub_input[0..4]); - inner_vd_hashes.extend_from_slice(&inner_pub_input[4..8]); - } - - // hash the public input & make it public - let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(pub_input); - builder.register_public_inputs(&hash_inner_pub_input.elements); - - // virtual target for the verifier data - let inner_verifier_data = builder.add_virtual_verifier_data(inner_common.config.fri_config.cap_height); - - // register verifier data hash as public input. H(H_l, H_l, H_n) -> public input - let mut vd_pub_input = vec![]; - vd_pub_input.extend_from_slice(&inner_verifier_data.circuit_digest.elements); - for i in 0..builder.config.fri_config.num_cap_elements() { - vd_pub_input.extend_from_slice(&inner_verifier_data.constants_sigmas_cap.0[i].elements); - } - let vd_hash = builder.hash_n_to_hash_no_pad::(vd_pub_input); - inner_vd_hashes.extend_from_slice(&vd_hash.elements); - let vd_hash_all = builder.hash_n_to_hash_no_pad::(inner_vd_hashes); - builder.register_public_inputs(&vd_hash_all.elements); - - // verify the proofs in-circuit - M proofs - for i in 0..M { - builder.verify_proof::(&vir_proofs[i], &inner_verifier_data, &inner_common); - } - - // let proofs = vec_to_array::<2, ProofWithPublicInputsTarget>(vir_proofs)?; - - // return targets - let t = NodeTargets { - leaf_proofs: vir_proofs, - verifier_data: inner_verifier_data, - }; - Ok(t) - - } - - /// assign the leaf targets with given input - pub fn assign_targets( - &self, pw: &mut PartialWitness, - targets: &NodeTargets, - node_proofs: &[ProofWithPublicInputs], - verifier_only_data: &VerifierOnlyCircuitData, - ) -> Result<()> { - // assert size of proofs vec - assert_eq!(node_proofs.len(), M); - - // assign the proofs - for i in 0..M { - pw.set_proof_with_pis_target(&targets.leaf_proofs[i], &node_proofs[i]) - .map_err(|e| { - CircuitError::ProofTargetAssignmentError("inner-proof".to_string(), e.to_string()) - })?; - } - - // assign the verifier data - pw.set_verifier_data_target(&targets.verifier_data, &verifier_only_data) - .map_err(|e| { - CircuitError::VerifierDataTargetAssignmentError(e.to_string()) - })?; - - Ok(()) - } - - /// returns the leaf circuit data - pub fn get_circuit_data (&self) -> Result> - where - >::Hasher: AlgebraicHasher - { - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - - self.build(&mut builder)?; - - let circ_data = builder.build::(); - - Ok(circ_data) - } - -} - - diff --git a/recursion_experiments/recursion/uniform/tree.rs b/recursion_experiments/recursion/uniform/tree.rs deleted file mode 100644 index 5924ccb..0000000 --- a/recursion_experiments/recursion/uniform/tree.rs +++ /dev/null @@ -1,252 +0,0 @@ -use std::marker::PhantomData; -use plonky2::hash::hash_types::{HashOut, RichField}; -use plonky2::iop::witness::PartialWitness; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitData, VerifierOnlyCircuitData}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2::plonk::proof::ProofWithPublicInputs; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::recursion::circuits::inner_circuit::InnerCircuit; -use plonky2_field::extension::Extendable; -use crate::{error::CircuitError, Result}; -use crate::recursion::uniform::{leaf::{LeafTargets,LeafCircuit},node::{NodeTargets,NodeCircuit}}; - -/// tree recursion -pub struct TreeRecursion< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - H: AlgebraicHasher, - const N: usize, - const M: usize, -> where - >::Hasher: AlgebraicHasher -{ - leaf: LeafCircuit, - node: NodeCircuit, - leaf_circ_data: CircuitData, - node_circ_data: CircuitData, - leaf_targets: LeafTargets, - node_targets: NodeTargets, - phantom_data: PhantomData<(H)> -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - H: AlgebraicHasher, - const N: usize, - const M: usize, -> TreeRecursion where - >::Hasher: AlgebraicHasher -{ - - pub fn build( - inner_common_data: CommonCircuitData - ) -> Result { - // build leaf with standard recursion config - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - let leaf = LeafCircuit::<_,D,_,_,N>::new(inner_common_data.clone()); - let leaf_targets = leaf.build(&mut builder)?; - let leaf_circ_data = builder.build::(); - // println!("leaf circuit size = {:?}", leaf_circ_data.common.degree_bits()); - - // build node with standard recursion config - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - let node = NodeCircuit::<_,D,_,_,M>::new(leaf_circ_data.common.clone()); - let node_targets = node.build(&mut builder)?; - let node_circ_data = builder.build::(); - // println!("node circuit size = {:?}", node_circ_data.common.degree_bits()); - - Ok(Self{ - leaf, - node, - leaf_circ_data, - node_circ_data, - leaf_targets, - node_targets, - phantom_data: Default::default(), - }) - } - - pub fn get_leaf_verifier_data(&self) -> VerifierCircuitData{ - self.leaf_circ_data.verifier_data() - } - - pub fn get_node_verifier_data(&self) -> VerifierCircuitData{ - self.node_circ_data.verifier_data() - } - - pub fn prove_tree - ( - &mut self, - proofs_with_pi: &[ProofWithPublicInputs], - inner_verifier_only_data: &VerifierOnlyCircuitData, - ) -> Result<(ProofWithPublicInputs)> - { - if proofs_with_pi.len() % 2 != 0 { - return - Err(CircuitError::RecursionTreeError(format!( - "input proofs must be divisible by {}, got {}", 2, proofs_with_pi.len()) - )) - } - // process leaves - let leaf_proofs = self.get_leaf_proofs( - proofs_with_pi, - inner_verifier_only_data, - )?; - - // process nodes - let (root_proof, vd) = - self.prove(&leaf_proofs,&self.leaf_circ_data.verifier_only)?; - - Ok(root_proof) - } - - fn get_leaf_proofs - ( - &mut self, - proofs_with_pi: &[ProofWithPublicInputs], - inner_verifier_only_data: &VerifierOnlyCircuitData, - ) -> Result<(Vec>)> { - - let mut leaf_proofs = vec![]; - - for proof in proofs_with_pi.chunks(N){ - let mut pw = PartialWitness::::new(); - - self.leaf.assign_targets(&mut pw,&self.leaf_targets,proof,inner_verifier_only_data)?; - let proof = self.leaf_circ_data.prove(pw).unwrap(); - leaf_proofs.push(proof); - } - - Ok(leaf_proofs) - } - - /// generates a proof - fn prove( - &self, - proofs_with_pi: &[ProofWithPublicInputs], - verifier_only_data: &VerifierOnlyCircuitData, - ) -> Result<(ProofWithPublicInputs, VerifierOnlyCircuitData)> where - >::Hasher: AlgebraicHasher - { - - if proofs_with_pi.len() == 1 { - return Ok((proofs_with_pi[0].clone(), verifier_only_data.clone())); - } - - let mut new_proofs = vec![]; - - for chunk in proofs_with_pi.chunks(M) { - - let mut inner_pw = PartialWitness::new(); - - self.node.assign_targets( - &mut inner_pw, - &self.node_targets, - chunk, - verifier_only_data, - )?; - - let proof = self.node_circ_data.prove(inner_pw) - .map_err(|e| CircuitError::ProofGenerationError(e.to_string()))?; - new_proofs.push(proof); - } - - self.prove(&new_proofs, &self.node_circ_data.verifier_only) - } - - pub fn verify_proof_and_public_input( - &self, - proof: ProofWithPublicInputs, - inner_public_input: Vec>, - inner_verifier_data: &VerifierCircuitData) -> Result<()> - { - let public_input = proof.public_inputs.clone(); - self.node_circ_data.verify(proof) - .map_err(|e| CircuitError::InvalidProofError(e.to_string()))?; - self.verify_public_input(public_input, inner_public_input, inner_verifier_data) - } - - pub fn verify_public_input(&self, public_input: Vec, inner_public_input: Vec>, inner_verifier_data: &VerifierCircuitData) -> Result<()>{ - assert_eq!(public_input.len(), 8); - - let given_input_hash = &public_input[0..4]; - let given_vd_hash = &public_input[4..8]; - - let inner_hash = Self::get_hash_of_verifier_data(&inner_verifier_data); - - let leaf_hash = Self::get_hash_of_verifier_data(&self.leaf_circ_data.verifier_data()); - - let node_hash = Self::get_hash_of_verifier_data(&self.node_circ_data.verifier_data()); - - - let mut pub_in_hashes = vec![]; - let mut inner_vd_hashes = vec![]; - for pub_in in inner_public_input.chunks(N){ - let pub_in_flat: Vec = pub_in - .iter() - .flat_map(|v| v.iter().cloned()) - .collect(); - let hash = H::hash_no_pad(&pub_in_flat); - pub_in_hashes.push(hash); - inner_vd_hashes.push(inner_hash.clone()); - } - - let mut level = 0; - while pub_in_hashes.len() > 1 { - let mut next_level_pi_hashes = Vec::new(); - let mut next_level_vd_hashes = Vec::new(); - for (pi_chunk, vd_chunk) in pub_in_hashes.chunks(M).zip(inner_vd_hashes.chunks(M)) { - // collect field elements - let pi_chunk_f: Vec = pi_chunk.iter() - .flat_map(|h| h.elements.iter().cloned()) - .collect(); - let mut vd_chunk_f: Vec = vd_chunk.iter() - .flat_map(|h| h.elements.iter().cloned()) - .collect(); - let hash_n = if level == 0 {leaf_hash} else{node_hash}; - vd_chunk_f.extend_from_slice(&hash_n.elements); - - // Compute Poseidon2 hash of the concatenated chunk - let pi_hash = H::hash_no_pad(&pi_chunk_f); - let vd_hash = H::hash_no_pad(&vd_chunk_f); - next_level_pi_hashes.push(pi_hash); - next_level_vd_hashes.push(vd_hash); - } - pub_in_hashes = next_level_pi_hashes; - inner_vd_hashes = next_level_vd_hashes; - level +=1; - } - - //check expected hash - let expected_pi_hash = pub_in_hashes[0]; - let expected_vd_hash = inner_vd_hashes[0]; - - assert_eq!(given_input_hash, expected_pi_hash.elements); - assert_eq!(given_vd_hash, expected_vd_hash.elements); - Ok(()) - } - - /// helper fn to generate hash of verifier data - fn get_hash_of_verifier_data(verifier_data: &VerifierCircuitData) -> HashOut{ - let mut vd = vec![]; - let digest: &HashOut = &verifier_data.verifier_only.circuit_digest; - let caps = &verifier_data.verifier_only.constants_sigmas_cap; - vd.extend_from_slice(&digest.elements); - for i in 0..verifier_data.common.config.fri_config.num_cap_elements() { - let cap_hash = caps.0[i] as HashOut; - vd.extend_from_slice(&cap_hash.elements); - } - - H::hash_no_pad(&vd) - } - -} - diff --git a/recursion_experiments/recursion/utils/conditional_verifier.rs b/recursion_experiments/recursion/utils/conditional_verifier.rs deleted file mode 100644 index 2956e67..0000000 --- a/recursion_experiments/recursion/utils/conditional_verifier.rs +++ /dev/null @@ -1,121 +0,0 @@ -use plonky2::gates::noop::NoopGate; -use plonky2::hash::hash_types::RichField; -use plonky2::iop::target::BoolTarget; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitData, CommonCircuitData, VerifierCircuitTarget}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2::plonk::proof::ProofWithPublicInputsTarget; -use plonky2_field::extension::Extendable; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; - -/// this takes verifier data (not public) and doesn't check the verifier data for consistency -pub fn conditionally_verify_recursion_proof_or_dummy + Poseidon2, const D: usize ,C: GenericConfig + 'static>( - builder: &mut CircuitBuilder, - condition: BoolTarget, - cyclic_proof_with_pis: &ProofWithPublicInputsTarget, - verifier_data: &VerifierCircuitTarget, - common_data: &CommonCircuitData, -) -> anyhow::Result<()> - where - C::Hasher: AlgebraicHasher, -{ - let (dummy_proof_with_pis_target, dummy_verifier_data_target) = - dummy_proof_and_vk_no_generator::(builder, common_data)?; - - // TODO: make verifier data public - // // Connect previous verifier data to current one. This guarantees that every proof in the cycle uses the same verifier data. - // self.connect_hashes( - // inner_cyclic_pis.circuit_digest, - // verifier_data.circuit_digest, - // ); - // self.connect_merkle_caps( - // &inner_cyclic_pis.constants_sigmas_cap, - // &verifier_data.constants_sigmas_cap, - // ); - - // Verify the cyclic proof if `condition` is set to true, otherwise verify the other proof. - builder.conditionally_verify_proof::( - condition, - cyclic_proof_with_pis, - verifier_data, - &dummy_proof_with_pis_target, - &dummy_verifier_data_target, - common_data, - ); - - // Make sure we have every gate to match `common_data`. - for g in &common_data.gates { - builder.add_gate_to_gate_set(g.clone()); - } - - Ok(()) -} - -/// Conditionally verify a proof with a new generated dummy proof. -pub fn conditionally_verify_proof_or_dummy + Poseidon2, const D: usize ,C: GenericConfig + 'static>( - builder: &mut CircuitBuilder, - condition: BoolTarget, - proof_with_pis: &ProofWithPublicInputsTarget, - inner_verifier_data: &VerifierCircuitTarget, - inner_common_data: &CommonCircuitData, -) -> anyhow::Result<()> - where - C::Hasher: AlgebraicHasher, -{ - let (dummy_proof_with_pis_target, dummy_verifier_data_target) = - dummy_proof_and_vk_no_generator::(builder, inner_common_data)?; - builder.conditionally_verify_proof::( - condition, - proof_with_pis, - inner_verifier_data, - &dummy_proof_with_pis_target, - &dummy_verifier_data_target, - inner_common_data, - ); - Ok(()) -} - -/// Generate a circuit matching a given `CommonCircuitData`. -pub(crate) fn dummy_circuit + Poseidon2, C: GenericConfig, const D: usize>( - common_data: &CommonCircuitData, -) -> CircuitData { - let config = common_data.config.clone(); - assert!( - !common_data.config.zero_knowledge, - "Degree calculation can be off if zero-knowledge is on." - ); - - // Number of `NoopGate`s to add to get a circuit of size `degree` in the end. - // Need to account for public input hashing, a `PublicInputGate` and a `ConstantGate`. - let degree = common_data.degree(); - let num_noop_gate = degree - common_data.num_public_inputs.div_ceil(8) - 2; - - let mut builder = CircuitBuilder::::new(config); - for _ in 0..num_noop_gate { - builder.add_gate(NoopGate, vec![]); - } - for gate in &common_data.gates { - builder.add_gate_to_gate_set(gate.clone()); - } - for _ in 0..common_data.num_public_inputs { - builder.add_virtual_public_input(); - } - - let circuit = builder.build::(); - assert_eq!(&circuit.common, common_data); - circuit -} - -pub(crate) fn dummy_proof_and_vk_no_generator + Poseidon2, const D: usize ,C: GenericConfig + 'static> ( - builder: &mut CircuitBuilder, - common_data: &CommonCircuitData, -) -> anyhow::Result<(ProofWithPublicInputsTarget, VerifierCircuitTarget)> - where - C::Hasher: AlgebraicHasher, -{ - let dummy_circuit = dummy_circuit::(common_data); - let dummy_proof_with_pis_target = builder.add_virtual_proof_with_pis(common_data); - let dummy_verifier_data_target = builder.constant_verifier_data(&dummy_circuit.verifier_only); - - Ok((dummy_proof_with_pis_target, dummy_verifier_data_target)) -} diff --git a/recursion_experiments/recursion/utils/dummy_gen.rs b/recursion_experiments/recursion/utils/dummy_gen.rs deleted file mode 100644 index 7b412d6..0000000 --- a/recursion_experiments/recursion/utils/dummy_gen.rs +++ /dev/null @@ -1,79 +0,0 @@ -use std::marker::PhantomData; -use plonky2::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; -use plonky2::plonk::proof::{ProofWithPublicInputs}; -use plonky2::recursion::dummy_circuit::{dummy_proof}; -use crate::recursion::utils::conditional_verifier::dummy_circuit; -use hashbrown::HashMap; -use plonky2::hash::hash_types::{ RichField}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2_field::extension::Extendable; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use crate::{error::CircuitError, Result}; -use crate::circuits::utils::vec_to_array; - -/// A generator for creating dummy proofs. -pub struct DummyProofGen< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, - > where - >::Hasher: AlgebraicHasher -{ - phantom_data: PhantomData<(F,C)>, -} - -impl< - F: RichField + Extendable + Poseidon2, - const D: usize, - C: GenericConfig, -> DummyProofGen - where - >::Hasher: AlgebraicHasher -{ - - /// Generates a single dummy leaf proof. - pub fn gen_dummy_leaf_proof( - common_data: &CommonCircuitData, - ) -> Result> { - dummy_proof::(&dummy_circuit::(common_data), HashMap::new()) - .map_err(|e| CircuitError::DummyProofGenerationError(e.to_string())) - } - - /// Generates a single dummy node proof. - pub fn get_dummy_node_proof( - node_common: &CommonCircuitData, - node_verifier_only_data: &VerifierOnlyCircuitData, - ) -> ProofWithPublicInputs { - Self::recursion_base_proof(node_common, HashMap::new()) - } - - fn recursion_base_proof( - common_data: &CommonCircuitData, - mut nonzero_public_inputs: HashMap - ) -> ProofWithPublicInputs{ - dummy_proof::( - &dummy_circuit::(common_data), - nonzero_public_inputs, - ) - .unwrap() - } - - /// Generates an array of `N` dummy leaf proofs. - pub fn gen_n_dummy_leaf_proofs( - common_data: &CommonCircuitData, - ) -> Result<[ProofWithPublicInputs; N]> { - let dummy_proof = Self::gen_dummy_leaf_proof(common_data)?; - let n_dummy_vec = (0..N).map(|_| dummy_proof.clone()).collect::>(); - vec_to_array::>(n_dummy_vec) - } - - /// Generates an array of `N` dummy node proofs. - pub fn gen_n_dummy_node_proofs( - node_common: &CommonCircuitData, - node_verifier_only_data: &VerifierOnlyCircuitData, - ) -> Result<[ProofWithPublicInputs; N]> { - let dummy_proof = Self::get_dummy_node_proof(node_common, node_verifier_only_data); - let n_dummy_vec = (0..N).map(|_| dummy_proof.clone()).collect::>(); - vec_to_array::>(n_dummy_vec) - } -} diff --git a/recursion_experiments/recursion/utils/mod.rs b/recursion_experiments/recursion/utils/mod.rs deleted file mode 100644 index 09b3dd3..0000000 --- a/recursion_experiments/recursion/utils/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod dummy_gen; -pub mod conditional_verifier; diff --git a/recursion_experiments/tests/cyclic_recursion.rs b/recursion_experiments/tests/cyclic_recursion.rs deleted file mode 100644 index 9ac7c6f..0000000 --- a/recursion_experiments/tests/cyclic_recursion.rs +++ /dev/null @@ -1,104 +0,0 @@ -// some tests for cyclic recursion - -#[cfg(test)] -mod tests { - use std::time::Instant; - use anyhow::Result; - use plonky2::hash::hash_types::HashOut; - use plonky2::hash::hashing::hash_n_to_hash_no_pad; - use plonky2::hash::poseidon::PoseidonPermutation; - use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::CircuitConfig; - use plonky2::plonk::config::GenericConfig; - use crate::params::{F, D, C, HF}; - use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; - use crate::gen_input::gen_testing_circuit_input; - use crate::params::Params; - use codex_plonky2_circuits::recursion::cyclic::CyclicCircuit; - - - /// Uses cyclic recursion to sample the dataset - #[test] - fn test_cyclic_recursion() -> Result<()> { - - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - let one = builder.one(); - - - let mut params = Params::default(); - let inner_sampling_circuit = SamplingRecursion::::new(params.circuit_params); - let circ_input = gen_testing_circuit_input::(¶ms.input_params); - - let s = Instant::now(); - let mut cyclic_circ = CyclicCircuit::::build_circuit::(inner_sampling_circuit)?; - println!("build = {:?}", s.elapsed()); - let s = Instant::now(); - let proof = cyclic_circ.prove_one_layer(&circ_input)?; - println!("prove = {:?}", s.elapsed()); - println!("num of pi = {}", proof.public_inputs.len()); - println!("pub input: {:?}", proof.public_inputs); - let s = Instant::now(); - assert!( - cyclic_circ.verify_latest_proof().is_ok(), - "proof verification failed" - ); - println!("verify = {:?}", s.elapsed()); - - // check public input hash is correct - let mut hash_input = vec![]; - hash_input.push(circ_input.slot_index); - hash_input.extend_from_slice(&circ_input.dataset_root.elements); - hash_input.extend_from_slice(&circ_input.entropy.elements); - - let hash_res = hash_n_to_hash_no_pad::>(&hash_input); - let zero_hash = HashOut::::ZERO; - let mut hash_input2 = vec![]; - hash_input2.extend_from_slice(&hash_res.elements); - hash_input2.extend_from_slice(&zero_hash.elements); - let hash_res = hash_n_to_hash_no_pad::>(&hash_input2); - - println!("hash input = {:?}", hash_res.elements); - assert_eq!( - proof.public_inputs[0..4].to_vec(), - hash_res.elements.to_vec(), - "public input hash incorrect" - ); - - Ok(()) - } - - /// Uses cyclic recursion to sample the dataset n times - #[test] - fn test_cyclic_recursion_n_layers() -> Result<()> { - const N : usize = 2; - - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - let one = builder.one(); - - let mut params = Params::default(); - let inner_sampling_circuit = SamplingRecursion::::new(params.circuit_params); - let mut circ_inputs = vec![]; - for i in 0..N { - circ_inputs.push(gen_testing_circuit_input::(¶ms.input_params)); - } - - let s = Instant::now(); - let mut cyclic_circ = CyclicCircuit::::build_circuit::(inner_sampling_circuit)?; - println!("build = {:?}", s.elapsed()); - let s = Instant::now(); - let proof = cyclic_circ.prove_n_layers(circ_inputs)?; - println!("prove = {:?}", s.elapsed()); - println!("num of pi = {}", proof.public_inputs.len()); - println!("pub input: {:?}", proof.public_inputs); - let s = Instant::now(); - assert!( - cyclic_circ.verify_latest_proof().is_ok(), - "proof verification failed" - ); - println!("verify = {:?}", s.elapsed()); - - Ok(()) - } -} \ No newline at end of file diff --git a/recursion_experiments/tests/hybrid.rs b/recursion_experiments/tests/hybrid.rs deleted file mode 100644 index 8334149..0000000 --- a/recursion_experiments/tests/hybrid.rs +++ /dev/null @@ -1,124 +0,0 @@ -// some tests for approach 2 of the tree recursion - -#[cfg(test)] -mod tests { - use std::time::Instant; - use plonky2::iop::witness::PartialWitness; - use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::CircuitConfig; - use plonky2::plonk::config::{GenericConfig, Hasher}; - use plonky2::plonk::proof::{ProofWithPublicInputs}; - 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::hybrid::tree_circuit::HybridTreeRecursion; - - - #[test] - fn test_hybrid_recursion() -> anyhow::Result<()> { - const N: usize = 2; // binary tree - const M: usize = 1; // number of proofs in leaves - const K: usize = 8; - - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - - //------------ sampling inner circuit ---------------------- - // Circuit that does the sampling - default input - let mut params = Params::default(); - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?; - let inner_data = sampling_builder.build::(); - println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); - let inner_proof = inner_data.prove(pw)?; - - // ------------------- leaf -------------------- - // leaf circuit that verifies the sampling proof - let inner_circ = SamplingRecursion::::new(Params::default().circuit_params); - let leaf_circuit = LeafCircuit::::new(inner_circ); - - // ------------- tree circuit ------------------ - - let mut tree = HybridTreeRecursion::::new(leaf_circuit); - - // prepare input - let input_proofs: Vec> = (0..K) - .map(|_| { - inner_proof.clone() - }) - .collect::>(); - - // prove tree - - let s = Instant::now(); - let (tree_root_proof, verifier_data) = tree.prove_tree::(&input_proofs, inner_data.verifier_data())?; - println!("prove = {:?}", s.elapsed()); - println!("num of pi = {}", tree_root_proof.public_inputs.len()); - let s = Instant::now(); - assert!( - verifier_data.verify(tree_root_proof.clone()).is_ok(), - "proof verification failed" - ); - - assert_eq!( - tree_root_proof.public_inputs[0..4].to_vec(), - get_expected_tree_root_pi_hash::(input_proofs), - "Public input of tree_root_proof does not match the expected root hash" - ); - println!("verify = {:?}", s.elapsed()); - - Ok(()) - } - - // ------------ Public Input Verification ------------ - /// Recompute the expected root public input hash outside the circuit - fn get_expected_tree_root_pi_hash(input_proofs: Vec>) -> Vec{ - // Compute the leaf hashes - - let mut current_hashes = vec![]; - for chunk in input_proofs.chunks(M){ - let chunk_f: Vec = chunk.iter() - .flat_map(|p| p.public_inputs.iter().cloned()) - .collect(); - - let hash = HF::hash_no_pad(&chunk_f); - current_hashes.push(hash); - } - - // compute parent hashes until one root hash remains - while current_hashes.len() > 1 { - let mut next_level_hashes = Vec::new(); - - for chunk in current_hashes.chunks(N) { - // Ensure each chunk has exactly N elements - assert!( - chunk.len() == N, - "Number of proofs is not divisible by N" - ); - - // collect field elements - let chunk_f: Vec = chunk.iter() - .flat_map(|h| h.elements.iter().cloned()) - .collect(); - - // Compute Poseidon2 hash of the concatenated chunk - let hash = HF::hash_no_pad(&chunk_f); - next_level_hashes.push(hash); - } - - current_hashes = next_level_hashes; - } - - //the expected root hash - current_hashes[0].elements.to_vec() - } -} \ No newline at end of file diff --git a/recursion_experiments/tests/mod.rs b/recursion_experiments/tests/mod.rs deleted file mode 100644 index d91a328..0000000 --- a/recursion_experiments/tests/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod simple_recursion; -pub mod simple_tree; -pub mod cyclic_recursion; -pub mod tree1; -pub mod tree2; -mod hybrid; -mod uniform; \ No newline at end of file diff --git a/recursion_experiments/tests/simple_recursion.rs b/recursion_experiments/tests/simple_recursion.rs deleted file mode 100644 index 72bc43b..0000000 --- a/recursion_experiments/tests/simple_recursion.rs +++ /dev/null @@ -1,162 +0,0 @@ -// tests for simple recursion approaches - -use std::time::Instant; -use plonky2::hash::hash_types::{HashOut, NUM_HASH_OUT_ELTS}; -use plonky2::iop::witness::PartialWitness; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData}; -use plonky2::plonk::config::AlgebraicHasher; -use plonky2_field::types::Field; -use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; -use codex_plonky2_circuits::recursion::simple::simple_recursion::{SimpleRecursionCircuit, SimpleRecursionInput}; -use codex_plonky2_circuits::recursion::simple::simple_recursion_hashed_pi::{SimpleRecursionCircuitHashedPI, SimpleRecursionInputHashedPI}; -use crate::gen_input::{build_circuit, prove_circuit}; -use crate::params::{C, D, F, HF, Params}; - - -// test the simple recursion approach -#[test] -pub fn test_simple_recursion()-> anyhow::Result<()>{ - // number of samples in each proof - let n_samples = 5; - // number of inner proofs: - const N_INNER: usize = 4; - let mut data: Option> = 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()); - - // careful here, the sampling recursion is the default so proofs should be for circuit - // with default params - let sampling_inner_circ = SamplingRecursion::::new(Params::default().circuit_params); - let rec_circuit = SimpleRecursionCircuit::::new(sampling_inner_circ); - - // Create the circuit - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::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::(); - println!("build time = {:?}", start.elapsed()); - println!("agg circuit size = {:?}", agg_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()); - println!("public input count = {:?}", proof.public_inputs.len()); - - // Verify the proof - let verifier_data = agg_data.verifier_data(); - assert!( - verifier_data.verify(proof).is_ok(), - "proof verification failed" - ); - - Ok(()) -} - -// test the simple recursion approach with hashed public input -#[test] -pub fn test_simple_recursion_with_hashed_pi()-> anyhow::Result<()>{ - // number of samples in each proof - let n_samples = 5; - // number of inner proofs: - const N_INNER: usize = 4; - let mut data: Option> = 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()); - - // careful here, the sampling recursion is the default so proofs should be for circuit - // with default params - let sampling_inner_circ = SamplingRecursion::::new(Params::default().circuit_params); - let rec_circuit = SimpleRecursionCircuitHashedPI::::new(sampling_inner_circ); - - // Create the circuit - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::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::(); - println!("build time = {:?}", start.elapsed()); - println!("agg circuit size = {:?}", agg_data.common.degree_bits()); - - let mut default_entropy = HashOut::ZERO; - default_entropy.elements[0] = F::from_canonical_u64(1234567); - - let w = SimpleRecursionInputHashedPI{ - proofs: proofs_with_pi.clone(), - verifier_data: data.verifier_data(), - }; - - rec_circuit.assign_witness(&mut pw,&targets,w)?; - - let start = Instant::now(); - let proof = agg_data.prove(pw)?; - println!("prove time = {:?}", start.elapsed()); - println!("public input count = {:?}", proof.public_inputs.len()); - - // Verify the proof - let verifier_data = agg_data.verifier_data(); - assert!( - verifier_data.verify(proof.clone()).is_ok(), - "proof verification failed" - ); - - let inner_pi: Vec = proofs_with_pi.iter() - .flat_map(|p| p.public_inputs.iter()) - .cloned() - .collect(); - - assert!( - check_agg_proof_hash::(inner_pi, proof.public_inputs), - "public input verification failed" - ); - - Ok(()) -} - -pub fn check_agg_proof_hash>(inner_pi: Vec, agg_pi: Vec) -> bool{ - - if agg_pi.len() != NUM_HASH_OUT_ELTS { - return false; - } - let expected = H::hash_no_pad(&inner_pi); - - expected == HashOut::from_vec(agg_pi) -} \ No newline at end of file diff --git a/recursion_experiments/tests/simple_tree.rs b/recursion_experiments/tests/simple_tree.rs deleted file mode 100644 index effe92b..0000000 --- a/recursion_experiments/tests/simple_tree.rs +++ /dev/null @@ -1,64 +0,0 @@ -// tests for simple recursion approaches - -use std::time::Instant; -use plonky2::plonk::circuit_data::{CircuitData}; -use crate::gen_input::{build_circuit, prove_circuit}; -use codex_plonky2_circuits::recursion::simple::simple_tree_recursion::aggregate_sampling_proofs_tree; -use crate::params::{C, D, F,HF}; - -// Test simple tree recursion -#[test] -fn test_simple_tree_recursion() -> anyhow::Result<()> { - // number of samples in each proof - let n_samples = 5; - // number of inner proofs: - let n_inner = 4; - let mut data: Option> = 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()); - // serialization - // let gate_serializer = DefaultGateSerializer; - // let generator_serializer =DefaultGeneratorSerializer::::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.verifier_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()); - - // serialization - // // let gate_serializer = DefaultGateSerializer; - // // let generator_serializer =DefaultGeneratorSerializer::::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(()) -} diff --git a/recursion_experiments/tests/tree1.rs b/recursion_experiments/tests/tree1.rs deleted file mode 100644 index 1f4b6c9..0000000 --- a/recursion_experiments/tests/tree1.rs +++ /dev/null @@ -1,165 +0,0 @@ -// some tests for approach 1 of the tree recursion - -#[cfg(test)] -mod tests { - use std::time::Instant; - use plonky2::plonk::config::{GenericConfig, GenericHashOut, Hasher}; - use plonky2_field::types::Field; - use codex_plonky2_circuits::circuits::sample_cells::SampleCircuitInput; - use crate::params::{C, D, F, HF, Params}; - use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; - use codex_plonky2_circuits::recursion::circuits::inner_circuit::InnerCircuit; - use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; - use crate::gen_input::get_m_default_circ_input; - use codex_plonky2_circuits::recursion::tree1::tree_circuit::TreeRecursion; - - /// Uses node recursion to sample the dataset - #[test] - fn test_tree1_node_recursion() -> anyhow::Result<()> { - const M: usize = 1; - const N: usize = 2; - - let default_params = Params::default().circuit_params; - let inner_sampling_circuit = SamplingRecursion::::new(default_params); - - let circ_input = get_m_default_circ_input::(); - - let s = Instant::now(); - let mut tree_circ = TreeRecursion::::build::(inner_sampling_circuit)?; - println!("build = {:?}", s.elapsed()); - println!("tree circuit size = {:?}", tree_circ.node_circ.cyclic_circuit_data.common.degree_bits()); - let s = Instant::now(); - let proof = tree_circ.prove(&circ_input,None, true)?; - println!("prove = {:?}", s.elapsed()); - println!("num of pi = {}", proof.public_inputs.len()); - let s = Instant::now(); - assert!( - tree_circ.verify_proof(proof).is_ok(), - "proof verification failed" - ); - println!("verify = {:?}", s.elapsed()); - - Ok(()) - } - - /// Uses node recursion to sample the dataset - #[test] - fn test_tree_recursion_approach1() -> anyhow::Result<()> { - const M: usize = 1; - const N: usize = 2; - - const DEPTH: usize = 3; - const TOTAL_INPUT: usize = (N.pow(DEPTH as u32) - 1) / (N - 1); - - let default_params = Params::default().circuit_params; - let inner_sampling_circuit = SamplingRecursion::::new(default_params); - - let all_circ_input = get_m_default_circ_input::().to_vec(); - - let s = Instant::now(); - let mut tree_circ = TreeRecursion::::build::(inner_sampling_circuit)?; - println!("build = {:?}", s.elapsed()); - println!("tree circuit size = {:?}", tree_circ.node_circ.cyclic_circuit_data.common.degree_bits()); - let s = Instant::now(); - let proof = tree_circ.prove_tree(all_circ_input.clone(),DEPTH)?; - println!("prove = {:?}", s.elapsed()); - println!("num of pi = {}", proof.public_inputs.len()); - - // Extract the final public input hash from the proof - let final_proof_hash = &proof.public_inputs[0..4]; - - // Recompute the expected final public input hash (outside the circuit) - let expected_hash = compute_expected_pub_input_hash( - &all_circ_input, - DEPTH, - M, - N - )?; - - // Check that the final hash in the proof matches the expected hash - assert_eq!(final_proof_hash, expected_hash.as_slice(), "Public input hash mismatch"); - - let s = Instant::now(); - assert!( - tree_circ.verify_proof(proof).is_ok(), - "proof verification failed" - ); - println!("verify = {:?}", s.elapsed()); - - Ok(()) - } - - /// Recursively compute the final public input hash for a single node in the recursion tree. - /// This is the same logic from `NodeCircuit::build_circuit` - /// TODO: optimize this - fn compute_node_hash( - all_circ_inputs: &[SampleCircuitInput], - depth: usize, - current_depth: usize, - node_idx: usize, - M: usize, - N: usize, - ) -> [F; 4] { - // Calculate the index in all_circ_inputs for this node's M inputs. - // Total inputs per layer: sum_{k=0}^{current_depth-1} M*N^k = M * ((N^current_depth - 1)/(N-1)) - let offset_for_layer = ((N.pow(current_depth as u32) - 1) / (N - 1)) * M; - let node_start = offset_for_layer + node_idx * M; - let node_inputs = &all_circ_inputs[node_start..node_start + M]; - - // Compute the outer public input hash: - // public inputs are [slot_index, dataset_root.elements, entropy.elements]. - let mut outer_pi_hashes = vec![]; - for inp in node_inputs { - let mut pi_vec = vec![inp.slot_index]; - pi_vec.extend_from_slice(&inp.dataset_root.elements); - pi_vec.extend_from_slice(&inp.entropy.elements); - let hash_res = HF::hash_no_pad(&pi_vec); - outer_pi_hashes.extend_from_slice(&hash_res.elements); - } - - // hash all these M hashes into one - let outer_pi_hash = HF::hash_no_pad(&outer_pi_hashes); - - let is_leaf = current_depth == depth - 1; - - // Compute the inner proof hash (or zero hash if leaf) - let inner_pi_hash_or_zero = if is_leaf { - // condition = false at leaf, so inner proofs = zero hash - [F::ZERO; 4] - } else { - // condition = true at non-leaf node -> recursively compute child hashes - let next_depth = current_depth + 1; - let child_start = node_idx * N; - - let mut inner_pub_input_hashes = vec![]; - for i in child_start..child_start + N { - let child_hash = compute_node_hash(all_circ_inputs, depth, next_depth, i, M, N); - inner_pub_input_hashes.extend_from_slice(&child_hash); - } - - let inner_pub_input_hash = HF::hash_no_pad(&inner_pub_input_hashes); - inner_pub_input_hash.elements - }; - - // Combine outer_pi_hash and inner_pi_hash_or_zero - let mut final_input = vec![]; - final_input.extend_from_slice(&outer_pi_hash.elements); - final_input.extend_from_slice(&inner_pi_hash_or_zero); - - let final_hash = HF::hash_no_pad(&final_input); - final_hash.elements - } - - /// Compute the expected public input hash for the entire recursion tree. - /// This function calls `compute_node_hash` starting from the root (layer 0, node 0). - pub fn compute_expected_pub_input_hash( - all_circ_inputs: &[SampleCircuitInput], - depth: usize, - M: usize, - N: usize, - ) -> anyhow::Result> { - // The root node is at layer = 0 and node_idx = 0 - let final_hash = compute_node_hash(all_circ_inputs, depth, 0, 0, M, N); - Ok(final_hash.to_vec()) - } -} \ No newline at end of file diff --git a/recursion_experiments/tests/tree2.rs b/recursion_experiments/tests/tree2.rs deleted file mode 100644 index 53744b4..0000000 --- a/recursion_experiments/tests/tree2.rs +++ /dev/null @@ -1,198 +0,0 @@ -// some tests for approach 2 of the tree recursion - -#[cfg(test)] -mod tests { - use std::time::Instant; - use plonky2::hash::hash_types::HashOut; - use plonky2::iop::witness::PartialWitness; - use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::CircuitConfig; - use plonky2::plonk::config::{GenericConfig, Hasher}; - use plonky2::plonk::proof::{ProofWithPublicInputs}; - 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, LeafInput}; - // 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::tree2::{tree_circuit::TreeRecursion}; - - - /// Uses node recursion to sample the dataset - #[test] - fn test_leaf_circuit() -> anyhow::Result<()> { - const M: usize = 1; - const N: usize = 2; - - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - let params = Params::default(); - - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut builder)?; - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input); - let inner_d = builder.build::(); - let inner_prf = inner_d.prove(pw)?; - - let leaf_in = LeafInput::{ - inner_proof:[inner_prf; M], - verifier_data: inner_d.verifier_data(), - }; - let config2 = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config2); - - let inner_circ = SamplingRecursion::::new(Params::default().circuit_params); - let leaf_circuit = LeafCircuit::::new(inner_circ); - - let s = Instant::now(); - let leaf_tar = leaf_circuit.build::(&mut builder)?; - let circ_data = builder.build::(); - println!("build = {:?}", s.elapsed()); - println!("sampling circuit size = {:?}", circ_data.common.degree_bits()); - let s = Instant::now(); - let mut pw = PartialWitness::::new(); - leaf_circuit.assign_targets::(&mut pw, &leaf_tar, &leaf_in)?; - let proof = circ_data.prove(pw)?; - println!("prove = {:?}", s.elapsed()); - println!("num of pi = {}", proof.public_inputs.len()); - let s = Instant::now(); - assert!( - circ_data.verify(proof).is_ok(), - "proof verification failed" - ); - println!("verify = {:?}", s.elapsed()); - - Ok(()) - } - - #[test] - fn test_tree_recursion_approach2() -> anyhow::Result<()> { - const M: usize = 1; - const N: usize = 2; // binary tree - const K: usize = 2; // number of leaves/slots sampled - should be power of 2 - - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - - //------------ sampling inner circuit ---------------------- - // Circuit that does the sampling - default input - let mut params = Params::default(); - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?; - let inner_data = sampling_builder.build::(); - println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); - let inner_proof = inner_data.prove(pw)?; - - // ------------------- leaf -------------------- - // leaf circuit that verifies the sampling proof - let inner_circ = SamplingRecursion::::new(Params::default().circuit_params); - let leaf_circuit = LeafCircuit::::new(inner_circ); - - let leaf_in = LeafInput::{ - inner_proof:[inner_proof; M], - verifier_data: inner_data.verifier_data(), - }; - let config = CircuitConfig::standard_recursion_config(); - let mut leaf_builder = CircuitBuilder::::new(config); - // build - let s = Instant::now(); - let leaf_targets = leaf_circuit.build::(&mut leaf_builder)?; - let leaf_circ_data = leaf_builder.build::(); - println!("build = {:?}", s.elapsed()); - println!("leaf circuit size = {:?}", leaf_circ_data.common.degree_bits()); - // prove - let s = Instant::now(); - let mut pw = PartialWitness::::new(); - leaf_circuit.assign_targets::(&mut pw, &leaf_targets, &leaf_in)?; - let leaf_proof = leaf_circ_data.prove(pw)?; - println!("prove = {:?}", s.elapsed()); - println!("num of pi = {}", leaf_proof.public_inputs.len()); - // verify - let s = Instant::now(); - assert!( - leaf_circ_data.verify(leaf_proof.clone()).is_ok(), - "proof verification failed" - ); - println!("verify = {:?}", s.elapsed()); - - // ------------- tree circuit ------------------ - // node circuit that verifies leafs or itself - // build - let s = Instant::now(); - let mut tree = TreeRecursion::::build::<_,HF, M>(leaf_circuit)?; - println!("build = {:?}", s.elapsed()); - println!("node circuit degree bits = {:?}", tree.node.node_data.node_circuit_data.common.degree_bits()); - - // prove leaf - let s = Instant::now(); - let leaf_proofs: Vec> = (0..K) - .map(|_| { - leaf_proof.clone() - }) - .collect::>(); - - let tree_root_proof = tree.prove_tree(leaf_proofs.clone())?; - println!("prove = {:?}", s.elapsed()); - println!("num of pi = {}", tree_root_proof.public_inputs.len()); - let s = Instant::now(); - assert!( - tree.verify_proof(tree_root_proof.clone(),false).is_ok(), - "proof verification failed" - ); - - assert_eq!( - tree_root_proof.public_inputs[0..4].to_vec(), - get_expected_tree_root_pi_hash::(leaf_proofs), - "Public input of tree_root_proof does not match the expected root hash" - ); - println!("verify = {:?}", s.elapsed()); - - Ok(()) - } - - // ------------ Public Input Verification ------------ - /// Recompute the expected root public input hash outside the circuit - fn get_expected_tree_root_pi_hash(leaf_proofs: Vec>) - -> Vec{ - // Step 1: Extract relevant public inputs from each leaf proof - let mut current_hashes: Vec> = leaf_proofs - .iter() - .map(|p|HashOut::from_vec(p.public_inputs.clone())) // Adjust index if different - .collect(); - - // Step 2: Iteratively compute parent hashes until one root hash remains - while current_hashes.len() > 1 { - let mut next_level_hashes = Vec::new(); - - for chunk in current_hashes.chunks(N) { - // Ensure each chunk has exactly N elements - assert!( - chunk.len() == N, - "Number of proofs is not divisible by N" - ); - - // collect field elements - let chunk_f: Vec = chunk.iter() - .flat_map(|h| h.elements.iter().cloned()) - .collect(); - - // Compute Poseidon2 hash of the concatenated chunk - let hash = HF::hash_no_pad(&chunk_f); - next_level_hashes.push(hash); - } - - current_hashes = next_level_hashes; - } - - // The final hash is the expected root hash - current_hashes[0].elements.to_vec() - } -} \ No newline at end of file diff --git a/recursion_experiments/tests/uniform.rs b/recursion_experiments/tests/uniform.rs deleted file mode 100644 index 5acedc9..0000000 --- a/recursion_experiments/tests/uniform.rs +++ /dev/null @@ -1,67 +0,0 @@ -// some tests for approach 2 of the tree recursion - -#[cfg(test)] -mod tests { - use std::fs; - use plonky2::iop::witness::{PartialWitness}; - use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::{CircuitConfig}; - use plonky2::plonk::config::{ GenericConfig}; - use plonky2::plonk::proof::{ProofWithPublicInputs}; - use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit; - use crate::params::{F, D, C, HF}; - use crate::gen_input::gen_testing_circuit_input; - use crate::params::Params; - use codex_plonky2_circuits::recursion::uniform::{tree::TreeRecursion}; - - #[test] - fn test_uniform_recursion() -> anyhow::Result<()> { - - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - - //------------ sampling inner circuit ---------------------- - // Circuit that does the sampling - 100 samples - let mut params = Params::default(); - params.input_params.n_samples = 100; - params.circuit_params.n_samples = 100; - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?; - let inner_data = sampling_builder.build::(); - println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); - let inner_proof = inner_data.prove(pw)?; - - let proofs: Vec> = (0..16).map(|i| inner_proof.clone()).collect(); - - // ------------------- tree -------------------- - const N: usize = 1; - const M: usize = 4; - - let mut tree = TreeRecursion::::build(inner_data.common.clone())?; - - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&tree.get_leaf_verifier_data().common ).unwrap(); - fs::write("leaf_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&tree.get_node_verifier_data().common ).unwrap(); - fs::write("node_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - - let root = tree.prove_tree(&proofs, &inner_data.verifier_only)?; - println!("pub input size = {}", root.public_inputs.len()); - - let inner_pi: Vec> = proofs.iter().map(|p| p.public_inputs.clone()).collect(); - - assert!( - tree.verify_proof_and_public_input(root,inner_pi,&inner_data.verifier_data()).is_ok(), - "proof verification failed" - ); - - Ok(()) - } -} \ No newline at end of file diff --git a/recursion_experiments/tests/uniform_arch.rs b/recursion_experiments/tests/uniform_arch.rs deleted file mode 100644 index 0c91789..0000000 --- a/recursion_experiments/tests/uniform_arch.rs +++ /dev/null @@ -1,395 +0,0 @@ -// some tests for approach 2 of the tree recursion - -#[cfg(test)] -mod tests { - use std::fs; - use std::time::Instant; - use plonky2::gates::constant::ConstantGate; - use plonky2::iop::witness::{PartialWitness, WitnessWrite}; - use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; - use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher}; - use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; - use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit; - use crate::params::{F, D, C, HF}; - use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion; - // use codex_plonky2_circuits::recursion::circuits::inner_circuit::InnerCircuit; - // use codex_plonky2_circuits::recursion::circuits::leaf_circuit::{LeafCircuit}; - // use plonky2_poseidon2::poseidon2_hash::poseidon2::{Poseidon2, Poseidon2Hash}; - use crate::gen_input::gen_testing_circuit_input; - use crate::params::Params; - use codex_plonky2_circuits::recursion::uniform::{leaf::{LeafCircuit,LeafInput,LeafTargets},node::{NodeCircuit,NodeInput,NodeTargets}, tree::TreeRecursion}; - - #[test] - fn test_treeuniform() -> anyhow::Result<()> { - - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - - //------------ sampling inner circuit ---------------------- - // Circuit that does the sampling - default input - let mut params = Params::default(); - params.input_params.n_samples = 100; - params.circuit_params.n_samples = 100; - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?; - let inner_data = sampling_builder.build::(); - println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); - let inner_proof = inner_data.prove(pw)?; - - let proofs: Vec> = (0..4).map(|i| inner_proof.clone()).collect(); - - // ------------------- tree -------------------- - - let mut tree = TreeRecursion::::build(inner_data.common.clone())?; - - let root = tree.prove_tree(&proofs, inner_data.verifier_data())?; - - Ok(()) - } - - #[test] - fn test_2uniform() -> anyhow::Result<()> { - - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - - //------------ sampling inner circuit ---------------------- - // Circuit that does the sampling - default input - let mut params = Params::default(); - params.input_params.n_samples = 100; - params.circuit_params.n_samples = 100; - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?; - let inner_data = sampling_builder.build::(); - println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); - let inner_proof = inner_data.prove(pw)?; - - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&inner_data.common ).unwrap(); - fs::write("circ_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - - // ------------------- leaf -------------------- - - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - - let leaf_circ = LeafCircuit::::new(inner_data.common.clone()); - let leaf_targ = leaf_circ.build(&mut builder)?; - - // let (proof_targ, vd_targ) = build_proof_ver_circuit::(&mut builder,&inner_data.common).unwrap(); - // let leaf_targets = leaf_circuit.build::(&mut builder)?; - - // // add a ConstantGate - // builder.add_gate( - // ConstantGate::new(config.num_constants), - // vec![], - // ); - - let leaf_data = builder.build::(); - println!("leaf circuit size = {:?}", leaf_data.common.degree_bits()); - - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&leaf_data.common ).unwrap(); - fs::write("leaf_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - // prove - let mut pw = PartialWitness::::new(); - // pw.set_proof_with_pis_target(&proof_targ, &inner_proof)?; - // pw.set_verifier_data_target(&vd_targ,&inner_data.verifier_only)?; - let leaf_in = LeafInput{ - inner_proof: inner_proof.clone(), - verifier_data: inner_data.verifier_data().clone(), - }; - - leaf_circ.assign_targets(&mut pw, &leaf_targ, &leaf_in)?; - - let leaf_proof = leaf_data.prove(pw)?; - - leaf_data.verify(leaf_proof.clone())?; - - // ------------- node1 circuit ------------------ - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - let node_circ = NodeCircuit::::new(leaf_data.common.clone()); - let node_targ = node_circ.build(&mut builder)?; - - // let (proof_targ, vd_targ) = build_node_proof_circuit::(&mut builder,&leaf_data.common).unwrap(); - // let leaf_targets = leaf_circuit.build::(&mut builder)?; - - let node_data = builder.build::(); - println!("node circuit size = {:?}", node_data.common.degree_bits()); - - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&node_data.common ).unwrap(); - fs::write("node_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - // prove - let mut pw = PartialWitness::::new(); - // pw.set_proof_with_pis_target(&proof_targ[0], &leaf_proof)?; - // pw.set_proof_with_pis_target(&proof_targ[1], &leaf_proof)?; - // pw.set_verifier_data_target(&vd_targ,&leaf_data.verifier_only)?; - - let node_in = NodeInput{ - node_proofs: [leaf_proof.clone(),leaf_proof.clone()], - verifier_data: leaf_data.verifier_data(), - }; - - node_circ.assign_targets(&mut pw, &node_targ,&node_in)?; - - let node_proof = node_data.prove(pw)?; - - node_data.verify(node_proof.clone())?; - - - // ------------- check ---------------- - // prove - let mut pw = PartialWitness::::new(); - - let node_in = NodeInput{ - node_proofs: [node_proof.clone(),node_proof.clone()], - verifier_data: node_data.verifier_data(), - }; - - node_circ.assign_targets(&mut pw, &node_targ,&node_in)?; - - let node2_proof = node_data.prove(pw)?; - - node_data.verify(node2_proof.clone())?; - - - // ------------- node2 circuit ------------------ - // let config = CircuitConfig::standard_recursion_config(); - // let mut builder = CircuitBuilder::::new(config); - // - // let (proof_targ, vd_targ) = build_node_proof_circuit::(&mut builder,&node_data.common).unwrap(); - // // let leaf_targets = leaf_circuit.build::(&mut builder)?; - // - // let node2_data = builder.build::(); - // println!("node2 circuit size = {:?}", node2_data.common.degree_bits()); - // - // // serialize circuit into JSON - // let common_circuit_data_serialized = serde_json::to_string(&node2_data.common ).unwrap(); - // fs::write("node2_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - // - // // prove - // let mut pw = PartialWitness::::new(); - // pw.set_proof_with_pis_target(&proof_targ[0], &leaf_proof)?; - // pw.set_proof_with_pis_target(&proof_targ[1], &leaf_proof)?; - // pw.set_verifier_data_target(&vd_targ,&leaf_data.verifier_only)?; - // - // let node_proof = node2_data.prove(pw)?; - - - // prove node - // let mut pw = PartialWitness::::new(); - // pw.set_proof_with_pis_target(&proof_targ[0], &node_proof)?; - // pw.set_proof_with_pis_target(&proof_targ[1], &node_proof)?; - // pw.set_verifier_data_target(&vd_targ,&node_data.verifier_only)?; - // - // let node2_proof = node_data.prove(pw)?; - - - Ok(()) - } - - #[test] - fn test_uniform_recursion() -> anyhow::Result<()> { - // const N: usize = 2; // binary tree - // const M: usize = 1; // number of proofs in leaves - // const K: usize = 8; - - let config = CircuitConfig::standard_recursion_config(); - let mut sampling_builder = CircuitBuilder::::new(config); - - //------------ sampling inner circuit ---------------------- - // Circuit that does the sampling - default input - let mut params = Params::default(); - params.input_params.n_samples = 100; - params.circuit_params.n_samples = 100; - let one_circ_input = gen_testing_circuit_input::(¶ms.input_params); - let samp_circ = SampleCircuit::::new(params.circuit_params); - let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?; - // get generate a sampling proof - let mut pw = PartialWitness::::new(); - samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?; - let inner_data = sampling_builder.build::(); - println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits()); - let inner_proof = inner_data.prove(pw)?; - - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&inner_data.common ).unwrap(); - fs::write("circ_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - - // ------------------- leaf -------------------- - - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config.clone()); - - let (proof_targ, vd_targ) = build_proof_ver_circuit::(&mut builder,&inner_data.common).unwrap(); - // let leaf_targets = leaf_circuit.build::(&mut builder)?; - - // // add a ConstantGate - // builder.add_gate( - // ConstantGate::new(config.num_constants), - // vec![], - // ); - - let leaf_data = builder.build::(); - println!("leaf circuit size = {:?}", leaf_data.common.degree_bits()); - - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&leaf_data.common ).unwrap(); - fs::write("leaf_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - // prove - let mut pw = PartialWitness::::new(); - pw.set_proof_with_pis_target(&proof_targ, &inner_proof)?; - pw.set_verifier_data_target(&vd_targ,&inner_data.verifier_only)?; - - let leaf_proof = leaf_data.prove(pw)?; - - // ------------- node1 circuit ------------------ - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - let (proof_targ, vd_targ) = build_node_proof_circuit::(&mut builder,&leaf_data.common).unwrap(); - // let leaf_targets = leaf_circuit.build::(&mut builder)?; - - let node_data = builder.build::(); - println!("node circuit size = {:?}", node_data.common.degree_bits()); - - // serialize circuit into JSON - let common_circuit_data_serialized = serde_json::to_string(&node_data.common ).unwrap(); - fs::write("node_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - - // prove - let mut pw = PartialWitness::::new(); - pw.set_proof_with_pis_target(&proof_targ[0], &leaf_proof)?; - pw.set_proof_with_pis_target(&proof_targ[1], &leaf_proof)?; - pw.set_verifier_data_target(&vd_targ,&leaf_data.verifier_only)?; - - let node_proof = node_data.prove(pw)?; - - - // ------------- node2 circuit ------------------ - // let config = CircuitConfig::standard_recursion_config(); - // let mut builder = CircuitBuilder::::new(config); - // - // let (proof_targ, vd_targ) = build_node_proof_circuit::(&mut builder,&node_data.common).unwrap(); - // // let leaf_targets = leaf_circuit.build::(&mut builder)?; - // - // let node2_data = builder.build::(); - // println!("node2 circuit size = {:?}", node2_data.common.degree_bits()); - // - // // serialize circuit into JSON - // let common_circuit_data_serialized = serde_json::to_string(&node2_data.common ).unwrap(); - // fs::write("node2_common.json" , common_circuit_data_serialized) .expect("Unable to write file"); - // - // // prove - // let mut pw = PartialWitness::::new(); - // pw.set_proof_with_pis_target(&proof_targ[0], &leaf_proof)?; - // pw.set_proof_with_pis_target(&proof_targ[1], &leaf_proof)?; - // pw.set_verifier_data_target(&vd_targ,&leaf_data.verifier_only)?; - // - // let node_proof = node2_data.prove(pw)?; - - - // prove node - let mut pw = PartialWitness::::new(); - pw.set_proof_with_pis_target(&proof_targ[0], &node_proof)?; - pw.set_proof_with_pis_target(&proof_targ[1], &node_proof)?; - pw.set_verifier_data_target(&vd_targ,&node_data.verifier_only)?; - - let node2_proof = node_data.prove(pw)?; - - - Ok(()) - } - - /// builds the node circuit - pub fn build_proof_ver_circuit< - H: AlgebraicHasher, - >( - builder: &mut CircuitBuilder, - common_data: &CommonCircuitData, - ) -> anyhow::Result<(ProofWithPublicInputsTarget, VerifierCircuitTarget)>{ - - // the proof virtual targets - // let mut proof_targets = vec![]; - let mut inner_pub_input = vec![]; - // for _i in 0..N { - let vir_proof = builder.add_virtual_proof_with_pis(common_data); - // collect the public input - inner_pub_input.extend_from_slice(&vir_proof.public_inputs); - // collect the proof targets - // proof_targets.push(vir_proof); - // } - // hash the public input & make it public - let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(inner_pub_input); - builder.register_public_inputs(&hash_inner_pub_input.elements); - - // virtual target for the verifier data - let inner_verifier_data = builder.add_virtual_verifier_data(common_data.config.fri_config.cap_height); - - // verify the proofs in-circuit - // for i in 0..N { - builder.verify_proof::(&vir_proof,&inner_verifier_data,&common_data); - // } - // let proof_target_array = vec_to_array::>(proof_targets)?; - - Ok( - (vir_proof, - inner_verifier_data) - ) - } - - /// builds the node circuit - pub fn build_node_proof_circuit< - H: AlgebraicHasher, - >( - builder: &mut CircuitBuilder, - common_data: &CommonCircuitData, - ) -> anyhow::Result<(Vec>, VerifierCircuitTarget)>{ - - // the proof virtual targets - let mut proof_targets = vec![]; - let mut inner_pub_input = vec![]; - for _i in 0..2 { - let vir_proof = builder.add_virtual_proof_with_pis(common_data); - // collect the public input - inner_pub_input.extend_from_slice(&vir_proof.public_inputs); - // collect the proof targets - proof_targets.push(vir_proof); - } - // hash the public input & make it public - let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(inner_pub_input); - builder.register_public_inputs(&hash_inner_pub_input.elements); - - // virtual target for the verifier data - let inner_verifier_data = builder.add_virtual_verifier_data(common_data.config.fri_config.cap_height); - - // verify the proofs in-circuit - for i in 0..2 { - builder.verify_proof::(&proof_targets[i],&inner_verifier_data,&common_data); - } - // let proof_target_array = vec_to_array::>(proof_targets)?; - - Ok( - (proof_targets, - inner_verifier_data) - ) - } - -} \ No newline at end of file