What is public
What the Solana chain shows for each Voidcash transaction, and what stays private.
Every Voidcash transaction is an ordinary Solana transaction calling the pool program's transact. Anyone can read
it. What it reveals depends on whether SOL crosses the pool's edge: shields and unshields show an address and an
amount; private transfers show neither.
On every transaction
Each transact carries the same parts, whatever it does:
- a 256-byte Groth16 proof;
- the index of the recent root it was proven against;
- two nullifiers, one per input note, real or dummy;
- two commitments, one per output note;
- two 88-byte ciphertexts, one per output note; an unused output carries random bytes of the same length;
- the ext data: the SOL crossing the pool's edge (
ext_amount, zero for a private transfer), the relayer fee, the deadline slot and the fee rate; - the fee payer, the recipient account and the relayer account.
A nullifier cannot be linked to the commitment it spends without the owner's spending key, and a commitment shows
neither its owner nor its amount. The Inserted event repeats the two commitments with the index of the first leaf.
Per move
| Shield | Private transfer | Unshield | |
|---|---|---|---|
| Fee payer | Your wallet, which signs | The relayer | The relayer |
| Who | Your wallet's address | Nobody: no sender, no recipient | The recipient's address |
| Amount | The amount shielded, and the shield fee on top | None. Only the relayer's fee, paid from the notes | The amount unshielded; the recipient receives it less the exit fee |
| SOL that moves | Your wallet to the vault, and the fee to the treasury and the buyback | The vault to the relayer, its fee | The vault to the recipient, the treasury, the buyback and the relayer |
Exited event | No | Yes, when a relayer fee is paid: that fee and the vault's balance after it | Yes: the SOL that left and the vault's balance after it |
A note merge, two of your notes combined into one, is a private transfer to yourself and looks exactly like any other private transfer. A shield can create a note for another Voidcash address; the chain shows the depositor's wallet, not whose note it is.
So the chain shows that a private transfer happened, two nullifiers and two commitments, and the relayer as fee payer. Not who sent it, who received it, or how much.
What stays private
- Your balance. Notes are encrypted to your viewing key; only that key opens them.
- Who pays whom. A private transfer links no sender to any recipient, and a spend does not show which notes it spent.
- Amounts inside the pool. Private transfers carry no amount. Notes hold their amounts only inside commitments and ciphertexts.
- Your keys. Created and kept in your browser, never sent to a server.
Off the chain
- The relayer receives each private transfer and unshield before it lands: the same data the chain then shows, plus the connection and its timing. It keeps no request logs. See Trust model.
- The indexer serves every leaf and every nullifier to everyone, so a download does not say which notes are yours. Its activity feed lists what the chain shows: each transaction's kind and, for shields and unshields, its amount.
- The RPC answers the app's reads of the pool's own accounts (the tree, the config, the vault), which are the same for every user.
Shields and unshields are public at the pool's edge: shielding and unshielding the same amount minutes apart is easy to match, so let time pass and vary amounts.