//! Measure wrap proofs over recursive (IVC) proofs of nox runs.
//!
//! `cargo run --release -p zheng --example wrap_bench -- [fixture…]`
//!
//! IVC parameters as `ivc_bench` (`ZHENG_RATE`, `ZHENG_POW`, `ZHENG_STEP`).
//! `ZHENG_WRAP` lists the wrap levels, innermost first, as
//! `<log inv rate><i|f>[:<pow>[:<fold>]]` (`i`: inner mode, `f`: final
//! mode β€” only the last level), default `wrap::SHIPPED`. `ZHENG_IVC_DIR=<dir>`: store / reuse IVC proofs there
//! (`<fixture>.ivc`).

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

use std::time::Instant;
use zheng::execution::ExecutionNoun as N;
use zheng::machine;
use zheng::recursion::ivc;
use zheng::recursion::wrap::{self, FinalProof, Inner, Mode, WrapParams};

fn fixture(name: &str) -> Option<(N, 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)
}

fn levels(base: &lens::WhirParams) -> Vec<WrapParams> {
    let spec: String = env("ZHENG_WRAP", wrap::SHIPPED.to_string());
    spec.split(',')
        .map(|l| {
            let mut parts = l.split(':');
            let head = parts.next().expect("level");
            let (rate, mode) = head.split_at(head.len() - 1);
            let mut whir = *base;
            whir.log_inv_rate = rate.parse().expect("rate");
            if let Some(p) = parts.next() {
                whir.pow_bits = p.parse().expect("pow");
            }
            if let Some(k) = parts.next() {
                whir.folding_factor = k.parse().expect("fold");
            }
            let mode = if mode == "f" {
                Mode::Final
            } else {
                Mode::Inner
            };
            WrapParams { whir, n: 0, mode }
        })
        .collect()
}

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

