From c2279c8907bb1467e5d2983df9fe2854627d8367 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Dec 2025 07:49:45 +0000 Subject: [PATCH 1/3] refactor: simplify merkle_proof and merkle_root by removing len parameter - Remove redundant `len: u32` parameter from merkle_proof, merkle_proof_mixed, and merkle_root - Use array size N directly instead of separate length parameter - Update documentation to clarify how to calculate proof capacity P - Simplify API: merkle_proof(leaves, target, hash_fn) instead of merkle_proof(leaves, len, target, hash_fn) --- merklez/src/merkle_proof.nr | 10 ++++------ merklez/src/merkle_proof_mixed.nr | 18 +++++++----------- merklez/src/merkle_root.nr | 29 ++++++++++++++++------------- tests/src/merkle_proof/mod.nr | 30 +++++++++++++++--------------- tests/src/merkle_root/mod.nr | 6 +++--- 5 files changed, 45 insertions(+), 48 deletions(-) diff --git a/merklez/src/merkle_proof.nr b/merklez/src/merkle_proof.nr index 8c2b29a..7b605bf 100644 --- a/merklez/src/merkle_proof.nr +++ b/merklez/src/merkle_proof.nr @@ -16,7 +16,6 @@ use crate::types::{HashFn, Leaf, Proof}; /// /// # Arguments /// * `leaves` - Array of all leaf hashes in the tree -/// * `len` - Number of actual leaves (must be <= N) /// * `leaf` - The leaf to generate a proof for /// * `hash_fn` - Hash function to combine two hashes /// @@ -24,20 +23,19 @@ use crate::types::{HashFn, Leaf, Proof}; /// A Proof struct containing the sibling nodes needed to verify the leaf /// /// # Type Parameters -/// * `N` - Maximum capacity for leaves array -/// * `P` - Maximum capacity for proof nodes (should be log2(N) or more) +/// * `N` - Number of leaves in the tree +/// * `P` - Proof capacity (use ceil(log2(N)): N=2→P=1, N=3-4→P=2, N=5-8→P=3, N=9-16→P=4) /// /// # Example /// ``` /// let leaves: [Leaf; 4] = [leaf_a, leaf_b, leaf_c, leaf_d]; -/// let proof = merkle_proof(leaves, 4, leaf_b, hash_fn); +/// let proof: Proof<2> = merkle_proof(leaves, leaf_b, hash_fn); /// // proof contains the sibling nodes needed to verify leaf_b /// ``` pub fn merkle_proof( leaves: [Leaf; N], - len: u32, leaf: Leaf, hash_fn: HashFn, ) -> Proof

{ - merkle_proof_mixed(leaves, len, leaf, hash_fn) + merkle_proof_mixed(leaves, leaf, hash_fn) } diff --git a/merklez/src/merkle_proof_mixed.nr b/merklez/src/merkle_proof_mixed.nr index 303eff4..324023a 100644 --- a/merklez/src/merkle_proof_mixed.nr +++ b/merklez/src/merkle_proof_mixed.nr @@ -12,11 +12,11 @@ use crate::types::{HashFn, Leaf, Proof}; /// Find the index of a leaf in an array of leaves /// Returns the index if found, or N (out of bounds) if not found -fn find_leaf_index(leaves: [Leaf; N], len: u32, target: Leaf) -> u32 { +fn find_leaf_index(leaves: [Leaf; N], target: Leaf) -> u32 { let mut index: u32 = N; // Default to out of bounds let mut found = false; for i in 0..N { - if (i < len) & (!found) { + if !found { let mut is_equal = true; for j in 0..32 { if leaves[i][j] != target[j] { @@ -43,12 +43,10 @@ fn up_layer(leaves: [Leaf; N], len: u32, hash_fn: HashFn) -> ([Leaf; for _k in 0..N { if i < len { if i + 1 < len { - // Hash pair of leaves new_layer[new_len] = hash_fn(leaves[i], leaves[i + 1]); new_len += 1; i += 2; } else { - // Odd leaf, promote to next layer new_layer[new_len] = leaves[i]; new_len += 1; i += 1; @@ -68,7 +66,6 @@ fn up_layer(leaves: [Leaf; N], len: u32, hash_fn: HashFn) -> ([Leaf; /// /// # Arguments /// * `leaves` - Array of all leaf hashes in the tree -/// * `len` - Number of actual leaves (must be <= N) /// * `leaf` - The leaf to generate a proof for /// * `hash_fn` - Hash function to combine two hashes /// @@ -76,26 +73,25 @@ fn up_layer(leaves: [Leaf; N], len: u32, hash_fn: HashFn) -> ([Leaf; /// A Proof struct containing the sibling nodes needed to verify the leaf pub fn merkle_proof_mixed( leaves: [Leaf; N], - len: u32, leaf: Leaf, hash_fn: HashFn, ) -> Proof

