ab_merkle_tree/sparse.rs
1//! Sparse Merkle Tree and related data structures.
2//!
3//! Sparse Merkle Tree is essentially a huge Balanced Merkle Tree, where most of the leaves are
4//! empty. By "empty" here we mean `[0u8; 32]`. To optimize proofs and their verification, the
5//! hashing function is customized and returns `[0u8; 32]` when both left and right branch are
6//! `[0u8; 32]`, otherwise BLAKE3 hash is used like in a Balanced Merkle Tree.
7
8use crate::{OUT_LEN, hash_pair};
9use core::num::NonZeroU128;
10
11/// Number of elements in a proof for a tree with `BITS`
12pub const PROOF_ELEMENTS<const BITS: u8>: usize = usize::from(BITS);
13const STACK_SIZE<const BITS: u8>: usize = usize::from(BITS) + 1;
14
15/// Ensuring only supported `NUM_BITS` can be specified for [`SparseMerkleTree`].
16///
17/// This is essentially a workaround for the current Rust type system constraints that do not allow
18/// a nicer way to do the same thing at compile time.
19const ENSURE_SUPPORTED_BITS<const BITS: u8>: usize = {
20 assert!(
21 BITS <= 128,
22 "This Sparse Merkle Tree doesn't support more than 2^128 leaves"
23 );
24
25 assert!(
26 BITS != 0,
27 "This Sparse Merkle Tree must have more than one leaf"
28 );
29
30 0
31};
32
33/// Sparse Merkle Tree Leaf
34#[derive(Debug)]
35pub enum Leaf<'a> {
36 // TODO: Batch of leaves for efficiently, especially with SIMD?
37 /// Leaf contains a value
38 Occupied {
39 /// Leaf value
40 leaf: &'a [u8; OUT_LEN],
41 },
42 /// Leaf contains a value (owned)
43 OccupiedOwned {
44 /// Leaf value
45 leaf: [u8; OUT_LEN],
46 },
47 /// Leaf is empty
48 Empty {
49 /// Number of consecutive empty leaves
50 skip_count: NonZeroU128,
51 },
52}
53
54impl<'a> From<&'a [u8; OUT_LEN]> for Leaf<'a> {
55 #[inline(always)]
56 fn from(leaf: &'a [u8; OUT_LEN]) -> Self {
57 Self::Occupied { leaf }
58 }
59}
60
61// TODO: A version that can hold intermediate nodes in memory, efficiently update leaves, etc.
62/// Sparse Merkle Tree variant that has hash-sized leaves, with most leaves being empty
63/// (have value `[0u8; 32]`).
64///
65/// In contrast to a proper Balanced Merkle Tree, constant `BITS` here specifies the max number of
66/// leaves hypothetically possible in a tree (2^BITS, often intractable), rather than the number of
67/// non-empty leaves actually present.
68#[derive(Debug)]
69pub struct SparseMerkleTree<const BITS: u8>;
70
71// TODO: Optimize by implementing SIMD-accelerated hashing of multiple values:
72// https://github.com/BLAKE3-team/BLAKE3/issues/478
73impl<const BITS: u8> SparseMerkleTree<BITS>
74where
75 [(); ENSURE_SUPPORTED_BITS::<BITS>]:,
76{
77 // TODO: Method that generates not only root, but also proof, like Unbalanced Merkle Tree
78 /// Compute Merkle Tree root.
79 ///
80 /// If provided iterator ends early, it means the rest of the leaves are empty.
81 ///
82 /// There must be no [`Leaf::Occupied`] for empty/unoccupied leaves or else they may result in
83 /// invalid root, [`Leaf::Empty`] must be used instead.
84 ///
85 /// Returns `None` if too many leaves were provided.
86 #[inline]
87 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
88 pub fn compute_root_only<'a, Iter>(leaves: Iter) -> Option<[u8; OUT_LEN]>
89 where
90 Iter: IntoIterator<Item = Leaf<'a>> + 'a,
91 {
92 // Stack of intermediate nodes per tree level
93 let mut stack = [[0u8; OUT_LEN]; _];
94 let mut processed_some = false;
95 let mut num_leaves = 0u128;
96
97 for leaf in leaves {
98 if u32::from(BITS) < u128::BITS {
99 // How many leaves were processed so far
100 if num_leaves == 2u128.pow(u32::from(BITS)) {
101 return None;
102 }
103 } else {
104 // For `BITS == u128::BITS` `num_leaves` will wrap around back to zero right at the
105 // very end
106 if processed_some && num_leaves == 0 {
107 return None;
108 }
109 processed_some = true;
110 }
111
112 let leaf = match leaf {
113 Leaf::Occupied { leaf } => *leaf,
114 Leaf::OccupiedOwned { leaf } => leaf,
115 Leaf::Empty { skip_count } => {
116 num_leaves = Self::skip_leaves(
117 &mut stack,
118 &mut processed_some,
119 num_leaves,
120 skip_count.get(),
121 )?;
122 continue;
123 }
124 };
125
126 let mut current = leaf;
127
128 // Every bit set to `1` corresponds to an active Merkle Tree level
129 let lowest_active_levels = num_leaves.trailing_ones() as usize;
130 for item in stack.iter().take(lowest_active_levels) {
131 current = hash_pair(item, ¤t);
132 }
133
134 // Place the current hash at the first inactive level
135 // SAFETY: Number of lowest active levels corresponds to the number of inserted
136 // elements, which in turn is checked above to fit into 2^BITS, while `BITS`
137 // generic in turn ensured sufficient stack size
138 *unsafe { stack.get_unchecked_mut(lowest_active_levels) } = current;
139 // Wrapping is needed for `BITS == u128::BITS`, where number of leaves narrowly
140 // doesn't fit into `u128` itself
141 num_leaves = num_leaves.wrapping_add(1);
142 }
143
144 if u32::from(BITS) < u128::BITS {
145 Self::skip_leaves(
146 &mut stack,
147 &mut processed_some,
148 num_leaves,
149 2u128.pow(u32::from(BITS)) - num_leaves,
150 )?;
151 } else if processed_some && num_leaves != 0 {
152 // For `BITS == u128::BITS` `num_leaves` will wrap around back to zero right at the
153 // very end, so we reverse the mechanism here
154 Self::skip_leaves(
155 &mut stack,
156 &mut processed_some,
157 num_leaves,
158 0u128.wrapping_sub(num_leaves),
159 )?;
160 }
161
162 Some(stack[BITS as usize])
163 }
164
165 /// Returns updated number of leaves
166 #[inline]
167 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
168 fn skip_leaves(
169 stack: &mut [[u8; OUT_LEN]; STACK_SIZE::<BITS>],
170 processed_some: &mut bool,
171 mut num_leaves: u128,
172 mut skip_count: u128,
173 ) -> Option<u128> {
174 const ZERO: [u8; OUT_LEN] = [0; OUT_LEN];
175
176 if u32::from(BITS) < u128::BITS {
177 // How many leaves were processed so far
178 if num_leaves.checked_add(skip_count)? > 2u128.pow(u32::from(BITS)) {
179 return None;
180 }
181 } else {
182 // For `BITS == u128::BITS` `num_leaves` will wrap around back to zero right at the
183 // very end
184 let (overflow_amount, overflowed) = num_leaves.overflowing_add(skip_count);
185 if *processed_some && overflowed && overflow_amount > 0 {
186 return None;
187 }
188 *processed_some = true;
189 }
190
191 while skip_count > 0 {
192 // Find the largest aligned chunk to skip for the current state of the tree
193 let max_levels_to_skip = skip_count.ilog2().min(num_leaves.trailing_zeros());
194 let chunk_size = 1u128 << max_levels_to_skip;
195
196 let mut level = max_levels_to_skip;
197 let mut current = ZERO;
198 for item in stack.iter().skip(max_levels_to_skip as usize) {
199 // Check the active level for merging up the stack.
200 //
201 // `BITS == u128::BITS` condition is only added for better dead code elimination
202 // since that check is only relevant for 2^128 leaves case and nothing else.
203 if (u32::from(BITS) == u128::BITS && level == u128::BITS)
204 || num_leaves & (1 << level) == 0
205 {
206 // Level wasn't active before, stop here
207 break;
208 }
209
210 // Hash together unless both are zero
211 if !(item == &ZERO && current == ZERO) {
212 current = hash_pair(item, ¤t);
213 }
214
215 level += 1;
216 }
217 // SAFETY: Level is limited by the number of leaves, which in turn is checked above to
218 // fit into 2^BITS, while `BITS` generic in turn ensured sufficient stack size
219 *unsafe { stack.get_unchecked_mut(level as usize) } = current;
220
221 // Wrapping is needed for `BITS == u128::BITS`, where number of leaves narrowly
222 // doesn't fit into `u128` itself
223 num_leaves = num_leaves.wrapping_add(chunk_size);
224 skip_count -= chunk_size;
225 }
226
227 Some(num_leaves)
228 }
229
230 /// Verify previously generated proof.
231 ///
232 /// Leaf can either be leaf value for a leaf that is occupied or `[0; 32]` for a leaf that is
233 /// supposed to be empty.
234 #[inline]
235 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
236 pub fn verify(
237 root: &[u8; OUT_LEN],
238 proof: &[[u8; OUT_LEN]; PROOF_ELEMENTS::<BITS>],
239 leaf_index: u128,
240 leaf: [u8; OUT_LEN],
241 ) -> bool {
242 // For `BITS == u128::BITS` any index is valid by definition
243 if u32::from(BITS) < u128::BITS && leaf_index >= 2u128.pow(u32::from(BITS)) {
244 return false;
245 }
246
247 let mut computed_root = leaf;
248
249 let mut position = leaf_index;
250 for hash in proof {
251 computed_root = if position.is_multiple_of(2) {
252 hash_pair(&computed_root, hash)
253 } else {
254 hash_pair(hash, &computed_root)
255 };
256
257 position /= 2;
258 }
259
260 root == &computed_root
261 }
262}