What is a UTXO?
A UTXO (Unspent Transaction Output) in Umbra is a cryptographic commitment to a token deposit. It represents the right to claim a specific amount of tokens - without publicly linking that right to who created it. A UTXO encodes:- Amount - how many tokens are locked
- Recipient address - who is authorized to claim
- Secret randomness - private entropy known only to the depositor
The Mixer: How It Works
The mixer is a shared Indexed Merkle Tree stored on-chain. Each leaf in the tree is a UTXO commitment.Create a UTXO (deposit)
You call one of the
createUtxo functions. The SDK computes a commitment from (amount, recipient, randomness) and inserts it as a new leaf into the tree. Your tokens are locked in the shielded pool.At this point, anyone can see that a deposit happened and the tree grew by one leaf - but cannot see the amount, recipient, or any other detail.Build the anonymity set
As more users deposit into the same tree, your commitment becomes one of many. The larger the set, the harder it is to link your deposit to your eventual withdrawal. Trees hold up to 1,048,576 leaves (depth-20 tree).
Fetch your UTXO
The SDK queries the indexer to find UTXO ciphertexts addressed to your X25519 key, decrypts them locally, and fetches the Merkle inclusion proof for each one. See Fetching UTXOs.
Claim your UTXO
You present a zero-knowledge proof that proves:
- You know the secret inputs behind a commitment that exists in the tree
- You haven’t claimed it before (nullifier is unspent)
UTXO Types
Umbra supports four kinds of UTXOs depending on who can claim them and where the funds come from:- Self-claimable (ephemeral) - funded from your encrypted balance or public ATA. Claimable only by you (same wallet).
- Receiver-claimable - funded from another user’s ATA. Claimable by a specified recipient address.
Nullifiers: Preventing Double-Spends
Each UTXO has a corresponding nullifier - a deterministic hash derived from its private inputs. When a UTXO is claimed, its nullifier is stored in an on-chain treap (a self-balancing sorted tree). Before allowing a claim, the on-chain program checks that:- The nullifier has not been seen before
- The ZK proof is valid for a commitment in the current Merkle tree
Ciphertext Discovery
After you create a UTXO, the SDK publishes an encrypted ciphertext on-chain. This ciphertext is addressed to the recipient’s X25519 public key - only the recipient can decrypt it to learn the commitment’s secret inputs (amount, randomness, etc.). The ciphertext payload contains:- Amount (8 bytes)
- Recipient address (32 bytes)
- Generation index (16 bytes)
- Domain separator identifying the UTXO type (12 bytes)
Your private key never leaves your device. Decryption happens in the SDK using your locally derived X25519 key.
Anonymity Set Size
The privacy guarantee of the mixer depends on how many other UTXOs exist in the same tree at the time you claim. A tree with only one leaf offers no privacy - it’s obvious which commitment is being claimed. In practice:- Wait for more users to deposit before claiming
- Claiming into a different address from your deposit address increases privacy
- Combining mixer withdrawals with encrypted balances hides the final destination further