arborist/docs/zk-frontier-bench.md
russell@unturf.com 0154191bd4
#000016 parked: ZK frontier-proof bench plan + wire protocol
Two arborist-side artifacts close the v7 § 16.1 hand-wave without
violating the language constraint (arborist stays pure-Python; ZK
toolchain lives in sibling repo arborist-zk-bench).

docs/zk-frontier-bench.md — bench plan + parked verdict
========================================================

Bench plan covers Plonky3 (or equivalent) circuit at three sizes
(256/1024/4096 affine), measurement targets (prover ms, proof
bytes, verify ms, peak memory), platform pair (Apple M3 + Linux
x86), acceptance thresholds (≤30s prover at 4096; ≤100KB proof;
≤100ms verify; ≤16GB peak).

Preliminary projection from published Plonky3/Halo2 numbers:

  size 256:   0.5–2 s prove  / 30–80 KB / 5–30 ms verify
  size 1024:  5–30 s prove   / 50–120 KB / 10–50 ms verify
  size 4096:  60–600 s prove / 100–300 KB / 30–200 ms verify
                              ↑ likely UNAFFORDABLE at frontier scale

Most-likely outcome: VIABLE at small scales (256/1024 — useful for
distillation models); UNAFFORDABLE at LLaMA-class hidden width
(4096).

Decision tree from real measurement:
  VIABLE       → commission ZK as v8 capability;
                 follow-up tickets for arborist [zk] extra,
                 governance_policy.frontier_proof_mode field,
                 hermes-side activation export.
  UNAFFORDABLE → park ZK; v7-Local stays v7's terminal
                 contribution; answer→model binding stays
                 out of scope.

docs/zk-wire-protocol.md — consumer-side schema
================================================

Specifies the wire format arborist consumes WHEN/IF ZK proofs
become available. The sibling repo emits proofs; arborist
validates schema + signature + delegates ZK verification to a
sibling-repo verifier binary. arborist itself NEVER runs the
prover or verifier — that's the language-constraint contract.

  - Artifact: arborist-zk-proof-v1 JSON with schema_version,
    proof_system, circuit_id, frontier_node, public_inputs,
    public_outputs, proof_bytes_b64, verifier_setup_id, issued_at,
    issuer_pubkey_ed25519, issuer_signature_ed25519.
  - Trigger: governance_policy.frontier_proof_mode ∈
    {"reveal" (default), "zk"}.
  - Binding: model_weights_zk_root + frontier_proof_circuit_id
    columns added to providence_cache (schema migration deferred
    to integration ticket).
  - Validation pipeline: schema check → recompute commitment
    sanity → Ed25519 signature check → delegate to sibling
    verifier → bind to audit chain.
  - Threat model: compromised prover, wire-format injection,
    proof replay, issuer-key compromise — each with its own
    mitigation.

Status closure
==============

Ticket flipped from "open · awaiting go/no-go" to "parked ·
bench-plan + wire-protocol landed 2026-05-09 (sibling-repo
measurement pending)." This is honest: arborist's side is done.
Sibling repo `arborist-zk-bench` (not yet built) produces the
real numbers; doc updates roll back here when measurements
arrive.

Result: the v7 § 16.1 hand-wave is replaced with explicit
thresholds + preliminary projection + ready consumer schema.
The hand-wave is closed even though the bench-question is
parked.
2026-05-09 15:05:08 -04:00

