# Référence du SDK des programmes invités

> Chaque élément public de la crate guest-sdk, avec sa signature exacte et son comportement. Seuls exit et les shims de délégation émettent un ecall; tout le reste n’est que chargements et rangements.

`crates/guest-sdk` constitue tout l’environnement d’exécution d’un programme invité : le code de démarrage, la macro d’entrée, l’allocateur, le gestionnaire de panique et les shims d’ecall. Elle ne se compile que pour `riscv32imac-unknown-none-elf`.

## Point d’entrée

```rust
guest_sdk::entry!(main);
```

Exporte le symbole `main` qu’appelle le code de démarrage, sous la forme d’une enveloppe qui appelle votre fonction, laquelle ne prend aucun argument et renvoie `()`. Votre fonction garde son propre nom et peut elle-même s’appeler `main`. Le retour de cette fonction équivaut à `exit(0)`.

## Les régions

| Élément | Signature | Comportement |
| --- | --- | --- |
| `public_input` | `fn public_input() -> &'static [u8]` | La charge utile de l’entrée publique, son mot de longueur étant plafonné à la fenêtre. Aucune copie, aucun ecall |
| `read_input` | `fn read_input(buf: &mut [u8]) -> usize` | Copie `min(buf.len(), public_input().len())` octets et renvoie leur nombre. La fonction peut en copier moins que demandé |
| `advice` | `fn advice() -> &'static [u8]` | La charge utile des données auxiliaires (*advice*), sa longueur étant plafonnée à la région. Liée à rien : le programme invité la vérifie donc. `OutOfBounds` fatal dans une exécution sans données auxiliaires |
| `commit` | `fn commit(bytes: &[u8])` | Ajoute au journal et met à jour son mot de longueur. Termine l’exécution avec le statut 70 plutôt que de faire déborder la fenêtre de 16 380 octets |
| `journal` | `fn journal() -> &'static [u8]` | Tout ce qui a été consigné jusqu’ici |
| `exit` | `fn exit(code: i32) -> !` | Termine l’exécution avec `code` comme statut de sortie de l’énoncé. Ne publie rien au-delà de ce qui a été consigné |

## Hachage

| Élément | Signature | Comportement |
| --- | --- | --- |
| `keccak256` | `fn keccak256(input: &[u8]) -> [u8; 32]` | Le Keccak-256 d’Ethereum, pas SHA3-256. L’éponge et le bourrage s’exécutent dans le code du programme invité; chaque tour de keccak-f[1600] est un appel à `KECCAK_F`. Repli logiciel si le premier appel répond `-ENOSYS` |
| `sha256` | `fn sha256(input: &[u8]) -> [u8; 32]` | SHA-256 selon FIPS 180-4. Le bourrage et la boucle sur les blocs s’exécutent dans le code du programme invité; chaque compression représente seize appels à `SHA256_COMP`. Repli logiciel comme ci-dessus |
| `poseidon2_permute` | `fn poseidon2_permute(state: &mut [u8; 96]) -> bool` | La permutation Poseidon2 de largeur 3 sur trois voies `Fr` canoniques petit-boutistes, sur place, par `POSEIDON2`. Renvoie `false` sur `-ENOSYS`, pour que l’appelant emprunte son propre chemin logiciel |

## Courbes elliptiques

```rust
pub type ProjectivePoint = [[u32; 8]; 3];
```

Un point en coordonnées **projectives homogènes**, `x = X/Z` et `y = Y/Z`, chaque coordonnée étant formée de huit mots de 32 bits petit-boutistes et inférieure au module du corps de la courbe. Ce type n’est pas jacobien : le `Projective` d’arkworks l’est, si bien qu’un appelant qui convertit depuis ce dernier applique `(X·Z, Y·Z², Z)` à l’entrée et `(X·Z, Y, Z³)` à la sortie. L’élément neutre est `(0 : 1 : 0)`.

| Élément | Signature | Comportement |
| --- | --- | --- |
| `ec_add` | `fn ec_add(codes: &[u32; 3], p: &ProjectivePoint, q: &ProjectivePoint) -> Option<ProjectivePoint>` | `p + q` par la formule complète, au moyen de trois appels à `EC_ADD` dans l’ordre des groupes. `None` sur `-ENOSYS` |
| `ec_mul` | `fn ec_mul(codes: &[u32; 3], p: &ProjectivePoint, k: &[u32; 8]) -> Option<ProjectivePoint>` | `k·p` par doublement et addition à partir du bit de poids fort. `k` est utilisé tel quel; le réduire modulo l’ordre du groupe est l’affaire de l’appelant |
| `ec_identity` | `fn ec_identity() -> ProjectivePoint` | `(0 : 1 : 0)` |
| `recursion::SECP256K1_GROUPS`, `recursion::BN254_GROUPS` | `[u32; 3]` | L’argument `codes` : quelle courbe, sous la forme des trois sélecteurs de groupe d’une addition |

