Protocol
Operations

Private transfer (Private Send)

How a private transfer spends your notes and creates new ones for a recipient, what the relayer adds, and what each party can and cannot learn.

Umbra's clients, not the protocol

Deriving your keys from your account signature, as this page describes, is what Umbra's SDKs and client interfaces do. The protocol checks only that the proof's keys match your identity commitment and notes, not how they were made.

A private transfer (Private Send) spends notes you own and creates new notes for a recipient, and no public token balance changes. A chain observer sees that the shielded pool processed a transaction and which relayer submitted it, plus the relayer's tip and its token if one is paid. The sender, the recipient, the amount, the token and the zone are private.

Private Send
Everything a chain observer can read
Program
Shielded pool, process_3x3x2x2
Submitter and fee payer
The relayer's own address
Relayer tip
An amount and a token, or nothingZero when the relayer sponsors the transaction
Tip account
The relayer's accrual for that token
Nullifiers
Three field elementsUnlinkable to the notes they cancel
New note commitments
Three field elements
Fee commitments
Three field elements
Sender
Private
Recipient
Private
Amount
PrivateInside the note commitments
Token
PrivateUnless the tip is paid in the token sent
How many notes were real
Private
Zone
Private
Memo
Private
A private transfer publishes values that fix the new notes and cancel the old ones, and nothing that says whose they are.

Summary

A private transfer uses the same instruction as a deposit and a withdrawal, with no deposit or withdrawal lane active. It spends up to three of your notes and creates up to three, typically the recipient's note, your change and a dummy of amount zero. The transaction proof shows that you own the notes, that they are in the note tree and still valid, that their nullifiers are correct, and that value in equals value out plus fees, token by token.

Notes spent
input note
input note
dummy
Deposit lanes
dummy
dummy
One transaction
same shape every time
Notes created
output note
output note
dummy
Withdrawal lanes
dummy
dummy
A private transfer that spends two notes and creates two: the recipient's note and your change. The third input and output are dummies.

The SDK fills all three input slots when it can, since a dummy costs as much to prove as a real note and spending fewer notes than you create grows your note count. A relayer submits the transaction and adds the nullifier freshness proof, a second Groth16 proof that the nullifiers are new.

Before you start

  • You and the recipient are registered. The proof checks you and any identity you pay against the pool's identity tree, so you cannot pay an identity that never registered. A recipient can also be a Solana address such as a program. See register.
  • You hold enough of the token for the amount, the protocol fee on each new note and the relayer's tip.
  • A relayer will carry it. Its policy names its submitter address, tip accounts, minimum tips and tokens, and Umbra's relayer refuses a zero tip unless configured to sponsor.
  • Every attester is available. The three guardian nodes, the screener, the fee enclave and the data endorser must all sign, and the guardian cluster must be Active.

How a private transfer runs

Your device prepares the transaction and collects six attester signatures while it proves. A relayer then adds the freshness proof and submits.

flowchart LR
A["Your device prepares"] --> B["Attesters sign"]
A --> C["Your device proves"]
B --> D["Relayer adds freshness proof"]
C --> D
D --> E["Pool checks and settles"]

The context digest, a hash of the instruction and every account it names, ties the phases together. Every attester signs it, the zone authorities sign a message derived from it, and the transaction proof takes it as a public input.

Phase 1: preparing on your device

Your device calls the relayer, the indexer and, where needed, zone authorities.

sequenceDiagram
participant U as Your device
participant R as Relayer
participant I as Indexer
participant Z as Zone authorities
U->>R: read policy
R-->>U: submitter, tip accounts
U->>I: one read for paths
I-->>U: paths, recipient key, rates
U->>U: build notes and digest
opt a zone other than zone 0
  U->>Z: authorisation message
  Z-->>U: EdDSA signature
end

1. Your device reads the relayer's policy

The SDK reads the relayer's policy first, because the relayer's submitter address and tip account are bound into the context digest, and the submitter is screened even when no tip is paid. It checks that the relayer will carry this token and tip before it spends a proof.

2. Your device selects notes and derives its keys

The SDK picks up to three notes of the token, preferring more notes over a smaller total, derives your keys from your account signature and draws fresh randomness.

3. The indexer returns paths and the recipient's key

One indexer request returns Merkle paths for your notes and for both identities, the recipient's ML-KEM-768 public key and the fee rates. A wrong answer only costs time, because the paths must match roots the pool still accepts.

4. Your device builds the notes, the record and the digest

The SDK prices the fees, builds and encrypts the recipient's note and your change, and builds the sender record, which describes the whole transaction. It splits that record's viewing key into one share per guardian node and computes the context digest.

5. Zone authorities sign, outside zone 0

