//! Time the verifier of a stored outermost (final) proof.
//!
//! `wrap_verify <fixture>` with `ZHENG_IVC_DIR` (the proofs `wrap_bench`
//! stored) and `ZHENG_WRAP` (the levels, as `wrap_bench`). The final
//! level's verifying key is read from `<dir>/final-<levels>.vk` when it
//! exists (else every level's key is derived and the file written).
//! `ZHENG_RUNS` timed verifications (default 21) after the first one of
//! the process, which is reported alone ("cold": the key just loaded, the
//! caches cold); `ZHENG_VERIFY_THREADS` sets the verifier's threads.

#[path = "../../tests/common/mod.rs"]
mod common;

use std::time::Instant;
use zheng::machine;
use zheng::recursion::ivc;
use zheng::recursion::perm;
use zheng::recursion::wrap::{self, FinalProof, Mode, WrapKey, WrapParams};

fn fixture(name: &str) -> Option<(zheng::execution::ExecutionNoun, Vec<u64>)> {
    Some(match name {
        "add.tri" => (common::parse(common::ADD), vec![7, 5]),
        "hash.tri" => (common::parse(common::HASH), vec![7]),
        "merkle-32" => {
            let root = machine::execute(&common::merkle_program(32, None), &[5], 1 << 40).ok()?;
            let r = machine::statement::parse(&root.statement.output).ok()?;
            (common::merkle_program(32, Some(&r)), vec![5])
        }
        t if t.starts_with("tree-") => (common::tree_program(t[5..].parse().ok()?), vec![3]),
        t if t.starts_with("rec-") => (common::rec_program(), vec![t[4..].parse().ok()?]),
        _ => return None,
    })
}

fn env<T: std::str::FromStr>(k: &str, d: T) -> T {
    std::env::var(k)
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(d)
}

use zheng::recursion::ivc::thread_cpu_ms;

fn ms(t: Instant) -> f64 {
    t.elapsed().as_secs_f64() * 1e3
}

fn derive(spec: &[&str], whir: &lens::WhirParams, ikey: &ivc::Key) -> WrapKey {
    let mut keys: Vec<WrapKey> = Vec::new();
    for l in spec {
        let mut parts = l.split(':');
        let head = parts.next().expect("level");
        let (rate, mode) = head.split_at(head.len() - 1);
        let mut w = *whir;
        w.log_inv_rate = rate.parse().expect("rate");
        if let Some(p) = parts.next() {
            w.pow_bits = p.parse().expect("pow");
        }
        if let Some(k) = parts.next() {
            w.folding_factor = k.parse().expect("fold");
        }
        let params = WrapParams {
            whir: w,
            n: 0,
            mode: if mode == "f" {
                Mode::Final
            } else {
                Mode::Inner
            },
        };
        let k = match keys.last() {
            None => wrap::derive_key_ivc(params, ikey),
            Some(prev) => wrap::derive_key_wrap(params, prev),
        }
        .expect("key");
        keys.push(k);
    }
    keys.pop().expect("a level")
}

