use crate::imp::core::bytes::Bytes32;
use crate::imp::core::codec::{Decode, DecodeError, Decoder, Encode, Encoder};
use crate::imp::core::hash::sha256;
use alloc::vec::Vec;
pub const LEAF_TAG: &[u8] = b"digstore:leaf:v1";
pub const NODE_TAG: &[u8] = b"digstore:node:v1";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProofStep {
pub hash: Bytes32,
pub is_left: bool,
}
impl Encode for ProofStep {
fn encode(&self, enc: &mut Encoder) {
self.hash.encode(enc);
(self.is_left as u8).encode(enc);
}
}
impl Decode for ProofStep {
fn decode(dec: &mut Decoder<'_>) -> Result<Self, DecodeError> {
let hash = Bytes32::decode(dec)?;
let flag = u8::decode(dec)?;
let is_left = match flag {
0 => false,
1 => true,
other => return Err(DecodeError::InvalidTag(other)),
};
Ok(ProofStep { hash, is_left })
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MerkleProof {
pub leaf: Bytes32,
pub path: Vec<ProofStep>,
pub root: Bytes32,
}
impl MerkleProof {
pub fn verify(&self) -> bool {
let mut acc = self.leaf;
for step in &self.path {
acc = if step.is_left {
hash_pair(&step.hash, &acc)
} else {
hash_pair(&acc, &step.hash)
};
}
acc == self.root
}
}
impl Encode for MerkleProof {
fn encode(&self, enc: &mut Encoder) {
self.leaf.encode(enc);
self.path.encode(enc);
self.root.encode(enc);
}
}
impl Decode for MerkleProof {
fn decode(dec: &mut Decoder<'_>) -> Result<Self, DecodeError> {
Ok(MerkleProof {
leaf: Bytes32::decode(dec)?,
path: Vec::<ProofStep>::decode(dec)?,
root: Bytes32::decode(dec)?,
})
}
}
fn hash_pair(left: &Bytes32, right: &Bytes32) -> Bytes32 {
let mut buf = Vec::with_capacity(NODE_TAG.len() + 64);
buf.extend_from_slice(NODE_TAG);
buf.extend_from_slice(&left.0);
buf.extend_from_slice(&right.0);
sha256(&buf)
}
fn hash_leaf(chunk: &[u8]) -> Bytes32 {
let mut buf = Vec::with_capacity(LEAF_TAG.len() + chunk.len());
buf.extend_from_slice(LEAF_TAG);
buf.extend_from_slice(chunk);
sha256(&buf)
}
pub fn resource_leaf(ciphertext: &[u8]) -> Bytes32 {
sha256(ciphertext)
}
#[derive(Debug, Clone)]
pub struct MerkleTree {
levels: Vec<Vec<Bytes32>>,
}
impl MerkleTree {
pub fn build(chunks: &[Vec<u8>]) -> MerkleTree {
let leaves: Vec<Bytes32> = chunks.iter().map(|c| hash_leaf(c)).collect();
Self::from_leaves(leaves)
}
pub fn from_leaves(leaves: Vec<Bytes32>) -> MerkleTree {
let mut levels: Vec<Vec<Bytes32>> = Vec::new();
let first = if leaves.is_empty() {
alloc::vec![sha256(&[])]
} else {
leaves
};
levels.push(first);
while levels.last().map(|l| l.len()).unwrap_or(0) > 1 {
let prev = levels.last().unwrap();
let mut next = Vec::with_capacity(prev.len().div_ceil(2));
let mut i = 0;
while i < prev.len() {
if i + 1 < prev.len() {
next.push(hash_pair(&prev[i], &prev[i + 1]));
i += 2;
} else {
next.push(prev[i]);
i += 1;
}
}
levels.push(next);
}
MerkleTree { levels }
}
pub fn root(&self) -> Bytes32 {
*self.levels.last().unwrap().last().unwrap()
}
pub fn leaf_count(&self) -> usize {
self.levels[0].len()
}
pub fn prove(&self, index: usize) -> Option<MerkleProof> {
if index >= self.leaf_count() {
return None;
}
let leaf = self.levels[0][index];
let mut path = Vec::new();
let mut idx = index;
for level in &self.levels[..self.levels.len() - 1] {
if idx.is_multiple_of(2) {
if idx + 1 < level.len() {
path.push(ProofStep {
hash: level[idx + 1],
is_left: false,
});
}
} else {
path.push(ProofStep {
hash: level[idx - 1],
is_left: true,
});
}
idx /= 2;
}
Some(MerkleProof {
leaf,
path,
root: self.root(),
})
}
}
#[cfg(all(test, not(target_arch = "wasm32")))]
mod domain_separation_tests {
use super::*;
use alloc::vec;
#[test]
fn leaf_and_node_tags_are_distinct() {
let chunk = vec![0xABu8; 13];
let leaf = hash_leaf(&chunk);
assert_ne!(leaf, sha256(&chunk), "leaf must carry the LEAF domain tag");
let node = hash_pair(&leaf, &leaf);
let mut cat = Vec::new();
cat.extend_from_slice(&leaf.0);
cat.extend_from_slice(&leaf.0);
assert_ne!(node, hash_leaf(&cat), "node tag must differ from leaf tag");
assert_ne!(node, sha256(&cat), "node must carry the NODE domain tag");
assert_ne!(LEAF_TAG, NODE_TAG);
}
}