arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/merkle/path_set.rs
src/merkle/path_set.rsRaw
  1use super::{BTreeMap, MerkleError, MerklePath, NodeIndex, Rpo256, ValuePath, Vec, Word, ZERO};
  2
  3// MERKLE PATH SET
  4// ================================================================================================
  5
  6/// A set of Merkle paths.
  7#[derive(Debug, Clone, PartialEq, Eq)]
  8pub struct MerklePathSet {
  9    root: Word,
 10    total_depth: u8,
 11    paths: BTreeMap<u64, MerklePath>,
 12}
 13
 14impl MerklePathSet {
 15    // CONSTRUCTOR
 16    // --------------------------------------------------------------------------------------------
 17
 18    /// Returns an empty MerklePathSet.
 19    pub fn new(depth: u8) -> Self {
 20        let root = [ZERO; 4];
 21        let paths = BTreeMap::new();
 22
 23        Self {
 24            root,
 25            total_depth: depth,
 26            paths,
 27        }
 28    }
 29
 30    /// Appends the provided paths iterator into the set.
 31    ///
 32    /// Analogous to `[Self::add_path]`.
 33    pub fn with_paths<I>(self, paths: I) -> Result<Self, MerkleError>
 34    where
 35        I: IntoIterator<Item = (u64, Word, MerklePath)>,
 36    {
 37        paths.into_iter().try_fold(self, |mut set, (index, value, path)| {
 38            set.add_path(index, value, path)?;
 39            Ok(set)
 40        })
 41    }
 42
 43    // PUBLIC ACCESSORS
 44    // --------------------------------------------------------------------------------------------
 45
 46    /// Returns the root to which all paths in this set resolve.
 47    pub const fn root(&self) -> Word {
 48        self.root
 49    }
 50
 51    /// Returns the depth of the Merkle tree implied by the paths stored in this set.
 52    ///
 53    /// Merkle tree of depth 1 has two leaves, depth 2 has four leaves etc.
 54    pub const fn depth(&self) -> u8 {
 55        self.total_depth
 56    }
 57
 58    /// Returns a node at the specified index.
 59    ///
 60    /// # Errors
 61    /// Returns an error if:
 62    /// * The specified index is not valid for the depth of structure.
 63    /// * Requested node does not exist in the set.
 64    pub fn get_node(&self, index: NodeIndex) -> Result<Word, MerkleError> {
 65        if index.depth() != self.total_depth {
 66            return Err(MerkleError::InvalidDepth {
 67                expected: self.total_depth,
 68                provided: index.depth(),
 69            });
 70        }
 71
 72        let parity = index.value() & 1;
 73        let path_key = index.value() - parity;
 74        self.paths
 75            .get(&path_key)
 76            .ok_or(MerkleError::NodeNotInSet(path_key))
 77            .map(|path| path[parity as usize])
 78    }
 79
 80    /// Returns a leaf at the specified index.
 81    ///
 82    /// # Errors
 83    /// * The specified index is not valid for the depth of the structure.
 84    /// * Leaf with the requested path does not exist in the set.
 85    pub fn get_leaf(&self, index: u64) -> Result<Word, MerkleError> {
 86        let index = NodeIndex::new(self.depth(), index)?;
 87        self.get_node(index)
 88    }
 89
 90    /// Returns a Merkle path to the node at the specified index. The node itself is
 91    /// not included in the path.
 92    ///
 93    /// # Errors
 94    /// Returns an error if:
 95    /// * The specified index is not valid for the depth of structure.
 96    /// * Node of the requested path does not exist in the set.
 97    pub fn get_path(&self, index: NodeIndex) -> Result<MerklePath, MerkleError> {
 98        if index.depth() != self.total_depth {
 99            return Err(MerkleError::InvalidDepth {
100                expected: self.total_depth,
101                provided: index.depth(),
102            });
103        }
104
105        let parity = index.value() & 1;
106        let path_key = index.value() - parity;
107        let mut path = self
108            .paths
109            .get(&path_key)
110            .cloned()
111            .ok_or(MerkleError::NodeNotInSet(index.value()))?;
112        path.remove(parity as usize);
113        Ok(path)
114    }
115
116    /// Returns all paths in this path set together with their indexes.
117    pub fn to_paths(&self) -> Vec<(u64, ValuePath)> {
118        let mut result = Vec::with_capacity(self.paths.len() * 2);
119
120        for (&index, path) in self.paths.iter() {
121            // push path for the even index into the result
122            let path1 = ValuePath {
123                value: path[0],
124                path: MerklePath::new(path[1..].to_vec()),
125            };
126            result.push((index, path1));
127
128            // push path for the odd index into the result
129            let mut path2 = path.clone();
130            let leaf2 = path2.remove(1);
131            let path2 = ValuePath {
132                value: leaf2,
133                path: path2,
134            };
135            result.push((index + 1, path2));
136        }
137
138        result
139    }
140
141    // STATE MUTATORS
142    // --------------------------------------------------------------------------------------------
143
144    /// Adds the specified Merkle path to this [MerklePathSet]. The `index` and `value` parameters
145    /// specify the leaf node at which the path starts.
146    ///
147    /// # Errors
148    /// Returns an error if:
149    /// - The specified index is is not valid in the context of this Merkle path set (i.e., the
150    ///   index implies a greater depth than is specified for this set).
151    /// - The specified path is not consistent with other paths in the set (i.e., resolves to a
152    ///   different root).
153    pub fn add_path(
154        &mut self,
155        index_value: u64,
156        value: Word,
157        mut path: MerklePath,
158    ) -> Result<(), MerkleError> {
159        let mut index = NodeIndex::new(path.len() as u8, index_value)?;
160        if index.depth() != self.total_depth {
161            return Err(MerkleError::InvalidDepth {
162                expected: self.total_depth,
163                provided: index.depth(),
164            });
165        }
166
167        // update the current path
168        let parity = index_value & 1;
169        path.insert(parity as usize, value);
170
171        // traverse to the root, updating the nodes
172        let root: Word = Rpo256::merge(&[path[0].into(), path[1].into()]).into();
173        let root = path.iter().skip(2).copied().fold(root, |root, hash| {
174            index.move_up();
175            Rpo256::merge(&index.build_node(root.into(), hash.into())).into()
176        });
177
178        // if the path set is empty (the root is all ZEROs), set the root to the root of the added
179        // path; otherwise, the root of the added path must be identical to the current root
180        if self.root == [ZERO; 4] {
181            self.root = root;
182        } else if self.root != root {
183            return Err(MerkleError::ConflictingRoots([self.root, root].to_vec()));
184        }
185
186        // finish updating the path
187        let path_key = index_value - parity;
188        self.paths.insert(path_key, path);
189        Ok(())
190    }
191
192    /// Replaces the leaf at the specified index with the provided value.
193    ///
194    /// # Errors
195    /// Returns an error if:
196    /// * Requested node does not exist in the set.
197    pub fn update_leaf(&mut self, base_index_value: u64, value: Word) -> Result<(), MerkleError> {
198        let mut index = NodeIndex::new(self.depth(), base_index_value)?;
199        let parity = index.value() & 1;
200        let path_key = index.value() - parity;
201        let path = match self.paths.get_mut(&path_key) {
202            Some(path) => path,
203            None => return Err(MerkleError::NodeNotInSet(base_index_value)),
204        };
205
206        // Fill old_hashes vector -----------------------------------------------------------------
207        let mut current_index = index;
208        let mut old_hashes = Vec::with_capacity(path.len().saturating_sub(2));
209        let mut root: Word = Rpo256::merge(&[path[0].into(), path[1].into()]).into();
210        for hash in path.iter().skip(2).copied() {
211            old_hashes.push(root);
212            current_index.move_up();
213            let input = current_index.build_node(hash.into(), root.into());
214            root = Rpo256::merge(&input).into();
215        }
216
217        // Fill new_hashes vector -----------------------------------------------------------------
218        path[index.is_value_odd() as usize] = value;
219
220        let mut new_hashes = Vec::with_capacity(path.len().saturating_sub(2));
221        let mut new_root: Word = Rpo256::merge(&[path[0].into(), path[1].into()]).into();
222        for path_hash in path.iter().skip(2).copied() {
223            new_hashes.push(new_root);
224            index.move_up();
225            let input = current_index.build_node(path_hash.into(), new_root.into());
226            new_root = Rpo256::merge(&input).into();
227        }
228
229        self.root = new_root;
230
231        // update paths ---------------------------------------------------------------------------
232        for path in self.paths.values_mut() {
233            for i in (0..old_hashes.len()).rev() {
234                if path[i + 2] == old_hashes[i] {
235                    path[i + 2] = new_hashes[i];
236                    break;
237                }
238            }
239        }
240
241        Ok(())
242    }
243}
244
245// TESTS
246// ================================================================================================
247
248#[cfg(test)]
249mod tests {
250    use super::*;
251    use crate::merkle::int_to_node;
252
253    #[test]
254    fn get_root() {
255        let leaf0 = int_to_node(0);
256        let leaf1 = int_to_node(1);
257        let leaf2 = int_to_node(2);
258        let leaf3 = int_to_node(3);
259
260        let parent0 = calculate_parent_hash(leaf0, 0, leaf1);
261        let parent1 = calculate_parent_hash(leaf2, 2, leaf3);
262
263        let root_exp = calculate_parent_hash(parent0, 0, parent1);
264
265        let set = super::MerklePathSet::new(2)
266            .with_paths([(0, leaf0, vec![leaf1, parent1].into())])
267            .unwrap();
268
269        assert_eq!(set.root(), root_exp);
270    }
271
272    #[test]
273    fn add_and_get_path() {
274        let path_6 = vec![int_to_node(7), int_to_node(45), int_to_node(123)];
275        let hash_6 = int_to_node(6);
276        let index = 6_u64;
277        let depth = 3_u8;
278        let set = super::MerklePathSet::new(depth)
279            .with_paths([(index, hash_6, path_6.clone().into())])
280            .unwrap();
281        let stored_path_6 = set.get_path(NodeIndex::make(depth, index)).unwrap();
282
283        assert_eq!(path_6, *stored_path_6);
284    }
285
286    #[test]
287    fn get_node() {
288        let path_6 = vec![int_to_node(7), int_to_node(45), int_to_node(123)];
289        let hash_6 = int_to_node(6);
290        let index = 6_u64;
291        let depth = 3_u8;
292        let set = MerklePathSet::new(depth).with_paths([(index, hash_6, path_6.into())]).unwrap();
293
294        assert_eq!(int_to_node(6u64), set.get_node(NodeIndex::make(depth, index)).unwrap());
295    }
296
297    #[test]
298    fn update_leaf() {
299        let hash_4 = int_to_node(4);
300        let hash_5 = int_to_node(5);
301        let hash_6 = int_to_node(6);
302        let hash_7 = int_to_node(7);
303        let hash_45 = calculate_parent_hash(hash_4, 12u64, hash_5);
304        let hash_67 = calculate_parent_hash(hash_6, 14u64, hash_7);
305
306        let hash_0123 = int_to_node(123);
307
308        let path_6 = vec![hash_7, hash_45, hash_0123];
309        let path_5 = vec![hash_4, hash_67, hash_0123];
310        let path_4 = vec![hash_5, hash_67, hash_0123];
311
312        let index_6 = 6_u64;
313        let index_5 = 5_u64;
314        let index_4 = 4_u64;
315        let depth = 3_u8;
316        let mut set = MerklePathSet::new(depth)
317            .with_paths([
318                (index_6, hash_6, path_6.into()),
319                (index_5, hash_5, path_5.into()),
320                (index_4, hash_4, path_4.into()),
321            ])
322            .unwrap();
323
324        let new_hash_6 = int_to_node(100);
325        let new_hash_5 = int_to_node(55);
326
327        set.update_leaf(index_6, new_hash_6).unwrap();
328        let new_path_4 = set.get_path(NodeIndex::make(depth, index_4)).unwrap();
329        let new_hash_67 = calculate_parent_hash(new_hash_6, 14_u64, hash_7);
330        assert_eq!(new_hash_67, new_path_4[1]);
331
332        set.update_leaf(index_5, new_hash_5).unwrap();
333        let new_path_4 = set.get_path(NodeIndex::make(depth, index_4)).unwrap();
334        let new_path_6 = set.get_path(NodeIndex::make(depth, index_6)).unwrap();
335        let new_hash_45 = calculate_parent_hash(new_hash_5, 13_u64, hash_4);
336        assert_eq!(new_hash_45, new_path_6[1]);
337        assert_eq!(new_hash_5, new_path_4[0]);
338    }
339
340    #[test]
341    fn depth_3_is_correct() {
342        let a = int_to_node(1);
343        let b = int_to_node(2);
344        let c = int_to_node(3);
345        let d = int_to_node(4);
346        let e = int_to_node(5);
347        let f = int_to_node(6);
348        let g = int_to_node(7);
349        let h = int_to_node(8);
350
351        let i = Rpo256::merge(&[a.into(), b.into()]);
352        let j = Rpo256::merge(&[c.into(), d.into()]);
353        let k = Rpo256::merge(&[e.into(), f.into()]);
354        let l = Rpo256::merge(&[g.into(), h.into()]);
355
356        let m = Rpo256::merge(&[i.into(), j.into()]);
357        let n = Rpo256::merge(&[k.into(), l.into()]);
358
359        let root = Rpo256::merge(&[m.into(), n.into()]);
360
361        let mut set = MerklePathSet::new(3);
362
363        let value = b;
364        let index = 1;
365        let path = MerklePath::new([a.into(), j.into(), n.into()].to_vec());
366        set.add_path(index, value, path.clone()).unwrap();
367        assert_eq!(value, set.get_leaf(index).unwrap());
368        assert_eq!(Word::from(root), set.root());
369
370        let value = e;
371        let index = 4;
372        let path = MerklePath::new([f.into(), l.into(), m.into()].to_vec());
373        set.add_path(index, value, path.clone()).unwrap();
374        assert_eq!(value, set.get_leaf(index).unwrap());
375        assert_eq!(Word::from(root), set.root());
376
377        let value = a;
378        let index = 0;
379        let path = MerklePath::new([b.into(), j.into(), n.into()].to_vec());
380        set.add_path(index, value, path.clone()).unwrap();
381        assert_eq!(value, set.get_leaf(index).unwrap());
382        assert_eq!(Word::from(root), set.root());
383
384        let value = h;
385        let index = 7;
386        let path = MerklePath::new([g.into(), k.into(), m.into()].to_vec());
387        set.add_path(index, value, path.clone()).unwrap();
388        assert_eq!(value, set.get_leaf(index).unwrap());
389        assert_eq!(Word::from(root), set.root());
390    }
391
392    // HELPER FUNCTIONS
393    // --------------------------------------------------------------------------------------------
394
395    const fn is_even(pos: u64) -> bool {
396        pos & 1 == 0
397    }
398
399    /// Calculates the hash of the parent node by two sibling ones
400    /// - node — current node
401    /// - node_pos — position of the current node
402    /// - sibling — neighboring vertex in the tree
403    fn calculate_parent_hash(node: Word, node_pos: u64, sibling: Word) -> Word {
404        if is_even(node_pos) {
405            Rpo256::merge(&[node.into(), sibling.into()]).into()
406        } else {
407            Rpo256::merge(&[sibling.into(), node.into()]).into()
408        }
409    }
410}