Skip to main content

miden_crypto/merkle/partial_mt/
mod.rs

1use alloc::{
2    collections::{BTreeMap, BTreeSet},
3    string::String,
4    vec::Vec,
5};
6use core::fmt;
7
8use super::{
9    EMPTY_WORD, Eidos, InnerNodeInfo, MerkleError, MerklePath, MerkleProof, NodeIndex, Word,
10};
11use crate::utils::{
12    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, word_to_hex,
13};
14
15#[cfg(test)]
16mod tests;
17
18// ARBITRARY (proptest)
19// ================================================================================================
20
21#[cfg(any(test, feature = "arbitrary"))]
22mod arbitrary {
23    extern crate alloc;
24
25    use alloc::vec::Vec;
26
27    use proptest::prelude::*;
28
29    use super::PartialMerkleTree;
30    use crate::{
31        Word,
32        merkle::{MerklePath, MerkleTree, NodeIndex},
33    };
34
35    impl Arbitrary for PartialMerkleTree {
36        type Parameters = ();
37        type Strategy = BoxedStrategy<Self>;
38
39        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
40            // Sound by construction. Branch A opens a subset of leaves of a real MerkleTree:
41            // all paths share one depth, so no entry can be an ancestor of another (the
42            // ambiguity `with_leaves` rejects), and an all-false mask yields the empty tree.
43            // Branch B contributes a single synthetic deep path (no other path, so still no
44            // ambiguity), exercising large NodeIndex depth/position wire encodings cheaply -
45            // path provenance is irrelevant to the leaves-only wire format. No generation-time
46            // panics: every input is valid for any shrunken prefix.
47            prop_oneof![paths_from_real_tree().boxed(), single_deep_path().boxed()].boxed()
48        }
49    }
50
51    fn paths_from_real_tree() -> impl Strategy<Value = PartialMerkleTree> {
52        (1u8..=6)
53            .prop_flat_map(|depth| {
54                let count = 1usize << depth;
55                (
56                    Just(depth),
57                    proptest::collection::vec(any::<Word>(), count),
58                    proptest::collection::vec(any::<bool>(), count),
59                )
60            })
61            .prop_map(|(depth, leaves, track_mask)| {
62                let tree = MerkleTree::new(&leaves).expect("leaf count is a power of two >= 2");
63                let paths: Vec<(u64, Word, MerklePath)> = track_mask
64                    .iter()
65                    .enumerate()
66                    .filter(|(_, tracked)| **tracked)
67                    .map(|(pos, _)| {
68                        let node_index =
69                            NodeIndex::new(depth, pos as u64).expect("position fits the depth");
70                        let path = tree.get_path(node_index).expect("position within the tree");
71                        (pos as u64, leaves[pos], path)
72                    })
73                    .collect();
74                PartialMerkleTree::with_paths(paths)
75                    .expect("paths from one tree share a depth and no ancestor relation")
76            })
77    }
78
79    fn single_deep_path() -> impl Strategy<Value = PartialMerkleTree> {
80        (7u8..=64, any::<u64>(), any::<Word>())
81            .prop_flat_map(|(depth, index, value)| {
82                let mask = if depth == 64 { u64::MAX } else { (1u64 << depth) - 1 };
83                (
84                    Just(depth),
85                    Just(value),
86                    Just(index & mask),
87                    proptest::collection::vec(any::<Word>(), depth as usize),
88                )
89            })
90            .prop_map(|(_depth, value, index, path_nodes)| {
91                let path = MerklePath::new(path_nodes);
92                PartialMerkleTree::with_paths([(index, value, path)])
93                    .expect("a single path is always a valid partial tree")
94            })
95    }
96}
97
98// CONSTANTS
99// ================================================================================================
100
101/// Index of the root node.
102const ROOT_INDEX: NodeIndex = NodeIndex::root();
103
104/// An Word consisting of 4 ZERO elements.
105const EMPTY_DIGEST: Word = EMPTY_WORD;
106
107// PARTIAL MERKLE TREE
108// ================================================================================================
109
110/// A partial Merkle tree with NodeIndex keys and 4-element [Word] leaf values. Partial Merkle
111/// Tree allows to create Merkle Tree by providing Merkle paths of different lengths.
112///
113/// The root of the tree is recomputed on each new leaf update.
114#[derive(Debug, Clone, PartialEq, Eq)]
115#[cfg_attr(
116    all(feature = "arbitrary", test),
117    miden_test_serialization_macros::serialization_test
118)]
119pub struct PartialMerkleTree {
120    max_depth: u8,
121    nodes: BTreeMap<NodeIndex, Word>,
122    leaves: BTreeSet<NodeIndex>,
123}
124
125impl Default for PartialMerkleTree {
126    fn default() -> Self {
127        Self::new()
128    }
129}
130
131impl PartialMerkleTree {
132    // CONSTANTS
133    // --------------------------------------------------------------------------------------------
134
135    /// Minimum supported depth.
136    pub const MIN_DEPTH: u8 = 1;
137
138    /// Maximum supported depth.
139    pub const MAX_DEPTH: u8 = 64;
140
141    // CONSTRUCTORS
142    // --------------------------------------------------------------------------------------------
143
144    /// Returns a new empty [PartialMerkleTree].
145    pub fn new() -> Self {
146        PartialMerkleTree {
147            max_depth: 0,
148            nodes: BTreeMap::new(),
149            leaves: BTreeSet::new(),
150        }
151    }
152
153    /// Appends the provided paths iterator into the set.
154    ///
155    /// Analogous to [Self::add_path].
156    pub fn with_paths<I>(paths: I) -> Result<Self, MerkleError>
157    where
158        I: IntoIterator<Item = (u64, Word, MerklePath)>,
159    {
160        // create an empty tree
161        let tree = PartialMerkleTree::new();
162
163        paths.into_iter().try_fold(tree, |mut tree, (index, value, path)| {
164            tree.add_path(index, value, path)?;
165            Ok(tree)
166        })
167    }
168
169    /// Returns a new [PartialMerkleTree] instantiated with leaves map as specified by the provided
170    /// entries.
171    ///
172    /// # Errors
173    /// Returns an error if:
174    /// - Any entry has depth 0 or is greater than 64.
175    /// - The number of entries exceeds the maximum tree capacity, that is 2^{depth}.
176    /// - The provided entries contain an insufficient set of nodes.
177    /// - Any entry is an ancestor of another entry (creates hash ambiguity).
178    ///
179    /// An empty input returns an empty tree.
180    pub fn with_leaves<R, I>(entries: R) -> Result<Self, MerkleError>
181    where
182        R: IntoIterator<IntoIter = I>,
183        I: Iterator<Item = (NodeIndex, Word)> + ExactSizeIterator,
184    {
185        let entries = entries.into_iter();
186        if entries.len() == 0 {
187            return Ok(PartialMerkleTree::new());
188        }
189
190        let mut layers: BTreeMap<u8, Vec<u64>> = BTreeMap::new();
191        let mut leaves = BTreeSet::new();
192        let mut nodes = BTreeMap::new();
193
194        // add data to the leaves and nodes maps and also fill layers map, where the key is the
195        // depth of the node and value is its index.
196        for (node_index, hash) in entries {
197            Self::check_depth(node_index.depth())?;
198            leaves.insert(node_index);
199            nodes.insert(node_index, hash);
200            layers
201                .entry(node_index.depth())
202                .and_modify(|layer_vec| layer_vec.push(node_index.position()))
203                .or_insert(vec![node_index.position()]);
204        }
205
206        // Get maximum depth
207        let max_depth = *layers.keys().next_back().unwrap_or(&0);
208
209        // fill layers without nodes with empty vector
210        for depth in 0..max_depth {
211            layers.entry(depth).or_default();
212        }
213
214        let mut layer_iter = layers.into_values().rev();
215        let mut parent_layer = layer_iter.next().unwrap();
216        let mut current_layer;
217
218        for depth in (1..max_depth + 1).rev() {
219            // set current_layer = parent_layer and parent_layer = layer_iter.next()
220            current_layer = layer_iter.next().unwrap();
221            core::mem::swap(&mut current_layer, &mut parent_layer);
222
223            // Siblings have the same parent position. Sort them together and retain one child per
224            // parent so each parent is computed once.
225            current_layer.sort_unstable();
226            current_layer.dedup_by_key(|position| *position / 2);
227
228            for index_value in current_layer {
229                // get the parent node index
230                let parent_node = NodeIndex::new(depth - 1, index_value / 2)?;
231
232                // A user-provided parent cannot also have a descendant in the input set.
233                if leaves.contains(&parent_node) {
234                    return Err(MerkleError::EntryIsNotLeaf { node: parent_node });
235                }
236
237                // create current node index
238                let index = NodeIndex::new(depth, index_value)?;
239
240                // get hash of the current node
241                let node = nodes.get(&index).ok_or(MerkleError::NodeIndexNotFoundInTree(index))?;
242                // get hash of the sibling node
243                let sibling = nodes
244                    .get(&index.sibling())
245                    .ok_or(MerkleError::NodeIndexNotFoundInTree(index.sibling()))?;
246                // get parent hash
247                let parent = Eidos::merge(&index.build_node(*node, *sibling));
248
249                // add index value of the calculated node to the parents layer
250                parent_layer.push(parent_node.position());
251                // add index and hash to the nodes map
252                nodes.insert(parent_node, parent);
253            }
254        }
255
256        Ok(PartialMerkleTree { max_depth, nodes, leaves })
257    }
258
259    // PUBLIC ACCESSORS
260    // --------------------------------------------------------------------------------------------
261
262    /// Returns the root of this Merkle tree.
263    pub fn root(&self) -> Word {
264        self.nodes.get(&ROOT_INDEX).cloned().unwrap_or(EMPTY_DIGEST)
265    }
266
267    /// Returns the depth of this Merkle tree.
268    pub fn max_depth(&self) -> u8 {
269        self.max_depth
270    }
271
272    /// Returns a node at the specified NodeIndex.
273    ///
274    /// # Errors
275    /// Returns an error if the specified NodeIndex is not contained in the nodes map.
276    pub fn get_node(&self, index: NodeIndex) -> Result<Word, MerkleError> {
277        self.nodes
278            .get(&index)
279            .ok_or(MerkleError::NodeIndexNotFoundInTree(index))
280            .copied()
281    }
282
283    /// Returns true if provided index contains in the leaves set, false otherwise.
284    pub fn is_leaf(&self, index: NodeIndex) -> bool {
285        self.leaves.contains(&index)
286    }
287
288    /// Returns a vector of paths from every leaf to the root.
289    pub fn to_paths(&self) -> Vec<(NodeIndex, MerkleProof)> {
290        let mut paths = Vec::new();
291        self.leaves.iter().for_each(|&leaf| {
292            paths.push((
293                leaf,
294                MerkleProof {
295                    value: self.get_node(leaf).expect("Failed to get leaf node"),
296                    path: self.get_path(leaf).expect("Failed to get path"),
297                },
298            ));
299        });
300        paths
301    }
302
303    /// Returns a Merkle path from the node at the specified index to the root.
304    ///
305    /// The node itself is not included in the path.
306    ///
307    /// # Errors
308    /// Returns an error if:
309    /// - the specified index has depth set to 0 or the depth is greater than the depth of this
310    ///   Merkle tree.
311    /// - the specified index is not contained in the nodes map.
312    pub fn get_path(&self, mut index: NodeIndex) -> Result<MerklePath, MerkleError> {
313        if index.is_root() {
314            return Err(MerkleError::DepthTooSmall(index.depth()));
315        } else if index.depth() > self.max_depth() {
316            return Err(MerkleError::DepthTooBig(index.depth() as u64));
317        }
318
319        if !self.nodes.contains_key(&index) {
320            return Err(MerkleError::NodeIndexNotFoundInTree(index));
321        }
322
323        let mut path = Vec::new();
324        for _ in 0..index.depth() {
325            let sibling_index = index.sibling();
326            index.move_up();
327            let sibling =
328                self.nodes.get(&sibling_index).cloned().expect("Sibling node not in the map");
329            path.push(sibling);
330        }
331        Ok(MerklePath::new(path))
332    }
333
334    // ITERATORS
335    // --------------------------------------------------------------------------------------------
336
337    /// Returns an iterator over the leaves of this [PartialMerkleTree].
338    pub fn leaves(&self) -> impl Iterator<Item = (NodeIndex, Word)> + '_ {
339        self.leaves.iter().map(|&leaf| {
340            (
341                leaf,
342                self.get_node(leaf)
343                    .unwrap_or_else(|_| panic!("Leaf with {leaf} is not in the nodes map")),
344            )
345        })
346    }
347
348    /// Returns an iterator over the inner nodes of this Merkle tree.
349    pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
350        let inner_nodes = self.nodes.iter().filter(|(index, _)| !self.leaves.contains(index));
351        inner_nodes.map(|(index, digest)| {
352            let left_hash =
353                self.nodes.get(&index.left_child()).expect("Failed to get left child hash");
354            let right_hash =
355                self.nodes.get(&index.right_child()).expect("Failed to get right child hash");
356            InnerNodeInfo {
357                value: *digest,
358                left: *left_hash,
359                right: *right_hash,
360            }
361        })
362    }
363
364    // STATE MUTATORS
365    // --------------------------------------------------------------------------------------------
366
367    /// Adds the nodes of the specified Merkle path to this [PartialMerkleTree]. The `index_value`
368    /// and `value` parameters specify the leaf node at which the path starts.
369    ///
370    /// # Errors
371    /// Returns an error if:
372    /// - The depth of the specified node_index is greater than 64 or smaller than 1.
373    /// - The specified path is not consistent with other paths in the set (i.e., resolves to a
374    ///   different root).
375    pub fn add_path(
376        &mut self,
377        index_value: u64,
378        value: Word,
379        path: MerklePath,
380    ) -> Result<(), MerkleError> {
381        let index_value = NodeIndex::new(path.len() as u8, index_value)?;
382
383        Self::check_depth(index_value.depth())?;
384        self.update_depth(index_value.depth());
385
386        // add provided node and its sibling to the leaves set
387        self.leaves.insert(index_value);
388        let sibling_node_index = index_value.sibling();
389        self.leaves.insert(sibling_node_index);
390
391        // add provided node and its sibling to the nodes map
392        self.nodes.insert(index_value, value);
393        self.nodes.insert(sibling_node_index, path[0]);
394
395        // traverse to the root, updating the nodes
396        let mut index_value = index_value;
397        let node = Eidos::merge(&index_value.build_node(value, path[0]));
398        let root = path.iter().skip(1).copied().fold(node, |node, hash| {
399            index_value.move_up();
400            // insert calculated node to the nodes map
401            self.nodes.insert(index_value, node);
402
403            // if the calculated node was a leaf, remove it from leaves set.
404            self.leaves.remove(&index_value);
405
406            let sibling_node = index_value.sibling();
407
408            // Insert node from Merkle path to the nodes map. This sibling node becomes a leaf only
409            // if it is a new node (it wasn't in nodes map).
410            // Node can be in 3 states: internal node, leaf of the tree and not a tree node at all.
411            // - Internal node can only stay in this state -- addition of a new path can't make it
412            // a leaf or remove it from the tree.
413            // - Leaf node can stay in the same state (remain a leaf) or can become an internal
414            // node. In the first case we don't need to do anything, and the second case is handled
415            // by the call of `self.leaves.remove(&index_value);`
416            // - New node can be a calculated node or a "sibling" node from a Merkle Path:
417            // --- Calculated node, obviously, never can be a leaf.
418            // --- Sibling node can be only a leaf, because otherwise it is not a new node.
419            if self.nodes.insert(sibling_node, hash).is_none() {
420                self.leaves.insert(sibling_node);
421            }
422
423            Eidos::merge(&index_value.build_node(node, hash))
424        });
425
426        // if the path set is empty (the root is all ZEROs), set the root to the root of the added
427        // path; otherwise, the root of the added path must be identical to the current root
428        if self.root() == EMPTY_DIGEST {
429            self.nodes.insert(ROOT_INDEX, root);
430        } else if self.root() != root {
431            return Err(MerkleError::ConflictingRoots {
432                expected_root: self.root(),
433                actual_root: root,
434            });
435        }
436
437        Ok(())
438    }
439
440    /// Updates value of the leaf at the specified index returning the old leaf value.
441    ///
442    /// By default the specified index is assumed to belong to the deepest layer. If the considered
443    /// node does not belong to the tree, the first node on the way to the root will be changed.
444    ///
445    /// This also recomputes all hashes between the leaf and the root, updating the root itself.
446    ///
447    /// # Errors
448    /// Returns an error if:
449    /// - No entry exists at the specified index.
450    /// - The specified index is greater than the maximum number of nodes on the deepest layer.
451    pub fn update_leaf(&mut self, index: u64, value: Word) -> Result<Word, MerkleError> {
452        let mut node_index = NodeIndex::new(self.max_depth(), index)?;
453
454        // proceed to the leaf
455        for _ in 0..node_index.depth() {
456            if !self.leaves.contains(&node_index) {
457                node_index.move_up();
458            }
459        }
460
461        // add node value to the nodes Map
462        let old_value = self
463            .nodes
464            .insert(node_index, value)
465            .ok_or(MerkleError::NodeIndexNotFoundInTree(node_index))?;
466
467        // if the old value and new value are the same, there is nothing to update
468        if value == old_value {
469            return Ok(old_value);
470        }
471
472        let mut value = value;
473        for _ in 0..node_index.depth() {
474            let sibling = self.nodes.get(&node_index.sibling()).expect("sibling should exist");
475            value = Eidos::merge(&node_index.build_node(value, *sibling));
476            node_index.move_up();
477            self.nodes.insert(node_index, value);
478        }
479
480        Ok(old_value)
481    }
482
483    // UTILITY FUNCTIONS
484    // --------------------------------------------------------------------------------------------
485
486    /// Utility to visualize a [PartialMerkleTree] in text.
487    pub fn print(&self) -> Result<String, fmt::Error> {
488        let indent = "  ";
489        let mut s = String::new();
490        s.push_str("root: ");
491        s.push_str(&word_to_hex(&self.root())?);
492        s.push('\n');
493        for d in 1..=self.max_depth() {
494            let entries = 2u64.pow(d.into());
495            for i in 0..entries {
496                let index = NodeIndex::new(d, i).expect("The index must always be valid");
497                let node = self.get_node(index);
498                let node = match node {
499                    Err(_) => continue,
500                    Ok(node) => node,
501                };
502
503                for _ in 0..d {
504                    s.push_str(indent);
505                }
506                s.push_str(&format!("({}, {}): ", index.depth(), index.position()));
507                s.push_str(&word_to_hex(&node)?);
508                s.push('\n');
509            }
510        }
511
512        Ok(s)
513    }
514
515    // HELPER METHODS
516    // --------------------------------------------------------------------------------------------
517
518    /// Updates depth value with the maximum of current and provided depth.
519    fn update_depth(&mut self, new_depth: u8) {
520        self.max_depth = new_depth.max(self.max_depth);
521    }
522
523    /// Returns an error if the depth is 0 or is greater than 64.
524    fn check_depth(depth: u8) -> Result<(), MerkleError> {
525        // validate the range of the depth.
526        if depth < Self::MIN_DEPTH {
527            return Err(MerkleError::DepthTooSmall(depth));
528        } else if Self::MAX_DEPTH < depth {
529            return Err(MerkleError::DepthTooBig(depth as u64));
530        }
531        Ok(())
532    }
533}
534
535// SERIALIZATION
536// ================================================================================================
537
538impl Serializable for PartialMerkleTree {
539    fn write_into<W: ByteWriter>(&self, target: &mut W) {
540        // write leaf nodes
541        target.write_u64(self.leaves.len() as u64);
542        for leaf_index in self.leaves.iter() {
543            leaf_index.write_into(target);
544            self.get_node(*leaf_index).expect("Leaf hash not found").write_into(target);
545        }
546    }
547}
548
549impl Deserializable for PartialMerkleTree {
550    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
551        let leaves_len_u64 = source.read_u64()?;
552        let leaves_len = usize::try_from(leaves_len_u64).map_err(|_| {
553            DeserializationError::InvalidValue("PartialMerkleTree leaf count too large".into())
554        })?;
555
556        // Use read_many_iter to avoid eager allocation and respect BudgetedReader limits
557        let leaf_nodes: Vec<(NodeIndex, Word)> =
558            source.read_many_iter(leaves_len)?.collect::<Result<_, _>>()?;
559
560        let pmt = PartialMerkleTree::with_leaves(leaf_nodes).map_err(|_| {
561            DeserializationError::InvalidValue("Invalid data for PartialMerkleTree creation".into())
562        })?;
563
564        Ok(pmt)
565    }
566
567    /// Minimum serialized size: u64 length prefix (0 entries).
568    fn min_serialized_size() -> usize {
569        8
570    }
571}