# On-Chain abwickeln

> Von einem Basisbeweis aus Hunderten von Shards zu einem einzigen Groth16-Beweis, den ein Ethereum-Contract prüft. Der Rekursionsbaum, die Zeremonie des Deciders, die Schnittstelle des Contracts und was ein Deployment festlegt.

Ein Basisbeweis ist ein Block aus Shard-Beweisen, jeder ein GKR-Beweis mit seinen Commitments: Megabytes an Daten und Hunderte von Kurvenpunkten, die kein Contract prüfen kann. Die Abwicklung komprimiert ihn in drei Stufen, jede mit `bench` im Wurzelverzeichnis des Repositorys ausgeführt.

> Figure: Abwicklung. Jede Stufe verifiziert die vorherige. Vor dem Contract findet kein Pairing statt: Jede Mercury-Prüfung wird aufgeschoben und in einen einzigen Akkumulator gefaltet, den der Contract mit zwei Pairings einlöst. Die Zahlen stammen von Block 257.510.

## 1. Der Rekursionsbaum

Ein **Knoten** ist Apogee beim Beweisen eines Verifier-Programms. Ein **Blatt** verifiziert eine Reihe aufeinanderfolgender Basis-Shards; ein innerer Knoten verifiziert zwei bis vier Kind-Beweise; die **Wurzel** deckt jeden Basis-Shard ab. Jeder Knoten faltet außerdem jede Mercury-Prüfung, die seine Shards und Kinder aufschieben, in ein einziges Punktepaar, sodass der ganze Baum an der Spitze auf eine einzige Pairing-Behauptung hinausläuft.

```sh
# the base proof as an archive: host::proof_archive::write_proof from your host
# program, or `bench prove ... --out <dir>` for the Ethereum guests
cargo run --release -p bench -- recurse <dir>/<stem> --out <out> --in-flight 4
```

`recurse` schreibt die Schlüssel der beiden Rekursionsprogramme, baut darauf die Blatt- und Knoten-Binaries, legt einen Plan fest, bevor irgendetwas bewiesen wird (`<out>/tree.txt`: Blätter aus höchstens `--leaf` 64 Basis-Shards, dann Knoten aus höchstens `--fan-in` 4 Kindern), und beweist Knoten für Knoten. Jeder Knoten ist ein eigener Prozess, der seine Eingaben vor dem Beweisen nativ verifiziert; eine fehlerhafte Eingabe wird also namentlich zurückgewiesen. Ein angehaltener Lauf lässt sich fortsetzen: Bereits in `<out>` liegende Beweise bleiben erhalten, und ein Lauf mit abweichendem Plan oder abweichenden Programmen wird zurückgewiesen.

Das Beweisen der Basis bleibt von alledem unberührt. Ein Blatt verifiziert Basis-Shards genau so, wie sie sind.

## 2. Der Decider

Die Wurzel ist immer noch ein GKR-Beweis und einige Hundert Punkte. Der **Decider** ist ein Groth16-Schaltkreis, der die Wurzel so verifiziert, wie es ein Knoten täte, und nichts faltet. Stattdessen bindet er als Wires, deren Werte der Contract liefert, die Identitäten der beiden Rekursionsprogramme, den Exit-Status der Basisaussage, ihre öffentliche Eingabe und ihr Journal Byte für Byte sowie jeden Punkt, dem die Wurzel ein Pairing schuldet, mit seinem Skalar. Der Groth16-Beweis trägt ein einziges Commitment auf all diese Wires, und der Contract prüft es gegen die Werte, die er besitzt.

Ein Groth16-Schlüssel braucht eine Zeremonie. Phase 1 ist dieselbe Powers-of-Tau-Datei, auf der die Commitments des Baums beruhen. Phase 2 ist schaltkreisspezifisch und läuft in zwei Beitragsrunden:

```sh
cargo run --release -p bench -- ceremony <out> init          # once per root shape
cargo run --release -p bench -- ceremony <out> contribute    # round 1: alpha and beta, each contributor in turn
cargo run --release -p bench -- ceremony <out> seal
cargo run --release -p bench -- ceremony <out> contribute    # round 2: gamma, delta and eta
cargo run --release -p bench -- ceremony <out> key
cargo run --release -p bench -- decide <out>                 # the Groth16 proof, checked natively and in an EVM
```

