Implement library for verifying Merkle proofs.
This commit is contained in:
parent
af8b8d519c
commit
7bb5e1c151
@ -9,6 +9,7 @@ members = [
|
|||||||
"eth2/utils/boolean-bitfield",
|
"eth2/utils/boolean-bitfield",
|
||||||
"eth2/utils/hashing",
|
"eth2/utils/hashing",
|
||||||
"eth2/utils/honey-badger-split",
|
"eth2/utils/honey-badger-split",
|
||||||
|
"eth2/utils/merkle_proof",
|
||||||
"eth2/utils/int_to_bytes",
|
"eth2/utils/int_to_bytes",
|
||||||
"eth2/utils/slot_clock",
|
"eth2/utils/slot_clock",
|
||||||
"eth2/utils/ssz",
|
"eth2/utils/ssz",
|
||||||
|
9
eth2/utils/merkle_proof/Cargo.toml
Normal file
9
eth2/utils/merkle_proof/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "merkle_proof"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Michael Sproul <michael@sigmaprime.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ethereum-types = "0.5"
|
||||||
|
hashing = { path = "../hashing" }
|
148
eth2/utils/merkle_proof/src/lib.rs
Normal file
148
eth2/utils/merkle_proof/src/lib.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
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 in 0..depth {
|
||||||
|
let ith_bit = (index >> i) & 0x01;
|
||||||
|
if ith_bit == 1 {
|
||||||
|
let input = concat(branch[i].as_bytes().to_vec(), merkle_root);
|
||||||
|
merkle_root = hash(&input);
|
||||||
|
} else {
|
||||||
|
let mut input = merkle_root;
|
||||||
|
input.extend_from_slice(branch[i].as_bytes());
|
||||||
|
merkle_root = hash(&input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
H256::from_slice(&merkle_root)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Concatenate two vectors.
|
||||||
|
fn concat(mut vec1: Vec<u8>, mut vec2: Vec<u8>) -> Vec<u8> {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user