From 59e054554ca2e77bac3c1a272f77d4c3b6504797 Mon Sep 17 00:00:00 2001 From: M Alghazwi Date: Thu, 9 Jan 2025 10:37:54 +0100 Subject: [PATCH] clean up and improve with comments --- .../src/circuits/merkle_circuit.rs | 100 +++++------------- 1 file changed, 29 insertions(+), 71 deletions(-) diff --git a/codex-plonky2-circuits/src/circuits/merkle_circuit.rs b/codex-plonky2-circuits/src/circuits/merkle_circuit.rs index 99aa3fc..cd98e4e 100644 --- a/codex-plonky2-circuits/src/circuits/merkle_circuit.rs +++ b/codex-plonky2-circuits/src/circuits/merkle_circuit.rs @@ -3,17 +3,19 @@ // https://github.com/codex-storage/codex-storage-proofs-circuits/blob/master/circuit/codex/merkle.circom use anyhow::Result; -use plonky2::field::extension::Extendable; -use plonky2::field::types::Field; -use plonky2::hash::hash_types::{HashOutTarget, RichField, NUM_HASH_OUT_ELTS}; -use plonky2::iop::target::{BoolTarget, Target}; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, GenericHashOut, Hasher, PoseidonGoldilocksConfig}; +use plonky2::{ + field::{extension::Extendable, types::Field}, + hash::hash_types::{HashOutTarget, RichField, NUM_HASH_OUT_ELTS}, + iop::target::BoolTarget, + plonk::{ + circuit_builder::CircuitBuilder, + }, +}; use std::marker::PhantomData; use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; use crate::circuits::keyed_compress::key_compress_circuit; use crate::circuits::params::HF; -use crate::circuits::utils::{add_assign_hash_out_target, assign_bool_targets, assign_hash_out_targets, mul_hash_out_target}; +use crate::circuits::utils::{add_assign_hash_out_target, mul_hash_out_target}; use crate::merkle_tree::merkle_safe::{KEY_NONE,KEY_BOTTOM_LAYER}; /// Merkle tree targets representing the input to the circuit @@ -54,63 +56,18 @@ impl< } } - /// takes the params from the targets struct - /// outputs the reconstructed merkle root - pub fn reconstruct_merkle_root_circuit( - builder: &mut CircuitBuilder, - targets: &mut MerkleTreeTargets, - max_depth: usize, - ) -> HashOutTarget { - let mut state: HashOutTarget = targets.leaf; - let zero = builder.zero(); - let one = builder.one(); - let two = builder.two(); - debug_assert_eq!(targets.path_bits.len(), targets.merkle_path.path.len()); - - // 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) { - debug_assert_eq!(sibling.elements.len(), NUM_HASH_OUT_ELTS); - - let bottom = if i == 0 { - builder.constant(F::from_canonical_u64(KEY_BOTTOM_LAYER)) - } else { - builder.constant(F::from_canonical_u64(KEY_NONE)) - }; - - // 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 i in 0..NUM_HASH_OUT_ELTS { - left.push( builder.select(bit, sibling.elements[i], state.elements[i])); - right.push( builder.select(bit, state.elements[i], sibling.elements[i])); - } - - state = key_compress_circuit::(builder,left,right,key); - - i += 1; - } - - return state; - } - - /// takes the params from the targets struct - /// outputs the reconstructed merkle root - /// this one uses the mask bits to select the right layer + /// 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, @@ -133,13 +90,14 @@ impl< let mut i: usize = 0; for (&bit, &sibling) in targets.path_bits.iter().zip(&targets.merkle_path.path) { - debug_assert_eq!(sibling.elements.len(), NUM_HASH_OUT_ELTS); - let bottom = if i == 0 { - builder.constant(F::from_canonical_u64(KEY_BOTTOM_LAYER)) + // logic: we add KEY_BOTTOM_LAYER if i == 0, otherwise KEY_NONE. + let bottom_key_val = if i == 0 { + KEY_BOTTOM_LAYER } else { - builder.constant(F::from_canonical_u64(KEY_NONE)) + 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 @@ -156,14 +114,14 @@ impl< right.push( builder.select(bit, state[i].elements[j], sibling.elements[j])); } - state.push(key_compress_circuit::(builder,left,right,key)); + // Compress them with a keyed-hash function + let combined_hash = key_compress_circuit::(builder, left, right, key); + state.push(combined_hash); i += 1; } // select the right layer using the mask bits - // another way to do this is to use builder.select - // but that might be less efficient & more constraints 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);