fn main() {
    common::backend();
    let mut whir = zheng::execution::succinct::params_for(20);
    whir.log_inv_rate = env("ZHENG_RATE", ivc::SHIPPED_RATE);
    whir.pow_bits = env("ZHENG_POW", ivc::SHIPPED_POW);
    let n: u32 = env("ZHENG_STEP", 15);
    let args: Vec<String> = std::env::args().skip(1).collect();
    let names = if args.is_empty() {
        vec!["add.tri".into()]
    } else {
        args
    };
    let mut wbase = whir;
    wbase.pow_bits = env("ZHENG_WPOW", 24);
    let lv = levels(&wbase);
    let t0 = Instant::now();
    let ikey = ivc::key(&whir, n as usize).expect("key");
    eprintln!("ivc key: {:.0} ms", ms(t0));

    // keys derive level by level as the chain proves: a level's key is
    // kept only while it proves and while the next level verifies it
    let derive = |i: usize, prev: Option<&wrap::WrapKey>| -> wrap::WrapKey {
        let p = &lv[i];
        let t = Instant::now();
        let k = match prev {
            None => wrap::derive_key_ivc(*p, &ikey),
            Some(prev) => wrap::derive_key_wrap(*p, prev),
        }
        .expect("wrap key");
        let reads = k.wiring.as_ref().map_or(0, |w| w.reads);
        let rows = wrap::ledger(&k.params, &k.cfg, k.constraints, reads);
        let (wname, wbits) = rows.iter().fold(("", f64::INFINITY), |a, (nm, b)| {
            if *b < a.1 { (nm.as_str(), *b) } else { a }
        });
        eprintln!(
            "wrap {i} ledger: {} rows, weakest {wname} {wbits:.2} bits",
            rows.len()
        );
        assert!(wbits >= 128.0, "a ledger row below 128 bits");
        eprintln!(
            "wrap {i} key: circuit {} rows (gates {} bits {} blocks {}) β†’ 2^{} Β· rate 1/{} pow {} k {} Β· {:?} Β· bits {:.2} Β· {:.0} ms",
            k.rows,
            k.census[0],
            k.census[1],
            k.census[2],
            k.params.n,
            1u32 << p.whir.log_inv_rate,
            p.whir.pow_bits,
            p.whir.folding_factor,
            p.mode,
            k.cfg.security_bits(),
            ms(t)
        );
        k
    };
    if std::env::var_os("ZHENG_KEYS_ONLY").is_some() {
        let mut prev: Option<wrap::WrapKey> = None;
        for i in 0..lv.len() {
            prev = Some(derive(i, prev.as_ref()));
        }
        return;
    }
    for name in names {
        let (prog, input) = fixture(&name).unwrap_or_else(|| panic!("fixture {name}"));
        let run = machine::execute_exact(&prog, &input, 1 << 40, n).expect("run");
        let file = std::env::var("ZHENG_IVC_DIR")
            .ok()
            .map(|d| format!("{d}/{name}.ivc"));
        let stored = file.as_ref().and_then(|f| std::fs::read(f).ok());
        let proof = match stored {
            Some(bytes) => {
                eprintln!("{name}: IVC proof from {}", file.as_ref().unwrap());
                ivc::IvcProof::from_bytes(&bytes, |lr| ivc::key(&whir, lr as usize)).expect("parse")
            }
            None => {
                let t = Instant::now();
                let p = ivc::prove_run(&run, &whir).expect("prove");
                eprintln!("{name}: IVC prove {:.0} ms", ms(t));
                if let Some(f) = &file {
                    std::fs::write(f, p.to_bytes(&ikey)).expect("store");
                }
                p
            }
        };
        let ivc_bytes = proof.to_bytes(&ikey).len();
        let prep = ivc::prepare(
            &run.statement,
            &whir,
            proof.log_rows,
            proof.start,
            proof.segments,
            proof.chain,
        )
        .expect("prepare");
        let t = Instant::now();
        let pn = ivc::verify_claim(&prep, &proof).expect("ivc verify");
        println!(
            "{name}: cycles {} Β· {} steps Β· IVC proof {ivc_bytes} B Β· IVC verify {:.2} ms",
            run.statement.cycles,
            run.segments(),
            ms(t)
        );
        let mut wraps = Vec::new();
        let spec: String = env("ZHENG_WRAP", wrap::SHIPPED.to_string());
        let specs: Vec<&str> = spec.split(',').collect();
        let levels = lv.len();
        let mut prev_key: Option<wrap::WrapKey> = None;
        let mut last_key: Option<wrap::WrapKey> = None;
        common::prof_report("IVC and keys");
        for i in 0..levels {
            let key_i = derive(i, prev_key.as_ref());
            common::prof_report(&format!("wrap {i} key"));
            let k = &key_i;
            let t = Instant::now();
            // a stored proof of this level (the levels up to it named in the file)
            let wfile = std::env::var("ZHENG_IVC_DIR")
                .ok()
                .map(|d| format!("{d}/{name}.w{i}-{}", specs[..=i].join("_")));
            let stored = wfile.as_ref().and_then(|f| std::fs::read(f).ok());
            let (wp, x, tp) = match stored {
                Some(b) if i + 1 < levels => {
                    let wp = wrap::WrapProof::from_bytes(&b, k).expect("stored wrap");
                    let x = wrap::public_digest_native(&prep.publics, &pn).expect("digest");
                    eprintln!("{name}: wrap {i} from {}", wfile.as_ref().unwrap());
                    (wp, x, f64::NAN)
                }
                _ => {
                    let inner = if i == 0 {
                        Inner::Ivc {
                            key: &ikey,
                            proof: &proof,
                        }
                    } else {
                        Inner::Wrap {
                            key: prev_key.as_ref().expect("previous key"),
                            proof: &wraps[i - 1],
                        }
                    };
                    let (wp, x) = wrap::prove(k, &inner, &prep.publics, &pn).expect("wrap prove");
                    let tp = ms(t);
                    common::prof_report(&format!("wrap {i} prove"));
                    if let Some(f) = &wfile {
                        std::fs::write(f, wp.to_bytes(k)).expect("store wrap");
                    }
                    (wp, x, tp)
                }
            };
            let bytes = wp.to_bytes(k);
            let parsed = wrap::WrapProof::from_bytes(&bytes, k).expect("parse");
            assert_eq!(parsed, wp);
            let mut v = Vec::new();
            for _ in 0..5 {
                let t = Instant::now();
                wrap::verify_native(k, x, &parsed).expect("wrap verify");
                v.push(ms(t));
            }
            v.sort_by(|a, b| a.partial_cmp(b).unwrap());
            println!(
                "{name}: wrap {i}: proof {} B Β· prove {tp:.0} ms Β· verify median {:.2} ms",
                bytes.len(),
                v[2]
            );
            wraps.push(parsed);
            // the previous level's key is no longer needed
            if i + 1 == levels {
                last_key = Some(key_i);
            } else {
                prev_key = Some(key_i);
            }
        }
        drop(prev_key);
        let last = last_key.as_ref().expect("a level");
        let fp = FinalProof {
            log_rows: proof.log_rows,
            start: proof.start,
            segments: proof.segments,
            chain: proof.chain,
            pn: pn.clone(),
            wrap: wraps.pop().expect("a wrap"),
        };
        let bytes = fp.to_bytes(last);
        let fp = FinalProof::from_bytes(&bytes, last).expect("parse");
        let mut v = Vec::new();
        for _ in 0..5 {
            let t = Instant::now();
            wrap::verify_final(&prep, last, &fp).expect("final verify");
            v.push(ms(t));
        }
        v.sort_by(|a, b| a.partial_cmp(b).unwrap());
        let parts: Vec<String> = fp
            .sizes(last)
            .iter()
            .map(|(k, v)| format!("{k} {v}"))
            .collect();
        println!(
            "{name}: FINAL proof {} B ({}) Β· verify median {:.2} ms (statement prepared)",
            bytes.len(),
            parts.join(" Β· "),
            v[2]
        );
        if let Ok(d) = std::env::var("ZHENG_IVC_DIR") {
            std::fs::write(format!("{d}/{name}.final-{}", specs.join("_")), &bytes)
                .expect("store final");
        }
    }
}

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
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/wrap_verify/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