# Démarrage rapide

> D’une crate vide à une preuve vérifiée. Un programme invité de trois lignes, compilé, exécuté, inspecté et prouvé, avec la sortie réelle de chaque étape.

Cette page parcourt une fois la boucle complète avec le plus petit programme invité qui fasse quelque chose : il lit son entrée publique et la publie comme journal. Chaque sortie ci-dessous a été produite en exécutant exactement ces commandes sur Apogee v1.0.0.

> [!NOTE]
> **Ce qu’il vous faut.** Une copie de travail du dépôt Apogee VM à la v1.0.0, et `rustup`; le dépôt fixe tout le reste. Les commandes s’exécutent à partir de la racine du dépôt, sauf quand une étape change de répertoire. Les étapes 5 et 6 nécessitent aussi le fichier de cérémonie `assets/ptau/ppot_0080_24.ptau`, et l’étape 6, une machine dotée de dizaines de GiB de mémoire. [Préparer l’environnement](https://apogee.gweb3networks.com/docs/launch/setup) traite des deux.

### Créer le programme invité

Un programme invité est une crate binaire `no_std` dans l’espace de travail `guests/`. Créez `guests/hello` :

```toml title="guests/hello/Cargo.toml"
[package]
name = "hello"
version.workspace = true
edition.workspace = true
publish.workspace = true

[dependencies]
guest-sdk.workspace = true
```

```rust title="guests/hello/src/main.rs"
#![no_std]
#![no_main]

guest_sdk::entry!(main);

fn main() {
    // The public input is memory: a slice, with no ecall and no cursor.
    guest_sdk::commit(guest_sdk::public_input());
}
```

`#![no_std]`, parce que la cible n’a pas de système d’exploitation. `#![no_main]` avec `entry!(main)`, parce que le code de démarrage du SDK initialise le pointeur de pile, met `.bss` à zéro et appelle un symbole `main` que la macro exporte autour de votre fonction. Le retour de cette fonction équivaut à `exit(0)`.

### L’ajouter à l’espace de travail des programmes invités

Ajoutez `"hello"` à la fin de la liste `members` dans `guests/Cargo.toml` :

```toml title="guests/Cargo.toml"
members = ["fib", "echo", … , "recursion", "hello"]
```

### Le compiler

À partir du répertoire du programme invité lui-même, sans autre option que la cible :

```sh
cd guests/hello
cargo build --release --target riscv32imac-unknown-none-elf
cd ../..
```

L’ELF se retrouve dans `guests/target/riscv32imac-unknown-none-elf/release/hello`. L’espace de travail des programmes invités fournit le script d’édition de liens et `--no-relax` : il n’y a rien d’autre à passer.

### L’exécuter

Le profileur exécute un programme invité dans l’émulateur d’Apogee, sans preuve, et indique où sont allés les cycles :

```sh
printf 'hello, apogee' > /tmp/hello.in
cargo run --release -p profiler -- elf guests/target/riscv32imac-unknown-none-elf/release/hello --input /tmp/hello.in
```

```text
workload
  label                        hello
  guest                        hello
  guest cycles                 114
  exit status                  0
  journal bytes                13

cycles by family
  ADD_SUB_LUI_AUIPC            64
  JUMP_BRANCH_SLT              21
  MEM_WORD                     3
  MEM_SUBWORD                  26
```

Les 114 instructions exécutées deviendront chacune une ligne prouvée. Les 13 octets du journal sont l’entrée, renvoyée telle quelle. Les 26 lignes `MEM_SUBWORD` sont celles de `commit`, qui copie l’entrée octet par octet avec `lbu` et `sb`.

### Voir ce que la VM prouvera

```sh
cargo run --release -p artifact-dump -- tables \
    guests/target/riscv32imac-unknown-none-elf/release/hello \
    --ptau assets/ptau/ppot_0080_24.ptau
```

```text
program identity  9ead85cee880df30daa8eba657316215107a075640a64ccf2424a054b758b802

VmConfig
--------
  id  family              height     live rows  columns
   0  ADD_SUB_LUI_AUIPC     4194304         33  pc next_pc rs1 rs2 rd imm extra_mask
   1  JUMP_BRANCH_SLT       4194304         12  pc next_pc rs1 rs2 rd imm extra_mask
   4  MEM_WORD              4194304          3  pc next_pc rs1 rs2 rd imm extra_mask
   5  MEM_SUBWORD           4194304          3  pc next_pc rs1 rs2 rd imm extra_mask
   7  INIT_TEARDOWN         4194304          0  none: claims no pc
   8  ZERO_WINDOWS          4194304          0  none: claims no pc
  12  PUBLIC_INPUT             4096          0  none: claims no pc
  13  PUBLIC_OUTPUT            4096          0  none: claims no pc
  14  ADVICE_WINDOWS        4194304          0  none: claims no pc
```

Voici la forme statique du programme aux hauteurs par défaut : les quatre familles d’instructions qu’utilise son code, chacune avec une table décodée, et les cinq familles de fenêtres que possède tout programme. L’**identité du programme** est un seul élément du corps qui condense le tout. La vôtre sera différente : un ELF incorpore des chemins absolus dans ses chaînes de panique, si bien qu’une compilation sur une autre machine donne une autre image, et tout changement de hauteurs, une autre identité.

### Prouver et vérifier

Un programme hôte demande la preuve. Placez-le à côté du SDK hôte, sous forme d’exemple :

```rust title="crates/host/examples/prove_hello.rs"
use constants::family;
use emulator::GuestIo;
use program::ProgramParams;
use srs::Srs;

fn main() {
    let elf = std::fs::read("guests/target/riscv32imac-unknown-none-elf/release/hello")
        .expect("build the guest with --release first");

    // Small heights for a small program: the seven instruction families at
    // their 2^20 floor, the three RAM-window families at 2^16. Every choice of
    // heights is its own program identity.
    let mut params = 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;
    }

    // As many ceremony powers as the tallest family has rows: 2^20 here.
    let ptau = std::path::Path::new("assets/ptau/ppot_0080_24.ptau");
    let srs = Srs::from_ptau(ptau, 20).expect("the ceremony file reads");
    let setup = host::setup(&elf, &params, srs).expect("the program registers");

    let io = GuestIo { input: b"hello, apogee".to_vec(), advice: Vec::new() };
    let proven = host::prove(&setup, &io, 2).expect("the run proves"); // two shards in flight
    host::verify(&setup.vk, &proven.block).expect("the block verifies");

    assert_eq!(proven.exit_code, 0);
    assert_eq!(proven.journal, b"hello, apogee");
    let id: String = setup.vk.identity.to_bytes().iter().map(|b| format!("{b:02x}")).collect();
    println!("identity  {id}");
    println!("cycles    {}", proven.cycles);
    println!("shards    {}", proven.report.shards);
    println!("journal   {:?}", core::str::from_utf8(&proven.journal).unwrap());
}
```

```sh
cargo run --release -p host --example prove_hello
```

```text
identity  606d1f1d720459cc1a078787381656b29c9fce5a9e539b36f899e62b64129c14
cycles    114
shards    7
journal   "hello, apogee"
```

Sur un portable à 18 cœurs doté de 48 GiB, cela a pris 52 secondes, avec un pic de mémoire de 18 GB, presque entièrement dû aux deux shards `2^20` en cours de traitement. L’identité diffère de celle de l’étape 5 parce que les hauteurs diffèrent : l’identité lie chaque hauteur.

### Conserver l’identité

Un vérificateur ne prend jamais l’identité dans la preuve, dans la clé ni auprès du prouveur. Il détient sa propre copie, obtenue de quiconque a compilé la version publiée, et compare :

```rust
assert_eq!(setup.vk.identity.to_bytes(), registered); // `registered` from your own channel
```

Face à une identité fournie par le prouveur, une preuve montre seulement qu’un programme *quelconque* s’est exécuté.

## Ce qui vient de se passer

L’émulateur a exécuté les 114 instructions deux fois. La première passe a engagé les colonnes mémoire de chaque shard et fixé l’énoncé. La seconde a rempli chaque shard et l’a prouvé. Il y avait sept shards : un pour chacune des quatre familles d’instructions exécutées, un pour la fenêtre mémoire qui contient l’image du programme, puis un pour l’entrée publique et un pour le journal. Ce programme invité n’a jamais touché à sa pile, si bien qu’aucune autre fenêtre n’a eu besoin d’un shard; un programme typique y ajoute celui de la pile. Chaque shard a été prouvé par le circuit GKR de sa famille et ouvert avec une seule preuve Mercury, et le vérificateur a rapproché les lectures et les écritures mémoire des sept shards en une seule équation. [La vue d’ensemble de l’architecture](https://apogee.gweb3networks.com/docs/architecture) suit le même chemin en détail.

## Pour la suite

- [Écrire un programme invité](https://apogee.gweb3networks.com/docs/launch/write): L’organisation de la crate, les dépendances, le tas, et les tests sur l’hôte.

- [Entrées, données auxiliaires et journal](https://apogee.gweb3networks.com/docs/launch/io): Comment les données entrent et sortent, et ce que lie la preuve.

- [Régler sur la chaîne](https://apogee.gweb3networks.com/docs/launch/on-chain): D’une preuve de bloc à un contrat qui répond true.
