34 Commits

Author SHA1 Message Date
Bobbin Threadbare
2ed880d976 chore: add TieredSmt to readme 2023-05-26 14:41:22 -07:00
Bobbin Threadbare
daa27f49f2 Merge pull request #140 from 0xPolygonMiden/next
Tracking PR for v0.5 release
2023-05-26 14:36:20 -07:00
Bobbin Threadbare
dcda57f71a chore: update changelog 2023-05-26 14:32:17 -07:00
Bobbin Threadbare
d9e3211418 Merge pull request #153 from 0xPolygonMiden/bobbin-tsmt-iter
Tiered SMT iterators
2023-05-20 22:52:59 -07:00
Bobbin Threadbare
21e7a5c07d feat: implement iterators over contents of TieredSmt 2023-05-20 22:47:07 -07:00
Bobbin Threadbare
02673ff87e Merge pull request #152 from 0xPolygonMiden/bobbin-tsmt
Basic Tiered MST
2023-05-16 15:42:34 -07:00
Bobbin Threadbare
b768eade4d feat: added handling of bottom tier to TieredSmt 2023-05-16 15:38:05 -07:00
Bobbin Threadbare
51ce07cc34 feat: implement basic TieredSmt 2023-05-12 11:33:34 -07:00
Bobbin Threadbare
550738bd94 Merge pull request #151 from 0xPolygonMiden/bobbin-mstore-subset
MerkleStore subset and more
2023-05-11 00:41:01 -07:00
Bobbin Threadbare
629494b601 feat: add leaves() iterator to SimpleSmt 2023-05-11 00:37:16 -07:00
Bobbin Threadbare
13aeda5a27 feat: add subset() to MerkleStore 2023-05-09 18:38:21 -07:00
Bobbin Threadbare
e5aba870a2 Merge pull request #149 from 0xPolygonMiden/bobbin-simple-smt
SimpleSmt updates
2023-05-08 07:35:00 -07:00
Bobbin Threadbare
fcf03478ba refactor: update SimpleSmt interfaces 2023-05-08 00:12:24 -07:00
frisitano
0ddd0db89b Merge pull request #148 from 0xPolygonMiden/frisitano-mmr-accumulator
refactor: Mmr accumulator
2023-05-05 17:56:46 +08:00
frisitano
2100d6c861 refactor(mmr): expose method to join mmr peaks in a vector and pad 2023-05-05 12:03:32 +08:00
Bobbin Threadbare
52409ac039 Merge pull request #146 from 0xPolygonMiden/frisitano-merkle-store-inner-nodes
feat: add .inner_nodes() to [MerkleStore]
2023-05-04 13:49:36 -07:00
frisitano
4555fc918f feat: add .inner_nodes() to [MerkleStore] 2023-05-04 19:15:52 +07:00
Bobbin Threadbare
52db23cd42 chore: update crate version to v0.5.0 2023-04-21 15:48:18 -07:00
Bobbin Threadbare
09025b4014 Merge pull request #129 from 0xPolygonMiden/next
Tracking PR for v0.4 release
2023-04-21 15:38:33 -07:00
Bobbin Threadbare
e983e940b2 chore: update changelog 2023-04-21 14:42:08 -07:00
Bobbin Threadbare
ae4e27b6c7 Merge pull request #139 from 0xPolygonMiden/hacka-support-adding-existing-structures-to-store
store: support adding existing structures
2023-04-21 14:32:52 -07:00
Bobbin Threadbare
130ae3d12a feat: add inner node iterator to MerklePath 2023-04-21 14:27:58 -07:00
Bobbin Threadbare
22c9f382c4 fix: serialization test 2023-04-21 11:39:49 -07:00
Bobbin Threadbare
9be4253f19 feat: remove clone requirement for MerkleStore From constructors 2023-04-21 11:22:36 -07:00
Augusto F. Hack
59595a2e04 feat: added From convertions for the MerkleStore 2023-04-21 14:47:58 +02:00
Augusto F. Hack
eb316f51bc store: remove SimpleSMT/MerkleTree/Mmr add/with methods 2023-04-21 14:47:48 +02:00
Augusto F. Hack
8161477d6a store: support adding existing structures 2023-04-20 13:45:31 +02:00
Augusto Hack
158167356d Merge pull request #138 from 0xPolygonMiden/hacka-merge-support-for-leaves
feat: allow merging of leaves
2023-04-17 12:29:13 +02:00
Augusto F. Hack
3996374a8b feat: allow merging of leaves
Consider the case of a MMR with one entry, and a new entry is being
added. Both of these values are quite unique, they are at the same time
the root and only leaf of their corresponding tree. Currently this
representation is not supported by the [MerkleStore], so the leaves are
not in it. Once the two values are merged, they both become leaves of a
new tree under the new parent, and the existing validation didn't permit
that promotion from happening.

This lifts the validation, and changes the method to clarify that not
only `root` are being merged, by arbitrary nodes of a tree (leafs,
internal, or roots), with arbitrary mixing of each.
2023-04-17 12:21:51 +02:00
Augusto Hack
7fa03c7967 Merge pull request #137 from 0xPolygonMiden/frisitano-reexport-mmr-proof
re-export mmr proof
2023-04-14 14:34:58 +02:00
frisitano
79915cc346 feat: re-export MmrProof 2023-04-14 13:25:19 +01:00
Augusto Hack
45412b5cec Merge pull request #134 from 0xPolygonMiden/add-rustfmt-config
config: add rustfmt config
2023-04-11 17:58:06 +02:00
Augusto F. Hack
bbb1e641a3 config: add rustfmt config 2023-04-11 17:38:39 +02:00
Bobbin Threadbare
e02507d11e chore: update version to v0.4.0 2023-04-08 12:46:53 -07:00
25 changed files with 1783 additions and 905 deletions

View File

