Mina as the trust anchor for complex TEE architectures.
Why the coming wave of confidential cloud apps needs a light client with the certainty of a full node, and why only Mina has one.
Why the coming wave of confidential cloud apps needs a light client with the certainty of a full node, and why only Mina has one.
$18 B of confidential computing against ~$0.9 T of cloud spend.
$154 B of confidential computing against $2 T of cloud spend.
Same metric and sources for both years. Confidential computing: Grand View Research ($18.1 B 2026, $153.8 B 2030). Cloud: Goldman Sachs Research ($2 T by 2030, 22% CAGR; 2026 derived). Blue area to scale. A spend proxy, not a workload count.
The vulnerability apocalypse is said to be arriving. The harder your system the better; TEEs force system hardening by means of verifiable integrity.
Location means something. Same chip, but a TEE located in your basement is a side-channel liability; a TEE provably located in a hyperscaler data center is a proper trust boundary.
An attestation is only as good as someone reading the attested code. AI agents can now review entire TEE codebases at speed, and with languages like Rust the reproducible build can be done quickly and deterministically.
People hand AI their most sensitive data. This single workload will account for tens of billions in increased spend on TEEs.
Every hyperscaler now ships a production confidential-compute offering, with years of hardening and long lists of case studies.
Attested container workloads; the image digest is the trust anchor.
Isolated enclaves attested by PCR measurements of the enclave image.
Whole VMs isolated from the host and hypervisor, with hardware attestation.
Example: Meta’s Muse, a personal AI agent announced September 2026, with Signal creator Moxie Marlinspike involved.
A dedicated VM per user. A Sentinel agent gatekeeps all outbound network traffic.
The entire VM encrypted with a key held only by the user. Meta removes itself from the trust equation.
Source: Forkast, “When the building owner doesn’t have the key: Meta’s Muse, confidential VM and the third trust architecture” (Sep 2026).
Many different TEEs doing different jobs, working together through complex modes of orchestration.
Two service examples:
Post-update key distributor
Releases keys to other TEEs after their code is updated, once the update is proven approved.
TEE Group X is updated, and each TEE in the group needs the keys the pre-update TEE Group had.
The code for the image of the key-release TEE must be rock hard and updated infrequently. TEEs around it can change often, but it does not.
Must have trusted communication with the outside world to know a release is allowed.
The host of a TEE controls every byte in and out. The TEE must be 100% immune to any attempt from a malicious host with total control of the pipe.
| Full node | Other light clients | Mina light client | |
|---|---|---|---|
| Small enough for a TEE | ✕ | ✓ | ✓ |
| Full-node certainty | ✓ | ✕ | ✓ |
| “Refresh-proof” trust anchor | ✓ | ✕ | ✓ |
| Rarely needs updating | ✕ | ✕ | ✓ |
Baked into the image. That is the only trust input.
Pulled through the untrusted host.
One recursive proof covers the chain back to genesis.
Merkle path against the snarked ledger, e.g. the approved code hash of a new TEE.
Only to attested code whose hash matches.
Full overview of our test build in the appendix.
A Rust light client, small enough to measure and ship inside the TEE image.
Speaks Mina’s native binprot encoding directly.
Runs, fetches and verifies zkApp state end to end.
| Other light clients | Mina light client | |
|---|---|---|
| Trust anchor lifetime | Goes out of date after a short time (weak-subjectivity windows, rotating committees). Must constantly cycle or hit bootstrap problems. | Valid until the next hard fork, set and forget. |
| Basis of trust | Trusted parties signing: consensus / committee signatures, honest-majority assumption. | Cryptographic proof via the snarked ledger. |
| Verification work | Follow headers and every validator-set change since the anchor. | One constant-size proof, however long the TEE was offline. |
| A lying host can… | Exploit a stale anchor, feed a minority fork, or stall bootstrap. | Only withhold or delay. Liveness, never safety. |
| Updates to the TEE | Track forks, committee and client changes, with frequent re-measurement. | Hard forks only. Fits a rarely-updated key-release TEE. |
| Security vs a full node | Strictly weaker. | Equivalent cryptographic strength. |
Opt-in / opt-out orchestration
Carries each user’s decision on an update to every TEE that holds their data.
AI has advanced to the point where individual corporate users of applications running in TEE ecosystems can use their AI agents to review code updates, and decide to remain in the ecosystem or not before the update takes place.
The host can update the code at any time. When an update hits, whatever attested code your IT team reviewed on signing the contract is invalid. (And the team are not going to do a review again!)
Your agents attest every proposed update in the background. You have a verifiable, credible exit before the update hits, for example if the agent detects a meaningful change in security posture.
Individual users’ agents read the new code at speed and decide whether the update is acceptable to them.
New code hash published for review.
AI reads the diff against the user’s own policy.
Not okay? Opt out (or simply don’t opt in).
Tells every TEE holding that user’s private data.
The user’s data never reaches code they rejected.
Admins, quorums, time-locks, per-user opt-outs, expressed as zkApp logic.
Approvals are proofs, not signatures. Who approved can stay private.
Thousands of individual decisions fold into a single state the key-release TEE reads in one step.
Reads the approved code hash and the per-user opt-outs from the same Mina state, then releases keys accordingly.
Each stays smaller and simpler. Both anchor to the same Mina light client pattern.
| General property | Practical implication of the general property for this use case |
|---|---|
| Succinctness | A long-lasting trust anchor and full-node security in 8 MB of Rust. |
| Recursion | Compresses the overall vote state into a single artefact without the need to reference or cross-check. |
| General ZK | Users can agree to remain users of the application or credibly exit without revealing they were or are using it. |
| TypeScript | Key parts of the opt-in / opt-out flow can be browser-based, allowing for widespread implementation. |
Every complex TEE ecosystem needs this, or something like it. The question is mainly one of productisation and promotion.
Full-node certainty about Mina state from one constant-size proof. Runs inside a TEE, trusts nothing but its own embedded anchors, and verifies today’s post-Mesa mainnet.
One wasm32-wasip2 component (8,221,817 B), of which 4.6 MB is Mina’s public SRS, embedded.
~3,000 lines of our own code on top of o1-labs’ pickles verifier and openmina’s wire types.
Peak RAM of the wasmtime process during a verify (~72 MB settled). RAM-only: no disk, no sidecar.
One post-Mesa block verified at native speed.
Of mina-tree’s ~79k lines, we use the hashing and account types.
no_std, from o1js-to-zkvmv1 used openmina’s verifier; v2 swapped it out. That swap is what made Mesa fixable.
Read from the daemon’s blockchainVerificationKey and spliced into kimchi’s format. Cross-checked byte-for-byte against an independent copy (28/28 commitments).
The fork-genesis state hash, chain id and captured headers for offline tests. Publicly checkable against any explorer.
Our patched daemon serves the account bytes and a 35-level path from the snarked ledger. Stock nodes don’t expose these. Every byte is checked against the verified header.
The block header itself can come from any Mina peer. Our latest test used a public mainnet seed.
Every verified block must cite it. Post-Mesa mainnet genesis, block #548,147.
The wrap-circuit VK: 3.6 KB, 28 curve-point commitments. Identifies which circuit a proof must satisfy.
Public parameters (Pallas + Vesta, 4.6 MB) and the gate definitions. Embedded, so they sit inside the measured wasm hash.
Config, not trust: libp2p chain id 0718f61a… (only keys the peer handshake), and finality depth k = 290. The app’s own anchor, the zkApp, is next. Chain anchors change only at a hard fork; the last was Mesa, 3 Sep 2026.
A merkle proof shows an account is in the ledger, not that it’s ours. So the zkApp’s identity is compiled in next to the chain anchors, inside the measured hash.
The zkApp’s public key.
Default MINA token, so the address maps to a single account.
The verification key of the contract allowed to hold this state.
Pin Proof so only the contract can change state. Our test zkApp uses Signature (owner key).
Headers, the account bytes and its 35-level merkle path, the node’s URL. Each is checked against what is already burned in.
Without the pin, a lying node can return any other real account and its merkle proof passes. Found in the June build; fixed and covered by five tests.
Approved reference values for a mixed TEE fleet. Stored as hi/lo field pairs; the zkApp enforces the state transitions.
| [0] | policy_epoch | 42 |
| [1] | status | COMMITTED (write-once latch) |
| [2] | committed_at | block 556,412 |
| [3–4] | gcp_cs.image_digest | sha256:9c1e4f…7b0a4b7a |
| [5–6] | aws_nitro.pcr0 | sha384:5a0d83…e1c2f9d6 |
| [7–8] | intel_tdx.mrtd | sha384:b41f07…3d9e06a2 |
| [9] | timelock_until | block 556,040 (review window) |
Transitions are proof-authorised (editState = Proof): the circuit only allows PROPOSED → COMMITTED, never back.
New measurements published as PROPOSED. Nothing is released.
Auditors, AI review and opt-outs act here. The only place to stop it.
Status latches to COMMITTED. The contract cannot unset it.
Consensus-final: no reorg can remove the commit.
The key-release TEE verifies the commit against the snarked ledger.
Keys go to workloads whose attestation evidence matches the reference values.
Once final, key release cannot be recalled. The ~24 h before the TEE sees it is delivery latency, not a cancellation window.
Revocation only blocks future releases (a new epoch that drops the reference value); keys already released stay released. Values shown are illustrative.
| State fields | Actions | Events | |
|---|---|---|---|
| Where it lives | In the zkApp account, a leaf of the ledger | Data on archive nodes; the account keeps only a rolling hash (action_state) | Archive nodes only; never in the ledger |
| Light-client proof | ✓ One merkle path to the proven snarked root | Needs the full untrusted list, re-hashed, plus the reduce logic | ✕ Nothing on-chain to check against |
| Takes effect | When the transaction is applied | Only after a later reduce transaction folds it into state | Never: a log, not state |
| Capacity | 32 fields since Mesa; one field can hold a merkle root for more | Unbounded queue | Unbounded log |
| Best for | Few, deliberate writes the TEE must trust: a release policy | Many concurrent writers, e.g. per-user opt-in/opt-out votes | Indexing and UI history |
Actions can feed the zkApp, events only log it. State is what the TEE trusts.
Many-writer flows (opt-in/opt-out) dispatch actions, a reducer folds them into a state-field root, and the key-release TEE reads that root, never the actions themselves.
From any Mina peer. 12.7 KB of binprot, of which ~11 KB is the chain proof.
passed in from outsideExact wire types from openmina’s p2p-messages.
inside the TEEHeader must cite the embedded fork-genesis hash.
inside the TEEWe compute it ourselves; it becomes the proof’s public input.
inside the TEEAccumulator check + kimchi opening. One proof covers the chain back to genesis.
inside the TEEledger_proof_statement.target, now proven, not claimed.
Account binprot and 35 sibling hashes from a node.
passed in from outsideIt must be the burned-in zkApp, and its merkle path must reach step 06’s root. Then read its state.
inside the TEEReadable = proven and final. The scan-state wait shrinks as network volume grows; finality is fixed at 290 blocks. Below ~18.8 h of scan state, the 290 blocks become the wait (the 12 h row). Today’s ~700 user txns/day gives ~55 h. Volumes include ~1.7 coinbase/fee transfers per block.
Model: lag ≈ 24 trees × 128 txns ÷ txns per hour (matched June’s measurement within 1%). Mesa halved slot time (180 s → 90 s); the scan state is unchanged. Mesa rows are estimates at 3.9 min blocks; the June row was measured on a real zkApp write.
27 scan-state slots, shared with coinbase and fee transfers → ~126 user txns.
90 s slots, 39% filled → a ceiling of ~46,700 user txns/day (~0.5 TPS).
Mesa halved it. ~4,400 zkApp commands/day today, the real bottleneck for zkApp-heavy volume.
Tip-read lag at full blocks (24 blocks). The root read never beats ~20 h; the k-leg is fixed.
Plain payments are the cheap way to fill the pipeline: ~1,700 extra txns/day reaches 24 h. Either way, no IT team is signing off on an update before 24 hours, agents or no agents.
12,717 bytes. Fields back to back, no names or tags. First bytes of block #556,001 from a mainnet seed.
protocol_statewhat we hashprotocol_state_proof≈ 11.1 KB recursive Pickles proofdelta_block_chain_proofcurrent_protocol_versionproposed_protocol_version_opt0x00–0x7f is the value itself (1 byte). 0xfe/0xfd/0xfc prefix a 2/4/8-byte value.
Fields in type-definition order, no names, no lengths. Decoding needs the exact type.
One tag byte (00 = None, 01 = Some …), then the payload.
32-byte little-endian integers. Lists are a length, then items.
ledger_proof_statement, sub_window_densities, the consensus constants, genesis_ledger_hashStable.V2 → V3); the Mesa header stayed byte-compatibleTested: flip one byte of the header’s protocol state and verification fails.
On the Mesa testnet: VK, state hash, proof shape, accumulator all matched. Eight hypotheses ruled out; the kimchi opening check still rejected.
proof-systems #3514: the EndoSclMul gate went from 11 to 12 constraints, shipped with Mesa. Our verifier checked the old gate.
Mesa-gate proof-systems, VK spliced from mainnet (2 of 28 commitments differ from testnet), fork-genesis hash. Post-Mesa mainnet verifies.
Lesson: a hard fork can change the verifier code, not just the key, which is why anchors are re-measured only at hard forks.
| Date | Network | What | Result |
|---|---|---|---|
| 2026-05-22 | Mainnet (pre-Mesa) | v1 (openmina verifier), header over libp2p | ✓ 442 ms native |
| 2026-05-22 | Mesa testnet | v1 on Mesa blocks; zkApp V3 decode + inclusion | ✕ OpenProof |
| 2026-06-12 | Mainnet (pre-Mesa) | v2 inside wasmtime, RAM-only | ✓ 18 s M1 · 85 s e2-small |
| 2026-06-13 | Mainnet (pre-Mesa) | Merkle inclusion against the snarked root | ✓ root matched |
| 2026-06-14 | Mainnet (pre-Mesa) | zkApp write → snarked read, tip-materialisation patch | ✓ after ~84 h |
| 2026-09-24 | Mainnet (post-Mesa) | Mesa gate + new anchors; header from a public seed | ✓ #556,001 in 1.3 s |
| 2026-09-24 | Mainnet (post-Mesa) | Rebuilt 8 MB wasm (zkApp burned in), verified inside wasmtime | ✓ 26 s · ~90 MB |
| 2026-09-24 | Library | Burned-in zkApp: wrong address, token, contract or write rule | ✓ all rejected |
| 2026-09-24 | Mainnet (post-Mesa) | Controls: tampered header, altered state hash, pre-fork proof, June image on the new chain | ✓ all rejected |
The public mainnet seed, minascan GraphQL and our patched OCaml daemon are all untrusted in this design; each was used as a source in testing.