Notes
What a note is, the thirteen fields it carries, the three kinds of note, and where a note's contents live when the chain holds only a hash of them.
A note is the unit of private balance: a fixed amount of one token, owned by one party, that is spent whole and replaced. Your private balance is the sum of the unspent notes you can open, and the chain never sees any of them, only a commitment to each.
Cash in an envelope
Think of a note as a banknote sealed in an envelope. The envelope sits in a public ledger where anyone can see that it exists, but only the owner knows what is inside. To pay, the owner does not tear the note in half. They hand in whole notes and have new ones issued: one for the payee and one for their own change. Each note handed in is cancelled so it cannot be handed in again; the nullifiers page explains how.
The code calls an identity-owned note a UTXO, short for unspent transaction output. The term comes from ledgers that keep value in discrete outputs, each spent in full by a later transaction that creates new outputs. Umbra's notes work the same way, except that the outputs are private.
The thirteen fields
Every note has the same thirteen fields, whatever its kind. Six are small numbers, which the circuit range-checks to a fixed width whenever it builds a note's commitment; the other seven are full elements of the BN254 scalar field. They fall into five groups.
Format, kind and zone
Version. The note format, as a 16-bit number. The SDK writes 1.
Kind. A 16-bit number the code calls the discriminator: 0 for a dummy, 1 for an identity-owned note, 2 for a program-owned note. The kind decides how the note is spent and how its nullifier is keyed; the three kinds are described below.
Zone. The note's zone number, up to 20 bits, or 0 for a note in no zone. A transaction that spends or creates a zoned note must carry that zone's signature. See zones.
Value and time
Amount. The value, in the token's base units, up to 64 bits. A real note's amount is never 0, and a dummy's is always 0.
Valid after and valid before. Two 48-bit slot numbers that bound when the note can be spent: from the valid-after slot, and until the valid-before slot, where 0 means it never expires. The validity windows section explains how they are checked.
Randomness
Blinding factor. A random field element that makes the commitment hiding. Without it, anyone could hash guesses of the other fields and compare them with the commitment.
Nullifier blinding factor. A second random value, used only to derive the note's nullifier, together with the note's position in the tree. The blinding factor plays no part in the nullifier. See nullifiers.
Owner and token
Owner commitment. Who can spend the note: a registered identity commitment (sometimes called the user commitment), or for a program-owned note the commitment of a Solana address.
Mint identifier. Which token the note holds: a Poseidon hash of the mint address's two 16-byte halves. The circuit balances each token separately by this value.
Provenance and memo
Funding user commitment and funding program commitment. Who paid for the note. The circuit sets them, not the sender, by the rule described after this list.
Memo hash. An opaque value the circuit carries into the commitment without interpreting it. The SDK writes 0.
No deposit, private transfer (Private Send) or withdrawal publishes any of these fields, though the public amount of a deposit or withdrawal lane can narrow down the notes behind it. The sender and the recipient know them. Beyond those two, the sender record carries each output's owner, token and amount under the per-transaction viewing key; the disclosure tree carries owner, amount, token, the funding user commitment and kind for zone authorities; and an escape hatch makes most of the spent note's fields public. The disclosure page has the detail.
The two funding fields are set by the circuit, not chosen by the sender. For each output, the circuit checks whether any identity-owned input has the same token; if one does, the output's funding user commitment must be the sender's identity commitment (sometimes called the user commitment), and otherwise it must be 0. The funding program commitment follows the same rule for program-owned inputs. A recipient therefore learns who paid them whenever the sender spent a note of the same token, which is the usual case. A note funded only by a deposit carries 0 in both.
Three kinds
The owner commitment is a registered identity commitment. Its owner spends it by proving, inside the transaction proof, that they know the opening of that identity commitment and that it is in the identity tree. No key signs anything. The circuit also requires every identity-owned output's owner to be in the identity tree, so a note cannot be made out to an identity that has not registered. This is the ordinary note, and the one the code calls a UTXO.
Change, split and merge
Every value transaction has exactly three input slots and three output slots, plus up to two deposit lanes and two withdrawal lanes. Paying someone usually spends one or two of your notes and creates two: the payment and your change. The same shape merges several small notes into one, or splits one note into several. Unused slots hold dummies, so from the outside every transaction looks the same.
The chart below follows the amounts through that transaction: two of your notes and a dummy go in, and the payment, your change and a dummy come out.
flowchart LR
a["Your note: 60"] --> t{{"Transaction"}}
b["Your note: 50"] --> t
d["Dummy input: 0"] --> t
t --> p["Payee's note: 80"]
t --> c["Your change: 30"]
t --> e["Dummy output: 0"]
The amounts are illustrative and leave out fees. In a real transaction the protocol fee and any relayer tip also come out of the inputs; see the fee model. A transaction can involve at most three distinct tokens across all its real notes and active lanes, and the circuit balances each token separately; see value conservation.
Validity windows
A note can carry a window of slots in which it is spendable. For every real input, the circuit checks that valid after is at or below the transaction's execution slot, and that valid before is either 0 or above it. The execution slot is a value the transaction names; the program accepts it only if it is no later than the current slot and no older than the proof-age window governance sets, between 300 and 216,000 slots. A transaction whose execution slot falls inside a note's window can therefore still land up to one proof-age window after the window has closed in real time.
Where a note's contents live
The chain holds one 32-byte value per note: a leaf of the note tree, which wraps the note's commitment with the slot and position at which the chain appended it. Everything else lives off chain.
- The encrypted note. The sender encrypts twelve of the thirteen fields to the recipient: a 232-byte plaintext, sealed with ML-KEM-768 and AES-256-GCM into a 1,352-byte blob that starts with a 4-byte view tag. The data endorser archives it and the indexer serves it. The chain binds the blobs to the transaction through the memo digest, but does not store them. See encryption and receiving and syncing.
- The owner commitment is left out of the plaintext. The recipient already knows it: it is their own identity commitment, or the commitment of their address.
- The insertion slot and position are not in the plaintext either, because the sender cannot know them in advance. The chain chooses them when it appends the leaf and records the first position in its program log, where the recipient and the indexer read them.
The recipient needs the blinding factor, the nullifier blinding factor, the slot and the position to rebuild the leaf, prove it is in the tree and later derive its nullifier. A payment from someone else is opened only through its encrypted copy: if the recipient can never obtain it, the note stays in the tree, still theirs, and unspendable.
Related
Last updated
Recovery
How an Umbra account comes back on a new device, what the recovery depends on, and what cannot be recovered or undone.
Note commitments
How a note's thirteen fields become one commitment, why the chain wraps that commitment with a slot and a position before storing it, and what the chain checks about either.