use elements_miniscript::elements::bitcoin::hashes::{sha256, Hash, HashEngine};
pub struct MerkleTree {
root: Tree,
leaves: Vec<[u8; 32]>,
}
impl MerkleTree {
pub fn new(leaves: Vec<[u8; 32]>) -> Self {
Self {
root: Tree::new(&leaves, 0, leaves.len()),
leaves,
}
}
pub fn size(&self) -> usize {
self.leaves.len()
}
pub fn root_hash(&self) -> &[u8; 32] {
match &self.root {
Tree::Node { value, .. } => value,
Tree::Leaf(idx) => &self.leaves[*idx],
}
}
pub fn get_leaf(&self, i: usize) -> Option<&[u8; 32]> {
self.leaves.get(i)
}
pub fn get_leaf_index(&self, val: &[u8]) -> Option<usize> {
self.leaves.iter().position(|v| v == val)
}
pub fn get_leaf_proof(&self, index: usize) -> Option<Vec<Vec<u8>>> {
if index >= self.leaves.len() {
None
} else {
Some(self.root.get_proof(&self.leaves, index))
}
}
}
enum Tree {
Node {
value: [u8; 32],
left: Box<Tree>,
right: Box<Tree>,
height: usize,
},
Leaf(usize),
}
impl Tree {
fn new(leaves: &[[u8; 32]], start: usize, size: usize) -> Self {
if size == 1 {
return Tree::Leaf(start);
}
let lchild_size = largest_power_of_2_less_than(size);
let lchild = Tree::new(leaves, start, lchild_size);
let rchild = Tree::new(leaves, start + lchild_size, size - lchild_size);
let mut input = vec![0x01];
input.extend_from_slice(lchild.value(leaves));
input.extend_from_slice(rchild.value(leaves));
let mut engine = sha256::Hash::engine();
engine.input(input.as_slice());
let value = sha256::Hash::from_engine(engine).to_byte_array();
Tree::Node {
height: lchild.height() + 1,
left: Box::new(lchild),
right: Box::new(rchild),
value,
}
}
fn value<'a>(&'a self, leaves: &'a [[u8; 32]]) -> &'a [u8; 32] {
match self {
Self::Node { value, .. } => value,
Self::Leaf(idx) => &leaves[*idx],
}
}
fn height(&self) -> usize {
match self {
Self::Node { height, .. } => *height,
Self::Leaf(_) => 0,
}
}
fn get_proof(&self, leaves: &[[u8; 32]], index: usize) -> Vec<Vec<u8>> {
match self {
Self::Leaf(_) => Vec::new(),
Self::Node { left, right, .. } => {
let (mut proof, sibling) = if index < pow2(left.height()) {
(left.get_proof(leaves, index), right)
} else {
(right.get_proof(leaves, index - pow2(left.height())), left)
};
match **sibling {
Self::Node { value, .. } => proof.push(value.to_vec()),
Self::Leaf(idx) => proof.push(leaves[idx].to_vec()),
}
proof
}
}
}
}
fn floor_lg(n: usize) -> usize {
assert!(n > 0);
let mut r = 0;
let mut t = 1;
while 2 * t <= n {
t *= 2;
r += 1;
}
r
}
fn pow2(n: usize) -> usize {
let mut p = 1;
for _i in 0..n {
p *= 2
}
p
}
fn is_power_of_2(n: usize) -> bool {
assert!(n >= 1);
n & (n - 1) == 0
}
fn largest_power_of_2_less_than(n: usize) -> usize {
if n == 2 {
return 1;
}
assert!(n > 1);
if is_power_of_2(n) {
n / 2
} else {
1 << floor_lg(n)
}
}
#[cfg(test)]
mod tests {
use super::*;
use elements_miniscript::elements::bitcoin::hashes::{sha256, Hash, HashEngine};
#[test]
fn test_merkle_tree() {
let leaves = [
[
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
0x78, 0x52, 0xb8, 0x55,
],
[
0xd7, 0xa8, 0xfb, 0xb3, 0x07, 0xd7, 0x80, 0x94, 0x69, 0xca, 0x9a, 0xbc, 0xb0, 0x08,
0x2e, 0x4f, 0x8d, 0x56, 0x51, 0xe4, 0x6d, 0x3c, 0xdb, 0x76, 0x2d, 0x02, 0xd0, 0xbf,
0x37, 0xc9, 0xe5, 0x92,
],
[
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6,
0x3d, 0x97, 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, 0xb7, 0x65, 0x44, 0x8c,
0x86, 0x35, 0xfb, 0x6c,
],
[
0x00, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6,
0x3d, 0x00, 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, 0xb7, 0x65, 0x44, 0x8c,
0x86, 0x35, 0xfb, 0x6c,
],
];
let tree = MerkleTree::new(leaves[0..3].to_vec());
assert_eq!(
tree.get_leaf_proof(0),
Some(vec![leaves[1].to_vec(), leaves[2].to_vec()])
);
assert_eq!(
tree.get_leaf_proof(1),
Some(vec![leaves[0].to_vec(), leaves[2].to_vec()])
);
let mut input = vec![0x01];
input.extend_from_slice(&leaves[0]);
input.extend_from_slice(&leaves[1]);
let mut engine = sha256::Hash::engine();
engine.input(input.as_slice());
let value = sha256::Hash::from_engine(engine).to_byte_array();
assert_eq!(tree.get_leaf_proof(2), Some(vec![value.to_vec()]));
let _tree = MerkleTree::new(leaves.to_vec());
}
}