//! Verify the outermost (final) proof of a fixture from the proofs
//! `wrap_bench` stored, time it, and scan every bit flip of its bytes
//! (each flipped proof parsed and verified; reports how many decoded and
//! how many were accepted โ€” must be 0).
//!
//! `wrap_flip <fixture>` with `ZHENG_IVC_DIR` (the stored proofs) and
//! `ZHENG_WRAP` (the levels, as `wrap_bench`). `ZHENG_FLIP=0` skips the
//! scan; `ZHENG_STRIDE=<k>` scans every k-th bit.

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

use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;
use zheng::machine;
use zheng::recursion::ivc;
use zheng::recursion::wrap::{self, FinalProof, Mode, WrapParams};

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 main() {
    let name: String = std::env::args().nth(1).unwrap_or_else(|| "add.tri".into());
    let (prog, input) = match name.as_str() {
        "add.tri" => (common::parse(common::ADD), vec![7u64, 5]),
        "hash.tri" => (common::parse(common::HASH), vec![7]),
        "merkle-32" => {
            let root =
                machine::execute(&common::merkle_program(32, None), &[5], 1 << 40).expect("run");
            let r = machine::statement::parse(&root.statement.output).expect("root");
            (common::merkle_program(32, Some(&r)), vec![5])
        }
        t if t.starts_with("tree-") => (common::tree_program(t[5..].parse().unwrap()), vec![3]),
        t if t.starts_with("rec-") => (common::rec_program(), vec![t[4..].parse().unwrap()]),
        other => panic!("fixture {other}"),
    };
    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 t = Instant::now();
    let mut keys = Vec::new();
    for l in &specs {
        let mut parts = l.split(':');
        let head = parts.next().expect("level");
        let (rate, mode) = head.split_at(head.len() - 1);
        // wrap levels grind 24 bits unless named (the IVC's own budget,
        // `ivc::SHIPPED_POW`, is not theirs: as `wrap_bench`, `wrap_verify`)
        let mut w = whir;
        w.pow_bits = 24;
        w.log_inv_rate = rate.parse().expect("rate");
        if let Some(p) = parts.next() {
            w.pow_bits = p.parse().expect("pow");
        }
        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);
    }
    eprintln!("keys {:.0} s", t.elapsed().as_secs_f64());
    let last = keys.last().expect("a level");
    let ivc_bytes = std::fs::read(format!("{dir}/{name}.ivc")).expect("stored IVC proof");
    let proof =
        ivc::IvcProof::from_bytes(&ivc_bytes, |lr| ivc::key(&whir, lr as usize)).expect("parse");
    let prep = ivc::prepare(
        &run.statement,
        &whir,
        proof.log_rows,
        proof.start,
        proof.segments,
        proof.chain,
    )
    .expect("prepare");
    let pn = ivc::verify_claim(&prep, &proof).expect("ivc");
    let wb = std::fs::read(format!(
        "{dir}/{name}.w{}-{}",
        specs.len() - 1,
        specs.join("_")
    ))
    .expect("stored final wrap");
    let wp = wrap::WrapProof::from_bytes(&wb, last).expect("parse wrap");
    let fp = FinalProof {
        log_rows: proof.log_rows,
        start: proof.start,
        segments: proof.segments,
        chain: proof.chain,
        pn,
        wrap: wp,
    };
    let bytes = fp.to_bytes(last);
    std::fs::write(format!("{dir}/{name}.final-{}", specs.join("_")), &bytes).expect("store final");
    let parse = |b: &[u8]| FinalProof::from_bytes(b, last);
    wrap::verify_statement(&run.statement, &whir, last, &parse(&bytes).expect("parses"))
        .expect("verifies");
    // verify time: the statement prepared once, and from the statement
    let mut v = Vec::new();
    let mut vs = Vec::new();
    for _ in 0..11 {
        let t = Instant::now();
        let q = parse(&bytes).expect("parse");
        wrap::verify_final(&prep, last, &q).expect("verify");
        v.push(t.elapsed().as_secs_f64() * 1e3);
        let t = Instant::now();
        wrap::verify_statement(&run.statement, &whir, last, &q).expect("verify");
        vs.push(t.elapsed().as_secs_f64() * 1e3);
    }
    v.sort_by(|a, b| a.partial_cmp(b).unwrap());
    vs.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), {:.2} ms (from the statement)",
        bytes.len(),
        parts.join(" ยท "),
        v[5],
        vs[5]
    );
    if std::env::var("ZHENG_FLIP").is_ok_and(|v| v == "0") {
        return;
    }
    let stride: usize = env("ZHENG_STRIDE", 1);
    let bits = bytes.len() * 8;
    let next = AtomicUsize::new(0);
    let (flips, decoded, accepted) = (
        AtomicUsize::new(0),
        AtomicUsize::new(0),
        AtomicUsize::new(0),
    );
    let t0 = Instant::now();
    let threads = std::thread::available_parallelism()
        .map_or(1, |n| n.get())
        .min(16);
    std::thread::scope(|s| {
        for _ in 0..threads {
            s.spawn(|| {
                let mut buf = bytes.clone();
                loop {
                    let k = next.fetch_add(1, Ordering::Relaxed) * stride;
                    if k >= bits {
                        break;
                    }
                    buf[k / 8] ^= 1 << (k % 8);
                    flips.fetch_add(1, Ordering::Relaxed);
                    if let Ok(q) = parse(&buf) {
                        decoded.fetch_add(1, Ordering::Relaxed);
                        let ok = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                            let same = prep.header == (q.log_rows, q.start, q.segments, q.chain);
                            if same {
                                wrap::verify_final(&prep, last, &q).is_ok()
                            } else {
                                wrap::verify_statement(&run.statement, &whir, last, &q).is_ok()
                            }
                        }));
                        match ok {
                            Ok(false) => {}
                            Ok(true) => {
                                accepted.fetch_add(1, Ordering::Relaxed);
                                eprintln!("ACCEPTED flip of bit {k}");
                            }
                            Err(_) => eprintln!("PANIC on flip of bit {k}"),
                        }
                    }
                    buf[k / 8] ^= 1 << (k % 8);
                    let f = flips.load(Ordering::Relaxed);
                    if f % 50_000 == 0 {
                        eprintln!("  {f} flips ยท {:.0} s", t0.elapsed().as_secs_f64());
                    }
                }
            });
        }
    });
    println!(
        "bit-flip scan: {} bytes ยท {} flips (stride {stride}) ยท {} decoded ยท {} accepted ยท {:.0} s",
        bytes.len(),
        flips.load(Ordering::Relaxed),
        decoded.load(Ordering::Relaxed),
        accepted.load(Ordering::Relaxed),
        t0.elapsed().as_secs_f64()
    );
}

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