Privacy-preserving DEX
with compliant identity.
Trades are matched off-chain by a relayer network and settled on-chain through Groth16 proofs over a commitment pool — orders, amounts, and trader identities never appear in plaintext on-chain. A multi-CA zk-X509 identity gate keeps the system compliant without doxxing the user.
Three-layer architecture
Each layer publishes the minimum surface the next one needs — the frontend never trusts the relayer, the contract never trusts either.
Wallet, EdDSA signing, browser-side proof generation. The user's order is signed locally; amount and side never leave the device unencrypted.
Permissionless nodes pull from the shared orderbook, match pairs, generate half-proofs (~15K constraints per side), and submit settlement.
PrivateSettlement verifies the proof and writes a commitment to the pool. RelayerRegistry gates submitters; IdentityGate gates the order side.
Frontend (Next.js / RN) → Relayer network (Node.js) → Contracts (Solidity)
│ │ │
▼ ▼ ▼
EdDSA keys Order matching PrivateSettlement
Half-proof gen Half-proof per side CommitmentPool (IMT)
Commitment build Settlement submission RelayerRegistry
IdentityGate (multi-CA)Five Circom circuits, one settlement story
Each circuit covers exactly one user action. Constraint counts are the headline cost — relayer hardware sizing falls out of these.
| Circuit | Constraints | Role |
|---|---|---|
| authorize.circom | ~15K | Half-proof per-side settlement authorization |
| cancel.circom | ~8K | Private order cancel |
| claim.circom | ~1.5K | Claim with Merkle inclusion proof |
| withdraw.circom | ~6K | Withdrawal from commitment pool |
| deposit.circom | ~4K | Private deposit into commitment pool |
Settlements as Merkle leaves.
The on-chain settlement contract does not store balances. It stores commitments — Poseidon hashes of (amount, owner, secret) tuples — in an incremental Merkle tree. A trader spends a commitment by proving membership and revealing a nullifier; the nullifier is logged so the same commitment can't be spent twice, but the committed values stay hidden.
Because the pool's anonymity set is the union of every active commitment, a single trader's actions blend into the rest of the network's. There is no per-user balance to read on-chain.
zk-X509 identity gating.
IdentityGate verifies that the trader holds a signed attestation from one of a configured set of certificate authorities (X.509 PKIX, including KISA-path), without revealing the underlying credential. The proof asserts jurisdiction and sanctions status; the trader's identity stays on the trader's device.
The CA set is multi-issuer and on-chain configurable. Adding a new CA does not recompile circuits — the verifier reads the current root list and accepts proofs against any of them.
Off-chain matching, on-chain proof.
Anyone can register a relayer with a stake. The orderbook is shared; competition is on latency and uptime.
Relayers submit and pay gas. The fee comes out of the trade in the quote token.
Order payloads are encrypted before they reach the relayer; the settlement contract only accepts the proof. Reordering you can't read isn't a strategy.
Trust model
Each role has the smallest possible trust surface. Compromise at one layer does not compromise the next.
| Actor | Trusts | Proves |
|---|---|---|
| Trader | Local key material, browser proof gen | Authorization, identity, balance |
| Relayer | Nothing about the trader's order | Match validity, half-proof on submit |
| Contract | Nothing about either | Verifies Groth16; rejects bad proofs |
Read the paper, then build.
Half-proof authorization, commitment-pool settlement, multi-CA zk-X509 identity gating — designed and analyzed in the open.