use sha2::{Digest, Sha256};
pub const MERKLE_BLOCK_SIZE: usize = 16384;
pub struct MerkleTree {
leaves: Vec<[u8; 32]>,
nodes: Vec<[u8; 32]>,
}
impl MerkleTree {
pub fn new() -> Self {
Self {
leaves: Vec::new(),
nodes: Vec::new(),
}
}
pub fn from_piece_hashes(hashes: Vec<[u8; 32]>) -> Self {
let mut tree = Self {
leaves: hashes,
nodes: Vec::new(),
};
tree.build();
tree
}
pub fn add_leaf(&mut self, hash: [u8; 32]) {
self.leaves.push(hash);
}
pub fn build(&mut self) {
if self.leaves.is_empty() {
return;
}
let leaf_count = self.leaves.len().next_power_of_two();
let mut level: Vec<[u8; 32]> = self.leaves.clone();
while level.len() < leaf_count {
level.push([0u8; 32]);
}
self.nodes.clear();
self.nodes.extend_from_slice(&level);
while level.len() > 1 {
let mut next_level = Vec::with_capacity(level.len() / 2);
for chunk in level.chunks(2) {
let hash = hash_pair(&chunk[0], &chunk[1]);
next_level.push(hash);
}
self.nodes.extend_from_slice(&next_level);
level = next_level;
}
}
pub fn root(&self) -> Option<[u8; 32]> {
self.nodes.last().copied()
}
pub fn proof(&self, leaf_index: usize) -> Option<Vec<[u8; 32]>> {
if leaf_index >= self.leaves.len() {
return None;
}
let leaf_count = self.leaves.len().next_power_of_two();
let mut proof = Vec::new();
let mut index = leaf_index;
let mut level_start = 0;
let mut level_size = leaf_count;
while level_size > 1 {
let sibling_index = if index % 2 == 0 { index + 1 } else { index - 1 };
if level_start + sibling_index < self.nodes.len() {
proof.push(self.nodes[level_start + sibling_index]);
}
level_start += level_size;
level_size /= 2;
index /= 2;
}
Some(proof)
}
pub fn verify(root: &[u8; 32], leaf: &[u8; 32], index: usize, proof: &[[u8; 32]]) -> bool {
let mut hash = *leaf;
let mut idx = index;
for sibling in proof {
hash = if idx % 2 == 0 {
hash_pair(&hash, sibling)
} else {
hash_pair(sibling, &hash)
};
idx /= 2;
}
&hash == root
}
pub fn leaf_count(&self) -> usize {
self.leaves.len()
}
}
impl Default for MerkleTree {
fn default() -> Self {
Self::new()
}
}
fn hash_pair(left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(left);
hasher.update(right);
hasher.finalize().into()
}
pub fn hash_block(data: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize().into()
}
pub fn hash_data_blocks(data: &[u8]) -> Vec<[u8; 32]> {
data.chunks(MERKLE_BLOCK_SIZE).map(hash_block).collect()
}
pub fn compute_root(data: &[u8]) -> [u8; 32] {
let block_hashes = hash_data_blocks(data);
if block_hashes.is_empty() {
return [0u8; 32];
}
let tree = MerkleTree::from_piece_hashes(block_hashes);
tree.root().unwrap_or([0u8; 32])
}
pub fn verify_piece(data: &[u8], expected_root: &[u8; 32]) -> bool {
let computed_root = compute_root(data);
&computed_root == expected_root
}
pub fn verify_piece_layer(data: &[u8], expected_hash: &[u8; 32], piece_length: u64) -> bool {
if data.is_empty() {
return false;
}
let mut block_hashes = hash_data_blocks(data);
let full_piece_blocks = (piece_length as usize).div_ceil(MERKLE_BLOCK_SIZE);
while block_hashes.len() < full_piece_blocks {
block_hashes.push([0u8; 32]);
}
let tree = MerkleTree::from_piece_hashes(block_hashes);
let computed = tree.root().unwrap_or([0u8; 32]);
&computed == expected_hash
}
pub fn compute_piece_root(data: &[u8], piece_length: u64) -> [u8; 32] {
if data.is_empty() {
return [0u8; 32];
}
let mut block_hashes = hash_data_blocks(data);
let full_piece_blocks = (piece_length as usize).div_ceil(MERKLE_BLOCK_SIZE);
while block_hashes.len() < full_piece_blocks {
block_hashes.push([0u8; 32]);
}
let tree = MerkleTree::from_piece_hashes(block_hashes);
tree.root().unwrap_or([0u8; 32])
}
pub fn generate_proof_hashes(
tree: &MerkleTree,
base_layer: usize,
start_index: usize,
count: usize,
proof_layers: usize,
) -> Vec<[u8; 32]> {
if proof_layers == 0 || tree.nodes.is_empty() {
return Vec::new();
}
let leaf_count = tree.leaves.len().next_power_of_two();
let mut proof_hashes = Vec::with_capacity(proof_layers);
let scale = 1usize << base_layer;
let effective_start = start_index * scale;
let effective_end = effective_start + count * scale;
let mut current_start = effective_start;
let mut current_end = effective_end;
let mut level_size = leaf_count >> base_layer;
let mut level_start = calculate_level_start(leaf_count, base_layer);
for _ in 0..proof_layers {
if level_size <= 1 {
break;
}
let parent_start = current_start / 2;
let parent_end = current_end.div_ceil(2);
let uncle_index = if current_start % 2 == 0 {
current_end
} else {
current_start - 1
};
let uncle_index = uncle_index.min(level_size - 1);
if level_start + uncle_index < tree.nodes.len() {
proof_hashes.push(tree.nodes[level_start + uncle_index]);
}
current_start = parent_start;
current_end = parent_end;
level_start += level_size;
level_size /= 2;
}
proof_hashes
}
fn calculate_level_start(leaf_count: usize, level: usize) -> usize {
let mut start = 0;
let mut size = leaf_count;
for _ in 0..level {
start += size;
size /= 2;
}
start
}
pub fn extract_layer_hashes(
tree: &MerkleTree,
layer: usize,
start_index: usize,
count: usize,
) -> Vec<[u8; 32]> {
if tree.nodes.is_empty() {
return Vec::new();
}
let leaf_count = tree.leaves.len().next_power_of_two();
let level_size = leaf_count >> layer;
if level_size == 0 || start_index >= level_size {
return Vec::new();
}
let level_start = calculate_level_start(leaf_count, layer);
let actual_count = count.min(level_size - start_index);
tree.nodes[level_start + start_index..level_start + start_index + actual_count].to_vec()
}