From cb0cc6527e23a9bad11e954525e0c34b74f07ac3 Mon Sep 17 00:00:00 2001 From: Tom Wambsgans Date: Sat, 20 Sep 2025 14:46:55 +0400 Subject: [PATCH 1/5] MIN_LOG_MEMORY_SIZE --- crates/lean_prover/src/verify_execution.rs | 8 ++++---- crates/lean_vm/src/memory.rs | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/lean_prover/src/verify_execution.rs b/crates/lean_prover/src/verify_execution.rs index 2d29c2fda..8a78156df 100644 --- a/crates/lean_prover/src/verify_execution.rs +++ b/crates/lean_prover/src/verify_execution.rs @@ -72,15 +72,15 @@ pub fn verify_execution( let public_memory = build_public_memory(public_input); - if log2_ceil_usize(private_memory_len + private_memory_len) > MAX_MEMORY_SIZE { - return Err(ProofError::InvalidProof); - } - let log_public_memory = log2_strict_usize(public_memory.len()); let log_memory = log2_ceil_usize(public_memory.len() + private_memory_len); let log_n_p16 = log2_ceil_usize(n_poseidons_16); let log_n_p24 = log2_ceil_usize(n_poseidons_24); + if log_memory > MAX_LOG_MEMORY_SIZE || log_memory < MIN_LOG_MEMORY_SIZE { + return Err(ProofError::InvalidProof); + } + let table_dot_products_log_n_rows = log2_ceil_usize(n_rows_table_dot_products); let dot_product_padding_len = n_rows_table_dot_products.next_power_of_two() - n_rows_table_dot_products; diff --git a/crates/lean_vm/src/memory.rs b/crates/lean_vm/src/memory.rs index 0aaff6d72..a086e996e 100644 --- a/crates/lean_vm/src/memory.rs +++ b/crates/lean_vm/src/memory.rs @@ -5,10 +5,11 @@ use rayon::prelude::*; use crate::*; -pub const MAX_MEMORY_SIZE: usize = 1 << 29; +pub const MIN_LOG_MEMORY_SIZE: usize = 16; +pub const MAX_LOG_MEMORY_SIZE: usize = 29; // For now, we restrict ourselves to executions where memory usage < 2^24 words. -// But the VM supports theorically a memory of size MAX_MEMORY_SIZE = 2^29. +// But the VM supports theorically a memory of size 2^29. pub(crate) const MAX_RUNNER_MEMORY_SIZE: usize = 1 << 24; #[derive(Debug, Clone, Default)] From d6f1793944e211a384080253ac3bf679f625eed3 Mon Sep 17 00:00:00 2001 From: adust09 Date: Sat, 20 Sep 2025 21:01:20 +0900 Subject: [PATCH 2/5] Update Cargo.lock and Cargo.toml to add new dependencies and benchmarks; refactor rec_aggregation module to expose recursion and xmss_aggregate. Introduce examples module in the library and adjust main.rs to use updated paths. --- Cargo.lock | 198 ++++++++++++++++++++++++++++-- Cargo.toml | 16 +++ crates/rec_aggregation/src/lib.rs | 8 +- src/lib.rs | 1 + src/main.rs | 4 +- 5 files changed, 210 insertions(+), 17 deletions(-) create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index bbe5b4e86..8eeaf2205 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,6 +29,12 @@ dependencies = [ "whir-p3", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "ansi_term" version = "0.12.1" @@ -103,12 +109,45 @@ dependencies = [ "generic-array", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cfg-if" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "4.5.47" @@ -173,6 +212,37 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools 0.13.0", + "num-traits", + "oorandom", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" +dependencies = [ + "cast", + "itertools 0.13.0", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -198,6 +268,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.6" @@ -246,6 +322,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "heck" version = "0.5.0" @@ -258,6 +344,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -267,6 +362,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + [[package]] name = "lazy_static" version = "1.5.0" @@ -453,6 +554,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + [[package]] name = "p3-air" version = "0.3.0" @@ -492,7 +599,7 @@ name = "p3-commit" version = "0.3.0" source = "git+https://github.com/TomWambsgans/Plonky3.git?branch=lean-multisig#54cffa3ace6ae9de34b5a9d854fa03c52c948d9c" dependencies = [ - "itertools", + "itertools 0.14.0", "p3-challenger", "p3-dft", "p3-field", @@ -506,7 +613,7 @@ name = "p3-dft" version = "0.3.0" source = "git+https://github.com/TomWambsgans/Plonky3.git?branch=lean-multisig#54cffa3ace6ae9de34b5a9d854fa03c52c948d9c" dependencies = [ - "itertools", + "itertools 0.14.0", "p3-field", "p3-matrix", "p3-maybe-rayon", @@ -519,7 +626,7 @@ name = "p3-field" version = "0.3.0" source = "git+https://github.com/TomWambsgans/Plonky3.git?branch=lean-multisig#54cffa3ace6ae9de34b5a9d854fa03c52c948d9c" dependencies = [ - "itertools", + "itertools 0.14.0", "num-bigint", "p3-maybe-rayon", "p3-util", @@ -545,7 +652,7 @@ name = "p3-koala-bear" version = "0.3.0" source = "git+https://github.com/TomWambsgans/Plonky3.git?branch=lean-multisig#54cffa3ace6ae9de34b5a9d854fa03c52c948d9c" dependencies = [ - "itertools", + "itertools 0.14.0", "num-bigint", "p3-field", "p3-monty-31", @@ -561,7 +668,7 @@ name = "p3-matrix" version = "0.3.0" source = "git+https://github.com/TomWambsgans/Plonky3.git?branch=lean-multisig#54cffa3ace6ae9de34b5a9d854fa03c52c948d9c" dependencies = [ - "itertools", + "itertools 0.14.0", "p3-field", "p3-maybe-rayon", "p3-util", @@ -596,7 +703,7 @@ name = "p3-merkle-tree" version = "0.3.0" source = "git+https://github.com/TomWambsgans/Plonky3.git?branch=lean-multisig#54cffa3ace6ae9de34b5a9d854fa03c52c948d9c" dependencies = [ - "itertools", + "itertools 0.14.0", "p3-commit", "p3-field", "p3-matrix", @@ -613,7 +720,7 @@ name = "p3-monty-31" version = "0.3.0" source = "git+https://github.com/TomWambsgans/Plonky3.git?branch=lean-multisig#54cffa3ace6ae9de34b5a9d854fa03c52c948d9c" dependencies = [ - "itertools", + "itertools 0.14.0", "num-bigint", "p3-dft", "p3-field", @@ -661,7 +768,7 @@ name = "p3-symmetric" version = "0.3.0" source = "git+https://github.com/TomWambsgans/Plonky3.git?branch=lean-multisig#54cffa3ace6ae9de34b5a9d854fa03c52c948d9c" dependencies = [ - "itertools", + "itertools 0.14.0", "p3-field", "serde", ] @@ -671,7 +778,7 @@ name = "p3-uni-stark" version = "0.3.0" source = "git+https://github.com/TomWambsgans/Plonky3.git?branch=lean-multisig#54cffa3ace6ae9de34b5a9d854fa03c52c948d9c" dependencies = [ - "itertools", + "itertools 0.14.0", "p3-air", "p3-challenger", "p3-commit", @@ -874,6 +981,18 @@ dependencies = [ "xmss", ] +[[package]] +name = "regex" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + [[package]] name = "regex-automata" version = "0.4.10" @@ -891,6 +1010,21 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "serde" version = "1.0.225" @@ -921,6 +1055,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + [[package]] name = "sha2" version = "0.10.9" @@ -1014,6 +1161,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tracing" version = "0.1.41" @@ -1184,6 +1341,16 @@ dependencies = [ "xmss", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.14.7+wasi-0.2.4" @@ -1208,7 +1375,7 @@ version = "0.1.0" source = "git+https://github.com/TomWambsgans/whir-p3?branch=lean-multisig#4a36527ee9d25556451be2279820885032de530d" dependencies = [ "clap", - "itertools", + "itertools 0.14.0", "p3-baby-bear", "p3-challenger", "p3-commit", @@ -1235,6 +1402,7 @@ name = "whirlaway" version = "0.1.0" dependencies = [ "air", + "criterion", "p3-air", "p3-challenger", "p3-field", @@ -1247,6 +1415,7 @@ dependencies = [ "p3-util", "packed_pcs", "rand", + "rec_aggregation", "utils", "whir-p3", ] @@ -1267,6 +1436,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.60.2", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 60d3a2f7b..3024623e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,3 +98,19 @@ utils.workspace = true p3-util.workspace = true packed_pcs.workspace = true p3-air.workspace = true + +[dev-dependencies] +criterion = { version = "0.7", default-features = false, features = ["cargo_bench_support"] } +rec_aggregation.workspace = true + +[[bench]] +name = "poseidon2" +harness = false + +[[bench]] +name = "recursion" +harness = false + +[[bench]] +name = "xmss" +harness = false diff --git a/crates/rec_aggregation/src/lib.rs b/crates/rec_aggregation/src/lib.rs index 51779ea68..672799f81 100644 --- a/crates/rec_aggregation/src/lib.rs +++ b/crates/rec_aggregation/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(not(test), allow(unused_crate_dependencies))] -#[cfg(test)] -mod recursion; +pub mod recursion; +pub mod xmss_aggregate; -#[cfg(test)] -mod xmss_aggregate; +pub use recursion::bench_recursion; +pub use xmss_aggregate::bench_xmss; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..e837f5d98 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod examples; diff --git a/src/main.rs b/src/main.rs index 00fd38ff7..3bb01817e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,7 @@ #![cfg_attr(not(test), allow(unused_crate_dependencies))] -mod examples; - -use crate::examples::prove_poseidon2::{Poseidon2Config, prove_poseidon2}; use whir_p3::whir::config::{FoldingFactor, SecurityAssumption}; +use whirlaway::examples::prove_poseidon2::{Poseidon2Config, prove_poseidon2}; fn main() { let config = Poseidon2Config { From 6af1001bbe73dcf4299eaf29a03f0ddf7a0a5a7c Mon Sep 17 00:00:00 2001 From: adust09 Date: Sat, 20 Sep 2025 21:06:10 +0900 Subject: [PATCH 3/5] Add benchmark for Poseidon2 implementation This commit introduces a new benchmark for the Poseidon2 algorithm, utilizing the Criterion library for performance measurement. The benchmark is configured with specific parameters for logging and security assumptions, and it measures the prover time of the Poseidon2 configuration. The new file is located in `benches/poseidon2.rs`. --- benches/poseidon2.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 benches/poseidon2.rs diff --git a/benches/poseidon2.rs b/benches/poseidon2.rs new file mode 100644 index 000000000..6539be42a --- /dev/null +++ b/benches/poseidon2.rs @@ -0,0 +1,42 @@ +use std::{hint::black_box, time::Duration}; + +use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main}; +use whir_p3::whir::config::{FoldingFactor, SecurityAssumption}; +use whirlaway::examples::prove_poseidon2::{Poseidon2Config, prove_poseidon2}; + +fn bench_poseidon2(c: &mut Criterion) { + const L16: usize = 17; + const L24: usize = 17; + + let mut group = c.benchmark_group("poseidon2"); + group.sample_size(10); + group.measurement_time(Duration::from_secs(60)); + group.warm_up_time(Duration::from_secs(10)); + group.throughput(Throughput::Elements((1u64 << L16) + (1u64 << L24))); + + let config = Poseidon2Config { + log_n_poseidons_16: L16, + log_n_poseidons_24: L24, + univariate_skips: 4, + folding_factor: FoldingFactor::new(7, 4), + log_inv_rate: 4, + soundness_type: SecurityAssumption::CapacityBound, + pow_bits: 16, + security_level: 128, + rs_domain_initial_reduction_factor: 5, + max_num_variables_to_send_coeffs: 3, + display_logs: false, + }; + + group.bench_function("poseidon2", |b| { + b.iter(|| { + let result = prove_poseidon2(black_box(&config)); + black_box(result.prover_time); + }); + }); + + group.finish(); +} + +criterion_group!(benches, bench_poseidon2); +criterion_main!(benches); From 12bb6f821224fb3b0baf397daffcb0be9c34f394 Mon Sep 17 00:00:00 2001 From: adust09 Date: Sat, 20 Sep 2025 21:15:42 +0900 Subject: [PATCH 4/5] Add recursion benchmark using Criterion This commit introduces a new benchmark for the recursion functionality in the `rec_aggregation` module, utilizing the Criterion library for performance measurement. The benchmark is configured with specific parameters for sample size, measurement time, and warm-up time, and it measures the proving time of the recursion implementation. The new benchmark file is located in `benches/recursion.rs`, and the recursion logic has been refactored to support this benchmarking. Additionally, constants have been introduced for better readability and maintainability. --- benches/recursion.rs | 26 +++++++++++++ crates/rec_aggregation/src/recursion.rs | 51 +++++++++++++++---------- 2 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 benches/recursion.rs diff --git a/benches/recursion.rs b/benches/recursion.rs new file mode 100644 index 000000000..9518f6694 --- /dev/null +++ b/benches/recursion.rs @@ -0,0 +1,26 @@ +use std::{hint::black_box, time::Duration}; + +use criterion::{Criterion, Throughput, criterion_group, criterion_main}; +use rec_aggregation::bench_recursion; + +fn bench_recursion_benchmark(c: &mut Criterion) { + const NUM_VARIABLES: u32 = 25; + + let mut group = c.benchmark_group("recursion"); + group.sample_size(10); + group.measurement_time(Duration::from_secs(60)); + group.warm_up_time(Duration::from_secs(10)); + group.throughput(Throughput::Elements(1u64 << NUM_VARIABLES)); + + group.bench_function("recursion", |b| { + b.iter(|| { + let duration = bench_recursion(); + black_box(duration); + }); + }); + + group.finish(); +} + +criterion_group!(benches, bench_recursion_benchmark); +criterion_main!(benches); diff --git a/crates/rec_aggregation/src/recursion.rs b/crates/rec_aggregation/src/recursion.rs index 77b343476..5970ef546 100644 --- a/crates/rec_aggregation/src/recursion.rs +++ b/crates/rec_aggregation/src/recursion.rs @@ -1,5 +1,5 @@ use std::path::Path; -use std::time::Instant; +use std::time::{Duration, Instant}; use lean_compiler::compile_program; use lean_prover::prove_execution::prove_execution; @@ -7,7 +7,6 @@ use lean_prover::verify_execution::verify_execution; use lean_prover::whir_config_builder; use lean_vm::*; use p3_field::BasedVectorSpace; -use p3_field::Field; use p3_field::PrimeCharacteristicRing; use rand::{Rng, SeedableRng, rngs::StdRng}; use utils::padd_with_zero_to_next_multiple_of; @@ -19,12 +18,16 @@ use whir_p3::{ whir::config::{FoldingFactor, SecurityAssumption, WhirConfig, WhirConfigBuilder}, }; -#[test] -pub fn test_whir_recursion() { +const NUM_VARIABLES: usize = 25; + +struct RecursionBenchStats { + proving_time: Duration, + proof_size: usize, +} + +fn run_recursion_benchmark() -> RecursionBenchStats { let src_file = Path::new(env!("CARGO_MANIFEST_DIR")).join("recursion_program.lean_lang"); let mut program_str = std::fs::read_to_string(src_file).unwrap(); - - let num_variables = 25; let recursion_config_builder = WhirConfigBuilder { max_num_variables_to_send_coeffs: 6, security_level: 128, @@ -37,7 +40,7 @@ pub fn test_whir_recursion() { rs_domain_initial_reduction_factor: 3, }; - let mut recursion_config = WhirConfig::new(recursion_config_builder.clone(), num_variables); + let mut recursion_config = WhirConfig::new(recursion_config_builder.clone(), NUM_VARIABLES); // TODO remove overriding this { @@ -50,10 +53,6 @@ pub fn test_whir_recursion() { assert_eq!(recursion_config.committment_ood_samples, 1); // println!("Whir parameters: {}", params.to_string()); for (i, round) in recursion_config.round_parameters.iter().enumerate() { - println!( - "Round {}: {} queries, pow: {} bits", - i, round.num_queries, round.pow_bits - ); program_str = program_str .replace( &format!("NUM_QUERIES_{i}_PLACEHOLDER"), @@ -64,10 +63,6 @@ pub fn test_whir_recursion() { &round.pow_bits.to_string(), ); } - println!( - "Final round: {} queries, pow: {} bits", - recursion_config.final_queries, recursion_config.final_pow_bits - ); program_str = program_str .replace( &format!("NUM_QUERIES_{}_PLACEHOLDER", recursion_config.n_rounds()), @@ -95,11 +90,11 @@ pub fn test_whir_recursion() { ); let mut rng = StdRng::seed_from_u64(0); - let polynomial = (0..1 << num_variables) + let polynomial = (0..1 << NUM_VARIABLES) .map(|_| rng.random()) .collect::>(); - let point = MultilinearPoint::::rand(&mut rng, num_variables); + let point = MultilinearPoint::::rand(&mut rng, NUM_VARIABLES); let mut statement = Vec::new(); let eval = polynomial.evaluate(&point); @@ -163,7 +158,7 @@ pub fn test_whir_recursion() { "PADDING_FOR_INITIAL_MERKLE_LEAVES_PLACEHOLDER", &proof_data_padding.to_string(), ) - .replace("N_VARS_PLACEHOLDER", &num_variables.to_string()) + .replace("N_VARS_PLACEHOLDER", &NUM_VARIABLES.to_string()) .replace( "LOG_INV_RATE_PLACEHOLDER", &recursion_config_builder.starting_log_inv_rate.to_string(), @@ -200,10 +195,24 @@ pub fn test_whir_recursion() { whir_config_builder(), false, ); + let proving_time = time.elapsed(); + verify_execution(&bytecode, &public_input, proof_data, whir_config_builder()).unwrap(); + RecursionBenchStats { + proving_time, + proof_size, + } +} + +pub fn bench_recursion() -> Duration { + run_recursion_benchmark().proving_time +} + +#[test] +fn test_whir_recursion() { + let stats = run_recursion_benchmark(); println!( "\nWHIR recursion, proving time: {:?}, proof size: {} KiB (not optimized)", - time.elapsed(), - proof_size * F::bits() / (8 * 1024) + stats.proving_time, + stats.proof_size * F::bits() / (8 * 1024) ); - verify_execution(&bytecode, &public_input, proof_data, whir_config_builder()).unwrap(); } From 9e76b0ed62b33174b8467970e23b49e490168d68 Mon Sep 17 00:00:00 2001 From: adust09 Date: Sat, 20 Sep 2025 21:20:16 +0900 Subject: [PATCH 5/5] Add benchmark for XMSS implementation This commit introduces a new benchmark for the XMSS algorithm in the `benches/xmss.rs` file, utilizing the Criterion library for performance measurement. The benchmark is configured with specific parameters for sample size, measurement time, and warm-up time, and it measures the proving time of the XMSS implementation. Additionally, the `xmss_aggregate.rs` file has been refactored to include a new `XmssBenchStats` struct for better organization of benchmarking results and to streamline the benchmarking process. The test function for XMSS aggregation has also been updated to utilize the new benchmarking structure. --- benches/xmss.rs | 27 +++++++ crates/rec_aggregation/src/xmss_aggregate.rs | 84 +++++++++++--------- 2 files changed, 74 insertions(+), 37 deletions(-) create mode 100644 benches/xmss.rs diff --git a/benches/xmss.rs b/benches/xmss.rs new file mode 100644 index 000000000..ad786c474 --- /dev/null +++ b/benches/xmss.rs @@ -0,0 +1,27 @@ +use std::{hint::black_box, time::Duration}; + +use criterion::{Criterion, Throughput, criterion_group, criterion_main}; +use rec_aggregation::bench_xmss; + +fn bench_xmss_benchmark(c: &mut Criterion) { + const N: usize = 500; + const LOG_LIFETIME: usize = 32; + + let mut group = c.benchmark_group("xmss"); + group.sample_size(10); + group.measurement_time(Duration::from_secs(60)); + group.warm_up_time(Duration::from_secs(10)); + group.throughput(Throughput::Elements(N as u64)); + + group.bench_function("xmss", |b| { + b.iter(|| { + let duration = bench_xmss(N, LOG_LIFETIME); + black_box(duration); + }); + }); + + group.finish(); +} + +criterion_group!(benches, bench_xmss_benchmark); +criterion_main!(benches); diff --git a/crates/rec_aggregation/src/xmss_aggregate.rs b/crates/rec_aggregation/src/xmss_aggregate.rs index e213679a7..23ee00572 100644 --- a/crates/rec_aggregation/src/xmss_aggregate.rs +++ b/crates/rec_aggregation/src/xmss_aggregate.rs @@ -1,8 +1,7 @@ -use std::{env, time::Instant}; +use std::time::{Duration, Instant}; use lean_compiler::*; use lean_prover::whir_config_builder; -use p3_field::Field; use p3_field::PrimeCharacteristicRing; use rand::{Rng, SeedableRng, rngs::StdRng}; use rayon::prelude::*; @@ -11,8 +10,13 @@ use lean_prover::{prove_execution::prove_execution, verify_execution::verify_exe use lean_vm::*; use xmss::{PhonyXmssSecretKey, V, XmssSignature}; -#[test] -fn test_xmss_aggregate() { +struct XmssBenchStats { + proving_time: Duration, + proof_size: usize, + verified_signatures: usize, +} + +fn run_xmss_benchmark(n_public_keys: usize) -> XmssBenchStats { // Public input: message_hash | all_public_keys | bitield // Private input: signatures = (randomness | chain_tips | merkle_path) let mut program_str = r#" @@ -207,14 +211,8 @@ fn test_xmss_aggregate() { } "#.to_string(); - const LOG_LIFETIME: usize = 32; const INV_BITFIELD_DENSITY: usize = 1; // (1 / INV_BITFIELD_DENSITY) of the bits are 1 in the bitfield - let n_public_keys: usize = env::var("NUM_XMSS_AGGREGATED") - .unwrap_or("100".to_string()) - .parse() - .unwrap(); - let xmss_signature_size_padded = (V + 1 + LOG_LIFETIME) + LOG_LIFETIME.div_ceil(8); program_str = program_str .replace("LOG_LIFETIME_PLACE_HOLDER", &LOG_LIFETIME.to_string()) @@ -281,32 +279,44 @@ fn test_xmss_aggregate() { ); private_input.extend(F::zero_vec(LOG_LIFETIME.next_multiple_of(8) - LOG_LIFETIME)); } - if env::var("PROVE_XMSS_AGGREGATED").unwrap_or("true".to_string()) == "true" { - utils::init_tracing(); - let (bytecode, function_locations) = compile_program(&program_str); - let time = Instant::now(); - let (proof_data, proof_size) = prove_execution( - &bytecode, - &program_str, - &function_locations, - &public_input, - &private_input, - whir_config_builder(), - false, - ); - let proving_time = time.elapsed(); - verify_execution(&bytecode, &public_input, proof_data, whir_config_builder()).unwrap(); - println!( - "\nXMSS aggregation (n_signatures = {}, lifetime = 2^{})", - n_public_keys / INV_BITFIELD_DENSITY, - LOG_LIFETIME - ); - println!( - "Proving time: {:?}, proof size: {} KiB (not optimized)", - proving_time, - proof_size * F::bits() / (8 * 1024) - ); - } else { - compile_and_run(&program_str, &public_input, &private_input, false); + let (bytecode, function_locations) = compile_program(&program_str); + let time = Instant::now(); + let (proof_data, proof_size) = prove_execution( + &bytecode, + &program_str, + &function_locations, + &public_input, + &private_input, + whir_config_builder(), + false, + ); + let proving_time = time.elapsed(); + verify_execution(&bytecode, &public_input, proof_data, whir_config_builder()).unwrap(); + XmssBenchStats { + proving_time, + proof_size, + verified_signatures: n_public_keys / INV_BITFIELD_DENSITY, } } + +pub fn bench_xmss(n: usize, log_lifetime: usize) -> Duration { + match log_lifetime { + 32 => run_xmss_benchmark::<32>(n), + _ => panic!("unsupported log_lifetime {log_lifetime}"), + } + .proving_time +} + +#[test] +fn test_xmss_aggregate() { + let stats = run_xmss_benchmark::<32>(100); + println!( + "\nXMSS aggregation (n_signatures = {}, lifetime = 2^{})", + stats.verified_signatures, 32 + ); + println!( + "Proving time: {:?}, proof size: {} KiB (not optimized)", + stats.proving_time, + stats.proof_size * F::bits() / (8 * 1024) + ); +}