# L’architecture

> Apogee VM de bout en bout. Ce qu’énonce une preuve, le chemin d’un binaire de programme invité jusqu’à un appel de contrat, la façon dont les grands composants s’articulent, et les choix de conception qui les façonnent.

Apogee prouve des exécutions de programmes RV32IMAC. Cette section décrit le système au niveau de ses grands composants : ce que fait chacun, pourquoi il est construit ainsi, et comment il passe le relais au suivant. La section [Auditeurs](https://apogee.gweb3networks.com/docs/auditors) présente le même système au niveau de chaque colonne et de chaque porte.

## Ce qu’énonce une preuve

Un vérificateur détient trois éléments qu’il ne croit pas sur la seule parole du prouveur :

- l’**identité du programme**, un élément du corps qui condense les tables d’instructions du programme, son image mémoire initiale, son pc d’entrée et sa configuration;
- le **condensé SRS** de la cérémonie que doit porter une clé de vérification;
- une **clé de vérification**, qui peut provenir de n’importe qui, car son chargement recalcule l’identité et le condensé SRS à partir de son propre contenu et exige que ses circuits soient ceux du registre du vérificateur.

L’énoncé de la preuve porte l’entrée publique, la sortie publique (le **journal**), le statut de sortie, et l’enregistrement de la forme de l’exécution : les nombres de shards, les fenêtres mémoire, les registres et le pc finaux, ainsi que les engagements mémoire et les racines de chaque shard. Une preuve dont la vérification réussit établit que le programme de cette identité, lancé à son pc d’entrée sur son image, avec l’entrée publique dans sa fenêtre d’entrée et des données auxiliaires (*advice*) choisies par le prouveur, s’exécute instruction par instruction jusqu’à `EXIT` avec ce statut, après avoir écrit ce journal. Rien n’est affirmé au sujet des données auxiliaires, et rien n’est caché : aucun engagement ni aucune preuve n’est aveuglé.

## D’un binaire à un appel de contrat

> Figure: Les quatre étapes. Le programme est fixé avant que quoi que ce soit ne s’exécute; l’exécution est découpée en shards; chaque shard est prouvé isolément, à l’exception de l’argument de mémoire, qui se referme une seule fois sur l’ensemble des shards; le règlement compresse le bloc pour un contrat.

1. **Le programme.** Le chargeur lit l’ELF dans une `ProgramImage`, en développant sur place les instructions compressées. Le décodeur achemine chaque instruction vers l’une des sept familles d’instructions et construit la table décodée de chaque famille, une ligne par demi-mot de code, puis engage le tout sous la forme de l’identité du programme. [Programmes et identité](https://apogee.gweb3networks.com/docs/architecture/program).
2. **Exécution.** L’émulateur exécute le programme invité sur un seul hart. Un cycle est une ligne de la famille à laquelle appartient son instruction, et cette ligne enregistre des lectures et des écritures horodatées du pc, des registres et de la RAM. Le hachage et l’arithmétique des grands entiers sont délégués : un `ecall` désigne un cadre en RAM, et une ligne d’une famille de délégation effectue le travail sur ce cadre. [Exécution, familles et shards](https://apogee.gweb3networks.com/docs/architecture/execution).
3. **Shards.** Les lignes d’une famille sont découpées en shards de la hauteur de la famille, une puissance de deux comprise entre `2^8` et `2^22`. La mémoire que touche une exécution est couverte par des shards des familles de fenêtres, qui donnent à chaque mot ses valeurs initiale et finale. Le shard est l’unité de preuve; un bloc en compte des centaines.
4. **La preuve d’un shard.** Ses colonnes sont engagées avec [Mercury](https://apogee.gweb3networks.com/docs/architecture/mercury). Le circuit de la famille est parcouru à rebours par le [moteur GKR](https://apogee.gweb3networks.com/docs/architecture/gkr), de ses sorties jusqu’à ces colonnes, à raison d’un sumcheck par couche, et chaque colonne est ouverte au point unique où aboutit cette passe, en une seule ouverture groupée.
5. **Le bloc.** Un `BlockProof` est l’énoncé accompagné des preuves de ses shards. La vérification exécute la transcription globale une fois, les vérifications de chaque shard, et le [rapprochement de la mémoire](https://apogee.gweb3networks.com/docs/architecture/memory-lookups) une fois, sur les racines de tous les shards.
6. **Récursion et règlement.** Des programmes vérificateurs, prouvés par Apogee lui-même, vérifient des suites de shards et replient leurs couplages différés. Un arbre de tels programmes aboutit à une racine, un circuit Groth16 revérifie la racine, et `ApogeeVerifier.sol` vérifie cette preuve et le couplage replié. [Récursion et règlement](https://apogee.gweb3networks.com/docs/architecture/recursion).

Le prouveur exécute le programme invité deux fois : une fois pour engager les colonnes mémoire de chaque shard, ce qui fixe l’énoncé et ses défis, et une fois pour prouver chaque shard à mesure qu’il se remplit. Sa mémoire est bornée par les shards en cours de traitement, et non par la longueur de l’exécution. [Le prouveur en flux](https://apogee.gweb3networks.com/docs/architecture/streaming).

## Les choix qui le façonnent

**Un seul corps, une seule courbe.** Tout est défini sur le corps des scalaires de BN254 : les circuits, la transcription, les engagements et la récursion. C’est ce qui permet à un nœud de l’arbre de récursion de vérifier des shards de base dans sa propre arithmétique, et à l’arbre de se terminer par une preuve Groth16 qu’Ethereum vérifie avec son précompilé de couplage.

**Des circuits GKR en couches plutôt que des tables de contraintes engagées.** Le circuit d’une famille est un empilement de couches de portes de degré 2 au-dessus de ses colonnes engagées. Seule la couche inférieure est engagée; chaque couche au-dessus est prouvée par sumcheck en une seule passe arrière, sans jamais être engagée. À la fin de la passe, chaque colonne engagée fait l’objet d’une affirmation en un même point : un shard a donc besoin d’exactement une ouverture. [Le moteur GKR](https://apogee.gweb3networks.com/docs/architecture/gkr) explique pourquoi c’est là l’économie centrale du moteur.

**Une ouverture de taille constante.** Mercury ouvre un engagement multilinéaire avec huit points de courbe et six éléments du corps, soit 704 octets, quelle que soit la taille du polynôme et quel que soit le nombre de colonnes qui partagent le point. Ses vérifications ont la forme `e(A, [1]_2) = e(B, [x]_2)`, que la récursion peut replier au lieu d’effectuer le couplage.

**Un seul argument de mémoire pour toute l’exécution.** Chaque accès, dans chaque shard de chaque famille, est un tuple d’un même multiensemble lecture/écriture, et le vérificateur rapproche les produits une fois par énoncé. Le pc est une cellule de ce multiensemble : l’ordre, la continuité et l’unicité des cycles d’un shard à l’autre ne demandent donc aucun autre argument, et aucun shard n’a besoin de s’enchaîner à son voisin.

**Des délégations sous forme de familles, et non d’instructions.** Une fonction coûteuse dispose de sa propre famille de circuits, invoquée par un `ecall` sur un cadre de RAM et appariée une à une avec sa demande par le même multiensemble. Les circuits d’instructions restent petits, et un programme invité ne paie une délégation que s’il l’appelle.

**Le flux plutôt que la matérialisation.** À environ 300 octets par cycle, la trace serait le plus gros objet du système : elle n’existe donc jamais. Le prouveur exécute deux fois et ne détient que les shards en cours de traitement.

**Aucune cryptographie empruntée.** Les corps, la courbe, le couplage, la MSM, le hachage, l’engagement polynomial, GKR et Groth16 sont implémentés dans le dépôt et spécifiés page par page. arkworks, Plonky3 et zkhash n’apparaissent que comme oracles de test.

## Comment la solidité (*soundness*) se compose

La passe GKR et l’ouverture de chaque shard rattachent les sorties de son circuit à des colonnes engagées. Par-dessus, les arguments suivants couvrent toute l’exécution :

| Affirmation | Portée par |
| --- | --- |
| Chaque ligne obéit à son instruction | les portes de contrainte du circuit de la famille, nulles sur chaque ligne |
| L’instruction d’une ligne est celle du programme à son pc | un lookup du pc et des champs de la ligne dans la table décodée de la famille, que l’identité engage |
| Chaque lecture renvoie la dernière écriture | un seul multiensemble sur tous les shards; le vérificateur multiplie les racines de lecture et d’écriture de chaque shard avec des facteurs de frontière pour les registres et le pc |
| Les lignes forment un seul chemin du pc d’entrée jusqu’à la sortie, dans l’ordre du programme | le pc est une cellule de ce multiensemble, écrite au moins quatre horodatages après sa lecture |
| Une valeur est un octet, un mot, un signe, un XOR | des canaux LogUp sur des tables d’intervalle, des tables d’octets et la table générique |
| L’entrée publique et le journal sont les octets annoncés | les colonnes initiale et finale des deux fenêtres publiques, astreintes aux extensions multilinéaires des octets |
| Un calcul délégué est celui de la fonction | des lignes d’invocation qui lisent et écrivent le cadre par le même multiensemble, appariées une à une avec leur `ecall` |

Les défis proviennent d’une transcription duplex Poseidon2. La transcription globale absorbe l’énoncé entier, engagements mémoire de chaque shard compris, avant que les défis mémoire n’existent; la transcription de chaque shard est amorcée à partir de son état final. La [carte de solidité](https://apogee.gweb3networks.com/docs/auditors/soundness-map) mène chaque ligne du tableau jusqu’aux sections qui la prouvent.

## Le code, couche par couche

| Couche | Crates | Rôle |
| --- | --- | --- |
| Arithmétique | `field`, `curve`, `poly`, `sumcheck` | `Fr`; la tour `Fq`, G1, G2, le couplage, la MSM; les polynômes multilinéaires; le zerocheck |
| Fiat–Shamir et mise en place | `transcript`, `srs` | Poseidon2 et la transcription duplex; l’ingestion de la cérémonie, KZG, la phase 1 de Groth16 |
| Engagements | `pcs`, `pcs-verify` | Mercury et sa vérification différée |
| Le programme | `loader`, `isa`, `program` | de l’ELF à l’image, le décodeur, les tables décodées, `VmConfig` et l’identité |
| Exécution | `emulator`, `trace` | l’exécuteur et ses traceurs; les lignes, l’état de la mémoire, les constructeurs de colonnes |
| Circuits | `constraints`, `gkr-verify`, `gkr` | chaque circuit sous forme de données; le vérificateur et le prouveur GKR |
| Preuve et vérification | `verifier-core`, `verifier`, `prover` | l’énoncé, les transcriptions, les clés, chaque vérification; le prouveur en flux |
| Règlement | `host`, `groth16`, `contracts/` | le SDK hôte, l’arbre de récursion et le décideur; `ApogeeVerifier.sol` |
| Assurance | `checker`, `tools/` | des validateurs indépendants, la suite de falsification, des bancs d’essai, des profileurs, des oracles |

Le vérificateur est la seule partie de confiance : le prouveur ne valide rien, et une entrée erronée coûte à un prouveur honnête une preuve qui échoue. [Le modèle de sécurité](https://apogee.gweb3networks.com/docs/architecture/security) énumère précisément les crates sur lesquelles repose la solidité.