Jeder Beitrag multipliziert eine Falltür mit einem Faktor, den nur sein Beitragender kannte, und wird mit einem Schnorr-Beweis festgehalten; jeder Zustand lässt sich also allein gegen den Schaltkreis und die Zeremoniedatei verifizieren. Eine Falltür ist unbekannt, solange einer ihrer Beitragenden ehrlich war. **Die Reihenfolge der Runden ist Teil der Soundness**: `alpha` und `beta` sind abgeschlossen, bevor irgendetwas durch `delta` oder `eta` geteilt wird.

> [!CAUTION]
> `bench decide --dev-key` leitet jede Falltür aus einem öffentlichen Seed ab, für Entwicklung und Tests. Jeder kann damit einen Beweis fälschen, und seine Ausgaben werden als `development.*` geschrieben, damit sie nicht mit denen einer Zeremonie verwechselt werden können. Eine Zeremonie, die auf einer einzigen Maschine läuft, ist ebenfalls keine Zeremonie: Sie braucht einen ehrlichen Beitragenden pro Runde.

`decide` schreibt `decision.constructor` und `decision.calldata`: die Deployment-Argumente und den Aufruf, als Hex.

## 3. Der Contract

`contracts/ApogeeVerifier.sol` hat einen einzigen Einsprungpunkt:

```solidity
function verify(
    bytes calldata input,        // the base program's public input
    bytes calldata output,       // its journal
    uint256 exitStatus,          // the status you require, normally 0
    uint256[10] calldata proof,  // Groth16 A, B, C and the bound wires' commitment D
    uint256[] calldata points    // x, y and scalar of each point, side [1]_2's then side [x]_2's
) external view returns (bool);
```

Der Contract rekonstruiert die gebundenen Werte aus den Calldata, prüft die Pairing-Gleichung von Groth16, faltet die Punkte jeder Seite mit `ecMul` und `ecAdd`, was zugleich erzwingt, dass jeder Punkt auf der Kurve liegt, und prüft die gefaltete Behauptung `e(A, [1]_2) = e(B, [x]_2)`. Ein Anwendungs-Contract ruft ihn auf und handelt dann anhand des Journals: siehe die [Skizze des Hauptbuchs](https://apogee.gweb3networks.com/docs/blockchain-native#ledger-native).

## Was ein Deployment festlegt

Der Konstruktor nimmt den Groth16-Schlüssel, die beiden G2-Punkte der Zeremonie, die Identitäten der Blatt- und Knotenprogramme, die Zahl der Punkte auf jeder Seite und **die Bytelängen der öffentlichen Eingabe und des Journals** entgegen. Ein bereitgestellter Verifier bedient also:

- **Ein einziges Basisprogramm.** Seine Identität ist eine Konstante im Image des Blattprogramms, die die Identität des Blatts bindet.
- **Eine einzige Wurzelform.** Der Schaltkreis des Deciders hängt vom Programm der Wurzel, ihren Shard-Zahlen und den Längen der öffentlichen Werte ab; ein Schlüssel und seine Zeremonie gelten also je Form.
- **Öffentliche Werte fester Länge.** `verify` weist eine Eingabe oder ein Journal jeder anderen Länge zurück. Entwerfen Sie Gastprogramme (Guests), deren öffentliche Werte on-chain eine feste Größe haben, etwa einen festen Datensatz oder einen 32-Byte-Digest.

Der Contract zahlt etwa 9.000 gas pro Punkt, weil der Schaltkreis keinen davon faltet.

## Gemessen

Block 257.510, mit dem Baum auf einer Maschine mit 32 CPUs und 247 GiB und mit Zeremonie und Decider auf einem Laptop mit 18 Kernen:

| Stufe | Ergebnis |
| --- | --- |
| Basisbeweis | 207 Shards, 14,5 MB, 2.481 s |
| Baum | 4 Blätter aus höchstens 64 Basis-Shards und eine Wurzel: 116 Shards |
| Blätter, vier gleichzeitig | 21, 24, 23 und 27 Shards; 2.157 s; Spitze 92 GiB |
| Wurzel, vier Shards gleichzeitig in Bearbeitung | 21 Shards, 460 s, 1,03 MB |
| Decider-Schaltkreis | 7.896.686 Constraints, eine Domäne der Größe `2^23` |
| Zeremonie | `init` 65 s; ein Beitrag 50–56 s; `key` 70 s und 12,7 GB; der Schlüssel 2,65 GB |
| Decider-Beweis | Schlüssel in 1 s eingelesen, Beweis 18,5 s, 6,1 GB |
| Contract | 358 Punkte; 3.620.026 gas; 34.980 Byte Calldata |

Die Spezifikation all dessen ist [Rekursion und Decider](https://apogee.gweb3networks.com/docs/auditors/spec/recursion).
