Private-money architecture¶
The privacy overview describes the goal. This page describes the machinery: how a balance becomes private, how a payment proves itself, and the contracts that enforce it.
Encrypted notes, not a public balance¶
A transparent token is a public map of address -> amount. AURA's private layer replaces that
with encrypted notes. A note is a commitment to an amount and an owner; only the owner can
recognise which notes are theirs, and the public sees only commitments.
| Concept | What it is | What the public sees |
|---|---|---|
| Note | A committed (amount, owner, salt) |
A commitment hash in a tree |
| Commitment tree | A Merkle tree of all notes | The root, not the contents |
| Nullifier | A one-time marker published when a note is spent | That a note was spent, not which |
| Viewing key | Lets a chosen party detect and read notes | Nothing, unless you share it |
A private transfer, step by step¶
Spending does not reveal the note. It publishes a zero-knowledge proof that the spend is valid, plus new output notes and the nullifiers of the inputs.
flowchart LR
IN["Input notes<br/>(owned, in the tree)"] --> PROOF{"ZK proof"}
PROOF --> OUT["Output notes<br/>payee + change"]
PROOF --> NUL["Nullifiers<br/>inputs now spent"]
PROOF --> ROOT["New tree root"]
OUT --> CH["Public chain verifies the proof,<br/>learns no amount, owner or link"]
NUL --> CH
ROOT --> CH
The proof establishes, in zero knowledge, that the spender owns the inputs, that the inputs are unspent (their nullifiers are new), that inputs equal outputs plus fee, and that each output commits to a valid owner. The chain checks the mathematics and updates the tree. It never learns who paid whom, or how much.
Confirm by reading state back, never by the receipt
As everywhere in AURA, a payment is "cleared" only when the state actually changed: the nullifier is recorded and the output note is in the tree. A bundle can succeed while an inner operation reverts, so the client verifies the post-state rather than trusting a receipt.
The privacy contracts¶
AURA keeps the private layer modular rather than one monolith, so each piece can be audited and replaced on its own.
| Contract | Responsibility |
|---|---|
AuraPrivateVault |
Shield and unshield, the note set, nullifier set, asset registry |
AuraPrivateTransfer |
Verify the transfer proof, conserve value, prevent double-spends |
AuraViewingKeyRegistry |
Register and scope viewing keys for selective disclosure |
AuraComplianceVerifier |
Check the ZK compliance proof a transfer carries |
On the first production rail these are expressed against an existing shielded-asset protocol (Starknet's STRK20) through an adapter, rather than reimplemented from scratch. See Rails and chain strategy.
The invariants a private pool must hold¶
These become the fuzz and invariant test suite before any real value moves:
- Value is conserved. The sum of valid inputs equals the sum of valid outputs plus fees.
- Every nullifier is spent once. A replayed nullifier is rejected; this is what prevents double-spending a note.
- Every output has a valid owner commitment. No note can be created that no one can later prove they own.
- No invalid proof updates state. A transfer that does not verify leaves the tree untouched.
- Shield in equals unshield out. Over the lifetime of the pool, assets shielded and assets unshielded reconcile against the public token balance the vault holds.
Status¶
Planned The note model, the vault and transfer contracts, and the invariant suite are designed and under evaluation against Starknet/STRK20; none of this runs in the live demo yet, which remains transparent on Base Sepolia. See Implementation status.