From 6d8a60c310fb8ff8b6ea0d751b4a2e4c23e78aeb Mon Sep 17 00:00:00 2001 From: markoburcul Date: Wed, 23 Apr 2025 11:54:35 +0200 Subject: [PATCH 01/24] flake: add rust overlay and shell dependencies --- flake.lock | 23 ++++++++++++++++++++++- flake.nix | 25 +++++++++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/flake.lock b/flake.lock index 46a1cbf8..d0ab16ca 100644 --- a/flake.lock +++ b/flake.lock @@ -18,7 +18,28 @@ }, "root": { "inputs": { - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1745289264, + "narHash": "sha256-7nt+UJ7qaIUe2J7BdnEEph9n2eKEwxUwKS/QIr091uA=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "3b7171858c20d5293360042936058fb0c4cb93a9", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index 5aa94d5c..f49614cc 100644 --- a/flake.nix +++ b/flake.nix @@ -4,9 +4,13 @@ inputs = { # Version 24.11 nixpkgs.url = "github:NixOS/nixpkgs?rev=f44bd8ca21e026135061a0a57dcf3d0775b67a49"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = { self, nixpkgs }: + outputs = { self, nixpkgs, rust-overlay }: let stableSystems = [ "x86_64-linux" "aarch64-linux" @@ -15,7 +19,8 @@ "i686-windows" ]; forAllSystems = nixpkgs.lib.genAttrs stableSystems; - pkgsFor = forAllSystems (system: import nixpkgs { inherit system; }); + overlays = [ (import rust-overlay) ]; + pkgsFor = forAllSystems (system: import nixpkgs { inherit system overlays; }); in rec { packages = forAllSystems (system: let @@ -29,9 +34,21 @@ pkgs = pkgsFor.${system}; in { default = pkgs.mkShell { - inputsFrom = [ - packages.${system}.default + buildInputs = with pkgs; [ + git + cmake + cargo-make + gnuplot + rustup + xz + wasm-pack + rust-bin.stable.latest.default ]; + # Shared library liblzma.so.5 used by wasm-pack + shellHook = '' + xz_lib=$(nix-store -q --references $(which xz) | grep xz) + export LD_LIBRARY_PATH=$xz_lib/lib:$LD_LIBRARY_PATH + ''; }; }); }; From e12ab776b3ef66f60da007407e8697c29843a862 Mon Sep 17 00:00:00 2001 From: markoburcul Date: Mon, 5 May 2025 09:51:49 +0200 Subject: [PATCH 02/24] makefile: install wasm-pack with cargo --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b3c74ee9..893149d3 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ endif [ -s "$$NVM_DIR/nvm.sh" ] && \. "$$NVM_DIR/nvm.sh" && \ nvm install 22.14.0 && \ nvm use 22.14.0' - @curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + @cargo install wasm-pack @echo "\033[1;32m>>> Now run this command to activate Node.js 22.14.0: \033[1;33msource $$HOME/.nvm/nvm.sh && nvm use 22.14.0\033[0m" build: .pre-build From 601f2d8e787911061eed433ece588d88dce9d053 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Tue, 6 May 2025 15:49:49 +0200 Subject: [PATCH 03/24] feat: Add zk-kit-lean-imt as dev-dependency --- Cargo.lock | 10 ++++++++++ utils/Cargo.toml | 1 + 2 files changed, 11 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 56d597ac..30bca727 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2543,4 +2543,14 @@ dependencies = [ "sled", "tiny-keccak", "vacp2p_pmtree", + "zk-kit-lean-imt", +] + +[[package]] +name = "zk-kit-lean-imt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd2ef671845634af5f8e3c28962b6d7d9ab49c69ce4a4a09d35e7a697cbf321" +dependencies = [ + "thiserror", ] diff --git a/utils/Cargo.toml b/utils/Cargo.toml index f13bc9a7..62fbdc20 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -31,6 +31,7 @@ num-traits = "0.2.19" hex-literal = "1.0.0" tiny-keccak = { version = "2.0.2", features = ["keccak"] } criterion = { version = "0.4.0", features = ["html_reports"] } +zk-kit-lean-imt = "0.1.0" [features] default = [] From 3692bf5626f1fb817873d81ef3ac2817f61b7cfb Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Mon, 12 May 2025 12:49:38 +0200 Subject: [PATCH 04/24] fix: Use typical data in merkle tree bench --- Cargo.lock | 57 +++++++++++++++++++++----- utils/Cargo.toml | 10 ++++- utils/benches/imt_benchy.rs | 55 +++++++++++++++++++++++++ utils/benches/merkle_tree_benchmark.rs | 42 ++++++++++++++----- 4 files changed, 142 insertions(+), 22 deletions(-) create mode 100644 utils/benches/imt_benchy.rs diff --git a/Cargo.lock b/Cargo.lock index 30bca727..92b34879 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1226,6 +1226,18 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +[[package]] +name = "light-poseidon" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3d87542063daaccbfecd78b60f988079b6ec4e089249658b9455075c78d42" +dependencies = [ + "ark-bn254", + "ark-ff 0.5.0", + "num-bigint", + "thiserror 1.0.69", +] + [[package]] name = "litrs" version = "0.4.1" @@ -1415,7 +1427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.12", "ucd-trie", ] @@ -1564,13 +1576,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy 0.8.24", ] [[package]] @@ -1706,7 +1717,7 @@ dependencies = [ "serde", "serde_json", "sled", - "thiserror", + "thiserror 2.0.12", "tiny-keccak", "zerokit_utils", ] @@ -1770,7 +1781,7 @@ dependencies = [ "primitive-types", "proptest", "rand 0.8.5", - "rand 0.9.0", + "rand 0.9.1", "rlp", "ruint-macro", "serde", @@ -2008,13 +2019,33 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] @@ -2537,8 +2568,13 @@ dependencies = [ "hex", "hex-literal", "lazy_static", + "light-poseidon", "num-bigint", "num-traits", + "rand 0.9.1", + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "rln", "serde", "sled", "tiny-keccak", @@ -2548,9 +2584,8 @@ dependencies = [ [[package]] name = "zk-kit-lean-imt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd2ef671845634af5f8e3c28962b6d7d9ab49c69ce4a4a09d35e7a697cbf321" +version = "0.1.1" +source = "git+https://github.com/privacy-scaling-explorations/zk-kit.rust#1014994e0505befc33d51e854c73ab8717b64d90" dependencies = [ - "thiserror", + "thiserror 2.0.12", ] diff --git a/utils/Cargo.toml b/utils/Cargo.toml index 62fbdc20..48949a2d 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -25,13 +25,21 @@ serde = "1.0" lazy_static = "1.5.0" hex = "0.4" + + [dev-dependencies] ark-bn254 = { version = "0.5.0", features = ["std"] } num-traits = "0.2.19" hex-literal = "1.0.0" tiny-keccak = { version = "2.0.2", features = ["keccak"] } criterion = { version = "0.4.0", features = ["html_reports"] } -zk-kit-lean-imt = "0.1.0" +rand = "0.9.1" +rand_chacha = "0.9.0" +rand_core = "0.9.3" +# dev artifact for benching zk-kit lean-imt +light-poseidon = "0.3.0" +zk-kit-lean-imt = { git = "https://github.com/privacy-scaling-explorations/zk-kit.rust", package = "zk-kit-lean-imt" } +rln = { path = "../rln", default-features = false } [features] default = [] diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs new file mode 100644 index 00000000..c9d63900 --- /dev/null +++ b/utils/benches/imt_benchy.rs @@ -0,0 +1,55 @@ +use light_poseidon::{PoseidonBytesHasher, PoseidonHasher}; +use rln::{circuit::Fr, utils::fr_to_bytes_le}; +use zerokit_utils::Poseidon; +use zk_kit_lean_imt::{hashed_tree::{HashedLeanIMT, LeanIMTHasher}, lean_imt::*}; + + +const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [ + (2, 8, 56, 0), + (3, 8, 57, 0), + (4, 8, 56, 0), + (5, 8, 60, 0), + (6, 8, 60, 0), + (7, 8, 63, 0), + (8, 8, 64, 0), + (9, 8, 63, 0), +]; + + +struct BenchyIFTHasher; +struct BenchyLightPosHasher; + +impl LeanIMTHasher for BenchyIFTHasher { + fn hash(input: &[u8]) -> [u8; N] { + let hasher = Poseidon::::from(&ROUND_PARAMS); + let input_as_frs: Vec<_> = input.chunks(N).map(|ch| rln::utils::bytes_le_to_fr(ch).0).collect(); + let res = hasher.hash(&input_as_frs).unwrap(); + let byte_vec: Vec = fr_to_bytes_le(&res); + let mut res = [0; N]; + if byte_vec.len() >= N { + res.copy_from_slice(&byte_vec[..N]); + } else { + res.copy_from_slice(&byte_vec); + }; + res + } +} +impl LeanIMTHasher<32> for BenchyLightPosHasher { + fn hash(input: &[u8]) -> [u8; 32] { + let mut hasher = light_poseidon::Poseidon::::new_circom(1).unwrap(); + let chunks: Vec< &[u8] > = input.chunks(32).collect(); + hasher.hash_bytes_le(&chunks).unwrap() + } +} +fn benchy_prototype_code() { + let mut tree = HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher).unwrap(); + tree.insert(&[1; 32]); + tree.insert(&[2; 32]); + tree.insert_many(&[[4; 32], [4; 32], [5; 32]]).unwrap(); + + println!("Tree root: {:?}", tree.root().unwrap()); + println!("Tree depth: {}", tree.depth()); + + let proof = tree.generate_proof(3).unwrap(); + assert!(HashedLeanIMT::<32, BenchyIFTHasher>::verify_proof(&proof)); +} diff --git a/utils/benches/merkle_tree_benchmark.rs b/utils/benches/merkle_tree_benchmark.rs index 89ebbe62..c4102c43 100644 --- a/utils/benches/merkle_tree_benchmark.rs +++ b/utils/benches/merkle_tree_benchmark.rs @@ -1,6 +1,8 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use hex_literal::hex; use lazy_static::lazy_static; +use rand::RngCore; +use rand_chacha::ChaCha8Rng; +use rand_core::SeedableRng; use std::{fmt::Display, str::FromStr}; use tiny_keccak::{Hasher as _, Keccak}; use zerokit_utils::{ @@ -14,6 +16,28 @@ struct Keccak256; #[derive(Clone, Copy, Eq, PartialEq, Debug, Default)] struct TestFr([u8; 32]); +// ChaCha8Rng is chosen for its portable determinism +struct FrRngStream { + rng: ChaCha8Rng, +} + +impl FrRngStream { + fn seeded_stream(seed: u64) -> Self { + let rng = ChaCha8Rng::seed_from_u64(seed); + Self { rng } + } +} + +impl Iterator for FrRngStream { + type Item = TestFr; + + fn next(&mut self) -> Option { + let mut res = [0; 32]; + self.rng.fill_bytes(&mut res); + Some(TestFr(res)) + } +} + impl Hasher for Keccak256 { type Fr = TestFr; @@ -47,13 +71,11 @@ impl FromStr for TestFr { } lazy_static! { - static ref LEAVES: [TestFr; 4] = [ - hex!("0000000000000000000000000000000000000000000000000000000000000001"), - hex!("0000000000000000000000000000000000000000000000000000000000000002"), - hex!("0000000000000000000000000000000000000000000000000000000000000003"), - hex!("0000000000000000000000000000000000000000000000000000000000000004"), - ] - .map(TestFr); + static ref LEAVES: [TestFr; 40] = FrRngStream::seeded_stream(42) + .take(40) + .collect::>() + .try_into() + .unwrap(); } pub fn optimal_merkle_tree_benchmark(c: &mut Criterion) { @@ -75,7 +97,7 @@ pub fn optimal_merkle_tree_benchmark(c: &mut Criterion) { c.bench_function("OptimalMerkleTree::override_range", |b| { b.iter(|| { - tree.override_range(0, LEAVES.into_iter(), [0, 1, 2, 3].into_iter()) + tree.override_range(0, LEAVES.into_iter().take(4), [0, 1, 2, 3].into_iter()) .unwrap(); }) }); @@ -124,7 +146,7 @@ pub fn full_merkle_tree_benchmark(c: &mut Criterion) { c.bench_function("FullMerkleTree::override_range", |b| { b.iter(|| { - tree.override_range(0, LEAVES.into_iter(), [0, 1, 2, 3].into_iter()) + tree.override_range(0, LEAVES.into_iter().take(4), [0, 1, 2, 3].into_iter()) .unwrap(); }) }); From fc9e84b0fa0f7a01cf867a08b5b453fbf3b05819 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Mon, 12 May 2025 15:36:22 +0200 Subject: [PATCH 05/24] use deterministic+portable PRNG for tree nodes --- utils/Cargo.toml | 1 + utils/benches/imt_benchy.rs | 55 ++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/utils/Cargo.toml b/utils/Cargo.toml index 48949a2d..3ac50227 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -40,6 +40,7 @@ rand_core = "0.9.3" light-poseidon = "0.3.0" zk-kit-lean-imt = { git = "https://github.com/privacy-scaling-explorations/zk-kit.rust", package = "zk-kit-lean-imt" } rln = { path = "../rln", default-features = false } +lazy_static = "1.5.0" [features] default = [] diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index c9d63900..3e51c97e 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -1,8 +1,13 @@ use light_poseidon::{PoseidonBytesHasher, PoseidonHasher}; +use rand::RngCore; +use rand_chacha::ChaCha8Rng; +use rand_core::SeedableRng; use rln::{circuit::Fr, utils::fr_to_bytes_le}; use zerokit_utils::Poseidon; -use zk_kit_lean_imt::{hashed_tree::{HashedLeanIMT, LeanIMTHasher}, lean_imt::*}; - +use zk_kit_lean_imt::{ + hashed_tree::{HashedLeanIMT, LeanIMTHasher}, + lean_imt::*, +}; const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [ (2, 8, 56, 0), @@ -14,7 +19,34 @@ const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [ (8, 8, 64, 0), (9, 8, 63, 0), ]; +// ChaCha8Rng is chosen for its portable determinism +struct HashMockStream { + rng: ChaCha8Rng, +} + +impl HashMockStream { + fn seeded_stream(seed: u64) -> Self { + let rng = ChaCha8Rng::seed_from_u64(seed); + Self { rng } + } +} +impl Iterator for HashMockStream { + type Item = [u8; 32]; + + fn next(&mut self) -> Option { + let mut res = [0; 32]; + self.rng.fill_bytes(&mut res); + Some(res) + } +} +lazy_static::lazy_static! { + static ref LEAVES: [[u8; 32]; 40] = HashMockStream::seeded_stream(42) + .take(40) + .collect::>() + .try_into() + .unwrap(); +} struct BenchyIFTHasher; struct BenchyLightPosHasher; @@ -22,7 +54,10 @@ struct BenchyLightPosHasher; impl LeanIMTHasher for BenchyIFTHasher { fn hash(input: &[u8]) -> [u8; N] { let hasher = Poseidon::::from(&ROUND_PARAMS); - let input_as_frs: Vec<_> = input.chunks(N).map(|ch| rln::utils::bytes_le_to_fr(ch).0).collect(); + let input_as_frs: Vec<_> = input + .chunks(N) + .map(|ch| rln::utils::bytes_le_to_fr(ch).0) + .collect(); let res = hasher.hash(&input_as_frs).unwrap(); let byte_vec: Vec = fr_to_bytes_le(&res); let mut res = [0; N]; @@ -37,15 +72,21 @@ impl LeanIMTHasher for BenchyIFTHasher { impl LeanIMTHasher<32> for BenchyLightPosHasher { fn hash(input: &[u8]) -> [u8; 32] { let mut hasher = light_poseidon::Poseidon::::new_circom(1).unwrap(); - let chunks: Vec< &[u8] > = input.chunks(32).collect(); + let chunks: Vec<&[u8]> = input.chunks(32).collect(); hasher.hash_bytes_le(&chunks).unwrap() } } fn benchy_prototype_code() { let mut tree = HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher).unwrap(); - tree.insert(&[1; 32]); - tree.insert(&[2; 32]); - tree.insert_many(&[[4; 32], [4; 32], [5; 32]]).unwrap(); + let mut genned_hashes = LEAVES.iter(); + tree.insert(genned_hashes.next().unwrap()); + tree.insert(genned_hashes.next().unwrap()); + tree.insert_many(&[ + *genned_hashes.next().unwrap(), + *genned_hashes.next().unwrap(), + *genned_hashes.next().unwrap(), + ]) + .unwrap(); println!("Tree root: {:?}", tree.root().unwrap()); println!("Tree depth: {}", tree.depth()); From a9838697c236d32d7bc40cfdbe5f5a1e2f09161d Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Mon, 12 May 2025 16:56:03 +0200 Subject: [PATCH 06/24] Add first merkle tree benchmark --- utils/Cargo.toml | 3 +++ utils/benches/imt_benchy.rs | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/utils/Cargo.toml b/utils/Cargo.toml index 3ac50227..216c0599 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -53,3 +53,6 @@ harness = false [[bench]] name = "poseidon_benchmark" harness = false +[[bench]] +name = "imt_benchy" +harness = false diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 3e51c97e..d4925302 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -1,3 +1,4 @@ +use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; use light_poseidon::{PoseidonBytesHasher, PoseidonHasher}; use rand::RngCore; use rand_chacha::ChaCha8Rng; @@ -40,6 +41,11 @@ impl Iterator for HashMockStream { Some(res) } } +impl LeanIMTHasher<32> for HashMockStream { + fn hash(input: &[u8]) -> [u8; 32] { + input.try_into().unwrap() + } +} lazy_static::lazy_static! { static ref LEAVES: [[u8; 32]; 40] = HashMockStream::seeded_stream(42) .take(40) @@ -94,3 +100,45 @@ fn benchy_prototype_code() { let proof = tree.generate_proof(3).unwrap(); assert!(HashedLeanIMT::<32, BenchyIFTHasher>::verify_proof(&proof)); } + +pub fn imt_benchy(c: &mut Criterion) { + let mut group = c.benchmark_group("markle tree setup"); + + for size in [7u32, 13, 17].iter() { + group.bench_with_input( + BenchmarkId::new("Lean IMT setup", size), + size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source: Vec<[u8; 32]> = HashMockStream::seeded_stream(42) + .take(size as usize) + .collect(); + let tree = HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| { + for d in data_source.iter() { + tree.insert(d); + } + }, + BatchSize::SmallInput, + ) + }, + ); + } + group.finish(); +} + +criterion_group! { + name = benchies; + config = Criterion::default() + .warm_up_time(std::time::Duration::from_millis(500)) + .measurement_time(std::time::Duration::from_secs(4)) + .sample_size(10); + targets = imt_benchy +} +criterion_main!(benchies); From 702ac11a7c4f777c8ad244b4f05ee9f40706e516 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Mon, 12 May 2025 18:56:47 +0200 Subject: [PATCH 07/24] Add batch setup to the imt setup group --- utils/benches/imt_benchy.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index d4925302..43233007 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -102,11 +102,11 @@ fn benchy_prototype_code() { } pub fn imt_benchy(c: &mut Criterion) { - let mut group = c.benchmark_group("markle tree setup"); + let mut group = c.benchmark_group("merkle tree setup"); for size in [7u32, 13, 17].iter() { group.bench_with_input( - BenchmarkId::new("Lean IMT setup", size), + BenchmarkId::new("Lean IMT setup incremental", size), size, |b, &size| { b.iter_batched( @@ -129,6 +129,29 @@ pub fn imt_benchy(c: &mut Criterion) { ) }, ); + group.bench_with_input( + BenchmarkId::new("Lean IMT setup batch", size), + size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source: Vec<[u8; 32]> = HashMockStream::seeded_stream(42) + .take(size as usize) + .collect() + ; + let tree = HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| { + tree.insert_many(&data_source[..]) + }, + BatchSize::SmallInput, + ) + }, + ); } group.finish(); } From 9f4da7f319979a2b3a635d5654c63cd875c20cdd Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Mon, 12 May 2025 19:13:38 +0200 Subject: [PATCH 08/24] use less unecissary allocation inside the bench --- utils/benches/imt_benchy.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 43233007..bd35f899 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -101,10 +101,13 @@ fn benchy_prototype_code() { assert!(HashedLeanIMT::<32, BenchyIFTHasher>::verify_proof(&proof)); } -pub fn imt_benchy(c: &mut Criterion) { - let mut group = c.benchmark_group("merkle tree setup"); - - for size in [7u32, 13, 17].iter() { +pub fn hashless_imt_benchy(c: &mut Criterion) { + let mut group = c.benchmark_group("hashless merkle tree setup"); + let size_group = [7u32, 13, 17]; + let data_table: Vec<[u8; 32]> = HashMockStream::seeded_stream(42) + .take(*size_group.iter().max().unwrap() as usize) + .collect(); + for size in size_group.iter() { group.bench_with_input( BenchmarkId::new("Lean IMT setup incremental", size), size, @@ -112,9 +115,7 @@ pub fn imt_benchy(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source: Vec<[u8; 32]> = HashMockStream::seeded_stream(42) - .take(size as usize) - .collect(); + let data_source = &data_table[0..size as usize]; let tree = HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher) .unwrap(); (tree, data_source) @@ -136,18 +137,13 @@ pub fn imt_benchy(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source: Vec<[u8; 32]> = HashMockStream::seeded_stream(42) - .take(size as usize) - .collect() - ; + let data_source = &data_table[0..size as usize]; let tree = HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher) .unwrap(); (tree, data_source) }, // Actual benchmark - |(mut tree, data_source)| { - tree.insert_many(&data_source[..]) - }, + |(mut tree, data_source)| tree.insert_many(data_source), BatchSize::SmallInput, ) }, @@ -162,6 +158,6 @@ criterion_group! { .warm_up_time(std::time::Duration::from_millis(500)) .measurement_time(std::time::Duration::from_secs(4)) .sample_size(10); - targets = imt_benchy + targets = hashless_imt_benchy } criterion_main!(benchies); From a701bda92ac3b02718a840b2aed0ad3644b9ba19 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Tue, 13 May 2025 13:36:18 +0200 Subject: [PATCH 09/24] IFT optimal vs IMT benched --- utils/benches/imt_benchy.rs | 128 +++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 31 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index bd35f899..051c3882 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -1,10 +1,15 @@ +use std::{fmt::Display, str::FromStr}; + +use ark_ff::Field; use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; use light_poseidon::{PoseidonBytesHasher, PoseidonHasher}; use rand::RngCore; use rand_chacha::ChaCha8Rng; use rand_core::SeedableRng; use rln::{circuit::Fr, utils::fr_to_bytes_le}; -use zerokit_utils::Poseidon; +use zerokit_utils::{ + Hasher, OptimalMerkleConfig, OptimalMerkleTree, Poseidon, ZerokitMerkleTree as _, +}; use zk_kit_lean_imt::{ hashed_tree::{HashedLeanIMT, LeanIMTHasher}, lean_imt::*, @@ -54,8 +59,20 @@ lazy_static::lazy_static! { .unwrap(); } +#[derive(Debug)] struct BenchyIFTHasher; struct BenchyLightPosHasher; +impl Hasher for BenchyIFTHasher { + type Fr = Fr; + + fn default_leaf() -> Self::Fr { + Fr::default() + } + + fn hash(input: &[Self::Fr]) -> Self::Fr { + *input.first().unwrap_or(&Self::default_leaf()) + } +} impl LeanIMTHasher for BenchyIFTHasher { fn hash(input: &[u8]) -> [u8; N] { @@ -75,6 +92,7 @@ impl LeanIMTHasher for BenchyIFTHasher { res } } + impl LeanIMTHasher<32> for BenchyLightPosHasher { fn hash(input: &[u8]) -> [u8; 32] { let mut hasher = light_poseidon::Poseidon::::new_circom(1).unwrap(); @@ -82,35 +100,36 @@ impl LeanIMTHasher<32> for BenchyLightPosHasher { hasher.hash_bytes_le(&chunks).unwrap() } } -fn benchy_prototype_code() { - let mut tree = HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher).unwrap(); - let mut genned_hashes = LEAVES.iter(); - tree.insert(genned_hashes.next().unwrap()); - tree.insert(genned_hashes.next().unwrap()); - tree.insert_many(&[ - *genned_hashes.next().unwrap(), - *genned_hashes.next().unwrap(), - *genned_hashes.next().unwrap(), - ]) - .unwrap(); - - println!("Tree root: {:?}", tree.root().unwrap()); - println!("Tree depth: {}", tree.depth()); - - let proof = tree.generate_proof(3).unwrap(); - assert!(HashedLeanIMT::<32, BenchyIFTHasher>::verify_proof(&proof)); -} -pub fn hashless_imt_benchy(c: &mut Criterion) { - let mut group = c.benchmark_group("hashless merkle tree setup"); +fn make_data_table() -> (Vec<[u8; 32]>, Vec, impl Iterator) { let size_group = [7u32, 13, 17]; let data_table: Vec<[u8; 32]> = HashMockStream::seeded_stream(42) .take(*size_group.iter().max().unwrap() as usize) .collect(); - for size in size_group.iter() { + + let fr_table = HashMockStream::seeded_stream(42) + .take(*size_group.iter().max().unwrap() as usize) + .map(|bytes: [u8; 32]| { + Fr::from_str( + bytes + .iter() + .map(|b| format!("{}", b % 10)) + .collect::() + .as_str(), + ) + }) + .collect::, _>>() + .unwrap(); + (data_table, fr_table, size_group.into_iter()) +} + +pub fn hashless_setup_iterative(c: &mut Criterion) { + let mut group = c.benchmark_group("hashless tree iterative setup"); + let (data_table, fr_table, size_group) = make_data_table(); + for size in size_group { group.bench_with_input( - BenchmarkId::new("Lean IMT setup incremental", size), - size, + BenchmarkId::new("Lean IMT iterative", size), + &size, |b, &size| { b.iter_batched( // Setup: create values for each benchmark iteration @@ -131,24 +150,71 @@ pub fn hashless_imt_benchy(c: &mut Criterion) { }, ); group.bench_with_input( - BenchmarkId::new("Lean IMT setup batch", size), - size, + BenchmarkId::new("IFT iterative", size), + &size, |b, &size| { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source = &data_table[0..size as usize]; - let tree = HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher) - .unwrap(); + let data_source = &fr_table[0..size as usize]; + let tree = OptimalMerkleTree::::new( + 6, + Fr::default(), + OptimalMerkleConfig::default(), + ) + .unwrap(); (tree, data_source) }, // Actual benchmark - |(mut tree, data_source)| tree.insert_many(data_source), + |(mut tree, data_source)| { + for (i, d) in data_source.iter().enumerate() { + tree.set(i, *d).unwrap(); + } + }, BatchSize::SmallInput, ) }, ); } +} +pub fn hashless_setup_batch(c: &mut Criterion) { + let mut group = c.benchmark_group("hashless tree batch setup"); + let (data_table, fr_table, size_group) = make_data_table(); + for size in size_group { + group.bench_with_input(BenchmarkId::new("Lean IMT", size), &size, |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &data_table[0..size as usize]; + let tree = + HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher).unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.insert_many(data_source), + BatchSize::SmallInput, + ) + }); + group.bench_with_input(BenchmarkId::new("IFT", size), &size, |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &fr_table[0..size as usize]; + let data_source = data_source.iter().copied(); + let tree = OptimalMerkleTree::::new( + 6, + Fr::default(), + OptimalMerkleConfig::default(), + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.set_range(0, data_source), + BatchSize::SmallInput, + ) + }); + } group.finish(); } @@ -158,6 +224,6 @@ criterion_group! { .warm_up_time(std::time::Duration::from_millis(500)) .measurement_time(std::time::Duration::from_secs(4)) .sample_size(10); - targets = hashless_imt_benchy + targets = hashless_setup_batch, hashless_setup_iterative } criterion_main!(benchies); From 7fd9291d1e271404a2c88c64351dac32895a8487 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Tue, 13 May 2025 13:45:05 +0200 Subject: [PATCH 10/24] Include ift optimal tree --- utils/benches/imt_benchy.rs | 66 ++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 051c3882..2634bab0 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -1,19 +1,18 @@ -use std::{fmt::Display, str::FromStr}; +use std::str::FromStr; -use ark_ff::Field; use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; -use light_poseidon::{PoseidonBytesHasher, PoseidonHasher}; +use light_poseidon::PoseidonBytesHasher; use rand::RngCore; use rand_chacha::ChaCha8Rng; use rand_core::SeedableRng; use rln::{circuit::Fr, utils::fr_to_bytes_le}; use zerokit_utils::{ - Hasher, OptimalMerkleConfig, OptimalMerkleTree, Poseidon, ZerokitMerkleTree as _, -}; -use zk_kit_lean_imt::{ - hashed_tree::{HashedLeanIMT, LeanIMTHasher}, - lean_imt::*, + FullMerkleConfig, FullMerkleTree, Hasher, OptimalMerkleConfig, OptimalMerkleTree, Poseidon, + ZerokitMerkleTree as _, }; +use zk_kit_lean_imt:: + hashed_tree::{HashedLeanIMT, LeanIMTHasher} +; const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [ (2, 8, 56, 0), @@ -61,7 +60,7 @@ lazy_static::lazy_static! { #[derive(Debug)] struct BenchyIFTHasher; -struct BenchyLightPosHasher; + impl Hasher for BenchyIFTHasher { type Fr = Fr; @@ -150,7 +149,7 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { }, ); group.bench_with_input( - BenchmarkId::new("IFT iterative", size), + BenchmarkId::new("IFT optimal iterative", size), &size, |b, &size| { b.iter_batched( @@ -175,6 +174,32 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { ) }, ); + group.bench_with_input( + BenchmarkId::new("IFT full iterative", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &fr_table[0..size as usize]; + let tree = FullMerkleTree::::new( + 6, + Fr::default(), + FullMerkleConfig::default(), + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| { + for (i, d) in data_source.iter().enumerate() { + tree.set(i, *d).unwrap(); + } + }, + BatchSize::SmallInput, + ) + }, + ); } } pub fn hashless_setup_batch(c: &mut Criterion) { @@ -195,7 +220,7 @@ pub fn hashless_setup_batch(c: &mut Criterion) { BatchSize::SmallInput, ) }); - group.bench_with_input(BenchmarkId::new("IFT", size), &size, |b, &size| { + group.bench_with_input(BenchmarkId::new("IFT optimal", size), &size, |b, &size| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -214,6 +239,25 @@ pub fn hashless_setup_batch(c: &mut Criterion) { BatchSize::SmallInput, ) }); + group.bench_with_input(BenchmarkId::new("IFT full", size), &size, |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &fr_table[0..size as usize]; + let data_source = data_source.iter().copied(); + let tree = FullMerkleTree::::new( + 6, + Fr::default(), + FullMerkleConfig::default(), + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.set_range(0, data_source), + BatchSize::SmallInput, + ) + }); } group.finish(); } From 27eb9d78d7e4d1795f0fa3ea8ebbcb8b5c1763eb Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Tue, 13 May 2025 16:16:16 +0200 Subject: [PATCH 11/24] fix: hashed -> lean imt tree (oops) --- utils/benches/imt_benchy.rs | 206 +++++++++++++++++++----------------- 1 file changed, 109 insertions(+), 97 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 2634bab0..4131ee15 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -1,18 +1,17 @@ -use std::str::FromStr; +use std::{fmt::Display, str::FromStr}; +use ark_ff::Field; use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; -use light_poseidon::PoseidonBytesHasher; +use light_poseidon::{PoseidonBytesHasher, PoseidonHasher}; use rand::RngCore; use rand_chacha::ChaCha8Rng; use rand_core::SeedableRng; -use rln::{circuit::Fr, utils::fr_to_bytes_le}; +use rln::{circuit::Fr, hashers::PoseidonHash, utils::fr_to_bytes_le}; use zerokit_utils::{ FullMerkleConfig, FullMerkleTree, Hasher, OptimalMerkleConfig, OptimalMerkleTree, Poseidon, ZerokitMerkleTree as _, }; -use zk_kit_lean_imt:: - hashed_tree::{HashedLeanIMT, LeanIMTHasher} -; +use zk_kit_lean_imt::lean_imt::LeanIMT; const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [ (2, 8, 56, 0), @@ -45,11 +44,11 @@ impl Iterator for HashMockStream { Some(res) } } -impl LeanIMTHasher<32> for HashMockStream { - fn hash(input: &[u8]) -> [u8; 32] { - input.try_into().unwrap() - } -} +// impl LeanIMTHasher<32> for HashMockStream { +// fn hash(input: &[u8]) -> [u8; 32] { +// input.try_into().unwrap() +// } +// } lazy_static::lazy_static! { static ref LEAVES: [[u8; 32]; 40] = HashMockStream::seeded_stream(42) .take(40) @@ -60,7 +59,7 @@ lazy_static::lazy_static! { #[derive(Debug)] struct BenchyIFTHasher; - +struct BenchyLightPosHasher; impl Hasher for BenchyIFTHasher { type Fr = Fr; @@ -73,34 +72,34 @@ impl Hasher for BenchyIFTHasher { } } -impl LeanIMTHasher for BenchyIFTHasher { - fn hash(input: &[u8]) -> [u8; N] { - let hasher = Poseidon::::from(&ROUND_PARAMS); - let input_as_frs: Vec<_> = input - .chunks(N) - .map(|ch| rln::utils::bytes_le_to_fr(ch).0) - .collect(); - let res = hasher.hash(&input_as_frs).unwrap(); - let byte_vec: Vec = fr_to_bytes_le(&res); - let mut res = [0; N]; - if byte_vec.len() >= N { - res.copy_from_slice(&byte_vec[..N]); - } else { - res.copy_from_slice(&byte_vec); - }; - res - } -} +// impl LeanIMTHasher for BenchyIFTHasher { +// fn hash(input: &[u8]) -> [u8; N] { +// let hasher = Poseidon::::from(&ROUND_PARAMS); +// let input_as_frs: Vec<_> = input +// .chunks(N) +// .map(|ch| rln::utils::bytes_le_to_fr(ch).0) +// .collect(); +// let res = hasher.hash(&input_as_frs).unwrap(); +// let byte_vec: Vec = fr_to_bytes_le(&res); +// let mut res = [0; N]; +// if byte_vec.len() >= N { +// res.copy_from_slice(&byte_vec[..N]); +// } else { +// res.copy_from_slice(&byte_vec); +// }; +// res +// } +// } +// +// impl LeanIMTHasher<32> for BenchyLightPosHasher { +// fn hash(input: &[u8]) -> [u8; 32] { +// let mut hasher = light_poseidon::Poseidon::::new_circom(1).unwrap(); +// let chunks: Vec<&[u8]> = input.chunks(32).collect(); +// hasher.hash_bytes_le(&chunks).unwrap() +// } +// } -impl LeanIMTHasher<32> for BenchyLightPosHasher { - fn hash(input: &[u8]) -> [u8; 32] { - let mut hasher = light_poseidon::Poseidon::::new_circom(1).unwrap(); - let chunks: Vec<&[u8]> = input.chunks(32).collect(); - hasher.hash_bytes_le(&chunks).unwrap() - } -} - -fn make_data_table() -> (Vec<[u8; 32]>, Vec, impl Iterator) { +fn make_data_table() -> (Vec<[u8; 32]>, Vec, [u32; 3]) { let size_group = [7u32, 13, 17]; let data_table: Vec<[u8; 32]> = HashMockStream::seeded_stream(42) .take(*size_group.iter().max().unwrap() as usize) @@ -119,12 +118,15 @@ fn make_data_table() -> (Vec<[u8; 32]>, Vec, impl Iterator) { }) .collect::, _>>() .unwrap(); - (data_table, fr_table, size_group.into_iter()) + (data_table, fr_table, size_group) +} +fn noop_hash(data: &[u8]) -> [u8; 32] { + data[0..32].try_into().unwrap() } - pub fn hashless_setup_iterative(c: &mut Criterion) { let mut group = c.benchmark_group("hashless tree iterative setup"); let (data_table, fr_table, size_group) = make_data_table(); + for size in size_group { group.bench_with_input( BenchmarkId::new("Lean IMT iterative", size), @@ -134,14 +136,13 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { // Setup: create values for each benchmark iteration || { let data_source = &data_table[0..size as usize]; - let tree = HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher) - .unwrap(); + let tree = LeanIMT::<32>::new(&[], noop_hash).unwrap(); (tree, data_source) }, // Actual benchmark |(mut tree, data_source)| { for d in data_source.iter() { - tree.insert(d); + tree.insert(d, noop_hash); } }, BatchSize::SmallInput, @@ -206,58 +207,69 @@ pub fn hashless_setup_batch(c: &mut Criterion) { let mut group = c.benchmark_group("hashless tree batch setup"); let (data_table, fr_table, size_group) = make_data_table(); for size in size_group { - group.bench_with_input(BenchmarkId::new("Lean IMT", size), &size, |b, &size| { - b.iter_batched( - // Setup: create values for each benchmark iteration - || { - let data_source = &data_table[0..size as usize]; - let tree = - HashedLeanIMT::<32, BenchyIFTHasher>::new(&[], BenchyIFTHasher).unwrap(); - (tree, data_source) - }, - // Actual benchmark - |(mut tree, data_source)| tree.insert_many(data_source), - BatchSize::SmallInput, - ) - }); - group.bench_with_input(BenchmarkId::new("IFT optimal", size), &size, |b, &size| { - b.iter_batched( - // Setup: create values for each benchmark iteration - || { - let data_source = &fr_table[0..size as usize]; - let data_source = data_source.iter().copied(); - let tree = OptimalMerkleTree::::new( - 6, - Fr::default(), - OptimalMerkleConfig::default(), - ) - .unwrap(); - (tree, data_source) - }, - // Actual benchmark - |(mut tree, data_source)| tree.set_range(0, data_source), - BatchSize::SmallInput, - ) - }); - group.bench_with_input(BenchmarkId::new("IFT full", size), &size, |b, &size| { - b.iter_batched( - // Setup: create values for each benchmark iteration - || { - let data_source = &fr_table[0..size as usize]; - let data_source = data_source.iter().copied(); - let tree = FullMerkleTree::::new( - 6, - Fr::default(), - FullMerkleConfig::default(), - ) - .unwrap(); - (tree, data_source) - }, - // Actual benchmark - |(mut tree, data_source)| tree.set_range(0, data_source), - BatchSize::SmallInput, - ) - }); + group.bench_with_input( + BenchmarkId::new("Lean IMT batch", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &data_table[0..size as usize]; + let tree = LeanIMT::<32>::new(&[], noop_hash).unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.insert_many(data_source, noop_hash), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT optimal batch", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &fr_table[0..size as usize]; + let data_source = data_source.iter().copied(); + let tree = OptimalMerkleTree::::new( + 6, + Fr::default(), + OptimalMerkleConfig::default(), + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.set_range(0, data_source), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT full batch", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &fr_table[0..size as usize]; + let data_source = data_source.iter().copied(); + let tree = FullMerkleTree::::new( + 6, + Fr::default(), + FullMerkleConfig::default(), + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.set_range(0, data_source), + BatchSize::SmallInput, + ) + }, + ); } group.finish(); } @@ -266,7 +278,7 @@ criterion_group! { name = benchies; config = Criterion::default() .warm_up_time(std::time::Duration::from_millis(500)) - .measurement_time(std::time::Duration::from_secs(4)) + .measurement_time(std::time::Duration::from_secs(2)) .sample_size(10); targets = hashless_setup_batch, hashless_setup_iterative } From 610703ea30d59aee01e53b94f3a1b1538b1bd7c2 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Tue, 13 May 2025 19:02:59 +0200 Subject: [PATCH 12/24] Run a tree/hash benchmark shootout --- utils/benches/imt_benchy.rs | 236 +++++++++++++++++++++++++++++------- 1 file changed, 190 insertions(+), 46 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 4131ee15..77942268 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -1,28 +1,33 @@ -use std::{fmt::Display, str::FromStr}; +use std::str::FromStr; -use ark_ff::Field; +use ark_ff::{BigInteger, Field, PrimeField}; use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; -use light_poseidon::{PoseidonBytesHasher, PoseidonHasher}; +use light_poseidon::PoseidonBytesHasher; use rand::RngCore; use rand_chacha::ChaCha8Rng; use rand_core::SeedableRng; -use rln::{circuit::Fr, hashers::PoseidonHash, utils::fr_to_bytes_le}; +use rln::{ + circuit::Fr, + hashers::{PoseidonHash, ROUND_PARAMS}, +}; use zerokit_utils::{ FullMerkleConfig, FullMerkleTree, Hasher, OptimalMerkleConfig, OptimalMerkleTree, Poseidon, ZerokitMerkleTree as _, }; -use zk_kit_lean_imt::lean_imt::LeanIMT; +use zk_kit_lean_imt::{hashed_tree::LeanIMTHasher, lean_imt::LeanIMT}; + +impl zerokit_utils::Hasher for BenchyLightPosHasher { + type Fr = Fr; -const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [ - (2, 8, 56, 0), - (3, 8, 57, 0), - (4, 8, 56, 0), - (5, 8, 60, 0), - (6, 8, 60, 0), - (7, 8, 63, 0), - (8, 8, 64, 0), - (9, 8, 63, 0), -]; + fn default_leaf() -> Self::Fr { + Self::Fr::default() + } + + fn hash(input: &[Self::Fr]) -> Self::Fr { + let hasher = Poseidon::from(&ROUND_PARAMS); + hasher.hash(input).unwrap() + } +} // ChaCha8Rng is chosen for its portable determinism struct HashMockStream { rng: ChaCha8Rng, @@ -50,8 +55,8 @@ impl Iterator for HashMockStream { // } // } lazy_static::lazy_static! { - static ref LEAVES: [[u8; 32]; 40] = HashMockStream::seeded_stream(42) - .take(40) + static ref LEAVES: [[u8; 32]; 400] = HashMockStream::seeded_stream(42) + .take(400) .collect::>() .try_into() .unwrap(); @@ -72,32 +77,28 @@ impl Hasher for BenchyIFTHasher { } } -// impl LeanIMTHasher for BenchyIFTHasher { -// fn hash(input: &[u8]) -> [u8; N] { -// let hasher = Poseidon::::from(&ROUND_PARAMS); -// let input_as_frs: Vec<_> = input -// .chunks(N) -// .map(|ch| rln::utils::bytes_le_to_fr(ch).0) -// .collect(); -// let res = hasher.hash(&input_as_frs).unwrap(); -// let byte_vec: Vec = fr_to_bytes_le(&res); -// let mut res = [0; N]; -// if byte_vec.len() >= N { -// res.copy_from_slice(&byte_vec[..N]); -// } else { -// res.copy_from_slice(&byte_vec); -// }; -// res -// } -// } -// -// impl LeanIMTHasher<32> for BenchyLightPosHasher { -// fn hash(input: &[u8]) -> [u8; 32] { -// let mut hasher = light_poseidon::Poseidon::::new_circom(1).unwrap(); -// let chunks: Vec<&[u8]> = input.chunks(32).collect(); -// hasher.hash_bytes_le(&chunks).unwrap() -// } -// } +impl LeanIMTHasher for BenchyIFTHasher { + fn hash(input: &[u8]) -> [u8; N] { + let hasher = Poseidon::::from(&ROUND_PARAMS); + + let frs = input + .chunks(N) + .map(|bytes| Fr::from_random_bytes(bytes).unwrap_or(Fr::default())) + .collect::>(); + let frs = frs.as_slice(); + let res_fr: Fr = hasher.hash(frs).unwrap(); + let res_bytes: [u8; N] = res_fr.into_bigint().to_bytes_le().try_into().unwrap(); + res_bytes + } +} +impl LeanIMTHasher<32> for BenchyLightPosHasher { + fn hash(input: &[u8]) -> [u8; 32] { + let mut hasher = light_poseidon::Poseidon::::new_circom(1).unwrap(); + // TODO: this should be doable without mucking around with heap-memory + let chunks: Vec<&[u8]> = input.chunks(32).collect(); + hasher.hash_bytes_le(&chunks).unwrap() + } +} fn make_data_table() -> (Vec<[u8; 32]>, Vec, [u32; 3]) { let size_group = [7u32, 13, 17]; @@ -274,12 +275,155 @@ pub fn hashless_setup_batch(c: &mut Criterion) { group.finish(); } +fn tree_hash_batch_shootout(c: &mut Criterion) { + let mut group = c.benchmark_group("hash+tree batch shootout"); + let (data_table, fr_table, size_group) = make_data_table(); + for size in size_group { + group.bench_with_input( + BenchmarkId::new("Lean IMT batch poseidon", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &data_table[0..size as usize]; + let tree = + LeanIMT::<32>::new(&[], >::hash) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| { + tree.insert_many(data_source, >::hash) + }, + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("Lean IMT batch light-poseidon", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &data_table[0..size as usize]; + let tree = LeanIMT::<32>::new( + &[], + >::hash, + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| { + tree.insert_many(data_source, >::hash) + }, + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT optimal batch poseidon", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &fr_table[0..size as usize]; + let data_source = data_source.iter().copied(); + let tree = OptimalMerkleTree::::new( + 6, + Fr::default(), + OptimalMerkleConfig::default(), + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.set_range(0, data_source), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT optimal batch light-poseidon", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &fr_table[0..size as usize]; + let data_source = data_source.iter().copied(); + let tree = OptimalMerkleTree::::new( + 6, + Fr::default(), + OptimalMerkleConfig::default(), + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.set_range(0, data_source), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT full batch poseidon", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &fr_table[0..size as usize]; + let data_source = data_source.iter().copied(); + let tree = FullMerkleTree::::new( + 6, + Fr::default(), + FullMerkleConfig::default(), + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.set_range(0, data_source), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT full batch light-poseidon", size), + &size, + |b, &size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let data_source = &fr_table[0..size as usize]; + let data_source = data_source.iter().copied(); + let tree = FullMerkleTree::::new( + 6, + Fr::default(), + FullMerkleConfig::default(), + ) + .unwrap(); + (tree, data_source) + }, + // Actual benchmark + |(mut tree, data_source)| tree.set_range(0, data_source), + BatchSize::SmallInput, + ) + }, + ); + } +} + criterion_group! { name = benchies; config = Criterion::default() .warm_up_time(std::time::Duration::from_millis(500)) - .measurement_time(std::time::Duration::from_secs(2)) - .sample_size(10); - targets = hashless_setup_batch, hashless_setup_iterative + .measurement_time(std::time::Duration::from_secs(4)) + .sample_size(50); + targets = /* hashless_setup_batch, hashless_setup_iterative, */ tree_hash_batch_shootout } criterion_main!(benchies); From d07649a225f6dac0ca01278d963dafb55f35b16b Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Wed, 14 May 2025 17:58:45 +0200 Subject: [PATCH 13/24] Clean up benchies --- utils/benches/imt_benchy.rs | 187 ++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 73 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 77942268..6a098da1 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -1,18 +1,19 @@ -use std::str::FromStr; +use std::{hint::black_box, str::FromStr}; -use ark_ff::{BigInteger, Field, PrimeField}; +use ark_ff::{BigInteger, PrimeField}; use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; -use light_poseidon::PoseidonBytesHasher; +use light_poseidon::{Poseidon as LtPoseidon, PoseidonBytesHasher as LtPoseidonBytesHasher}; use rand::RngCore; use rand_chacha::ChaCha8Rng; use rand_core::SeedableRng; use rln::{ circuit::Fr, hashers::{PoseidonHash, ROUND_PARAMS}, + utils::{bytes_le_to_fr, fr_to_bytes_le}, }; use zerokit_utils::{ FullMerkleConfig, FullMerkleTree, Hasher, OptimalMerkleConfig, OptimalMerkleTree, Poseidon, - ZerokitMerkleTree as _, + ZerokitMerkleTree, }; use zk_kit_lean_imt::{hashed_tree::LeanIMTHasher, lean_imt::LeanIMT}; @@ -63,9 +64,11 @@ lazy_static::lazy_static! { } #[derive(Debug)] +struct BenchyNoOpHasher; struct BenchyIFTHasher; struct BenchyLightPosHasher; -impl Hasher for BenchyIFTHasher { + +impl Hasher for BenchyNoOpHasher { type Fr = Fr; fn default_leaf() -> Self::Fr { @@ -77,13 +80,13 @@ impl Hasher for BenchyIFTHasher { } } -impl LeanIMTHasher for BenchyIFTHasher { +impl LeanIMTHasher for BenchyNoOpHasher { fn hash(input: &[u8]) -> [u8; N] { let hasher = Poseidon::::from(&ROUND_PARAMS); let frs = input .chunks(N) - .map(|bytes| Fr::from_random_bytes(bytes).unwrap_or(Fr::default())) + .map(Fr::from_le_bytes_mod_order) .collect::>(); let frs = frs.as_slice(); let res_fr: Fr = hasher.hash(frs).unwrap(); @@ -93,15 +96,37 @@ impl LeanIMTHasher for BenchyIFTHasher { } impl LeanIMTHasher<32> for BenchyLightPosHasher { fn hash(input: &[u8]) -> [u8; 32] { - let mut hasher = light_poseidon::Poseidon::::new_circom(1).unwrap(); // TODO: this should be doable without mucking around with heap-memory let chunks: Vec<&[u8]> = input.chunks(32).collect(); + let mut hasher = LtPoseidon::::new_circom(chunks.len()).unwrap(); hasher.hash_bytes_le(&chunks).unwrap() } } +impl LeanIMTHasher<32> for BenchyIFTHasher { + fn hash(input: &[u8]) -> [u8; 32] { + // assert_eq!(input.len() % 32, 0, "Slice length must be a multiple of 32, got modulo {}", input.len() % 32); + let chunks: Vec<&[u8]> = input.chunks(32).collect(); + let mut lt_hasher = LtPoseidon::::new_circom(chunks.len()).unwrap(); + lt_hasher.hash_bytes_le(&chunks).unwrap() + } +} +/// We start with pseudorandom bytes, and make the changes needed for them +/// to be valid Fr bytes, just needing raw reinterpretation. +fn lean_data_prep(raw_vec: &[[u8; 32]]) -> Vec<[u8; 32]> { + raw_vec + .iter() + .cloned() + // take raw bytes and Fr-ize it + .map(|chunk| bytes_le_to_fr(&chunk).0) + // turn it back into a byte collection + .map(|bytes| fr_to_bytes_le(&bytes)) + // coorce it into the [u8; 32]s needed for light-imt hash signature + .map(|bytes| std::convert::TryInto::<[u8; 32]>::try_into(bytes).unwrap()) + .collect() +} -fn make_data_table() -> (Vec<[u8; 32]>, Vec, [u32; 3]) { - let size_group = [7u32, 13, 17]; +fn make_data_table() -> (Vec<[u8; 32]>, Vec, [u32; 4]) { + let size_group = [7u32, 13, 17, 40]; let data_table: Vec<[u8; 32]> = HashMockStream::seeded_stream(42) .take(*size_group.iter().max().unwrap() as usize) .collect(); @@ -129,47 +154,44 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { let (data_table, fr_table, size_group) = make_data_table(); for size in size_group { + let data_source = &data_table[0..size as usize]; + let fr_source = &fr_table[0..size as usize]; group.bench_with_input( BenchmarkId::new("Lean IMT iterative", size), &size, - |b, &size| { + |b, &_size| { b.iter_batched( // Setup: create values for each benchmark iteration - || { - let data_source = &data_table[0..size as usize]; - let tree = LeanIMT::<32>::new(&[], noop_hash).unwrap(); - (tree, data_source) - }, + || LeanIMT::<32>::new(&[], noop_hash).unwrap(), // Actual benchmark - |(mut tree, data_source)| { + |mut tree| { for d in data_source.iter() { - tree.insert(d, noop_hash); + black_box(tree.insert(d, noop_hash)); } }, BatchSize::SmallInput, ) }, ); + group.bench_with_input( BenchmarkId::new("IFT optimal iterative", size), &size, - |b, &size| { + |b, &_size| { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source = &fr_table[0..size as usize]; - let tree = OptimalMerkleTree::::new( + OptimalMerkleTree::::new( 6, Fr::default(), OptimalMerkleConfig::default(), ) - .unwrap(); - (tree, data_source) + .unwrap() }, // Actual benchmark - |(mut tree, data_source)| { - for (i, d) in data_source.iter().enumerate() { - tree.set(i, *d).unwrap(); + |mut tree| { + for (i, d) in fr_source.iter().enumerate() { + black_box(tree.set(i, *d)).unwrap(); } }, BatchSize::SmallInput, @@ -179,23 +201,21 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { group.bench_with_input( BenchmarkId::new("IFT full iterative", size), &size, - |b, &size| { + |b, &_size| { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source = &fr_table[0..size as usize]; - let tree = FullMerkleTree::::new( + FullMerkleTree::::new( 6, Fr::default(), FullMerkleConfig::default(), ) - .unwrap(); - (tree, data_source) + .unwrap() }, // Actual benchmark - |(mut tree, data_source)| { - for (i, d) in data_source.iter().enumerate() { - tree.set(i, *d).unwrap(); + |mut tree| { + for (i, d) in fr_source.iter().enumerate() { + black_box(tree.set(i, *d)).unwrap(); } }, BatchSize::SmallInput, @@ -208,19 +228,16 @@ pub fn hashless_setup_batch(c: &mut Criterion) { let mut group = c.benchmark_group("hashless tree batch setup"); let (data_table, fr_table, size_group) = make_data_table(); for size in size_group { + let data_source = &data_table[0..size as usize]; group.bench_with_input( BenchmarkId::new("Lean IMT batch", size), &size, - |b, &size| { + |b, &_size| { b.iter_batched( // Setup: create values for each benchmark iteration - || { - let data_source = &data_table[0..size as usize]; - let tree = LeanIMT::<32>::new(&[], noop_hash).unwrap(); - (tree, data_source) - }, + || LeanIMT::<32>::new(&[], noop_hash).unwrap(), // Actual benchmark - |(mut tree, data_source)| tree.insert_many(data_source, noop_hash), + |mut tree| black_box(tree.insert_many(data_source, noop_hash)), BatchSize::SmallInput, ) }, @@ -234,7 +251,7 @@ pub fn hashless_setup_batch(c: &mut Criterion) { || { let data_source = &fr_table[0..size as usize]; let data_source = data_source.iter().copied(); - let tree = OptimalMerkleTree::::new( + let tree = OptimalMerkleTree::::new( 6, Fr::default(), OptimalMerkleConfig::default(), @@ -243,7 +260,7 @@ pub fn hashless_setup_batch(c: &mut Criterion) { (tree, data_source) }, // Actual benchmark - |(mut tree, data_source)| tree.set_range(0, data_source), + |(mut tree, data_source)| black_box(tree.set_range(0, data_source)), BatchSize::SmallInput, ) }, @@ -257,7 +274,7 @@ pub fn hashless_setup_batch(c: &mut Criterion) { || { let data_source = &fr_table[0..size as usize]; let data_source = data_source.iter().copied(); - let tree = FullMerkleTree::::new( + let tree = FullMerkleTree::::new( 6, Fr::default(), FullMerkleConfig::default(), @@ -266,7 +283,7 @@ pub fn hashless_setup_batch(c: &mut Criterion) { (tree, data_source) }, // Actual benchmark - |(mut tree, data_source)| tree.set_range(0, data_source), + |(mut tree, data_source)| black_box(tree.set_range(0, data_source)), BatchSize::SmallInput, ) }, @@ -275,26 +292,28 @@ pub fn hashless_setup_batch(c: &mut Criterion) { group.finish(); } -fn tree_hash_batch_shootout(c: &mut Criterion) { +fn tree_hash_batch_setup_shootout(c: &mut Criterion) { let mut group = c.benchmark_group("hash+tree batch shootout"); - let (data_table, fr_table, size_group) = make_data_table(); + let (_data_table, fr_table, size_group) = make_data_table(); for size in size_group { + let data_stream = HashMockStream::seeded_stream(size as u64); + let data_source = data_stream.take(size as usize).collect::>(); group.bench_with_input( BenchmarkId::new("Lean IMT batch poseidon", size), &size, - |b, &size| { + |b, &_size| { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source = &data_table[0..size as usize]; + let byte_form = lean_data_prep(&data_source); let tree = LeanIMT::<32>::new(&[], >::hash) .unwrap(); - (tree, data_source) + (tree, byte_form) }, // Actual benchmark - |(mut tree, data_source)| { - tree.insert_many(data_source, >::hash) + |(mut tree, byte_form)| { + black_box(tree.insert_many(&byte_form, >::hash)) }, BatchSize::SmallInput, ) @@ -303,21 +322,24 @@ fn tree_hash_batch_shootout(c: &mut Criterion) { group.bench_with_input( BenchmarkId::new("Lean IMT batch light-poseidon", size), &size, - |b, &size| { + |b, &_size| { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source = &data_table[0..size as usize]; + let byte_form = lean_data_prep(&data_source); let tree = LeanIMT::<32>::new( &[], >::hash, ) .unwrap(); - (tree, data_source) + (tree, byte_form) }, // Actual benchmark |(mut tree, data_source)| { - tree.insert_many(data_source, >::hash) + black_box(tree.insert_many( + &data_source, + >::hash, + )) }, BatchSize::SmallInput, ) @@ -330,18 +352,18 @@ fn tree_hash_batch_shootout(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source = &fr_table[0..size as usize]; - let data_source = data_source.iter().copied(); + let fr_slice = &fr_table[0..size as usize]; + let fr_iter = fr_slice.iter().copied(); let tree = OptimalMerkleTree::::new( 6, Fr::default(), OptimalMerkleConfig::default(), ) .unwrap(); - (tree, data_source) + (tree, fr_iter) }, // Actual benchmark - |(mut tree, data_source)| tree.set_range(0, data_source), + |(mut tree, data_source)| black_box(tree.set_range(0, data_source)), BatchSize::SmallInput, ) }, @@ -353,18 +375,18 @@ fn tree_hash_batch_shootout(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source = &fr_table[0..size as usize]; - let data_source = data_source.iter().copied(); + let fr_slice = &fr_table[0..size as usize]; + let fr_iter = fr_slice.iter().copied(); let tree = OptimalMerkleTree::::new( 6, Fr::default(), OptimalMerkleConfig::default(), ) .unwrap(); - (tree, data_source) + (tree, fr_iter) }, // Actual benchmark - |(mut tree, data_source)| tree.set_range(0, data_source), + |(mut tree, fr_iter)| black_box(tree.set_range(0, fr_iter)), BatchSize::SmallInput, ) }, @@ -376,18 +398,18 @@ fn tree_hash_batch_shootout(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source = &fr_table[0..size as usize]; - let data_source = data_source.iter().copied(); + let fr_slice = &fr_table[0..size as usize]; + let fr_iter = fr_slice.iter().copied(); let tree = FullMerkleTree::::new( 6, Fr::default(), FullMerkleConfig::default(), ) .unwrap(); - (tree, data_source) + (tree, fr_iter) }, // Actual benchmark - |(mut tree, data_source)| tree.set_range(0, data_source), + |(mut tree, fr_iter)| black_box(tree.set_range(0, fr_iter)), BatchSize::SmallInput, ) }, @@ -399,15 +421,25 @@ fn tree_hash_batch_shootout(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let data_source = &fr_table[0..size as usize]; - let data_source = data_source.iter().copied(); + let fr_slice = &fr_table[0..size as usize]; + let fr_iter = fr_slice.iter().copied(); let tree = FullMerkleTree::::new( 6, Fr::default(), FullMerkleConfig::default(), ) .unwrap(); - (tree, data_source) + (tree, fr_iter) + }, + // Actual benchmark + |(mut tree, fr_iter)| black_box(tree.set_range(0, fr_iter)), + BatchSize::SmallInput, + ) + }, + ); + } + group.finish(); +} }, // Actual benchmark |(mut tree, data_source)| tree.set_range(0, data_source), @@ -418,12 +450,21 @@ fn tree_hash_batch_shootout(c: &mut Criterion) { } } +criterion_main!(tree_benchies); criterion_group! { - name = benchies; + name = tree_benchies; + config = Criterion::default() + .warm_up_time(std::time::Duration::from_millis(500)) + .measurement_time(std::time::Duration::from_secs(4)) + .sample_size(40); + targets = + hashless_setup_batch, + hashless_setup_iterative, + tree_hash_batch_setup_shootout, +} config = Criterion::default() .warm_up_time(std::time::Duration::from_millis(500)) .measurement_time(std::time::Duration::from_secs(4)) .sample_size(50); targets = /* hashless_setup_batch, hashless_setup_iterative, */ tree_hash_batch_shootout } -criterion_main!(benchies); From e94e019f18f01baaa83e8774a4824b23cc56fcc1 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Wed, 14 May 2025 18:02:58 +0200 Subject: [PATCH 14/24] Clean up benchies --- utils/benches/imt_benchy.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 6a098da1..9fbb412d 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -166,7 +166,8 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { // Actual benchmark |mut tree| { for d in data_source.iter() { - black_box(tree.insert(d, noop_hash)); + #[allow(clippy::unit_arg)] + black_box(tree.insert(d, noop_hash)) } }, BatchSize::SmallInput, @@ -440,15 +441,6 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { } group.finish(); } - }, - // Actual benchmark - |(mut tree, data_source)| tree.set_range(0, data_source), - BatchSize::SmallInput, - ) - }, - ); - } -} criterion_main!(tree_benchies); criterion_group! { @@ -461,10 +453,4 @@ criterion_group! { hashless_setup_batch, hashless_setup_iterative, tree_hash_batch_setup_shootout, -} - config = Criterion::default() - .warm_up_time(std::time::Duration::from_millis(500)) - .measurement_time(std::time::Duration::from_secs(4)) - .sample_size(50); - targets = /* hashless_setup_batch, hashless_setup_iterative, */ tree_hash_batch_shootout } From 810472f6dd7a9406e1e16a4a2473633fb7755ec4 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Wed, 14 May 2025 18:05:20 +0200 Subject: [PATCH 15/24] Add zk benchies --- utils/benches/imt_benchy.rs | 190 ++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 9fbb412d..ff6fc4be 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -442,6 +442,186 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { group.finish(); } +pub fn proof_gen_shootout(c: &mut Criterion) { + let mut group = c.benchmark_group("MTree proof-gen shootout"); + let (_data_table, _fr_table, size_group) = make_data_table(); + for size in size_group { + let data_stream = HashMockStream::seeded_stream(size as u64); + let chunk_vec = data_stream.take(size as usize).collect::>(); + group.bench_with_input( + BenchmarkId::new("Lean IMT proof generation", size), + &size, + |b, &_size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let frd_byte_chunks = lean_data_prep(&chunk_vec); + LeanIMT::<32>::new( + &frd_byte_chunks, + >::hash, + ) + .unwrap() + }, + // Actual benchmark + |tree| black_box(tree.generate_proof(0)), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT full proof generation", size), + &size, + |b, &_size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let fr_form: Vec = chunk_vec + .iter() + .cloned() + // take raw bytes and Fr-ize it + .map(|chunk| bytes_le_to_fr(&chunk).0) + .collect(); + let mut tree = FullMerkleTree::::new( + 7, + Fr::default(), + FullMerkleConfig::default(), + ) + .unwrap(); + tree.set_range(0, fr_form.into_iter()).unwrap(); + tree + }, + // Actual benchmark + |tree| black_box(tree.proof(0)), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT optimal proof generation", size), + &size, + |b, &_size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let fr_form: Vec = chunk_vec + .iter() + .cloned() + // take raw bytes and Fr-ize it + .map(|chunk| bytes_le_to_fr(&chunk).0) + .collect(); + let mut tree = OptimalMerkleTree::::new( + 7, + Fr::default(), + OptimalMerkleConfig::default(), + ) + .unwrap(); + tree.set_range(0, fr_form.into_iter()).unwrap(); + tree + }, + // Actual benchmark + |tree| black_box(tree.proof(0)), + BatchSize::SmallInput, + ) + }, + ); + } +} + +pub fn verification_shootout(c: &mut Criterion) { + let mut group = c.benchmark_group("MTree verification shootout"); + let (_data_table, _fr_table, size_group) = make_data_table(); + for size in size_group { + let data_stream = HashMockStream::seeded_stream(size as u64); + let data_source = data_stream.take(size as usize).collect::>(); + group.bench_with_input( + BenchmarkId::new("Lean IMT verification", size), + &size, + |b, &_size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let frd_bytes = lean_data_prep(&data_source); + let tree = LeanIMT::<32>::new( + &frd_bytes, + >::hash, + ) + .unwrap(); + let proof = tree.generate_proof(0).unwrap(); + // assert!(LeanIMT::verify_proof(&proof, >::hash)); + proof + }, + // Actual benchmark + |proof| { + black_box(LeanIMT::verify_proof(&proof, >::hash)) + }, + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT full verification", size), + &size, + |b, &_size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let fr_form: Vec = data_source + .iter() + .cloned() + // take raw bytes and Fr-ize it + .map(|chunk| bytes_le_to_fr(&chunk).0) + .collect(); + let mut tree = FullMerkleTree::::new( + 7, + Fr::default(), + FullMerkleConfig::default(), + ) + .unwrap(); + let first_leaf = *fr_form.first().unwrap(); + tree.set_range(0, fr_form.into_iter()).unwrap(); + let proof = tree.proof(0).unwrap(); + // assert!(tree.verify(&first_leaf, &proof).unwrap()); + (first_leaf, tree, proof) + }, + // Actual benchmark + |(first_leaf, tree, proof)| black_box(tree.verify(&first_leaf, &proof)), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT optimal verification", size), + &size, + |b, &_size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let fr_form: Vec = data_source + .iter() + .cloned() + // take raw bytes and Fr-ize it + .map(|chunk| bytes_le_to_fr(&chunk).0) + .collect(); + let mut tree = OptimalMerkleTree::::new( + 7, + Fr::default(), + OptimalMerkleConfig::default(), + ) + .unwrap(); + let first_leaf = *fr_form.first().unwrap(); + tree.set_range(0, fr_form.into_iter()).unwrap(); + let proof = tree.proof(0).unwrap(); + // assert!(tree.verify(&first_leaf, &proof).unwrap()); + (first_leaf, tree, proof) + }, + // Actual benchmark + |(first_leaf, tree, proof)| black_box(tree.verify(&first_leaf, &proof)), + BatchSize::SmallInput, + ) + }, + ); + } +} criterion_main!(tree_benchies); criterion_group! { name = tree_benchies; @@ -454,3 +634,13 @@ criterion_group! { hashless_setup_iterative, tree_hash_batch_setup_shootout, } +criterion_group! { + name = tree_zk_benchies; + config = Criterion::default() + .warm_up_time(std::time::Duration::from_millis(500)) + .measurement_time(std::time::Duration::from_secs(4)) + .sample_size(10); + targets = + proof_gen_shootout, + verification_shootout +} From 0061def3889195266f8e3e48076d16c622964df5 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Wed, 14 May 2025 18:46:21 +0200 Subject: [PATCH 16/24] cleanup and cross-wired fixups --- utils/benches/imt_benchy.rs | 166 +++++++++++++++++++----------------- 1 file changed, 86 insertions(+), 80 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index ff6fc4be..974c2396 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -1,39 +1,27 @@ use std::{hint::black_box, str::FromStr}; -use ark_ff::{BigInteger, PrimeField}; use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; -use light_poseidon::{Poseidon as LtPoseidon, PoseidonBytesHasher as LtPoseidonBytesHasher}; +use light_poseidon::{ + Poseidon as LtPoseidon, PoseidonBytesHasher as LtPoseidonBytesHasher, PoseidonHasher as _, +}; use rand::RngCore; use rand_chacha::ChaCha8Rng; use rand_core::SeedableRng; use rln::{ circuit::Fr, - hashers::{PoseidonHash, ROUND_PARAMS}, + hashers::PoseidonHash, utils::{bytes_le_to_fr, fr_to_bytes_le}, }; use zerokit_utils::{ - FullMerkleConfig, FullMerkleTree, Hasher, OptimalMerkleConfig, OptimalMerkleTree, Poseidon, - ZerokitMerkleTree, + FullMerkleConfig, FullMerkleTree, Hasher as ZKitUtilsHasher, OptimalMerkleConfig, + OptimalMerkleTree, ZerokitMerkleTree, }; use zk_kit_lean_imt::{hashed_tree::LeanIMTHasher, lean_imt::LeanIMT}; -impl zerokit_utils::Hasher for BenchyLightPosHasher { - type Fr = Fr; - - fn default_leaf() -> Self::Fr { - Self::Fr::default() - } - - fn hash(input: &[Self::Fr]) -> Self::Fr { - let hasher = Poseidon::from(&ROUND_PARAMS); - hasher.hash(input).unwrap() - } -} // ChaCha8Rng is chosen for its portable determinism struct HashMockStream { rng: ChaCha8Rng, } - impl HashMockStream { fn seeded_stream(seed: u64) -> Self { let rng = ChaCha8Rng::seed_from_u64(seed); @@ -50,25 +38,19 @@ impl Iterator for HashMockStream { Some(res) } } -// impl LeanIMTHasher<32> for HashMockStream { -// fn hash(input: &[u8]) -> [u8; 32] { -// input.try_into().unwrap() -// } -// } -lazy_static::lazy_static! { - static ref LEAVES: [[u8; 32]; 400] = HashMockStream::seeded_stream(42) - .take(400) - .collect::>() - .try_into() - .unwrap(); -} #[derive(Debug)] +/// To benchmark the data structure abscent of the hashing overhead struct BenchyNoOpHasher; struct BenchyIFTHasher; struct BenchyLightPosHasher; -impl Hasher for BenchyNoOpHasher { +// ===== +// Ships to IFT Hasher interface +// IFT poseidon hasher doesn't need +// ===== + +impl ZKitUtilsHasher for BenchyNoOpHasher { type Fr = Fr; fn default_leaf() -> Self::Fr { @@ -80,23 +62,30 @@ impl Hasher for BenchyNoOpHasher { } } +impl ZKitUtilsHasher for BenchyLightPosHasher { + type Fr = Fr; + + fn default_leaf() -> Self::Fr { + Self::Fr::default() + } + + fn hash(input: &[Self::Fr]) -> Self::Fr { + let mut hasher = LtPoseidon::::new_circom(input.len()).unwrap(); + hasher.hash(input).unwrap() + } +} + +// ===== +// shims for lean imt interface +// ===== + impl LeanIMTHasher for BenchyNoOpHasher { fn hash(input: &[u8]) -> [u8; N] { - let hasher = Poseidon::::from(&ROUND_PARAMS); - - let frs = input - .chunks(N) - .map(Fr::from_le_bytes_mod_order) - .collect::>(); - let frs = frs.as_slice(); - let res_fr: Fr = hasher.hash(frs).unwrap(); - let res_bytes: [u8; N] = res_fr.into_bigint().to_bytes_le().try_into().unwrap(); - res_bytes + input[0..32].try_into().unwrap() } } impl LeanIMTHasher<32> for BenchyLightPosHasher { fn hash(input: &[u8]) -> [u8; 32] { - // TODO: this should be doable without mucking around with heap-memory let chunks: Vec<&[u8]> = input.chunks(32).collect(); let mut hasher = LtPoseidon::::new_circom(chunks.len()).unwrap(); hasher.hash_bytes_le(&chunks).unwrap() @@ -104,14 +93,16 @@ impl LeanIMTHasher<32> for BenchyLightPosHasher { } impl LeanIMTHasher<32> for BenchyIFTHasher { fn hash(input: &[u8]) -> [u8; 32] { - // assert_eq!(input.len() % 32, 0, "Slice length must be a multiple of 32, got modulo {}", input.len() % 32); let chunks: Vec<&[u8]> = input.chunks(32).collect(); let mut lt_hasher = LtPoseidon::::new_circom(chunks.len()).unwrap(); lt_hasher.hash_bytes_le(&chunks).unwrap() } } -/// We start with pseudorandom bytes, and make the changes needed for them + +/// We start with the data to be hashed, and make the changes needed for them /// to be valid Fr bytes, just needing raw reinterpretation. +/// Needed for LeanIMT because it processes &[u8], not &[Fr] +/// and we want to do away with that mapping as a performance variable fn lean_data_prep(raw_vec: &[[u8; 32]]) -> Vec<[u8; 32]> { raw_vec .iter() @@ -125,14 +116,12 @@ fn lean_data_prep(raw_vec: &[[u8; 32]]) -> Vec<[u8; 32]> { .collect() } -fn make_data_table() -> (Vec<[u8; 32]>, Vec, [u32; 4]) { - let size_group = [7u32, 13, 17, 40]; - let data_table: Vec<[u8; 32]> = HashMockStream::seeded_stream(42) - .take(*size_group.iter().max().unwrap() as usize) - .collect(); +fn spawn_inputs(size_group: &[u32]) -> (Vec<[u8; 32]>, Vec) { + let max = *size_group.iter().max().unwrap() as usize; + let data_table: Vec<[u8; 32]> = HashMockStream::seeded_stream(42).take(max).collect(); let fr_table = HashMockStream::seeded_stream(42) - .take(*size_group.iter().max().unwrap() as usize) + .take(max) .map(|bytes: [u8; 32]| { Fr::from_str( bytes @@ -144,14 +133,13 @@ fn make_data_table() -> (Vec<[u8; 32]>, Vec, [u32; 4]) { }) .collect::, _>>() .unwrap(); - (data_table, fr_table, size_group) -} -fn noop_hash(data: &[u8]) -> [u8; 32] { - data[0..32].try_into().unwrap() + (data_table, fr_table) } + pub fn hashless_setup_iterative(c: &mut Criterion) { let mut group = c.benchmark_group("hashless tree iterative setup"); - let (data_table, fr_table, size_group) = make_data_table(); + let size_group = [7u32, 13, 17, 40]; + let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { let data_source = &data_table[0..size as usize]; @@ -162,12 +150,15 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { |b, &_size| { b.iter_batched( // Setup: create values for each benchmark iteration - || LeanIMT::<32>::new(&[], noop_hash).unwrap(), + || { + LeanIMT::<32>::new(&[], >::hash) + .unwrap() + }, // Actual benchmark |mut tree| { for d in data_source.iter() { #[allow(clippy::unit_arg)] - black_box(tree.insert(d, noop_hash)) + black_box(tree.insert(d, >::hash)) } }, BatchSize::SmallInput, @@ -227,7 +218,8 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { } pub fn hashless_setup_batch(c: &mut Criterion) { let mut group = c.benchmark_group("hashless tree batch setup"); - let (data_table, fr_table, size_group) = make_data_table(); + let size_group = [7u32, 13, 17, 40]; + let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { let data_source = &data_table[0..size as usize]; group.bench_with_input( @@ -236,9 +228,17 @@ pub fn hashless_setup_batch(c: &mut Criterion) { |b, &_size| { b.iter_batched( // Setup: create values for each benchmark iteration - || LeanIMT::<32>::new(&[], noop_hash).unwrap(), + || { + LeanIMT::<32>::new(&[], >::hash) + .unwrap() + }, // Actual benchmark - |mut tree| black_box(tree.insert_many(data_source, noop_hash)), + |mut tree| { + black_box(tree.insert_many( + data_source, + >::hash, + )) + }, BatchSize::SmallInput, ) }, @@ -295,10 +295,10 @@ pub fn hashless_setup_batch(c: &mut Criterion) { fn tree_hash_batch_setup_shootout(c: &mut Criterion) { let mut group = c.benchmark_group("hash+tree batch shootout"); - let (_data_table, fr_table, size_group) = make_data_table(); + let size_group = [7u32, 13, 17, 40]; + let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { - let data_stream = HashMockStream::seeded_stream(size as u64); - let data_source = data_stream.take(size as usize).collect::>(); + let data_source = &data_table[0..size as usize]; group.bench_with_input( BenchmarkId::new("Lean IMT batch poseidon", size), &size, @@ -306,7 +306,7 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let byte_form = lean_data_prep(&data_source); + let byte_form = lean_data_prep(data_source); let tree = LeanIMT::<32>::new(&[], >::hash) .unwrap(); @@ -314,7 +314,12 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { }, // Actual benchmark |(mut tree, byte_form)| { - black_box(tree.insert_many(&byte_form, >::hash)) + black_box( + tree.insert_many( + &byte_form, + >::hash, + ), + ) }, BatchSize::SmallInput, ) @@ -327,7 +332,7 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let byte_form = lean_data_prep(&data_source); + let byte_form = lean_data_prep(data_source); let tree = LeanIMT::<32>::new( &[], >::hash, @@ -444,10 +449,12 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { pub fn proof_gen_shootout(c: &mut Criterion) { let mut group = c.benchmark_group("MTree proof-gen shootout"); - let (_data_table, _fr_table, size_group) = make_data_table(); + let size_group = [7u32, 13, 17, 40]; + let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { - let data_stream = HashMockStream::seeded_stream(size as u64); - let chunk_vec = data_stream.take(size as usize).collect::>(); + let data_source = &data_table[0..size as usize]; + // let data_stream = HashMockStream::seeded_stream(size as u64); + // let chunk_vec = data_stream.take(size as usize).collect::>(); group.bench_with_input( BenchmarkId::new("Lean IMT proof generation", size), &size, @@ -455,7 +462,7 @@ pub fn proof_gen_shootout(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let frd_byte_chunks = lean_data_prep(&chunk_vec); + let frd_byte_chunks = lean_data_prep(data_source); LeanIMT::<32>::new( &frd_byte_chunks, >::hash, @@ -475,7 +482,7 @@ pub fn proof_gen_shootout(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let fr_form: Vec = chunk_vec + let fr_form: Vec = data_source .iter() .cloned() // take raw bytes and Fr-ize it @@ -503,19 +510,15 @@ pub fn proof_gen_shootout(c: &mut Criterion) { b.iter_batched( // Setup: create values for each benchmark iteration || { - let fr_form: Vec = chunk_vec - .iter() - .cloned() - // take raw bytes and Fr-ize it - .map(|chunk| bytes_le_to_fr(&chunk).0) - .collect(); + let fr_slice = &fr_table[0..size as usize]; + let fr_iter = fr_slice.iter().copied(); let mut tree = OptimalMerkleTree::::new( 7, Fr::default(), OptimalMerkleConfig::default(), ) .unwrap(); - tree.set_range(0, fr_form.into_iter()).unwrap(); + tree.set_range(0, fr_iter).unwrap(); tree }, // Actual benchmark @@ -529,7 +532,7 @@ pub fn proof_gen_shootout(c: &mut Criterion) { pub fn verification_shootout(c: &mut Criterion) { let mut group = c.benchmark_group("MTree verification shootout"); - let (_data_table, _fr_table, size_group) = make_data_table(); + let size_group = [7u32, 13, 17, 40]; for size in size_group { let data_stream = HashMockStream::seeded_stream(size as u64); let data_source = data_stream.take(size as usize).collect::>(); @@ -552,7 +555,10 @@ pub fn verification_shootout(c: &mut Criterion) { }, // Actual benchmark |proof| { - black_box(LeanIMT::verify_proof(&proof, >::hash)) + black_box(LeanIMT::verify_proof( + &proof, + >::hash, + )) }, BatchSize::SmallInput, ) From ee6fb5dd12c8671ad323fb599c8191d26270e701 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Wed, 14 May 2025 22:00:50 +0200 Subject: [PATCH 17/24] set tree sized from data sizes --- utils/benches/imt_benchy.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 974c2396..0c762721 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -169,12 +169,12 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { group.bench_with_input( BenchmarkId::new("IFT optimal iterative", size), &size, - |b, &_size| { + |b, &size| { b.iter_batched( // Setup: create values for each benchmark iteration || { OptimalMerkleTree::::new( - 6, + (size.ilog2() + 1) as usize, Fr::default(), OptimalMerkleConfig::default(), ) @@ -193,12 +193,12 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { group.bench_with_input( BenchmarkId::new("IFT full iterative", size), &size, - |b, &_size| { + |b, &size| { b.iter_batched( // Setup: create values for each benchmark iteration || { FullMerkleTree::::new( - 6, + (size.ilog2() + 1) as usize, Fr::default(), FullMerkleConfig::default(), ) @@ -253,7 +253,7 @@ pub fn hashless_setup_batch(c: &mut Criterion) { let data_source = &fr_table[0..size as usize]; let data_source = data_source.iter().copied(); let tree = OptimalMerkleTree::::new( - 6, + (size.ilog2() + 1) as usize, Fr::default(), OptimalMerkleConfig::default(), ) @@ -276,7 +276,7 @@ pub fn hashless_setup_batch(c: &mut Criterion) { let data_source = &fr_table[0..size as usize]; let data_source = data_source.iter().copied(); let tree = FullMerkleTree::::new( - 6, + (size.ilog2() + 1) as usize, Fr::default(), FullMerkleConfig::default(), ) @@ -361,7 +361,7 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { let fr_slice = &fr_table[0..size as usize]; let fr_iter = fr_slice.iter().copied(); let tree = OptimalMerkleTree::::new( - 6, + (size.ilog2() + 1) as usize, Fr::default(), OptimalMerkleConfig::default(), ) @@ -384,7 +384,7 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { let fr_slice = &fr_table[0..size as usize]; let fr_iter = fr_slice.iter().copied(); let tree = OptimalMerkleTree::::new( - 6, + (size.ilog2() + 1) as usize, Fr::default(), OptimalMerkleConfig::default(), ) @@ -407,7 +407,7 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { let fr_slice = &fr_table[0..size as usize]; let fr_iter = fr_slice.iter().copied(); let tree = FullMerkleTree::::new( - 6, + (size.ilog2() + 1) as usize, Fr::default(), FullMerkleConfig::default(), ) @@ -430,7 +430,7 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { let fr_slice = &fr_table[0..size as usize]; let fr_iter = fr_slice.iter().copied(); let tree = FullMerkleTree::::new( - 6, + (size.ilog2() + 1) as usize, Fr::default(), FullMerkleConfig::default(), ) From 20cfed53f295502c78c36001b4c8981f4d7adc7d Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Thu, 15 May 2025 16:09:30 +0200 Subject: [PATCH 18/24] More thorough black-box use --- utils/benches/imt_benchy.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 0c762721..4db0fa92 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -236,7 +236,7 @@ pub fn hashless_setup_batch(c: &mut Criterion) { |mut tree| { black_box(tree.insert_many( data_source, - >::hash, + black_box(>::hash), )) }, BatchSize::SmallInput, @@ -317,7 +317,7 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { black_box( tree.insert_many( &byte_form, - >::hash, + black_box(>::hash), ), ) }, @@ -344,7 +344,7 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { |(mut tree, data_source)| { black_box(tree.insert_many( &data_source, - >::hash, + black_box(>::hash), )) }, BatchSize::SmallInput, From bdf899bdcd23f7a2031fd5462ceb78d19c09ff72 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Thu, 15 May 2025 16:10:01 +0200 Subject: [PATCH 19/24] Clear redundant use of inputs in benchies --- utils/benches/imt_benchy.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 4db0fa92..4fe21d73 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -144,10 +144,9 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { for size in size_group { let data_source = &data_table[0..size as usize]; let fr_source = &fr_table[0..size as usize]; - group.bench_with_input( + group.bench_function( BenchmarkId::new("Lean IMT iterative", size), - &size, - |b, &_size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -222,10 +221,9 @@ pub fn hashless_setup_batch(c: &mut Criterion) { let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { let data_source = &data_table[0..size as usize]; - group.bench_with_input( + group.bench_function( BenchmarkId::new("Lean IMT batch", size), - &size, - |b, &_size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -299,10 +297,9 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { let data_source = &data_table[0..size as usize]; - group.bench_with_input( + group.bench_function( BenchmarkId::new("Lean IMT batch poseidon", size), - &size, - |b, &_size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -325,10 +322,9 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("Lean IMT batch light-poseidon", size), - &size, - |b, &_size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { From 36c5af39d34f3bd9e89f17da8ce6c0c69052931f Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Thu, 15 May 2025 16:10:23 +0200 Subject: [PATCH 20/24] cargo-fmt --- utils/benches/imt_benchy.rs | 113 +++++++++++++++--------------------- 1 file changed, 48 insertions(+), 65 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 4fe21d73..2a667bee 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -144,26 +144,20 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { for size in size_group { let data_source = &data_table[0..size as usize]; let fr_source = &fr_table[0..size as usize]; - group.bench_function( - BenchmarkId::new("Lean IMT iterative", size), - |b| { - b.iter_batched( - // Setup: create values for each benchmark iteration - || { - LeanIMT::<32>::new(&[], >::hash) - .unwrap() - }, - // Actual benchmark - |mut tree| { - for d in data_source.iter() { - #[allow(clippy::unit_arg)] - black_box(tree.insert(d, >::hash)) - } - }, - BatchSize::SmallInput, - ) - }, - ); + group.bench_function(BenchmarkId::new("Lean IMT iterative", size), |b| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || LeanIMT::<32>::new(&[], >::hash).unwrap(), + // Actual benchmark + |mut tree| { + for d in data_source.iter() { + #[allow(clippy::unit_arg)] + black_box(tree.insert(d, >::hash)) + } + }, + BatchSize::SmallInput, + ) + }); group.bench_with_input( BenchmarkId::new("IFT optimal iterative", size), @@ -221,26 +215,20 @@ pub fn hashless_setup_batch(c: &mut Criterion) { let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { let data_source = &data_table[0..size as usize]; - group.bench_function( - BenchmarkId::new("Lean IMT batch", size), - |b| { - b.iter_batched( - // Setup: create values for each benchmark iteration - || { - LeanIMT::<32>::new(&[], >::hash) - .unwrap() - }, - // Actual benchmark - |mut tree| { - black_box(tree.insert_many( - data_source, - black_box(>::hash), - )) - }, - BatchSize::SmallInput, - ) - }, - ); + group.bench_function(BenchmarkId::new("Lean IMT batch", size), |b| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || LeanIMT::<32>::new(&[], >::hash).unwrap(), + // Actual benchmark + |mut tree| { + black_box(tree.insert_many( + data_source, + black_box(>::hash), + )) + }, + BatchSize::SmallInput, + ) + }); group.bench_with_input( BenchmarkId::new("IFT optimal batch", size), &size, @@ -297,31 +285,26 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { let data_source = &data_table[0..size as usize]; - group.bench_function( - BenchmarkId::new("Lean IMT batch poseidon", size), - |b| { - b.iter_batched( - // Setup: create values for each benchmark iteration - || { - let byte_form = lean_data_prep(data_source); - let tree = - LeanIMT::<32>::new(&[], >::hash) - .unwrap(); - (tree, byte_form) - }, - // Actual benchmark - |(mut tree, byte_form)| { - black_box( - tree.insert_many( - &byte_form, - black_box(>::hash), - ), - ) - }, - BatchSize::SmallInput, - ) - }, - ); + group.bench_function(BenchmarkId::new("Lean IMT batch poseidon", size), |b| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let byte_form = lean_data_prep(data_source); + let tree = + LeanIMT::<32>::new(&[], >::hash) + .unwrap(); + (tree, byte_form) + }, + // Actual benchmark + |(mut tree, byte_form)| { + black_box(tree.insert_many( + &byte_form, + black_box(>::hash), + )) + }, + BatchSize::SmallInput, + ) + }); group.bench_function( BenchmarkId::new("Lean IMT batch light-poseidon", size), |b| { From eb950b64a01282e2d6ac5312ae28dfd7a1c512aa Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Thu, 15 May 2025 16:22:49 +0200 Subject: [PATCH 21/24] Compare backing hashers with verifications --- utils/benches/imt_benchy.rs | 110 +++++++++++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 13 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 2a667bee..a007b7c2 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -511,14 +511,13 @@ pub fn proof_gen_shootout(c: &mut Criterion) { pub fn verification_shootout(c: &mut Criterion) { let mut group = c.benchmark_group("MTree verification shootout"); - let size_group = [7u32, 13, 17, 40]; + let size_group = [7u32, 17, 40]; for size in size_group { let data_stream = HashMockStream::seeded_stream(size as u64); let data_source = data_stream.take(size as usize).collect::>(); - group.bench_with_input( - BenchmarkId::new("Lean IMT verification", size), - &size, - |b, &_size| { + group.bench_function( + BenchmarkId::new("Lean IMT + ift-pos verification", size), + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -543,10 +542,66 @@ pub fn verification_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( - BenchmarkId::new("IFT full verification", size), - &size, - |b, &_size| { + group.bench_function( + BenchmarkId::new("Lean IMT + light-pos verification", size), + |b| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let frd_bytes = lean_data_prep(&data_source); + let tree = LeanIMT::<32>::new( + &frd_bytes, + >::hash, + ) + .unwrap(); + let proof = tree.generate_proof(0).unwrap(); + // assert!(LeanIMT::verify_proof(&proof, >::hash)); + proof + }, + // Actual benchmark + |proof| { + black_box(LeanIMT::verify_proof( + &proof, + >::hash, + )) + }, + BatchSize::SmallInput, + ) + }, + ); + group.bench_function( + BenchmarkId::new("IFT full + light-pos verification", size), + |b| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let fr_form: Vec = data_source + .iter() + .cloned() + // take raw bytes and Fr-ize it + .map(|chunk| bytes_le_to_fr(&chunk).0) + .collect(); + let mut tree = FullMerkleTree::::new( + 7, + Fr::default(), + FullMerkleConfig::default(), + ) + .unwrap(); + let first_leaf = *fr_form.first().unwrap(); + tree.set_range(0, fr_form.into_iter()).unwrap(); + let proof = tree.proof(0).unwrap(); + // assert!(tree.verify(&first_leaf, &proof).unwrap()); + (first_leaf, tree, proof) + }, + // Actual benchmark + |(first_leaf, tree, proof)| black_box(tree.verify(&first_leaf, &proof)), + BatchSize::SmallInput, + ) + }, + ); + group.bench_function( + BenchmarkId::new("IFT full + ift-pos verification", size), + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -574,10 +629,39 @@ pub fn verification_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( - BenchmarkId::new("IFT optimal verification", size), - &size, - |b, &_size| { + group.bench_function( + BenchmarkId::new("IFT optimal + light-pos verification", size), + |b| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let fr_form: Vec = data_source + .iter() + .cloned() + // take raw bytes and Fr-ize it + .map(|chunk| bytes_le_to_fr(&chunk).0) + .collect(); + let mut tree = OptimalMerkleTree::::new( + 7, + Fr::default(), + OptimalMerkleConfig::default(), + ) + .unwrap(); + let first_leaf = *fr_form.first().unwrap(); + tree.set_range(0, fr_form.into_iter()).unwrap(); + let proof = tree.proof(0).unwrap(); + // assert!(tree.verify(&first_leaf, &proof).unwrap()); + (first_leaf, tree, proof) + }, + // Actual benchmark + |(first_leaf, tree, proof)| black_box(tree.verify(&first_leaf, &proof)), + BatchSize::SmallInput, + ) + }, + ); + group.bench_function( + BenchmarkId::new("IFT optimal + ift-pos verification", size), + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { From 756119cf42ce2039142a9f3ffb6c3550b842c6d7 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Thu, 15 May 2025 16:27:10 +0200 Subject: [PATCH 22/24] a/b bench the hashers in proof-gen --- utils/benches/imt_benchy.rs | 78 +++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index a007b7c2..946fffb1 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -435,7 +435,7 @@ pub fn proof_gen_shootout(c: &mut Criterion) { // let data_stream = HashMockStream::seeded_stream(size as u64); // let chunk_vec = data_stream.take(size as usize).collect::>(); group.bench_with_input( - BenchmarkId::new("Lean IMT proof generation", size), + BenchmarkId::new("Lean IMT + ift_pos proof generation", size), &size, |b, &_size| { b.iter_batched( @@ -455,7 +455,27 @@ pub fn proof_gen_shootout(c: &mut Criterion) { }, ); group.bench_with_input( - BenchmarkId::new("IFT full proof generation", size), + BenchmarkId::new("Lean IMT + light-pos proof generation", size), + &size, + |b, &_size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let frd_byte_chunks = lean_data_prep(data_source); + LeanIMT::<32>::new( + &frd_byte_chunks, + >::hash, + ) + .unwrap() + }, + // Actual benchmark + |tree| black_box(tree.generate_proof(0)), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT full + ift-pos proof generation", size), &size, |b, &_size| { b.iter_batched( @@ -483,7 +503,35 @@ pub fn proof_gen_shootout(c: &mut Criterion) { }, ); group.bench_with_input( - BenchmarkId::new("IFT optimal proof generation", size), + BenchmarkId::new("IFT full + light-pos proof generation", size), + &size, + |b, &_size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let fr_form: Vec = data_source + .iter() + .cloned() + // take raw bytes and Fr-ize it + .map(|chunk| bytes_le_to_fr(&chunk).0) + .collect(); + let mut tree = FullMerkleTree::::new( + 7, + Fr::default(), + FullMerkleConfig::default(), + ) + .unwrap(); + tree.set_range(0, fr_form.into_iter()).unwrap(); + tree + }, + // Actual benchmark + |tree| black_box(tree.proof(0)), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("IFT optimal + ift-pos proof generation", size), &size, |b, &_size| { b.iter_batched( @@ -506,6 +554,30 @@ pub fn proof_gen_shootout(c: &mut Criterion) { ) }, ); + group.bench_with_input( + BenchmarkId::new("IFT optimal + light-pos proof generation", size), + &size, + |b, &_size| { + b.iter_batched( + // Setup: create values for each benchmark iteration + || { + let fr_slice = &fr_table[0..size as usize]; + let fr_iter = fr_slice.iter().copied(); + let mut tree = OptimalMerkleTree::::new( + 7, + Fr::default(), + OptimalMerkleConfig::default(), + ) + .unwrap(); + tree.set_range(0, fr_iter).unwrap(); + tree + }, + // Actual benchmark + |tree| black_box(tree.proof(0)), + BatchSize::SmallInput, + ) + }, + ); } } From 113e1bb4096f9475a2130c0889d53ed49a79ef0f Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Thu, 15 May 2025 16:32:04 +0200 Subject: [PATCH 23/24] more redundant size-input clearing --- utils/benches/imt_benchy.rs | 86 ++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index 946fffb1..f3fcb74d 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -159,10 +159,9 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { ) }); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT optimal iterative", size), - &size, - |b, &size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -183,10 +182,9 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT full iterative", size), - &size, - |b, &size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -229,10 +227,9 @@ pub fn hashless_setup_batch(c: &mut Criterion) { BatchSize::SmallInput, ) }); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT optimal batch", size), - &size, - |b, &size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -252,10 +249,9 @@ pub fn hashless_setup_batch(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT full batch", size), - &size, - |b, &size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -330,10 +326,9 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT optimal batch poseidon", size), - &size, - |b, &size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -353,10 +348,9 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT optimal batch light-poseidon", size), - &size, - |b, &size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -376,10 +370,9 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT full batch poseidon", size), - &size, - |b, &size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -399,10 +392,9 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT full batch light-poseidon", size), - &size, - |b, &size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -434,10 +426,9 @@ pub fn proof_gen_shootout(c: &mut Criterion) { let data_source = &data_table[0..size as usize]; // let data_stream = HashMockStream::seeded_stream(size as u64); // let chunk_vec = data_stream.take(size as usize).collect::>(); - group.bench_with_input( + group.bench_function( BenchmarkId::new("Lean IMT + ift_pos proof generation", size), - &size, - |b, &_size| { + |b,| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -454,10 +445,9 @@ pub fn proof_gen_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("Lean IMT + light-pos proof generation", size), - &size, - |b, &_size| { + |b,| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -474,10 +464,9 @@ pub fn proof_gen_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT full + ift-pos proof generation", size), - &size, - |b, &_size| { + |b| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -488,7 +477,7 @@ pub fn proof_gen_shootout(c: &mut Criterion) { .map(|chunk| bytes_le_to_fr(&chunk).0) .collect(); let mut tree = FullMerkleTree::::new( - 7, + size.ilog2() as usize + 1, Fr::default(), FullMerkleConfig::default(), ) @@ -502,10 +491,9 @@ pub fn proof_gen_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT full + light-pos proof generation", size), - &size, - |b, &_size| { + |b,| { b.iter_batched( // Setup: create values for each benchmark iteration || { @@ -516,7 +504,7 @@ pub fn proof_gen_shootout(c: &mut Criterion) { .map(|chunk| bytes_le_to_fr(&chunk).0) .collect(); let mut tree = FullMerkleTree::::new( - 7, + size.ilog2() as usize + 1, Fr::default(), FullMerkleConfig::default(), ) @@ -530,17 +518,16 @@ pub fn proof_gen_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT optimal + ift-pos proof generation", size), - &size, - |b, &_size| { + |b,| { b.iter_batched( // Setup: create values for each benchmark iteration || { let fr_slice = &fr_table[0..size as usize]; let fr_iter = fr_slice.iter().copied(); let mut tree = OptimalMerkleTree::::new( - 7, + size.ilog2() as usize + 1, Fr::default(), OptimalMerkleConfig::default(), ) @@ -554,17 +541,16 @@ pub fn proof_gen_shootout(c: &mut Criterion) { ) }, ); - group.bench_with_input( + group.bench_function( BenchmarkId::new("IFT optimal + light-pos proof generation", size), - &size, - |b, &_size| { + |b,| { b.iter_batched( // Setup: create values for each benchmark iteration || { let fr_slice = &fr_table[0..size as usize]; let fr_iter = fr_slice.iter().copied(); let mut tree = OptimalMerkleTree::::new( - 7, + size.ilog2() as usize + 1, Fr::default(), OptimalMerkleConfig::default(), ) @@ -654,7 +640,7 @@ pub fn verification_shootout(c: &mut Criterion) { .map(|chunk| bytes_le_to_fr(&chunk).0) .collect(); let mut tree = FullMerkleTree::::new( - 7, + size.ilog2() as usize + 1, Fr::default(), FullMerkleConfig::default(), ) @@ -684,7 +670,7 @@ pub fn verification_shootout(c: &mut Criterion) { .map(|chunk| bytes_le_to_fr(&chunk).0) .collect(); let mut tree = FullMerkleTree::::new( - 7, + size.ilog2() as usize + 1, Fr::default(), FullMerkleConfig::default(), ) @@ -714,7 +700,7 @@ pub fn verification_shootout(c: &mut Criterion) { .map(|chunk| bytes_le_to_fr(&chunk).0) .collect(); let mut tree = OptimalMerkleTree::::new( - 7, + size.ilog2() as usize + 1, Fr::default(), OptimalMerkleConfig::default(), ) @@ -744,7 +730,7 @@ pub fn verification_shootout(c: &mut Criterion) { .map(|chunk| bytes_le_to_fr(&chunk).0) .collect(); let mut tree = OptimalMerkleTree::::new( - 7, + size.ilog2() as usize + 1, Fr::default(), OptimalMerkleConfig::default(), ) From 800a0e0571614dda224f6c52e0077bf4aa63c699 Mon Sep 17 00:00:00 2001 From: Ben-PH Date: Thu, 15 May 2025 18:43:32 +0200 Subject: [PATCH 24/24] clean up test params --- utils/benches/imt_benchy.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/utils/benches/imt_benchy.rs b/utils/benches/imt_benchy.rs index f3fcb74d..2ba48934 100644 --- a/utils/benches/imt_benchy.rs +++ b/utils/benches/imt_benchy.rs @@ -1,4 +1,4 @@ -use std::{hint::black_box, str::FromStr}; +use std::{hint::black_box, str::FromStr, time::Duration}; use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; use light_poseidon::{ @@ -138,6 +138,7 @@ fn spawn_inputs(size_group: &[u32]) -> (Vec<[u8; 32]>, Vec) { pub fn hashless_setup_iterative(c: &mut Criterion) { let mut group = c.benchmark_group("hashless tree iterative setup"); + group.measurement_time(Duration::from_secs(10)); let size_group = [7u32, 13, 17, 40]; let (data_table, fr_table) = spawn_inputs(&size_group); @@ -209,6 +210,7 @@ pub fn hashless_setup_iterative(c: &mut Criterion) { } pub fn hashless_setup_batch(c: &mut Criterion) { let mut group = c.benchmark_group("hashless tree batch setup"); + group.measurement_time(Duration::from_secs(10)); let size_group = [7u32, 13, 17, 40]; let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { @@ -277,6 +279,7 @@ pub fn hashless_setup_batch(c: &mut Criterion) { fn tree_hash_batch_setup_shootout(c: &mut Criterion) { let mut group = c.benchmark_group("hash+tree batch shootout"); + group.measurement_time(Duration::from_secs(10)); let size_group = [7u32, 13, 17, 40]; let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { @@ -420,6 +423,7 @@ fn tree_hash_batch_setup_shootout(c: &mut Criterion) { pub fn proof_gen_shootout(c: &mut Criterion) { let mut group = c.benchmark_group("MTree proof-gen shootout"); + group.measurement_time(Duration::from_secs(15)); let size_group = [7u32, 13, 17, 40]; let (data_table, fr_table) = spawn_inputs(&size_group); for size in size_group { @@ -569,6 +573,7 @@ pub fn proof_gen_shootout(c: &mut Criterion) { pub fn verification_shootout(c: &mut Criterion) { let mut group = c.benchmark_group("MTree verification shootout"); + group.measurement_time(Duration::from_secs(15)); let size_group = [7u32, 17, 40]; for size in size_group { let data_stream = HashMockStream::seeded_stream(size as u64); @@ -752,22 +757,11 @@ pub fn verification_shootout(c: &mut Criterion) { criterion_main!(tree_benchies); criterion_group! { name = tree_benchies; - config = Criterion::default() - .warm_up_time(std::time::Duration::from_millis(500)) - .measurement_time(std::time::Duration::from_secs(4)) - .sample_size(40); + config = Criterion::default(); targets = hashless_setup_batch, hashless_setup_iterative, tree_hash_batch_setup_shootout, -} -criterion_group! { - name = tree_zk_benchies; - config = Criterion::default() - .warm_up_time(std::time::Duration::from_millis(500)) - .measurement_time(std::time::Duration::from_secs(4)) - .sample_size(10); - targets = proof_gen_shootout, verification_shootout }