# Referenz des Guest-SDK

> Jedes öffentliche Element des Crates guest-sdk, mit seiner genauen Signatur und seinem Verhalten. Nur exit und die Delegations-Shims setzen einen ecall ab; alles andere sind Lade- und Speicherbefehle.

`crates/guest-sdk` ist die gesamte Laufzeitumgebung eines Gastprogramms (Guest): der Startup-Code, das Einsprungmakro, der Allokator, der Panic-Handler und die ecall-Shims. Es kompiliert nur für `riscv32imac-unknown-none-elf`.

## Einsprung

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

Exportiert das Symbol `main`, das der Startup-Code aufruft, als Wrapper, der Ihre Funktion aufruft; diese nimmt keine Argumente und gibt `()` zurück. Ihre Funktion behält ihren eigenen Namen und darf selbst `main` heißen. Eine Rückkehr aus ihr ist gleichbedeutend mit `exit(0)`.

## Die Speicherbereiche

| Element | Signatur | Verhalten |
| --- | --- | --- |
| `public_input` | `fn public_input() -> &'static [u8]` | Die Nutzlast der öffentlichen Eingabe, ihr Längenwort auf das Fenster begrenzt. Keine Kopie, kein ecall |
| `read_input` | `fn read_input(buf: &mut [u8]) -> usize` | Kopiert `min(buf.len(), public_input().len())` Bytes und gibt die Anzahl zurück. Es kann weniger liefern als angefordert |
| `advice` | `fn advice() -> &'static [u8]` | Die Nutzlast der Hilfsdaten (Advice), ihre Länge auf den Bereich begrenzt. An nichts gebunden, daher prüft das Gastprogramm sie. Fataler `OutOfBounds`-Fehler in einem Lauf ohne Hilfsdaten |
| `commit` | `fn commit(bytes: &[u8])` | Hängt an das Journal an und aktualisiert sein Längenwort. Endet mit Exit 70, statt das Fenster von 16.380 Byte überlaufen zu lassen |
| `journal` | `fn journal() -> &'static [u8]` | Alles bisher Festgeschriebene |
| `exit` | `fn exit(code: i32) -> !` | Beendet den Lauf mit `code` als Exit-Status der Aussage. Veröffentlicht nichts über das Festgeschriebene hinaus |

## Hashing

| Element | Signatur | Verhalten |
| --- | --- | --- |
| `keccak256` | `fn keccak256(input: &[u8]) -> [u8; 32]` | Das Keccak-256 von Ethereum, nicht SHA3-256. Sponge und Padding laufen im Code des Gastprogramms; jede Runde von keccak-f[1600] ist ein `KECCAK_F`-Aufruf. Software-Fallback, wenn der erste Aufruf `-ENOSYS` als Antwort erhält |
| `sha256` | `fn sha256(input: &[u8]) -> [u8; 32]` | SHA-256 nach FIPS 180-4. Padding und die Blockschleife laufen im Code des Gastprogramms; jede Kompression sind sechzehn `SHA256_COMP`-Aufrufe. Software-Fallback wie oben |
| `poseidon2_permute` | `fn poseidon2_permute(state: &mut [u8; 96]) -> bool` | Die Poseidon2-Permutation der Breite 3 über drei kanonischen `Fr`-Lanes in Little-Endian, an Ort und Stelle, über `POSEIDON2`. Gibt bei `-ENOSYS` `false` zurück, für den eigenen Softwarepfad des Aufrufers |

## Elliptische Kurven

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

Ein Punkt in **homogen projektiven** Koordinaten, `x = X/Z` und `y = Y/Z`, jede Koordinate acht Little-Endian-Limbs zu 32 Bit unterhalb des Körpermoduls der Kurve. Das sind keine Jacobi-Koordinaten: `Projective` von arkworks verwendet solche; ein Aufrufer, der von dort konvertiert, bildet also beim Hineinkonvertieren auf `(X·Z, Y·Z², Z)` und beim Zurückkonvertieren auf `(X·Z, Y, Z³)` ab. Das neutrale Element ist `(0 : 1 : 0)`.

| Element | Signatur | Verhalten |
| --- | --- | --- |
| `ec_add` | `fn ec_add(codes: &[u32; 3], p: &ProjectivePoint, q: &ProjectivePoint) -> Option<ProjectivePoint>` | `p + q` nach der vollständigen Formel, über drei `EC_ADD`-Aufrufe in der Reihenfolge der Gruppen. `None` bei `-ENOSYS` |
| `ec_mul` | `fn ec_mul(codes: &[u32; 3], p: &ProjectivePoint, k: &[u32; 8]) -> Option<ProjectivePoint>` | `k·p` per Double-and-Add ab dem höchsten Bit. `k` wird so verwendet, wie es übergeben wird; es modulo der Gruppenordnung zu reduzieren, ist Sache des Aufrufers |
| `ec_identity` | `fn ec_identity() -> ProjectivePoint` | `(0 : 1 : 0)` |
| `recursion::SECP256K1_GROUPS`, `recursion::BN254_GROUPS` | `[u32; 3]` | Das Argument `codes`: welche Kurve, ausgedrückt als die drei Gruppenselektoren einer Addition |

