> For AI agents: the documentation index is at https://docs.umbraprivacy.com/llms.txt, and every page is available as Markdown at its URL with .md appended.

# System map (/docs/architecture/overview)

Umbra has three layers. Your device holds your keys and makes your proofs, a set of off-chain services checks and co-signs what you send, and eight Solana programs verify all of it and hold the state.

This page draws each layer, then follows one value transaction (a deposit, a private transfer or a withdrawal) through them: how it gathers its six signatures, and how it reaches the chain and then the indexer.

## The three layers

The chart below shows the three layers and what passes between them. Your device is the only place your spending keys exist; the guardian nodes hold shares of your viewing keys, as described below. The off-chain services see what you send them and nothing more. The programs see the finished transaction.

```mermaid
flowchart LR
D["Your device"] -->|"requests to sign"| S["Off-chain services"]
S -->|"signatures, paths, notes"| D
D -->|"finished transaction"| C["Solana programs"]
C -->|"program logs"| S
```

*The three layers of Umbra and what passes between them.*

Requests go from your device to the services, and signatures, Merkle paths and encrypted notes come back. The finished transaction goes to the chain, either directly or through a relayer. The indexer, one of the services, reads what the programs log and serves it back to devices.

### Your device

Your device holds everything that is yours alone: in Umbra's clients, the account signature every key is derived from, the keys themselves, and a store of your [notes](https://docs.umbraprivacy.com/docs/state/notes), the units of your private balance, and your history. It builds each transaction, splits that transaction's per-transaction viewing key into shares for the guardian nodes, and makes the [zero-knowledge proof](https://docs.umbraprivacy.com/docs/cryptography/zero-knowledge-proofs) that the transaction is valid: a proof that every rule holds which reveals nothing else. Proving runs on the device, in the browser or app, so no service ever receives your spending keys. The note store is a cache: it can be rebuilt by rescanning with your account signature, as long as the archive of encrypted notes is available. See [your account](https://docs.umbraprivacy.com/docs/account/overview).

### The attesters

Six services must co-sign every value transaction. These are the attesters: three guardian nodes, the screener, the fee enclave and the data endorser. Each checks a different part of the transaction, and each signs the same value, the transaction's context digest. The shielded pool program accepts the transaction only if one combined signature verifies against the sum of all six attesters' keys, so any one of them can stop a transaction by refusing to sign.

They run in two kinds of place. The guardian nodes and the fee enclave run in AWS Nitro enclaves, and their keys are registered on chain only after an attestation document shows which code image the enclave runs. The screener and the data endorser are ordinary servers, registered on chain by governance with their signing keys. See [guardian nodes](https://docs.umbraprivacy.com/docs/guardian-nodes), [the fee enclave](https://docs.umbraprivacy.com/docs/fees/fee-enclave), [screening](https://docs.umbraprivacy.com/docs/screening) and [off-chain services](https://docs.umbraprivacy.com/docs/architecture/services).

### The other services

Three more services make the protocol usable without being able to change a transaction. The relayer submits private transfers and withdrawals so your own wallet never signs them, and pays their Solana fee. The indexer mirrors the program's trees and serves Merkle paths and the encrypted notes the data endorser archived to devices. The forester inserts spent notes' [nullifiers](https://docs.umbraprivacy.com/docs/state/nullifiers), the values that mark a note spent, into the nullifier tree. The program checks a relayer's or forester's work through proofs and signatures, so anyone may run either. See [off-chain services](https://docs.umbraprivacy.com/docs/architecture/services).

### The Solana programs

Eight programs hold the protocol's state and check every rule. The shielded pool holds the pooled tokens and the trees and settles every operation. Six of the others keep the records the pool relies on: which guardian cluster, screener, data endorser, fee enclave and zone signers it may trust, and the checks on AWS attestations behind the enclave records. The eighth, the user registry, binds your main wallet to your platform wallet and stores nothing: the transaction is the record. No Umbra program calls another. The pool reads the other programs' accounts and checks who owns them. See [on-chain programs](https://docs.umbraprivacy.com/docs/architecture/programs).

## Gathering the six signatures

A value transaction is built on your device before any service sees it. The device first reads the indexer for the [Merkle paths](https://docs.umbraprivacy.com/docs/cryptography/merkle-trees) of the notes it will spend and the other values its proof needs. It then builds the new notes, encrypts them to their recipients, splits the per-transaction viewing key into three shares, and computes the context digest: a Keccak-256 hash of the instruction payload and of every account the instruction names, the submitter's included. If the transaction moves notes into or out of a zone, the device also gets that zone's signature over a message derived from the digest, which the proof checks.

The chart below shows the next step. The device sends each attester only what that attester checks, and all of them work at once.

```mermaid
sequenceDiagram
participant U as Your device
participant G as Guardian nodes
participant A as Other attesters
Note over G: three nodes
Note over A: screener, fee enclave, data endorser
par
  U->>G: one encrypted share each
  G-->>U: one signature each
and
  U->>A: payload, fee openings, notes
  A-->>U: one signature each
end
U->>U: add the six signatures
```

*The device sends each attester its part of one transaction, and each returns a signature over the same context digest.*

What each attester receives, and what it checks before it signs:

- **Each guardian node** receives its own share of the per-transaction viewing key, encrypted to that node. It decrypts the share, checks that it matches the share commitment, and checks that the commitment sits in the privacy artifacts root the payload commits to. It keeps an encrypted escrow copy of the share, then signs. It does not check the proof, the amounts or the screening.
- **The screener** receives the public payload and bound accounts. It screens the submitter of every value transaction, plus the depositors and source-account owners on deposit lanes and the destination parties on withdrawal lanes. It signs only a Clear verdict after its independent input-nullifier checks pass. A Private Send still screens its submitter, usually the relayer.
- **The fee enclave** receives the openings of the transaction's fee commitments. It checks them against the fee schedule and the transaction's tokens, rebuilds the fee commitments from them, and signs the digest of the payload as it rebuilt it. If the device's fee commitments differ from the rebuilt ones, the enclave's signature is over a different digest and the combined signature fails. It keeps an escrow copy of the openings, which fee collection needs later.
- **The data endorser** receives the encrypted notes and the leaves of the privacy artifacts root. It checks that the notes fold to the memo digest in the payload and that the leaves fold to the privacy artifacts root, archives the notes, and signs. Without that archive a recipient could not find a note sent to them.

While the attesters work, the device makes the transaction proof. When the six signatures are back, it adds them into one.

- Guardian node 1
- Guardian node 2
- Guardian node 3
- Screener
- Fee enclave
- Data endorser

six BLS signatures over one context digest, added together → Combined attester signature: checked on chain against the sum of the six keys

*BLS signatures on BN254 add up, so six signers produce one 32-byte signature.*

The pool rebuilds the matching key itself. It reads the guardian cluster's aggregate key from the guardian node registry, adds the screener's and data endorser's keys from the screener registry and the fee enclave's key from the fee enclave program, and checks the combined signature against that sum. A transaction may instead name a committee-key account that caches the same sum, which the pool uses only when the four keys stored with it match the ones it reads; see [the cached committee key](https://docs.umbraprivacy.com/docs/cryptography/signatures#the-cached-committee-key). Because the cluster key is a plain sum of its members' keys, the check needs every signer: it is six of six, not a threshold.

## Reaching the chain and the indexer

The chart below shows what happens once the transaction is signed and proved. A private transfer or a withdrawal goes through a relayer. A deposit is submitted by your device, because the relayer refuses deposits: a deposit needs the depositor's own signature. For a deposit, your device makes both proofs itself and sends one Solana transaction that also moves the tokens to your platform wallet. By default your main wallet signs it and pays the fee, and your platform wallet signs as the depositor.

```mermaid
sequenceDiagram
participant U as Your device
participant R as Relayer
participant P as Shielded pool
participant I as Indexer
U->>R: signed, proved transaction
R->>R: make freshness proof
R->>P: submit and pay fee
P->>P: check and settle
P-->>I: program logs
I-->>U: encrypted notes
```

*A relayed transaction from your device to the shielded pool, then to the indexer.*

1. **The relayer completes the transaction.** It checks the request against its published policy, then picks a recent root of the nullifier tree and makes the nullifier-freshness proof: a second proof that the transaction's nullifiers are not yet in that tree. The root and the proof are left out of the context digest on purpose, so the relayer can choose the root as late as possible without invalidating the signatures. Its submitter address is inside the digest even when no tip is paid, so changing relayers requires a new context, screening, attester signatures and proof.
2. **The shielded pool program checks and settles.** It checks the payload's shape and the accounts, rebuilds the context digest, checks that every token is supported and that deposited tokens are allowed, that the guardian cluster is Active and the other attesters are registered, that the named roots are recent and the proof is not too old. It then verifies the combined attester signature, moves any deposited tokens in, and verifies the transaction proof and the freshness proof. Only then does it change state: it stages the three nullifiers, appends three note commitments and three fee commitments, pays any withdrawals and credits the relayer's tip. The staged nullifiers and the appended commitments, with their positions in the trees, are written to the program's logs, which is how the tree leaves reach anyone off chain.
3. **The indexer publishes what landed.** It watches the pool's transactions, decodes each instruction and the records the program logged, updates its mirrors of the trees, and joins each transaction with the encrypted notes the data endorser archived. It publishes the notes in sealed chunks, which every device downloads to find the notes meant for it. See [receiving and syncing](https://docs.umbraprivacy.com/docs/operations/receive-and-sync).
4. **A forester inserts the nullifiers.** Spent notes' nullifiers wait in the nullifier staging buffer, which the code calls the turnstile, until a forester inserts a batch of them into the nullifier tree with a batch-append proof. No account signs that instruction: the proof is the only authority. Later freshness proofs are made against the updated tree. See [the forester](https://docs.umbraprivacy.com/docs/state/forester).

## Operations that use fewer attesters

Registration and the escape hatch take different paths. Registration is co-signed by the guardian nodes and the data endorser only: it publishes your identity commitment and gives each guardian node a share of your outgoing viewing key, and it moves no tokens. See [register](https://docs.umbraprivacy.com/docs/operations/register). The escape hatch needs no attester at all. It withdraws one note under its own proof, and pays for that by disclosing the note it spends. See [the escape hatch](https://docs.umbraprivacy.com/docs/operations/escape-hatch).

## Related

- [On-chain programs](https://docs.umbraprivacy.com/docs/architecture/programs): The eight programs and how they trust each other.
- [Off-chain services](https://docs.umbraprivacy.com/docs/architecture/services): Every service, what it holds and what happens when it is down.
- [Deposit](https://docs.umbraprivacy.com/docs/operations/deposit): The value transaction step by step.
- [Where data lives](https://docs.umbraprivacy.com/docs/architecture/data): Chain, archive and device.


Last updated 12 October 2026
