arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/merkle/partial_mt/mod.rs
src/merkle/partial_mt/mod.rsRaw
  1use super::{
  2    BTreeMap, BTreeSet, MerkleError, MerklePath, NodeIndex, Rpo256, RpoDigest, ValuePath, Vec,
  3    Word, EMPTY_WORD,
  4};
  5
  6#[cfg(test)]
  7mod tests;
  8
  9// CONSTANTS
 10// ================================================================================================
 11
 12/// Index of the root node.
 13const ROOT_INDEX: NodeIndex = NodeIndex::root();
 14
 15/// An RpoDigest consisting of 4 ZERO elements.
 16const EMPTY_DIGEST: RpoDigest = RpoDigest::new(EMPTY_WORD);
 17
 18// PARTIAL MERKLE TREE
 19// ================================================================================================
 20
 21/// A partial Merkle tree with NodeIndex keys and 4-element RpoDigest leaf values. Partial Merkle
 22/// Tree allows to create Merkle Tree by providing Merkle paths of different lengths.
 23///
 24/// The root of the tree is recomputed on each new leaf update.
 25pub struct PartialMerkleTree {
 26    max_depth: u8,
 27    nodes: BTreeMap<NodeIndex, RpoDigest>,
 28    leaves: BTreeSet<NodeIndex>,
 29}
 30
 31impl Default for PartialMerkleTree {
 32    fn default() -> Self {
 33        Self::new()
 34    }
 35}
 36
 37impl PartialMerkleTree {
 38    // CONSTANTS
 39    // --------------------------------------------------------------------------------------------
 40
 41    /// Minimum supported depth.
 42    pub const MIN_DEPTH: u8 = 1;
 43
 44    /// Maximum supported depth.
 45    pub const MAX_DEPTH: u8 = 64;
 46
 47    // CONSTRUCTORS
 48    // --------------------------------------------------------------------------------------------
 49
 50    /// Returns a new emply [PartialMerkleTree].
 51    pub fn new() -> Self {
 52        PartialMerkleTree {
 53            max_depth: 0,
 54            nodes: BTreeMap::new(),
 55            leaves: BTreeSet::new(),
 56        }
 57    }
 58
 59    /// Appends the provided paths iterator into the set.
 60    ///
 61    /// Analogous to [Self::add_path].
 62    pub fn with_paths<I>(paths: I) -> Result<Self, MerkleError>
 63    where
 64        I: IntoIterator<Item = (u64, RpoDigest, MerklePath)>,
 65    {
 66        // create an empty tree
 67        let tree = PartialMerkleTree::new();
 68
 69        paths.into_iter().try_fold(tree, |mut tree, (index, value, path)| {
 70            tree.add_path(index, value, path)?;
 71            Ok(tree)
 72        })
 73    }
 74
 75    // PUBLIC ACCESSORS
 76    // --------------------------------------------------------------------------------------------
 77
 78    /// Returns the root of this Merkle tree.
 79    pub fn root(&self) -> RpoDigest {
 80        self.nodes.get(&ROOT_INDEX).cloned().unwrap_or(EMPTY_DIGEST)
 81    }
 82
 83    /// Returns the depth of this Merkle tree.
 84    pub fn max_depth(&self) -> u8 {
 85        self.max_depth
 86    }
 87
 88    /// Returns a node at the specified NodeIndex.
 89    ///
 90    /// # Errors
 91    /// Returns an error if the specified NodeIndex is not contained in the nodes map.
 92    pub fn get_node(&self, index: NodeIndex) -> Result<RpoDigest, MerkleError> {
 93        self.nodes.get(&index).ok_or(MerkleError::NodeNotInSet(index)).map(|hash| *hash)
 94    }
 95
 96    /// Returns true if provided index contains in the leaves set, false otherwise.
 97    pub fn is_leaf(&self, index: NodeIndex) -> bool {
 98        self.leaves.contains(&index)
 99    }
100
101    pub fn get_leaf_depth(&self, index: u64) -> Result<u8, MerkleError> {
102        let mut node_index = NodeIndex::new(self.max_depth(), index)?;
103        for _ in 0..node_index.depth() {
104            if self.leaves.contains(&node_index) {
105                return Ok(node_index.depth());
106            }
107            node_index.move_up()
108        }
109        Ok(0_u8)
110    }
111
112    /// Returns a vector of paths from every leaf to the root.
113    pub fn paths(&self) -> Vec<(NodeIndex, ValuePath)> {
114        let mut paths = Vec::new();
115        self.leaves.iter().for_each(|leaf| {
116            paths.push((
117                *leaf,
118                ValuePath {
119                    value: *self.get_node(*leaf).expect("Failed to get leaf node"),
120                    path: self.get_path(*leaf).expect("Failed to get path"),
121                },
122            ));
123        });
124        paths
125    }
126
127    /// Returns a Merkle path from the node at the specified index to the root.
128    ///
129    /// The node itself is not included in the path.
130    ///
131    /// # Errors
132    /// Returns an error if:
133    /// - the specified index has depth set to 0 or the depth is greater than the depth of this
134    /// Merkle tree.
135    /// - the specified index is not contained in the nodes map.
136    pub fn get_path(&self, mut index: NodeIndex) -> Result<MerklePath, MerkleError> {
137        if index.is_root() {
138            return Err(MerkleError::DepthTooSmall(index.depth()));
139        } else if index.depth() > self.max_depth() {
140            return Err(MerkleError::DepthTooBig(index.depth() as u64));
141        }
142
143        if !self.nodes.contains_key(&index) {
144            return Err(MerkleError::NodeNotInSet(index));
145        }
146
147        let mut path = Vec::new();
148        for _ in 0..index.depth() {
149            let sibling_index = index.sibling();
150            index.move_up();
151            let sibling =
152                self.nodes.get(&sibling_index).cloned().expect("Sibling node not in the map");
153            path.push(Word::from(sibling));
154        }
155        Ok(MerklePath::new(path))
156    }
157
158    // ITERATORS
159    // --------------------------------------------------------------------------------------------
160
161    /// Returns an iterator over the leaves of this [PartialMerkleTree].
162    pub fn leaves(&self) -> impl Iterator<Item = (NodeIndex, RpoDigest)> + '_ {
163        self.leaves.iter().map(|leaf| {
164            (
165                *leaf,
166                self.get_node(*leaf).unwrap_or_else(|_| {
167                    panic!(
168                        "Leaf with node index ({}, {}) is not in the nodes map",
169                        leaf.depth(),
170                        leaf.value()
171                    )
172                }),
173            )
174        })
175    }
176
177    // STATE MUTATORS
178    // --------------------------------------------------------------------------------------------
179
180    /// Adds the nodes of the specified Merkle path to this [PartialMerkleTree]. The `index_value`
181    /// and `value` parameters specify the leaf node at which the path starts.
182    ///
183    /// # Errors
184    /// Returns an error if:
185    /// - The depth of the specified node_index is greater than 64 or smaller than 1.
186    /// - The specified path is not consistent with other paths in the set (i.e., resolves to a
187    ///   different root).
188    pub fn add_path(
189        &mut self,
190        index_value: u64,
191        value: RpoDigest,
192        path: MerklePath,
193    ) -> Result<(), MerkleError> {
194        let index_value = NodeIndex::new(path.len() as u8, index_value)?;
195
196        Self::check_depth(index_value.depth())?;
197        self.update_depth(index_value.depth());
198
199        // add provided node and its sibling to the leaves set
200        self.leaves.insert(index_value);
201        let sibling_node_index = index_value.sibling();
202        self.leaves.insert(sibling_node_index);
203
204        // add provided node and its sibling to the nodes map
205        self.nodes.insert(index_value, value);
206        self.nodes.insert(sibling_node_index, path[0].into());
207
208        // traverse to the root, updating the nodes
209        let mut index_value = index_value;
210        let node = Rpo256::merge(&index_value.build_node(value, path[0].into()));
211        let root = path.iter().skip(1).copied().fold(node, |node, hash| {
212            index_value.move_up();
213            // insert calculated node to the nodes map
214            self.nodes.insert(index_value, node);
215
216            // if the calculated node was a leaf, remove it from leaves set.
217            if self.leaves.contains(&index_value) {
218                self.leaves.remove(&index_value);
219            }
220
221            let sibling_node = index_value.sibling();
222            // node became a leaf only if it is a new node (it wasn't in nodes map)
223            if !self.nodes.contains_key(&sibling_node) {
224                self.leaves.insert(sibling_node);
225            }
226
227            // insert node from Merkle path to the nodes map
228            self.nodes.insert(sibling_node, hash.into());
229
230            Rpo256::merge(&index_value.build_node(node, hash.into()))
231        });
232
233        // if the path set is empty (the root is all ZEROs), set the root to the root of the added
234        // path; otherwise, the root of the added path must be identical to the current root
235        if self.root() == EMPTY_DIGEST {
236            self.nodes.insert(ROOT_INDEX, root);
237        } else if self.root() != root {
238            return Err(MerkleError::ConflictingRoots([*self.root(), *root].to_vec()));
239        }
240
241        // self.update_leaves()?;
242
243        Ok(())
244    }
245
246    /// Updates value of the leaf at the specified index returning the old leaf value.
247    ///
248    /// This also recomputes all hashes between the leaf and the root, updating the root itself.
249    pub fn update_leaf(
250        &mut self,
251        node_index: NodeIndex,
252        value: RpoDigest,
253    ) -> Result<RpoDigest, MerkleError> {
254        // check correctness of the depth and update it
255        Self::check_depth(node_index.depth())?;
256        self.update_depth(node_index.depth());
257
258        // insert NodeIndex to the leaves Set
259        self.leaves.insert(node_index);
260
261        // add node value to the nodes Map
262        let old_value = self.nodes.insert(node_index, value).unwrap_or(EMPTY_DIGEST);
263
264        // if the old value and new value are the same, there is nothing to update
265        if value == old_value {
266            return Ok(value);
267        }
268
269        let mut node_index = node_index;
270        let mut value = value;
271        for _ in 0..node_index.depth() {
272            let is_right = node_index.is_value_odd();
273            let (left, right) = if is_right {
274                let left_index = NodeIndex::new(node_index.depth(), node_index.value() - 1)?;
275                (
276                    self.nodes
277                        .get(&left_index)
278                        .cloned()
279                        .ok_or(MerkleError::NodeNotInSet(left_index))?,
280                    value,
281                )
282            } else {
283                let right_index = NodeIndex::new(node_index.depth(), node_index.value() + 1)?;
284                (
285                    value,
286                    self.nodes
287                        .get(&right_index)
288                        .cloned()
289                        .ok_or(MerkleError::NodeNotInSet(right_index))?,
290                )
291            };
292            node_index.move_up();
293            value = Rpo256::merge(&[left, right]);
294            self.nodes.insert(node_index, value);
295        }
296
297        Ok(old_value)
298    }
299
300    // HELPER METHODS
301    // --------------------------------------------------------------------------------------------
302
303    /// Updates depth value with the maximum of current and provided depth.
304    fn update_depth(&mut self, new_depth: u8) {
305        self.max_depth = new_depth.max(self.max_depth);
306    }
307
308    /// Returns an error if the depth is 0 or is greater than 64.
309    fn check_depth(depth: u8) -> Result<(), MerkleError> {
310        // validate the range of the depth.
311        if depth < Self::MIN_DEPTH {
312            return Err(MerkleError::DepthTooSmall(depth));
313        } else if Self::MAX_DEPTH < depth {
314            return Err(MerkleError::DepthTooBig(depth as u64));
315        }
316        Ok(())
317    }
318}