mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-05-22 01:30:00 +00:00
chore(cycle_bench): tighten lint discipline (allow → expect, fix issues in code)
- Switch crate-level #![allow] to #![expect] in main.rs and prune 17 entries the compiler reports as unfulfilled or workspace-allowed. - Fix the underlying issues rather than allow: source ordering (mods/uses regrouped), doc_markdown (identifiers backticked), redundant_type_annotations, map_unwrap_or, unnecessary_wraps. - Extract feature-gated mod ppe_impl into its own file tools/cycle_bench/src/ppe/ppe_impl.rs so the mod declaration can precede the public structs per arbitrary_source_item_ordering. Net: 35 → 12 expects in main.rs, all load-bearing.
This commit is contained in:
parent
9efc26495b
commit
28db42315b
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -1971,6 +1971,24 @@ dependencies = [
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cycle_bench"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"amm_core",
|
||||
"anyhow",
|
||||
"ata_core",
|
||||
"borsh",
|
||||
"clap",
|
||||
"clock_core",
|
||||
"nssa",
|
||||
"nssa_core",
|
||||
"risc0-zkvm",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"token_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
|
||||
@ -7,50 +7,24 @@
|
||||
//! Run with `cargo run --release -p cycle_bench`. `RISC0_DEV_MODE` has no effect on
|
||||
//! executor cycle counts.
|
||||
|
||||
#![allow(
|
||||
clippy::arbitrary_source_item_ordering,
|
||||
#![expect(
|
||||
clippy::arithmetic_side_effects,
|
||||
clippy::as_conversions,
|
||||
clippy::cast_precision_loss,
|
||||
clippy::doc_markdown,
|
||||
clippy::float_arithmetic,
|
||||
clippy::ignored_unit_patterns,
|
||||
clippy::items_after_statements,
|
||||
clippy::let_underscore_must_use,
|
||||
clippy::let_underscore_untyped,
|
||||
clippy::map_unwrap_or,
|
||||
clippy::missing_const_for_fn,
|
||||
clippy::missing_docs_in_private_items,
|
||||
clippy::module_inception,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::no_effect_underscore_binding,
|
||||
clippy::non_ascii_literal,
|
||||
clippy::print_literal,
|
||||
clippy::print_stderr,
|
||||
clippy::print_stdout,
|
||||
clippy::redundant_type_annotations,
|
||||
clippy::ref_option,
|
||||
clippy::ref_patterns,
|
||||
clippy::similar_names,
|
||||
clippy::single_call_fn,
|
||||
clippy::single_match_else,
|
||||
clippy::std_instead_of_alloc,
|
||||
clippy::std_instead_of_core,
|
||||
clippy::too_many_arguments,
|
||||
clippy::too_many_lines,
|
||||
clippy::unnecessary_wraps,
|
||||
clippy::unwrap_used,
|
||||
clippy::useless_format,
|
||||
clippy::wildcard_enum_match_arm,
|
||||
reason = "Bench tool: matches test-style fixture code"
|
||||
)]
|
||||
|
||||
use std::{path::PathBuf, time::Instant};
|
||||
|
||||
mod ppe;
|
||||
mod stats;
|
||||
|
||||
use amm_core::{PoolDefinition, compute_liquidity_token_pda, compute_pool_pda, compute_vault_pda};
|
||||
use anyhow::Result;
|
||||
use ata_core::{compute_ata_seed, get_associated_token_account_id};
|
||||
@ -71,9 +45,13 @@ use nssa_core::{
|
||||
};
|
||||
use risc0_zkvm::{ExecutorEnv, default_executor, default_prover};
|
||||
use serde::Serialize;
|
||||
use stats::Stats;
|
||||
use token_core::{TokenDefinition, TokenHolding};
|
||||
|
||||
use stats::Stats;
|
||||
|
||||
mod ppe;
|
||||
mod stats;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(about = "Per-program executor and (optionally) prover cycle measurements")]
|
||||
struct Cli {
|
||||
@ -82,14 +60,14 @@ struct Cli {
|
||||
prove: bool,
|
||||
|
||||
/// Also run privacy-preserving execution circuit (PPE) composition cases:
|
||||
/// (a) single auth_transfer Transfer through `execute_and_prove`, (b) chain_caller
|
||||
/// (a) single `auth_transfer` Transfer through `execute_and_prove`, (b) `chain_caller`
|
||||
/// with depth N=1,3,5,9. Requires --features ppe at build time. Very slow.
|
||||
#[arg(long)]
|
||||
ppe: bool,
|
||||
|
||||
/// After running --ppe-style proving once for auth_transfer-in-PPE, time
|
||||
/// receipt.verify(PRIVACY_PRESERVING_CIRCUIT_ID) over many iterations.
|
||||
/// Produces G_verify for the fee model. Requires --features ppe.
|
||||
/// `receipt.verify(PRIVACY_PRESERVING_CIRCUIT_ID)` over many iterations.
|
||||
/// Produces `G_verify` for the fee model. Requires --features ppe.
|
||||
#[arg(long)]
|
||||
verify: bool,
|
||||
|
||||
@ -343,11 +321,11 @@ fn amm_lp_def_id() -> AccountId {
|
||||
compute_liquidity_token_pda(AMM_ID, amm_pool_id())
|
||||
}
|
||||
|
||||
/// Pool seeded with reserves 1_000 / 500, lp supply sqrt(1000*500) = 707.
|
||||
/// Pool seeded with reserves `1_000` / `500`, lp supply `sqrt(1000*500) = 707`.
|
||||
fn amm_pool_account() -> AccountWithMetadata {
|
||||
let reserve_a: u128 = 1_000;
|
||||
let reserve_b: u128 = 500;
|
||||
let lp_supply: u128 = (reserve_a * reserve_b).isqrt();
|
||||
let lp_supply = (reserve_a * reserve_b).isqrt();
|
||||
AccountWithMetadata {
|
||||
account: Account {
|
||||
program_owner: AMM_ID,
|
||||
@ -384,7 +362,7 @@ fn amm_add_liquidity_pre_states() -> Vec<AccountWithMetadata> {
|
||||
let pool = amm_pool_account();
|
||||
let vault_a = token_holding(amm_token_a_def_id(), amm_vault_a_id(), 1_000, true);
|
||||
let vault_b = token_holding(amm_token_b_def_id(), amm_vault_b_id(), 500, true);
|
||||
let lp_supply: u128 = (1_000_u128 * 500_u128).isqrt();
|
||||
let lp_supply = (1_000_u128 * 500_u128).isqrt();
|
||||
let lp_def = token_definition(amm_lp_def_id(), lp_supply, true);
|
||||
let user_a = token_holding(amm_token_a_def_id(), AccountId::new([45; 32]), 1_000, true);
|
||||
let user_b = token_holding(amm_token_b_def_id(), AccountId::new([46; 32]), 500, true);
|
||||
@ -538,7 +516,7 @@ fn main() -> Result<()> {
|
||||
print_table(&results, prove);
|
||||
|
||||
#[cfg(feature = "ppe")]
|
||||
let ppe_results = if cli.ppe { ppe::run_all()? } else { Vec::new() };
|
||||
let ppe_results = if cli.ppe { ppe::run_all() } else { Vec::new() };
|
||||
#[cfg(not(feature = "ppe"))]
|
||||
let ppe_results: Vec<ppe::PpeBenchResult> = {
|
||||
if cli.ppe {
|
||||
@ -637,16 +615,14 @@ fn print_table(results: &[BenchResult], prove: bool) {
|
||||
for r in results {
|
||||
let total = r
|
||||
.prove_total_cycles
|
||||
.map(|c| c.to_string())
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
let pms = r
|
||||
.prove_stats
|
||||
.map(|s| format!("{:.1} ({:.1}s)", s.best_ms, s.best_ms / 1_000.0))
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
.map_or_else(|| "-".to_owned(), |c| c.to_string());
|
||||
let pms = r.prove_stats.map_or_else(
|
||||
|| "-".to_owned(),
|
||||
|s| format!("{:.1} ({:.1}s)", s.best_ms, s.best_ms / 1_000.0),
|
||||
);
|
||||
let psegs = r
|
||||
.prove_segments
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
.map_or_else(|| "-".to_owned(), |s| s.to_string());
|
||||
println!(
|
||||
"{:<pw$} {:<iw$} {:>pcw$} {:>pwallw$} {:>psw$}",
|
||||
r.program, r.instruction, total, pms, psegs,
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
//! Privacy-preserving execution (PPE) cases for cycle_bench.
|
||||
//! Privacy-preserving execution (PPE) cases for `cycle_bench`.
|
||||
//!
|
||||
//! Composition cost is the delta between standalone `prover.prove(env, elf)` for
|
||||
//! a single program (measured in the main bench) and a full `execute_and_prove`
|
||||
//! that wraps the same program in the privacy circuit. Chained-call depth sweep
|
||||
//! uses the `chain_caller` test program (loaded from artifacts/) with N=1, 3, 5, 9.
|
||||
//!
|
||||
//! `run_verify` produces G_verify for the fee model: it generates one PPE
|
||||
//! receipt (auth_transfer Transfer in PPE) and times `Receipt::verify` over
|
||||
//! `run_verify` produces `G_verify` for the fee model: it generates one PPE
|
||||
//! receipt (`auth_transfer` Transfer in PPE) and times `Receipt::verify` over
|
||||
//! `iters` iterations. The proof bytes captured here are also the on-wire
|
||||
//! "outer proof" payload (S_agg in the fee model).
|
||||
//! "outer proof" payload (`S_agg` in the fee model).
|
||||
|
||||
#![allow(
|
||||
dead_code,
|
||||
@ -20,12 +20,15 @@ use serde::Serialize;
|
||||
|
||||
use crate::stats::Stats;
|
||||
|
||||
#[cfg(feature = "ppe")]
|
||||
mod ppe_impl;
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct PpeBenchResult {
|
||||
pub label: String,
|
||||
pub chain_depth: usize,
|
||||
pub prove_wall_ms: Option<f64>,
|
||||
/// borsh-serialized InnerReceipt length (S_agg in the fee model).
|
||||
/// borsh-serialized `InnerReceipt` length (`S_agg` in the fee model).
|
||||
pub proof_bytes: Option<usize>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
@ -39,12 +42,12 @@ pub struct VerifyBenchResult {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ppe"))]
|
||||
pub fn run_all() -> Result<Vec<PpeBenchResult>> {
|
||||
Ok(Vec::new())
|
||||
pub fn run_all() -> Vec<PpeBenchResult> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
#[cfg(feature = "ppe")]
|
||||
pub fn run_all() -> Result<Vec<PpeBenchResult>> {
|
||||
pub fn run_all() -> Vec<PpeBenchResult> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
eprintln!("PPE: running composition cost (auth_transfer Transfer in PPE)");
|
||||
@ -55,7 +58,7 @@ pub fn run_all() -> Result<Vec<PpeBenchResult>> {
|
||||
results.push(ppe_impl::run_chain_caller(depth));
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
results
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ppe"))]
|
||||
@ -87,14 +90,13 @@ pub fn print_table(results: &[PpeBenchResult]) {
|
||||
);
|
||||
println!("{}", "-".repeat(lw + 60));
|
||||
for r in results {
|
||||
let p = r
|
||||
.prove_wall_ms
|
||||
.map(|v| format!("{v:.1} ({:.1}s)", v / 1_000.0))
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
let p = r.prove_wall_ms.map_or_else(
|
||||
|| "-".to_owned(),
|
||||
|v| format!("{v:.1} ({:.1}s)", v / 1_000.0),
|
||||
);
|
||||
let b = r
|
||||
.proof_bytes
|
||||
.map(|n| n.to_string())
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
.map_or_else(|| "-".to_owned(), |n| n.to_string());
|
||||
let e = r.error.as_deref().unwrap_or("");
|
||||
println!(
|
||||
"{:<lw$} {:>5} {:>20} {:>12} {}",
|
||||
@ -118,199 +120,3 @@ pub fn print_verify(r: &VerifyBenchResult) {
|
||||
println!(" journal_bytes : {}", r.journal_bytes);
|
||||
println!(" verify_ms : {}", r.stats.format());
|
||||
}
|
||||
|
||||
#[cfg(feature = "ppe")]
|
||||
mod ppe_impl {
|
||||
use std::{collections::HashMap, time::Instant};
|
||||
|
||||
use nssa::{
|
||||
execute_and_prove,
|
||||
privacy_preserving_transaction::circuit::{ProgramWithDependencies, Proof},
|
||||
program::Program,
|
||||
program_methods::PRIVACY_PRESERVING_CIRCUIT_ID,
|
||||
};
|
||||
use nssa_core::{
|
||||
InputAccountIdentity, PrivacyPreservingCircuitOutput,
|
||||
account::{Account, AccountId, AccountWithMetadata},
|
||||
program::ProgramId,
|
||||
};
|
||||
use risc0_zkvm::{InnerReceipt, Receipt, serde::to_vec};
|
||||
|
||||
use super::{PpeBenchResult, VerifyBenchResult};
|
||||
use crate::stats::Stats;
|
||||
|
||||
const AUTH_TRANSFER_ID: ProgramId = nssa::program_methods::AUTHENTICATED_TRANSFER_ID;
|
||||
const AUTH_TRANSFER_ELF: &[u8] = nssa::program_methods::AUTHENTICATED_TRANSFER_ELF;
|
||||
|
||||
/// chain_caller bytecode shipped at artifacts/test_program_methods/chain_caller.bin.
|
||||
/// Loaded at compile time so we don't need a dev-dependency on test_program_methods.
|
||||
const CHAIN_CALLER_ELF: &[u8] =
|
||||
include_bytes!("../../../artifacts/test_program_methods/chain_caller.bin");
|
||||
|
||||
pub fn run_auth_transfer_in_ppe() -> PpeBenchResult {
|
||||
let label = "auth_transfer Transfer in PPE".to_owned();
|
||||
let started = Instant::now();
|
||||
match prove_auth_transfer_in_ppe() {
|
||||
Ok((_out, proof)) => {
|
||||
let prove_ms = started.elapsed().as_secs_f64() * 1_000.0;
|
||||
PpeBenchResult {
|
||||
label,
|
||||
chain_depth: 0,
|
||||
prove_wall_ms: Some(prove_ms),
|
||||
proof_bytes: Some(proof.into_inner().len()),
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
Err(err) => PpeBenchResult {
|
||||
label,
|
||||
chain_depth: 0,
|
||||
prove_wall_ms: None,
|
||||
proof_bytes: None,
|
||||
error: Some(err.to_string()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn prove_auth_transfer_in_ppe() -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> {
|
||||
let program = Program::new(AUTH_TRANSFER_ELF.to_vec())?;
|
||||
let pwd = ProgramWithDependencies::from(program);
|
||||
|
||||
// For PPE to allow the sender's balance to be decremented by this
|
||||
// program, the sender must already be claimed by auth_transfer.
|
||||
// Recipient stays default-owned so the first call can claim it.
|
||||
let sender = AccountWithMetadata {
|
||||
account: Account {
|
||||
program_owner: AUTH_TRANSFER_ID,
|
||||
balance: 1_000_000,
|
||||
..Account::default()
|
||||
},
|
||||
is_authorized: true,
|
||||
account_id: AccountId::new([1; 32]),
|
||||
};
|
||||
let recipient = AccountWithMetadata {
|
||||
account: Account::default(),
|
||||
is_authorized: true,
|
||||
account_id: AccountId::new([2; 32]),
|
||||
};
|
||||
let pre_states = vec![sender, recipient];
|
||||
|
||||
let balance_to_move: u128 = 5_000;
|
||||
let instruction_data = to_vec(&balance_to_move)?;
|
||||
|
||||
let account_identities = vec![InputAccountIdentity::Public; pre_states.len()];
|
||||
|
||||
Ok(execute_and_prove(
|
||||
pre_states,
|
||||
instruction_data,
|
||||
account_identities,
|
||||
&pwd,
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn run_chain_caller(depth: u32) -> PpeBenchResult {
|
||||
let label = format!("chain_caller depth={depth}");
|
||||
let started = Instant::now();
|
||||
match prove_chain_caller(depth) {
|
||||
Ok((_out, proof)) => {
|
||||
let prove_ms = started.elapsed().as_secs_f64() * 1_000.0;
|
||||
PpeBenchResult {
|
||||
label,
|
||||
chain_depth: depth as usize,
|
||||
prove_wall_ms: Some(prove_ms),
|
||||
proof_bytes: Some(proof.into_inner().len()),
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
Err(err) => PpeBenchResult {
|
||||
label,
|
||||
chain_depth: depth as usize,
|
||||
prove_wall_ms: None,
|
||||
proof_bytes: None,
|
||||
error: Some(err.to_string()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn prove_chain_caller(
|
||||
num_chain_calls: u32,
|
||||
) -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> {
|
||||
let chain_caller = Program::new(CHAIN_CALLER_ELF.to_vec())?;
|
||||
let auth_transfer = Program::new(AUTH_TRANSFER_ELF.to_vec())?;
|
||||
let mut deps = HashMap::new();
|
||||
deps.insert(AUTH_TRANSFER_ID, auth_transfer);
|
||||
let pwd = ProgramWithDependencies::new(chain_caller, deps);
|
||||
|
||||
// Both accounts pre-claimed by auth_transfer. chain_caller doesn't
|
||||
// track recipient's post-claim program_owner, so a default recipient
|
||||
// would cause a state mismatch on subsequent chained calls.
|
||||
let recipient_pre = AccountWithMetadata {
|
||||
account: Account {
|
||||
program_owner: AUTH_TRANSFER_ID,
|
||||
..Account::default()
|
||||
},
|
||||
is_authorized: true,
|
||||
account_id: AccountId::new([2; 32]),
|
||||
};
|
||||
let sender_pre = AccountWithMetadata {
|
||||
account: Account {
|
||||
program_owner: AUTH_TRANSFER_ID,
|
||||
balance: 1_000_000,
|
||||
..Account::default()
|
||||
},
|
||||
is_authorized: true,
|
||||
account_id: AccountId::new([1; 32]),
|
||||
};
|
||||
// chain_caller expects pre_states = [recipient, sender].
|
||||
let pre_states = vec![recipient_pre, sender_pre];
|
||||
|
||||
let balance: u128 = 1;
|
||||
let pda_seed: Option<nssa_core::program::PdaSeed> = None;
|
||||
let instruction = (balance, AUTH_TRANSFER_ID, num_chain_calls, pda_seed);
|
||||
let instruction_data = to_vec(&instruction)?;
|
||||
|
||||
let account_identities = vec![InputAccountIdentity::Public; pre_states.len()];
|
||||
|
||||
Ok(execute_and_prove(
|
||||
pre_states,
|
||||
instruction_data,
|
||||
account_identities,
|
||||
&pwd,
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn run_verify(iters: usize) -> anyhow::Result<VerifyBenchResult> {
|
||||
eprintln!("verify: generating PPE receipt for auth_transfer Transfer (~1 prove)");
|
||||
let (output, proof) = prove_auth_transfer_in_ppe()?;
|
||||
let journal = output.to_bytes();
|
||||
let journal_bytes = journal.len();
|
||||
let proof_bytes_vec = proof.into_inner();
|
||||
let proof_bytes = proof_bytes_vec.len();
|
||||
|
||||
let inner: InnerReceipt = borsh::from_slice(&proof_bytes_vec)
|
||||
.map_err(|e| anyhow::anyhow!("InnerReceipt deserialize: {e}"))?;
|
||||
let receipt = Receipt::new(inner, journal);
|
||||
|
||||
// Sanity-check before the timing loop so we don't measure 1000 failures.
|
||||
receipt
|
||||
.verify(PRIVACY_PRESERVING_CIRCUIT_ID)
|
||||
.map_err(|e| anyhow::anyhow!("verify sanity check failed: {e}"))?;
|
||||
|
||||
eprintln!("verify: timing {iters} iters of receipt.verify(...)");
|
||||
let mut samples = Vec::with_capacity(iters);
|
||||
for _ in 0..iters {
|
||||
let started = Instant::now();
|
||||
receipt
|
||||
.verify(PRIVACY_PRESERVING_CIRCUIT_ID)
|
||||
.map_err(|e| anyhow::anyhow!("verify failed mid-loop: {e}"))?;
|
||||
samples.push(started.elapsed().as_secs_f64() * 1_000.0);
|
||||
}
|
||||
let stats = Stats::from_samples(&samples);
|
||||
|
||||
Ok(VerifyBenchResult {
|
||||
label: "auth_transfer Transfer in PPE".to_owned(),
|
||||
stats,
|
||||
proof_bytes,
|
||||
journal_bytes,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
194
tools/cycle_bench/src/ppe/ppe_impl.rs
Normal file
194
tools/cycle_bench/src/ppe/ppe_impl.rs
Normal file
@ -0,0 +1,194 @@
|
||||
//! Feature-gated implementation of PPE composition and verify benches.
|
||||
|
||||
use std::{collections::HashMap, time::Instant};
|
||||
|
||||
use nssa::{
|
||||
execute_and_prove,
|
||||
privacy_preserving_transaction::circuit::{ProgramWithDependencies, Proof},
|
||||
program::Program,
|
||||
program_methods::PRIVACY_PRESERVING_CIRCUIT_ID,
|
||||
};
|
||||
use nssa_core::{
|
||||
InputAccountIdentity, PrivacyPreservingCircuitOutput,
|
||||
account::{Account, AccountId, AccountWithMetadata},
|
||||
program::ProgramId,
|
||||
};
|
||||
use risc0_zkvm::{InnerReceipt, Receipt, serde::to_vec};
|
||||
|
||||
use super::{PpeBenchResult, VerifyBenchResult};
|
||||
use crate::stats::Stats;
|
||||
|
||||
const AUTH_TRANSFER_ID: ProgramId = nssa::program_methods::AUTHENTICATED_TRANSFER_ID;
|
||||
const AUTH_TRANSFER_ELF: &[u8] = nssa::program_methods::AUTHENTICATED_TRANSFER_ELF;
|
||||
|
||||
/// `chain_caller` bytecode shipped at `artifacts/test_program_methods/chain_caller.bin`.
|
||||
/// Loaded at compile time so we don't need a dev-dependency on `test_program_methods`.
|
||||
const CHAIN_CALLER_ELF: &[u8] =
|
||||
include_bytes!("../../../../artifacts/test_program_methods/chain_caller.bin");
|
||||
|
||||
pub fn run_auth_transfer_in_ppe() -> PpeBenchResult {
|
||||
let label = "auth_transfer Transfer in PPE".to_owned();
|
||||
let started = Instant::now();
|
||||
match prove_auth_transfer_in_ppe() {
|
||||
Ok((_out, proof)) => {
|
||||
let prove_ms = started.elapsed().as_secs_f64() * 1_000.0;
|
||||
PpeBenchResult {
|
||||
label,
|
||||
chain_depth: 0,
|
||||
prove_wall_ms: Some(prove_ms),
|
||||
proof_bytes: Some(proof.into_inner().len()),
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
Err(err) => PpeBenchResult {
|
||||
label,
|
||||
chain_depth: 0,
|
||||
prove_wall_ms: None,
|
||||
proof_bytes: None,
|
||||
error: Some(err.to_string()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn prove_auth_transfer_in_ppe() -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> {
|
||||
let program = Program::new(AUTH_TRANSFER_ELF.to_vec())?;
|
||||
let pwd = ProgramWithDependencies::from(program);
|
||||
|
||||
// For PPE to allow the sender's balance to be decremented by this
|
||||
// program, the sender must already be claimed by auth_transfer.
|
||||
// Recipient stays default-owned so the first call can claim it.
|
||||
let sender = AccountWithMetadata {
|
||||
account: Account {
|
||||
program_owner: AUTH_TRANSFER_ID,
|
||||
balance: 1_000_000,
|
||||
..Account::default()
|
||||
},
|
||||
is_authorized: true,
|
||||
account_id: AccountId::new([1; 32]),
|
||||
};
|
||||
let recipient = AccountWithMetadata {
|
||||
account: Account::default(),
|
||||
is_authorized: true,
|
||||
account_id: AccountId::new([2; 32]),
|
||||
};
|
||||
let pre_states = vec![sender, recipient];
|
||||
|
||||
let balance_to_move: u128 = 5_000;
|
||||
let instruction_data = to_vec(&balance_to_move)?;
|
||||
|
||||
let account_identities = vec![InputAccountIdentity::Public; pre_states.len()];
|
||||
|
||||
Ok(execute_and_prove(
|
||||
pre_states,
|
||||
instruction_data,
|
||||
account_identities,
|
||||
&pwd,
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn run_chain_caller(depth: u32) -> PpeBenchResult {
|
||||
let label = format!("chain_caller depth={depth}");
|
||||
let started = Instant::now();
|
||||
match prove_chain_caller(depth) {
|
||||
Ok((_out, proof)) => {
|
||||
let prove_ms = started.elapsed().as_secs_f64() * 1_000.0;
|
||||
PpeBenchResult {
|
||||
label,
|
||||
chain_depth: depth as usize,
|
||||
prove_wall_ms: Some(prove_ms),
|
||||
proof_bytes: Some(proof.into_inner().len()),
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
Err(err) => PpeBenchResult {
|
||||
label,
|
||||
chain_depth: depth as usize,
|
||||
prove_wall_ms: None,
|
||||
proof_bytes: None,
|
||||
error: Some(err.to_string()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn prove_chain_caller(
|
||||
num_chain_calls: u32,
|
||||
) -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> {
|
||||
let chain_caller = Program::new(CHAIN_CALLER_ELF.to_vec())?;
|
||||
let auth_transfer = Program::new(AUTH_TRANSFER_ELF.to_vec())?;
|
||||
let mut deps = HashMap::new();
|
||||
deps.insert(AUTH_TRANSFER_ID, auth_transfer);
|
||||
let pwd = ProgramWithDependencies::new(chain_caller, deps);
|
||||
|
||||
// Both accounts pre-claimed by auth_transfer. chain_caller doesn't
|
||||
// track recipient's post-claim program_owner, so a default recipient
|
||||
// would cause a state mismatch on subsequent chained calls.
|
||||
let recipient_pre = AccountWithMetadata {
|
||||
account: Account {
|
||||
program_owner: AUTH_TRANSFER_ID,
|
||||
..Account::default()
|
||||
},
|
||||
is_authorized: true,
|
||||
account_id: AccountId::new([2; 32]),
|
||||
};
|
||||
let sender_pre = AccountWithMetadata {
|
||||
account: Account {
|
||||
program_owner: AUTH_TRANSFER_ID,
|
||||
balance: 1_000_000,
|
||||
..Account::default()
|
||||
},
|
||||
is_authorized: true,
|
||||
account_id: AccountId::new([1; 32]),
|
||||
};
|
||||
// chain_caller expects pre_states = [recipient, sender].
|
||||
let pre_states = vec![recipient_pre, sender_pre];
|
||||
|
||||
let balance: u128 = 1;
|
||||
let pda_seed: Option<nssa_core::program::PdaSeed> = None;
|
||||
let instruction = (balance, AUTH_TRANSFER_ID, num_chain_calls, pda_seed);
|
||||
let instruction_data = to_vec(&instruction)?;
|
||||
|
||||
let account_identities = vec![InputAccountIdentity::Public; pre_states.len()];
|
||||
|
||||
Ok(execute_and_prove(
|
||||
pre_states,
|
||||
instruction_data,
|
||||
account_identities,
|
||||
&pwd,
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn run_verify(iters: usize) -> anyhow::Result<VerifyBenchResult> {
|
||||
eprintln!("verify: generating PPE receipt for auth_transfer Transfer (~1 prove)");
|
||||
let (output, proof) = prove_auth_transfer_in_ppe()?;
|
||||
let journal = output.to_bytes();
|
||||
let journal_bytes = journal.len();
|
||||
let proof_bytes_vec = proof.into_inner();
|
||||
let proof_bytes = proof_bytes_vec.len();
|
||||
|
||||
let inner: InnerReceipt = borsh::from_slice(&proof_bytes_vec)
|
||||
.map_err(|e| anyhow::anyhow!("InnerReceipt deserialize: {e}"))?;
|
||||
let receipt = Receipt::new(inner, journal);
|
||||
|
||||
// Sanity-check before the timing loop so we don't measure 1000 failures.
|
||||
receipt
|
||||
.verify(PRIVACY_PRESERVING_CIRCUIT_ID)
|
||||
.map_err(|e| anyhow::anyhow!("verify sanity check failed: {e}"))?;
|
||||
|
||||
eprintln!("verify: timing {iters} iters of receipt.verify(...)");
|
||||
let mut samples = Vec::with_capacity(iters);
|
||||
for _ in 0..iters {
|
||||
let started = Instant::now();
|
||||
receipt
|
||||
.verify(PRIVACY_PRESERVING_CIRCUIT_ID)
|
||||
.map_err(|e| anyhow::anyhow!("verify failed mid-loop: {e}"))?;
|
||||
samples.push(started.elapsed().as_secs_f64() * 1_000.0);
|
||||
}
|
||||
let stats = Stats::from_samples(&samples);
|
||||
|
||||
Ok(VerifyBenchResult {
|
||||
label: "auth_transfer Transfer in PPE".to_owned(),
|
||||
stats,
|
||||
proof_bytes,
|
||||
journal_bytes,
|
||||
})
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user