use crate::sponge::Hash;
use crate::tree::hash_node;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Side {
Left,
Right,
}
pub fn merkle_verify_path(root: &Hash, leaf_hash: &Hash, path: &[(Hash, Side)]) -> bool {
if path.is_empty() {
return leaf_hash == root;
}
let last = path.len() - 1;
let mut current = *leaf_hash;
for (i, (sibling, side)) in path.iter().enumerate() {
let is_root = i == last;
current = match side {
Side::Left => hash_node(sibling, ¤t, is_root),
Side::Right => hash_node(¤t, sibling, is_root),
};
}
current == *root
}
#[cfg(test)]
mod tests {
extern crate std;
use super::*;
use crate::tree::{hash_leaf, hash_node};
use crate::params::OUTPUT_BYTES;
fn two_leaf_tree() -> (Hash, Hash, Hash) {
let leaf0 = hash_leaf(b"leaf zero data", 0, false);
let leaf1 = hash_leaf(b"leaf one data", 1, false);
let root = hash_node(&leaf0, &leaf1, true);
(root, leaf0, leaf1)
}
#[test]
fn two_leaf_left_leaf_verifies() {
let (root, leaf0, leaf1) = two_leaf_tree();
let path = [(leaf1, Side::Right)];
assert!(merkle_verify_path(&root, &leaf0, &path));
}
#[test]
fn two_leaf_right_leaf_verifies() {
let (root, leaf0, leaf1) = two_leaf_tree();
let path = [(leaf0, Side::Left)];
assert!(merkle_verify_path(&root, &leaf1, &path));
}
#[test]
fn wrong_leaf_hash_fails() {
let (root, _leaf0, leaf1) = two_leaf_tree();
let wrong_leaf = Hash::from_bytes([0xAA; OUTPUT_BYTES]);
let path = [(leaf1, Side::Right)];
assert!(!merkle_verify_path(&root, &wrong_leaf, &path));
}
#[test]
fn wrong_sibling_hash_fails() {
let (root, leaf0, _leaf1) = two_leaf_tree();
let wrong_sibling = Hash::from_bytes([0xBB; OUTPUT_BYTES]);
let path = [(wrong_sibling, Side::Right)];
assert!(!merkle_verify_path(&root, &leaf0, &path));
}
#[test]
fn swapped_sides_fails() {
let (root, leaf0, leaf1) = two_leaf_tree();
let path = [(leaf1, Side::Left)]; assert!(!merkle_verify_path(&root, &leaf0, &path));
}
#[test]
fn wrong_root_fails() {
let (_root, leaf0, leaf1) = two_leaf_tree();
let wrong_root = Hash::from_bytes([0xFF; OUTPUT_BYTES]);
let path = [(leaf1, Side::Right)];
assert!(!merkle_verify_path(&wrong_root, &leaf0, &path));
}
#[test]
fn empty_path_leaf_equals_root() {
let leaf = hash_leaf(b"solo", 0, true);
assert!(merkle_verify_path(&leaf, &leaf, &[]));
}
#[test]
fn empty_path_wrong_hash_fails() {
let leaf = hash_leaf(b"solo", 0, true);
let other = Hash::from_bytes([0x01; OUTPUT_BYTES]);
assert!(!merkle_verify_path(&leaf, &other, &[]));
}
#[test]
fn four_leaf_tree_all_leaves_verify() {
let c0 = hash_leaf(b"c0", 0, false);
let c1 = hash_leaf(b"c1", 1, false);
let c2 = hash_leaf(b"c2", 2, false);
let c3 = hash_leaf(b"c3", 3, false);
let p01 = hash_node(&c0, &c1, false);
let p23 = hash_node(&c2, &c3, false);
let root = hash_node(&p01, &p23, true);
assert!(merkle_verify_path(&root, &c0, &[(c1, Side::Right), (p23, Side::Right)]));
assert!(merkle_verify_path(&root, &c1, &[(c0, Side::Left), (p23, Side::Right)]));
assert!(merkle_verify_path(&root, &c2, &[(c3, Side::Right), (p01, Side::Left)]));
assert!(merkle_verify_path(&root, &c3, &[(c2, Side::Left), (p01, Side::Left)]));
}
}