Guest programs use airbender-sdk (imported as airbender) to read host inputs and commit outputs.
[dependencies]
airbender = { package = "airbender-sdk", path = "../../crates/airbender-sdk" }Enable std guest support only when needed:
airbender = { package = "airbender-sdk", path = "../../crates/airbender-sdk", features = ["std"] }Enable crypto to expose airbender::crypto from the SDK. This is guest-oriented and always enables airbender-crypto's proving feature:
airbender = { package = "airbender-sdk", path = "../../crates/airbender-sdk", features = ["crypto"] }Allocator selection is feature-based (allocator-talc default, or allocator-bump / allocator-custom):
airbender = { package = "airbender-sdk", path = "../../crates/airbender-sdk", default-features = false, features = ["allocator-bump"] }Write a regular Rust function and annotate it:
#[airbender::main]
fn main() -> u32 {
42
}Rules:
- function must not take arguments
- function must not be
async - function should return a value that can be committed (or
())
The macro provides the runtime entry point and commits the function result as guest output.
For custom allocator wiring (allocator-custom), you must provide an init hook:
#[airbender::main(allocator_init = crate::custom_allocator::init)]
fn main() -> u32 {
42
}Use airbender::guest::read::<T>() for typed values:
use airbender::guest::read;
#[airbender::main]
fn main() -> u32 {
let n: u32 = read().expect("failed to read input");
n + 1
}For custom transports (e.g. tests), use read_with(&mut transport).
You have two common patterns:
- Return a value from
#[airbender::main](automatic commit) - Call commit functions directly:
use airbender::guest::{commit, exit_error};
// Commit 8-word output and exit success.
commit(123u32);
// Exit with an error.
exit_error();Built-in commit support includes (), u32, u64, i64, bool, and [u32; 8].
To map your own type into output registers, implement Commit from airbender::guest for 8-word output ([u32; 8]).
This keeps guest-host output contracts explicit and stable.
- Host
Inputs::push(...)order == guestread::<T>()consumption order - Guest output maps to host
Receiptfields:output(x10..x17)output_extended(x10..x25, includes recursion-specific words)
See end-to-end guest code in: