# Entrées, données auxiliaires et journal

> Un programme invité n’a aucun appel système d’E/S. Son entrée publique, les données auxiliaires du prouveur et son journal sont trois régions de mémoire. Ce que contient chacune, ce que lie la preuve, et le motif que suit tout programme invité qui reçoit des données.

Un programme invité d’Apogee n’a ni descripteurs de fichiers, ni flux, ni appel système d’E/S. Ses entrées et ses sorties sont trois régions de mémoire, lues et écrites par des chargements et des rangements ordinaires, et la preuve en lie deux.

## Les trois régions

| Région | SDK | Contenu | Taille | Liée par la preuve |
| --- | --- | --- | --- | --- |
| Entrée publique | `public_input()`, `read_input(buf)` | les octets de l’énoncé, choisis par quiconque demande la preuve | au plus 16 380 octets | oui, son contenu initial |
| Données auxiliaires (*advice*) | `advice()` | des octets que choisit le prouveur | jusqu’à 2 GiB | **non** |
| Journal | `commit(bytes)`, `journal()` | ce que le programme invité y a ajouté | au plus 16 380 octets | oui, son contenu final |

```rust
let input: &[u8] = guest_sdk::public_input(); // a slice over the input window, no copy
let data: &[u8] = guest_sdk::advice();        // a slice over the advice region
guest_sdk::commit(b"result");                  // appends to the journal
```

- `public_input()` et `advice()` renvoient des tranches sur la mémoire; rien n’est copié. `read_input(buf)` copie `min(buf.len(), input.len())` octets et renvoie leur nombre : la fonction peut donc en copier moins que demandé.
- `commit` ajoute à la fin du journal et tient à jour un mot de longueur, et c’est ce qui fait que la preuve lie une chaîne d’octets exacte plutôt qu’une fenêtre complétée par des zéros. La fonction termine l’exécution avec le statut **70** plutôt que de faire déborder la fenêtre.
- `advice()` dans une exécution sans données auxiliaires provoque un `OutOfBounds` fatal, et non une tranche vide : une exécution sans données auxiliaires n’a aucune région de données auxiliaires, et ne paie rien pour en avoir une.

## Ce que signifie « lié »

L’énoncé qu’établit une preuve porte les octets de l’entrée publique, les octets du journal et le statut de sortie. La preuve montre que la fenêtre d’entrée contenait exactement l’entrée de l’énoncé avant le premier accès du programme invité, et que la fenêtre du journal contenait exactement la sortie de l’énoncé quand le programme invité s’est terminé. Cela repose sur l’argument de mémoire, et non sur quoi que ce soit que fasse le programme invité : il n’y a aucun hachage que le programme invité doive calculer ni aucune convention qu’il doive suivre.

Les données auxiliaires, c’est autre chose. Le contenu initial de leur région est ce que le prouveur y a écrit, quel qu’il soit, et rien ne le rattache à l’identité du programme, à l’énoncé ni à aucune porte. Une preuve dit qu’il existe *certaines* données auxiliaires avec lesquelles le programme, sur cette entrée, a publié ce journal. Une telle affirmation vaut exactement ce que valent les vérifications que le programme invité fait lui-même sur les données auxiliaires.

## Le motif : engager, fournir, vérifier

Un programme invité dont l’entrée est volumineuse en reçoit l’essentiel sous forme de données auxiliaires, sur lesquelles l’entrée publique s’engage, puis vérifie la concordance des deux avant que quoi que ce soit qui dérive des données auxiliaires n’atteigne le journal :

```rust title="Vérifier les données auxiliaires avant de s’y fier"
fn main() {
    let want = guest_sdk::public_input(); // 32 bytes: keccak256 of the advice
    let data = guest_sdk::advice();       // the prover's bytes, bound by nothing
    if guest_sdk::keccak256(data).as_slice() != want {
        guest_sdk::exit(1); // refused before anything derived from it is committed
    }
    let sum = data.iter().fold(0u32, |s, b| s.wrapping_add(u32::from(*b)));
    guest_sdk::commit(&sum.to_le_bytes()); // the journal: what the proof publishes
}
```