Die Formel beweist Arithmetik, nicht die Zugehörigkeit zur Kurve: Prüfen Sie Punkte, die aus Hilfsdaten stammen, selbst.

## Rohe Delegations-Shims

`guest_sdk::recursion` enthält die Shims über wortausgerichteten Frame-Typen. Jeder Frame-Typ ist `#[repr(C, align(4))]`; seine Ausrichtung ergibt sich also aus dem Typ und nicht daraus, wo der Codegenerator gerade eine lokale Variable abgelegt hat. Ein Shim im Basisformat gibt genau bei `-ENOSYS` `false` zurück; jede andere Antwort ungleich null führt zu Exit 72.

| Element | Zweck |
| --- | --- |
| `mod_mul(&mut ModMulFrame) -> bool` | Ein `a·b mod m`. Bauen Sie den Frame mit `ModMulFrame::of(modulus, &a, &b)` und lesen Sie `frame.result()`. Die Modulcodes sind `SECP256K1_P`, `SECP256K1_N`, `BN254_P` und `BN254_R`, und beide Operanden müssen bereits unterhalb des Moduls liegen |
| `sha256_comp(&mut Sha256Frame) -> bool` | Eine ganze Kompression: sechzehn Aufrufe in Reihenfolge. `Sha256Frame::of(&state, &block)`, dann `frame.working()`; das Ergebnis zum Verkettungswert zu addieren, ist Sache des Aufrufers |
| `ec_add_complete(&mut EcAddFrame, &[u32; 3]) -> bool` | Eine vollständige Addition: drei Aufrufe in der Reihenfolge der Gruppen. `EcAddFrame::of(&codes, &p, &q)`, dann `frame.result()` |
| `poseidon2(&mut Poseidon2Frame) -> bool`, `fr_arith(&mut FrArithFrame) -> bool` | Die Permutation und eine `Fr`-Operation über Byte-Frames; `field` und `transcript` rufen sie für Sie auf |
| `sha256_rounds`, `ec_add` | Einzelne Schritte der obigen Operationen. Ein Schritt in falscher Reihenfolge wird nicht zurückgewiesen, er berechnet etwas anderes; bevorzugen Sie daher die Funktionen für ganze Operationen |
| `fr_op`, `p2_field`, `field_io`, `fq_op`, `import`, `import_run`, `replay` | Die Koprozessor-Aufrufe des Rekursionsformats, die die eigenen Programme des Rekursionsbaums verwenden. Sie haben keinen Softwarepfad |

Jeder Shim liest seine ecall-Nummer aus dem Deklarationsdatensatz seiner Familie, einem 12-Byte-`static` in einer eigenen Linker-Sektion. Einen Shim zu linken deklariert die Familie; eine deklarierte Familie, die nie aufgerufen wird, beweist null Shards.

## Laufzeitverhalten

| Komponente | Verhalten |
| --- | --- |
| Start | `_start` bei `0x0001_0000` setzt `sp` auf `__stack_top` (`0x8000_0000`), füllt `.bss` Byte für Byte mit Nullen, ruft `main` auf und endet mit Exit 0, wenn es zurückkehrt |
| Allokator | Wächst ab `__heap_start` nach oben und gibt nie Speicher frei. Endet mit Exit 71, wenn ein Block oberhalb von `__stack_top − 8 MiB` oder oberhalb des aktuellen `sp` enden würde |
| Panic-Handler | Endet mit Exit 101 und schreibt nichts. Ein Gastprogramm, das einen Panic auslöst, ist beweisbar und hat veröffentlicht, was es festgeschrieben hat |
| Exit-Status | 70 Überlauf des Journals, 71 Heap erschöpft, 72 eine Delegation hat mit einem Fehler geantwortet, 101 Panic |

## Transparente Delegation

Zwei Bibliotheks-Crates des Repositorys delegieren auf dem Target der Gastprogramme, ohne das SDK zu benennen, über eine nur für dieses Target geltende Abhängigkeit davon:

- `field::Fr`: Addition, Montgomery-Multiplikation (`*`, `square`, `pow` und die Konvertierungen) und `inverse` für Werte ungleich null rufen `FR_ARITH` auf. Ein Gastprogramm, das `Fr`-Arithmetik verwendet, deklariert diese Familie.
- `transcript::poseidon2_permute` ruft `POSEIDON2` auf.

Die mitgelieferten `k256`, `ark-ff` und `revm-precompile` tun dasselbe für secp256k1, BN254 und die Precompiles der EVM: [Delegationen](https://apogee.gweb3networks.com/docs/launch/delegations#vendored).

Die Spezifikation des ABI, das all dem zugrunde liegt, ist [Gastprogramm-ABI](https://apogee.gweb3networks.com/docs/auditors/spec/ecall-abi).
