diff --git a/codex-plonky2-circuits/benches/safe_circuit.rs b/codex-plonky2-circuits/benches/safe_circuit.rs index 1fdff3f..8ae9b00 100644 --- a/codex-plonky2-circuits/benches/safe_circuit.rs +++ b/codex-plonky2-circuits/benches/safe_circuit.rs @@ -94,7 +94,7 @@ fn build_circuit( // For each proof, create targets, add constraints, and assign witnesses for &leaf_index in leaf_indices.iter() { // Build the circuit for each proof - let mut targets = circuit_instance.build_circuit(&mut builder); + let (mut targets, _root) = circuit_instance.build_circuit(&mut builder); // Assign witnesses for each proof circuit_instance.assign_witness(&mut pw, &mut targets, leaf_index)?; diff --git a/codex-plonky2-circuits/src/circuits/safe_tree_circuit.rs b/codex-plonky2-circuits/src/circuits/safe_tree_circuit.rs index 5ccb2cc..c7d5af9 100644 --- a/codex-plonky2-circuits/src/circuits/safe_tree_circuit.rs +++ b/codex-plonky2-circuits/src/circuits/safe_tree_circuit.rs @@ -66,7 +66,7 @@ impl< pub fn build_circuit( &mut self, builder: &mut CircuitBuilder:: - ) -> MerkleTreeTargets{ + ) -> (MerkleTreeTargets, HashOutTarget) { // Retrieve tree depth let depth = self.tree.depth(); @@ -94,10 +94,10 @@ impl< }; // Add Merkle proof verification constraints to the circuit - Self::reconstruct_merkle_root_circuit(builder, &mut targets); + let expected_root_target = Self::reconstruct_merkle_root_circuit(builder, &mut targets); // Return MerkleTreeTargets - targets + (targets, expected_root_target) } /// assign the witness values in the circuit targets @@ -268,7 +268,7 @@ mod tests { tree: tree.clone(), _phantom: PhantomData, }; - let mut targets = circuit_instance.build_circuit(&mut builder); + let (mut targets, expected_root_target) = circuit_instance.build_circuit(&mut builder); // create a PartialWitness and assign let mut pw = PartialWitness::new(); @@ -324,7 +324,7 @@ mod tests { tree: tree.clone(), _phantom: PhantomData, }; - let mut targets = circuit_instance.build_circuit(&mut builder); + let (mut targets, expected_root_target) = circuit_instance.build_circuit(&mut builder); let data = builder.build::(); diff --git a/codex-plonky2-circuits/src/circuits/sample_cells.rs b/codex-plonky2-circuits/src/circuits/sample_cells.rs index af7c519..aa565c7 100644 --- a/codex-plonky2-circuits/src/circuits/sample_cells.rs +++ b/codex-plonky2-circuits/src/circuits/sample_cells.rs @@ -7,7 +7,7 @@ use anyhow::Result; use plonky2::field::extension::Extendable; -use plonky2::hash::hash_types::{HashOut, RichField}; +use plonky2::hash::hash_types::{HashOut, HashOutTarget, NUM_HASH_OUT_ELTS, RichField}; use plonky2::iop::target::{BoolTarget, Target}; use plonky2::iop::witness::{PartialWitness, WitnessWrite, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; @@ -205,13 +205,15 @@ impl< //------- single cell struct ------ -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone)] pub struct DatasetTargets< F: RichField + Extendable + Poseidon2, C: GenericConfig, const D: usize, H: Hasher + AlgebraicHasher, > { + pub dataset_proof: MerkleTreeTargets, + pub dataset_root: HashOutTarget, pub slot_proofs: Vec>, _phantom: PhantomData<(C,H)>, @@ -231,6 +233,16 @@ impl< builder: &mut CircuitBuilder::, )-> DatasetTargets{ + let (dataset_proof, dataset_root_target) = self.tree.build_circuit(builder); + + // expected Merkle root + let dataset_expected_root = builder.add_virtual_hash(); + + // check equality with expected root + for i in 0..NUM_HASH_OUT_ELTS { + builder.connect(dataset_expected_root.elements[i], dataset_root_target.elements[i]); + } + let mut slot_proofs =vec![]; for i in 0..N_SAMPLES{ let proof_i = SlotTreeCircuit::::prove_single_cell(builder); @@ -238,6 +250,8 @@ impl< } DatasetTargets::{ + dataset_proof, + dataset_root: dataset_expected_root, slot_proofs, _phantom: Default::default(), } @@ -252,9 +266,21 @@ impl< slot_index:usize, entropy:usize, ){ + // assign witness for dataset level target (proving slot root is in dataset tree) + self.tree.assign_witness(pw,&mut targets.dataset_proof,slot_index); + + // assign the expected Merkle root of dataset to the target + let expected_root = self.tree.tree.root().unwrap(); + let expected_root_hash_out = expected_root.to_vec(); + for j in 0..expected_root_hash_out.len() { + pw.set_target(targets.dataset_root.elements[j], expected_root_hash_out[j]); + } + + // the sampled slot let slot = &self.slot_trees[slot_index]; let slot_root = slot.tree.tree.root().unwrap(); + // do the sample N times for i in 0..N_SAMPLES { let cell_index_bits = calculate_cell_index_bits(entropy, slot_root, i); let cell_index = bits_le_padded_to_usize(&cell_index_bits);