Skip to main content

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 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.
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.
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.

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