use ethereum_types::H256; use hashing::hash; /// Verify a proof that `leaf` exists at `index` in a Merkle tree rooted at `root`. /// /// The `branch` argument is the main component of the proof: it should be a list of internal /// node hashes such that the root can be reconstructed (in bottom-up order). pub fn verify_merkle_proof( leaf: H256, branch: &[H256], depth: usize, index: usize, root: H256, ) -> bool { if branch.len() == depth { merkle_root_from_branch(leaf, branch, depth, index) == root } else { false } } /// Compute a root hash from a leaf and a Merkle proof. fn merkle_root_from_branch(leaf: H256, branch: &[H256], depth: usize, index: usize) -> H256 { assert_eq!(branch.len(), depth, "proof length should equal depth"); let mut merkle_root = leaf.as_bytes().to_vec(); for (i, leaf) in branch.iter().enumerate().take(depth) { let ith_bit = (index >> i) & 0x01; if ith_bit == 1 { let input = concat(leaf.as_bytes().to_vec(), merkle_root); merkle_root = hash(&input); } else { let mut input = merkle_root; input.extend_from_slice(leaf.as_bytes()); merkle_root = hash(&input); } } H256::from_slice(&merkle_root) } /// Concatenate two vectors. fn concat(mut vec1: Vec, mut vec2: Vec) -> Vec { vec1.append(&mut vec2); vec1 } #[cfg(test)] mod tests { use super::*; fn hash_concat(h1: H256, h2: H256) -> H256 { H256::from_slice(&hash(&concat( h1.as_bytes().to_vec(), h2.as_bytes().to_vec(), ))) } #[test] fn verify_small_example() { // Construct a small merkle tree manually let leaf_b00 = H256::from([0xAA; 32]); let leaf_b01 = H256::from([0xBB; 32]); let leaf_b10 = H256::from([0xCC; 32]); let leaf_b11 = H256::from([0xDD; 32]); let node_b0x = hash_concat(leaf_b00, leaf_b01); let node_b1x = hash_concat(leaf_b10, leaf_b11); let root = hash_concat(node_b0x, node_b1x); // Run some proofs assert!(verify_merkle_proof( leaf_b00, &[leaf_b01, node_b1x], 2, 0b00, root )); assert!(verify_merkle_proof( leaf_b01, &[leaf_b00, node_b1x], 2, 0b01, root )); assert!(verify_merkle_proof( leaf_b10, &[leaf_b11, node_b0x], 2, 0b10, root )); assert!(verify_merkle_proof( leaf_b11, &[leaf_b10, node_b0x], 2, 0b11, root )); assert!(verify_merkle_proof( leaf_b11, &[leaf_b10], 1, 0b11, node_b1x )); // Ensure that incorrect proofs fail // Zero-length proof assert!(!verify_merkle_proof(leaf_b01, &[], 2, 0b01, root)); // Proof in reverse order assert!(!verify_merkle_proof( leaf_b01, &[node_b1x, leaf_b00], 2, 0b01, root )); // Proof too short assert!(!verify_merkle_proof(leaf_b01, &[leaf_b00], 2, 0b01, root)); // Wrong index assert!(!verify_merkle_proof( leaf_b01, &[leaf_b00, node_b1x], 2, 0b10, root )); // Wrong root assert!(!verify_merkle_proof( leaf_b01, &[leaf_b00, node_b1x], 2, 0b01, node_b1x )); } #[test] fn verify_zero_depth() { let leaf = H256::from([0xD6; 32]); let junk = H256::from([0xD7; 32]); assert!(verify_merkle_proof(leaf, &[], 0, 0, leaf)); assert!(!verify_merkle_proof(leaf, &[], 0, 7, junk)); } }