> 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.

# Off-chain services (/docs/architecture/services)

Umbra's off-chain services fall into three groups. Six attesters must sign every value transaction, a few more make the protocol usable, and a last group sets up the keys the enclaves run with.

None of them can move tokens. The shielded pool program checks what each one signs or proves, and an attester's only power over a transaction is to refuse it.

Because the check is six of six, each attester is a single point of liveness. The escape hatch is the one way out that needs none of them. See [liveness](https://docs.umbraprivacy.com/docs/security/liveness).

## The attesters

### Guardian nodes

The guardian nodes are three services, each in its own AWS Nitro enclave, registered together as a guardian cluster in the guardian node registry. Each is given one share of every user's outgoing viewing key at registration, and one share of each value transaction's per-transaction viewing key. Any two shares rebuild a key; one reveals nothing. A node is stateless: it returns each share it checks as an encrypted escrow copy, which the relay in front of it archives.

For a value transaction, a node receives its share encrypted to its own per-boot transport key, together with the transaction's payload. It recomputes the context digest from the payload, decrypts the share, checks that the share matches its commitment, and checks that the commitment sits in the privacy artifacts root the payload commits to. If every check holds, it seals the escrow copy of the share under a key derived from the node's own secrets, and signs the digest. A node does not check the transaction proof, the amounts, the screening or the nullifiers: the program and the other attesters cover those.

Its signing key comes from a root sealed to it at boot (see [root generation](#root-generation)), and the registry accepts that key only after an attestation document shows the enclave runs an approved image. The cluster's on-chain key is the plain sum of its members' keys, so the pool needs all three nodes to sign. The pool also refuses any cluster that is not Active, so a node marked down or running an unapproved image halts transactions until the cluster is repaired. See [guardian nodes](https://docs.umbraprivacy.com/docs/guardian-nodes) and [what guardian nodes check](https://docs.umbraprivacy.com/docs/guardian-nodes#what-they-check).

### Fee enclave

The fee enclave is one service in an AWS Nitro enclave, recorded in the fee enclave program. It checks the protocol fee a transaction pays. The device sends it the openings of the transaction's three fee commitments, one per token slot, and the fee reductions it asks for.

The enclave checks that the request names its own guardian cluster, that every blinding value is non-zero, that the requested reductions match its fee schedule, and that every token on a live deposit or withdrawal lane is one of the fee slots' tokens. It then rebuilds the fee commitments and the fee voucher commitment from the openings, writes them into the payload, and signs the digest of the payload as rebuilt. If the device sent different commitments, the enclave's signature covers a different digest and the combined signature fails on chain. The enclave also escrows the openings, because collecting the fees later requires them. See [the fee enclave](https://docs.umbraprivacy.com/docs/fees/fee-enclave).

It sees each fee slot's token and fee total. It does not see the transaction's notes or who sent them.

### Screener

The screener checks every transaction's bound submitter, plus the depositor and source-account owner on each deposit lane and the destination party on each withdrawal lane. It screens each against its sources and returns one of three verdicts. A transaction is Clear only when every subject was fully answered and none was flagged. It is Indeterminate when any subject was not fully answered, and Deny when every subject was answered and one was flagged.

It signs only a Clear verdict. The work is split between two processes: the screener derives the subjects, screens them and attests the verdict with an Ed25519 key, and a separate signer checks that attestation, recomputes the context digest from the payload and refuses anything not Clear before it signs with the registered BLS key. A Private Send screens its submitter, usually the relayer, and checks its input nullifiers against the indexer. See [screening](https://docs.umbraprivacy.com/docs/screening), including the coordinated policy rollout.

### Data endorser

The data endorser makes sure the encrypted notes a transaction creates exist off chain and match what the transaction commits to. The device sends it the encrypted notes, the auxiliary records and the leaves of the privacy artifacts root. It checks that the notes and records fold to the memo digest in the payload, and that the leaves fold to the privacy artifacts root. If both hold, it writes all of it to its archive and signs.

The chain never holds an encrypted note; it holds only the memo digest that binds them. So the endorser's signature is what guarantees that a recipient can find a note sent to them. It also co-signs registrations, where it checks that the ML-KEM public key the registration commits to is the one supplied, and archives that too. It does not verify proofs or read the chain. See [receiving and syncing](https://docs.umbraprivacy.com/docs/operations/receive-and-sync).

## Services that make the protocol usable

The program never trusts these services with anything it cannot check. They decide whether, and how quickly, things happen.

### Relayer

The relayer (the code calls it the submitter) submits private transfers and withdrawals on a user's behalf and pays their Solana fee, so the user's own wallet never appears on them. It publishes its policy before a client proves: its submitter address, the tokens it relays and its minimum fee in each. The client builds the transaction for that one relayer, because the account that collects the relayer's tip is inside the context digest.

When a request arrives, the relayer reads the accounts it names, rejects anything outside its policy, picks a recent root of the nullifier tree and makes the nullifier-freshness proof against it. That root and proof sit after the signed part of the payload, so the relayer can add them without invalidating the attesters' signatures. It then builds, signs, simulates and sends the transaction and watches for it to land. Its default configuration refuses deposits, which need the depositor's own signature, and program-owned spends. A relayer can refuse or delay a transaction; it cannot change one. See [relayers](https://docs.umbraprivacy.com/docs/fees/relayers).

### Indexer

The indexer makes the chain's data usable. It watches the shielded pool's transactions, decodes each instruction and the records the program logged, and keeps mirrors of the trees and the nullifier staging buffer. It reads the encrypted notes the data endorser archived and publishes them in sealed chunks, which devices download to find the notes meant for them.

It serves three read interfaces: Merkle paths, the archived notes, nullifiers and records, and a context service. The context service answers one request per spend with every path and value that spend needs. To do that it receives the sender's identity commitment, the positions of the notes being spent, their nullifiers and the destination in one request, so its operator can link them. If the indexer is down, devices cannot build new transactions or find new notes, though nothing already on chain is lost. See [how privacy is lost](https://docs.umbraprivacy.com/docs/privacy/leaks).

### Forester

Spent notes' nullifiers wait in the nullifier staging buffer, which the code calls the turnstile, until a forester inserts them into the nullifier tree. When a staging buffer is full, a forester takes the next twelve nullifiers from it, proves with a batch-append proof that inserting them gives the new tree root, and submits that proof. No account signs the instruction: the proof is the only authority, so anyone may run a forester. There are two staging buffers per pool index. If no forester runs, the second fills while the first waits, and new spends stop until a forester empties one. See [the forester](https://docs.umbraprivacy.com/docs/state/forester).

### Fee inserter

A value transaction stages its three fee commitments in its pool index's fee store, and a fee note can be collected only once an insert has appended them to the fee commitment tree. Left alone, the store fills to 1,024 staged transactions, and from then on each new transaction inserts only the oldest entry itself. The fee inserter is a function that a schedule runs once a minute for one pool index. Each run reads the fee store and, while anything is staged, sends an insert and reads the store again. One insert takes up to sixteen entries, so a backlog drains within a single run. The insert carries no proof and no account signs it, so anyone may run a fee inserter; when two race, the one that finds the store empty is refused and changes nothing. It holds only a fee-payer key, and it sends nothing while that key's balance is below a floor. A run that fails is not retried, because the next scheduled run does the same work. If none runs, nothing is held up: fee commitments wait in the store until a collector sends the inserts its notes need, or a full store inserts the oldest itself. A stack for mainnet-v2 pool index 0 is defined but not yet deployed.

### Gateway

The gateway is an API gateway that sits in front of services such as the indexer and the relayer. A caller presents an API key, and the gateway checks it, meters the call against that key's quotas and forwards it. It sees callers' network addresses and which key made each call. It checks nothing about transactions.

### Relays and escrow archives

Each enclave service has a relay in front of it. The enclave accepts requests only when they are signed by its pinned relay key, and the relay signs whatever reaches it, so the relay's network position is its access control. The guardian node relay and the fee enclave relay have a second job: they take the escrow copy out of each signing response and store it in a write-once archive. Two archiver services read escrow records from a message stream into a database. The fee enclave's escrows are how fee collection gets the fee openings.

## Services that set up enclave keys

These services run before the enclaves serve any transaction. The chart below shows how keys reach the enclaves that sign transactions. Operators hold two different things: shares of each enclave's QuorumOS quorum key, and separate shares of the escrow key root generation keeps its root under. A threshold of signers, the escrow-share holders and one more key, decides which code may receive the root.

```mermaid
flowchart TD
Q["Quorum key generation"] -->|"quorum key shares"| O["Operators"]
R["Root generation"] -->|"escrow shares, once"| O
S["Grant signers"] -->|"signed grants"| R
R -->|"sealed root"| C["Provisioning courier"]
C -->|"sealed root"| G["Guardian nodes"]
C -->|"sealed root"| F["Fee enclave"]
```

*How the enclaves that sign transactions get their keys.*

Operators receive their quorum-key shares and escrow shares from the generating enclaves, and keep them; no share passes to a consuming enclave. Root generation seals the root to a consuming enclave only when that enclave's attestation shows code a signed grant names, and the courier carries the sealed root without being able to open it.

### Quorum key generation

QuorumOS, the enclave operating system the enclaves run under, unlocks an enclave with a quorum key. The quorum key generation service creates that key inside an enclave and splits it into shares, each encrypted to one operator, so no single operator holds it.

### Ceremony coordinator

The ceremony coordinator runs the QuorumOS ceremonies that start an enclave and provision it with its quorum key: it collects operators' registrations and shares and moves them to the enclave in the right order.

### Root generation

Root generation holds the one root the guardian nodes and the fee enclave derive their keys from. At genesis, once a threshold of grant signers has authorised that boot, it draws the root and deals an escrow secret as Shamir shares sealed to its operators, any two of three of whom reconstruct it in the production build, and one of two in the development build. Once every operator has acknowledged keeping their share, it escrows the root under that secret and under a key derived from its own QuorumOS quorum key, so a later boot can recover the same root with a threshold of shares, the root record the grant signers sign after genesis, and an authorisation for that boot signed by as many grant signers as a grant needs.

It serves the root only to a consuming enclave whose attestation matches a grant in force: the QuorumOS release and manifest of code that all but one of the grant signers approved. The grant signers are the shard operators and an export authority. A consuming enclave accepts the root only from root generation code those signers named, and only if it matches the root commitment the enclave was started with. Every consumer receives the same root, and each derives its own keys from it, so every replica of one service derives the same signing key, which is the one registered on chain. A restart of either side keeps the keys; only a new genesis changes them.

### Provisioning courier

The provisioning courier runs every minute for each consuming enclave. In each run it finds every replica it can reach that holds no root, carries each one's attested request to root generation, and carries the sealed root and root generation's attested offer back. It reaches root generation through a door that forwards only that one request, and the consuming enclaves' public relays refuse the provisioning routes, so only the courier's doors reach them. It holds the relay keys that let it reach both ends, and nothing that opens what it carries, so the most it can do is withhold a delivery.

### Prover enclave

The prover enclave is a library for making the transaction proof inside an enclave. It is not deployed. Every proof that needs a user's keys is made on the user's device.

## Related

- [System map](https://docs.umbraprivacy.com/docs/architecture/overview): How a transaction moves through every layer.
- [Guardian nodes](https://docs.umbraprivacy.com/docs/guardian-nodes): The largest attester group.
- [Liveness](https://docs.umbraprivacy.com/docs/security/liveness): What stops when a service is down.
- [Where data lives](https://docs.umbraprivacy.com/docs/architecture/data): What each service stores.


Last updated 12 October 2026