Spending from or sending to a zone other than zone 0 needs an EdDSA signature from that zone's authority, and every real output must sit in the source or destination zone. The proof checks these signatures, not the chain, so the signer stays private. See zones.

Phase 2: collecting signatures and proving

The attesters need only the context digest and what each is sent, so the SDK asks all six at once and proves while it waits.

sequenceDiagram
participant U as Your device
participant G as Guardian nodes
participant A as Other attesters
Note over A: screener, fee enclave, data endorser
par attest
  U->>G: one encrypted share each
  G-->>U: three BLS signatures
  U->>A: what each one checks
  A-->>U: three BLS signatures
and prove
  U->>U: transaction proof
end
U->>U: combine six signatures

6. Each guardian node checks its share and signs

Each guardian node decrypts its share of the viewing key, checks it against what the payload commits to, escrows it and signs. It checks no proof and no amount. See what a guardian node checks.

7. The screener screens the submitter

Nothing crosses the pool boundary, so the submitter, usually the relayer, is the screener's only subject, and the recipient is not screened. The screener signs only if every screening module has answered, none has flagged the wallet and its own input-nullifier checks pass. See screening.

8. The fee enclave opens the fee commitments and signs

The fee enclave opens the three fee commitments, fills the fee voucher from its discount schedule, recomputes the commitments, escrows the openings and signs. See the fee enclave.

9. The data endorser checks the encrypted notes and signs

The data endorser checks the encrypted notes against the payload's memo digest and archives them before it signs. The recipient later finds the note in that archive.

10. Your device proves and combines the signatures

The device finishes the proof and adds the six BLS signatures into one combined attester signature.

Phase 3: relaying and settling

Your device sends the relayer the finished instruction, with the nullifier root and freshness proof left empty. Relayers covers what the relayer does and sees.

sequenceDiagram
participant U as Your device
participant R as Relayer
participant P as Shielded pool
U->>R: instruction, freshness left empty
R->>R: check against policy
R->>R: prove freshness
R->>P: signed v1 transaction
P->>P: check, verify, settle
R-->>U: landed

11. The relayer accepts the request

Before any work, the relayer checks that the context digest matches the payload and accounts, that the submitter and tip account are its own, that the token and tip meet its policy, and that the proof is not close to expiring.

12. The relayer proves freshness and builds the transaction

The relayer proves that none of the three nullifiers is in the nullifier tree at the latest root. The root and proof sit outside the context digest, so adding them last disturbs no signature and keeps the root recent. The relayer then sends a Solana v1 transaction as submitter and fee payer.

13. The shielded pool checks, verifies and settles

The program runs the same ordered checks as a deposit, with no token moved in or out. It checks the payload, the accounts and the context digest. It then checks that the guardian cluster is Active, that every root is still recent, that the screener, data endorser and fee enclave are live, and that the execution slot is inside the proof-age window. It verifies the combined attester signature and both proofs together.

The pool then stages the three nullifiers, refusing any it already holds, appends three note commitments to the note tree and stages three fee commitments. The tip comes out of your notes and accrues to the relayer inside the pool for fee collection.

What the recipient learns

The recipient finds the note by trial-decrypting the archive (see receive and sync) and learns its amount, token, zone, validity window and memo. When you spend an identity-owned note of the same token, the normal case, its funding field holds your identity commitment. That commitment is public at registration and linked to your wallets, so the recipient can learn which wallet paid them.

What can go wrong

  • The relayer refuses. It refuses a token it does not carry, a tip below its minimum or a nearly expired proof, and since the submitter is bound, switching relayers needs new attester signatures and a new proof.
  • The submitter fails screening. The screener does not sign if the relayer's wallet is flagged or cannot be fully screened.
  • A nullifier is already staged. The note was already spent, or an earlier attempt that spends it is still in flight.
  • A root ages out. The note and identity trees keep 512 recent roots and the zone signer-set root counts only while live, so a busy tree or a zone change means proving again.
  • The proof expires. The transaction must land within the proof-age window after its execution slot, which governance sets between 300 and 216,000 slots.
  • An attester is down. Any one of the six stops the transfer; the escape hatch needs none of them.

Privacy notes

  • The tip's token is public. The SDK tips in the token sent by default, and a zero-tip transfer names no token.
  • The relayer sees your IP address and timing, and nothing else that will not be on chain moments later.
  • The indexer sees the whole request: your identity commitment, the notes you spend, their nullifiers and the recipient.
  • The recipient can identify you through the funding field.
  • Submitting it yourself puts your wallet on chain as fee payer. The program allows it; the SDK does not build it.
  • The shape hides the count. Every transfer publishes three nullifiers, three note commitments and three fee commitments, dummies included.

Last updated

On this page