Verify
Enclave Verification Guide
This page explains how to verify that our treasury enclave is running exactly the code we claim. AWS Nitro Enclaves provide cryptographic proof — called remote attestation — that ties a running enclave to a specific, measurable code image. No one (including us) can modify code inside the enclave without changing its measurement hash.
What is an Enclave?
An AWS Nitro Enclave is an isolated virtual machine with no persistent storage, no network access, and no interactive login — not even for the server operator. The only way to communicate with it is through a narrow, predefined API. Private keys never leave the enclave's memory.
The enclave's code is measured at launch by the Nitro hypervisor, producing a PCR0 hash — a SHA-384 fingerprint of the entire enclave image. This hash is embedded in a cryptographically signed attestation document issued by AWS, which anyone can verify.
The Three Pillars of Verification
1. Source Code
Everything that runs inside the enclave is published below. There is no additional code — the Dockerfile copies only these files into the enclave image.
Dockerfile
The enclave image is built from Dockerfile.enclave:
- Base image: Amazon Linux 2 (multi-stage build)
- Builder stage: Installs Python 3.8 and the minimal dependency set, then downloads and SHA-256-verifies the official AWS Nitro root certificate
- Runtime stage: Copies only the enclave application code (no database, no API server, no watcher/sweeper). Generates a self-signed TLS certificate for the encrypted vsock channel. Verifies that mock/dev credentials are excluded from the image
- Baked-in policy constants: Platform fee addresses (EVM, BTC, LTC, SOL), maximum fee rate, and maximum merchant count are set as
ENVvariables in the Dockerfile. Because these are part of the image, they are included in the PCR0 measurement — changing any fee address changes the hash, requiring an explicit update to the allowed PCR list on the host
Production safety checks baked into the build:
_mock_root_key.pem(dev-only mock signing key) must NOT be present — build fails if it isaws_nitro_root.pem(real AWS root cert) MUST be present — build fails if it is missing- Plaintext provisioning endpoint is physically removed from the running server in production
Application Code
| File | Purpose |
|---|---|
enclave/server.py | FastAPI server — the only process running inside the enclave. Exposes endpoints for encrypted provisioning, policy provisioning, address derivation, and transaction signing. Enforces one-shot provisioning (mnemonic and policy cannot be changed without restarting the enclave), transaction policy validation (rejects any transaction that violates the whitelist), and rate limiting (bounds signing operations per hour). In production, insecure routes are physically removed at module load. Holds per-merchant mnemonics only in memory (never written to disk). |
enclave/policy.py | Transaction policy engine. Validates every transaction before signing against a strict whitelist: only sweep transactions (deposit → treasury) and gas funding transactions (treasury → deposit) are permitted. Enforces per-chain rules for EVM (native + ERC-20), Bitcoin, Litecoin, and Solana (native SOL + SPL tokens). Rejects contract deployments, arbitrary contract calls, forbidden token instructions (approve, transferFrom, etc.), and outputs to unknown addresses. Enforces fee conservation bounds and miner fee caps. Platform fee addresses are baked into the enclave image (part of PCR0). |
enclave/protocol.py | Pydantic request/response models shared between enclave and host. Defines the wire format for all RPC calls including policy provisioning. |
enclave/crypto.py | RSA-2048 OAEP keypair generation and encryption/decryption. The enclave generates a fresh keypair at startup; callers encrypt mnemonics with the public key before sending them in. |
enclave/attestation_provider.py | Attestation abstraction. In production, calls /dev/nsm (the Nitro Security Module) to obtain a hardware-signed attestation document from the hypervisor. Verifies attestation documents by decoding CBOR/COSE_Sign1, validating the AWS certificate chain, checking PCR0, and confirming public key binding. Returns the attested public key for encrypted provisioning (prevents MITM key substitution). |
enclave/attestation.py | Attestation document parsing and signature verification logic. |
enclave/vsock_bridge.py | Vsock-to-TCP bridge. Nitro enclaves have no TCP networking — only vsock. This bridge forwards vsock connections to the local uvicorn server. |
enclave/transport.py | TLS transport layer with certificate pinning support. |
enclave/nitro_defaults.py | Deployment constants (ports, paths, recommended environment variables). |
signer/interface.py | Abstract signer interface (defines derive_address, sign, sign_transaction, sign_sol_transaction). |
signer/local_signer.py | BIP44/SLIP-10 HD wallet implementation. Derives addresses and signs transactions for Ethereum (and all EVM chains — Polygon, BSC, Base, Arbitrum, MegaETH, Monad, HyperEVM), Bitcoin, Litecoin, and Solana. Private keys are derived in-memory from the mnemonic and never leave the process. |
token_registry.py | Chain and token definitions. Maps asset identifiers to chain types, contract addresses, and decimal precision. Used by the signer for multi-chain address derivation. |
logging_config.py | Structured logging configuration for the enclave server. |
Dependencies
The enclave uses a minimal dependency set (requirements-enclave.txt):
| Package | Purpose |
|---|---|
fastapi, uvicorn | HTTP server |
eth-account, bip44, base58 | HD wallet derivation (BIP39/BIP44/SLIP-10) |
pycoin | Bitcoin and Litecoin transaction signing |
solders | Solana Ed25519 keypairs, address derivation, and signing |
cryptography | RSA-OAEP encryption, TLS certificates |
cbor2 | CBOR/COSE attestation document parsing |
aws_nsm_interface | Nitro Security Module device access (/dev/nsm) |
requests | HTTP client |
eval_type_backport | Python type-hint compatibility for Python 3.8 |
python-dotenv | Environment variable loading |
2. Build Instructions
To reproduce the enclave image and independently verify the PCR0 hash, run the following on a Nitro-capable EC2 instance (e.g., m5.xlarge or any .metal instance with Nitro Enclaves enabled):
Prerequisites: Docker, nitro-cli (installed via amazon-linux-extras install aws-nitro-enclaves-cli)
# Clone the repositorygit clone <repo-url>cd backend# Build the Docker imagedocker build -f Dockerfile.enclave -t enclave-signer:latest .# Build the Enclave Image File (EIF)nitro-cli build-enclave \--docker-uri enclave-signer:latest \--output-file enclave-signer.eif
The nitro-cli build-enclave command outputs JSON containing the PCR measurements:
{"Measurements": {"HashAlgorithm": "Sha384","PCR0": "<96-character hex string>","PCR1": "...","PCR2": "..."}}
PCR0 is the measurement that matters — it is the SHA-384 hash of the entire enclave image. Compare it to the expected value published below.
Note on reproducibility: The enclave image generates a random TLS certificate at build time, which means a fresh build will produce a different PCR0 than ours. The purpose of publishing the source code is so that anyone can audit what the enclave does — the attestation document from AWS proves that our specific build is what is actually running. Both pieces together provide the full guarantee.
How Attestation Works
When the enclave starts, the following happens:
- The Nitro hypervisor measures the enclave image and records the hash as PCR0
- The enclave generates a fresh RSA-2048 keypair in memory
- The enclave requests an attestation document from the hypervisor via
/dev/nsm, embedding its public key - The hypervisor returns a COSE_Sign1 document signed by the AWS Nitro root certificate, containing:
- The PCR0 measurement
- The enclave's public key
- A certificate chain back to the AWS Nitro root CA
- Anyone can fetch this attestation document and verify:
- The signature chains back to the AWS Nitro root certificate
- The PCR0 matches the expected value published on this page
- The public key is bound to the attestation (so you know you're encrypting secrets for this specific enclave)
This proves that the enclave is running the exact code that produced the published PCR0, and that no one — including the server operator — has tampered with it.
What This Guarantees
| Guarantee | How |
|---|---|
| Private keys never leave the enclave | No disk, no network, no shell access. Keys exist only in volatile memory. |
| The code running is the code published | PCR0 measurement is signed by AWS hardware — unforgeable. |
| No one can modify the enclave at runtime | Nitro enclaves have no SSH, no debug port, no interactive access. |
| Provisioned secrets are encrypted in transit | RSA-OAEP encryption with a key extracted from the attested enclave — MITM key substitution is impossible. |
| Plaintext provisioning is impossible in production | The endpoint is physically removed from the server at startup. |
| Only whitelisted transactions are signed | The enclave validates every transaction against a strict policy before signing. Only sweeps (deposit → treasury) and gas funding (treasury → deposit) are permitted. Contract deployments, arbitrary calls, and forbidden token operations are rejected. |
| Fee addresses are immutable | Platform fee addresses are baked into the enclave image as environment variables. Changing them changes the PCR0 hash, requiring an explicit host-side update. |
| Mnemonic cannot be changed at runtime | One-shot provisioning: once a mnemonic is loaded, re-provisioning with a different mnemonic is rejected (409) until enclave restart. |
| Signing is rate-limited | The enclave enforces per-merchant rate limits on signing operations, bounding the damage from a compromised host. |