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.
11 KiB
ZK wire protocol — arborist consumer schema
Companion to: docs/zk-frontier-bench.md (the bench plan +
parked verdict for #000016).
Status: draft v0, 2026-05-09.
This document specifies the wire format arborist consumes
when ZK proofs become available. The toolchain producing those
proofs lives in a sibling repo (arborist-zk-bench); arborist
itself stays pure-Python and never gains a Rust dependency. The
language constraint from #000016 §1.21 is hard — this protocol
is the bridge.
1. Scope
What this protocol covers:
- Canonical-byte JSON schema for one frontier-proof artifact.
- The minimum binding info arborist needs to fold a proof into the v9.8 audit chain.
- Versioning + forward-compatibility rules.
- The trigger condition (
governance_policy.frontier_proof_mode) for when arborist asks for a proof.
What this protocol does NOT cover:
- The prover or verifier itself (sibling repo).
- Plonky3 / Halo2 / Groth16 internals.
- Circuit construction.
- ZK-side privacy analysis.
2. Trigger condition
ZK proofs are opt-in via a governance-policy flag:
governance_policy["frontier_proof_mode"] = "zk" # opt-in
governance_policy["frontier_proof_mode"] = "reveal" # default
The flag folds into governance_policy_hash so the v9.8
8-dim cache_key reflects which mode produced any given record.
Switching modes invalidates prior records on lookup.
When mode == "zk", arborist's QA path (or any caller producing
a frontier-proof binding) calls out to the sibling repo, gets
back a wire-protocol artifact, validates it, and folds the proof
root into the providence record.
When mode == "reveal" (default), no ZK call happens; activations
are revealed locally per v7-Local.
3. Artifact shape (proof_v1.json)
{
"schema_version": "arborist-zk-proof-v1",
"proof_system": "plonky3 | halo2 | groth16 | stark",
"proof_system_version": "<vendor-specific git sha or release tag>",
"circuit_id": "<sha256 of canonical circuit definition>",
"circuit_kind": "affine_preact" ,
"frontier_node": {
"node_kind": "affine_preact",
"size": 4096,
"epsilon_num": 1,
"epsilon_den": 100
},
"public_inputs": {
"weights_commitment_sha256": "<64-hex>",
"activations_commitment_sha256": "<64-hex>",
"subset_mask_sha256": "<64-hex>",
"epsilon_pair": [1, 100]
},
"public_outputs": {
"epsilon_inequality_holds": true
},
"proof_bytes_b64": "<standard-base64 of the raw proof bytes>",
"verifier_setup_id": "<sha256 of the verifier's KZG/CRS or FRI setup>",
"issued_at": "<ISO-8601 UTC>",
"issuer_pubkey_ed25519": "<32-byte hex>",
"issuer_signature_ed25519": "<64-byte hex over canonical-bytes(this object)>"
}
3.1 Field-by-field
schema_version— fixed string"arborist-zk-proof-v1". Arborist rejects any artifact with an unknown schema_version; v2 onward bumps the validator.proof_system— vendor name. Determines which deserializer (in the sibling repo) parsesproof_bytes_b64.circuit_id— sha256 of the canonical circuit definition. Two artifacts produced by the same circuit have the samecircuit_id; this is what arborist binds to in the audit chain rather than the raw proof bytes (which vary per witness).frontier_node— describes WHICH node was proved. arborist matches this against the model snapshot's frontier-node enumeration to confirm the proof's scope.public_inputs— the inputs the verifier checks. arborist recomputesweights_commitment_sha256from its own copy of the weight bytes,activations_commitment_sha256from the published activation chain, and confirms equality before consuming the proof.public_outputs.epsilon_inequality_holds— the boolean the prover claims is true, which the verifier checks.proof_bytes_b64— the actual proof. Arborist does NOT parse this; it forwards to the sibling-repo verifier (or a separate trusted binary).verifier_setup_id— sha256 of the verifier's setup (KZG CRS / FRI parameters). Pinned per-circuit; rotation is a circuit bump, which changescircuit_id.issued_at— wall-clock UTC, sanity-check only.issuer_pubkey_ed25519+issuer_signature_ed25519— the prover signs the canonical-byte form of this artifact (with the signature field omitted) so arborist can verify provenance of the proof artifact independently of the ZK proof itself.
3.2 Canonical-byte form
For SHA-256 commitment + signature purposes, the canonical bytes
of this artifact are: JSON with sorted keys, separators=(",",":"),
no whitespace, UTF-8 encoded, EXCLUDING the
issuer_signature_ed25519 field. Standard JSON-canonicalization
the rest of arborist uses (_canonical_json in arborist.qa.dag).
4. Binding into the v9.8 audit chain
When arborist consumes a valid proof, it folds the proof's identity into the providence record:
ALTER TABLE providence_cache ADD COLUMN model_weights_zk_root TEXT;
ALTER TABLE providence_cache ADD COLUMN frontier_proof_circuit_id TEXT;
(Schema migration would land at the integration ticket, not this doc. Sketched here so the binding shape is explicit.)
The new fields:
model_weights_zk_root— SHA-256 of the artifact's canonical bytes (excluding signature). Becomes part of the audit-event body forprovidence_queryrows produced underfrontier_proof_mode = "zk".frontier_proof_circuit_id— the artifact'scircuit_id, exposed for cross-record queries ("show me all rows that used circuit X").
governance_policy_hash folds in the frontier_proof_mode field
so cache_key changes when the mode flips. Records produced under
reveal and zk for the same question land at distinct cache_keys.
5. Validation pipeline (arborist side)
When arborist receives an artifact:
def validate_zk_proof(artifact: dict) -> None:
"""Pure-Python validation. NEVER runs the ZK verifier;
delegates that to the sibling-repo verifier binary."""
# 1. Schema check.
if artifact.get("schema_version") != "arborist-zk-proof-v1":
raise PiStarError("unknown schema_version")
for required in (
"proof_system", "circuit_id", "circuit_kind",
"frontier_node", "public_inputs", "public_outputs",
"proof_bytes_b64", "verifier_setup_id", "issued_at",
"issuer_pubkey_ed25519", "issuer_signature_ed25519",
):
if required not in artifact:
raise PiStarError(f"missing field: {required!r}")
# 2. Recompute commitment sanity.
pub = artifact["public_inputs"]
if not _is_hex_64(pub["weights_commitment_sha256"]):
raise PiStarError("bad weights commitment")
# … similar for activations + subset_mask
# 3. Issuer signature check (Ed25519).
canonical = _canonical_json_no_signature(artifact)
if not _ed25519_verify(
artifact["issuer_pubkey_ed25519"],
canonical,
artifact["issuer_signature_ed25519"],
):
raise PiStarError("issuer signature failed")
# 4. ZK verification — DELEGATED.
# This is where arborist hands off to the sibling-repo verifier
# binary or a trusted external process. Arborist itself does
# NOT run the ZK verifier.
if not _delegate_zk_verify(artifact):
raise PiStarError("zk verifier rejected proof")
# 5. Bind into audit chain.
# Caller adds model_weights_zk_root + frontier_proof_circuit_id
# to the providence row.
_delegate_zk_verify is the wire-protocol's other side: arborist
either spawns a subprocess running the sibling verifier OR posts
to a known endpoint. Either way, arborist sees only the boolean
verdict.
6. Versioning + forward compatibility
- Schema bumps require a new
schema_versionstring. v1 → v2 drops a field, adds one, or changes semantics. - arborist supports a fixed set of schema versions at any time; unknown versions are rejected loudly.
- The sibling repo's git sha pins which prover/verifier produced the proof. arborist surfaces this in the audit body so a future replay knows which sibling-repo version to invoke.
circuit_idis content-addressed; circuit changes always produce a newcircuit_id, never reuse.
7. Threat model
- Compromised sibling-repo prover. A compromised prover
can forge
epsilon_inequality_holds = trueonly if it can forge the proof bytes themselves AND the issuer signature. Arborist's defenses: Ed25519 signature check on the artifact (step 3), delegated verifier invocation (step 4). The verifier is the trust anchor; if it's compromised, the chain breaks upstream of arborist. - Wire-format injection. Adversary submits malformed JSON hoping to bypass schema validation. Mitigation: every required field checked; type checks on commitment hex; signature check before delegating.
- Proof replay. Adversary replays a valid proof for a
different question. Mitigation:
circuit_idandfrontier_nodeare tied to the model snapshot's frontier enumeration; arborist binds the proof to a specific (cache_key, frontier_node) pair before storage. Replay against a different cache_key fails the binding check. - Issuer-key compromise. Adversary obtains the prover's signing key. Mitigation: keys rotate per major-version; arborist maintains a published list of trusted issuer keys, rejects artifacts signed under revoked keys.
8. What arborist gains over time
If ZK turns out VIABLE per the bench (docs/zk-frontier-bench.md),
arborist gains:
- An
[zk]extra inpyproject.tomlpulling JSON-schema validator + Ed25519 verification (NOT the prover/verifier binary). - An
arborist/zk/wire.pymodule implementingvalidate_zk_proof()plus_delegate_zk_verify()calling the sibling-repo verifier. - A schema migration adding
model_weights_zk_rootandfrontier_proof_circuit_idcolumns toprovidence_cache, plus a CHECK constraint update. - A new policy field
frontier_proof_modefolded intogovernance_policy_hash. - New audit-event type
providence_zk_prooffor the binding event.
If ZK stays UNAFFORDABLE, this protocol stays as a documented artifact — when ZK matures (hardware, libraries, theory), the arborist side is ready.
9. Cross-references
docs/zk-frontier-bench.md— bench plan + parked verdict.- #000016 — the ticket this closes the arborist-side hand-wave for.
- #000018 — soft-hash covert-channel analysis; the M3 mitigation there is the only existing defense if ZK proves UNAFFORDABLE.
- #000013 — v7-W spatial-temporal substrate; world-state observations have the same privacy concerns and inherit this protocol.
- v7 § 16.1 — the original "swap SHA-256 → Poseidon" hand-wave.
10. Status
Draft v0. Becomes the consumer-side schema spec when the sibling repo lands measurements + the validator. Until then: this is the contract arborist commits to honor on the receive side.