WIP(smt): impl simple subtree8 hashing and benchmarks for it
bench(smt-subtree): add a benchmark for single-leaf subtrees make build_subtree also return the next leaf row convert (col, hash) tuples to a dedicated struct
This commit is contained in:
parent
ecf358a19e
commit
e569bfa9c1
6 changed files with 157 additions and 4 deletions
|
@ -27,6 +27,10 @@ harness = false
|
||||||
name = "smt"
|
name = "smt"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "smt-subtree"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "store"
|
name = "store"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
136
benches/smt-subtree.rs
Normal file
136
benches/smt-subtree.rs
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
use std::{fmt::Debug, hint, mem, time::Duration};
|
||||||
|
|
||||||
|
use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion};
|
||||||
|
use miden_crypto::{
|
||||||
|
hash::rpo::RpoDigest,
|
||||||
|
merkle::{NodeIndex, Smt, SmtLeaf, SubtreeLeaf, SMT_DEPTH},
|
||||||
|
Felt, Word, ONE,
|
||||||
|
};
|
||||||
|
use rand_utils::prng_array;
|
||||||
|
use winter_utils::Randomizable;
|
||||||
|
|
||||||
|
const PAIR_COUNTS: [u64; 5] = [1, 64, 128, 192, 256];
|
||||||
|
|
||||||
|
fn smt_subtree_even(c: &mut Criterion) {
|
||||||
|
let mut seed = [0u8; 32];
|
||||||
|
|
||||||
|
let mut group = c.benchmark_group("subtree8-even");
|
||||||
|
|
||||||
|
for pair_count in PAIR_COUNTS {
|
||||||
|
let bench_id = BenchmarkId::from_parameter(pair_count);
|
||||||
|
group.bench_with_input(bench_id, &pair_count, |b, &pair_count| {
|
||||||
|
b.iter_batched(
|
||||||
|
|| {
|
||||||
|
// Setup.
|
||||||
|
let entries: Vec<(RpoDigest, Word)> = (0..pair_count)
|
||||||
|
.map(|n| {
|
||||||
|
// A single depth-8 subtree can have a maximum of 255 leaves.
|
||||||
|
let leaf_index = ((n as f64 / pair_count as f64) * 255.0) as u64;
|
||||||
|
let key = RpoDigest::new([
|
||||||
|
generate_value(&mut seed),
|
||||||
|
ONE,
|
||||||
|
Felt::new(n),
|
||||||
|
Felt::new(leaf_index),
|
||||||
|
]);
|
||||||
|
let value = generate_word(&mut seed);
|
||||||
|
(key, value)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut leaves: Vec<_> = entries
|
||||||
|
.iter()
|
||||||
|
.map(|(key, value)| {
|
||||||
|
let leaf = SmtLeaf::new_single(*key, *value);
|
||||||
|
let col = NodeIndex::from(leaf.index()).value();
|
||||||
|
let hash = leaf.hash();
|
||||||
|
SubtreeLeaf { col, hash }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
leaves.sort();
|
||||||
|
leaves.dedup_by_key(|leaf| leaf.col);
|
||||||
|
leaves
|
||||||
|
},
|
||||||
|
|leaves| {
|
||||||
|
// Benchmarked function.
|
||||||
|
let (subtree, _) =
|
||||||
|
Smt::build_subtree(hint::black_box(leaves), hint::black_box(SMT_DEPTH));
|
||||||
|
assert!(!subtree.is_empty());
|
||||||
|
},
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn smt_subtree_random(c: &mut Criterion) {
|
||||||
|
let mut seed = [0u8; 32];
|
||||||
|
|
||||||
|
let mut group = c.benchmark_group("subtree8-rand");
|
||||||
|
|
||||||
|
for pair_count in PAIR_COUNTS {
|
||||||
|
let bench_id = BenchmarkId::from_parameter(pair_count);
|
||||||
|
group.bench_with_input(bench_id, &pair_count, |b, &pair_count| {
|
||||||
|
b.iter_batched(
|
||||||
|
|| {
|
||||||
|
// Setup.
|
||||||
|
let entries: Vec<(RpoDigest, Word)> = (0..pair_count)
|
||||||
|
.map(|i| {
|
||||||
|
let leaf_index: u8 = generate_value(&mut seed);
|
||||||
|
let key = RpoDigest::new([
|
||||||
|
ONE,
|
||||||
|
ONE,
|
||||||
|
Felt::new(i),
|
||||||
|
Felt::new(leaf_index as u64),
|
||||||
|
]);
|
||||||
|
let value = generate_word(&mut seed);
|
||||||
|
(key, value)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut leaves: Vec<_> = entries
|
||||||
|
.iter()
|
||||||
|
.map(|(key, value)| {
|
||||||
|
let leaf = SmtLeaf::new_single(*key, *value);
|
||||||
|
let col = NodeIndex::from(leaf.index()).value();
|
||||||
|
let hash = leaf.hash();
|
||||||
|
SubtreeLeaf { col, hash }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
leaves.sort();
|
||||||
|
leaves
|
||||||
|
},
|
||||||
|
|leaves| {
|
||||||
|
let (subtree, _) =
|
||||||
|
Smt::build_subtree(hint::black_box(leaves), hint::black_box(SMT_DEPTH));
|
||||||
|
assert!(!subtree.is_empty());
|
||||||
|
},
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group! {
|
||||||
|
name = smt_subtree_group;
|
||||||
|
config = Criterion::default()
|
||||||
|
.measurement_time(Duration::from_secs(40))
|
||||||
|
.sample_size(60)
|
||||||
|
.configure_from_args();
|
||||||
|
targets = smt_subtree_even, smt_subtree_random
|
||||||
|
}
|
||||||
|
criterion_main!(smt_subtree_group);
|
||||||
|
|
||||||
|
// HELPER FUNCTIONS
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
fn generate_value<T: Copy + Debug + Randomizable>(seed: &mut [u8; 32]) -> T {
|
||||||
|
mem::swap(seed, &mut prng_array(*seed));
|
||||||
|
let value: [T; 1] = rand_utils::prng_array(*seed);
|
||||||
|
value[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_word(seed: &mut [u8; 32]) -> Word {
|
||||||
|
mem::swap(seed, &mut 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])]
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ pub use path::{MerklePath, RootPath, ValuePath};
|
||||||
mod smt;
|
mod smt;
|
||||||
pub use smt::{
|
pub use smt::{
|
||||||
LeafIndex, MutationSet, SimpleSmt, Smt, SmtLeaf, SmtLeafError, SmtProof, SmtProofError,
|
LeafIndex, MutationSet, SimpleSmt, Smt, SmtLeaf, SmtLeafError, SmtProof, SmtProofError,
|
||||||
SMT_DEPTH, SMT_MAX_DEPTH, SMT_MIN_DEPTH,
|
SubtreeLeaf, SMT_DEPTH, SMT_MAX_DEPTH, SMT_MIN_DEPTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod mmr;
|
mod mmr;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use alloc::{
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
EmptySubtreeRoots, Felt, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, MerklePath,
|
EmptySubtreeRoots, Felt, InnerNode, InnerNodeInfo, LeafIndex, MerkleError, MerklePath,
|
||||||
MutationSet, NodeIndex, Rpo256, RpoDigest, SparseMerkleTree, Word, EMPTY_WORD,
|
MutationSet, NodeIndex, Rpo256, RpoDigest, SparseMerkleTree, SubtreeLeaf, Word, EMPTY_WORD,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
@ -249,6 +249,13 @@ impl Smt {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_subtree(
|
||||||
|
leaves: Vec<SubtreeLeaf>,
|
||||||
|
bottom_depth: u8,
|
||||||
|
) -> (BTreeMap<NodeIndex, InnerNode>, Vec<SubtreeLeaf>) {
|
||||||
|
<Self as SparseMerkleTree<SMT_DEPTH>>::build_subtree(leaves, bottom_depth)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SparseMerkleTree<SMT_DEPTH> for Smt {
|
impl SparseMerkleTree<SMT_DEPTH> for Smt {
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use alloc::{collections::BTreeMap, vec::Vec};
|
use alloc::{collections::BTreeMap, vec::Vec};
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
use num::Integer;
|
||||||
|
|
||||||
use super::{EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, NodeIndex};
|
use super::{EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, NodeIndex};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -493,7 +496,7 @@ pub(crate) trait SparseMerkleTree<const DEPTH: u8> {
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub(crate) struct InnerNode {
|
pub struct InnerNode {
|
||||||
pub left: RpoDigest,
|
pub left: RpoDigest,
|
||||||
pub right: RpoDigest,
|
pub right: RpoDigest,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use alloc::collections::{BTreeMap, BTreeSet};
|
use alloc::{
|
||||||
|
collections::{BTreeMap, BTreeSet},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::ValuePath, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError,
|
super::ValuePath, EmptySubtreeRoots, InnerNode, InnerNodeInfo, LeafIndex, MerkleError,
|
||||||
|
|
Loading…
Add table
Reference in a new issue