Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/risc0/risc0/llms.txt

Use this file to discover all available pages before exploring further.

bonsai-sdk

The bonsai-sdk crate provides a Rust SDK for interacting with Bonsai, RISC Zero’s remote proving service. It supports both blocking and async (non-blocking) APIs.

Installation

[dependencies]
bonsai-sdk = "1.4.3"

Overview

Bonsai is a remote proving service that generates RISC Zero proofs in the cloud. This SDK provides a simple interface to upload programs, submit proving requests, and retrieve results.
You need a Bonsai API key to use this service. Sign up at bonsai.xyz

Feature Flags

non_blocking
feature
Enables async/await API using Tokio.
  • Default: Blocking API

Modules

blocking

blocking
module
Synchronous/blocking API (default).
use bonsai_sdk::blocking::{Client, SessionId};

non_blocking

non_blocking
module
Asynchronous/non-blocking API (requires non_blocking feature).
use bonsai_sdk::non_blocking::{Client, SessionId};

Client

Client
struct
Main client for interacting with Bonsai.
pub struct Client {
    url: String,
    client: HttpClient,
}

Construction

Client::from_env
method
Create a client from environment variables.
pub fn from_env(risc0_version: &str) -> Result<Self, SdkErr>
Environment Variables:
  • BONSAI_API_URL: Bonsai API endpoint
  • BONSAI_API_KEY: Your API key
  • BONSAI_TIMEOUT_MS: Request timeout (optional, default: 30000)
  • RISC0_RELEASE_CHANNEL: Release channel (optional)
Example:
let client = Client::from_env(risc0_zkvm::VERSION)?;
Client::from_parts
method
Create a client with explicit parameters.
pub fn from_parts(
    url: String,
    key: String,
    risc0_version: &str
) -> Result<Self, SdkErr>
Example:
let client = Client::from_parts(
    "https://api.bonsai.xyz".to_string(),
    api_key.to_string(),
    risc0_zkvm::VERSION,
)?;

Image Management

upload_img
method
Upload a guest program image.
pub async fn upload_img(
    &self,
    image_id: &str,
    buf: Vec<u8>
) -> Result<bool, SdkErr>
Parameters:
  • image_id: Hex-encoded image ID
  • buf: ELF binary or encoded MemoryImage
Returns: true if image already existed, false if newly uploadedExample:
let image_id = hex::encode(compute_image_id(ELF)?).to_string();
client.upload_img(&image_id, ELF.to_vec())?;
upload_img_file
method
Upload a guest program from a file.
pub async fn upload_img_file(
    &self,
    image_id: &str,
    path: &Path
) -> Result<bool, SdkErr>
has_img
method
Check if an image exists.
pub async fn has_img(&self, image_id: &str) -> Result<bool, SdkErr>
image_delete
method
Delete an image.
pub async fn image_delete(&self, image_id: &str) -> Result<(), SdkErr>

Input Management

upload_input
method
Upload input data for a proving session.
pub async fn upload_input(&self, buf: Vec<u8>) -> Result<String, SdkErr>
Returns: UUID for the uploaded inputExample:
let input_data = to_vec(&input)?;
let input_data = bytemuck::cast_slice(&input_data).to_vec();
let input_id = client.upload_input(input_data)?;
upload_input_file
method
Upload input from a file.
pub async fn upload_input_file(&self, path: &Path) -> Result<String, SdkErr>
input_delete
method
Delete uploaded input.
pub async fn input_delete(&self, input_uuid: &str) -> Result<(), SdkErr>

Session Management

Creating Sessions

create_session
method
Create a new proving session.
pub async fn create_session(
    &self,
    img_id: String,
    input_id: String,
    assumptions: Vec<String>,
    execute_only: bool,
) -> Result<SessionId, SdkErr>
Parameters:
  • img_id: Image ID from upload_img
  • input_id: Input ID from upload_input
  • assumptions: List of assumption receipt UUIDs
  • execute_only: If true, only execute without proving
Example:
let session = client.create_session(
    image_id,
    input_id,
    vec![],
    false,
)?;
create_session_with_limit
method
Create a session with custom cycle limit.
pub async fn create_session_with_limit(
    &self,
    img_id: String,
    input_id: String,
    assumptions: Vec<String>,
    execute_only: bool,
    exec_cycle_limit: Option<u64>,
) -> Result<SessionId, SdkErr>

SessionId

SessionId
struct
Represents a proving session.
pub struct SessionId {
    pub uuid: String,
}
SessionId::status
method
Check session status.
pub async fn status(
    &self,
    client: &Client
) -> Result<SessionStatusRes, SdkErr>
Example:
let status = session.status(&client)?;
match status.status.as_str() {
    "RUNNING" => println!("Still running..."),
    "SUCCEEDED" => println!("Proof complete!"),
    "FAILED" => println!("Failed: {}", status.error_msg.unwrap()),
    _ => {}
}
SessionId::logs
method
Fetch execution logs.
pub async fn logs(&self, client: &Client) -> Result<String, SdkErr>
SessionId::stop
method
Stop a running session.
pub async fn stop(&self, client: &Client) -> Result<(), SdkErr>
SessionId::exec_only_journal
method
Get journal from execute-only session.
pub async fn exec_only_journal(
    &self,
    client: &Client
) -> Result<Vec<u8>, SdkErr>

SessionStatusRes

SessionStatusRes
struct
Session status response.
pub struct SessionStatusRes {
    pub status: String,          // RUNNING | SUCCEEDED | FAILED | TIMED_OUT | ABORTED
    pub receipt_url: Option<String>,
    pub error_msg: Option<String>,
    pub state: Option<String>,   // Current proving stage
    pub elapsed_time: Option<f64>,
    pub stats: Option<SessionStats>,
}

