pub const MERKLE_OCTREE_NODES: usize = 73;
pub const MERKLE_OCTREE_LEAVES: usize = 64;
pub const MERKLE_OCTREE_BRANCHING: usize = 8;
pub const HASH_SIZE: usize = 32;
pub const MERKLE_OCTREE_INTERNAL: usize = 8;
pub const MERKLE_OCTREE_DEPTH: u8 = 3;
#[derive(Clone, Debug)]
pub struct MerkleOctree {
pub hashes: [[u8; HASH_SIZE]; MERKLE_OCTREE_NODES],
}
impl MerkleOctree {
pub const ZERO: Self = Self {
hashes: [[0u8; HASH_SIZE]; MERKLE_OCTREE_NODES],
};
pub fn build_from_leaves(leaf_hashes: &[[u8; HASH_SIZE]; MERKLE_OCTREE_LEAVES]) -> Self {
let mut tree = Self::ZERO;
tree.hashes[MERKLE_OCTREE_INTERNAL + 1..=MERKLE_OCTREE_INTERNAL + MERKLE_OCTREE_LEAVES]
.copy_from_slice(leaf_hashes);
for i in (1..=MERKLE_OCTREE_INTERNAL).rev() {
let child_start = i * MERKLE_OCTREE_BRANCHING + 1;
tree.hashes[i] = Self::hash_children(
&tree.hashes[child_start..child_start + MERKLE_OCTREE_BRANCHING],
);
}
tree.hashes[0] = Self::hash_children(&tree.hashes[1..=MERKLE_OCTREE_INTERNAL]);
tree
}
pub fn build_from_raw_leaves(leaf_data_blocks: &[&[u8]]) -> Self {
let mut leaf_hashes = [[0u8; HASH_SIZE]; MERKLE_OCTREE_LEAVES];
for (i, block) in leaf_data_blocks.iter().enumerate() {
if i >= MERKLE_OCTREE_LEAVES {
break;
}
leaf_hashes[i] = *blake3::hash(block).as_bytes();
}
Self::build_from_leaves(&leaf_hashes)
}
#[inline(always)]
pub fn root(&self) -> &[u8; HASH_SIZE] {
&self.hashes[0]
}
#[inline(always)]
pub fn leaf_hash(&self, leaf_index: usize) -> Option<&[u8; HASH_SIZE]> {
if leaf_index < MERKLE_OCTREE_LEAVES {
Some(&self.hashes[MERKLE_OCTREE_INTERNAL + 1 + leaf_index])
} else {
None
}
}
#[inline(always)]
pub fn internal_hash(&self, internal_index: usize) -> Option<&[u8; HASH_SIZE]> {
if internal_index < MERKLE_OCTREE_INTERNAL {
Some(&self.hashes[1 + internal_index])
} else {
None
}
}
#[inline(always)]
fn hash_children(children: &[[u8; HASH_SIZE]]) -> [u8; HASH_SIZE] {
let mut hasher = blake3::Hasher::new();
for child in children {
hasher.update(child);
}
*hasher.finalize().as_bytes()
}
}
#[derive(Clone, Debug)]
pub struct MerkleProof {
pub leaf_index: u8,
pub leaf_hash: [u8; HASH_SIZE],
pub siblings: [[u8; HASH_SIZE]; Self::SIBLING_LEVELS * Self::SIBLINGS_PER_LEVEL],
}
impl MerkleProof {
const SIBLINGS_PER_LEVEL: usize = MERKLE_OCTREE_BRANCHING - 1;
const SIBLING_LEVELS: usize = MERKLE_OCTREE_DEPTH as usize - 1;
pub fn generate(tree: &MerkleOctree, leaf_index: u8) -> Option<Self> {
if leaf_index as usize >= MERKLE_OCTREE_LEAVES {
return None;
}
let leaf_hash = tree.hashes[MERKLE_OCTREE_INTERNAL + 1 + leaf_index as usize];
let mut siblings = [[0u8; HASH_SIZE]; Self::SIBLING_LEVELS * Self::SIBLINGS_PER_LEVEL];
let mut current_idx = MERKLE_OCTREE_INTERNAL + 1 + leaf_index as usize;
for level in 0..Self::SIBLING_LEVELS {
let parent_idx = (current_idx - 1) / MERKLE_OCTREE_BRANCHING;
let child_start = parent_idx * MERKLE_OCTREE_BRANCHING + 1;
let mut sib_idx = 0;
for c in 0..MERKLE_OCTREE_BRANCHING {
let child_idx = child_start + c;
if child_idx != current_idx {
siblings[level * Self::SIBLINGS_PER_LEVEL + sib_idx] = tree.hashes[child_idx];
sib_idx += 1;
}
}
current_idx = parent_idx;
}
Some(Self {
leaf_index,
leaf_hash,
siblings,
})
}
pub fn verify(&self, expected_root: &[u8; HASH_SIZE]) -> bool {
let mut current_hash = self.leaf_hash;
let mut current_idx = MERKLE_OCTREE_INTERNAL + 1 + self.leaf_index as usize;
for level in 0..Self::SIBLING_LEVELS {
let parent_idx = (current_idx - 1) / MERKLE_OCTREE_BRANCHING;
let child_start = parent_idx * MERKLE_OCTREE_BRANCHING + 1;
let position_in_parent = current_idx - child_start;
let mut hasher = blake3::Hasher::new();
let mut sib_idx = 0;
for c in 0..MERKLE_OCTREE_BRANCHING {
if c == position_in_parent {
hasher.update(¤t_hash);
} else {
hasher.update(&self.siblings[level * Self::SIBLINGS_PER_LEVEL + sib_idx]);
sib_idx += 1;
}
}
current_hash = *hasher.finalize().as_bytes();
current_idx = parent_idx;
}
current_hash == *expected_root
}
}