@@ -1,3 +1,17 @@
## 0.5.0 (2023-05-26)
* Implemented `TieredSmt` (#152, #153).
* Implemented ability to extract a subset of a `MerkleStore` (#151).
* Cleaned up `SimpleSmt` interface (#149).
* Decoupled hashing and padding of peaks in `Mmr` (#148).
* Added `inner_nodes()` to `MerkleStore` (#146).
## 0.4.0 (2023-04-21)
- Exported `MmrProof` from the crate (#137).
- Allowed merging of leaves in `MerkleStore` (#138).
- [BREAKING] Refactored how existing data structures are added to `MerkleStore` (#139).
## 0.3.0 (2023-04-08) ## 0.3.0 (2023-04-08)
- Added `depth` parameter to SMT constructors in `MerkleStore` (#115). - Added `depth` parameter to SMT constructors in `MerkleStore` (#115).

View File

@@ -1,12 +1,12 @@
[package] [package]
name = "miden-crypto" name = "miden-crypto"
version = "0.3.0" version = "0.5.0"
description = "Miden Cryptographic primitives" description = "Miden Cryptographic primitives"
authors = ["miden contributors"] authors = ["miden contributors"]
readme = "README.md" readme = "README.md"
license = "MIT" license = "MIT"
repository = "https://github.com/0xPolygonMiden/crypto" repository = "https://github.com/0xPolygonMiden/crypto"
documentation = "https://docs.rs/miden-crypto/0.3.0" documentation = "https://docs.rs/miden-crypto/0.5.0"
categories = ["cryptography", "no-std"] categories = ["cryptography", "no-std"]
keywords = ["miden", "crypto", "hash", "merkle"] keywords = ["miden", "crypto", "hash", "merkle"]
edition = "2021" edition = "2021"
@@ -35,6 +35,6 @@ winter_math = { version = "0.6", package = "winter-math", default-features = fal
winter_utils = { version = "0.6", package = "winter-utils", default-features = false } winter_utils = { version = "0.6", package = "winter-utils", default-features = false }
[dev-dependencies] [dev-dependencies]
criterion = { version = "0.4", features = ["html_reports"] } criterion = { version = "0.5", features = ["html_reports"] }
proptest = "1.1.0" proptest = "1.1.0"
rand_utils = { version = "0.6", package = "winter-rand-utils" } rand_utils = { version = "0.6", package = "winter-rand-utils" }

View File

@@ -13,16 +13,14 @@ For performance benchmarks of these hash functions and their comparison to other
[Merkle module](./src/merkle/) provides a set of data structures related to Merkle trees. All these data structures are implemented using the RPO hash function described above. The data structures are: [Merkle module](./src/merkle/) provides a set of data structures related to Merkle trees. All these data structures are implemented using the RPO hash function described above. The data structures are:
* `MerkleTree`: a regular fully-balanced binary Merkle tree. The depth of this tree can be at most 64. * `MerkleTree`: a regular fully-balanced binary Merkle tree. The depth of this tree can be at most 64.
* `SimpleSmt`: a Sparse Merkle Tree, mapping 64-bit keys to 4-element leaf values.
* `MerklePathSet`: a collection of Merkle authentication paths all resolving to the same root. The length of the paths can be at most 64. * `MerklePathSet`: a collection of Merkle authentication paths all resolving to the same root. The length of the paths can be at most 64.
* `MerkleStore`: a collection of Merkle trees of different heights designed to efficiently store trees with common subtrees. * `MerkleStore`: a collection of Merkle trees of different heights designed to efficiently store trees with common subtrees.
* `Mmr`: a Merkle mountain range structure designed to function as an append-only log. * `Mmr`: a Merkle mountain range structure designed to function as an append-only log.
* `SimpleSmt`: a Sparse Merkle Tree (with no compaction), mapping 64-bit keys to 4-element values.
* `TieredSmt`: a Sparse Merkle tree (with compaction), mapping 4-element keys to 4-element values.
The module also contains additional supporting components such as `NodeIndex`, `MerklePath`, and `MerkleError` to assist with tree indexation, opening proofs, and reporting inconsistent arguments/state. The module also contains additional supporting components such as `NodeIndex`, `MerklePath`, and `MerkleError` to assist with tree indexation, opening proofs, and reporting inconsistent arguments/state.
## Extra
[Root module](./src/lib.rs) provides a set of constants, types, aliases, and utils required to use the primitives of this library.
## Crate features ## Crate features
This crate can be compiled with the following features: This crate can be compiled with the following features:

View File

@@ -106,11 +106,5 @@ fn blake3_sequential(c: &mut Criterion) {
}); });
} }
criterion_group!( criterion_group!(hash_group, rpo256_2to1, rpo256_sequential, blake3_2to1, blake3_sequential);
hash_group,
rpo256_2to1,
rpo256_sequential,
blake3_2to1,
blake3_sequential
);
criterion_main!(hash_group); criterion_main!(hash_group);

View File

@@ -18,8 +18,8 @@ fn smt_rpo(c: &mut Criterion) {
(i, word) (i, word)
}) })
.collect(); .collect();
let tree = SimpleSmt::new(depth).unwrap().with_leaves(entries).unwrap(); let tree = SimpleSmt::with_leaves(depth, entries).unwrap();
trees.push(tree); trees.push((tree, count));
} }
} }
@@ -29,10 +29,9 @@ fn smt_rpo(c: &mut Criterion) {
let mut insert = c.benchmark_group(format!("smt update_leaf")); let mut insert = c.benchmark_group(format!("smt update_leaf"));
for tree in trees.iter_mut() { for (tree, count) in trees.iter_mut() {
let depth = tree.depth(); let depth = tree.depth();
let count = tree.leaves_count() as u64; let key = *count >> 2;
let key = count >> 2;
insert.bench_with_input( insert.bench_with_input(
format!("simple smt(depth:{depth},count:{count})"), format!("simple smt(depth:{depth},count:{count})"),
&(key, leaf), &(key, leaf),
@@ -48,10 +47,9 @@ fn smt_rpo(c: &mut Criterion) {
let mut path = c.benchmark_group(format!("smt get_leaf_path")); let mut path = c.benchmark_group(format!("smt get_leaf_path"));
for tree in trees.iter_mut() { for (tree, count) in trees.iter_mut() {
let depth = tree.depth(); let depth = tree.depth();
let count = tree.leaves_count() as u64; let key = *count >> 2;
let key = count >> 2;
path.bench_with_input( path.bench_with_input(
format!("simple smt(depth:{depth},count:{count})"), format!("simple smt(depth:{depth},count:{count})"),
&key, &key,
@@ -75,10 +73,5 @@ criterion_main!(smt_group);
fn generate_word(seed: &mut [u8; 32]) -> Word { fn generate_word(seed: &mut [u8; 32]) -> Word {
swap(seed, &mut prng_array(*seed)); swap(seed, &mut prng_array(*seed));
let nums: [u64; 4] = prng_array(*seed); let nums: [u64; 4] = prng_array(*seed);
[ [Felt::new(nums[0]), Felt::new(nums[1]), Felt::new(nums[2]), Felt::new(nums[3])]
Felt::new(nums[0]),
Felt::new(nums[1]),
Felt::new(nums[2]),
Felt::new(nums[3]),
]
} }

View File

@@ -34,7 +34,7 @@ fn get_empty_leaf_simplesmt(c: &mut Criterion) {
// both SMT and the store are pre-populated with empty hashes, accessing these values is what is // 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 // being benchmarked here, so no values are inserted into the backends
let smt = SimpleSmt::new(depth).unwrap(); let smt = SimpleSmt::new(depth).unwrap();
let store = MerkleStore::new(); let store = MerkleStore::from(&smt);
let root = smt.root(); let root = smt.root();
group.bench_function(BenchmarkId::new("SimpleSmt", depth), |b| { group.bench_function(BenchmarkId::new("SimpleSmt", depth), |b| {
@@ -66,7 +66,7 @@ fn get_leaf_merkletree(c: &mut Criterion) {
let mtree_leaves: Vec<Word> = leaves.iter().map(|v| v.into()).collect(); let mtree_leaves: Vec<Word> = leaves.iter().map(|v| v.into()).collect();
let mtree = MerkleTree::new(mtree_leaves.clone()).unwrap(); let mtree = MerkleTree::new(mtree_leaves.clone()).unwrap();
let store = MerkleStore::new().with_merkle_tree(mtree_leaves).unwrap(); let store = MerkleStore::from(&mtree);
let depth = mtree.depth(); let depth = mtree.depth();
let root = mtree.root(); let root = mtree.root();
let size_u64 = size as u64; let size_u64 = size as u64;
@@ -104,13 +104,8 @@ fn get_leaf_simplesmt(c: &mut Criterion) {
.enumerate() .enumerate()
.map(|(c, v)| (c.try_into().unwrap(), v.into())) .map(|(c, v)| (c.try_into().unwrap(), v.into()))
.collect::<Vec<(u64, Word)>>(); .collect::<Vec<(u64, Word)>>();
let smt = SimpleSmt::new(SimpleSmt::MAX_DEPTH) let smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, smt_leaves.clone()).unwrap();
.unwrap() let store = MerkleStore::from(&smt);
.with_leaves(smt_leaves.clone())
.unwrap();
let store = MerkleStore::new()
.with_sparse_merkle_tree(SimpleSmt::MAX_DEPTH, smt_leaves)
.unwrap();
let depth = smt.depth(); let depth = smt.depth();
let root = smt.root(); let root = smt.root();
let size_u64 = size as u64; let size_u64 = size as u64;
@@ -143,7 +138,7 @@ fn get_node_of_empty_simplesmt(c: &mut Criterion) {
// of these values is what is being benchmarked here, so no values are inserted into the // of these values is what is being benchmarked here, so no values are inserted into the
// backends. // backends.
let smt = SimpleSmt::new(depth).unwrap(); let smt = SimpleSmt::new(depth).unwrap();
let store = MerkleStore::new(); let store = MerkleStore::from(&smt);
let root = smt.root(); let root = smt.root();
let half_depth = depth / 2; let half_depth = depth / 2;
let half_size = 2_u64.pow(half_depth as u32); let half_size = 2_u64.pow(half_depth as u32);
@@ -178,7 +173,7 @@ fn get_node_merkletree(c: &mut Criterion) {
let mtree_leaves: Vec<Word> = leaves.iter().map(|v| v.into()).collect(); let mtree_leaves: Vec<Word> = leaves.iter().map(|v| v.into()).collect();
let mtree = MerkleTree::new(mtree_leaves.clone()).unwrap(); let mtree = MerkleTree::new(mtree_leaves.clone()).unwrap();
let store = MerkleStore::new().with_merkle_tree(mtree_leaves).unwrap(); let store = MerkleStore::from(&mtree);
let root = mtree.root(); let root = mtree.root();
let half_depth = mtree.depth() / 2; let half_depth = mtree.depth() / 2;
let half_size = 2_u64.pow(half_depth as u32); let half_size = 2_u64.pow(half_depth as u32);
@@ -217,13 +212,8 @@ fn get_node_simplesmt(c: &mut Criterion) {
.enumerate() .enumerate()
.map(|(c, v)| (c.try_into().unwrap(), v.into())) .map(|(c, v)| (c.try_into().unwrap(), v.into()))
.collect::<Vec<(u64, Word)>>(); .collect::<Vec<(u64, Word)>>();
let smt = SimpleSmt::new(SimpleSmt::MAX_DEPTH) let smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, smt_leaves.clone()).unwrap();
.unwrap() let store = MerkleStore::from(&smt);
.with_leaves(smt_leaves.clone())
.unwrap();
let store = MerkleStore::new()
.with_sparse_merkle_tree(SimpleSmt::MAX_DEPTH, smt_leaves)
.unwrap();
let root = smt.root(); let root = smt.root();
let half_depth = smt.depth() / 2; let half_depth = smt.depth() / 2;
let half_size = 2_u64.pow(half_depth as u32); let half_size = 2_u64.pow(half_depth as u32);
@@ -258,7 +248,7 @@ fn get_leaf_path_merkletree(c: &mut Criterion) {
let mtree_leaves: Vec<Word> = leaves.iter().map(|v| v.into()).collect(); let mtree_leaves: Vec<Word> = leaves.iter().map(|v| v.into()).collect();
let mtree = MerkleTree::new(mtree_leaves.clone()).unwrap(); let mtree = MerkleTree::new(mtree_leaves.clone()).unwrap();
let store = MerkleStore::new().with_merkle_tree(mtree_leaves).unwrap(); let store = MerkleStore::from(&mtree);
let depth = mtree.depth(); let depth = mtree.depth();
let root = mtree.root(); let root = mtree.root();
let size_u64 = size as u64; let size_u64 = size as u64;
@@ -296,13 +286,8 @@ fn get_leaf_path_simplesmt(c: &mut Criterion) {
.enumerate() .enumerate()
.map(|(c, v)| (c.try_into().unwrap(), v.into())) .map(|(c, v)| (c.try_into().unwrap(), v.into()))
.collect::<Vec<(u64, Word)>>(); .collect::<Vec<(u64, Word)>>();
let smt = SimpleSmt::new(SimpleSmt::MAX_DEPTH) let smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, smt_leaves.clone()).unwrap();
.unwrap() let store = MerkleStore::from(&smt);
.with_leaves(smt_leaves.clone())
.unwrap();
let store = MerkleStore::new()
.with_sparse_merkle_tree(SimpleSmt::MAX_DEPTH, smt_leaves)
.unwrap();
let depth = smt.depth(); let depth = smt.depth();
let root = smt.root(); let root = smt.root();
let size_u64 = size as u64; let size_u64 = size as u64;
@@ -347,16 +332,16 @@ fn new(c: &mut Criterion) {
// This could be done with `bench_with_input`, however to remove variables while comparing // This could be done with `bench_with_input`, however to remove variables while comparing
// with MerkleTree it is using `iter_batched` // with MerkleTree it is using `iter_batched`
group.bench_function( group.bench_function(BenchmarkId::new("MerkleStore::extend::MerkleTree", size), |b| {
BenchmarkId::new("MerkleStore::with_merkle_tree", size), b.iter_batched(
|b| { || leaves.iter().map(|v| v.into()).collect::<Vec<Word>>(),
b.iter_batched( |l| {
|| leaves.iter().map(|v| v.into()).collect::<Vec<Word>>(), let mtree = MerkleTree::new(l).unwrap();
|l| black_box(MerkleStore::new().with_merkle_tree(l)), black_box(MerkleStore::from(&mtree));
BatchSize::SmallInput, },
) BatchSize::SmallInput,
}, )
); });
group.bench_function(BenchmarkId::new("SimpleSmt::new", size), |b| { group.bench_function(BenchmarkId::new("SimpleSmt::new", size), |b| {
b.iter_batched( b.iter_batched(
@@ -367,31 +352,27 @@ fn new(c: &mut Criterion) {
.map(|(c, v)| (c.try_into().unwrap(), v.into())) .map(|(c, v)| (c.try_into().unwrap(), v.into()))
.collect::<Vec<(u64, Word)>>() .collect::<Vec<(u64, Word)>>()
}, },
|l| black_box(SimpleSmt::new(SimpleSmt::MAX_DEPTH).unwrap().with_leaves(l)), |l| black_box(SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, l)),
BatchSize::SmallInput, BatchSize::SmallInput,
) )
}); });
group.bench_function( group.bench_function(BenchmarkId::new("MerkleStore::extend::SimpleSmt", size), |b| {
BenchmarkId::new("MerkleStore::with_sparse_merkle_tree", size), b.iter_batched(
|b| { || {
b.iter_batched( leaves
|| { .iter()
leaves .enumerate()
.iter() .map(|(c, v)| (c.try_into().unwrap(), v.into()))
.enumerate() .collect::<Vec<(u64, Word)>>()
.map(|(c, v)| (c.try_into().unwrap(), v.into())) },
.collect::<Vec<(u64, Word)>>() |l| {
}, let smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, l).unwrap();
|l| { black_box(MerkleStore::from(&smt));
black_box( },
MerkleStore::new().with_sparse_merkle_tree(SimpleSmt::MAX_DEPTH, l), BatchSize::SmallInput,
) )
}, });
BatchSize::SmallInput,
)
},
);
} }
} }
@@ -407,7 +388,7 @@ fn update_leaf_merkletree(c: &mut Criterion) {
let mtree_leaves: Vec<Word> = leaves.iter().map(|v| v.into()).collect(); let mtree_leaves: Vec<Word> = leaves.iter().map(|v| v.into()).collect();
let mut mtree = MerkleTree::new(mtree_leaves.clone()).unwrap(); let mut mtree = MerkleTree::new(mtree_leaves.clone()).unwrap();
let mut store = MerkleStore::new().with_merkle_tree(mtree_leaves).unwrap(); let mut store = MerkleStore::from(&mtree);
let depth = mtree.depth(); let depth = mtree.depth();
let root = mtree.root(); let root = mtree.root();
let size_u64 = size as u64; let size_u64 = size as u64;
@@ -452,13 +433,8 @@ fn update_leaf_simplesmt(c: &mut Criterion) {
.enumerate() .enumerate()
.map(|(c, v)| (c.try_into().unwrap(), v.into())) .map(|(c, v)| (c.try_into().unwrap(), v.into()))
.collect::<Vec<(u64, Word)>>(); .collect::<Vec<(u64, Word)>>();
let mut smt = SimpleSmt::new(SimpleSmt::MAX_DEPTH) let mut smt = SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, smt_leaves.clone()).unwrap();
.unwrap() let mut store = MerkleStore::from(&smt);
.with_leaves(smt_leaves.clone())
.unwrap();
let mut store = MerkleStore::new()
.with_sparse_merkle_tree(SimpleSmt::MAX_DEPTH, smt_leaves)
.unwrap();
let depth = smt.depth(); let depth = smt.depth();
let root = smt.root(); let root = smt.root();
let size_u64 = size as u64; let size_u64 = size as u64;

20
rustfmt.toml Normal file
View File

@@ -0,0 +1,20 @@
edition = "2021"
array_width = 80
attr_fn_like_width = 80
chain_width = 80
#condense_wildcard_suffixes = true
#enum_discrim_align_threshold = 40
fn_call_width = 80
#fn_single_line = true
#format_code_in_doc_comments = true
#format_macro_matchers = true
#format_strings = true
#group_imports = "StdExternalCrate"
#hex_literal_case = "Lower"
#imports_granularity = "Crate"
newline_style = "Unix"
#normalize_doc_attributes = true
#reorder_impl_items = true
single_line_if_else_max_width = 60
use_field_init_shorthand = true
use_try_shorthand = true

View File

@@ -270,10 +270,7 @@ impl Blake3_160 {
/// Zero-copy ref shrink to array. /// Zero-copy ref shrink to array.
fn shrink_bytes<const M: usize, const N: usize>(bytes: &[u8; M]) -> &[u8; N] { fn shrink_bytes<const M: usize, const N: usize>(bytes: &[u8; M]) -> &[u8; N] {
// compile-time assertion // compile-time assertion
assert!( assert!(M >= N, "N should fit in M so it can be safely transmuted into a smaller slice!");
M >= N,
"N should fit in M so it can be safely transmuted into a smaller slice!"
);
// safety: bytes len is asserted // safety: bytes len is asserted
unsafe { transmute(bytes) } unsafe { transmute(bytes) }
} }

View File

@@ -2,7 +2,7 @@ use super::{Digest, Felt, StarkField, DIGEST_SIZE, ZERO};
use crate::utils::{ use crate::utils::{
string::String, ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, string::String, ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
}; };
use core::{cmp::Ordering, ops::Deref}; use core::{cmp::Ordering, fmt::Display, ops::Deref};
// DIGEST TRAIT IMPLEMENTATIONS // DIGEST TRAIT IMPLEMENTATIONS
// ================================================================================================ // ================================================================================================
@@ -85,6 +85,28 @@ impl From<RpoDigest> for [Felt; DIGEST_SIZE] {
} }
} }
impl From<&RpoDigest> for [u64; DIGEST_SIZE] {
fn from(value: &RpoDigest) -> Self {
[
value.0[0].as_int(),
value.0[1].as_int(),
value.0[2].as_int(),
value.0[3].as_int(),
]
}
}
impl From<RpoDigest> for [u64; DIGEST_SIZE] {
fn from(value: RpoDigest) -> Self {
[
value.0[0].as_int(),
value.0[1].as_int(),
value.0[2].as_int(),
value.0[3].as_int(),
]
}
}
impl From<&RpoDigest> for [u8; 32] { impl From<&RpoDigest> for [u8; 32] {
fn from(value: &RpoDigest) -> Self { fn from(value: &RpoDigest) -> Self {
value.as_bytes() value.as_bytes()
@@ -118,14 +140,13 @@ impl Ord for RpoDigest {
// finally, we use `Felt::inner` instead of `Felt::as_int` so we avoid performing a // finally, we use `Felt::inner` instead of `Felt::as_int` so we avoid performing a
// montgomery reduction for every limb. that is safe because every inner element of the // montgomery reduction for every limb. that is safe because every inner element of the
// digest is guaranteed to be in its canonical form (that is, `x in [0,p)`). // digest is guaranteed to be in its canonical form (that is, `x in [0,p)`).
self.0 self.0.iter().map(Felt::inner).zip(other.0.iter().map(Felt::inner)).fold(
.iter() Ordering::Equal,
.map(Felt::inner) |ord, (a, b)| match ord {
.zip(other.0.iter().map(Felt::inner))
.fold(Ordering::Equal, |ord, (a, b)| match ord {
Ordering::Equal => a.cmp(&b), Ordering::Equal => a.cmp(&b),
_ => ord, _ => ord,
}) },
)
} }
} }
@@ -135,6 +156,15 @@ impl PartialOrd for RpoDigest {
} }
} }
impl Display for RpoDigest {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for byte in self.as_bytes() {
write!(f, "{byte:02x}")?;
}
Ok(())
}
}
// TESTS // TESTS
// ================================================================================================ // ================================================================================================

View File

@@ -1,6 +1,12 @@
use super::{Felt, RpoDigest, WORD_SIZE, ZERO}; use super::{Felt, RpoDigest, Word, WORD_SIZE, ZERO};
use core::slice; use core::slice;
// CONSTANTS
// ================================================================================================
/// A word consisting of 4 ZERO elements.
pub const EMPTY_WORD: Word = [ZERO; WORD_SIZE];
// EMPTY NODES SUBTREES // EMPTY NODES SUBTREES
// ================================================================================================ // ================================================================================================
@@ -1570,7 +1576,7 @@ fn all_depths_opens_to_zero() {
assert_eq!(depth as usize + 1, subtree.len()); assert_eq!(depth as usize + 1, subtree.len());
// assert the opening is zero // assert the opening is zero
let initial = RpoDigest::new([ZERO; WORD_SIZE]); let initial = RpoDigest::new(EMPTY_WORD);
assert_eq!(initial, subtree.remove(0)); assert_eq!(initial, subtree.remove(0));
// compute every node of the path manually and compare with the output // compute every node of the path manually and compare with the output

View File

@@ -1,4 +1,5 @@
use super::{Felt, MerkleError, RpoDigest, StarkField}; use super::{Felt, MerkleError, RpoDigest, StarkField};
use core::fmt::Display;
// NODE INDEX // NODE INDEX
// ================================================================================================ // ================================================================================================
@@ -40,6 +41,12 @@ impl NodeIndex {
} }
} }
/// Creates a new node index without checking its validity.
pub const fn new_unchecked(depth: u8, value: u64) -> Self {
debug_assert!((64 - value.leading_zeros()) <= depth as u32);
Self { depth, value }
}
/// Creates a new node index for testing purposes. /// Creates a new node index for testing purposes.
/// ///
/// # Panics /// # Panics
@@ -67,12 +74,26 @@ impl NodeIndex {
Self { depth: 0, value: 0 } Self { depth: 0, value: 0 }
} }
/// Computes the value of the sibling of the current node. /// Computes sibling index of the current node.
pub fn sibling(mut self) -> Self { pub const fn sibling(mut self) -> Self {
self.value ^= 1; self.value ^= 1;
self self
} }
/// Returns left child index of the current node.
pub const fn left_child(mut self) -> Self {
self.depth += 1;
self.value <<= 1;
self
}
/// Returns right child index of the current node.
pub const fn right_child(mut self) -> Self {
self.depth += 1;
self.value = (self.value << 1) + 1;
self
}
// PROVIDERS // PROVIDERS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
@@ -117,11 +138,26 @@ impl NodeIndex {
// STATE MUTATORS // STATE MUTATORS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
/// Traverse one level towards the root, decrementing the depth by `1`. /// Traverses one level towards the root, decrementing the depth by `1`.
pub fn move_up(&mut self) -> &mut Self { pub fn move_up(&mut self) {
self.depth = self.depth.saturating_sub(1); self.depth = self.depth.saturating_sub(1);
self.value >>= 1; self.value >>= 1;
self }
/// Traverses towards the root until the specified depth is reached.
///
/// Assumes that the specified depth is smaller than the current depth.
pub fn move_up_to(&mut self, depth: u8) {
debug_assert!(depth < self.depth);
let delta = self.depth.saturating_sub(depth);
self.depth = self.depth.saturating_sub(delta);
self.value >>= delta as u32;
}
}
impl Display for NodeIndex {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "depth={}, value={}", self.depth, self.value)
} }
} }
@@ -132,10 +168,7 @@ mod tests {
#[test] #[test]
fn test_node_index_value_too_high() { fn test_node_index_value_too_high() {
assert_eq!( assert_eq!(NodeIndex::new(0, 0).unwrap(), NodeIndex { depth: 0, value: 0 });
NodeIndex::new(0, 0).unwrap(),
NodeIndex { depth: 0, value: 0 }
);
match NodeIndex::new(0, 1) { match NodeIndex::new(0, 1) {
Err(MerkleError::InvalidIndex { depth, value }) => { Err(MerkleError::InvalidIndex { depth, value }) => {
assert_eq!(depth, 0); assert_eq!(depth, 0);

View File

@@ -109,14 +109,33 @@ impl MerkleTree {
index.move_up(); index.move_up();
} }
debug_assert!( debug_assert!(index.is_root(), "the path walk must go all the way to the root");
index.is_root(),
"the path walk must go all the way to the root"
);
Ok(path.into()) Ok(path.into())
} }
// ITERATORS
// --------------------------------------------------------------------------------------------
/// Returns an iterator over the leaves of this [MerkleTree].
pub fn leaves(&self) -> impl Iterator<Item = (u64, &Word)> {
let leaves_start = self.nodes.len() / 2;
self.nodes.iter().skip(leaves_start).enumerate().map(|(i, v)| (i as u64, v))
}
/// Returns n iterator over every inner node of this [MerkleTree].
///
/// The iterator order is unspecified.
pub fn inner_nodes(&self) -> InnerNodeIterator {
InnerNodeIterator {
nodes: &self.nodes,
index: 1, // index 0 is just padding, start at 1
}
}
// STATE MUTATORS
// --------------------------------------------------------------------------------------------
/// Replaces the leaf at the specified index with the provided value. /// Replaces the leaf at the specified index with the provided value.
/// ///
/// # Errors /// # Errors
@@ -152,14 +171,6 @@ impl MerkleTree {
Ok(()) Ok(())
} }
/// An iterator over every inner node in the tree. The iterator order is unspecified.
pub fn inner_nodes(&self) -> MerkleTreeNodes<'_> {
MerkleTreeNodes {
nodes: &self.nodes,
index: 1, // index 0 is just padding, start at 1
}
}
} }
// ITERATORS // ITERATORS
@@ -168,12 +179,12 @@ impl MerkleTree {
/// An iterator over every inner node of the [MerkleTree]. /// An iterator over every inner node of the [MerkleTree].
/// ///
/// Use this to extract the data of the tree, there is no guarantee on the order of the elements. /// Use this to extract the data of the tree, there is no guarantee on the order of the elements.
pub struct MerkleTreeNodes<'a> { pub struct InnerNodeIterator<'a> {
nodes: &'a Vec<Word>, nodes: &'a Vec<Word>,
index: usize, index: usize,
} }
impl<'a> Iterator for MerkleTreeNodes<'a> { impl<'a> Iterator for InnerNodeIterator<'a> {
type Item = InnerNodeInfo; type Item = InnerNodeInfo;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@@ -195,6 +206,9 @@ impl<'a> Iterator for MerkleTreeNodes<'a> {
} }
} }
// UTILITY FUNCTIONS
// ================================================================================================
/// Utility to visualize a [MerkleTree] in text. /// Utility to visualize a [MerkleTree] in text.
pub fn tree_to_text(tree: &MerkleTree) -> Result<String, fmt::Error> { pub fn tree_to_text(tree: &MerkleTree) -> Result<String, fmt::Error> {
let indent = " "; let indent = " ";
@@ -248,12 +262,7 @@ mod tests {
use core::mem::size_of; use core::mem::size_of;
use proptest::prelude::*; use proptest::prelude::*;
const LEAVES4: [Word; 4] = [ const LEAVES4: [Word; 4] = [int_to_node(1), int_to_node(2), int_to_node(3), int_to_node(4)];
int_to_node(1),
int_to_node(2),
int_to_node(3),
int_to_node(4),
];
const LEAVES8: [Word; 8] = [ const LEAVES8: [Word; 8] = [
int_to_node(1), int_to_node(1),
@@ -309,22 +318,10 @@ mod tests {
let (_, node2, node3) = compute_internal_nodes(); let (_, node2, node3) = compute_internal_nodes();
// check depth 2 // check depth 2
assert_eq!( assert_eq!(vec![LEAVES4[1], node3], *tree.get_path(NodeIndex::make(2, 0)).unwrap());
vec![LEAVES4[1], node3], assert_eq!(vec![LEAVES4[0], node3], *tree.get_path(NodeIndex::make(2, 1)).unwrap());
*tree.get_path(NodeIndex::make(2, 0)).unwrap() assert_eq!(vec![LEAVES4[3], node2], *tree.get_path(NodeIndex::make(2, 2)).unwrap());
); assert_eq!(vec![LEAVES4[2], node2], *tree.get_path(NodeIndex::make(2, 3)).unwrap());
assert_eq!(
vec![LEAVES4[0], node3],
*tree.get_path(NodeIndex::make(2, 1)).unwrap()
);
assert_eq!(
vec![LEAVES4[3], node2],
*tree.get_path(NodeIndex::make(2, 2)).unwrap()
);
assert_eq!(
vec![LEAVES4[2], node2],
*tree.get_path(NodeIndex::make(2, 3)).unwrap()
);
// check depth 1 // check depth 1
assert_eq!(vec![node3], *tree.get_path(NodeIndex::make(1, 0)).unwrap()); assert_eq!(vec![node3], *tree.get_path(NodeIndex::make(1, 0)).unwrap());

View File

@@ -1,8 +1,4 @@
use super::{ use super::{super::Vec, super::ZERO, Felt, MmrProof, Rpo256, Word};
super::Vec,
super::{WORD_SIZE, ZERO},
MmrProof, Rpo256, Word,
};
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct MmrPeaks { pub struct MmrPeaks {
@@ -35,27 +31,49 @@ pub struct MmrPeaks {
impl MmrPeaks { impl MmrPeaks {
/// Hashes the peaks. /// Hashes the peaks.
/// ///
/// The hashing is optimized to work with the Miden VM, the procedure will: /// The procedure will:
/// /// - Flatten and pad the peaks to a vector of Felts.
/// - Pad the peaks with ZERO to an even number of words, this removes the need to handle RPO padding. /// - Hash the vector of Felts.
/// - Pad the peaks to a minimum length of 16 words, which reduces the constant cost of
/// hashing.
pub fn hash_peaks(&self) -> Word { pub fn hash_peaks(&self) -> Word {
let mut copy = self.peaks.clone(); Rpo256::hash_elements(&self.flatten_and_pad_peaks()).into()
if copy.len() < 16 {
copy.resize(16, [ZERO; WORD_SIZE])
} else if copy.len() % 2 == 1 {
copy.push([ZERO; WORD_SIZE])
}
Rpo256::hash_elements(&copy.as_slice().concat()).into()
} }
pub fn verify(&self, value: Word, opening: MmrProof) -> bool { pub fn verify(&self, value: Word, opening: MmrProof) -> bool {
let root = &self.peaks[opening.peak_index()]; let root = &self.peaks[opening.peak_index()];
opening opening.merkle_path.verify(opening.relative_pos() as u64, value, root)
.merkle_path }
.verify(opening.relative_pos() as u64, value, root)
/// Flattens and pads the peaks to make hashing inside of the Miden VM easier.
///
/// The procedure will:
/// - Flatten the vector of Words into a vector of Felts.
/// - Pad the peaks with ZERO to an even number of words, this removes the need to handle RPO
/// padding.
/// - Pad the peaks to a minimum length of 16 words, which reduces the constant cost of
/// hashing.
pub fn flatten_and_pad_peaks(&self) -> Vec<Felt> {
let num_peaks = self.peaks.len();
// To achieve the padding rules above we calculate the length of the final vector.
// This is calculated as the number of field elements. Each peak is 4 field elements.
// The length is calculated as follows:
// - If there are less than 16 peaks, the data is padded to 16 peaks and as such requires
// 64 field elements.
// - If there are more than 16 peaks and the number of peaks is odd, the data is padded to
// an even number of peaks and as such requires `(num_peaks + 1) * 4` field elements.
// - If there are more than 16 peaks and the number of peaks is even, the data is not padded
// and as such requires `num_peaks * 4` field elements.
let len = if num_peaks < 16 {
64
} else if num_peaks % 2 == 1 {
(num_peaks + 1) * 4
} else {
num_peaks * 4
};
let mut elements = Vec::with_capacity(len);
elements.extend_from_slice(&self.peaks.as_slice().concat());
elements.resize(len, ZERO);
elements
} }
} }

View File

@@ -280,10 +280,7 @@ impl<'a> Iterator for MmrNodes<'a> {
type Item = InnerNodeInfo; type Item = InnerNodeInfo;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
debug_assert!( debug_assert!(self.last_right.count_ones() <= 1, "last_right tracks zero or one element");
self.last_right.count_ones() <= 1,
"last_right tracks zero or one element"
);
// only parent nodes are emitted, remove the single node tree from the forest // only parent nodes are emitted, remove the single node tree from the forest
let target = self.mmr.forest & (usize::MAX << 1); let target = self.mmr.forest & (usize::MAX << 1);

View File

@@ -6,7 +6,7 @@ mod proof;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use super::{Rpo256, Word}; use super::{Felt, Rpo256, Word};
// REEXPORTS // REEXPORTS
// ================================================================================================ // ================================================================================================

View File

@@ -118,9 +118,7 @@ fn test_mmr_simple() {
postorder.push(LEAVES[2]); postorder.push(LEAVES[2]);
postorder.push(LEAVES[3]); postorder.push(LEAVES[3]);
postorder.push(*Rpo256::hash_elements(&[LEAVES[2], LEAVES[3]].concat())); postorder.push(*Rpo256::hash_elements(&[LEAVES[2], LEAVES[3]].concat()));
postorder.push(*Rpo256::hash_elements( postorder.push(*Rpo256::hash_elements(&[postorder[2], postorder[5]].concat()));
&[postorder[2], postorder[5]].concat(),
));
postorder.push(LEAVES[4]); postorder.push(LEAVES[4]);
postorder.push(LEAVES[5]); postorder.push(LEAVES[5]);
postorder.push(*Rpo256::hash_elements(&[LEAVES[4], LEAVES[5]].concat())); postorder.push(*Rpo256::hash_elements(&[LEAVES[4], LEAVES[5]].concat()));
@@ -201,10 +199,7 @@ fn test_mmr_open() {
let h23: Word = Rpo256::hash_elements(&LEAVES[2..4].concat()).into(); let h23: Word = Rpo256::hash_elements(&LEAVES[2..4].concat()).into();
// node at pos 7 is the root // node at pos 7 is the root
assert!( assert!(mmr.open(7).is_err(), "Element 7 is not in the tree, result should be None");
mmr.open(7).is_err(),
"Element 7 is not in the tree, result should be None"
);
// node at pos 6 is the root // node at pos 6 is the root
let empty: MerklePath = MerklePath::new(vec![]); let empty: MerklePath = MerklePath::new(vec![]);
@@ -297,41 +292,13 @@ fn test_mmr_open() {
#[test] #[test]
fn test_mmr_get() { fn test_mmr_get() {
let mmr: Mmr = LEAVES.into(); let mmr: Mmr = LEAVES.into();
assert_eq!( assert_eq!(mmr.get(0).unwrap(), LEAVES[0], "value at pos 0 must correspond");
mmr.get(0).unwrap(), assert_eq!(mmr.get(1).unwrap(), LEAVES[1], "value at pos 1 must correspond");
LEAVES[0], assert_eq!(mmr.get(2).unwrap(), LEAVES[2], "value at pos 2 must correspond");
"value at pos 0 must correspond" assert_eq!(mmr.get(3).unwrap(), LEAVES[3], "value at pos 3 must correspond");
); assert_eq!(mmr.get(4).unwrap(), LEAVES[4], "value at pos 4 must correspond");
assert_eq!( assert_eq!(mmr.get(5).unwrap(), LEAVES[5], "value at pos 5 must correspond");
mmr.get(1).unwrap(), assert_eq!(mmr.get(6).unwrap(), LEAVES[6], "value at pos 6 must correspond");
LEAVES[1],
"value at pos 1 must correspond"
);
assert_eq!(
mmr.get(2).unwrap(),
LEAVES[2],
"value at pos 2 must correspond"
);
assert_eq!(
mmr.get(3).unwrap(),
LEAVES[3],
"value at pos 3 must correspond"
);
assert_eq!(
mmr.get(4).unwrap(),
LEAVES[4],
"value at pos 4 must correspond"
);
assert_eq!(
mmr.get(5).unwrap(),
LEAVES[5],
"value at pos 5 must correspond"
);
assert_eq!(
mmr.get(6).unwrap(),
LEAVES[6],
"value at pos 6 must correspond"
);
assert!(mmr.get(7).is_err()); assert!(mmr.get(7).is_err());
} }
@@ -341,11 +308,7 @@ fn test_mmr_invariants() {
for v in 1..=1028 { for v in 1..=1028 {
mmr.add(int_to_node(v)); mmr.add(int_to_node(v));
let accumulator = mmr.accumulator(); let accumulator = mmr.accumulator();
assert_eq!( assert_eq!(v as usize, mmr.forest(), "MMR leaf count must increase by one on every add");
v as usize,
mmr.forest(),
"MMR leaf count must increase by one on every add"
);
assert_eq!( assert_eq!(
v as usize, accumulator.num_leaves, v as usize, accumulator.num_leaves,
"MMR and its accumulator must match leaves count" "MMR and its accumulator must match leaves count"
@@ -374,41 +337,21 @@ fn test_bit_position_iterator() {
assert_eq!(TrueBitPositionIterator::new(0).count(), 0); assert_eq!(TrueBitPositionIterator::new(0).count(), 0);
assert_eq!(TrueBitPositionIterator::new(0).rev().count(), 0); assert_eq!(TrueBitPositionIterator::new(0).rev().count(), 0);
assert_eq!( assert_eq!(TrueBitPositionIterator::new(1).collect::<Vec<u32>>(), vec![0]);
TrueBitPositionIterator::new(1).collect::<Vec<u32>>(), assert_eq!(TrueBitPositionIterator::new(1).rev().collect::<Vec<u32>>(), vec![0],);
vec![0]
);
assert_eq!(
TrueBitPositionIterator::new(1).rev().collect::<Vec<u32>>(),
vec![0],
);
assert_eq!( assert_eq!(TrueBitPositionIterator::new(2).collect::<Vec<u32>>(), vec![1]);
TrueBitPositionIterator::new(2).collect::<Vec<u32>>(), assert_eq!(TrueBitPositionIterator::new(2).rev().collect::<Vec<u32>>(), vec![1],);
vec![1]
);
assert_eq!(
TrueBitPositionIterator::new(2).rev().collect::<Vec<u32>>(),
vec![1],
);
assert_eq!( assert_eq!(TrueBitPositionIterator::new(3).collect::<Vec<u32>>(), vec![0, 1],);
TrueBitPositionIterator::new(3).collect::<Vec<u32>>(), assert_eq!(TrueBitPositionIterator::new(3).rev().collect::<Vec<u32>>(), vec![1, 0],);
vec![0, 1],
);
assert_eq!(
TrueBitPositionIterator::new(3).rev().collect::<Vec<u32>>(),
vec![1, 0],
);
assert_eq!( assert_eq!(
TrueBitPositionIterator::new(0b11010101).collect::<Vec<u32>>(), TrueBitPositionIterator::new(0b11010101).collect::<Vec<u32>>(),
vec![0, 2, 4, 6, 7], vec![0, 2, 4, 6, 7],
); );
assert_eq!( assert_eq!(
TrueBitPositionIterator::new(0b11010101) TrueBitPositionIterator::new(0b11010101).rev().collect::<Vec<u32>>(),
.rev()
.collect::<Vec<u32>>(),
vec![7, 6, 4, 2, 0], vec![7, 6, 4, 2, 0],
); );
} }
@@ -463,10 +406,7 @@ fn test_mmr_hash_peaks() {
// minimum length is 16 // minimum length is 16
let mut expected_peaks = [first_peak, second_peak, third_peak].to_vec(); let mut expected_peaks = [first_peak, second_peak, third_peak].to_vec();
expected_peaks.resize(16, [ZERO; WORD_SIZE]); expected_peaks.resize(16, [ZERO; WORD_SIZE]);
assert_eq!( assert_eq!(peaks.hash_peaks(), *Rpo256::hash_elements(&expected_peaks.as_slice().concat()));
peaks.hash_peaks(),
*Rpo256::hash_elements(&expected_peaks.as_slice().concat())
);
} }
#[test] #[test]

View File

@@ -1,6 +1,6 @@
use super::{ use super::{
hash::rpo::{Rpo256, RpoDigest}, hash::rpo::{Rpo256, RpoDigest},
utils::collections::{vec, BTreeMap, Vec}, utils::collections::{vec, BTreeMap, BTreeSet, Vec},
Felt, StarkField, Word, WORD_SIZE, ZERO, Felt, StarkField, Word, WORD_SIZE, ZERO,
}; };
use core::fmt; use core::fmt;
@@ -10,6 +10,7 @@ use core::fmt;
mod empty_roots; mod empty_roots;
pub use empty_roots::EmptySubtreeRoots; pub use empty_roots::EmptySubtreeRoots;
use empty_roots::EMPTY_WORD;
mod index; mod index;
pub use index::NodeIndex; pub use index::NodeIndex;
@@ -26,8 +27,11 @@ pub use path_set::MerklePathSet;
mod simple_smt; mod simple_smt;
pub use simple_smt::SimpleSmt; pub use simple_smt::SimpleSmt;
mod tiered_smt;
pub use tiered_smt::TieredSmt;
mod mmr; mod mmr;
pub use mmr::{Mmr, MmrPeaks}; pub use mmr::{Mmr, MmrPeaks, MmrProof};
mod store; mod store;
pub use store::MerkleStore; pub use store::MerkleStore;
@@ -43,13 +47,15 @@ pub enum MerkleError {
ConflictingRoots(Vec<Word>), ConflictingRoots(Vec<Word>),
DepthTooSmall(u8), DepthTooSmall(u8),
DepthTooBig(u64), DepthTooBig(u64),
NodeNotInStore(Word, NodeIndex), DuplicateValuesForIndex(u64),
NumLeavesNotPowerOfTwo(usize), DuplicateValuesForKey(RpoDigest),
InvalidIndex { depth: u8, value: u64 }, InvalidIndex { depth: u8, value: u64 },
InvalidDepth { expected: u8, provided: u8 }, InvalidDepth { expected: u8, provided: u8 },
InvalidPath(MerklePath), InvalidPath(MerklePath),
InvalidEntriesCount(usize, usize), InvalidNumEntries(usize, usize),
NodeNotInSet(u64), NodeNotInSet(NodeIndex),
NodeNotInStore(Word, NodeIndex),
NumLeavesNotPowerOfTwo(usize),
RootNotInStore(Word), RootNotInStore(Word),
} }
@@ -60,9 +66,8 @@ impl fmt::Display for MerkleError {
ConflictingRoots(roots) => write!(f, "the merkle paths roots do not match {roots:?}"), ConflictingRoots(roots) => write!(f, "the merkle paths roots do not match {roots:?}"),
DepthTooSmall(depth) => write!(f, "the provided depth {depth} is too small"), DepthTooSmall(depth) => write!(f, "the provided depth {depth} is too small"),
DepthTooBig(depth) => write!(f, "the provided depth {depth} is too big"), DepthTooBig(depth) => write!(f, "the provided depth {depth} is too big"),
NumLeavesNotPowerOfTwo(leaves) => { DuplicateValuesForIndex(key) => write!(f, "multiple values provided for key {key}"),
write!(f, "the leaves count {leaves} is not a power of 2") DuplicateValuesForKey(key) => write!(f, "multiple values provided for key {key}"),
}
InvalidIndex{ depth, value} => write!( InvalidIndex{ depth, value} => write!(
f, f,
"the index value {value} is not valid for the depth {depth}" "the index value {value} is not valid for the depth {depth}"
@@ -72,9 +77,12 @@ impl fmt::Display for MerkleError {
"the provided depth {provided} is not valid for {expected}" "the provided depth {provided} is not valid for {expected}"
), ),
InvalidPath(_path) => write!(f, "the provided path is not valid"), InvalidPath(_path) => write!(f, "the provided path is not valid"),
InvalidEntriesCount(max, provided) => write!(f, "the provided number of entries is {provided}, but the maximum for the given depth is {max}"), InvalidNumEntries(max, provided) => write!(f, "the provided number of entries is {provided}, but the maximum for the given depth is {max}"),
NodeNotInSet(index) => write!(f, "the node indexed by {index} is not in the set"), NodeNotInSet(index) => write!(f, "the node with index ({index}) is not in the set"),
NodeNotInStore(hash, index) => write!(f, "the node {:?} indexed by {} and depth {} is not in the store", hash, index.value(), index.depth(),), NodeNotInStore(hash, index) => write!(f, "the node {hash:?} with index ({index}) is not in the store"),
NumLeavesNotPowerOfTwo(leaves) => {
write!(f, "the leaves count {leaves} is not a power of 2")
}
RootNotInStore(root) => write!(f, "the root {:?} is not in the store", root), RootNotInStore(root) => write!(f, "the root {:?} is not in the store", root),
} }
} }

View File

@@ -1,4 +1,4 @@
use super::{vec, MerkleError, NodeIndex, Rpo256, Vec, Word}; use super::{vec, InnerNodeInfo, MerkleError, NodeIndex, Rpo256, Vec, Word};
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
// MERKLE PATH // MERKLE PATH
@@ -22,6 +22,11 @@ impl MerklePath {
// PROVIDERS // PROVIDERS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
/// Returns the depth in which this Merkle path proof is valid.
pub fn depth(&self) -> u8 {
self.nodes.len() as u8
}
/// Computes the merkle root for this opening. /// Computes the merkle root for this opening.
pub fn compute_root(&self, index: u64, node: Word) -> Result<Word, MerkleError> { pub fn compute_root(&self, index: u64, node: Word) -> Result<Word, MerkleError> {
let mut index = NodeIndex::new(self.depth(), index)?; let mut index = NodeIndex::new(self.depth(), index)?;
@@ -34,11 +39,6 @@ impl MerklePath {
Ok(root) Ok(root)
} }
/// Returns the depth in which this Merkle path proof is valid.
pub fn depth(&self) -> u8 {
self.nodes.len() as u8
}
/// Verifies the Merkle opening proof towards the provided root. /// Verifies the Merkle opening proof towards the provided root.
/// ///
/// Returns `true` if `node` exists at `index` in a Merkle tree with `root`. /// Returns `true` if `node` exists at `index` in a Merkle tree with `root`.
@@ -48,6 +48,20 @@ impl MerklePath {
Err(_) => false, Err(_) => false,
} }
} }
/// Returns an iterator over every inner node of this [MerklePath].
///
/// The iteration order is unspecified.
///
/// # Errors
/// Returns an error if the specified index is not valid for this path.
pub fn inner_nodes(&self, index: u64, node: Word) -> Result<InnerNodeIterator, MerkleError> {
Ok(InnerNodeIterator {
nodes: &self.nodes,
index: NodeIndex::new(self.depth(), index)?,
value: node,
})
}
} }
impl From<Vec<Word>> for MerklePath { impl From<Vec<Word>> for MerklePath {
@@ -72,6 +86,9 @@ impl DerefMut for MerklePath {
} }
} }
// ITERATORS
// ================================================================================================
impl FromIterator<Word> for MerklePath { impl FromIterator<Word> for MerklePath {
fn from_iter<T: IntoIterator<Item = Word>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = Word>>(iter: T) -> Self {
Self::new(iter.into_iter().collect()) Self::new(iter.into_iter().collect())
@@ -87,6 +104,39 @@ impl IntoIterator for MerklePath {
} }
} }
/// An iterator over internal nodes of a [MerklePath].
pub struct InnerNodeIterator<'a> {
nodes: &'a Vec<Word>,
index: NodeIndex,
value: Word,
}
impl<'a> Iterator for InnerNodeIterator<'a> {
type Item = InnerNodeInfo;
fn next(&mut self) -> Option<Self::Item> {
if !self.index.is_root() {
let sibling_pos = self.nodes.len() - self.index.depth() as usize;
let (left, right) = if self.index.is_value_odd() {
(self.nodes[sibling_pos], self.value)
} else {
(self.value, self.nodes[sibling_pos])
};
self.value = Rpo256::merge(&[left.into(), right.into()]).into();
self.index.move_up();
Some(InnerNodeInfo {
value: self.value,
left,
right,
})
} else {
None
}
}
}
// MERKLE PATH CONTAINERS // MERKLE PATH CONTAINERS
// ================================================================================================ // ================================================================================================
@@ -110,3 +160,25 @@ pub struct RootPath {
/// The path from `value` to `root` (exclusive). /// The path from `value` to `root` (exclusive).
pub path: MerklePath, pub path: MerklePath,
} }
// TESTS
// ================================================================================================
#[cfg(test)]
mod tests {
use crate::merkle::{int_to_node, MerklePath};
#[test]
fn test_inner_nodes() {
let nodes = vec![int_to_node(1), int_to_node(2), int_to_node(3), int_to_node(4)];
let merkle_path = MerklePath::new(nodes);
let index = 6;
let node = int_to_node(5);
let root = merkle_path.compute_root(index, node).unwrap();
let inner_root = merkle_path.inner_nodes(index, node).unwrap().last().unwrap().value;
assert_eq!(root, inner_root);
}
}

View File

@@ -34,12 +34,10 @@ impl MerklePathSet {
where where
I: IntoIterator<Item = (u64, Word, MerklePath)>, I: IntoIterator<Item = (u64, Word, MerklePath)>,
{ {
paths paths.into_iter().try_fold(self, |mut set, (index, value, path)| {
.into_iter() set.add_path(index, value, path)?;
.try_fold(self, |mut set, (index, value, path)| { Ok(set)
set.add_path(index, value, path)?; })
Ok(set)
})
} }
// PUBLIC ACCESSORS // PUBLIC ACCESSORS
@@ -75,7 +73,7 @@ impl MerklePathSet {
let path_key = index.value() - parity; let path_key = index.value() - parity;
self.paths self.paths
.get(&path_key) .get(&path_key)
.ok_or(MerkleError::NodeNotInSet(path_key)) .ok_or(MerkleError::NodeNotInSet(index))
.map(|path| path[parity as usize]) .map(|path| path[parity as usize])
} }
@@ -106,11 +104,8 @@ impl MerklePathSet {
let parity = index.value() & 1; let parity = index.value() & 1;
let path_key = index.value() - parity; let path_key = index.value() - parity;
let mut path = self let mut path =
.paths self.paths.get(&path_key).cloned().ok_or(MerkleError::NodeNotInSet(index))?;
.get(&path_key)
.cloned()
.ok_or(MerkleError::NodeNotInSet(index.value()))?;
path.remove(parity as usize); path.remove(parity as usize);
Ok(path) Ok(path)
} }
@@ -202,7 +197,7 @@ impl MerklePathSet {
let path_key = index.value() - parity; let path_key = index.value() - parity;
let path = match self.paths.get_mut(&path_key) { let path = match self.paths.get_mut(&path_key) {
Some(path) => path, Some(path) => path,
None => return Err(MerkleError::NodeNotInSet(base_index_value)), None => return Err(MerkleError::NodeNotInSet(index)),
}; };
// Fill old_hashes vector ----------------------------------------------------------------- // Fill old_hashes vector -----------------------------------------------------------------
@@ -291,14 +286,9 @@ mod tests {
let hash_6 = int_to_node(6); let hash_6 = int_to_node(6);
let index = 6_u64; let index = 6_u64;
let depth = 3_u8; let depth = 3_u8;
let set = MerklePathSet::new(depth) let set = MerklePathSet::new(depth).with_paths([(index, hash_6, path_6.into())]).unwrap();
.with_paths([(index, hash_6, path_6.into())])
.unwrap();
assert_eq!( assert_eq!(int_to_node(6u64), set.get_node(NodeIndex::make(depth, index)).unwrap());
int_to_node(6u64),
set.get_node(NodeIndex::make(depth, index)).unwrap()
);
} }
#[test] #[test]

View File

@@ -1,6 +1,6 @@
use super::{ use super::{
BTreeMap, EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, NodeIndex, Rpo256, BTreeMap, BTreeSet, EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, NodeIndex,
RpoDigest, Vec, Word, Rpo256, RpoDigest, Vec, Word, EMPTY_WORD,
}; };
#[cfg(test)] #[cfg(test)]
@@ -10,6 +10,7 @@ mod tests;
// ================================================================================================ // ================================================================================================
/// A sparse Merkle tree with 64-bit keys and 4-element leaf values, without compaction. /// 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. /// The root of the tree is recomputed on each new leaf update.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct SimpleSmt { pub struct SimpleSmt {
@@ -20,18 +21,6 @@ pub struct SimpleSmt {
empty_hashes: Vec<RpoDigest>, empty_hashes: Vec<RpoDigest>,
} }
#[derive(Debug, Default, Clone, PartialEq, Eq)]
struct BranchNode {
left: RpoDigest,
right: RpoDigest,
}
impl BranchNode {
fn parent(&self) -> RpoDigest {
Rpo256::merge(&[self.left, self.right])
}
}
impl SimpleSmt { impl SimpleSmt {
// CONSTANTS // CONSTANTS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
@@ -45,7 +34,12 @@ impl SimpleSmt {
// CONSTRUCTORS // CONSTRUCTORS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
/// Creates a new simple SMT with the provided depth. /// 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<Self, MerkleError> { pub fn new(depth: u8) -> Result<Self, MerkleError> {
// validate the range of the depth. // validate the range of the depth.
if depth < Self::MIN_DEPTH { if depth < Self::MIN_DEPTH {
@@ -66,36 +60,47 @@ impl SimpleSmt {
}) })
} }
/// Appends the provided entries as leaves of the tree. /// 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 /// # Errors
/// /// Returns an error if:
/// The function will fail if the provided entries count exceed the maximum tree capacity, that /// - If the depth is 0 or is greater than 64.
/// is `2^{depth}`. /// - The number of entries exceeds the maximum tree capacity, that is 2^{depth}.
pub fn with_leaves<R, I>(mut self, entries: R) -> Result<Self, MerkleError> /// - The provided entries contain multiple values for the same key.
pub fn with_leaves<R, I>(depth: u8, entries: R) -> Result<Self, MerkleError>
where where
R: IntoIterator<IntoIter = I>, R: IntoIterator<IntoIter = I>,
I: Iterator<Item = (u64, Word)> + ExactSizeIterator, I: Iterator<Item = (u64, Word)> + ExactSizeIterator,
{ {
// check if the leaves count will fit the depth setup // create an empty tree
let mut entries = entries.into_iter(); let mut tree = Self::new(depth)?;
let max = 1 << self.depth.min(63);
// check if the number of leaves can be accommodated by the tree's depth; we use a min
// depth of 63 because we consider passing in a vector of size 2^64 infeasible.
let entries = entries.into_iter();
let max = 1 << tree.depth.min(63);
if entries.len() > max { if entries.len() > max {
return Err(MerkleError::InvalidEntriesCount(max, entries.len())); return Err(MerkleError::InvalidNumEntries(max, entries.len()));
} }
// append leaves and return // append leaves to the tree returning an error if a duplicate entry for the same key
entries.try_for_each(|(key, leaf)| self.insert_leaf(key, leaf))?; // is found
Ok(self) let mut empty_entries = BTreeSet::new();
} for (key, value) in entries {
let old_value = tree.update_leaf(key, value)?;
/// Replaces the internal empty digests used when a given depth doesn't contain a node. if old_value != EMPTY_WORD || empty_entries.contains(&key) {
pub fn with_empty_subtrees<I>(mut self, hashes: I) -> Self return Err(MerkleError::DuplicateValuesForIndex(key));
where }
I: IntoIterator<Item = RpoDigest>, // if we've processed an empty entry, add the key to the set of empty entry keys, and
{ // if this key was already in the set, return an error
self.replace_empty_subtrees(hashes.into_iter().collect()); if value == EMPTY_WORD && !empty_entries.insert(key) {
self return Err(MerkleError::DuplicateValuesForIndex(key));
}
}
Ok(tree)
} }
// PUBLIC ACCESSORS // PUBLIC ACCESSORS
@@ -111,45 +116,43 @@ impl SimpleSmt {
self.depth self.depth
} }
// PROVIDERS
// --------------------------------------------------------------------------------------------
/// Returns the set count of the keys of the leaves.
pub fn leaves_count(&self) -> usize {
self.leaves.len()
}
/// Returns a node at the specified index. /// Returns a node at the specified index.
/// ///
/// # Errors /// # Errors
/// Returns an error if: /// Returns an error if the specified index has depth set to 0 or the depth is greater than
/// * The specified depth is greater than the depth of the tree. /// the depth of this Merkle tree.
pub fn get_node(&self, index: NodeIndex) -> Result<Word, MerkleError> { pub fn get_node(&self, index: NodeIndex) -> Result<Word, MerkleError> {
if index.is_root() { if index.is_root() {
Err(MerkleError::DepthTooSmall(index.depth())) Err(MerkleError::DepthTooSmall(index.depth()))
} else if index.depth() > self.depth() { } else if index.depth() > self.depth() {
Err(MerkleError::DepthTooBig(index.depth() as u64)) Err(MerkleError::DepthTooBig(index.depth() as u64))
} else if index.depth() == self.depth() { } else if index.depth() == self.depth() {
self.get_leaf_node(index.value()) // the lookup in empty_hashes could fail only if empty_hashes were not built correctly
.or_else(|| { // by the constructor as we check the depth of the lookup above.
self.empty_hashes Ok(self
.get(index.depth() as usize) .get_leaf_node(index.value())
.copied() .unwrap_or_else(|| self.empty_hashes[index.depth() as usize].into()))
.map(Word::from)
})
.ok_or(MerkleError::NodeNotInSet(index.value()))
} else { } else {
let branch_node = self.get_branch_node(&index); Ok(self.get_branch_node(&index).parent().into())
Ok(Rpo256::merge(&[branch_node.left, branch_node.right]).into())
} }
} }
/// Returns a Merkle path from the node at the specified key to the root. The node itself is /// Returns a value of the leaf at the specified index.
/// not included in the path.
/// ///
/// # Errors /// # Errors
/// Returns an error if: /// Returns an error if the index is greater than the maximum tree capacity, that is 2^{depth}.
/// * The specified depth is greater than the depth of the tree. pub fn get_leaf(&self, index: u64) -> Result<Word, MerkleError> {
let index = NodeIndex::new(self.depth, index)?;
self.get_node(index)
}
/// 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<MerklePath, MerkleError> { pub fn get_path(&self, mut index: NodeIndex) -> Result<MerklePath, MerkleError> {
if index.is_root() { if index.is_root() {
return Err(MerkleError::DepthTooSmall(index.depth())); return Err(MerkleError::DepthTooSmall(index.depth()));
@@ -168,18 +171,26 @@ impl SimpleSmt {
Ok(path.into()) Ok(path.into())
} }
/// Return a Merkle path from the leaf at the specified key to the root. The leaf itself is not /// Return a Merkle path from the leaf at the specified index to the root.
/// included in the path. ///
/// The leaf itself is not included in the path.
/// ///
/// # Errors /// # Errors
/// Returns an error if: /// Returns an error if the index is greater than the maximum tree capacity, that is 2^{depth}.
/// * The specified key does not exist as a leaf node. pub fn get_leaf_path(&self, index: u64) -> Result<MerklePath, MerkleError> {
pub fn get_leaf_path(&self, key: u64) -> Result<MerklePath, MerkleError> { let index = NodeIndex::new(self.depth(), index)?;
let index = NodeIndex::new(self.depth(), key)?;
self.get_path(index) self.get_path(index)
} }
/// Iterator over the inner nodes of the [SimpleSmt]. // ITERATORS
// --------------------------------------------------------------------------------------------
/// Returns an iterator over the leaves of this [SimpleSmt].
pub fn leaves(&self) -> impl Iterator<Item = (u64, &Word)> {
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<Item = InnerNodeInfo> + '_ { pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
self.branches.values().map(|e| InnerNodeInfo { self.branches.values().map(|e| InnerNodeInfo {
value: e.parent().into(), value: e.parent().into(),
@@ -191,61 +202,43 @@ impl SimpleSmt {
// STATE MUTATORS // STATE MUTATORS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
/// Replaces the leaf located at the specified key, and recomputes hashes by walking up the /// Updates value of the leaf at the specified index returning the old leaf value.
/// tree. ///
/// This also recomputes all hashes between the leaf and the root, updating the root itself.
/// ///
/// # Errors /// # Errors
/// Returns an error if the specified key is not a valid leaf index for this tree. /// Returns an error if the index is greater than the maximum tree capacity, that is 2^{depth}.
pub fn update_leaf(&mut self, key: u64, value: Word) -> Result<(), MerkleError> { pub fn update_leaf(&mut self, index: u64, value: Word) -> Result<Word, MerkleError> {
let index = NodeIndex::new(self.depth(), key)?; let old_value = self.insert_leaf_node(index, value).unwrap_or(EMPTY_WORD);
if !self.check_leaf_node_exists(key) {
return Err(MerkleError::NodeNotInSet(index.value())); // if the old value and new value are the same, there is nothing to update
if value == old_value {
return Ok(value);
} }
self.insert_leaf(key, value)?;
Ok(()) let mut index = NodeIndex::new(self.depth(), index)?;
}
/// Inserts a leaf located at the specified key, and recomputes hashes by walking up the tree
pub fn insert_leaf(&mut self, key: u64, value: Word) -> Result<(), MerkleError> {
self.insert_leaf_node(key, value);
// TODO consider using a map `index |-> word` instead of `index |-> (word, word)`
let mut index = NodeIndex::new(self.depth(), key)?;
let mut value = RpoDigest::from(value); let mut value = RpoDigest::from(value);
for _ in 0..index.depth() { for _ in 0..index.depth() {
let is_right = index.is_value_odd(); let is_right = index.is_value_odd();
index.move_up(); index.move_up();
let BranchNode { left, right } = self.get_branch_node(&index); let BranchNode { left, right } = self.get_branch_node(&index);
let (left, right) = if is_right { let (left, right) = if is_right { (left, value) } else { (value, right) };
(left, value)
} else {
(value, right)
};
self.insert_branch_node(index, left, right); self.insert_branch_node(index, left, right);
value = Rpo256::merge(&[left, right]); value = Rpo256::merge(&[left, right]);
} }
self.root = value.into(); self.root = value.into();
Ok(()) Ok(old_value)
} }
// HELPER METHODS // HELPER METHODS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
fn replace_empty_subtrees(&mut self, hashes: Vec<RpoDigest>) {
self.empty_hashes = hashes;
}
fn check_leaf_node_exists(&self, key: u64) -> bool {
self.leaves.contains_key(&key)
}
fn get_leaf_node(&self, key: u64) -> Option<Word> { fn get_leaf_node(&self, key: u64) -> Option<Word> {
self.leaves.get(&key).copied() self.leaves.get(&key).copied()
} }
fn insert_leaf_node(&mut self, key: u64, node: Word) { fn insert_leaf_node(&mut self, key: u64, node: Word) -> Option<Word> {
self.leaves.insert(key, node); self.leaves.insert(key, node)
} }
fn get_branch_node(&self, index: &NodeIndex) -> BranchNode { fn get_branch_node(&self, index: &NodeIndex) -> BranchNode {
@@ -263,3 +256,18 @@ impl SimpleSmt {
self.branches.insert(index, branch); self.branches.insert(index, branch);
} }
} }
// BRANCH NODE
// ================================================================================================
#[derive(Debug, Default, Clone, PartialEq, Eq)]
struct BranchNode {
left: RpoDigest,
right: RpoDigest,
}
impl BranchNode {
fn parent(&self) -> RpoDigest {
Rpo256::merge(&[self.left, self.right])
}
}

View File

@@ -1,19 +1,15 @@
use super::{ use super::{
super::{int_to_node, InnerNodeInfo, MerkleError, MerkleTree, RpoDigest, SimpleSmt}, super::{int_to_node, InnerNodeInfo, MerkleError, MerkleTree, RpoDigest, SimpleSmt},
NodeIndex, Rpo256, Vec, Word, NodeIndex, Rpo256, Vec, Word, EMPTY_WORD,
}; };
use proptest::prelude::*;
use rand_utils::prng_array; // TEST DATA
// ================================================================================================
const KEYS4: [u64; 4] = [0, 1, 2, 3]; const KEYS4: [u64; 4] = [0, 1, 2, 3];
const KEYS8: [u64; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; const KEYS8: [u64; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
const VALUES4: [Word; 4] = [ const VALUES4: [Word; 4] = [int_to_node(1), int_to_node(2), int_to_node(3), int_to_node(4)];
int_to_node(1),
int_to_node(2),
int_to_node(3),
int_to_node(4),
];
const VALUES8: [Word; 8] = [ const VALUES8: [Word; 8] = [
int_to_node(1), int_to_node(1),
@@ -28,25 +24,17 @@ const VALUES8: [Word; 8] = [
const ZERO_VALUES8: [Word; 8] = [int_to_node(0); 8]; const ZERO_VALUES8: [Word; 8] = [int_to_node(0); 8];
// TESTS
// ================================================================================================
#[test] #[test]
fn build_empty_tree() { fn build_empty_tree() {
// tree of depth 3
let smt = SimpleSmt::new(3).unwrap(); let smt = SimpleSmt::new(3).unwrap();
let mt = MerkleTree::new(ZERO_VALUES8.to_vec()).unwrap(); let mt = MerkleTree::new(ZERO_VALUES8.to_vec()).unwrap();
assert_eq!(mt.root(), smt.root()); assert_eq!(mt.root(), smt.root());
} }
#[test]
fn empty_digests_are_consistent() {
let depth = 5;
let root = SimpleSmt::new(depth).unwrap().root();
let computed: [RpoDigest; 2] = (0..depth).fold([Default::default(); 2], |state, _| {
let digest = Rpo256::merge(&state);
[digest; 2]
});
assert_eq!(Word::from(computed[0]), root);
}
#[test] #[test]
fn build_sparse_tree() { fn build_sparse_tree() {
let mut smt = SimpleSmt::new(3).unwrap(); let mut smt = SimpleSmt::new(3).unwrap();
@@ -56,94 +44,59 @@ fn build_sparse_tree() {
let key = 6; let key = 6;
let new_node = int_to_node(7); let new_node = int_to_node(7);
values[key as usize] = new_node; values[key as usize] = new_node;
smt.insert_leaf(key, new_node) let old_value = smt.update_leaf(key, new_node).expect("Failed to update leaf");
.expect("Failed to insert leaf");
let mt2 = MerkleTree::new(values.clone()).unwrap(); let mt2 = MerkleTree::new(values.clone()).unwrap();
assert_eq!(mt2.root(), smt.root()); assert_eq!(mt2.root(), smt.root());
assert_eq!( assert_eq!(
mt2.get_path(NodeIndex::make(3, 6)).unwrap(), mt2.get_path(NodeIndex::make(3, 6)).unwrap(),
smt.get_path(NodeIndex::make(3, 6)).unwrap() smt.get_path(NodeIndex::make(3, 6)).unwrap()
); );
assert_eq!(old_value, EMPTY_WORD);
// insert second value at distinct leaf branch // insert second value at distinct leaf branch
let key = 2; let key = 2;
let new_node = int_to_node(3); let new_node = int_to_node(3);
values[key as usize] = new_node; values[key as usize] = new_node;
smt.insert_leaf(key, new_node) let old_value = smt.update_leaf(key, new_node).expect("Failed to update leaf");
.expect("Failed to insert leaf");
let mt3 = MerkleTree::new(values).unwrap(); let mt3 = MerkleTree::new(values).unwrap();
assert_eq!(mt3.root(), smt.root()); assert_eq!(mt3.root(), smt.root());
assert_eq!( assert_eq!(
mt3.get_path(NodeIndex::make(3, 2)).unwrap(), mt3.get_path(NodeIndex::make(3, 2)).unwrap(),
smt.get_path(NodeIndex::make(3, 2)).unwrap() smt.get_path(NodeIndex::make(3, 2)).unwrap()
); );
assert_eq!(old_value, EMPTY_WORD);
} }
#[test] #[test]
fn build_full_tree() { fn test_depth2_tree() {
let tree = SimpleSmt::new(2) let tree = SimpleSmt::with_leaves(2, KEYS4.into_iter().zip(VALUES4.into_iter())).unwrap();
.unwrap()
.with_leaves(KEYS4.into_iter().zip(VALUES4.into_iter()))
.unwrap();
// check internal structure
let (root, node2, node3) = compute_internal_nodes(); let (root, node2, node3) = compute_internal_nodes();
assert_eq!(root, tree.root()); assert_eq!(root, tree.root());
assert_eq!(node2, tree.get_node(NodeIndex::make(1, 0)).unwrap()); assert_eq!(node2, tree.get_node(NodeIndex::make(1, 0)).unwrap());
assert_eq!(node3, tree.get_node(NodeIndex::make(1, 1)).unwrap()); assert_eq!(node3, tree.get_node(NodeIndex::make(1, 1)).unwrap());
}
#[test] // check get_node()
fn get_values() {
let tree = SimpleSmt::new(2)
.unwrap()
.with_leaves(KEYS4.into_iter().zip(VALUES4.into_iter()))
.unwrap();
// check depth 2
assert_eq!(VALUES4[0], tree.get_node(NodeIndex::make(2, 0)).unwrap()); assert_eq!(VALUES4[0], tree.get_node(NodeIndex::make(2, 0)).unwrap());
assert_eq!(VALUES4[1], tree.get_node(NodeIndex::make(2, 1)).unwrap()); assert_eq!(VALUES4[1], tree.get_node(NodeIndex::make(2, 1)).unwrap());
assert_eq!(VALUES4[2], tree.get_node(NodeIndex::make(2, 2)).unwrap()); assert_eq!(VALUES4[2], tree.get_node(NodeIndex::make(2, 2)).unwrap());
assert_eq!(VALUES4[3], tree.get_node(NodeIndex::make(2, 3)).unwrap()); assert_eq!(VALUES4[3], tree.get_node(NodeIndex::make(2, 3)).unwrap());
}
#[test] // check get_path(): depth 2
fn get_path() { assert_eq!(vec![VALUES4[1], node3], *tree.get_path(NodeIndex::make(2, 0)).unwrap());
let tree = SimpleSmt::new(2) assert_eq!(vec![VALUES4[0], node3], *tree.get_path(NodeIndex::make(2, 1)).unwrap());
.unwrap() assert_eq!(vec![VALUES4[3], node2], *tree.get_path(NodeIndex::make(2, 2)).unwrap());
.with_leaves(KEYS4.into_iter().zip(VALUES4.into_iter())) assert_eq!(vec![VALUES4[2], node2], *tree.get_path(NodeIndex::make(2, 3)).unwrap());
.unwrap();
let (_, node2, node3) = compute_internal_nodes(); // check get_path(): depth 1
// check 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 depth 1
assert_eq!(vec![node3], *tree.get_path(NodeIndex::make(1, 0)).unwrap()); 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![node2], *tree.get_path(NodeIndex::make(1, 1)).unwrap());
} }
#[test] #[test]
fn test_parent_node_iterator() -> Result<(), MerkleError> { fn test_inner_node_iterator() -> Result<(), MerkleError> {
let tree = SimpleSmt::new(2) let tree = SimpleSmt::with_leaves(2, KEYS4.into_iter().zip(VALUES4.into_iter())).unwrap();
.unwrap()
.with_leaves(KEYS4.into_iter().zip(VALUES4.into_iter()))
.unwrap();
// check depth 2 // check depth 2
assert_eq!(VALUES4[0], tree.get_node(NodeIndex::make(2, 0)).unwrap()); assert_eq!(VALUES4[0], tree.get_node(NodeIndex::make(2, 0)).unwrap());
@@ -185,35 +138,28 @@ fn test_parent_node_iterator() -> Result<(), MerkleError> {
#[test] #[test]
fn update_leaf() { fn update_leaf() {
let mut tree = SimpleSmt::new(3) let mut tree = SimpleSmt::with_leaves(3, KEYS8.into_iter().zip(VALUES8.into_iter())).unwrap();
.unwrap()
.with_leaves(KEYS8.into_iter().zip(VALUES8.into_iter()))
.unwrap();
// update one value // update one value
let key = 3; let key = 3;
let new_node = int_to_node(9); let new_node = int_to_node(9);
let mut expected_values = VALUES8.to_vec(); let mut expected_values = VALUES8.to_vec();
expected_values[key] = new_node; expected_values[key] = new_node;
let expected_tree = SimpleSmt::new(3) let expected_tree = MerkleTree::new(expected_values.clone()).unwrap();
.unwrap()
.with_leaves(KEYS8.into_iter().zip(expected_values.clone().into_iter()))
.unwrap();
tree.update_leaf(key as u64, new_node).unwrap(); let old_leaf = tree.update_leaf(key as u64, new_node).unwrap();
assert_eq!(expected_tree.root, tree.root); assert_eq!(expected_tree.root(), tree.root);
assert_eq!(old_leaf, VALUES8[key]);
// update another value // update another value
let key = 6; let key = 6;
let new_node = int_to_node(10); let new_node = int_to_node(10);
expected_values[key] = new_node; expected_values[key] = new_node;
let expected_tree = SimpleSmt::new(3) let expected_tree = MerkleTree::new(expected_values.clone()).unwrap();
.unwrap()
.with_leaves(KEYS8.into_iter().zip(expected_values.into_iter()))
.unwrap();
tree.update_leaf(key as u64, new_node).unwrap(); let old_leaf = tree.update_leaf(key as u64, new_node).unwrap();
assert_eq!(expected_tree.root, tree.root); assert_eq!(expected_tree.root(), tree.root);
assert_eq!(old_leaf, VALUES8[key]);
} }
#[test] #[test]
@@ -245,7 +191,7 @@ fn small_tree_opening_is_consistent() {
let depth = 3; let depth = 3;
let entries = vec![(0, a), (1, b), (4, c), (7, d)]; let entries = vec![(0, a), (1, b), (4, c), (7, d)];
let tree = SimpleSmt::new(depth).unwrap().with_leaves(entries).unwrap(); let tree = SimpleSmt::with_leaves(depth, entries).unwrap();
assert_eq!(tree.root(), Word::from(k)); assert_eq!(tree.root(), Word::from(k));
@@ -269,56 +215,30 @@ fn small_tree_opening_is_consistent() {
} }
} }
proptest! { #[test]
#[test] fn fail_on_duplicates() {
fn arbitrary_openings_single_leaf( let entries = [(1_u64, int_to_node(1)), (5, int_to_node(2)), (1_u64, int_to_node(3))];
depth in SimpleSmt::MIN_DEPTH..SimpleSmt::MAX_DEPTH, let smt = SimpleSmt::with_leaves(64, entries);
key in prop::num::u64::ANY, assert!(smt.is_err());
leaf in prop::num::u64::ANY,
) {
let mut tree = SimpleSmt::new(depth).unwrap();
let key = key % (1 << depth as u64); let entries = [(1_u64, int_to_node(0)), (5, int_to_node(2)), (1_u64, int_to_node(0))];
let leaf = int_to_node(leaf); let smt = SimpleSmt::with_leaves(64, entries);
assert!(smt.is_err());
tree.insert_leaf(key, leaf.into()).unwrap(); let entries = [(1_u64, int_to_node(0)), (5, int_to_node(2)), (1_u64, int_to_node(1))];
tree.get_leaf_path(key).unwrap(); let smt = SimpleSmt::with_leaves(64, entries);
assert!(smt.is_err());
// traverse to root, fetching all paths let entries = [(1_u64, int_to_node(1)), (5, int_to_node(2)), (1_u64, int_to_node(0))];
for d in 1..depth { let smt = SimpleSmt::with_leaves(64, entries);
let k = key >> (depth - d); assert!(smt.is_err());
tree.get_path(NodeIndex::make(d, k)).unwrap(); }
}
}
#[test] #[test]
fn arbitrary_openings_multiple_leaves( fn with_no_duplicates_empty_node() {
depth in SimpleSmt::MIN_DEPTH..SimpleSmt::MAX_DEPTH, let entries = [(1_u64, int_to_node(0)), (5, int_to_node(2))];
count in 2u8..10u8, let smt = SimpleSmt::with_leaves(64, entries);
ref seed in any::<[u8; 32]>() assert!(smt.is_ok());
) {
let mut tree = SimpleSmt::new(depth).unwrap();
let mut seed = *seed;
let leaves = (1 << depth) - 1;
for _ in 0..count {
seed = prng_array(seed);
let mut key = [0u8; 8];
let mut leaf = [0u8; 8];
key.copy_from_slice(&seed[..8]);
leaf.copy_from_slice(&seed[8..16]);
let key = u64::from_le_bytes(key);
let key = key % leaves;
let leaf = u64::from_le_bytes(leaf);
let leaf = int_to_node(leaf);
tree.insert_leaf(key, leaf).unwrap();
tree.get_leaf_path(key).unwrap();
}
}
} }
// HELPER FUNCTIONS // HELPER FUNCTIONS

View File

@@ -1,9 +1,9 @@
use super::mmr::{Mmr, MmrPeaks};
use super::{ use super::{
BTreeMap, EmptySubtreeRoots, MerkleError, MerklePath, MerklePathSet, MerkleTree, NodeIndex, mmr::Mmr, BTreeMap, EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, MerklePathSet,
RootPath, Rpo256, RpoDigest, SimpleSmt, ValuePath, Vec, Word, MerkleTree, NodeIndex, RootPath, Rpo256, RpoDigest, SimpleSmt, TieredSmt, ValuePath, Vec, Word,
}; };
use crate::utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}; use crate::utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
use core::borrow::Borrow;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@@ -14,7 +14,7 @@ pub struct Node {
right: RpoDigest, right: RpoDigest,
} }
/// An in-memory data store for Merkle-lized data. /// An in-memory data store for Merkelized data.
/// ///
/// This is a in memory data store for Merkle trees, this store allows all the nodes of multiple /// This is a in memory data store for Merkle trees, this store allows all the nodes of multiple
/// trees to live as long as necessary and without duplication, this allows the implementation of /// trees to live as long as necessary and without duplication, this allows the implementation of
@@ -47,9 +47,13 @@ pub struct Node {
/// // the store is initialized with the SMT empty nodes /// // the store is initialized with the SMT empty nodes
/// assert_eq!(store.num_internal_nodes(), 255); /// assert_eq!(store.num_internal_nodes(), 255);
/// ///
/// let tree1 = MerkleTree::new(vec![A, B, C, D, E, F, G, H0]).unwrap();
/// let tree2 = MerkleTree::new(vec![A, B, C, D, E, F, G, H1]).unwrap();
///
/// // populates the store with two merkle trees, common nodes are shared /// // populates the store with two merkle trees, common nodes are shared
/// store.add_merkle_tree([A, B, C, D, E, F, G, H0]); /// store
/// store.add_merkle_tree([A, B, C, D, E, F, G, H1]); /// .extend(tree1.inner_nodes())
/// .extend(tree2.inner_nodes());
/// ///
/// // every leaf except the last are the same /// // every leaf except the last are the same
/// for i in 0..7 { /// for i in 0..7 {
@@ -111,60 +115,6 @@ impl MerkleStore {
MerkleStore { nodes } MerkleStore { nodes }
} }
/// Appends the provided merkle tree represented by its `leaves` to the set.
pub fn with_merkle_tree<I>(mut self, leaves: I) -> Result<Self, MerkleError>
where
I: IntoIterator<Item = Word>,
{
self.add_merkle_tree(leaves)?;
Ok(self)
}
/// Appends the provided Sparse Merkle tree represented by its `entries` to the set.
///
/// For more information, check [MerkleStore::add_sparse_merkle_tree].
pub fn with_sparse_merkle_tree<R, I>(
mut self,
depth: u8,
entries: R,
) -> Result<Self, MerkleError>
where
R: IntoIterator<IntoIter = I>,
I: Iterator<Item = (u64, Word)> + ExactSizeIterator,
{
self.add_sparse_merkle_tree(depth, entries)?;
Ok(self)
}
/// Appends the provided merkle path set.
pub fn with_merkle_path(
mut self,
index_value: u64,
node: Word,
path: MerklePath,
) -> Result<Self, MerkleError> {
self.add_merkle_path(index_value, node, path)?;
Ok(self)
}
/// Appends the provided merkle path set.
pub fn with_merkle_paths<I>(mut self, paths: I) -> Result<Self, MerkleError>
where
I: IntoIterator<Item = (u64, Word, MerklePath)>,
{
self.add_merkle_paths(paths)?;
Ok(self)
}
/// Appends the provided [Mmr] represented by its `leaves` to the set.
pub fn with_mmr<I>(mut self, leaves: I) -> Result<Self, MerkleError>
where
I: IntoIterator<Item = Word>,
{
self.add_mmr(leaves)?;
Ok(self)
}
// PUBLIC ACCESSORS // PUBLIC ACCESSORS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
@@ -184,15 +134,11 @@ impl MerkleStore {
let mut hash: RpoDigest = root.into(); let mut hash: RpoDigest = root.into();
// corner case: check the root is in the store when called with index `NodeIndex::root()` // corner case: check the root is in the store when called with index `NodeIndex::root()`
self.nodes self.nodes.get(&hash).ok_or(MerkleError::RootNotInStore(hash.into()))?;
.get(&hash)
.ok_or(MerkleError::RootNotInStore(hash.into()))?;
for i in (0..index.depth()).rev() { for i in (0..index.depth()).rev() {
let node = self let node =
.nodes self.nodes.get(&hash).ok_or(MerkleError::NodeNotInStore(hash.into(), index))?;
.get(&hash)
.ok_or(MerkleError::NodeNotInStore(hash.into(), index))?;
let bit = (index.value() >> i) & 1; let bit = (index.value() >> i) & 1;
hash = if bit == 0 { node.left } else { node.right } hash = if bit == 0 { node.left } else { node.right }
@@ -206,7 +152,6 @@ impl MerkleStore {
/// The path starts at the sibling of the target leaf. /// The path starts at the sibling of the target leaf.
/// ///
/// # Errors /// # Errors
///
/// This method can return the following errors: /// This method can return the following errors:
/// - `RootNotInStore` if the `root` is not present in the store. /// - `RootNotInStore` if the `root` is not present in the store.
/// - `NodeNotInStore` if a node needed to traverse from `root` to `index` is not present in the store. /// - `NodeNotInStore` if a node needed to traverse from `root` to `index` is not present in the store.
@@ -215,15 +160,11 @@ impl MerkleStore {
let mut path = Vec::with_capacity(index.depth().into()); let mut path = Vec::with_capacity(index.depth().into());
// corner case: check the root is in the store when called with index `NodeIndex::root()` // corner case: check the root is in the store when called with index `NodeIndex::root()`
self.nodes self.nodes.get(&hash).ok_or(MerkleError::RootNotInStore(hash.into()))?;
.get(&hash)
.ok_or(MerkleError::RootNotInStore(hash.into()))?;
for i in (0..index.depth()).rev() { for i in (0..index.depth()).rev() {
let node = self let node =
.nodes self.nodes.get(&hash).ok_or(MerkleError::NodeNotInStore(hash.into(), index))?;
.get(&hash)
.ok_or(MerkleError::NodeNotInStore(hash.into(), index))?;
let bit = (index.value() >> i) & 1; let bit = (index.value() >> i) & 1;
hash = if bit == 0 { hash = if bit == 0 {
@@ -302,11 +243,7 @@ impl MerkleStore {
}; };
// traverse down // traverse down
hash = if path & 1 == 0 { hash = if path & 1 == 0 { children.left } else { children.right };
children.left
} else {
children.right
};
path >>= 1; path >>= 1;
} }
@@ -319,71 +256,53 @@ impl MerkleStore {
Ok(tree_depth) Ok(tree_depth)
} }
// DATA EXTRACTORS
// --------------------------------------------------------------------------------------------
/// Returns a subset of this Merkle store such that the returned Merkle store contains all
/// nodes which are descendants of the specified roots.
///
/// The roots for which no descendants exist in this Merkle store are ignored.
pub fn subset<I, R>(&self, roots: I) -> MerkleStore
where
I: Iterator<Item = R>,
R: Borrow<Word>,
{
let mut store = MerkleStore::new();
for root in roots {
let root = RpoDigest::from(*root.borrow());
store.clone_tree_from(root, self);
}
store
}
/// Iterator over the inner nodes of the [MerkleStore].
pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
self.nodes.iter().map(|(r, n)| InnerNodeInfo {
value: r.into(),
left: n.left.into(),
right: n.right.into(),
})
}
// STATE MUTATORS // STATE MUTATORS
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
/// Adds all the nodes of a Merkle tree represented by `leaves`. /// Adds a sequence of nodes yielded by the provided iterator into the store.
/// pub fn extend<I>(&mut self, iter: I) -> &mut MerkleStore
/// This will instantiate a Merkle tree using `leaves` and include all the nodes into the
/// store.
///
/// # Errors
///
/// This method may return the following errors:
/// - `DepthTooSmall` if leaves is empty or contains only 1 element
/// - `NumLeavesNotPowerOfTwo` if the number of leaves is not a power-of-two
pub fn add_merkle_tree<I>(&mut self, leaves: I) -> Result<Word, MerkleError>
where where
I: IntoIterator<Item = Word>, I: Iterator<Item = InnerNodeInfo>,
{ {
let leaves: Vec<_> = leaves.into_iter().collect(); for node in iter {
if leaves.len() < 2 { let value: RpoDigest = node.value.into();
return Err(MerkleError::DepthTooSmall(leaves.len() as u8)); let left: RpoDigest = node.left.into();
let right: RpoDigest = node.right.into();
debug_assert_eq!(Rpo256::merge(&[left, right]), value);
self.nodes.insert(value, Node { left, right });
} }
let tree = MerkleTree::new(leaves)?; self
for node in tree.inner_nodes() {
self.nodes.insert(
node.value.into(),
Node {
left: node.left.into(),
right: node.right.into(),
},
);
}
Ok(tree.root())
}
/// Adds a Sparse Merkle tree defined by the specified `entries` to the store, and returns the
/// root of the added tree.
///
/// The entries are expected to contain tuples of `(index, node)` describing nodes in the tree
/// at `depth`.
///
/// # Errors
/// Returns an error if the provided `depth` is greater than [SimpleSmt::MAX_DEPTH].
pub fn add_sparse_merkle_tree<R, I>(
&mut self,
depth: u8,
entries: R,
) -> Result<Word, MerkleError>
where
R: IntoIterator<IntoIter = I>,
I: Iterator<Item = (u64, Word)> + ExactSizeIterator,
{
let smt = SimpleSmt::new(depth)?.with_leaves(entries)?;
for node in smt.inner_nodes() {
self.nodes.insert(
node.value.into(),
Node {
left: node.left.into(),
right: node.right.into(),
},
);
}
Ok(smt.root())
} }
/// Adds all the nodes of a Merkle path represented by `path`, opening to `node`. Returns the /// Adds all the nodes of a Merkle path represented by `path`, opening to `node`. Returns the
@@ -393,31 +312,21 @@ impl MerkleStore {
/// include all the nodes into the store. /// include all the nodes into the store.
pub fn add_merkle_path( pub fn add_merkle_path(
&mut self, &mut self,
index_value: u64, index: u64,
mut node: Word, node: Word,
path: MerklePath, path: MerklePath,
) -> Result<Word, MerkleError> { ) -> Result<Word, MerkleError> {
let mut index = NodeIndex::new(path.len() as u8, index_value)?; let root = path.inner_nodes(index, node)?.fold(Word::default(), |_, node| {
let value: RpoDigest = node.value.into();
let left: RpoDigest = node.left.into();
let right: RpoDigest = node.right.into();
for sibling in path { debug_assert_eq!(Rpo256::merge(&[left, right]), value);
let (left, right) = match index.is_value_odd() { self.nodes.insert(value, Node { left, right });
true => (sibling, node),
false => (node, sibling),
};
let parent = Rpo256::merge(&[left.into(), right.into()]);
self.nodes.insert(
parent,
Node {
left: left.into(),
right: right.into(),
},
);
index.move_up(); node.value
node = parent.into(); });
} Ok(root)
Ok(node)
} }
/// Adds all the nodes of multiple Merkle paths into the store. /// Adds all the nodes of multiple Merkle paths into the store.
@@ -447,25 +356,6 @@ impl MerkleStore {
Ok(root) Ok(root)
} }
/// Appends the provided [Mmr] into the store.
pub fn add_mmr<I>(&mut self, leaves: I) -> Result<MmrPeaks, MerkleError>
where
I: IntoIterator<Item = Word>,
{
let mmr = Mmr::from(leaves);
for node in mmr.inner_nodes() {
self.nodes.insert(
node.value.into(),
Node {
left: node.left.into(),
right: node.right.into(),
},
);
}
Ok(mmr.accumulator())
}
/// Sets a node to `value`. /// Sets a node to `value`.
/// ///
/// # Errors /// # Errors
@@ -490,29 +380,90 @@ impl MerkleStore {
Ok(RootPath { root, path }) Ok(RootPath { root, path })
} }
/// Merges two elements and adds the resulting node into the store.
///
/// Merges arbitrary values. They may be leafs, nodes, or a mixture of both.
pub fn merge_roots(&mut self, root1: Word, root2: Word) -> Result<Word, MerkleError> { pub fn merge_roots(&mut self, root1: Word, root2: Word) -> Result<Word, MerkleError> {
let root1: RpoDigest = root1.into(); let left: RpoDigest = root1.into();
let root2: RpoDigest = root2.into(); let right: RpoDigest = root2.into();
if !self.nodes.contains_key(&root1) { let parent = Rpo256::merge(&[left, right]);
Err(MerkleError::NodeNotInStore(root1.into(), NodeIndex::root())) self.nodes.insert(parent, Node { left, right });
} else if !self.nodes.contains_key(&root1) {
Err(MerkleError::NodeNotInStore(root2.into(), NodeIndex::root()))
} else {
let parent: Word = Rpo256::merge(&[root1, root2]).into();
self.nodes.insert(
parent.into(),
Node {
left: root1,
right: root2,
},
);
Ok(parent) Ok(parent.into())
}
// HELPER METHODS
// --------------------------------------------------------------------------------------------
/// Recursively clones a tree with the specified root from the specified source into self.
///
/// If the source store does not contain a tree with the specified root, this is a noop.
fn clone_tree_from(&mut self, root: RpoDigest, source: &Self) {
// process the node only if it is in the source
if let Some(node) = source.nodes.get(&root) {
// if the node has already been inserted, no need to process it further as all of its
// descendants should be already cloned from the source store
if matches!(self.nodes.insert(root, *node), None) {
self.clone_tree_from(node.left, source);
self.clone_tree_from(node.right, source);
}
} }
} }
} }
// CONVERSIONS
// ================================================================================================
impl From<&MerkleTree> for MerkleStore {
fn from(value: &MerkleTree) -> Self {
let mut store = MerkleStore::new();
store.extend(value.inner_nodes());
store
}
}
impl From<&SimpleSmt> for MerkleStore {
fn from(value: &SimpleSmt) -> Self {
let mut store = MerkleStore::new();
store.extend(value.inner_nodes());
store
}
}
impl From<&Mmr> for MerkleStore {
fn from(value: &Mmr) -> Self {
let mut store = MerkleStore::new();
store.extend(value.inner_nodes());
store
}
}
impl From<&TieredSmt> for MerkleStore {
fn from(value: &TieredSmt) -> Self {
let mut store = MerkleStore::new();
store.extend(value.inner_nodes());
store
}
}
impl FromIterator<InnerNodeInfo> for MerkleStore {
fn from_iter<T: IntoIterator<Item = InnerNodeInfo>>(iter: T) -> Self {
let mut store = MerkleStore::new();
store.extend(iter.into_iter());
store
}
}
// ITERATORS
// ================================================================================================
impl Extend<InnerNodeInfo> for MerkleStore {
fn extend<T: IntoIterator<Item = InnerNodeInfo>>(&mut self, iter: T) {
self.extend(iter.into_iter());
}
}
// SERIALIZATION // SERIALIZATION
// ================================================================================================ // ================================================================================================

View File

@@ -1,34 +1,48 @@
use super::*; use super::{
super::EMPTY_WORD, Deserializable, EmptySubtreeRoots, MerkleError, MerklePath, MerkleStore,
NodeIndex, RpoDigest, Serializable,
};
use crate::{ use crate::{
hash::rpo::Rpo256, hash::rpo::Rpo256,
merkle::{int_to_node, MerklePathSet}, merkle::{int_to_node, MerklePathSet, MerkleTree, SimpleSmt},
Felt, Word, WORD_SIZE, ZERO, Felt, Word, WORD_SIZE,
}; };
#[cfg(std)] #[cfg(feature = "std")]
use std::error::Error; use std::error::Error;
// TEST DATA
// ================================================================================================
const KEYS4: [u64; 4] = [0, 1, 2, 3]; const KEYS4: [u64; 4] = [0, 1, 2, 3];
const LEAVES4: [Word; 4] = [ const VALUES4: [Word; 4] = [int_to_node(1), int_to_node(2), int_to_node(3), int_to_node(4)];
const VALUES8: [Word; 8] = [
int_to_node(1), int_to_node(1),
int_to_node(2), int_to_node(2),
int_to_node(3), int_to_node(3),
int_to_node(4), int_to_node(4),
int_to_node(5),
int_to_node(6),
int_to_node(7),
int_to_node(8),
]; ];
const EMPTY: Word = [ZERO; WORD_SIZE];
// TESTS
// ================================================================================================
#[test] #[test]
fn test_root_not_in_store() -> Result<(), MerkleError> { fn test_root_not_in_store() -> Result<(), MerkleError> {
let mtree = MerkleTree::new(LEAVES4.to_vec())?; let mtree = MerkleTree::new(VALUES4.to_vec())?;
let store = MerkleStore::default().with_merkle_tree(LEAVES4)?; let store = MerkleStore::from(&mtree);
assert_eq!( assert_eq!(
store.get_node(LEAVES4[0], NodeIndex::make(mtree.depth(), 0)), store.get_node(VALUES4[0], NodeIndex::make(mtree.depth(), 0)),
Err(MerkleError::RootNotInStore(LEAVES4[0])), Err(MerkleError::RootNotInStore(VALUES4[0])),
"Leaf 0 is not a root" "Leaf 0 is not a root"
); );
assert_eq!( assert_eq!(
store.get_path(LEAVES4[0], NodeIndex::make(mtree.depth(), 0)), store.get_path(VALUES4[0], NodeIndex::make(mtree.depth(), 0)),
Err(MerkleError::RootNotInStore(LEAVES4[0])), Err(MerkleError::RootNotInStore(VALUES4[0])),
"Leaf 0 is not a root" "Leaf 0 is not a root"
); );
@@ -37,35 +51,33 @@ fn test_root_not_in_store() -> Result<(), MerkleError> {
#[test] #[test]
fn test_merkle_tree() -> Result<(), MerkleError> { fn test_merkle_tree() -> Result<(), MerkleError> {
let mut store = MerkleStore::default(); let mtree = MerkleTree::new(VALUES4.to_vec())?;
let store = MerkleStore::from(&mtree);
let mtree = MerkleTree::new(LEAVES4.to_vec())?; // STORE LEAVES ARE CORRECT -------------------------------------------------------------------
store.add_merkle_tree(LEAVES4.to_vec())?;
// STORE LEAVES ARE CORRECT ==============================================================
// checks the leaves in the store corresponds to the expected values // checks the leaves in the store corresponds to the expected values
assert_eq!( assert_eq!(
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 0)), store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 0)),
Ok(LEAVES4[0]), Ok(VALUES4[0]),
"node 0 must be in the tree" "node 0 must be in the tree"
); );
assert_eq!( assert_eq!(
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 1)), store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 1)),
Ok(LEAVES4[1]), Ok(VALUES4[1]),
"node 1 must be in the tree" "node 1 must be in the tree"
); );
assert_eq!( assert_eq!(
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 2)), store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 2)),
Ok(LEAVES4[2]), Ok(VALUES4[2]),
"node 2 must be in the tree" "node 2 must be in the tree"
); );
assert_eq!( assert_eq!(
store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 3)), store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 3)),
Ok(LEAVES4[3]), Ok(VALUES4[3]),
"node 3 must be in the tree" "node 3 must be in the tree"
); );
// STORE LEAVES MATCH TREE =============================================================== // STORE LEAVES MATCH TREE --------------------------------------------------------------------
// sanity check the values returned by the store and the tree // sanity check the values returned by the store and the tree
assert_eq!( assert_eq!(
mtree.get_node(NodeIndex::make(mtree.depth(), 0)), mtree.get_node(NodeIndex::make(mtree.depth(), 0)),
@@ -90,11 +102,9 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
// STORE MERKLE PATH MATCHS ============================================================== // STORE MERKLE PATH MATCHS ==============================================================
// assert the merkle path returned by the store is the same as the one in the tree // assert the merkle path returned by the store is the same as the one in the tree
let result = store let result = store.get_path(mtree.root(), NodeIndex::make(mtree.depth(), 0)).unwrap();
.get_path(mtree.root(), NodeIndex::make(mtree.depth(), 0))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[0], result.value, VALUES4[0], result.value,
"Value for merkle path at index 0 must match leaf value" "Value for merkle path at index 0 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -103,11 +113,9 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore" "merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(mtree.root(), NodeIndex::make(mtree.depth(), 1)).unwrap();
.get_path(mtree.root(), NodeIndex::make(mtree.depth(), 1))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[1], result.value, VALUES4[1], result.value,
"Value for merkle path at index 0 must match leaf value" "Value for merkle path at index 0 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -116,11 +124,9 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore" "merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(mtree.root(), NodeIndex::make(mtree.depth(), 2)).unwrap();
.get_path(mtree.root(), NodeIndex::make(mtree.depth(), 2))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[2], result.value, VALUES4[2], result.value,
"Value for merkle path at index 0 must match leaf value" "Value for merkle path at index 0 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -129,11 +135,9 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore" "merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(mtree.root(), NodeIndex::make(mtree.depth(), 3)).unwrap();
.get_path(mtree.root(), NodeIndex::make(mtree.depth(), 3))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[3], result.value, VALUES4[3], result.value,
"Value for merkle path at index 0 must match leaf value" "Value for merkle path at index 0 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -148,7 +152,7 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
#[test] #[test]
fn test_empty_roots() { fn test_empty_roots() {
let store = MerkleStore::default(); let store = MerkleStore::default();
let mut root = RpoDigest::new(EMPTY); let mut root = RpoDigest::new(EMPTY_WORD);
for depth in 0..255 { for depth in 0..255 {
root = Rpo256::merge(&[root; 2]); root = Rpo256::merge(&[root; 2]);
@@ -172,16 +176,13 @@ fn test_leaf_paths_for_empty_trees() -> Result<(), MerkleError> {
let index = NodeIndex::make(depth, 0); let index = NodeIndex::make(depth, 0);
let store_path = store.get_path(smt.root(), index)?; let store_path = store.get_path(smt.root(), index)?;
let smt_path = smt.get_path(index)?; let smt_path = smt.get_path(index)?;
assert_eq!( assert_eq!(store_path.value, EMPTY_WORD, "the leaf of an empty tree is always ZERO");
store_path.value, EMPTY,
"the leaf of an empty tree is always ZERO"
);
assert_eq!( assert_eq!(
store_path.path, smt_path, store_path.path, smt_path,
"the returned merkle path does not match the computed values" "the returned merkle path does not match the computed values"
); );
assert_eq!( assert_eq!(
store_path.path.compute_root(depth.into(), EMPTY).unwrap(), store_path.path.compute_root(depth.into(), EMPTY_WORD).unwrap(),
smt.root(), smt.root(),
"computed root from the path must match the empty tree root" "computed root from the path must match the empty tree root"
); );
@@ -192,80 +193,62 @@ fn test_leaf_paths_for_empty_trees() -> Result<(), MerkleError> {
#[test] #[test]
fn test_get_invalid_node() { fn test_get_invalid_node() {
let mut store = MerkleStore::default(); let mtree = MerkleTree::new(VALUES4.to_vec()).expect("creating a merkle tree must work");
let mtree = MerkleTree::new(LEAVES4.to_vec()).expect("creating a merkle tree must work"); let store = MerkleStore::from(&mtree);
store
.add_merkle_tree(LEAVES4.to_vec())
.expect("adding a merkle tree to the store must work");
let _ = store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 3)); let _ = store.get_node(mtree.root(), NodeIndex::make(mtree.depth(), 3));
} }
#[test] #[test]
fn test_add_sparse_merkle_tree_one_level() -> Result<(), MerkleError> { fn test_add_sparse_merkle_tree_one_level() -> Result<(), MerkleError> {
let mut store = MerkleStore::default();
let keys2: [u64; 2] = [0, 1]; let keys2: [u64; 2] = [0, 1];
let leaves2: [Word; 2] = [int_to_node(1), int_to_node(2)]; let leaves2: [Word; 2] = [int_to_node(1), int_to_node(2)];
store.add_sparse_merkle_tree(48, keys2.into_iter().zip(leaves2.into_iter()))?; let smt = SimpleSmt::with_leaves(1, keys2.into_iter().zip(leaves2.into_iter())).unwrap();
let smt = SimpleSmt::new(1) let store = MerkleStore::from(&smt);
.unwrap()
.with_leaves(keys2.into_iter().zip(leaves2.into_iter()))
.unwrap();
let idx = NodeIndex::make(1, 0); let idx = NodeIndex::make(1, 0);
assert_eq!(smt.get_node(idx).unwrap(), leaves2[0]); assert_eq!(smt.get_node(idx).unwrap(), leaves2[0]);
assert_eq!( assert_eq!(store.get_node(smt.root(), idx).unwrap(), smt.get_node(idx).unwrap());
store.get_node(smt.root(), idx).unwrap(),
smt.get_node(idx).unwrap()
);
let idx = NodeIndex::make(1, 1); let idx = NodeIndex::make(1, 1);
assert_eq!(smt.get_node(idx).unwrap(), leaves2[1]); assert_eq!(smt.get_node(idx).unwrap(), leaves2[1]);
assert_eq!( assert_eq!(store.get_node(smt.root(), idx).unwrap(), smt.get_node(idx).unwrap());
store.get_node(smt.root(), idx).unwrap(),
smt.get_node(idx).unwrap()
);
Ok(()) Ok(())
} }
#[test] #[test]
fn test_sparse_merkle_tree() -> Result<(), MerkleError> { fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
let mut store = MerkleStore::default(); let smt =
store.add_sparse_merkle_tree( SimpleSmt::with_leaves(SimpleSmt::MAX_DEPTH, KEYS4.into_iter().zip(VALUES4.into_iter()))
SimpleSmt::MAX_DEPTH, .unwrap();
KEYS4.into_iter().zip(LEAVES4.into_iter()),
)?;
let smt = SimpleSmt::new(SimpleSmt::MAX_DEPTH) let store = MerkleStore::from(&smt);
.unwrap()
.with_leaves(KEYS4.into_iter().zip(LEAVES4.into_iter()))
.unwrap();
// STORE LEAVES ARE CORRECT ============================================================== // STORE LEAVES ARE CORRECT ==============================================================
// checks the leaves in the store corresponds to the expected values // checks the leaves in the store corresponds to the expected values
assert_eq!( assert_eq!(
store.get_node(smt.root(), NodeIndex::make(smt.depth(), 0)), store.get_node(smt.root(), NodeIndex::make(smt.depth(), 0)),
Ok(LEAVES4[0]), Ok(VALUES4[0]),
"node 0 must be in the tree" "node 0 must be in the tree"
); );
assert_eq!( assert_eq!(
store.get_node(smt.root(), NodeIndex::make(smt.depth(), 1)), store.get_node(smt.root(), NodeIndex::make(smt.depth(), 1)),
Ok(LEAVES4[1]), Ok(VALUES4[1]),
"node 1 must be in the tree" "node 1 must be in the tree"
); );
assert_eq!( assert_eq!(
store.get_node(smt.root(), NodeIndex::make(smt.depth(), 2)), store.get_node(smt.root(), NodeIndex::make(smt.depth(), 2)),
Ok(LEAVES4[2]), Ok(VALUES4[2]),
"node 2 must be in the tree" "node 2 must be in the tree"
); );
assert_eq!( assert_eq!(
store.get_node(smt.root(), NodeIndex::make(smt.depth(), 3)), store.get_node(smt.root(), NodeIndex::make(smt.depth(), 3)),
Ok(LEAVES4[3]), Ok(VALUES4[3]),
"node 3 must be in the tree" "node 3 must be in the tree"
); );
assert_eq!( assert_eq!(
store.get_node(smt.root(), NodeIndex::make(smt.depth(), 4)), store.get_node(smt.root(), NodeIndex::make(smt.depth(), 4)),
Ok(EMPTY), Ok(EMPTY_WORD),
"unmodified node 4 must be ZERO" "unmodified node 4 must be ZERO"
); );
@@ -299,11 +282,9 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
// STORE MERKLE PATH MATCHS ============================================================== // STORE MERKLE PATH MATCHS ==============================================================
// assert the merkle path returned by the store is the same as the one in the tree // assert the merkle path returned by the store is the same as the one in the tree
let result = store let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 0)).unwrap();
.get_path(smt.root(), NodeIndex::make(smt.depth(), 0))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[0], result.value, VALUES4[0], result.value,
"Value for merkle path at index 0 must match leaf value" "Value for merkle path at index 0 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -312,11 +293,9 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore" "merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 1)).unwrap();
.get_path(smt.root(), NodeIndex::make(smt.depth(), 1))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[1], result.value, VALUES4[1], result.value,
"Value for merkle path at index 1 must match leaf value" "Value for merkle path at index 1 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -325,11 +304,9 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore" "merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 2)).unwrap();
.get_path(smt.root(), NodeIndex::make(smt.depth(), 2))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[2], result.value, VALUES4[2], result.value,
"Value for merkle path at index 2 must match leaf value" "Value for merkle path at index 2 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -338,11 +315,9 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
"merkle path for index 2 must be the same for the MerkleTree and MerkleStore" "merkle path for index 2 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 3)).unwrap();
.get_path(smt.root(), NodeIndex::make(smt.depth(), 3))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[3], result.value, VALUES4[3], result.value,
"Value for merkle path at index 3 must match leaf value" "Value for merkle path at index 3 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -351,11 +326,9 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
"merkle path for index 3 must be the same for the MerkleTree and MerkleStore" "merkle path for index 3 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(smt.root(), NodeIndex::make(smt.depth(), 4)).unwrap();
.get_path(smt.root(), NodeIndex::make(smt.depth(), 4))
.unwrap();
assert_eq!( assert_eq!(
EMPTY, result.value, EMPTY_WORD, result.value,
"Value for merkle path at index 4 must match leaf value" "Value for merkle path at index 4 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -369,7 +342,7 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
#[test] #[test]
fn test_add_merkle_paths() -> Result<(), MerkleError> { fn test_add_merkle_paths() -> Result<(), MerkleError> {
let mtree = MerkleTree::new(LEAVES4.to_vec())?; let mtree = MerkleTree::new(VALUES4.to_vec())?;
let i0 = 0; let i0 = 0;
let p0 = mtree.get_path(NodeIndex::make(2, i0)).unwrap(); let p0 = mtree.get_path(NodeIndex::make(2, i0)).unwrap();
@@ -384,16 +357,14 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
let p3 = mtree.get_path(NodeIndex::make(2, i3)).unwrap(); let p3 = mtree.get_path(NodeIndex::make(2, i3)).unwrap();
let paths = [ let paths = [
(i0, LEAVES4[i0 as usize], p0), (i0, VALUES4[i0 as usize], p0),
(i1, LEAVES4[i1 as usize], p1), (i1, VALUES4[i1 as usize], p1),
(i2, LEAVES4[i2 as usize], p2), (i2, VALUES4[i2 as usize], p2),
(i3, LEAVES4[i3 as usize], p3), (i3, VALUES4[i3 as usize], p3),
]; ];
let mut store = MerkleStore::default(); let mut store = MerkleStore::default();
store store.add_merkle_paths(paths.clone()).expect("the valid paths must work");
.add_merkle_paths(paths.clone())
.expect("the valid paths must work");
let depth = 2; let depth = 2;
let set = MerklePathSet::new(depth).with_paths(paths).unwrap(); let set = MerklePathSet::new(depth).with_paths(paths).unwrap();
@@ -402,22 +373,22 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
// checks the leaves in the store corresponds to the expected values // checks the leaves in the store corresponds to the expected values
assert_eq!( assert_eq!(
store.get_node(set.root(), NodeIndex::make(set.depth(), 0)), store.get_node(set.root(), NodeIndex::make(set.depth(), 0)),
Ok(LEAVES4[0]), Ok(VALUES4[0]),
"node 0 must be in the set" "node 0 must be in the set"
); );
assert_eq!( assert_eq!(
store.get_node(set.root(), NodeIndex::make(set.depth(), 1)), store.get_node(set.root(), NodeIndex::make(set.depth(), 1)),
Ok(LEAVES4[1]), Ok(VALUES4[1]),
"node 1 must be in the set" "node 1 must be in the set"
); );
assert_eq!( assert_eq!(
store.get_node(set.root(), NodeIndex::make(set.depth(), 2)), store.get_node(set.root(), NodeIndex::make(set.depth(), 2)),
Ok(LEAVES4[2]), Ok(VALUES4[2]),
"node 2 must be in the set" "node 2 must be in the set"
); );
assert_eq!( assert_eq!(
store.get_node(set.root(), NodeIndex::make(set.depth(), 3)), store.get_node(set.root(), NodeIndex::make(set.depth(), 3)),
Ok(LEAVES4[3]), Ok(VALUES4[3]),
"node 3 must be in the set" "node 3 must be in the set"
); );
@@ -446,11 +417,9 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
// STORE MERKLE PATH MATCHS ============================================================== // STORE MERKLE PATH MATCHS ==============================================================
// assert the merkle path returned by the store is the same as the one in the set // assert the merkle path returned by the store is the same as the one in the set
let result = store let result = store.get_path(set.root(), NodeIndex::make(set.depth(), 0)).unwrap();
.get_path(set.root(), NodeIndex::make(set.depth(), 0))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[0], result.value, VALUES4[0], result.value,
"Value for merkle path at index 0 must match leaf value" "Value for merkle path at index 0 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -459,11 +428,9 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore" "merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(set.root(), NodeIndex::make(set.depth(), 1)).unwrap();
.get_path(set.root(), NodeIndex::make(set.depth(), 1))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[1], result.value, VALUES4[1], result.value,
"Value for merkle path at index 0 must match leaf value" "Value for merkle path at index 0 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -472,11 +439,9 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore" "merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(set.root(), NodeIndex::make(set.depth(), 2)).unwrap();
.get_path(set.root(), NodeIndex::make(set.depth(), 2))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[2], result.value, VALUES4[2], result.value,
"Value for merkle path at index 0 must match leaf value" "Value for merkle path at index 0 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -485,11 +450,9 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore" "merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
); );
let result = store let result = store.get_path(set.root(), NodeIndex::make(set.depth(), 3)).unwrap();
.get_path(set.root(), NodeIndex::make(set.depth(), 3))
.unwrap();
assert_eq!( assert_eq!(
LEAVES4[3], result.value, VALUES4[3], result.value,
"Value for merkle path at index 0 must match leaf value" "Value for merkle path at index 0 must match leaf value"
); );
assert_eq!( assert_eq!(
@@ -519,7 +482,8 @@ fn wont_open_to_different_depth_root() {
// For this example, the depth of the Merkle tree is 1, as we have only two leaves. Here we // For this example, the depth of the Merkle tree is 1, as we have only two leaves. Here we
// attempt to fetch a node on the maximum depth, and it should fail because the root shouldn't // attempt to fetch a node on the maximum depth, and it should fail because the root shouldn't
// exist for the set. // exist for the set.
let store = MerkleStore::default().with_merkle_tree([a, b]).unwrap(); let mtree = MerkleTree::new(vec![a, b]).unwrap();
let store = MerkleStore::from(&mtree);
let index = NodeIndex::root(); let index = NodeIndex::root();
let err = store.get_node(root, index).err().unwrap(); let err = store.get_node(root, index).err().unwrap();
assert_eq!(err, MerkleError::RootNotInStore(root)); assert_eq!(err, MerkleError::RootNotInStore(root));
@@ -546,13 +510,9 @@ fn store_path_opens_from_leaf() {
let root = Rpo256::merge(&[m.into(), n.into()]); let root = Rpo256::merge(&[m.into(), n.into()]);
let store = MerkleStore::default() let mtree = MerkleTree::new(vec![a, b, c, d, e, f, g, h]).unwrap();
.with_merkle_tree([a, b, c, d, e, f, g, h]) let store = MerkleStore::from(&mtree);
.unwrap(); let path = store.get_path(root.into(), NodeIndex::make(3, 1)).unwrap().path;
let path = store
.get_path(root.into(), NodeIndex::make(3, 1))
.unwrap()
.path;
let expected = MerklePath::new([a.into(), j.into(), n.into()].to_vec()); let expected = MerklePath::new([a.into(), j.into(), n.into()].to_vec());
assert_eq!(path, expected); assert_eq!(path, expected);
@@ -560,24 +520,20 @@ fn store_path_opens_from_leaf() {
#[test] #[test]
fn test_set_node() -> Result<(), MerkleError> { fn test_set_node() -> Result<(), MerkleError> {
let mtree = MerkleTree::new(LEAVES4.to_vec())?; let mtree = MerkleTree::new(VALUES4.to_vec())?;
let mut store = MerkleStore::default().with_merkle_tree(LEAVES4)?; let mut store = MerkleStore::from(&mtree);
let value = int_to_node(42); let value = int_to_node(42);
let index = NodeIndex::make(mtree.depth(), 0); let index = NodeIndex::make(mtree.depth(), 0);
let new_root = store.set_node(mtree.root(), index, value)?.root; let new_root = store.set_node(mtree.root(), index, value)?.root;
assert_eq!( assert_eq!(store.get_node(new_root, index), Ok(value), "Value must have changed");
store.get_node(new_root, index),
Ok(value),
"Value must have changed"
);
Ok(()) Ok(())
} }
#[test] #[test]
fn test_constructors() -> Result<(), MerkleError> { fn test_constructors() -> Result<(), MerkleError> {
let store = MerkleStore::new().with_merkle_tree(LEAVES4)?; let mtree = MerkleTree::new(VALUES4.to_vec())?;
let mtree = MerkleTree::new(LEAVES4.to_vec())?; let store = MerkleStore::from(&mtree);
let depth = mtree.depth(); let depth = mtree.depth();
let leaves = 2u64.pow(depth.into()); let leaves = 2u64.pow(depth.into());
@@ -588,12 +544,8 @@ fn test_constructors() -> Result<(), MerkleError> {
} }
let depth = 32; let depth = 32;
let store = MerkleStore::default() let smt = SimpleSmt::with_leaves(depth, KEYS4.into_iter().zip(VALUES4.into_iter())).unwrap();
.with_sparse_merkle_tree(depth, KEYS4.into_iter().zip(LEAVES4.into_iter()))?; let store = MerkleStore::from(&smt);
let smt = SimpleSmt::new(depth)
.unwrap()
.with_leaves(KEYS4.into_iter().zip(LEAVES4.into_iter()))
.unwrap();
let depth = smt.depth(); let depth = smt.depth();
for key in KEYS4 { for key in KEYS4 {
@@ -604,34 +556,20 @@ fn test_constructors() -> Result<(), MerkleError> {
let d = 2; let d = 2;
let paths = [ let paths = [
( (0, VALUES4[0], mtree.get_path(NodeIndex::make(d, 0)).unwrap()),
0, (1, VALUES4[1], mtree.get_path(NodeIndex::make(d, 1)).unwrap()),
LEAVES4[0], (2, VALUES4[2], mtree.get_path(NodeIndex::make(d, 2)).unwrap()),
mtree.get_path(NodeIndex::make(d, 0)).unwrap(), (3, VALUES4[3], mtree.get_path(NodeIndex::make(d, 3)).unwrap()),
),
(
1,
LEAVES4[1],
mtree.get_path(NodeIndex::make(d, 1)).unwrap(),
),
(
2,
LEAVES4[2],
mtree.get_path(NodeIndex::make(d, 2)).unwrap(),
),
(
3,
LEAVES4[3],
mtree.get_path(NodeIndex::make(d, 3)).unwrap(),
),
]; ];
let store1 = MerkleStore::default().with_merkle_paths(paths.clone())?; let mut store1 = MerkleStore::default();
let store2 = MerkleStore::default() store1.add_merkle_paths(paths.clone())?;
.with_merkle_path(0, LEAVES4[0], mtree.get_path(NodeIndex::make(d, 0))?)?
.with_merkle_path(1, LEAVES4[1], mtree.get_path(NodeIndex::make(d, 1))?)? let mut store2 = MerkleStore::default();
.with_merkle_path(2, LEAVES4[2], mtree.get_path(NodeIndex::make(d, 2))?)? store2.add_merkle_path(0, VALUES4[0], mtree.get_path(NodeIndex::make(d, 0))?)?;
.with_merkle_path(3, LEAVES4[3], mtree.get_path(NodeIndex::make(d, 3))?)?; store2.add_merkle_path(1, VALUES4[1], mtree.get_path(NodeIndex::make(d, 1))?)?;
store2.add_merkle_path(2, VALUES4[2], mtree.get_path(NodeIndex::make(d, 2))?)?;
store2.add_merkle_path(3, VALUES4[3], mtree.get_path(NodeIndex::make(d, 3))?)?;
let set = MerklePathSet::new(d).with_paths(paths).unwrap(); let set = MerklePathSet::new(d).with_paths(paths).unwrap();
for key in [0, 1, 2, 3] { for key in [0, 1, 2, 3] {
@@ -792,17 +730,72 @@ fn get_leaf_depth_works_with_depth_8() {
// duplicate the tree on `a` and assert the depth is short-circuited by such sub-tree // duplicate the tree on `a` and assert the depth is short-circuited by such sub-tree
let index = NodeIndex::new(8, a).unwrap(); let index = NodeIndex::new(8, a).unwrap();
root = store.set_node(root, index, root).unwrap().root; root = store.set_node(root, index, root).unwrap().root;
assert_eq!( assert_eq!(Err(MerkleError::DepthTooBig(9)), store.get_leaf_depth(root, 8, a));
Err(MerkleError::DepthTooBig(9)),
store.get_leaf_depth(root, 8, a)
);
} }
#[cfg(std)] // SUBSET EXTRACTION
// ================================================================================================
#[test]
fn mstore_subset() {
// add a Merkle tree of depth 3 to the store
let mtree = MerkleTree::new(VALUES8.to_vec()).unwrap();
let mut store = MerkleStore::default();
let empty_store_num_nodes = store.nodes.len();
store.extend(mtree.inner_nodes());
// build 3 subtrees contained within the above Merkle tree; note that subtree2 is a subset
// of subtree1
let subtree1 = MerkleTree::new(VALUES8[..4].to_vec()).unwrap();
let subtree2 = MerkleTree::new(VALUES8[2..4].to_vec()).unwrap();
let subtree3 = MerkleTree::new(VALUES8[6..].to_vec()).unwrap();
// --- extract all 3 subtrees ---------------------------------------------
let substore = store.subset([subtree1.root(), subtree2.root(), subtree3.root()].iter());
// number of nodes should increase by 4: 3 nodes form subtree1 and 1 node from subtree3
assert_eq!(substore.nodes.len(), empty_store_num_nodes + 4);
// make sure paths that all subtrees are in the store
check_mstore_subtree(&substore, &subtree1);
check_mstore_subtree(&substore, &subtree2);
check_mstore_subtree(&substore, &subtree3);
// --- extract subtrees 1 and 3 -------------------------------------------
// this should give the same result as above as subtree2 is nested withing subtree1
let substore = store.subset([subtree1.root(), subtree3.root()].iter());
// number of nodes should increase by 4: 3 nodes form subtree1 and 1 node from subtree3
assert_eq!(substore.nodes.len(), empty_store_num_nodes + 4);
// make sure paths that all subtrees are in the store
check_mstore_subtree(&substore, &subtree1);
check_mstore_subtree(&substore, &subtree2);
check_mstore_subtree(&substore, &subtree3);
}
fn check_mstore_subtree(store: &MerkleStore, subtree: &MerkleTree) {
for (i, value) in subtree.leaves() {
let index = NodeIndex::new(subtree.depth(), i).unwrap();
let path1 = store.get_path(subtree.root(), index).unwrap();
assert_eq!(&path1.value, value);
let path2 = subtree.get_path(index).unwrap();
assert_eq!(path1.path, path2);
}
}
// SERIALIZATION
// ================================================================================================
#[cfg(feature = "std")]
#[test] #[test]
fn test_serialization() -> Result<(), Box<dyn Error>> { fn test_serialization() -> Result<(), Box<dyn Error>> {
let original = MerkleStore::new().with_merkle_tree(LEAVES4)?; let mtree = MerkleTree::new(VALUES4.to_vec())?;
let decoded = MerkleStore::read_from_bytes(&original.to_bytes())?; let store = MerkleStore::from(&mtree);
assert_eq!(original, decoded); let decoded = MerkleStore::read_from_bytes(&store.to_bytes()).expect("deserialization failed");
assert_eq!(store, decoded);
Ok(()) Ok(())
} }

View File

@@ -0,0 +1,482 @@
use super::{
BTreeMap, BTreeSet, EmptySubtreeRoots, Felt, InnerNodeInfo, MerkleError, MerklePath, NodeIndex,
Rpo256, RpoDigest, StarkField, Vec, Word, EMPTY_WORD, ZERO,
};
use core::cmp;
#[cfg(test)]
mod tests;
// TIERED SPARSE MERKLE TREE
// ================================================================================================
/// Tiered (compacted) Sparse Merkle tree mapping 256-bit keys to 256-bit values. Both keys and
/// values are represented by 4 field elements.
///
/// Leaves in the tree can exist only on specific depths called "tiers". These depths are: 16, 32,
/// 48, and 64. Initially, when a tree is empty, it is equivalent to an empty Sparse Merkle tree
/// of depth 64 (i.e., leaves at depth 64 are set to [ZERO; 4]). As non-empty values are inserted
/// into the tree they are added to the first available tier.
///
/// For example, when the first key-value is inserted, it will be stored in a node at depth 16
/// such that the first 16 bits of the key determine the position of the node at depth 16. If
/// another value with a key sharing the same 16-bit prefix is inserted, both values move into
/// the next tier (depth 32). This process is repeated until values end up at tier 64. If multiple
/// values have keys with a common 64-bit prefix, such key-value pairs are stored in a sorted list
/// at the last tier (depth = 64).
///
/// To differentiate between internal and leaf nodes, node values are computed as follows:
/// - Internal nodes: hash(left_child, right_child).
/// - Leaf node at depths 16, 32, or 64: hash(rem_key, value, domain=depth).
/// - Leaf node at depth 64: hash([rem_key_0, value_0, ..., rem_key_n, value_n, domain=64]).
///
/// Where rem_key is computed by replacing d most significant bits of the key with zeros where d
/// is depth (i.e., for a leaf at depth 16, we replace 16 most significant bits of the key with 0).
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TieredSmt {
root: RpoDigest,
nodes: BTreeMap<NodeIndex, RpoDigest>,
upper_leaves: BTreeMap<NodeIndex, RpoDigest>, // node_index |-> key map
bottom_leaves: BTreeMap<u64, BottomLeaf>, // leaves of depth 64
values: BTreeMap<RpoDigest, Word>,
}
impl TieredSmt {
// CONSTANTS
// --------------------------------------------------------------------------------------------
/// The number of levels between tiers.
const TIER_SIZE: u8 = 16;
/// Depths at which leaves can exist in a tiered SMT.
const TIER_DEPTHS: [u8; 4] = [16, 32, 48, 64];
/// Maximum node depth. This is also the bottom tier of the tree.
const MAX_DEPTH: u8 = 64;
// CONSTRUCTORS
// --------------------------------------------------------------------------------------------
/// Returns a new [TieredSmt] instantiated with the specified key-value pairs.
///
/// # Errors
/// Returns an error if the provided entries contain multiple values for the same key.
pub fn with_leaves<R, I>(entries: R) -> Result<Self, MerkleError>
where
R: IntoIterator<IntoIter = I>,
I: Iterator<Item = (RpoDigest, Word)> + ExactSizeIterator,
{
// create an empty tree
let mut tree = Self::default();
// append leaves to the tree returning an error if a duplicate entry for the same key
// is found
let mut empty_entries = BTreeSet::new();
for (key, value) in entries {
let old_value = tree.insert(key, value);
if old_value != EMPTY_WORD || empty_entries.contains(&key) {
return Err(MerkleError::DuplicateValuesForKey(key));
}
// if we've processed an empty entry, add the key to the set of empty entry keys, and
// if this key was already in the set, return an error
if value == EMPTY_WORD && !empty_entries.insert(key) {
return Err(MerkleError::DuplicateValuesForKey(key));
}
}
Ok(tree)
}
// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------
/// Returns the root of this Merkle tree.
pub const fn root(&self) -> RpoDigest {
self.root
}
/// Returns a node at the specified index.
///
/// # Errors
/// Returns an error if:
/// - The specified index depth is 0 or greater than 64.
/// - The node with the specified index does not exists in the Merkle tree. This is possible
/// when a leaf node with the same index prefix exists at a tier higher than the requested
/// node.
pub fn get_node(&self, index: NodeIndex) -> Result<RpoDigest, MerkleError> {
self.validate_node_access(index)?;
Ok(self.get_node_unchecked(&index))
}
/// 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 depth is 0 or greater than 64.
/// - The node with the specified index does not exists in the Merkle tree. This is possible
/// when a leaf node with the same index prefix exists at a tier higher than the node to
/// which the path is requested.
pub fn get_path(&self, mut index: NodeIndex) -> Result<MerklePath, MerkleError> {
self.validate_node_access(index)?;
let mut path = Vec::with_capacity(index.depth() as usize);
for _ in 0..index.depth() {
let node = self.get_node_unchecked(&index.sibling());
path.push(node.into());
index.move_up();
}
Ok(path.into())
}
/// Returns the value associated with the specified key.
///
/// If nothing was inserted into this tree for the specified key, [ZERO; 4] is returned.
pub fn get_value(&self, key: RpoDigest) -> Word {
match self.values.get(&key) {
Some(value) => *value,
None => EMPTY_WORD,
}
}
// STATE MUTATORS
// --------------------------------------------------------------------------------------------
/// Inserts the provided value into the tree under the specified key and returns the value
/// previously stored under this key.
///
/// If the value for the specified key was not previously set, [ZERO; 4] is returned.
pub fn insert(&mut self, key: RpoDigest, value: Word) -> Word {
// insert the value into the key-value map, and if nothing has changed, return
let old_value = self.values.insert(key, value).unwrap_or(EMPTY_WORD);
if old_value == value {
return old_value;
}
// determine the index for the value node; this index could have 3 different meanings:
// - it points to a root of an empty subtree (excluding depth = 64); in this case, we can
// replace the node with the value node immediately.
// - it points to a node at the bottom tier (i.e., depth = 64); in this case, we need to
// process bottom-tier insertion which will be handled by insert_node().
// - it points to a leaf node; this node could be a node with the same key or a different
// key with a common prefix; in the latter case, we'll need to move the leaf to a lower
// tier; for this scenario the `leaf_key` will contain the key of the leaf node
let (mut index, leaf_key) = self.get_insert_location(&key);
// if the returned index points to a leaf, and this leaf is for a different key, we need
// to move the leaf to a lower tier
if let Some(other_key) = leaf_key {
if other_key != key {
// determine how far down the tree should we move the existing leaf
let common_prefix_len = get_common_prefix_tier(&key, &other_key);
let depth = cmp::min(common_prefix_len + Self::TIER_SIZE, Self::MAX_DEPTH);
// move the leaf to the new location; this requires first removing the existing
// index, re-computing node value, and inserting the node at a new location
let other_index = key_to_index(&other_key, depth);
let other_value = *self.values.get(&other_key).expect("no value for other key");
self.upper_leaves.remove(&index).expect("other node key not in map");
self.insert_node(other_index, other_key, other_value);
// the new leaf also needs to move down to the same tier
index = key_to_index(&key, depth);
}
}
// insert the node and return the old value
self.insert_node(index, key, value);
old_value
}
// ITERATORS
// --------------------------------------------------------------------------------------------
/// Returns an iterator over all inner nodes of this [TieredSmt] (i.e., nodes not at depths 16
/// 32, 48, or 64).
///
/// The iterator order is unspecified.
pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
self.nodes.iter().filter_map(|(index, node)| {
if is_inner_node(index) {
Some(InnerNodeInfo {
value: node.into(),
left: self.get_node_unchecked(&index.left_child()).into(),
right: self.get_node_unchecked(&index.right_child()).into(),
})
} else {
None
}
})
}
/// Returns an iterator over upper leaves (i.e., depth = 16, 32, or 48) for this [TieredSmt].
///
/// Each yielded item is a (node, key, value) tuple where key is a full un-truncated key (i.e.,
/// with key[3] element unmodified).
///
/// The iterator order is unspecified.
pub fn upper_leaves(&self) -> impl Iterator<Item = (RpoDigest, RpoDigest, Word)> + '_ {
self.upper_leaves.iter().map(|(index, key)| {
let node = self.get_node_unchecked(index);
let value = self.get_value(*key);
(node, *key, value)
})
}
/// Returns an iterator over bottom leaves (i.e., depth = 64) of this [TieredSmt].
///
/// Each yielded item consists of the hash of the leaf and its contents, where contents is
/// a vector containing key-value pairs of entries storied in this leaf. Note that keys are
/// un-truncated keys (i.e., with key[3] element unmodified).
///
/// The iterator order is unspecified.
pub fn bottom_leaves(&self) -> impl Iterator<Item = (RpoDigest, Vec<(RpoDigest, Word)>)> + '_ {
self.bottom_leaves.values().map(|leaf| (leaf.hash(), leaf.contents()))
}
// HELPER METHODS
// --------------------------------------------------------------------------------------------
/// Checks if the specified index is valid in the context of this Merkle tree.
///
/// # Errors
/// Returns an error if:
/// - The specified index depth is 0 or greater than 64.
/// - The node for the specified index does not exists in the Merkle tree. This is possible
/// when an ancestors of the specified index is a leaf node.
fn validate_node_access(&self, index: NodeIndex) -> Result<(), MerkleError> {
if index.is_root() {
return Err(MerkleError::DepthTooSmall(index.depth()));
} else if index.depth() > Self::MAX_DEPTH {
return Err(MerkleError::DepthTooBig(index.depth() as u64));
} else {
// make sure that there are no leaf nodes in the ancestors of the index; since leaf
// nodes can live at specific depth, we just need to check these depths.
let tier = get_index_tier(&index);
let mut tier_index = index;
for &depth in Self::TIER_DEPTHS[..tier].iter().rev() {
tier_index.move_up_to(depth);
if self.upper_leaves.contains_key(&tier_index) {
return Err(MerkleError::NodeNotInSet(index));
}
}
}
Ok(())
}
/// Returns a node at the specified index. If the node does not exist at this index, a root
/// for an empty subtree at the index's depth is returned.
///
/// Unlike [TieredSmt::get_node()] this does not perform any checks to verify that the returned
/// node is valid in the context of this tree.
fn get_node_unchecked(&self, index: &NodeIndex) -> RpoDigest {
match self.nodes.get(index) {
Some(node) => *node,
None => EmptySubtreeRoots::empty_hashes(Self::MAX_DEPTH)[index.depth() as usize],
}
}
/// Returns an index at which a node for the specified key should be inserted. If a leaf node
/// already exists at that index, returns the key associated with that leaf node.
///
/// In case the index falls into the bottom tier (depth = 64), leaf node key is not returned
/// as the bottom tier may contain multiple key-value pairs in the same leaf.
fn get_insert_location(&self, key: &RpoDigest) -> (NodeIndex, Option<RpoDigest>) {
// traverse the tree from the root down checking nodes at tiers 16, 32, and 48. Return if
// a node at any of the tiers is either a leaf or a root of an empty subtree.
let mse = Word::from(key)[3].as_int();
for depth in (Self::TIER_DEPTHS[0]..Self::MAX_DEPTH).step_by(Self::TIER_SIZE as usize) {
let index = NodeIndex::new_unchecked(depth, mse >> (Self::MAX_DEPTH - depth));
if let Some(leaf_key) = self.upper_leaves.get(&index) {
return (index, Some(*leaf_key));
} else if !self.nodes.contains_key(&index) {
return (index, None);
}
}
// if we got here, that means all of the nodes checked so far are internal nodes, and
// the new node would need to be inserted in the bottom tier.
let index = NodeIndex::new_unchecked(Self::MAX_DEPTH, mse);
(index, None)
}
/// Inserts the provided key-value pair at the specified index and updates the root of this
/// Merkle tree by recomputing the path to the root.
fn insert_node(&mut self, mut index: NodeIndex, key: RpoDigest, value: Word) {
let depth = index.depth();
// insert the key into index-key map and compute the new value of the node
let mut node = if index.depth() == Self::MAX_DEPTH {
// for the bottom tier, we add the key-value pair to the existing leaf, or create a
// new leaf with this key-value pair
self.bottom_leaves
.entry(index.value())
.and_modify(|leaves| leaves.add_value(key, value))
.or_insert(BottomLeaf::new(key, value))
.hash()
} else {
// for the upper tiers, we just update the index-key map and compute the value of the
// node
self.upper_leaves.insert(index, key);
// the node value is computed as: hash(remaining_key || value, domain = depth)
let remaining_path = get_remaining_path(key, depth.into());
Rpo256::merge_in_domain(&[remaining_path, value.into()], depth.into())
};
// insert the node and update the path from the node to the root
for _ in 0..index.depth() {
self.nodes.insert(index, node);
let sibling = self.get_node_unchecked(&index.sibling());
node = Rpo256::merge(&index.build_node(node, sibling));
index.move_up();
}
// update the root
self.nodes.insert(NodeIndex::root(), node);
self.root = node;
}
}
impl Default for TieredSmt {
fn default() -> Self {
Self {
root: EmptySubtreeRoots::empty_hashes(Self::MAX_DEPTH)[0],
nodes: BTreeMap::new(),
upper_leaves: BTreeMap::new(),
bottom_leaves: BTreeMap::new(),
values: BTreeMap::new(),
}
}
}
// HELPER FUNCTIONS
// ================================================================================================
/// Returns the remaining path for the specified key at the specified depth.
///
/// Remaining path is computed by setting n most significant bits of the key to zeros, where n is
/// the specified depth.
fn get_remaining_path(key: RpoDigest, depth: u32) -> RpoDigest {
let mut key = Word::from(key);
key[3] = if depth == 64 {
ZERO
} else {
// remove `depth` bits from the most significant key element
((key[3].as_int() << depth) >> depth).into()
};
key.into()
}
/// Returns index for the specified key inserted at the specified depth.
///
/// The value for the key is computed by taking n most significant bits from the most significant
/// element of the key, where n is the specified depth.
fn key_to_index(key: &RpoDigest, depth: u8) -> NodeIndex {
let mse = Word::from(key)[3].as_int();
let value = match depth {
16 | 32 | 48 | 64 => mse >> ((TieredSmt::MAX_DEPTH - depth) as u32),
_ => unreachable!("invalid depth: {depth}"),
};
NodeIndex::new_unchecked(depth, value)
}
/// Returns tiered common prefix length between the most significant elements of the provided keys.
///
/// Specifically:
/// - returns 64 if the most significant elements are equal.
/// - returns 48 if the common prefix is between 48 and 63 bits.
/// - returns 32 if the common prefix is between 32 and 47 bits.
/// - returns 16 if the common prefix is between 16 and 31 bits.
/// - returns 0 if the common prefix is fewer than 16 bits.
fn get_common_prefix_tier(key1: &RpoDigest, key2: &RpoDigest) -> u8 {
let e1 = Word::from(key1)[3].as_int();
let e2 = Word::from(key2)[3].as_int();
let ex = (e1 ^ e2).leading_zeros() as u8;
(ex / 16) * 16
}
/// Returns a tier for the specified index.
///
/// The tiers are defined as follows:
/// - Tier 0: depth 0 through 16 (inclusive).
/// - Tier 1: depth 17 through 32 (inclusive).
/// - Tier 2: depth 33 through 48 (inclusive).
/// - Tier 3: depth 49 through 64 (inclusive).
const fn get_index_tier(index: &NodeIndex) -> usize {
debug_assert!(index.depth() <= TieredSmt::MAX_DEPTH, "invalid depth");
match index.depth() {
0..=16 => 0,
17..=32 => 1,
33..=48 => 2,
_ => 3,
}
}
/// Returns true if the specified index is an index for an inner node (i.e., the depth is not 16,
/// 32, 48, or 64).
const fn is_inner_node(index: &NodeIndex) -> bool {
!matches!(index.depth(), 16 | 32 | 48 | 64)
}
// BOTTOM LEAF
// ================================================================================================
/// Stores contents of the bottom leaf (i.e., leaf at depth = 64) in a [TieredSmt].
///
/// Bottom leaf can contain one or more key-value pairs all sharing the same 64-bit key prefix.
/// The values are sorted by key to make sure the structure of the leaf is independent of the
/// insertion order. This guarantees that a leaf with the same set of key-value pairs always has
/// the same hash value.
#[derive(Debug, Clone, PartialEq, Eq)]
struct BottomLeaf {
prefix: u64,
values: BTreeMap<[u64; 4], Word>,
}
impl BottomLeaf {
/// Returns a new [BottomLeaf] with a single key-value pair added.
pub fn new(key: RpoDigest, value: Word) -> Self {
let prefix = Word::from(key)[3].as_int();
let mut values = BTreeMap::new();
let key = get_remaining_path(key, TieredSmt::MAX_DEPTH as u32);
values.insert(key.into(), value);
Self { prefix, values }
}
/// Adds a new key-value pair to this leaf.
pub fn add_value(&mut self, key: RpoDigest, value: Word) {
let key = get_remaining_path(key, TieredSmt::MAX_DEPTH as u32);
self.values.insert(key.into(), value);
}
/// Computes a hash of this leaf.
pub fn hash(&self) -> RpoDigest {
let mut elements = Vec::with_capacity(self.values.len() * 2);
for (key, val) in self.values.iter() {
key.iter().for_each(|&v| elements.push(Felt::new(v)));
elements.extend_from_slice(val);
}
// TODO: hash in domain
Rpo256::hash_elements(&elements)
}
/// Returns contents of this leaf as a vector of (key, value) pairs.
///
/// The keys are returned in their un-truncated form.
pub fn contents(&self) -> Vec<(RpoDigest, Word)> {
self.values
.iter()
.map(|(key, val)| {
let key = RpoDigest::from([
Felt::new(key[0]),
Felt::new(key[1]),
Felt::new(key[2]),
Felt::new(self.prefix),
]);
(key, *val)
})
.collect()
}
}

View File

@@ -0,0 +1,441 @@
use super::{
super::{super::ONE, Felt, MerkleStore, WORD_SIZE, ZERO},
get_remaining_path, EmptySubtreeRoots, InnerNodeInfo, NodeIndex, Rpo256, RpoDigest, TieredSmt,
Vec, Word,
};
#[test]
fn tsmt_insert_one() {
let mut smt = TieredSmt::default();
let mut store = MerkleStore::default();
let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]);
let value = [ONE; WORD_SIZE];
// since the tree is empty, the first node will be inserted at depth 16 and the index will be
// 16 most significant bits of the key
let index = NodeIndex::make(16, raw >> 48);
let leaf_node = build_leaf_node(key, value, 16);
let tree_root = store.set_node(smt.root().into(), index, leaf_node.into()).unwrap().root;
smt.insert(key, value);
assert_eq!(smt.root(), tree_root.into());
// make sure the value was inserted, and the node is at the expected index
assert_eq!(smt.get_value(key), value);
assert_eq!(smt.get_node(index).unwrap(), leaf_node);
// make sure the paths we get from the store and the tree match
let expected_path = store.get_path(tree_root, index).unwrap();
assert_eq!(smt.get_path(index).unwrap(), expected_path.path);
// make sure inner nodes match
let expected_nodes = get_non_empty_nodes(&store);
let actual_nodes = smt.inner_nodes().collect::<Vec<_>>();
assert_eq!(actual_nodes.len(), expected_nodes.len());
actual_nodes.iter().for_each(|node| assert!(expected_nodes.contains(node)));
// make sure leaves are returned correctly
let mut leaves = smt.upper_leaves();
assert_eq!(leaves.next(), Some((leaf_node, key, value)));
assert_eq!(leaves.next(), None);
}
#[test]
fn tsmt_insert_two_16() {
let mut smt = TieredSmt::default();
let mut store = MerkleStore::default();
// --- insert the first value ---------------------------------------------
let raw_a = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_a = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_a)]);
let val_a = [ONE; WORD_SIZE];
smt.insert(key_a, val_a);
// --- insert the second value --------------------------------------------
// the key for this value has the same 16-bit prefix as the key for the first value,
// thus, on insertions, both values should be pushed to depth 32 tier
let raw_b = 0b_10101010_10101010_10011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_b = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_b)]);
let val_b = [Felt::new(2); WORD_SIZE];
smt.insert(key_b, val_b);
// --- build Merkle store with equivalent data ----------------------------
let mut tree_root = get_init_root();
let index_a = NodeIndex::make(32, raw_a >> 32);
let leaf_node_a = build_leaf_node(key_a, val_a, 32);
tree_root = store.set_node(tree_root, index_a, leaf_node_a.into()).unwrap().root;
let index_b = NodeIndex::make(32, raw_b >> 32);
let leaf_node_b = build_leaf_node(key_b, val_b, 32);
tree_root = store.set_node(tree_root, index_b, leaf_node_b.into()).unwrap().root;
// --- verify that data is consistent between store and tree --------------
assert_eq!(smt.root(), tree_root.into());
assert_eq!(smt.get_value(key_a), val_a);
assert_eq!(smt.get_node(index_a).unwrap(), leaf_node_a);
let expected_path = store.get_path(tree_root, index_a).unwrap().path;
assert_eq!(smt.get_path(index_a).unwrap(), expected_path);
assert_eq!(smt.get_value(key_b), val_b);
assert_eq!(smt.get_node(index_b).unwrap(), leaf_node_b);
let expected_path = store.get_path(tree_root, index_b).unwrap().path;
assert_eq!(smt.get_path(index_b).unwrap(), expected_path);
// make sure inner nodes match - the store contains more entries because it keeps track of
// all prior state - so, we don't check that the number of inner nodes is the same in both
let expected_nodes = get_non_empty_nodes(&store);
let actual_nodes = smt.inner_nodes().collect::<Vec<_>>();
actual_nodes.iter().for_each(|node| assert!(expected_nodes.contains(node)));
// make sure leaves are returned correctly
let mut leaves = smt.upper_leaves();
assert_eq!(leaves.next(), Some((leaf_node_a, key_a, val_a)));
assert_eq!(leaves.next(), Some((leaf_node_b, key_b, val_b)));
assert_eq!(leaves.next(), None);
}
#[test]
fn tsmt_insert_two_32() {
let mut smt = TieredSmt::default();
let mut store = MerkleStore::default();
// --- insert the first value ---------------------------------------------
let raw_a = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_a = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_a)]);
let val_a = [ONE; WORD_SIZE];
smt.insert(key_a, val_a);
// --- insert the second value --------------------------------------------
// the key for this value has the same 32-bit prefix as the key for the first value,
// thus, on insertions, both values should be pushed to depth 48 tier
let raw_b = 0b_10101010_10101010_00011111_11111111_00010110_10010011_11100000_00000000_u64;
let key_b = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_b)]);
let val_b = [Felt::new(2); WORD_SIZE];
smt.insert(key_b, val_b);
// --- build Merkle store with equivalent data ----------------------------
let mut tree_root = get_init_root();
let index_a = NodeIndex::make(48, raw_a >> 16);
let leaf_node_a = build_leaf_node(key_a, val_a, 48);
tree_root = store.set_node(tree_root, index_a, leaf_node_a.into()).unwrap().root;
let index_b = NodeIndex::make(48, raw_b >> 16);
let leaf_node_b = build_leaf_node(key_b, val_b, 48);
tree_root = store.set_node(tree_root, index_b, leaf_node_b.into()).unwrap().root;
// --- verify that data is consistent between store and tree --------------
assert_eq!(smt.root(), tree_root.into());
assert_eq!(smt.get_value(key_a), val_a);
assert_eq!(smt.get_node(index_a).unwrap(), leaf_node_a);
let expected_path = store.get_path(tree_root, index_a).unwrap().path;
assert_eq!(smt.get_path(index_a).unwrap(), expected_path);
assert_eq!(smt.get_value(key_b), val_b);
assert_eq!(smt.get_node(index_b).unwrap(), leaf_node_b);
let expected_path = store.get_path(tree_root, index_b).unwrap().path;
assert_eq!(smt.get_path(index_b).unwrap(), expected_path);
// make sure inner nodes match - the store contains more entries because it keeps track of
// all prior state - so, we don't check that the number of inner nodes is the same in both
let expected_nodes = get_non_empty_nodes(&store);
let actual_nodes = smt.inner_nodes().collect::<Vec<_>>();
actual_nodes.iter().for_each(|node| assert!(expected_nodes.contains(node)));
}
#[test]
fn tsmt_insert_three() {
let mut smt = TieredSmt::default();
let mut store = MerkleStore::default();
// --- insert the first value ---------------------------------------------
let raw_a = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_a = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_a)]);
let val_a = [ONE; WORD_SIZE];
smt.insert(key_a, val_a);
// --- insert the second value --------------------------------------------
// the key for this value has the same 16-bit prefix as the key for the first value,
// thus, on insertions, both values should be pushed to depth 32 tier
let raw_b = 0b_10101010_10101010_10011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_b = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_b)]);
let val_b = [Felt::new(2); WORD_SIZE];
smt.insert(key_b, val_b);
// --- insert the third value ---------------------------------------------
// the key for this value has the same 16-bit prefix as the keys for the first two,
// values; thus, on insertions, it will be inserted into depth 32 tier, but will not
// affect locations of the other two values
let raw_c = 0b_10101010_10101010_11011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_c = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_c)]);
let val_c = [Felt::new(3); WORD_SIZE];
smt.insert(key_c, val_c);
// --- build Merkle store with equivalent data ----------------------------
let mut tree_root = get_init_root();
let index_a = NodeIndex::make(32, raw_a >> 32);
let leaf_node_a = build_leaf_node(key_a, val_a, 32);
tree_root = store.set_node(tree_root, index_a, leaf_node_a.into()).unwrap().root;
let index_b = NodeIndex::make(32, raw_b >> 32);
let leaf_node_b = build_leaf_node(key_b, val_b, 32);
tree_root = store.set_node(tree_root, index_b, leaf_node_b.into()).unwrap().root;
let index_c = NodeIndex::make(32, raw_c >> 32);
let leaf_node_c = build_leaf_node(key_c, val_c, 32);
tree_root = store.set_node(tree_root, index_c, leaf_node_c.into()).unwrap().root;
// --- verify that data is consistent between store and tree --------------
assert_eq!(smt.root(), tree_root.into());
assert_eq!(smt.get_value(key_a), val_a);
assert_eq!(smt.get_node(index_a).unwrap(), leaf_node_a);
let expected_path = store.get_path(tree_root, index_a).unwrap().path;
assert_eq!(smt.get_path(index_a).unwrap(), expected_path);
assert_eq!(smt.get_value(key_b), val_b);
assert_eq!(smt.get_node(index_b).unwrap(), leaf_node_b);
let expected_path = store.get_path(tree_root, index_b).unwrap().path;
assert_eq!(smt.get_path(index_b).unwrap(), expected_path);
assert_eq!(smt.get_value(key_c), val_c);
assert_eq!(smt.get_node(index_c).unwrap(), leaf_node_c);
let expected_path = store.get_path(tree_root, index_c).unwrap().path;
assert_eq!(smt.get_path(index_c).unwrap(), expected_path);
// make sure inner nodes match - the store contains more entries because it keeps track of
// all prior state - so, we don't check that the number of inner nodes is the same in both
let expected_nodes = get_non_empty_nodes(&store);
let actual_nodes = smt.inner_nodes().collect::<Vec<_>>();
actual_nodes.iter().for_each(|node| assert!(expected_nodes.contains(node)));
}
#[test]
fn tsmt_update() {
let mut smt = TieredSmt::default();
let mut store = MerkleStore::default();
// --- insert a value into the tree ---------------------------------------
let raw = 0b_01101001_01101100_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]);
let value_a = [ONE; WORD_SIZE];
smt.insert(key, value_a);
// --- update the value ---------------------------------------------------
let value_b = [Felt::new(2); WORD_SIZE];
smt.insert(key, value_b);
// --- verify consistency -------------------------------------------------
let mut tree_root = get_init_root();
let index = NodeIndex::make(16, raw >> 48);
let leaf_node = build_leaf_node(key, value_b, 16);
tree_root = store.set_node(tree_root, index, leaf_node.into()).unwrap().root;
assert_eq!(smt.root(), tree_root.into());
assert_eq!(smt.get_value(key), value_b);
assert_eq!(smt.get_node(index).unwrap(), leaf_node);
let expected_path = store.get_path(tree_root, index).unwrap().path;
assert_eq!(smt.get_path(index).unwrap(), expected_path);
// make sure inner nodes match - the store contains more entries because it keeps track of
// all prior state - so, we don't check that the number of inner nodes is the same in both
let expected_nodes = get_non_empty_nodes(&store);
let actual_nodes = smt.inner_nodes().collect::<Vec<_>>();
actual_nodes.iter().for_each(|node| assert!(expected_nodes.contains(node)));
}
// BOTTOM TIER TESTS
// ================================================================================================
#[test]
fn tsmt_bottom_tier() {
let mut smt = TieredSmt::default();
let mut store = MerkleStore::default();
// common prefix for the keys
let prefix = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
// --- insert the first value ---------------------------------------------
let key_a = RpoDigest::from([ONE, ONE, ONE, Felt::new(prefix)]);
let val_a = [ONE; WORD_SIZE];
smt.insert(key_a, val_a);
// --- insert the second value --------------------------------------------
// this key has the same 64-bit prefix and thus both values should end up in the same
// node at depth 64
let key_b = RpoDigest::from([ZERO, ONE, ONE, Felt::new(prefix)]);
let val_b = [Felt::new(2); WORD_SIZE];
smt.insert(key_b, val_b);
// --- build Merkle store with equivalent data ----------------------------
let index = NodeIndex::make(64, prefix);
// to build bottom leaf we sort by key starting with the least significant element, thus
// key_b is smaller than key_a.
let leaf_node = build_bottom_leaf_node(&[key_b, key_a], &[val_b, val_a]);
let mut tree_root = get_init_root();
tree_root = store.set_node(tree_root, index, leaf_node.into()).unwrap().root;
// --- verify that data is consistent between store and tree --------------
assert_eq!(smt.root(), tree_root.into());
assert_eq!(smt.get_value(key_a), val_a);
assert_eq!(smt.get_value(key_b), val_b);
assert_eq!(smt.get_node(index).unwrap(), leaf_node);
let expected_path = store.get_path(tree_root, index).unwrap().path;
assert_eq!(smt.get_path(index).unwrap(), expected_path);
// make sure inner nodes match - the store contains more entries because it keeps track of
// all prior state - so, we don't check that the number of inner nodes is the same in both
let expected_nodes = get_non_empty_nodes(&store);
let actual_nodes = smt.inner_nodes().collect::<Vec<_>>();
actual_nodes.iter().for_each(|node| assert!(expected_nodes.contains(node)));
// make sure leaves are returned correctly
let mut leaves = smt.bottom_leaves();
assert_eq!(leaves.next(), Some((leaf_node, vec![(key_b, val_b), (key_a, val_a)])));
assert_eq!(leaves.next(), None);
}
#[test]
fn tsmt_bottom_tier_two() {
let mut smt = TieredSmt::default();
let mut store = MerkleStore::default();
// --- insert the first value ---------------------------------------------
let raw_a = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key_a = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_a)]);
let val_a = [ONE; WORD_SIZE];
smt.insert(key_a, val_a);
// --- insert the second value --------------------------------------------
// the key for this value has the same 48-bit prefix as the key for the first value,
// thus, on insertions, both should end up in different nodes at depth 64
let raw_b = 0b_10101010_10101010_00011111_11111111_10010110_10010011_01100000_00000000_u64;
let key_b = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_b)]);
let val_b = [Felt::new(2); WORD_SIZE];
smt.insert(key_b, val_b);
// --- build Merkle store with equivalent data ----------------------------
let mut tree_root = get_init_root();
let index_a = NodeIndex::make(64, raw_a);
let leaf_node_a = build_bottom_leaf_node(&[key_a], &[val_a]);
tree_root = store.set_node(tree_root, index_a, leaf_node_a.into()).unwrap().root;
let index_b = NodeIndex::make(64, raw_b);
let leaf_node_b = build_bottom_leaf_node(&[key_b], &[val_b]);
tree_root = store.set_node(tree_root, index_b, leaf_node_b.into()).unwrap().root;
// --- verify that data is consistent between store and tree --------------
assert_eq!(smt.root(), tree_root.into());
assert_eq!(smt.get_value(key_a), val_a);
assert_eq!(smt.get_node(index_a).unwrap(), leaf_node_a);
let expected_path = store.get_path(tree_root, index_a).unwrap().path;
assert_eq!(smt.get_path(index_a).unwrap(), expected_path);
assert_eq!(smt.get_value(key_b), val_b);
assert_eq!(smt.get_node(index_b).unwrap(), leaf_node_b);
let expected_path = store.get_path(tree_root, index_b).unwrap().path;
assert_eq!(smt.get_path(index_b).unwrap(), expected_path);
// make sure inner nodes match - the store contains more entries because it keeps track of
// all prior state - so, we don't check that the number of inner nodes is the same in both
let expected_nodes = get_non_empty_nodes(&store);
let actual_nodes = smt.inner_nodes().collect::<Vec<_>>();
actual_nodes.iter().for_each(|node| assert!(expected_nodes.contains(node)));
// make sure leaves are returned correctly
let mut leaves = smt.bottom_leaves();
assert_eq!(leaves.next(), Some((leaf_node_b, vec![(key_b, val_b)])));
assert_eq!(leaves.next(), Some((leaf_node_a, vec![(key_a, val_a)])));
assert_eq!(leaves.next(), None);
}
// ERROR TESTS
// ================================================================================================
#[test]
fn tsmt_node_not_available() {
let mut smt = TieredSmt::default();
let raw = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
let key = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw)]);
let value = [ONE; WORD_SIZE];
// build an index which is just below the inserted leaf node
let index = NodeIndex::make(17, raw >> 47);
// since we haven't inserted the node yet, we should be able to get node and path to this index
assert!(smt.get_node(index).is_ok());
assert!(smt.get_path(index).is_ok());
smt.insert(key, value);
// but once the node is inserted, everything under it should be unavailable
assert!(smt.get_node(index).is_err());
assert!(smt.get_path(index).is_err());
let index = NodeIndex::make(32, raw >> 32);
assert!(smt.get_node(index).is_err());
assert!(smt.get_path(index).is_err());
let index = NodeIndex::make(34, raw >> 30);
assert!(smt.get_node(index).is_err());
assert!(smt.get_path(index).is_err());
let index = NodeIndex::make(50, raw >> 14);
assert!(smt.get_node(index).is_err());
assert!(smt.get_path(index).is_err());
let index = NodeIndex::make(64, raw);
assert!(smt.get_node(index).is_err());
assert!(smt.get_path(index).is_err());
}
// HELPER FUNCTIONS
// ================================================================================================
fn get_init_root() -> Word {
EmptySubtreeRoots::empty_hashes(64)[0].into()
}
fn build_leaf_node(key: RpoDigest, value: Word, depth: u8) -> RpoDigest {
let remaining_path = get_remaining_path(key, depth as u32);
Rpo256::merge_in_domain(&[remaining_path, value.into()], depth.into())
}
fn build_bottom_leaf_node(keys: &[RpoDigest], values: &[Word]) -> RpoDigest {
assert_eq!(keys.len(), values.len());
let mut elements = Vec::with_capacity(keys.len());
for (key, val) in keys.iter().zip(values.iter()) {
let mut key = Word::from(key);
key[3] = ZERO;
elements.extend_from_slice(&key);
elements.extend_from_slice(val);
}
Rpo256::hash_elements(&elements)
}
fn get_non_empty_nodes(store: &MerkleStore) -> Vec<InnerNodeInfo> {
store
.inner_nodes()
.filter(|node| !is_empty_subtree(&RpoDigest::from(node.value)))
.collect::<Vec<_>>()
}
fn is_empty_subtree(node: &RpoDigest) -> bool {
EmptySubtreeRoots::empty_hashes(255).contains(&node)
}