{ let mut proof_nodes: [Node; P] = [Node { data: [0u8; 32], side: Side::left() }; P]; let mut proof_len: u32 = 0; - // Handle edge cases: len == 0 or len == 1 means no proof needed + // Handle edge cases: N == 0 or N == 1 means no proof needed // We use a flag to skip the main logic in these cases - let should_process = len > 1; + let should_process = N > 1; if should_process { // Find the target leaf index - let initial_index = find_leaf_index(leaves, len, leaf); - assert(initial_index < len, "Leaf does not exist in the tree"); + let initial_index = find_leaf_index(leaves, leaf); + assert(initial_index < N, "Leaf does not exist in the tree"); // Track current position in the tree let mut leaf_index: u32 = initial_index; let mut current_leaves: [Leaf; N] = leaves; - let mut current_len: u32 = len; + let mut current_len: u32 = N; // Build proof by traversing up the tree layer by layer for _level in 0..P { diff --git a/merklez/src/merkle_root.nr b/merklez/src/merkle_root.nr index 33cc9ac..f747125 100644 --- a/merklez/src/merkle_root.nr +++ b/merklez/src/merkle_root.nr @@ -14,26 +14,29 @@ use crate::types::{HashFn, Leaf, Root}; /// * `leaves` - Array of leaf hashes /// * `hash_fn` - Hash function to combine two hashes /// +/// # Type Parameters +/// * `N` - Number of leaves in the tree +/// /// # Returns /// The root hash of the Merkle tree -pub fn merkle_root(leaves: [Leaf; N], len: u32, hash_fn: HashFn) -> Root { +pub fn merkle_root(leaves: [Leaf; N], hash_fn: HashFn) -> Root { let mut level: [Leaf; N] = leaves; let mut next_level: [Leaf; N] = leaves; - let mut curr_len: u32 = len; + let mut curr_len: u32 = N; for _p in 0..N { - if curr_len > 1u32 { - let mut next_len: u32 = 0u32; - let mut i: u32 = 0u32; + if curr_len > 1 { + let mut next_len: u32 = 0; + let mut i: u32 = 0; for _k in 0..N { - if i >= curr_len {} else if i + 1u32 < curr_len { - next_level[next_len] = hash_fn(level[i], level[i + 1u32]); - next_len += 1u32; - i += 2u32; + if i >= curr_len {} else if i + 1 < curr_len { + next_level[next_len] = hash_fn(level[i], level[i + 1]); + next_len += 1; + i += 2; } else { next_level[next_len] = level[i]; - next_len += 1u32; - i += 1u32; + next_len += 1; + i += 1; } } for j in 0..N { @@ -45,10 +48,10 @@ pub fn merkle_root(leaves: [Leaf; N], len: u32, hash_fn: HashFn) -> } } - if curr_len == 0u32 { + if N == 0 { [0u8; 32] } else { - level[0u32] + level[0] } } diff --git a/tests/src/merkle_proof/mod.nr b/tests/src/merkle_proof/mod.nr index 0d0a3a6..0aa31e0 100644 --- a/tests/src/merkle_proof/mod.nr +++ b/tests/src/merkle_proof/mod.nr @@ -115,14 +115,14 @@ fn test_merkle_proof_leaves_even_make_proof() { }, ]; - let proof: Proof<4> = merkle_proof(leaves, 6, target, keccak_hash); + let proof: Proof<4> = merkle_proof(leaves, target, keccak_hash); assert(proof.len == 2); assert(proof.nodes[0] == expected_proof[0]); assert(proof.nodes[1] == expected_proof[1]); // Also verify the proof produces the correct root - let expected_root = merkle_root(leaves, 6, keccak_hash); + let expected_root = merkle_root(leaves, keccak_hash); let computed_root = verify_proof(target, proof, keccak_hash); assert(computed_root == expected_root); } @@ -170,7 +170,7 @@ fn test_merkle_proof_leaves_odd_make_proof() { }, ]; - let proof: Proof<4> = merkle_proof(leaves, 5, target, keccak_hash); + let proof: Proof<4> = merkle_proof(leaves, target, keccak_hash); assert(proof.len == 3); assert(proof.nodes[0] == expected_proof[0]); @@ -178,7 +178,7 @@ fn test_merkle_proof_leaves_odd_make_proof() { assert(proof.nodes[2] == expected_proof[2]); // Also verify the proof produces the correct root - let expected_root = merkle_root(leaves, 5, keccak_hash); + let expected_root = merkle_root(leaves, keccak_hash); let computed_root = verify_proof(target, proof, keccak_hash); assert(computed_root == expected_root); } @@ -213,14 +213,14 @@ fn test_merkle_proof_leaves_base_2_make_proof() { }, ]; - let proof: Proof<4> = merkle_proof(leaves, 4, target, keccak_hash); + let proof: Proof<4> = merkle_proof(leaves, target, keccak_hash); assert(proof.len == 2); assert(proof.nodes[0] == expected_proof[0]); assert(proof.nodes[1] == expected_proof[1]); // Also verify the proof produces the correct root - let expected_root = merkle_root(leaves, 4, keccak_hash); + let expected_root = merkle_root(leaves, keccak_hash); let computed_root = verify_proof(target, proof, keccak_hash); assert(computed_root == expected_root); } @@ -233,9 +233,9 @@ fn test_merkle_proof_leaves_base_2_make_proof() { fn test_merkle_proof_2_leaves_first() { let leaves: [Leaf; 2] = [get_leaf_a(), get_leaf_b()]; let target = get_leaf_a(); - let expected_root = merkle_root(leaves, 2, keccak_hash); + let expected_root = merkle_root(leaves, keccak_hash); - let proof: Proof<2> = merkle_proof(leaves, 2, target, keccak_hash); + let proof: Proof<2> = merkle_proof(leaves, target, keccak_hash); assert(proof.len == 1); // First leaf (index 0) - sibling is on the right @@ -250,9 +250,9 @@ fn test_merkle_proof_2_leaves_first() { fn test_merkle_proof_2_leaves_second() { let leaves: [Leaf; 2] = [get_leaf_a(), get_leaf_b()]; let target = get_leaf_b(); - let expected_root = merkle_root(leaves, 2, keccak_hash); + let expected_root = merkle_root(leaves, keccak_hash); - let proof: Proof<2> = merkle_proof(leaves, 2, target, keccak_hash); + let proof: Proof<2> = merkle_proof(leaves, target, keccak_hash); assert(proof.len == 1); // Second leaf (index 1) - sibling is on the left @@ -268,7 +268,7 @@ fn test_merkle_proof_single_leaf() { let leaves: [Leaf; 1] = [get_leaf_a()]; let target = get_leaf_a(); - let proof: Proof<1> = merkle_proof(leaves, 1, target, keccak_hash); + let proof: Proof<1> = merkle_proof(leaves, target, keccak_hash); // Single leaf tree has no proof nodes assert(proof.len == 0); @@ -278,9 +278,9 @@ fn test_merkle_proof_single_leaf() { fn test_merkle_proof_3_leaves() { let leaves: [Leaf; 3] = [get_leaf_a(), get_leaf_b(), get_leaf_c()]; let target = get_leaf_c(); - let expected_root = merkle_root(leaves, 3, keccak_hash); + let expected_root = merkle_root(leaves, keccak_hash); - let proof: Proof<3> = merkle_proof(leaves, 3, target, keccak_hash); + let proof: Proof<3> = merkle_proof(leaves, target, keccak_hash); let computed_root = verify_proof(target, proof, keccak_hash); assert(computed_root == expected_root); @@ -289,12 +289,12 @@ fn test_merkle_proof_3_leaves() { #[test] fn test_merkle_proof_4_leaves_all_positions() { let leaves: [Leaf; 4] = [get_leaf_a(), get_leaf_b(), get_leaf_c(), get_leaf_d()]; - let expected_root = merkle_root(leaves, 4, keccak_hash); + let expected_root = merkle_root(leaves, keccak_hash); // Test all 4 positions for i in 0..4 { let target = leaves[i]; - let proof: Proof<4> = merkle_proof(leaves, 4, target, keccak_hash); + let proof: Proof<4> = merkle_proof(leaves, target, keccak_hash); let computed_root = verify_proof(target, proof, keccak_hash); assert(computed_root == expected_root); } diff --git a/tests/src/merkle_root/mod.nr b/tests/src/merkle_root/mod.nr index 759c7e6..9053003 100644 --- a/tests/src/merkle_root/mod.nr +++ b/tests/src/merkle_root/mod.nr @@ -43,7 +43,7 @@ fn test_merkle_root_leaves_even_make_root() { 183, 166, 100, 162, 191, 148, 141, 180, 250, 145, 150, 4, 131, ], ]; - let result = merkle_root::<6>(setup_leaves, 6u32, keccak_hash); + let result = merkle_root(setup_leaves, keccak_hash); assert(result == setup_root); } @@ -75,7 +75,7 @@ fn test_merkle_root_leaves_odd_make_root() { 175, 60, 142, 14, 179, 18, 239, 29, 51, 130, 231, 97, ], ]; - let result = merkle_root::<5>(setup_leaves, 5u32, keccak_hash); + let result = merkle_root(setup_leaves, keccak_hash); assert(result == setup_root); } @@ -103,6 +103,6 @@ fn test_merkle_root_leaves_base_2_make_root() { 225, 155, 252, 10, 161, 10, 182, 116, 255, 117, 179, 210, 243, ], ]; - let result = merkle_root::<4>(setup_leaves, 4u32, keccak_hash); + let result = merkle_root(setup_leaves, keccak_hash); assert(result == setup_root); } From 22fb542540e44b5816d5dafb83ecd7a823461c34 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Dec 2025 07:51:30 +0000 Subject: [PATCH 2/3] docs: update README to reflect simplified API - Remove len parameter from merkle_root and merkle_proof examples - Update API reference with new function signatures - Add documentation for proof capacity P calculation --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6f6161a..01f1a55 100644 --- a/README.md +++ b/README.md @@ -188,10 +188,10 @@ fn main() { let leaves: [Leaf; 4] = [leaf_a, leaf_b, leaf_c, leaf_d]; // Calculate root directly - let root = merkle_root(leaves, 4, my_hash); + let root = merkle_root(leaves, my_hash); - // Generate proof for leaf at index 2 - let proof: Proof<8> = merkle_proof(leaves, 4, 2, my_hash); + // Generate proof for leaf_c + let proof: Proof<2> = merkle_proof(leaves, leaf_c, my_hash); // Verify proof let computed = merkle_proof_check(proof, leaf_c, my_hash); @@ -252,14 +252,15 @@ Calculates the merkle root from an array of leaves. ```noir pub fn merkle_root( leaves: [Leaf; N], - leaves_len: u32, hash_fn: HashFn ) -> Root ``` +**Type Parameters:** +- `N`: Number of leaves in the tree + **Parameters:** - `leaves`: Array of leaf hashes -- `leaves_len`: Actual number of leaves (array might be larger) - `hash_fn`: Custom hash function to combine two hashes **Returns:** The merkle root hash @@ -271,16 +272,18 @@ Generates a merkle proof for a specific leaf. ```noir pub fn merkle_proof( leaves: [Leaf; N], - leaves_len: u32, - leaf_index: u32, + leaf: Leaf, hash_fn: HashFn ) -> Proof

``` +**Type Parameters:** +- `N`: Number of leaves in the tree +- `P`: Proof capacity (use `ceil(log2(N))`): N=2→P=1, N=3-4→P=2, N=5-8→P=3, N=9-16→P=4 + **Parameters:** - `leaves`: Array of all leaves -- `leaves_len`: Actual number of leaves -- `leaf_index`: Index of the leaf to prove +- `leaf`: The leaf to generate a proof for - `hash_fn`: Custom hash function **Returns:** A Proof struct containing the path from leaf to root From ceab0a5385eea1d7f9ed82d8009420739f12f52c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Dec 2025 07:53:34 +0000 Subject: [PATCH 3/3] fix: replace non-ASCII arrows with ASCII in comments --- merklez/src/merkle_proof.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/merklez/src/merkle_proof.nr b/merklez/src/merkle_proof.nr index 7b605bf..a4dedef 100644 --- a/merklez/src/merkle_proof.nr +++ b/merklez/src/merkle_proof.nr @@ -24,7 +24,7 @@ use crate::types::{HashFn, Leaf, Proof}; /// /// # Type Parameters /// * `N` - Number of leaves in the tree -/// * `P` - Proof capacity (use ceil(log2(N)): N=2→P=1, N=3-4→P=2, N=5-8→P=3, N=9-16→P=4) +/// * `P` - Proof capacity (use ceil(log2(N)): N=2->P=1, N=3-4->P=2, N=5-8->P=3, N=9-16->P=4) /// /// # Example /// ```