Skip to main content
Version: 0.3.0

Architecture

The system provides three progressive levels of financial privacy, referred to as Public, Encrypted, and Shielded:

  • Public Layer — Standard ERC-20 tokens. Balances and transfers are fully visible on-chain, as with any token contract.
  • Encrypted Layer — Balances are stored as ElGamal ciphertexts on-chain. Transfer amounts are hidden, but the transaction graph (who sends to whom) remains visible.
  • Shielded Layer — Funds are deposited into a shared commitment pool and withdrawn via nullifiers. Both amounts and the transaction graph are hidden.

Each privacy layer is implemented across three tiers of software: on-chain smart contracts in Solidity that enforce state transitions and verify proofs, zero-knowledge circuits in Noir that prove correctness of private operations, and client-side libraries in TypeScript that construct transactions and manage local state.

A relayer service sits between users and the blockchain. It abstracts away gas fees and removes the need for users to submit transactions from their own addresses — which would otherwise leak their identity on-chain.

For app developers, the system ships an SDK compatible with web, iOS, and Android (via React Native). Any application wishing to integrate privacy can use the SDK directly — it exposes a high-level interface that hides the complexities of proof generation, encrypted state synchronization, and transaction construction.

┌───────────────────────────────────────────┐
│ Application │
│ (uses SDK) │
└───────────────────┬───────────────────────┘

┌───────────▼───────────┐
│ SDK │
│ (TypeScript, │
│ Noir circuits) │
└───────────┬───────────┘

┌───────────▼───────────┐
│ Partner Backend │
│ (holds SK_partner, │
│ signs requests) │
└───────────┬───────────┘

┌───────────▼───────────┐
│ ERC-4337 Bundler │
└───────────┬───────────┘

┌────────────────▼────────────────────┐
│ Paymaster + SharedAccount │
│ (gas sponsorship, graph privacy) │
└────────────────┬────────────────────┘

┌────────────────▼────────────────────┐
│ Smart Contracts │
│ (Solidity — proof verification, │
│ balance storage, state transitions)│
└─────────────────────────────────────┘

Transaction Submission

Users never submit transactions directly. The SDK constructs a UserOperation (including any ZK proofs) and sends it to the partner's backend. The partner backend signs the request with its registered key and forwards it to an ERC-4337 bundler. The bundler submits the UserOperation to a Paymaster, which sponsors the gas.

For Encrypted Layer operations, the UserOperation originates from the user's smart wallet. For Shielded Layer operations (merge, shielded withdrawal), the UserOperation is routed through a SharedAccount — an ownerless smart account that hides the sender's identity on-chain. For details see Relayer.

Compliance

To comply with European regulations, the system includes a compliance component. Although technically intertwined with the Encrypted and Shielded Layers — the encryption is enforced inside their circuits — it can be thought of as conceptually independent: everything works without it, and removing it would not break any privacy or correctness guarantees for end users.

The compliance mechanism relies on a Guardian Committee controlling a threshold decryption key. Whenever an operation hides an amount, the transaction emits an on-chain payload encrypting that amount under the committee's public key. Authorized disclosure requires the controlled committee process, so no single party has unilateral access to private user data.

Component Summary

Encrypted Balances

Users deposit ERC-20 tokens into the contract, which stores their balance as an ElGamal ciphertext on the Grumpkin curve (encrypted via the user's keypair). Transfers update the sender's ciphertext (proved correct by a Noir circuit) and add the transfer ciphertext to the recipient's balance via on-chain point addition — no decryption needed, thanks to the homomorphic property. The recipient decrypts locally using their encryption secret key, which requires solving a discrete log. For details see Encrypted Balances.

Shielded Layer

The anonymous layer breaks the transaction graph. Users deposit from the Encrypted Layer into a shared commitment pool via a shielded deposit, then later withdraw to any Encrypted Layer account via a shielded withdrawal by proving knowledge of a valid commitment and revealing a nullifier — without linking the withdrawal to the original deposit. A background merge service aggregates multiple notes into one using homomorphic addition.

Relayer

The relayer sponsors gas via an ERC-4337 Paymaster and submits transactions on behalf of users, so that users don't need an ETH-funded address — which would link their on-chain identity to their privacy operations. Only authenticated partners can submit requests, so the relayer is protected from abuse. For details see Relayer.

Addressing (EPK)

The system does not use EVM addresses for identifying users. Instead, each user has an Encryption Public Key (EPK) — a point on the Grumpkin curve derived from their spending key. On-chain, balances are stored in a mapping keyed by the hash of the EPK, not by msg.sender. This means a user's privacy identity is entirely separate from their Ethereum account: knowing someone's EVM address reveals nothing about their encrypted balance, and vice versa. To send someone funds, you need their EPK. For details on how keys are derived, see Key Management.

SDK

The SDK handles key management, transaction construction, proof generation, balance decryption, and state synchronization behind a high-level TypeScript API. The two most platform-sensitive operations — circuit proving and discrete-log solving — are abstracted behind adapter interfaces, with native implementations for iOS (Rust via MoPro and Expo modules) and WASM fallbacks for web and Android. Key storage is similarly abstracted: MMKV on iOS, localStorage or IndexedDB in the browser, filesystem on Node.