> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stateset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Set L2 Compliance Proofs

> Prove a policy held over data you never reveal — zero-knowledge proofs anchored on-chain.

# Set L2 Compliance Proofs

A compliance proof answers a question that inclusion proofs can't: **did this event satisfy a
policy?** — while the payload stays encrypted.

That matters when the thing you need to prove is about a value you can't share. A partner can
confirm every order stayed under an AML threshold without ever seeing an order amount.

## Proof metadata

Each batch commitment can carry proof metadata:

| Field                        | Meaning                                               |
| ---------------------------- | ----------------------------------------------------- |
| `proofHash` / `proof_hash`   | Hash of the proof artifact                            |
| `policyHash` / `policy_hash` | Hash of the policy definition                         |
| `allCompliant`               | Whether every event in the batch satisfied the policy |

<Note>
  Field names appear in two conventions — camelCase on the on-chain contract surface, snake\_case in
  the sequencer's own schema (`ves_compliance_proofs`). They're the same values; use whichever your
  side of the boundary exposes.
</Note>

The sequencer stores the fuller record: `proof_type` (e.g. `stark.compliance.v1`), `policy_id`
(e.g. `aml.threshold`), `policy_params` (e.g. `{"threshold": 10000}`), `public_inputs` in
canonical JCS form, `witness_commitment` as a Rescue hash of the private witness, and the proof
bytes themselves at roughly 100–200KB.

## Verification flow

**1. Fetch proof metadata from Set L2.** The on-chain record gives you `proofHash`, `policyHash`,
and `allCompliant`.

**2. Retrieve the proof artifact** from your prover storage. Proofs are large, so they're
referenced on-chain by hash rather than stored there.

**3. Verify the proof locally** against the policy inputs, using the STARK verifier.

**4. Compare hashes.** Hash the artifact you just verified and check it equals the on-chain
`proofHash`. Separately, check `policyHash` matches the policy you care about.

```
verify(proof, public_inputs)  ──▶ valid?
sha256(proof) == proofHash    ──▶ same proof that was anchored?
policyHash    == expected     ──▶ the policy you actually meant?

all three ──▶ the policy held.
```

<Warning>
  Step 4 is where verification usually goes wrong. A **valid proof of the wrong policy** is
  worthless — and a valid proof of the *right* policy that isn't the artifact anchored on-chain is
  equally worthless. Both hash comparisons are load-bearing, not belt-and-braces.
</Warning>

## What `allCompliant` does and doesn't tell you

`allCompliant` is a batch-level flag: every event in the batch satisfied the policy. A `false`
value tells you something in the batch didn't — it doesn't tell you which event. For per-event
detail you need the individual proof records, keyed by `event_id`.

## When to use them

| Situation                                   | Why a proof rather than a report                          |
| ------------------------------------------- | --------------------------------------------------------- |
| **Regulatory compliance** — AML, order caps | Provable to a regulator, not just asserted                |
| **Third-party verification**                | The partner checks it themselves; no audit access needed  |
| **Trust minimisation across vendors**       | Neither side has to expose data or trust the other's word |

## Related

* [Set L2 Verification](/set/stateset-set-l2-verification)
* [Set L2 Architecture](/set/stateset-set-l2-architecture) — the full proof record
* [Verified Decisions](/stateset-nsr-decisions) — the same principle for authorising actions
