Executive Summary
JIL Sovereign's zero-knowledge verifier registry centralizes every verifier contract the platform's compliance, KYC and biometric-uniqueness circuits rely on behind a single lookup surface, keyed jointly by circuit type and version number. Nine native circuit types are modeled - biometric uniqueness, biometric liveness, and six KYC/AML circuit categories - each of which can be independently upgraded, deactivated, or migrated to a different proof system without touching any of the contracts that call into it.
Because a circuit's active version advances forward monotonically while every prior version's record is preserved rather than deleted, a caller can either dispatch to "whatever is current" or explicitly pin verification to a specific historical version - letting proofs generated months earlier against a now-superseded circuit remain verifiable indefinitely, even after the circuit has moved on to a new proof system entirely.
Problem Statement
Zero-knowledge circuits and their trusted-setup artifacts age. A discovered bug, a parameter upgrade, or a deliberate shift from one proof system to another - for example moving a circuit from a Groth16 trusted-setup construction to a setup-free PLONK construction - conventionally forces every downstream contract that hardcodes a verifier's address to be redeployed and rewired. Worse, a naive "just point at the new verifier" migration silently breaks verification of every proof already generated against the old circuit, because the new verifier's parameters don't match the proof that was produced under the old one.
Why Existing Solutions Are Insufficient
- Hardcoded per-protocol verifiers: a single verifier address wired directly into calling contracts means any circuit upgrade requires migrating every caller in lockstep, with no graceful coexistence period.
- Single proof-system deployments: committing to one proof system (Groth16-only, for example) at the protocol level forecloses using a better-suited system for a different circuit - range proofs, membership proofs, and attestation proofs each have different proof-system tradeoffs.
- Generic verifier registries without circuit-type semantics: a flat address-to-address mapping with no circuit-type or version dimension cannot express "this is version 2 of the AML circuit using PLONK" versus "this is version 1 using Groth16" as distinct, independently addressable entries.
- Delete-on-upgrade patterns: registries that overwrite a verifier's record on upgrade rather than preserving history make it impossible to keep verifying proofs generated against a superseded circuit version.
Technical Architecture
The Circuit Type × Version Matrix
| Field | Purpose |
|---|---|
circuitType | Which semantic circuit this verifier checks (see native types below) |
version | Monotonic version number within that circuit type |
verifierAddress | The independently deployed contract that performs the actual pairing/verification check |
proofType | Groth16 / PLONK / STARK / FFLONK - the proof system this verifier implements |
circuitHash | Integrity hash of the compiled circuit, for provenance verification |
active | Deactivation flips this flag; the record and its proof-count history are preserved |
proofsVerified | Per-verifier usage counter, incremented only on successful verification |
Native Circuit Types
Nine circuit types are modeled out of the box: BIOMETRIC_UNIQUENESS and BIOMETRIC_LIVENESS (feeding the platform's biometric proof-of-humanity system), KYC_AGE, KYC_JURISDICTION, KYC_ACCREDITATION, AML_COMPLIANCE, SANCTIONS_CLEAR, and INCOME_THRESHOLD (feeding the compliance and KYC layers), plus a CUSTOM category for anything not yet enumerated.
Forward-Only Latest-Version Tracking
Registering a verifier for a circuit type advances that circuit's recorded "latest version" only if the newly registered version number exceeds the current latest - so registering an older version out of order (for backfill or documentation purposes) never accidentally regresses which version new callers dispatch to by default. Registering an already-existing (circuitType, version) pair is rejected outright rather than silently overwritten.
Dual Dispatch: Latest or Pinned
Callers can invoke verifyProof, which always resolves to the circuit type's current latest version, or verifyProofWithVersion, which pins verification to an explicitly named version regardless of what has since become latest. This lets historical proofs remain verifiable against the exact circuit they were generated for even after the platform has moved on to a newer version or an entirely different proof system for that circuit type.
Deactivation Without Deletion
Deactivating a verifier flips its active flag to false - callers attempting to verify against a deactivated version are rejected - but the record, its circuit hash, and its accumulated proof count remain queryable. A deactivated verifier can also be explicitly reactivated, supporting an emergency-pause-then-restore operational pattern without any loss of registry history.
Custom Circuits Keyed by Hash
For proof types outside the nine enumerated circuit categories, a parallel registration path keys a verifier directly by an arbitrary circuit hash rather than a (type, version) pair, with its own dedicated verification entry point - accommodating one-off or emerging circuit designs without requiring an enum change to the core registry.
Prior Art Differentiation
| Approach | Versioned by Circuit? | Multi-Proof-System? | Old Proofs Stay Verifiable? | Preserves History on Deactivation? |
|---|---|---|---|---|
| Hardcoded per-protocol verifier | No | No - single system | No - breaks on migration | N/A |
| Single proof-system deployment | Partial - manual versioning | No | Depends on migration discipline | Depends on implementation |
| Flat address-to-address registry | No circuit-type dimension | Untyped | No | No |
| Delete-on-upgrade registry | Yes, but destructive | Varies | No | No |
| JIL Sovereign ZKVerifierRegistry | Yes, CircuitType × version matrix | Yes, Groth16/PLONK/STARK/FFLONK | Yes, version-pinned dispatch | Yes, deactivate/reactivate |