diff --git a/codex-plonky2-circuits/src/circuit_helper/mod.rs b/codex-plonky2-circuits/src/circuit_helper/mod.rs new file mode 100644 index 0000000..e12c947 --- /dev/null +++ b/codex-plonky2-circuits/src/circuit_helper/mod.rs @@ -0,0 +1,105 @@ +use plonky2::hash::hash_types::RichField; +use plonky2::iop::witness::PartialWitness; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, ProverCircuitData, VerifierCircuitData}; +use plonky2::plonk::config::GenericConfig; +use plonky2::plonk::proof::ProofWithPublicInputs; +use plonky2_field::extension::Extendable; +use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; +use crate::error::CircuitError; +use crate::Result; + +/// Plonky2Circuit is the trait used to define the logic of the circuit and assign witnesses +/// to that circuit instance. +pub trait Plonky2Circuit< + F: RichField + Extendable + Poseidon2, + C: GenericConfig, + const D: usize, +> { + type Targets; + type Input:Clone; + + /// build the circuit with standard config + fn build_with_standard_config( + &self, + ) -> Result<(Self::Targets,CircuitData)>{ + self.build(CircuitConfig::standard_recursion_config()) + } + + /// build the circuit + fn build( + &self, + circuit_config: CircuitConfig, + ) -> Result<(Self::Targets,CircuitData)>{ + let mut builder = CircuitBuilder::::new(circuit_config); + + let targets = self.add_targets(&mut builder, true)?; + + Ok((targets,builder.build::())) + } + + /// build the circuit logic and return targets to be assigned later + /// based on register_pi, registers the public input or not. + fn add_targets( + &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<()>; + + /// get the common data for the circuit with standard config + fn get_common_data_standard_config( + &self + ) -> Result>{ + self.get_common_data(CircuitConfig::standard_recursion_config()) + } + + /// get the common data for the circuit + fn get_common_data( + &self, + circuit_config: CircuitConfig, + ) -> Result>{ + let mut builder = CircuitBuilder::::new(circuit_config); + + self.add_targets(&mut builder, true)?; + + let circ_data = builder.build::(); + + Ok(circ_data) + } + + /// generates a proof for the circuit using the given targets, input and prover circuit data + fn prove( + &self, + targets: &Self::Targets, + input: &Self::Input, + prover_circuit_data: ProverCircuitData + )-> Result>{ + let mut pw = PartialWitness::new(); + self.assign_targets(&mut pw, targets, input)?; + + let proof = prover_circuit_data.prove(pw).map_err( + |e| CircuitError::ProofGenerationError(e.to_string()) + )?; + + Ok(proof) + } + + /// verify the given proof with the verifier circuit data + fn verify( + proof_with_pi: ProofWithPublicInputs, + verifier_circuit_data: VerifierCircuitData + ) -> Result<()>{ + verifier_circuit_data.verify(proof_with_pi).map_err( |e| + CircuitError::InvalidProofError(e.to_string()) + ) + } +} + diff --git a/codex-plonky2-circuits/src/circuits/merkle_circuit.rs b/codex-plonky2-circuits/src/circuits/merkle_circuit.rs index 3d43d2e..0f08cb9 100644 --- a/codex-plonky2-circuits/src/circuits/merkle_circuit.rs +++ b/codex-plonky2-circuits/src/circuits/merkle_circuit.rs @@ -3,7 +3,7 @@ // https://github.com/codex-storage/codex-storage-proofs-circuits/blob/master/circuit/codex/merkle.circom use plonky2::{ - field::{extension::Extendable, types::Field}, + field::extension::Extendable, hash::hash_types::{HashOutTarget, RichField, NUM_HASH_OUT_ELTS}, iop::target::BoolTarget, plonk::{ diff --git a/codex-plonky2-circuits/src/circuits/sample_cells.rs b/codex-plonky2-circuits/src/circuits/sample_cells.rs index 5d4f454..cd0cbc4 100644 --- a/codex-plonky2-circuits/src/circuits/sample_cells.rs +++ b/codex-plonky2-circuits/src/circuits/sample_cells.rs @@ -11,7 +11,6 @@ use plonky2::{ field::extension::Extendable, hash::{ hash_types::{HashOut, HashOutTarget, NUM_HASH_OUT_ELTS, RichField}, - hashing::PlonkyPermutation, }, iop::{ target::{BoolTarget, Target}, @@ -19,7 +18,6 @@ use plonky2::{ }, plonk::circuit_builder::CircuitBuilder, }; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData}; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; @@ -33,6 +31,7 @@ use crate::{ Result, error::CircuitError, }; +use crate::circuit_helper::Plonky2Circuit; /// circuit for sampling a slot in a dataset merkle tree #[derive(Clone, Debug)] @@ -168,7 +167,6 @@ impl< // 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); @@ -200,7 +198,6 @@ impl< // 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 { @@ -212,7 +209,6 @@ impl< 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(); @@ -229,7 +225,7 @@ impl< 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 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 @@ -238,7 +234,7 @@ impl< 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::>(); + let 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); @@ -256,13 +252,13 @@ impl< } // 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 s_path_bits = b_path_bits.split_off(block_tree_depth); - let mut b_merkle_path = MerkleProofTarget { + let b_merkle_path = MerkleProofTarget { path: (0..block_tree_depth).map(|_| builder.add_virtual_hash()).collect(), }; - let mut s_merkle_path = MerkleProofTarget { + let s_merkle_path = MerkleProofTarget { path: (0..(max_depth - block_tree_depth)).map(|_| builder.add_virtual_hash()).collect(), }; @@ -323,7 +319,7 @@ impl< } /// 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> { + 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); @@ -421,3 +417,27 @@ impl< } } + +/// Implements the Plonky2Circuit trait +impl< + F: RichField + Extendable + Poseidon2, + C: GenericConfig, + const D: usize, + H: AlgebraicHasher, +> Plonky2Circuit for SampleCircuit { + type Targets = SampleTargets; + type Input = SampleCircuitInput; + + fn add_targets(&self, builder: &mut CircuitBuilder, register_pi: bool) -> Result { + let targets = if register_pi { + self.sample_slot_circuit_with_public_input(builder) + } else { self.sample_slot_circuit(builder) }; + + targets + } + + fn assign_targets(&self, pw: &mut PartialWitness, targets: &Self::Targets, input: &Self::Input) -> Result<()> { + self.sample_slot_assign_witness(pw,targets,input) + } + +} diff --git a/codex-plonky2-circuits/src/lib.rs b/codex-plonky2-circuits/src/lib.rs index c67e5be..7926659 100644 --- a/codex-plonky2-circuits/src/lib.rs +++ b/codex-plonky2-circuits/src/lib.rs @@ -1,5 +1,6 @@ pub mod circuits; pub mod recursion; pub mod error; +pub mod circuit_helper; pub type Result = core::result::Result; diff --git a/codex-plonky2-circuits/src/recursion/utils/mod.rs b/codex-plonky2-circuits/src/recursion/utils/mod.rs index 09b3dd3..f8e0bc8 100644 --- a/codex-plonky2-circuits/src/recursion/utils/mod.rs +++ b/codex-plonky2-circuits/src/recursion/utils/mod.rs @@ -1,2 +1,2 @@ pub mod dummy_gen; -pub mod conditional_verifier; +pub mod conditional_verifier; \ No newline at end of file