Two Models, One Goal
Every blockchain privacy system needs to answer the same question: what exactly is being hidden? The chain must remain auditable by validators (to prevent double-spending), but opaque to observers (to protect user privacy). How you answer that question determines almost everything about your cryptographic circuit design, your UX, and your anonymity set properties.
Two dominant models have emerged from years of applied cryptography research. The first, used by Zcash and Penumbra, treats private value as notes — discrete, immutable objects that are created, transferred, and destroyed. The second, used by Aztec, treats private state as shielded accounts — encrypted account balances that are updated in place through encrypted state transitions. Both achieve privacy. They achieve it differently, and the tradeoffs are significant.
UTXO Note Pools: The Zcash and Penumbra Model
In a note pool system, a deposit into the shielded pool does not add to an account balance. It creates a note. A note is a commitment to a specific value, asset type, and recipient key, stored as a leaf in an append-only Merkle tree. To spend a note, the spender proves (in zero knowledge) that they know the spending key for some note in the tree, reveals a nullifier (a deterministic value derived from the note and key that cannot be linked back to the note without the key), and produces a new commitment for the recipient.
The chain records the nullifier to prevent double-spending and appends the new commitment to the tree. At no point does any on-chain data reveal which note was spent, who sent it, or who received the new one. The anonymity set is the entire pool of unspent notes.
Fixed-Denomination Notes
Sanect uses fixed-denomination notes — a design choice that deserves explicit explanation. Rather than allowing arbitrary value amounts, the shielded pool accepts deposits in fixed sizes (e.g., 1 SNCT, 10 SNCT, 100 SNCT). This is the same approach used by Tornado Cash's circuit design, and the privacy rationale is straightforward: if every note has the same denomination, there is no value fingerprint to use for de-anonymization. A transaction spending a 10 SNCT note is indistinguishable from any other transaction spending a 10 SNCT note, regardless of who the sender or recipient is.
The tradeoff is that sending an arbitrary amount requires composing multiple notes, which adds some complexity to the wallet layer. We consider this acceptable: the wallet handles composition automatically, and the privacy gain is worth the UX cost.
Account Shielding: The Aztec Model
Aztec's approach starts from a different premise. Rather than discrete notes, Aztec maintains encrypted account state: each account has an encrypted balance, and transactions are encrypted state transitions that update that balance. The prover generates a ZK proof that the new encrypted state is a valid update of the old encrypted state, without revealing the values involved.
The appeal of account shielding is its familiarity. Users think of it as "my private balance" — the same mental model as a bank account or an Ethereum address. Smart contracts can also maintain encrypted state, enabling privacy-preserving DeFi without the note-composition complexity.
The cost is circuit complexity and a subtler anonymity model. Account shielding requires proving encrypted state transitions, which involves more constraints than the simpler "note in, nullifier out" model. More critically, the anonymity set is bounded by the number of accounts that have interacted with a given contract — not the total pool of notes. If a private account has only ever interacted with one counterparty, the transaction graph may be more constrained than it appears.
Why Sanect Chose the Note Pool
We evaluated both models against four criteria: anonymity set size, circuit complexity, auditability surface area, and alignment with the Noir/UltraHonk proving stack. The note pool wins on every axis except UX familiarity.
- Anonymity set: Note pool anonymity scales with the number of unspent notes across all users. Every deposit by every user increases the anonymity set for every other user. Account shielding anonymity is scoped to per-contract interaction graphs — structurally smaller.
- Circuit simplicity: The spend circuit for a fixed-denomination note is significantly simpler than an encrypted state transition circuit. Simpler circuits mean faster proving, smaller proof sizes, and a smaller attack surface in the cryptographic layer.
- No account state leakage: In account shielding, the fact that an account exists and has been updated is always public — only the value is encrypted. In a note pool, the existence of a transaction is known but nothing about its parties or structure is revealed beyond the denomination.
- Noir/UltraHonk alignment: Sanect's custom 2-in/2-out Noir circuit compiles to UltraHonk proofs via Barretenberg's universal SRS. The note pool model maps cleanly to Noir's constraint system — input notes, nullifiers, output commitments, and value conservation are all expressible as straightforward circuit assertions.
The Memo Protocol
Sending a note to a recipient requires a secure out-of-band channel to communicate the note details. Sanect uses an encrypted memo field in each shielded transaction: a fixed-size envelope attached to the note commitment that can only be decrypted by the intended recipient's viewing key.
The encryption scheme is X25519 ECDH + ChaCha20-Poly1305. The sender generates a fresh ephemeral X25519 keypair for every transaction, derives a shared secret with the recipient's viewing public key, and uses HKDF-SHA256 to derive a 32-byte ChaCha20 key and a 12-byte nonce. The ephemeral public key is included in the memo as additional authenticated data (AAD), binding it to the MAC and preventing substitution attacks.
The Fixed-Size Memo Structure
The fixed memo size is not arbitrary. It is the minimum size that accommodates:
- 32 bytes — ephemeral X25519 public key
- 96 bytes — encrypted note plaintext (value, asset ID, diversifier, memo data)
- 16 bytes — Poly1305 authentication tag
Fixing the memo size to exactly the same number of bytes (240 today, of which 96 are reserved for future fuzzy message detection flags) means all memos are indistinguishable in length on-chain. A variable-length memo would leak information about the note's content even without decryption. The memo plaintext packs the 96 bytes tightly: 8 bytes for value, 32 bytes for asset ID, 11 bytes for the note's diversifier, and 45 bytes of free memo data for applications to use.
Every shielded transaction on Sanect produces a 240-byte memo (with 96 of those bytes reserved for future privacy-preserving fuzzy message detection flags). You cannot tell from the on-chain data whether two memos are from the same sender, the same recipient, or carry the same value. That uniformity is not a side effect — it is a design constraint.
The UX Tradeoff
The honest answer is that note pools are harder to explain than account balances. "You have 3 unspent notes worth 10 SNCT each" is less intuitive than "your shielded balance is 30 SNCT." Sanect's wallet layer abstracts this: the interface displays a balance, not a note count, and handles note selection and composition automatically. But the underlying model is notes, and sophisticated users should understand that — both to reason about their privacy properties and to understand why some transactions require multiple proofs.
We made this tradeoff deliberately. The privacy model is the product. UX complexity that serves stronger privacy is worth the investment in wallet engineering.