# Prouver et vérifier

> Enregistrer un programme, prouver une exécution, vérifier le bloc et conserver la preuve. Les hauteurs, les shards en cours de traitement, les puissances de la cérémonie dont une preuve a besoin, et les deux valeurs qu’un vérificateur doit détenir lui-même.

## Les trois appels

```rust title="Mise en place, preuve, vérification"
let params = program::ProgramParams::defaults();
let ptau = std::path::Path::new("assets/ptau/ppot_0080_24.ptau");
let srs = srs::Srs::from_ptau(ptau, 22).expect("ceremony");

let setup = host::setup(&elf, &params, srs).expect("registers");          // once per program
let proven = host::prove(&setup, &io, 4).expect("proves");                // at most 4 shards in flight
host::verify(&setup.vk, &proven.block).expect("verifies");

assert_eq!(setup.vk.identity.to_bytes(), registered); // from your own channel, never the proof
assert_eq!(proven.exit_code, 0);
```

- **`host::setup`** charge l’ELF, le décode en ses tables de familles et sa `VmConfig`, engage les colonnes de mise en place sous la cérémonie, et construit la clé de vérification. Son coût se paie une fois par programme et par choix de hauteurs, et non à chaque exécution.
- **`host::prove`** exécute le programme invité deux fois et prouve chaque shard ([ci-dessous](#two-passes)). Il renvoie un `Proven` : le `BlockProof`, le code de sortie, le nombre de cycles, le journal et un rapport sur l’exécution.
- **`host::verify`** vérifie le bloc par rapport à la clé, à l’aide de l’énoncé que porte le bloc. Il ne compare ni l’identité ni le condensé SRS à quoi que ce soit : cette comparaison vous revient.

Le [Démarrage rapide](https://apogee.gweb3networks.com/docs/launch/quickstart#prove) exécute exactement ce code sur un petit programme invité, avec sa sortie réelle.

## Ce qu’un vérificateur doit détenir lui-même

Deux valeurs proviennent d’un canal que le prouveur ne contrôle pas :

1. **L’identité du programme.** Face à une identité fournie par le prouveur, une preuve montre seulement qu’un programme *quelconque* s’est exécuté. Un vérificateur enregistre l’identité de la version à laquelle il fait confiance et la compare à celle de la clé.
2. **Le condensé SRS de la cérémonie.** Une clé se charge sous le condensé que donnent ses propres points, quel qu’il soit. Une clé construite sur un `τ` connu pourrait ouvrir n’importe quoi, et n’est refusée que par la comparaison de son condensé avec celui de la cérémonie.

La clé de vérification elle-même peut provenir de n’importe qui, y compris du prouveur : 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. Lisez ensuite l’énoncé : le statut de sortie d’abord, puis le journal.

## Hauteurs

Chaque famille a une **hauteur**, le nombre de lignes de l’un de ses shards, choisie parmi `2^8, 2^12, 2^16, 2^18, 2^20, 2^22`. Les hauteurs font partie du programme, et non d’une exécution : chaque hauteur est liée dans l’identité.

| Groupe de familles | Par défaut | Plancher | Notes |
| --- | --- | --- | --- |
| Les sept familles d’instructions | `2^22`, ou `2^20` pour `MUL_DIV` et `ATOMICS` | `2^20` | le plancher de leurs vérifications d’intervalle sur les horodatages |
| `INIT_TEARDOWN`, `ZERO_WINDOWS`, `ADVICE_WINDOWS` | `2^22` | `2^16` | une seule hauteur de fenêtre partagée; la fenêtre 0 doit contenir chaque octet de l’image issu du fichier |
| `PUBLIC_INPUT`, `PUBLIC_OUTPUT` | `2^12` | fixée | la hauteur place leurs fenêtres |
| Familles de délégation | voir [Délégations](https://apogee.gweb3networks.com/docs/launch/delegations#cost) | propre à chaque famille | |

Une famille qui a des lignes coûte au moins un shard entier de sa hauteur : une exécution courte gaspille donc moins aux petites hauteurs, et une longue a besoin de moins de shards aux grandes hauteurs. Une table décodée doit aussi être assez haute pour atteindre la dernière instruction de la famille : `2^20` atteint 1,9375 MiB de code et `2^22` atteint 7,9375 MiB. Le programme invité Ethereum se prouve à `2^20` pour chaque famille dont la hauteur est au choix.

```rust title="Familles d’instructions à leur plancher, fenêtres de RAM à 2^16"
use constants::family;

let mut params = program::ProgramParams::defaults();
for f in 0..7 {
    params.heights[f] = 1 << 20;
}
for f in [family::INIT_TEARDOWN, family::ZERO_WINDOWS, family::ADVICE_WINDOWS] {
    params.heights[f as usize] = 1 << 16; // window 0 is then 256 KiB: the image must fit in it
}
```

La cérémonie doit fournir autant de puissances que la famille la plus haute a de lignes, et au moins `2^18` pour la table de lookup générique : `Srs::from_ptau(path, k)` avec `2^k` au moins égal à la plus grande hauteur.

## Shards en cours de traitement

Le troisième argument de `host::prove` est `max_in_flight`, le nombre de shards prouvés simultanément. C’est le seul réglage qui échange de la mémoire contre du temps :

- **La mémoire suit les shards en cours de traitement**, et non le nombre de cycles. Chaque shard en cours de traitement occupe ses lignes, sa passe avant et sa preuve à mesure qu’elle grandit. Un shard `2^20` de la famille d’instructions la plus large occupe environ 8,4 GiB dans sa passe avant; un shard `KECCAK_F` de `2^18`, environ 42 GiB.
- **Le temps suit le nombre de shards qui avancent côte à côte**, jusqu’à concurrence de vos cœurs. Au sein d’un shard, le travail s’exécute sur tous les cœurs.
- **La preuve n’en dépend pas.** Le bloc est identique octet pour octet avec 1 ou 8 shards en cours de traitement.

Commencez bas sur un portable, à deux ou quatre, et augmentez la valeur sur un serveur jusqu’à ce que la limite soit la mémoire, et non les cœurs. `bench prove` utilise 8 par défaut.

## Les deux passes

`host::prove` travaille en flux. Il ne détient jamais la trace d’exécution entière, qui, à environ 300 octets par cycle, serait le plus gros objet du système.

1. **La passe 1** exécute le programme invité et, à mesure que chaque shard se remplit, engage ses colonnes mémoire, conserve les engagements et abandonne les lignes. À la sortie, elle construit l’énoncé et tire les défis que partagent tous les shards.
2. **La passe 2** exécute de nouveau. L’émulateur est déterministe : elle découpe donc les mêmes shards. Chacun est rempli, prouvé et abandonné à son arrivée, et seule sa preuve est conservée.

C’est pourquoi la génération de preuves prend le temps de deux exécutions, avec une mémoire bornée par les shards en cours de traitement. [Le prouveur en flux](https://apogee.gweb3networks.com/docs/architecture/streaming) l’explique en profondeur.

## Conserver la preuve

`host::proof_archive::write_proof(dir, stem, vk, block)` écrit quatre fichiers, chacun contenant les octets bruts de son type :

```text
<stem>.vk         the verifying key
<stem>.identity   the key's identity, 64 lowercase hex digits and a newline
<stem>.public     the statement: input, journal, exit status, the execution's record
<stem>.block      the block proof
```

`read_proof(dir, stem)` les relit. Le fichier `.identity` enregistre ce qu’a affirmé l’exécution; un vérificateur compare tout de même avec sa propre copie. L’outil en ligne de commande `verifier` vérifie une archive :

```sh
cargo run --release -p verifier -- block <stem>.vk  <stem>.public <stem>.block
```

Il se termine avec le code 0 quand tout est vérifié, 1 en nommant le premier refus, et 2 en cas d’erreur d’utilisation ou d’identité mal formée. Il compare l’identité que vous passez à celle de la clé, et prend le condensé SRS dans le fichier de la clé.

## Quand une preuve échoue

Un prouveur honnête ne produit jamais une preuve qui échoue : un échec signifie donc une entrée qu’il n’aurait pas dû accepter, ou un bogue. Recompilez avec le journal de débogage du prouveur activé, puis relancez :

```sh
cargo run --release -p bench --features prover/debug-info -- prove ...
APOGEE_DEBUG=detail <the same run> 2>&1 | tee run.log
grep -E 'FAIL|NOT CANONICAL|UNBALANCED|OVER the|NAMES NO|DISAGREES|NOT LOOPING|ABORTED' run.log
```

Le journal de débogage nomme le shard qui a échoué, et `self_check FAILED` nomme la première porte que viole une ligne, avec la valeur de chaque opérande. [Outils](https://apogee.gweb3networks.com/docs/reference/tools#s3) énumère chaque marqueur. Ce journal n’existe que dans les compilations dotées de la fonctionnalité `debug-info` et ne change aucun octet de preuve.

Ensuite : [Régler sur la chaîne](https://apogee.gweb3networks.com/docs/launch/on-chain).