La vérification n’a pas besoin d’être un hachage de toutes les données auxiliaires. Ce peut être un chemin de Merkle vérifié par rapport à une racine que porte l’entrée, comme dans [l’exemple du registre](https://apogee.gweb3networks.com/docs/blockchain-native#ledger-native), ou une signature sur les données, ou une contrainte que le résultat lui-même satisfait, comme un ordre trié annoncé que le programme invité vérifie en une seule passe au lieu de trier. Ce qui compte, c’est que ce par rapport à quoi elles sont vérifiées soit lié.

> [!CAUTION]
> Consigner une fonction quelconque de données auxiliaires non vérifiées publie une valeur choisie par le prouveur. C’est la façon la plus courante d’écrire un programme invité dont la preuve ne signifie rien.

## Données structurées

Encodez les entrées structurées avec un sérialiseur `no_std` comme `postcard` sur `serde` avec la fonctionnalité `alloc`, ce qu’utilise le programme invité Ethereum du dépôt lui-même pour son témoin de bloc. Deux habitudes gardent un format honnête :

- **Utilisez des entiers de largeur fixe.** `u32` et `u64`, jamais `usize`, dont la largeur diffère entre votre hôte et le programme invité.
- **Exigez un seul encodage par valeur** quand cela compte. Un désérialiseur qui accepte des octets en trop à la fin ou des varints non minimaux admet deux chaînes d’octets pour une même valeur. Là où l’unicité compte, décodez, réencodez et comparez, comme le fait `BlockWitness::decode` dans le programme invité Ethereum.

## Les sorties qui grandissent

Le journal contient 16 380 octets. Une sortie qui grandit avec le travail, comme un enregistrement par transaction, n’a pas de borne fixe, et l’exécution finira par se terminer avec le statut 70. Publiez plutôt un condensé : hachez les enregistrements à mesure que vous les produisez et consignez le résultat de 32 octets, puis laissez quiconque a besoin des enregistrements les recalculer en natif et comparer. Le validateur Ethereum sans état du dépôt publie ainsi un journal de 43 octets pour un bloc entier.

Pour une preuve vérifiée sur Ethereum, donnez aux deux valeurs publiques une **longueur fixe**. Le contrat vérificateur déployé est construit pour une seule longueur d’entrée et une seule longueur de sortie, et refuse tout le reste ([Régler sur la chaîne](https://apogee.gweb3networks.com/docs/launch/on-chain#shape)).

## Le statut de sortie

Rien n’est publié à la sortie au-delà de ce qui a été consigné, et une exécution qui panique ou se termine avec un statut non nul a une preuve valide de ce qu’elle a fait. Un vérificateur lit donc le statut de sortie avant de lire le journal. Sur la chaîne, le contrat vérificateur prend le statut attendu en argument, et une application passe `0`. Les statuts propres au SDK :

| Statut | Signification |
| --- | --- |
| 0 | retour de `main`, ou `exit(0)` |
| 70 | `commit` aurait dépassé 16 380 octets |
| 71 | une allocation aurait atteint la pile : voir [le tas](https://apogee.gweb3networks.com/docs/launch/write#heap) |
| 72 | une délégation a répondu quelque chose que son shim refuse |
| 101 | une panique, qui n’affiche rien |

Choisissez vos propres codes d’échec en dehors de ceux-ci, comme le fait l’exemple du registre avec 1, 2 et 3.

## Ce que la preuve ne dit pas

- **Rien n’ordonne les écritures du journal**, et rien n’oblige un programme invité à lire son entrée. La preuve lie le contenu des fenêtres, pas les accès qui l’ont produit.
- **Les données auxiliaires sont modifiables.** Un rangement dans leur région est un rangement ordinaire. Elles restent non liées dans un cas comme dans l’autre.
- **Le journal est tout le contenu final de la fenêtre.** `commit` maintient cette forme. Un programme invité qui écrit directement dans la fenêtre doit la respecter : une longueur d’au plus 16 380, autant d’octets, puis des zéros.

La spécification énonce tout cela avec précision : [Valeurs publiques et données auxiliaires](https://apogee.gweb3networks.com/docs/auditors/spec/public-values).
