# Quickstart

> From an empty crate to a verified proof. A three-line guest, built, run, inspected and proved, with the real output of every step.

This page walks the whole loop once with the smallest guest that does something: it reads its public input and publishes it as its journal. Every output below was produced by running these exact commands on Apogee v1.0.0.

> [!NOTE]
> **What you need.** A checkout of the Apogee VM repository at v1.0.0, and `rustup`; the repository pins everything else. Commands run from the repository root unless a step changes directory. Steps 5 and 6 also need the ceremony file `assets/ptau/ppot_0080_24.ptau`, and step 6 a machine with tens of GiB of memory. [Set up](https://apogee.gweb3networks.com/docs/launch/setup) covers both.

### Create the guest

A guest is a `no_std` binary crate in the `guests/` workspace. Create `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]` because the target is bare metal. `#![no_main]` with `entry!(main)` because the SDK's startup code sets the stack pointer, zeroes `.bss` and calls a `main` symbol the macro exports around your function. Returning from it is `exit(0)`.

### Add it to the guest workspace

Append `"hello"` to the `members` list in `guests/Cargo.toml`:

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

### Build it

From the guest's own directory, with no flag but the target:

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

The ELF lands at `guests/target/riscv32imac-unknown-none-elf/release/hello`. The guest workspace supplies the linker script and `--no-relax`, so there is nothing else to pass.

### Run it

The profiler runs a guest in Apogee's emulator, with no proof, and reports where the cycles went:

```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
```

114 instructions ran, each of which will be a proved row. The 13 journal bytes are the input, echoed. The 26 `MEM_SUBWORD` rows are `commit` copying the input byte by byte with `lbu` and `sb`.

### See what the VM will prove

```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
```

This is the program's static shape at the default heights: the four instruction families its code uses, each with a decoded table, and the five window families every program has. The **program identity** is one field element that digests all of it. Yours will differ: an ELF embeds absolute paths in its panic strings, so a build on another machine is another image, and every change of heights is another identity.

### Prove and verify

A host program asks for the proof. Put it beside the host SDK as an example:

```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"
```

On an 18-core laptop with 48 GiB this took 52 seconds and peaked at 18 GB of memory, almost all of it the two `2^20` shards in flight. The identity differs from step 5's because the heights do: the identity binds every height.

### Keep the identity

A verifier never takes the identity from the proof, the key or the prover. It holds its own copy, obtained from whoever built the release, and compares:

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

Against an identity the prover supplied, a proof shows only that *some* program ran.

## What just happened

The emulator ran the 114 instructions twice. The first pass committed the memory columns of every shard and fixed the statement. The second filled each shard and proved it. There were seven shards: one for each of the four instruction families that executed, one for the memory window that holds the program's image, and one each for the public input and the journal. This guest never touched its stack, so no other window needed one; a typical program adds the stack's. Each shard was proved by its family's GKR circuit and opened with one Mercury proof, and the verifier reconciled the memory reads and writes of all seven in one equation. [The architecture overview](https://apogee.gweb3networks.com/docs/architecture) follows the same path in detail.

## Next

- [Write a guest](https://apogee.gweb3networks.com/docs/launch/write): Crate layout, dependencies, the heap, and testing on the host.

- [Inputs, advice and the journal](https://apogee.gweb3networks.com/docs/launch/io): How data gets in and out, and what the proof binds.

- [Settle on-chain](https://apogee.gweb3networks.com/docs/launch/on-chain): From a block proof to a contract that says true.
