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/ 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..a8c410f9 100644 --- a/benches/smt.rs +++ b/benches/smt.rs @@ -1,16 +1,20 @@ 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}, + 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 +22,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 = DEPTH; + let key = count >> 2; + insert.bench_with_input( + format!("simple smt(depth:{depth},count:{count})"), + &(key, leaf), + |b, (key, leaf)| { + b.iter(|| { + tree.insert(black_box(LeafIndex::::new(*key).unwrap()), black_box(*leaf)); + }); + }, + ); - 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 = DEPTH; + let key = count >> 2; + path.bench_with_input( + format!("simple smt(depth:{depth},count:{count})"), + &key, + |b, key| { + b.iter(|| { + tree.open(black_box(&LeafIndex::::new(*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..ca1bbcd1 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, LeafIndex, MerkleTree, NodeIndex, SimpleSmt, 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 = 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,15 +106,14 @@ 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(); 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, ) @@ -120,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, ) @@ -132,18 +133,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 = 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 +152,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,10 +213,10 @@ 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; + 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| { @@ -286,23 +287,24 @@ 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(); let size_u64 = size as u64; group.bench_function(BenchmarkId::new("SimpleSmt", size), |b| { b.iter_batched( - || random_index(size_u64, depth), - |index| black_box(smt.get_path(index)), + || random_index(size_u64, SMT_MAX_DEPTH), + |index| { + black_box(smt.open(&LeafIndex::::new(index.value()).unwrap())) + }, BatchSize::SmallInput, ) }); 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, ) @@ -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,16 +435,17 @@ 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(); let size_u64 = size as u64; 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.insert(LeafIndex::::new(index).unwrap(), value)) + }, BatchSize::SmallInput, ) }); @@ -450,7 +453,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 064cd01b..baede807 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::with_leaves(30, 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::*; + + #[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::::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(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(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(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, TREE_DEPTH, &store).unwrap(); + let expected_merkle_delta = MerkleTreeDelta { + depth: TREE_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/mod.rs b/src/merkle/mod.rs index 9c6c3c77..c3ad147e 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -24,8 +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; +mod smt; +pub use smt::{LeafIndex, SimpleSmt, SMT_MAX_DEPTH, SMT_MIN_DEPTH}; mod tiered_smt; pub use tiered_smt::{TieredSmt, TieredSmtProof, TieredSmtProofError}; diff --git a/src/merkle/path.rs b/src/merkle/path.rs index f2b12b77..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}; @@ -174,8 +176,14 @@ 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 } + } +} + +impl From<(MerklePath, Word)> for ValuePath { + fn from((path, value): (MerklePath, Word)) -> Self { + ValuePath::new(value.into(), path) } } diff --git a/src/merkle/simple_smt/mod.rs b/src/merkle/simple_smt/mod.rs deleted file mode 100644 index 4ce94a41..00000000 --- a/src/merkle/simple_smt/mod.rs +++ /dev/null @@ -1,389 +0,0 @@ -use super::{ - BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, MerkleTreeDelta, - NodeIndex, Rpo256, RpoDigest, StoreNode, TryApplyDiff, Vec, Word, -}; - -#[cfg(test)] -mod tests; - -// SPARSE MERKLE TREE -// ================================================================================================ - -/// A sparse Merkle tree with 64-bit keys and 4-element leaf values, without compaction. -/// -/// 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, - 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; - - // CONSTRUCTORS - // -------------------------------------------------------------------------------------------- - - /// Returns a new [SimpleSmt] instantiated with the specified depth. - /// - /// 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. - pub fn new(depth: u8) -> 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)); - } - - let root = *EmptySubtreeRoots::entry(depth, 0); - - Ok(Self { - root, - depth, - leaves: BTreeMap::new(), - branches: BTreeMap::new(), - }) - } - - /// Returns a new [SimpleSmt] instantiated with the specified depth and 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: - /// - If the depth is 0 or is greater than 64. - /// - 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)?; - - // 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 != Self::EMPTY_VALUE || key_set_to_zero.contains(&key) { - return Err(MerkleError::DuplicateValuesForIndex(key)); - } - - if value == Self::EMPTY_VALUE { - key_set_to_zero.insert(key); - }; - } - Ok(tree) - } - - /// 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() - .map(|(idx, word)| (idx.try_into().expect("tree max depth is 2^8"), word)), - ) - } - - // 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 { - self.depth - } - - /// Returns a node at the specified index. - /// - /// # 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_node(&self, index: NodeIndex) -> Result { - if index.is_root() { - Err(MerkleError::DepthTooSmall(index.depth())) - } 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) - } else { - Ok(self.get_branch_node(&index).parent()) - } - } - - /// 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()) - } - - /// 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 BranchNode { 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 - // -------------------------------------------------------------------------------------------- - - /// Returns an iterator over the leaves of this [SimpleSmt]. - pub fn leaves(&self) -> impl Iterator { - self.leaves.iter().map(|(i, w)| (*i, w)) - } - - /// 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(), - left: e.left, - right: e.right, - }) - } - - // 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.insert_leaf_node(index, value).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 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()`. - /// - /// Returns the new root. - pub fn set_subtree( - &mut self, - subtree_insertion_index: u64, - subtree: SimpleSmt, - ) -> Result { - if subtree.depth() > self.depth() { - return Err(MerkleError::InvalidSubtreeDepth { - subtree_depth: subtree.depth(), - tree_depth: self.depth(), - }); - } - - // Verify that `subtree_insertion_index` is valid. - let subtree_root_insertion_depth = self.depth() - subtree.depth(); - let subtree_root_index = - NodeIndex::new(subtree_root_insertion_depth, subtree_insertion_index)?; - - // add leaves - // -------------- - - // The subtree's leaf indices live in their own context - i.e. a subtree of depth `d`. If we - // insert the subtree at `subtree_insertion_index = 0`, then the subtree leaf indices are - // valid as they are. However, consider what happens when we insert at - // `subtree_insertion_index = 1`. The first leaf of our subtree now will have index `2^d`; - // 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()); - 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())); - - self.insert_leaf_node(new_leaf_idx, *leaf_value); - } - - // add subtree's branch nodes (which includes the root) - // -------------- - for (branch_idx, branch_node) in subtree.branches { - 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()) - + branch_idx.value(); - - NodeIndex::new(new_depth, new_value).expect("index guaranteed to be valid") - }; - - self.branches.insert(new_branch_idx, branch_node); - } - - // recompute nodes starting from subtree root - // -------------- - self.recompute_nodes_from_index_to_root(subtree_root_index, subtree.root); - - Ok(self.root) - } - - // 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 BranchNode { 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]); - } - self.root = value; - } - - 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) - } - - fn get_branch_node(&self, index: &NodeIndex) -> BranchNode { - self.branches.get(index).cloned().unwrap_or_else(|| { - let node = EmptySubtreeRoots::entry(self.depth, index.depth() + 1); - BranchNode { left: *node, right: *node } - }) - } - - fn insert_branch_node(&mut self, index: NodeIndex, left: RpoDigest, right: RpoDigest) { - let branch = BranchNode { 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 { - type Error = MerkleError; - 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(), - }); - } - - for slot in diff.cleared_slots() { - self.update_leaf(*slot, Self::EMPTY_VALUE)?; - } - - for (slot, value) in diff.updated_slots() { - self.update_leaf(*slot, *value)?; - } - - Ok(()) - } -} diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs new file mode 100644 index 00000000..67bb8167 --- /dev/null +++ b/src/merkle/smt/mod.rs @@ -0,0 +1,238 @@ +use winter_math::StarkField; + +use crate::{ + hash::rpo::{Rpo256, RpoDigest}, + Word, +}; + +use super::{MerkleError, MerklePath, NodeIndex, Vec}; + +mod simple; +pub use simple::SimpleSmt; + +// 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 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); + + 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; + + /// Maps a key to a leaf index + 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 const 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() + } +} diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs new file mode 100644 index 00000000..4186cf7d --- /dev/null +++ b/src/merkle/smt/simple/mod.rs @@ -0,0 +1,325 @@ +use crate::{ + merkle::{EmptySubtreeRoots, InnerNodeInfo, MerkleTreeDelta, StoreNode, ValuePath}, + utils::collections::TryApplyDiff, + EMPTY_WORD, +}; + +use super::{ + InnerNode, LeafIndex, MerkleError, NodeIndex, RpoDigest, SparseMerkleTree, Word, SMT_MAX_DEPTH, + SMT_MIN_DEPTH, +}; +use crate::utils::collections::{BTreeMap, BTreeSet}; + +#[cfg(test)] +mod tests; + +// SPARSE MERKLE TREE +// ================================================================================================ + +/// A sparse Merkle tree with 64-bit keys and 4-element leaf values, without compaction. +/// +/// 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 { + root: RpoDigest, + leaves: BTreeMap, + inner_nodes: BTreeMap, +} + +impl SimpleSmt { + // CONSTANTS + // -------------------------------------------------------------------------------------------- + + /// The default value used to compute the hash of empty leaves + pub const EMPTY_VALUE: Word = >::EMPTY_VALUE; + + // CONSTRUCTORS + // -------------------------------------------------------------------------------------------- + + /// Returns a new [SimpleSmt]. + /// + /// All leaves in the returned tree are set to [ZERO; 4]. + /// + /// # Errors + /// 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 { + return Err(MerkleError::DepthTooSmall(DEPTH)); + } else if SMT_MAX_DEPTH < DEPTH { + return Err(MerkleError::DepthTooBig(DEPTH as u64)); + } + + let root = *EmptySubtreeRoots::entry(DEPTH, 0); + + Ok(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: + /// - If the depth is 0 or is greater than 64. + /// - 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( + 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(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.insert(LeafIndex::::new(key)?, value); + + if old_value != Self::EMPTY_VALUE || key_set_to_zero.contains(&key) { + return Err(MerkleError::DuplicateValuesForIndex(key)); + } + + if value == Self::EMPTY_VALUE { + key_set_to_zero.insert(key); + }; + } + Ok(tree) + } + + /// Wrapper around [`SimpleSmt::with_leaves`] which inserts leaves at contiguous indices + /// starting at index 0. + pub fn with_contiguous_leaves( + entries: impl IntoIterator, + ) -> Result { + Self::with_leaves( + entries + .into_iter() + .enumerate() + .map(|(idx, word)| (idx.try_into().expect("tree max depth is 2^8"), word)), + ) + } + + // 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) + } + + /// Returns the leaf at the specified index. + pub fn get_leaf(&self, key: &LeafIndex) -> Word { + >::get_leaf(self, key) + } + + /// Returns a node at the specified index. + /// + /// # 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_node(&self, index: NodeIndex) -> Result { + if index.is_root() { + Err(MerkleError::DepthTooSmall(index.depth())) + } 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)?); + + Ok(leaf.into()) + } else { + Ok(self.get_inner_node(index).hash()) + } + } + + /// 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) -> ValuePath { + >::open(self, key) + } + + // ITERATORS + // -------------------------------------------------------------------------------------------- + + /// Returns an iterator over the leaves of this [SimpleSmt]. + pub fn leaves(&self) -> impl Iterator { + self.leaves.iter().map(|(i, w)| (*i, w)) + } + + /// 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(), + left: e.left, + right: e.right, + }) + } + + // 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: LeafIndex, value: Word) -> Word { + >::insert(self, key, value) + } + + /// Inserts a subtree at the specified index. The depth at which the subtree is inserted is + /// computed as `DEPTH - SUBTREE_DEPTH`. + /// + /// Returns the new root. + pub fn set_subtree( + &mut self, + subtree_insertion_index: u64, + subtree: SimpleSmt, + ) -> Result { + if SUBTREE_DEPTH > DEPTH { + return Err(MerkleError::InvalidSubtreeDepth { + subtree_depth: SUBTREE_DEPTH, + tree_depth: DEPTH, + }); + } + + // Verify that `subtree_insertion_index` is valid. + let subtree_root_insertion_depth = DEPTH - SUBTREE_DEPTH; + let subtree_root_index = + NodeIndex::new(subtree_root_insertion_depth, subtree_insertion_index)?; + + // add leaves + // -------------- + + // The subtree's leaf indices live in their own context - i.e. a subtree of depth `d`. If we + // insert the subtree at `subtree_insertion_index = 0`, then the subtree leaf indices are + // valid as they are. However, consider what happens when we insert at + // `subtree_insertion_index = 1`. The first leaf of our subtree now will have index `2^d`; + // 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()); + 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(DEPTH.into())); + + self.leaves.insert(new_leaf_idx, *leaf_value); + } + + // add subtree's branch nodes (which includes the root) + // -------------- + 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()) + + branch_idx.value(); + + NodeIndex::new(new_depth, new_value).expect("index guaranteed to be valid") + }; + + self.inner_nodes.insert(new_branch_idx, branch_node); + } + + // recompute nodes starting from subtree root + // -------------- + self.recompute_nodes_from_index_to_root(subtree_root_index, subtree.root); + + Ok(self.root) + } +} + +impl SparseMerkleTree for SimpleSmt { + type Key = LeafIndex; + type Value = Word; + type Leaf = Word; + type Opening = ValuePath; + + 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(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: LeafIndex, value: Word) -> Option { + self.leaves.insert(key.value(), value) + } + + 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) => *word, + None => Word::from(*EmptySubtreeRoots::entry(DEPTH, DEPTH)), + } + } + + fn hash_leaf(leaf: &Word) -> RpoDigest { + // `SimpleSmt` takes the leaf value itself as the hash + leaf.into() + } + + fn key_to_leaf_index(key: &LeafIndex) -> LeafIndex { + *key + } +} + +// TRY APPLY DIFF +// ================================================================================================ +impl TryApplyDiff for SimpleSmt { + type Error = MerkleError; + type DiffType = MerkleTreeDelta; + + fn try_apply(&mut self, diff: MerkleTreeDelta) -> Result<(), MerkleError> { + if diff.depth() != DEPTH { + return Err(MerkleError::InvalidDepth { expected: DEPTH, provided: diff.depth() }); + } + + for slot in diff.cleared_slots() { + self.insert(LeafIndex::::new(*slot)?, Self::EMPTY_VALUE); + } + + for (slot, value) in diff.updated_slots() { + self.insert(LeafIndex::::new(*slot)?, *value); + } + + Ok(()) + } +} diff --git a/src/merkle/simple_smt/tests.rs b/src/merkle/smt/simple/tests.rs similarity index 66% rename from src/merkle/simple_smt/tests.rs rename to src/merkle/smt/simple/tests.rs index 7949646f..87b385d7 100644 --- a/src/merkle/simple_smt/tests.rs +++ b/src/merkle/smt/simple/tests.rs @@ -1,10 +1,15 @@ use super::{ - super::{InnerNodeInfo, MerkleError, MerkleTree, RpoDigest, SimpleSmt, EMPTY_WORD}, - NodeIndex, Rpo256, Vec, + super::{MerkleError, RpoDigest, SimpleSmt}, + NodeIndex, }; use crate::{ - merkle::{digests_to_words, int_to_leaf, int_to_node, EmptySubtreeRoots}, - Word, + hash::rpo::Rpo256, + merkle::{ + digests_to_words, int_to_leaf, int_to_node, smt::SparseMerkleTree, EmptySubtreeRoots, + InnerNodeInfo, LeafIndex, MerkleTree, + }, + utils::collections::Vec, + Word, EMPTY_WORD, }; // TEST DATA @@ -34,26 +39,27 @@ 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(); + 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.insert(LeafIndex::::new(key).unwrap(), new_node); let mt2 = MerkleTree::new(values.clone()).unwrap(); 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.open(&LeafIndex::<3>::new(6).unwrap()).path ); assert_eq!(old_value, EMPTY_WORD); @@ -61,12 +67,12 @@ 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.insert(LeafIndex::::new(key).unwrap(), new_node); let mt3 = MerkleTree::new(values).unwrap(); 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.open(&LeafIndex::<3>::new(2).unwrap()).path ); assert_eq!(old_value, EMPTY_WORD); } @@ -75,11 +81,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 +93,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(); @@ -102,20 +108,16 @@ 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.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] 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()); @@ -145,8 +147,9 @@ fn test_inner_node_iterator() -> Result<(), MerkleError> { #[test] fn update_leaf() { + const DEPTH: u8 = 3; let mut tree = - SimpleSmt::with_leaves(3, 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; @@ -155,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(key as u64, new_node).unwrap(); + 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]); @@ -165,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(key as u64, new_node).unwrap(); + 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]); } @@ -197,29 +200,22 @@ 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); - 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.open(&LeafIndex::<3>::new(key).unwrap()); - assert_eq!(path, *opening); + assert_eq!(path, *opening.path); } } @@ -241,12 +237,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,56 +250,10 @@ 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()); } -#[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::new(1).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 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 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::new(1).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 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 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 @@ -311,17 +261,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 +280,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 +328,15 @@ 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 + const TREE_DEPTH: u8 = 3; 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::::with_leaves(entries).unwrap(); tree.set_subtree(2, subtree).unwrap(); @@ -395,8 +344,8 @@ 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_leaf(&LeafIndex::::new(4).unwrap()), c); + 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 @@ -424,15 +373,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 +409,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..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 @@ -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 2d22b3d0..74986b47 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, LeafIndex, MerkleTree, SimpleSmt, 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,12 +177,12 @@ 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)?; + let smt_path = smt.open(&LeafIndex::::new(0)?).path; assert_eq!( store_path.value, RpoDigest::default(), @@ -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,38 +231,36 @@ 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, - 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); // 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" ); @@ -265,86 +268,86 @@ 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 MATCHES ============================================================== // 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" ); assert_eq!( - smt.get_path(NodeIndex::make(smt.depth(), 0)), - Ok(result.path), + smt.open(&LeafIndex::::new(0).unwrap()).path, + result.path, "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" ); assert_eq!( - smt.get_path(NodeIndex::make(smt.depth(), 1)), - Ok(result.path), + smt.open(&LeafIndex::::new(1).unwrap()).path, + result.path, "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" ); assert_eq!( - smt.get_path(NodeIndex::make(smt.depth(), 2)), - Ok(result.path), + smt.open(&LeafIndex::::new(2).unwrap()).path, + result.path, "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" ); assert_eq!( - smt.get_path(NodeIndex::make(smt.depth(), 3)), - Ok(result.path), + smt.open(&LeafIndex::::new(3).unwrap()).path, + result.path, "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, "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.open(&LeafIndex::::new(4).unwrap()).path, + result.path, "merkle path for index 4 must be the same for the MerkleTree and MerkleStore" ); @@ -552,16 +555,15 @@ fn test_constructors() -> Result<(), MerkleError> { assert_eq!(mtree.get_path(index)?, value_path.path); } - let depth = 32; + const DEPTH: u8 = 32; let smt = - SimpleSmt::with_leaves(depth, 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 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.open(&LeafIndex::::new(key).unwrap()).path, value_path.path); } let d = 2; @@ -880,8 +882,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::with_leaves( - 64, + + const TREE_DEPTH: u8 = 64; + let smtree = SimpleSmt::::with_leaves( KEYS8.into_iter().zip(VALUES8.into_iter().map(|x| x.into()).rev()), ) .unwrap(); @@ -894,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); @@ -917,10 +920,13 @@ 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(&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(); + 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()); }