From 84a1fec9420fcbb6e17afeeb4ffa513a05f4e045 Mon Sep 17 00:00:00 2001 From: Moudy Date: Fri, 15 May 2026 10:51:51 +0200 Subject: [PATCH 1/5] feat: add wallet_crypto_bench tool for wallet-side cryptographic primitives --- Cargo.toml | 1 + docs/benchmarks/README.md | 10 ++ docs/benchmarks/wallet_crypto_bench.md | 43 ++++++ tools/wallet_crypto_bench/Cargo.toml | 19 +++ tools/wallet_crypto_bench/README.md | 20 +++ tools/wallet_crypto_bench/src/main.rs | 173 +++++++++++++++++++++++++ 6 files changed, 266 insertions(+) create mode 100644 docs/benchmarks/README.md create mode 100644 docs/benchmarks/wallet_crypto_bench.md create mode 100644 tools/wallet_crypto_bench/Cargo.toml create mode 100644 tools/wallet_crypto_bench/README.md create mode 100644 tools/wallet_crypto_bench/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 1bce967f..f41a41df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ members = [ "examples/program_deployment/methods/guest", "testnet_initial_state", "indexer/ffi", + "tools/wallet_crypto_bench", ] [workspace.dependencies] diff --git a/docs/benchmarks/README.md b/docs/benchmarks/README.md new file mode 100644 index 00000000..65a57c80 --- /dev/null +++ b/docs/benchmarks/README.md @@ -0,0 +1,10 @@ +# Benchmarks + +Bench tools live under `tools/` with READMEs for how to run each one. This directory holds the result write-ups: machine, raw tables, and short findings. + +| Bench | Doc | +|---|---| +| cycle_bench | [cycle_bench.md](cycle_bench.md) | +| wallet_crypto_bench | [wallet_crypto_bench.md](wallet_crypto_bench.md) | + +All numbers are from a single M2 Pro dev box unless noted otherwise. diff --git a/docs/benchmarks/wallet_crypto_bench.md b/docs/benchmarks/wallet_crypto_bench.md new file mode 100644 index 00000000..a786f875 --- /dev/null +++ b/docs/benchmarks/wallet_crypto_bench.md @@ -0,0 +1,43 @@ +# wallet_crypto_bench + +Wallet-side cryptographic primitives. Measures the per-call cost of key derivation, sender-side DH for note encryption, and Account note symmetric encrypt/decrypt. Standalone host binary, no live stack required. + +## Machine + +| Field | Value | +|---|---| +| Chip | Apple M2 Pro (8P+4E) | +| RAM | 16 GB | +| OS | macOS 15.5 | +| Rust | 1.94.0 | +| Profile | release | + +## Results + +100 timed iterations per operation, 2 warmup discarded. + +| Operation | best (µs) | mean (µs) | stdev (µs) | +|---|---:|---:|---:| +| KeyChain::new_os_random | 2,979.62 (2.98 ms) | 3,138.18 (3.14 ms) | 258.59 (0.26 ms) | +| KeyChain::new_mnemonic | 2,979.12 (2.98 ms) | 3,012.76 (3.01 ms) | 46.09 (0.05 ms) | +| SharedSecretKey::new (sender DH) | 74.17 (0.07 ms) | 74.48 (0.07 ms) | 0.22 (<0.01 ms) | +| EncryptionScheme::encrypt | 0.88 (<0.01 ms) | 0.92 (<0.01 ms) | 0.03 (<0.01 ms) | +| EncryptionScheme::decrypt | 0.75 (<0.01 ms) | 0.78 (<0.01 ms) | 0.04 (<0.01 ms) | + +## Findings + +- Keychain creation is dominated by the 2048-round HMAC-SHA512 PBKDF in the mnemonic-to-SSK path. ≈ 3 ms. +- Per-recipient DH (secp256k1) is ≈ 80 µs. Outbound shielded transfers to N recipients cost ≈ 80·N µs of crypto on top of proving. +- Symmetric encrypt/decrypt over a 49-byte Account note is sub-µs. Bulk encryption is not the bottleneck. + +## Reproduce + +```sh +cargo run --release -p wallet_crypto_bench +``` + +JSON output: `target/wallet_crypto_bench.json`. + +## Caveats + +- Single-thread, no SIMD acceleration. Bench dev box uses the pure-Rust secp256k1 backend. diff --git a/tools/wallet_crypto_bench/Cargo.toml b/tools/wallet_crypto_bench/Cargo.toml new file mode 100644 index 00000000..a0b223f6 --- /dev/null +++ b/tools/wallet_crypto_bench/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "wallet_crypto_bench" +version = "0.1.0" +edition = "2024" +license = { workspace = true } +publish = false + +[lints] +workspace = true + +[dependencies] +key_protocol.workspace = true +nssa_core = { workspace = true, features = ["host"] } + +anyhow.workspace = true +serde.workspace = true +serde_json.workspace = true +bip39.workspace = true +rand = { workspace = true } diff --git a/tools/wallet_crypto_bench/README.md b/tools/wallet_crypto_bench/README.md new file mode 100644 index 00000000..84a67bf1 --- /dev/null +++ b/tools/wallet_crypto_bench/README.md @@ -0,0 +1,20 @@ +# wallet_crypto_bench + +Wallet-side cryptographic microbenchmarks. Single host binary, no live sequencer or Bedrock needed. + +## Run + +```sh +cargo run --release -p wallet_crypto_bench +``` + +## What you'll see + +Per-operation `best_us`, `mean_us`, and `stdev_us` over 100 iterations (plus 2 warmup): + +- `KeyChain::new_os_random` — full mnemonic → SSK → NSK/VSK + public-key derivation (HMAC-SHA512 PBKDF dominates). +- `KeyChain::new_mnemonic` — same pipeline, mnemonic exposed. +- `SharedSecretKey::new (sender DH)` — secp256k1 ECDH per recipient. +- `EncryptionScheme::encrypt` / `decrypt` — ChaCha20 over an Account note. + +JSON output is written to `target/wallet_crypto_bench.json`. diff --git a/tools/wallet_crypto_bench/src/main.rs b/tools/wallet_crypto_bench/src/main.rs new file mode 100644 index 00000000..ac969276 --- /dev/null +++ b/tools/wallet_crypto_bench/src/main.rs @@ -0,0 +1,173 @@ +//! Wallet-side cryptographic microbenchmarks. +//! +//! Measures: +//! - KeyChain::new_os_random (mnemonic → SSK → NSK/VSK + public keys) +//! - KeyChain::new_mnemonic (same, but mnemonic exposed) +//! - SharedSecretKey::new (Diffie-Hellman shared key derivation, the per-recipient cost) +//! - EncryptionScheme::encrypt / decrypt (Account note encryption) +//! +//! Reports best-of-N wall time per operation. No live stack required. + +#![allow( + clippy::arithmetic_side_effects, + clippy::print_stdout, + clippy::print_stderr, + clippy::std_instead_of_alloc, + clippy::std_instead_of_core, + clippy::float_arithmetic, + reason = "Bench tool" +)] + +use std::{path::PathBuf, time::Instant}; + +use anyhow::Result; +use key_protocol::key_management::KeyChain; +use nssa_core::{ + Commitment, EncryptionScheme, SharedSecretKey, + account::{Account, AccountId}, + encryption::{EphemeralPublicKey, EphemeralSecretKey}, +}; +use rand::{RngCore as _, rngs::OsRng}; +use serde::Serialize; + +const ITERS: usize = 100; + +#[derive(Debug, Serialize)] +struct OpResult { + op: &'static str, + iters: usize, + best_us: f64, + mean_us: f64, + stdev_us: f64, +} + +fn time(op: &'static str, iters: usize, mut f: F) -> OpResult { + // Warmup + for _ in 0..2 { + f(); + } + let mut samples_ns: Vec = Vec::with_capacity(iters); + for _ in 0..iters { + let t = Instant::now(); + f(); + samples_ns.push(t.elapsed().as_nanos() as f64); + } + let best_ns = samples_ns.iter().copied().fold(f64::INFINITY, f64::min); + let mean_ns: f64 = samples_ns.iter().sum::() / iters as f64; + let stdev_ns = if iters > 1 { + let var: f64 = samples_ns + .iter() + .map(|s| (s - mean_ns).powi(2)) + .sum::() + / (iters - 1) as f64; + var.sqrt() + } else { + 0.0 + }; + OpResult { + op, + iters, + best_us: best_ns / 1_000.0, + mean_us: mean_ns / 1_000.0, + stdev_us: stdev_ns / 1_000.0, + } +} + +fn main() -> Result<()> { + let mut results: Vec = Vec::new(); + + results.push(time("KeyChain::new_os_random", ITERS, || { + let _kc = KeyChain::new_os_random(); + })); + + results.push(time("KeyChain::new_mnemonic", ITERS, || { + let (_kc, _mnemonic) = KeyChain::new_mnemonic(""); + })); + + // SharedSecretKey: caller has ephemeral secret, recipient has VSK→VPK. + // We bench the SENDER side: derive ephemeral pubkey, then SharedSecretKey::new(scalar, point). + let recipient_kc = KeyChain::new_os_random(); + let vpk = recipient_kc.viewing_public_key.clone(); + results.push(time("SharedSecretKey::new (sender DH)", ITERS, || { + let mut bytes = [0u8; 32]; + OsRng.fill_bytes(&mut bytes); + let esk: EphemeralSecretKey = bytes; + let _epk = EphemeralPublicKey::from(&esk); + let _ssk = SharedSecretKey::new(&esk, &vpk); + })); + + // EncryptionScheme::encrypt / decrypt over a small Account note. + let account = Account::default(); + let account_id = AccountId::new([7; 32]); + let commitment = Commitment::new(&account_id, &account); + let shared = { + let mut bytes = [0u8; 32]; + OsRng.fill_bytes(&mut bytes); + let esk: EphemeralSecretKey = bytes; + SharedSecretKey::new(&esk, &vpk) + }; + let identifier: u128 = 0; + let output_index: u32 = 0; + + let mut produced_ct = None; + results.push(time("EncryptionScheme::encrypt", ITERS, || { + let ct = EncryptionScheme::encrypt(&account, identifier, &shared, &commitment, output_index); + produced_ct = Some(ct); + })); + let ct = produced_ct.expect("encrypt produced ciphertext"); + results.push(time("EncryptionScheme::decrypt", ITERS, || { + let _decoded = EncryptionScheme::decrypt(&ct, &shared, &commitment, output_index); + })); + + print_table(&results); + write_json(&results)?; + Ok(()) +} + +fn print_table(results: &[OpResult]) { + let ow = results + .iter() + .map(|r| r.op.len()) + .max() + .unwrap_or(0) + .max("op".len()); + let cw = 22_usize; + println!( + "{:6} {:>cw$} {:>cw$} {:>cw$}", + "op", "iters", "best_us (ms)", "mean_us (ms)", "stdev_us (ms)", + ); + println!("{}", "-".repeat(ow + 6 + cw * 3 + 8)); + for r in results { + println!( + "{:6} {:>cw$} {:>cw$} {:>cw$}", + r.op, + r.iters, + fmt_us_ms(r.best_us), + fmt_us_ms(r.mean_us), + fmt_us_ms(r.stdev_us), + ); + } +} + +fn fmt_us_ms(us: f64) -> String { + let ms = us / 1_000.0; + if ms < 0.01 { + format!("{us:.2} (<0.01 ms)") + } else { + format!("{us:.2} ({ms:.2} ms)") + } +} + +fn write_json(results: &[OpResult]) -> Result<()> { + let workspace_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("..") + .join("..") + .canonicalize()?; + let out_path = workspace_root.join("target").join("wallet_crypto_bench.json"); + if let Some(parent) = out_path.parent() { + std::fs::create_dir_all(parent)?; + } + std::fs::write(&out_path, serde_json::to_string_pretty(&results)?)?; + println!("\nJSON written to {}", out_path.display()); + Ok(()) +} From 4a8825e63c57f80c99ab1f1c9518582e10143c23 Mon Sep 17 00:00:00 2001 From: Moudy Date: Fri, 15 May 2026 12:53:04 +0200 Subject: [PATCH 2/5] fix: ci --- tools/wallet_crypto_bench/Cargo.toml | 1 - tools/wallet_crypto_bench/src/main.rs | 13 ++++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/wallet_crypto_bench/Cargo.toml b/tools/wallet_crypto_bench/Cargo.toml index a0b223f6..aa0e51b1 100644 --- a/tools/wallet_crypto_bench/Cargo.toml +++ b/tools/wallet_crypto_bench/Cargo.toml @@ -15,5 +15,4 @@ nssa_core = { workspace = true, features = ["host"] } anyhow.workspace = true serde.workspace = true serde_json.workspace = true -bip39.workspace = true rand = { workspace = true } diff --git a/tools/wallet_crypto_bench/src/main.rs b/tools/wallet_crypto_bench/src/main.rs index ac969276..98c6fbbc 100644 --- a/tools/wallet_crypto_bench/src/main.rs +++ b/tools/wallet_crypto_bench/src/main.rs @@ -26,6 +26,7 @@ use nssa_core::{ Commitment, EncryptionScheme, SharedSecretKey, account::{Account, AccountId}, encryption::{EphemeralPublicKey, EphemeralSecretKey}, + program::PrivateAccountKind, }; use rand::{RngCore as _, rngs::OsRng}; use serde::Serialize; @@ -89,7 +90,7 @@ fn main() -> Result<()> { let recipient_kc = KeyChain::new_os_random(); let vpk = recipient_kc.viewing_public_key.clone(); results.push(time("SharedSecretKey::new (sender DH)", ITERS, || { - let mut bytes = [0u8; 32]; + let mut bytes = [0_u8; 32]; OsRng.fill_bytes(&mut bytes); let esk: EphemeralSecretKey = bytes; let _epk = EphemeralPublicKey::from(&esk); @@ -101,17 +102,17 @@ fn main() -> Result<()> { let account_id = AccountId::new([7; 32]); let commitment = Commitment::new(&account_id, &account); let shared = { - let mut bytes = [0u8; 32]; + let mut bytes = [0_u8; 32]; OsRng.fill_bytes(&mut bytes); let esk: EphemeralSecretKey = bytes; SharedSecretKey::new(&esk, &vpk) }; - let identifier: u128 = 0; + let kind = PrivateAccountKind::Regular(0_u128); let output_index: u32 = 0; let mut produced_ct = None; results.push(time("EncryptionScheme::encrypt", ITERS, || { - let ct = EncryptionScheme::encrypt(&account, identifier, &shared, &commitment, output_index); + let ct = EncryptionScheme::encrypt(&account, &kind, &shared, &commitment, output_index); produced_ct = Some(ct); })); let ct = produced_ct.expect("encrypt produced ciphertext"); @@ -163,7 +164,9 @@ fn write_json(results: &[OpResult]) -> Result<()> { .join("..") .join("..") .canonicalize()?; - let out_path = workspace_root.join("target").join("wallet_crypto_bench.json"); + let out_path = workspace_root + .join("target") + .join("wallet_crypto_bench.json"); if let Some(parent) = out_path.parent() { std::fs::create_dir_all(parent)?; } From 891b23c18a7766c8f75ececfd2d6bb48fae3396b Mon Sep 17 00:00:00 2001 From: Moudy Date: Fri, 15 May 2026 15:27:30 +0200 Subject: [PATCH 3/5] fix: ci --- tools/wallet_crypto_bench/src/main.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/wallet_crypto_bench/src/main.rs b/tools/wallet_crypto_bench/src/main.rs index 98c6fbbc..df52aacf 100644 --- a/tools/wallet_crypto_bench/src/main.rs +++ b/tools/wallet_crypto_bench/src/main.rs @@ -10,11 +10,14 @@ #![allow( clippy::arithmetic_side_effects, - clippy::print_stdout, + clippy::as_conversions, + clippy::cast_precision_loss, + clippy::doc_markdown, + clippy::float_arithmetic, clippy::print_stderr, + clippy::print_stdout, clippy::std_instead_of_alloc, clippy::std_instead_of_core, - clippy::float_arithmetic, reason = "Bench tool" )] @@ -88,7 +91,7 @@ fn main() -> Result<()> { // SharedSecretKey: caller has ephemeral secret, recipient has VSK→VPK. // We bench the SENDER side: derive ephemeral pubkey, then SharedSecretKey::new(scalar, point). let recipient_kc = KeyChain::new_os_random(); - let vpk = recipient_kc.viewing_public_key.clone(); + let vpk = recipient_kc.viewing_public_key; results.push(time("SharedSecretKey::new (sender DH)", ITERS, || { let mut bytes = [0_u8; 32]; OsRng.fill_bytes(&mut bytes); From ba65b168dd3d96d3f3f009bc5e768f3de51273fb Mon Sep 17 00:00:00 2001 From: Moudy Date: Mon, 18 May 2026 17:13:07 +0200 Subject: [PATCH 4/5] rename(wallet_crypto_bench): rename to crypto_primitives_bench --- Cargo.lock | 12 ++++++++++++ Cargo.toml | 2 +- docs/benchmarks/README.md | 2 +- ...et_crypto_bench.md => crypto_primitives_bench.md} | 8 ++++---- .../Cargo.toml | 2 +- .../README.md | 8 ++++---- .../src/main.rs | 2 +- 7 files changed, 24 insertions(+), 12 deletions(-) rename docs/benchmarks/{wallet_crypto_bench.md => crypto_primitives_bench.md} (77%) rename tools/{wallet_crypto_bench => crypto_primitives_bench}/Cargo.toml (90%) rename tools/{wallet_crypto_bench => crypto_primitives_bench}/README.md (63%) rename tools/{wallet_crypto_bench => crypto_primitives_bench}/src/main.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index 1c49d7e7..cfb08176 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1934,6 +1934,18 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "crypto_primitives_bench" +version = "0.1.0" +dependencies = [ + "anyhow", + "key_protocol", + "nssa_core", + "rand 0.8.5", + "serde", + "serde_json", +] + [[package]] name = "ctr" version = "0.9.2" diff --git a/Cargo.toml b/Cargo.toml index f41a41df..aa8eaba4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ members = [ "examples/program_deployment/methods/guest", "testnet_initial_state", "indexer/ffi", - "tools/wallet_crypto_bench", + "tools/crypto_primitives_bench", ] [workspace.dependencies] diff --git a/docs/benchmarks/README.md b/docs/benchmarks/README.md index 65a57c80..9289d2bf 100644 --- a/docs/benchmarks/README.md +++ b/docs/benchmarks/README.md @@ -5,6 +5,6 @@ Bench tools live under `tools/` with READMEs for how to run each one. This direc | Bench | Doc | |---|---| | cycle_bench | [cycle_bench.md](cycle_bench.md) | -| wallet_crypto_bench | [wallet_crypto_bench.md](wallet_crypto_bench.md) | +| crypto_primitives_bench | [crypto_primitives_bench.md](crypto_primitives_bench.md) | All numbers are from a single M2 Pro dev box unless noted otherwise. diff --git a/docs/benchmarks/wallet_crypto_bench.md b/docs/benchmarks/crypto_primitives_bench.md similarity index 77% rename from docs/benchmarks/wallet_crypto_bench.md rename to docs/benchmarks/crypto_primitives_bench.md index a786f875..f25650af 100644 --- a/docs/benchmarks/wallet_crypto_bench.md +++ b/docs/benchmarks/crypto_primitives_bench.md @@ -1,6 +1,6 @@ -# wallet_crypto_bench +# crypto_primitives_bench -Wallet-side cryptographic primitives. Measures the per-call cost of key derivation, sender-side DH for note encryption, and Account note symmetric encrypt/decrypt. Standalone host binary, no live stack required. +Cryptographic primitives used by client/wallet code. Measures the per-call cost of key derivation, sender-side DH for note encryption, and Account note symmetric encrypt/decrypt. Standalone host binary, no live stack required. ## Machine @@ -33,10 +33,10 @@ Wallet-side cryptographic primitives. Measures the per-call cost of key derivati ## Reproduce ```sh -cargo run --release -p wallet_crypto_bench +cargo run --release -p crypto_primitives_bench ``` -JSON output: `target/wallet_crypto_bench.json`. +JSON output: `target/crypto_primitives_bench.json`. ## Caveats diff --git a/tools/wallet_crypto_bench/Cargo.toml b/tools/crypto_primitives_bench/Cargo.toml similarity index 90% rename from tools/wallet_crypto_bench/Cargo.toml rename to tools/crypto_primitives_bench/Cargo.toml index aa0e51b1..e6d1240c 100644 --- a/tools/wallet_crypto_bench/Cargo.toml +++ b/tools/crypto_primitives_bench/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "wallet_crypto_bench" +name = "crypto_primitives_bench" version = "0.1.0" edition = "2024" license = { workspace = true } diff --git a/tools/wallet_crypto_bench/README.md b/tools/crypto_primitives_bench/README.md similarity index 63% rename from tools/wallet_crypto_bench/README.md rename to tools/crypto_primitives_bench/README.md index 84a67bf1..f45174c4 100644 --- a/tools/wallet_crypto_bench/README.md +++ b/tools/crypto_primitives_bench/README.md @@ -1,11 +1,11 @@ -# wallet_crypto_bench +# crypto_primitives_bench -Wallet-side cryptographic microbenchmarks. Single host binary, no live sequencer or Bedrock needed. +Cryptographic primitive microbenchmarks used by client/wallet code. Single host binary, no live sequencer or Bedrock needed. ## Run ```sh -cargo run --release -p wallet_crypto_bench +cargo run --release -p crypto_primitives_bench ``` ## What you'll see @@ -17,4 +17,4 @@ Per-operation `best_us`, `mean_us`, and `stdev_us` over 100 iterations (plus 2 w - `SharedSecretKey::new (sender DH)` — secp256k1 ECDH per recipient. - `EncryptionScheme::encrypt` / `decrypt` — ChaCha20 over an Account note. -JSON output is written to `target/wallet_crypto_bench.json`. +JSON output is written to `target/crypto_primitives_bench.json`. diff --git a/tools/wallet_crypto_bench/src/main.rs b/tools/crypto_primitives_bench/src/main.rs similarity index 99% rename from tools/wallet_crypto_bench/src/main.rs rename to tools/crypto_primitives_bench/src/main.rs index df52aacf..ea727654 100644 --- a/tools/wallet_crypto_bench/src/main.rs +++ b/tools/crypto_primitives_bench/src/main.rs @@ -169,7 +169,7 @@ fn write_json(results: &[OpResult]) -> Result<()> { .canonicalize()?; let out_path = workspace_root .join("target") - .join("wallet_crypto_bench.json"); + .join("crypto_primitives_bench.json"); if let Some(parent) = out_path.parent() { std::fs::create_dir_all(parent)?; } From dbe8ac61605ddd63e1fcd70ca76575d543a4206b Mon Sep 17 00:00:00 2001 From: Moudy Date: Mon, 18 May 2026 17:36:07 +0200 Subject: [PATCH 5/5] chore(crypto_primitives_bench): switch allow to expect, fix doc_markdown inline --- tools/crypto_primitives_bench/src/main.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/tools/crypto_primitives_bench/src/main.rs b/tools/crypto_primitives_bench/src/main.rs index ea727654..3fe71d92 100644 --- a/tools/crypto_primitives_bench/src/main.rs +++ b/tools/crypto_primitives_bench/src/main.rs @@ -1,23 +1,19 @@ -//! Wallet-side cryptographic microbenchmarks. +//! Cryptographic primitive microbenchmarks used by client/wallet code. //! //! Measures: -//! - KeyChain::new_os_random (mnemonic → SSK → NSK/VSK + public keys) -//! - KeyChain::new_mnemonic (same, but mnemonic exposed) -//! - SharedSecretKey::new (Diffie-Hellman shared key derivation, the per-recipient cost) -//! - EncryptionScheme::encrypt / decrypt (Account note encryption) +//! - `KeyChain::new_os_random` (mnemonic → SSK → NSK/VSK + public keys) +//! - `KeyChain::new_mnemonic` (same, but mnemonic exposed) +//! - `SharedSecretKey::new` (Diffie-Hellman shared key derivation, the per-recipient cost) +//! - `EncryptionScheme::encrypt` / `decrypt` (Account note encryption) //! //! Reports best-of-N wall time per operation. No live stack required. -#![allow( +#![expect( clippy::arithmetic_side_effects, clippy::as_conversions, clippy::cast_precision_loss, - clippy::doc_markdown, clippy::float_arithmetic, - clippy::print_stderr, clippy::print_stdout, - clippy::std_instead_of_alloc, - clippy::std_instead_of_core, reason = "Bench tool" )]