# Recursion and Settlement

> How a base proof of hundreds of shards becomes one Groth16 proof that a contract checks. Apogee proving its own verifier, the tapes that make that cheap, the transcript chained across a tree, and pairings folded until only one is left.

A base proof of an Ethereum block is 207 shard proofs: 14.5 MB, each shard a GKR proof with its commitments and a Mercury opening that ends in a pairing check. A contract can check none of that directly. Recursion compresses it, and the way it does is the most consequential design choice after the GKR engine itself.

## The base proof is untouched

The first decision is what recursion does *not* do. No base key, statement or proof changes to make recursion possible: a leaf verifies base shards exactly as a native verifier would. Everything recursion needs is added above the base proof, never inside it. A block can be verified natively, recursed, or both, from the same bytes.

## Apogee proves its own verifier

A **node** of the tree is Apogee proving a verifier program. A **leaf** verifies a run of consecutive base shards, from `from` to `to`; an internal **node** verifies two to four children, each a whole proof of a leaf or node program; the **root** covers every base shard. Every node is proved by the same streaming prover as a base block.

Running the Rust verifier as RISC-V instructions would work, and measured 3.0 billion cycles for one block's 207 shards: fifteen times the block itself. So nodes run in a **recursion format** instead.

## The recursion format

A statement is in the recursion format exactly when its program declares field families. The format adds one address space and four coprocessor families on it, all invoked through the ordinary delegation ABI, and changes nothing else:

| Family | One row is |
| --- | --- |
| `FIELD_WINDOWS` | one **field cell**: a memory cell holding a whole `Fr` element, in the same memory multiset as RAM |
| `FR_OP` | one field operation over cells: multiply, add, subtract, multiply-accumulate, invert, assert-equal, and constant-building steps |
| `P2_FIELD` | one Poseidon2 duplex step over cells, so a transcript runs at one row per permutation |
| `FIELD_IO` | eight RAM words into a cell, or a cell back into eight words |
| `FQ_OP` | one BN254 base-field operation, an element being four cells of 64-bit limbs, so curve arithmetic runs at one row per field operation |

Two further changes make a recursion shard cheaper to verify by its parent. Its memory and witness columns are committed as **stacks** of up to `2^24` evaluations, so a parent folds a handful of points instead of hundreds. And a recursion request writes its frame base advanced past the frame, so frames laid back to back replay as back-to-back `ecall`s, one row a call.

## Tapes

A shard's checks have a fixed shape for its family and height. So the host compiles them, once, into a **tape**: a straight-line list of coprocessor calls over absolute cells, in which nothing branches on a value. A shard's tape is the native verifier's steps for that shard, call for call: the shard transcript, the GKR backward pass, the lookup and root checks, and the Mercury opening's twelve scalars. Every check is an assert-equal.

Each recursion program's tapes, fold templates and constants are built at compile time by the verifier crate itself and placed in the program's read-only data. The program identity therefore binds every tape the program replays: proving that a node ran its program is proving that it ran exactly these checks.

## A transcript chained across the tree

The base statement's global transcript is one sponge over the whole statement. The tree splits it without changing it. The node holding shard 0 runs the prefix, through the public input digest; every node absorbs its own shards' memory commitments, continuing from the state its predecessor left; the node holding the last shard runs the suffix and draws the memory challenges every node had taken as claims. A node's journal records the chain's state at both ends of its range, and a parent holds its children's states to meet.

A node also holds its children to one another: exit status 0, one base statement (its shape, digest, challenges, input and journal digest, exit status and shard count), adjacent shard ranges, chain states that meet, time windows in order across the seam, and the identities of the recursion programs. A node that holds a whole statement makes the memory argument.

## Folding the pairings

No node computes a pairing. Each shard's Mercury check is deferred as twelve `(side, scalar, point)` entries; after the shard's tape, the node's own transcript absorbs the shard transcript's final state and draws weights, and every entry is added, weighted, into one running pair of points `(A, B)` representing the claim `e(A, [1]_2) = e(B, [x]_2)`. The batch check that ties a shard's combined commitment to its columns is folded beside it. Points every shard of a family shares, such as `[1]_1` and the setup commitments, accumulate one scalar each and enter once. A child's `(A, B)` enters under a weight drawn after its whole journal.

Each side is one multi-scalar multiplication on `FQ_OP`, run as a static template: Pippenger with 8-bit digits over GLV halves, every point held to the curve, every step fixed in advance. A point costs about 400 `FQ_OP` calls.

At the root, the tree's whole content has collapsed: every base shard verified, the transcript run end to end, the memory argument made, and every opening folded into one pairing claim. What remains is that claim and two program identities.

## The decider

The root is still a GKR proof and some hundreds of points, which a contract cannot check. The **decider** is a Groth16 circuit that runs the node procedure over one child, the root, through a driver that writes rank-1 constraints instead of coprocessor calls, and holds the root's journal to the whole range of base shards. It folds nothing: each point the root owes the final pairing, with its scalar, becomes a **bound wire**, a value the verifier holds, committed in the proof under a fifth trapdoor rather than passed as a public input. So are the two identities, the base exit status, and the base public input and journal, byte by byte.

Apogee's Groth16 differs from the textbook in three ways: the bound-wire commitment, no blinding, and a proving key over the Lagrange basis that the powers-of-tau ceremony already publishes. Its key comes from a two-phase ceremony: phase 1 is the same ceremony file the commitments are under; phase 2 is the circuit's own, with contributions to `α` and `β` finished before any to `γ`, `δ` and `η`, an order that is itself part of soundness.

`ApogeeVerifier.sol` rebuilds the bound values from calldata, checks the Groth16 equation, folds both sides' points with `ecMul` and `ecAdd`, which also holds every point to the curve, and checks the one remaining pairing. Its constructor fixes the key, the ceremony's two G2 points and the two recursion programs' identities. A deployment serves one base program, one root shape and fixed public-value lengths.

## Measured

Block 257,510, tree on a 32-CPU machine, ceremony and decider on an 18-core laptop:

| | |
| --- | --- |
| Base proof | 207 shards, 14.5 MB, 2,481 s |
| Tree | 4 leaves of at most 64 base shards and a root: 116 shards in all |
| Leaves, four at once | 21, 24, 23 and 27 shards; 2,157 s; 92 GiB peak |
| Root | 21 shards, 460 s, 1.03 MB |
| Decider | 7,896,686 constraints; proof in 18.5 s and 6.1 GB |
| Contract | 358 points; 3,620,026 gas; 34,980 bytes of calldata |

The specification: [Recursion and decider](https://apogee.gweb3networks.com/docs/auditors/spec/recursion). Running it yourself: [Settle on-chain](https://apogee.gweb3networks.com/docs/launch/on-chain).
