Protocol
Cryptography

Building blocks

Every cryptographic primitive Umbra uses, the job each one does, and which of them are post-quantum.

Umbra uses a small set of standard primitives, each chosen for one job. Most of them live on BN254, the pairing-friendly curve Solana supports with native syscalls; the encryption that has to stay private for decades is post-quantum.

Seven jobs need cryptography, and the sections below take them one at a time: what the job is, which primitive does it, and why that one. Security levels compares how strong each primitive is and which of them a quantum computer would break.

Hashing

Poseidon over the BN254 scalar field is the hash for everything a proof has to recompute. Note commitments, identity commitments and fee commitments are Poseidon hashes, and so are nullifiers and every node and leaf of the Merkle trees. Every proof the program verifies also has exactly one public input, a Poseidon hash of all its public values, which the program recomputes from its own accounts. Poseidon is used because it is built from field additions and multiplications, which cost few constraints inside a circuit, and because Solana has a Poseidon syscall, so the program computes the same hash cheaply on chain.

Keccak-256 binds bytes that never enter a circuit as field elements. The context digest that every attester signs is a Keccak-256 hash of the transaction's payload and accounts. The memo digest over a transaction's encrypted notes is Keccak-256, and so are the enclave measurements the Nitro attestation verifier records, each one a hash of an enclave image's first three PCR values. Keccak is cheap on chain through its own syscall and has no field-size limit on its input.

Hash functions explains both Poseidon forms and how every hashed object is kept apart from every other.

Zero-knowledge proofs

Groth16 on BN254, with circuits written in Circom, proves every statement the program cannot check in the clear: the transaction proof, the nullifier-freshness proof, and the registration, escape-hatch, batch-append and fee-collection proofs. Groth16 proofs are 128 bytes whatever the circuit, and verifying one takes a fixed number of pairings, which the program does with Solana's BN254 syscalls. See zero-knowledge proofs.

Signatures

Five signature schemes are in use, each where its verifier can afford it.

BLS on BN254 carries the combined attester signature on registrations and value transactions. BLS signatures on the same message add together, so the six attesters' signatures become one 32-byte signature that the program checks with one pairing equation against the sum of their keys.

EdDSA-Poseidon on BabyJubJub carries a zone authority's approval of notes leaving or entering its zone. BabyJubJub is a curve defined over the BN254 scalar field, so the signature is checked inside the transaction circuit, which is what keeps the zone itself private.

Ed25519 is Solana's own scheme. Your main wallet and platform wallet sign with it, and the account signature that Umbra's clients derive every key from is an Ed25519 signature by your main wallet.

ECDSA P-384 with SHA-384 is what AWS signs Nitro attestation documents with. A dedicated program, the P-384 signature verifier, checks those signatures on chain so that an enclave key can be admitted.

ML-DSA-87 combined with Ed25519 signs guardian node responses and the requests their relays forward. Both halves sign the same digest, so a forger has to break both.

Signatures covers each scheme in turn.

Encryption

ML-KEM-768 with AES-256-GCM encrypts each new note to its recipient. Encrypted notes are published for anyone to keep, so this is the encryption that has to last, and ML-KEM is a post-quantum key-encapsulation mechanism (FIPS 203).

ML-KEM combined with X25519, then AES-256-GCM protects what your device sends to an enclave: viewing-key shares to guardian nodes over ML-KEM-1024 with X25519, and fee openings to the fee enclave over ML-KEM-768 with X25519. The hybrid holds as long as either half does.

A Poseidon keystream keyed by the per-transaction viewing key encrypts the sender record inside the proof, so the circuit itself guarantees that the ciphertext says what the transaction did.

Encryption gives the details of all three.

Secret sharing

Shamir 2-of-3 sharing over the BN254 scalar field splits your outgoing viewing key at registration and each transaction's per-transaction viewing key among the three guardian nodes. One share reveals nothing about the key whatever the attacker's computer; any two reconstruct it. The shares are computed inside the circuits, so the proof fixes them alongside everything else it proves. See secret sharing.

Key derivation

HKDF over SHA-512, in RFC 9180's labelled form, derives every Umbra key from the account signature, each under its own label. This is the standard Umbra's SDKs and client interfaces follow; the protocol does not enforce it. The signature first becomes the entropy of a 24-word BIP-39 phrase, whose seed (PBKDF2-HMAC-SHA512) everything else comes from. The platform wallet, a Solana keypair, takes that seed through SLIP-0010, the hierarchical derivation scheme for Ed25519 keys; the identity keys are HKDF expansions of a master secret derived from it. See your keys.

One field for everything proved

Everything a circuit touches is an element of the BN254 scalar field, a prime field of about 254 bits. Amounts, slots and flags fit in one element each. A Solana address or mint is 256 bits and does not, so it enters the circuits as two 128-bit halves (its first 16 bytes and its last 16, each read little-endian), and a mint is referred to inside notes by the Poseidon hash of its two halves.

Staying in one field keeps the circuits small: Poseidon, the Shamir shares, the BabyJubJub curve and the in-circuit encryption are all arithmetic in that field. The same field is the one the Solana runtime's Poseidon and BN254 syscalls work in, so the program can recompute anything a proof commits to.

Where each primitive runs

  • In the circuit. Poseidon, EdDSA-Poseidon, Shamir sharing and the Poseidon keystream are all proved inside the Groth16 circuits on your device.
  • In the program. The shielded pool program recomputes Poseidon with the sol_poseidon syscall and Keccak-256 with sol_keccak256, verifies Groth16 proofs and BLS signatures with the BN254 group and pairing syscalls, and relies on the P-384 verifier program for attestation signatures.
  • On your device. Ed25519 wallet signatures, HKDF, BIP-39 and SLIP-0010 key derivation, and ML-KEM note encryption.
  • In the enclaves. The hybrid transport and response signatures, and each enclave's BLS signing key.

Last updated

On this page