dig_block/hash.rs
1//! Tagged Merkle hashing for **binary** Merkle trees (HSH-007).
2//!
3//! **Normative:** [HSH-007](docs/requirements/domains/hashing/specs/HSH-007.md) / [hashing NORMATIVE](docs/requirements/domains/hashing/NORMATIVE.md)
4//! **Crate spec:** [SPEC §3.3](docs/resources/SPEC.md)
5//! **Prefixes:** [`crate::HASH_LEAF_PREFIX`] and [`crate::HASH_TREE_PREFIX`] ([BLK-005](docs/requirements/domains/block_types/specs/BLK-005.md)).
6//!
7//! ## What this module is for
8//!
9//! - [`hash_leaf`] and [`hash_node`] are the explicit SHA-256 formulas Chia uses for **leaf** and **internal**
10//! nodes in [`chia_sdk_types::MerkleTree`] (see `merkle_tree.rs` in that crate: `HASH_LEAF_PREFIX = &[1]`,
11//! `HASH_TREE_PREFIX = &[2]` — [upstream source](https://github.com/Chia-Network/chia-sdk/blob/main/crates/chia-sdk-types/src/merkle_tree.rs)).
12//! - DIG block code builds those trees via the crate-internal `merkle_util::merkle_tree_root` helper and direct `chia_sdk_types::MerkleTree::new`
13//! calls; **do not** hand-roll a parallel Merkle implementation with different tags.
14//!
15//! ## What this is *not*
16//!
17//! - [`chia_consensus::merkle_set::compute_merkle_set_root`] (additions/removals roots) uses Chia’s **radix / sorted-set**
18//! tree and a **different** internal `hash(ltype, rtype, left, right)` — not `0x01||data` / `0x02||a||b`.
19//! That path is correct for HSH-004/HSH-005 but is **out of scope** for the formulas in this file (see the crate-internal `merkle_util` module for Merkle-set callers).
20//!
21//! ## Rationale
22//!
23//! Exposing [`hash_leaf`] / [`hash_node`] makes the domain separation **testable** and gives downstream crates a
24//! single place to name the tagging scheme, while the actual tree shape remains delegated to `chia-sdk-types`.
25
26use chia_protocol::Bytes32;
27use chia_sha2::Sha256;
28
29use crate::constants::{HASH_LEAF_PREFIX, HASH_TREE_PREFIX};
30
31/// Leaf digest: **SHA-256( [`HASH_LEAF_PREFIX`](crate::HASH_LEAF_PREFIX) ‖ `data` )** ([SPEC §3.3](docs/resources/SPEC.md)).
32///
33/// For a [`Bytes32`] leaf value `v` in [`chia_sdk_types::MerkleTree`], this is exactly the digest
34/// mixed at the leaf level. Matches Chia's `merkle_utils.py` leaf formula.
35///
36/// **Chia source:** [`merkle_tree.rs` HASH_LEAF_PREFIX](https://github.com/Chia-Network/chia-sdk/blob/main/crates/chia-sdk-types/src/merkle_tree.rs).
37#[must_use]
38pub fn hash_leaf(data: &[u8]) -> Bytes32 {
39 let mut hasher = Sha256::new();
40 hasher.update([HASH_LEAF_PREFIX]);
41 hasher.update(data);
42 Bytes32::new(hasher.finalize())
43}
44
45/// Internal node digest: **SHA-256( [`HASH_TREE_PREFIX`](crate::HASH_TREE_PREFIX) ‖ `left` ‖ `right` )** ([SPEC §3.3](docs/resources/SPEC.md)).
46///
47/// Combines two **already-hashed** child digests (typically outputs of [`hash_leaf`] or nested
48/// [`hash_node`] results). Prevents second-preimage attacks where a valid Merkle proof for a leaf
49/// could be reinterpreted as an internal node ([SPEC §1.3 Decision 13](docs/resources/SPEC.md)).
50///
51/// **Chia source:** [`merkle_tree.rs` HASH_TREE_PREFIX](https://github.com/Chia-Network/chia-sdk/blob/main/crates/chia-sdk-types/src/merkle_tree.rs).
52#[must_use]
53pub fn hash_node(left: &Bytes32, right: &Bytes32) -> Bytes32 {
54 let mut hasher = Sha256::new();
55 hasher.update([HASH_TREE_PREFIX]);
56 hasher.update(left.as_ref());
57 hasher.update(right.as_ref());
58 Bytes32::new(hasher.finalize())
59}