Protocol
Cryptography

Commitments

What hiding and binding mean, why every commitment carries a blinding factor, and where Umbra commits to values instead of publishing them.

A commitment is a hash that fixes a value without showing it. Umbra publishes commitments wherever the chain needs to hold on to something private: every note, every identity, every fee and every viewing-key share goes on chain as a commitment, never as itself.

A sealed envelope

Think of a commitment as a letter in a sealed, opaque envelope left on a public table. Everyone can see the envelope and can check later that it has not been swapped. Nobody can read the letter through it. When the writer opens it, everyone can check that the letter inside is the one that was sealed, and the writer cannot say it held something else.

Umbra's envelopes are rarely opened in public. The zero-knowledge proof opens them privately instead: it shows that the letters inside satisfy the rules, for example that the amounts balance, without anyone seeing the letters.

Hiding and binding

A commitment scheme has two properties.

  • Hiding. The commitment reveals nothing about the value. Seeing a note's commitment tells you nothing about its amount, token or owner.
  • Binding. Once published, a commitment can be opened to only one value. Nobody can find a second note with the same commitment and a larger amount.

Every commitment in Umbra is a Poseidon hash, almost always the circuit form with its own domain (see hash functions). Binding rests on Poseidon being collision-resistant. Hiding rests on Poseidon behaving like a random function and on the blinding factor described below.

Blinding factors

A hash of a guessable value is not hiding. If a note's commitment were a hash of only its amount, token and owner, anyone could hash every plausible combination and compare. Every Umbra commitment therefore includes a blinding factor: a random field element known only to whoever needs to open the commitment. With a random field element inside, trying candidates gets nowhere.

Most of a transaction's blinding factors are derived from one random value the transaction publishes, together with its nullifiers and the sender's outgoing viewing key, so whoever holds that key can reproduce them instead of storing them. A recipient gets a note's own two blinding factors inside the note's encrypted payload, so it can recompute the note's commitment and, later, its nullifier. Blinding factors nobody will ever need again, such as a dummy input's nullifier blinding factor, are drawn at random and discarded.

Where Umbra uses commitments

Seven kinds of commitment carry a transaction's private data. Each section below says what one fixes, what blinds it and where it ends up. The domain each is hashed under is listed on the hash functions page.

Note commitment

A note commitment fixes all 13 fields of a note: its version, its kind, its zone, its amount, its validity window, its owner, its token, the two funding fields that record who funded it, its memo hash, and its two blinding factors. The blinding factor hides the commitment. The nullifier blinding factor is used again later, when the note is spent, to make its nullifier.

The note tree does not hold the commitment alone. When the program appends a note, it wraps the commitment together with the slot it was inserted in and its position in the tree, and the result is the leaf. Note commitments follows that step.

Identity slot leaves and the identity commitment

Your identity commitment (sometimes called the user commitment) is a commitment to commitments. It has eight slots, and each slot is committed on its own with its own blinder: the spending key, the nullifier key, the outgoing viewing key, the proof-authorisation key, the platform wallet's address, the hash of your ML-KEM public key, and two slots that are unused and hold zero. The eight slot leaves are then hashed together into the identity commitment, which is appended to the identity tree when you register.

Slots 0 to 2
spending, nullifier and outgoing viewing keys
Slot 3
proof-authorisation key
Slot 4
platform wallet address
Slot 6
hash of the ML-KEM public key
Slots 5 and 7
unused, zero
each slot hashed with its own blinder, then the eight leaves hashed together
Identity commitment
a leaf of the identity tree
The identity commitment folds eight separately blinded slot leaves into one value.

Committing to each slot separately is what lets a spend proof open only what it needs. A transaction proof opens the three keys it uses and treats the other five slot leaves as opaque values, so it never has to handle the platform wallet's address or the encryption key. See your identity commitment.

Fee commitment

A fee commitment fixes one token's protocol fee total in a transaction, blinded by a blinding and a nullifier blinding. Every transaction stages three of them for the fee commitment tree, one per token slot, whether the slot is used or not, and an insert later appends them. The fee enclave is given the opening of all three, recomputes each commitment from it and checks the fees against its policy before it signs. When the treasury later collects fees, it spends these commitments much as a user spends notes.

Viewing-key share leaf

Each guardian node's share of a viewing key is committed as a share leaf, blinded by a matching share of a random blinding value, so the leaf reveals nothing about the share. At registration, the three leaves for your outgoing viewing key are hashed into a sharing root that the registration proof publishes. In a value transaction, the three leaves for the per-transaction viewing key go into the privacy artifacts root described below. Each guardian node recomputes its own leaf from the share it decrypts, which tells it whether the share it received is the one the proof committed to.

Disclosure field leaves

A disclosure field leaf fixes one field of one note (its owner, amount, token, creator, kind or slot), blinded by a per-field blinding. The leaves of each note are folded together, and the folds are gathered into two zone sections, one for the zone notes leave and one for the zone they enter. The two sections go into the privacy artifacts root. Because each field has its own leaf and blinding, a holder of the blindings can open one field to a zone authority without opening the others; disclosure covers who can do that.

Sender record lane commitment

The sender record is encrypted inside the proof with a keystream, one lane per field. Each lane is committed separately, blinded by a lane of a second keystream, and the 19 lane commitments go into the privacy artifacts root alongside the 19 ciphertexts.

The privacy artifacts root

Three kinds of commitment above never go on chain individually: share leaves, disclosure sections and lane commitments. They are folded, with the encrypted sender record, into one value: the privacy artifacts root. It is carried in the transaction and bound into its proof.

Sender record
19 ciphertext lanes
Lane commitments
19, one per lane
Share leaves
3, one per guardian node
Disclosure sections
2, source and destination
chained Poseidon fold over 43 values
Privacy artifacts root
in the payload, bound into the proof
The privacy artifacts root commits to everything the guardian nodes and the data endorser check outside the chain.

Since the proof fixes the root, the guardian nodes and the data endorser can check what they are sent against it, and anything that does not match the root does not match the transaction the program will accept.

A commitment without a blinder

One value that looks like a commitment has no blinder. A note owned by a Solana address rather than an identity names its owner by the program owner commitment, a hash of the address's two halves under domain 34. Anyone who knows the address can compute it, so it hides nothing about which address owns the note. The consequences for linking such notes are on the nullifiers page.

What a commitment does not do

A commitment says nothing about whether its contents make sense. That an amount is below 2⁶⁴, that a validity window has opened or that the outputs balance the inputs is proved by the circuit, which opens the commitments inside the proof and checks their contents. A commitment made outside any proof, such as a fee opening given to the fee enclave, is checked by whoever receives the opening: the fee enclave recomputes each fee commitment from the opening it is sent, and a guardian node recomputes its share leaf from the share it decrypts.

Last updated

On this page