fn main() {
    let name: String = std::env::args().nth(1).unwrap_or_else(|| "add.tri".into());
    let (prog, input) = fixture(&name).unwrap_or_else(|| panic!("fixture {name}"));
    let mut whir = zheng::execution::succinct::params_for(20);
    whir.log_inv_rate = ivc::SHIPPED_RATE;
    whir.pow_bits = ivc::SHIPPED_POW;
    let n = 15u32;
    let dir: String = std::env::var("ZHENG_IVC_DIR").expect("ZHENG_IVC_DIR");
    let spec: String = env("ZHENG_WRAP", wrap::SHIPPED.to_string());
    let specs: Vec<&str> = spec.split(',').collect();
    let run = machine::execute_exact(&prog, &input, 1 << 40, n).expect("run");
    let ikey = ivc::key(&whir, n as usize).expect("key");
    let vk_file = format!("{dir}/final-{}.vk", specs.join("_"));
    let t = Instant::now();
    let last = match std::fs::read(&vk_file) {
        Ok(b) => {
            let k = WrapKey::from_vk_bytes(&b).expect("verifying key");
            eprintln!(
                "verifying key {vk_file}: {} B, loaded in {:.1} ms",
                b.len(),
                ms(t)
            );
            k
        }
        Err(_) => {
            let mut wbase = whir;
            wbase.pow_bits = 24;
            let k = derive(&specs, &wbase, &ikey);
            let b = k.vk_bytes();
            std::fs::write(&vk_file, &b).expect("store key");
            eprintln!(
                "verifying key derived in {:.0} s, stored ({} B)",
                t.elapsed().as_secs_f64(),
                b.len()
            );
            let back = WrapKey::from_vk_bytes(&b).expect("reload");
            assert_eq!(back.vk_bytes(), b, "verifying key round trip");
            back
        }
    };
    if let Some(w) = &last.wiring {
        eprintln!(
            "wiring: {} reads ({} cells), {} writes ({} cells); graph {} ops; key {} entries in {} of {} columns used",
            w.reads,
            w.read_cells.len(),
            w.write_at.len() - 1,
            w.write_cells.len(),
            last.gc.len(),
            last.sparse
                .iter()
                .zip(&last.key_cols)
                .filter(|c| *c.1)
                .map(|c| c.0.len())
                .sum::<usize>(),
            last.key_cols.iter().filter(|&&u| u).count(),
            last.key_cols.len()
        );
    }
    let bytes = std::fs::read(format!("{dir}/{name}.final-{}", specs.join("_")))
        .expect("stored final proof");
    let header = FinalProof::from_bytes(&bytes, &last).expect("parse");
    let prep = ivc::prepare(
        &run.statement,
        &whir,
        header.log_rows,
        header.start,
        header.segments,
        header.chain,
    )
    .expect("prepare");
    let threads = std::env::var("ZHENG_VERIFY_THREADS").unwrap_or_else(|_| "all".into());
    // cold: the first verification of the process
    let p0 = perm::count();
    let t = Instant::now();
    let q = FinalProof::from_bytes(&bytes, &last).expect("parse");
    wrap::verify_final(&prep, &last, &q).expect("verify");
    let cold = ms(t);
    let p1 = perm::count();
    let runs: usize = env("ZHENG_RUNS", 21);
    let mut v = Vec::with_capacity(runs);
    let mut cpu = Vec::with_capacity(runs);
    let mut parse_cpu = Vec::with_capacity(runs);
    for _ in 0..runs {
        let t = Instant::now();
        let c = thread_cpu_ms();
        let q = FinalProof::from_bytes(&bytes, &last).expect("parse");
        parse_cpu.push(thread_cpu_ms() - c);
        wrap::verify_final(&prep, &last, &q).expect("verify");
        cpu.push(thread_cpu_ms() - c);
        v.push(ms(t));
    }
    v.sort_by(|a, b| a.partial_cmp(b).expect("times"));
    cpu.sort_by(|a, b| a.partial_cmp(b).expect("times"));
    parse_cpu.sort_by(|a, b| a.partial_cmp(b).expect("times"));
    let load = std::fs::read_to_string("/proc/loadavg").ok().or_else(|| {
        std::process::Command::new("sysctl")
            .args(["-n", "vm.loadavg"])
            .output()
            .ok()
            .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
    });
    println!(
        "{name}: final proof {} B (โ‰ค {} B over every transcript) ยท threads {threads} ยท verify cold {cold:.3} ms ยท warm median {:.3} ms (min {:.3}, max {:.3}, {runs} runs; main-thread CPU median {:.3} ms, of it parsing {:.3} ms) ยท permutations {} single + {} batched ยท load {}",
        bytes.len(),
        wrap::max_proof_bytes(&last),
        v[runs / 2],
        v[0],
        v[runs - 1],
        cpu[runs / 2],
        parse_cpu[runs / 2],
        p1.0 - p0.0,
        p1.1 - p0.1,
        load.unwrap_or_default()
    );
}

Homonyms

