arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
Merge pull request #99 from 0xPolygonMiden/vlopes11-merkle-store-containers

feat: add merkle path containers and return them on tree update
Victor Lopes victor@codx.io
Tue, 21 Mar 2023 20:54:36 +0100
commit

7305a72295367c4fbc0a02b0c6a82b8c0702f4e4

parent

a6819529828f9afe63ea34fee43621adbb785192

4 files changed, 80 insertions(+), 45 deletions(-)

jump to
M src/merkle/mod.rs → src/merkle/mod.rs

@@ -18,7 +18,7 @@ mod merkle_tree;

pub use merkle_tree::MerkleTree; mod path; -pub use path::MerklePath; +pub use path::{MerklePath, RootPath, ValuePath}; mod path_set; pub use path_set::MerklePathSet;
M src/merkle/path.rs → src/merkle/path.rs

@@ -82,3 +82,27 @@ fn into_iter(self) -> Self::IntoIter {

self.nodes.into_iter() } } + +// MERKLE PATH CONTAINERS +// ================================================================================================ + +/// A container for a [Word] value and its [MerklePath] opening. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct ValuePath { + /// The node value opening for `path`. + pub value: Word, + /// The path from `value` to `root` (exclusive). + pub path: MerklePath, +} + +/// A container for a [MerklePath] and its [Word] root. +/// +/// This structure does not provide any guarantees regarding the correctness of the path to the +/// root. For more information, check [MerklePath::verify]. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct RootPath { + /// The node value opening for `path`. + pub root: Word, + /// The path from `value` to `root` (exclusive). + pub path: MerklePath, +}
M src/merkle/store/mod.rs → src/merkle/store/mod.rs

@@ -5,7 +5,7 @@ //! (leaves or internal) to live as long as necessary and without duplication, this allows the

//! implementation of efficient persistent data structures use super::{ BTreeMap, BTreeSet, EmptySubtreeRoots, MerkleError, MerklePath, MerklePathSet, MerkleTree, - NodeIndex, Rpo256, RpoDigest, SimpleSmt, Vec, Word, + NodeIndex, RootPath, Rpo256, RpoDigest, SimpleSmt, ValuePath, Vec, Word, }; #[cfg(test)]

@@ -122,11 +122,7 @@ ///

/// This method can return the following errors: /// - `RootNotInStore` if the `root` is not present in the store. /// - `NodeNotInStore` if a node needed to traverse from `root` to `index` is not present in the store. - pub fn get_path( - &self, - root: Word, - index: NodeIndex, - ) -> Result<(Word, MerklePath), MerkleError> { + pub fn get_path(&self, root: Word, index: NodeIndex) -> Result<ValuePath, MerkleError> { let mut hash: RpoDigest = root.into(); let mut path = Vec::with_capacity(index.depth().into());

@@ -150,8 +146,13 @@ node.left

} } + // the path is computed from root to leaf, so it must be reversed path.reverse(); - Ok((hash.into(), MerklePath::new(path))) + + Ok(ValuePath { + value: hash.into(), + path: MerklePath::new(path), + }) } // STATE MUTATORS

@@ -233,17 +234,17 @@

Ok(smt.root()) } - /// Adds all the nodes of a Merkle path represented by `path`. + /// Adds all the nodes of a Merkle path represented by `path`, opening to `node`. Returns the + /// new root. /// /// This will compute the sibling elements determined by the Merkle `path` and `node`, and /// include all the nodes into the store. pub fn add_merkle_path( &mut self, index_value: u64, - node: Word, + mut node: Word, path: MerklePath, ) -> Result<Word, MerkleError> { - let mut node = node; let mut index = NodeIndex::new(self.nodes.len() as u8, index_value); for sibling in path {

@@ -272,6 +273,8 @@ ///

/// This will compute the sibling elements for each Merkle `path` and include all the nodes /// into the store. /// + /// For further reference, check [MerkleStore::add_merkle_path]. + /// /// # Errors /// /// Every path must resolve to the same root, otherwise this will return an `ConflictingRoots`

@@ -301,6 +304,8 @@ Ok(roots.iter().next().unwrap().into())

} /// Appends the provided [MerklePathSet] into the store. + /// + /// For further reference, check [MerkleStore::add_merkle_path]. pub fn add_merkle_path_set(&mut self, path_set: &MerklePathSet) -> Result<Word, MerkleError> { let root = path_set.root(); path_set.indexes().try_fold(root, |_, index| {

@@ -319,16 +324,19 @@ /// - `RootNotInStore` if the `root` is not present in the store.

/// - `NodeNotInStore` if a node needed to traverse from `root` to `index` is not present in the store. pub fn set_node( &mut self, - root: Word, + mut root: Word, index: NodeIndex, value: Word, - ) -> Result<Word, MerkleError> { - let result = self.get_path(root, index)?; - if result.0 != value { - self.add_merkle_path(index.value(), value, result.1) - } else { - Ok(root) + ) -> Result<RootPath, MerkleError> { + let node = value; + let ValuePath { value, path } = self.get_path(root, index)?; + + // performs the update only if the node value differs from the opening + if node != value { + root = self.add_merkle_path(index.value(), node, path.clone())?; } + + Ok(RootPath { root, path }) } pub fn merge_roots(&mut self, root1: Word, root2: Word) -> Result<Word, MerkleError> {
M src/merkle/store/tests.rs → src/merkle/store/tests.rs

