Skip to main content

javm_cap/
hash.rs

1//! Hash trait and default Blake2b-256 implementation.
2//!
3//! All v3 hash computations (image_hash chain, BMT, content-addressing)
4//! go through the `Hash` trait. `Blake2b256` is the spec default.
5//! The trait exists so we can swap in a mock hash for testing or
6//! a different hash function later without churning call sites.
7
8use alloc::vec::Vec;
9
10/// Hash function abstraction.
11///
12/// Implementations are stateless types (typically unit structs);
13/// `hash` is a pure function from bytes to a fixed-size digest.
14pub trait Hash {
15    /// Digest type. Must be `Copy` for use in BMT and cap fields.
16    type Out: Copy + Eq + core::fmt::Debug;
17
18    /// Hash a byte slice.
19    fn hash(bytes: &[u8]) -> Self::Out;
20
21    /// Hash the concatenation of two byte slices, without
22    /// materializing the concatenation. Default impl just allocates;
23    /// implementations should override for efficiency where possible.
24    fn hash_pair(a: &[u8], b: &[u8]) -> Self::Out {
25        let mut buf = Vec::with_capacity(a.len() + b.len());
26        buf.extend_from_slice(a);
27        buf.extend_from_slice(b);
28        Self::hash(&buf)
29    }
30}
31
32/// Default v3 hash: Blake2b-256 (32-byte output).
33pub struct Blake2b256;
34
35impl Hash for Blake2b256 {
36    type Out = [u8; 32];
37
38    fn hash(bytes: &[u8]) -> Self::Out {
39        use blake2::digest::{Update, VariableOutput};
40        let mut hasher = blake2::Blake2bVar::new(32).expect("32 ≤ Blake2b max output");
41        hasher.update(bytes);
42        let mut out = [0u8; 32];
43        hasher.finalize_variable(&mut out).expect("32-byte buffer");
44        out
45    }
46
47    fn hash_pair(a: &[u8], b: &[u8]) -> Self::Out {
48        use blake2::digest::{Update, VariableOutput};
49        let mut hasher = blake2::Blake2bVar::new(32).expect("32 ≤ Blake2b max output");
50        hasher.update(a);
51        hasher.update(b);
52        let mut out = [0u8; 32];
53        hasher.finalize_variable(&mut out).expect("32-byte buffer");
54        out
55    }
56}
57
58/// Central alias for content-addressing and the few places that deliberately
59/// need fixed-width derived keys.
60///
61/// TODO(hash-unify): this is Blake2b-256, but the SSZ merkle digest used by
62/// [`crate::cap::Cap::cap_hash`] (`ssz::hash_tree_root`, the `ssz` `sha2`
63/// feature) is Sha256. The two hashes should eventually be unified —
64/// probably switch everything to Sha256. Centralised here so the swap is a
65/// one-line change.
66pub type Hasher = Blake2b256;