Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing methods to Smt #268

Merged
merged 7 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions src/merkle/smt/full/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,18 @@ impl Smt {
<Self as SparseMerkleTree<SMT_DEPTH>>::root(self)
}

/// Returns the leaf at the specified index.
/// Returns the leaf to which `key` maps
pub fn get_leaf(&self, key: &RpoDigest) -> SmtLeaf {
<Self as SparseMerkleTree<SMT_DEPTH>>::get_leaf(self, key)
}

/// Returns the value associated with `key`
pub fn get_value(&self, key: &RpoDigest) -> Word {
let leaf = self.get_leaf(key);

leaf.get_value(key)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comment as above: this may result in closing of the leaf first and then getting a value from it. May be better to make sure we don't rely on the compiler for optimizing away unnecessary cloning/allocations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

}

/// 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) {
Expand All @@ -130,6 +137,11 @@ impl Smt {
.map(|(leaf_index, leaf)| (LeafIndex::new_max_depth(*leaf_index), leaf))
}

/// Returns an iterator over the key-value pairs of this [Smt].
pub fn entries(&self) -> impl Iterator<Item = &(RpoDigest, Word)> {
self.leaves().flat_map(|(_, leaf)| leaf.entries())
}

/// Returns an iterator over the inner nodes of this [Smt].
pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
self.inner_nodes.values().map(|e| InnerNodeInfo {
Expand Down Expand Up @@ -270,11 +282,11 @@ impl SmtLeaf {

/// Converts a leaf to a list of field elements
pub fn into_elements(self) -> Vec<Felt> {
self.into_kv_pairs().into_iter().flat_map(kv_to_elements).collect()
self.into_entries().into_iter().flat_map(kv_to_elements).collect()
}

/// Returns the key-value pairs in the leaf
pub fn kv_pairs(&self) -> Vec<&(RpoDigest, Word)> {
pub fn entries(&self) -> Vec<&(RpoDigest, Word)> {
match self {
SmtLeaf::Empty => Vec::new(),
SmtLeaf::Single(kv_pair) => vec![kv_pair],
Expand All @@ -283,7 +295,7 @@ impl SmtLeaf {
}

/// Converts a leaf the key-value pairs in the leaf
pub fn into_kv_pairs(self) -> Vec<(RpoDigest, Word)> {
pub fn into_entries(self) -> Vec<(RpoDigest, Word)> {
match self {
SmtLeaf::Empty => Vec::new(),
SmtLeaf::Single(kv_pair) => vec![kv_pair],
Expand All @@ -306,6 +318,17 @@ impl SmtLeaf {
// HELPERS
// ---------------------------------------------------------------------------------------------

/// Returns the value associated with `key` in the leaf
fn get_value(&self, key: &RpoDigest) -> Word {
for (key_in_leaf, value_in_leaf) in self.entries() {
if key == key_in_leaf {
return *value_in_leaf;
}
}

EMPTY_WORD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the compiler can optimize this away, but I'd prefer to handle it using a match statement to avoid potential unnecessary allocations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

}

/// 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<Word> {
Expand Down
45 changes: 45 additions & 0 deletions src/merkle/smt/full/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,51 @@ fn test_empty_leaf_hash() {
assert_eq!(leaf.hash(), EMPTY_WORD.into());
}

/// Tests that `get_value()` works as expected
#[test]
fn test_smt_get_value() {
let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, ONE]);
let key_2: RpoDigest =
RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), 2_u64.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();

let returned_value_1 = smt.get_value(&key_1);
let returned_value_2 = smt.get_value(&key_2);

assert_eq!(value_1, returned_value_1);
assert_eq!(value_2, returned_value_2);

// Check that a key with no inserted value returns the empty word
let key_no_value =
RpoDigest::from([42_u64.into(), 42_u64.into(), 42_u64.into(), 42_u64.into()]);

assert_eq!(EMPTY_WORD, smt.get_value(&key_no_value));
}

/// Tests that `entries()` works as expected
#[test]
fn test_smt_entries() {
let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, ONE]);
let key_2: RpoDigest =
RpoDigest::from([2_u64.into(), 2_u64.into(), 2_u64.into(), 2_u64.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();

let mut entries = smt.entries();

// Note: for simplicity, we assume the order `(k1,v1), (k2,v2)`. If a new implementation
// switches the order, it is OK to modify the order here as well.
assert_eq!(&(key_1, value_1), entries.next().unwrap());
assert_eq!(&(key_2, value_2), entries.next().unwrap());
assert!(entries.next().is_none());
}
// HELPERS
// --------------------------------------------------------------------------------------------

Expand Down
Loading