# Zero-knowledge proofs
Source: https://docs.treeship.dev/concepts/zero-knowledge

> Four layers of proof -- signatures, Merkle, Circom, RISC Zero -- each answering different questions about your agent workflows.

Treeship stacks four ZK-adjacent layers. Each one answers a different question, and each one has different performance characteristics. You pick the layers you need; Ed25519 signatures are always on.

<Callout type="warn">
  **Current status (2026-07, ZK layer under rebuild).** Only the first two
  layers (Ed25519 signatures and the Merkle audit log) ship enabled by default,
  and they are the entire trust story of every release binary. The ZK layers 3
  and 4 live behind the `--features zk` build flag, are excluded from release
  binaries, and are being rebuilt statement-first. A July 2026 internal audit
  applied cryptographer-level scrutiny to this layer and it did not pass; the
  findings and the rebuild are in
  [the ZK verification spec](https://github.com/treeship/treeship/blob/main/docs/specs/private-verification.md).

  * **Layer 1 (Ed25519 signatures):** stable, always on.
  * **Layer 2 (Merkle audit log):** stable, always on.
  * **Layer 3 (Circom/Groth16):** **quarantined.** The path generated proving
    keys locally with no real trusted-setup ceremony, which makes it forgeable
    by construction, and its policy constraint was unsatisfiable. `treeship
    prove` / `verify-proof` fail closed with a pointer to the rebuild. The
    `.circom` sources are retained as design references; a sound path returns
    only under a real ceremony or a transparent proof system.
  * **Layer 4 (RISC Zero zkVM):** the transparent path (STARK-based, no trusted
    setup) that re-verifies signatures and chain linkage inside the guest. This
    is the primary non-interactive path in the rebuild; it is being hardened
    (in-guest artifact-id re-derivation, payload-extracted linkage, nonce
    binding, abort-on-violation) before it is unhidden.
  * **TLSNotary:** not implemented. A designed direction for external-transcript
    capture, not a current capability.

  Browser ZK verification is part of the rebuild target, not a current shipping
  capability: the published `@treeship/core-wasm` build does not enable the ZK
  feature. The always-on browser verification of signatures and Merkle proofs at
  `treeship.dev/verify` is real today; browser verification of ZK proofs is not.
</Callout>

## The four layers

### Layer 1: Ed25519 signatures (always on)

Every artifact is signed the moment it's created. This is not optional and adds no measurable latency.

**What it proves:** this artifact was created by this Treeship and has not been modified since.

**What it does not prove:** anything about the artifact's contents, timing relative to other artifacts, or policy compliance.

### Layer 2: Merkle audit log (instant)

Every artifact hash is appended to a local Merkle tree. The tree is append-only and tamper-evident. Generating a Merkle inclusion proof is instant because it's a tree traversal, not a computation.

**What it proves:** this artifact existed at this position in the log, and no artifacts before it have been removed or reordered.

**What it does not prove:** anything about what the artifact contains or whether it complied with policy.

### Layer 3: Circom/Groth16 (quarantined, under rebuild)

The intended shape of this layer is a circuit that proves an action conforms
to a policy without revealing the action or the policy set. The implementation
shipped behind `--features zk` did not achieve that: it generated proving keys
with no real trusted-setup ceremony (forgeable by construction), left the
artifact binding unconstrained, and used a placeholder hash that made the
policy constraint unsatisfiable.

The path is therefore **quarantined**. `treeship prove` and `verify-proof`
fail closed with a pointer to the rebuild rather than produce a proof that
looks valid but establishes almost nothing. The rebuild (see
[the ZK verification spec](https://github.com/treeship/treeship/blob/main/docs/specs/private-verification.md))
binds the committed value inside the signed artifact so a proof is meaningless
unless the classical signature verifies, states each proof as a formal
statement the verifier's own policy pins, and reaches for either a real
multi-party ceremony or a transparent proof system before this layer returns
to a release path.

### Layer 4: RISC Zero (minutes, per-session, background)

A RISC Zero proof covers an entire session: a sequence of artifacts, their Merkle positions, and the session's causal chain. This is the most expensive layer and is intended to run in the background.

**What it proves:** the session chain is intact and every artifact's Ed25519 signature verifies against the same public key, all checked inside the zkVM. The verifier learns the chain is well-formed without re-running every per-artifact check itself.

**What it does not prove today:** the per-artifact Circom policy proofs are
not currently re-verified inside the RISC Zero guest. Composing the two layers
end-to-end is roadmap work, not a property of the v0.10.4 receipt.

**What it does not prove at all:** anything about network interactions or external API responses (that's TLSNotary's job, and TLSNotary is not yet implemented in this repo).

**Performance:** local CPU proving takes several minutes per session and is
expected to run in the background -- the daemon kicks off chain proofs
asynchronously. Verification of a finished receipt is well under a second.
Bonsai hosted proving would be faster but is not wired yet (see status callout
at the top of this page).

**Requirements today:** `--features zk` build flag. The RISC Zero zkVM links
in via `treeship-zk-risc0`. The image ID is embedded at compile time, so
verification is fully offline once a receipt exists.

## How layers compose

Each layer builds on the ones below it. A fully-proved session looks like this:

```json
{
  "artifact": {
    "content_hash": "sha256:abc123...",
    "ed25519_signature": "sig:...",
    "merkle_proof": {
      "root": "0xdef...",
      "path": ["0x1a...", "0x2b...", "0x3c..."],
      "index": 42
    },
    "circom_proof": {
      "policy": "budget_under_10k",
      "proof": "base64:...",
      "public_signals": ["1"]
    }
  },
  "session_proof": {
    "risc_zero_receipt": "base64:...",
    "session_id": "session:...",
    "artifact_count": 47
  }
}
```

You don't need all layers for every use case. A simple audit trail needs only layers 1 and 2. Policy compliance adds layer 3. Full session integrity adds layer 4.

## Verification commands

Verify an artifact's signature (always available):

```bash
treeship verify artifact.json
```

Verify a Merkle inclusion proof (always available):

```bash
treeship verify --merkle artifact.json
```

Verify a Circom policy proof (requires `--features zk` build and `snarkjs`
installed on PATH):

```bash
treeship verify-proof art_xxx.policy-checker.zkproof
```

Generate a Circom proof for a single artifact (same build requirements as
above, plus `circom` and `node` on PATH):

```bash
treeship prove --circuit policy-checker --artifact art_xxx --policy ./policy.json
```

Prove a full session chain via RISC Zero (requires `--features zk`, runs for
several minutes on CPU):

```bash
treeship prove-chain <session_id>
```

## TLSNotary (roadmap)

TLSNotary would prove that a specific HTTPS request and response occurred between an agent and an external API. This is intended for commerce workflows where you need to prove that a payment API returned a specific confirmation, or that a price quote was real.

TLSNotary is **not yet implemented in Treeship.** There is no notary integration in `packages/` today; the section here describes the intended shape, not shipping code.

<Callout type="info">
  TLSNotary is scoped to commerce workflows and is roadmap only. Most agent attestation use cases do not need it.
</Callout>

## Status

| Layer                          | Status            | Notes                                                                                                                                                                                                   |
| ------------------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Ed25519 signatures             | Stable, always on | Since v0.1.0                                                                                                                                                                                            |
| Merkle audit log               | Stable, always on | Since v0.2.0                                                                                                                                                                                            |
| Circom/Groth16 proofs          | Quarantined       | Forgeable as implemented (no real trusted setup) and unsatisfiable policy constraint. `prove` / `verify-proof` fail closed; `.circom` sources kept as design references. Being rebuilt statement-first. |
| RISC Zero chain proofs (local) | Under rebuild     | `--features zk` build, excluded from release binaries. Local CPU proving via `risc0-zkvm`. The transparent, no-trusted-setup path being hardened as the primary non-interactive proof path.             |
| RISC Zero Bonsai (hosted)      | Roadmap           | `BONSAI_API_KEY` is detected but unused; logs "coming in v0.6.0" and falls back to the local prover.                                                                                                    |
| TLSNotary                      | Roadmap           | Not implemented in this repo.                                                                                                                                                                           |

## Build flag

ZK layers (Circom and RISC Zero) are behind a feature flag to keep the default binary small. To build with ZK support:

```bash
cargo build --features zk
```

The Ed25519 and Merkle layers are always included.

## Trust model

Every ZK layer in Treeship is designed to work locally without contacting a Treeship-operated service to produce or verify a proof.

**Fully local, no external trust:**

* **Ed25519 signatures** -- your key, your machine.
* **Merkle proofs** -- your key, your machine, self-contained proof file.
* **Circom/Groth16 (quarantined)** -- the previous path shelled out to local
  `snarkjs` and generated proving keys locally with no real trusted-setup
  ceremony, which makes it forgeable by construction. It is quarantined and
  fails closed. The rebuild binds the proven value inside the signed artifact
  and reaches for a real ceremony or a transparent system before this layer
  returns.
* **RISC Zero chain proving and verification** -- local zkVM via the
  `risc0-zkvm` crate, transparent (no trusted setup). The image ID is embedded
  at compile time, so a finished receipt is verified offline. Under rebuild:
  the guest is being hardened to re-derive artifact ids and extract chain
  linkage from the signed bytes, and CLI verification is being wired.

**Trusted setup:**

* The quarantined Groth16 path had **no real phase-2 ceremony** -- proving keys
  were generated locally with zero contributions, which is exactly why it is
  quarantined. Any future succinct path either uses a transparent system (no
  setup) or relies on a named, real multi-party ceremony, and says which.

**Roadmap (not opt-in today):**

* **RISC Zero Bonsai** would be a hosted prover for chain proofs. Setting
  `BONSAI_API_KEY` is detected by the prover but is not yet wired -- the code
  logs "Bonsai integration is coming in v0.6.0" and runs the local prover
  instead. Track this as roadmap, not as an available opt-in.

**Verify offline with no server trust (requires `--features zk` build and
`snarkjs` on PATH):**

```bash
treeship verify-proof art_xxx.policy-checker.zkproof
```

This works air-gapped today via the local `snarkjs` verifier. The browser
verifier at `treeship.dev/verify` runs the equivalent Groth16 pairing check
in pure Rust WASM with no shell-out and no network call -- Hub cannot forge a
passing result. Once the in-repo `ark-circom` path lands, the CLI will offer
the same pure-Rust verification with no toolchain dependency.