La formule prouve l’arithmétique, pas l’appartenance à la courbe : vérifiez vous-même les points tirés des données auxiliaires.

## Shims de délégation bruts

`guest_sdk::recursion` contient les shims sur des types de cadres alignés sur un mot. Chaque type de cadre est `#[repr(C, align(4))]`, si bien que son alignement est celui du type, et non celui de l’endroit où le générateur de code a placé une variable locale. Un shim du format de base renvoie `false` exactement sur `-ENOSYS`; toute autre réponse non nulle termine l’exécution avec le statut 72.

| Élément | Rôle |
| --- | --- |
| `mod_mul(&mut ModMulFrame) -> bool` | Un `a·b mod m`. Construisez le cadre avec `ModMulFrame::of(modulus, &a, &b)` et lisez `frame.result()`. Les codes de module sont `SECP256K1_P`, `SECP256K1_N`, `BN254_P` et `BN254_R`, et les deux opérandes doivent déjà être inférieurs au module |
| `sha256_comp(&mut Sha256Frame) -> bool` | Une compression entière : seize appels dans l’ordre. `Sha256Frame::of(&state, &block)`, puis `frame.working()`; ajouter le résultat à la valeur de chaînage revient à l’appelant |
| `ec_add_complete(&mut EcAddFrame, &[u32; 3]) -> bool` | Une addition complète : trois appels dans l’ordre des groupes. `EcAddFrame::of(&codes, &p, &q)`, puis `frame.result()` |
| `poseidon2(&mut Poseidon2Frame) -> bool`, `fr_arith(&mut FrArithFrame) -> bool` | La permutation et une opération sur `Fr`, sur des cadres d’octets; `field` et `transcript` les appellent pour vous |
| `sha256_rounds`, `ec_add` | Des étapes isolées des opérations ci-dessus. Une étape exécutée dans le mauvais ordre n’est pas refusée, elle calcule autre chose : préférez donc les fonctions qui couvrent l’opération entière |
| `fr_op`, `p2_field`, `field_io`, `fq_op`, `import`, `import_run`, `replay` | Les appels de coprocesseur du format de récursion, qu’utilisent les programmes de l’arbre de récursion eux-mêmes. Ils n’ont pas de chemin logiciel |

Chaque shim lit son numéro d’ecall dans l’enregistrement de déclaration de sa famille, un `static` de 12 octets placé dans sa propre section de l’éditeur de liens. Lier un shim déclare la famille; une famille déclarée qui n’est jamais appelée prouve zéro shard.

## Comportement à l’exécution

| Composant | Comportement |
| --- | --- |
| Démarrage | `_start`, à `0x0001_0000`, fait pointer `sp` vers `__stack_top` (`0x8000_0000`), met `.bss` à zéro octet par octet, appelle `main`, et termine l’exécution avec le statut 0 si cette fonction revient |
| Allocateur | Monte à partir de `__heap_start`, ne libère jamais rien. Termine l’exécution avec le statut 71 quand un bloc se terminerait au-dessus de `__stack_top − 8 MiB` ou au-dessus du `sp` courant |
| Gestionnaire de panique | Termine l’exécution avec le statut 101 et n’écrit rien. Un programme invité qui panique est prouvable et a publié ce qu’il avait consigné |
| Statuts de sortie | 70 débordement du journal, 71 tas épuisé, 72 une délégation a répondu par une erreur, 101 panique |

## Délégation transparente

Deux crates de bibliothèque du dépôt délèguent sur la cible des programmes invités sans nommer le SDK, par une dépendance sur celui-ci réservée à cette cible :

- `field::Fr` : l’addition, la multiplication de Montgomery (`*`, `square`, `pow` et les conversions) et `inverse` d’un élément non nul appellent `FR_ARITH`. Un programme invité qui utilise l’arithmétique de `Fr` déclare cette famille.
- `transcript::poseidon2_permute` appelle `POSEIDON2`.

Les versions embarquées de `k256`, `ark-ff` et `revm-precompile` font de même pour secp256k1, BN254 et les précompilés de l’EVM : [Délégations](https://apogee.gweb3networks.com/docs/launch/delegations#vendored).

La spécification de l’ABI qui sous-tend tout cela se trouve dans [ABI du programme invité](https://apogee.gweb3networks.com/docs/auditors/spec/ecall-abi).