cyber/src/main.rs
cyb/cli/src/main.rs
soft3/nox/cli/main.rs
neural/trident/src/main.rs
cyb/optica/src/main.rs
soft3/glia/import/main.rs
cyberia/cyberia-my/src/main.rs
cyb/apps/src/main.rs
soft3/tru/cli/main.rs
neural/rune/cli/main.rs
warriors/trisha/cli/main.rs
warriors/joy/cli/main.rs
cyb/shell/src/main.rs
soft3/conformance/rs/src/main.rs
neural/eidos/cli/src/main.rs
soft3/radio/iroh-dns-server/src/main.rs
soft3/radio/iroh-relay/src/main.rs
soft3/radio/particle/src/main.rs
soft3/strata/cli/src/main.rs
soft3/zheng/cli/src/main.rs
neural/rs/pure-rust-check/src/main.rs
soft3/hemera/cli/src/main.rs
soft3/neuron/cli/src/main.rs
soft3/glia/run/cli/main.rs
neural/rs/link/src/main.rs
soft3/radio/radio-cli/src/main.rs
soft3/foculus/src/bin/main.rs
neural/rs/macho-linker/src/main.rs
soft3/bbg/cli/src/main.rs
neural/rs/rsc/src/main.rs
neural/rs/cli/src/main.rs
soft3/lens/cli/src/main.rs
soft3/cybergraph/cli/src/main.rs
warriors/erga/cli/src/main.rs
soft3/zheng/rs/examples/ivc_bench/main.rs
soft3/zheng/rs/examples/wrap_plan/main.rs
cyb/honeycrisp/acpu/src/probe/main.rs
soft3/strata/jali/cli/src/main.rs
soft3/zheng/rs/examples/wrap_keys/main.rs
soft3/mudra/audit/quantus-mldsa-crosscheck/src/main.rs
soft3/zheng/rs/examples/envelope_profiles/main.rs
soft3/zheng/specs/proto/zheng_spartan/main.rs
soft3/zheng/rs/examples/wrap_chain/main.rs
warriors/erga/rs/rtable-bench/src/main.rs
soft3/strata/kuro/cli/src/main.rs
soft3/strata/trop/cli/src/main.rs
soft3/zheng/rs/examples/wrap_flip/main.rs
soft3/zheng/rs/examples/wrap_bench/main.rs
warriors/trisha/tools/neptune-policy-oracle/src/main.rs
soft3/zheng/specs/proto/zheng_bug/main.rs
soft3/zheng/specs/proto/zheng_inner/main.rs
soft3/zheng/rs/examples/fast_path/main.rs
soft3/zheng/specs/proto/zheng_spartan_fixed/main.rs
warriors/erga/rs/mine-bench/src/main.rs
soft3/zheng/rs/examples/wrapped_sizes/main.rs
soft3/zheng/rs/examples/ivc_plan/main.rs
soft3/zheng/rs/examples/ivc_flip/main.rs
soft3/zheng/rs/examples/machine_bench/main.rs
soft3/zheng/rs/examples/succinct_bakeoff/main.rs
soft3/zheng/specs/proto/zheng_outer/main.rs
neural/inf/rs/cli/src/main.rs
cyb/wysm/crates/cli/src/main.rs
warriors/erga/rs/blake-bench/src/main.rs
soft3/strata/nebu/cli/src/main.rs
soft3/lytics/rs/agent/src/main.rs
cyb/honeycrisp/rane/src/probe/main.rs
neural/trident/silicon/src/bin/main.rs
soft3/strata/genies/cli/src/main.rs
soft3/lytics/rs/ingest/src/main.rs
soft3/radio/audit/2026-10-12-bao-bounded-proof/nostd/src/main.rs
soft3/radio/audit/2026-10-12-bao-proof-research/probe/src/main.rs
soft3/mudra/audit/signature-optimality/xnt-predicate-check/src/main.rs
cyb/honeycrisp/unimem/experiments/hyp_probe/src/main.rs
soft3/radio/audit/2026-10-12-bao-bounded-proof/fixture-probe/src/main.rs
soft3/radio/audit/2026-10-12-bao-bounded-proof/nostd-parent/src/main.rs
soft3/radio/audit/2026-10-12-bao-proof-research/primary-probe/src/main.rs
cyb/honeycrisp/unimem/experiments/iosurface_probe/src/main.rs
cyb/honeycrisp/unimem/experiments/dext_contiguous_alloc/client/src/main.rs
cyb/honeycrisp/unimem/experiments/dext_iosurface_pa/client/src/main.rs

Graph