236 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ZK frontier-proof bench plan
**Verdict:** **PARKED · pending sibling-repo measurement.**
**Ticket:** #000016
**Authored:** 2026-05-09
This document is the arborist-side closure for #000016. It captures
the bench plan, acceptance thresholds, and a preliminary
projection. **Actual measurements live in the sibling repo
`arborist-zk-bench`** (not yet built), per #000016's language
constraint that arborist stays pure-Python and never gains a Rust
dependency.
When `arborist-zk-bench` produces real numbers, this doc gets
updated with the verdict line at top flipping from PARKED to
**VIABLE** or **UNAFFORDABLE**, and arborist consumes the wire
format spec'd in `docs/zk-wire-protocol.md`.
---
## 1. Why parked, not closed
#000016's closure criterion (§7) is measured numbers at three
circuit sizes (256, 1024, 4096) on commodity hardware. Producing
those numbers requires a working Plonky3 (or equivalent) circuit
in a Rust crate, plus prover + verifier binaries, plus
reproducible-build infrastructure. That belongs in
`arborist-zk-bench` per #000016 §1.21 and §4.1.
Building the sibling repo before there's a v8/v7-W demand for ZK
is speculative work. The ticket itself recommends "deferring until
a v8 / v7-W ticket creates real demand" (§7).
So: arborist produces the bench plan + the wire protocol +
preliminary projection, and parks measurement until demand
materializes. The hand-wave is replaced with an explicit
PARKED-with-thresholds artifact.
## 2. Bench plan (for the future sibling repo)
### 2.1 Circuit shape
One affine preactivation node, three sizes:
| Size | Inputs | Weights | Cost class |
|------|--------|---------|------------|
| 256 | 256 int64 | 256×256 int64 | small / unit-test scale |
| 1024 | 1024 int64 | 1024×1024 int64 | medium / typical-frontier scale |
| 4096 | 4096 int64 | 4096×4096 int64 | LLaMA-class hidden-width scale |
Per node:
- Inputs (witness, private): full activation vector A, full weight
matrix W.
- Inputs (public): `bias` B, subset-mask `S`, epsilon as
`(num, den)` integer pair.
- Outputs (public): SHA-256 commitments of W and A, commitment to
`(S, ε)`, boolean "ε-inequality holds".
- Constraints: range checks on int64 values, field-level GEMM,
L1-norm via sum of absolute values, final inequality check.
### 2.2 Measurement targets
- Wall-clock prover time (ms).
- Proof size (bytes).
- Verification time (ms).
- Memory peak during prover (MB).
- Setup time (ms) — one-shot per circuit.
### 2.3 Platform pair
- **Apple Silicon** — M3 Max or equivalent (representative dev
machine).
- **Linux x86_64** — generic cloud commodity (representative server).
Run twice per platform; report median + range.
### 2.4 Bench harness sketch
`arborist-zk-bench/bench/zk_frontier_bench.py` (in the sibling
repo, not here):
```python
sizes = [256, 1024, 4096]
seeds = [42, 137]
for size in sizes:
for seed in seeds:
rng = numpy.random.RandomState(seed)
A = rng.randint(-(2**31), 2**31, size, dtype=numpy.int64)
W = rng.randint(-(2**31), 2**31, (size, size),
dtype=numpy.int64)
B = rng.randint(-(2**31), 2**31, size, dtype=numpy.int64)
S = rng.choice([0, 1], size).astype(numpy.int64)
eps = (1, 100) # 1% L1 error budget
t = time.monotonic()
proof = prove_affine(W, A, B, S, eps)
prove_ms = (time.monotonic() - t) * 1000
t = time.monotonic()
ok = verify_affine(proof, public_inputs(W, A, B, S, eps))
verify_ms = (time.monotonic() - t) * 1000
record({
"size": size, "seed": seed, "platform": platform_id(),
"prove_ms": prove_ms, "verify_ms": verify_ms,
"proof_bytes": len(proof), "memory_peak_mb": ...,
"ok": ok,
})
```
### 2.5 Acceptance thresholds
For ZK to flip from PARKED to VIABLE in this bench:
| Metric | Threshold (size 4096) |
|---------------------|-------------------------------|
| Prover wall-clock | ≤ 30 seconds |
| Proof size | ≤ 100 KB |
| Verifier wall-clock | ≤ 100 ms |
| Memory peak | ≤ 16 GB |
| Verification result | `ok == True` on all seeds |
**All thresholds must pass.** Single-metric failure → PARKED
with the failing metric named.
## 3. Preliminary projection (no measurement)
Lower-confidence estimates from published Plonky3 / Halo2
benchmarks (2024-2025 era), to inform expectations BEFORE
real bench runs:
| Size | Prove (projected) | Proof bytes | Verify | Confidence |
|------|-------------------|-------------|--------|------------|
| 256 | 0.52 s | 3080 KB | 530 ms | Medium |
| 1024 | 530 s | 50120 KB | 1050 ms | LowMedium |
| 4096 | 60600 s | 100300 KB | 30200 ms | Low |
Sources: Plonky3 benchmark posts, Halo2 GEMM-circuit reports.
**These are not measurements**; they're estimates from related
circuits. Real numbers will diverge.
**Most-likely outcome based on these estimates**: at size 4096,
prover time exceeds the 30-second threshold; ZK stays PARKED for
the LLM-frontier scale. ZK might be VIABLE at the 256/1024 scales
relevant to small distillation models.
## 4. Decision tree from measurement
```
arborist-zk-bench measurement
┌───────────┴────────────┐
│ │
VIABLE UNAFFORDABLE
│ │
│ │
commission ZK as v8 capability park ZK; v7-Local stays
open follow-up tickets: v7's terminal contribution;
- arborist [zk] extra wiring v7-Local proofs require
(wire-format consumer only) activation publication;
- governance_policy.frontier_ answer→model binding stays
proof_mode policy field out of scope
- v8 ForkScore: ZK availability
as a fork-quality signal
- hermes-side circuit-friendly
activation export
```
Either branch closes #000016: VIABLE → ZK lands; PARKED →
documented constraint, future ticket if Plonky3 evolves.
## 5. What arborist does NOT need to do
Per #000016 §1.21 / §4.1 / §7 language constraints:
- **No Rust code in arborist.** `arborist/zk/` reserved as a
future namespace for the wire-format consumer (pure-Python
schema validator); no prover, no verifier.
- **No Plonky3 dependency in `pyproject.toml`.** `[zk]` extra
(when it lands) pulls a JSON-schema validator + a binary
protocol parser, never the prover binary.
- **No circuit code in arborist.** `circuits/affine_preact.rs`
lives in the sibling repo.
- **No bench harness in arborist.** `bench/zk_frontier_bench.py`
lives in the sibling repo. arborist's `bench/` stays pure-
Python deterministic-fixture work.
## 6. What the wire protocol looks like
Detailed spec in `docs/zk-wire-protocol.md` (sibling document).
Brief summary:
- Sibling repo emits proofs as canonical-byte JSON conforming to
a versioned schema.
- arborist consumes proofs at the providence-record write
boundary, optionally adding a `model_weights_zk_root` field to
the v9.8 cache_key (governance-hash-folded).
- arborist's verifier helper validates schema + checks SHA-256
binding against the providence chain. It does NOT run the ZK
verifier — that's also in the sibling repo or in a separate
trusted binary.
## 7. Cross-references
- #000016 — this ticket (parked).
- #000018 — adversarial soft-hash analysis (closed); the M3
mitigation there ("drop the anchor") is the only existing
defense if ZK proves UNAFFORDABLE and v7-Local activation
publication is also out of scope.
- #000013 — v7-W spatial-temporal substrate (closed); v7-W
inherits the ZK question — world-state observations are ALSO
privacy-sensitive, and the same VIABLE/PARKED decision tree
applies.
- v7 § 16.1 — the original "swap SHA-256 → Poseidon" hand-wave
this doc replaces.
## 8. Status / closure
**This document closes the arborist-side hand-wave.** The
sibling repo's measurement work remains open as a separate
project; #000016 is parked rather than fully closed because the
verdict line awaits real numbers.
When `arborist-zk-bench` produces measurements:
1. Update §3 with measured numbers, replacing the projection.
2. Flip the verdict line at top of this doc: PARKED →
VIABLE or UNAFFORDABLE.
3. Open follow-up tickets per §4's decision tree.
4. Update #000016 ticket status: parked → closed (verdict
recorded).
Until then: this is the artifact. The hand-wave from v7 § 16.1
is replaced with explicit thresholds + preliminary projection +
parked-status with named open work.