ab_merkle_tree/lib.rs
1//! High-performance Merkle Tree and related data structures (Merkle Mountain Range, Sparse Merkle
2//! Tree).
3//!
4//! This crate contains several high-performance Merkle Tree implementations and related data
5//! structures, many of which are a subset of each other.
6//!
7//! These implementations can be an order of magnitude faster than traditional implementations by
8//! leveraging the ability of hash functions like BLAKE3 to hash multiple blocks at once with SIMD.
9//! Typical Merkle Tree crates only allow customizing a hash function of two leaves, which makes it
10//! impossible to benefit from the inherent strength of such hash functions.
11//!
12//! Currently [`BalancedMerkleTree`], [`UnbalancedMerkleTree`], [`MerkleMountainRange`] and
13//! [`SparseMerkleTree`] are available.
14//!
15//! [`BalancedMerkleTree`] is an optimized special case of [`UnbalancedMerkleTree`], which is in
16//! turn an optimized version of [`MerkleMountainRange`], and all 3 will return the same results for
17//! identical inputs and hasher.
18//!
19//! [`SparseMerkleTree`] is a special kind of Merkle Tree, usually of intractable size, where most
20//! of the leaves are empty (missing). It will also produce the same root as other trees in case the
21//! tree doesn't have any empty leaves, though it is unlikely to happen in practice.
22//!
23//! [`BalancedMerkleTree`]: balanced::BalancedMerkleTree
24//! [`MerkleMountainRange`]: mmr::MerkleMountainRange
25//! [`UnbalancedMerkleTree`]: unbalanced::UnbalancedMerkleTree
26//! [`SparseMerkleTree`]: sparse::SparseMerkleTree
27//!
28//! All trees are generic over [`MerkleHasher`], which can hash many pairs of nodes at once and
29//! defines the size of nodes. Hashers are created with [`Default`] when they don't depend on the
30//! number of leaves, otherwise with [`NewMerkleHasherForTreeSize`], which is implemented for all
31//! hashers that implement [`Default`]. Trees that don't know the number of leaves upfront, like
32//! [`MerkleMountainRange`], only support hashers that implement [`Default`].
33//!
34//! `blake3` module contains the BLAKE3 hasher and aliases of all trees that use it (requires
35//! `blake3` feature).
36//!
37//! Does not require a standard library (`no_std`), most APIs are usable without an allocator, never
38//! panics.
39
40#![expect(incomplete_features, reason = "generic_const_*")]
41#![feature(
42 const_block_items,
43 const_convert,
44 const_default,
45 const_trait_impl,
46 gca_const_items,
47 gca_macroless_args,
48 gca_min_const_items,
49 generic_const_items,
50 iter_advance_by,
51 maybe_uninit_uninit_array_transpose,
52 phantom_variance_markers,
53 trusted_len
54)]
55#![no_std]
56
57pub mod balanced;
58#[cfg(feature = "blake3")]
59pub mod blake3;
60pub mod mmr;
61pub mod sparse;
62pub mod unbalanced;
63
64#[cfg(feature = "alloc")]
65extern crate alloc;
66
67use core::mem;
68
69/// Hash function for inner nodes of Merkle Trees.
70///
71/// Hashing of many pairs at once is a part of the API, such that hash functions like BLAKE3 can use
72/// SIMD to hash multiple pairs in parallel.
73pub trait MerkleHasher {
74 /// Size of a node hash in bytes
75 const OUT_LEN: usize;
76
77 /// Hash a pair of nodes together
78 fn hash_pair(&self, pair: &[[u8; Self::OUT_LEN]; 2]) -> [u8; Self::OUT_LEN];
79
80 /// Similar to [`Self::hash_pair()`], but hashes multiple pairs at once.
81 ///
82 /// The default implementation hashes pairs one by one, hash functions that can do better
83 /// should override it. An override must return the same as [`Self::hash_pair()`] for each pair,
84 /// because trees mix both.
85 #[inline(always)]
86 fn hash_pairs<const NUM_PAIRS: usize>(
87 &self,
88 pairs: &[[[u8; Self::OUT_LEN]; 2]; NUM_PAIRS],
89 ) -> [[u8; Self::OUT_LEN]; NUM_PAIRS] {
90 pairs.each_ref().map(|pair| self.hash_pair(pair))
91 }
92
93 /// Root of an [`UnbalancedMerkleTree`] or [`MerkleMountainRange`] with a single leaf.
94 ///
95 /// The default implementation returns the leaf unchanged, which keeps a tree of trees the
96 /// same as a single larger tree. Hashers that depend on the tree size should hash the leaf
97 /// instead, otherwise the size isn't committed to when the tree has a single leaf and no inner
98 /// nodes.
99 ///
100 /// [`UnbalancedMerkleTree`]: unbalanced::UnbalancedMerkleTree
101 /// [`MerkleMountainRange`]: mmr::MerkleMountainRange
102 #[inline(always)]
103 fn hash_single_leaf(&self, leaf: &[u8; Self::OUT_LEN]) -> [u8; Self::OUT_LEN] {
104 *leaf
105 }
106}
107
108/// Creates hashers for trees with a known number of leaves.
109///
110/// A hasher either ignores the tree size, in which case it implements [`Default`] and gets this
111/// trait through the blanket implementation, or depends on it, in which case it implements this
112/// trait directly and must not implement [`Default`]. It can't be both: the two implementations
113/// would conflict.
114pub const trait NewMerkleHasherForTreeSize: Sized {
115 /// Create a hasher for a tree with `num_leaves` leaves
116 fn new_for_tree_size(num_leaves: u64) -> Self;
117}
118
119/// Hashers that implement [`Default`] ignore the tree size
120const impl<H> NewMerkleHasherForTreeSize for H
121where
122 H: [const] Default,
123{
124 #[inline(always)]
125 fn new_for_tree_size(_num_leaves: u64) -> Self {
126 H::default()
127 }
128}
129
130// TODO: Combine `NUM_PAIRS` and `NUM_LEAVES` into a single generic parameter once compiler is
131// smart enough to deal with it
132/// Similar to [`MerkleHasher::hash_pairs()`], but takes pairs as a flat list of nodes.
133///
134/// # Panics
135/// Panics when `NUM_LEAVES != NUM_PAIRS * 2`.
136#[inline(always)]
137// TODO: Unlock on RISC-V, it started failing since https://github.com/nazar-pc/abundance/pull/551
138// for unknown reason
139#[cfg_attr(
140 all(feature = "no-panic", not(target_arch = "riscv64")),
141 no_panic::no_panic
142)]
143fn hash_pairs<const NUM_PAIRS: usize, const NUM_LEAVES: usize, H>(
144 hasher: &H,
145 leaves: &[[u8; H::OUT_LEN]; NUM_LEAVES],
146) -> [[u8; H::OUT_LEN]; NUM_PAIRS]
147where
148 H: MerkleHasher,
149{
150 // This protects the invariant of the function
151 assert_eq!(NUM_LEAVES, NUM_PAIRS * 2);
152
153 // SAFETY: Same size (checked above) and alignment
154 let pairs = unsafe {
155 mem::transmute::<&[[u8; H::OUT_LEN]; NUM_LEAVES], &[[[u8; H::OUT_LEN]; 2]; NUM_PAIRS]>(
156 leaves,
157 )
158 };
159 hasher.hash_pairs(pairs)
160}