use crate::trie::{InternalData, LeafData, Node, NodeKind, TERMINATOR};
pub trait NodeHasher {
fn hash_leaf(data: &LeafData) -> [u8; 32];
fn hash_internal(data: &InternalData) -> [u8; 32];
fn node_kind(node: &Node) -> NodeKind;
}
pub trait ValueHasher {
fn hash_value(value: &[u8]) -> [u8; 32];
}
pub fn node_kind_by_msb(node: &Node) -> NodeKind {
if node[0] >> 7 == 1 {
NodeKind::Leaf
} else if node == &TERMINATOR {
NodeKind::Terminator
} else {
NodeKind::Internal
}
}
pub fn set_msb(node: &mut Node) {
node[0] |= 0b10000000;
}
pub fn unset_msb(node: &mut Node) {
node[0] &= 0b01111111;
}
pub trait BinaryHash {
fn hash(input: &[u8]) -> [u8; 32];
fn hash2_32_concat(left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
let mut buf = [0u8; 64];
buf[0..32].copy_from_slice(left);
buf[32..64].copy_from_slice(right);
Self::hash(&buf)
}
}
pub struct BinaryHasher<H>(core::marker::PhantomData<H>);
impl<H: BinaryHash> ValueHasher for BinaryHasher<H> {
fn hash_value(value: &[u8]) -> [u8; 32] {
H::hash(value)
}
}
impl<H: BinaryHash> NodeHasher for BinaryHasher<H> {
fn hash_leaf(data: &LeafData) -> [u8; 32] {
let mut h = H::hash2_32_concat(&data.key_path, &data.value_hash);
set_msb(&mut h);
h
}
fn hash_internal(data: &InternalData) -> [u8; 32] {
let mut h = H::hash2_32_concat(&data.left, &data.right);
unset_msb(&mut h);
h
}
fn node_kind(node: &Node) -> NodeKind {
node_kind_by_msb(node)
}
}
impl<H: digest::Digest<OutputSize = digest::typenum::U32> + Send + Sync> BinaryHash for H {
fn hash(input: &[u8]) -> [u8; 32] {
H::digest(input).into()
}
}
#[cfg(any(feature = "blake3-hasher", test))]
pub use blake3::Blake3Hasher;
#[cfg(any(feature = "blake3-hasher", test))]
pub mod blake3 {
use super::{BinaryHash, BinaryHasher};
pub struct Blake3BinaryHasher;
pub type Blake3Hasher = BinaryHasher<Blake3BinaryHasher>;
impl BinaryHash for Blake3BinaryHasher {
fn hash(value: &[u8]) -> [u8; 32] {
blake3::hash(value).into()
}
fn hash2_32_concat(left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
let mut hasher = blake3::Hasher::new();
hasher.update(left);
hasher.update(right);
hasher.finalize().into()
}
}
}
#[cfg(feature = "sha2-hasher")]
pub use sha2::Sha2Hasher;
#[cfg(feature = "sha2-hasher")]
pub mod sha2 {
use super::{BinaryHash, BinaryHasher};
use sha2::{Digest, Sha256};
pub struct Sha2BinaryHasher;
pub type Sha2Hasher = BinaryHasher<Sha2BinaryHasher>;
impl BinaryHash for Sha2BinaryHasher {
fn hash(value: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(value);
hasher.finalize().into()
}
fn hash2_32_concat(left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(left);
hasher.update(right);
hasher.finalize().into()
}
}
}