From 674e8c8368b0aad8b6b5da5ee3789472cc9b6a3c Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 07:55:47 -0500 Subject: [PATCH 001/121] smt: scaffolding --- src/merkle/mod.rs | 3 ++ src/merkle/smt.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/merkle/smt.rs diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 9c6c3c77..07c9703f 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -27,6 +27,9 @@ pub use path::{MerklePath, RootPath, ValuePath}; mod simple_smt; pub use simple_smt::SimpleSmt; +mod smt; +pub use smt::{InnerNode, LeafIndex, SparseMerkleTree}; + mod tiered_smt; pub use tiered_smt::{TieredSmt, TieredSmtProof, TieredSmtProofError}; diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs new file mode 100644 index 00000000..8bfff791 --- /dev/null +++ b/src/merkle/smt.rs @@ -0,0 +1,79 @@ +use crate::hash::rpo::{Rpo256, RpoDigest}; + +use super::{MerklePath, NodeIndex}; + +pub type LeafIndex = u64; + +/// An abstract description of a sparse Merkle tree. +/// +/// A sparse Merkle tree is a key-value map which also supports proving that a given value is indeed +/// stored at a given key in the tree. It is viewed as always being fully populated. If a leaf's +/// value was not explicitly updated, then its value is the default value. Typically, the vast +/// majority of leaves will store the default value (hence it is "sparse"), and therefore the +/// internal representation of the tree will only keep track of the leaves that have a different +/// value from the default. +/// +/// All leaves sit at the same depth. The deeper the tree, the more leaves it has; but also the +/// longer its proofs are - of exactly `log(depth)` size. +/// +/// Every key value maps to one leaf. If there are as many keys as there are leaves, then +/// [Self::Leaf] should be the same type as [Self::Value], as is the case with +/// [crate::merkle::SimpleSmt]. However, if there are more keys than leaves, then [`Self::Leaf`] +/// must accomodate all keys that map to the same leaf. +pub trait SparseMerkleTree { + /// The type for a key, which must be convertible into a `u64` infaillibly + type Key: Into; + /// The type for a value + type Value: Default; + /// The type for a leaf + type Leaf; + + // PROVIDED METHODS + // --------------------------------------------------------------------------------------------- + + /// Returns a Merkle path from the leaf node specified by the key to the root. + /// + /// The node itself is not included in the path. + fn get_merkle_path(&self, key: &Self::Key) -> MerklePath { + todo!() + } + + /// Updates value of the leaf at the specified index returning the old leaf value. + /// + /// This also recomputes all hashes between the leaf and the root, updating the root itself. + fn update_leaf_at(&mut self, key: &Self::Key, value: Self::Value) -> Self::Value { + todo!() + } + + // ABSTRACT METHODS + // --------------------------------------------------------------------------------------------- + + /// The root of the tree + fn root(&self) -> RpoDigest; + + /// The depth of the tree + fn depth(&self) -> u8; + + /// Retrieves an inner node at the given index + fn get_inner_node(&self, index: NodeIndex) -> InnerNode; + + /// Inserts a leaf node, and returns the value at the key if already exists + fn insert_leaf_node(&self, key: Self::Key, value: Self::Value) -> Option; + + /// Returns the hash of a leaf + fn hash_leaf(v: Self::Leaf) -> RpoDigest; +} + +// TODO: Reconcile somehow with `simple_smt::BranchNode` +#[derive(Debug, Default, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct InnerNode { + left: RpoDigest, + right: RpoDigest, +} + +impl InnerNode { + pub fn hash(&self) -> RpoDigest { + Rpo256::merge(&[self.left, self.right]) + } +} From a50b1cda3759360fe3a288ca128b78b9fa2be310 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 09:54:51 -0500 Subject: [PATCH 002/121] implement `update_leaf_at` --- src/merkle/smt.rs | 57 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 8bfff791..9122abb5 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -1,6 +1,6 @@ use crate::hash::rpo::{Rpo256, RpoDigest}; -use super::{MerklePath, NodeIndex}; +use super::{MerkleError, MerklePath, NodeIndex}; pub type LeafIndex = u64; @@ -22,9 +22,9 @@ pub type LeafIndex = u64; /// must accomodate all keys that map to the same leaf. pub trait SparseMerkleTree { /// The type for a key, which must be convertible into a `u64` infaillibly - type Key: Into; + type Key: Into + Clone; /// The type for a value - type Value: Default; + type Value: Clone + Default + PartialEq; /// The type for a leaf type Leaf; @@ -34,15 +34,29 @@ pub trait SparseMerkleTree { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - fn get_merkle_path(&self, key: &Self::Key) -> MerklePath { + fn get_merkle_path(&self, key: Self::Key) -> MerklePath { todo!() } /// Updates value of the leaf at the specified index returning the old leaf value. /// /// This also recomputes all hashes between the leaf and the root, updating the root itself. - fn update_leaf_at(&mut self, key: &Self::Key, value: Self::Value) -> Self::Value { - todo!() + fn update_leaf_at( + &mut self, + key: Self::Key, + value: Self::Value, + ) -> Result { + let old_value = self.insert_leaf_node(key.clone(), value.clone()).unwrap_or_default(); + + // if the old value and new value are the same, there is nothing to update + if value == old_value { + return Ok(value); + } + + let idx = NodeIndex::new(self.depth(), key.into())?; + recompute_nodes_from_index_to_root(self, idx, Self::hash_value(value)); + + Ok(old_value) } // ABSTRACT METHODS @@ -51,17 +65,46 @@ pub trait SparseMerkleTree { /// The root of the tree fn root(&self) -> RpoDigest; + /// Sets the root of the tree + fn set_root(&mut self, root: RpoDigest); + /// The depth of the tree fn depth(&self) -> u8; /// Retrieves an inner node at the given index fn get_inner_node(&self, index: NodeIndex) -> InnerNode; + /// Inserts an inner node at the given index + fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode); + /// Inserts a leaf node, and returns the value at the key if already exists fn insert_leaf_node(&self, key: Self::Key, value: Self::Value) -> Option; /// Returns the hash of a leaf - fn hash_leaf(v: Self::Leaf) -> RpoDigest; + fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest; + + /// Returns the hash of a value + /// FIXME: I found no good interface to mean "is hashable into a RpoDigest" that I could apply to `Self::Value` + fn hash_value(value: Self::Value) -> RpoDigest; +} + +fn recompute_nodes_from_index_to_root( + smt: &mut T, + mut index: NodeIndex, + node_hash_at_index: RpoDigest, +) where + T: SparseMerkleTree + ?Sized, +{ + let mut value = node_hash_at_index; + for _ in 0..index.depth() { + let is_right = index.is_value_odd(); + index.move_up(); + let InnerNode { left, right } = smt.get_inner_node(index); + let (left, right) = if is_right { (left, value) } else { (value, right) }; + smt.insert_inner_node(index, InnerNode { left, right }); + value = Rpo256::merge(&[left, right]); + } + smt.set_root(value); } // TODO: Reconcile somehow with `simple_smt::BranchNode` From f26d4c4fa752365257380d4416077629395408da Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 09:58:52 -0500 Subject: [PATCH 003/121] docstring --- src/merkle/smt.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 9122abb5..aee9a637 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -20,6 +20,8 @@ pub type LeafIndex = u64; /// [Self::Leaf] should be the same type as [Self::Value], as is the case with /// [crate::merkle::SimpleSmt]. However, if there are more keys than leaves, then [`Self::Leaf`] /// must accomodate all keys that map to the same leaf. +/// +/// [SparseMerkleTree] currently doesn't support optimizations that compress Merkle proofs. pub trait SparseMerkleTree { /// The type for a key, which must be convertible into a `u64` infaillibly type Key: Into + Clone; From 5cfd5667ac981aa38330789374014dffac5f6c26 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 10:05:48 -0500 Subject: [PATCH 004/121] move `recompute_nodes_from_index_to_root` into trait --- src/merkle/smt.rs | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index aee9a637..ffeb05e5 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -20,7 +20,7 @@ pub type LeafIndex = u64; /// [Self::Leaf] should be the same type as [Self::Value], as is the case with /// [crate::merkle::SimpleSmt]. However, if there are more keys than leaves, then [`Self::Leaf`] /// must accomodate all keys that map to the same leaf. -/// +/// /// [SparseMerkleTree] currently doesn't support optimizations that compress Merkle proofs. pub trait SparseMerkleTree { /// The type for a key, which must be convertible into a `u64` infaillibly @@ -56,11 +56,30 @@ pub trait SparseMerkleTree { } let idx = NodeIndex::new(self.depth(), key.into())?; - recompute_nodes_from_index_to_root(self, idx, Self::hash_value(value)); + self.recompute_nodes_from_index_to_root(idx, Self::hash_value(value)); Ok(old_value) } + /// Recomputes the branch nodes (including the root) from `index` all the way to the root. + /// `node_hash_at_index` is the hash of the node stored at index. + fn recompute_nodes_from_index_to_root( + &mut self, + mut index: NodeIndex, + node_hash_at_index: RpoDigest, + ) { + let mut value = node_hash_at_index; + for _ in 0..index.depth() { + let is_right = index.is_value_odd(); + index.move_up(); + let InnerNode { left, right } = self.get_inner_node(index); + let (left, right) = if is_right { (left, value) } else { (value, right) }; + self.insert_inner_node(index, InnerNode { left, right }); + value = Rpo256::merge(&[left, right]); + } + self.set_root(value); + } + // ABSTRACT METHODS // --------------------------------------------------------------------------------------------- @@ -90,26 +109,6 @@ pub trait SparseMerkleTree { fn hash_value(value: Self::Value) -> RpoDigest; } -fn recompute_nodes_from_index_to_root( - smt: &mut T, - mut index: NodeIndex, - node_hash_at_index: RpoDigest, -) where - T: SparseMerkleTree + ?Sized, -{ - let mut value = node_hash_at_index; - for _ in 0..index.depth() { - let is_right = index.is_value_odd(); - index.move_up(); - let InnerNode { left, right } = smt.get_inner_node(index); - let (left, right) = if is_right { (left, value) } else { (value, right) }; - smt.insert_inner_node(index, InnerNode { left, right }); - value = Rpo256::merge(&[left, right]); - } - smt.set_root(value); -} - -// TODO: Reconcile somehow with `simple_smt::BranchNode` #[derive(Debug, Default, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct InnerNode { From 49c7a8d0bb6586cc2b439d49ab6d4c96cb56b2f2 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 10:29:03 -0500 Subject: [PATCH 005/121] implement `get_merkle_path` --- src/merkle/smt.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index ffeb05e5..4caf8d02 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -36,8 +36,27 @@ pub trait SparseMerkleTree { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - fn get_merkle_path(&self, key: Self::Key) -> MerklePath { - todo!() + /// + /// # Errors + /// Returns an error if the specified index is too large given the depth of this Merkle tree. + fn get_merkle_path(&self, key: Self::Key) -> Result { + let mut index = NodeIndex::new(self.depth(), key.into())?; + + if index.is_root() { + return Err(MerkleError::DepthTooSmall(index.depth())); + } else if index.depth() > self.depth() { + return Err(MerkleError::DepthTooBig(index.depth() as u64)); + } + + let mut path = Vec::with_capacity(index.depth() as usize); + for _ in 0..index.depth() { + let is_right = index.is_value_odd(); + index.move_up(); + let InnerNode { left, right } = self.get_inner_node(index); + let value = if is_right { left } else { right }; + path.push(value); + } + Ok(MerklePath::new(path)) } /// Updates value of the leaf at the specified index returning the old leaf value. From 72e5b6d6a366cad929eef05e6c234655ab757e2e Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 10:48:34 -0500 Subject: [PATCH 006/121] introduce `DEPTH` const generic to remove runtime errors --- src/merkle/smt.rs | 64 +++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 4caf8d02..83eec923 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -2,8 +2,6 @@ use crate::hash::rpo::{Rpo256, RpoDigest}; use super::{MerkleError, MerklePath, NodeIndex}; -pub type LeafIndex = u64; - /// An abstract description of a sparse Merkle tree. /// /// A sparse Merkle tree is a key-value map which also supports proving that a given value is indeed @@ -22,9 +20,9 @@ pub type LeafIndex = u64; /// must accomodate all keys that map to the same leaf. /// /// [SparseMerkleTree] currently doesn't support optimizations that compress Merkle proofs. -pub trait SparseMerkleTree { +pub trait SparseMerkleTree { /// The type for a key, which must be convertible into a `u64` infaillibly - type Key: Into + Clone; + type Key: Into> + Clone; /// The type for a value type Value: Clone + Default + PartialEq; /// The type for a leaf @@ -39,14 +37,11 @@ pub trait SparseMerkleTree { /// /// # Errors /// Returns an error if the specified index is too large given the depth of this Merkle tree. - fn get_merkle_path(&self, key: Self::Key) -> Result { - let mut index = NodeIndex::new(self.depth(), key.into())?; - - if index.is_root() { - return Err(MerkleError::DepthTooSmall(index.depth())); - } else if index.depth() > self.depth() { - return Err(MerkleError::DepthTooBig(index.depth() as u64)); - } + fn get_merkle_path(&self, key: Self::Key) -> MerklePath { + let mut index: NodeIndex = { + let leaf_index: LeafIndex = key.into(); + leaf_index.into() + }; let mut path = Vec::with_capacity(index.depth() as usize); for _ in 0..index.depth() { @@ -56,28 +51,29 @@ pub trait SparseMerkleTree { let value = if is_right { left } else { right }; path.push(value); } - Ok(MerklePath::new(path)) + + MerklePath::new(path) } /// Updates value of the leaf at the specified index returning the old leaf value. /// /// This also recomputes all hashes between the leaf and the root, updating the root itself. - fn update_leaf_at( - &mut self, - key: Self::Key, - value: Self::Value, - ) -> Result { + fn update_leaf_at(&mut self, key: Self::Key, value: Self::Value) -> Self::Value { let old_value = self.insert_leaf_node(key.clone(), value.clone()).unwrap_or_default(); // if the old value and new value are the same, there is nothing to update if value == old_value { - return Ok(value); + return value; } - let idx = NodeIndex::new(self.depth(), key.into())?; - self.recompute_nodes_from_index_to_root(idx, Self::hash_value(value)); + let node_index = { + let leaf_index: LeafIndex = key.into(); + leaf_index.into() + }; - Ok(old_value) + self.recompute_nodes_from_index_to_root(node_index, Self::hash_value(value)); + + old_value } /// Recomputes the branch nodes (including the root) from `index` all the way to the root. @@ -108,9 +104,6 @@ pub trait SparseMerkleTree { /// Sets the root of the tree fn set_root(&mut self, root: RpoDigest); - /// The depth of the tree - fn depth(&self) -> u8; - /// Retrieves an inner node at the given index fn get_inner_node(&self, index: NodeIndex) -> InnerNode; @@ -128,6 +121,27 @@ pub trait SparseMerkleTree { fn hash_value(value: Self::Value) -> RpoDigest; } +/// The index of a leaf, at a depth known at compile-time. +pub struct LeafIndex { + index: NodeIndex, +} + +impl LeafIndex { + pub fn new(value: u64) -> Result { + Ok(LeafIndex { index: NodeIndex::new(DEPTH, value)? }) + } + + pub fn value(&self) -> u64 { + self.index.value() + } +} + +impl From> for NodeIndex { + fn from(value: LeafIndex) -> Self { + value.index + } +} + #[derive(Debug, Default, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct InnerNode { From 2cf5d1e7b50bd91d9fd690c57703be920d1debf3 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 11:04:10 -0500 Subject: [PATCH 007/121] leaf index at depth 64 --- src/merkle/smt.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 83eec923..e685f005 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -1,4 +1,7 @@ -use crate::hash::rpo::{Rpo256, RpoDigest}; +use crate::{ + hash::rpo::{Rpo256, RpoDigest}, + Word, +}; use super::{MerkleError, MerklePath, NodeIndex}; @@ -136,12 +139,26 @@ impl LeafIndex { } } +impl LeafIndex<64> { + pub fn new_max_depth(value: u64) -> Self { + LeafIndex { + index: NodeIndex::new_unchecked(64, value), + } + } +} + impl From> for NodeIndex { fn from(value: LeafIndex) -> Self { value.index } } +impl From for LeafIndex<64> { + fn from(value: Word) -> Self { + Self::new_max_depth(value[0].inner()) + } +} + #[derive(Debug, Default, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct InnerNode { From 2f7263bdb1e453699d684835fc291fff59ac5a0e Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 11:08:38 -0500 Subject: [PATCH 008/121] add `depth()` method to smt --- src/merkle/smt.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index e685f005..83ab5680 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -98,6 +98,11 @@ pub trait SparseMerkleTree { self.set_root(value); } + /// Returns the depth of the sparse Merkle tree + fn depth(&self) -> u8 { + DEPTH + } + // ABSTRACT METHODS // --------------------------------------------------------------------------------------------- From c29d722b22e71416a18ff0b2868cb82ea85472db Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 11:23:54 -0500 Subject: [PATCH 009/121] file separators --- src/merkle/smt.rs | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 83ab5680..25457a4c 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -5,6 +5,9 @@ use crate::{ use super::{MerkleError, MerklePath, NodeIndex}; +// SPARSE MERKLE TREE +// ================================================================================================ + /// An abstract description of a sparse Merkle tree. /// /// A sparse Merkle tree is a key-value map which also supports proving that a given value is indeed @@ -129,6 +132,25 @@ pub trait SparseMerkleTree { fn hash_value(value: Self::Value) -> RpoDigest; } +// INNER NODE +// ================================================================================================ + +#[derive(Debug, Default, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct InnerNode { + left: RpoDigest, + right: RpoDigest, +} + +impl InnerNode { + pub fn hash(&self) -> RpoDigest { + Rpo256::merge(&[self.left, self.right]) + } +} + +// LEAF INDEX +// ================================================================================================ + /// The index of a leaf, at a depth known at compile-time. pub struct LeafIndex { index: NodeIndex, @@ -163,16 +185,3 @@ impl From for LeafIndex<64> { Self::new_max_depth(value[0].inner()) } } - -#[derive(Debug, Default, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct InnerNode { - left: RpoDigest, - right: RpoDigest, -} - -impl InnerNode { - pub fn hash(&self) -> RpoDigest { - Rpo256::merge(&[self.left, self.right]) - } -} From 266fac1817b02371091205a8e0e6d320457b9eed Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 11:31:41 -0500 Subject: [PATCH 010/121] remove hash_value --- src/merkle/smt.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 25457a4c..5b138355 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -72,12 +72,13 @@ pub trait SparseMerkleTree { return value; } + let leaf = self.get_leaf_at(&key); let node_index = { let leaf_index: LeafIndex = key.into(); leaf_index.into() }; - self.recompute_nodes_from_index_to_root(node_index, Self::hash_value(value)); + self.recompute_nodes_from_index_to_root(node_index, Self::hash_leaf(&leaf)); old_value } @@ -124,12 +125,11 @@ pub trait SparseMerkleTree { /// Inserts a leaf node, and returns the value at the key if already exists fn insert_leaf_node(&self, key: Self::Key, value: Self::Value) -> Option; + /// Returns the leaf at the specified index. + fn get_leaf_at(&self, key: &Self::Key) -> Self::Leaf; + /// Returns the hash of a leaf fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest; - - /// Returns the hash of a value - /// FIXME: I found no good interface to mean "is hashable into a RpoDigest" that I could apply to `Self::Value` - fn hash_value(value: Self::Value) -> RpoDigest; } // INNER NODE From 0cd9a0f69c10d9d866036db6c3c0fdb208556ef1 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 11:32:35 -0500 Subject: [PATCH 011/121] use Vec --- src/merkle/smt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 5b138355..f4df3633 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -3,7 +3,7 @@ use crate::{ Word, }; -use super::{MerkleError, MerklePath, NodeIndex}; +use super::{MerkleError, MerklePath, NodeIndex, Vec}; // SPARSE MERKLE TREE // ================================================================================================ From f0b3527f1a858f20a545808d73af047df3f69148 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 13:23:20 -0500 Subject: [PATCH 012/121] use `InnerNode` in `SimpleSmt` --- src/merkle/simple_smt/mod.rs | 36 ++++++++++------------------------ src/merkle/simple_smt/tests.rs | 2 +- src/merkle/smt.rs | 4 ++-- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 4ce94a41..2e9a05ac 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,6 +1,6 @@ use super::{ - BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, MerkleTreeDelta, - NodeIndex, Rpo256, RpoDigest, StoreNode, TryApplyDiff, Vec, Word, + BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, MerkleError, MerklePath, + MerkleTreeDelta, NodeIndex, Rpo256, RpoDigest, StoreNode, TryApplyDiff, Vec, Word, }; #[cfg(test)] @@ -18,7 +18,7 @@ pub struct SimpleSmt { depth: u8, root: RpoDigest, leaves: BTreeMap, - branches: BTreeMap, + branches: BTreeMap, } impl SimpleSmt { @@ -152,7 +152,7 @@ impl SimpleSmt { }; Ok(leaf) } else { - Ok(self.get_branch_node(&index).parent()) + Ok(self.get_branch_node(&index).hash()) } } @@ -183,7 +183,7 @@ impl SimpleSmt { for _ in 0..index.depth() { let is_right = index.is_value_odd(); index.move_up(); - let BranchNode { left, right } = self.get_branch_node(&index); + let InnerNode { left, right } = self.get_branch_node(&index); let value = if is_right { left } else { right }; path.push(value); } @@ -212,7 +212,7 @@ impl SimpleSmt { /// Returns an iterator over the inner nodes of this Merkle tree. pub fn inner_nodes(&self) -> impl Iterator + '_ { self.branches.values().map(|e| InnerNodeInfo { - value: e.parent(), + value: e.hash(), left: e.left, right: e.right, }) @@ -317,7 +317,7 @@ impl SimpleSmt { for _ in 0..index.depth() { let is_right = index.is_value_odd(); index.move_up(); - let BranchNode { left, right } = self.get_branch_node(&index); + let InnerNode { left, right } = self.get_branch_node(&index); let (left, right) = if is_right { (left, value) } else { (value, right) }; self.insert_branch_node(index, left, right); value = Rpo256::merge(&[left, right]); @@ -333,35 +333,19 @@ impl SimpleSmt { self.leaves.insert(key, node) } - fn get_branch_node(&self, index: &NodeIndex) -> BranchNode { + fn get_branch_node(&self, index: &NodeIndex) -> InnerNode { self.branches.get(index).cloned().unwrap_or_else(|| { let node = EmptySubtreeRoots::entry(self.depth, index.depth() + 1); - BranchNode { left: *node, right: *node } + InnerNode { left: *node, right: *node } }) } fn insert_branch_node(&mut self, index: NodeIndex, left: RpoDigest, right: RpoDigest) { - let branch = BranchNode { left, right }; + let branch = InnerNode { left, right }; self.branches.insert(index, branch); } } -// BRANCH NODE -// ================================================================================================ - -#[derive(Debug, Default, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -struct BranchNode { - left: RpoDigest, - right: RpoDigest, -} - -impl BranchNode { - fn parent(&self) -> RpoDigest { - Rpo256::merge(&[self.left, self.right]) - } -} - // TRY APPLY DIFF // ================================================================================================ impl TryApplyDiff for SimpleSmt { diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 7949646f..92f80b8a 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -396,7 +396,7 @@ fn test_simplesmt_set_subtree() { assert_eq!(tree.root(), k); assert_eq!(tree.get_leaf(4).unwrap(), c); - assert_eq!(tree.get_branch_node(&NodeIndex::new_unchecked(2, 2)).parent(), g); + assert_eq!(tree.get_branch_node(&NodeIndex::new_unchecked(2, 2)).hash(), g); } /// Ensures that an invalid input node index into `set_subtree()` incurs no mutation of the tree diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index f4df3633..8add4971 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -138,8 +138,8 @@ pub trait SparseMerkleTree { #[derive(Debug, Default, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct InnerNode { - left: RpoDigest, - right: RpoDigest, + pub left: RpoDigest, + pub right: RpoDigest, } impl InnerNode { From cf5ff366910bd685cbcb3d6e337de2f07d07b4ae Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 14:20:42 -0500 Subject: [PATCH 013/121] SimpleSmt: make DEPTH const generic --- Cargo.toml | 14 ++++-- benches/smt.rs | 82 ++++++++++++++++------------------ benches/store.rs | 38 ++++++++-------- src/merkle/delta.rs | 2 +- src/merkle/mod.rs | 2 +- src/merkle/simple_smt/mod.rs | 71 ++++++++++++++--------------- src/merkle/simple_smt/tests.rs | 70 +++++++++++++---------------- src/merkle/store/mod.rs | 4 +- src/merkle/store/tests.rs | 28 ++++++------ 9 files changed, 154 insertions(+), 157 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 008936f9..394c7111 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,19 +35,27 @@ harness = false default = ["std"] executable = ["dep:clap", "dep:rand_utils", "std"] serde = ["dep:serde", "serde?/alloc", "winter_math/serde"] -std = ["blake3/std", "dep:cc", "dep:libc", "winter_crypto/std", "winter_math/std", "winter_utils/std"] +std = [ + "blake3/std", + "dep:cc", + "dep:libc", + "winter_crypto/std", + "winter_math/std", + "winter_utils/std", +] [dependencies] blake3 = { version = "1.5", default-features = false } clap = { version = "4.4", features = ["derive"], optional = true } -libc = { version = "0.2", default-features = false, optional = true } +libc = { version = "0.2", default-features = false, optional = true } rand_utils = { version = "0.7", package = "winter-rand-utils", optional = true } -serde = { version = "1.0", features = [ "derive" ], default-features = false, optional = true } +serde = { version = "1.0", features = ["derive"], default-features = false, optional = true } winter_crypto = { version = "0.7", package = "winter-crypto", default-features = false } winter_math = { version = "0.7", package = "winter-math", default-features = false } winter_utils = { version = "0.7", package = "winter-utils", default-features = false } [dev-dependencies] +seq-macro = { version = "0.3" } criterion = { version = "0.5", features = ["html_reports"] } proptest = "1.4" rand_utils = { version = "0.7", package = "winter-rand-utils" } diff --git a/benches/smt.rs b/benches/smt.rs index 0f9c371a..601206b8 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -2,15 +2,16 @@ use core::mem::swap; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use miden_crypto::{merkle::SimpleSmt, Felt, Word}; use rand_utils::prng_array; +use seq_macro::seq; fn smt_rpo(c: &mut Criterion) { // setup trees let mut seed = [0u8; 32]; - let mut trees = vec![]; + let leaf = generate_word(&mut seed); - for depth in 14..=20 { - let leaves = ((1 << depth) - 1) as u64; + seq!(DEPTH in 14..=20 { + let leaves = ((1 << DEPTH) - 1) as u64; for count in [1, leaves / 2, leaves] { let entries: Vec<_> = (0..count) .map(|i| { @@ -18,50 +19,45 @@ fn smt_rpo(c: &mut Criterion) { (i, word) }) .collect(); - let tree = SimpleSmt::with_leaves(depth, entries).unwrap(); - trees.push((tree, count)); - } - } - - let leaf = generate_word(&mut seed); + let mut tree = SimpleSmt::::with_leaves(entries).unwrap(); - // benchmarks + // benchmark 1 + let mut insert = c.benchmark_group("smt update_leaf".to_string()); + { + let depth = tree.depth(); + let key = count >> 2; + insert.bench_with_input( + format!("simple smt(depth:{depth},count:{count})"), + &(key, leaf), + |b, (key, leaf)| { + b.iter(|| { + tree.update_leaf(black_box(*key), black_box(*leaf)).unwrap(); + }); + }, + ); - let mut insert = c.benchmark_group("smt update_leaf".to_string()); + } + insert.finish(); - for (tree, count) in trees.iter_mut() { - let depth = tree.depth(); - let key = *count >> 2; - insert.bench_with_input( - format!("simple smt(depth:{depth},count:{count})"), - &(key, leaf), - |b, (key, leaf)| { - b.iter(|| { - tree.update_leaf(black_box(*key), black_box(*leaf)).unwrap(); - }); - }, - ); - } + // benchmark 2 + let mut path = c.benchmark_group("smt get_leaf_path".to_string()); + { + let depth = tree.depth(); + let key = count >> 2; + path.bench_with_input( + format!("simple smt(depth:{depth},count:{count})"), + &key, + |b, key| { + b.iter(|| { + tree.get_leaf_path(black_box(*key)).unwrap(); + }); + }, + ); - insert.finish(); - - let mut path = c.benchmark_group("smt get_leaf_path".to_string()); - - for (tree, count) in trees.iter_mut() { - let depth = tree.depth(); - let key = *count >> 2; - path.bench_with_input( - format!("simple smt(depth:{depth},count:{count})"), - &key, - |b, key| { - b.iter(|| { - tree.get_leaf_path(black_box(*key)).unwrap(); - }); - }, - ); - } - - path.finish(); + } + path.finish(); + } + }); } criterion_group!(smt_group, smt_rpo); diff --git a/benches/store.rs b/benches/store.rs index 0abeb980..bc761b45 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -1,5 +1,7 @@ use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; -use miden_crypto::merkle::{DefaultMerkleStore as MerkleStore, MerkleTree, NodeIndex, SimpleSmt}; +use miden_crypto::merkle::{ + DefaultMerkleStore as MerkleStore, MerkleTree, NodeIndex, SimpleSmt, SIMPLE_SMT_MAX_DEPTH, +}; use miden_crypto::Word; use miden_crypto::{hash::rpo::RpoDigest, Felt}; use rand_utils::{rand_array, rand_value}; @@ -28,26 +30,26 @@ fn random_index(range: u64, depth: u8) -> NodeIndex { fn get_empty_leaf_simplesmt(c: &mut Criterion) { let mut group = c.benchmark_group("get_empty_leaf_simplesmt"); - let depth = SimpleSmt::MAX_DEPTH; + const DEPTH: u8 = SIMPLE_SMT_MAX_DEPTH; let size = u64::MAX; // both SMT and the store are pre-populated with empty hashes, accessing these values is what is // being benchmarked here, so no values are inserted into the backends - let smt = SimpleSmt::new(depth).unwrap(); + let smt = SimpleSmt::::new().unwrap(); let store = MerkleStore::from(&smt); let root = smt.root(); - group.bench_function(BenchmarkId::new("SimpleSmt", depth), |b| { + group.bench_function(BenchmarkId::new("SimpleSmt", DEPTH), |b| { b.iter_batched( - || random_index(size, depth), + || random_index(size, DEPTH), |index| black_box(smt.get_node(index)), BatchSize::SmallInput, ) }); - group.bench_function(BenchmarkId::new("MerkleStore", depth), |b| { + group.bench_function(BenchmarkId::new("MerkleStore", DEPTH), |b| { b.iter_batched( - || random_index(size, depth), + || random_index(size, DEPTH), |index| black_box(store.get_node(root, index)), BatchSize::SmallInput, ) @@ -104,7 +106,7 @@ fn get_leaf_simplesmt(c: &mut Criterion) { .enumerate() .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>(); - let smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, smt_leaves.clone()).unwrap(); + let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let store = MerkleStore::from(&smt); let depth = smt.depth(); let root = smt.root(); @@ -132,18 +134,18 @@ fn get_leaf_simplesmt(c: &mut Criterion) { fn get_node_of_empty_simplesmt(c: &mut Criterion) { let mut group = c.benchmark_group("get_node_of_empty_simplesmt"); - let depth = SimpleSmt::MAX_DEPTH; + const DEPTH: u8 = SIMPLE_SMT_MAX_DEPTH; // both SMT and the store are pre-populated with the empty hashes, accessing the internal nodes // of these values is what is being benchmarked here, so no values are inserted into the // backends. - let smt = SimpleSmt::new(depth).unwrap(); + let smt = SimpleSmt::::new().unwrap(); let store = MerkleStore::from(&smt); let root = smt.root(); - let half_depth = depth / 2; + let half_depth = DEPTH / 2; let half_size = 2_u64.pow(half_depth as u32); - group.bench_function(BenchmarkId::new("SimpleSmt", depth), |b| { + group.bench_function(BenchmarkId::new("SimpleSmt", DEPTH), |b| { b.iter_batched( || random_index(half_size, half_depth), |index| black_box(smt.get_node(index)), @@ -151,7 +153,7 @@ fn get_node_of_empty_simplesmt(c: &mut Criterion) { ) }); - group.bench_function(BenchmarkId::new("MerkleStore", depth), |b| { + group.bench_function(BenchmarkId::new("MerkleStore", DEPTH), |b| { b.iter_batched( || random_index(half_size, half_depth), |index| black_box(store.get_node(root, index)), @@ -212,7 +214,7 @@ fn get_node_simplesmt(c: &mut Criterion) { .enumerate() .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>(); - let smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, smt_leaves.clone()).unwrap(); + let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let store = MerkleStore::from(&smt); let root = smt.root(); let half_depth = smt.depth() / 2; @@ -286,7 +288,7 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { .enumerate() .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>(); - let smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, smt_leaves.clone()).unwrap(); + let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let store = MerkleStore::from(&smt); let depth = smt.depth(); let root = smt.root(); @@ -352,7 +354,7 @@ fn new(c: &mut Criterion) { .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>() }, - |l| black_box(SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, l)), + |l| black_box(SimpleSmt::::with_leaves(l)), BatchSize::SmallInput, ) }); @@ -367,7 +369,7 @@ fn new(c: &mut Criterion) { .collect::>() }, |l| { - let smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, l).unwrap(); + let smt = SimpleSmt::::with_leaves(l).unwrap(); black_box(MerkleStore::from(&smt)); }, BatchSize::SmallInput, @@ -433,7 +435,7 @@ fn update_leaf_simplesmt(c: &mut Criterion) { .enumerate() .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>(); - let mut smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, smt_leaves.clone()).unwrap(); + let mut smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let mut store = MerkleStore::from(&smt); let depth = smt.depth(); let root = smt.root(); diff --git a/src/merkle/delta.rs b/src/merkle/delta.rs index 064cd01b..4de94750 100644 --- a/src/merkle/delta.rs +++ b/src/merkle/delta.rs @@ -126,7 +126,7 @@ fn test_compute_merkle_delta() { (20, [Felt::new(8), Felt::new(9), Felt::new(10), Felt::new(11)]), (31, [Felt::new(12), Felt::new(13), Felt::new(14), Felt::new(15)]), ]; - let simple_smt = SimpleSmt::with_leaves(30, entries.clone()).unwrap(); + let simple_smt = SimpleSmt::<30>::with_leaves(entries.clone()).unwrap(); let mut store: MerkleStore = (&simple_smt).into(); let root = simple_smt.root(); diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 07c9703f..64a11d4b 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -25,7 +25,7 @@ mod path; pub use path::{MerklePath, RootPath, ValuePath}; mod simple_smt; -pub use simple_smt::SimpleSmt; +pub use simple_smt::{SimpleSmt, SIMPLE_SMT_MAX_DEPTH, SIMPLE_SMT_MIN_DEPTH}; mod smt; pub use smt::{InnerNode, LeafIndex, SparseMerkleTree}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 2e9a05ac..fcd4a878 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -6,6 +6,18 @@ use super::{ #[cfg(test)] mod tests; +// CONSTANTS +// ================================================================================================ + +/// Minimum supported depth. +pub const SIMPLE_SMT_MIN_DEPTH: u8 = 1; + +/// Maximum supported depth. +pub const SIMPLE_SMT_MAX_DEPTH: u8 = 64; + +/// Value of an empty leaf. +pub const EMPTY_VALUE: Word = super::EMPTY_WORD; + // SPARSE MERKLE TREE // ================================================================================================ @@ -14,26 +26,13 @@ mod tests; /// The root of the tree is recomputed on each new leaf update. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct SimpleSmt { - depth: u8, +pub struct SimpleSmt { root: RpoDigest, leaves: BTreeMap, branches: BTreeMap, } -impl SimpleSmt { - // CONSTANTS - // -------------------------------------------------------------------------------------------- - - /// Minimum supported depth. - pub const MIN_DEPTH: u8 = 1; - - /// Maximum supported depth. - pub const MAX_DEPTH: u8 = 64; - - /// Value of an empty leaf. - pub const EMPTY_VALUE: Word = super::EMPTY_WORD; - +impl SimpleSmt { // CONSTRUCTORS // -------------------------------------------------------------------------------------------- @@ -43,19 +42,18 @@ impl SimpleSmt { /// /// # Errors /// Returns an error if the depth is 0 or is greater than 64. - pub fn new(depth: u8) -> Result { + pub fn new() -> Result { // validate the range of the depth. - if depth < Self::MIN_DEPTH { - return Err(MerkleError::DepthTooSmall(depth)); - } else if Self::MAX_DEPTH < depth { - return Err(MerkleError::DepthTooBig(depth as u64)); + if DEPTH < SIMPLE_SMT_MIN_DEPTH { + return Err(MerkleError::DepthTooSmall(DEPTH)); + } else if SIMPLE_SMT_MAX_DEPTH < DEPTH { + return Err(MerkleError::DepthTooBig(DEPTH as u64)); } - let root = *EmptySubtreeRoots::entry(depth, 0); + let root = *EmptySubtreeRoots::entry(DEPTH, 0); Ok(Self { root, - depth, leaves: BTreeMap::new(), branches: BTreeMap::new(), }) @@ -72,15 +70,14 @@ impl SimpleSmt { /// - The number of entries exceeds the maximum tree capacity, that is 2^{depth}. /// - The provided entries contain multiple values for the same key. pub fn with_leaves( - depth: u8, entries: impl IntoIterator, ) -> Result { // create an empty tree - let mut tree = Self::new(depth)?; + let mut tree = Self::new()?; // compute the max number of entries. We use an upper bound of depth 63 because we consider // passing in a vector of size 2^64 infeasible. - let max_num_entries = 2_usize.pow(tree.depth.min(63).into()); + let max_num_entries = 2_usize.pow(tree.depth().min(63).into()); // This being a sparse data structure, the EMPTY_WORD is not assigned to the `BTreeMap`, so // entries with the empty value need additional tracking. @@ -93,11 +90,11 @@ impl SimpleSmt { let old_value = tree.update_leaf(key, value)?; - if old_value != Self::EMPTY_VALUE || key_set_to_zero.contains(&key) { + if old_value != EMPTY_VALUE || key_set_to_zero.contains(&key) { return Err(MerkleError::DuplicateValuesForIndex(key)); } - if value == Self::EMPTY_VALUE { + if value == EMPTY_VALUE { key_set_to_zero.insert(key); }; } @@ -107,11 +104,9 @@ impl SimpleSmt { /// Wrapper around [`SimpleSmt::with_leaves`] which inserts leaves at contiguous indices /// starting at index 0. pub fn with_contiguous_leaves( - depth: u8, entries: impl IntoIterator, ) -> Result { Self::with_leaves( - depth, entries .into_iter() .enumerate() @@ -129,7 +124,7 @@ impl SimpleSmt { /// Returns the depth of this Merkle tree. pub const fn depth(&self) -> u8 { - self.depth + DEPTH } /// Returns a node at the specified index. @@ -148,7 +143,7 @@ impl SimpleSmt { let leaf_pos = index.value(); let leaf = match self.get_leaf_node(leaf_pos) { Some(word) => word.into(), - None => *EmptySubtreeRoots::entry(self.depth, index.depth()), + None => *EmptySubtreeRoots::entry(self.depth(), index.depth()), }; Ok(leaf) } else { @@ -161,7 +156,7 @@ impl SimpleSmt { /// # Errors /// Returns an error if the index is greater than the maximum tree capacity, that is 2^{depth}. pub fn get_leaf(&self, index: u64) -> Result { - let index = NodeIndex::new(self.depth, index)?; + let index = NodeIndex::new(self.depth(), index)?; Ok(self.get_node(index)?.into()) } @@ -231,7 +226,7 @@ impl SimpleSmt { // validate the index before modifying the structure let idx = NodeIndex::new(self.depth(), index)?; - let old_value = self.insert_leaf_node(index, value).unwrap_or(Self::EMPTY_VALUE); + let old_value = self.insert_leaf_node(index, value).unwrap_or(EMPTY_VALUE); // if the old value and new value are the same, there is nothing to update if value == old_value { @@ -247,10 +242,10 @@ impl SimpleSmt { /// computed as `self.depth() - subtree.depth()`. /// /// Returns the new root. - pub fn set_subtree( + pub fn set_subtree( &mut self, subtree_insertion_index: u64, - subtree: SimpleSmt, + subtree: SimpleSmt, ) -> Result { if subtree.depth() > self.depth() { return Err(MerkleError::InvalidSubtreeDepth { @@ -335,7 +330,7 @@ impl SimpleSmt { fn get_branch_node(&self, index: &NodeIndex) -> InnerNode { self.branches.get(index).cloned().unwrap_or_else(|| { - let node = EmptySubtreeRoots::entry(self.depth, index.depth() + 1); + let node = EmptySubtreeRoots::entry(self.depth(), index.depth() + 1); InnerNode { left: *node, right: *node } }) } @@ -348,7 +343,7 @@ impl SimpleSmt { // TRY APPLY DIFF // ================================================================================================ -impl TryApplyDiff for SimpleSmt { +impl TryApplyDiff for SimpleSmt { type Error = MerkleError; type DiffType = MerkleTreeDelta; @@ -361,7 +356,7 @@ impl TryApplyDiff for SimpleSmt { } for slot in diff.cleared_slots() { - self.update_leaf(*slot, Self::EMPTY_VALUE)?; + self.update_leaf(*slot, EMPTY_VALUE)?; } for (slot, value) in diff.updated_slots() { diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 92f80b8a..3a43cd44 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -34,14 +34,14 @@ const ZERO_VALUES8: [Word; 8] = [int_to_leaf(0); 8]; #[test] fn build_empty_tree() { // tree of depth 3 - let smt = SimpleSmt::new(3).unwrap(); + let smt = SimpleSmt::<3>::new().unwrap(); let mt = MerkleTree::new(ZERO_VALUES8).unwrap(); assert_eq!(mt.root(), smt.root()); } #[test] fn build_sparse_tree() { - let mut smt = SimpleSmt::new(3).unwrap(); + let mut smt = SimpleSmt::<3>::new().unwrap(); let mut values = ZERO_VALUES8.to_vec(); // insert single value @@ -75,11 +75,11 @@ fn build_sparse_tree() { #[test] fn build_contiguous_tree() { let tree_with_leaves = - SimpleSmt::with_leaves(2, [0, 1, 2, 3].into_iter().zip(digests_to_words(&VALUES4))) + SimpleSmt::<2>::with_leaves([0, 1, 2, 3].into_iter().zip(digests_to_words(&VALUES4))) .unwrap(); let tree_with_contiguous_leaves = - SimpleSmt::with_contiguous_leaves(2, digests_to_words(&VALUES4)).unwrap(); + SimpleSmt::<2>::with_contiguous_leaves(digests_to_words(&VALUES4)).unwrap(); assert_eq!(tree_with_leaves, tree_with_contiguous_leaves); } @@ -87,7 +87,7 @@ fn build_contiguous_tree() { #[test] fn test_depth2_tree() { let tree = - SimpleSmt::with_leaves(2, KEYS4.into_iter().zip(digests_to_words(&VALUES4))).unwrap(); + SimpleSmt::<2>::with_leaves(KEYS4.into_iter().zip(digests_to_words(&VALUES4))).unwrap(); // check internal structure let (root, node2, node3) = compute_internal_nodes(); @@ -115,7 +115,7 @@ fn test_depth2_tree() { #[test] fn test_inner_node_iterator() -> Result<(), MerkleError> { let tree = - SimpleSmt::with_leaves(2, KEYS4.into_iter().zip(digests_to_words(&VALUES4))).unwrap(); + SimpleSmt::<2>::with_leaves(KEYS4.into_iter().zip(digests_to_words(&VALUES4))).unwrap(); // check depth 2 assert_eq!(VALUES4[0], tree.get_node(NodeIndex::make(2, 0)).unwrap()); @@ -146,7 +146,7 @@ fn test_inner_node_iterator() -> Result<(), MerkleError> { #[test] fn update_leaf() { let mut tree = - SimpleSmt::with_leaves(3, KEYS8.into_iter().zip(digests_to_words(&VALUES8))).unwrap(); + SimpleSmt::<3>::with_leaves(KEYS8.into_iter().zip(digests_to_words(&VALUES8))).unwrap(); // update one value let key = 3; @@ -197,9 +197,8 @@ fn small_tree_opening_is_consistent() { let k = Rpo256::merge(&[i, j]); - let depth = 3; let entries = vec![(0, a), (1, b), (4, c), (7, d)]; - let tree = SimpleSmt::with_leaves(depth, entries).unwrap(); + let tree = SimpleSmt::<3>::with_leaves(entries).unwrap(); assert_eq!(tree.root(), k); @@ -241,12 +240,12 @@ fn test_simplesmt_fail_on_duplicates() { for (first, second) in values.iter() { // consecutive let entries = [(1, *first), (1, *second)]; - let smt = SimpleSmt::with_leaves(64, entries); + let smt = SimpleSmt::<64>::with_leaves(entries); assert_eq!(smt.unwrap_err(), MerkleError::DuplicateValuesForIndex(1)); // not consecutive let entries = [(1, *first), (5, int_to_leaf(5)), (1, *second)]; - let smt = SimpleSmt::with_leaves(64, entries); + let smt = SimpleSmt::<64>::with_leaves(entries); assert_eq!(smt.unwrap_err(), MerkleError::DuplicateValuesForIndex(1)); } } @@ -254,7 +253,7 @@ fn test_simplesmt_fail_on_duplicates() { #[test] fn with_no_duplicates_empty_node() { let entries = [(1_u64, int_to_leaf(0)), (5, int_to_leaf(2))]; - let smt = SimpleSmt::with_leaves(64, entries); + let smt = SimpleSmt::<64>::with_leaves(entries); assert!(smt.is_ok()); } @@ -264,19 +263,19 @@ fn test_simplesmt_update_nonexisting_leaf_with_zero() { // -------------------------------------------------------------------------------------------- // Depth 1 has 2 leaf. Position is 0-indexed, position 2 doesn't exist. - let mut smt = SimpleSmt::new(1).unwrap(); + let mut smt = SimpleSmt::<1>::new().unwrap(); let result = smt.update_leaf(2, EMPTY_WORD); assert!(!smt.leaves.contains_key(&2)); assert!(result.is_err()); // Depth 2 has 4 leaves. Position is 0-indexed, position 4 doesn't exist. - let mut smt = SimpleSmt::new(2).unwrap(); + let mut smt = SimpleSmt::<2>::new().unwrap(); let result = smt.update_leaf(4, EMPTY_WORD); assert!(!smt.leaves.contains_key(&4)); assert!(result.is_err()); // Depth 3 has 8 leaves. Position is 0-indexed, position 8 doesn't exist. - let mut smt = SimpleSmt::new(3).unwrap(); + let mut smt = SimpleSmt::<3>::new().unwrap(); let result = smt.update_leaf(8, EMPTY_WORD); assert!(!smt.leaves.contains_key(&8)); assert!(result.is_err()); @@ -286,19 +285,19 @@ fn test_simplesmt_update_nonexisting_leaf_with_zero() { let value = int_to_node(1); // Depth 1 has 2 leaves. Position is 0-indexed, position 1 doesn't exist. - let mut smt = SimpleSmt::new(1).unwrap(); + let mut smt = SimpleSmt::<1>::new().unwrap(); let result = smt.update_leaf(2, *value); assert!(!smt.leaves.contains_key(&2)); assert!(result.is_err()); // Depth 2 has 4 leaves. Position is 0-indexed, position 2 doesn't exist. - let mut smt = SimpleSmt::new(2).unwrap(); + let mut smt = SimpleSmt::<2>::new().unwrap(); let result = smt.update_leaf(4, *value); assert!(!smt.leaves.contains_key(&4)); assert!(result.is_err()); // Depth 3 has 8 leaves. Position is 0-indexed, position 4 doesn't exist. - let mut smt = SimpleSmt::new(3).unwrap(); + let mut smt = SimpleSmt::<3>::new().unwrap(); let result = smt.update_leaf(8, *value); assert!(!smt.leaves.contains_key(&8)); assert!(result.is_err()); @@ -311,17 +310,17 @@ fn test_simplesmt_with_leaves_nonexisting_leaf() { // Depth 1 has 2 leaf. Position is 0-indexed, position 2 doesn't exist. let leaves = [(2, EMPTY_WORD)]; - let result = SimpleSmt::with_leaves(1, leaves); + let result = SimpleSmt::<1>::with_leaves(leaves); assert!(result.is_err()); // Depth 2 has 4 leaves. Position is 0-indexed, position 4 doesn't exist. let leaves = [(4, EMPTY_WORD)]; - let result = SimpleSmt::with_leaves(2, leaves); + let result = SimpleSmt::<2>::with_leaves(leaves); assert!(result.is_err()); // Depth 3 has 8 leaves. Position is 0-indexed, position 8 doesn't exist. let leaves = [(8, EMPTY_WORD)]; - let result = SimpleSmt::with_leaves(3, leaves); + let result = SimpleSmt::<3>::with_leaves(leaves); assert!(result.is_err()); // TESTING WITH A VALUE @@ -330,17 +329,17 @@ fn test_simplesmt_with_leaves_nonexisting_leaf() { // Depth 1 has 2 leaves. Position is 0-indexed, position 2 doesn't exist. let leaves = [(2, *value)]; - let result = SimpleSmt::with_leaves(1, leaves); + let result = SimpleSmt::<1>::with_leaves(leaves); assert!(result.is_err()); // Depth 2 has 4 leaves. Position is 0-indexed, position 4 doesn't exist. let leaves = [(4, *value)]; - let result = SimpleSmt::with_leaves(2, leaves); + let result = SimpleSmt::<2>::with_leaves(leaves); assert!(result.is_err()); // Depth 3 has 8 leaves. Position is 0-indexed, position 8 doesn't exist. let leaves = [(8, *value)]; - let result = SimpleSmt::with_leaves(3, leaves); + let result = SimpleSmt::<3>::with_leaves(leaves); assert!(result.is_err()); } @@ -378,16 +377,14 @@ fn test_simplesmt_set_subtree() { // / \ // c 0 let subtree = { - let depth = 1; let entries = vec![(0, c)]; - SimpleSmt::with_leaves(depth, entries).unwrap() + SimpleSmt::<1>::with_leaves(entries).unwrap() }; // insert subtree let tree = { - let depth = 3; let entries = vec![(0, a), (1, b), (7, d)]; - let mut tree = SimpleSmt::with_leaves(depth, entries).unwrap(); + let mut tree = SimpleSmt::<3>::with_leaves(entries).unwrap(); tree.set_subtree(2, subtree).unwrap(); @@ -424,15 +421,13 @@ fn test_simplesmt_set_subtree_unchanged_for_wrong_index() { // / \ // c 0 let subtree = { - let depth = 1; let entries = vec![(0, c)]; - SimpleSmt::with_leaves(depth, entries).unwrap() + SimpleSmt::<1>::with_leaves(entries).unwrap() }; let mut tree = { - let depth = 3; let entries = vec![(0, a), (1, b), (7, d)]; - SimpleSmt::with_leaves(depth, entries).unwrap() + SimpleSmt::<3>::with_leaves(entries).unwrap() }; let tree_root_before_insertion = tree.root(); @@ -462,21 +457,20 @@ fn test_simplesmt_set_subtree_entire_tree() { let c = Word::from(Rpo256::merge(&[b.into(); 2])); let d = Word::from(Rpo256::merge(&[c.into(); 2])); - let depth = 3; - // subtree: E3 - let subtree = { SimpleSmt::with_leaves(depth, Vec::new()).unwrap() }; - assert_eq!(subtree.root(), *EmptySubtreeRoots::entry(depth, 0)); + const DEPTH: u8 = 3; + let subtree = { SimpleSmt::::with_leaves(Vec::new()).unwrap() }; + assert_eq!(subtree.root(), *EmptySubtreeRoots::entry(DEPTH, 0)); // insert subtree let mut tree = { let entries = vec![(0, a), (1, b), (4, c), (7, d)]; - SimpleSmt::with_leaves(depth, entries).unwrap() + SimpleSmt::<3>::with_leaves(entries).unwrap() }; tree.set_subtree(0, subtree).unwrap(); - assert_eq!(tree.root(), *EmptySubtreeRoots::entry(depth, 0)); + assert_eq!(tree.root(), *EmptySubtreeRoots::entry(DEPTH, 0)); } // HELPER FUNCTIONS diff --git a/src/merkle/store/mod.rs b/src/merkle/store/mod.rs index caba99e5..7e931904 100644 --- a/src/merkle/store/mod.rs +++ b/src/merkle/store/mod.rs @@ -490,8 +490,8 @@ impl> From<&MerkleTree> for MerkleStore { } } -impl> From<&SimpleSmt> for MerkleStore { - fn from(value: &SimpleSmt) -> Self { +impl, const DEPTH: u8> From<&SimpleSmt> for MerkleStore { + fn from(value: &SimpleSmt) -> Self { let nodes = combine_nodes_with_empty_hashes(value.inner_nodes()).collect(); Self { nodes } } diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index 004e020e..24c017c7 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -3,7 +3,9 @@ use super::{ PartialMerkleTree, RecordingMerkleStore, Rpo256, RpoDigest, }; use crate::{ - merkle::{digests_to_words, int_to_leaf, int_to_node, MerkleTree, SimpleSmt}, + merkle::{ + digests_to_words, int_to_leaf, int_to_node, MerkleTree, SimpleSmt, SIMPLE_SMT_MAX_DEPTH, + }, Felt, Word, ONE, WORD_SIZE, ZERO, }; @@ -13,6 +15,8 @@ use super::{Deserializable, Serializable}; #[cfg(feature = "std")] use std::error::Error; +use seq_macro::seq; + // TEST DATA // ================================================================================================ @@ -173,10 +177,10 @@ fn test_leaf_paths_for_empty_trees() -> Result<(), MerkleError> { // Starts at 1 because leafs are not included in the store. // Ends at 64 because it is not possible to represent an index of a depth greater than 64, // because a u64 is used to index the leaf. - for depth in 1..64 { - let smt = SimpleSmt::new(depth)?; + seq!(DEPTH in 1_u8..64_u8 { + let smt = SimpleSmt::::new()?; - let index = NodeIndex::make(depth, 0); + let index = NodeIndex::make(DEPTH, 0); let store_path = store.get_path(smt.root(), index)?; let smt_path = smt.get_path(index)?; assert_eq!( @@ -189,11 +193,12 @@ fn test_leaf_paths_for_empty_trees() -> Result<(), MerkleError> { "the returned merkle path does not match the computed values" ); assert_eq!( - store_path.path.compute_root(depth.into(), RpoDigest::default()).unwrap(), + store_path.path.compute_root(DEPTH.into(), RpoDigest::default()).unwrap(), smt.root(), "computed root from the path must match the empty tree root" ); - } + + }); Ok(()) } @@ -210,7 +215,7 @@ fn test_get_invalid_node() { fn test_add_sparse_merkle_tree_one_level() -> Result<(), MerkleError> { let keys2: [u64; 2] = [0, 1]; let leaves2: [Word; 2] = [int_to_leaf(1), int_to_leaf(2)]; - let smt = SimpleSmt::with_leaves(1, keys2.into_iter().zip(leaves2)).unwrap(); + let smt = SimpleSmt::<1>::with_leaves(keys2.into_iter().zip(leaves2)).unwrap(); let store = MerkleStore::from(&smt); let idx = NodeIndex::make(1, 0); @@ -226,8 +231,7 @@ fn test_add_sparse_merkle_tree_one_level() -> Result<(), MerkleError> { #[test] fn test_sparse_merkle_tree() -> Result<(), MerkleError> { - let smt = SimpleSmt::with_leaves( - SimpleSmt::MAX_DEPTH, + let smt = SimpleSmt::::with_leaves( KEYS4.into_iter().zip(digests_to_words(&VALUES4)), ) .unwrap(); @@ -552,9 +556,8 @@ fn test_constructors() -> Result<(), MerkleError> { assert_eq!(mtree.get_path(index)?, value_path.path); } - let depth = 32; let smt = - SimpleSmt::with_leaves(depth, KEYS4.into_iter().zip(digests_to_words(&VALUES4))).unwrap(); + SimpleSmt::<32>::with_leaves(KEYS4.into_iter().zip(digests_to_words(&VALUES4))).unwrap(); let store = MerkleStore::from(&smt); let depth = smt.depth(); @@ -880,8 +883,7 @@ fn test_serialization() -> Result<(), Box> { fn test_recorder() { // instantiate recorder from MerkleTree and SimpleSmt let mtree = MerkleTree::new(digests_to_words(&VALUES4)).unwrap(); - let smtree = SimpleSmt::with_leaves( - 64, + let smtree = SimpleSmt::<64>::with_leaves( KEYS8.into_iter().zip(VALUES8.into_iter().map(|x| x.into()).rev()), ) .unwrap(); From e111a7daeba6f821498f93669d38550da5e19ef6 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 14:24:11 -0500 Subject: [PATCH 014/121] LeafIndex: derives --- src/merkle/smt.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 8add4971..cf1440db 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -152,6 +152,8 @@ impl InnerNode { // ================================================================================================ /// The index of a leaf, at a depth known at compile-time. +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct LeafIndex { index: NodeIndex, } From e90f1afe345574618abc154df95995569e642958 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 14:32:42 -0500 Subject: [PATCH 015/121] implement SparseMerkleTree for SimpleSmt --- src/merkle/simple_smt/mod.rs | 42 ++++++++++++++++++++++++++++++++++-- src/merkle/smt.rs | 2 +- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index fcd4a878..7234954d 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,6 +1,7 @@ use super::{ - BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, MerkleError, MerklePath, - MerkleTreeDelta, NodeIndex, Rpo256, RpoDigest, StoreNode, TryApplyDiff, Vec, Word, + BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, + MerklePath, MerkleTreeDelta, NodeIndex, Rpo256, RpoDigest, SparseMerkleTree, StoreNode, + TryApplyDiff, Vec, Word, }; #[cfg(test)] @@ -341,6 +342,43 @@ impl SimpleSmt { } } +impl SparseMerkleTree for SimpleSmt { + type Key = LeafIndex; + type Value = Word; + type Leaf = Word; + + fn root(&self) -> RpoDigest { + self.root() + } + + fn set_root(&mut self, root: RpoDigest) { + self.root = root; + } + + fn get_inner_node(&self, index: NodeIndex) -> InnerNode { + self.get_branch_node(&index) + } + + fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { + let InnerNode { left, right } = inner_node; + + self.insert_branch_node(index, left, right) + } + + fn insert_leaf_node(&mut self, key: LeafIndex, value: Word) -> Option { + self.leaves.insert(key.value(), value) + } + + fn get_leaf_at(&self, key: &LeafIndex) -> Word { + self.get_leaf(key.value()) + .expect("we have compile-time guarantees on the depth of the tree") + } + + fn hash_leaf(leaf: &Word) -> RpoDigest { + leaf.into() + } +} + // TRY APPLY DIFF // ================================================================================================ impl TryApplyDiff for SimpleSmt { diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index cf1440db..0a794a5d 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -123,7 +123,7 @@ pub trait SparseMerkleTree { fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode); /// Inserts a leaf node, and returns the value at the key if already exists - fn insert_leaf_node(&self, key: Self::Key, value: Self::Value) -> Option; + fn insert_leaf_node(&mut self, key: Self::Key, value: Self::Value) -> Option; /// Returns the leaf at the specified index. fn get_leaf_at(&self, key: &Self::Key) -> Self::Leaf; From 85f7923b9ee931bfd7c4171242bc04b9f9944d77 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 14:34:24 -0500 Subject: [PATCH 016/121] Remove old comment --- src/merkle/smt.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 0a794a5d..a70efb14 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -40,9 +40,6 @@ pub trait SparseMerkleTree { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - /// - /// # Errors - /// Returns an error if the specified index is too large given the depth of this Merkle tree. fn get_merkle_path(&self, key: Self::Key) -> MerklePath { let mut index: NodeIndex = { let leaf_index: LeafIndex = key.into(); From d962ced569653a60ff1a2878fd96a902ed892e34 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 10 Jan 2024 14:38:45 -0500 Subject: [PATCH 017/121] Rename get_merkle_path --- src/merkle/smt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index a70efb14..34567ac5 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -40,7 +40,7 @@ pub trait SparseMerkleTree { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - fn get_merkle_path(&self, key: Self::Key) -> MerklePath { + fn get_leaf_path(&self, key: Self::Key) -> MerklePath { let mut index: NodeIndex = { let leaf_index: LeafIndex = key.into(); leaf_index.into() From f1bc852b451759d3a067e8d2ed3cb4cb86eec197 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 07:23:50 -0500 Subject: [PATCH 018/121] Remove `SimpleSmt::get_path()` and `get_leaf_path()` --- benches/smt.rs | 7 ++++-- benches/store.rs | 9 ++++++-- src/merkle/simple_smt/mod.rs | 39 +------------------------------ src/merkle/simple_smt/tests.rs | 42 ++++++++++++++-------------------- src/merkle/store/tests.rs | 30 ++++++++++++------------ 5 files changed, 46 insertions(+), 81 deletions(-) diff --git a/benches/smt.rs b/benches/smt.rs index 601206b8..828019b2 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -1,6 +1,9 @@ use core::mem::swap; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use miden_crypto::{merkle::SimpleSmt, Felt, Word}; +use miden_crypto::{ + merkle::{LeafIndex, SimpleSmt, SparseMerkleTree}, + Felt, Word, +}; use rand_utils::prng_array; use seq_macro::seq; @@ -49,7 +52,7 @@ fn smt_rpo(c: &mut Criterion) { &key, |b, key| { b.iter(|| { - tree.get_leaf_path(black_box(*key)).unwrap(); + tree.get_leaf_path(black_box(LeafIndex::::new(*key).unwrap())); }); }, ); diff --git a/benches/store.rs b/benches/store.rs index bc761b45..38e6282e 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -1,6 +1,7 @@ use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; use miden_crypto::merkle::{ - DefaultMerkleStore as MerkleStore, MerkleTree, NodeIndex, SimpleSmt, SIMPLE_SMT_MAX_DEPTH, + DefaultMerkleStore as MerkleStore, LeafIndex, MerkleTree, NodeIndex, SimpleSmt, + SparseMerkleTree, SIMPLE_SMT_MAX_DEPTH, }; use miden_crypto::Word; use miden_crypto::{hash::rpo::RpoDigest, Felt}; @@ -297,7 +298,11 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { group.bench_function(BenchmarkId::new("SimpleSmt", size), |b| { b.iter_batched( || random_index(size_u64, depth), - |index| black_box(smt.get_path(index)), + |index| { + black_box(smt.get_leaf_path( + LeafIndex::::new(index.value()).unwrap(), + )) + }, BatchSize::SmallInput, ) }); diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 7234954d..90c4a850 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,7 +1,6 @@ use super::{ BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, - MerklePath, MerkleTreeDelta, NodeIndex, Rpo256, RpoDigest, SparseMerkleTree, StoreNode, - TryApplyDiff, Vec, Word, + MerkleTreeDelta, NodeIndex, Rpo256, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, Word, }; #[cfg(test)] @@ -161,42 +160,6 @@ impl SimpleSmt { Ok(self.get_node(index)?.into()) } - /// Returns a Merkle path from the node at the specified index to the root. - /// - /// The node itself is not included in the path. - /// - /// # Errors - /// Returns an error if the specified index has depth set to 0 or the depth is greater than - /// the depth of this Merkle tree. - pub fn get_path(&self, mut index: NodeIndex) -> Result { - if index.is_root() { - return Err(MerkleError::DepthTooSmall(index.depth())); - } else if index.depth() > self.depth() { - return Err(MerkleError::DepthTooBig(index.depth() as u64)); - } - - let mut path = Vec::with_capacity(index.depth() as usize); - for _ in 0..index.depth() { - let is_right = index.is_value_odd(); - index.move_up(); - let InnerNode { left, right } = self.get_branch_node(&index); - let value = if is_right { left } else { right }; - path.push(value); - } - Ok(MerklePath::new(path)) - } - - /// Return a Merkle path from the leaf at the specified index to the root. - /// - /// The leaf itself is not included in the path. - /// - /// # Errors - /// Returns an error if the index is greater than the maximum tree capacity, that is 2^{depth}. - pub fn get_leaf_path(&self, index: u64) -> Result { - let index = NodeIndex::new(self.depth(), index)?; - self.get_path(index) - } - // ITERATORS // -------------------------------------------------------------------------------------------- diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 3a43cd44..2c0e5745 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -1,9 +1,11 @@ use super::{ super::{InnerNodeInfo, MerkleError, MerkleTree, RpoDigest, SimpleSmt, EMPTY_WORD}, - NodeIndex, Rpo256, Vec, + NodeIndex, Rpo256, }; use crate::{ - merkle::{digests_to_words, int_to_leaf, int_to_node, EmptySubtreeRoots}, + merkle::{ + digests_to_words, int_to_leaf, int_to_node, EmptySubtreeRoots, LeafIndex, SparseMerkleTree, + }, Word, }; @@ -53,7 +55,7 @@ fn build_sparse_tree() { assert_eq!(mt2.root(), smt.root()); assert_eq!( mt2.get_path(NodeIndex::make(3, 6)).unwrap(), - smt.get_path(NodeIndex::make(3, 6)).unwrap() + smt.get_leaf_path(LeafIndex::<3>::new(6).unwrap()) ); assert_eq!(old_value, EMPTY_WORD); @@ -66,7 +68,7 @@ fn build_sparse_tree() { assert_eq!(mt3.root(), smt.root()); assert_eq!( mt3.get_path(NodeIndex::make(3, 2)).unwrap(), - smt.get_path(NodeIndex::make(3, 2)).unwrap() + smt.get_leaf_path(LeafIndex::<3>::new(2).unwrap()) ); assert_eq!(old_value, EMPTY_WORD); } @@ -102,14 +104,10 @@ fn test_depth2_tree() { assert_eq!(VALUES4[3], tree.get_node(NodeIndex::make(2, 3)).unwrap()); // check get_path(): depth 2 - assert_eq!(vec![VALUES4[1], node3], *tree.get_path(NodeIndex::make(2, 0)).unwrap()); - assert_eq!(vec![VALUES4[0], node3], *tree.get_path(NodeIndex::make(2, 1)).unwrap()); - assert_eq!(vec![VALUES4[3], node2], *tree.get_path(NodeIndex::make(2, 2)).unwrap()); - assert_eq!(vec![VALUES4[2], node2], *tree.get_path(NodeIndex::make(2, 3)).unwrap()); - - // check get_path(): depth 1 - assert_eq!(vec![node3], *tree.get_path(NodeIndex::make(1, 0)).unwrap()); - assert_eq!(vec![node2], *tree.get_path(NodeIndex::make(1, 1)).unwrap()); + assert_eq!(vec![VALUES4[1], node3], *tree.get_leaf_path(LeafIndex::<2>::new(0).unwrap())); + assert_eq!(vec![VALUES4[0], node3], *tree.get_leaf_path(LeafIndex::<2>::new(1).unwrap())); + assert_eq!(vec![VALUES4[3], node2], *tree.get_leaf_path(LeafIndex::<2>::new(2).unwrap())); + assert_eq!(vec![VALUES4[2], node2], *tree.get_leaf_path(LeafIndex::<2>::new(3).unwrap())); } #[test] @@ -202,21 +200,15 @@ fn small_tree_opening_is_consistent() { assert_eq!(tree.root(), k); - let cases: Vec<(u8, u64, Vec)> = vec![ - (3, 0, vec![b.into(), f, j]), - (3, 1, vec![a.into(), f, j]), - (3, 4, vec![z.into(), h, i]), - (3, 7, vec![z.into(), g, i]), - (2, 0, vec![f, j]), - (2, 1, vec![e, j]), - (2, 2, vec![h, i]), - (2, 3, vec![g, i]), - (1, 0, vec![j]), - (1, 1, vec![i]), + let cases: Vec<(u64, Vec)> = vec![ + (0, vec![b.into(), f, j]), + (1, vec![a.into(), f, j]), + (4, vec![z.into(), h, i]), + (7, vec![z.into(), g, i]), ]; - for (depth, key, path) in cases { - let opening = tree.get_path(NodeIndex::make(depth, key)).unwrap(); + for (key, path) in cases { + let opening = tree.get_leaf_path(LeafIndex::<3>::new(key).unwrap()); assert_eq!(path, *opening); } diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index 24c017c7..81e5875d 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -4,7 +4,8 @@ use super::{ }; use crate::{ merkle::{ - digests_to_words, int_to_leaf, int_to_node, MerkleTree, SimpleSmt, SIMPLE_SMT_MAX_DEPTH, + digests_to_words, int_to_leaf, int_to_node, LeafIndex, MerkleTree, SimpleSmt, + SparseMerkleTree, SIMPLE_SMT_MAX_DEPTH, }, Felt, Word, ONE, WORD_SIZE, ZERO, }; @@ -182,7 +183,7 @@ fn test_leaf_paths_for_empty_trees() -> Result<(), MerkleError> { let index = NodeIndex::make(DEPTH, 0); let store_path = store.get_path(smt.root(), index)?; - let smt_path = smt.get_path(index)?; + let smt_path = smt.get_leaf_path(LeafIndex::::new(0)?); assert_eq!( store_path.value, RpoDigest::default(), @@ -302,8 +303,8 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 0 must match leaf value" ); assert_eq!( - smt.get_path(NodeIndex::make(smt.depth(), 0)), - Ok(result.path), + smt.get_leaf_path(LeafIndex::::new(0).unwrap()), + result.path, "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" ); @@ -313,8 +314,8 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 1 must match leaf value" ); assert_eq!( - smt.get_path(NodeIndex::make(smt.depth(), 1)), - Ok(result.path), + smt.get_leaf_path(LeafIndex::::new(1).unwrap()), + result.path, "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" ); @@ -324,8 +325,8 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 2 must match leaf value" ); assert_eq!( - smt.get_path(NodeIndex::make(smt.depth(), 2)), - Ok(result.path), + smt.get_leaf_path(LeafIndex::::new(2).unwrap()), + result.path, "merkle path for index 2 must be the same for the MerkleTree and MerkleStore" ); @@ -335,8 +336,8 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 3 must match leaf value" ); assert_eq!( - smt.get_path(NodeIndex::make(smt.depth(), 3)), - Ok(result.path), + smt.get_leaf_path(LeafIndex::::new(3).unwrap()), + result.path, "merkle path for index 3 must be the same for the MerkleTree and MerkleStore" ); @@ -347,8 +348,8 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 4 must match leaf value" ); assert_eq!( - smt.get_path(NodeIndex::make(smt.depth(), 4)), - Ok(result.path), + smt.get_leaf_path(LeafIndex::::new(4).unwrap()), + result.path, "merkle path for index 4 must be the same for the MerkleTree and MerkleStore" ); @@ -556,15 +557,16 @@ fn test_constructors() -> Result<(), MerkleError> { assert_eq!(mtree.get_path(index)?, value_path.path); } + const DEPTH: u8 = 32; let smt = - SimpleSmt::<32>::with_leaves(KEYS4.into_iter().zip(digests_to_words(&VALUES4))).unwrap(); + SimpleSmt::::with_leaves(KEYS4.into_iter().zip(digests_to_words(&VALUES4))).unwrap(); let store = MerkleStore::from(&smt); let depth = smt.depth(); for key in KEYS4 { let index = NodeIndex::make(depth, key); let value_path = store.get_path(smt.root(), index)?; - assert_eq!(smt.get_path(index)?, value_path.path); + assert_eq!(smt.get_leaf_path(LeafIndex::::new(key).unwrap()), value_path.path); } let d = 2; From 720552fd2c62e53680697db43cd04e26afad7637 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 07:47:09 -0500 Subject: [PATCH 019/121] add tryfrom NodeIndex for LeafIndex --- src/merkle/smt.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 34567ac5..e5cd7958 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -179,6 +179,21 @@ impl From> for NodeIndex { } } +impl TryFrom for LeafIndex { + type Error = MerkleError; + + fn try_from(node_index: NodeIndex) -> Result { + if node_index.depth() != DEPTH { + return Err(MerkleError::InvalidDepth { + expected: DEPTH, + provided: node_index.depth(), + }); + } + + Self::new(node_index.value()) + } +} + impl From for LeafIndex<64> { fn from(value: Word) -> Self { Self::new_max_depth(value[0].inner()) From 7d52935a7be91ad45602fa4424e3f44be3a099c8 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 07:53:33 -0500 Subject: [PATCH 020/121] impl get_leaf_at on its own --- src/merkle/simple_smt/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 90c4a850..f717acd5 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -333,8 +333,14 @@ impl SparseMerkleTree for SimpleSmt { } fn get_leaf_at(&self, key: &LeafIndex) -> Word { - self.get_leaf(key.value()) - .expect("we have compile-time guarantees on the depth of the tree") + // the lookup in empty_hashes could fail only if empty_hashes were not built correctly + // by the constructor as we check the depth of the lookup above. + let leaf_pos = key.value(); + + match self.get_leaf_node(leaf_pos) { + Some(word) => word, + None => Word::from(*EmptySubtreeRoots::entry(self.depth(), self.depth())), + } } fn hash_leaf(leaf: &Word) -> RpoDigest { From 0400214b2531ed910a49499b448c9563185e819b Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 07:55:35 -0500 Subject: [PATCH 021/121] impl get_node in terms of get_leaf_at --- src/merkle/simple_smt/mod.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index f717acd5..90df1137 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -138,14 +138,9 @@ impl SimpleSmt { } else if index.depth() > self.depth() { Err(MerkleError::DepthTooBig(index.depth() as u64)) } else if index.depth() == self.depth() { - // the lookup in empty_hashes could fail only if empty_hashes were not built correctly - // by the constructor as we check the depth of the lookup above. - let leaf_pos = index.value(); - let leaf = match self.get_leaf_node(leaf_pos) { - Some(word) => word.into(), - None => *EmptySubtreeRoots::entry(self.depth(), index.depth()), - }; - Ok(leaf) + let leaf = self.get_leaf_at(&LeafIndex::::try_from(index)?); + + Ok(leaf.into()) } else { Ok(self.get_branch_node(&index).hash()) } From 8dcb2974e7f5a852b0090adc4646ba81332cb1b1 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 07:59:03 -0500 Subject: [PATCH 022/121] Remove `get_leaf()` --- src/merkle/simple_smt/mod.rs | 9 --------- src/merkle/simple_smt/tests.rs | 5 +++-- src/merkle/store/tests.rs | 9 +++++++-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 90df1137..8b32d440 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -146,15 +146,6 @@ impl SimpleSmt { } } - /// Returns a value of the leaf at the specified index. - /// - /// # Errors - /// Returns an error if the index is greater than the maximum tree capacity, that is 2^{depth}. - pub fn get_leaf(&self, index: u64) -> Result { - let index = NodeIndex::new(self.depth(), index)?; - Ok(self.get_node(index)?.into()) - } - // ITERATORS // -------------------------------------------------------------------------------------------- diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 2c0e5745..10191a54 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -374,9 +374,10 @@ fn test_simplesmt_set_subtree() { }; // insert subtree + const TREE_DEPTH: u8 = 3; let tree = { let entries = vec![(0, a), (1, b), (7, d)]; - let mut tree = SimpleSmt::<3>::with_leaves(entries).unwrap(); + let mut tree = SimpleSmt::::with_leaves(entries).unwrap(); tree.set_subtree(2, subtree).unwrap(); @@ -384,7 +385,7 @@ fn test_simplesmt_set_subtree() { }; assert_eq!(tree.root(), k); - assert_eq!(tree.get_leaf(4).unwrap(), c); + assert_eq!(tree.get_leaf_at(&LeafIndex::::new(4).unwrap()), c); assert_eq!(tree.get_branch_node(&NodeIndex::new_unchecked(2, 2)).hash(), g); } diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index 81e5875d..e7ae41e1 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -885,7 +885,9 @@ fn test_serialization() -> Result<(), Box> { fn test_recorder() { // instantiate recorder from MerkleTree and SimpleSmt let mtree = MerkleTree::new(digests_to_words(&VALUES4)).unwrap(); - let smtree = SimpleSmt::<64>::with_leaves( + + const TREE_DEPTH: u8 = 64; + let smtree = SimpleSmt::::with_leaves( KEYS8.into_iter().zip(VALUES8.into_iter().map(|x| x.into()).rev()), ) .unwrap(); @@ -921,7 +923,10 @@ fn test_recorder() { assert_eq!(node, smtree.get_node(index_1).unwrap()); let node = merkle_store.get_node(smtree.root(), index_2).unwrap(); - assert_eq!(node, smtree.get_leaf(index_2.value()).unwrap().into()); + assert_eq!( + node, + smtree.get_leaf_at(&LeafIndex::::try_from(index_2).unwrap()).into() + ); // assert that is doesnt contain nodes that were not recorded let not_recorded_index = NodeIndex::new(smtree.depth(), 4).unwrap(); From b574bf6cbfc67a2a547b817a581d87c92468cb85 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 07:59:45 -0500 Subject: [PATCH 023/121] rename get_leaf_at --- src/merkle/simple_smt/mod.rs | 4 ++-- src/merkle/simple_smt/tests.rs | 2 +- src/merkle/smt.rs | 4 ++-- src/merkle/store/tests.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 8b32d440..e3669b19 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -138,7 +138,7 @@ impl SimpleSmt { } else if index.depth() > self.depth() { Err(MerkleError::DepthTooBig(index.depth() as u64)) } else if index.depth() == self.depth() { - let leaf = self.get_leaf_at(&LeafIndex::::try_from(index)?); + let leaf = self.get_leaf(&LeafIndex::::try_from(index)?); Ok(leaf.into()) } else { @@ -318,7 +318,7 @@ impl SparseMerkleTree for SimpleSmt { self.leaves.insert(key.value(), value) } - fn get_leaf_at(&self, key: &LeafIndex) -> Word { + fn get_leaf(&self, key: &LeafIndex) -> Word { // the lookup in empty_hashes could fail only if empty_hashes were not built correctly // by the constructor as we check the depth of the lookup above. let leaf_pos = key.value(); diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 10191a54..2c9169fd 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -385,7 +385,7 @@ fn test_simplesmt_set_subtree() { }; assert_eq!(tree.root(), k); - assert_eq!(tree.get_leaf_at(&LeafIndex::::new(4).unwrap()), c); + assert_eq!(tree.get_leaf(&LeafIndex::::new(4).unwrap()), c); assert_eq!(tree.get_branch_node(&NodeIndex::new_unchecked(2, 2)).hash(), g); } diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index e5cd7958..c0e13a28 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -69,7 +69,7 @@ pub trait SparseMerkleTree { return value; } - let leaf = self.get_leaf_at(&key); + let leaf = self.get_leaf(&key); let node_index = { let leaf_index: LeafIndex = key.into(); leaf_index.into() @@ -123,7 +123,7 @@ pub trait SparseMerkleTree { fn insert_leaf_node(&mut self, key: Self::Key, value: Self::Value) -> Option; /// Returns the leaf at the specified index. - fn get_leaf_at(&self, key: &Self::Key) -> Self::Leaf; + fn get_leaf(&self, key: &Self::Key) -> Self::Leaf; /// Returns the hash of a leaf fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest; diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index e7ae41e1..ff4d6b56 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -925,7 +925,7 @@ fn test_recorder() { let node = merkle_store.get_node(smtree.root(), index_2).unwrap(); assert_eq!( node, - smtree.get_leaf_at(&LeafIndex::::try_from(index_2).unwrap()).into() + smtree.get_leaf(&LeafIndex::::try_from(index_2).unwrap()).into() ); // assert that is doesnt contain nodes that were not recorded From 037ceab108bcb4d7d350fb914f7cd0de405ae122 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:09:47 -0500 Subject: [PATCH 024/121] remove get_branch_node --- src/merkle/simple_smt/mod.rs | 17 +++++++---------- src/merkle/simple_smt/tests.rs | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index e3669b19..280d5a33 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -142,7 +142,7 @@ impl SimpleSmt { Ok(leaf.into()) } else { - Ok(self.get_branch_node(&index).hash()) + Ok(self.get_inner_node(index).hash()) } } @@ -262,7 +262,7 @@ impl SimpleSmt { for _ in 0..index.depth() { let is_right = index.is_value_odd(); index.move_up(); - let InnerNode { left, right } = self.get_branch_node(&index); + let InnerNode { left, right } = self.get_inner_node(index); let (left, right) = if is_right { (left, value) } else { (value, right) }; self.insert_branch_node(index, left, right); value = Rpo256::merge(&[left, right]); @@ -278,13 +278,6 @@ impl SimpleSmt { self.leaves.insert(key, node) } - fn get_branch_node(&self, index: &NodeIndex) -> InnerNode { - self.branches.get(index).cloned().unwrap_or_else(|| { - let node = EmptySubtreeRoots::entry(self.depth(), index.depth() + 1); - InnerNode { left: *node, right: *node } - }) - } - fn insert_branch_node(&mut self, index: NodeIndex, left: RpoDigest, right: RpoDigest) { let branch = InnerNode { left, right }; self.branches.insert(index, branch); @@ -305,7 +298,11 @@ impl SparseMerkleTree for SimpleSmt { } fn get_inner_node(&self, index: NodeIndex) -> InnerNode { - self.get_branch_node(&index) + self.branches.get(&index).cloned().unwrap_or_else(|| { + let node = EmptySubtreeRoots::entry(self.depth(), index.depth() + 1); + + InnerNode { left: *node, right: *node } + }) } fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 2c9169fd..5a0c2a9b 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -386,7 +386,7 @@ fn test_simplesmt_set_subtree() { assert_eq!(tree.root(), k); assert_eq!(tree.get_leaf(&LeafIndex::::new(4).unwrap()), c); - assert_eq!(tree.get_branch_node(&NodeIndex::new_unchecked(2, 2)).hash(), g); + assert_eq!(tree.get_inner_node(NodeIndex::new_unchecked(2, 2)).hash(), g); } /// Ensures that an invalid input node index into `set_subtree()` incurs no mutation of the tree From 7965436cffafdddc038d16ea98268f5439807a1e Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:12:27 -0500 Subject: [PATCH 025/121] remove insert_branch_node --- src/merkle/simple_smt/mod.rs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 280d5a33..4e98574d 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -29,7 +29,7 @@ pub const EMPTY_VALUE: Word = super::EMPTY_WORD; pub struct SimpleSmt { root: RpoDigest, leaves: BTreeMap, - branches: BTreeMap, + inner_nodes: BTreeMap, } impl SimpleSmt { @@ -55,7 +55,7 @@ impl SimpleSmt { Ok(Self { root, leaves: BTreeMap::new(), - branches: BTreeMap::new(), + inner_nodes: BTreeMap::new(), }) } @@ -156,7 +156,7 @@ impl SimpleSmt { /// Returns an iterator over the inner nodes of this Merkle tree. pub fn inner_nodes(&self) -> impl Iterator + '_ { - self.branches.values().map(|e| InnerNodeInfo { + self.inner_nodes.values().map(|e| InnerNodeInfo { value: e.hash(), left: e.left, right: e.right, @@ -229,7 +229,7 @@ impl SimpleSmt { // add subtree's branch nodes (which includes the root) // -------------- - for (branch_idx, branch_node) in subtree.branches { + for (branch_idx, branch_node) in subtree.inner_nodes { let new_branch_idx = { let new_depth = subtree_root_insertion_depth + branch_idx.depth(); let new_value = subtree_insertion_index * 2_u64.pow(branch_idx.depth().into()) @@ -238,7 +238,7 @@ impl SimpleSmt { NodeIndex::new(new_depth, new_value).expect("index guaranteed to be valid") }; - self.branches.insert(new_branch_idx, branch_node); + self.inner_nodes.insert(new_branch_idx, branch_node); } // recompute nodes starting from subtree root @@ -264,7 +264,7 @@ impl SimpleSmt { index.move_up(); let InnerNode { left, right } = self.get_inner_node(index); let (left, right) = if is_right { (left, value) } else { (value, right) }; - self.insert_branch_node(index, left, right); + self.insert_inner_node(index, InnerNode { left, right }); value = Rpo256::merge(&[left, right]); } self.root = value; @@ -277,11 +277,6 @@ impl SimpleSmt { fn insert_leaf_node(&mut self, key: u64, node: Word) -> Option { self.leaves.insert(key, node) } - - fn insert_branch_node(&mut self, index: NodeIndex, left: RpoDigest, right: RpoDigest) { - let branch = InnerNode { left, right }; - self.branches.insert(index, branch); - } } impl SparseMerkleTree for SimpleSmt { @@ -298,7 +293,7 @@ impl SparseMerkleTree for SimpleSmt { } fn get_inner_node(&self, index: NodeIndex) -> InnerNode { - self.branches.get(&index).cloned().unwrap_or_else(|| { + self.inner_nodes.get(&index).cloned().unwrap_or_else(|| { let node = EmptySubtreeRoots::entry(self.depth(), index.depth() + 1); InnerNode { left: *node, right: *node } @@ -306,9 +301,7 @@ impl SparseMerkleTree for SimpleSmt { } fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { - let InnerNode { left, right } = inner_node; - - self.insert_branch_node(index, left, right) + self.inner_nodes.insert(index, inner_node); } fn insert_leaf_node(&mut self, key: LeafIndex, value: Word) -> Option { From fda8dc7ca632e5119a648445753a33480b9bfb57 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:14:33 -0500 Subject: [PATCH 026/121] remove duplicate recompute_nodes_from_index_to_root --- src/merkle/simple_smt/mod.rs | 21 +-------------------- src/merkle/simple_smt/tests.rs | 3 ++- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 4e98574d..7154360e 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,6 +1,6 @@ use super::{ BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, - MerkleTreeDelta, NodeIndex, Rpo256, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, Word, + MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, Word, }; #[cfg(test)] @@ -251,25 +251,6 @@ impl SimpleSmt { // HELPER METHODS // -------------------------------------------------------------------------------------------- - /// Recomputes the branch nodes (including the root) from `index` all the way to the root. - /// `node_hash_at_index` is the hash of the node stored at index. - fn recompute_nodes_from_index_to_root( - &mut self, - mut index: NodeIndex, - node_hash_at_index: RpoDigest, - ) { - let mut value = node_hash_at_index; - for _ in 0..index.depth() { - let is_right = index.is_value_odd(); - index.move_up(); - let InnerNode { left, right } = self.get_inner_node(index); - let (left, right) = if is_right { (left, value) } else { (value, right) }; - self.insert_inner_node(index, InnerNode { left, right }); - value = Rpo256::merge(&[left, right]); - } - self.root = value; - } - fn get_leaf_node(&self, key: u64) -> Option { self.leaves.get(&key).copied() } diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 5a0c2a9b..123389d7 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -1,8 +1,9 @@ use super::{ super::{InnerNodeInfo, MerkleError, MerkleTree, RpoDigest, SimpleSmt, EMPTY_WORD}, - NodeIndex, Rpo256, + NodeIndex, }; use crate::{ + hash::rpo::Rpo256, merkle::{ digests_to_words, int_to_leaf, int_to_node, EmptySubtreeRoots, LeafIndex, SparseMerkleTree, }, From beaf2a16073c675873b9d5a02c5ea97dbf39a707 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:18:01 -0500 Subject: [PATCH 027/121] remove private get_leaf_node --- src/merkle/simple_smt/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 7154360e..9df721c3 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -251,10 +251,6 @@ impl SimpleSmt { // HELPER METHODS // -------------------------------------------------------------------------------------------- - fn get_leaf_node(&self, key: u64) -> Option { - self.leaves.get(&key).copied() - } - fn insert_leaf_node(&mut self, key: u64, node: Word) -> Option { self.leaves.insert(key, node) } @@ -294,8 +290,8 @@ impl SparseMerkleTree for SimpleSmt { // by the constructor as we check the depth of the lookup above. let leaf_pos = key.value(); - match self.get_leaf_node(leaf_pos) { - Some(word) => word, + match self.leaves.get(&leaf_pos) { + Some(word) => *word, None => Word::from(*EmptySubtreeRoots::entry(self.depth(), self.depth())), } } From 2a2bf9dcdba849126359158c7f48548e3dcf804a Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:21:26 -0500 Subject: [PATCH 028/121] remove trivial helper --- src/merkle/simple_smt/mod.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 9df721c3..b5b58299 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -176,7 +176,7 @@ impl SimpleSmt { // validate the index before modifying the structure let idx = NodeIndex::new(self.depth(), index)?; - let old_value = self.insert_leaf_node(index, value).unwrap_or(EMPTY_VALUE); + let old_value = self.leaves.insert(index, value).unwrap_or(EMPTY_VALUE); // if the old value and new value are the same, there is nothing to update if value == old_value { @@ -224,7 +224,7 @@ impl SimpleSmt { let new_leaf_idx = leaf_index_shift + subtree_leaf_idx; debug_assert!(new_leaf_idx < 2_u64.pow(self.depth().into())); - self.insert_leaf_node(new_leaf_idx, *leaf_value); + self.leaves.insert(new_leaf_idx, *leaf_value); } // add subtree's branch nodes (which includes the root) @@ -247,13 +247,6 @@ impl SimpleSmt { Ok(self.root) } - - // HELPER METHODS - // -------------------------------------------------------------------------------------------- - - fn insert_leaf_node(&mut self, key: u64, node: Word) -> Option { - self.leaves.insert(key, node) - } } impl SparseMerkleTree for SimpleSmt { From 77def41c61f07a9cb22ee13fc3eed92bb113fdca Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:35:28 -0500 Subject: [PATCH 029/121] remove extra `root()` method --- src/merkle/delta.rs | 91 +++++++++++++++++------------------- src/merkle/simple_smt/mod.rs | 7 +-- 2 files changed, 44 insertions(+), 54 deletions(-) diff --git a/src/merkle/delta.rs b/src/merkle/delta.rs index 4de94750..1c0e4f41 100644 --- a/src/merkle/delta.rs +++ b/src/merkle/delta.rs @@ -25,7 +25,6 @@ pub struct MerkleStoreDelta(pub Vec<(RpoDigest, MerkleTreeDelta)>); /// - depth: the depth of the merkle tree. /// - cleared_slots: indexes of slots where values were set to [ZERO; 4]. /// - updated_slots: index-value pairs of slots where values were set to non [ZERO; 4] values. -#[cfg(not(test))] #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct MerkleTreeDelta { @@ -105,52 +104,48 @@ pub fn merkle_tree_delta>( }) } -// INTERNALS -// -------------------------------------------------------------------------------------------- -#[cfg(test)] -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct MerkleTreeDelta { - pub depth: u8, - pub cleared_slots: Vec, - pub updated_slots: Vec<(u64, Word)>, -} - -// MERKLE DELTA +// TESTS // ================================================================================================ -#[test] -fn test_compute_merkle_delta() { - let entries = vec![ - (10, [ZERO, ONE, Felt::new(2), Felt::new(3)]), - (15, [Felt::new(4), Felt::new(5), Felt::new(6), Felt::new(7)]), - (20, [Felt::new(8), Felt::new(9), Felt::new(10), Felt::new(11)]), - (31, [Felt::new(12), Felt::new(13), Felt::new(14), Felt::new(15)]), - ]; - let simple_smt = SimpleSmt::<30>::with_leaves(entries.clone()).unwrap(); - let mut store: MerkleStore = (&simple_smt).into(); - let root = simple_smt.root(); - - // add a new node - let new_value = [Felt::new(16), Felt::new(17), Felt::new(18), Felt::new(19)]; - let new_index = NodeIndex::new(simple_smt.depth(), 32).unwrap(); - let root = store.set_node(root, new_index, new_value.into()).unwrap().root; - - // update an existing node - let update_value = [Felt::new(20), Felt::new(21), Felt::new(22), Felt::new(23)]; - let update_idx = NodeIndex::new(simple_smt.depth(), entries[0].0).unwrap(); - let root = store.set_node(root, update_idx, update_value.into()).unwrap().root; - - // remove a node - let remove_idx = NodeIndex::new(simple_smt.depth(), entries[1].0).unwrap(); - let root = store.set_node(root, remove_idx, EMPTY_WORD.into()).unwrap().root; - - let merkle_delta = - merkle_tree_delta(simple_smt.root(), root, simple_smt.depth(), &store).unwrap(); - let expected_merkle_delta = MerkleTreeDelta { - depth: simple_smt.depth(), - cleared_slots: vec![remove_idx.value()], - updated_slots: vec![(update_idx.value(), update_value), (new_index.value(), new_value)], - }; - - assert_eq!(merkle_delta, expected_merkle_delta); + +#[cfg(test)] +mod tests { + use super::*; + use crate::merkle::SparseMerkleTree; + + #[test] + fn test_compute_merkle_delta() { + let entries = vec![ + (10, [ZERO, ONE, Felt::new(2), Felt::new(3)]), + (15, [Felt::new(4), Felt::new(5), Felt::new(6), Felt::new(7)]), + (20, [Felt::new(8), Felt::new(9), Felt::new(10), Felt::new(11)]), + (31, [Felt::new(12), Felt::new(13), Felt::new(14), Felt::new(15)]), + ]; + let simple_smt = SimpleSmt::<30>::with_leaves(entries.clone()).unwrap(); + let mut store: MerkleStore = (&simple_smt).into(); + let root = simple_smt.root(); + + // add a new node + let new_value = [Felt::new(16), Felt::new(17), Felt::new(18), Felt::new(19)]; + let new_index = NodeIndex::new(simple_smt.depth(), 32).unwrap(); + let root = store.set_node(root, new_index, new_value.into()).unwrap().root; + + // update an existing node + let update_value = [Felt::new(20), Felt::new(21), Felt::new(22), Felt::new(23)]; + let update_idx = NodeIndex::new(simple_smt.depth(), entries[0].0).unwrap(); + let root = store.set_node(root, update_idx, update_value.into()).unwrap().root; + + // remove a node + let remove_idx = NodeIndex::new(simple_smt.depth(), entries[1].0).unwrap(); + let root = store.set_node(root, remove_idx, EMPTY_WORD.into()).unwrap().root; + + let merkle_delta = + merkle_tree_delta(simple_smt.root(), root, simple_smt.depth(), &store).unwrap(); + let expected_merkle_delta = MerkleTreeDelta { + depth: simple_smt.depth(), + cleared_slots: vec![remove_idx.value()], + updated_slots: vec![(update_idx.value(), update_value), (new_index.value(), new_value)], + }; + + assert_eq!(merkle_delta, expected_merkle_delta); + } } diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index b5b58299..cad3beb7 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -117,11 +117,6 @@ impl SimpleSmt { // PUBLIC ACCESSORS // -------------------------------------------------------------------------------------------- - /// Returns the root of this Merkle tree. - pub const fn root(&self) -> RpoDigest { - self.root - } - /// Returns the depth of this Merkle tree. pub const fn depth(&self) -> u8 { DEPTH @@ -255,7 +250,7 @@ impl SparseMerkleTree for SimpleSmt { type Leaf = Word; fn root(&self) -> RpoDigest { - self.root() + self.root } fn set_root(&mut self, root: RpoDigest) { From 61d98e93577d0a1652ad2dcfbf6a5f1582285427 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:38:38 -0500 Subject: [PATCH 030/121] add vscode gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 1f178797..d4a844e3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ Cargo.lock # Generated by cmake cmake-build-* + +# VS Code +.vscode/ From 2417ea69cbbe6e066a663940697e5cd0a680f9c8 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:49:50 -0500 Subject: [PATCH 031/121] remove old `get_leaf()` --- benches/smt.rs | 2 +- benches/store.rs | 7 +++- src/merkle/simple_smt/mod.rs | 28 ++-------------- src/merkle/simple_smt/tests.rs | 60 +++++----------------------------- 4 files changed, 18 insertions(+), 79 deletions(-) diff --git a/benches/smt.rs b/benches/smt.rs index 828019b2..2a2f2b46 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -34,7 +34,7 @@ fn smt_rpo(c: &mut Criterion) { &(key, leaf), |b, (key, leaf)| { b.iter(|| { - tree.update_leaf(black_box(*key), black_box(*leaf)).unwrap(); + tree.update_leaf_at(black_box(LeafIndex::::new(*key).unwrap()), black_box(*leaf)); }); }, ); diff --git a/benches/store.rs b/benches/store.rs index 38e6282e..9ee7e727 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -449,7 +449,12 @@ fn update_leaf_simplesmt(c: &mut Criterion) { group.bench_function(BenchmarkId::new("SimpleSMT", size), |b| { b.iter_batched( || (rand_value::() % size_u64, random_word()), - |(index, value)| black_box(smt.update_leaf(index, value)), + |(index, value)| { + black_box(smt.update_leaf_at( + LeafIndex::::new(index).unwrap(), + value, + )) + }, BatchSize::SmallInput, ) }); diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index cad3beb7..5aa0357e 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -88,7 +88,7 @@ impl SimpleSmt { return Err(MerkleError::InvalidNumEntries(max_num_entries)); } - let old_value = tree.update_leaf(key, value)?; + let old_value = tree.update_leaf_at(LeafIndex::::new(key)?, value); if old_value != EMPTY_VALUE || key_set_to_zero.contains(&key) { return Err(MerkleError::DuplicateValuesForIndex(key)); @@ -161,28 +161,6 @@ impl SimpleSmt { // STATE MUTATORS // -------------------------------------------------------------------------------------------- - /// Updates value of the leaf at the specified index returning the old leaf value. - /// - /// This also recomputes all hashes between the leaf and the root, updating the root itself. - /// - /// # Errors - /// Returns an error if the index is greater than the maximum tree capacity, that is 2^{depth}. - pub fn update_leaf(&mut self, index: u64, value: Word) -> Result { - // validate the index before modifying the structure - let idx = NodeIndex::new(self.depth(), index)?; - - let old_value = self.leaves.insert(index, value).unwrap_or(EMPTY_VALUE); - - // if the old value and new value are the same, there is nothing to update - if value == old_value { - return Ok(value); - } - - self.recompute_nodes_from_index_to_root(idx, RpoDigest::from(value)); - - Ok(old_value) - } - /// Inserts a subtree at the specified index. The depth at which the subtree is inserted is /// computed as `self.depth() - subtree.depth()`. /// @@ -304,11 +282,11 @@ impl TryApplyDiff for SimpleSmt { } for slot in diff.cleared_slots() { - self.update_leaf(*slot, EMPTY_VALUE)?; + self.update_leaf_at(LeafIndex::::new(*slot)?, EMPTY_VALUE); } for (slot, value) in diff.updated_slots() { - self.update_leaf(*slot, *value)?; + self.update_leaf_at(LeafIndex::::new(*slot)?, *value); } Ok(()) diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 123389d7..65c1667b 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -44,14 +44,15 @@ fn build_empty_tree() { #[test] fn build_sparse_tree() { - let mut smt = SimpleSmt::<3>::new().unwrap(); + const DEPTH: u8 = 3; + let mut smt = SimpleSmt::::new().unwrap(); let mut values = ZERO_VALUES8.to_vec(); // insert single value let key = 6; let new_node = int_to_leaf(7); values[key as usize] = new_node; - let old_value = smt.update_leaf(key, new_node).expect("Failed to update leaf"); + let old_value = smt.update_leaf_at(LeafIndex::::new(key).unwrap(), new_node); let mt2 = MerkleTree::new(values.clone()).unwrap(); assert_eq!(mt2.root(), smt.root()); assert_eq!( @@ -64,7 +65,7 @@ fn build_sparse_tree() { let key = 2; let new_node = int_to_leaf(3); values[key as usize] = new_node; - let old_value = smt.update_leaf(key, new_node).expect("Failed to update leaf"); + let old_value = smt.update_leaf_at(LeafIndex::::new(key).unwrap(), new_node); let mt3 = MerkleTree::new(values).unwrap(); assert_eq!(mt3.root(), smt.root()); assert_eq!( @@ -144,8 +145,9 @@ fn test_inner_node_iterator() -> Result<(), MerkleError> { #[test] fn update_leaf() { + const DEPTH: u8 = 3; let mut tree = - SimpleSmt::<3>::with_leaves(KEYS8.into_iter().zip(digests_to_words(&VALUES8))).unwrap(); + SimpleSmt::::with_leaves(KEYS8.into_iter().zip(digests_to_words(&VALUES8))).unwrap(); // update one value let key = 3; @@ -154,7 +156,7 @@ fn update_leaf() { expected_values[key] = new_node; let expected_tree = MerkleTree::new(expected_values.clone()).unwrap(); - let old_leaf = tree.update_leaf(key as u64, new_node).unwrap(); + let old_leaf = tree.update_leaf_at(LeafIndex::::new(key as u64).unwrap(), new_node); assert_eq!(expected_tree.root(), tree.root); assert_eq!(old_leaf, *VALUES8[key]); @@ -164,7 +166,7 @@ fn update_leaf() { expected_values[key] = new_node; let expected_tree = MerkleTree::new(expected_values.clone()).unwrap(); - let old_leaf = tree.update_leaf(key as u64, new_node).unwrap(); + let old_leaf = tree.update_leaf_at(LeafIndex::::new(key as u64).unwrap(), new_node); assert_eq!(expected_tree.root(), tree.root); assert_eq!(old_leaf, *VALUES8[key]); } @@ -250,52 +252,6 @@ fn with_no_duplicates_empty_node() { assert!(smt.is_ok()); } -#[test] -fn test_simplesmt_update_nonexisting_leaf_with_zero() { - // TESTING WITH EMPTY WORD - // -------------------------------------------------------------------------------------------- - - // Depth 1 has 2 leaf. Position is 0-indexed, position 2 doesn't exist. - let mut smt = SimpleSmt::<1>::new().unwrap(); - let result = smt.update_leaf(2, EMPTY_WORD); - assert!(!smt.leaves.contains_key(&2)); - assert!(result.is_err()); - - // Depth 2 has 4 leaves. Position is 0-indexed, position 4 doesn't exist. - let mut smt = SimpleSmt::<2>::new().unwrap(); - let result = smt.update_leaf(4, EMPTY_WORD); - assert!(!smt.leaves.contains_key(&4)); - assert!(result.is_err()); - - // Depth 3 has 8 leaves. Position is 0-indexed, position 8 doesn't exist. - let mut smt = SimpleSmt::<3>::new().unwrap(); - let result = smt.update_leaf(8, EMPTY_WORD); - assert!(!smt.leaves.contains_key(&8)); - assert!(result.is_err()); - - // TESTING WITH A VALUE - // -------------------------------------------------------------------------------------------- - let value = int_to_node(1); - - // Depth 1 has 2 leaves. Position is 0-indexed, position 1 doesn't exist. - let mut smt = SimpleSmt::<1>::new().unwrap(); - let result = smt.update_leaf(2, *value); - assert!(!smt.leaves.contains_key(&2)); - assert!(result.is_err()); - - // Depth 2 has 4 leaves. Position is 0-indexed, position 2 doesn't exist. - let mut smt = SimpleSmt::<2>::new().unwrap(); - let result = smt.update_leaf(4, *value); - assert!(!smt.leaves.contains_key(&4)); - assert!(result.is_err()); - - // Depth 3 has 8 leaves. Position is 0-indexed, position 4 doesn't exist. - let mut smt = SimpleSmt::<3>::new().unwrap(); - let result = smt.update_leaf(8, *value); - assert!(!smt.leaves.contains_key(&8)); - assert!(result.is_err()); -} - #[test] fn test_simplesmt_with_leaves_nonexisting_leaf() { // TESTING WITH EMPTY WORD From 9faad2ea4a0a0ac182ff7b63ca97efb6a117df80 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:50:13 -0500 Subject: [PATCH 032/121] Rename `update_leaf_at` --- benches/smt.rs | 2 +- benches/store.rs | 2 +- src/merkle/simple_smt/mod.rs | 6 +++--- src/merkle/simple_smt/tests.rs | 8 ++++---- src/merkle/smt.rs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/benches/smt.rs b/benches/smt.rs index 2a2f2b46..dec4a0e3 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -34,7 +34,7 @@ fn smt_rpo(c: &mut Criterion) { &(key, leaf), |b, (key, leaf)| { b.iter(|| { - tree.update_leaf_at(black_box(LeafIndex::::new(*key).unwrap()), black_box(*leaf)); + tree.update_leaf(black_box(LeafIndex::::new(*key).unwrap()), black_box(*leaf)); }); }, ); diff --git a/benches/store.rs b/benches/store.rs index 9ee7e727..8856d670 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -450,7 +450,7 @@ fn update_leaf_simplesmt(c: &mut Criterion) { b.iter_batched( || (rand_value::() % size_u64, random_word()), |(index, value)| { - black_box(smt.update_leaf_at( + black_box(smt.update_leaf( LeafIndex::::new(index).unwrap(), value, )) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 5aa0357e..b85ae63c 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -88,7 +88,7 @@ impl SimpleSmt { return Err(MerkleError::InvalidNumEntries(max_num_entries)); } - let old_value = tree.update_leaf_at(LeafIndex::::new(key)?, value); + let old_value = tree.update_leaf(LeafIndex::::new(key)?, value); if old_value != EMPTY_VALUE || key_set_to_zero.contains(&key) { return Err(MerkleError::DuplicateValuesForIndex(key)); @@ -282,11 +282,11 @@ impl TryApplyDiff for SimpleSmt { } for slot in diff.cleared_slots() { - self.update_leaf_at(LeafIndex::::new(*slot)?, EMPTY_VALUE); + self.update_leaf(LeafIndex::::new(*slot)?, EMPTY_VALUE); } for (slot, value) in diff.updated_slots() { - self.update_leaf_at(LeafIndex::::new(*slot)?, *value); + self.update_leaf(LeafIndex::::new(*slot)?, *value); } Ok(()) diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 65c1667b..96de6d7d 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -52,7 +52,7 @@ fn build_sparse_tree() { let key = 6; let new_node = int_to_leaf(7); values[key as usize] = new_node; - let old_value = smt.update_leaf_at(LeafIndex::::new(key).unwrap(), new_node); + let old_value = smt.update_leaf(LeafIndex::::new(key).unwrap(), new_node); let mt2 = MerkleTree::new(values.clone()).unwrap(); assert_eq!(mt2.root(), smt.root()); assert_eq!( @@ -65,7 +65,7 @@ fn build_sparse_tree() { let key = 2; let new_node = int_to_leaf(3); values[key as usize] = new_node; - let old_value = smt.update_leaf_at(LeafIndex::::new(key).unwrap(), new_node); + let old_value = smt.update_leaf(LeafIndex::::new(key).unwrap(), new_node); let mt3 = MerkleTree::new(values).unwrap(); assert_eq!(mt3.root(), smt.root()); assert_eq!( @@ -156,7 +156,7 @@ fn update_leaf() { expected_values[key] = new_node; let expected_tree = MerkleTree::new(expected_values.clone()).unwrap(); - let old_leaf = tree.update_leaf_at(LeafIndex::::new(key as u64).unwrap(), new_node); + let old_leaf = tree.update_leaf(LeafIndex::::new(key as u64).unwrap(), new_node); assert_eq!(expected_tree.root(), tree.root); assert_eq!(old_leaf, *VALUES8[key]); @@ -166,7 +166,7 @@ fn update_leaf() { expected_values[key] = new_node; let expected_tree = MerkleTree::new(expected_values.clone()).unwrap(); - let old_leaf = tree.update_leaf_at(LeafIndex::::new(key as u64).unwrap(), new_node); + let old_leaf = tree.update_leaf(LeafIndex::::new(key as u64).unwrap(), new_node); assert_eq!(expected_tree.root(), tree.root); assert_eq!(old_leaf, *VALUES8[key]); } diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index c0e13a28..321fe122 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -61,7 +61,7 @@ pub trait SparseMerkleTree { /// Updates value of the leaf at the specified index returning the old leaf value. /// /// This also recomputes all hashes between the leaf and the root, updating the root itself. - fn update_leaf_at(&mut self, key: Self::Key, value: Self::Value) -> Self::Value { + fn update_leaf(&mut self, key: Self::Key, value: Self::Value) -> Self::Value { let old_value = self.insert_leaf_node(key.clone(), value.clone()).unwrap_or_default(); // if the old value and new value are the same, there is nothing to update From ae39832ebd0522cbb610e3596a3fa230f5a8d625 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 08:51:37 -0500 Subject: [PATCH 033/121] add comment --- src/merkle/simple_smt/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index b85ae63c..a1c74783 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -263,6 +263,7 @@ impl SparseMerkleTree for SimpleSmt { } fn hash_leaf(leaf: &Word) -> RpoDigest { + // `SimpleSmt` takes the leaf value itself as the hash leaf.into() } } From 78def63793371a7fd484516b12f5c3c790ab40f2 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 09:25:04 -0500 Subject: [PATCH 034/121] import `Vec` for `no_std` --- src/merkle/simple_smt/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index 96de6d7d..c9ac88d1 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -7,6 +7,7 @@ use crate::{ merkle::{ digests_to_words, int_to_leaf, int_to_node, EmptySubtreeRoots, LeafIndex, SparseMerkleTree, }, + utils::collections::Vec, Word, }; From 2d1ce1c2a507028863ff860b44a572c5f3e44868 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 09:26:25 -0500 Subject: [PATCH 035/121] fix docstring --- src/merkle/smt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 321fe122..226651bf 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -12,7 +12,7 @@ use super::{MerkleError, MerklePath, NodeIndex, Vec}; /// /// A sparse Merkle tree is a key-value map which also supports proving that a given value is indeed /// stored at a given key in the tree. It is viewed as always being fully populated. If a leaf's -/// value was not explicitly updated, then its value is the default value. Typically, the vast +/// value was not explicitly set, then its value is the default value. Typically, the vast /// majority of leaves will store the default value (hence it is "sparse"), and therefore the /// internal representation of the tree will only keep track of the leaves that have a different /// value from the default. From 52a4eb510b32ef7465e66eeb1eeb7c3289792d91 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 09:28:08 -0500 Subject: [PATCH 036/121] nightly fmt --- benches/store.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/benches/store.rs b/benches/store.rs index 8856d670..aca86e09 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -450,10 +450,12 @@ fn update_leaf_simplesmt(c: &mut Criterion) { b.iter_batched( || (rand_value::() % size_u64, random_word()), |(index, value)| { - black_box(smt.update_leaf( - LeafIndex::::new(index).unwrap(), - value, - )) + black_box( + smt.update_leaf( + LeafIndex::::new(index).unwrap(), + value, + ), + ) }, BatchSize::SmallInput, ) From 2e2288ff4839e6577bfe0e7ed04e03db62392b41 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 09:38:07 -0500 Subject: [PATCH 037/121] new_smt scaffolding --- src/merkle/mod.rs | 3 ++ src/merkle/new_smt/mod.rs | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/merkle/new_smt/mod.rs diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 64a11d4b..76fcfd1a 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -30,6 +30,9 @@ pub use simple_smt::{SimpleSmt, SIMPLE_SMT_MAX_DEPTH, SIMPLE_SMT_MIN_DEPTH}; mod smt; pub use smt::{InnerNode, LeafIndex, SparseMerkleTree}; +mod new_smt; +pub use new_smt::{NewSmt, NewSmtKey, NewSmtLeaf, NEW_SMT_DEPTH}; + mod tiered_smt; pub use tiered_smt::{TieredSmt, TieredSmtProof, TieredSmtProofError}; diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs new file mode 100644 index 00000000..186941d2 --- /dev/null +++ b/src/merkle/new_smt/mod.rs @@ -0,0 +1,65 @@ +use super::{BTreeMap, InnerNode, LeafIndex, NodeIndex, RpoDigest, SparseMerkleTree, Word}; + +pub const NEW_SMT_DEPTH: u8 = 64; + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct NewSmt { + root: RpoDigest, + leaves: BTreeMap, + inner_nodes: BTreeMap, +} + +impl SparseMerkleTree for NewSmt { + type Key = NewSmtKey; + + type Value = Word; + + type Leaf = NewSmtLeaf; + + fn root(&self) -> RpoDigest { + todo!() + } + + fn set_root(&mut self, root: RpoDigest) { + todo!() + } + + fn get_inner_node(&self, index: NodeIndex) -> InnerNode { + todo!() + } + + fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { + todo!() + } + + fn insert_leaf_node(&mut self, key: Self::Key, value: Self::Value) -> Option { + todo!() + } + + fn get_leaf(&self, key: &Self::Key) -> Self::Leaf { + todo!() + } + + fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest { + todo!() + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum NewSmtLeaf { + Single((u64, Word)), + Multiple(Vec<(u64, Word)>), +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct NewSmtKey { + word: Word, +} + +impl From for LeafIndex { + fn from(key: NewSmtKey) -> Self { + let most_significant_felt = key.word[0]; + Self::new_max_depth(most_significant_felt.inner()) + } +} From d26f387fdb8e2ec43416b8fd53136e5e40e7b9f6 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 10:00:38 -0500 Subject: [PATCH 038/121] implement `hash_leaf()` --- src/merkle/new_smt/mod.rs | 41 +++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index 186941d2..ca092eab 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -1,4 +1,9 @@ -use super::{BTreeMap, InnerNode, LeafIndex, NodeIndex, RpoDigest, SparseMerkleTree, Word}; +use crate::hash::rpo::Rpo256; +use crate::Felt; + +use super::{ + BTreeMap, EmptySubtreeRoots, InnerNode, LeafIndex, NodeIndex, RpoDigest, SparseMerkleTree, Word, +}; pub const NEW_SMT_DEPTH: u8 = 64; @@ -18,19 +23,23 @@ impl SparseMerkleTree for NewSmt { type Leaf = NewSmtLeaf; fn root(&self) -> RpoDigest { - todo!() + self.root } fn set_root(&mut self, root: RpoDigest) { - todo!() + self.root = root; } fn get_inner_node(&self, index: NodeIndex) -> InnerNode { - todo!() + self.inner_nodes.get(&index).cloned().unwrap_or_else(|| { + let node = EmptySubtreeRoots::entry(self.depth(), index.depth() + 1); + + InnerNode { left: *node, right: *node } + }) } fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { - todo!() + self.inner_nodes.insert(index, inner_node); } fn insert_leaf_node(&mut self, key: Self::Key, value: Self::Value) -> Option { @@ -42,7 +51,7 @@ impl SparseMerkleTree for NewSmt { } fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest { - todo!() + leaf.hash() } } @@ -52,6 +61,26 @@ pub enum NewSmtLeaf { Multiple(Vec<(u64, Word)>), } +impl NewSmtLeaf { + pub fn hash(&self) -> RpoDigest { + fn tuple_to_elements((key, value): &(u64, Word)) -> impl Iterator + '_ { + let key_ele = Felt::from(*key); + let value_eles = value.iter().copied(); + + std::iter::once(key_ele).chain(value_eles) + } + + let elements: Vec = match self { + NewSmtLeaf::Single(tuple) => tuple_to_elements(tuple).collect(), + NewSmtLeaf::Multiple(tuples) => { + tuples.into_iter().flat_map(tuple_to_elements).collect() + } + }; + + Rpo256::hash_elements(&elements) + } +} + #[derive(Clone, Copy, Debug, PartialEq)] pub struct NewSmtKey { word: Word, From a085e81a9f65667ea682bacf21f8ee5f884c05cf Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 10:09:17 -0500 Subject: [PATCH 039/121] implement `get_leaf()` --- src/merkle/new_smt/mod.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index ca092eab..a540dc54 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -11,7 +11,7 @@ pub const NEW_SMT_DEPTH: u8 = 64; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct NewSmt { root: RpoDigest, - leaves: BTreeMap, + leaves: BTreeMap, inner_nodes: BTreeMap, } @@ -47,7 +47,15 @@ impl SparseMerkleTree for NewSmt { } fn get_leaf(&self, key: &Self::Key) -> Self::Leaf { - todo!() + let leaf_pos = LeafIndex::::from(*key).value(); + + match self.leaves.get(&leaf_pos) { + Some(leaf) => leaf.clone(), + None => NewSmtLeaf::Single(( + leaf_pos, + Word::from(*EmptySubtreeRoots::entry(self.depth(), self.depth())), + )), + } } fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest { @@ -55,7 +63,8 @@ impl SparseMerkleTree for NewSmt { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum NewSmtLeaf { Single((u64, Word)), Multiple(Vec<(u64, Word)>), From b54ab12100977ee8a8140a3170c020eb430c8ce4 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 11:18:53 -0500 Subject: [PATCH 040/121] use `Vec` --- src/merkle/new_smt/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index a540dc54..cdda8196 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -1,4 +1,5 @@ use crate::hash::rpo::Rpo256; +use crate::utils::collections::Vec; use crate::Felt; use super::{ From 821f6edfe8c1972fc3ceb4a2d51f078b653a2a18 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 11:43:59 -0500 Subject: [PATCH 041/121] insert_leaf_node scaffold --- src/merkle/new_smt/mod.rs | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index cdda8196..cbfebe3c 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -44,7 +44,18 @@ impl SparseMerkleTree for NewSmt { } fn insert_leaf_node(&mut self, key: Self::Key, value: Self::Value) -> Option { - todo!() + let leaf_index: LeafIndex = key.into(); + match self.leaves.get(&leaf_index.value()) { + Some(leaf) => match leaf { + NewSmtLeaf::Single(kv_pair) => todo!(), + NewSmtLeaf::Multiple(_) => todo!(), + }, + None => { + self.leaves.insert(leaf_index.value(), NewSmtLeaf::Single((key.clone(), value))); + + Some(Self::Value::default()) + } + } } fn get_leaf(&self, key: &Self::Key) -> Self::Leaf { @@ -53,7 +64,7 @@ impl SparseMerkleTree for NewSmt { match self.leaves.get(&leaf_pos) { Some(leaf) => leaf.clone(), None => NewSmtLeaf::Single(( - leaf_pos, + key.clone(), Word::from(*EmptySubtreeRoots::entry(self.depth(), self.depth())), )), } @@ -67,31 +78,30 @@ impl SparseMerkleTree for NewSmt { #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum NewSmtLeaf { - Single((u64, Word)), - Multiple(Vec<(u64, Word)>), + Single((NewSmtKey, Word)), + Multiple(Vec<(NewSmtKey, Word)>), } impl NewSmtLeaf { pub fn hash(&self) -> RpoDigest { - fn tuple_to_elements((key, value): &(u64, Word)) -> impl Iterator + '_ { - let key_ele = Felt::from(*key); - let value_eles = value.iter().copied(); + fn kv_to_elements((key, value): &(NewSmtKey, Word)) -> impl Iterator + '_ { + let key_elements = key.word.iter().copied(); + let value_elements = value.iter().copied(); - std::iter::once(key_ele).chain(value_eles) + key_elements.chain(value_elements) } let elements: Vec = match self { - NewSmtLeaf::Single(tuple) => tuple_to_elements(tuple).collect(), - NewSmtLeaf::Multiple(tuples) => { - tuples.into_iter().flat_map(tuple_to_elements).collect() - } + NewSmtLeaf::Single(kv) => kv_to_elements(kv).collect(), + NewSmtLeaf::Multiple(kvs) => kvs.into_iter().flat_map(kv_to_elements).collect(), }; Rpo256::hash_elements(&elements) } } -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct NewSmtKey { word: Word, } From 316ebd8b522747ceda372c8bac69ed2ab00fdcd2 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 12:03:47 -0500 Subject: [PATCH 042/121] insert on leaf with single element --- src/merkle/new_smt/mod.rs | 53 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index cbfebe3c..8cd96301 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -1,3 +1,7 @@ +use core::cmp::Ordering; + +use winter_math::StarkField; + use crate::hash::rpo::Rpo256; use crate::utils::collections::Vec; use crate::Felt; @@ -45,9 +49,25 @@ impl SparseMerkleTree for NewSmt { fn insert_leaf_node(&mut self, key: Self::Key, value: Self::Value) -> Option { let leaf_index: LeafIndex = key.into(); - match self.leaves.get(&leaf_index.value()) { + match self.leaves.get_mut(&leaf_index.value()) { Some(leaf) => match leaf { - NewSmtLeaf::Single(kv_pair) => todo!(), + NewSmtLeaf::Single(kv_pair) => { + // if the key is already in this entry, update the value and return + if kv_pair.0 == key { + let old_value = kv_pair.1; + kv_pair.1 = value; + return Some(old_value); + } + + // transform the entry into a list entry, and make sure the key-value pairs + // are sorted by key + let mut pairs = vec![*kv_pair, (key, value)]; + pairs.sort_by(|pair_1, pair_2| cmp_pairs(*pair_1, *pair_2)); + + self.leaves.insert(leaf_index.value(), NewSmtLeaf::Multiple(pairs)); + + None + } NewSmtLeaf::Multiple(_) => todo!(), }, None => { @@ -112,3 +132,32 @@ impl From for LeafIndex { Self::new_max_depth(most_significant_felt.inner()) } } + +// HELPER FUNCTIONS +// ================================================================================================ + +/// Compares two (key-value) pairs, ordered first by keys, then values. +/// +/// Both keys and values are compared element-by-element using their integer representations +/// starting with the most significant element. +fn cmp_pairs((key_1, value_1): (NewSmtKey, Word), (key_2, value_2): (NewSmtKey, Word)) -> Ordering { + let key_order = cmp_words(key_1.word, key_2.word); + + if key_order != Ordering::Equal { + key_order + } else { + cmp_words(value_1, value_2) + } +} + +fn cmp_words(w1: Word, w2: Word) -> Ordering { + for (v1, v2) in w1.iter().zip(w2.iter()).rev() { + let v1 = v1.as_int(); + let v2 = v2.as_int(); + if v1 != v2 { + return v1.cmp(&v2); + } + } + + Ordering::Equal +} From d3cbfb17c14a98af9b6a4bfd56ce21b0c707ea64 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 12:10:48 -0500 Subject: [PATCH 043/121] cmp just keys --- src/merkle/new_smt/mod.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index 8cd96301..fe9d764c 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -62,7 +62,7 @@ impl SparseMerkleTree for NewSmt { // transform the entry into a list entry, and make sure the key-value pairs // are sorted by key let mut pairs = vec![*kv_pair, (key, value)]; - pairs.sort_by(|pair_1, pair_2| cmp_pairs(*pair_1, *pair_2)); + pairs.sort_by(|(key_1, _), (key_2, _)| cmp_keys(*key_1, *key_2)); self.leaves.insert(leaf_index.value(), NewSmtLeaf::Multiple(pairs)); @@ -136,22 +136,10 @@ impl From for LeafIndex { // HELPER FUNCTIONS // ================================================================================================ -/// Compares two (key-value) pairs, ordered first by keys, then values. -/// -/// Both keys and values are compared element-by-element using their integer representations -/// starting with the most significant element. -fn cmp_pairs((key_1, value_1): (NewSmtKey, Word), (key_2, value_2): (NewSmtKey, Word)) -> Ordering { - let key_order = cmp_words(key_1.word, key_2.word); - - if key_order != Ordering::Equal { - key_order - } else { - cmp_words(value_1, value_2) - } -} - -fn cmp_words(w1: Word, w2: Word) -> Ordering { - for (v1, v2) in w1.iter().zip(w2.iter()).rev() { +/// Compares two keys, compared element-by-element using their integer representations starting with +/// the most significant element. +fn cmp_keys(key_1: NewSmtKey, key_2: NewSmtKey) -> Ordering { + for (v1, v2) in key_1.word.iter().zip(key_2.word.iter()).rev() { let v1 = v1.as_int(); let v2 = v2.as_int(); if v1 != v2 { From 42ce148ff6929edc4d0cf0e2f4d909b02848e537 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 12:14:35 -0500 Subject: [PATCH 044/121] insert leaf: multiple --- src/merkle/new_smt/mod.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index fe9d764c..36d35e61 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -68,10 +68,24 @@ impl SparseMerkleTree for NewSmt { None } - NewSmtLeaf::Multiple(_) => todo!(), + NewSmtLeaf::Multiple(kv_pairs) => { + match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { + Ok(pos) => { + let old_value = kv_pairs[pos].1; + kv_pairs[pos].1 = value; + + Some(old_value) + } + Err(pos) => { + kv_pairs.insert(pos, (key, value)); + + None + } + } + } }, None => { - self.leaves.insert(leaf_index.value(), NewSmtLeaf::Single((key.clone(), value))); + self.leaves.insert(leaf_index.value(), NewSmtLeaf::Single((key, value))); Some(Self::Value::default()) } @@ -84,7 +98,7 @@ impl SparseMerkleTree for NewSmt { match self.leaves.get(&leaf_pos) { Some(leaf) => leaf.clone(), None => NewSmtLeaf::Single(( - key.clone(), + *key, Word::from(*EmptySubtreeRoots::entry(self.depth(), self.depth())), )), } @@ -113,7 +127,7 @@ impl NewSmtLeaf { let elements: Vec = match self { NewSmtLeaf::Single(kv) => kv_to_elements(kv).collect(), - NewSmtLeaf::Multiple(kvs) => kvs.into_iter().flat_map(kv_to_elements).collect(), + NewSmtLeaf::Multiple(kvs) => kvs.iter().flat_map(kv_to_elements).collect(), }; Rpo256::hash_elements(&elements) From 4a26c5be636558d2b06aebbf2692a849223a5af7 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 12:15:57 -0500 Subject: [PATCH 045/121] reorg file --- src/merkle/new_smt/mod.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index 36d35e61..16eebaf6 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -109,6 +109,25 @@ impl SparseMerkleTree for NewSmt { } } +// KEY +// ================================================================================================ + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct NewSmtKey { + word: Word, +} + +impl From for LeafIndex { + fn from(key: NewSmtKey) -> Self { + let most_significant_felt = key.word[0]; + Self::new_max_depth(most_significant_felt.inner()) + } +} + +// LEAF +// ================================================================================================ + #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum NewSmtLeaf { @@ -134,19 +153,6 @@ impl NewSmtLeaf { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct NewSmtKey { - word: Word, -} - -impl From for LeafIndex { - fn from(key: NewSmtKey) -> Self { - let most_significant_felt = key.word[0]; - Self::new_max_depth(most_significant_felt.inner()) - } -} - // HELPER FUNCTIONS // ================================================================================================ From a4c93f783d2f3be951dc8aa418c2df909b687dac Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 12:19:53 -0500 Subject: [PATCH 046/121] no_std vec --- src/merkle/new_smt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index 16eebaf6..ce7fc3be 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -3,7 +3,7 @@ use core::cmp::Ordering; use winter_math::StarkField; use crate::hash::rpo::Rpo256; -use crate::utils::collections::Vec; +use crate::utils::{collections::Vec, vec}; use crate::Felt; use super::{ From 410659329ee40de4f37eb186fe8c966179031657 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 13:54:19 -0500 Subject: [PATCH 047/121] rename `SMT_MAX_DEPTH` --- benches/store.rs | 22 +++++++++++----------- src/merkle/mod.rs | 2 +- src/merkle/simple_smt/mod.rs | 4 ++-- src/merkle/store/tests.rs | 14 +++++++------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/benches/store.rs b/benches/store.rs index aca86e09..1cca8bfc 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -1,7 +1,7 @@ use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; use miden_crypto::merkle::{ DefaultMerkleStore as MerkleStore, LeafIndex, MerkleTree, NodeIndex, SimpleSmt, - SparseMerkleTree, SIMPLE_SMT_MAX_DEPTH, + SparseMerkleTree, SMT_MAX_DEPTH, }; use miden_crypto::Word; use miden_crypto::{hash::rpo::RpoDigest, Felt}; @@ -31,7 +31,7 @@ fn random_index(range: u64, depth: u8) -> NodeIndex { fn get_empty_leaf_simplesmt(c: &mut Criterion) { let mut group = c.benchmark_group("get_empty_leaf_simplesmt"); - const DEPTH: u8 = SIMPLE_SMT_MAX_DEPTH; + const DEPTH: u8 = SMT_MAX_DEPTH; let size = u64::MAX; // both SMT and the store are pre-populated with empty hashes, accessing these values is what is @@ -107,7 +107,7 @@ fn get_leaf_simplesmt(c: &mut Criterion) { .enumerate() .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>(); - let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); + let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let store = MerkleStore::from(&smt); let depth = smt.depth(); let root = smt.root(); @@ -135,7 +135,7 @@ fn get_leaf_simplesmt(c: &mut Criterion) { fn get_node_of_empty_simplesmt(c: &mut Criterion) { let mut group = c.benchmark_group("get_node_of_empty_simplesmt"); - const DEPTH: u8 = SIMPLE_SMT_MAX_DEPTH; + const DEPTH: u8 = SMT_MAX_DEPTH; // both SMT and the store are pre-populated with the empty hashes, accessing the internal nodes // of these values is what is being benchmarked here, so no values are inserted into the @@ -215,7 +215,7 @@ fn get_node_simplesmt(c: &mut Criterion) { .enumerate() .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>(); - let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); + let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let store = MerkleStore::from(&smt); let root = smt.root(); let half_depth = smt.depth() / 2; @@ -289,7 +289,7 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { .enumerate() .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>(); - let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); + let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let store = MerkleStore::from(&smt); let depth = smt.depth(); let root = smt.root(); @@ -300,7 +300,7 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { || random_index(size_u64, depth), |index| { black_box(smt.get_leaf_path( - LeafIndex::::new(index.value()).unwrap(), + LeafIndex::::new(index.value()).unwrap(), )) }, BatchSize::SmallInput, @@ -359,7 +359,7 @@ fn new(c: &mut Criterion) { .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>() }, - |l| black_box(SimpleSmt::::with_leaves(l)), + |l| black_box(SimpleSmt::::with_leaves(l)), BatchSize::SmallInput, ) }); @@ -374,7 +374,7 @@ fn new(c: &mut Criterion) { .collect::>() }, |l| { - let smt = SimpleSmt::::with_leaves(l).unwrap(); + let smt = SimpleSmt::::with_leaves(l).unwrap(); black_box(MerkleStore::from(&smt)); }, BatchSize::SmallInput, @@ -440,7 +440,7 @@ fn update_leaf_simplesmt(c: &mut Criterion) { .enumerate() .map(|(c, v)| (c.try_into().unwrap(), v.into())) .collect::>(); - let mut smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); + let mut smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let mut store = MerkleStore::from(&smt); let depth = smt.depth(); let root = smt.root(); @@ -452,7 +452,7 @@ fn update_leaf_simplesmt(c: &mut Criterion) { |(index, value)| { black_box( smt.update_leaf( - LeafIndex::::new(index).unwrap(), + LeafIndex::::new(index).unwrap(), value, ), ) diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 76fcfd1a..4f63bb12 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -25,7 +25,7 @@ mod path; pub use path::{MerklePath, RootPath, ValuePath}; mod simple_smt; -pub use simple_smt::{SimpleSmt, SIMPLE_SMT_MAX_DEPTH, SIMPLE_SMT_MIN_DEPTH}; +pub use simple_smt::{SimpleSmt, SMT_MAX_DEPTH, SIMPLE_SMT_MIN_DEPTH}; mod smt; pub use smt::{InnerNode, LeafIndex, SparseMerkleTree}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index a1c74783..f4ba7a9a 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -13,7 +13,7 @@ mod tests; pub const SIMPLE_SMT_MIN_DEPTH: u8 = 1; /// Maximum supported depth. -pub const SIMPLE_SMT_MAX_DEPTH: u8 = 64; +pub const SMT_MAX_DEPTH: u8 = 64; /// Value of an empty leaf. pub const EMPTY_VALUE: Word = super::EMPTY_WORD; @@ -46,7 +46,7 @@ impl SimpleSmt { // validate the range of the depth. if DEPTH < SIMPLE_SMT_MIN_DEPTH { return Err(MerkleError::DepthTooSmall(DEPTH)); - } else if SIMPLE_SMT_MAX_DEPTH < DEPTH { + } else if SMT_MAX_DEPTH < DEPTH { return Err(MerkleError::DepthTooBig(DEPTH as u64)); } diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index ff4d6b56..e9582cfe 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -5,7 +5,7 @@ use super::{ use crate::{ merkle::{ digests_to_words, int_to_leaf, int_to_node, LeafIndex, MerkleTree, SimpleSmt, - SparseMerkleTree, SIMPLE_SMT_MAX_DEPTH, + SparseMerkleTree, SMT_MAX_DEPTH, }, Felt, Word, ONE, WORD_SIZE, ZERO, }; @@ -232,7 +232,7 @@ fn test_add_sparse_merkle_tree_one_level() -> Result<(), MerkleError> { #[test] fn test_sparse_merkle_tree() -> Result<(), MerkleError> { - let smt = SimpleSmt::::with_leaves( + let smt = SimpleSmt::::with_leaves( KEYS4.into_iter().zip(digests_to_words(&VALUES4)), ) .unwrap(); @@ -303,7 +303,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 0 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(0).unwrap()), + smt.get_leaf_path(LeafIndex::::new(0).unwrap()), result.path, "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" ); @@ -314,7 +314,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 1 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(1).unwrap()), + smt.get_leaf_path(LeafIndex::::new(1).unwrap()), result.path, "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" ); @@ -325,7 +325,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 2 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(2).unwrap()), + smt.get_leaf_path(LeafIndex::::new(2).unwrap()), result.path, "merkle path for index 2 must be the same for the MerkleTree and MerkleStore" ); @@ -336,7 +336,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 3 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(3).unwrap()), + smt.get_leaf_path(LeafIndex::::new(3).unwrap()), result.path, "merkle path for index 3 must be the same for the MerkleTree and MerkleStore" ); @@ -348,7 +348,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 4 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(4).unwrap()), + smt.get_leaf_path(LeafIndex::::new(4).unwrap()), result.path, "merkle path for index 4 must be the same for the MerkleTree and MerkleStore" ); From c4638f1f2202c6d8efd8827df68df175302dfcf6 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 13:56:31 -0500 Subject: [PATCH 048/121] use `SMT_MAX_DEPTH` --- src/merkle/mod.rs | 4 ++-- src/merkle/simple_smt/mod.rs | 5 +---- src/merkle/smt.rs | 12 +++++++++--- src/merkle/store/tests.rs | 7 +++---- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 4f63bb12..363ab7b1 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -25,10 +25,10 @@ mod path; pub use path::{MerklePath, RootPath, ValuePath}; mod simple_smt; -pub use simple_smt::{SimpleSmt, SMT_MAX_DEPTH, SIMPLE_SMT_MIN_DEPTH}; +pub use simple_smt::{SimpleSmt, SIMPLE_SMT_MIN_DEPTH}; mod smt; -pub use smt::{InnerNode, LeafIndex, SparseMerkleTree}; +pub use smt::{InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH}; mod new_smt; pub use new_smt::{NewSmt, NewSmtKey, NewSmtLeaf, NEW_SMT_DEPTH}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index f4ba7a9a..dbd0e011 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,6 +1,6 @@ use super::{ BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, - MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, Word, + MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, Word, smt::SMT_MAX_DEPTH, }; #[cfg(test)] @@ -12,9 +12,6 @@ mod tests; /// Minimum supported depth. pub const SIMPLE_SMT_MIN_DEPTH: u8 = 1; -/// Maximum supported depth. -pub const SMT_MAX_DEPTH: u8 = 64; - /// Value of an empty leaf. pub const EMPTY_VALUE: Word = super::EMPTY_WORD; diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 226651bf..a24b5b90 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -5,6 +5,12 @@ use crate::{ use super::{MerkleError, MerklePath, NodeIndex, Vec}; +// CONSTANTS +// ================================================================================================ + +/// Maximum supported depth. +pub const SMT_MAX_DEPTH: u8 = 64; + // SPARSE MERKLE TREE // ================================================================================================ @@ -165,10 +171,10 @@ impl LeafIndex { } } -impl LeafIndex<64> { +impl LeafIndex { pub fn new_max_depth(value: u64) -> Self { LeafIndex { - index: NodeIndex::new_unchecked(64, value), + index: NodeIndex::new_unchecked(SMT_MAX_DEPTH, value), } } } @@ -194,7 +200,7 @@ impl TryFrom for LeafIndex { } } -impl From for LeafIndex<64> { +impl From for LeafIndex { fn from(value: Word) -> Self { Self::new_max_depth(value[0].inner()) } diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index e9582cfe..b652dbec 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -232,10 +232,9 @@ fn test_add_sparse_merkle_tree_one_level() -> Result<(), MerkleError> { #[test] fn test_sparse_merkle_tree() -> Result<(), MerkleError> { - let smt = SimpleSmt::::with_leaves( - KEYS4.into_iter().zip(digests_to_words(&VALUES4)), - ) - .unwrap(); + let smt = + SimpleSmt::::with_leaves(KEYS4.into_iter().zip(digests_to_words(&VALUES4))) + .unwrap(); let store = MerkleStore::from(&smt); From 576ed4c4e4e1e53fab01a2a99108c8a9e46f8604 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 14:08:08 -0500 Subject: [PATCH 049/121] `SMT_MIN_DEPTH` --- src/merkle/mod.rs | 2 +- src/merkle/simple_smt/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 363ab7b1..ae0596fe 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -25,7 +25,7 @@ mod path; pub use path::{MerklePath, RootPath, ValuePath}; mod simple_smt; -pub use simple_smt::{SimpleSmt, SIMPLE_SMT_MIN_DEPTH}; +pub use simple_smt::{SimpleSmt, SMT_MIN_DEPTH}; mod smt; pub use smt::{InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index dbd0e011..75aa7fe8 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -10,7 +10,7 @@ mod tests; // ================================================================================================ /// Minimum supported depth. -pub const SIMPLE_SMT_MIN_DEPTH: u8 = 1; +pub const SMT_MIN_DEPTH: u8 = 1; /// Value of an empty leaf. pub const EMPTY_VALUE: Word = super::EMPTY_WORD; @@ -41,7 +41,7 @@ impl SimpleSmt { /// Returns an error if the depth is 0 or is greater than 64. pub fn new() -> Result { // validate the range of the depth. - if DEPTH < SIMPLE_SMT_MIN_DEPTH { + if DEPTH < SMT_MIN_DEPTH { return Err(MerkleError::DepthTooSmall(DEPTH)); } else if SMT_MAX_DEPTH < DEPTH { return Err(MerkleError::DepthTooBig(DEPTH as u64)); From 66701fe529b7af1399f9668cfc5ebd7fe42145b1 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 14:11:21 -0500 Subject: [PATCH 050/121] Enforce `SMT_MIN_DEPTH` in `LeafIndex` --- src/merkle/mod.rs | 4 ++-- src/merkle/simple_smt/mod.rs | 5 +---- src/merkle/smt.rs | 18 +++++++++++++----- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index ae0596fe..11119698 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -25,10 +25,10 @@ mod path; pub use path::{MerklePath, RootPath, ValuePath}; mod simple_smt; -pub use simple_smt::{SimpleSmt, SMT_MIN_DEPTH}; +pub use simple_smt::SimpleSmt; mod smt; -pub use smt::{InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH}; +pub use smt::{InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; mod new_smt; pub use new_smt::{NewSmt, NewSmtKey, NewSmtLeaf, NEW_SMT_DEPTH}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 75aa7fe8..03e1f472 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,6 +1,6 @@ use super::{ BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, - MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, Word, smt::SMT_MAX_DEPTH, + MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, Word, smt::SMT_MAX_DEPTH, SMT_MIN_DEPTH, }; #[cfg(test)] @@ -9,9 +9,6 @@ mod tests; // CONSTANTS // ================================================================================================ -/// Minimum supported depth. -pub const SMT_MIN_DEPTH: u8 = 1; - /// Value of an empty leaf. pub const EMPTY_VALUE: Word = super::EMPTY_WORD; diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index a24b5b90..545d9369 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -8,6 +8,9 @@ use super::{MerkleError, MerklePath, NodeIndex, Vec}; // CONSTANTS // ================================================================================================ +/// Minimum supported depth. +pub const SMT_MIN_DEPTH: u8 = 1; + /// Maximum supported depth. pub const SMT_MAX_DEPTH: u8 = 64; @@ -18,13 +21,14 @@ pub const SMT_MAX_DEPTH: u8 = 64; /// /// A sparse Merkle tree is a key-value map which also supports proving that a given value is indeed /// stored at a given key in the tree. It is viewed as always being fully populated. If a leaf's -/// value was not explicitly set, then its value is the default value. Typically, the vast -/// majority of leaves will store the default value (hence it is "sparse"), and therefore the -/// internal representation of the tree will only keep track of the leaves that have a different -/// value from the default. +/// value was not explicitly set, then its value is the default value. Typically, the vast majority +/// of leaves will store the default value (hence it is "sparse"), and therefore the internal +/// representation of the tree will only keep track of the leaves that have a different value from +/// the default. /// /// All leaves sit at the same depth. The deeper the tree, the more leaves it has; but also the -/// longer its proofs are - of exactly `log(depth)` size. +/// longer its proofs are - of exactly `log(depth)` size. A tree cannot have depth 0, since such a +/// tree is just a single value, and is probably a programming mistake. /// /// Every key value maps to one leaf. If there are as many keys as there are leaves, then /// [Self::Leaf] should be the same type as [Self::Value], as is the case with @@ -163,6 +167,10 @@ pub struct LeafIndex { impl LeafIndex { pub fn new(value: u64) -> Result { + if DEPTH < SMT_MIN_DEPTH { + return Err(MerkleError::DepthTooSmall(DEPTH)); + } + Ok(LeafIndex { index: NodeIndex::new(DEPTH, value)? }) } From 1a6a2595d7a3fa15dcc4b4dd41e1a3fd509393f6 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 14:13:12 -0500 Subject: [PATCH 051/121] nightly fmt --- benches/store.rs | 11 ++++------- src/merkle/simple_smt/mod.rs | 5 +++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/benches/store.rs b/benches/store.rs index 1cca8bfc..1981540e 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -299,9 +299,9 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { b.iter_batched( || random_index(size_u64, depth), |index| { - black_box(smt.get_leaf_path( - LeafIndex::::new(index.value()).unwrap(), - )) + black_box( + smt.get_leaf_path(LeafIndex::::new(index.value()).unwrap()), + ) }, BatchSize::SmallInput, ) @@ -451,10 +451,7 @@ fn update_leaf_simplesmt(c: &mut Criterion) { || (rand_value::() % size_u64, random_word()), |(index, value)| { black_box( - smt.update_leaf( - LeafIndex::::new(index).unwrap(), - value, - ), + smt.update_leaf(LeafIndex::::new(index).unwrap(), value), ) }, BatchSize::SmallInput, diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 03e1f472..e6a83443 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,6 +1,7 @@ use super::{ - BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, - MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, Word, smt::SMT_MAX_DEPTH, SMT_MIN_DEPTH, + smt::SMT_MAX_DEPTH, BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, + MerkleError, MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, + Word, SMT_MIN_DEPTH, }; #[cfg(test)] From 782217a1983322f8932b9c17df9ae539bc1a7514 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 14:15:23 -0500 Subject: [PATCH 052/121] `as_int` instead of `inner()` --- src/merkle/new_smt/mod.rs | 2 +- src/merkle/smt.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index ce7fc3be..c50ce95a 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -121,7 +121,7 @@ pub struct NewSmtKey { impl From for LeafIndex { fn from(key: NewSmtKey) -> Self { let most_significant_felt = key.word[0]; - Self::new_max_depth(most_significant_felt.inner()) + Self::new_max_depth(most_significant_felt.as_int()) } } diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index 545d9369..aa349748 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -1,3 +1,5 @@ +use winter_math::StarkField; + use crate::{ hash::rpo::{Rpo256, RpoDigest}, Word, @@ -210,6 +212,6 @@ impl TryFrom for LeafIndex { impl From for LeafIndex { fn from(value: Word) -> Self { - Self::new_max_depth(value[0].inner()) + Self::new_max_depth(value[0].as_int()) } } From 08b5604e04107615113f8dd240d7e8c97dc2f82e Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 14:23:36 -0500 Subject: [PATCH 053/121] rename `insert_leaf_node` --- src/merkle/new_smt/mod.rs | 2 +- src/merkle/simple_smt/mod.rs | 2 +- src/merkle/smt.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index c50ce95a..8e143956 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -47,7 +47,7 @@ impl SparseMerkleTree for NewSmt { self.inner_nodes.insert(index, inner_node); } - fn insert_leaf_node(&mut self, key: Self::Key, value: Self::Value) -> Option { + fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option { let leaf_index: LeafIndex = key.into(); match self.leaves.get_mut(&leaf_index.value()) { Some(leaf) => match leaf { diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index e6a83443..a09ad33d 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -242,7 +242,7 @@ impl SparseMerkleTree for SimpleSmt { self.inner_nodes.insert(index, inner_node); } - fn insert_leaf_node(&mut self, key: LeafIndex, value: Word) -> Option { + fn insert_value(&mut self, key: LeafIndex, value: Word) -> Option { self.leaves.insert(key.value(), value) } diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index aa349748..c9e67b2f 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -74,7 +74,7 @@ pub trait SparseMerkleTree { /// /// This also recomputes all hashes between the leaf and the root, updating the root itself. fn update_leaf(&mut self, key: Self::Key, value: Self::Value) -> Self::Value { - let old_value = self.insert_leaf_node(key.clone(), value.clone()).unwrap_or_default(); + let old_value = self.insert_value(key.clone(), value.clone()).unwrap_or_default(); // if the old value and new value are the same, there is nothing to update if value == old_value { @@ -132,7 +132,7 @@ pub trait SparseMerkleTree { fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode); /// Inserts a leaf node, and returns the value at the key if already exists - fn insert_leaf_node(&mut self, key: Self::Key, value: Self::Value) -> Option; + fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option; /// Returns the leaf at the specified index. fn get_leaf(&self, key: &Self::Key) -> Self::Leaf; From efeaa757ad4572cd1f3c7661eee8c657cd72942f Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 14:33:06 -0500 Subject: [PATCH 054/121] add tests mod --- src/merkle/new_smt/mod.rs | 9 +++++++++ src/merkle/new_smt/tests.rs | 0 2 files changed, 9 insertions(+) create mode 100644 src/merkle/new_smt/tests.rs diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index 8e143956..d7ea41ba 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -10,8 +10,17 @@ use super::{ BTreeMap, EmptySubtreeRoots, InnerNode, LeafIndex, NodeIndex, RpoDigest, SparseMerkleTree, Word, }; +#[cfg(test)] +mod tests; + +// CONSTANTS +// ================================================================================================ + pub const NEW_SMT_DEPTH: u8 = 64; +// SMT +// ================================================================================================ + #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct NewSmt { diff --git a/src/merkle/new_smt/tests.rs b/src/merkle/new_smt/tests.rs new file mode 100644 index 00000000..e69de29b From dbb3d8495a5fa5f7c8892a76d859aed12f88bba2 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 14:40:42 -0500 Subject: [PATCH 055/121] most signifcant felt: last felt of word --- src/merkle/smt.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/merkle/smt.rs b/src/merkle/smt.rs index c9e67b2f..5b72c2ca 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/smt.rs @@ -212,6 +212,7 @@ impl TryFrom for LeafIndex { impl From for LeafIndex { fn from(value: Word) -> Self { - Self::new_max_depth(value[0].as_int()) + // We use the most significant `Felt` of a `Word` as the leaf index. + Self::new_max_depth(value[3].as_int()) } } From edb17cb9d5d466d027710efb02c590c71d0cd7b3 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 14:47:01 -0500 Subject: [PATCH 056/121] fix comments --- src/merkle/simple_smt/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index a09ad33d..9eaabd91 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -31,12 +31,12 @@ impl SimpleSmt { // CONSTRUCTORS // -------------------------------------------------------------------------------------------- - /// Returns a new [SimpleSmt] instantiated with the specified depth. + /// Returns a new [SimpleSmt]. /// /// All leaves in the returned tree are set to [ZERO; 4]. /// /// # Errors - /// Returns an error if the depth is 0 or is greater than 64. + /// Returns an error if [DEPTH] is 0 or is greater than 64. pub fn new() -> Result { // validate the range of the depth. if DEPTH < SMT_MIN_DEPTH { @@ -54,8 +54,7 @@ impl SimpleSmt { }) } - /// Returns a new [SimpleSmt] instantiated with the specified depth and with leaves - /// set as specified by the provided entries. + /// Returns a new [SimpleSmt] instantiated with leaves set as specified by the provided entries. /// /// All leaves omitted from the entries list are set to [ZERO; 4]. /// From 9fab7d600c0836b8ddb8a1fb881830cf040d6d80 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 14:49:27 -0500 Subject: [PATCH 057/121] `NewSmt` constructor --- src/merkle/new_smt/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index d7ea41ba..2443a005 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -29,6 +29,21 @@ pub struct NewSmt { inner_nodes: BTreeMap, } +impl NewSmt { + /// Returns a new [NewSmt]. + /// + /// All leaves in the returned tree are set to [ZERO; 4]. + pub fn new() -> Self { + let root = *EmptySubtreeRoots::entry(NEW_SMT_DEPTH, 0); + + Self { + root, + leaves: BTreeMap::new(), + inner_nodes: BTreeMap::new(), + } + } +} + impl SparseMerkleTree for NewSmt { type Key = NewSmtKey; From 007d56211f58221a754491177bfc3bf41269d536 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Thu, 11 Jan 2024 15:14:23 -0500 Subject: [PATCH 058/121] fix comment --- src/merkle/new_smt/mod.rs | 81 ++++++++++++++++++++++++++++++++++++- src/merkle/new_smt/tests.rs | 1 + 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index 2443a005..fa6a1e43 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -4,10 +4,11 @@ use winter_math::StarkField; use crate::hash::rpo::Rpo256; use crate::utils::{collections::Vec, vec}; -use crate::Felt; +use crate::{Felt, EMPTY_WORD}; use super::{ - BTreeMap, EmptySubtreeRoots, InnerNode, LeafIndex, NodeIndex, RpoDigest, SparseMerkleTree, Word, + BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, LeafIndex, MerkleError, NodeIndex, RpoDigest, + SparseMerkleTree, Word, }; #[cfg(test)] @@ -42,6 +43,48 @@ impl NewSmt { inner_nodes: BTreeMap::new(), } } + + /// Returns a new [SimpleSmt] instantiated with leaves set as specified by the provided entries. + /// + /// All leaves omitted from the entries list are set to [ZERO; 4]. + /// + /// # Errors + /// Returns an error if: + /// - The number of entries exceeds 2^63 entries. + /// - The provided entries contain multiple values for the same key. + pub fn with_entries( + entries: impl IntoIterator, + ) -> Result { + // create an empty tree + let mut tree = Self::new(); + + // compute the max number of entries. We use an upper bound of depth 63 because we consider + // passing in a vector of size 2^64 infeasible. + let max_num_entries = 2_usize.pow(tree.depth().min(63).into()); + + // This being a sparse data structure, the EMPTY_WORD is not assigned to the `BTreeMap`, so + // entries with the empty value need additional tracking. + let mut key_set_to_zero = BTreeSet::new(); + + for (idx, (key, value)) in entries.into_iter().enumerate() { + if idx >= max_num_entries { + return Err(MerkleError::InvalidNumEntries(max_num_entries)); + } + + let old_value = tree.update_leaf(key, value); + + if old_value != EMPTY_WORD || key_set_to_zero.contains(&key) { + return Err(MerkleError::DuplicateValuesForIndex( + LeafIndex::::from(key).value(), + )); + } + + if value == EMPTY_WORD { + key_set_to_zero.insert(key); + }; + } + Ok(tree) + } } impl SparseMerkleTree for NewSmt { @@ -133,6 +176,12 @@ impl SparseMerkleTree for NewSmt { } } +impl Default for NewSmt { + fn default() -> Self { + Self::new() + } +} + // KEY // ================================================================================================ @@ -149,6 +198,34 @@ impl From for LeafIndex { } } +impl Ord for NewSmtKey { + fn cmp(&self, other: &Self) -> Ordering { + // Note that the indices are reversed. This is because a `Word` is treated as little-endian + // (i.e. most significant Felt is at index 3). In comparing integer arrays, we want to + // compare the most significant felts first, and so on until the least signifcant felt. + let self_word: [u64; 4] = [ + self.word[3].as_int(), + self.word[2].as_int(), + self.word[1].as_int(), + self.word[0].as_int(), + ]; + let other_word: [u64; 4] = [ + other.word[3].as_int(), + other.word[2].as_int(), + other.word[1].as_int(), + other.word[0].as_int(), + ]; + + self_word.cmp(&other_word) + } +} + +impl PartialOrd for NewSmtKey { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + // LEAF // ================================================================================================ diff --git a/src/merkle/new_smt/tests.rs b/src/merkle/new_smt/tests.rs index e69de29b..8b137891 100644 --- a/src/merkle/new_smt/tests.rs +++ b/src/merkle/new_smt/tests.rs @@ -0,0 +1 @@ + From 2565b220839d0d4383c05e40cd098efcaf315823 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 08:26:23 -0500 Subject: [PATCH 059/121] Remove `max_num_entries` in `NewSmt` --- src/merkle/new_smt/mod.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index fa6a1e43..3216ea3f 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -58,19 +58,11 @@ impl NewSmt { // create an empty tree let mut tree = Self::new(); - // compute the max number of entries. We use an upper bound of depth 63 because we consider - // passing in a vector of size 2^64 infeasible. - let max_num_entries = 2_usize.pow(tree.depth().min(63).into()); - // This being a sparse data structure, the EMPTY_WORD is not assigned to the `BTreeMap`, so // entries with the empty value need additional tracking. let mut key_set_to_zero = BTreeSet::new(); - for (idx, (key, value)) in entries.into_iter().enumerate() { - if idx >= max_num_entries { - return Err(MerkleError::InvalidNumEntries(max_num_entries)); - } - + for (key, value) in entries { let old_value = tree.update_leaf(key, value); if old_value != EMPTY_WORD || key_set_to_zero.contains(&key) { From ede3c72e7fb6d7a49d1b1336912ab5d0b57bdf13 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 08:33:23 -0500 Subject: [PATCH 060/121] Rename `NewSmt` to `Smt` --- src/merkle/mod.rs | 2 +- src/merkle/new_smt/mod.rs | 62 +++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 11119698..51d1ca90 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -31,7 +31,7 @@ mod smt; pub use smt::{InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; mod new_smt; -pub use new_smt::{NewSmt, NewSmtKey, NewSmtLeaf, NEW_SMT_DEPTH}; +pub use new_smt::{Smt, SmtKey, SmtLeaf, SMT_DEPTH}; mod tiered_smt; pub use tiered_smt::{TieredSmt, TieredSmtProof, TieredSmtProofError}; diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/new_smt/mod.rs index 3216ea3f..9f407068 100644 --- a/src/merkle/new_smt/mod.rs +++ b/src/merkle/new_smt/mod.rs @@ -17,25 +17,25 @@ mod tests; // CONSTANTS // ================================================================================================ -pub const NEW_SMT_DEPTH: u8 = 64; +pub const SMT_DEPTH: u8 = 64; // SMT // ================================================================================================ #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct NewSmt { +pub struct Smt { root: RpoDigest, - leaves: BTreeMap, + leaves: BTreeMap, inner_nodes: BTreeMap, } -impl NewSmt { +impl Smt { /// Returns a new [NewSmt]. /// /// All leaves in the returned tree are set to [ZERO; 4]. pub fn new() -> Self { - let root = *EmptySubtreeRoots::entry(NEW_SMT_DEPTH, 0); + let root = *EmptySubtreeRoots::entry(SMT_DEPTH, 0); Self { root, @@ -53,7 +53,7 @@ impl NewSmt { /// - The number of entries exceeds 2^63 entries. /// - The provided entries contain multiple values for the same key. pub fn with_entries( - entries: impl IntoIterator, + entries: impl IntoIterator, ) -> Result { // create an empty tree let mut tree = Self::new(); @@ -67,7 +67,7 @@ impl NewSmt { if old_value != EMPTY_WORD || key_set_to_zero.contains(&key) { return Err(MerkleError::DuplicateValuesForIndex( - LeafIndex::::from(key).value(), + LeafIndex::::from(key).value(), )); } @@ -79,12 +79,12 @@ impl NewSmt { } } -impl SparseMerkleTree for NewSmt { - type Key = NewSmtKey; +impl SparseMerkleTree for Smt { + type Key = SmtKey; type Value = Word; - type Leaf = NewSmtLeaf; + type Leaf = SmtLeaf; fn root(&self) -> RpoDigest { self.root @@ -107,10 +107,10 @@ impl SparseMerkleTree for NewSmt { } fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option { - let leaf_index: LeafIndex = key.into(); + let leaf_index: LeafIndex = key.into(); match self.leaves.get_mut(&leaf_index.value()) { Some(leaf) => match leaf { - NewSmtLeaf::Single(kv_pair) => { + SmtLeaf::Single(kv_pair) => { // if the key is already in this entry, update the value and return if kv_pair.0 == key { let old_value = kv_pair.1; @@ -123,11 +123,11 @@ impl SparseMerkleTree for NewSmt { let mut pairs = vec![*kv_pair, (key, value)]; pairs.sort_by(|(key_1, _), (key_2, _)| cmp_keys(*key_1, *key_2)); - self.leaves.insert(leaf_index.value(), NewSmtLeaf::Multiple(pairs)); + self.leaves.insert(leaf_index.value(), SmtLeaf::Multiple(pairs)); None } - NewSmtLeaf::Multiple(kv_pairs) => { + SmtLeaf::Multiple(kv_pairs) => { match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { Ok(pos) => { let old_value = kv_pairs[pos].1; @@ -144,7 +144,7 @@ impl SparseMerkleTree for NewSmt { } }, None => { - self.leaves.insert(leaf_index.value(), NewSmtLeaf::Single((key, value))); + self.leaves.insert(leaf_index.value(), SmtLeaf::Single((key, value))); Some(Self::Value::default()) } @@ -152,11 +152,11 @@ impl SparseMerkleTree for NewSmt { } fn get_leaf(&self, key: &Self::Key) -> Self::Leaf { - let leaf_pos = LeafIndex::::from(*key).value(); + let leaf_pos = LeafIndex::::from(*key).value(); match self.leaves.get(&leaf_pos) { Some(leaf) => leaf.clone(), - None => NewSmtLeaf::Single(( + None => SmtLeaf::Single(( *key, Word::from(*EmptySubtreeRoots::entry(self.depth(), self.depth())), )), @@ -168,7 +168,7 @@ impl SparseMerkleTree for NewSmt { } } -impl Default for NewSmt { +impl Default for Smt { fn default() -> Self { Self::new() } @@ -179,18 +179,18 @@ impl Default for NewSmt { #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct NewSmtKey { +pub struct SmtKey { word: Word, } -impl From for LeafIndex { - fn from(key: NewSmtKey) -> Self { +impl From for LeafIndex { + fn from(key: SmtKey) -> Self { let most_significant_felt = key.word[0]; Self::new_max_depth(most_significant_felt.as_int()) } } -impl Ord for NewSmtKey { +impl Ord for SmtKey { fn cmp(&self, other: &Self) -> Ordering { // Note that the indices are reversed. This is because a `Word` is treated as little-endian // (i.e. most significant Felt is at index 3). In comparing integer arrays, we want to @@ -212,7 +212,7 @@ impl Ord for NewSmtKey { } } -impl PartialOrd for NewSmtKey { +impl PartialOrd for SmtKey { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } @@ -223,14 +223,14 @@ impl PartialOrd for NewSmtKey { #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub enum NewSmtLeaf { - Single((NewSmtKey, Word)), - Multiple(Vec<(NewSmtKey, Word)>), +pub enum SmtLeaf { + Single((SmtKey, Word)), + Multiple(Vec<(SmtKey, Word)>), } -impl NewSmtLeaf { +impl SmtLeaf { pub fn hash(&self) -> RpoDigest { - fn kv_to_elements((key, value): &(NewSmtKey, Word)) -> impl Iterator + '_ { + fn kv_to_elements((key, value): &(SmtKey, Word)) -> impl Iterator + '_ { let key_elements = key.word.iter().copied(); let value_elements = value.iter().copied(); @@ -238,8 +238,8 @@ impl NewSmtLeaf { } let elements: Vec = match self { - NewSmtLeaf::Single(kv) => kv_to_elements(kv).collect(), - NewSmtLeaf::Multiple(kvs) => kvs.iter().flat_map(kv_to_elements).collect(), + SmtLeaf::Single(kv) => kv_to_elements(kv).collect(), + SmtLeaf::Multiple(kvs) => kvs.iter().flat_map(kv_to_elements).collect(), }; Rpo256::hash_elements(&elements) @@ -251,7 +251,7 @@ impl NewSmtLeaf { /// Compares two keys, compared element-by-element using their integer representations starting with /// the most significant element. -fn cmp_keys(key_1: NewSmtKey, key_2: NewSmtKey) -> Ordering { +fn cmp_keys(key_1: SmtKey, key_2: SmtKey) -> Ordering { for (v1, v2) in key_1.word.iter().zip(key_2.word.iter()).rev() { let v1 = v1.as_int(); let v2 = v2.as_int(); From dc925b6c6fdf0ec7972eba88a32f1b4f06d222eb Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 08:40:10 -0500 Subject: [PATCH 061/121] Rename `NewSmt` to `Smt`, and `smt` module to `sparse_merkle_tree` --- src/merkle/mod.rs | 8 ++++---- src/merkle/simple_smt/mod.rs | 2 +- src/merkle/{new_smt => smt}/mod.rs | 0 src/merkle/{new_smt => smt}/tests.rs | 0 src/merkle/{smt.rs => sparse_merkle_tree.rs} | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) rename src/merkle/{new_smt => smt}/mod.rs (100%) rename src/merkle/{new_smt => smt}/tests.rs (100%) rename src/merkle/{smt.rs => sparse_merkle_tree.rs} (98%) diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 51d1ca90..93a97002 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -27,11 +27,11 @@ pub use path::{MerklePath, RootPath, ValuePath}; mod simple_smt; pub use simple_smt::SimpleSmt; -mod smt; -pub use smt::{InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; +mod sparse_merkle_tree; +pub use sparse_merkle_tree::{InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; -mod new_smt; -pub use new_smt::{Smt, SmtKey, SmtLeaf, SMT_DEPTH}; +mod smt; +pub use smt::{Smt, SmtKey, SmtLeaf, SMT_DEPTH}; mod tiered_smt; pub use tiered_smt::{TieredSmt, TieredSmtProof, TieredSmtProofError}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 9eaabd91..8168736c 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,5 +1,5 @@ use super::{ - smt::SMT_MAX_DEPTH, BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, + sparse_merkle_tree::SMT_MAX_DEPTH, BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, Word, SMT_MIN_DEPTH, }; diff --git a/src/merkle/new_smt/mod.rs b/src/merkle/smt/mod.rs similarity index 100% rename from src/merkle/new_smt/mod.rs rename to src/merkle/smt/mod.rs diff --git a/src/merkle/new_smt/tests.rs b/src/merkle/smt/tests.rs similarity index 100% rename from src/merkle/new_smt/tests.rs rename to src/merkle/smt/tests.rs diff --git a/src/merkle/smt.rs b/src/merkle/sparse_merkle_tree.rs similarity index 98% rename from src/merkle/smt.rs rename to src/merkle/sparse_merkle_tree.rs index 5b72c2ca..baa8ba94 100644 --- a/src/merkle/smt.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -32,7 +32,7 @@ pub const SMT_MAX_DEPTH: u8 = 64; /// longer its proofs are - of exactly `log(depth)` size. A tree cannot have depth 0, since such a /// tree is just a single value, and is probably a programming mistake. /// -/// Every key value maps to one leaf. If there are as many keys as there are leaves, then +/// Every key maps to one leaf. If there are as many keys as there are leaves, then /// [Self::Leaf] should be the same type as [Self::Value], as is the case with /// [crate::merkle::SimpleSmt]. However, if there are more keys than leaves, then [`Self::Leaf`] /// must accomodate all keys that map to the same leaf. From c254af267bd7417bc4747c4437488d8fad3e158b Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 08:46:56 -0500 Subject: [PATCH 062/121] Replace `Value`'s `Default` trait bound with `EMPTY_VALUE` associated constant --- src/merkle/simple_smt/mod.rs | 10 +++++++--- src/merkle/smt/mod.rs | 4 ++-- src/merkle/sparse_merkle_tree.rs | 7 +++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 8168736c..80e75b6b 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,7 +1,9 @@ +use crate::EMPTY_WORD; + use super::{ - sparse_merkle_tree::SMT_MAX_DEPTH, BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, - MerkleError, MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, StoreNode, TryApplyDiff, - Word, SMT_MIN_DEPTH, + sparse_merkle_tree::SMT_MAX_DEPTH, BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, + InnerNodeInfo, LeafIndex, MerkleError, MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, + StoreNode, TryApplyDiff, Word, SMT_MIN_DEPTH, }; #[cfg(test)] @@ -221,6 +223,8 @@ impl SparseMerkleTree for SimpleSmt { type Value = Word; type Leaf = Word; + const EMPTY_VALUE: Self::Value = EMPTY_WORD; + fn root(&self) -> RpoDigest { self.root } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 9f407068..069613b2 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -81,11 +81,11 @@ impl Smt { impl SparseMerkleTree for Smt { type Key = SmtKey; - type Value = Word; - type Leaf = SmtLeaf; + const EMPTY_VALUE: Self::Value = EMPTY_WORD; + fn root(&self) -> RpoDigest { self.root } diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index baa8ba94..9cf87035 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -42,10 +42,13 @@ pub trait SparseMerkleTree { /// The type for a key, which must be convertible into a `u64` infaillibly type Key: Into> + Clone; /// The type for a value - type Value: Clone + Default + PartialEq; + type Value: Clone + PartialEq; /// The type for a leaf type Leaf; + /// The default value used to compute the hash of empty leaves + const EMPTY_VALUE: Self::Value; + // PROVIDED METHODS // --------------------------------------------------------------------------------------------- @@ -74,7 +77,7 @@ pub trait SparseMerkleTree { /// /// This also recomputes all hashes between the leaf and the root, updating the root itself. fn update_leaf(&mut self, key: Self::Key, value: Self::Value) -> Self::Value { - let old_value = self.insert_value(key.clone(), value.clone()).unwrap_or_default(); + let old_value = self.insert_value(key.clone(), value.clone()).unwrap_or(Self::EMPTY_VALUE); // if the old value and new value are the same, there is nothing to update if value == old_value { From 9c9f246bc78fe2fe4258b0c003bc0b0a5ac39f62 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 08:47:45 -0500 Subject: [PATCH 063/121] remove `SimpleSmt`'s `EMPTY_VALUE` constant --- src/merkle/mod.rs | 4 +++- src/merkle/simple_smt/mod.rs | 12 +++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 93a97002..36b5b37f 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -28,7 +28,9 @@ mod simple_smt; pub use simple_smt::SimpleSmt; mod sparse_merkle_tree; -pub use sparse_merkle_tree::{InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; +pub use sparse_merkle_tree::{ + InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH, SMT_MIN_DEPTH, +}; mod smt; pub use smt::{Smt, SmtKey, SmtLeaf, SMT_DEPTH}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 80e75b6b..056e0bb1 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -9,12 +9,6 @@ use super::{ #[cfg(test)] mod tests; -// CONSTANTS -// ================================================================================================ - -/// Value of an empty leaf. -pub const EMPTY_VALUE: Word = super::EMPTY_WORD; - // SPARSE MERKLE TREE // ================================================================================================ @@ -86,11 +80,11 @@ impl SimpleSmt { let old_value = tree.update_leaf(LeafIndex::::new(key)?, value); - if old_value != EMPTY_VALUE || key_set_to_zero.contains(&key) { + if old_value != Self::EMPTY_VALUE || key_set_to_zero.contains(&key) { return Err(MerkleError::DuplicateValuesForIndex(key)); } - if value == EMPTY_VALUE { + if value == Self::EMPTY_VALUE { key_set_to_zero.insert(key); }; } @@ -281,7 +275,7 @@ impl TryApplyDiff for SimpleSmt { } for slot in diff.cleared_slots() { - self.update_leaf(LeafIndex::::new(*slot)?, EMPTY_VALUE); + self.update_leaf(LeafIndex::::new(*slot)?, Self::EMPTY_VALUE); } for (slot, value) in diff.updated_slots() { From c97e9da36e6feb13bf5bfb4e5719809b1d8c737f Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 08:48:29 -0500 Subject: [PATCH 064/121] ABSTRACT -> PROVIDED --- src/merkle/sparse_merkle_tree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index 9cf87035..41efa563 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -119,7 +119,7 @@ pub trait SparseMerkleTree { DEPTH } - // ABSTRACT METHODS + // REQUIRED METHODS // --------------------------------------------------------------------------------------------- /// The root of the tree From 42b6b28412ccf86108309ae12bc72c3d2968ac5c Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 08:58:28 -0500 Subject: [PATCH 065/121] remove `depth()` method --- src/merkle/smt/mod.rs | 9 ++++----- src/merkle/sparse_merkle_tree.rs | 5 ----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 069613b2..5e047f36 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -96,7 +96,7 @@ impl SparseMerkleTree for Smt { fn get_inner_node(&self, index: NodeIndex) -> InnerNode { self.inner_nodes.get(&index).cloned().unwrap_or_else(|| { - let node = EmptySubtreeRoots::entry(self.depth(), index.depth() + 1); + let node = EmptySubtreeRoots::entry(SMT_DEPTH, index.depth() + 1); InnerNode { left: *node, right: *node } }) @@ -156,10 +156,9 @@ impl SparseMerkleTree for Smt { match self.leaves.get(&leaf_pos) { Some(leaf) => leaf.clone(), - None => SmtLeaf::Single(( - *key, - Word::from(*EmptySubtreeRoots::entry(self.depth(), self.depth())), - )), + None => { + SmtLeaf::Single((*key, Word::from(*EmptySubtreeRoots::entry(SMT_DEPTH, SMT_DEPTH)))) + } } } diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index 41efa563..237e18af 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -114,11 +114,6 @@ pub trait SparseMerkleTree { self.set_root(value); } - /// Returns the depth of the sparse Merkle tree - fn depth(&self) -> u8 { - DEPTH - } - // REQUIRED METHODS // --------------------------------------------------------------------------------------------- From cf46c91a56159d7309b17bc30f05da87cccfde21 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 09:08:43 -0500 Subject: [PATCH 066/121] `SmtKey`: use `RpoDigest` internally --- src/merkle/smt/mod.rs | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 5e047f36..47c19b35 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -173,13 +173,17 @@ impl Default for Smt { } } -// KEY +// SMT KEY // ================================================================================================ -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +/// Represents a key (256 bits) for the Smt. +/// +/// The most significant `u64` determines the corresponding leaf index when inserting values into +/// the Smt. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct SmtKey { - word: Word, + word: RpoDigest, } impl From for LeafIndex { @@ -189,34 +193,6 @@ impl From for LeafIndex { } } -impl Ord for SmtKey { - fn cmp(&self, other: &Self) -> Ordering { - // Note that the indices are reversed. This is because a `Word` is treated as little-endian - // (i.e. most significant Felt is at index 3). In comparing integer arrays, we want to - // compare the most significant felts first, and so on until the least signifcant felt. - let self_word: [u64; 4] = [ - self.word[3].as_int(), - self.word[2].as_int(), - self.word[1].as_int(), - self.word[0].as_int(), - ]; - let other_word: [u64; 4] = [ - other.word[3].as_int(), - other.word[2].as_int(), - other.word[1].as_int(), - other.word[0].as_int(), - ]; - - self_word.cmp(&other_word) - } -} - -impl PartialOrd for SmtKey { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - // LEAF // ================================================================================================ From 293558f178ff47761ec822fe5622fd5652d15dc1 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 09:10:06 -0500 Subject: [PATCH 067/121] add constructors to `SmtKey` --- src/merkle/smt/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 47c19b35..6eb86afe 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -193,6 +193,18 @@ impl From for LeafIndex { } } +impl From for SmtKey { + fn from(digest: RpoDigest) -> Self { + Self { word: digest } + } +} + +impl From for SmtKey { + fn from(word: Word) -> Self { + Self { word: word.into() } + } +} + // LEAF // ================================================================================================ From e161bfa47ca0a44e8a10330ab76a0d59e0ebccc7 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 09:24:37 -0500 Subject: [PATCH 068/121] optimize `SmtLeaf::hash()` --- src/merkle/smt/mod.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 6eb86afe..32764b69 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -224,12 +224,13 @@ impl SmtLeaf { key_elements.chain(value_elements) } - let elements: Vec = match self { - SmtLeaf::Single(kv) => kv_to_elements(kv).collect(), - SmtLeaf::Multiple(kvs) => kvs.iter().flat_map(kv_to_elements).collect(), - }; - - Rpo256::hash_elements(&elements) + match self { + SmtLeaf::Single((key, value)) => Rpo256::merge(&[key.word.into(), value.into()]), + SmtLeaf::Multiple(kvs) => { + let elements: Vec = kvs.iter().flat_map(kv_to_elements).collect(); + Rpo256::hash_elements(&elements) + } + } } } From 4a33f787bae45ed37009b29a202b0f93f9dc36b8 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 09:36:09 -0500 Subject: [PATCH 069/121] impl `to_elements()` and `into_elements()` for `SmtLeaf` --- src/merkle/smt/mod.rs | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 32764b69..5eab01ae 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -216,18 +216,25 @@ pub enum SmtLeaf { } impl SmtLeaf { - pub fn hash(&self) -> RpoDigest { - fn kv_to_elements((key, value): &(SmtKey, Word)) -> impl Iterator + '_ { - let key_elements = key.word.iter().copied(); - let value_elements = value.iter().copied(); + /// Converts a leaf to a list of field elements + pub fn to_elements(&self) -> Vec { + self.clone().into_elements() + } - key_elements.chain(value_elements) + /// Converts a leaf to a list of field elements + pub fn into_elements(self) -> Vec { + match self { + SmtLeaf::Single(kv_pair) => kv_to_elements(kv_pair).collect(), + SmtLeaf::Multiple(kv_pairs) => kv_pairs.into_iter().flat_map(kv_to_elements).collect(), } + } + /// Compute the hash of the leaf + pub fn hash(&self) -> RpoDigest { match self { - SmtLeaf::Single((key, value)) => Rpo256::merge(&[key.word.into(), value.into()]), + SmtLeaf::Single((key, value)) => Rpo256::merge(&[key.word, value.into()]), SmtLeaf::Multiple(kvs) => { - let elements: Vec = kvs.iter().flat_map(kv_to_elements).collect(); + let elements: Vec = kvs.iter().copied().flat_map(kv_to_elements).collect(); Rpo256::hash_elements(&elements) } } @@ -237,6 +244,14 @@ impl SmtLeaf { // HELPER FUNCTIONS // ================================================================================================ +/// Converts a key-value tuple to an iterator of `Felt`s +fn kv_to_elements((key, value): (SmtKey, Word)) -> impl Iterator { + let key_elements = key.word.into_iter(); + let value_elements = value.into_iter(); + + key_elements.chain(value_elements) +} + /// Compares two keys, compared element-by-element using their integer representations starting with /// the most significant element. fn cmp_keys(key_1: SmtKey, key_2: SmtKey) -> Ordering { From e9548fc8a680e743e23c05ed2041cf7a995157c5 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 10:59:08 -0500 Subject: [PATCH 070/121] Make `SparseMerkleTree` pub(crate) --- benches/smt.rs | 2 +- benches/store.rs | 3 +-- src/merkle/delta.rs | 1 - src/merkle/mod.rs | 6 ++---- src/merkle/simple_smt/mod.rs | 36 +++++++++++++++++++++++++++++--- src/merkle/simple_smt/tests.rs | 4 +--- src/merkle/smt/mod.rs | 34 ++++++++++++++++++++++++++++-- src/merkle/sparse_merkle_tree.rs | 2 +- src/merkle/store/tests.rs | 3 +-- 9 files changed, 72 insertions(+), 19 deletions(-) diff --git a/benches/smt.rs b/benches/smt.rs index dec4a0e3..60307ab0 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -1,7 +1,7 @@ use core::mem::swap; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use miden_crypto::{ - merkle::{LeafIndex, SimpleSmt, SparseMerkleTree}, + merkle::{LeafIndex, SimpleSmt}, Felt, Word, }; use rand_utils::prng_array; diff --git a/benches/store.rs b/benches/store.rs index 1981540e..15b8f61e 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -1,7 +1,6 @@ use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; use miden_crypto::merkle::{ - DefaultMerkleStore as MerkleStore, LeafIndex, MerkleTree, NodeIndex, SimpleSmt, - SparseMerkleTree, SMT_MAX_DEPTH, + DefaultMerkleStore as MerkleStore, LeafIndex, MerkleTree, NodeIndex, SimpleSmt, SMT_MAX_DEPTH, }; use miden_crypto::Word; use miden_crypto::{hash::rpo::RpoDigest, Felt}; diff --git a/src/merkle/delta.rs b/src/merkle/delta.rs index 1c0e4f41..8049fa41 100644 --- a/src/merkle/delta.rs +++ b/src/merkle/delta.rs @@ -110,7 +110,6 @@ pub fn merkle_tree_delta>( #[cfg(test)] mod tests { use super::*; - use crate::merkle::SparseMerkleTree; #[test] fn test_compute_merkle_delta() { diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 36b5b37f..83e44d75 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -27,10 +27,8 @@ pub use path::{MerklePath, RootPath, ValuePath}; mod simple_smt; pub use simple_smt::SimpleSmt; -mod sparse_merkle_tree; -pub use sparse_merkle_tree::{ - InnerNode, LeafIndex, SparseMerkleTree, SMT_MAX_DEPTH, SMT_MIN_DEPTH, -}; +pub(crate) mod sparse_merkle_tree; +pub use sparse_merkle_tree::{InnerNode, LeafIndex, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; mod smt; pub use smt::{Smt, SmtKey, SmtLeaf, SMT_DEPTH}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 056e0bb1..791a212e 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,9 +1,10 @@ use crate::EMPTY_WORD; use super::{ - sparse_merkle_tree::SMT_MAX_DEPTH, BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, - InnerNodeInfo, LeafIndex, MerkleError, MerkleTreeDelta, NodeIndex, RpoDigest, SparseMerkleTree, - StoreNode, TryApplyDiff, Word, SMT_MIN_DEPTH, + sparse_merkle_tree::{SparseMerkleTree, SMT_MAX_DEPTH}, + BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, + MerklePath, MerkleTreeDelta, NodeIndex, RpoDigest, StoreNode, TryApplyDiff, Word, + SMT_MIN_DEPTH, }; #[cfg(test)] @@ -112,6 +113,28 @@ impl SimpleSmt { DEPTH } + /// Returns the root of the tree + pub fn root(&self) -> RpoDigest { + >::root(self) + } + + /// Returns the leaf at the specified index. + pub fn get_leaf(&self, key: &LeafIndex) -> Word { + >::get_leaf(self, key) + } + + /// Inserts an inner node at the given index + pub fn get_inner_node(&self, index: NodeIndex) -> InnerNode { + >::get_inner_node(self, index) + } + + /// Returns a Merkle path from the leaf node specified by the key to the root. + /// + /// The node itself is not included in the path. + pub fn get_leaf_path(&self, key: LeafIndex) -> MerklePath { + >::get_leaf_path(self, key) + } + /// Returns a node at the specified index. /// /// # Errors @@ -151,6 +174,13 @@ impl SimpleSmt { // STATE MUTATORS // -------------------------------------------------------------------------------------------- + /// Updates value of the leaf at the specified index returning the old leaf value. + /// + /// This also recomputes all hashes between the leaf and the root, updating the root itself. + pub fn update_leaf(&mut self, key: LeafIndex, value: Word) -> Word { + >::update_leaf(self, key, value) + } + /// Inserts a subtree at the specified index. The depth at which the subtree is inserted is /// computed as `self.depth() - subtree.depth()`. /// diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index c9ac88d1..dd780aee 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -4,9 +4,7 @@ use super::{ }; use crate::{ hash::rpo::Rpo256, - merkle::{ - digests_to_words, int_to_leaf, int_to_node, EmptySubtreeRoots, LeafIndex, SparseMerkleTree, - }, + merkle::{digests_to_words, int_to_leaf, int_to_node, EmptySubtreeRoots, LeafIndex}, utils::collections::Vec, Word, }; diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 5eab01ae..0caab4cc 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -6,9 +6,10 @@ use crate::hash::rpo::Rpo256; use crate::utils::{collections::Vec, vec}; use crate::{Felt, EMPTY_WORD}; +use super::sparse_merkle_tree::SparseMerkleTree; use super::{ - BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, LeafIndex, MerkleError, NodeIndex, RpoDigest, - SparseMerkleTree, Word, + BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, LeafIndex, MerkleError, MerklePath, + NodeIndex, RpoDigest, Word, }; #[cfg(test)] @@ -77,6 +78,35 @@ impl Smt { } Ok(tree) } + + /// Returns the root of the tree + pub fn root(&self) -> RpoDigest { + >::root(self) + } + + /// Returns the leaf at the specified index. + pub fn get_leaf(&self, key: &SmtKey) -> SmtLeaf { + >::get_leaf(self, key) + } + + /// Inserts an inner node at the given index + pub fn get_inner_node(&self, index: NodeIndex) -> InnerNode { + >::get_inner_node(self, index) + } + + /// Returns a Merkle path from the leaf node specified by the key to the root. + /// + /// The node itself is not included in the path. + pub fn get_leaf_path(&self, key: SmtKey) -> MerklePath { + >::get_leaf_path(self, key) + } + + /// Updates value of the leaf at the specified index returning the old leaf value. + /// + /// This also recomputes all hashes between the leaf and the root, updating the root itself. + pub fn update_leaf(&mut self, key: SmtKey, value: Word) -> Word { + >::update_leaf(self, key, value) + } } impl SparseMerkleTree for Smt { diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index 237e18af..3a1f90a5 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -38,7 +38,7 @@ pub const SMT_MAX_DEPTH: u8 = 64; /// must accomodate all keys that map to the same leaf. /// /// [SparseMerkleTree] currently doesn't support optimizations that compress Merkle proofs. -pub trait SparseMerkleTree { +pub(crate) trait SparseMerkleTree { /// The type for a key, which must be convertible into a `u64` infaillibly type Key: Into> + Clone; /// The type for a value diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index b652dbec..e39fbfaf 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -4,8 +4,7 @@ use super::{ }; use crate::{ merkle::{ - digests_to_words, int_to_leaf, int_to_node, LeafIndex, MerkleTree, SimpleSmt, - SparseMerkleTree, SMT_MAX_DEPTH, + digests_to_words, int_to_leaf, int_to_node, LeafIndex, MerkleTree, SimpleSmt, SMT_MAX_DEPTH, }, Felt, Word, ONE, WORD_SIZE, ZERO, }; From 11d68622f03319d322abb51d071f8c3e06c1beac Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 11:01:53 -0500 Subject: [PATCH 071/121] add sections to `Smt` --- src/merkle/smt/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 0caab4cc..139235d5 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -32,6 +32,9 @@ pub struct Smt { } impl Smt { + // CONSTRUCTORS + // -------------------------------------------------------------------------------------------- + /// Returns a new [NewSmt]. /// /// All leaves in the returned tree are set to [ZERO; 4]. @@ -79,6 +82,9 @@ impl Smt { Ok(tree) } + // PUBLIC ACCESSORS + // -------------------------------------------------------------------------------------------- + /// Returns the root of the tree pub fn root(&self) -> RpoDigest { >::root(self) @@ -101,6 +107,9 @@ impl Smt { >::get_leaf_path(self, key) } + // STATE MUTATORS + // -------------------------------------------------------------------------------------------- + /// Updates value of the leaf at the specified index returning the old leaf value. /// /// This also recomputes all hashes between the leaf and the root, updating the root itself. From a6068001828af3c2e2e041b819fb930d1467aac2 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 11:10:49 -0500 Subject: [PATCH 072/121] remove `SimpleSmt::depth()` --- benches/smt.rs | 4 +-- benches/store.rs | 15 +++++------ src/merkle/delta.rs | 15 +++++------ src/merkle/simple_smt/mod.rs | 36 +++++++++++--------------- src/merkle/store/tests.rs | 49 ++++++++++++++++++------------------ 5 files changed, 54 insertions(+), 65 deletions(-) diff --git a/benches/smt.rs b/benches/smt.rs index 60307ab0..d2800c4a 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -27,7 +27,7 @@ fn smt_rpo(c: &mut Criterion) { // benchmark 1 let mut insert = c.benchmark_group("smt update_leaf".to_string()); { - let depth = tree.depth(); + let depth = DEPTH; let key = count >> 2; insert.bench_with_input( format!("simple smt(depth:{depth},count:{count})"), @@ -45,7 +45,7 @@ fn smt_rpo(c: &mut Criterion) { // benchmark 2 let mut path = c.benchmark_group("smt get_leaf_path".to_string()); { - let depth = tree.depth(); + let depth = DEPTH; let key = count >> 2; path.bench_with_input( format!("simple smt(depth:{depth},count:{count})"), diff --git a/benches/store.rs b/benches/store.rs index 15b8f61e..ed1b159c 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -108,13 +108,12 @@ fn get_leaf_simplesmt(c: &mut Criterion) { .collect::>(); let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let store = MerkleStore::from(&smt); - let depth = smt.depth(); let root = smt.root(); let size_u64 = size as u64; group.bench_function(BenchmarkId::new("SimpleSmt", size), |b| { b.iter_batched( - || random_index(size_u64, depth), + || random_index(size_u64, SMT_MAX_DEPTH), |index| black_box(smt.get_node(index)), BatchSize::SmallInput, ) @@ -122,7 +121,7 @@ fn get_leaf_simplesmt(c: &mut Criterion) { group.bench_function(BenchmarkId::new("MerkleStore", size), |b| { b.iter_batched( - || random_index(size_u64, depth), + || random_index(size_u64, SMT_MAX_DEPTH), |index| black_box(store.get_node(root, index)), BatchSize::SmallInput, ) @@ -217,7 +216,7 @@ fn get_node_simplesmt(c: &mut Criterion) { let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let store = MerkleStore::from(&smt); let root = smt.root(); - let half_depth = smt.depth() / 2; + let half_depth = SMT_MAX_DEPTH / 2; let half_size = 2_u64.pow(half_depth as u32); group.bench_function(BenchmarkId::new("SimpleSmt", size), |b| { @@ -290,13 +289,12 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { .collect::>(); let smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let store = MerkleStore::from(&smt); - let depth = smt.depth(); let root = smt.root(); let size_u64 = size as u64; group.bench_function(BenchmarkId::new("SimpleSmt", size), |b| { b.iter_batched( - || random_index(size_u64, depth), + || random_index(size_u64, SMT_MAX_DEPTH), |index| { black_box( smt.get_leaf_path(LeafIndex::::new(index.value()).unwrap()), @@ -308,7 +306,7 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { group.bench_function(BenchmarkId::new("MerkleStore", size), |b| { b.iter_batched( - || random_index(size_u64, depth), + || random_index(size_u64, SMT_MAX_DEPTH), |index| black_box(store.get_path(root, index)), BatchSize::SmallInput, ) @@ -441,7 +439,6 @@ fn update_leaf_simplesmt(c: &mut Criterion) { .collect::>(); let mut smt = SimpleSmt::::with_leaves(smt_leaves.clone()).unwrap(); let mut store = MerkleStore::from(&smt); - let depth = smt.depth(); let root = smt.root(); let size_u64 = size as u64; @@ -460,7 +457,7 @@ fn update_leaf_simplesmt(c: &mut Criterion) { let mut store_root = root; group.bench_function(BenchmarkId::new("MerkleStore", size), |b| { b.iter_batched( - || (random_index(size_u64, depth), random_word()), + || (random_index(size_u64, SMT_MAX_DEPTH), random_word()), |(index, value)| { // The MerkleTree automatically updates its internal root, the Store maintains // the old root and adds the new one. Here we update the root to have a fair diff --git a/src/merkle/delta.rs b/src/merkle/delta.rs index 8049fa41..baede807 100644 --- a/src/merkle/delta.rs +++ b/src/merkle/delta.rs @@ -113,34 +113,35 @@ mod tests { #[test] fn test_compute_merkle_delta() { + const TREE_DEPTH: u8 = 30; + let entries = vec![ (10, [ZERO, ONE, Felt::new(2), Felt::new(3)]), (15, [Felt::new(4), Felt::new(5), Felt::new(6), Felt::new(7)]), (20, [Felt::new(8), Felt::new(9), Felt::new(10), Felt::new(11)]), (31, [Felt::new(12), Felt::new(13), Felt::new(14), Felt::new(15)]), ]; - let simple_smt = SimpleSmt::<30>::with_leaves(entries.clone()).unwrap(); + let simple_smt = SimpleSmt::::with_leaves(entries.clone()).unwrap(); let mut store: MerkleStore = (&simple_smt).into(); let root = simple_smt.root(); // add a new node let new_value = [Felt::new(16), Felt::new(17), Felt::new(18), Felt::new(19)]; - let new_index = NodeIndex::new(simple_smt.depth(), 32).unwrap(); + let new_index = NodeIndex::new(TREE_DEPTH, 32).unwrap(); let root = store.set_node(root, new_index, new_value.into()).unwrap().root; // update an existing node let update_value = [Felt::new(20), Felt::new(21), Felt::new(22), Felt::new(23)]; - let update_idx = NodeIndex::new(simple_smt.depth(), entries[0].0).unwrap(); + let update_idx = NodeIndex::new(TREE_DEPTH, entries[0].0).unwrap(); let root = store.set_node(root, update_idx, update_value.into()).unwrap().root; // remove a node - let remove_idx = NodeIndex::new(simple_smt.depth(), entries[1].0).unwrap(); + let remove_idx = NodeIndex::new(TREE_DEPTH, entries[1].0).unwrap(); let root = store.set_node(root, remove_idx, EMPTY_WORD.into()).unwrap().root; - let merkle_delta = - merkle_tree_delta(simple_smt.root(), root, simple_smt.depth(), &store).unwrap(); + let merkle_delta = merkle_tree_delta(simple_smt.root(), root, TREE_DEPTH, &store).unwrap(); let expected_merkle_delta = MerkleTreeDelta { - depth: simple_smt.depth(), + depth: TREE_DEPTH, cleared_slots: vec![remove_idx.value()], updated_slots: vec![(update_idx.value(), update_value), (new_index.value(), new_value)], }; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 791a212e..e06d398d 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -68,7 +68,7 @@ impl SimpleSmt { // compute the max number of entries. We use an upper bound of depth 63 because we consider // passing in a vector of size 2^64 infeasible. - let max_num_entries = 2_usize.pow(tree.depth().min(63).into()); + let max_num_entries = 2_usize.pow(DEPTH.min(63).into()); // This being a sparse data structure, the EMPTY_WORD is not assigned to the `BTreeMap`, so // entries with the empty value need additional tracking. @@ -108,11 +108,6 @@ impl SimpleSmt { // PUBLIC ACCESSORS // -------------------------------------------------------------------------------------------- - /// Returns the depth of this Merkle tree. - pub const fn depth(&self) -> u8 { - DEPTH - } - /// Returns the root of the tree pub fn root(&self) -> RpoDigest { >::root(self) @@ -143,9 +138,9 @@ impl SimpleSmt { pub fn get_node(&self, index: NodeIndex) -> Result { if index.is_root() { Err(MerkleError::DepthTooSmall(index.depth())) - } else if index.depth() > self.depth() { + } else if index.depth() > DEPTH { Err(MerkleError::DepthTooBig(index.depth() as u64)) - } else if index.depth() == self.depth() { + } else if index.depth() == DEPTH { let leaf = self.get_leaf(&LeafIndex::::try_from(index)?); Ok(leaf.into()) @@ -182,7 +177,7 @@ impl SimpleSmt { } /// Inserts a subtree at the specified index. The depth at which the subtree is inserted is - /// computed as `self.depth() - subtree.depth()`. + /// computed as `DEPTH - SUBTREE_DEPTH`. /// /// Returns the new root. pub fn set_subtree( @@ -190,15 +185,15 @@ impl SimpleSmt { subtree_insertion_index: u64, subtree: SimpleSmt, ) -> Result { - if subtree.depth() > self.depth() { + if SUBTREE_DEPTH > DEPTH { return Err(MerkleError::InvalidSubtreeDepth { - subtree_depth: subtree.depth(), - tree_depth: self.depth(), + subtree_depth: SUBTREE_DEPTH, + tree_depth: DEPTH, }); } // Verify that `subtree_insertion_index` is valid. - let subtree_root_insertion_depth = self.depth() - subtree.depth(); + let subtree_root_insertion_depth = DEPTH - SUBTREE_DEPTH; let subtree_root_index = NodeIndex::new(subtree_root_insertion_depth, subtree_insertion_index)?; @@ -212,10 +207,10 @@ impl SimpleSmt { // you can see it as there's a full subtree sitting on its left. In general, for // `subtree_insertion_index = i`, there are `i` subtrees sitting before the subtree we want // to insert, so we need to adjust all its leaves by `i * 2^d`. - let leaf_index_shift: u64 = subtree_insertion_index * 2_u64.pow(subtree.depth().into()); + let leaf_index_shift: u64 = subtree_insertion_index * 2_u64.pow(SUBTREE_DEPTH.into()); for (subtree_leaf_idx, leaf_value) in subtree.leaves() { let new_leaf_idx = leaf_index_shift + subtree_leaf_idx; - debug_assert!(new_leaf_idx < 2_u64.pow(self.depth().into())); + debug_assert!(new_leaf_idx < 2_u64.pow(DEPTH.into())); self.leaves.insert(new_leaf_idx, *leaf_value); } @@ -259,7 +254,7 @@ impl SparseMerkleTree for SimpleSmt { fn get_inner_node(&self, index: NodeIndex) -> InnerNode { self.inner_nodes.get(&index).cloned().unwrap_or_else(|| { - let node = EmptySubtreeRoots::entry(self.depth(), index.depth() + 1); + let node = EmptySubtreeRoots::entry(DEPTH, index.depth() + 1); InnerNode { left: *node, right: *node } }) @@ -280,7 +275,7 @@ impl SparseMerkleTree for SimpleSmt { match self.leaves.get(&leaf_pos) { Some(word) => *word, - None => Word::from(*EmptySubtreeRoots::entry(self.depth(), self.depth())), + None => Word::from(*EmptySubtreeRoots::entry(DEPTH, DEPTH)), } } @@ -297,11 +292,8 @@ impl TryApplyDiff for SimpleSmt { type DiffType = MerkleTreeDelta; fn try_apply(&mut self, diff: MerkleTreeDelta) -> Result<(), MerkleError> { - if diff.depth() != self.depth() { - return Err(MerkleError::InvalidDepth { - expected: self.depth(), - provided: diff.depth(), - }); + if diff.depth() != DEPTH { + return Err(MerkleError::InvalidDepth { expected: DEPTH, provided: diff.depth() }); } for slot in diff.cleared_slots() { diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index e39fbfaf..c537c855 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -240,27 +240,27 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { // STORE LEAVES ARE CORRECT ============================================================== // checks the leaves in the store corresponds to the expected values assert_eq!( - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 0)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 0)), Ok(VALUES4[0]), "node 0 must be in the tree" ); assert_eq!( - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 1)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 1)), Ok(VALUES4[1]), "node 1 must be in the tree" ); assert_eq!( - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 2)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 2)), Ok(VALUES4[2]), "node 2 must be in the tree" ); assert_eq!( - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 3)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 3)), Ok(VALUES4[3]), "node 3 must be in the tree" ); assert_eq!( - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 4)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 4)), Ok(RpoDigest::default()), "unmodified node 4 must be ZERO" ); @@ -268,34 +268,34 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { // STORE LEAVES MATCH TREE =============================================================== // sanity check the values returned by the store and the tree assert_eq!( - smt.get_node(NodeIndex::make(smt.depth(), 0)), - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 0)), + smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 0)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 0)), "node 0 must be the same for both SparseMerkleTree and MerkleStore" ); assert_eq!( - smt.get_node(NodeIndex::make(smt.depth(), 1)), - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 1)), + smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 1)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 1)), "node 1 must be the same for both SparseMerkleTree and MerkleStore" ); assert_eq!( - smt.get_node(NodeIndex::make(smt.depth(), 2)), - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 2)), + smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 2)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 2)), "node 2 must be the same for both SparseMerkleTree and MerkleStore" ); assert_eq!( - smt.get_node(NodeIndex::make(smt.depth(), 3)), - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 3)), + smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 3)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 3)), "node 3 must be the same for both SparseMerkleTree and MerkleStore" ); assert_eq!( - smt.get_node(NodeIndex::make(smt.depth(), 4)), - store.get_node(smt.root(), NodeIndex::make(smt.depth(), 4)), + smt.get_node(NodeIndex::make(SMT_MAX_DEPTH, 4)), + store.get_node(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 4)), "node 4 must be the same for both SparseMerkleTree and MerkleStore" ); // STORE MERKLE PATH MATCHS ============================================================== // assert the merkle path returned by the store is the same as the one in the tree - let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 0)).unwrap(); + let result = store.get_path(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 0)).unwrap(); assert_eq!( VALUES4[0], result.value, "Value for merkle path at index 0 must match leaf value" @@ -306,7 +306,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" ); - let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 1)).unwrap(); + let result = store.get_path(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 1)).unwrap(); assert_eq!( VALUES4[1], result.value, "Value for merkle path at index 1 must match leaf value" @@ -317,7 +317,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" ); - let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 2)).unwrap(); + let result = store.get_path(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 2)).unwrap(); assert_eq!( VALUES4[2], result.value, "Value for merkle path at index 2 must match leaf value" @@ -328,7 +328,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "merkle path for index 2 must be the same for the MerkleTree and MerkleStore" ); - let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 3)).unwrap(); + let result = store.get_path(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 3)).unwrap(); assert_eq!( VALUES4[3], result.value, "Value for merkle path at index 3 must match leaf value" @@ -339,7 +339,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "merkle path for index 3 must be the same for the MerkleTree and MerkleStore" ); - let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 4)).unwrap(); + let result = store.get_path(smt.root(), NodeIndex::make(SMT_MAX_DEPTH, 4)).unwrap(); assert_eq!( RpoDigest::default(), result.value, @@ -559,10 +559,9 @@ fn test_constructors() -> Result<(), MerkleError> { let smt = SimpleSmt::::with_leaves(KEYS4.into_iter().zip(digests_to_words(&VALUES4))).unwrap(); let store = MerkleStore::from(&smt); - let depth = smt.depth(); for key in KEYS4 { - let index = NodeIndex::make(depth, key); + let index = NodeIndex::make(DEPTH, key); let value_path = store.get_path(smt.root(), index)?; assert_eq!(smt.get_leaf_path(LeafIndex::::new(key).unwrap()), value_path.path); } @@ -898,13 +897,13 @@ fn test_recorder() { let node = recorder.get_node(mtree.root(), index_0).unwrap(); assert_eq!(node, mtree.get_node(index_0).unwrap()); - let index_1 = NodeIndex::new(smtree.depth(), 1).unwrap(); + let index_1 = NodeIndex::new(TREE_DEPTH, 1).unwrap(); let node = recorder.get_node(smtree.root(), index_1).unwrap(); assert_eq!(node, smtree.get_node(index_1).unwrap()); // insert a value and assert that when we request it next time it is accurate let new_value = [ZERO, ZERO, ONE, ONE].into(); - let index_2 = NodeIndex::new(smtree.depth(), 2).unwrap(); + let index_2 = NodeIndex::new(TREE_DEPTH, 2).unwrap(); let root = recorder.set_node(smtree.root(), index_2, new_value).unwrap().root; assert_eq!(recorder.get_node(root, index_2).unwrap(), new_value); @@ -927,7 +926,7 @@ fn test_recorder() { ); // assert that is doesnt contain nodes that were not recorded - let not_recorded_index = NodeIndex::new(smtree.depth(), 4).unwrap(); + let not_recorded_index = NodeIndex::new(TREE_DEPTH, 4).unwrap(); assert!(merkle_store.get_node(smtree.root(), not_recorded_index).is_err()); assert!(smtree.get_node(not_recorded_index).is_ok()); } From 4f9aa816631d05885640d923df9fe9ff6602e528 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 11:17:18 -0500 Subject: [PATCH 073/121] fix `get_inner_node()` docstring --- src/merkle/simple_smt/mod.rs | 2 +- src/merkle/smt/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index e06d398d..504644ba 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -118,7 +118,7 @@ impl SimpleSmt { >::get_leaf(self, key) } - /// Inserts an inner node at the given index + /// Retrieves an inner node at the given index pub fn get_inner_node(&self, index: NodeIndex) -> InnerNode { >::get_inner_node(self, index) } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 139235d5..630c96c5 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -95,7 +95,7 @@ impl Smt { >::get_leaf(self, key) } - /// Inserts an inner node at the given index + /// Retrieves an inner node at the given index pub fn get_inner_node(&self, index: NodeIndex) -> InnerNode { >::get_inner_node(self, index) } From 5c612619c6ab2d5b13513ceec6e26cbfb90e062b Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 11:20:56 -0500 Subject: [PATCH 074/121] remove `get_inner_node` from public API --- src/merkle/mod.rs | 2 +- src/merkle/simple_smt/mod.rs | 12 +++--------- src/merkle/simple_smt/tests.rs | 5 ++++- src/merkle/smt/mod.rs | 11 +++-------- src/merkle/sparse_merkle_tree.rs | 2 +- 5 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 83e44d75..5d8b5421 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -28,7 +28,7 @@ mod simple_smt; pub use simple_smt::SimpleSmt; pub(crate) mod sparse_merkle_tree; -pub use sparse_merkle_tree::{InnerNode, LeafIndex, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; +pub use sparse_merkle_tree::{LeafIndex, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; mod smt; pub use smt::{Smt, SmtKey, SmtLeaf, SMT_DEPTH}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 504644ba..a81fa8d9 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -1,10 +1,9 @@ use crate::EMPTY_WORD; use super::{ - sparse_merkle_tree::{SparseMerkleTree, SMT_MAX_DEPTH}, - BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, - MerklePath, MerkleTreeDelta, NodeIndex, RpoDigest, StoreNode, TryApplyDiff, Word, - SMT_MIN_DEPTH, + sparse_merkle_tree::{InnerNode, SparseMerkleTree, SMT_MAX_DEPTH}, + BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNodeInfo, LeafIndex, MerkleError, MerklePath, + MerkleTreeDelta, NodeIndex, RpoDigest, StoreNode, TryApplyDiff, Word, SMT_MIN_DEPTH, }; #[cfg(test)] @@ -118,11 +117,6 @@ impl SimpleSmt { >::get_leaf(self, key) } - /// Retrieves an inner node at the given index - pub fn get_inner_node(&self, index: NodeIndex) -> InnerNode { - >::get_inner_node(self, index) - } - /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index dd780aee..c6552b1a 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -4,7 +4,10 @@ use super::{ }; use crate::{ hash::rpo::Rpo256, - merkle::{digests_to_words, int_to_leaf, int_to_node, EmptySubtreeRoots, LeafIndex}, + merkle::{ + digests_to_words, int_to_leaf, int_to_node, sparse_merkle_tree::SparseMerkleTree, + EmptySubtreeRoots, LeafIndex, + }, utils::collections::Vec, Word, }; diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 630c96c5..9ff059e4 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -6,10 +6,10 @@ use crate::hash::rpo::Rpo256; use crate::utils::{collections::Vec, vec}; use crate::{Felt, EMPTY_WORD}; -use super::sparse_merkle_tree::SparseMerkleTree; +use super::sparse_merkle_tree::{InnerNode, SparseMerkleTree}; use super::{ - BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNode, LeafIndex, MerkleError, MerklePath, - NodeIndex, RpoDigest, Word, + BTreeMap, BTreeSet, EmptySubtreeRoots, LeafIndex, MerkleError, MerklePath, NodeIndex, + RpoDigest, Word, }; #[cfg(test)] @@ -95,11 +95,6 @@ impl Smt { >::get_leaf(self, key) } - /// Retrieves an inner node at the given index - pub fn get_inner_node(&self, index: NodeIndex) -> InnerNode { - >::get_inner_node(self, index) - } - /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index 3a1f90a5..3bd9e05e 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -144,7 +144,7 @@ pub(crate) trait SparseMerkleTree { #[derive(Debug, Default, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct InnerNode { +pub(crate) struct InnerNode { pub left: RpoDigest, pub right: RpoDigest, } From eded7c5015bb1e5311bdfb0c9eb3f1e6166a4672 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 12:05:40 -0500 Subject: [PATCH 075/121] insert_value: if no value at key, always return `None` --- src/merkle/smt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 9ff059e4..843af430 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -180,7 +180,7 @@ impl SparseMerkleTree for Smt { None => { self.leaves.insert(leaf_index.value(), SmtLeaf::Single((key, value))); - Some(Self::Value::default()) + None } } } From a26cbc81388a6d91f8ceb7284460991e59049b10 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 13:46:54 -0500 Subject: [PATCH 076/121] cover case of inserting an `EMPTY_VALUE` --- src/merkle/smt/mod.rs | 138 +++++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 37 deletions(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 843af430..8c967663 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -111,55 +111,36 @@ impl Smt { pub fn update_leaf(&mut self, key: SmtKey, value: Word) -> Word { >::update_leaf(self, key, value) } -} - -impl SparseMerkleTree for Smt { - type Key = SmtKey; - type Value = Word; - type Leaf = SmtLeaf; - - const EMPTY_VALUE: Self::Value = EMPTY_WORD; - - fn root(&self) -> RpoDigest { - self.root - } - - fn set_root(&mut self, root: RpoDigest) { - self.root = root; - } - fn get_inner_node(&self, index: NodeIndex) -> InnerNode { - self.inner_nodes.get(&index).cloned().unwrap_or_else(|| { - let node = EmptySubtreeRoots::entry(SMT_DEPTH, index.depth() + 1); - - InnerNode { left: *node, right: *node } - }) - } + // HELPERS + // -------------------------------------------------------------------------------------------- - fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { - self.inner_nodes.insert(index, inner_node); - } + /// Inserts `value` at leaf index pointed to by `key`. `value` is guaranteed to not be the empty + /// value, such that this is indeed an insertion. + fn perform_insert(&mut self, key: SmtKey, value: Word) -> Option { + debug_assert_ne!(value, Self::EMPTY_VALUE); - fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option { let leaf_index: LeafIndex = key.into(); + match self.leaves.get_mut(&leaf_index.value()) { Some(leaf) => match leaf { SmtLeaf::Single(kv_pair) => { - // if the key is already in this entry, update the value and return if kv_pair.0 == key { + // the key is already in this leaf. Update the value and return the previous + // value let old_value = kv_pair.1; kv_pair.1 = value; - return Some(old_value); - } - - // transform the entry into a list entry, and make sure the key-value pairs - // are sorted by key - let mut pairs = vec![*kv_pair, (key, value)]; - pairs.sort_by(|(key_1, _), (key_2, _)| cmp_keys(*key_1, *key_2)); + Some(old_value) + } else { + // Another entry is present in this leaf. Transform the entry into a list + // entry, and make sure the key-value pairs are sorted by key + let mut pairs = vec![*kv_pair, (key, value)]; + pairs.sort_by(|(key_1, _), (key_2, _)| cmp_keys(*key_1, *key_2)); - self.leaves.insert(leaf_index.value(), SmtLeaf::Multiple(pairs)); + self.leaves.insert(leaf_index.value(), SmtLeaf::Multiple(pairs)); - None + None + } } SmtLeaf::Multiple(kv_pairs) => { match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { @@ -185,6 +166,89 @@ impl SparseMerkleTree for Smt { } } + /// Removes `key`/`value` pair at leaf index pointed to by `key` if it exists. + fn perform_remove(&mut self, key: SmtKey) -> Option { + let leaf_index: LeafIndex = key.into(); + + if let Some(leaf) = self.leaves.get_mut(&leaf_index.value()) { + match leaf { + SmtLeaf::Single((key_at_leaf, value_at_leaf)) => { + if *key_at_leaf == key { + // our key was indeed stored in the leaf, so we remove the leaf and return + // the value that was stored in it + let old_value = *value_at_leaf; + self.leaves.remove(&leaf_index.value()); + Some(old_value) + } else { + // another key is stored at leaf; nothing to update + None + } + } + SmtLeaf::Multiple(kv_pairs) => { + match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { + Ok(pos) => { + let old_value = kv_pairs[pos].1; + + kv_pairs.remove(pos); + debug_assert!(!kv_pairs.is_empty()); + + if kv_pairs.len() == 1 { + // convert the leaf into `Single` + *leaf = SmtLeaf::Single(kv_pairs[0]); + } + + Some(old_value) + } + Err(_) => { + // other keys are stored at leaf; nothing to update + None + } + } + } + } + } else { + // there's nothing stored at the leaf; nothing to update + None + } + } +} + +impl SparseMerkleTree for Smt { + type Key = SmtKey; + type Value = Word; + type Leaf = SmtLeaf; + + const EMPTY_VALUE: Self::Value = EMPTY_WORD; + + fn root(&self) -> RpoDigest { + self.root + } + + fn set_root(&mut self, root: RpoDigest) { + self.root = root; + } + + fn get_inner_node(&self, index: NodeIndex) -> InnerNode { + self.inner_nodes.get(&index).cloned().unwrap_or_else(|| { + let node = EmptySubtreeRoots::entry(SMT_DEPTH, index.depth() + 1); + + InnerNode { left: *node, right: *node } + }) + } + + fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { + self.inner_nodes.insert(index, inner_node); + } + + fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option { + // inserting an `EMPTY_VALUE` is equivalent to removing any value associated with `key` + if value != Self::EMPTY_VALUE { + self.perform_insert(key, value) + } else { + self.perform_remove(key) + } + } + fn get_leaf(&self, key: &Self::Key) -> Self::Leaf { let leaf_pos = LeafIndex::::from(*key).value(); From c8edefdf8674cfee9fc3726ba93a7d8ce90b71f3 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 14:05:53 -0500 Subject: [PATCH 077/121] `NewLeaf::insert` --- src/merkle/smt/mod.rs | 79 ++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 8c967663..11e2d119 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -123,41 +123,7 @@ impl Smt { let leaf_index: LeafIndex = key.into(); match self.leaves.get_mut(&leaf_index.value()) { - Some(leaf) => match leaf { - SmtLeaf::Single(kv_pair) => { - if kv_pair.0 == key { - // the key is already in this leaf. Update the value and return the previous - // value - let old_value = kv_pair.1; - kv_pair.1 = value; - Some(old_value) - } else { - // Another entry is present in this leaf. Transform the entry into a list - // entry, and make sure the key-value pairs are sorted by key - let mut pairs = vec![*kv_pair, (key, value)]; - pairs.sort_by(|(key_1, _), (key_2, _)| cmp_keys(*key_1, *key_2)); - - self.leaves.insert(leaf_index.value(), SmtLeaf::Multiple(pairs)); - - None - } - } - SmtLeaf::Multiple(kv_pairs) => { - match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { - Ok(pos) => { - let old_value = kv_pairs[pos].1; - kv_pairs[pos].1 = value; - - Some(old_value) - } - Err(pos) => { - kv_pairs.insert(pos, (key, value)); - - None - } - } - } - }, + Some(leaf) => leaf.insert(key, value), None => { self.leaves.insert(leaf_index.value(), SmtLeaf::Single((key, value))); @@ -337,6 +303,49 @@ impl SmtLeaf { } } } + + // HELPERS + // --------------------------------------------------------------------------------------------- + + /// Insert key-value pair into the leaf; return the previous value associated with `key`, if + /// any. + fn insert(&mut self, key: SmtKey, value: Word) -> Option { + match self { + SmtLeaf::Single(kv_pair) => { + if kv_pair.0 == key { + // the key is already in this leaf. Update the value and return the previous + // value + let old_value = kv_pair.1; + kv_pair.1 = value; + Some(old_value) + } else { + // Another entry is present in this leaf. Transform the entry into a list + // entry, and make sure the key-value pairs are sorted by key + let mut pairs = vec![*kv_pair, (key, value)]; + pairs.sort_by(|(key_1, _), (key_2, _)| cmp_keys(*key_1, *key_2)); + + *self = SmtLeaf::Multiple(pairs); + + None + } + } + SmtLeaf::Multiple(kv_pairs) => { + match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { + Ok(pos) => { + let old_value = kv_pairs[pos].1; + kv_pairs[pos].1 = value; + + Some(old_value) + } + Err(pos) => { + kv_pairs.insert(pos, (key, value)); + + None + } + } + } + } + } } // HELPER FUNCTIONS From 97fe6ce583a4f3d231ff0dd70fb1a7f0927e37f3 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 14:15:09 -0500 Subject: [PATCH 078/121] update comment --- src/merkle/smt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 11e2d119..ae3c79dc 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -132,7 +132,7 @@ impl Smt { } } - /// Removes `key`/`value` pair at leaf index pointed to by `key` if it exists. + /// Removes key-value pair at leaf index pointed to by `key` if it exists. fn perform_remove(&mut self, key: SmtKey) -> Option { let leaf_index: LeafIndex = key.into(); From 646c0fbd77bb5a17d46493a8921ca3b51bd62000 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 15:03:29 -0500 Subject: [PATCH 079/121] test_smt_insert_at_same_key --- src/merkle/smt/tests.rs | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index 8b137891..05ee6802 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -1 +1,52 @@ +use crate::{merkle::MerkleStore, ONE, WORD_SIZE}; +use super::*; + +/// This test checks that inserting twice at the same key functions as expected. The test covers +/// only the case where the key is alone in its leaf +#[test] +fn test_smt_insert_at_same_key() { + let mut smt = Smt::default(); + let mut store: MerkleStore = MerkleStore::default(); + + assert_eq!(smt.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0)); + + let key_1: SmtKey = { + let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; + + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + }; + let key_1_index: NodeIndex = LeafIndex::::from(key_1).into(); + + let value_1 = [ONE; WORD_SIZE]; + let value_2 = [ONE + ONE; WORD_SIZE]; + + // Insert value 1 and ensure root is as expected + { + let leaf_node = build_single_leaf_node(key_1, value_1); + let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; + + let old_value_1 = smt.update_leaf(key_1, value_1); + assert_eq!(old_value_1, EMPTY_WORD); + + assert_eq!(smt.root(), tree_root); + } + + // Insert value 2 and ensure root is as expected + { + let leaf_node = build_single_leaf_node(key_1, value_2); + let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; + + let old_value_2 = smt.update_leaf(key_1, value_2); + assert_eq!(old_value_2, value_1); + + assert_eq!(smt.root(), tree_root); + } +} + +// HELPERS +// -------------------------------------------------------------------------------------------- + +fn build_single_leaf_node(key: SmtKey, value: Word) -> RpoDigest { + SmtLeaf::Single((key, value)).hash() +} From bee733afb17aee351c54a2fd2597fa5eb57a9c7a Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 15:09:32 -0500 Subject: [PATCH 080/121] test_smt_insert_at_same_key_2 --- src/merkle/smt/tests.rs | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index 05ee6802..f6529630 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -44,6 +44,63 @@ fn test_smt_insert_at_same_key() { } } +/// This test checks that inserting twice at the same key functions as expected. The test covers +/// only the case where the leaf type is `SmtLeaf::Multiple` +#[test] +fn test_smt_insert_at_same_key_2() { + let key_already_present: SmtKey = { + let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; + + RpoDigest::from([ONE + ONE, ONE + ONE, ONE + ONE, Felt::new(raw)]).into() + }; + let key_already_present_index: NodeIndex = + LeafIndex::::from(key_already_present).into(); + let value_already_present = [ONE + ONE + ONE; WORD_SIZE]; + + let mut smt = + Smt::with_entries(std::iter::once((key_already_present, value_already_present))).unwrap(); + let mut store: MerkleStore = { + let mut store = MerkleStore::default(); + + let leaf_node = build_single_leaf_node(key_already_present, value_already_present); + store + .set_node(*EmptySubtreeRoots::entry(SMT_DEPTH, 0), key_already_present_index, leaf_node) + .unwrap(); + store + }; + + let key_1: SmtKey = { + let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; + + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + }; + let key_1_index: NodeIndex = LeafIndex::::from(key_1).into(); + + let value_1 = [ONE; WORD_SIZE]; + let value_2 = [ONE + ONE; WORD_SIZE]; + + // Insert value 1 and ensure root is as expected + { + let leaf_node = build_single_leaf_node(key_1, value_1); + let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; + + let old_value_1 = smt.update_leaf(key_1, value_1); + assert_eq!(old_value_1, EMPTY_WORD); + + assert_eq!(smt.root(), tree_root); + } + + // Insert value 2 and ensure root is as expected + { + let leaf_node = build_single_leaf_node(key_1, value_2); + let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; + + let old_value_2 = smt.update_leaf(key_1, value_2); + assert_eq!(old_value_2, value_1); + + assert_eq!(smt.root(), tree_root); + } +} // HELPERS // -------------------------------------------------------------------------------------------- From 7619a109d0bd89dd2a22c04a398e92eeb913f884 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 15:16:00 -0500 Subject: [PATCH 081/121] fix most_significant_felt for `SmtKey` --- src/merkle/smt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index ae3c79dc..ad9b88c0 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -252,7 +252,7 @@ pub struct SmtKey { impl From for LeafIndex { fn from(key: SmtKey) -> Self { - let most_significant_felt = key.word[0]; + let most_significant_felt = key.word[3]; Self::new_max_depth(most_significant_felt.as_int()) } } From 2c7cee53e7236973dd04900e930348398af691e9 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 15:21:17 -0500 Subject: [PATCH 082/121] fix test_smt_insert_at_same_key_2 --- src/merkle/smt/tests.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index f6529630..98db5206 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -76,12 +76,18 @@ fn test_smt_insert_at_same_key_2() { }; let key_1_index: NodeIndex = LeafIndex::::from(key_1).into(); + assert_eq!(key_1_index, key_already_present_index); + let value_1 = [ONE; WORD_SIZE]; let value_2 = [ONE + ONE; WORD_SIZE]; // Insert value 1 and ensure root is as expected { - let leaf_node = build_single_leaf_node(key_1, value_1); + // Note: key_1 comes first because it is smaller + let leaf_node = build_multiple_leaf_node(&[ + (key_1, value_1), + (key_already_present, value_already_present), + ]); let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; let old_value_1 = smt.update_leaf(key_1, value_1); @@ -92,7 +98,10 @@ fn test_smt_insert_at_same_key_2() { // Insert value 2 and ensure root is as expected { - let leaf_node = build_single_leaf_node(key_1, value_2); + let leaf_node = build_multiple_leaf_node(&[ + (key_1, value_2), + (key_already_present, value_already_present), + ]); let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; let old_value_2 = smt.update_leaf(key_1, value_2); @@ -101,9 +110,24 @@ fn test_smt_insert_at_same_key_2() { assert_eq!(smt.root(), tree_root); } } + // HELPERS // -------------------------------------------------------------------------------------------- fn build_single_leaf_node(key: SmtKey, value: Word) -> RpoDigest { SmtLeaf::Single((key, value)).hash() } + +fn build_multiple_leaf_node(kv_pairs: &[(SmtKey, Word)]) -> RpoDigest { + let elements: Vec = kv_pairs + .iter() + .flat_map(|(key, value)| { + let key_elements = key.word.into_iter(); + let value_elements = value.clone().into_iter(); + + key_elements.chain(value_elements) + }) + .collect(); + + Rpo256::hash_elements(&elements) +} From 2b65a8215a0c3d438c3b910d78f7e12c2104055f Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 15:35:42 -0500 Subject: [PATCH 083/121] test inserting multiple values --- src/merkle/smt/tests.rs | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index 98db5206..23f3eaaf 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -111,6 +111,51 @@ fn test_smt_insert_at_same_key_2() { } } +/// This test ensures that the root of the tree is as expected when we add 3 items at 3 different +/// keys +#[test] +fn test_smt_insert_multiple_values() { + let mut smt = Smt::default(); + let mut store: MerkleStore = MerkleStore::default(); + + assert_eq!(smt.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0)); + + let key_1: SmtKey = { + let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; + + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + }; + + let key_2: SmtKey = { + let raw = 0b_11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111_u64; + + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + }; + + let key_3: SmtKey = { + let raw = 0b_00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000_u64; + + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + }; + + let value_1 = [ONE; WORD_SIZE]; + let value_2 = [ONE + ONE; WORD_SIZE]; + let value_3 = [ONE + ONE + ONE; WORD_SIZE]; + + let key_values = [(key_1, value_1), (key_2, value_2), (key_3, value_3)]; + + for (key, value) in key_values { + let key_index: NodeIndex = LeafIndex::::from(key).into(); + + let leaf_node = build_single_leaf_node(key, value); + let tree_root = store.set_node(smt.root(), key_index, leaf_node).unwrap().root; + + let old_value = smt.update_leaf(key, value); + assert_eq!(old_value, EMPTY_WORD); + + assert_eq!(smt.root(), tree_root); + } +} // HELPERS // -------------------------------------------------------------------------------------------- From 8f69d40e568dda021afd0f9533b8b56c2453b96c Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 15:51:49 -0500 Subject: [PATCH 084/121] test_smt_insert_multiple_values --- src/merkle/smt/tests.rs | 78 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index 23f3eaaf..686d804c 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -156,6 +156,84 @@ fn test_smt_insert_multiple_values() { assert_eq!(smt.root(), tree_root); } } + +/// This tests that inserting the empty value does indeed remove the key-value contained at the +/// leaf. We insert & remove 3 values at the same leaf to ensure that all cases are covered (empty, +/// single, multiple). +#[test] +fn test_smt_removal() { + let mut smt = Smt::default(); + + let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; + + let key_1: SmtKey = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into(); + let key_2: SmtKey = + RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(raw)]).into(); + let key_3: SmtKey = + RpoDigest::from([3_u64.into(), 3_u64.into(), 3_u64.into(), Felt::new(raw)]).into(); + + let value_1 = [ONE; WORD_SIZE]; + let value_2 = [2_u64.into(); WORD_SIZE]; + let value_3: [Felt; 4] = [3_u64.into(); WORD_SIZE]; + + // insert key-value 1 + { + let old_value_1 = smt.update_leaf(key_1, value_1); + assert_eq!(old_value_1, EMPTY_WORD); + + assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, value_1))); + } + + // insert key-value 2 + { + let old_value_2 = smt.update_leaf(key_2, value_2); + assert_eq!(old_value_2, EMPTY_WORD); + + assert_eq!( + smt.get_leaf(&key_2), + SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)]) + ); + } + + // insert key-value 3 + { + let old_value_3 = smt.update_leaf(key_3, value_3); + assert_eq!(old_value_3, EMPTY_WORD); + + assert_eq!( + smt.get_leaf(&key_3), + SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2), (key_3, value_3)]) + ); + } + + // remove key 3 + { + let old_value_3 = smt.update_leaf(key_3, EMPTY_WORD); + assert_eq!(old_value_3, value_3); + + assert_eq!( + smt.get_leaf(&key_3), + SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)]) + ); + } + + // remove key 2 + { + let old_value_2 = smt.update_leaf(key_2, EMPTY_WORD); + assert_eq!(old_value_2, value_2); + + assert_eq!(smt.get_leaf(&key_2), SmtLeaf::Single((key_1, value_1))); + } + + // remove key 1 + { + let old_value_1 = smt.update_leaf(key_1, EMPTY_WORD); + assert_eq!(old_value_1, value_1); + + assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, EMPTY_WORD))); + } +} + // HELPERS // -------------------------------------------------------------------------------------------- From f8643bc6c7836bde848426ef750322bb0c39341c Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 15:52:35 -0500 Subject: [PATCH 085/121] simplify interface --- src/merkle/smt/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index ad9b88c0..56d4888f 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -220,9 +220,7 @@ impl SparseMerkleTree for Smt { match self.leaves.get(&leaf_pos) { Some(leaf) => leaf.clone(), - None => { - SmtLeaf::Single((*key, Word::from(*EmptySubtreeRoots::entry(SMT_DEPTH, SMT_DEPTH)))) - } + None => SmtLeaf::Single((*key, Self::EMPTY_VALUE)), } } From 56cc9758f7e5142054cefbed2351bd41d5f9435e Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 15:53:27 -0500 Subject: [PATCH 086/121] core::iter instead of std --- src/merkle/smt/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index 686d804c..aa289950 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -58,7 +58,7 @@ fn test_smt_insert_at_same_key_2() { let value_already_present = [ONE + ONE + ONE; WORD_SIZE]; let mut smt = - Smt::with_entries(std::iter::once((key_already_present, value_already_present))).unwrap(); + Smt::with_entries(core::iter::once((key_already_present, value_already_present))).unwrap(); let mut store: MerkleStore = { let mut store = MerkleStore::default(); From c0dfc2cb8ced9f731838d05e7d8aa3ac81d1e75b Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 16:00:36 -0500 Subject: [PATCH 087/121] test_smt_path_to_keys_in_same_leaf_are_equal --- src/merkle/smt/tests.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index aa289950..3fcf5c73 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -112,7 +112,7 @@ fn test_smt_insert_at_same_key_2() { } /// This test ensures that the root of the tree is as expected when we add 3 items at 3 different -/// keys +/// keys. This also tests that the merkle paths produced are as expected. #[test] fn test_smt_insert_multiple_values() { let mut smt = Smt::default(); @@ -154,6 +154,9 @@ fn test_smt_insert_multiple_values() { assert_eq!(old_value, EMPTY_WORD); assert_eq!(smt.root(), tree_root); + + let expected_path = store.get_path(tree_root, key_index).unwrap(); + assert_eq!(smt.get_leaf_path(key), expected_path.path); } } @@ -234,6 +237,23 @@ fn test_smt_removal() { } } +/// Tests that 2 key-value pairs stored in the same leaf have the same path +#[test] +fn test_smt_path_to_keys_in_same_leaf_are_equal() { + let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; + + let key_1: SmtKey = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into(); + let key_2: SmtKey = + RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(raw)]).into(); + + let value_1 = [ONE; WORD_SIZE]; + let value_2 = [2_u64.into(); WORD_SIZE]; + + let smt = Smt::with_entries([(key_1, value_1), (key_2, value_2)]).unwrap(); + + assert_eq!(smt.get_leaf_path(key_1), smt.get_leaf_path(key_2)); +} + // HELPERS // -------------------------------------------------------------------------------------------- From 8e7457de70caf9989228f3c4f0d33def5a6eaa57 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 16:09:58 -0500 Subject: [PATCH 088/121] cleanup `perform_remove()` --- src/merkle/partial_mt/mod.rs | 2 +- src/merkle/smt/mod.rs | 79 ++++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/src/merkle/partial_mt/mod.rs b/src/merkle/partial_mt/mod.rs index 35af8cd7..1019fcf5 100644 --- a/src/merkle/partial_mt/mod.rs +++ b/src/merkle/partial_mt/mod.rs @@ -179,7 +179,7 @@ impl PartialMerkleTree { /// # Errors /// Returns an error if the specified NodeIndex is not contained in the nodes map. pub fn get_node(&self, index: NodeIndex) -> Result { - self.nodes.get(&index).ok_or(MerkleError::NodeNotInSet(index)).map(|hash| *hash) + self.nodes.get(&index).ok_or(MerkleError::NodeNotInSet(index)).copied() } /// Returns true if provided index contains in the leaves set, false otherwise. diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 56d4888f..97753c4f 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -137,41 +137,11 @@ impl Smt { let leaf_index: LeafIndex = key.into(); if let Some(leaf) = self.leaves.get_mut(&leaf_index.value()) { - match leaf { - SmtLeaf::Single((key_at_leaf, value_at_leaf)) => { - if *key_at_leaf == key { - // our key was indeed stored in the leaf, so we remove the leaf and return - // the value that was stored in it - let old_value = *value_at_leaf; - self.leaves.remove(&leaf_index.value()); - Some(old_value) - } else { - // another key is stored at leaf; nothing to update - None - } - } - SmtLeaf::Multiple(kv_pairs) => { - match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { - Ok(pos) => { - let old_value = kv_pairs[pos].1; - - kv_pairs.remove(pos); - debug_assert!(!kv_pairs.is_empty()); - - if kv_pairs.len() == 1 { - // convert the leaf into `Single` - *leaf = SmtLeaf::Single(kv_pairs[0]); - } - - Some(old_value) - } - Err(_) => { - // other keys are stored at leaf; nothing to update - None - } - } - } + let (old_value, is_empty) = leaf.remove(key); + if is_empty { + self.leaves.remove(&leaf_index.value()); } + old_value } else { // there's nothing stored at the leaf; nothing to update None @@ -344,6 +314,47 @@ impl SmtLeaf { } } } + + /// Remove key-value pair into the leaf stored at key; return the previous value associated with + /// `key`, if any. We also return an `is_empty` flag which indicates whether the leaf is empty, + /// and must be removed from the data structure it is contained in. + fn remove(&mut self, key: SmtKey) -> (Option, bool) { + match self { + SmtLeaf::Single((key_at_leaf, value_at_leaf)) => { + if *key_at_leaf == key { + // our key was indeed stored in the leaf, so we return the value that was stored + // in it, and indicate that the leaf should be removed + let old_value = *value_at_leaf; + + (Some(old_value), true) + } else { + // another key is stored at leaf; nothing to update + (None, false) + } + } + SmtLeaf::Multiple(kv_pairs) => { + match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { + Ok(pos) => { + let old_value = kv_pairs[pos].1; + + kv_pairs.remove(pos); + debug_assert!(!kv_pairs.is_empty()); + + if kv_pairs.len() == 1 { + // convert the leaf into `Single` + *self = SmtLeaf::Single(kv_pairs[0]); + } + + (Some(old_value), false) + } + Err(_) => { + // other keys are stored at leaf; nothing to update + (None, false) + } + } + } + } + } } // HELPER FUNCTIONS From 2179b86901d2060078ce6a6fdf5f0b221e8668b7 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 12 Jan 2024 16:15:19 -0500 Subject: [PATCH 089/121] clippy --- src/merkle/smt/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index 3fcf5c73..a0c584da 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -266,7 +266,7 @@ fn build_multiple_leaf_node(kv_pairs: &[(SmtKey, Word)]) -> RpoDigest { .iter() .flat_map(|(key, value)| { let key_elements = key.word.into_iter(); - let value_elements = value.clone().into_iter(); + let value_elements = (*value).into_iter(); key_elements.chain(value_elements) }) From 3d509d4e87dd685600410e0cbcda6a8a038b941d Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 10:38:39 -0500 Subject: [PATCH 090/121] fix comment --- src/merkle/smt/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 97753c4f..39409737 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -316,8 +316,8 @@ impl SmtLeaf { } /// Remove key-value pair into the leaf stored at key; return the previous value associated with - /// `key`, if any. We also return an `is_empty` flag which indicates whether the leaf is empty, - /// and must be removed from the data structure it is contained in. + /// `key`, if any. We also return an `is_empty` flag which indicates whether the leaf became + /// empty, and must be removed from the data structure it is contained in. fn remove(&mut self, key: SmtKey) -> (Option, bool) { match self { SmtLeaf::Single((key_at_leaf, value_at_leaf)) => { From 0158abd5ad32f7c204bd4c2a3fc1b5cd03fb00ba Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 10:40:53 -0500 Subject: [PATCH 091/121] add `depth()` function --- src/merkle/smt/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 39409737..0ce29346 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -95,6 +95,11 @@ impl Smt { >::get_leaf(self, key) } + /// Returns the depth of the tree + pub const fn depth(&self) -> u8 { + SMT_DEPTH + } + /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. From 609e17c00718f3ec45130969aa6c6502addfa0cc Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 10:41:29 -0500 Subject: [PATCH 092/121] add depth() fn to simple smt --- src/merkle/simple_smt/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index a81fa8d9..1d7bce4a 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -117,6 +117,11 @@ impl SimpleSmt { >::get_leaf(self, key) } + /// Returns the depth of the tree + pub const fn depth(&self) -> u8 { + DEPTH + } + /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. From 1202ff97c7e1b6fdd467d89725c1817daced6f61 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 10:51:25 -0500 Subject: [PATCH 093/121] `SparseMerkleTtree`: rename `update_leaf` to `insert` --- src/merkle/simple_smt/mod.rs | 2 +- src/merkle/smt/mod.rs | 2 +- src/merkle/sparse_merkle_tree.rs | 9 ++++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 1d7bce4a..70bcf00e 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -172,7 +172,7 @@ impl SimpleSmt { /// /// This also recomputes all hashes between the leaf and the root, updating the root itself. pub fn update_leaf(&mut self, key: LeafIndex, value: Word) -> Word { - >::update_leaf(self, key, value) + >::insert(self, key, value) } /// Inserts a subtree at the specified index. The depth at which the subtree is inserted is diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 0ce29346..f71f9f73 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -114,7 +114,7 @@ impl Smt { /// /// This also recomputes all hashes between the leaf and the root, updating the root itself. pub fn update_leaf(&mut self, key: SmtKey, value: Word) -> Word { - >::update_leaf(self, key, value) + >::insert(self, key, value) } // HELPERS diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index 3bd9e05e..24a135e4 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -73,10 +73,13 @@ pub(crate) trait SparseMerkleTree { MerklePath::new(path) } - /// Updates value of the leaf at the specified index returning the old leaf value. + /// Inserts a value at the specified key, returning the previous value associated with that key. + /// Recall that by definition, any key that hasn't been updated is associated with + /// [`Self::EMPTY_VALUE`]. /// - /// This also recomputes all hashes between the leaf and the root, updating the root itself. - fn update_leaf(&mut self, key: Self::Key, value: Self::Value) -> Self::Value { + /// This also recomputes all hashes between the leaf (associated with the key) and the root, + /// updating the root itself. + fn insert(&mut self, key: Self::Key, value: Self::Value) -> Self::Value { let old_value = self.insert_value(key.clone(), value.clone()).unwrap_or(Self::EMPTY_VALUE); // if the old value and new value are the same, there is nothing to update From 6d10f8bff05c65c7d51d41eae10dfc758382cc02 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 10:53:27 -0500 Subject: [PATCH 094/121] `Smt`: rename `update_leaf` --- src/merkle/smt/mod.rs | 11 +++++++---- src/merkle/smt/tests.rs | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index f71f9f73..ed7a4519 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -67,7 +67,7 @@ impl Smt { let mut key_set_to_zero = BTreeSet::new(); for (key, value) in entries { - let old_value = tree.update_leaf(key, value); + let old_value = tree.insert(key, value); if old_value != EMPTY_WORD || key_set_to_zero.contains(&key) { return Err(MerkleError::DuplicateValuesForIndex( @@ -110,10 +110,13 @@ impl Smt { // STATE MUTATORS // -------------------------------------------------------------------------------------------- - /// Updates value of the leaf at the specified index returning the old leaf value. + /// Inserts a value at the specified key, returning the previous value associated with that key. + /// Recall that by definition, any key that hasn't been updated is associated with + /// [`Self::EMPTY_VALUE`]. /// - /// This also recomputes all hashes between the leaf and the root, updating the root itself. - pub fn update_leaf(&mut self, key: SmtKey, value: Word) -> Word { + /// This also recomputes all hashes between the leaf (associated with the key) and the root, + /// updating the root itself. + pub fn insert(&mut self, key: SmtKey, value: Word) -> Word { >::insert(self, key, value) } diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index a0c584da..e6522032 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -26,7 +26,7 @@ fn test_smt_insert_at_same_key() { let leaf_node = build_single_leaf_node(key_1, value_1); let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; - let old_value_1 = smt.update_leaf(key_1, value_1); + let old_value_1 = smt.insert(key_1, value_1); assert_eq!(old_value_1, EMPTY_WORD); assert_eq!(smt.root(), tree_root); @@ -37,7 +37,7 @@ fn test_smt_insert_at_same_key() { let leaf_node = build_single_leaf_node(key_1, value_2); let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; - let old_value_2 = smt.update_leaf(key_1, value_2); + let old_value_2 = smt.insert(key_1, value_2); assert_eq!(old_value_2, value_1); assert_eq!(smt.root(), tree_root); @@ -90,7 +90,7 @@ fn test_smt_insert_at_same_key_2() { ]); let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; - let old_value_1 = smt.update_leaf(key_1, value_1); + let old_value_1 = smt.insert(key_1, value_1); assert_eq!(old_value_1, EMPTY_WORD); assert_eq!(smt.root(), tree_root); @@ -104,7 +104,7 @@ fn test_smt_insert_at_same_key_2() { ]); let tree_root = store.set_node(smt.root(), key_1_index, leaf_node).unwrap().root; - let old_value_2 = smt.update_leaf(key_1, value_2); + let old_value_2 = smt.insert(key_1, value_2); assert_eq!(old_value_2, value_1); assert_eq!(smt.root(), tree_root); @@ -150,7 +150,7 @@ fn test_smt_insert_multiple_values() { let leaf_node = build_single_leaf_node(key, value); let tree_root = store.set_node(smt.root(), key_index, leaf_node).unwrap().root; - let old_value = smt.update_leaf(key, value); + let old_value = smt.insert(key, value); assert_eq!(old_value, EMPTY_WORD); assert_eq!(smt.root(), tree_root); @@ -181,7 +181,7 @@ fn test_smt_removal() { // insert key-value 1 { - let old_value_1 = smt.update_leaf(key_1, value_1); + let old_value_1 = smt.insert(key_1, value_1); assert_eq!(old_value_1, EMPTY_WORD); assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, value_1))); @@ -189,7 +189,7 @@ fn test_smt_removal() { // insert key-value 2 { - let old_value_2 = smt.update_leaf(key_2, value_2); + let old_value_2 = smt.insert(key_2, value_2); assert_eq!(old_value_2, EMPTY_WORD); assert_eq!( @@ -200,7 +200,7 @@ fn test_smt_removal() { // insert key-value 3 { - let old_value_3 = smt.update_leaf(key_3, value_3); + let old_value_3 = smt.insert(key_3, value_3); assert_eq!(old_value_3, EMPTY_WORD); assert_eq!( @@ -211,7 +211,7 @@ fn test_smt_removal() { // remove key 3 { - let old_value_3 = smt.update_leaf(key_3, EMPTY_WORD); + let old_value_3 = smt.insert(key_3, EMPTY_WORD); assert_eq!(old_value_3, value_3); assert_eq!( @@ -222,7 +222,7 @@ fn test_smt_removal() { // remove key 2 { - let old_value_2 = smt.update_leaf(key_2, EMPTY_WORD); + let old_value_2 = smt.insert(key_2, EMPTY_WORD); assert_eq!(old_value_2, value_2); assert_eq!(smt.get_leaf(&key_2), SmtLeaf::Single((key_1, value_1))); @@ -230,7 +230,7 @@ fn test_smt_removal() { // remove key 1 { - let old_value_1 = smt.update_leaf(key_1, EMPTY_WORD); + let old_value_1 = smt.insert(key_1, EMPTY_WORD); assert_eq!(old_value_1, value_1); assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, EMPTY_WORD))); From 4de3face19a9b5c9067075a5b33edf19072fdc51 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 10:55:01 -0500 Subject: [PATCH 095/121] `SimpleSmt`: rename `update_leaf` --- benches/smt.rs | 2 +- benches/store.rs | 2 +- src/merkle/simple_smt/mod.rs | 15 +++++++++------ src/merkle/simple_smt/tests.rs | 8 ++++---- src/merkle/smt/mod.rs | 2 +- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/benches/smt.rs b/benches/smt.rs index d2800c4a..27d26e2f 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -34,7 +34,7 @@ fn smt_rpo(c: &mut Criterion) { &(key, leaf), |b, (key, leaf)| { b.iter(|| { - tree.update_leaf(black_box(LeafIndex::::new(*key).unwrap()), black_box(*leaf)); + tree.insert(black_box(LeafIndex::::new(*key).unwrap()), black_box(*leaf)); }); }, ); diff --git a/benches/store.rs b/benches/store.rs index ed1b159c..43992db7 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -447,7 +447,7 @@ fn update_leaf_simplesmt(c: &mut Criterion) { || (rand_value::() % size_u64, random_word()), |(index, value)| { black_box( - smt.update_leaf(LeafIndex::::new(index).unwrap(), value), + smt.insert(LeafIndex::::new(index).unwrap(), value), ) }, BatchSize::SmallInput, diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 70bcf00e..1f0d814e 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -78,7 +78,7 @@ impl SimpleSmt { return Err(MerkleError::InvalidNumEntries(max_num_entries)); } - let old_value = tree.update_leaf(LeafIndex::::new(key)?, value); + let old_value = tree.insert(LeafIndex::::new(key)?, value); if old_value != Self::EMPTY_VALUE || key_set_to_zero.contains(&key) { return Err(MerkleError::DuplicateValuesForIndex(key)); @@ -168,10 +168,13 @@ impl SimpleSmt { // STATE MUTATORS // -------------------------------------------------------------------------------------------- - /// Updates value of the leaf at the specified index returning the old leaf value. + /// Inserts a value at the specified key, returning the previous value associated with that key. + /// Recall that by definition, any key that hasn't been updated is associated with + /// [`EMPTY_WORD`]. /// - /// This also recomputes all hashes between the leaf and the root, updating the root itself. - pub fn update_leaf(&mut self, key: LeafIndex, value: Word) -> Word { + /// This also recomputes all hashes between the leaf (associated with the key) and the root, + /// updating the root itself. + pub fn insert(&mut self, key: LeafIndex, value: Word) -> Word { >::insert(self, key, value) } @@ -296,11 +299,11 @@ impl TryApplyDiff for SimpleSmt { } for slot in diff.cleared_slots() { - self.update_leaf(LeafIndex::::new(*slot)?, Self::EMPTY_VALUE); + self.insert(LeafIndex::::new(*slot)?, Self::EMPTY_VALUE); } for (slot, value) in diff.updated_slots() { - self.update_leaf(LeafIndex::::new(*slot)?, *value); + self.insert(LeafIndex::::new(*slot)?, *value); } Ok(()) diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index c6552b1a..ac7c943c 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -54,7 +54,7 @@ fn build_sparse_tree() { let key = 6; let new_node = int_to_leaf(7); values[key as usize] = new_node; - let old_value = smt.update_leaf(LeafIndex::::new(key).unwrap(), new_node); + let old_value = smt.insert(LeafIndex::::new(key).unwrap(), new_node); let mt2 = MerkleTree::new(values.clone()).unwrap(); assert_eq!(mt2.root(), smt.root()); assert_eq!( @@ -67,7 +67,7 @@ fn build_sparse_tree() { let key = 2; let new_node = int_to_leaf(3); values[key as usize] = new_node; - let old_value = smt.update_leaf(LeafIndex::::new(key).unwrap(), new_node); + let old_value = smt.insert(LeafIndex::::new(key).unwrap(), new_node); let mt3 = MerkleTree::new(values).unwrap(); assert_eq!(mt3.root(), smt.root()); assert_eq!( @@ -158,7 +158,7 @@ fn update_leaf() { expected_values[key] = new_node; let expected_tree = MerkleTree::new(expected_values.clone()).unwrap(); - let old_leaf = tree.update_leaf(LeafIndex::::new(key as u64).unwrap(), new_node); + let old_leaf = tree.insert(LeafIndex::::new(key as u64).unwrap(), new_node); assert_eq!(expected_tree.root(), tree.root); assert_eq!(old_leaf, *VALUES8[key]); @@ -168,7 +168,7 @@ fn update_leaf() { expected_values[key] = new_node; let expected_tree = MerkleTree::new(expected_values.clone()).unwrap(); - let old_leaf = tree.update_leaf(LeafIndex::::new(key as u64).unwrap(), new_node); + let old_leaf = tree.insert(LeafIndex::::new(key as u64).unwrap(), new_node); assert_eq!(expected_tree.root(), tree.root); assert_eq!(old_leaf, *VALUES8[key]); } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index ed7a4519..5e77cc30 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -112,7 +112,7 @@ impl Smt { /// Inserts a value at the specified key, returning the previous value associated with that key. /// Recall that by definition, any key that hasn't been updated is associated with - /// [`Self::EMPTY_VALUE`]. + /// [`EMPTY_WORD`]. /// /// This also recomputes all hashes between the leaf (associated with the key) and the root, /// updating the root itself. From bd7d65d1b93c20afe702d990ec34c0c8a6444f8d Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 10:57:09 -0500 Subject: [PATCH 096/121] fmt --- benches/store.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/benches/store.rs b/benches/store.rs index 43992db7..080c5cd9 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -446,9 +446,7 @@ fn update_leaf_simplesmt(c: &mut Criterion) { b.iter_batched( || (rand_value::() % size_u64, random_word()), |(index, value)| { - black_box( - smt.insert(LeafIndex::::new(index).unwrap(), value), - ) + black_box(smt.insert(LeafIndex::::new(index).unwrap(), value)) }, BatchSize::SmallInput, ) From 25f1c64e5c8e241a7613361b58fdbb892f7bc2f4 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 15:01:21 -0500 Subject: [PATCH 097/121] get_leaf_path -> open --- benches/smt.rs | 2 +- benches/store.rs | 2 +- src/merkle/simple_smt/mod.rs | 4 ++-- src/merkle/simple_smt/tests.rs | 14 +++++++------- src/merkle/smt/mod.rs | 4 ++-- src/merkle/smt/tests.rs | 4 ++-- src/merkle/sparse_merkle_tree.rs | 2 +- src/merkle/store/tests.rs | 14 +++++++------- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/benches/smt.rs b/benches/smt.rs index 27d26e2f..a0296d8c 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -52,7 +52,7 @@ fn smt_rpo(c: &mut Criterion) { &key, |b, key| { b.iter(|| { - tree.get_leaf_path(black_box(LeafIndex::::new(*key).unwrap())); + tree.open(black_box(LeafIndex::::new(*key).unwrap())); }); }, ); diff --git a/benches/store.rs b/benches/store.rs index 080c5cd9..f59a917b 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -297,7 +297,7 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { || random_index(size_u64, SMT_MAX_DEPTH), |index| { black_box( - smt.get_leaf_path(LeafIndex::::new(index.value()).unwrap()), + smt.open(LeafIndex::::new(index.value()).unwrap()), ) }, BatchSize::SmallInput, diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 1f0d814e..83478f25 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -125,8 +125,8 @@ impl SimpleSmt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn get_leaf_path(&self, key: LeafIndex) -> MerklePath { - >::get_leaf_path(self, key) + pub fn open(&self, key: LeafIndex) -> MerklePath { + >::open(self, key) } /// Returns a node at the specified index. diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index ac7c943c..d0a31a43 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -59,7 +59,7 @@ fn build_sparse_tree() { assert_eq!(mt2.root(), smt.root()); assert_eq!( mt2.get_path(NodeIndex::make(3, 6)).unwrap(), - smt.get_leaf_path(LeafIndex::<3>::new(6).unwrap()) + smt.open(LeafIndex::<3>::new(6).unwrap()) ); assert_eq!(old_value, EMPTY_WORD); @@ -72,7 +72,7 @@ fn build_sparse_tree() { assert_eq!(mt3.root(), smt.root()); assert_eq!( mt3.get_path(NodeIndex::make(3, 2)).unwrap(), - smt.get_leaf_path(LeafIndex::<3>::new(2).unwrap()) + smt.open(LeafIndex::<3>::new(2).unwrap()) ); assert_eq!(old_value, EMPTY_WORD); } @@ -108,10 +108,10 @@ fn test_depth2_tree() { assert_eq!(VALUES4[3], tree.get_node(NodeIndex::make(2, 3)).unwrap()); // check get_path(): depth 2 - assert_eq!(vec![VALUES4[1], node3], *tree.get_leaf_path(LeafIndex::<2>::new(0).unwrap())); - assert_eq!(vec![VALUES4[0], node3], *tree.get_leaf_path(LeafIndex::<2>::new(1).unwrap())); - assert_eq!(vec![VALUES4[3], node2], *tree.get_leaf_path(LeafIndex::<2>::new(2).unwrap())); - assert_eq!(vec![VALUES4[2], node2], *tree.get_leaf_path(LeafIndex::<2>::new(3).unwrap())); + assert_eq!(vec![VALUES4[1], node3], *tree.open(LeafIndex::<2>::new(0).unwrap())); + assert_eq!(vec![VALUES4[0], node3], *tree.open(LeafIndex::<2>::new(1).unwrap())); + assert_eq!(vec![VALUES4[3], node2], *tree.open(LeafIndex::<2>::new(2).unwrap())); + assert_eq!(vec![VALUES4[2], node2], *tree.open(LeafIndex::<2>::new(3).unwrap())); } #[test] @@ -213,7 +213,7 @@ fn small_tree_opening_is_consistent() { ]; for (key, path) in cases { - let opening = tree.get_leaf_path(LeafIndex::<3>::new(key).unwrap()); + let opening = tree.open(LeafIndex::<3>::new(key).unwrap()); assert_eq!(path, *opening); } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 5e77cc30..350342b1 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -103,8 +103,8 @@ impl Smt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn get_leaf_path(&self, key: SmtKey) -> MerklePath { - >::get_leaf_path(self, key) + pub fn open(&self, key: SmtKey) -> MerklePath { + >::open(self, key) } // STATE MUTATORS diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index e6522032..7d8b03b9 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -156,7 +156,7 @@ fn test_smt_insert_multiple_values() { assert_eq!(smt.root(), tree_root); let expected_path = store.get_path(tree_root, key_index).unwrap(); - assert_eq!(smt.get_leaf_path(key), expected_path.path); + assert_eq!(smt.open(key), expected_path.path); } } @@ -251,7 +251,7 @@ fn test_smt_path_to_keys_in_same_leaf_are_equal() { let smt = Smt::with_entries([(key_1, value_1), (key_2, value_2)]).unwrap(); - assert_eq!(smt.get_leaf_path(key_1), smt.get_leaf_path(key_2)); + assert_eq!(smt.open(key_1), smt.open(key_2)); } // HELPERS diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index 24a135e4..0aee6111 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -55,7 +55,7 @@ pub(crate) trait SparseMerkleTree { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - fn get_leaf_path(&self, key: Self::Key) -> MerklePath { + fn open(&self, key: Self::Key) -> MerklePath { let mut index: NodeIndex = { let leaf_index: LeafIndex = key.into(); leaf_index.into() diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index c537c855..0e3cd0ac 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -182,7 +182,7 @@ fn test_leaf_paths_for_empty_trees() -> Result<(), MerkleError> { let index = NodeIndex::make(DEPTH, 0); let store_path = store.get_path(smt.root(), index)?; - let smt_path = smt.get_leaf_path(LeafIndex::::new(0)?); + let smt_path = smt.open(LeafIndex::::new(0)?); assert_eq!( store_path.value, RpoDigest::default(), @@ -301,7 +301,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 0 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(0).unwrap()), + smt.open(LeafIndex::::new(0).unwrap()), result.path, "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" ); @@ -312,7 +312,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 1 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(1).unwrap()), + smt.open(LeafIndex::::new(1).unwrap()), result.path, "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" ); @@ -323,7 +323,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 2 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(2).unwrap()), + smt.open(LeafIndex::::new(2).unwrap()), result.path, "merkle path for index 2 must be the same for the MerkleTree and MerkleStore" ); @@ -334,7 +334,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 3 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(3).unwrap()), + smt.open(LeafIndex::::new(3).unwrap()), result.path, "merkle path for index 3 must be the same for the MerkleTree and MerkleStore" ); @@ -346,7 +346,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 4 must match leaf value" ); assert_eq!( - smt.get_leaf_path(LeafIndex::::new(4).unwrap()), + smt.open(LeafIndex::::new(4).unwrap()), result.path, "merkle path for index 4 must be the same for the MerkleTree and MerkleStore" ); @@ -563,7 +563,7 @@ fn test_constructors() -> Result<(), MerkleError> { for key in KEYS4 { let index = NodeIndex::make(DEPTH, key); let value_path = store.get_path(smt.root(), index)?; - assert_eq!(smt.get_leaf_path(LeafIndex::::new(key).unwrap()), value_path.path); + assert_eq!(smt.open(LeafIndex::::new(key).unwrap()), value_path.path); } let d = 2; From 5171cd8316049eeda960884db72a929a3aa6a770 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 15:08:23 -0500 Subject: [PATCH 098/121] `SparseMerkleTree::Opening` type --- benches/store.rs | 4 +--- src/merkle/simple_smt/mod.rs | 1 + src/merkle/smt/mod.rs | 1 + src/merkle/sparse_merkle_tree.rs | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/benches/store.rs b/benches/store.rs index f59a917b..ede98bed 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -296,9 +296,7 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { b.iter_batched( || random_index(size_u64, SMT_MAX_DEPTH), |index| { - black_box( - smt.open(LeafIndex::::new(index.value()).unwrap()), - ) + black_box(smt.open(LeafIndex::::new(index.value()).unwrap())) }, BatchSize::SmallInput, ) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 83478f25..c337729a 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -243,6 +243,7 @@ impl SparseMerkleTree for SimpleSmt { type Key = LeafIndex; type Value = Word; type Leaf = Word; + type Opening = (MerklePath, Word); const EMPTY_VALUE: Self::Value = EMPTY_WORD; diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 350342b1..3800bfb7 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -161,6 +161,7 @@ impl SparseMerkleTree for Smt { type Key = SmtKey; type Value = Word; type Leaf = SmtLeaf; + type Opening = (MerklePath, SmtLeaf); const EMPTY_VALUE: Self::Value = EMPTY_WORD; diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index 0aee6111..3e1f25a5 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -45,6 +45,8 @@ pub(crate) trait SparseMerkleTree { type Value: Clone + PartialEq; /// The type for a leaf type Leaf; + /// The type for an opening (i.e. a "proof") of a leaf + type Opening: Into<(MerklePath, Self::Leaf)>; /// The default value used to compute the hash of empty leaves const EMPTY_VALUE: Self::Value; From 81e5d2a712d68306fc00aad696f6c865b21c41e0 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 15:27:39 -0500 Subject: [PATCH 099/121] `open()` returns `Self::Opening` --- src/merkle/simple_smt/mod.rs | 2 +- src/merkle/simple_smt/tests.rs | 14 +++++++------- src/merkle/smt/mod.rs | 2 +- src/merkle/smt/tests.rs | 2 +- src/merkle/sparse_merkle_tree.rs | 28 +++++++++++++++++----------- src/merkle/store/tests.rs | 14 +++++++------- 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index c337729a..6a05a6d1 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -125,7 +125,7 @@ impl SimpleSmt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: LeafIndex) -> MerklePath { + pub fn open(&self, key: LeafIndex) -> (MerklePath, Word) { >::open(self, key) } diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index d0a31a43..b952adfa 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -59,7 +59,7 @@ fn build_sparse_tree() { assert_eq!(mt2.root(), smt.root()); assert_eq!( mt2.get_path(NodeIndex::make(3, 6)).unwrap(), - smt.open(LeafIndex::<3>::new(6).unwrap()) + smt.open(LeafIndex::<3>::new(6).unwrap()).0 ); assert_eq!(old_value, EMPTY_WORD); @@ -72,7 +72,7 @@ fn build_sparse_tree() { assert_eq!(mt3.root(), smt.root()); assert_eq!( mt3.get_path(NodeIndex::make(3, 2)).unwrap(), - smt.open(LeafIndex::<3>::new(2).unwrap()) + smt.open(LeafIndex::<3>::new(2).unwrap()).0 ); assert_eq!(old_value, EMPTY_WORD); } @@ -108,10 +108,10 @@ fn test_depth2_tree() { assert_eq!(VALUES4[3], tree.get_node(NodeIndex::make(2, 3)).unwrap()); // check get_path(): depth 2 - assert_eq!(vec![VALUES4[1], node3], *tree.open(LeafIndex::<2>::new(0).unwrap())); - assert_eq!(vec![VALUES4[0], node3], *tree.open(LeafIndex::<2>::new(1).unwrap())); - assert_eq!(vec![VALUES4[3], node2], *tree.open(LeafIndex::<2>::new(2).unwrap())); - assert_eq!(vec![VALUES4[2], node2], *tree.open(LeafIndex::<2>::new(3).unwrap())); + assert_eq!(vec![VALUES4[1], node3], *tree.open(LeafIndex::<2>::new(0).unwrap()).0); + assert_eq!(vec![VALUES4[0], node3], *tree.open(LeafIndex::<2>::new(1).unwrap()).0); + assert_eq!(vec![VALUES4[3], node2], *tree.open(LeafIndex::<2>::new(2).unwrap()).0); + assert_eq!(vec![VALUES4[2], node2], *tree.open(LeafIndex::<2>::new(3).unwrap()).0); } #[test] @@ -213,7 +213,7 @@ fn small_tree_opening_is_consistent() { ]; for (key, path) in cases { - let opening = tree.open(LeafIndex::<3>::new(key).unwrap()); + let (opening, _) = tree.open(LeafIndex::<3>::new(key).unwrap()); assert_eq!(path, *opening); } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 3800bfb7..624da8d1 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -103,7 +103,7 @@ impl Smt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: SmtKey) -> MerklePath { + pub fn open(&self, key: SmtKey) -> (MerklePath, SmtLeaf) { >::open(self, key) } diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index 7d8b03b9..02b10534 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -156,7 +156,7 @@ fn test_smt_insert_multiple_values() { assert_eq!(smt.root(), tree_root); let expected_path = store.get_path(tree_root, key_index).unwrap(); - assert_eq!(smt.open(key), expected_path.path); + assert_eq!(smt.open(key).0, expected_path.path); } } diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index 3e1f25a5..1400bc00 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -46,7 +46,7 @@ pub(crate) trait SparseMerkleTree { /// The type for a leaf type Leaf; /// The type for an opening (i.e. a "proof") of a leaf - type Opening: Into<(MerklePath, Self::Leaf)>; + type Opening: From<(MerklePath, Self::Leaf)>; /// The default value used to compute the hash of empty leaves const EMPTY_VALUE: Self::Value; @@ -57,22 +57,28 @@ pub(crate) trait SparseMerkleTree { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - fn open(&self, key: Self::Key) -> MerklePath { + fn open(&self, key: Self::Key) -> Self::Opening { + let leaf = self.get_leaf(&key); + let mut index: NodeIndex = { let leaf_index: LeafIndex = key.into(); leaf_index.into() }; - let mut path = Vec::with_capacity(index.depth() as usize); - for _ in 0..index.depth() { - let is_right = index.is_value_odd(); - index.move_up(); - let InnerNode { left, right } = self.get_inner_node(index); - let value = if is_right { left } else { right }; - path.push(value); - } + let merkle_path = { + let mut path = Vec::with_capacity(index.depth() as usize); + for _ in 0..index.depth() { + let is_right = index.is_value_odd(); + index.move_up(); + let InnerNode { left, right } = self.get_inner_node(index); + let value = if is_right { left } else { right }; + path.push(value); + } + + MerklePath::new(path) + }; - MerklePath::new(path) + (merkle_path, leaf).into() } /// Inserts a value at the specified key, returning the previous value associated with that key. diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index 0e3cd0ac..3bb11e1b 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -182,7 +182,7 @@ fn test_leaf_paths_for_empty_trees() -> Result<(), MerkleError> { let index = NodeIndex::make(DEPTH, 0); let store_path = store.get_path(smt.root(), index)?; - let smt_path = smt.open(LeafIndex::::new(0)?); + let smt_path = smt.open(LeafIndex::::new(0)?).0; assert_eq!( store_path.value, RpoDigest::default(), @@ -301,7 +301,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 0 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(0).unwrap()), + smt.open(LeafIndex::::new(0).unwrap()).0, result.path, "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" ); @@ -312,7 +312,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 1 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(1).unwrap()), + smt.open(LeafIndex::::new(1).unwrap()).0, result.path, "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" ); @@ -323,7 +323,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 2 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(2).unwrap()), + smt.open(LeafIndex::::new(2).unwrap()).0, result.path, "merkle path for index 2 must be the same for the MerkleTree and MerkleStore" ); @@ -334,7 +334,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 3 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(3).unwrap()), + smt.open(LeafIndex::::new(3).unwrap()).0, result.path, "merkle path for index 3 must be the same for the MerkleTree and MerkleStore" ); @@ -346,7 +346,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 4 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(4).unwrap()), + smt.open(LeafIndex::::new(4).unwrap()).0, result.path, "merkle path for index 4 must be the same for the MerkleTree and MerkleStore" ); @@ -563,7 +563,7 @@ fn test_constructors() -> Result<(), MerkleError> { for key in KEYS4 { let index = NodeIndex::make(DEPTH, key); let value_path = store.get_path(smt.root(), index)?; - assert_eq!(smt.open(LeafIndex::::new(key).unwrap()), value_path.path); + assert_eq!(smt.open(LeafIndex::::new(key).unwrap()).0, value_path.path); } let d = 2; From c7149d520fec09c4387f2285a5a104b021059193 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 16:03:35 -0500 Subject: [PATCH 100/121] Introduce `key_to_leaf_index` --- src/merkle/mod.rs | 2 +- src/merkle/simple_smt/mod.rs | 4 ++ src/merkle/smt/mod.rs | 75 ++++++++++---------------------- src/merkle/smt/tests.rs | 46 ++++++++++---------- src/merkle/sparse_merkle_tree.rs | 16 +++++-- 5 files changed, 64 insertions(+), 79 deletions(-) diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 5d8b5421..8bbc38ac 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -31,7 +31,7 @@ pub(crate) mod sparse_merkle_tree; pub use sparse_merkle_tree::{LeafIndex, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; mod smt; -pub use smt::{Smt, SmtKey, SmtLeaf, SMT_DEPTH}; +pub use smt::{Smt, SmtLeaf, SMT_DEPTH}; mod tiered_smt; pub use tiered_smt::{TieredSmt, TieredSmtProof, TieredSmtProofError}; diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index 6a05a6d1..a486d18b 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -286,6 +286,10 @@ impl SparseMerkleTree for SimpleSmt { // `SimpleSmt` takes the leaf value itself as the hash leaf.into() } + + fn key_to_leaf_index(leaf: &LeafIndex) -> LeafIndex { + *leaf + } } // TRY APPLY DIFF diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 624da8d1..ee684893 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -57,7 +57,7 @@ impl Smt { /// - The number of entries exceeds 2^63 entries. /// - The provided entries contain multiple values for the same key. pub fn with_entries( - entries: impl IntoIterator, + entries: impl IntoIterator, ) -> Result { // create an empty tree let mut tree = Self::new(); @@ -91,7 +91,7 @@ impl Smt { } /// Returns the leaf at the specified index. - pub fn get_leaf(&self, key: &SmtKey) -> SmtLeaf { + pub fn get_leaf(&self, key: &RpoDigest) -> SmtLeaf { >::get_leaf(self, key) } @@ -103,7 +103,7 @@ impl Smt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: SmtKey) -> (MerklePath, SmtLeaf) { + pub fn open(&self, key: RpoDigest) -> (MerklePath, SmtLeaf) { >::open(self, key) } @@ -116,7 +116,7 @@ impl Smt { /// /// This also recomputes all hashes between the leaf (associated with the key) and the root, /// updating the root itself. - pub fn insert(&mut self, key: SmtKey, value: Word) -> Word { + pub fn insert(&mut self, key: RpoDigest, value: Word) -> Word { >::insert(self, key, value) } @@ -125,10 +125,10 @@ impl Smt { /// Inserts `value` at leaf index pointed to by `key`. `value` is guaranteed to not be the empty /// value, such that this is indeed an insertion. - fn perform_insert(&mut self, key: SmtKey, value: Word) -> Option { + fn perform_insert(&mut self, key: RpoDigest, value: Word) -> Option { debug_assert_ne!(value, Self::EMPTY_VALUE); - let leaf_index: LeafIndex = key.into(); + let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); match self.leaves.get_mut(&leaf_index.value()) { Some(leaf) => leaf.insert(key, value), @@ -141,8 +141,8 @@ impl Smt { } /// Removes key-value pair at leaf index pointed to by `key` if it exists. - fn perform_remove(&mut self, key: SmtKey) -> Option { - let leaf_index: LeafIndex = key.into(); + fn perform_remove(&mut self, key: RpoDigest) -> Option { + let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); if let Some(leaf) = self.leaves.get_mut(&leaf_index.value()) { let (old_value, is_empty) = leaf.remove(key); @@ -158,7 +158,7 @@ impl Smt { } impl SparseMerkleTree for Smt { - type Key = SmtKey; + type Key = RpoDigest; type Value = Word; type Leaf = SmtLeaf; type Opening = (MerklePath, SmtLeaf); @@ -194,7 +194,7 @@ impl SparseMerkleTree for Smt { } } - fn get_leaf(&self, key: &Self::Key) -> Self::Leaf { + fn get_leaf(&self, key: &RpoDigest) -> Self::Leaf { let leaf_pos = LeafIndex::::from(*key).value(); match self.leaves.get(&leaf_pos) { @@ -206,6 +206,11 @@ impl SparseMerkleTree for Smt { fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest { leaf.hash() } + + fn key_to_leaf_index(key: &RpoDigest) -> LeafIndex { + let most_significant_felt = key[3]; + LeafIndex::new_max_depth(most_significant_felt.as_int()) + } } impl Default for Smt { @@ -214,46 +219,14 @@ impl Default for Smt { } } -// SMT KEY -// ================================================================================================ - -/// Represents a key (256 bits) for the Smt. -/// -/// The most significant `u64` determines the corresponding leaf index when inserting values into -/// the Smt. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct SmtKey { - word: RpoDigest, -} - -impl From for LeafIndex { - fn from(key: SmtKey) -> Self { - let most_significant_felt = key.word[3]; - Self::new_max_depth(most_significant_felt.as_int()) - } -} - -impl From for SmtKey { - fn from(digest: RpoDigest) -> Self { - Self { word: digest } - } -} - -impl From for SmtKey { - fn from(word: Word) -> Self { - Self { word: word.into() } - } -} - // LEAF // ================================================================================================ #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum SmtLeaf { - Single((SmtKey, Word)), - Multiple(Vec<(SmtKey, Word)>), + Single((RpoDigest, Word)), + Multiple(Vec<(RpoDigest, Word)>), } impl SmtLeaf { @@ -273,7 +246,7 @@ impl SmtLeaf { /// Compute the hash of the leaf pub fn hash(&self) -> RpoDigest { match self { - SmtLeaf::Single((key, value)) => Rpo256::merge(&[key.word, value.into()]), + SmtLeaf::Single((key, value)) => Rpo256::merge(&[*key, value.into()]), SmtLeaf::Multiple(kvs) => { let elements: Vec = kvs.iter().copied().flat_map(kv_to_elements).collect(); Rpo256::hash_elements(&elements) @@ -286,7 +259,7 @@ impl SmtLeaf { /// Insert key-value pair into the leaf; return the previous value associated with `key`, if /// any. - fn insert(&mut self, key: SmtKey, value: Word) -> Option { + fn insert(&mut self, key: RpoDigest, value: Word) -> Option { match self { SmtLeaf::Single(kv_pair) => { if kv_pair.0 == key { @@ -327,7 +300,7 @@ impl SmtLeaf { /// Remove key-value pair into the leaf stored at key; return the previous value associated with /// `key`, if any. We also return an `is_empty` flag which indicates whether the leaf became /// empty, and must be removed from the data structure it is contained in. - fn remove(&mut self, key: SmtKey) -> (Option, bool) { + fn remove(&mut self, key: RpoDigest) -> (Option, bool) { match self { SmtLeaf::Single((key_at_leaf, value_at_leaf)) => { if *key_at_leaf == key { @@ -370,8 +343,8 @@ impl SmtLeaf { // ================================================================================================ /// Converts a key-value tuple to an iterator of `Felt`s -fn kv_to_elements((key, value): (SmtKey, Word)) -> impl Iterator { - let key_elements = key.word.into_iter(); +fn kv_to_elements((key, value): (RpoDigest, Word)) -> impl Iterator { + let key_elements = key.into_iter(); let value_elements = value.into_iter(); key_elements.chain(value_elements) @@ -379,8 +352,8 @@ fn kv_to_elements((key, value): (SmtKey, Word)) -> impl Iterator { /// Compares two keys, compared element-by-element using their integer representations starting with /// the most significant element. -fn cmp_keys(key_1: SmtKey, key_2: SmtKey) -> Ordering { - for (v1, v2) in key_1.word.iter().zip(key_2.word.iter()).rev() { +fn cmp_keys(key_1: RpoDigest, key_2: RpoDigest) -> Ordering { + for (v1, v2) in key_1.iter().zip(key_2.iter()).rev() { let v1 = v1.as_int(); let v2 = v2.as_int(); if v1 != v2 { diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index 02b10534..d341cab3 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -11,10 +11,10 @@ fn test_smt_insert_at_same_key() { assert_eq!(smt.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0)); - let key_1: SmtKey = { + let key_1: RpoDigest = { let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; - RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]) }; let key_1_index: NodeIndex = LeafIndex::::from(key_1).into(); @@ -48,10 +48,10 @@ fn test_smt_insert_at_same_key() { /// only the case where the leaf type is `SmtLeaf::Multiple` #[test] fn test_smt_insert_at_same_key_2() { - let key_already_present: SmtKey = { + let key_already_present: RpoDigest = { let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; - RpoDigest::from([ONE + ONE, ONE + ONE, ONE + ONE, Felt::new(raw)]).into() + RpoDigest::from([ONE + ONE, ONE + ONE, ONE + ONE, Felt::new(raw)]) }; let key_already_present_index: NodeIndex = LeafIndex::::from(key_already_present).into(); @@ -69,10 +69,10 @@ fn test_smt_insert_at_same_key_2() { store }; - let key_1: SmtKey = { + let key_1: RpoDigest = { let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; - RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]) }; let key_1_index: NodeIndex = LeafIndex::::from(key_1).into(); @@ -120,22 +120,22 @@ fn test_smt_insert_multiple_values() { assert_eq!(smt.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0)); - let key_1: SmtKey = { + let key_1: RpoDigest = { let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; - RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]) }; - let key_2: SmtKey = { + let key_2: RpoDigest = { let raw = 0b_11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111_u64; - RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]) }; - let key_3: SmtKey = { + let key_3: RpoDigest = { let raw = 0b_00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000_u64; - RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into() + RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]) }; let value_1 = [ONE; WORD_SIZE]; @@ -169,11 +169,11 @@ fn test_smt_removal() { let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; - let key_1: SmtKey = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into(); - let key_2: SmtKey = - RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(raw)]).into(); - let key_3: SmtKey = - RpoDigest::from([3_u64.into(), 3_u64.into(), 3_u64.into(), Felt::new(raw)]).into(); + let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]); + let key_2: RpoDigest = + RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(raw)]); + let key_3: RpoDigest = + RpoDigest::from([3_u64.into(), 3_u64.into(), 3_u64.into(), Felt::new(raw)]); let value_1 = [ONE; WORD_SIZE]; let value_2 = [2_u64.into(); WORD_SIZE]; @@ -242,9 +242,9 @@ fn test_smt_removal() { fn test_smt_path_to_keys_in_same_leaf_are_equal() { let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; - let key_1: SmtKey = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]).into(); - let key_2: SmtKey = - RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(raw)]).into(); + let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]); + let key_2: RpoDigest = + RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(raw)]); let value_1 = [ONE; WORD_SIZE]; let value_2 = [2_u64.into(); WORD_SIZE]; @@ -257,15 +257,15 @@ fn test_smt_path_to_keys_in_same_leaf_are_equal() { // HELPERS // -------------------------------------------------------------------------------------------- -fn build_single_leaf_node(key: SmtKey, value: Word) -> RpoDigest { +fn build_single_leaf_node(key: RpoDigest, value: Word) -> RpoDigest { SmtLeaf::Single((key, value)).hash() } -fn build_multiple_leaf_node(kv_pairs: &[(SmtKey, Word)]) -> RpoDigest { +fn build_multiple_leaf_node(kv_pairs: &[(RpoDigest, Word)]) -> RpoDigest { let elements: Vec = kv_pairs .iter() .flat_map(|(key, value)| { - let key_elements = key.word.into_iter(); + let key_elements = key.into_iter(); let value_elements = (*value).into_iter(); key_elements.chain(value_elements) diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index 1400bc00..d01000a0 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -39,8 +39,8 @@ pub const SMT_MAX_DEPTH: u8 = 64; /// /// [SparseMerkleTree] currently doesn't support optimizations that compress Merkle proofs. pub(crate) trait SparseMerkleTree { - /// The type for a key, which must be convertible into a `u64` infaillibly - type Key: Into> + Clone; + /// The type for a key + type Key: Clone; /// The type for a value type Value: Clone + PartialEq; /// The type for a leaf @@ -61,7 +61,7 @@ pub(crate) trait SparseMerkleTree { let leaf = self.get_leaf(&key); let mut index: NodeIndex = { - let leaf_index: LeafIndex = key.into(); + let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); leaf_index.into() }; @@ -97,7 +97,7 @@ pub(crate) trait SparseMerkleTree { let leaf = self.get_leaf(&key); let node_index = { - let leaf_index: LeafIndex = key.into(); + let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); leaf_index.into() }; @@ -148,6 +148,8 @@ pub(crate) trait SparseMerkleTree { /// Returns the hash of a leaf fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest; + + fn key_to_leaf_index(key: &Self::Key) -> LeafIndex; } // INNER NODE @@ -225,3 +227,9 @@ impl From for LeafIndex { Self::new_max_depth(value[3].as_int()) } } + +impl From for LeafIndex { + fn from(value: RpoDigest) -> Self { + Word::from(value).into() + } +} From a9b53c0429f5756e2afc690f5c3a6e109e48040e Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 16:07:17 -0500 Subject: [PATCH 101/121] open() takes a reference to `key` --- benches/smt.rs | 2 +- benches/store.rs | 2 +- src/merkle/simple_smt/mod.rs | 2 +- src/merkle/simple_smt/tests.rs | 14 +++++++------- src/merkle/smt/mod.rs | 2 +- src/merkle/smt/tests.rs | 4 ++-- src/merkle/sparse_merkle_tree.rs | 6 +++--- src/merkle/store/tests.rs | 14 +++++++------- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/benches/smt.rs b/benches/smt.rs index a0296d8c..a8c410f9 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -52,7 +52,7 @@ fn smt_rpo(c: &mut Criterion) { &key, |b, key| { b.iter(|| { - tree.open(black_box(LeafIndex::::new(*key).unwrap())); + tree.open(black_box(&LeafIndex::::new(*key).unwrap())); }); }, ); diff --git a/benches/store.rs b/benches/store.rs index ede98bed..ca1bbcd1 100644 --- a/benches/store.rs +++ b/benches/store.rs @@ -296,7 +296,7 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) { b.iter_batched( || random_index(size_u64, SMT_MAX_DEPTH), |index| { - black_box(smt.open(LeafIndex::::new(index.value()).unwrap())) + black_box(smt.open(&LeafIndex::::new(index.value()).unwrap())) }, BatchSize::SmallInput, ) diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs index a486d18b..8a167755 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/simple_smt/mod.rs @@ -125,7 +125,7 @@ impl SimpleSmt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: LeafIndex) -> (MerklePath, Word) { + pub fn open(&self, key: &LeafIndex) -> (MerklePath, Word) { >::open(self, key) } diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/simple_smt/tests.rs index b952adfa..3c74cef6 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/simple_smt/tests.rs @@ -59,7 +59,7 @@ fn build_sparse_tree() { assert_eq!(mt2.root(), smt.root()); assert_eq!( mt2.get_path(NodeIndex::make(3, 6)).unwrap(), - smt.open(LeafIndex::<3>::new(6).unwrap()).0 + smt.open(&LeafIndex::<3>::new(6).unwrap()).0 ); assert_eq!(old_value, EMPTY_WORD); @@ -72,7 +72,7 @@ fn build_sparse_tree() { assert_eq!(mt3.root(), smt.root()); assert_eq!( mt3.get_path(NodeIndex::make(3, 2)).unwrap(), - smt.open(LeafIndex::<3>::new(2).unwrap()).0 + smt.open(&LeafIndex::<3>::new(2).unwrap()).0 ); assert_eq!(old_value, EMPTY_WORD); } @@ -108,10 +108,10 @@ fn test_depth2_tree() { assert_eq!(VALUES4[3], tree.get_node(NodeIndex::make(2, 3)).unwrap()); // check get_path(): depth 2 - assert_eq!(vec![VALUES4[1], node3], *tree.open(LeafIndex::<2>::new(0).unwrap()).0); - assert_eq!(vec![VALUES4[0], node3], *tree.open(LeafIndex::<2>::new(1).unwrap()).0); - assert_eq!(vec![VALUES4[3], node2], *tree.open(LeafIndex::<2>::new(2).unwrap()).0); - assert_eq!(vec![VALUES4[2], node2], *tree.open(LeafIndex::<2>::new(3).unwrap()).0); + assert_eq!(vec![VALUES4[1], node3], *tree.open(&LeafIndex::<2>::new(0).unwrap()).0); + assert_eq!(vec![VALUES4[0], node3], *tree.open(&LeafIndex::<2>::new(1).unwrap()).0); + assert_eq!(vec![VALUES4[3], node2], *tree.open(&LeafIndex::<2>::new(2).unwrap()).0); + assert_eq!(vec![VALUES4[2], node2], *tree.open(&LeafIndex::<2>::new(3).unwrap()).0); } #[test] @@ -213,7 +213,7 @@ fn small_tree_opening_is_consistent() { ]; for (key, path) in cases { - let (opening, _) = tree.open(LeafIndex::<3>::new(key).unwrap()); + let (opening, _) = tree.open(&LeafIndex::<3>::new(key).unwrap()); assert_eq!(path, *opening); } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index ee684893..b5f0624b 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -103,7 +103,7 @@ impl Smt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: RpoDigest) -> (MerklePath, SmtLeaf) { + pub fn open(&self, key: &RpoDigest) -> (MerklePath, SmtLeaf) { >::open(self, key) } diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/tests.rs index d341cab3..66b40ec5 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/tests.rs @@ -156,7 +156,7 @@ fn test_smt_insert_multiple_values() { assert_eq!(smt.root(), tree_root); let expected_path = store.get_path(tree_root, key_index).unwrap(); - assert_eq!(smt.open(key).0, expected_path.path); + assert_eq!(smt.open(&key).0, expected_path.path); } } @@ -251,7 +251,7 @@ fn test_smt_path_to_keys_in_same_leaf_are_equal() { let smt = Smt::with_entries([(key_1, value_1), (key_2, value_2)]).unwrap(); - assert_eq!(smt.open(key_1), smt.open(key_2)); + assert_eq!(smt.open(&key_1), smt.open(&key_2)); } // HELPERS diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs index d01000a0..5cc7a0ff 100644 --- a/src/merkle/sparse_merkle_tree.rs +++ b/src/merkle/sparse_merkle_tree.rs @@ -57,11 +57,11 @@ pub(crate) trait SparseMerkleTree { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - fn open(&self, key: Self::Key) -> Self::Opening { - let leaf = self.get_leaf(&key); + fn open(&self, key: &Self::Key) -> Self::Opening { + let leaf = self.get_leaf(key); let mut index: NodeIndex = { - let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); + let leaf_index: LeafIndex = Self::key_to_leaf_index(key); leaf_index.into() }; diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index 3bb11e1b..958bba1d 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -182,7 +182,7 @@ fn test_leaf_paths_for_empty_trees() -> Result<(), MerkleError> { let index = NodeIndex::make(DEPTH, 0); let store_path = store.get_path(smt.root(), index)?; - let smt_path = smt.open(LeafIndex::::new(0)?).0; + let smt_path = smt.open(&LeafIndex::::new(0)?).0; assert_eq!( store_path.value, RpoDigest::default(), @@ -301,7 +301,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 0 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(0).unwrap()).0, + smt.open(&LeafIndex::::new(0).unwrap()).0, result.path, "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" ); @@ -312,7 +312,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 1 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(1).unwrap()).0, + smt.open(&LeafIndex::::new(1).unwrap()).0, result.path, "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" ); @@ -323,7 +323,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 2 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(2).unwrap()).0, + smt.open(&LeafIndex::::new(2).unwrap()).0, result.path, "merkle path for index 2 must be the same for the MerkleTree and MerkleStore" ); @@ -334,7 +334,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 3 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(3).unwrap()).0, + smt.open(&LeafIndex::::new(3).unwrap()).0, result.path, "merkle path for index 3 must be the same for the MerkleTree and MerkleStore" ); @@ -346,7 +346,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 4 must match leaf value" ); assert_eq!( - smt.open(LeafIndex::::new(4).unwrap()).0, + smt.open(&LeafIndex::::new(4).unwrap()).0, result.path, "merkle path for index 4 must be the same for the MerkleTree and MerkleStore" ); @@ -563,7 +563,7 @@ fn test_constructors() -> Result<(), MerkleError> { for key in KEYS4 { let index = NodeIndex::make(DEPTH, key); let value_path = store.get_path(smt.root(), index)?; - assert_eq!(smt.open(LeafIndex::::new(key).unwrap()).0, value_path.path); + assert_eq!(smt.open(&LeafIndex::::new(key).unwrap()).0, value_path.path); } let d = 2; From 6637542d41fd779fbb6527181d364f93ede4b17c Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 16:33:34 -0500 Subject: [PATCH 102/121] new directory structure --- src/merkle/mod.rs | 8 +- src/merkle/smt/full/mod.rs | 367 ++++++++++++++ src/merkle/smt/{ => full}/tests.rs | 6 +- src/merkle/smt/mod.rs | 472 +++++++----------- src/merkle/{simple_smt => smt/simple}/mod.rs | 12 +- .../{simple_smt => smt/simple}/tests.rs | 8 +- src/merkle/sparse_merkle_tree.rs | 235 --------- 7 files changed, 558 insertions(+), 550 deletions(-) create mode 100644 src/merkle/smt/full/mod.rs rename src/merkle/smt/{ => full}/tests.rs (99%) rename src/merkle/{simple_smt => smt/simple}/mod.rs (97%) rename src/merkle/{simple_smt => smt/simple}/tests.rs (98%) delete mode 100644 src/merkle/sparse_merkle_tree.rs diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 8bbc38ac..edd75d40 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -24,14 +24,8 @@ pub use merkle_tree::{path_to_text, tree_to_text, MerkleTree}; mod path; pub use path::{MerklePath, RootPath, ValuePath}; -mod simple_smt; -pub use simple_smt::SimpleSmt; - -pub(crate) mod sparse_merkle_tree; -pub use sparse_merkle_tree::{LeafIndex, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; - mod smt; -pub use smt::{Smt, SmtLeaf, SMT_DEPTH}; +pub use smt::{LeafIndex, SimpleSmt, Smt, SmtLeaf, SMT_DEPTH, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; mod tiered_smt; pub use tiered_smt::{TieredSmt, TieredSmtProof, TieredSmtProofError}; diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs new file mode 100644 index 00000000..f8c17aca --- /dev/null +++ b/src/merkle/smt/full/mod.rs @@ -0,0 +1,367 @@ +use core::cmp::Ordering; + +use winter_math::StarkField; + +use crate::hash::rpo::Rpo256; +use crate::merkle::EmptySubtreeRoots; +use crate::utils::{ + collections::{BTreeMap, BTreeSet, Vec}, + vec, +}; +use crate::{Felt, EMPTY_WORD}; + +use super::{ + InnerNode, LeafIndex, MerkleError, MerklePath, NodeIndex, RpoDigest, SparseMerkleTree, Word, +}; + +#[cfg(test)] +mod tests; + +// CONSTANTS +// ================================================================================================ + +pub const SMT_DEPTH: u8 = 64; + +// SMT +// ================================================================================================ + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Smt { + root: RpoDigest, + leaves: BTreeMap, + inner_nodes: BTreeMap, +} + +impl Smt { + // CONSTRUCTORS + // -------------------------------------------------------------------------------------------- + + /// Returns a new [NewSmt]. + /// + /// All leaves in the returned tree are set to [ZERO; 4]. + pub fn new() -> Self { + let root = *EmptySubtreeRoots::entry(SMT_DEPTH, 0); + + Self { + root, + leaves: BTreeMap::new(), + inner_nodes: BTreeMap::new(), + } + } + + /// Returns a new [SimpleSmt] instantiated with leaves set as specified by the provided entries. + /// + /// All leaves omitted from the entries list are set to [ZERO; 4]. + /// + /// # Errors + /// Returns an error if: + /// - The number of entries exceeds 2^63 entries. + /// - The provided entries contain multiple values for the same key. + pub fn with_entries( + entries: impl IntoIterator, + ) -> Result { + // create an empty tree + let mut tree = Self::new(); + + // This being a sparse data structure, the EMPTY_WORD is not assigned to the `BTreeMap`, so + // entries with the empty value need additional tracking. + let mut key_set_to_zero = BTreeSet::new(); + + for (key, value) in entries { + let old_value = tree.insert(key, value); + + if old_value != EMPTY_WORD || key_set_to_zero.contains(&key) { + return Err(MerkleError::DuplicateValuesForIndex( + LeafIndex::::from(key).value(), + )); + } + + if value == EMPTY_WORD { + key_set_to_zero.insert(key); + }; + } + Ok(tree) + } + + // PUBLIC ACCESSORS + // -------------------------------------------------------------------------------------------- + + /// Returns the root of the tree + pub fn root(&self) -> RpoDigest { + >::root(self) + } + + /// Returns the leaf at the specified index. + pub fn get_leaf(&self, key: &RpoDigest) -> SmtLeaf { + >::get_leaf(self, key) + } + + /// Returns the depth of the tree + pub const fn depth(&self) -> u8 { + SMT_DEPTH + } + + /// Returns a Merkle path from the leaf node specified by the key to the root. + /// + /// The node itself is not included in the path. + pub fn open(&self, key: &RpoDigest) -> (MerklePath, SmtLeaf) { + >::open(self, key) + } + + // STATE MUTATORS + // -------------------------------------------------------------------------------------------- + + /// Inserts a value at the specified key, returning the previous value associated with that key. + /// Recall that by definition, any key that hasn't been updated is associated with + /// [`EMPTY_WORD`]. + /// + /// This also recomputes all hashes between the leaf (associated with the key) and the root, + /// updating the root itself. + pub fn insert(&mut self, key: RpoDigest, value: Word) -> Word { + >::insert(self, key, value) + } + + // HELPERS + // -------------------------------------------------------------------------------------------- + + /// Inserts `value` at leaf index pointed to by `key`. `value` is guaranteed to not be the empty + /// value, such that this is indeed an insertion. + fn perform_insert(&mut self, key: RpoDigest, value: Word) -> Option { + debug_assert_ne!(value, Self::EMPTY_VALUE); + + let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); + + match self.leaves.get_mut(&leaf_index.value()) { + Some(leaf) => leaf.insert(key, value), + None => { + self.leaves.insert(leaf_index.value(), SmtLeaf::Single((key, value))); + + None + } + } + } + + /// Removes key-value pair at leaf index pointed to by `key` if it exists. + fn perform_remove(&mut self, key: RpoDigest) -> Option { + let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); + + if let Some(leaf) = self.leaves.get_mut(&leaf_index.value()) { + let (old_value, is_empty) = leaf.remove(key); + if is_empty { + self.leaves.remove(&leaf_index.value()); + } + old_value + } else { + // there's nothing stored at the leaf; nothing to update + None + } + } +} + +impl SparseMerkleTree for Smt { + type Key = RpoDigest; + type Value = Word; + type Leaf = SmtLeaf; + type Opening = (MerklePath, SmtLeaf); + + const EMPTY_VALUE: Self::Value = EMPTY_WORD; + + fn root(&self) -> RpoDigest { + self.root + } + + fn set_root(&mut self, root: RpoDigest) { + self.root = root; + } + + fn get_inner_node(&self, index: NodeIndex) -> InnerNode { + self.inner_nodes.get(&index).cloned().unwrap_or_else(|| { + let node = EmptySubtreeRoots::entry(SMT_DEPTH, index.depth() + 1); + + InnerNode { left: *node, right: *node } + }) + } + + fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { + self.inner_nodes.insert(index, inner_node); + } + + fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option { + // inserting an `EMPTY_VALUE` is equivalent to removing any value associated with `key` + if value != Self::EMPTY_VALUE { + self.perform_insert(key, value) + } else { + self.perform_remove(key) + } + } + + fn get_leaf(&self, key: &RpoDigest) -> Self::Leaf { + let leaf_pos = LeafIndex::::from(*key).value(); + + match self.leaves.get(&leaf_pos) { + Some(leaf) => leaf.clone(), + None => SmtLeaf::Single((*key, Self::EMPTY_VALUE)), + } + } + + fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest { + leaf.hash() + } + + fn key_to_leaf_index(key: &RpoDigest) -> LeafIndex { + let most_significant_felt = key[3]; + LeafIndex::new_max_depth(most_significant_felt.as_int()) + } +} + +impl Default for Smt { + fn default() -> Self { + Self::new() + } +} + +// LEAF +// ================================================================================================ + +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum SmtLeaf { + Single((RpoDigest, Word)), + Multiple(Vec<(RpoDigest, Word)>), +} + +impl SmtLeaf { + /// Converts a leaf to a list of field elements + pub fn to_elements(&self) -> Vec { + self.clone().into_elements() + } + + /// Converts a leaf to a list of field elements + pub fn into_elements(self) -> Vec { + match self { + SmtLeaf::Single(kv_pair) => kv_to_elements(kv_pair).collect(), + SmtLeaf::Multiple(kv_pairs) => kv_pairs.into_iter().flat_map(kv_to_elements).collect(), + } + } + + /// Compute the hash of the leaf + pub fn hash(&self) -> RpoDigest { + match self { + SmtLeaf::Single((key, value)) => Rpo256::merge(&[*key, value.into()]), + SmtLeaf::Multiple(kvs) => { + let elements: Vec = kvs.iter().copied().flat_map(kv_to_elements).collect(); + Rpo256::hash_elements(&elements) + } + } + } + + // HELPERS + // --------------------------------------------------------------------------------------------- + + /// Insert key-value pair into the leaf; return the previous value associated with `key`, if + /// any. + fn insert(&mut self, key: RpoDigest, value: Word) -> Option { + match self { + SmtLeaf::Single(kv_pair) => { + if kv_pair.0 == key { + // the key is already in this leaf. Update the value and return the previous + // value + let old_value = kv_pair.1; + kv_pair.1 = value; + Some(old_value) + } else { + // Another entry is present in this leaf. Transform the entry into a list + // entry, and make sure the key-value pairs are sorted by key + let mut pairs = vec![*kv_pair, (key, value)]; + pairs.sort_by(|(key_1, _), (key_2, _)| cmp_keys(*key_1, *key_2)); + + *self = SmtLeaf::Multiple(pairs); + + None + } + } + SmtLeaf::Multiple(kv_pairs) => { + match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { + Ok(pos) => { + let old_value = kv_pairs[pos].1; + kv_pairs[pos].1 = value; + + Some(old_value) + } + Err(pos) => { + kv_pairs.insert(pos, (key, value)); + + None + } + } + } + } + } + + /// Remove key-value pair into the leaf stored at key; return the previous value associated with + /// `key`, if any. We also return an `is_empty` flag which indicates whether the leaf became + /// empty, and must be removed from the data structure it is contained in. + fn remove(&mut self, key: RpoDigest) -> (Option, bool) { + match self { + SmtLeaf::Single((key_at_leaf, value_at_leaf)) => { + if *key_at_leaf == key { + // our key was indeed stored in the leaf, so we return the value that was stored + // in it, and indicate that the leaf should be removed + let old_value = *value_at_leaf; + + (Some(old_value), true) + } else { + // another key is stored at leaf; nothing to update + (None, false) + } + } + SmtLeaf::Multiple(kv_pairs) => { + match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { + Ok(pos) => { + let old_value = kv_pairs[pos].1; + + kv_pairs.remove(pos); + debug_assert!(!kv_pairs.is_empty()); + + if kv_pairs.len() == 1 { + // convert the leaf into `Single` + *self = SmtLeaf::Single(kv_pairs[0]); + } + + (Some(old_value), false) + } + Err(_) => { + // other keys are stored at leaf; nothing to update + (None, false) + } + } + } + } + } +} + +// HELPER FUNCTIONS +// ================================================================================================ + +/// Converts a key-value tuple to an iterator of `Felt`s +fn kv_to_elements((key, value): (RpoDigest, Word)) -> impl Iterator { + let key_elements = key.into_iter(); + let value_elements = value.into_iter(); + + key_elements.chain(value_elements) +} + +/// Compares two keys, compared element-by-element using their integer representations starting with +/// the most significant element. +fn cmp_keys(key_1: RpoDigest, key_2: RpoDigest) -> Ordering { + for (v1, v2) in key_1.iter().zip(key_2.iter()).rev() { + let v1 = v1.as_int(); + let v2 = v2.as_int(); + if v1 != v2 { + return v1.cmp(&v2); + } + } + + Ordering::Equal +} diff --git a/src/merkle/smt/tests.rs b/src/merkle/smt/full/tests.rs similarity index 99% rename from src/merkle/smt/tests.rs rename to src/merkle/smt/full/tests.rs index 66b40ec5..f068e22f 100644 --- a/src/merkle/smt/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -1,6 +1,8 @@ -use crate::{merkle::MerkleStore, ONE, WORD_SIZE}; - use super::*; +use crate::{ + merkle::{EmptySubtreeRoots, MerkleStore}, + ONE, WORD_SIZE, +}; /// This test checks that inserting twice at the same key functions as expected. The test covers /// only the case where the key is alone in its leaf diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index b5f0624b..4e0e153c 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -1,365 +1,241 @@ -use core::cmp::Ordering; - use winter_math::StarkField; -use crate::hash::rpo::Rpo256; -use crate::utils::{collections::Vec, vec}; -use crate::{Felt, EMPTY_WORD}; - -use super::sparse_merkle_tree::{InnerNode, SparseMerkleTree}; -use super::{ - BTreeMap, BTreeSet, EmptySubtreeRoots, LeafIndex, MerkleError, MerklePath, NodeIndex, - RpoDigest, Word, +use crate::{ + hash::rpo::{Rpo256, RpoDigest}, + Word, }; -#[cfg(test)] -mod tests; +use super::{MerkleError, MerklePath, NodeIndex, Vec}; -// CONSTANTS -// ================================================================================================ +mod full; +pub use full::{Smt, SmtLeaf, SMT_DEPTH}; -pub const SMT_DEPTH: u8 = 64; +mod simple; +pub use simple::SimpleSmt; -// SMT +// CONSTANTS // ================================================================================================ -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Smt { - root: RpoDigest, - leaves: BTreeMap, - inner_nodes: BTreeMap, -} - -impl Smt { - // CONSTRUCTORS - // -------------------------------------------------------------------------------------------- - - /// Returns a new [NewSmt]. - /// - /// All leaves in the returned tree are set to [ZERO; 4]. - pub fn new() -> Self { - let root = *EmptySubtreeRoots::entry(SMT_DEPTH, 0); - - Self { - root, - leaves: BTreeMap::new(), - inner_nodes: BTreeMap::new(), - } - } - - /// Returns a new [SimpleSmt] instantiated with leaves set as specified by the provided entries. - /// - /// All leaves omitted from the entries list are set to [ZERO; 4]. - /// - /// # Errors - /// Returns an error if: - /// - The number of entries exceeds 2^63 entries. - /// - The provided entries contain multiple values for the same key. - pub fn with_entries( - entries: impl IntoIterator, - ) -> Result { - // create an empty tree - let mut tree = Self::new(); - - // This being a sparse data structure, the EMPTY_WORD is not assigned to the `BTreeMap`, so - // entries with the empty value need additional tracking. - let mut key_set_to_zero = BTreeSet::new(); - - for (key, value) in entries { - let old_value = tree.insert(key, value); - - if old_value != EMPTY_WORD || key_set_to_zero.contains(&key) { - return Err(MerkleError::DuplicateValuesForIndex( - LeafIndex::::from(key).value(), - )); - } - - if value == EMPTY_WORD { - key_set_to_zero.insert(key); - }; - } - Ok(tree) - } +/// Minimum supported depth. +pub const SMT_MIN_DEPTH: u8 = 1; - // PUBLIC ACCESSORS - // -------------------------------------------------------------------------------------------- +/// Maximum supported depth. +pub const SMT_MAX_DEPTH: u8 = 64; - /// Returns the root of the tree - pub fn root(&self) -> RpoDigest { - >::root(self) - } - - /// Returns the leaf at the specified index. - pub fn get_leaf(&self, key: &RpoDigest) -> SmtLeaf { - >::get_leaf(self, key) - } +// SPARSE MERKLE TREE +// ================================================================================================ - /// Returns the depth of the tree - pub const fn depth(&self) -> u8 { - SMT_DEPTH - } +/// An abstract description of a sparse Merkle tree. +/// +/// A sparse Merkle tree is a key-value map which also supports proving that a given value is indeed +/// stored at a given key in the tree. It is viewed as always being fully populated. If a leaf's +/// value was not explicitly set, then its value is the default value. Typically, the vast majority +/// of leaves will store the default value (hence it is "sparse"), and therefore the internal +/// representation of the tree will only keep track of the leaves that have a different value from +/// the default. +/// +/// All leaves sit at the same depth. The deeper the tree, the more leaves it has; but also the +/// longer its proofs are - of exactly `log(depth)` size. A tree cannot have depth 0, since such a +/// tree is just a single value, and is probably a programming mistake. +/// +/// Every key maps to one leaf. If there are as many keys as there are leaves, then +/// [Self::Leaf] should be the same type as [Self::Value], as is the case with +/// [crate::merkle::SimpleSmt]. However, if there are more keys than leaves, then [`Self::Leaf`] +/// must accomodate all keys that map to the same leaf. +/// +/// [SparseMerkleTree] currently doesn't support optimizations that compress Merkle proofs. +pub(crate) trait SparseMerkleTree { + /// The type for a key + type Key: Clone; + /// The type for a value + type Value: Clone + PartialEq; + /// The type for a leaf + type Leaf; + /// The type for an opening (i.e. a "proof") of a leaf + type Opening: From<(MerklePath, Self::Leaf)>; + + /// The default value used to compute the hash of empty leaves + const EMPTY_VALUE: Self::Value; + + // PROVIDED METHODS + // --------------------------------------------------------------------------------------------- /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: &RpoDigest) -> (MerklePath, SmtLeaf) { - >::open(self, key) - } + fn open(&self, key: &Self::Key) -> Self::Opening { + let leaf = self.get_leaf(key); + + let mut index: NodeIndex = { + let leaf_index: LeafIndex = Self::key_to_leaf_index(key); + leaf_index.into() + }; + + let merkle_path = { + let mut path = Vec::with_capacity(index.depth() as usize); + for _ in 0..index.depth() { + let is_right = index.is_value_odd(); + index.move_up(); + let InnerNode { left, right } = self.get_inner_node(index); + let value = if is_right { left } else { right }; + path.push(value); + } - // STATE MUTATORS - // -------------------------------------------------------------------------------------------- + MerklePath::new(path) + }; + + (merkle_path, leaf).into() + } /// Inserts a value at the specified key, returning the previous value associated with that key. /// Recall that by definition, any key that hasn't been updated is associated with - /// [`EMPTY_WORD`]. + /// [`Self::EMPTY_VALUE`]. /// /// This also recomputes all hashes between the leaf (associated with the key) and the root, /// updating the root itself. - pub fn insert(&mut self, key: RpoDigest, value: Word) -> Word { - >::insert(self, key, value) - } - - // HELPERS - // -------------------------------------------------------------------------------------------- - - /// Inserts `value` at leaf index pointed to by `key`. `value` is guaranteed to not be the empty - /// value, such that this is indeed an insertion. - fn perform_insert(&mut self, key: RpoDigest, value: Word) -> Option { - debug_assert_ne!(value, Self::EMPTY_VALUE); - - let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); - - match self.leaves.get_mut(&leaf_index.value()) { - Some(leaf) => leaf.insert(key, value), - None => { - self.leaves.insert(leaf_index.value(), SmtLeaf::Single((key, value))); + fn insert(&mut self, key: Self::Key, value: Self::Value) -> Self::Value { + let old_value = self.insert_value(key.clone(), value.clone()).unwrap_or(Self::EMPTY_VALUE); - None - } + // if the old value and new value are the same, there is nothing to update + if value == old_value { + return value; } - } - /// Removes key-value pair at leaf index pointed to by `key` if it exists. - fn perform_remove(&mut self, key: RpoDigest) -> Option { - let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); - - if let Some(leaf) = self.leaves.get_mut(&leaf_index.value()) { - let (old_value, is_empty) = leaf.remove(key); - if is_empty { - self.leaves.remove(&leaf_index.value()); - } - old_value - } else { - // there's nothing stored at the leaf; nothing to update - None + let leaf = self.get_leaf(&key); + let node_index = { + let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); + leaf_index.into() + }; + + self.recompute_nodes_from_index_to_root(node_index, Self::hash_leaf(&leaf)); + + old_value + } + + /// Recomputes the branch nodes (including the root) from `index` all the way to the root. + /// `node_hash_at_index` is the hash of the node stored at index. + fn recompute_nodes_from_index_to_root( + &mut self, + mut index: NodeIndex, + node_hash_at_index: RpoDigest, + ) { + let mut value = node_hash_at_index; + for _ in 0..index.depth() { + let is_right = index.is_value_odd(); + index.move_up(); + let InnerNode { left, right } = self.get_inner_node(index); + let (left, right) = if is_right { (left, value) } else { (value, right) }; + self.insert_inner_node(index, InnerNode { left, right }); + value = Rpo256::merge(&[left, right]); } + self.set_root(value); } -} -impl SparseMerkleTree for Smt { - type Key = RpoDigest; - type Value = Word; - type Leaf = SmtLeaf; - type Opening = (MerklePath, SmtLeaf); + // REQUIRED METHODS + // --------------------------------------------------------------------------------------------- - const EMPTY_VALUE: Self::Value = EMPTY_WORD; + /// The root of the tree + fn root(&self) -> RpoDigest; - fn root(&self) -> RpoDigest { - self.root - } - - fn set_root(&mut self, root: RpoDigest) { - self.root = root; - } + /// Sets the root of the tree + fn set_root(&mut self, root: RpoDigest); - fn get_inner_node(&self, index: NodeIndex) -> InnerNode { - self.inner_nodes.get(&index).cloned().unwrap_or_else(|| { - let node = EmptySubtreeRoots::entry(SMT_DEPTH, index.depth() + 1); + /// Retrieves an inner node at the given index + fn get_inner_node(&self, index: NodeIndex) -> InnerNode; - InnerNode { left: *node, right: *node } - }) - } + /// Inserts an inner node at the given index + fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode); - fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { - self.inner_nodes.insert(index, inner_node); - } + /// Inserts a leaf node, and returns the value at the key if already exists + fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option; - fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option { - // inserting an `EMPTY_VALUE` is equivalent to removing any value associated with `key` - if value != Self::EMPTY_VALUE { - self.perform_insert(key, value) - } else { - self.perform_remove(key) - } - } + /// Returns the leaf at the specified index. + fn get_leaf(&self, key: &Self::Key) -> Self::Leaf; - fn get_leaf(&self, key: &RpoDigest) -> Self::Leaf { - let leaf_pos = LeafIndex::::from(*key).value(); + /// Returns the hash of a leaf + fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest; - match self.leaves.get(&leaf_pos) { - Some(leaf) => leaf.clone(), - None => SmtLeaf::Single((*key, Self::EMPTY_VALUE)), - } - } + fn key_to_leaf_index(key: &Self::Key) -> LeafIndex; +} - fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest { - leaf.hash() - } +// INNER NODE +// ================================================================================================ - fn key_to_leaf_index(key: &RpoDigest) -> LeafIndex { - let most_significant_felt = key[3]; - LeafIndex::new_max_depth(most_significant_felt.as_int()) - } +#[derive(Debug, Default, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub(crate) struct InnerNode { + pub left: RpoDigest, + pub right: RpoDigest, } -impl Default for Smt { - fn default() -> Self { - Self::new() +impl InnerNode { + pub fn hash(&self) -> RpoDigest { + Rpo256::merge(&[self.left, self.right]) } } -// LEAF +// LEAF INDEX // ================================================================================================ -#[derive(Clone, Debug, PartialEq, Eq)] +/// The index of a leaf, at a depth known at compile-time. +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub enum SmtLeaf { - Single((RpoDigest, Word)), - Multiple(Vec<(RpoDigest, Word)>), +pub struct LeafIndex { + index: NodeIndex, } -impl SmtLeaf { - /// Converts a leaf to a list of field elements - pub fn to_elements(&self) -> Vec { - self.clone().into_elements() - } - - /// Converts a leaf to a list of field elements - pub fn into_elements(self) -> Vec { - match self { - SmtLeaf::Single(kv_pair) => kv_to_elements(kv_pair).collect(), - SmtLeaf::Multiple(kv_pairs) => kv_pairs.into_iter().flat_map(kv_to_elements).collect(), +impl LeafIndex { + pub fn new(value: u64) -> Result { + if DEPTH < SMT_MIN_DEPTH { + return Err(MerkleError::DepthTooSmall(DEPTH)); } - } - /// Compute the hash of the leaf - pub fn hash(&self) -> RpoDigest { - match self { - SmtLeaf::Single((key, value)) => Rpo256::merge(&[*key, value.into()]), - SmtLeaf::Multiple(kvs) => { - let elements: Vec = kvs.iter().copied().flat_map(kv_to_elements).collect(); - Rpo256::hash_elements(&elements) - } - } + Ok(LeafIndex { index: NodeIndex::new(DEPTH, value)? }) } - // HELPERS - // --------------------------------------------------------------------------------------------- + pub fn value(&self) -> u64 { + self.index.value() + } +} - /// Insert key-value pair into the leaf; return the previous value associated with `key`, if - /// any. - fn insert(&mut self, key: RpoDigest, value: Word) -> Option { - match self { - SmtLeaf::Single(kv_pair) => { - if kv_pair.0 == key { - // the key is already in this leaf. Update the value and return the previous - // value - let old_value = kv_pair.1; - kv_pair.1 = value; - Some(old_value) - } else { - // Another entry is present in this leaf. Transform the entry into a list - // entry, and make sure the key-value pairs are sorted by key - let mut pairs = vec![*kv_pair, (key, value)]; - pairs.sort_by(|(key_1, _), (key_2, _)| cmp_keys(*key_1, *key_2)); - - *self = SmtLeaf::Multiple(pairs); - - None - } - } - SmtLeaf::Multiple(kv_pairs) => { - match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { - Ok(pos) => { - let old_value = kv_pairs[pos].1; - kv_pairs[pos].1 = value; - - Some(old_value) - } - Err(pos) => { - kv_pairs.insert(pos, (key, value)); - - None - } - } - } +impl LeafIndex { + pub fn new_max_depth(value: u64) -> Self { + LeafIndex { + index: NodeIndex::new_unchecked(SMT_MAX_DEPTH, value), } } +} - /// Remove key-value pair into the leaf stored at key; return the previous value associated with - /// `key`, if any. We also return an `is_empty` flag which indicates whether the leaf became - /// empty, and must be removed from the data structure it is contained in. - fn remove(&mut self, key: RpoDigest) -> (Option, bool) { - match self { - SmtLeaf::Single((key_at_leaf, value_at_leaf)) => { - if *key_at_leaf == key { - // our key was indeed stored in the leaf, so we return the value that was stored - // in it, and indicate that the leaf should be removed - let old_value = *value_at_leaf; - - (Some(old_value), true) - } else { - // another key is stored at leaf; nothing to update - (None, false) - } - } - SmtLeaf::Multiple(kv_pairs) => { - match kv_pairs.binary_search_by(|kv_pair| cmp_keys(kv_pair.0, key)) { - Ok(pos) => { - let old_value = kv_pairs[pos].1; - - kv_pairs.remove(pos); - debug_assert!(!kv_pairs.is_empty()); - - if kv_pairs.len() == 1 { - // convert the leaf into `Single` - *self = SmtLeaf::Single(kv_pairs[0]); - } - - (Some(old_value), false) - } - Err(_) => { - // other keys are stored at leaf; nothing to update - (None, false) - } - } - } - } +impl From> for NodeIndex { + fn from(value: LeafIndex) -> Self { + value.index } } -// HELPER FUNCTIONS -// ================================================================================================ +impl TryFrom for LeafIndex { + type Error = MerkleError; -/// Converts a key-value tuple to an iterator of `Felt`s -fn kv_to_elements((key, value): (RpoDigest, Word)) -> impl Iterator { - let key_elements = key.into_iter(); - let value_elements = value.into_iter(); + fn try_from(node_index: NodeIndex) -> Result { + if node_index.depth() != DEPTH { + return Err(MerkleError::InvalidDepth { + expected: DEPTH, + provided: node_index.depth(), + }); + } - key_elements.chain(value_elements) + Self::new(node_index.value()) + } } -/// Compares two keys, compared element-by-element using their integer representations starting with -/// the most significant element. -fn cmp_keys(key_1: RpoDigest, key_2: RpoDigest) -> Ordering { - for (v1, v2) in key_1.iter().zip(key_2.iter()).rev() { - let v1 = v1.as_int(); - let v2 = v2.as_int(); - if v1 != v2 { - return v1.cmp(&v2); - } +impl From for LeafIndex { + fn from(value: Word) -> Self { + // We use the most significant `Felt` of a `Word` as the leaf index. + Self::new_max_depth(value[3].as_int()) } +} - Ordering::Equal +impl From for LeafIndex { + fn from(value: RpoDigest) -> Self { + Word::from(value).into() + } } diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/smt/simple/mod.rs similarity index 97% rename from src/merkle/simple_smt/mod.rs rename to src/merkle/smt/simple/mod.rs index 8a167755..c097fa95 100644 --- a/src/merkle/simple_smt/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -1,10 +1,14 @@ -use crate::EMPTY_WORD; +use crate::{ + merkle::{EmptySubtreeRoots, InnerNodeInfo, MerkleTreeDelta, StoreNode}, + utils::collections::TryApplyDiff, + EMPTY_WORD, +}; use super::{ - sparse_merkle_tree::{InnerNode, SparseMerkleTree, SMT_MAX_DEPTH}, - BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNodeInfo, LeafIndex, MerkleError, MerklePath, - MerkleTreeDelta, NodeIndex, RpoDigest, StoreNode, TryApplyDiff, Word, SMT_MIN_DEPTH, + InnerNode, LeafIndex, MerkleError, MerklePath, NodeIndex, RpoDigest, SparseMerkleTree, Word, + SMT_MAX_DEPTH, SMT_MIN_DEPTH, }; +use crate::utils::collections::{BTreeMap, BTreeSet}; #[cfg(test)] mod tests; diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/smt/simple/tests.rs similarity index 98% rename from src/merkle/simple_smt/tests.rs rename to src/merkle/smt/simple/tests.rs index 3c74cef6..4ef501c7 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/smt/simple/tests.rs @@ -1,15 +1,15 @@ use super::{ - super::{InnerNodeInfo, MerkleError, MerkleTree, RpoDigest, SimpleSmt, EMPTY_WORD}, + super::{MerkleError, RpoDigest, SimpleSmt}, NodeIndex, }; use crate::{ hash::rpo::Rpo256, merkle::{ - digests_to_words, int_to_leaf, int_to_node, sparse_merkle_tree::SparseMerkleTree, - EmptySubtreeRoots, LeafIndex, + digests_to_words, int_to_leaf, int_to_node, smt::SparseMerkleTree, EmptySubtreeRoots, + InnerNodeInfo, LeafIndex, MerkleTree, }, utils::collections::Vec, - Word, + Word, EMPTY_WORD, }; // TEST DATA diff --git a/src/merkle/sparse_merkle_tree.rs b/src/merkle/sparse_merkle_tree.rs deleted file mode 100644 index 5cc7a0ff..00000000 --- a/src/merkle/sparse_merkle_tree.rs +++ /dev/null @@ -1,235 +0,0 @@ -use winter_math::StarkField; - -use crate::{ - hash::rpo::{Rpo256, RpoDigest}, - Word, -}; - -use super::{MerkleError, MerklePath, NodeIndex, Vec}; - -// CONSTANTS -// ================================================================================================ - -/// Minimum supported depth. -pub const SMT_MIN_DEPTH: u8 = 1; - -/// Maximum supported depth. -pub const SMT_MAX_DEPTH: u8 = 64; - -// SPARSE MERKLE TREE -// ================================================================================================ - -/// An abstract description of a sparse Merkle tree. -/// -/// A sparse Merkle tree is a key-value map which also supports proving that a given value is indeed -/// stored at a given key in the tree. It is viewed as always being fully populated. If a leaf's -/// value was not explicitly set, then its value is the default value. Typically, the vast majority -/// of leaves will store the default value (hence it is "sparse"), and therefore the internal -/// representation of the tree will only keep track of the leaves that have a different value from -/// the default. -/// -/// All leaves sit at the same depth. The deeper the tree, the more leaves it has; but also the -/// longer its proofs are - of exactly `log(depth)` size. A tree cannot have depth 0, since such a -/// tree is just a single value, and is probably a programming mistake. -/// -/// Every key maps to one leaf. If there are as many keys as there are leaves, then -/// [Self::Leaf] should be the same type as [Self::Value], as is the case with -/// [crate::merkle::SimpleSmt]. However, if there are more keys than leaves, then [`Self::Leaf`] -/// must accomodate all keys that map to the same leaf. -/// -/// [SparseMerkleTree] currently doesn't support optimizations that compress Merkle proofs. -pub(crate) trait SparseMerkleTree { - /// The type for a key - type Key: Clone; - /// The type for a value - type Value: Clone + PartialEq; - /// The type for a leaf - type Leaf; - /// The type for an opening (i.e. a "proof") of a leaf - type Opening: From<(MerklePath, Self::Leaf)>; - - /// The default value used to compute the hash of empty leaves - const EMPTY_VALUE: Self::Value; - - // PROVIDED METHODS - // --------------------------------------------------------------------------------------------- - - /// Returns a Merkle path from the leaf node specified by the key to the root. - /// - /// The node itself is not included in the path. - fn open(&self, key: &Self::Key) -> Self::Opening { - let leaf = self.get_leaf(key); - - let mut index: NodeIndex = { - let leaf_index: LeafIndex = Self::key_to_leaf_index(key); - leaf_index.into() - }; - - let merkle_path = { - let mut path = Vec::with_capacity(index.depth() as usize); - for _ in 0..index.depth() { - let is_right = index.is_value_odd(); - index.move_up(); - let InnerNode { left, right } = self.get_inner_node(index); - let value = if is_right { left } else { right }; - path.push(value); - } - - MerklePath::new(path) - }; - - (merkle_path, leaf).into() - } - - /// Inserts a value at the specified key, returning the previous value associated with that key. - /// Recall that by definition, any key that hasn't been updated is associated with - /// [`Self::EMPTY_VALUE`]. - /// - /// This also recomputes all hashes between the leaf (associated with the key) and the root, - /// updating the root itself. - fn insert(&mut self, key: Self::Key, value: Self::Value) -> Self::Value { - let old_value = self.insert_value(key.clone(), value.clone()).unwrap_or(Self::EMPTY_VALUE); - - // if the old value and new value are the same, there is nothing to update - if value == old_value { - return value; - } - - let leaf = self.get_leaf(&key); - let node_index = { - let leaf_index: LeafIndex = Self::key_to_leaf_index(&key); - leaf_index.into() - }; - - self.recompute_nodes_from_index_to_root(node_index, Self::hash_leaf(&leaf)); - - old_value - } - - /// Recomputes the branch nodes (including the root) from `index` all the way to the root. - /// `node_hash_at_index` is the hash of the node stored at index. - fn recompute_nodes_from_index_to_root( - &mut self, - mut index: NodeIndex, - node_hash_at_index: RpoDigest, - ) { - let mut value = node_hash_at_index; - for _ in 0..index.depth() { - let is_right = index.is_value_odd(); - index.move_up(); - let InnerNode { left, right } = self.get_inner_node(index); - let (left, right) = if is_right { (left, value) } else { (value, right) }; - self.insert_inner_node(index, InnerNode { left, right }); - value = Rpo256::merge(&[left, right]); - } - self.set_root(value); - } - - // REQUIRED METHODS - // --------------------------------------------------------------------------------------------- - - /// The root of the tree - fn root(&self) -> RpoDigest; - - /// Sets the root of the tree - fn set_root(&mut self, root: RpoDigest); - - /// Retrieves an inner node at the given index - fn get_inner_node(&self, index: NodeIndex) -> InnerNode; - - /// Inserts an inner node at the given index - fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode); - - /// Inserts a leaf node, and returns the value at the key if already exists - fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option; - - /// Returns the leaf at the specified index. - fn get_leaf(&self, key: &Self::Key) -> Self::Leaf; - - /// Returns the hash of a leaf - fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest; - - fn key_to_leaf_index(key: &Self::Key) -> LeafIndex; -} - -// INNER NODE -// ================================================================================================ - -#[derive(Debug, Default, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub(crate) struct InnerNode { - pub left: RpoDigest, - pub right: RpoDigest, -} - -impl InnerNode { - pub fn hash(&self) -> RpoDigest { - Rpo256::merge(&[self.left, self.right]) - } -} - -// LEAF INDEX -// ================================================================================================ - -/// The index of a leaf, at a depth known at compile-time. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct LeafIndex { - index: NodeIndex, -} - -impl LeafIndex { - pub fn new(value: u64) -> Result { - if DEPTH < SMT_MIN_DEPTH { - return Err(MerkleError::DepthTooSmall(DEPTH)); - } - - Ok(LeafIndex { index: NodeIndex::new(DEPTH, value)? }) - } - - pub fn value(&self) -> u64 { - self.index.value() - } -} - -impl LeafIndex { - pub fn new_max_depth(value: u64) -> Self { - LeafIndex { - index: NodeIndex::new_unchecked(SMT_MAX_DEPTH, value), - } - } -} - -impl From> for NodeIndex { - fn from(value: LeafIndex) -> Self { - value.index - } -} - -impl TryFrom for LeafIndex { - type Error = MerkleError; - - fn try_from(node_index: NodeIndex) -> Result { - if node_index.depth() != DEPTH { - return Err(MerkleError::InvalidDepth { - expected: DEPTH, - provided: node_index.depth(), - }); - } - - Self::new(node_index.value()) - } -} - -impl From for LeafIndex { - fn from(value: Word) -> Self { - // We use the most significant `Felt` of a `Word` as the leaf index. - Self::new_max_depth(value[3].as_int()) - } -} - -impl From for LeafIndex { - fn from(value: RpoDigest) -> Self { - Word::from(value).into() - } -} From d39aee97d6be6890fbc689bdbfe4cceb7af58a97 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Tue, 16 Jan 2024 17:33:25 -0500 Subject: [PATCH 103/121] `SimpleSmtTrait`: Return possibly borrowed data --- src/merkle/smt/full/mod.rs | 18 +++++++++++------- src/merkle/smt/full/tests.rs | 12 ++++++------ src/merkle/smt/mod.rs | 11 +++++++---- src/merkle/smt/simple/mod.rs | 23 +++++++++++++++-------- src/merkle/smt/simple/tests.rs | 2 +- src/merkle/store/tests.rs | 5 ++++- src/utils/mod.rs | 4 ++-- 7 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index f8c17aca..921a432d 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -6,7 +6,7 @@ use crate::hash::rpo::Rpo256; use crate::merkle::EmptySubtreeRoots; use crate::utils::{ collections::{BTreeMap, BTreeSet, Vec}, - vec, + vec, Cow, }; use crate::{Felt, EMPTY_WORD}; @@ -93,7 +93,7 @@ impl Smt { } /// Returns the leaf at the specified index. - pub fn get_leaf(&self, key: &RpoDigest) -> SmtLeaf { + pub fn get_leaf(&self, key: &RpoDigest) -> Cow<'_, SmtLeaf> { >::get_leaf(self, key) } @@ -105,7 +105,7 @@ impl Smt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: &RpoDigest) -> (MerklePath, SmtLeaf) { + pub fn open(&self, key: &RpoDigest) -> (MerklePath, Cow<'_, SmtLeaf>) { >::open(self, key) } @@ -163,7 +163,7 @@ impl SparseMerkleTree for Smt { type Key = RpoDigest; type Value = Word; type Leaf = SmtLeaf; - type Opening = (MerklePath, SmtLeaf); + type Opening<'a> = (MerklePath, Cow<'a, SmtLeaf>); const EMPTY_VALUE: Self::Value = EMPTY_WORD; @@ -196,12 +196,16 @@ impl SparseMerkleTree for Smt { } } - fn get_leaf(&self, key: &RpoDigest) -> Self::Leaf { + fn get_leaf(&self, key: &RpoDigest) -> Cow<'_, Self::Leaf> { let leaf_pos = LeafIndex::::from(*key).value(); match self.leaves.get(&leaf_pos) { - Some(leaf) => leaf.clone(), - None => SmtLeaf::Single((*key, Self::EMPTY_VALUE)), + Some(leaf) => Cow::Borrowed(leaf), + None => { + let default_leaf = SmtLeaf::Single((*key, Self::EMPTY_VALUE)); + + Cow::Owned(default_leaf) + } } } diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index f068e22f..2a543044 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -186,7 +186,7 @@ fn test_smt_removal() { let old_value_1 = smt.insert(key_1, value_1); assert_eq!(old_value_1, EMPTY_WORD); - assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, value_1))); + assert_eq!(smt.get_leaf(&key_1).into_owned(), SmtLeaf::Single((key_1, value_1))); } // insert key-value 2 @@ -195,7 +195,7 @@ fn test_smt_removal() { assert_eq!(old_value_2, EMPTY_WORD); assert_eq!( - smt.get_leaf(&key_2), + smt.get_leaf(&key_2).into_owned(), SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)]) ); } @@ -206,7 +206,7 @@ fn test_smt_removal() { assert_eq!(old_value_3, EMPTY_WORD); assert_eq!( - smt.get_leaf(&key_3), + smt.get_leaf(&key_3).into_owned(), SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2), (key_3, value_3)]) ); } @@ -217,7 +217,7 @@ fn test_smt_removal() { assert_eq!(old_value_3, value_3); assert_eq!( - smt.get_leaf(&key_3), + smt.get_leaf(&key_3).into_owned(), SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)]) ); } @@ -227,7 +227,7 @@ fn test_smt_removal() { let old_value_2 = smt.insert(key_2, EMPTY_WORD); assert_eq!(old_value_2, value_2); - assert_eq!(smt.get_leaf(&key_2), SmtLeaf::Single((key_1, value_1))); + assert_eq!(smt.get_leaf(&key_2).into_owned(), SmtLeaf::Single((key_1, value_1))); } // remove key 1 @@ -235,7 +235,7 @@ fn test_smt_removal() { let old_value_1 = smt.insert(key_1, EMPTY_WORD); assert_eq!(old_value_1, value_1); - assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, EMPTY_WORD))); + assert_eq!(smt.get_leaf(&key_1).into_owned(), SmtLeaf::Single((key_1, EMPTY_WORD))); } } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 4e0e153c..9e3f983e 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -2,6 +2,7 @@ use winter_math::StarkField; use crate::{ hash::rpo::{Rpo256, RpoDigest}, + utils::Cow, Word, }; @@ -50,9 +51,11 @@ pub(crate) trait SparseMerkleTree { /// The type for a value type Value: Clone + PartialEq; /// The type for a leaf - type Leaf; + type Leaf: Clone; /// The type for an opening (i.e. a "proof") of a leaf - type Opening: From<(MerklePath, Self::Leaf)>; + type Opening<'a>: From<(MerklePath, Cow<'a, Self::Leaf>)> + where + Self: 'a; /// The default value used to compute the hash of empty leaves const EMPTY_VALUE: Self::Value; @@ -63,7 +66,7 @@ pub(crate) trait SparseMerkleTree { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - fn open(&self, key: &Self::Key) -> Self::Opening { + fn open(&self, key: &Self::Key) -> Self::Opening<'_> { let leaf = self.get_leaf(key); let mut index: NodeIndex = { @@ -150,7 +153,7 @@ pub(crate) trait SparseMerkleTree { fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option; /// Returns the leaf at the specified index. - fn get_leaf(&self, key: &Self::Key) -> Self::Leaf; + fn get_leaf(&self, key: &Self::Key) -> Cow<'_, Self::Leaf>; /// Returns the hash of a leaf fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest; diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index c097fa95..54640de4 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -8,7 +8,10 @@ use super::{ InnerNode, LeafIndex, MerkleError, MerklePath, NodeIndex, RpoDigest, SparseMerkleTree, Word, SMT_MAX_DEPTH, SMT_MIN_DEPTH, }; -use crate::utils::collections::{BTreeMap, BTreeSet}; +use crate::utils::{ + collections::{BTreeMap, BTreeSet}, + Cow, +}; #[cfg(test)] mod tests; @@ -117,7 +120,7 @@ impl SimpleSmt { } /// Returns the leaf at the specified index. - pub fn get_leaf(&self, key: &LeafIndex) -> Word { + pub fn get_leaf(&self, key: &LeafIndex) -> Cow<'_, Word> { >::get_leaf(self, key) } @@ -129,7 +132,7 @@ impl SimpleSmt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: &LeafIndex) -> (MerklePath, Word) { + pub fn open(&self, key: &LeafIndex) -> (MerklePath, Cow<'_, Word>) { >::open(self, key) } @@ -144,7 +147,7 @@ impl SimpleSmt { } else if index.depth() > DEPTH { Err(MerkleError::DepthTooBig(index.depth() as u64)) } else if index.depth() == DEPTH { - let leaf = self.get_leaf(&LeafIndex::::try_from(index)?); + let leaf = self.get_leaf(&LeafIndex::::try_from(index)?).into_owned(); Ok(leaf.into()) } else { @@ -247,7 +250,7 @@ impl SparseMerkleTree for SimpleSmt { type Key = LeafIndex; type Value = Word; type Leaf = Word; - type Opening = (MerklePath, Word); + type Opening<'a> = (MerklePath, Cow<'a, Word>); const EMPTY_VALUE: Self::Value = EMPTY_WORD; @@ -275,14 +278,18 @@ impl SparseMerkleTree for SimpleSmt { self.leaves.insert(key.value(), value) } - fn get_leaf(&self, key: &LeafIndex) -> Word { + fn get_leaf(&self, key: &LeafIndex) -> Cow<'_, Word> { // the lookup in empty_hashes could fail only if empty_hashes were not built correctly // by the constructor as we check the depth of the lookup above. let leaf_pos = key.value(); match self.leaves.get(&leaf_pos) { - Some(word) => *word, - None => Word::from(*EmptySubtreeRoots::entry(DEPTH, DEPTH)), + Some(word) => Cow::Borrowed(word), + None => { + let empty_root = *EmptySubtreeRoots::entry(DEPTH, DEPTH); + + Cow::Owned(empty_root.into()) + } } } diff --git a/src/merkle/smt/simple/tests.rs b/src/merkle/smt/simple/tests.rs index 4ef501c7..0a2c2d2a 100644 --- a/src/merkle/smt/simple/tests.rs +++ b/src/merkle/smt/simple/tests.rs @@ -344,7 +344,7 @@ fn test_simplesmt_set_subtree() { }; assert_eq!(tree.root(), k); - assert_eq!(tree.get_leaf(&LeafIndex::::new(4).unwrap()), c); + assert_eq!(tree.get_leaf(&LeafIndex::::new(4).unwrap()).into_owned(), c); assert_eq!(tree.get_inner_node(NodeIndex::new_unchecked(2, 2)).hash(), g); } diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index 958bba1d..f8dfc4cb 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -922,7 +922,10 @@ fn test_recorder() { let node = merkle_store.get_node(smtree.root(), index_2).unwrap(); assert_eq!( node, - smtree.get_leaf(&LeafIndex::::try_from(index_2).unwrap()).into() + smtree + .get_leaf(&LeafIndex::::try_from(index_2).unwrap()) + .into_owned() + .into() ); // assert that is doesnt contain nodes that were not recorded diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 715eee87..45a78084 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,10 +4,10 @@ use super::{utils::string::String, Word}; use core::fmt::{self, Display, Write}; #[cfg(not(feature = "std"))] -pub use alloc::{format, vec}; +pub use alloc::{borrow::Cow, format, vec}; #[cfg(feature = "std")] -pub use std::{format, vec}; +pub use std::{borrow::Cow, format, vec}; mod diff; mod kv_map; From 7c66cc66e759e8016c1d53397808c890394bad92 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 17 Jan 2024 09:06:25 -0500 Subject: [PATCH 104/121] Revert "`SimpleSmtTrait`: Return possibly borrowed data" This reverts commit d39aee97d6be6890fbc689bdbfe4cceb7af58a97. --- src/merkle/smt/full/mod.rs | 18 +++++++----------- src/merkle/smt/full/tests.rs | 12 ++++++------ src/merkle/smt/mod.rs | 11 ++++------- src/merkle/smt/simple/mod.rs | 23 ++++++++--------------- src/merkle/smt/simple/tests.rs | 2 +- src/merkle/store/tests.rs | 5 +---- src/utils/mod.rs | 4 ++-- 7 files changed, 29 insertions(+), 46 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index 921a432d..f8c17aca 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -6,7 +6,7 @@ use crate::hash::rpo::Rpo256; use crate::merkle::EmptySubtreeRoots; use crate::utils::{ collections::{BTreeMap, BTreeSet, Vec}, - vec, Cow, + vec, }; use crate::{Felt, EMPTY_WORD}; @@ -93,7 +93,7 @@ impl Smt { } /// Returns the leaf at the specified index. - pub fn get_leaf(&self, key: &RpoDigest) -> Cow<'_, SmtLeaf> { + pub fn get_leaf(&self, key: &RpoDigest) -> SmtLeaf { >::get_leaf(self, key) } @@ -105,7 +105,7 @@ impl Smt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: &RpoDigest) -> (MerklePath, Cow<'_, SmtLeaf>) { + pub fn open(&self, key: &RpoDigest) -> (MerklePath, SmtLeaf) { >::open(self, key) } @@ -163,7 +163,7 @@ impl SparseMerkleTree for Smt { type Key = RpoDigest; type Value = Word; type Leaf = SmtLeaf; - type Opening<'a> = (MerklePath, Cow<'a, SmtLeaf>); + type Opening = (MerklePath, SmtLeaf); const EMPTY_VALUE: Self::Value = EMPTY_WORD; @@ -196,16 +196,12 @@ impl SparseMerkleTree for Smt { } } - fn get_leaf(&self, key: &RpoDigest) -> Cow<'_, Self::Leaf> { + fn get_leaf(&self, key: &RpoDigest) -> Self::Leaf { let leaf_pos = LeafIndex::::from(*key).value(); match self.leaves.get(&leaf_pos) { - Some(leaf) => Cow::Borrowed(leaf), - None => { - let default_leaf = SmtLeaf::Single((*key, Self::EMPTY_VALUE)); - - Cow::Owned(default_leaf) - } + Some(leaf) => leaf.clone(), + None => SmtLeaf::Single((*key, Self::EMPTY_VALUE)), } } diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index 2a543044..f068e22f 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -186,7 +186,7 @@ fn test_smt_removal() { let old_value_1 = smt.insert(key_1, value_1); assert_eq!(old_value_1, EMPTY_WORD); - assert_eq!(smt.get_leaf(&key_1).into_owned(), SmtLeaf::Single((key_1, value_1))); + assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, value_1))); } // insert key-value 2 @@ -195,7 +195,7 @@ fn test_smt_removal() { assert_eq!(old_value_2, EMPTY_WORD); assert_eq!( - smt.get_leaf(&key_2).into_owned(), + smt.get_leaf(&key_2), SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)]) ); } @@ -206,7 +206,7 @@ fn test_smt_removal() { assert_eq!(old_value_3, EMPTY_WORD); assert_eq!( - smt.get_leaf(&key_3).into_owned(), + smt.get_leaf(&key_3), SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2), (key_3, value_3)]) ); } @@ -217,7 +217,7 @@ fn test_smt_removal() { assert_eq!(old_value_3, value_3); assert_eq!( - smt.get_leaf(&key_3).into_owned(), + smt.get_leaf(&key_3), SmtLeaf::Multiple(vec![(key_1, value_1), (key_2, value_2)]) ); } @@ -227,7 +227,7 @@ fn test_smt_removal() { let old_value_2 = smt.insert(key_2, EMPTY_WORD); assert_eq!(old_value_2, value_2); - assert_eq!(smt.get_leaf(&key_2).into_owned(), SmtLeaf::Single((key_1, value_1))); + assert_eq!(smt.get_leaf(&key_2), SmtLeaf::Single((key_1, value_1))); } // remove key 1 @@ -235,7 +235,7 @@ fn test_smt_removal() { let old_value_1 = smt.insert(key_1, EMPTY_WORD); assert_eq!(old_value_1, value_1); - assert_eq!(smt.get_leaf(&key_1).into_owned(), SmtLeaf::Single((key_1, EMPTY_WORD))); + assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, EMPTY_WORD))); } } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 9e3f983e..4e0e153c 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -2,7 +2,6 @@ use winter_math::StarkField; use crate::{ hash::rpo::{Rpo256, RpoDigest}, - utils::Cow, Word, }; @@ -51,11 +50,9 @@ pub(crate) trait SparseMerkleTree { /// The type for a value type Value: Clone + PartialEq; /// The type for a leaf - type Leaf: Clone; + type Leaf; /// The type for an opening (i.e. a "proof") of a leaf - type Opening<'a>: From<(MerklePath, Cow<'a, Self::Leaf>)> - where - Self: 'a; + type Opening: From<(MerklePath, Self::Leaf)>; /// The default value used to compute the hash of empty leaves const EMPTY_VALUE: Self::Value; @@ -66,7 +63,7 @@ pub(crate) trait SparseMerkleTree { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - fn open(&self, key: &Self::Key) -> Self::Opening<'_> { + fn open(&self, key: &Self::Key) -> Self::Opening { let leaf = self.get_leaf(key); let mut index: NodeIndex = { @@ -153,7 +150,7 @@ pub(crate) trait SparseMerkleTree { fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option; /// Returns the leaf at the specified index. - fn get_leaf(&self, key: &Self::Key) -> Cow<'_, Self::Leaf>; + fn get_leaf(&self, key: &Self::Key) -> Self::Leaf; /// Returns the hash of a leaf fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest; diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index 54640de4..c097fa95 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -8,10 +8,7 @@ use super::{ InnerNode, LeafIndex, MerkleError, MerklePath, NodeIndex, RpoDigest, SparseMerkleTree, Word, SMT_MAX_DEPTH, SMT_MIN_DEPTH, }; -use crate::utils::{ - collections::{BTreeMap, BTreeSet}, - Cow, -}; +use crate::utils::collections::{BTreeMap, BTreeSet}; #[cfg(test)] mod tests; @@ -120,7 +117,7 @@ impl SimpleSmt { } /// Returns the leaf at the specified index. - pub fn get_leaf(&self, key: &LeafIndex) -> Cow<'_, Word> { + pub fn get_leaf(&self, key: &LeafIndex) -> Word { >::get_leaf(self, key) } @@ -132,7 +129,7 @@ impl SimpleSmt { /// Returns a Merkle path from the leaf node specified by the key to the root. /// /// The node itself is not included in the path. - pub fn open(&self, key: &LeafIndex) -> (MerklePath, Cow<'_, Word>) { + pub fn open(&self, key: &LeafIndex) -> (MerklePath, Word) { >::open(self, key) } @@ -147,7 +144,7 @@ impl SimpleSmt { } else if index.depth() > DEPTH { Err(MerkleError::DepthTooBig(index.depth() as u64)) } else if index.depth() == DEPTH { - let leaf = self.get_leaf(&LeafIndex::::try_from(index)?).into_owned(); + let leaf = self.get_leaf(&LeafIndex::::try_from(index)?); Ok(leaf.into()) } else { @@ -250,7 +247,7 @@ impl SparseMerkleTree for SimpleSmt { type Key = LeafIndex; type Value = Word; type Leaf = Word; - type Opening<'a> = (MerklePath, Cow<'a, Word>); + type Opening = (MerklePath, Word); const EMPTY_VALUE: Self::Value = EMPTY_WORD; @@ -278,18 +275,14 @@ impl SparseMerkleTree for SimpleSmt { self.leaves.insert(key.value(), value) } - fn get_leaf(&self, key: &LeafIndex) -> Cow<'_, Word> { + fn get_leaf(&self, key: &LeafIndex) -> Word { // the lookup in empty_hashes could fail only if empty_hashes were not built correctly // by the constructor as we check the depth of the lookup above. let leaf_pos = key.value(); match self.leaves.get(&leaf_pos) { - Some(word) => Cow::Borrowed(word), - None => { - let empty_root = *EmptySubtreeRoots::entry(DEPTH, DEPTH); - - Cow::Owned(empty_root.into()) - } + Some(word) => *word, + None => Word::from(*EmptySubtreeRoots::entry(DEPTH, DEPTH)), } } diff --git a/src/merkle/smt/simple/tests.rs b/src/merkle/smt/simple/tests.rs index 0a2c2d2a..4ef501c7 100644 --- a/src/merkle/smt/simple/tests.rs +++ b/src/merkle/smt/simple/tests.rs @@ -344,7 +344,7 @@ fn test_simplesmt_set_subtree() { }; assert_eq!(tree.root(), k); - assert_eq!(tree.get_leaf(&LeafIndex::::new(4).unwrap()).into_owned(), c); + assert_eq!(tree.get_leaf(&LeafIndex::::new(4).unwrap()), c); assert_eq!(tree.get_inner_node(NodeIndex::new_unchecked(2, 2)).hash(), g); } diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index f8dfc4cb..958bba1d 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -922,10 +922,7 @@ fn test_recorder() { let node = merkle_store.get_node(smtree.root(), index_2).unwrap(); assert_eq!( node, - smtree - .get_leaf(&LeafIndex::::try_from(index_2).unwrap()) - .into_owned() - .into() + smtree.get_leaf(&LeafIndex::::try_from(index_2).unwrap()).into() ); // assert that is doesnt contain nodes that were not recorded diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 45a78084..715eee87 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,10 +4,10 @@ use super::{utils::string::String, Word}; use core::fmt::{self, Display, Write}; #[cfg(not(feature = "std"))] -pub use alloc::{borrow::Cow, format, vec}; +pub use alloc::{format, vec}; #[cfg(feature = "std")] -pub use std::{borrow::Cow, format, vec}; +pub use std::{format, vec}; mod diff; mod kv_map; From 52d9c395f9e7c07658c73948c0e2ff4610ac318b Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 17 Jan 2024 09:14:51 -0500 Subject: [PATCH 105/121] docstring --- src/merkle/smt/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 4e0e153c..92017021 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -155,6 +155,7 @@ pub(crate) trait SparseMerkleTree { /// Returns the hash of a leaf fn hash_leaf(leaf: &Self::Leaf) -> RpoDigest; + /// Maps a key to a leaf index fn key_to_leaf_index(key: &Self::Key) -> LeafIndex; } From deda8f1223ed47efd88ac72132dd603a22efb48a Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 17 Jan 2024 09:21:53 -0500 Subject: [PATCH 106/121] fix `open()` docstring --- src/merkle/smt/full/mod.rs | 5 ++--- src/merkle/smt/mod.rs | 5 ++--- src/merkle/smt/simple/mod.rs | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index f8c17aca..c63800bf 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -102,9 +102,8 @@ impl Smt { SMT_DEPTH } - /// Returns a Merkle path from the leaf node specified by the key to the root. - /// - /// The node itself is not included in the path. + /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle + /// path to the leaf, as well as the leaf itself. pub fn open(&self, key: &RpoDigest) -> (MerklePath, SmtLeaf) { >::open(self, key) } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 92017021..03920952 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -60,9 +60,8 @@ pub(crate) trait SparseMerkleTree { // PROVIDED METHODS // --------------------------------------------------------------------------------------------- - /// Returns a Merkle path from the leaf node specified by the key to the root. - /// - /// The node itself is not included in the path. + /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle + /// path to the leaf, as well as the leaf itself. fn open(&self, key: &Self::Key) -> Self::Opening { let leaf = self.get_leaf(key); diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index c097fa95..fc9b1096 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -126,9 +126,8 @@ impl SimpleSmt { DEPTH } - /// Returns a Merkle path from the leaf node specified by the key to the root. - /// - /// The node itself is not included in the path. + /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle + /// path to the leaf, as well as the leaf itself. pub fn open(&self, key: &LeafIndex) -> (MerklePath, Word) { >::open(self, key) } From 2685aa94e2706486761337fd4d95395d85c506b3 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 17 Jan 2024 09:23:55 -0500 Subject: [PATCH 107/121] move `depth()` function up --- src/merkle/smt/full/mod.rs | 10 +++++----- src/merkle/smt/simple/mod.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index c63800bf..c0cdaa69 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -87,6 +87,11 @@ impl Smt { // PUBLIC ACCESSORS // -------------------------------------------------------------------------------------------- + /// Returns the depth of the tree + pub const fn depth(&self) -> u8 { + SMT_DEPTH + } + /// Returns the root of the tree pub fn root(&self) -> RpoDigest { >::root(self) @@ -97,11 +102,6 @@ impl Smt { >::get_leaf(self, key) } - /// Returns the depth of the tree - pub const fn depth(&self) -> u8 { - SMT_DEPTH - } - /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle /// path to the leaf, as well as the leaf itself. pub fn open(&self, key: &RpoDigest) -> (MerklePath, SmtLeaf) { diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index fc9b1096..1c5f821e 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -111,6 +111,11 @@ impl SimpleSmt { // PUBLIC ACCESSORS // -------------------------------------------------------------------------------------------- + /// Returns the depth of the tree + pub const fn depth(&self) -> u8 { + DEPTH + } + /// Returns the root of the tree pub fn root(&self) -> RpoDigest { >::root(self) @@ -121,11 +126,6 @@ impl SimpleSmt { >::get_leaf(self, key) } - /// Returns the depth of the tree - pub const fn depth(&self) -> u8 { - DEPTH - } - /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle /// path to the leaf, as well as the leaf itself. pub fn open(&self, key: &LeafIndex) -> (MerklePath, Word) { From 9088d89bfea2bd69c0870ece1bb443f969bfec13 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 17 Jan 2024 09:25:08 -0500 Subject: [PATCH 108/121] fix var name --- src/merkle/smt/simple/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index 1c5f821e..da2306f2 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -290,8 +290,8 @@ impl SparseMerkleTree for SimpleSmt { leaf.into() } - fn key_to_leaf_index(leaf: &LeafIndex) -> LeafIndex { - *leaf + fn key_to_leaf_index(key: &LeafIndex) -> LeafIndex { + *key } } From e5bf0ce42c8d547270576fe9c0f1c148c634888a Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 17 Jan 2024 09:26:00 -0500 Subject: [PATCH 109/121] move `open()` down --- src/merkle/smt/simple/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index da2306f2..33518593 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -126,12 +126,6 @@ impl SimpleSmt { >::get_leaf(self, key) } - /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle - /// path to the leaf, as well as the leaf itself. - pub fn open(&self, key: &LeafIndex) -> (MerklePath, Word) { - >::open(self, key) - } - /// Returns a node at the specified index. /// /// # Errors @@ -151,6 +145,12 @@ impl SimpleSmt { } } + /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle + /// path to the leaf, as well as the leaf itself. + pub fn open(&self, key: &LeafIndex) -> (MerklePath, Word) { + >::open(self, key) + } + // ITERATORS // -------------------------------------------------------------------------------------------- From 49cdf6384fd136961a1dd10db7aa9b0975ea7712 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 17 Jan 2024 09:26:53 -0500 Subject: [PATCH 110/121] fix comment --- src/merkle/smt/simple/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index 33518593..a04e50b4 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -159,7 +159,7 @@ impl SimpleSmt { self.leaves.iter().map(|(i, w)| (*i, w)) } - /// Returns an iterator over the inner nodes of this Merkle tree. + /// Returns an iterator over the inner nodes of this [SimpleSmt]. pub fn inner_nodes(&self) -> impl Iterator + '_ { self.inner_nodes.values().map(|e| InnerNodeInfo { value: e.hash(), From 7e9afc9ead486a53005bf6421c194736c87248e7 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 17 Jan 2024 09:38:03 -0500 Subject: [PATCH 111/121] `ValuePath`: adjust constructor --- src/merkle/path.rs | 4 ++-- src/merkle/store/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/merkle/path.rs b/src/merkle/path.rs index f2b12b77..a1dfdf23 100644 --- a/src/merkle/path.rs +++ b/src/merkle/path.rs @@ -174,8 +174,8 @@ pub struct ValuePath { impl ValuePath { /// Returns a new [ValuePath] instantiated from the specified value and path. - pub fn new(value: RpoDigest, path: Vec) -> Self { - Self { value, path: MerklePath::new(path) } + pub fn new(value: RpoDigest, path: MerklePath) -> Self { + Self { value, path } } } diff --git a/src/merkle/store/mod.rs b/src/merkle/store/mod.rs index 7e931904..9f9bf0d6 100644 --- a/src/merkle/store/mod.rs +++ b/src/merkle/store/mod.rs @@ -173,7 +173,7 @@ impl> MerkleStore { // the path is computed from root to leaf, so it must be reversed path.reverse(); - Ok(ValuePath::new(hash, path)) + Ok(ValuePath::new(hash, MerklePath::new(path))) } // LEAF TRAVERSAL From 88797c393777c220089378a1b183c006effd98ae Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Wed, 17 Jan 2024 09:44:02 -0500 Subject: [PATCH 112/121] Use `ValuePath` in simple smt --- src/merkle/path.rs | 8 ++++++++ src/merkle/smt/simple/mod.rs | 10 +++++----- src/merkle/smt/simple/tests.rs | 16 ++++++++-------- src/merkle/store/tests.rs | 14 +++++++------- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/merkle/path.rs b/src/merkle/path.rs index a1dfdf23..a9c86b1a 100644 --- a/src/merkle/path.rs +++ b/src/merkle/path.rs @@ -1,3 +1,5 @@ +use crate::Word; + use super::{vec, InnerNodeInfo, MerkleError, NodeIndex, Rpo256, RpoDigest, Vec}; use core::ops::{Deref, DerefMut}; use winter_utils::{ByteReader, Deserializable, DeserializationError, Serializable}; @@ -179,6 +181,12 @@ impl ValuePath { } } +impl From<(MerklePath, Word)> for ValuePath { + fn from((path, value): (MerklePath, Word)) -> Self { + ValuePath::new(value.into(), path) + } +} + /// A container for a [MerklePath] and its [Word] root. /// /// This structure does not provide any guarantees regarding the correctness of the path to the diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index a04e50b4..05c8e214 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -1,12 +1,12 @@ use crate::{ - merkle::{EmptySubtreeRoots, InnerNodeInfo, MerkleTreeDelta, StoreNode}, + merkle::{EmptySubtreeRoots, InnerNodeInfo, MerkleTreeDelta, StoreNode, ValuePath}, utils::collections::TryApplyDiff, EMPTY_WORD, }; use super::{ - InnerNode, LeafIndex, MerkleError, MerklePath, NodeIndex, RpoDigest, SparseMerkleTree, Word, - SMT_MAX_DEPTH, SMT_MIN_DEPTH, + InnerNode, LeafIndex, MerkleError, NodeIndex, RpoDigest, SparseMerkleTree, Word, SMT_MAX_DEPTH, + SMT_MIN_DEPTH, }; use crate::utils::collections::{BTreeMap, BTreeSet}; @@ -147,7 +147,7 @@ impl SimpleSmt { /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle /// path to the leaf, as well as the leaf itself. - pub fn open(&self, key: &LeafIndex) -> (MerklePath, Word) { + pub fn open(&self, key: &LeafIndex) -> ValuePath { >::open(self, key) } @@ -246,7 +246,7 @@ impl SparseMerkleTree for SimpleSmt { type Key = LeafIndex; type Value = Word; type Leaf = Word; - type Opening = (MerklePath, Word); + type Opening = ValuePath; const EMPTY_VALUE: Self::Value = EMPTY_WORD; diff --git a/src/merkle/smt/simple/tests.rs b/src/merkle/smt/simple/tests.rs index 4ef501c7..87b385d7 100644 --- a/src/merkle/smt/simple/tests.rs +++ b/src/merkle/smt/simple/tests.rs @@ -59,7 +59,7 @@ fn build_sparse_tree() { assert_eq!(mt2.root(), smt.root()); assert_eq!( mt2.get_path(NodeIndex::make(3, 6)).unwrap(), - smt.open(&LeafIndex::<3>::new(6).unwrap()).0 + smt.open(&LeafIndex::<3>::new(6).unwrap()).path ); assert_eq!(old_value, EMPTY_WORD); @@ -72,7 +72,7 @@ fn build_sparse_tree() { assert_eq!(mt3.root(), smt.root()); assert_eq!( mt3.get_path(NodeIndex::make(3, 2)).unwrap(), - smt.open(&LeafIndex::<3>::new(2).unwrap()).0 + smt.open(&LeafIndex::<3>::new(2).unwrap()).path ); assert_eq!(old_value, EMPTY_WORD); } @@ -108,10 +108,10 @@ fn test_depth2_tree() { assert_eq!(VALUES4[3], tree.get_node(NodeIndex::make(2, 3)).unwrap()); // check get_path(): depth 2 - assert_eq!(vec![VALUES4[1], node3], *tree.open(&LeafIndex::<2>::new(0).unwrap()).0); - assert_eq!(vec![VALUES4[0], node3], *tree.open(&LeafIndex::<2>::new(1).unwrap()).0); - assert_eq!(vec![VALUES4[3], node2], *tree.open(&LeafIndex::<2>::new(2).unwrap()).0); - assert_eq!(vec![VALUES4[2], node2], *tree.open(&LeafIndex::<2>::new(3).unwrap()).0); + assert_eq!(vec![VALUES4[1], node3], *tree.open(&LeafIndex::<2>::new(0).unwrap()).path); + assert_eq!(vec![VALUES4[0], node3], *tree.open(&LeafIndex::<2>::new(1).unwrap()).path); + assert_eq!(vec![VALUES4[3], node2], *tree.open(&LeafIndex::<2>::new(2).unwrap()).path); + assert_eq!(vec![VALUES4[2], node2], *tree.open(&LeafIndex::<2>::new(3).unwrap()).path); } #[test] @@ -213,9 +213,9 @@ fn small_tree_opening_is_consistent() { ]; for (key, path) in cases { - let (opening, _) = tree.open(&LeafIndex::<3>::new(key).unwrap()); + let opening = tree.open(&LeafIndex::<3>::new(key).unwrap()); - assert_eq!(path, *opening); + assert_eq!(path, *opening.path); } } diff --git a/src/merkle/store/tests.rs b/src/merkle/store/tests.rs index 958bba1d..309b496e 100644 --- a/src/merkle/store/tests.rs +++ b/src/merkle/store/tests.rs @@ -182,7 +182,7 @@ fn test_leaf_paths_for_empty_trees() -> Result<(), MerkleError> { let index = NodeIndex::make(DEPTH, 0); let store_path = store.get_path(smt.root(), index)?; - let smt_path = smt.open(&LeafIndex::::new(0)?).0; + let smt_path = smt.open(&LeafIndex::::new(0)?).path; assert_eq!( store_path.value, RpoDigest::default(), @@ -301,7 +301,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 0 must match leaf value" ); assert_eq!( - smt.open(&LeafIndex::::new(0).unwrap()).0, + smt.open(&LeafIndex::::new(0).unwrap()).path, result.path, "merkle path for index 0 must be the same for the MerkleTree and MerkleStore" ); @@ -312,7 +312,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 1 must match leaf value" ); assert_eq!( - smt.open(&LeafIndex::::new(1).unwrap()).0, + smt.open(&LeafIndex::::new(1).unwrap()).path, result.path, "merkle path for index 1 must be the same for the MerkleTree and MerkleStore" ); @@ -323,7 +323,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 2 must match leaf value" ); assert_eq!( - smt.open(&LeafIndex::::new(2).unwrap()).0, + smt.open(&LeafIndex::::new(2).unwrap()).path, result.path, "merkle path for index 2 must be the same for the MerkleTree and MerkleStore" ); @@ -334,7 +334,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 3 must match leaf value" ); assert_eq!( - smt.open(&LeafIndex::::new(3).unwrap()).0, + smt.open(&LeafIndex::::new(3).unwrap()).path, result.path, "merkle path for index 3 must be the same for the MerkleTree and MerkleStore" ); @@ -346,7 +346,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> { "Value for merkle path at index 4 must match leaf value" ); assert_eq!( - smt.open(&LeafIndex::::new(4).unwrap()).0, + smt.open(&LeafIndex::::new(4).unwrap()).path, result.path, "merkle path for index 4 must be the same for the MerkleTree and MerkleStore" ); @@ -563,7 +563,7 @@ fn test_constructors() -> Result<(), MerkleError> { for key in KEYS4 { let index = NodeIndex::make(DEPTH, key); let value_path = store.get_path(smt.root(), index)?; - assert_eq!(smt.open(&LeafIndex::::new(key).unwrap()).0, value_path.path); + assert_eq!(smt.open(&LeafIndex::::new(key).unwrap()).path, value_path.path); } let d = 2; From 7897d4effe4dbd053dbcf49e82d4e28f25fde212 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 19 Jan 2024 09:56:54 -0500 Subject: [PATCH 113/121] Add `Self::EMPTY_VALUE` --- src/merkle/smt/full/mod.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index c0cdaa69..47c8251b 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -1,4 +1,5 @@ use core::cmp::Ordering; +use core::f64::consts::E; use winter_math::StarkField; @@ -34,12 +35,17 @@ pub struct Smt { } impl Smt { + // CONSTANTS + // -------------------------------------------------------------------------------------------- + /// The default value used to compute the hash of empty leaves + pub const EMPTY_VALUE: Word = >::EMPTY_VALUE; + // CONSTRUCTORS // -------------------------------------------------------------------------------------------- - /// Returns a new [NewSmt]. + /// Returns a new [Smt]. /// - /// All leaves in the returned tree are set to [ZERO; 4]. + /// All leaves in the returned tree are set to [Self::EMPTY_VALUE]. pub fn new() -> Self { let root = *EmptySubtreeRoots::entry(SMT_DEPTH, 0); @@ -50,9 +56,9 @@ impl Smt { } } - /// Returns a new [SimpleSmt] instantiated with leaves set as specified by the provided entries. + /// Returns a new [Smt] instantiated with leaves set as specified by the provided entries. /// - /// All leaves omitted from the entries list are set to [ZERO; 4]. + /// All leaves omitted from the entries list are set to [Self::EMPTY_VALUE]. /// /// # Errors /// Returns an error if: From 8d375d21420d6b346d12801fd8105863a023d51c Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 19 Jan 2024 09:59:37 -0500 Subject: [PATCH 114/121] Use `Self::EMPTY_VALUE` --- src/merkle/smt/full/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index 47c8251b..973968df 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -119,7 +119,7 @@ impl Smt { /// Inserts a value at the specified key, returning the previous value associated with that key. /// Recall that by definition, any key that hasn't been updated is associated with - /// [`EMPTY_WORD`]. + /// [`Self::EMPTY_VALUE`]. /// /// This also recomputes all hashes between the leaf (associated with the key) and the root, /// updating the root itself. From e6563e58e057186aff215fb3d7c3282f03e82514 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 19 Jan 2024 10:01:59 -0500 Subject: [PATCH 115/121] fix comment --- src/merkle/smt/full/mod.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index 973968df..0ba2595d 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -45,7 +45,7 @@ impl Smt { /// Returns a new [Smt]. /// - /// All leaves in the returned tree are set to [Self::EMPTY_VALUE]. + /// All keys in the returned tree are associated to [Self::EMPTY_VALUE]. pub fn new() -> Self { let root = *EmptySubtreeRoots::entry(SMT_DEPTH, 0); @@ -58,12 +58,10 @@ impl Smt { /// Returns a new [Smt] instantiated with leaves set as specified by the provided entries. /// - /// All leaves omitted from the entries list are set to [Self::EMPTY_VALUE]. + /// All keys omitted from the entries list are associated to [Self::EMPTY_VALUE]. /// /// # Errors - /// Returns an error if: - /// - The number of entries exceeds 2^63 entries. - /// - The provided entries contain multiple values for the same key. + /// Returns an error if the provided entries contain multiple values for the same key. pub fn with_entries( entries: impl IntoIterator, ) -> Result { From 13fc43151d0a6b3fb3a04996b69f52c7e1a53546 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 19 Jan 2024 10:21:37 -0500 Subject: [PATCH 116/121] remove unused import --- src/merkle/smt/full/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index 0ba2595d..ac1345fa 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -1,5 +1,4 @@ use core::cmp::Ordering; -use core::f64::consts::E; use winter_math::StarkField; From 6e0a9699f2013885884f3bca913c466cf7a21648 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 19 Jan 2024 10:27:07 -0500 Subject: [PATCH 117/121] adjust `remove` docstring --- src/merkle/smt/full/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index ac1345fa..ceb6472c 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -301,8 +301,8 @@ impl SmtLeaf { } } - /// Remove key-value pair into the leaf stored at key; return the previous value associated with - /// `key`, if any. We also return an `is_empty` flag which indicates whether the leaf became + /// Removes key-value pair from the leaf stored at key; returns the previous value associated + /// with `key`, if any. Also returns an `is_empty` flag, indicating whether the leaf became /// empty, and must be removed from the data structure it is contained in. fn remove(&mut self, key: RpoDigest) -> (Option, bool) { match self { From b6458a4f076261706db28a24df29125bb71188a2 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 19 Jan 2024 10:46:54 -0500 Subject: [PATCH 118/121] fix docstrings --- src/merkle/smt/full/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index ceb6472c..d0f425b1 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -247,7 +247,7 @@ impl SmtLeaf { } } - /// Compute the hash of the leaf + /// Computes the hash of the leaf pub fn hash(&self) -> RpoDigest { match self { SmtLeaf::Single((key, value)) => Rpo256::merge(&[*key, value.into()]), @@ -261,7 +261,7 @@ impl SmtLeaf { // HELPERS // --------------------------------------------------------------------------------------------- - /// Insert key-value pair into the leaf; return the previous value associated with `key`, if + /// Inserts key-value pair into the leaf; returns the previous value associated with `key`, if /// any. fn insert(&mut self, key: RpoDigest, value: Word) -> Option { match self { From 50f653d6d08a8e27dbf43d03880bfdd756e0146f Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 19 Jan 2024 10:53:38 -0500 Subject: [PATCH 119/121] clean up `test_smt_insert_at_same_key_2` --- src/merkle/smt/full/tests.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index f068e22f..796c16f2 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -50,11 +50,11 @@ fn test_smt_insert_at_same_key() { /// only the case where the leaf type is `SmtLeaf::Multiple` #[test] fn test_smt_insert_at_same_key_2() { - let key_already_present: RpoDigest = { - let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; + // The most significant u64 used for both keys (to ensure they map to the same leaf) + let key_msb: u64 = 42; - RpoDigest::from([ONE + ONE, ONE + ONE, ONE + ONE, Felt::new(raw)]) - }; + let key_already_present: RpoDigest = + RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), Felt::new(key_msb)]); let key_already_present_index: NodeIndex = LeafIndex::::from(key_already_present).into(); let value_already_present = [ONE + ONE + ONE; WORD_SIZE]; @@ -71,11 +71,7 @@ fn test_smt_insert_at_same_key_2() { store }; - let key_1: RpoDigest = { - let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64; - - RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]) - }; + let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, Felt::new(key_msb)]); let key_1_index: NodeIndex = LeafIndex::::from(key_1).into(); assert_eq!(key_1_index, key_already_present_index); From a880c880ab4f9f22507de24536b99f0700f61ebb Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 19 Jan 2024 12:26:07 -0500 Subject: [PATCH 120/121] Introduce SmtLeaf::Empty --- src/merkle/smt/full/mod.rs | 18 +++++++++++++++--- src/merkle/smt/full/tests.rs | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index d0f425b1..0a796a7e 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -44,7 +44,7 @@ impl Smt { /// Returns a new [Smt]. /// - /// All keys in the returned tree are associated to [Self::EMPTY_VALUE]. + /// All leaves in the returned tree are set to [Self::EMPTY_VALUE]. pub fn new() -> Self { let root = *EmptySubtreeRoots::entry(SMT_DEPTH, 0); @@ -57,7 +57,7 @@ impl Smt { /// Returns a new [Smt] instantiated with leaves set as specified by the provided entries. /// - /// All keys omitted from the entries list are associated to [Self::EMPTY_VALUE]. + /// All leaves omitted from the entries list are set to [Self::EMPTY_VALUE]. /// /// # Errors /// Returns an error if the provided entries contain multiple values for the same key. @@ -203,7 +203,7 @@ impl SparseMerkleTree for Smt { match self.leaves.get(&leaf_pos) { Some(leaf) => leaf.clone(), - None => SmtLeaf::Single((*key, Self::EMPTY_VALUE)), + None => SmtLeaf::Empty, } } @@ -229,6 +229,7 @@ impl Default for Smt { #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum SmtLeaf { + Empty, Single((RpoDigest, Word)), Multiple(Vec<(RpoDigest, Word)>), } @@ -242,6 +243,7 @@ impl SmtLeaf { /// Converts a leaf to a list of field elements pub fn into_elements(self) -> Vec { match self { + SmtLeaf::Empty => Vec::new(), SmtLeaf::Single(kv_pair) => kv_to_elements(kv_pair).collect(), SmtLeaf::Multiple(kv_pairs) => kv_pairs.into_iter().flat_map(kv_to_elements).collect(), } @@ -250,6 +252,7 @@ impl SmtLeaf { /// Computes the hash of the leaf pub fn hash(&self) -> RpoDigest { match self { + SmtLeaf::Empty => EMPTY_WORD.into(), SmtLeaf::Single((key, value)) => Rpo256::merge(&[*key, value.into()]), SmtLeaf::Multiple(kvs) => { let elements: Vec = kvs.iter().copied().flat_map(kv_to_elements).collect(); @@ -265,6 +268,10 @@ impl SmtLeaf { /// any. fn insert(&mut self, key: RpoDigest, value: Word) -> Option { match self { + SmtLeaf::Empty => { + *self = SmtLeaf::Single((key, value)); + None + } SmtLeaf::Single(kv_pair) => { if kv_pair.0 == key { // the key is already in this leaf. Update the value and return the previous @@ -306,12 +313,17 @@ impl SmtLeaf { /// empty, and must be removed from the data structure it is contained in. fn remove(&mut self, key: RpoDigest) -> (Option, bool) { match self { + SmtLeaf::Empty => (None, false), SmtLeaf::Single((key_at_leaf, value_at_leaf)) => { if *key_at_leaf == key { // our key was indeed stored in the leaf, so we return the value that was stored // in it, and indicate that the leaf should be removed let old_value = *value_at_leaf; + // Note: this is not strictly needed, since the caller is expected to drop this + // `SmtLeaf` object. + *self = SmtLeaf::Empty; + (Some(old_value), true) } else { // another key is stored at leaf; nothing to update diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index 796c16f2..e1603c11 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -231,7 +231,7 @@ fn test_smt_removal() { let old_value_1 = smt.insert(key_1, EMPTY_WORD); assert_eq!(old_value_1, value_1); - assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Single((key_1, EMPTY_WORD))); + assert_eq!(smt.get_leaf(&key_1), SmtLeaf::Empty); } } From 21214caa4165eba6e571a54ff5e7b26a78c245f2 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Fri, 19 Jan 2024 12:37:42 -0500 Subject: [PATCH 121/121] add empty leaf hash test --- src/merkle/smt/full/tests.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index e1603c11..b526cbf0 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -252,6 +252,15 @@ fn test_smt_path_to_keys_in_same_leaf_are_equal() { assert_eq!(smt.open(&key_1), smt.open(&key_2)); } +/// Tests that an empty leaf hashes to the empty word +#[test] +fn test_empty_leaf_hash() { + let smt = Smt::default(); + + let leaf = smt.get_leaf(&RpoDigest::default()); + assert_eq!(leaf.hash(), EMPTY_WORD.into()); +} + // HELPERS // --------------------------------------------------------------------------------------------