# Régler sur la chaîne

> D’une preuve de base de centaines de shards à une seule preuve Groth16 que vérifie un contrat Ethereum. L’arbre de récursion, la cérémonie du décideur, l’interface du contrat, et ce que fixe un déploiement.

Une preuve de base est un bloc de preuves de shards, chacune étant une preuve GKR accompagnée de ses engagements : des mégaoctets de données et des centaines de points de courbe, qu’aucun contrat ne peut vérifier. Le règlement la compresse en trois étapes, chacune lancée avec `bench` à partir de la racine du dépôt.

> Figure: Règlement. Chaque étape vérifie la précédente. Aucun couplage n’est calculé avant le contrat : chaque vérification Mercury est différée et repliée dans un seul accumulateur que le contrat acquitte avec deux couplages. Les chiffres sont ceux du bloc 257 510.

## 1. L’arbre de récursion

Un **nœud**, c’est Apogee qui prouve un programme vérificateur. Une **feuille** vérifie une suite de shards de base consécutifs; un nœud interne vérifie de deux à quatre preuves enfants; la **racine** couvre tous les shards de base. Chaque nœud replie aussi chaque vérification Mercury que ses shards et ses enfants diffèrent en une seule paire de points, si bien que l’arbre entier se réduit à une seule affirmation de couplage au sommet.

```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` écrit les clés des deux programmes de récursion, construit sur elles les binaires feuille et nœud, fixe un plan avant que quoi que ce soit ne soit prouvé (`<out>/tree.txt` : des feuilles d’au plus `--leaf` 64 shards de base, puis des nœuds d’au plus `--fan-in` 4 enfants), et prouve nœud par nœud. Chaque nœud est un processus distinct, qui vérifie ses entrées en natif avant de prouver, si bien qu’une mauvaise entrée est refusée nommément. Une exécution interrompue reprend : les preuves déjà présentes dans `<out>` sont conservées, et une exécution dont le plan ou les programmes diffèrent est refusée.

La preuve de base n’est en rien touchée par tout ceci. Une feuille vérifie les shards de base exactement tels qu’ils sont.

## 2. Le décideur

La racine reste une preuve GKR accompagnée de quelques centaines de points. Le **décideur** est un circuit Groth16 qui vérifie la racine comme le ferait un nœud, et ne replie rien. Il lie plutôt, sous forme de fils dont le contrat fournit les valeurs, les identités des deux programmes de récursion, le statut de sortie de l’énoncé de base, son entrée publique et son journal octet par octet, et chaque point auquel la racine doit un couplage, avec son scalaire. La preuve Groth16 porte un seul engagement sur l’ensemble de ces fils, et le contrat le vérifie par rapport aux valeurs qu’il détient.

Une clé Groth16 exige une cérémonie. La phase 1 est le même fichier de puissances de tau que celui sur lequel reposent les engagements de l’arbre. La phase 2 est propre au circuit et se déroule en deux tours de contributions :

```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
```

Chaque contribution multiplie une trappe par un facteur que seul son contributeur connaissait, et l’enregistre avec une preuve de Schnorr, si bien que tout état peut être vérifié par rapport au seul circuit et au seul fichier de cérémonie. Une trappe reste inconnue tant qu’un seul de ses contributeurs a été honnête. **L’ordre des tours fait partie de la solidité** (*soundness*) : `alpha` et `beta` sont achevés avant que quoi que ce soit ne soit divisé par `delta` ou `eta`.

> [!CAUTION]
> `bench decide --dev-key` dérive chaque trappe d’une graine publique, pour le développement et les tests. N’importe qui peut contrefaire une preuve sous cette clé, et ses sorties sont écrites sous le nom `development.*` pour qu’on ne puisse pas les confondre avec celles d’une cérémonie. Une cérémonie exécutée sur une seule machine n’est pas non plus une cérémonie : il lui faut un contributeur honnête par tour.

`decide` écrit `decision.constructor` et `decision.calldata` : les arguments de déploiement et l’appel, en hexadécimal.

## 3. Le contrat

`contracts/ApogeeVerifier.sol` a un seul point d’entrée :

```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);
```

Il reconstruit les valeurs liées à partir du calldata, vérifie l’équation de couplage de Groth16, replie les points de chaque côté avec `ecMul` et `ecAdd`, ce qui astreint aussi chaque point à la courbe, et vérifie l’affirmation repliée `e(A, [1]_2) = e(B, [x]_2)`. Un contrat d’application l’appelle, puis agit selon le journal : voir [l’esquisse du registre](https://apogee.gweb3networks.com/docs/blockchain-native#ledger-native).

## Ce que fixe un déploiement

Le constructeur prend la clé Groth16, les deux points G2 de la cérémonie, les identités des programmes feuille et nœud, le nombre de points de chaque côté, et **les longueurs en octets de l’entrée publique et du journal**. Un vérificateur déployé sert donc :

- **Un seul programme de base.** Son identité est une constante de l’image du programme feuille, que lie l’identité de la feuille.
- **Une seule forme de racine.** Le circuit du décideur dépend du programme de la racine, de ses nombres de shards et des longueurs des valeurs publiques : une clé et sa cérémonie sont donc propres à chaque forme.
- **Des valeurs publiques de longueur fixe.** `verify` refuse une entrée ou un journal de toute autre longueur. Concevez des programmes invités dont les valeurs publiques sur la chaîne ont une taille fixe, comme un enregistrement fixe ou un condensé de 32 octets.

Le contrat paie environ 9 000 gas par point, parce que le circuit n’en replie aucun.

## Mesures

Bloc 257 510, avec l’arbre sur une machine à 32 CPU et 247 GiB, et la cérémonie et le décideur sur un portable à 18 cœurs :

| Étape | Résultat |
| --- | --- |
| Preuve de base | 207 shards, 14,5 MB, 2 481 s |
| Arbre | 4 feuilles d’au plus 64 shards de base et une racine : 116 shards |
| Feuilles, quatre à la fois | 21, 24, 23 et 27 shards; 2 157 s; pic de 92 GiB |
| Racine, quatre shards en cours de traitement | 21 shards, 460 s, 1,03 MB |
| Circuit du décideur | 7 896 686 contraintes, sur un domaine de `2^23` |
| Cérémonie | `init` 65 s; une contribution de 50 à 56 s; `key` 70 s et 12,7 GB; la clé 2,65 GB |
| Preuve du décideur | clé lue en 1 s, preuve en 18,5 s, 6,1 GB |
| Contrat | 358 points; 3 620 026 gas; 34 980 octets de calldata |

La spécification de l’ensemble se trouve dans [Récursion et décideur](https://apogee.gweb3networks.com/docs/auditors/spec/recursion).
