use merkle_core::traits::HashFunction;
use sha2::{Digest as Sha2Digest, Sha256 as Sha2_256};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Sha256;
impl HashFunction for Sha256 {
type Digest = [u8; 32];
#[inline]
fn hash_nodes(left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
let mut hasher = Sha2_256::new();
hasher.update([0x01]); hasher.update(left);
hasher.update(right);
hasher.finalize().into()
}
#[inline]
fn hash(data: &[u8]) -> [u8; 32] {
let mut hasher = Sha2_256::new();
hasher.update([0x00]); hasher.update(data);
hasher.finalize().into()
}
#[inline]
fn empty() -> [u8; 32] {
[
0x6e, 0x34, 0x0b, 0x9c, 0xff, 0xb3, 0x7a, 0x98, 0x9c, 0xa5, 0x44, 0xe6, 0xbb, 0x78,
0x0a, 0x2c, 0x78, 0x90, 0x1d, 0x3f, 0xb3, 0x37, 0x38, 0x76, 0x85, 0x11, 0xa3, 0x06,
0x17, 0xaf, 0xa0, 0x1d,
]
}
fn algorithm_name() -> &'static str {
"SHA-256"
}
fn digest_size() -> usize {
32
}
}
#[cfg(test)]
mod tests {
use super::*;
const MERKLE_EMPTY_SENTINEL: [u8; 32] = [
0x6e, 0x34, 0x0b, 0x9c, 0xff, 0xb3, 0x7a, 0x98, 0x9c, 0xa5, 0x44, 0xe6, 0xbb, 0x78, 0x0a,
0x2c, 0x78, 0x90, 0x1d, 0x3f, 0xb3, 0x37, 0x38, 0x76, 0x85, 0x11, 0xa3, 0x06, 0x17, 0xaf,
0xa0, 0x1d,
];
#[test]
fn digest_size_is_32() {
assert_eq!(Sha256::digest_size(), 32);
}
#[test]
fn algorithm_name() {
assert_eq!(Sha256::algorithm_name(), "SHA-256");
}
#[test]
fn hash_is_deterministic() {
let input = b"merkleforge-test";
assert_eq!(Sha256::hash(input), Sha256::hash(input));
}
#[test]
fn empty_matches_precomputed() {
let mut h = Sha2_256::new();
h.update([0x00u8]);
let manual_compute: [u8; 32] = h.finalize().into();
assert_eq!(
Sha256::empty(),
manual_compute,
"Precomputed empty() must match SHA-256(0x00)"
);
assert_eq!(Sha256::empty(), MERKLE_EMPTY_SENTINEL);
}
#[test]
fn hash_nodes_non_commutative() {
let a = [0x11u8; 32];
let b = [0x22u8; 32];
assert_ne!(Sha256::hash_nodes(&a, &b), Sha256::hash_nodes(&b, &a));
}
#[test]
fn leaf_and_node_domain_separation() {
let data = [0xAAu8; 32];
let dummy = [0x00u8; 32];
let leaf_h = Sha256::hash(&data);
let node_h = Sha256::hash_nodes(&data, &dummy);
assert_ne!(
leaf_h, node_h,
"Leaf and Internal Node hashes must be domain-separated"
);
}
#[test]
fn different_inputs_different_hashes() {
assert_ne!(Sha256::hash(b"leaf1"), Sha256::hash(b"leaf2"));
}
}