Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -252,14 +252,15 @@ Calculates the merkle root from an array of leaves.
```noir
pub fn merkle_root<let N: u32>(
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
Expand All @@ -271,16 +272,18 @@ Generates a merkle proof for a specific leaf.
```noir
pub fn merkle_proof<let N: u32, let P: u32>(
leaves: [Leaf; N],
leaves_len: u32,
leaf_index: u32,
leaf: Leaf,
hash_fn: HashFn
) -> Proof<P>
```

**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
Expand Down
10 changes: 4 additions & 6 deletions merklez/src/merkle_proof.nr
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,26 @@ 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
///
/// # Returns
/// 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<let N: u32, let P: u32>(
leaves: [Leaf; N],
len: u32,
leaf: Leaf,
hash_fn: HashFn,
) -> Proof<P> {
merkle_proof_mixed(leaves, len, leaf, hash_fn)
merkle_proof_mixed(leaves, leaf, hash_fn)
}
18 changes: 7 additions & 11 deletions merklez/src/merkle_proof_mixed.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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<let N: u32>(leaves: [Leaf; N], len: u32, target: Leaf) -> u32 {
fn find_leaf_index<let N: u32>(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] {
Expand All @@ -43,12 +43,10 @@ fn up_layer<let N: u32>(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;
Expand All @@ -68,34 +66,32 @@ fn up_layer<let N: u32>(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
///
/// # Returns
/// A Proof struct containing the sibling nodes needed to verify the leaf
pub fn merkle_proof_mixed<let N: u32, let P: u32>(
leaves: [Leaf; N],
len: u32,
leaf: Leaf,
hash_fn: HashFn,
) -> Proof<P> {
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 {
Expand Down
29 changes: 16 additions & 13 deletions merklez/src/merkle_root.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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<let N: u32>(leaves: [Leaf; N], len: u32, hash_fn: HashFn) -> Root {
pub fn merkle_root<let N: u32>(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 {
Expand All @@ -45,10 +48,10 @@ pub fn merkle_root<let N: u32>(leaves: [Leaf; N], len: u32, hash_fn: HashFn) ->
}
}

if curr_len == 0u32 {
if N == 0 {
[0u8; 32]
} else {
level[0u32]
level[0]
}
}

Expand Down
30 changes: 15 additions & 15 deletions tests/src/merkle_proof/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -170,15 +170,15 @@ 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]);
assert(proof.nodes[1] == expected_proof[1]);
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);
}
Expand Down Expand Up @@ -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);
}
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
}
Expand Down
6 changes: 3 additions & 3 deletions tests/src/merkle_root/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}
Loading