Skip to main content

miden_crypto/merkle/smt/partial/
mod.rs

1use alloc::{collections::VecDeque, string::ToString, vec::Vec};
2
3use super::{EmptySubtreeRoots, LeafIndex, SMT_DEPTH};
4use crate::{
5    EMPTY_WORD, Map, Set, Word,
6    merkle::{
7        InnerNodeInfo, MerkleError, NodeIndex, SparseMerklePath,
8        smt::{InnerNode, InnerNodes, Leaves, SmtLeaf, SmtLeafError, SmtProof},
9    },
10    utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
11};
12
13mod serialization;
14#[cfg(test)]
15mod tests;
16
17pub use serialization::{NodeValue, UniqueNodes};
18
19/// A partial version of an [`super::Smt`].
20///
21/// This type can track a subset of the key-value pairs of a full [`super::Smt`] and allows for
22/// updating those pairs to compute the new root of the tree, as if the updates had been done on the
23/// full tree. This is useful so that not all leaves have to be present and loaded into memory to
24/// compute an update.
25///
26/// A key is considered "tracked" if either:
27/// 1. Its merkle path was explicitly added to the tree (via [`PartialSmt::add_path`] or
28///    [`PartialSmt::add_proof`]), or
29/// 2. The path from the leaf to the root goes through empty subtrees that are consistent with the
30///    stored inner nodes (provably empty with zero hash computations).
31///
32/// The second condition allows updating keys in empty subtrees without explicitly adding their
33/// merkle paths. This is verified by walking up from the leaf and checking that any stored
34/// inner node has an empty subtree root as the child on our path.
35///
36/// An important caveat is that only tracked keys can be updated. Attempting to update an
37/// untracked key will result in an error. See [`PartialSmt::insert`] for more details.
38///
39/// Once a partial SMT has been constructed, its root is set in stone. All subsequently added proofs
40/// or merkle paths must match that root, otherwise an error is returned.
41#[derive(Debug, Clone, PartialEq, Eq)]
42#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
43pub struct PartialSmt {
44    root: Word,
45    num_entries: usize,
46    leaves: Leaves<SmtLeaf>,
47    inner_nodes: InnerNodes,
48}
49
50impl PartialSmt {
51    // CONSTANTS
52    // --------------------------------------------------------------------------------------------
53
54    /// The default value used to compute the hash of empty leaves.
55    pub const EMPTY_VALUE: Word = EMPTY_WORD;
56
57    /// The root of an empty tree.
58    pub const EMPTY_ROOT: Word = *EmptySubtreeRoots::entry(SMT_DEPTH, 0);
59
60    // CONSTRUCTORS
61    // --------------------------------------------------------------------------------------------
62
63    /// Constructs a [`PartialSmt`] from a root.
64    ///
65    /// All subsequently added proofs or paths must have the same root.
66    pub fn new(root: Word) -> Self {
67        Self {
68            root,
69            num_entries: 0,
70            leaves: Leaves::<SmtLeaf>::default(),
71            inner_nodes: InnerNodes::default(),
72        }
73    }
74
75    /// Instantiates a new [`PartialSmt`] by calling [`PartialSmt::add_proof`] for all [`SmtProof`]s
76    /// in the provided iterator.
77    ///
78    /// If the provided iterator is empty, an empty [`PartialSmt`] is returned.
79    ///
80    /// # Errors
81    ///
82    /// Returns an error if:
83    /// - the roots of the provided proofs are not the same.
84    pub fn from_proofs<I>(proofs: I) -> Result<Self, MerkleError>
85    where
86        I: IntoIterator<Item = SmtProof>,
87    {
88        let mut proofs = proofs.into_iter();
89
90        let Some(first_proof) = proofs.next() else {
91            return Ok(Self::default());
92        };
93
94        // Add the first path to an empty partial SMT without checking that the existing root
95        // matches the new one. This sets the expected root to the root of the first proof and all
96        // subsequently added proofs must match it.
97        let mut partial_smt = Self::default();
98        let (path, leaf) = first_proof.into_parts();
99        let path_root = partial_smt.add_path_unchecked(leaf, path);
100        partial_smt.root = path_root;
101
102        for proof in proofs {
103            partial_smt.add_proof(proof)?;
104        }
105
106        Ok(partial_smt)
107    }
108
109    // PUBLIC ACCESSORS
110    // --------------------------------------------------------------------------------------------
111
112    /// Returns the root of the tree.
113    pub fn root(&self) -> Word {
114        self.root
115    }
116
117    /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle
118    /// path to the leaf, as well as the leaf itself.
119    ///
120    /// # Errors
121    ///
122    /// Returns an error if:
123    /// - the key is not tracked by this partial SMT.
124    pub fn open(&self, key: &Word) -> Result<SmtProof, MerkleError> {
125        let leaf = self.get_leaf(key)?;
126        let merkle_path = self.get_path(key);
127        Ok(SmtProof::new_unchecked(merkle_path, leaf))
128    }
129
130    /// Returns the leaf to which `key` maps.
131    ///
132    /// # Errors
133    ///
134    /// Returns an error if:
135    /// - the key is not tracked by this partial SMT.
136    pub fn get_leaf(&self, key: &Word) -> Result<SmtLeaf, MerkleError> {
137        self.get_tracked_leaf(key).ok_or(MerkleError::UntrackedKey(*key))
138    }
139
140    /// Returns the value associated with `key`.
141    ///
142    /// # Errors
143    ///
144    /// Returns an error if:
145    /// - the key is not tracked by this partial SMT.
146    pub fn get_value(&self, key: &Word) -> Result<Word, MerkleError> {
147        self.get_tracked_leaf(key)
148            .map(|leaf| leaf.get_value(key).unwrap_or_default())
149            .ok_or(MerkleError::UntrackedKey(*key))
150    }
151
152    /// Returns an iterator over the inner nodes of the [`PartialSmt`].
153    pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
154        self.inner_nodes.values().map(|e| InnerNodeInfo {
155            value: e.hash(),
156            left: e.left,
157            right: e.right,
158        })
159    }
160
161    /// Returns an iterator over the [`InnerNode`] and the respective [`NodeIndex`] of the
162    /// [`PartialSmt`].
163    pub fn inner_node_indices(&self) -> impl Iterator<Item = (NodeIndex, InnerNode)> + '_ {
164        self.inner_nodes.iter().map(|(idx, inner)| (*idx, inner.clone()))
165    }
166
167    /// Returns an iterator over the explicitly stored leaves of the [`PartialSmt`] in arbitrary
168    /// order.
169    ///
170    /// Note: This only returns leaves that were explicitly added via [`Self::add_path`] or
171    /// [`Self::add_proof`], or created through [`Self::insert`]. It does not include implicitly
172    /// trackable leaves in empty subtrees.
173    pub fn leaves(&self) -> impl Iterator<Item = (LeafIndex<SMT_DEPTH>, &SmtLeaf)> {
174        self.leaves
175            .iter()
176            .map(|(leaf_index, leaf)| (LeafIndex::new_max_depth(*leaf_index), leaf))
177    }
178
179    /// Returns an iterator over the tracked, non-empty key-value pairs of the [`PartialSmt`] in
180    /// arbitrary order.
181    pub fn entries(&self) -> impl Iterator<Item = &(Word, Word)> {
182        self.leaves().flat_map(|(_, leaf)| leaf.entries())
183    }
184
185    /// Returns the number of non-empty leaves in this tree.
186    ///
187    /// Note that this may return a different value from [Self::num_entries()] as a single leaf may
188    /// contain more than one key-value pair.
189    pub fn num_leaves(&self) -> usize {
190        self.leaves.len()
191    }
192
193    /// Returns the number of tracked, non-empty key-value pairs in this tree.
194    ///
195    /// Note that this may return a different value from [Self::num_leaves()] as a single leaf may
196    /// contain more than one key-value pair.
197    pub fn num_entries(&self) -> usize {
198        self.num_entries
199    }
200
201    /// Returns a boolean value indicating whether the [`PartialSmt`] tracks any leaves.
202    ///
203    /// Note that if a partial SMT does not track leaves, its root is not necessarily the empty SMT
204    /// root, since it could have been constructed from a different root but without tracking any
205    /// leaves.
206    pub fn tracks_leaves(&self) -> bool {
207        !self.leaves.is_empty()
208    }
209
210    // STATE MUTATORS
211    // --------------------------------------------------------------------------------------------
212
213    /// Inserts a value at the specified key, returning the previous value associated with that key.
214    /// Recall that by definition, any key that hasn't been updated is associated with
215    /// [`Self::EMPTY_VALUE`].
216    ///
217    /// This also recomputes all hashes between the leaf (associated with the key) and the root,
218    /// updating the root itself.
219    ///
220    /// # Errors
221    ///
222    /// Returns an error if:
223    /// - the key is not tracked (see the type documentation for the definition of "tracked"). If an
224    ///   error is returned the tree is in the same state as before.
225    /// - inserting the key-value pair would exceed [`super::MAX_LEAF_ENTRIES`] (1024 entries) in
226    ///   the leaf.
227    pub fn insert(&mut self, key: Word, value: Word) -> Result<Word, MerkleError> {
228        let current_leaf = self.get_tracked_leaf(&key).ok_or(MerkleError::UntrackedKey(key))?;
229        let leaf_index = current_leaf.index();
230        let previous_value = current_leaf.get_value(&key).unwrap_or(EMPTY_WORD);
231        let prev_entries = current_leaf.num_entries();
232
233        let leaf = self
234            .leaves
235            .entry(leaf_index.position())
236            .or_insert_with(|| SmtLeaf::new_empty(leaf_index));
237
238        if value != EMPTY_WORD {
239            leaf.insert(key, value).map_err(|e| match e {
240                SmtLeafError::TooManyLeafEntries { actual } => {
241                    MerkleError::TooManyLeafEntries { actual }
242                },
243                other => panic!("unexpected SmtLeaf::insert error: {other:?}"),
244            })?;
245        } else {
246            leaf.remove(key);
247        }
248        let current_entries = leaf.num_entries();
249        let new_leaf_hash = leaf.hash();
250        self.num_entries = self.num_entries + current_entries - prev_entries;
251
252        // Remove empty leaf
253        if current_entries == 0 {
254            self.leaves.remove(&leaf_index.position());
255        }
256
257        // Recompute the path from leaf to root
258        self.recompute_nodes_from_leaf_to_root(leaf_index, new_leaf_hash);
259
260        Ok(previous_value)
261    }
262
263    /// Adds an [`SmtProof`] to this [`PartialSmt`].
264    ///
265    /// This is a convenience method which calls [`Self::add_path`] on the proof. See its
266    /// documentation for details on errors.
267    pub fn add_proof(&mut self, proof: SmtProof) -> Result<(), MerkleError> {
268        let (path, leaf) = proof.into_parts();
269        self.add_path(leaf, path)
270    }
271
272    /// Adds a leaf and its sparse merkle path to this [`PartialSmt`].
273    ///
274    /// If this function was called, any key that is part of the `leaf` can subsequently be updated
275    /// to a new value and produce a correct new tree root.
276    ///
277    /// # Errors
278    ///
279    /// Returns an error if:
280    /// - the new root after the insertion of the leaf and the path does not match the existing
281    ///   root. If an error is returned, the tree is left in an inconsistent state.
282    pub fn add_path(&mut self, leaf: SmtLeaf, path: SparseMerklePath) -> Result<(), MerkleError> {
283        let path_root = self.add_path_unchecked(leaf, path);
284
285        // Check if the newly added merkle path is consistent with the existing tree. If not, the
286        // merkle path was invalid or computed against another tree.
287        if self.root() != path_root {
288            return Err(MerkleError::ConflictingRoots {
289                expected_root: self.root(),
290                actual_root: path_root,
291            });
292        }
293
294        Ok(())
295    }
296
297    // UNIQUE NODES
298    // --------------------------------------------------------------------------------------------
299
300    /// Converts `self` into the [`UniqueNodes`] serialization representation for compact
301    /// serialization.
302    ///
303    /// This method assumes that the `PartialSmt` is in a valid state.
304    ///
305    /// # Reconstructable Sets
306    ///
307    /// We define the notion of a reconstructable set as one which stores the minimum amount of
308    /// information necessary in order to reconstruct the full state of the tree. We build this set
309    /// as follows:
310    ///
311    /// 1. Start at the leaves and traverse toward the root.
312    /// 2. Wherever a node's value is determined solely by children already implicitly contained
313    ///    within the set, store no new information. If additional information is required (e.g. a
314    ///    sibling node) store that.
315    /// 3. Repeat until the root is reached.
316    ///
317    /// To reconstruct the tree, we just start at the leaves and compute all intermediary nodes from
318    /// the data stored in the reconstructible set.
319    pub fn to_unique_nodes(&self) -> UniqueNodes {
320        // We start by getting all the known leaves, as these give us the starting point for the
321        // reconstruction.
322        let leaf_nodes = self
323            .leaves()
324            .map(|(k, v)| (k, v.clone()))
325            .collect::<Map<LeafIndex<SMT_DEPTH>, SmtLeaf>>();
326
327        // We also create storage for the nodes necessary for reconstruction of the tree...
328        let mut needed_nodes: Map<NodeIndex, NodeValue> = Map::new();
329
330        // ... and grab the full set of inner nodes to work from as a queue for easy use. We sort
331        // them from the bottom of the tree to the top, but retain the standard left-to-right
332        // ordering.
333        let mut inner_nodes = self.inner_node_indices().collect::<Vec<(NodeIndex, InnerNode)>>();
334        inner_nodes.sort_by(|(il, _), (ir, _)| {
335            ir.depth().cmp(&il.depth()).then(il.position().cmp(&ir.position()))
336        });
337        let mut inner_nodes = inner_nodes.into_iter().collect::<VecDeque<(NodeIndex, InnerNode)>>();
338
339        // We also need to store the values for leaves where we ONLY have the hash value, rather
340        // than the proper leaf value.
341        let mut value_only_leaves = Vec::new();
342
343        // We then need to iterate over all the nodes to work out which ones are reconstructible,
344        // and which need us to store additional data to be reconstructible.
345        while let Some((ix, v)) = inner_nodes.pop_front() {
346            // There must be data available for both of the node's children for it to be
347            // reconstructible.
348            for (child, val) in [(ix.left_child(), v.left), (ix.right_child(), v.right)] {
349                if child.depth() != SMT_DEPTH {
350                    // A child of the node `v` can be in one of three states:
351                    //
352                    // 1. The child does not exist as a physical node in `self`, but its value as
353                    //    stored in `v` is real.
354                    // 2. The child does not exist as a physical node in `self`, but its value is
355                    //    the default empty subtree root.
356                    // 3. The child does exist as a physical node in `self`. By induction, as this
357                    //    algorithm runs bottom-up, the data to reconstruct the node already exists.
358                    if self.get_inner_node(child).is_none() {
359                        // In this case, the node does not exist physically, so we have to work out
360                        // which of the other cases it is.
361                        let new = if val == *EmptySubtreeRoots::entry(SMT_DEPTH, child.depth()) {
362                            NodeValue::EmptySubtreeRoot
363                        } else {
364                            NodeValue::Present(val)
365                        };
366
367                        // We allow overwriting existing inserts for algorithmic simplicity, but we
368                        // always check that it is the same value if an overwrite occurs as this
369                        // indicates a programmer bug.
370                        if let Some(v) = needed_nodes.insert(child, new.clone())
371                            && v != new
372                        {
373                            panic!("Overwrite occurred with a different value ")
374                        }
375                    } else {
376                        // Here, the node exists physically, so by induction, it is reconstructible.
377                    }
378                } else {
379                    // Here the child is a leaf node. Leaf nodes can be in one of three states:
380                    //
381                    // 1. A node that has the default empty value, in which case we encode it using
382                    //    absence in the compact representation.
383                    // 2. A node that has a hash value, but that does not exist in the physical
384                    //    leaves in the PartialSmt. These are encoded using an auxiliary buffer to
385                    //    aid in reconstruction.
386                    // 3. A node that exists in fully-materialized form. These are encoded with
387                    //    their full content.
388                    //
389                    // Cases 1 and 3 require no special handling here, as they are encoded with the
390                    // leaves below. Case 2 needs us to take action here.
391                    let empty_leaf_hash =
392                        SmtLeaf::new_empty(LeafIndex::new_max_depth(child.position())).hash();
393
394                    if val != empty_leaf_hash && !self.leaves.contains_key(&child.position()) {
395                        // We are in case 2 here, as the value is not that of the empty leaf, nor is
396                        // there a physical leaf stored in the tree for this. We store this leaf
397                        // value in the auxiliary buffer so we can reconstruct correctly in this
398                        // scenario.
399                        value_only_leaves.push((child.position(), val));
400                    }
401                }
402            }
403        }
404
405        // With all the data gathered, we can convert our types as necessary to create our output.
406        let leaves = leaf_nodes.into_iter().map(|(i, l)| (i.position(), l)).collect::<Vec<_>>();
407        let mut nodes: Map<u8, Vec<(u64, NodeValue)>> = Map::new();
408
409        for (ix, value) in needed_nodes {
410            nodes.entry(ix.depth()).or_default().push((ix.position(), value));
411        }
412
413        UniqueNodes {
414            root: self.root(),
415            leaves,
416            nodes,
417            value_only_leaves,
418        }
419    }
420
421    /// Constructs a new `PartialSmt` from the provided `unique_nodes`, reconstituting the full data
422    /// from the compact representation.
423    ///
424    /// This method assumes that the `unique_nodes` represent a valid `PartialSmt` instance.
425    ///
426    /// See the documentation of [`Self::to_unique_nodes`] for the reconstruction algorithm.
427    ///
428    /// # Errors
429    ///
430    /// - [`MerkleError::NodeIndexNotFoundInStore`] if any node necessary for reconstruction is not
431    ///   available in the provided `unique_nodes` data.
432    pub fn from_unique_nodes(unique_nodes: UniqueNodes) -> Result<Self, DeserializationError> {
433        // We perform our transformation by directly mutating a new instance of `Self`.
434        let mut smt = Self::new(unique_nodes.root);
435
436        // We rely on a minimal set of node values and leaf values to reconstruct the tree, so we
437        // have to be able to perform lookups.
438        let nodes = unique_nodes
439            .nodes
440            .into_iter()
441            .flat_map(|(depth, nodes)| {
442                nodes.into_iter().map(move |(ix, val)| Ok((NodeIndex::new(depth, ix)?, val)))
443            })
444            .collect::<Result<Map<NodeIndex, NodeValue>, MerkleError>>()
445            .map_err(|e| DeserializationError::InvalidValue(e.to_string()))?;
446        let all_leaves = unique_nodes
447            .leaves
448            .into_iter()
449            .map(|(ix, l)| {
450                let node_index = NodeIndex::new(SMT_DEPTH, ix)
451                    .map_err(|e| DeserializationError::InvalidValue(e.to_string()))?;
452                if node_index != l.index().index {
453                    Err(DeserializationError::InvalidValue(format!(
454                        "Node index {ix} did not match the embedded leaf index {}",
455                        l.index().index
456                    )))
457                } else {
458                    Ok((
459                        NodeIndex::new(SMT_DEPTH, ix)
460                            .map_err(|e| DeserializationError::InvalidValue(e.to_string()))?,
461                        l,
462                    ))
463                }
464            })
465            .collect::<Result<Map<_, _>, DeserializationError>>()?;
466
467        // We also need to grab the buffer of the additional leaf values, and we convert it into a
468        // map for easy lookup. It is safe to use `new_unchecked` here as, while this comes from
469        // untrusted input, `ix` can correctly take the value of any `u64`.
470        let value_only_leaves = unique_nodes
471            .value_only_leaves
472            .into_iter()
473            .map(|(ix, v)| (NodeIndex::new_unchecked(SMT_DEPTH, ix), v))
474            .collect::<Map<_, _>>();
475
476        // We then want to process leaf by leaf, with a queue of parent nodes that need visiting.
477        // Rather than trying to de-duplicate on the fly, we instead just discard nodes that have
478        // already been processed when we see them.
479        //
480        // It must be ensured that at no point an index that is lower in the tree than any index
481        // preceding it is inserted.
482        let leaf_based_starting_nodes =
483            all_leaves.keys().map(|k| k.parent()).collect::<VecDeque<_>>();
484
485        // We also, however, need to account for inner nodes which are not reachable in a parent
486        // chain from a leaf, such as those from an exclusion proof. These are all nodes that do not
487        // have a (present) child in the set of nodes or leaves, so to enforce our layering
488        // invariant we add them in sorted order from bottom to top, left to right.
489        //
490        // We process these after the leaf-based nodes to avoid issues with the layering invariant.
491        let mut additional_nodes = nodes.keys().map(|ix| ix.parent()).collect::<Vec<_>>();
492        additional_nodes
493            .sort_by(|il, ir| ir.depth().cmp(&il.depth()).then(il.position().cmp(&ir.position())));
494        let additional_nodes = additional_nodes.into_iter().collect::<VecDeque<_>>();
495
496        // We also track the nodes we have seen to avoid re-doing unnecessary work.
497        let mut seen_nodes = Set::new();
498
499        for mut active_nodes in [leaf_based_starting_nodes, additional_nodes] {
500            seen_nodes.clear();
501            while let Some(ix) = active_nodes.pop_front() {
502                // To avoid re-doing work we immediately discard a node that is already in our tree.
503                if smt.inner_nodes.contains_key(&ix) {
504                    continue;
505                }
506
507                if ix.depth() + 1 == SMT_DEPTH {
508                    // We have to handle the case where the children are the leaves specially.
509                    //
510                    // If no corresponding leaf is present, then either it was a default value, or
511                    // it exists in the value-only leaves buffer, so we have to check both.
512                    let left_child = ix.left_child();
513                    let left = all_leaves
514                        .get(&left_child)
515                        .map(SmtLeaf::hash)
516                        .or_else(|| value_only_leaves.get(&left_child).copied())
517                        .unwrap_or(
518                            SmtLeaf::new_empty(LeafIndex::new_max_depth(left_child.position()))
519                                .hash(),
520                        );
521                    let right_child = ix.right_child();
522                    let right = all_leaves
523                        .get(&right_child)
524                        .map(SmtLeaf::hash)
525                        .or_else(|| value_only_leaves.get(&right_child).copied())
526                        .unwrap_or(
527                            SmtLeaf::new_empty(LeafIndex::new_max_depth(right_child.position()))
528                                .hash(),
529                        );
530
531                    smt.insert_inner_node(ix, InnerNode { left, right })
532                } else {
533                    // If the children are not in the leaves, they can be either in the tree already
534                    // (having been reconstructed) or as a value in the nodes from the unique nodes
535                    // structure.
536                    let [left, right] = [ix.left_child(), ix.right_child()].map(|ix| {
537                        smt.get_inner_node(ix).map(|n| Ok(n.hash())).unwrap_or_else(|| match nodes
538                            .get(&ix)
539                            .ok_or_else(|| {
540                                DeserializationError::InvalidValue(format!(
541                                    "Node at {ix} not found but is required"
542                                ))
543                            })? {
544                            NodeValue::EmptySubtreeRoot => {
545                                Ok(*EmptySubtreeRoots::entry(SMT_DEPTH, ix.depth()))
546                            },
547                            NodeValue::Present(v) => Ok(*v),
548                        })
549                    });
550                    let left = left?;
551                    let right = right?;
552
553                    smt.insert_inner_node(ix, InnerNode { left, right });
554                }
555
556                // Finally, we push the node's parent into the queue if we have not already visited
557                // it. While it would be correct to do unconditionally, we operate over untrusted
558                // input and hence we have to be careful.
559                let parent = ix.parent();
560                if !seen_nodes.contains(&parent) {
561                    active_nodes.push_back(parent);
562                    seen_nodes.insert(parent);
563                }
564            }
565        }
566
567        // With that done, we simply have to write the remaining keys into the tree.
568        all_leaves.into_iter().for_each(|(ix, leaf)| {
569            smt.num_entries += leaf.num_entries();
570            smt.leaves.insert(ix.position(), leaf);
571        });
572
573        smt.validate()?;
574
575        Ok(smt)
576    }
577
578    // PRIVATE HELPERS
579    // --------------------------------------------------------------------------------------------
580
581    /// Adds a leaf and its sparse merkle path to this [`PartialSmt`] and returns the root of the
582    /// inserted path.
583    ///
584    /// This does not check that the path root matches the existing root of the tree and if so, the
585    /// tree is left in an inconsistent state. This state can be made consistent again by setting
586    /// the root of the SMT to the path root.
587    fn add_path_unchecked(&mut self, leaf: SmtLeaf, path: SparseMerklePath) -> Word {
588        let mut current_index = leaf.index().index;
589
590        let mut node_hash_at_current_index = leaf.hash();
591
592        let prev_entries = self
593            .leaves
594            .get(&current_index.position())
595            .map(SmtLeaf::num_entries)
596            .unwrap_or(0);
597        let current_entries = leaf.num_entries();
598        // Only store non-empty leaves
599        if current_entries > 0 {
600            self.leaves.insert(current_index.position(), leaf);
601        } else {
602            self.leaves.remove(&current_index.position());
603        }
604
605        // Guaranteed not to over/underflow. All variables are <= MAX_LEAF_ENTRIES and result > 0.
606        self.num_entries = self.num_entries + current_entries - prev_entries;
607
608        for sibling_hash in path {
609            // Find the index of the sibling node and compute whether it is a left or right child.
610            let is_sibling_right = current_index.sibling().is_position_odd();
611
612            // Move the index up so it points to the parent of the current index and the sibling.
613            current_index.move_up();
614
615            // Construct the new parent node from the child that was updated and the sibling from
616            // the merkle path.
617            let new_parent_node = if is_sibling_right {
618                InnerNode {
619                    left: node_hash_at_current_index,
620                    right: sibling_hash,
621                }
622            } else {
623                InnerNode {
624                    left: sibling_hash,
625                    right: node_hash_at_current_index,
626                }
627            };
628
629            node_hash_at_current_index = new_parent_node.hash();
630
631            self.insert_inner_node(current_index, new_parent_node);
632        }
633
634        node_hash_at_current_index
635    }
636
637    /// Returns the leaf for a key if it can be tracked.
638    ///
639    /// A key is trackable if:
640    /// 1. It was explicitly added via `add_path`/`add_proof`, OR
641    /// 2. The path to the leaf goes through empty subtrees (provably empty)
642    ///
643    /// Returns `None` if the key cannot be tracked (path goes through non-empty
644    /// subtrees we don't have data for).
645    fn get_tracked_leaf(&self, key: &Word) -> Option<SmtLeaf> {
646        let leaf_index = Self::key_to_leaf_index(key);
647
648        // Explicitly stored leaves are always trackable
649        if let Some(leaf) = self.leaves.get(&leaf_index.position()) {
650            return Some(leaf.clone());
651        }
652
653        // Empty tree - all leaves implicitly trackable
654        if self.root == Self::EMPTY_ROOT {
655            return Some(SmtLeaf::new_empty(leaf_index));
656        }
657
658        // Walk from root down towards the leaf
659        let target: NodeIndex = leaf_index.into();
660        let mut index = NodeIndex::root();
661
662        for i in (0..SMT_DEPTH).rev() {
663            let inner_node = self.get_inner_node(index)?;
664
665            let is_right = target.is_nth_bit_odd(i);
666            let child_hash = if is_right { inner_node.right } else { inner_node.left };
667
668            // If child is empty subtree root, leaf is implicitly trackable
669            if child_hash == *EmptySubtreeRoots::entry(SMT_DEPTH, SMT_DEPTH - i) {
670                return Some(SmtLeaf::new_empty(leaf_index));
671            }
672
673            index = if is_right {
674                index.right_child()
675            } else {
676                index.left_child()
677            };
678        }
679
680        // Reached leaf level without finding empty subtree - can't track
681        None
682    }
683
684    /// Converts a key to a leaf index.
685    fn key_to_leaf_index(key: &Word) -> LeafIndex<SMT_DEPTH> {
686        let most_significant_felt = key[3];
687        LeafIndex::new_max_depth(most_significant_felt.as_canonical_u64())
688    }
689
690    /// Returns the inner node at the specified index, or `None` if not stored.
691    fn get_inner_node(&self, index: NodeIndex) -> Option<InnerNode> {
692        self.inner_nodes.get(&index).cloned()
693    }
694
695    /// Returns the inner node at the specified index, falling back to the empty subtree root
696    /// if not stored.
697    fn get_inner_node_or_empty(&self, index: NodeIndex) -> InnerNode {
698        self.get_inner_node(index)
699            .unwrap_or_else(|| EmptySubtreeRoots::get_inner_node(SMT_DEPTH, index.depth()))
700    }
701
702    /// Inserts an inner node at the specified index, or removes it if it equals the empty
703    /// subtree root.
704    fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) {
705        if inner_node == EmptySubtreeRoots::get_inner_node(SMT_DEPTH, index.depth()) {
706            self.inner_nodes.remove(&index);
707        } else {
708            self.inner_nodes.insert(index, inner_node);
709        }
710    }
711
712    /// Returns the merkle path for a key by walking up the tree from the leaf.
713    fn get_path(&self, key: &Word) -> SparseMerklePath {
714        let index = NodeIndex::from(Self::key_to_leaf_index(key));
715
716        // Use proof_indices to get sibling indices from leaf to root,
717        // and get each sibling's hash
718        SparseMerklePath::from_sized_iter(index.proof_indices().map(|idx| self.get_node_hash(idx)))
719            .expect("path should be valid since it's from a valid SMT")
720    }
721
722    /// Get the hash of a node at an arbitrary index, including the root or leaf hashes.
723    ///
724    /// The root index simply returns the root. Other hashes are retrieved by looking at
725    /// the parent inner node and returning the respective child hash.
726    fn get_node_hash(&self, index: NodeIndex) -> Word {
727        if index.is_root() {
728            return self.root;
729        }
730
731        let InnerNode { left, right } = self.get_inner_node_or_empty(index.parent());
732
733        if index.is_position_odd() { right } else { left }
734    }
735
736    /// Recomputes all inner nodes from a leaf up to the root after a leaf value change.
737    fn recompute_nodes_from_leaf_to_root(
738        &mut self,
739        leaf_index: LeafIndex<SMT_DEPTH>,
740        leaf_hash: Word,
741    ) {
742        use crate::hash::poseidon2::Poseidon2;
743
744        let mut index: NodeIndex = leaf_index.into();
745        let mut node_hash = leaf_hash;
746
747        for _ in (0..index.depth()).rev() {
748            let is_right = index.is_position_odd();
749            index.move_up();
750            let InnerNode { left, right } = self.get_inner_node_or_empty(index);
751            let (left, right) = if is_right {
752                (left, node_hash)
753            } else {
754                (node_hash, right)
755            };
756            node_hash = Poseidon2::merge(&[left, right]);
757
758            // insert_inner_node handles removing empty subtree roots
759            self.insert_inner_node(index, InnerNode { left, right });
760        }
761        self.root = node_hash;
762    }
763
764    /// Validates the internal structure during deserialization.
765    ///
766    /// Checks that:
767    /// - Each inner node's hash is consistent with its parent.
768    /// - Each leaf's hash is consistent with its parent inner node's left/right child.
769    fn validate(&self) -> Result<(), DeserializationError> {
770        // Validate each inner node is consistent with its parent
771        for (&idx, node) in &self.inner_nodes {
772            let node_hash = node.hash();
773            let expected_hash = self.get_node_hash(idx);
774
775            if node_hash != expected_hash {
776                return Err(DeserializationError::InvalidValue(
777                    "inner node hash is inconsistent with parent".into(),
778                ));
779            }
780        }
781
782        // Validate each leaf's hash is consistent with its parent inner node
783        for (&leaf_pos, leaf) in &self.leaves {
784            let leaf_index = LeafIndex::<SMT_DEPTH>::new_max_depth(leaf_pos);
785            let node_index: NodeIndex = leaf_index.into();
786            let leaf_hash = leaf.hash();
787            let expected_hash = self.get_node_hash(node_index);
788
789            if leaf_hash != expected_hash {
790                return Err(DeserializationError::InvalidValue(
791                    "leaf hash is inconsistent with parent inner node".into(),
792                ));
793            }
794        }
795
796        Ok(())
797    }
798}
799
800impl Default for PartialSmt {
801    /// Returns a new, empty [`PartialSmt`].
802    ///
803    /// All leaves in the returned tree are set to [`Self::EMPTY_VALUE`].
804    fn default() -> Self {
805        Self::new(Self::EMPTY_ROOT)
806    }
807}
808
809// CONVERSIONS
810// ================================================================================================
811
812impl From<super::Smt> for PartialSmt {
813    fn from(smt: super::Smt) -> Self {
814        Self {
815            root: smt.root(),
816            num_entries: smt.num_entries(),
817            leaves: smt.leaves().map(|(idx, leaf)| (idx.position(), leaf.clone())).collect(),
818            inner_nodes: smt.inner_node_indices().collect(),
819        }
820    }
821}
822
823// SERIALIZATION
824// ================================================================================================
825
826impl Serializable for PartialSmt {
827    fn write_into<W: ByteWriter>(&self, target: &mut W) {
828        let unique_rep = self.to_unique_nodes();
829        unique_rep.write_into(target);
830    }
831}
832
833impl Deserializable for PartialSmt {
834    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
835        let unique_rep = UniqueNodes::read_from(source)?;
836        PartialSmt::from_unique_nodes(unique_rep)
837            .map_err(|e| DeserializationError::InvalidValue(format!("{e}")))
838    }
839}