Receipt Management

receipt_download
method
Download a completed receipt.
pub async fn receipt_download(
    &self,
    session_id: &SessionId
) -> Result<Vec<u8>, SdkErr>
Example:
let receipt_buf = client.receipt_download(&session)?;
let receipt: Receipt = bincode::deserialize(&receipt_buf)?;
upload_receipt
method
Upload a receipt (for assumptions).
pub async fn upload_receipt(&self, buf: Vec<u8>) -> Result<String, SdkErr>
download
method
Download data from a URL.
pub async fn download(&self, url: &str) -> Result<Vec<u8>, SdkErr>

SNARK Support

create_snark
method
Create a Groth16 SNARK from a STARK session.
pub async fn create_snark(
    &self,
    session_id: String
) -> Result<SnarkId, SdkErr>
Example:
let snark_session = client.create_snark(session.uuid)?;
SnarkId
struct
Represents a SNARK proving session.
pub struct SnarkId {
    pub uuid: String,
}
SnarkId::status
method
Check SNARK session status.
pub async fn status(
    &self,
    client: &Client
) -> Result<SnarkStatusRes, SdkErr>

Quota Management

quotas
method
Get current user quotas and cycle budget.
pub async fn quotas(&self) -> Result<Quotas, SdkErr>
Example:
let quotas = client.quotas()?;
println!("Cycle budget: {}", quotas.cycle_budget);
println!("Concurrent proofs: {}", quotas.concurrent_proofs);
version
method
Get supported Bonsai component versions.
pub async fn version(&self) -> Result<VersionInfo, SdkErr>

Error Handling

SdkErr
enum
SDK error types.
pub enum SdkErr {
    InternalServerErr(String),
    HttpErr(reqwest::Error),
    HttpHeaderErr(header::InvalidHeaderValue),
    MissingApiKey,
    MissingApiUrl,
    FileNotFound(std::io::Error),
    ReceiptNotFound,
}

Examples

Basic Proving Workflow

use bonsai_sdk::blocking::Client;
use risc0_zkvm::{compute_image_id, serde::to_vec, Receipt};

fn prove_on_bonsai() -> Result<()> {
    // Create client
    let client = Client::from_env(risc0_zkvm::VERSION)?;
    
    // Upload image
    let image_id = hex::encode(compute_image_id(METHOD_ELF)?);
    client.upload_img(&image_id, METHOD_ELF.to_vec())?;
    
    // Upload input
    let input_data = to_vec(&input)?;
    let input_data = bytemuck::cast_slice(&input_data).to_vec();
    let input_id = client.upload_input(input_data)?;
    
    // Start session
    let session = client.create_session(
        image_id,
        input_id,
        vec![],
        false,
    )?;
    
    // Poll for completion
    loop {
        let status = session.status(&client)?;
        
        match status.status.as_str() {
            "RUNNING" => {
                println!("Status: {}", status.state.unwrap_or_default());
                std::thread::sleep(Duration::from_secs(15));
            }
            "SUCCEEDED" => {
                let receipt_buf = client.download(&status.receipt_url.unwrap())?;
                let receipt: Receipt = bincode::deserialize(&receipt_buf)?;
                receipt.verify(METHOD_ID)?;
                break;
            }
            _ => {
                eprintln!("Error: {}", status.error_msg.unwrap_or_default());
                return Err(anyhow!("Proving failed"));
            }
        }
    }
    
    Ok(())
}

Async/Await (Non-Blocking)

use bonsai_sdk::non_blocking::Client;

#[tokio::main]
async fn prove_async() -> Result<()> {
    let client = Client::from_env(risc0_zkvm::VERSION)?;
    
    let image_id = hex::encode(compute_image_id(ELF)?);
    client.upload_img(&image_id, ELF.to_vec()).await?;
    
    let input_id = client.upload_input(input_data).await?;
    
    let session = client.create_session(
        image_id,
        input_id,
        vec![],
        false,
    ).await?;
    
    // Poll asynchronously
    loop {
        let status = session.status(&client).await?;
        if status.status == "SUCCEEDED" {
            let receipt_buf = client.download(
                &status.receipt_url.unwrap()
            ).await?;
            break;
        }
        tokio::time::sleep(Duration::from_secs(15)).await;
    }
    
    Ok(())
}

STARK to SNARK

use bonsai_sdk::blocking::Client;
use std::time::Duration;

fn stark_to_snark(stark_session_uuid: String) -> Result<()> {
    let client = Client::from_env(risc0_zkvm::VERSION)?;
    
    // Request SNARK conversion
    let snark_session = client.create_snark(stark_session_uuid)?;
    
    // Poll for completion
    loop {
        let status = snark_session.status(&client)?;
        
        match status.status.as_str() {
            "RUNNING" => {
                println!("Converting to SNARK...");
                std::thread::sleep(Duration::from_secs(15));
            }
            "SUCCEEDED" => {
                let snark_buf = client.download(&status.output.unwrap())?;
                let snark_receipt: Receipt = bincode::deserialize(&snark_buf)?;
                println!("SNARK proof complete!");
                break;
            }
            _ => {
                return Err(anyhow!("SNARK conversion failed: {}",
                    status.error_msg.unwrap_or_default()));
            }
        }
    }
    
    Ok(())
}

Environment Setup

export BONSAI_API_URL="https://api.bonsai.xyz"
export BONSAI_API_KEY="your_api_key_here"

# Optional settings
export BONSAI_TIMEOUT_MS="60000"  # 60 seconds
export RISC0_RELEASE_CHANNEL="stable"