From 99149fd2c689b45bdceac36088ce790f0024f1b7 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:30:48 +0500 Subject: [PATCH 01/19] feat: revert mutations generation, mutations serialization --- src/merkle/smt/full/mod.rs | 10 +-- src/merkle/smt/full/tests.rs | 117 +++++++++++++++++++++++++++++++++-- src/merkle/smt/mod.rs | 117 ++++++++++++++++++++++++++++++++--- src/merkle/smt/simple/mod.rs | 10 +-- 4 files changed, 229 insertions(+), 25 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index 226a8b18..68af2b38 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -210,7 +210,7 @@ impl Smt { pub fn apply_mutations( &mut self, mutations: MutationSet, - ) -> Result<(), MerkleError> { + ) -> Result, MerkleError> { >::apply_mutations(self, mutations) } @@ -275,12 +275,12 @@ impl SparseMerkleTree for Smt { .unwrap_or_else(|| EmptySubtreeRoots::get_inner_node(SMT_DEPTH, index.depth())) } - fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { - self.inner_nodes.insert(index, inner_node); + fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) -> Option { + self.inner_nodes.insert(index, inner_node) } - fn remove_inner_node(&mut self, index: NodeIndex) { - let _ = self.inner_nodes.remove(&index); + fn remove_inner_node(&mut self, index: NodeIndex) -> Option { + self.inner_nodes.remove(&index) } fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option { diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index 03eb3829..53406f67 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -1,12 +1,15 @@ use alloc::vec::Vec; +use std::collections::BTreeMap; use super::{Felt, LeafIndex, NodeIndex, Rpo256, RpoDigest, Smt, SmtLeaf, EMPTY_WORD, SMT_DEPTH}; use crate::{ - merkle::{smt::SparseMerkleTree, EmptySubtreeRoots, MerkleStore}, + merkle::{ + smt::{NodeMutation, SparseMerkleTree}, + EmptySubtreeRoots, MerkleStore, MutationSet, + }, utils::{Deserializable, Serializable}, Word, ONE, WORD_SIZE, }; - // SMT // -------------------------------------------------------------------------------------------- @@ -412,21 +415,49 @@ fn test_prospective_insertion() { let mutations = smt.compute_mutations(vec![(key_1, value_1)]); assert_eq!(mutations.root(), root_1, "prospective root 1 did not match actual root 1"); - smt.apply_mutations(mutations).unwrap(); + let revert = smt.apply_mutations(mutations).unwrap(); assert_eq!(smt.root(), root_1, "mutations before and after apply did not match"); + assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); + assert_eq!(revert.root(), root_empty, "reverse mutations new root did not match"); + assert_eq!( + revert.new_pairs, + BTreeMap::from_iter([(key_1, EMPTY_WORD)]), + "reverse mutations pairs did not match" + ); + assert_eq!( + revert.node_mutations, + smt.inner_nodes.iter().map(|(key, _)| (*key, NodeMutation::Removal)).collect(), + "reverse mutations inner nodes did not match" + ); let mutations = smt.compute_mutations(vec![(key_2, value_2)]); assert_eq!(mutations.root(), root_2, "prospective root 2 did not match actual root 2"); let mutations = smt.compute_mutations(vec![(key_3, EMPTY_WORD), (key_2, value_2), (key_3, value_3)]); assert_eq!(mutations.root(), root_3, "mutations before and after apply did not match"); - smt.apply_mutations(mutations).unwrap(); + let old_root = smt.root(); + let revert = smt.apply_mutations(mutations).unwrap(); + assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); + assert_eq!(revert.root(), old_root, "reverse mutations new root did not match"); + assert_eq!( + revert.new_pairs, + BTreeMap::from_iter([(key_2, EMPTY_WORD), (key_3, EMPTY_WORD)]), + "reverse mutations pairs did not match" + ); // Edge case: multiple values at the same key, where a later pair restores the original value. let mutations = smt.compute_mutations(vec![(key_3, EMPTY_WORD), (key_3, value_3)]); assert_eq!(mutations.root(), root_3); - smt.apply_mutations(mutations).unwrap(); + let old_root = smt.root(); + let revert = smt.apply_mutations(mutations).unwrap(); assert_eq!(smt.root(), root_3); + assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); + assert_eq!(revert.root(), old_root, "reverse mutations new root did not match"); + assert_eq!( + revert.new_pairs, + BTreeMap::from_iter([(key_3, value_3)]), + "reverse mutations pairs did not match" + ); // Test batch updates, and that the order doesn't matter. let pairs = @@ -437,8 +468,16 @@ fn test_prospective_insertion() { root_empty, "prospective root for batch removal did not match actual root", ); - smt.apply_mutations(mutations).unwrap(); + let old_root = smt.root(); + let revert = smt.apply_mutations(mutations).unwrap(); assert_eq!(smt.root(), root_empty, "mutations before and after apply did not match"); + assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); + assert_eq!(revert.root(), old_root, "reverse mutations new root did not match"); + assert_eq!( + revert.new_pairs, + BTreeMap::from_iter([(key_1, value_1), (key_2, value_2), (key_3, value_3)]), + "reverse mutations pairs did not match" + ); let pairs = vec![(key_3, value_3), (key_1, value_1), (key_2, value_2)]; let mutations = smt.compute_mutations(pairs); @@ -447,6 +486,72 @@ fn test_prospective_insertion() { assert_eq!(smt.root(), root_3); } +#[test] +fn test_mutations_revert() { + let mut smt = Smt::default(); + + let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, Felt::new(1)]); + let key_2: RpoDigest = + RpoDigest::from([2_u32.into(), 2_u32.into(), 2_u32.into(), Felt::new(2)]); + let key_3: RpoDigest = + RpoDigest::from([0_u32.into(), 0_u32.into(), 0_u32.into(), Felt::new(3)]); + + let value_1 = [ONE; WORD_SIZE]; + let value_2 = [2_u32.into(); WORD_SIZE]; + let value_3 = [3_u32.into(); WORD_SIZE]; + + smt.insert(key_1, value_1); + smt.insert(key_2, value_2); + + let mutations = + smt.compute_mutations(vec![(key_1, EMPTY_WORD), (key_2, value_1), (key_3, value_3)]); + + let original = smt.clone(); + + let revert = smt.apply_mutations(mutations).unwrap(); + assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); + assert_eq!(revert.root(), original.root(), "reverse mutations new root did not match"); + + let _ = smt.apply_mutations(revert).unwrap(); + + assert_eq!(smt, original, "SMT with applied revert mutations did not match original SMT"); +} + +#[test] +fn test_mutation_set_serialization() { + let mut smt = Smt::default(); + + let key_1: RpoDigest = RpoDigest::from([ONE, ONE, ONE, Felt::new(1)]); + let key_2: RpoDigest = + RpoDigest::from([2_u32.into(), 2_u32.into(), 2_u32.into(), Felt::new(2)]); + let key_3: RpoDigest = + RpoDigest::from([0_u32.into(), 0_u32.into(), 0_u32.into(), Felt::new(3)]); + + let value_1 = [ONE; WORD_SIZE]; + let value_2 = [2_u32.into(); WORD_SIZE]; + let value_3 = [3_u32.into(); WORD_SIZE]; + + smt.insert(key_1, value_1); + smt.insert(key_2, value_2); + + let mutations = + smt.compute_mutations(vec![(key_1, EMPTY_WORD), (key_2, value_1), (key_3, value_3)]); + + let serialized = mutations.to_bytes(); + let deserialized = + MutationSet::::read_from_bytes(&serialized).unwrap(); + + assert_eq!(deserialized, mutations, "deserialized mutations did not match original"); + + let revert = smt.apply_mutations(mutations).unwrap(); + + let serialized = revert.to_bytes(); + let deserialized = + MutationSet::::read_from_bytes(&serialized).unwrap(); + + assert_eq!(deserialized, revert, "deserialized mutations did not match original"); +} + /// Tests that 2 key-value pairs stored in the same leaf have the same path #[test] fn test_smt_path_to_keys_in_same_leaf_are_equal() { diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 056c221c..a9b29a2a 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -1,5 +1,8 @@ use alloc::{collections::BTreeMap, vec::Vec}; +use num::Integer; +use winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}; + use super::{EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, NodeIndex}; use crate::{ hash::rpo::{Rpo256, RpoDigest}, @@ -135,7 +138,7 @@ pub(crate) trait SparseMerkleTree { if node_hash == *EmptySubtreeRoots::entry(DEPTH, node_depth) { // If a subtree is empty, when can remove the inner node, since it's equal to the // default value - self.remove_inner_node(index) + self.remove_inner_node(index); } else { self.insert_inner_node(index, InnerNode { left, right }); } @@ -242,7 +245,7 @@ pub(crate) trait SparseMerkleTree { } /// Apply the prospective mutations computed with [`SparseMerkleTree::compute_mutations()`] to - /// this tree. + /// this tree. Return reverse mutation set. /// /// # Errors /// If `mutations` was computed on a tree with a different root than this one, returns @@ -252,7 +255,7 @@ pub(crate) trait SparseMerkleTree { fn apply_mutations( &mut self, mutations: MutationSet, - ) -> Result<(), MerkleError> + ) -> Result, MerkleError> where Self: Sized, { @@ -270,20 +273,41 @@ pub(crate) trait SparseMerkleTree { return Err(MerkleError::ConflictingRoots(vec![old_root, self.root()])); } + let mut reverse_mutations = BTreeMap::new(); for (index, mutation) in node_mutations { match mutation { - Removal => self.remove_inner_node(index), - Addition(node) => self.insert_inner_node(index, node), + Removal => { + if let Some(node) = self.remove_inner_node(index) { + reverse_mutations.insert(index, Addition(node)); + } + }, + Addition(node) => { + if let Some(old_node) = self.insert_inner_node(index, node) { + reverse_mutations.insert(index, Addition(old_node)); + } else { + reverse_mutations.insert(index, Removal); + } + }, } } + let mut reverse_pairs = BTreeMap::new(); for (key, value) in new_pairs { - self.insert_value(key, value); + if let Some(old_value) = self.insert_value(key.clone(), value) { + reverse_pairs.insert(key, old_value); + } else { + reverse_pairs.insert(key, Self::EMPTY_VALUE); + } } self.set_root(new_root); - Ok(()) + Ok(MutationSet { + old_root: new_root, + node_mutations: reverse_mutations, + new_pairs: reverse_pairs, + new_root: old_root, + }) } // REQUIRED METHODS @@ -299,10 +323,10 @@ pub(crate) trait SparseMerkleTree { fn get_inner_node(&self, index: NodeIndex) -> InnerNode; /// Inserts an inner node at the given index - fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode); + fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) -> Option; /// Removes an inner node at the given index - fn remove_inner_node(&mut self, index: NodeIndex); + fn remove_inner_node(&mut self, index: NodeIndex) -> Option; /// Inserts a leaf node, and returns the value at the key if already exists fn insert_value(&mut self, key: Self::Key, value: Self::Value) -> Option; @@ -459,3 +483,78 @@ impl MutationSet { self.new_root } } + +// SERIALIZATION +// ================================================================================================ + +impl Serializable for InnerNode { + fn write_into(&self, target: &mut W) { + self.left.write_into(target); + self.right.write_into(target); + } +} + +impl Deserializable for InnerNode { + fn read_from(source: &mut R) -> Result { + let left = source.read()?; + let right = source.read()?; + + Ok(Self { left, right }) + } +} + +impl Serializable for NodeMutation { + fn write_into(&self, target: &mut W) { + match self { + NodeMutation::Removal => target.write_bool(false), + NodeMutation::Addition(inner_node) => { + target.write_bool(true); + inner_node.write_into(target); + }, + } + } +} + +impl Deserializable for NodeMutation { + fn read_from(source: &mut R) -> Result { + if source.read_bool()? { + let inner_node = source.read()?; + return Ok(NodeMutation::Addition(inner_node)); + } + + Ok(NodeMutation::Removal) + } +} + +impl Serializable for MutationSet { + fn write_into(&self, target: &mut W) { + target.write(self.old_root); + target.write(self.new_root); + self.node_mutations.write_into(target); + self.new_pairs.write_into(target); + } +} + +impl Deserializable + for MutationSet +{ + fn read_from(source: &mut R) -> Result { + let old_root = source.read()?; + let new_root = source.read()?; + let node_mutations = source.read()?; + let new_pairs = source.read()?; + + Ok(Self { + old_root, + node_mutations, + new_pairs, + new_root, + }) + } +} + +// TESTS +// ================================================================================================ + +#[cfg(test)] +mod tests; diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index 6229ac25..b578e968 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -232,7 +232,7 @@ impl SimpleSmt { pub fn apply_mutations( &mut self, mutations: MutationSet, Word>, - ) -> Result<(), MerkleError> { + ) -> Result, Word>, MerkleError> { >::apply_mutations(self, mutations) } @@ -321,12 +321,12 @@ impl SparseMerkleTree for SimpleSmt { .unwrap_or_else(|| EmptySubtreeRoots::get_inner_node(DEPTH, index.depth())) } - fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) { - self.inner_nodes.insert(index, inner_node); + fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) -> Option { + self.inner_nodes.insert(index, inner_node) } - fn remove_inner_node(&mut self, index: NodeIndex) { - let _ = self.inner_nodes.remove(&index); + fn remove_inner_node(&mut self, index: NodeIndex) -> Option { + self.inner_nodes.remove(&index) } fn insert_value(&mut self, key: LeafIndex, value: Word) -> Option { From b85fd4a56fad7d6c154550aa496b001c4b76beb2 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:47:59 +0500 Subject: [PATCH 02/19] docs: update CHANGELOG.md --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc22853c..bc690860 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ -## 0.11.0 (2024-10-30) +## 0.12.1 (Unreleased) + +- Generate reverse mutations set on applying of mutations set, implemented serialization of `MutationsSet` (#355). + +## 0.12.0 (2024-10-30) - [BREAKING] Updated Winterfell dependency to v0.10 (#338). From 24d435f65c45eae7e364dfe502f40db3c7f350c3 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:56:16 +0500 Subject: [PATCH 03/19] fix: compilation error on using no-std target --- src/merkle/smt/full/tests.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index 53406f67..77bd97b5 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -1,5 +1,4 @@ -use alloc::vec::Vec; -use std::collections::BTreeMap; +use alloc::{collections::BTreeMap, vec::Vec}; use super::{Felt, LeafIndex, NodeIndex, Rpo256, RpoDigest, Smt, SmtLeaf, EMPTY_WORD, SMT_DEPTH}; use crate::{ From 32f10eaca7b68eae2fed0bd628b3eead7a791443 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:35:16 +0500 Subject: [PATCH 04/19] refactor: address review comments --- CHANGELOG.md | 2 +- src/merkle/smt/full/leaf.rs | 2 +- src/merkle/smt/full/mod.rs | 4 +++- src/merkle/smt/mod.rs | 5 +++-- src/merkle/smt/simple/mod.rs | 5 +++-- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc690860..1391c6ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.12.1 (Unreleased) +## Unreleased - Generate reverse mutations set on applying of mutations set, implemented serialization of `MutationsSet` (#355). diff --git a/src/merkle/smt/full/leaf.rs b/src/merkle/smt/full/leaf.rs index 585fc407..367e3968 100644 --- a/src/merkle/smt/full/leaf.rs +++ b/src/merkle/smt/full/leaf.rs @@ -68,7 +68,7 @@ impl SmtLeaf { Self::Single((key, value)) } - /// Returns a new single leaf with the specified entry. The leaf index is derived from the + /// Returns a new multiple leaf with the specified entries. The leaf index is derived from the /// entries' keys. /// /// # Errors diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index 68af2b38..8abdd9e5 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -200,7 +200,9 @@ impl Smt { >::compute_mutations(self, kv_pairs) } - /// Apply the prospective mutations computed with [`Smt::compute_mutations()`] to this tree. + /// Applies the prospective mutations computed with [`SparseMerkleTree::compute_mutations()`] to + /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the + /// updated tree will revert the changes. /// /// # Errors /// If `mutations` was computed on a tree with a different root than this one, returns diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index a9b29a2a..7cbdbaf8 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -244,8 +244,9 @@ pub(crate) trait SparseMerkleTree { } } - /// Apply the prospective mutations computed with [`SparseMerkleTree::compute_mutations()`] to - /// this tree. Return reverse mutation set. + /// Applies the prospective mutations computed with [`SparseMerkleTree::compute_mutations()`] to + /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the + /// updated tree will revert the changes. /// /// # Errors /// If `mutations` was computed on a tree with a different root than this one, returns diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index b578e968..4ae02df0 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -221,8 +221,9 @@ impl SimpleSmt { >::compute_mutations(self, kv_pairs) } - /// Apply the prospective mutations computed with [`SimpleSmt::compute_mutations()`] to this - /// tree. + /// Applies the prospective mutations computed with [`SparseMerkleTree::compute_mutations()`] to + /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the + /// updated tree will revert the changes. /// /// # Errors /// If `mutations` was computed on a tree with a different root than this one, returns From c25f59f0fdaec2716bdc3fd6046ce861ca83ccb9 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Tue, 17 Dec 2024 23:23:41 +0500 Subject: [PATCH 05/19] feat: implement benchmark --- Cargo.toml | 4 ++ benches/smt-mutations.rs | 108 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 benches/smt-mutations.rs diff --git a/Cargo.toml b/Cargo.toml index 5d124c68..98da1ac3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,10 @@ harness = false name = "smt" harness = false +[[bench]] +name = "smt-mutations" +harness = false + [[bench]] name = "store" harness = false diff --git a/benches/smt-mutations.rs b/benches/smt-mutations.rs new file mode 100644 index 00000000..d922ca05 --- /dev/null +++ b/benches/smt-mutations.rs @@ -0,0 +1,108 @@ +use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; +use miden_crypto::{ + merkle::{LeafIndex, SimpleSmt}, + Felt, Word, EMPTY_WORD, +}; +use rand::{prelude::SliceRandom, rngs::StdRng, Rng, SeedableRng}; + +const DEPTH: u8 = 64; + +fn benchmark_apply_mutations(c: &mut Criterion) { + let mut group = c.benchmark_group("apply_mutations"); + group.sample_size(10); + group.measurement_time(std::time::Duration::from_secs(300)); + + // Fixed seed for reproducibility + let rng_seed = 42; + let mut rng = StdRng::seed_from_u64(rng_seed); + + // Benchmark for various mutation set sizes + for &mutation_count in &[1_000, 100_000] { + group.bench_with_input( + BenchmarkId::new("SimpleSmt: apply_mutations", mutation_count), + &mutation_count, + |b, &mutation_count| { + // Batch-based benchmarking + b.iter_batched( + || { + const REMOVAL_PROBABILITY: f64 = 0.2; + + // Fill tree with 10x more initial elements + let initial_fill_count = mutation_count * 10; + + // Initialize the tree with initial random values + let initial_kv_pairs = generate_kv_pairs(&mut rng, initial_fill_count); + let smt = SimpleSmt::::with_leaves(initial_kv_pairs.iter().cloned()) + .unwrap(); + + // Select and change a half of pairs from the filled tree (values to be + // updated or removed with given probability) + let mut mutation_kv_pairs: Vec<_> = initial_kv_pairs + .choose_multiple(&mut rng, mutation_count / 2) + .cloned() + .map(|(key, _value)| { + let value = if rng.gen_bool(REMOVAL_PROBABILITY) { + EMPTY_WORD + } else { + generate_word(&mut rng) + }; + + (key, value) + }) + .collect(); + + // Append another half of new values (values to be added) + for _ in 0..mutation_count / 2 { + mutation_kv_pairs.push((rng.gen(), generate_word(&mut rng))); + } + + // Compute mutations + let mutations = smt.compute_mutations( + mutation_kv_pairs + .into_iter() + .map(|(key, value)| (LeafIndex::new(key).unwrap(), value)), + ); + + (smt, mutations) + }, + |(mut smt, mutations)| { + // Apply mutations in the benchmark to measure execution time + smt.apply_mutations(mutations).unwrap(); + }, + BatchSize::SmallInput, + ); + }, + ); + } + + group.finish(); +} + +criterion_group!(benches, benchmark_apply_mutations); +criterion_main!(benches); + +// HELPER FUNCTIONS +// ================================================================================================= + +/// Helper function to generate random `(u64, Word)` key-value pairs +fn generate_kv_pairs(rng: &mut StdRng, count: usize) -> Vec<(u64, Word)> { + (0..count) + .map(|_| { + let key = rng.gen(); + let value = generate_word(rng); + + (key, value) + }) + .collect() +} + +/// Helper function to generate random `Word` +fn generate_word(rng: &mut StdRng) -> Word { + // Random Word value + [ + Felt::new(rng.gen()), + Felt::new(rng.gen()), + Felt::new(rng.gen()), + Felt::new(rng.gen()), + ] +} From ca2fe003b1bac56f50fb6041a06893849c93e4e5 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:19:39 +0500 Subject: [PATCH 06/19] docs: fix error --- src/merkle/smt/full/mod.rs | 2 +- src/merkle/smt/simple/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index 8abdd9e5..6dbf02b9 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -200,7 +200,7 @@ impl Smt { >::compute_mutations(self, kv_pairs) } - /// Applies the prospective mutations computed with [`SparseMerkleTree::compute_mutations()`] to + /// Applies the prospective mutations computed with [`Smt::compute_mutations()`] to /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the /// updated tree will revert the changes. /// diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index 4ae02df0..4579e0b9 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -221,7 +221,7 @@ impl SimpleSmt { >::compute_mutations(self, kv_pairs) } - /// Applies the prospective mutations computed with [`SparseMerkleTree::compute_mutations()`] to + /// Applies the prospective mutations computed with [`SimpleSmt::compute_mutations()`] to /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the /// updated tree will revert the changes. /// From 61634bbad1eb2d2c16a82d2bffce7e919920ca42 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:44:41 +0500 Subject: [PATCH 07/19] feat: add benchmark for `compute_mutations` method --- Cargo.lock | 10 ---- benches/smt-mutations.rs | 121 +++++++++++++++++++++++++-------------- src/merkle/smt/mod.rs | 6 -- 3 files changed, 79 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e822fb3..527b15b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -382,18 +382,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "half" version = "2.4.1" @@ -525,8 +517,6 @@ dependencies = [ "cc", "clap", "criterion", - "getrandom", - "glob", "hex", "num", "num-complex", diff --git a/benches/smt-mutations.rs b/benches/smt-mutations.rs index d922ca05..77db4cce 100644 --- a/benches/smt-mutations.rs +++ b/benches/smt-mutations.rs @@ -7,6 +7,37 @@ use rand::{prelude::SliceRandom, rngs::StdRng, Rng, SeedableRng}; const DEPTH: u8 = 64; +fn benchmark_compute_mutations(c: &mut Criterion) { + let mut group = c.benchmark_group("compute_mutations"); + group.sample_size(10); + group.measurement_time(std::time::Duration::from_secs(300)); + + // Fixed seed for reproducibility + let rng_seed = 42; + let mut rng = StdRng::seed_from_u64(rng_seed); + + // Benchmark for various mutation set sizes + for &mutation_count in &[10_000] { + group.bench_with_input( + BenchmarkId::new("SimpleSmt: compute_mutations", mutation_count), + &mutation_count, + |b, &mutation_count| { + // Batch-based benchmarking + b.iter_batched( + || generate_tree_and_mutations(&mut rng, mutation_count), + |(smt, mutations)| { + // Compute mutations in the benchmark to measure execution time + let _mutations = smt.compute_mutations(mutations); + }, + BatchSize::SmallInput, + ); + }, + ); + } + + group.finish(); +} + fn benchmark_apply_mutations(c: &mut Criterion) { let mut group = c.benchmark_group("apply_mutations"); group.sample_size(10); @@ -17,7 +48,7 @@ fn benchmark_apply_mutations(c: &mut Criterion) { let mut rng = StdRng::seed_from_u64(rng_seed); // Benchmark for various mutation set sizes - for &mutation_count in &[1_000, 100_000] { + for &mutation_count in &[10_000] { group.bench_with_input( BenchmarkId::new("SimpleSmt: apply_mutations", mutation_count), &mutation_count, @@ -25,43 +56,11 @@ fn benchmark_apply_mutations(c: &mut Criterion) { // Batch-based benchmarking b.iter_batched( || { - const REMOVAL_PROBABILITY: f64 = 0.2; - - // Fill tree with 10x more initial elements - let initial_fill_count = mutation_count * 10; - - // Initialize the tree with initial random values - let initial_kv_pairs = generate_kv_pairs(&mut rng, initial_fill_count); - let smt = SimpleSmt::::with_leaves(initial_kv_pairs.iter().cloned()) - .unwrap(); - - // Select and change a half of pairs from the filled tree (values to be - // updated or removed with given probability) - let mut mutation_kv_pairs: Vec<_> = initial_kv_pairs - .choose_multiple(&mut rng, mutation_count / 2) - .cloned() - .map(|(key, _value)| { - let value = if rng.gen_bool(REMOVAL_PROBABILITY) { - EMPTY_WORD - } else { - generate_word(&mut rng) - }; - - (key, value) - }) - .collect(); - - // Append another half of new values (values to be added) - for _ in 0..mutation_count / 2 { - mutation_kv_pairs.push((rng.gen(), generate_word(&mut rng))); - } + let (smt, mutation_kv_pairs) = + generate_tree_and_mutations(&mut rng, mutation_count); // Compute mutations - let mutations = smt.compute_mutations( - mutation_kv_pairs - .into_iter() - .map(|(key, value)| (LeafIndex::new(key).unwrap(), value)), - ); + let mutations = smt.compute_mutations(mutation_kv_pairs); (smt, mutations) }, @@ -78,22 +77,60 @@ fn benchmark_apply_mutations(c: &mut Criterion) { group.finish(); } -criterion_group!(benches, benchmark_apply_mutations); +criterion_group!(benches, benchmark_compute_mutations, benchmark_apply_mutations); criterion_main!(benches); // HELPER FUNCTIONS // ================================================================================================= -/// Helper function to generate random `(u64, Word)` key-value pairs -fn generate_kv_pairs(rng: &mut StdRng, count: usize) -> Vec<(u64, Word)> { - (0..count) +/// Helper function to generate initial `SimpleSmt` tree with random keys and values and mutation +/// key-value pairs +fn generate_tree_and_mutations( + rng: &mut StdRng, + mutation_count: usize, +) -> (SimpleSmt, Vec<(LeafIndex, Word)>) { + const INITIAL_FILL_COUNT: usize = 1_000_000; + const REMOVAL_PROBABILITY: f64 = 0.2; + + // Initialize the tree with initial random values + let initial_kv_pairs: Vec<_> = (0..INITIAL_FILL_COUNT) .map(|_| { - let key = rng.gen(); + let key: u64 = rng.gen(); let value = generate_word(rng); (key, value) }) - .collect() + .collect(); + + // Select and change a half of pairs from the filled tree (values to be + // updated or removed with given probability) + let mut mutation_kv_pairs: Vec<_> = initial_kv_pairs + .choose_multiple(rng, mutation_count / 2) + .cloned() + .map(|(key, _value)| { + let value = if rng.gen_bool(REMOVAL_PROBABILITY) { + EMPTY_WORD + } else { + generate_word(rng) + }; + + (key, value) + }) + .collect(); + + // Append another half of new values (values to be added) + for _ in 0..mutation_count / 2 { + mutation_kv_pairs.push((rng.gen(), generate_word(rng))); + } + + let smt = SimpleSmt::::with_leaves(initial_kv_pairs).unwrap(); + + let mutations: Vec<_> = mutation_kv_pairs + .into_iter() + .map(|(key, value)| (LeafIndex::new(key).unwrap(), value)) + .collect(); + + (smt, mutations) } /// Helper function to generate random `Word` diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 7cbdbaf8..26916aa6 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -553,9 +553,3 @@ impl Deserializable }) } } - -// TESTS -// ================================================================================================ - -#[cfg(test)] -mod tests; From 69c2097a284b977c5fa14c2991ae85f2fccf880b Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:26:32 +0500 Subject: [PATCH 08/19] refactor: add getters for `MutationSet` fields --- src/merkle/index.rs | 2 +- src/merkle/smt/mod.rs | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/merkle/index.rs b/src/merkle/index.rs index 104ceb44..d6d6d86c 100644 --- a/src/merkle/index.rs +++ b/src/merkle/index.rs @@ -128,7 +128,7 @@ impl NodeIndex { self.value } - /// Returns true if the current instance points to a right sibling node. + /// Returns `true` if the current instance points to a right sibling node. pub const fn is_value_odd(&self) -> bool { (self.value & 1) == 1 } diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 26916aa6..c95cde04 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -445,7 +445,7 @@ impl TryFrom for LeafIndex { /// [`MutationSet`] stores this type in relation to a [`NodeIndex`] to keep track of what changes /// need to occur at which node indices. #[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum NodeMutation { +pub enum NodeMutation { /// Corresponds to [`SparseMerkleTree::remove_inner_node()`]. Removal, /// Corresponds to [`SparseMerkleTree::insert_inner_node()`]. @@ -478,11 +478,27 @@ pub struct MutationSet { } impl MutationSet { - /// Queries the root that was calculated during `SparseMerkleTree::compute_mutations()`. See + /// Returns the SMT root that was calculated during `SparseMerkleTree::compute_mutations()`. See /// that method for more information. pub fn root(&self) -> RpoDigest { self.new_root } + + /// Returns the SMT root before the mutations were applied. + pub fn old_root(&self) -> RpoDigest { + self.old_root + } + + /// Returns the set of inner nodes that need to be removed or added. + pub fn node_mutations(&self) -> &BTreeMap { + &self.node_mutations + } + + /// Returns the set of top-level key-value pairs that need to be added, updated or deleted + /// (i.e. set to `EMPTY_WORD`). + pub fn new_pairs(&self) -> &BTreeMap { + &self.new_pairs + } } // SERIALIZATION From bb31cbe5e6965cf13f121e987e6f30e6dee5bb25 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Mon, 23 Dec 2024 20:02:18 +0500 Subject: [PATCH 09/19] fix: clippy warnings --- src/merkle/smt/full/tests.rs | 2 +- src/merkle/smt/mod.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index 77bd97b5..bca2f8ae 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -425,7 +425,7 @@ fn test_prospective_insertion() { ); assert_eq!( revert.node_mutations, - smt.inner_nodes.iter().map(|(key, _)| (*key, NodeMutation::Removal)).collect(), + smt.inner_nodes.keys().map(|key| (*key, NodeMutation::Removal)).collect(), "reverse mutations inner nodes did not match" ); diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index c95cde04..e28c2ed6 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -1,6 +1,5 @@ use alloc::{collections::BTreeMap, vec::Vec}; -use num::Integer; use winter_utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}; use super::{EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, NodeIndex}; @@ -374,7 +373,7 @@ pub(crate) trait SparseMerkleTree { #[derive(Debug, Default, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub(crate) struct InnerNode { +pub struct InnerNode { pub left: RpoDigest, pub right: RpoDigest, } From 1a2eca52beebdb07a316c8076d2ace48220aeab6 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Mon, 23 Dec 2024 21:51:25 +0500 Subject: [PATCH 10/19] refactor: make two separate methods for mutations application --- src/merkle/smt/full/mod.rs | 18 ++++++++++-- src/merkle/smt/full/tests.rs | 12 ++++---- src/merkle/smt/mod.rs | 54 +++++++++++++++++++++++++++++++++++- src/merkle/smt/simple/mod.rs | 19 +++++++++++-- 4 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index 6dbf02b9..d04bb9d9 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -200,6 +200,20 @@ impl Smt { >::compute_mutations(self, kv_pairs) } + /// Applies the prospective mutations computed with [`Smt::compute_mutations()`] to this tree. + /// + /// # Errors + /// If `mutations` was computed on a tree with a different root than this one, returns + /// [`MerkleError::ConflictingRoots`] with a two-item [`Vec`]. The first item is the root hash + /// the `mutations` were computed against, and the second item is the actual current root of + /// this tree. + pub fn apply_mutations( + &mut self, + mutations: MutationSet, + ) -> Result<(), MerkleError> { + >::apply_mutations(self, mutations) + } + /// Applies the prospective mutations computed with [`Smt::compute_mutations()`] to /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the /// updated tree will revert the changes. @@ -209,11 +223,11 @@ impl Smt { /// [`MerkleError::ConflictingRoots`] with a two-item [`Vec`]. The first item is the root hash /// the `mutations` were computed against, and the second item is the actual current root of /// this tree. - pub fn apply_mutations( + pub fn apply_mutations_with_reversion( &mut self, mutations: MutationSet, ) -> Result, MerkleError> { - >::apply_mutations(self, mutations) + >::apply_mutations_with_reversion(self, mutations) } // HELPERS diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index bca2f8ae..c85f3bf5 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -414,7 +414,7 @@ fn test_prospective_insertion() { let mutations = smt.compute_mutations(vec![(key_1, value_1)]); assert_eq!(mutations.root(), root_1, "prospective root 1 did not match actual root 1"); - let revert = smt.apply_mutations(mutations).unwrap(); + let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); assert_eq!(smt.root(), root_1, "mutations before and after apply did not match"); assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), root_empty, "reverse mutations new root did not match"); @@ -435,7 +435,7 @@ fn test_prospective_insertion() { smt.compute_mutations(vec![(key_3, EMPTY_WORD), (key_2, value_2), (key_3, value_3)]); assert_eq!(mutations.root(), root_3, "mutations before and after apply did not match"); let old_root = smt.root(); - let revert = smt.apply_mutations(mutations).unwrap(); + let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), old_root, "reverse mutations new root did not match"); assert_eq!( @@ -448,7 +448,7 @@ fn test_prospective_insertion() { let mutations = smt.compute_mutations(vec![(key_3, EMPTY_WORD), (key_3, value_3)]); assert_eq!(mutations.root(), root_3); let old_root = smt.root(); - let revert = smt.apply_mutations(mutations).unwrap(); + let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); assert_eq!(smt.root(), root_3); assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), old_root, "reverse mutations new root did not match"); @@ -468,7 +468,7 @@ fn test_prospective_insertion() { "prospective root for batch removal did not match actual root", ); let old_root = smt.root(); - let revert = smt.apply_mutations(mutations).unwrap(); + let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); assert_eq!(smt.root(), root_empty, "mutations before and after apply did not match"); assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), old_root, "reverse mutations new root did not match"); @@ -507,7 +507,7 @@ fn test_mutations_revert() { let original = smt.clone(); - let revert = smt.apply_mutations(mutations).unwrap(); + let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), original.root(), "reverse mutations new root did not match"); @@ -542,7 +542,7 @@ fn test_mutation_set_serialization() { assert_eq!(deserialized, mutations, "deserialized mutations did not match original"); - let revert = smt.apply_mutations(mutations).unwrap(); + let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); let serialized = revert.to_bytes(); let deserialized = diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index e28c2ed6..4dbd84ca 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -243,6 +243,58 @@ pub(crate) trait SparseMerkleTree { } } + /// Applies the prospective mutations computed with [`SparseMerkleTree::compute_mutations()`] to + /// this tree. + /// + /// # Errors + /// If `mutations` was computed on a tree with a different root than this one, returns + /// [`MerkleError::ConflictingRoots`] with a two-item [`Vec`]. The first item is the root hash + /// the `mutations` were computed against, and the second item is the actual current root of + /// this tree. + fn apply_mutations( + &mut self, + mutations: MutationSet, + ) -> Result<(), MerkleError> + where + Self: Sized, + { + use NodeMutation::*; + let MutationSet { + old_root, + node_mutations, + new_pairs, + new_root, + } = mutations; + + // Guard against accidentally trying to apply mutations that were computed against a + // different tree, including a stale version of this tree. + if old_root != self.root() { + return Err(MerkleError::ConflictingRoots { + expected_root: self.root(), + actual_root: old_root, + }); + } + + for (index, mutation) in node_mutations { + match mutation { + Removal => { + self.remove_inner_node(index); + }, + Addition(node) => { + self.insert_inner_node(index, node); + }, + } + } + + for (key, value) in new_pairs { + self.insert_value(key, value); + } + + self.set_root(new_root); + + Ok(()) + } + /// Applies the prospective mutations computed with [`SparseMerkleTree::compute_mutations()`] to /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the /// updated tree will revert the changes. @@ -252,7 +304,7 @@ pub(crate) trait SparseMerkleTree { /// [`MerkleError::ConflictingRoots`] with a two-item [`Vec`]. The first item is the root hash /// the `mutations` were computed against, and the second item is the actual current root of /// this tree. - fn apply_mutations( + fn apply_mutations_with_reversion( &mut self, mutations: MutationSet, ) -> Result, MerkleError> diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index 4579e0b9..5976476c 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -221,6 +221,21 @@ impl SimpleSmt { >::compute_mutations(self, kv_pairs) } + /// Applies the prospective mutations computed with [`SimpleSmt::compute_mutations()`] to this + /// tree. + /// + /// # Errors + /// If `mutations` was computed on a tree with a different root than this one, returns + /// [`MerkleError::ConflictingRoots`] with a two-item [`alloc::vec::Vec`]. The first item is the + /// root hash the `mutations` were computed against, and the second item is the actual + /// current root of this tree. + pub fn apply_mutations( + &mut self, + mutations: MutationSet, Word>, + ) -> Result<(), MerkleError> { + >::apply_mutations(self, mutations) + } + /// Applies the prospective mutations computed with [`SimpleSmt::compute_mutations()`] to /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the /// updated tree will revert the changes. @@ -230,11 +245,11 @@ impl SimpleSmt { /// [`MerkleError::ConflictingRoots`] with a two-item [`alloc::vec::Vec`]. The first item is the /// root hash the `mutations` were computed against, and the second item is the actual /// current root of this tree. - pub fn apply_mutations( + pub fn apply_mutations_with_reversion( &mut self, mutations: MutationSet, Word>, ) -> Result, Word>, MerkleError> { - >::apply_mutations(self, mutations) + >::apply_mutations_with_reversion(self, mutations) } /// Inserts a subtree at the specified index. The depth at which the subtree is inserted is From 3cc7003166f5f3589db717890d17ed4b9a7c59e2 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Wed, 25 Dec 2024 12:17:24 +0500 Subject: [PATCH 11/19] tests: check both `apply_mutations` and `apply_mutations_with_reversion` --- src/merkle/smt/full/tests.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index c85f3bf5..8ed5af45 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -414,7 +414,7 @@ fn test_prospective_insertion() { let mutations = smt.compute_mutations(vec![(key_1, value_1)]); assert_eq!(mutations.root(), root_1, "prospective root 1 did not match actual root 1"); - let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); + let revert = apply_mutations(&mut smt, mutations); assert_eq!(smt.root(), root_1, "mutations before and after apply did not match"); assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), root_empty, "reverse mutations new root did not match"); @@ -435,7 +435,7 @@ fn test_prospective_insertion() { smt.compute_mutations(vec![(key_3, EMPTY_WORD), (key_2, value_2), (key_3, value_3)]); assert_eq!(mutations.root(), root_3, "mutations before and after apply did not match"); let old_root = smt.root(); - let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); + let revert = apply_mutations(&mut smt, mutations); assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), old_root, "reverse mutations new root did not match"); assert_eq!( @@ -448,7 +448,7 @@ fn test_prospective_insertion() { let mutations = smt.compute_mutations(vec![(key_3, EMPTY_WORD), (key_3, value_3)]); assert_eq!(mutations.root(), root_3); let old_root = smt.root(); - let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); + let revert = apply_mutations(&mut smt, mutations); assert_eq!(smt.root(), root_3); assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), old_root, "reverse mutations new root did not match"); @@ -468,7 +468,7 @@ fn test_prospective_insertion() { "prospective root for batch removal did not match actual root", ); let old_root = smt.root(); - let revert = smt.apply_mutations_with_reversion(mutations).unwrap(); + let revert = apply_mutations(&mut smt, mutations); assert_eq!(smt.root(), root_empty, "mutations before and after apply did not match"); assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), old_root, "reverse mutations new root did not match"); @@ -706,3 +706,19 @@ fn build_multiple_leaf_node(kv_pairs: &[(RpoDigest, Word)]) -> RpoDigest { Rpo256::hash_elements(&elements) } + +/// Applies mutations with and without reversion to the given SMT, comparing resulting SMTs, +/// returning mutation set for reversion. +fn apply_mutations( + smt: &mut Smt, + mutation_set: MutationSet, +) -> MutationSet { + let mut smt2 = smt.clone(); + + let reversion = smt.apply_mutations_with_reversion(mutation_set.clone()).unwrap(); + smt2.apply_mutations(mutation_set).unwrap(); + + assert_eq!(&smt2, smt); + + reversion +} From 0596892cec5a9bd00bd58362a0dfd5bc001f9cc9 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Wed, 25 Dec 2024 22:37:54 +0500 Subject: [PATCH 12/19] feat: add `num_leaves` method for `Smt` --- src/merkle/smt/full/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index d04bb9d9..0b0de3b9 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -114,6 +114,11 @@ impl Smt { >::root(self) } + /// Returns the number of non-empty leaves in this tree. + pub fn num_leaves(&self) -> usize { + self.leaves.len() + } + /// Returns the leaf to which `key` maps pub fn get_leaf(&self, key: &RpoDigest) -> SmtLeaf { >::get_leaf(self, key) From 6737fc0a62cce2a500d235a3e1efae2a73693556 Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Wed, 25 Dec 2024 22:38:11 +0500 Subject: [PATCH 13/19] refactor: improve ad-hoc benchmarks --- src/main.rs | 159 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 112 insertions(+), 47 deletions(-) diff --git a/src/main.rs b/src/main.rs index 776ccc21..cdd8b03b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,9 @@ use clap::Parser; use miden_crypto::{ hash::rpo::{Rpo256, RpoDigest}, merkle::{MerkleError, Smt}, - Felt, Word, ONE, + Felt, Word, EMPTY_WORD, ONE, }; +use rand::{prelude::IteratorRandom, thread_rng, Rng}; use rand_utils::rand_value; #[derive(Parser, Debug)] @@ -13,7 +14,7 @@ use rand_utils::rand_value; pub struct BenchmarkCmd { /// Size of the tree #[clap(short = 's', long = "size")] - size: u64, + size: usize, } fn main() { @@ -29,25 +30,25 @@ pub fn benchmark_smt() { let mut entries = Vec::new(); for i in 0..tree_size { let key = rand_value::(); - let value = [ONE, ONE, ONE, Felt::new(i)]; + let value = [ONE, ONE, ONE, Felt::new(i as u64)]; entries.push((key, value)); } - let mut tree = construction(entries, tree_size).unwrap(); - insertion(&mut tree, tree_size).unwrap(); - batched_insertion(&mut tree, tree_size).unwrap(); - proof_generation(&mut tree, tree_size).unwrap(); + let mut tree = construction(entries.clone(), tree_size).unwrap(); + insertion(&mut tree).unwrap(); + batched_insertion(&mut tree).unwrap(); + batched_update(&mut tree, entries).unwrap(); + proof_generation(&mut tree).unwrap(); } /// Runs the construction benchmark for [`Smt`], returning the constructed tree. -pub fn construction(entries: Vec<(RpoDigest, Word)>, size: u64) -> Result { +pub fn construction(entries: Vec<(RpoDigest, Word)>, size: usize) -> Result { println!("Running a construction benchmark:"); let now = Instant::now(); let tree = Smt::with_entries(entries)?; let elapsed = now.elapsed(); println!( - "Constructed a SMT with {} key-value pairs in {:.3} seconds", - size, + "Constructed a SMT with {size} key-value pairs in {:.3} seconds", elapsed.as_secs_f32(), ); @@ -57,39 +58,46 @@ pub fn construction(entries: Vec<(RpoDigest, Word)>, size: u64) -> Result Result<(), MerkleError> { +pub fn insertion(tree: &mut Smt) -> Result<(), MerkleError> { + const NUM_INSERTIONS: usize = 1_000; + println!("Running an insertion benchmark:"); + let size = tree.num_leaves(); + let mut insertion_times = Vec::new(); - for i in 0..20 { + for i in 0..NUM_INSERTIONS { let test_key = Rpo256::hash(&rand_value::().to_be_bytes()); - let test_value = [ONE, ONE, ONE, Felt::new(size + i)]; + let test_value = [ONE, ONE, ONE, Felt::new((size + i) as u64)]; let now = Instant::now(); tree.insert(test_key, test_value); let elapsed = now.elapsed(); - insertion_times.push(elapsed.as_secs_f32()); + insertion_times.push(elapsed.as_micros()); } println!( - "An average insertion time measured by 20 inserts into a SMT with {} key-value pairs is {:.3} milliseconds\n", - size, - // calculate the average by dividing by 20 and convert to milliseconds by multiplying by - // 1000. As a result, we can only multiply by 50 - insertion_times.iter().sum::() * 50f32, + "An average insertion time measured by {NUM_INSERTIONS} inserts into an SMT with {size} \ + leaves is {:.3} microseconds\n", + // calculate the average + insertion_times.iter().sum::() as f64 / (NUM_INSERTIONS as f64), ); Ok(()) } -pub fn batched_insertion(tree: &mut Smt, size: u64) -> Result<(), MerkleError> { +pub fn batched_insertion(tree: &mut Smt) -> Result<(), MerkleError> { + const NUM_INSERTIONS: usize = 10_000; + println!("Running a batched insertion benchmark:"); - let new_pairs: Vec<(RpoDigest, Word)> = (0..1000) + let size = tree.num_leaves(); + + let new_pairs: Vec<(RpoDigest, Word)> = (0..NUM_INSERTIONS) .map(|i| { let key = Rpo256::hash(&rand_value::().to_be_bytes()); - let value = [ONE, ONE, ONE, Felt::new(size + i)]; + let value = [ONE, ONE, ONE, Felt::new((size + i) as u64)]; (key, value) }) .collect(); @@ -99,31 +107,86 @@ pub fn batched_insertion(tree: &mut Smt, size: u64) -> Result<(), MerkleError> { let compute_elapsed = now.elapsed(); let now = Instant::now(); - tree.apply_mutations(mutations).unwrap(); + tree.apply_mutations(mutations)?; let apply_elapsed = now.elapsed(); println!( - "An average batch computation time measured by a 1k-batch into an SMT with {} key-value pairs over {:.3} milliseconds is {:.3} milliseconds", - size, - compute_elapsed.as_secs_f32() * 1000f32, - // Dividing by the number of iterations, 1000, and then multiplying by 1000 to get - // milliseconds, cancels out. - compute_elapsed.as_secs_f32(), + "An average insert-batch computation time measured by a {NUM_INSERTIONS}-batch into an SMT \ + with {size} leaves over {:.3} milliseconds is {:.3} milliseconds", + compute_elapsed.as_secs_f64() * 1000.0, + compute_elapsed.as_secs_f64() * 1000.0 / NUM_INSERTIONS as f64, ); println!( - "An average batch application time measured by a 1k-batch into an SMT with {} key-value pairs over {:.3} milliseconds is {:.3} milliseconds", - size, - apply_elapsed.as_secs_f32() * 1000f32, - // Dividing by the number of iterations, 1000, and then multiplying by 1000 to get - // milliseconds, cancels out. - apply_elapsed.as_secs_f32(), + "An average insert-batch application time measured by a {NUM_INSERTIONS}-batch into an SMT \ + with {size} leaves over {:.3} milliseconds is {:.3} milliseconds", + apply_elapsed.as_secs_f64() * 1000.0, + apply_elapsed.as_secs_f64() * 1000.0 / NUM_INSERTIONS as f64, ); println!( - "An average batch insertion time measured by a 1k-batch into an SMT with {} key-value pairs totals to {:.3} milliseconds", - size, - (compute_elapsed + apply_elapsed).as_secs_f32() * 1000f32, + "An average batch insertion time measured by a 10k-batch into an SMT with {size} leaves \ + totals to {:.3} milliseconds", + (compute_elapsed + apply_elapsed).as_secs_f64() * 1000.0, + ); + + println!(); + + Ok(()) +} + +pub fn batched_update(tree: &mut Smt, entries: Vec<(RpoDigest, Word)>) -> Result<(), MerkleError> { + const NUM_UPDATES: usize = 10_000; + const REMOVAL_PROBABILITY: f64 = 0.2; + + println!("Running a batched update benchmark:"); + + let size = tree.num_leaves(); + let mut rng = thread_rng(); + + let new_pairs = + entries + .into_iter() + .choose_multiple(&mut rng, NUM_UPDATES) + .into_iter() + .map(|(key, _)| { + let value = if rng.gen_bool(REMOVAL_PROBABILITY) { + EMPTY_WORD + } else { + [ONE, ONE, ONE, Felt::new(rng.gen())] + }; + + (key, value) + }); + + assert_eq!(new_pairs.len(), NUM_UPDATES); + + let now = Instant::now(); + let mutations = tree.compute_mutations(new_pairs); + let compute_elapsed = now.elapsed(); + + let now = Instant::now(); + tree.apply_mutations(mutations)?; + let apply_elapsed = now.elapsed(); + + println!( + "An average update-batch computation time measured by a {NUM_UPDATES}-batch into an SMT \ + with {size} leaves over {:.3} milliseconds is {:.3} milliseconds", + compute_elapsed.as_secs_f64() * 1000.0, + compute_elapsed.as_secs_f64() * 1000.0 / NUM_UPDATES as f64, + ); + + println!( + "An average update-batch application time measured by a {NUM_UPDATES}-batch into an SMT with \ + {size} leaves over {:.3} milliseconds is {:.3} milliseconds", + apply_elapsed.as_secs_f64() * 1000.0, + apply_elapsed.as_secs_f64() * 1000.0 / NUM_UPDATES as f64, + ); + + println!( + "An average batch update time measured by a 10k-batch into an SMT with {size} leaves \ + totals to {:.3} milliseconds", + (compute_elapsed + apply_elapsed).as_secs_f64() * 1000.0, ); println!(); @@ -132,28 +195,30 @@ pub fn batched_insertion(tree: &mut Smt, size: u64) -> Result<(), MerkleError> { } /// Runs the proof generation benchmark for the [`Smt`]. -pub fn proof_generation(tree: &mut Smt, size: u64) -> Result<(), MerkleError> { +pub fn proof_generation(tree: &mut Smt) -> Result<(), MerkleError> { + const NUM_PROOFS: usize = 20; + println!("Running a proof generation benchmark:"); let mut insertion_times = Vec::new(); + let size = tree.num_leaves(); + for i in 0..20 { let test_key = Rpo256::hash(&rand_value::().to_be_bytes()); - let test_value = [ONE, ONE, ONE, Felt::new(size + i)]; + let test_value = [ONE, ONE, ONE, Felt::new((size + i) as u64)]; tree.insert(test_key, test_value); let now = Instant::now(); let _proof = tree.open(&test_key); - let elapsed = now.elapsed(); - insertion_times.push(elapsed.as_secs_f32()); + insertion_times.push(now.elapsed().as_micros()); } println!( - "An average proving time measured by 20 value proofs in a SMT with {} key-value pairs in {:.3} microseconds", - size, - // calculate the average by dividing by 20 and convert to microseconds by multiplying by - // 1000000. As a result, we can only multiply by 50000 - insertion_times.iter().sum::() * 50000f32, + "An average proving time measured by {NUM_PROOFS} value proofs in an SMT with {size} \ + key-value pairs in {:.3} microseconds", + // calculate the average + insertion_times.iter().sum::() as f64 / (NUM_PROOFS as f64), ); Ok(()) From 533c459ecf5941e0ea87469e4c33c32668dde31a Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:24:28 +0500 Subject: [PATCH 14/19] refactor: remove criterion benches --- Cargo.toml | 4 - benches/smt-mutations.rs | 145 ----------------------------------- src/main.rs | 2 +- src/merkle/smt/full/tests.rs | 2 +- 4 files changed, 2 insertions(+), 151 deletions(-) delete mode 100644 benches/smt-mutations.rs diff --git a/Cargo.toml b/Cargo.toml index 98da1ac3..5d124c68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,10 +27,6 @@ harness = false name = "smt" harness = false -[[bench]] -name = "smt-mutations" -harness = false - [[bench]] name = "store" harness = false diff --git a/benches/smt-mutations.rs b/benches/smt-mutations.rs deleted file mode 100644 index 77db4cce..00000000 --- a/benches/smt-mutations.rs +++ /dev/null @@ -1,145 +0,0 @@ -use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; -use miden_crypto::{ - merkle::{LeafIndex, SimpleSmt}, - Felt, Word, EMPTY_WORD, -}; -use rand::{prelude::SliceRandom, rngs::StdRng, Rng, SeedableRng}; - -const DEPTH: u8 = 64; - -fn benchmark_compute_mutations(c: &mut Criterion) { - let mut group = c.benchmark_group("compute_mutations"); - group.sample_size(10); - group.measurement_time(std::time::Duration::from_secs(300)); - - // Fixed seed for reproducibility - let rng_seed = 42; - let mut rng = StdRng::seed_from_u64(rng_seed); - - // Benchmark for various mutation set sizes - for &mutation_count in &[10_000] { - group.bench_with_input( - BenchmarkId::new("SimpleSmt: compute_mutations", mutation_count), - &mutation_count, - |b, &mutation_count| { - // Batch-based benchmarking - b.iter_batched( - || generate_tree_and_mutations(&mut rng, mutation_count), - |(smt, mutations)| { - // Compute mutations in the benchmark to measure execution time - let _mutations = smt.compute_mutations(mutations); - }, - BatchSize::SmallInput, - ); - }, - ); - } - - group.finish(); -} - -fn benchmark_apply_mutations(c: &mut Criterion) { - let mut group = c.benchmark_group("apply_mutations"); - group.sample_size(10); - group.measurement_time(std::time::Duration::from_secs(300)); - - // Fixed seed for reproducibility - let rng_seed = 42; - let mut rng = StdRng::seed_from_u64(rng_seed); - - // Benchmark for various mutation set sizes - for &mutation_count in &[10_000] { - group.bench_with_input( - BenchmarkId::new("SimpleSmt: apply_mutations", mutation_count), - &mutation_count, - |b, &mutation_count| { - // Batch-based benchmarking - b.iter_batched( - || { - let (smt, mutation_kv_pairs) = - generate_tree_and_mutations(&mut rng, mutation_count); - - // Compute mutations - let mutations = smt.compute_mutations(mutation_kv_pairs); - - (smt, mutations) - }, - |(mut smt, mutations)| { - // Apply mutations in the benchmark to measure execution time - smt.apply_mutations(mutations).unwrap(); - }, - BatchSize::SmallInput, - ); - }, - ); - } - - group.finish(); -} - -criterion_group!(benches, benchmark_compute_mutations, benchmark_apply_mutations); -criterion_main!(benches); - -// HELPER FUNCTIONS -// ================================================================================================= - -/// Helper function to generate initial `SimpleSmt` tree with random keys and values and mutation -/// key-value pairs -fn generate_tree_and_mutations( - rng: &mut StdRng, - mutation_count: usize, -) -> (SimpleSmt, Vec<(LeafIndex, Word)>) { - const INITIAL_FILL_COUNT: usize = 1_000_000; - const REMOVAL_PROBABILITY: f64 = 0.2; - - // Initialize the tree with initial random values - let initial_kv_pairs: Vec<_> = (0..INITIAL_FILL_COUNT) - .map(|_| { - let key: u64 = rng.gen(); - let value = generate_word(rng); - - (key, value) - }) - .collect(); - - // Select and change a half of pairs from the filled tree (values to be - // updated or removed with given probability) - let mut mutation_kv_pairs: Vec<_> = initial_kv_pairs - .choose_multiple(rng, mutation_count / 2) - .cloned() - .map(|(key, _value)| { - let value = if rng.gen_bool(REMOVAL_PROBABILITY) { - EMPTY_WORD - } else { - generate_word(rng) - }; - - (key, value) - }) - .collect(); - - // Append another half of new values (values to be added) - for _ in 0..mutation_count / 2 { - mutation_kv_pairs.push((rng.gen(), generate_word(rng))); - } - - let smt = SimpleSmt::::with_leaves(initial_kv_pairs).unwrap(); - - let mutations: Vec<_> = mutation_kv_pairs - .into_iter() - .map(|(key, value)| (LeafIndex::new(key).unwrap(), value)) - .collect(); - - (smt, mutations) -} - -/// Helper function to generate random `Word` -fn generate_word(rng: &mut StdRng) -> Word { - // Random Word value - [ - Felt::new(rng.gen()), - Felt::new(rng.gen()), - Felt::new(rng.gen()), - Felt::new(rng.gen()), - ] -} diff --git a/src/main.rs b/src/main.rs index cdd8b03b..24293daf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -216,7 +216,7 @@ pub fn proof_generation(tree: &mut Smt) -> Result<(), MerkleError> { println!( "An average proving time measured by {NUM_PROOFS} value proofs in an SMT with {size} \ - key-value pairs in {:.3} microseconds", + leaves in {:.3} microseconds", // calculate the average insertion_times.iter().sum::() as f64 / (NUM_PROOFS as f64), ); diff --git a/src/merkle/smt/full/tests.rs b/src/merkle/smt/full/tests.rs index 8ed5af45..6404f294 100644 --- a/src/merkle/smt/full/tests.rs +++ b/src/merkle/smt/full/tests.rs @@ -511,7 +511,7 @@ fn test_mutations_revert() { assert_eq!(revert.old_root, smt.root(), "reverse mutations old root did not match"); assert_eq!(revert.root(), original.root(), "reverse mutations new root did not match"); - let _ = smt.apply_mutations(revert).unwrap(); + smt.apply_mutations(revert).unwrap(); assert_eq!(smt, original, "SMT with applied revert mutations did not match original SMT"); } From 7777e3344a0816cf6d37f0a0571a8795148ef32a Mon Sep 17 00:00:00 2001 From: polydez <155382956+polydez@users.noreply.github.com> Date: Thu, 26 Dec 2024 15:06:58 +0500 Subject: [PATCH 15/19] fix: compilation errors --- Cargo.lock | 10 ++++++++++ src/merkle/smt/mod.rs | 5 +---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 527b15b7..3e822fb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -382,10 +382,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "half" version = "2.4.1" @@ -517,6 +525,8 @@ dependencies = [ "cc", "clap", "criterion", + "getrandom", + "glob", "hex", "num", "num-complex", diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index 4dbd84ca..c5ba9b1e 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -269,10 +269,7 @@ pub(crate) trait SparseMerkleTree { // Guard against accidentally trying to apply mutations that were computed against a // different tree, including a stale version of this tree. if old_root != self.root() { - return Err(MerkleError::ConflictingRoots { - expected_root: self.root(), - actual_root: old_root, - }); + return Err(MerkleError::ConflictingRoots(vec![old_root, self.root()])); } for (index, mutation) in node_mutations { From 06596e27704719a590489c71ebbae19726f8cd60 Mon Sep 17 00:00:00 2001 From: Bobbin Threadbare Date: Thu, 26 Dec 2024 16:29:22 -0800 Subject: [PATCH 16/19] chore: fix build --- src/merkle/mmr/partial.rs | 2 +- src/merkle/smt/mod.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/merkle/mmr/partial.rs b/src/merkle/mmr/partial.rs index 5327548d..b29c4f52 100644 --- a/src/merkle/mmr/partial.rs +++ b/src/merkle/mmr/partial.rs @@ -303,7 +303,7 @@ impl PartialMmr { if leaf_pos + 1 == self.forest && path.depth() == 0 - && self.peaks.last().map_or(false, |v| *v == leaf) + && self.peaks.last().is_some_and(|v| *v == leaf) { self.track_latest = true; return Ok(()); diff --git a/src/merkle/smt/mod.rs b/src/merkle/smt/mod.rs index a7c25395..6543fb30 100644 --- a/src/merkle/smt/mod.rs +++ b/src/merkle/smt/mod.rs @@ -322,7 +322,10 @@ pub(crate) trait SparseMerkleTree { // Guard against accidentally trying to apply mutations that were computed against a // different tree, including a stale version of this tree. if old_root != self.root() { - return Err(MerkleError::ConflictingRoots(vec![old_root, self.root()])); + return Err(MerkleError::ConflictingRoots { + expected_root: self.root(), + actual_root: old_root, + }); } let mut reverse_mutations = BTreeMap::new(); From 2a2f7c5a55ba8bff750221fa4510d750bcc6048c Mon Sep 17 00:00:00 2001 From: Bobbin Threadbare Date: Thu, 26 Dec 2024 17:28:04 -0800 Subject: [PATCH 17/19] chore: minor smt benchmark improvements --- Makefile | 10 ++++-- src/main.rs | 67 +++++++++++++++--------------------- src/merkle/smt/full/mod.rs | 7 ++-- src/merkle/smt/simple/mod.rs | 5 +-- 4 files changed, 42 insertions(+), 47 deletions(-) diff --git a/Makefile b/Makefile index 31894c9a..dcf0eb48 100644 --- a/Makefile +++ b/Makefile @@ -81,6 +81,10 @@ build-sve: ## Build with sve support # --- benchmarking -------------------------------------------------------------------------------- -.PHONY: bench-tx -bench-tx: ## Run crypto benchmarks - cargo bench +.PHONY: bench +bench: ## Run crypto benchmarks + cargo bench --features="concurrent" + +.PHONY: bench-smt-concurrent +bench-smt-concurrent: ## Run SMT benchmarks with concurrent feature + cargo run --release --features executable -- --size 1000000 diff --git a/src/main.rs b/src/main.rs index 24293daf..fca8da0d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,12 +46,9 @@ pub fn construction(entries: Vec<(RpoDigest, Word)>, size: usize) -> Result Result<(), MerkleError> { } println!( - "An average insertion time measured by {NUM_INSERTIONS} inserts into an SMT with {size} \ - leaves is {:.3} microseconds\n", + "An average insertion time measured by {NUM_INSERTIONS} inserts into an SMT with {size} leaves is {:.1} μs\n", // calculate the average insertion_times.iter().sum::() as f64 / (NUM_INSERTIONS as f64), ); @@ -88,7 +84,7 @@ pub fn insertion(tree: &mut Smt) -> Result<(), MerkleError> { } pub fn batched_insertion(tree: &mut Smt) -> Result<(), MerkleError> { - const NUM_INSERTIONS: usize = 10_000; + const NUM_INSERTIONS: usize = 1_000; println!("Running a batched insertion benchmark:"); @@ -104,30 +100,27 @@ pub fn batched_insertion(tree: &mut Smt) -> Result<(), MerkleError> { let now = Instant::now(); let mutations = tree.compute_mutations(new_pairs); - let compute_elapsed = now.elapsed(); + let compute_elapsed = now.elapsed().as_secs_f64() * 1000_f64; let now = Instant::now(); tree.apply_mutations(mutations)?; - let apply_elapsed = now.elapsed(); + let apply_elapsed = now.elapsed().as_secs_f64() * 1000_f64; println!( - "An average insert-batch computation time measured by a {NUM_INSERTIONS}-batch into an SMT \ - with {size} leaves over {:.3} milliseconds is {:.3} milliseconds", - compute_elapsed.as_secs_f64() * 1000.0, - compute_elapsed.as_secs_f64() * 1000.0 / NUM_INSERTIONS as f64, + "An average insert-batch computation time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {:.1} ms", + compute_elapsed, + compute_elapsed / NUM_INSERTIONS as f64, ); println!( - "An average insert-batch application time measured by a {NUM_INSERTIONS}-batch into an SMT \ - with {size} leaves over {:.3} milliseconds is {:.3} milliseconds", - apply_elapsed.as_secs_f64() * 1000.0, - apply_elapsed.as_secs_f64() * 1000.0 / NUM_INSERTIONS as f64, + "An average insert-batch application time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {:.1} ms", + apply_elapsed, + apply_elapsed / NUM_INSERTIONS as f64, ); println!( - "An average batch insertion time measured by a 10k-batch into an SMT with {size} leaves \ - totals to {:.3} milliseconds", - (compute_elapsed + apply_elapsed).as_secs_f64() * 1000.0, + "An average batch insertion time measured by a 1k-batch into an SMT with {size} leaves totals to {:.1} ms", + (compute_elapsed + apply_elapsed), ); println!(); @@ -136,7 +129,7 @@ pub fn batched_insertion(tree: &mut Smt) -> Result<(), MerkleError> { } pub fn batched_update(tree: &mut Smt, entries: Vec<(RpoDigest, Word)>) -> Result<(), MerkleError> { - const NUM_UPDATES: usize = 10_000; + const NUM_UPDATES: usize = 1_000; const REMOVAL_PROBABILITY: f64 = 0.2; println!("Running a batched update benchmark:"); @@ -163,30 +156,27 @@ pub fn batched_update(tree: &mut Smt, entries: Vec<(RpoDigest, Word)>) -> Result let now = Instant::now(); let mutations = tree.compute_mutations(new_pairs); - let compute_elapsed = now.elapsed(); + let compute_elapsed = now.elapsed().as_secs_f64() * 1000_f64; // time in ms let now = Instant::now(); tree.apply_mutations(mutations)?; - let apply_elapsed = now.elapsed(); + let apply_elapsed = now.elapsed().as_secs_f64() * 1000_f64; // time in ms println!( - "An average update-batch computation time measured by a {NUM_UPDATES}-batch into an SMT \ - with {size} leaves over {:.3} milliseconds is {:.3} milliseconds", - compute_elapsed.as_secs_f64() * 1000.0, - compute_elapsed.as_secs_f64() * 1000.0 / NUM_UPDATES as f64, + "An average update-batch computation time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {:.1} ms", + compute_elapsed, + compute_elapsed / NUM_UPDATES as f64, ); println!( - "An average update-batch application time measured by a {NUM_UPDATES}-batch into an SMT with \ - {size} leaves over {:.3} milliseconds is {:.3} milliseconds", - apply_elapsed.as_secs_f64() * 1000.0, - apply_elapsed.as_secs_f64() * 1000.0 / NUM_UPDATES as f64, + "An average update-batch application time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {:.1} ms", + apply_elapsed, + apply_elapsed / NUM_UPDATES as f64, ); println!( - "An average batch update time measured by a 10k-batch into an SMT with {size} leaves \ - totals to {:.3} milliseconds", - (compute_elapsed + apply_elapsed).as_secs_f64() * 1000.0, + "An average batch update time measured by a 1k-batch into an SMT with {size} leaves totals to {:.1} ms", + (compute_elapsed + apply_elapsed), ); println!(); @@ -196,7 +186,7 @@ pub fn batched_update(tree: &mut Smt, entries: Vec<(RpoDigest, Word)>) -> Result /// Runs the proof generation benchmark for the [`Smt`]. pub fn proof_generation(tree: &mut Smt) -> Result<(), MerkleError> { - const NUM_PROOFS: usize = 20; + const NUM_PROOFS: usize = 100; println!("Running a proof generation benchmark:"); @@ -204,7 +194,7 @@ pub fn proof_generation(tree: &mut Smt) -> Result<(), MerkleError> { let size = tree.num_leaves(); - for i in 0..20 { + for i in 0..NUM_PROOFS { let test_key = Rpo256::hash(&rand_value::().to_be_bytes()); let test_value = [ONE, ONE, ONE, Felt::new((size + i) as u64)]; tree.insert(test_key, test_value); @@ -215,8 +205,7 @@ pub fn proof_generation(tree: &mut Smt) -> Result<(), MerkleError> { } println!( - "An average proving time measured by {NUM_PROOFS} value proofs in an SMT with {size} \ - leaves in {:.3} microseconds", + "An average proving time measured by {NUM_PROOFS} value proofs in an SMT with {size} leaves in {:.1} μs", // calculate the average insertion_times.iter().sum::() as f64 / (NUM_PROOFS as f64), ); diff --git a/src/merkle/smt/full/mod.rs b/src/merkle/smt/full/mod.rs index 0b0de3b9..d800185d 100644 --- a/src/merkle/smt/full/mod.rs +++ b/src/merkle/smt/full/mod.rs @@ -219,9 +219,10 @@ impl Smt { >::apply_mutations(self, mutations) } - /// Applies the prospective mutations computed with [`Smt::compute_mutations()`] to - /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the - /// updated tree will revert the changes. + /// Applies the prospective mutations computed with [`Smt::compute_mutations()`] to this tree + /// and returns the reverse mutation set. + /// + /// Applying the reverse mutation sets to the updated tree will revert the changes. /// /// # Errors /// If `mutations` was computed on a tree with a different root than this one, returns diff --git a/src/merkle/smt/simple/mod.rs b/src/merkle/smt/simple/mod.rs index c1b699f9..2a25706e 100644 --- a/src/merkle/smt/simple/mod.rs +++ b/src/merkle/smt/simple/mod.rs @@ -237,8 +237,9 @@ impl SimpleSmt { } /// Applies the prospective mutations computed with [`SimpleSmt::compute_mutations()`] to - /// this tree and returns the reverse mutation set. Applying the reverse mutation sets to the - /// updated tree will revert the changes. + /// this tree and returns the reverse mutation set. + /// + /// Applying the reverse mutation sets to the updated tree will revert the changes. /// /// # Errors /// If `mutations` was computed on a tree with a different root than this one, returns From eeaf3c1a06f641cce326bb83557b702e86b2b2c7 Mon Sep 17 00:00:00 2001 From: Bobbin Threadbare Date: Thu, 26 Dec 2024 17:49:36 -0800 Subject: [PATCH 18/19] chore: minor smt benchmark updates --- Makefile | 2 +- src/main.rs | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index dcf0eb48..c84805bb 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ build-sve: ## Build with sve support .PHONY: bench bench: ## Run crypto benchmarks - cargo bench --features="concurrent" + cargo bench .PHONY: bench-smt-concurrent bench-smt-concurrent: ## Run SMT benchmarks with concurrent feature diff --git a/src/main.rs b/src/main.rs index fca8da0d..85dd7e10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,7 +75,7 @@ pub fn insertion(tree: &mut Smt) -> Result<(), MerkleError> { } println!( - "An average insertion time measured by {NUM_INSERTIONS} inserts into an SMT with {size} leaves is {:.1} μs\n", + "An average insertion time measured by {NUM_INSERTIONS} inserts into an SMT with {size} leaves is {} μs\n", // calculate the average insertion_times.iter().sum::() as f64 / (NUM_INSERTIONS as f64), ); @@ -100,22 +100,22 @@ pub fn batched_insertion(tree: &mut Smt) -> Result<(), MerkleError> { let now = Instant::now(); let mutations = tree.compute_mutations(new_pairs); - let compute_elapsed = now.elapsed().as_secs_f64() * 1000_f64; + let compute_elapsed = now.elapsed().as_secs_f64() * 1000_f64; // time in ms let now = Instant::now(); tree.apply_mutations(mutations)?; - let apply_elapsed = now.elapsed().as_secs_f64() * 1000_f64; + let apply_elapsed = now.elapsed().as_secs_f64() * 1000_f64; // time in ms println!( - "An average insert-batch computation time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {:.1} ms", + "An average insert-batch computation time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {} μs", compute_elapsed, - compute_elapsed / NUM_INSERTIONS as f64, + compute_elapsed * 1000_f64 / NUM_INSERTIONS as f64, // time in μs ); println!( - "An average insert-batch application time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {:.1} ms", + "An average insert-batch application time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {} μs", apply_elapsed, - apply_elapsed / NUM_INSERTIONS as f64, + apply_elapsed * 1000_f64 / NUM_INSERTIONS as f64, // time in μs ); println!( @@ -163,15 +163,15 @@ pub fn batched_update(tree: &mut Smt, entries: Vec<(RpoDigest, Word)>) -> Result let apply_elapsed = now.elapsed().as_secs_f64() * 1000_f64; // time in ms println!( - "An average update-batch computation time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {:.1} ms", + "An average update-batch computation time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {} μs", compute_elapsed, - compute_elapsed / NUM_UPDATES as f64, + compute_elapsed * 1000_f64 / NUM_UPDATES as f64, // time in μs ); println!( - "An average update-batch application time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {:.1} ms", + "An average update-batch application time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {} μs", apply_elapsed, - apply_elapsed / NUM_UPDATES as f64, + apply_elapsed * 1000_f64 / NUM_UPDATES as f64, // time in μs ); println!( @@ -205,7 +205,7 @@ pub fn proof_generation(tree: &mut Smt) -> Result<(), MerkleError> { } println!( - "An average proving time measured by {NUM_PROOFS} value proofs in an SMT with {size} leaves in {:.1} μs", + "An average proving time measured by {NUM_PROOFS} value proofs in an SMT with {size} leaves in {} μs", // calculate the average insertion_times.iter().sum::() as f64 / (NUM_PROOFS as f64), ); From 0e3f79f906268d94def7e225bf63912c891e4c1d Mon Sep 17 00:00:00 2001 From: Bobbin Threadbare Date: Thu, 26 Dec 2024 18:09:42 -0800 Subject: [PATCH 19/19] chore: update crate version to v0.13.1 --- Cargo.lock | 124 ++++++++++++++++++++++++++-------------------------- Cargo.toml | 6 +-- src/main.rs | 12 ++--- 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 160a2e7a..253f0d39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,18 +92,18 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bit-set" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" @@ -113,9 +113,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blake3" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -153,9 +153,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.1" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" dependencies = [ "jobserver", "libc", @@ -197,9 +197,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -207,9 +207,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -231,9 +231,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" @@ -294,9 +294,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -313,9 +313,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -351,19 +351,19 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fnv" @@ -456,9 +456,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" @@ -471,10 +471,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -495,9 +496,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.164" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libm" @@ -525,7 +526,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miden-crypto" -version = "0.13.0" +version = "0.13.1" dependencies = [ "assert_matches", "blake3", @@ -685,9 +686,9 @@ dependencies = [ [[package]] name = "proptest" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", "bit-vec", @@ -711,9 +712,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -808,15 +809,15 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -854,18 +855,18 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -874,9 +875,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr", @@ -908,9 +909,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.89" +version = "2.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" dependencies = [ "proc-macro2", "quote", @@ -932,18 +933,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", @@ -1017,9 +1018,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -1028,13 +1029,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -1043,9 +1043,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1053,9 +1053,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", @@ -1066,15 +1066,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index b9a05ef5..87bf6821 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "miden-crypto" -version = "0.13.0" +version = "0.13.1" description = "Miden Cryptographic primitives" authors = ["miden contributors"] readme = "README.md" license = "MIT" repository = "https://github.com/0xPolygonMiden/crypto" -documentation = "https://docs.rs/miden-crypto/0.13.0" +documentation = "https://docs.rs/miden-crypto/0.13.1" categories = ["cryptography", "no-std"] keywords = ["miden", "crypto", "hash", "merkle"] edition = "2021" @@ -65,7 +65,7 @@ assert_matches = { version = "1.5", default-features = false } criterion = { version = "0.5", features = ["html_reports"] } getrandom = { version = "0.2", features = ["js"] } hex = { version = "0.4", default-features = false, features = ["alloc"] } -proptest = "1.5" +proptest = "1.6" rand_chacha = { version = "0.3", default-features = false } rand-utils = { version = "0.11", package = "winter-rand-utils" } seq-macro = { version = "0.3" } diff --git a/src/main.rs b/src/main.rs index 85dd7e10..2cc11ac2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,7 +75,7 @@ pub fn insertion(tree: &mut Smt) -> Result<(), MerkleError> { } println!( - "An average insertion time measured by {NUM_INSERTIONS} inserts into an SMT with {size} leaves is {} μs\n", + "An average insertion time measured by {NUM_INSERTIONS} inserts into an SMT with {size} leaves is {:.0} μs\n", // calculate the average insertion_times.iter().sum::() as f64 / (NUM_INSERTIONS as f64), ); @@ -107,13 +107,13 @@ pub fn batched_insertion(tree: &mut Smt) -> Result<(), MerkleError> { let apply_elapsed = now.elapsed().as_secs_f64() * 1000_f64; // time in ms println!( - "An average insert-batch computation time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {} μs", + "An average insert-batch computation time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {:.0} μs", compute_elapsed, compute_elapsed * 1000_f64 / NUM_INSERTIONS as f64, // time in μs ); println!( - "An average insert-batch application time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {} μs", + "An average insert-batch application time measured by a {NUM_INSERTIONS}-batch into an SMT with {size} leaves over {:.1} ms is {:.0} μs", apply_elapsed, apply_elapsed * 1000_f64 / NUM_INSERTIONS as f64, // time in μs ); @@ -163,13 +163,13 @@ pub fn batched_update(tree: &mut Smt, entries: Vec<(RpoDigest, Word)>) -> Result let apply_elapsed = now.elapsed().as_secs_f64() * 1000_f64; // time in ms println!( - "An average update-batch computation time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {} μs", + "An average update-batch computation time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {:.0} μs", compute_elapsed, compute_elapsed * 1000_f64 / NUM_UPDATES as f64, // time in μs ); println!( - "An average update-batch application time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {} μs", + "An average update-batch application time measured by a {NUM_UPDATES}-batch into an SMT with {size} leaves over {:.1} ms is {:.0} μs", apply_elapsed, apply_elapsed * 1000_f64 / NUM_UPDATES as f64, // time in μs ); @@ -205,7 +205,7 @@ pub fn proof_generation(tree: &mut Smt) -> Result<(), MerkleError> { } println!( - "An average proving time measured by {NUM_PROOFS} value proofs in an SMT with {size} leaves in {} μs", + "An average proving time measured by {NUM_PROOFS} value proofs in an SMT with {size} leaves in {:.0} μs", // calculate the average insertion_times.iter().sum::() as f64 / (NUM_PROOFS as f64), );