miden_crypto/merkle/smt/forest/
mod.rs

1use alloc::{collections::BTreeSet, vec::Vec};
2
3use super::{EmptySubtreeRoots, MerkleError, NodeIndex, SmtLeaf, SmtProof, Word};
4use crate::{
5    Map,
6    merkle::{
7        LeafIndex, SmtLeafError, SmtProofError,
8        smt::{SMT_DEPTH, forest::store::SmtStore},
9    },
10};
11
12mod store;
13
14#[cfg(test)]
15mod tests;
16
17// SPARSE MERKLE TREE FOREST
18// ================================================================================================
19
20/// An in-memory data collection of sparse Merkle trees (SMTs).
21///
22/// Each SMT in the forest is identified by its root hash. The forest stores all leaves of all SMTs
23/// in the forest, as well as all Merkle paths required to prove membership of any leaf in any SMT.
24///
25/// An empty tree root is always present in the forest.
26///
27/// Example usage:
28///
29/// ```rust
30/// use miden_crypto::{
31///     Felt, ONE, WORD_SIZE, Word, ZERO,
32///     merkle::{EmptySubtreeRoots, MAX_LEAF_ENTRIES, SMT_DEPTH, SmtForest},
33/// };
34///
35/// // Create a new SMT forest
36/// let mut forest = SmtForest::new();
37///
38/// // Insert a key-value pair into an SMT with an empty root
39/// let empty_tree_root = *EmptySubtreeRoots::entry(SMT_DEPTH, 0);
40/// let key = Word::new([ZERO; WORD_SIZE]);
41/// let value = Word::new([ONE; WORD_SIZE]);
42/// let new_root = forest.insert(empty_tree_root, key, value).unwrap();
43///
44/// // Insert multiple key-value pairs
45/// let mut entries = Vec::new();
46/// for i in 0..MAX_LEAF_ENTRIES {
47///     let key = Word::new([Felt::new(i as u64); WORD_SIZE]);
48///     let value = Word::new([Felt::new((i + 1) as u64); WORD_SIZE]);
49///     entries.push((key, value));
50/// }
51/// let new_root = forest.batch_insert(new_root, entries.into_iter()).unwrap();
52///
53/// // Open a proof for the inserted key
54/// let proof = forest.open(new_root, key).unwrap();
55///
56/// // Prune SMTs to release memory used by their nodes and leaves
57/// forest.pop_smts(vec![new_root]);
58/// ```
59#[derive(Debug, Clone, Eq, PartialEq)]
60pub struct SmtForest {
61    /// Roots of all SMTs in this forest. Any time an SMT in this forest is updated, we add a new
62    /// root to this set.
63    roots: BTreeSet<Word>,
64
65    /// Stores Merkle paths for all SMTs in this forest.
66    store: SmtStore,
67
68    /// Leaves of all SMTs stored in this forest
69    leaves: Map<Word, SmtLeaf>,
70}
71
72impl Default for SmtForest {
73    fn default() -> Self {
74        Self::new()
75    }
76}
77
78impl SmtForest {
79    // CONSTRUCTORS
80    // --------------------------------------------------------------------------------------------
81
82    /// Creates an empty `SmtForest` instance.
83    pub fn new() -> SmtForest {
84        let roots = BTreeSet::new();
85        let store = SmtStore::new();
86        let leaves = Map::new();
87
88        SmtForest { roots, store, leaves }
89    }
90
91    // DATA EXTRACTORS
92    // --------------------------------------------------------------------------------------------
93
94    /// Returns an opening for the specified key in the SMT with the specified root.
95    ///
96    /// Returns an error if an SMT with this root is not in the forest, or if the forest does
97    /// not have sufficient data to provide an opening for the specified key.
98    pub fn open(&self, root: Word, key: Word) -> Result<SmtProof, MerkleError> {
99        if !self.contains_root(root) {
100            return Err(MerkleError::RootNotInStore(root));
101        }
102
103        let leaf_index = NodeIndex::from(LeafIndex::from(key));
104
105        let proof = self.store.get_path(root, leaf_index)?;
106        let path = proof.path.try_into()?;
107        let leaf = proof.value;
108
109        let Some(leaf) = self.leaves.get(&leaf).cloned() else {
110            return Err(MerkleError::UntrackedKey(key));
111        };
112
113        SmtProof::new(path, leaf).map_err(|error| match error {
114            SmtProofError::InvalidMerklePathLength(depth) => MerkleError::InvalidPathLength(depth),
115        })
116    }
117
118    // STATE MUTATORS
119    // --------------------------------------------------------------------------------------------
120
121    /// Inserts the specified key-value pair into an SMT with the specified root. This will also
122    /// add a new root to the forest. Returns the new root.
123    ///
124    /// Returns an error if an SMT with the specified root is not in the forest, these is not
125    /// enough data in the forest to perform the insert, or if the insert would create a leaf
126    /// with too many entries.
127    pub fn insert(&mut self, root: Word, key: Word, value: Word) -> Result<Word, MerkleError> {
128        self.batch_insert(root, vec![(key, value)])
129    }
130
131    /// Inserts the specified key-value pairs into an SMT with the specified root. This will also
132    /// add a single new root to the forest for the entire batch of inserts. Returns the new root.
133    ///
134    /// Returns an error if an SMT with the specified root is not in the forest, these is not
135    /// enough data in the forest to perform the insert, or if the insert would create a leaf
136    /// with too many entries.
137    pub fn batch_insert(
138        &mut self,
139        root: Word,
140        entries: impl IntoIterator<Item = (Word, Word)> + Clone,
141    ) -> Result<Word, MerkleError> {
142        if !self.contains_root(root) {
143            return Err(MerkleError::RootNotInStore(root));
144        }
145
146        // Find all affected leaf indices
147        let indices = entries
148            .clone()
149            .into_iter()
150            .map(|(key, _)| LeafIndex::from(key))
151            .collect::<BTreeSet<_>>();
152
153        // Create new SmtLeaf objects for updated key-value pairs
154        let mut new_leaves = Map::new();
155        for index in indices {
156            let node_index = NodeIndex::from(index);
157            let current_hash = self.store.get_node(root, node_index)?;
158
159            let current_leaf = self
160                .leaves
161                .get(&current_hash)
162                .cloned()
163                .unwrap_or_else(|| SmtLeaf::new_empty(index));
164
165            new_leaves.insert(index, (current_hash, current_leaf));
166        }
167        for (key, value) in entries {
168            let index = LeafIndex::from(key);
169            let (_old_hash, leaf) = new_leaves.get_mut(&index).unwrap();
170            leaf.insert(key, value).map_err(to_merkle_error)?;
171        }
172
173        // Calculate new leaf hashes, skip processing unchanged leaves
174        new_leaves = new_leaves
175            .into_iter()
176            .filter_map(|(key, (old_hash, leaf))| {
177                let new_hash = leaf.hash();
178                if new_hash == old_hash {
179                    None
180                } else {
181                    Some((key, (new_hash, leaf)))
182                }
183            })
184            .collect();
185
186        // Update SmtStore with new leaf hashes
187        let new_leaf_entries =
188            new_leaves.iter().map(|(index, leaf)| (NodeIndex::from(*index), leaf.0));
189        let new_root = self.store.set_leaves(root, new_leaf_entries)?;
190
191        // Update successful, insert new leaves into the forest
192        for (leaf_hash, leaf) in new_leaves.into_values() {
193            self.leaves.insert(leaf_hash, leaf);
194        }
195        self.roots.insert(new_root);
196
197        Ok(new_root)
198    }
199
200    /// Removes the specified SMTs (identified by their roots) from the forest.
201    /// Releases memory used by nodes and leaves that are no longer reachable.
202    /// Roots not in the forest and empty trees are ignored.
203    pub fn pop_smts(&mut self, roots: impl IntoIterator<Item = Word>) {
204        let roots = roots
205            .into_iter()
206            .filter(|root| {
207                // don't use self.contains_root here because we don't remove empty trees
208                self.roots.contains(root)
209            })
210            .collect::<Vec<_>>();
211
212        for root in &roots {
213            self.roots.remove(root);
214        }
215
216        for leaf in self.store.remove_roots(roots) {
217            self.leaves.remove(&leaf);
218        }
219    }
220
221    // HELPER METHODS
222    // --------------------------------------------------------------------------------------------
223
224    /// Checks if the forest contains the specified root or if it is the empty tree root
225    /// (always present in the forest).
226    fn contains_root(&self, root: Word) -> bool {
227        self.roots.contains(&root) || *EmptySubtreeRoots::entry(SMT_DEPTH, 0) == root
228    }
229}
230
231fn to_merkle_error(err: SmtLeafError) -> MerkleError {
232    match err {
233        SmtLeafError::TooManyLeafEntries { actual } => MerkleError::TooManyLeafEntries { actual },
234        _ => unreachable!("other SmtLeafError variants should not be possible here"),
235    }
236}