@@ -90,12 +90,12 @@ let result = store

.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 0)) .unwrap(); assert_eq!( - LEAVES4[0], result.0, + LEAVES4[0], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( mtree.get_path(NodeIndex::new(mtree.depth(), 0)), - Ok(result.1), + Ok(result.path), "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" );

@@ -103,12 +103,12 @@ let result = store

.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 1)) .unwrap(); assert_eq!( - LEAVES4[1], result.0, + LEAVES4[1], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( mtree.get_path(NodeIndex::new(mtree.depth(), 1)), - Ok(result.1), + Ok(result.path), "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" );

@@ -116,12 +116,12 @@ let result = store

.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 2)) .unwrap(); assert_eq!( - LEAVES4[2], result.0, + LEAVES4[2], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( mtree.get_path(NodeIndex::new(mtree.depth(), 2)), - Ok(result.1), + Ok(result.path), "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" );

@@ -129,12 +129,12 @@ let result = store

.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 3)) .unwrap(); assert_eq!( - LEAVES4[3], result.0, + LEAVES4[3], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( mtree.get_path(NodeIndex::new(mtree.depth(), 3)), - Ok(result.1), + Ok(result.path), "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" );

@@ -241,12 +241,12 @@ let result = store

.get_path(smt.root(), NodeIndex::new(smt.depth(), 0)) .unwrap(); assert_eq!( - LEAVES4[0], result.0, + LEAVES4[0], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( smt.get_path(NodeIndex::new(smt.depth(), 0)), - Ok(result.1), + Ok(result.path), "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" );

@@ -254,12 +254,12 @@ let result = store

.get_path(smt.root(), NodeIndex::new(smt.depth(), 1)) .unwrap(); assert_eq!( - LEAVES4[1], result.0, + LEAVES4[1], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( smt.get_path(NodeIndex::new(smt.depth(), 1)), - Ok(result.1), + Ok(result.path), "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" );

@@ -267,12 +267,12 @@ let result = store

.get_path(smt.root(), NodeIndex::new(smt.depth(), 2)) .unwrap(); assert_eq!( - LEAVES4[2], result.0, + LEAVES4[2], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( smt.get_path(NodeIndex::new(smt.depth(), 2)), - Ok(result.1), + Ok(result.path), "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" );

@@ -280,12 +280,12 @@ let result = store

.get_path(smt.root(), NodeIndex::new(smt.depth(), 3)) .unwrap(); assert_eq!( - LEAVES4[3], result.0, + LEAVES4[3], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( smt.get_path(NodeIndex::new(smt.depth(), 3)), - Ok(result.1), + Ok(result.path), "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" );

@@ -375,12 +375,12 @@ let result = store

.get_path(set.root(), NodeIndex::new(set.depth() - 1, 0)) .unwrap(); assert_eq!( - LEAVES4[0], result.0, + LEAVES4[0], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( set.get_path(NodeIndex::new(set.depth(), 0)), - Ok(result.1), + Ok(result.path), "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" );

@@ -388,12 +388,12 @@ let result = store

.get_path(set.root(), NodeIndex::new(set.depth() - 1, 1)) .unwrap(); assert_eq!( - LEAVES4[1], result.0, + LEAVES4[1], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( set.get_path(NodeIndex::new(set.depth(), 1)), - Ok(result.1), + Ok(result.path), "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" );

@@ -401,12 +401,12 @@ let result = store

.get_path(set.root(), NodeIndex::new(set.depth() - 1, 2)) .unwrap(); assert_eq!( - LEAVES4[2], result.0, + LEAVES4[2], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( set.get_path(NodeIndex::new(set.depth(), 2)), - Ok(result.1), + Ok(result.path), "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" );

@@ -414,12 +414,12 @@ let result = store

.get_path(set.root(), NodeIndex::new(set.depth() - 1, 3)) .unwrap(); assert_eq!( - LEAVES4[3], result.0, + LEAVES4[3], result.value, "Value for merkle path at index 0 must match leaf value" ); assert_eq!( set.get_path(NodeIndex::new(set.depth(), 3)), - Ok(result.1), + Ok(result.path), "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" );

@@ -474,10 +474,13 @@

let store = MerkleStore::default() .with_merkle_tree([a, b, c, d, e, f, g, h]) .unwrap(); - let path = store.get_path(root.into(), NodeIndex::new(3, 1)).unwrap(); + let path = store + .get_path(root.into(), NodeIndex::new(3, 1)) + .unwrap() + .path; let expected = MerklePath::new([a.into(), j.into(), n.into()].to_vec()); - assert_eq!(path.1, expected); + assert_eq!(path, expected); } #[test]

@@ -486,7 +489,7 @@ let mtree = MerkleTree::new(LEAVES4.to_vec())?;

let mut store = MerkleStore::default().with_merkle_tree(LEAVES4)?; let value = int_to_node(42); let index = NodeIndex::new(mtree.depth(), 0); - let new_root = store.set_node(mtree.root(), index, value)?; + let new_root = store.set_node(mtree.root(), index, value)?.root; assert_eq!( store.get_node(new_root, index), Ok(value),