arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/merkle/tiered_smt/mod.rs
src/merkle/tiered_smt/mod.rsRaw
  1use super::{
  2    BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, NodeIndex,
  3    Rpo256, RpoDigest, StarkField, Vec, Word,
  4};
  5use crate::utils::vec;
  6use core::{cmp, ops::Deref};
  7
  8mod nodes;
  9use nodes::NodeStore;
 10
 11mod values;
 12use values::ValueStore;
 13
 14mod proof;
 15pub use proof::TieredSmtProof;
 16
 17mod error;
 18pub use error::TieredSmtProofError;
 19
 20#[cfg(test)]
 21mod tests;
 22
 23// TIERED SPARSE MERKLE TREE
 24// ================================================================================================
 25
 26/// Tiered (compacted) Sparse Merkle tree mapping 256-bit keys to 256-bit values. Both keys and
 27/// values are represented by 4 field elements.
 28///
 29/// Leaves in the tree can exist only on specific depths called "tiers". These depths are: 16, 32,
 30/// 48, and 64. Initially, when a tree is empty, it is equivalent to an empty Sparse Merkle tree
 31/// of depth 64 (i.e., leaves at depth 64 are set to [ZERO; 4]). As non-empty values are inserted
 32/// into the tree they are added to the first available tier.
 33///
 34/// For example, when the first key-value pair is inserted, it will be stored in a node at depth
 35/// 16 such that the 16 most significant bits of the key determine the position of the node at
 36/// depth 16. If another value with a key sharing the same 16-bit prefix is inserted, both values
 37/// move into the next tier (depth 32). This process is repeated until values end up at the bottom
 38/// tier (depth 64). If multiple values have keys with a common 64-bit prefix, such key-value pairs
 39/// are stored in a sorted list at the bottom tier.
 40///
 41/// To differentiate between internal and leaf nodes, node values are computed as follows:
 42/// - Internal nodes: hash(left_child, right_child).
 43/// - Leaf node at depths 16, 32, or 64: hash(key, value, domain=depth).
 44/// - Leaf node at depth 64: hash([key_0, value_0, ..., key_n, value_n], domain=64).
 45#[derive(Debug, Clone, PartialEq, Eq)]
 46pub struct TieredSmt {
 47    root: RpoDigest,
 48    nodes: NodeStore,
 49    values: ValueStore,
 50}
 51
 52impl TieredSmt {
 53    // CONSTANTS
 54    // --------------------------------------------------------------------------------------------
 55
 56    /// The number of levels between tiers.
 57    const TIER_SIZE: u8 = 16;
 58
 59    /// Depths at which leaves can exist in a tiered SMT.
 60    const TIER_DEPTHS: [u8; 4] = [16, 32, 48, 64];
 61
 62    /// Maximum node depth. This is also the bottom tier of the tree.
 63    const MAX_DEPTH: u8 = 64;
 64
 65    /// Value of an empty leaf.
 66    pub const EMPTY_VALUE: Word = super::empty_roots::EMPTY_WORD;
 67
 68    // CONSTRUCTORS
 69    // --------------------------------------------------------------------------------------------
 70
 71    /// Returns a new [TieredSmt] instantiated with the specified key-value pairs.
 72    ///
 73    /// # Errors
 74    /// Returns an error if the provided entries contain multiple values for the same key.
 75    pub fn with_leaves<R, I>(entries: R) -> Result<Self, MerkleError>
 76    where
 77        R: IntoIterator<IntoIter = I>,
 78        I: Iterator<Item = (RpoDigest, Word)> + ExactSizeIterator,
 79    {
 80        // create an empty tree
 81        let mut tree = Self::default();
 82
 83        // append leaves to the tree returning an error if a duplicate entry for the same key
 84        // is found
 85        let mut empty_entries = BTreeSet::new();
 86        for (key, value) in entries {
 87            let old_value = tree.insert(key, value);
 88            if old_value != Self::EMPTY_VALUE || empty_entries.contains(&key) {
 89                return Err(MerkleError::DuplicateValuesForKey(key));
 90            }
 91            // if we've processed an empty entry, add the key to the set of empty entry keys, and
 92            // if this key was already in the set, return an error
 93            if value == Self::EMPTY_VALUE && !empty_entries.insert(key) {
 94                return Err(MerkleError::DuplicateValuesForKey(key));
 95            }
 96        }
 97        Ok(tree)
 98    }
 99
100    // PUBLIC ACCESSORS
101    // --------------------------------------------------------------------------------------------
102
103    /// Returns the root of this Merkle tree.
104    pub const fn root(&self) -> RpoDigest {
105        self.root
106    }
107
108    /// Returns a node at the specified index.
109    ///
110    /// # Errors
111    /// Returns an error if:
112    /// - The specified index depth is 0 or greater than 64.
113    /// - The node with the specified index does not exists in the Merkle tree. This is possible
114    ///   when a leaf node with the same index prefix exists at a tier higher than the requested
115    ///   node.
116    pub fn get_node(&self, index: NodeIndex) -> Result<RpoDigest, MerkleError> {
117        self.nodes.get_node(index)
118    }
119
120    /// Returns a Merkle path from the node at the specified index to the root.
121    ///
122    /// The node itself is not included in the path.
123    ///
124    /// # Errors
125    /// Returns an error if:
126    /// - The specified index depth is 0 or greater than 64.
127    /// - The node with the specified index does not exists in the Merkle tree. This is possible
128    ///   when a leaf node with the same index prefix exists at a tier higher than the node to
129    ///   which the path is requested.
130    pub fn get_path(&self, index: NodeIndex) -> Result<MerklePath, MerkleError> {
131        self.nodes.get_path(index)
132    }
133
134    /// Returns the value associated with the specified key.
135    ///
136    /// If nothing was inserted into this tree for the specified key, [ZERO; 4] is returned.
137    pub fn get_value(&self, key: RpoDigest) -> Word {
138        match self.values.get(&key) {
139            Some(value) => *value,
140            None => Self::EMPTY_VALUE,
141        }
142    }
143
144    /// Returns a proof for a key-value pair defined by the specified key.
145    ///
146    /// The proof can be used to attest membership of this key-value pair in a Tiered Sparse Merkle
147    /// Tree defined by the same root as this tree.
148    pub fn prove(&self, key: RpoDigest) -> TieredSmtProof {
149        let (path, index, leaf_exists) = self.nodes.get_proof(&key);
150
151        let entries = if index.depth() == Self::MAX_DEPTH {
152            match self.values.get_all(index.value()) {
153                Some(entries) => entries,
154                None => vec![(key, Self::EMPTY_VALUE)],
155            }
156        } else if leaf_exists {
157            let entry =
158                self.values.get_first(index_to_prefix(&index)).expect("leaf entry not found");
159            debug_assert_eq!(entry.0, key);
160            vec![*entry]
161        } else {
162            vec![(key, Self::EMPTY_VALUE)]
163        };
164
165        TieredSmtProof::new(path, entries).expect("Bug detected, TSMT produced invalid proof")
166    }
167
168    // STATE MUTATORS
169    // --------------------------------------------------------------------------------------------
170
171    /// Inserts the provided value into the tree under the specified key and returns the value
172    /// previously stored under this key.
173    ///
174    /// If the value for the specified key was not previously set, [ZERO; 4] is returned.
175    pub fn insert(&mut self, key: RpoDigest, value: Word) -> Word {
176        // if an empty value is being inserted, remove the leaf node to make it look as if the
177        // value was never inserted
178        if value == Self::EMPTY_VALUE {
179            return self.remove_leaf_node(key);
180        }
181
182        // insert the value into the value store, and if the key was already in the store, update
183        // it with the new value
184        if let Some(old_value) = self.values.insert(key, value) {
185            if old_value != value {
186                // if the new value is different from the old value, determine the location of
187                // the leaf node for this key, build the node, and update the root
188                let (index, leaf_exists) = self.nodes.get_leaf_index(&key);
189                debug_assert!(leaf_exists);
190                let node = self.build_leaf_node(index, key, value);
191                self.root = self.nodes.update_leaf_node(index, node);
192            }
193            return old_value;
194        };
195
196        // determine the location for the leaf node; this index could have 3 different meanings:
197        // - it points to a root of an empty subtree or an empty node at depth 64; in this case,
198        //   we can replace the node with the value node immediately.
199        // - it points to an existing leaf at the bottom tier (i.e., depth = 64); in this case,
200        //   we need to process update the bottom leaf.
201        // - it points to an existing leaf node for a different key with the same prefix (same
202        //   key case was handled above); in this case, we need to move the leaf to a lower tier
203        let (index, leaf_exists) = self.nodes.get_leaf_index(&key);
204
205        self.root = if leaf_exists && index.depth() == Self::MAX_DEPTH {
206            // returned index points to a leaf at the bottom tier
207            let node = self.build_leaf_node(index, key, value);
208            self.nodes.update_leaf_node(index, node)
209        } else if leaf_exists {
210            // returned index pointes to a leaf for a different key with the same prefix
211
212            // get the key-value pair for the key with the same prefix; since the key-value
213            // pair has already been inserted into the value store, we need to filter it out
214            // when looking for the other key-value pair
215            let (other_key, other_value) = self
216                .values
217                .get_first_filtered(index_to_prefix(&index), &key)
218                .expect("other key-value pair not found");
219
220            // determine how far down the tree should we move the leaves
221            let common_prefix_len = get_common_prefix_tier_depth(&key, other_key);
222            let depth = cmp::min(common_prefix_len + Self::TIER_SIZE, Self::MAX_DEPTH);
223
224            // compute node locations for new and existing key-value paris
225            let new_index = LeafNodeIndex::from_key(&key, depth);
226            let other_index = LeafNodeIndex::from_key(other_key, depth);
227
228            // compute node values for the new and existing key-value pairs
229            let new_node = self.build_leaf_node(new_index, key, value);
230            let other_node = self.build_leaf_node(other_index, *other_key, *other_value);
231
232            // replace the leaf located at index with a subtree containing nodes for new and
233            // existing key-value paris
234            self.nodes.replace_leaf_with_subtree(
235                index,
236                [(new_index, new_node), (other_index, other_node)],
237            )
238        } else {
239            // returned index points to an empty subtree or an empty leaf at the bottom tier
240            let node = self.build_leaf_node(index, key, value);
241            self.nodes.insert_leaf_node(index, node)
242        };
243
244        Self::EMPTY_VALUE
245    }
246
247    // ITERATORS
248    // --------------------------------------------------------------------------------------------
249
250    /// Returns an iterator over all key-value pairs in this [TieredSmt].
251    pub fn iter(&self) -> impl Iterator<Item = &(RpoDigest, Word)> {
252        self.values.iter()
253    }
254
255    /// Returns an iterator over all inner nodes of this [TieredSmt] (i.e., nodes not at depths 16
256    /// 32, 48, or 64).
257    ///
258    /// The iterator order is unspecified.
259    pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
260        self.nodes.inner_nodes()
261    }
262
263    /// Returns an iterator over upper leaves (i.e., depth = 16, 32, or 48) for this [TieredSmt]
264    /// where each yielded item is a (node, key, value) tuple.
265    ///
266    /// The iterator order is unspecified.
267    pub fn upper_leaves(&self) -> impl Iterator<Item = (RpoDigest, RpoDigest, Word)> + '_ {
268        self.nodes.upper_leaves().map(|(index, node)| {
269            let key_prefix = index_to_prefix(index);
270            let (key, value) = self.values.get_first(key_prefix).expect("upper leaf not found");
271            debug_assert_eq!(*index, LeafNodeIndex::from_key(key, index.depth()).into());
272            (*node, *key, *value)
273        })
274    }
275
276    /// Returns an iterator over bottom leaves (i.e., depth = 64) of this [TieredSmt].
277    ///
278    /// Each yielded item consists of the hash of the leaf and its contents, where contents is
279    /// a vector containing key-value pairs of entries storied in this leaf.
280    ///
281    /// The iterator order is unspecified.
282    pub fn bottom_leaves(&self) -> impl Iterator<Item = (RpoDigest, Vec<(RpoDigest, Word)>)> + '_ {
283        self.nodes.bottom_leaves().map(|(&prefix, node)| {
284            let values = self.values.get_all(prefix).expect("bottom leaf not found");
285            (*node, values)
286        })
287    }
288
289    // HELPER METHODS
290    // --------------------------------------------------------------------------------------------
291
292    /// Removes the node holding the key-value pair for the specified key from this tree, and
293    /// returns the value associated with the specified key.
294    ///
295    /// If no value was associated with the specified key, [ZERO; 4] is returned.
296    fn remove_leaf_node(&mut self, key: RpoDigest) -> Word {
297        // remove the key-value pair from the value store; if no value was associated with the
298        // specified key, return.
299        let old_value = match self.values.remove(&key) {
300            Some(old_value) => old_value,
301            None => return Self::EMPTY_VALUE,
302        };
303
304        // determine the location of the leaf holding the key-value pair to be removed
305        let (index, leaf_exists) = self.nodes.get_leaf_index(&key);
306        debug_assert!(leaf_exists);
307
308        // if the leaf is at the bottom tier and after removing the key-value pair from it, the
309        // leaf is still not empty, we either just update it, or move it up to a higher tier (if
310        // the leaf doesn't have siblings at lower tiers)
311        if index.depth() == Self::MAX_DEPTH {
312            if let Some(entries) = self.values.get_all(index.value()) {
313                // if there is only one key-value pair left at the bottom leaf, and it can be
314                // moved up to a higher tier, truncate the branch and return
315                if entries.len() == 1 {
316                    let new_depth = self.nodes.get_last_single_child_parent_depth(index.value());
317                    if new_depth != Self::MAX_DEPTH {
318                        let node = hash_upper_leaf(entries[0].0, entries[0].1, new_depth);
319                        self.root = self.nodes.truncate_branch(index.value(), new_depth, node);
320                        return old_value;
321                    }
322                }
323
324                // otherwise just recompute the leaf hash and update the leaf node
325                let node = hash_bottom_leaf(&entries);
326                self.root = self.nodes.update_leaf_node(index, node);
327                return old_value;
328            };
329        }
330
331        // if the removed key-value pair has a lone sibling at the current tier with a root at
332        // higher tier, we need to move the sibling to a higher tier
333        if let Some((sib_key, sib_val, new_sib_index)) = self.values.get_lone_sibling(index) {
334            // determine the current index of the sibling node
335            let sib_index = LeafNodeIndex::from_key(sib_key, index.depth());
336            debug_assert!(sib_index.depth() > new_sib_index.depth());
337
338            // compute node value for the new location of the sibling leaf and replace the subtree
339            // with this leaf node
340            let node = self.build_leaf_node(new_sib_index, *sib_key, *sib_val);
341            let new_sib_depth = new_sib_index.depth();
342            self.root = self.nodes.replace_subtree_with_leaf(index, sib_index, new_sib_depth, node);
343        } else {
344            // if the removed key-value pair did not have a sibling at the current tier with a
345            // root at higher tiers, just clear the leaf node
346            self.root = self.nodes.clear_leaf_node(index);
347        }
348
349        old_value
350    }
351
352    /// Builds and returns a leaf node value for the node located as the specified index.
353    ///
354    /// This method assumes that the key-value pair for the node has already been inserted into
355    /// the value store, however, for depths 16, 32, and 48, the node is computed directly from
356    /// the passed-in values (for depth 64, the value store is queried to get all the key-value
357    /// pairs located at the specified index).
358    fn build_leaf_node(&self, index: LeafNodeIndex, key: RpoDigest, value: Word) -> RpoDigest {
359        let depth = index.depth();
360
361        // insert the key into index-key map and compute the new value of the node
362        if index.depth() == Self::MAX_DEPTH {
363            // for the bottom tier, we add the key-value pair to the existing leaf, or create a
364            // new leaf with this key-value pair
365            let values = self.values.get_all(index.value()).unwrap();
366            hash_bottom_leaf(&values)
367        } else {
368            debug_assert_eq!(self.values.get_first(index_to_prefix(&index)), Some(&(key, value)));
369            hash_upper_leaf(key, value, depth)
370        }
371    }
372}
373
374impl Default for TieredSmt {
375    fn default() -> Self {
376        let root = EmptySubtreeRoots::empty_hashes(Self::MAX_DEPTH)[0];
377        Self {
378            root,
379            nodes: NodeStore::new(root),
380            values: ValueStore::default(),
381        }
382    }
383}
384
385// LEAF NODE INDEX
386// ================================================================================================
387/// A wrapper around [NodeIndex] to provide type-safe references to nodes at depths 16, 32, 48, and
388/// 64.
389#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
390pub struct LeafNodeIndex(NodeIndex);
391
392impl LeafNodeIndex {
393    /// Returns a new [LeafNodeIndex] instantiated from the provided [NodeIndex].
394    ///
395    /// In debug mode, panics if index depth is not 16, 32, 48, or 64.
396    pub fn new(index: NodeIndex) -> Self {
397        // check if the depth is 16, 32, 48, or 64; this works because for a valid depth,
398        // depth - 16, can be 0, 16, 32, or 48 - i.e., the value is either 0 or any of the 4th
399        // or 5th bits are set. We can test for this by computing a bitwise AND with a value
400        // which has all but the 4th and 5th bits set (which is !48).
401        debug_assert_eq!(((index.depth() - 16) & !48), 0, "invalid tier depth {}", index.depth());
402        Self(index)
403    }
404
405    /// Returns a new [LeafNodeIndex] instantiated from the specified key inserted at the specified
406    /// depth.
407    ///
408    /// The value for the key is computed by taking n most significant bits from the most significant
409    /// element of the key, where n is the specified depth.
410    pub fn from_key(key: &RpoDigest, depth: u8) -> Self {
411        let mse = get_key_prefix(key);
412        Self::new(NodeIndex::new_unchecked(depth, mse >> (TieredSmt::MAX_DEPTH - depth)))
413    }
414
415    /// Returns a new [LeafNodeIndex] instantiated for testing purposes.
416    #[cfg(test)]
417    pub fn make(depth: u8, value: u64) -> Self {
418        Self::new(NodeIndex::make(depth, value))
419    }
420
421    /// Traverses towards the root until the specified depth is reached.
422    ///
423    /// The new depth must be a valid tier depth - i.e., 16, 32, 48, or 64.
424    pub fn move_up_to(&mut self, depth: u8) {
425        debug_assert_eq!(((depth - 16) & !48), 0, "invalid tier depth: {depth}");
426        self.0.move_up_to(depth);
427    }
428}
429
430impl Deref for LeafNodeIndex {
431    type Target = NodeIndex;
432
433    fn deref(&self) -> &Self::Target {
434        &self.0
435    }
436}
437
438impl From<NodeIndex> for LeafNodeIndex {
439    fn from(value: NodeIndex) -> Self {
440        Self::new(value)
441    }
442}
443
444impl From<LeafNodeIndex> for NodeIndex {
445    fn from(value: LeafNodeIndex) -> Self {
446        value.0
447    }
448}
449
450// HELPER FUNCTIONS
451// ================================================================================================
452
453/// Returns the value representing the 64 most significant bits of the specified key.
454fn get_key_prefix(key: &RpoDigest) -> u64 {
455    Word::from(key)[3].as_int()
456}
457
458/// Returns the index value shifted to be in the most significant bit positions of the returned
459/// u64 value.
460fn index_to_prefix(index: &NodeIndex) -> u64 {
461    index.value() << (TieredSmt::MAX_DEPTH - index.depth())
462}
463
464/// Returns tiered common prefix length between the most significant elements of the provided keys.
465///
466/// Specifically:
467/// - returns 64 if the most significant elements are equal.
468/// - returns 48 if the common prefix is between 48 and 63 bits.
469/// - returns 32 if the common prefix is between 32 and 47 bits.
470/// - returns 16 if the common prefix is between 16 and 31 bits.
471/// - returns 0 if the common prefix is fewer than 16 bits.
472fn get_common_prefix_tier_depth(key1: &RpoDigest, key2: &RpoDigest) -> u8 {
473    let e1 = get_key_prefix(key1);
474    let e2 = get_key_prefix(key2);
475    let ex = (e1 ^ e2).leading_zeros() as u8;
476    (ex / 16) * 16
477}
478
479/// Computes node value for leaves at tiers 16, 32, or 48.
480///
481/// Node value is computed as: hash(key || value, domain = depth).
482pub fn hash_upper_leaf(key: RpoDigest, value: Word, depth: u8) -> RpoDigest {
483    const NUM_UPPER_TIERS: usize = TieredSmt::TIER_DEPTHS.len() - 1;
484    debug_assert!(TieredSmt::TIER_DEPTHS[..NUM_UPPER_TIERS].contains(&depth));
485    Rpo256::merge_in_domain(&[key, value.into()], depth.into())
486}
487
488/// Computes node value for leaves at the bottom tier (depth 64).
489///
490/// Node value is computed as: hash([key_0, value_0, ..., key_n, value_n], domain=64).
491///
492/// TODO: when hashing in domain is implemented for `hash_elements()`, combine this function with
493/// `hash_upper_leaf()` function.
494pub fn hash_bottom_leaf(values: &[(RpoDigest, Word)]) -> RpoDigest {
495    let mut elements = Vec::with_capacity(values.len() * 8);
496    for (key, val) in values.iter() {
497        elements.extend_from_slice(key.as_elements());
498        elements.extend_from_slice(val.as_slice());
499    }
500    // TODO: hash in domain
501    Rpo256::hash_elements(&elements)
502}