# Welcome

## Welcome to Bonsol

Welcome to the official documentation for Bonsol, the verifiable computation framework designed to extend Solana's computational boundaries. Our mission is to allow developers to build complex, computationally-intensive applications on Solana without being constrained by its native limitations.

## What is Bonsol?

Bonsol is a Solana-native verifiable computation framework that enables developers to:

* **Off-load complex computations** off-chain while maintaining on-chain verifiability
* **Remove computational constraints** by generating cryptographic proofs for resource-intensive tasks
* **Maintain security and trust** through zero-knowledge proofs that can be efficiently verified on Solana
* **Build previously impossible applications** with unlimited compute potential

Bonsol transforms Solana from a place where only certain things are possible, to one where *anything* is possible.

## Why Bonsol?

Solana has established itself as a high-performance blockchain with ultra-fast transactions and low fees. However, as applications grow more sophisticated, they face inherent limitations:

* Fixed compute unit (CU) caps per transaction
* Transaction size limitations
* Constraints on complex logic execution

Bonsol breaks through these barriers by providing a decentralized prover network and developer toolkit that brings infinite computation to Solana-based applications.

## Key Features

* **Unlimited Compute Power**: Execute computationally intensive operations off-chain
* **On-Chain Verifiability**: Produce succinct, constant-size cryptographic proofs regardless of computational complexity
* **Native Solana Integration**: Seamlessly connect with existing Solana programs and resources
* **Privacy-Preserving Capabilities**: Support for private data proofs without exposing sensitive information
* **Community-Driven Development**: Open-source foundation with contributions welcome

## Use Cases

Bonsol enables a wide range of applications previously impossible on Solana:

* **Verifiable Agents**: Autonomous, provably secure agents operating without human intervention
* **Storage and Transaction Proofs**: Prove historical ownership or specific on-chain events
* **Provable Game Engines**: Build complex game mechanics by outsourcing simulations off-chain
* **Private Liquidity Pools**: Create pools where balances are provable without revealing participants
* **Cross-Chain Activity Proofs**: Enable secure cross-chain operations with trust-minimized proofs

## Join the Community

Bonsol is a community-driven initiative. We're building the Bonsol Collective, a collaborative ecosystem of people, projects, and companies working together to extend Solana's capabilities.

* [GitHub](https://github.com/bonsol-collective/bonsol/) - Contribute to our open-source codebase
* [Twitter](https://x.com/Bonsol_Labs) - Follow us for the latest updates
* [Telegram](https://t.me/bonsolsh) - Join our community discussions


# Introduction

An introduction to Bonsol, its underlying technologies, and how it integrates with Solana.

## Understanding Bonsol

Bonsol acts as a bridge between Solana's on-chain capabilities and off-chain computational power. It allows developers to execute computationally intensive tasks off-chain and then verify the results on-chain, leveraging the power of verifiable computation. Using Bonsol, developers can:

* Lower their regulatory burden
* Build trust with their community
* Simplify protocol design

Bonsol is deeply integrated with Solana and can be used to build a variety of use cases. You can compose other programs on top of Bonsol to add verifiable computation to your protocol, or add a verifiable layer on top of existing primitives. Bonsol is built on top of the excellent RISC Zero zkVM, which allows developers to write arbitrary programs and generate verifiable proofs of their execution, in some cases those proofs can be zero-knowledge with regard to the inputs.

## How Bonsol Works

1. Developers create verifiable programs using RISC Zero Tooling
2. These verifiable programs are registered with Bonsol
3. Users can request execution of these verifiable programs through Bonsol
4. Provers run the verifiable programs and generate STARK proofs
5. Bonsol wraps the STARK proof into a SNARK (Succinct Non-interactive ARgument of Knowledge)
6. The SNARK proof is verified natively on Solana

### RISC0 STARK Proofs

RISC Zero generates STARK proofs, which have several important properties:

1. Scalability: STARK proofs can handle arbitrarily large computations, with proof size and verification time growing logarithmically with the computation size.
2. Transparency: STARKs don't require a trusted setup, enhancing their security and reducing reliance on external parties.
3. Variable Length: The size of a STARK proof is directly related to the complexity and length of the computation being proved. This means that for simple computations, the proof can be quite small, while for more complex ones, it can grow larger.
4. Post-Quantum Security: STARKs are believed to be secure against attacks from quantum computers.

However, these proofs can become quite large for complex computations, which can be problematic for on-chain verification on Solana.

### STARK to SNARK Conversion

To address the potential size issues of STARK proofs, Bonsol converts them into Groth16 SNARKs. This process involves several steps:

1. Proof Aggregation: In the case of using Proofs as Inputs, Bonsol may first aggregate multiple proof segments into a single, more compact proof.
2. Circuit Generation: The STARK verification circuit is transformed into an arithmetic circuit suitable for SNARK proving.
3. Trusted Setup: A one-time trusted setup is performed for the Groth16 scheme. This setup is universal for all STARK to SNARK conversions in Bonsol.
4. Proof Generation: Using the Groth16 scheme, a new SNARK proof is generated that attests to the validity of the original STARK proof.

### Benefits of Groth16 SNARKs

The conversion to Groth16 SNARKs offers several advantages:

1. Constant-size proofs: Regardless of the complexity of the original computation, the Groth16 SNARK proof has a fixed, small size.
2. Fast verification: Groth16 proofs can be verified extremely quickly, which is crucial for on-chain verification.
3. Efficient implementation: The algebraic structure of Groth16 proofs allows for efficient implementation on Solana.

### Native Verification on Solana

Bonsol implements a native Groth16 verifier on Solana, allowing for:

* Efficient proof verification, with the verification call happening in less than 200k compute units
* This means we can compose over other programs in the same transaction

### Input Digest Verification

To ensure the integrity of inputs, Bonsol:

1. Ensures that verifiable programs compute a digest (hash) of all inputs (public and private)
2. Commits this digest as part of the verifiable programs execution
3. Verifies the digest on-chain during proof verification

This additional step prevents potential attacks where a malicious prover might try to use different inputs than those specified in the execution request.\\


# Architecture

Overview of Bonsol's architecture for enabling verifiable off-chain computation on Solana.

## Overview

Bonsol is a framework for building verifiable computation on Solana. It consists of tools and libraries that enable developers to create their own verifiable programs and prove computations that would be impossible to run on-chain. In addition to being a development framework, Bonsol also operates as a prover network, allowing computations to be executed by a distributed network of provers incentivized to process them as quickly as possible.

## Incentive Mechanism

The prover network operates through a claim mechanism. Provers observe the blockchain for execution requests, and when they identify a request they consider worthwhile (based on various heuristics), they can claim it and submit the proof to the blockchain. The first prover to claim a request is allocated a specific timeframe (measured in blocks) to deliver the proof, which must be less than the execution request's expiry. If a prover fails to deliver within the deadline, the request expires, invalidating the claim and allowing other provers to step in. Once a claim is made, the execution request is marked as claimed, and the tip value decreases according to a predefined curve, providing an incentive for the prover to generate the proof quickly.

## Core Components

Bonsol consists of several key components that work together to enable verifiable off-chain computation:

<details>

<summary>Provers</summary>

Provers are nodes that form the Bonsol network. They monitor transactions submitted to the Bonsol program on-chain, decide whether to claim execution requests, and submit proofs back to the verifier. The prover component is responsible for:

* Observing the blockchain for computation requests
* Ingesting the required data
* Performing off-chain computations
* Generating cryptographic proofs of those computations
* Submitting results and proofs back to the blockchain

</details>

<details>

<summary>Verifier</summary>

The verifier runs as a program on Solana and is responsible for:

* Verifying the cryptographic proofs submitted by provers
* Validating the integrity of the computation results
* Forwarding the validated output to the callback program

</details>

<details>

<summary>Callback Program</summary>

The callback program is developed by the application developer and receives output from the verifier. It can perform any desired actions with the verified results, such as:

* Updating on-chain state based on verified computation results
* Triggering additional on-chain processes
* Emitting events for off-chain systems to observe

</details>

## Workflow

The Bonsol workflow follows these steps:

1. **Deployment**: A zkprogram is deployed and registered on-chain
2. **Request**: An on-chain program requests computation through Bonsol
3. **Observation**: Prover nodes observe the request on the blockchain
4. **Claim**: A prover claims the request
5. **Ingestion**: The prover ingests the program and input data
6. **Computation & Proving**: Off-chain computation is performed, and a proof is generated
7. **Verification**: Results and proofs are submitted on-chain for verification
8. **Callback**: The verifier forwards verified results to the callback program to perform actions based on the verified results

<figure><img src="/files/5tunaYauErCBixd9Fdwy" alt=""><figcaption></figcaption></figure>


# Installation

Start by installing the Bonsol CLI which provides you with all the necessary tools for starting a new project. The Bonsol CLI is compatible with both Linux and macOS operating systems.

{% hint style="info" %}
Interested in contributing? Head over to the [Contributing](/contributing/contributor-guidelines) section to learn more.
{% endhint %}

## Requirements

* [Rust](https://solana.com/docs/intro/installation#install-rust)
* [Solana CLI](https://solana.com/docs/intro/installation#install-the-solana-cli)
* [Docker](https://docs.docker.com/engine/install/) ([WSL notes](#docker-setup-for-wsl))
* [FlatBuffers v24.3.25](https://github.com/google/flatbuffers/tree/v24.3.25) ([see notes](#notes))
* [Anchor CLI](https://solana.com/docs/intro/installation#install-anchor-cli) (optional, if you want to write your Solana programs in Anchor)

## Installation

Build with Bonsol by installing the following components:

* RISC Zero zkVM – Write secure off-chain logic.
* Bonsol CLI – Initialize, build, and deploy your off-chain programs.

You can install these tools using the provided install script or opt for manual installation.

### Install Script

```bash
# Install Bonsol CLI and Risc0 toolchain
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/bonsol-collective/bonsol/refs/heads/main/bin/install.sh | sh
```

Make sure the script completed without errors. Otherwise use the manual install method below.

### Manual Install

Install the RISC Zero version management library and CLI using `rzup`. Bonsol currently supports version 1.2.1.

```bash
curl -L https://risczero.com/install | bash
rzup install cargo-risczero 1.2.1
```

Then install the Bonsol CLI depending on your architecture:

<details>

<summary>Linux</summary>

Install the Bonsol CLI on Linux **without** CUDA support:

```bash
echo "Installing without cuda support, proving will be slower"
cargo install bonsol-cli --git https://github.com/bonsol-collective/bonsol --locked
```

</details>

<details>

<summary>Linux + CUDA</summary>

Install the Bonsol CLI on Linux **with** CUDA support:

```bash
echo "Installing with cuda support"
cargo install bonsol-cli --git https://github.com/bonsol-collective/bonsol --features linux --locked
```

</details>

<details>

<summary>macOS</summary>

Install the Bonsol CLI on macOS:

```bash
echo "Installing on mac"
cargo install bonsol-cli --git https://github.com/bonsol-collective/bonsol --features mac --locked
```

</details>

### Verify Installation

Verify the installation by running:

```bash
bonsol --help
```

You will see the following:

```bash
Usage: bonsol [OPTIONS] <COMMAND>

Commands:
  deploy    Deploy a program with various storage options, such as S3, or manually with a URL
  build     Build a ZK program
  estimate  Estimate the execution cost of a ZK RISC0 program
  execute
  prove
  init      Initialize a new project
  help      Print this message or the help of the given subcommand(s)

Options:
  -c, --config <CONFIG>    The path to a Solana CLI config [Default: '~/.config/solana/cli/config.yml']
  -k, --keypair <KEYPAIR>  The path to a Solana keypair file [Default: '~/.config/solana/id.json']
  -u, --rpc-url <RPC_URL>  The Solana cluster the Solana CLI will make requests to
  -h, --help               Print help
  -V, --version            Print version
```

See [here for documentation](/cli-commands) on these Bonsol CLI commands.

## Uninstall

If you want to uninstall Bonsol, simply run:

```bash
cargo uninstall bonsol-cli
```

Verify the uninstall using:

```bash
bonsol --version
```

You will see the following:

```bash
zsh: command not found: bonsol
```

## Notes

### Docker Setup for WSL

For Bonsol development in WSL, we strongly recommend installing Docker directly in your WSL environment rather than using Docker Desktop for Windows.

<details>

<summary>Docker in WSL</summary>

#### 1. Install Prerequisites

```
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
```

#### 2. Add Docker's Official GPG Key

```
# Create directory for keyrings
sudo install -m 0755 -d /etc/apt/keyrings

# Download and add GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Set permissions
sudo chmod a+r /etc/apt/keyrings/docker.gpg
```

#### 3. Add Docker Repository

```
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```

#### 4. Install Docker

```
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```

#### 5. Configure User Permissions

```
# Add your user to docker group
sudo usermod -aG docker $USER

# Apply changes to current session
newgrp docker
```

#### 6. Verify Installation

```
docker --version
docker compose version
```

### Notes

* Docker daemon starts automatically with WSL
* No Docker Desktop required
* GUI features available through Docker Desktop later if needed
* Compatible with all Bonsol development requirements

### Troubleshooting

If you encounter permission issues after installation:

1. Ensure you've logged out and back in after adding your user to the docker group
2. Or run `newgrp docker` to apply changes in current session

If Docker daemon isn't starting:

```
sudo service docker start
```

</details>

### FlatBuffers v24.3.25

FlatBuffers is a cross-platform serialization library. Build it from source on Linux or macOS.

<details>

<summary>Linux</summary>

Ensure you have the build requirements.

```bash
# Update package lists
sudo apt update

# Install CMake
sudo apt install -y cmake

# Verify CMake installation
cmake --version   # Should show version 3.28.3 or later

# Install make
sudo apt install -y g++ make

# Verify make installation
make --version   # Should show version 3.81 or later
```

Build and install FlatBuffers v24.3.25:

```bash
# Create a temporary directory for building
cd /tmp

# Clone the FlatBuffers repository
git clone https://github.com/google/flatbuffers.git

# Enter the repository directory
cd flatbuffers

# Checkout the specific version
git checkout v24.3.25

# Build FlatBuffers
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)

# Install flatc compiler
sudo mv flatc /usr/local/bin/

# Clean up
cd ..
rm -rf flatbuffers

# Verify the installation
flatc --version   # Should show version 24.3.25
```

</details>

<details>

<summary>macOS</summary>

Ensure you have the build requirements.

```bash
# Update package lists (macOS uses Homebrew instead of apt)
brew update

# Install CMake
brew install cmake

# Verify CMake installation
cmake --version   # Should show version 3.28.3 or later

# Install make (and g++ if needed)
brew install make gcc

# Verify make installation
make --version   # Should show version 3.81 or later
```

Build and install FlatBuffers v24.3.25:

```bash
# Create a temporary directory for building
cd /tmp

# Clone the FlatBuffers repository
git clone https://github.com/google/flatbuffers.git

# Enter the repository directory
cd flatbuffers

# Checkout the specific version
git checkout v24.3.25

# Build FlatBuffers
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
make

# Install flatc compiler
sudo mv flatc /usr/local/bin/

# Clean up
cd ..
rm -rf flatbuffers

# Verify the installation
flatc --version   # Should show version 24.3.25
```

</details>


# Quickstart

Let's create a hello world project using our newly installed Bonsol CLI.

{% stepper %}
{% step %}

#### Verify installation

```bash
$ bonsol --version
bonsol-cli 0.4.5
```

{% endstep %}

{% step %}

#### Initialize a new project

The `init` command creates a new verifiable program with the basic project structure and configuration needed to get started.

{% hint style="info" %}
Note: We suggest using an *underscore* when initializing multi-word projects as this can prevent issues with the downstream `cargo risczero` docker build process.
{% endhint %}

```bash
$ bonsol init --project-name say_hello
Project 'tutorial' initialized successfully!
```

Project structure:

```
say_hello/
├── Cargo.toml
├── README.md
└── src
    └── main.rs
```

The generated project includes a `Cargo.toml` with special metadata for your verifiable program's inputs:

```
[package.metadata.zkprogram]
input_order = ["Public"]
```

Valid input options are: `["Public", "Private", "PublicProof"]`.
{% endstep %}

{% step %}

#### Write a verifiable program

Navigate to `src/` and inspect `main.rs`:

```rust
// src/main.rs

use risc0_zkvm::{guest::{env, sha::Impl},sha::{Sha256}};

fn main() {
    let mut input_1 = Vec::new();
    env::read_slice(&mut input_1);
    let digest = Impl::hash_bytes(&input_1.as_slice());
    env::commit_slice(digest.as_bytes());
}
```

Run `cargo build` to make sure everything builds correctly:

```bash
cargo build
   Compiling say_hello v0.1.0 (/Users/chris/say_hello)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.74s
```

{% endstep %}

{% step %}

#### Build the verifiable program

The `build` command compiles your verifiable program and generates a manifest file containing the deployment information. Ensure your Docker daemon is running and build your verifiable program:

```bash
$ bonsol build --zk-program-path .
Build complete
```

This generates a `manifest.json` file containing:

* Program name
* Binary path
* Image ID
* Input order configuration
* Cryptographic signature
* Program size

Example `manifest.json`:

```json
{
  "name": "say_hello",
  "binaryPath": "./target/riscv-guest/riscv32im-risc0-zkvm-elf/docker/say_hello/say_hello",
  "imageId": "6700902caf52fb56277157db725faa5c1aeac0c08221d2e13e27430da2f77136",
  "inputOrder": [
    "Public"
  ],
  "signature": "k7XUcgk94oxsLpLZwzCQ3SdrZ5tq4TsCPW8paBC4JnDtKXMknwJ7MMENXs5ijFL2wDKAzFLrvFKGZCpFMPmRfo9",
  "size": 116744
}
```

{% endstep %}

{% step %}

#### Deploy the verifiable program

Verify you're on devnet:

```bash
$ solana config get
Config File: /Users/<user>/.config/solana/cli/config.yml
RPC URL: https://api.devnet.solana.com
WebSocket URL: wss://api.devnet.solana.com/ (computed)
Keypair Path: /Users/<user>/.config/solana/id.json
Commitment: confirmed
```

The `deploy` command uploads your newly built verifiable program to make it accessible to the prover network. We currently support S3-compatible storage hosts.

```bash
$ bonsol deploy s3 \
    --bucket <bucket-name> \
    --access-key <access-key> \
    --secret-key <secret-key> \
    --manifest-path <path-to-manifest.json>
Uploaded to S3 url https://bonsol.s3.us-east-1.amazonaws.com/say_hello-6700902caf52fb56277157db725faa5c1aeac0c08221d2e13e27430da2f77136
```

You'll be prompted to continue, press `y`:

```
Deploying to Solana, which will cost real money. Are you sure you want to continue? (y/n)
y
6700902caf52fb56277157db725faa5c1aeac0c08221d2e13e27430da2f77136 deployed
```

{% endstep %}

{% step %}

#### Create an execution request

An execution request is specified in a JSON file with the following structure:

```json
{
  "imageId": "6700902caf52fb56277157db725faa5c1aeac0c08221d2e13e27430da2f77136",
  "executionConfig": {
    "verifyInputHash": false,
    "forwardOutput": true
  },
  "inputs": [
    {
      "inputType": "PublicData",
      "data": "Hello, world!"
    }
  ],
  "tip": 12000,
  "expiry": 1000
}
```

**Required Fields**

* **imageId:** The unique identifier of the verifiable program image to execute. This is generated when building your program and is found in your `manifest.json`.
* **inputs**: An array of input objects that will be passed to the verifiable program. This program just uses one input.
* **inputType**: Type of input data.
* **data**: The actual input data, properly formatted as a string.
  {% endstep %}

{% step %}

#### Execute the verifiable program

Use the `execute` command to submit your execution request to the prover network:

```bash
$ bonsol execute -f execution-request.json --wait
Execution expiry 35436
current block 34436
  Claimed by 5RChCvEt8z5Uq9DF2yv2sJeazgm1SFmJChm1mrHH35oU at slot 34469, committed 17718
  Execution completed with exit code Success
```

* If the execution is not completed within the timeout period, you'll receive a timeout message.
* If the execution request expires without being claimed, you'll receive an expiry message.
  {% endstep %}
  {% endstepper %}

Congratulations! You've deployed your first verifiable program on Solana. See the [Setup a local environment](/developers/setup-a-local-environment) section to build a more fleshed out development environment to build fully unstoppable applications.


# CLI Commands

The Bonsol CLI is a command-line interface for creating, building, deploying, and interacting with verifiable programs on Solana.

## General Usage

Most Bonsol commands accept the following global arguments:

* `-c`or `--config`: Path to the config file
* `-k`or `--keypair`: Path to the keypair file
* `-u`or `--rpc-url`: URL for the Solana RPC

If these arguments aren't provided, Bonsol will use the default Solana config located in `~/.config/solana/`. For example:

```bash
bonsol -k ./keypair.json -u http://localhost:8899 [COMMAND]
```

## Commands

### init: Creating a New Bonsol Program

Initialize a new Bonsol project with the following command:

```bash
bonsol init --project-name <PROJECT_NAME> [--dir <DIR>]
```

Options:

* `-n`, `--project-name <PROJECT_NAME>`: Name of your new project (required)
* `-d`, `--dir <DIR>`: Directory where the project will be created

This command creates a new Bonsol program structure in the specified directory.

### build: Building a Bonsol ZK Program

Build your zero-knowledge program using:

```bash
build --zk-program-path <ZK_PROGRAM_PATH>
```

Options:

* `-z`, `--zk-program-path <ZK_PROGRAM_PATH>`: Path to a ZK program folder containing a Cargo.toml (required)

This command builds your ZK program and creates a `manifest.json`file in the program directory, containing all necessary information for deployment. Example `manifest.json`:

```json
{
  "name": "simple",
  "binaryPath": "images/simple/target/riscv-guest/riscv32im-risc0-zkvm-elf/docker/simple/simple",
  "imageId": "20b9db715f989e3f57842787badafae101ce0b16202491bac1a3aebf573da0ba",
  "inputOrder": [
    "Public",
    "Private"
  ],
  "signature": "3mdQ6RUV5Bw9f1oUJhfif4GqVQpE8Udcu7ZR5NjDeyEx5ls2aRxD74DC5v1d251q6c9Q4m523a5a1h0nOO5f+s",
  "size": 266608
}
```

### deploy: Deploying a Bonsol ZK Program

After building your ZK program, you can deploy it using various storage options:

```bash
bonsol deploy <COMMAND>
```

Commands:

* `s3`: Deploy using an AWS S3 bucket
* `url`: Deploy with a custom URL (e.g. localhost)

<details>

<summary>S3 Deployment</summary>

First, create an S3 bucket (skip this if you already have one):

```bash
aws s3api create-bucket \
    --bucket <BUCKET_NAME> \
    --region <REGION> \
    --create-bucket-configuration LocationConstraint=<REGION>
```

Then deploy your ZK program to your S3 bucket:

```bash
bonsol deploy s3 \
    --bucket <BUCKET_NAME> \
    --access-key <ACCESS_KEY> \
    --secret-key <SECRET_KEY> \
    --region <REGION> \
    --manifest-path <PATH_TO_MANIFEST> \
    --storage-account s3://<BUCKET_NAME>
```

</details>

<details>

<summary>URL</summary>

The `bonsol deploy url` command allows you to deploy your program by either uploading your binary to a URL endpoint or using an existing binary at a URL.

#### Usage

```warp-runnable-command
bonsol deploy url --url <URL> --manifest-path <MANIFEST_PATH> [OPTIONS]
```

#### Required Arguments

* `--url <URL>`
* The base URL endpoint for your binary
* Example: `http://localhost:8080`
* The actual binary will be stored at `<URL>/<program-name>-<image-id>`
* `--manifest-path <MANIFEST_PATH>`
* Path to your program's manifest file (manifest.json)
* Example: `images/simple/manifest.json`

#### Optional Arguments

* `--no-post`
* By default, the command uploads your binary to the URL
* With this flag, it instead verifies that the correct binary already exists at the URL
* Useful when your binary is already hosted and you just want to deploy it to Solana
* `--auto-confirm` or `-y`
* Skip the confirmation prompt for Solana deployment
* Use with caution as deployments cost real money

#### Examples

1. Upload and deploy a new binary:

```warp-runnable-command
bonsol deploy url \
    --url http://localhost:8080 \
    --manifest-path images/simple/manifest.json
```

2. Deploy using an existing binary (verifies the binary first):

```warp-runnable-command
bonsol deploy url \
    --url http://localhost:8080 \
    --manifest-path images/simple/manifest.json \
    --no-post
```

#### How It Works

1. The command constructs the full URL by appending your program name and image ID:

```warp-runnable-command
   <base-url>/<program-name>-<image-id>
```

For example: `http://localhost:8080/simple2-ec93e0a9592a2f00c177a7fce6ff191019740ff83f589e334153126c02f5772e`

2. Without `--no-post` (default):

* POSTs your binary to this URL
* Proceeds with Solana deployment after successful upload

3. With `--no-post`:

* Attempts to GET the binary from this URL
* Verifies it matches your local binary
* Only proceeds with Solana deployment if verification succeeds

#### Common Errors

1. "Binary does not match":

```warp-runnable-command
   Error: The binary uploaded does not match the local binary at path '...'

```

* This occurs when using `--no-post` and either:
  * No binary exists at the URL
  * The binary at the URL is different from your local binary

2. "Failed to connect":

* Check that your URL endpoint is accessible
* Ensure you have the correct permissions

#### Notes

* The command always requires a local binary for verification, even when using `--no-post`
* Deployments to Solana are immutable and cost real money
* The URL endpoint must support both POST and GET operations

</details>

### execute: Requesting Execution

Request execution of your ZK program:

```bash
bonsol execute [OPTIONS]
```

Options:

The execution request file should be a JSON file with the following structure:

* `-f`, `--execution-request-file <EXECUTION_REQUEST_FILE>`: Path to execution request JSON file
* `-p`,`--program-id <PROGRAM_ID>`: Program ID
* `-e`, `--execution-id <EXECUTION_ID>`: Execution ID
* `-x`, `--expiry <EXPIRY>`: Expiry for the execution
* `-m`, `--tip <TIP>`: Tip amount for execution
* `-i`, `--input-file <INPUT_FILE>`: Override inputs in execution request file
* `-w`, `--wait`: Wait for execution to be proven
* `-t`, `--timeout <TIMEOUT>`: Timeout in seconds

The execution request file should be a JSON file with the following structure:

```json
{
  "imageId": "20b9db715f989e3f57842787badafae101ce0b16202491bac1a3aebf573da0ba",
  "executionId": "9878798-987987-987987-987987",
  "tip": 100,
  "maxBlockHeight": 100,
  "inputs": [
    {
      "inputType": "Public",
      "data": "<base64 encoded data>"
    }
  ],
  "callbackConfig": {
    "programId": "your program id",
    "instructionPrefix": [0, 1, 2, 3],
    "extraAccounts": [
      {
        "address": "",
        "role": "writable"
      }
    ]
  },
  "executionConfig": {
    "verifyInputHash": true,
    "forwardOutput": true,
    "inputHash": "<hex encoded sha256 hash of the input data>"
  }
}
```

If you pass the `--wait` flag, the CLI will wait for execution completion and display the result:

```
Execution 9878798-987987-987987-987987 completed successfully
```

### prove: Local Proving with the CLI

Perform local proving against a deployed program:

```bash
bonsol prove --execution-id <EXECUTION_ID> [OPTIONS]
```

Options:

* `-m`, `--manifest-path <MANIFEST_PATH>`: Path to the manifest file
* `-p`, `--program-id <PROGRAM_ID>`: Program ID
* `-i <INPUT_FILE>`: Input file
* `-e`, `--execution-id <EXECUTION_ID>`: Execution ID (required)
* `-o <OUTPUT_LOCATION>`: Output location for the proof

You can provide inputs in a JSON file:

```json
{
  "imageId": "20b9db715f989e3f57842787badafae101ce0b16202491bac1a3aebf573da0ba",
  "inputs": [
    {
      "inputType": "PrivateLocal",
      "data": "<base64 encoded data>"
    }
  ]
}
```

Or pipe inputs directly:

```bash
echo '"{"attestation":"test"}" "nottest"' | bonsol prove -e <execution_id> -m images/simple/manifest.json
```

If proving succeeds, the CLI will save a serialized RISC-0 receipt file named `<execution_id>.bin` in the current directory or the specified output location.

:bulb: Note: Only private local inputs are supported for the prove command.\\


# Setup a local environment

This guide provides instructions for setting up a local Bonsol development environment. Whether you're contributing to the project or building with Bonsol, this documentation will help.

## Requirements

:bulb: In this section, you'll be running a local Bonsol proving node. Currently provers are limited to running on x86\_64-linux systems due to dependencies on [STARK-to-SNARK](https://bonsol.gitbook.io/docs/core-concepts/introduction#stark-to-snark-conversion) tooling. We're looking for workarounds for MacOS, but in the meantime we suggest developing on a remote Linux machine.

Before you begin, ensure you have the following system requirements:

* [Rust](https://solana.com/docs/intro/installation#install-rust)
* [Solana CLI](https://solana.com/docs/intro/installation#install-the-solana-cli)
* [pnpm/pnpx](https://pnpm.io/installation)

Verify you have these requirements by running:

```bash
cargo --version
rustc --version
solana --version
pnpm --version
```

## Local environment setup

{% stepper %}
{% step %}
**Clone the repository**

```bash
git clone https://github.com/bonsol-collective/bonsol
cd bonsol
```

{% endstep %}

{% step %}
**Install the RISC Zero prover**

```bash
# Install the prover to the default location (current directory)
./bin/install_prover.sh

# Or specify a custom installation location
./bin/install_prover.sh --prefix /path/to/install
```

{% endstep %}

{% step %}
**Run the setup script**

* Checks that the STARK verification tools are installed
* Generates and parses the verification key for on-chain use

```bash
# Set up local environment
./bin/setup.sh

# Or specify a custom installation prefix if you used one for install_prover.sh
./bin/setup.sh --prefix /path/to/install
```

{% endstep %}

{% step %}
**Run the Solana validator script**

* Builds the Solana BPF programs using `cargo build-sbf`
* Starts a local Solana validator with the Bonsol program at address `BoNsHRcyLLNdtnoDf8hiCNZpyehMC4FDMxs6NTxFi3ew`
* Includes a callback example program
* Allows adding additional BPF programs with their addresses

```bash
# Start a local validator
./bin/validator.sh

# Or run the local validator with the reset option
./bin/validator.sh -r
```

{% endstep %}

{% step %}
**Run the Bonfire Coordinator**

* Starts Elasticsearch (via Docker) for persistent log storage
* Automatically generates TLS certificates in certs/ if missing
* Starts the coordination server for Node communication

```bash
# Start Bonfire
./bin/run-bonfire.sh
```

{% endstep %}

{% step %}
**Run a local Bonsol node**

* Creates a new node keypair if one doesn't exist
* Airdrop SOL to the node keypair for transaction fees
* Run the Bonsol node with the appropriate hardware acceleration:
  * Linux: CPU or CUDA (if `-F cuda` flag is used)

```bash
# Start a node with default CPU configuration
./bin/run-node.sh

# For Linux systems with CUDA support
./bin/run-node.sh -F cuda
```

{% endstep %}
{% endstepper %}

## Troubleshooting

* If the prover installation fails, check your internet connection and try increasing the `--job-timeout` value.
  * `--job-timeout`: Set timeout for download operations in seconds (default: 3600)

```bash
# Install the prover with an increased timeout
./bin/install_prover.sh --job-timeout 7200
```

* If the validator fails to start, ensure that Rust and Solana CLI tools are properly installed
* For node startup issues, verify that the validator is running and that SOL was successfully airdropped to your node keypair


# Tutorial: Simple Program

This tutorial guides you through creating, building, and deploying a zero-knowledge program using Bonsol on Solana. By the end, you'll understand how to create ZK proofs that can be verified on-chain.

## Setting up your environment

### Setup a local environment

Refer to the [Setup a local environment](/developers/setup-a-local-environment) page for instructions on setting up a local environment.

### Start the Local Validator

The validator script builds and deploys necessary Solana programs, including the Bonsol core program and an example callback program (not used in this tutorial).

```bash
$ ./bin/validator.sh

./bin/validator.sh -r
++ which cargo
+ '[' '!' -x /home/ubuntu/.cargo/bin/cargo ']'
+ cargo build-sbf
   Compiling ...
   Compiling bonsol-interface v0.4.5 (/home/ubuntu/bonsol/onchain/interface)
   Compiling callback-example v0.4.5 (/home/ubuntu/bonsol/onchain/example-program-on-bonsol)
    Finished `release` profile [optimized] target(s) in 18.51s
+ solana-test-validator --limit-ledger-size 0 --bind-address 0.0.0.0 --rpc-pubsub-enable-block-subscription --bpf-program BoNsHRcyLLNdtnoDf8hiCNZpyehMC4FDMxs6NTxFi3ew target/deploy/bonsol.so --bpf-program exay1T7QqsJPNcwzMiWubR6vZnqrgM16jZRraHgqBGG target/deploy/callback_example.so -r
Ledger location: test-ledger
Log: test-ledger/validator.log
⠠ Initializing...                                                                                                        Waiting for fees to stabilize 1...
Identity: Bdudyg3GB4Gw3we7g9RCLBnL3E9TJ1N2bfsZTFAaocv6
Genesis Hash: HWEv5jLYLrzdxsEXcc56dkSV96b7h8cYwSPgKyR77a6Q
Version: 2.1.14
Shred Version: 64458
⠉ 00:18:59 | Processed Slot: 2789 | Confirmed Slot: 2789 | Finalized Slot: 2758 | Full Snapshot Slot: 2700 | Incremental Snapshot Slot: - | Transactions: 2788 | ◎499.986060000
```

> :bulb: Note: Keep this terminal window open as the validator needs to run throughout the tutorial.

### Run the Bonsol Prover Node

The prover node processes the off-chain computation. Open a new terminal and run:

```bash
$ ./bin/run-node.sh

Bonsol node keypair exists
Requesting airdrop of 1 SOL

Signature: 5xBZKBZhk9Zn9HdXSuo9w6pqzdiQTq6hriWy5n4xNKu6oD5DoZdih1gfAnjL4gzKr8wcv3DQ553uYGrdpKUWK7ta

1 SOL
Requesting airdrop of 1 SOL

Signature: 53GJFP1HMopNuyXfnQSxP7m49MZ2HfTTfRvVkMLdCk3dkzgKr8whfzQw7amWmVz2BP3zU6GhwJ913qD9V6VdPjS2

500000001 SOL
   Compiling bonsol-schema v0.4.5 (/home/ubuntu/bonsol/schemas)
   Compiling bonsol-prover v0.4.5 (/home/ubuntu/bonsol/prover)
   Compiling bonsol-interface v0.4.5 (/home/ubuntu/bonsol/onchain/interface)
   Compiling bonsol-node v0.4.5 (/home/ubuntu/bonsol/node)
    Finished `release` profile [optimized] target(s) in 26.01s
     Running `target/release/bonsol-node -f ./Node.toml`
{"timestamp":"2025-03-11T06:57:50.284199771Z","level":"INFO","fields":{"message":"Event: BonsolStartup","event":"BonsolStartup","up":true},"target":"bonsol_node"}
{"timestamp":"2025-03-11T06:57:50.284232745Z","level":"INFO","fields":{"message":"Using Keypair File"},"target":"bonsol_node"}
{"timestamp":"2025-03-11T06:57:50.284454687Z","level":"INFO","fields":{"message":"Using RPC Block Subscription"},"target":"bonsol_node"}
{"timestamp":"2025-03-11T06:57:50.384950857Z","level":"INFO","fields":{"message":"Loaded image: 7cb4887749266c099ad1793e8a7d486a27ff1426d614ec0cc9ff50e686d17699"},"target":"bonsol_node::risc0_runner"}
{"timestamp":"2025-03-11T06:57:50.453175244Z","level":"INFO","fields":{"message":"Loaded image: f899f7bf9823d6e1dab99f8a33a4e203f0341d1a0be98a6b8e07c25e834571a0"},"target":"bonsol_node::risc0_runner"}
{"timestamp":"2025-03-11T06:57:50.520950383Z","level":"INFO","fields":{"message":"Loaded image: 4fe2a1e650dc0ba12e58bccb07c66b23fe5a3ff90e2bd06dfddf87576f3f3b22"},"target":"bonsol_node::risc0_runner"}
{"timestamp":"2025-03-11T06:57:50.593944246Z","level":"INFO","fields":{"message":"Loaded image: 7cb4887749266c099ad1793e8a7d486a27ff1426d614ec0cc9ff50e686d17699"},"target":"bonsol_node::risc0_runner"}
{"timestamp":"2025-03-11T06:57:50.667674793Z","level":"INFO","fields":{"message":"Loaded image: 20b9db715f989e3f57842787badafae101ce0b16202491bac1a3aebf573da0ba"},"target":"bonsol_node::risc0_runner"}
{"timestamp":"2025-03-11T06:57:50.74100063Z","level":"INFO","fields":{"message":"Loaded image: 68f4b0c5f9ce034aa60ceb264a18d6c410a3af68fafd931bcfd9ebe7c1e42960"},"target":"bonsol_node::risc0_runner"}
{"timestamp":"2025-03-11T06:57:50.808491816Z","level":"INFO","fields":{"message":"Loaded image: 6700902caf52fb56277157db725faa5c1aeac0c08221d2e13e27430da2f77136"},"target":"bonsol_node::risc0_runner"}
{"timestamp":"2025-03-11T06:57:50.810318595Z","level":"INFO","fields":{"message":"Risc0 Prover with digest c101b42bcacd62e35222b1207223250814d05dd41d41f8cadc1f16f86707ae15"},"target":"bonsol_node::risc0_runner::verify_prover_version"}

```

> :bulb: Note: Keep this terminal window open as the prover node needs to run throughout the tutorial.

### Run the Local ZK Program Server

As explained in the [architecture](https://github.com/bonsol-collective/bonsol/blob/main/gitbook/core-concepts/architecture.md.md) page, provers on the network need to fetch the ZK programs and the input data used to generate the proof. The methods used to fetch these resources are stored on-chain by the ZK program developer.

For the purpose of local development, we will use a local HTTP server to host the ZK program data. This server stores everything in memory, so it will reset when the server is restarted. Open a new terminal and run:

```bash
$ cargo run -p local-zk-program-server
   Compiling local-zk-program-server v0.4.5 (/home/ubuntu/bonsol/local-zk-program-server)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.56s
     Running `target/debug/local-zk-program-server`
Server is running on 0.0.0.0:8080
```

> :bulb: Note: Keep this terminal window open as the prover node needs to run throughout the tutorial.

## Writing the ZK program

Let's examine the simple ZK program provided in the repo at `bonsol/images/simple/src/main.rs`.

```rust
# bonsol/images/simple/src/main.rs

use gjson::Kind;
use risc0_zkvm::{guest::{env, sha::Impl},sha::{Digest, Sha256}};

fn main() {
    let mut public1 = Vec::new();
    env::read_slice(&mut public1);
    let publici1 = String::from_utf8(public1).unwrap();
    let mut private2 = Vec::new();
    env::read_slice(&mut private2);
    let privatei2 = String::from_utf8(private2).unwrap();
    let valid = gjson::valid(&publici1);
    let mut res = 0;
    if valid {
        let val = gjson::get(&publici1, "attestation");
        if val.kind() == Kind::String && val.str() == privatei2 {
            res = 1;
        }
    }
    let digest = Impl::hash_bytes(
        &[
            publici1.as_bytes(),
            privatei2.as_bytes(),
        ].concat(),
    );
    env::commit_slice(digest.as_bytes());
    env::commit_slice(&[res]);
}

```

This simple program demonstrates private input validation, where only the prover knows the private input, but anyone can verify the result. Here's how the program works:

1. Reads two inputs
   * public1: A JSON string with an "attestation" field
   * private2: A private string to compare against the attestation
2. Validates if
   * The public input is valid JSON
   * The "attestation" field in the JSON matches the private input
3. Outputs
   * A cryptographic digest of both inputs
   * A result (1 for match, 0 for no match)

## Building the ZK program

Now that we understand the program, let's build it:

```bash
bonsol build --zk-program-path ./images/simple
```

This compiles the Rust code into a format compatible with the RISC Zero VM and generates a `manifest.json` file containing:

```json
{
  "name": "simple2",
  "binaryPath": "./images/simple/target/riscv-guest/riscv32im-risc0-zkvm-elf/docker/simple2/simple2",
  "imageId": "ec93e0a9592a2f00c177a7fce6ff191019740ff83f589e334153126c02f5772e",
  "inputOrder": ["Public", "Private"],
  "signature": "5PdbBK1A5Qtyg1P6GUbMLt2eG4VSPfYRMaGsPoxJRwoQzJbAgkFx9N5nafTHxpdG5d2CUqVUsBfUgWijyEBXtxqH",
  "size": 279880
}
```

> :bulb: Important: Take note of the `imageId` as you'll need it for the next steps. This uniquely identifies your ZK program in the network.

## Deploying the ZK program

Next, deploy the program to the local ZK program server and register it on-chain:

```bash
$ bonsol deploy url \
    --bucket bonsol \
    --url http://localhost:8080 \
    --post \
    --manifest-path ./images/simple/manifest.json

Program available at URL https://localhost:8080/simple2-ec93e0a9592a2f00c177a7fce6ff191019740ff83f589e334153126c02f5772e
Deploying to Solana, which will cost real money. Are you sure you want to continue? (y/n)
y
ec93e0a9592a2f00c177a7fce6ff191019740ff83f589e334153126c02f5772e deployed
```

> 💡 Note: When deploying to mainnet, this operation costs SOL to register your program on-chain.

## Creating and submitting an execution request

### Edit the execution request

Locate the sample execution request template at `bonsol/charts/input_files/simple_execution_request.json`. Update the template with your specific `imageId` from the `manifest.json`file:

```json
# bonsol/charts/input_files/simple_execution_request.json
{
  "imageId": "ec93e0a9592a2f00c177a7fce6ff191019740ff83f589e334153126c02f5772e",
  "executionConfig": {
    "verifyInputHash": false,
    "forwardOutput": true
  },
  "inputs": [
    {
      "inputType": "PublicData",
      "data": "{\"attestation\":\"test\"}"
    },
    {
      "inputType": "Private",
      "data": "https://echoserver.dev/server?response=N4IgFgpghgJhBOBnEAuA2mkBjA9gOwBcJCBaAgTwAcIQAaEIgDwIHpKAbKASzxAF0+9AEY4Y5VKArVUDCMzogYUAlBlFEBEAF96G5QFdkKAEwAGU1qA"
    }
  ],
  "tip": 12000,
  "expiry": 1000
}

```

### Understanding the request

* `imageId`: The identifier for your ZK program
* `executionConfig`: Configuration for execution behavior
* `inputs`: The inputs to your program (must match the order in manifest.json)
* First input: Public JSON data with `"attestation":"test"`
* Second input: Private data (URL-encoded and hosted remotely)
* `tip`: The amount to pay the prover (in lamports)
* `expiry`: Number of blocks until the request expires

### Submit the execution request

```bash
$ bonsol execute -f charts/input_files/simple_execution_request.json --wait

Execution expiry 13235
current block 13135
  Waiting for execution
  Claimed by 5RChCvEt8z5Uq9DF2yv2sJeazgm1SFmJChm1mrHH35oU at slot 13168, committed 6617
```

The `--wait` flag makes the command wait until the execution is complete. You should see:

1. The block at which your request will expire
2. When a prover claims your request
3. When the proof is committed on-chain

## Proof submission

Once the proof generates, you'll see the notification at your CLI:

```bash
bonsol execute -f charts/input_files/simple_execution_request.json --wait
Execution expiry 34380
current block 24380
  Waiting for execution
  Execution completed with exit code Success
```

You can check your prover logs for the corresponding on-chain transaction:

```
⠒ [0/1] Finalizing transaction 2j6iCbz8fKid1MKVKhB9QzvbAiziT4q4xeANAiEPP5DpQuwRTqAycD4JKJ3ca1pHkwNXxQ1fSJKmBdPFXYSrihtA  Sending to runner
{"timestamp":"2025-03-11T09:24:48.933897605Z","level":"INFO","fields":{"message":"Proof submitted: 2j6iCbz8fKid1MKVKhB9QzvbAiziT4q4xeANAiEPP5DpQuwRTqAycD4JKJ3ca1pHkwNXxQ1fSJKmBdPFXYSrihtA"},"target":"bonsol_node::risc0_runner"}
```


# Input Format Guide

A practical guide to formatting inputs for Bonsol ZK programs, covering common pitfalls and working solutions for different input scenarios.

## Overview

When creating execution requests for Bonsol ZK programs, proper input formatting is crucial for successful execution. This guide covers the practical aspects of formatting inputs that work with your ZK program's expectations.

## Understanding Input Format Mismatch

One of the most common issues developers face is input format mismatch between:

* The manifest file's `inputOrder` specification
* The execution request JSON format
* What the ZK program actually expects to read

### Common Error: InputError (0x3)

If you encounter `custom program error: 0x3` during execution, this indicates an `InputError`. Common causes include:

* **Wrong byte count**: ZK program expects 8-byte arrays but receives different sizes
* **Wrong input count**: Manifest specifies 1 input but you're sending multiple inputs
* **String vs. byte mismatch**: Sending string data when ZK program expects binary data

## Working Input Formats

### Single Combined Byte Input

**Best Practice**: When your ZK program reads multiple values using `env::read_slice()`, combine all values into a single input.

**Example**: Calculator program that reads 3 i64 values

```rust
// ZK program code
fn read_i64_input() -> i64 {
    let mut input_bytes = [0u8; 8];
    env::read_slice(&mut input_bytes);
    i64::from_le_bytes(input_bytes)
}

fn main() {
    let operation = read_i64_input();  // First 8 bytes
    let operand_a = read_i64_input();  // Next 8 bytes
    let operand_b = read_i64_input();  // Next 8 bytes
    // ... rest of program
}
```

**Corresponding Rust client code**:

```rust
// Create individual i64 values as little-endian bytes
let operation_bytes = 2i64.to_le_bytes();  // multiply operation
let operand_a_bytes = 7i64.to_le_bytes();  // first operand
let operand_b_bytes = 6i64.to_le_bytes();  // second operand

// Combine into single 24-byte input
let mut combined_input = Vec::with_capacity(24);
combined_input.extend_from_slice(&operation_bytes);
combined_input.extend_from_slice(&operand_a_bytes);
combined_input.extend_from_slice(&operand_b_bytes);

// Send as single input
let execution_instruction = execute_v1(
    &requester,
    &payer.pubkey(),
    image_id,
    execution_id,
    vec![
        InputRef::public(&combined_input),  // Single 24-byte input
    ],
    // ... other parameters
)?;
```

**Manifest alignment**:

```json
{
  "inputOrder": ["Public"]  // Single input, not multiple
}
```

### String Inputs (Limited Support)

**Caution**: String inputs may work for transaction submission but fail during ZK execution.

**What doesn't work**:

```rust
// This will fail during ZK execution
vec![
    InputRef::public("2".as_bytes()),    // [50] - only 1 byte
    InputRef::public("7".as_bytes()),    // [55] - only 1 byte
    InputRef::public("6".as_bytes()),    // [54] - only 1 byte
]
```

**Why it fails**: The ZK program expects 8-byte arrays, but strings produce variable-length byte arrays.

## Debugging Input Issues

### Enable Debug Output

Add debug printing to your client to understand exactly what's being sent:

```rust
println!("📥 Input being sent:");
println!("   Data: {:?} (length: {})", &input_data, input_data.len());
println!("   Expected by ZK program: {} calls to env::read_slice() with {}-byte arrays",
         num_reads, bytes_per_read);
```

### Check Transaction vs. Execution

* **Transaction success + execution failure**: Input format accepted by Bonsol but incompatible with ZK program
* **Transaction failure**: Input format rejected by Bonsol interface

### Monitor Bonsol Logs

Watch for these error patterns in the prover logs:

```
"0 inputs resolved"
"DeserializeUnexpectedEnd"
"Guest panicked"
```

## Best Practices

### 1. Align with ZK Program Expectations

**Do**: Format inputs to match exactly what your ZK program reads

```rust
// If ZK program does this:
let mut buffer = [0u8; 8];
env::read_slice(&mut buffer);

// Then send this:
let data = 42i64.to_le_bytes();  // Exactly 8 bytes
InputRef::public(&data)
```

### 2. Use Single Combined Inputs

**Do**: When reading multiple values sequentially, combine them into one input

```rust
// Multiple sequential reads = single combined input
let combined = [data1, data2, data3].concat();
vec![InputRef::public(&combined)]
```

**Don't**: Send separate inputs when ZK program expects sequential reads from one input

```rust
// This may not work as expected
vec![
    InputRef::public(&data1),
    InputRef::public(&data2),
    InputRef::public(&data3),
]
```

### 3. Match Manifest Input Count

Ensure your `inputOrder` in the manifest matches your actual input usage:

```json
{
  "inputOrder": ["Public"]  // One input
}
```

```rust
vec![InputRef::public(&single_combined_input)]  // One input
```

### 4. Test with Known Working Formats

Start with the byte format that matches your ZK program's expectations, then experiment with convenience formats.

## Example: Working Calculator Client

This example shows a complete working implementation:

```rust
// Client code that works
let operation_bytes = 2i64.to_le_bytes();     // [2,0,0,0,0,0,0,0]
let operand_a_bytes = 7i64.to_le_bytes();     // [7,0,0,0,0,0,0,0]
let operand_b_bytes = 6i64.to_le_bytes();     // [6,0,0,0,0,0,0,0]

let mut combined_input = Vec::with_capacity(24);
combined_input.extend_from_slice(&operation_bytes);
combined_input.extend_from_slice(&operand_a_bytes);
combined_input.extend_from_slice(&operand_b_bytes);

let execution_instruction = execute_v1(
    &requester,
    &payer.pubkey(),
    "5881e972d41fe651c2989c65699528da8b1ed68ab7057350a686b8a64a00fc91",
    "calc_exec_1",
    vec![InputRef::public(&combined_input)],
    1000,
    expiration,
    ExecutionConfig {
        verify_input_hash: false,
        input_hash: None,
        forward_output: true,
    },
    callback_config,
    None,
)?;
```

Result: ✅ Transaction succeeds + ZK execution succeeds

## Troubleshooting Checklist

* [ ] Input byte count matches ZK program's `env::read_slice()` expectations
* [ ] Number of inputs matches manifest's `inputOrder` length
* [ ] Using little-endian byte order for numeric values
* [ ] Combined sequential reads into single input
* [ ] Tested with raw bytes before trying convenience formats
* [ ] Checked Bonsol logs for execution errors
* [ ] Verified ZK program logic handles input format correctly

## Further Reading

* [Bonsol Input Types](https://github.com/bonsol-collective/bonsol/blob/main/gitbook/explanation/bonsol-input-types.md) - Overview of available input types
* [Tutorial: Simple Program](/developers/tutorial-simple-program) - Complete example with JSON inputs
* [CLI Commands](/cli-commands) - Bonsol CLI reference


# Bonsol Calculator Example

Building a Calculator DApp with Bonsol CLI

A zero-knowledge calculator web application using the Bonsol ZK network for verifiable computations. This guide walks you through building a simple calculator dApp using the [Bonsol CLI and local development environment.](https://bonsol.gitbook.io/docs/getting-started/installation)

Here’s a link to the repo:

> <https://github.com/en-tropyc/bonsol-calculator>

### **General flow**

The general flow of the process that we’ll be covering can be visualized below:

```markdown

React Frontend ──→ Express API ──→ Bonsol Network ──→ ZK Computation
      ↓               ↓               ↓               ↓
  localhost:3000  localhost:3001   ZK Execution    Verified Result
```

The proving system we use is the Groth16 SNARK that enables fast on-chain verification of proofs.

### **Prerequisites**

Make sure you have the following installed:

* Bonsol CLI - follow the steps in the [installation guide](https://bonsol.gitbook.io/docs/getting-started/installation) to get started
* [**Solana CLI**](https://solana.com/docs/intro/installation#install-rust)
* **Node.js** (v18+ recommended)
* [pnpm](https://pnpm.io/installation)

### Step 1: Set Up a Project

Firstly, we need to verify your installation

```solidity
bonsol --version
```

The current version is Version **0.4.5**

1. **Create a New Project Directory**:

```solidity
mkdir bonsol-calculator
cd bonsol-calculator
```

1. Clone the repository

```rust
git clone <https://github.com/en-tropyc/bonsol-calculator.git>
```

We should see the following project structure:

```rust
bonsol_calculator/
├── bonsol
├── calculator-api
├── client
├── frontend
├── local-server
├── solana-program
├── zk-program
├── Cargo.toml
├── README.md
```

### Step 2: Setting up the Local environment

The documentation [here](https://bonsol.gitbook.io/docs/developers/setup-a-local-environment) provides instructions for setting up a local Bonsol development environment for the calculator example.

\<aside> \<img src="/icons/activity\_pink.svg" alt="/icons/activity\_pink.svg" width="40px" />

At present, provers can only run on **x86\_64-linux** systems due to dependencies in the STARK-to-SNARK tooling. We’re actively exploring macOS support, but in the meantime, we recommend using a **remote Linux environment** for development.

\</aside>

In this step, you will need to

* **Start the Local Validator**

The validator script builds and deploys the necessary Solana programs, including the Bonsol core program and an example callback program

```rust
./bin/validator.sh -r
```

If the validator fails to start, ensure that Rust and Solana CLI tools are properly installed

* **Run the Bonsol Prover Node**

The prover node processes the off-chain computation. Open a new terminal and run:

```rust
$ ./bin/run-node.sh
```

* **Run the Local ZK Program Server**

Provers on the network need to fetch the ZK programs and the input data used to generate the proof.

Open a new terminal and run:

```rust
$ cargo run -p local-zk-program-server
```

### Step 3: The ZK Program

In `zk-program/src/main.rs`Let's go through the code snippet:

```rust

// Calculator ZK program (from zk-program/manifest.json)
const CALCULATOR_IMAGE_ID: &str = "5881e972d41fe651c2989c65699528da8b1ed68ab7057350a686b8a64a00fc91";
const CALLBACK_PROGRAM_ID: &str = "2zBRw2sEXvjskx7w1w9hqdFEMZWy7KipQ6jKPfwjpnL6";

// Calculator operation codes (from zk-program/src/main.rs)
const OP_ADD: i64 = 0;
const OP_SUBTRACT: i64 = 1;
const OP_MULTIPLY: i64 = 2;
const OP_DIVIDE: i64 = 3;
```

**Constants -** The program defines four operation codes as u8 values:

* OP\_ADD (0): Addition.
* OP\_SUBTRACT (1): Subtraction.
* OP\_MULTIPLY (2): Multiplication.
* OP\_DIVIDE (3): Division.

These constants serve as identifiers for the different arithmetic operations the program is designed to handle. By mapping each operation to a distinct `u8` value, the program can efficiently reference and execute these operations based on their numeric codes.

### Input Format

The calculator ZK program expects three inputs as i64 little-endian bytes:

1. **Operation Code** (8 bytes): 0=add, 1=subtract, 2=multiply, 3=divide
2. **Operand A** (8 bytes): First number
3. **Operand B** (8 bytes): Second number

For example, to calculate `5 + 3`:

* Operation: `0` (add) → `[0, 0, 0, 0, 0, 0, 0, 0]`
* Operand A: `5` → `[5, 0, 0, 0, 0, 0, 0, 0]`
* Operand B: `3` → `[3, 0, 0, 0, 0, 0, 0, 0]`

Now, let's build the zk Program

```rust
bonsol build --zk-program-path ./calculator-example/zk-program
```

### Step 4: The Solana Program

Let's examine the simple ZK program provided in the repo at `solana-program/src/lib.rs` We have a program that uses Bonsol to verify an off-chain addition:

#### Program Structure and Initialization

* This creates a calculator that uses the Bonsol prover network for computations. It imports key `solana_program` modules such as `AccountInfo`, `Pubkey`, and `ProgramError` for handling accounts and errors, and `borsh` for serializing data structures such as `CalculatorState` (tracking program state) and `CalculationRecord` (storing calculation details).
* The `CalculatorInstruction` enum defines four instructions: `Initialize`, `SubmitCalculation`, `GetHistory`, and `Callback`.

#### ZK Calculation and Handling

* The `submit_calculation` function prepares a calculation for the Bonsol ZK network by validating the payer, operation (add, subtract, multiply, divide), and owner. It serializes the operation and operands into a 24-byte input for the ZK program and creates a Bonsol instruction with `execute_v1,` including a callback configuration and 100-slot expiration.
* A pending `CalculationRecord` is stored in `CalculatorState`, which is updated and serialized. The `get_history` function logs the calculation count and last calculation details, while the callback function updates the `CalculationRecord` with the ZK result.

**Build the Code**

Run anchor `build` to make sure everything builds correctly:

```bash
cd solana-program
anchor build
anchor deploy
```

### Step 5: Set Up the Bonsol Calculator Client

```bash
cargo run --bin prover
```

Let's examine the Bonsol calculator client program provided in the repo at `zk-program/src/main.rs`

The Rust program is a client for submitting calculator execution requests to the Bonsol platform on the Solana blockchain, using the bonsol\_interface crate to create execution instructions.

**Key Components**

* Combines operation code and operands into a 24-byte input for the ZK calculator program.
* Configures `ExecutionConfig` (disables input hash, enables output forwarding) and CallbackConfig (specifies callback program and extra accounts).
* Uses `execute_v1` to create a Bonsol execution instruction with the image ID, execution ID, inputs, tip, and expiration.
* Sends the instruction as a signed transaction using `solana_client.`

```
cd client
cargo build
```

### Step 6: Start the Backend API Server

Firstly, we need to start up the Node.js Server

```tsx
cd calculator-api
npm install
npm start
```

Node.js Express server acts as a REST API wrapper for a Rust-based Bonsol calculator client, enabling users to submit arithmetic operations (add, subtract, multiply, divide) to the Bonsol platform on the Solana blockchain.

#### **Endpoints**

The core endpoint, `POST /calculate`, validates input (operation and operands), generates or uses a provided execution ID, and runs the Rust client with cargo run to submit the calculation to Bonsol via the direct-bonsol method, storing the request status and transaction signature in a Map. Additional endpoints (`GET /execution/:id`, `/executions`, `/health`, /) provide execution status, list all requests, check server health, and display API info.

If the command was successful, you should see the code below

<figure><img src="/files/qDVCfJpqxFSfdHasqG1r" alt=""><figcaption></figcaption></figure>

### Step 7: Build the Frontend

In this step, we will interact with the calculator with a frontend using the `CalculationRequest` and `CalculationResponse` that reveals `ExecutionStatus` as 'submitted', 'completed', or 'failed' in the file in `frontend/src/bonsol-api-client.ts`.

It defines a `BonsolApiClient` class that serves as a client for interacting with the Bonsol Calculator REST API, facilitating arithmetic operation submissions to the Bonsol platform on the Solana blockchain.

It provides methods to:

* Submit calculations via POST /calculate,
* Retrieve execution status with GET /execution/:id,
* List all executions using GET /executions
* Check API health with GET /health

Lastly, run the frontend client

```tsx
cd frontend
npm install
npm start
```

* Open `http://localhost:3000`

![](/files/g5Ljeykni6LiucT4mEm5)

### Step 8: Test Application

Run the computation:

* Enter numbers and select operation (e.g 25 \* 15)
* Click "Calculate with ZK"
* Wait \~15-30 seconds for ZK proof computation\\

What it does - submit calculations through a web interface that:

1. Sends requests to local API server
2. Submits to Bonsol ZK network for computation
3. Returns cryptographically verified results
4. Displays execution IDs and transaction signatures\\

Example successful execution:

* Calculation: 15 × 25 = 375
* Execution ID: `calc_1748059174997_35200c8e`
* Transaction: `5yTzwjn88HTWTPnciBoqpXnj7ouuYZJsRFN8n2GPM9YmjuctidvJkhywepj11dxuXjKvTRC48PXBetL6ERtDb5mF`

### Note

Here are some ideas if you are interested in extending the capabilities of this client example

1. Add support for more complex mathematical operations
2. Implement batch calculations
3. Add input validation and error handling
4. Support for floating-point operations (requires ZK program changes)
5. Add result verification and display


# AI OCR Example

Building Zero-Knowledge Applications with Bonsol

This guide walks you through building applications that leverage zero-knowledge proofs on Solana using the Bonsol framework. We'll use an OCR (Optical Character Recognition) example that runs a machine learning model off-chain while maintaining cryptographic accountability on-chain.

### How Bonsol Works

Bonsol enables you to move computation off-chain while keeping full transparency and verification on-chain:

1. **Your app calls your Solana program** with input data
2. **Your program schedules a ZK job** by calling the Bonsol program
3. **Bonsol provers pick up the job**, download your ZK program image, execute it, and generate a proof
4. **Bonsol verifies the proof** and calls your program back with the results
5. **Your program processes the verified results** on-chain

This architecture lets you run expensive computations (like ML inference, complex algorithms, or data processing) off-chain while maintaining the security guarantees of on-chain execution.

### Architecture Overview

<figure><img src="/files/igNnfw31RnfhsANAzBcb" alt=""><figcaption></figcaption></figure>

### Step 1: Building the ZK Program

Your ZK program runs inside the RISC0 zkVM. It reads inputs, performs computation, and commits outputs that will be verified on-chain.

#### Basic Structure

```rust
use risc0_zkvm::guest::env;

fn main() {
    // 1. Read input data
    let mut input_data = [0u8; DATA_SIZE];
    env::read_slice(&mut input_data);

    // 2. Process the data
    let result = process(input_data);

    // 3. Commit the output (this becomes your verified result)
    env::commit_slice(&result);
}

```

#### OCR Example

In our OCR example, we read a 28×28 pixel image (packed as bits), run it through a neural network, and output class probabilities:

```rust
fn main() {
    // Read 98 bytes (28*28 pixels / 8 bits)
    let mut image_bits = [0u8; IMAGE_BITS_SIZE];
    env::read_slice(&mut image_bits);

    // Unpack bits to floats
    let mut image = vec![0.0_f32; IMAGE_SIZE];
    for idx in 0..IMAGE_SIZE {
        image[idx] = ((image_bits[idx / 8] >> (7 - idx % 8)) & 1) as f32;
    }

    // Run ML inference
    let output: Vec<f32> = inference::Mnist::new().inference(&image).unwrap();

    // Commit results to be verified on-chain
    env::commit_slice(&output);
}

```

**Key points:**

* Use `env::read_slice()` to read input data
* Use `env::commit_slice()` to output results that will be available on-chain
* Keep your program focused and efficient while you're generating proofs of execution

#### 1.1: Building and Deploying

```bash
# Build your ZK program
bonsol build

# Deploy to an image server
bonsol deploy url --url [your-image-server] --manifest-path manifest.json

```

For development, start a local image server:

```bash
cargo run -p local-zk-program-server

```

Your program gets a unique image ID (SHA256 hash) that you'll reference on-chain.

### Step 2: Writing the Solana Program

Your Solana program acts as the orchestrator as it receives requests from users and schedules ZK jobs with Bonsol.

#### 2.1: Scheduling a ZK Execution

```rust
use bonsol_interface::instructions::{execute_v1, CallbackConfig, ExecutionConfig, InputRef};

pub fn do_ocr(
    ctx: Context<DoOcr>,
    execution_id: String,
    image_bits: [u8; 98],
    tip: u64,
) -> Result<()> {
    let slot = Clock::get()?.slot;

    let ix = execute_v1(
        ctx.accounts.payer.key,           // Requester
        ctx.accounts.payer.key,           // Payer for execution
        AI_IMAGE_ID,                      // Your ZK program's image ID
        &execution_id,                    // Unique execution identifier
        vec![InputRef::public(&image_bits)], // Input data
        tip,                              // Tip for provers (in lamports)
        slot + 100000000,                 // Expiration slot
        ExecutionConfig {
            forward_output: true,         // Send output to callback
            verify_input_hash: false,
            input_hash: None,
        },
        Some(CallbackConfig {
            program_id: crate::id(),
            instruction_prefix: vec![245, 250, 10, 62, 218, 252, 239, 91], // Callback discriminator
            extra_accounts: vec![
                AccountMeta::new(ctx.accounts.ai_result.key(), false)
            ],
        }),
        None,
        vec![],                           // Authorized provers (recommended)
    )?;

    invoke(&ix, &ctx.accounts.to_account_infos())?;
    Ok(())
}

```

**Key parameters:**

* **execution\_id**: Unique identifier for this execution (used to derive PDAs)
* **image\_id**: The SHA256 hash of your deployed ZK program
* **InputRef::public()**: Marks data as public input (there's also `InputRef::private()`)
* **tip**: Incentivizes provers to pick up your job quickly
* **CallbackConfig**: Tells Bonsol how to call your program back with results
* **Authorized provers:** A list of the public keys of provers that are authorized to run this job. It's recommended to use only trusted/performing provers.

#### 2.2: Receiving Results via Callback

```rust
pub fn callback(ctx: Context<Callback>, result: [f32; 10]) -> Result<()> {
    // Bonsol calls this after verification
    ctx.accounts.ai_result.result = result;
    Ok(())
}

#[derive(Accounts)]
pub struct Callback<'info> {
    /// CHECK: Verified by Bonsol
    pub execution_request: UncheckedAccount<'info>,

    #[account(mut)]
    pub ai_result: Account<'info, AiResult>,
}

```

**Important:** The callback is only invoked if the proof verification succeeds, in production you should verify that callback was called from our program.

#### 2.3: Account Structure

```rust
#[derive(Accounts)]
#[instruction(execution_id: String)]
pub struct DoOcr<'info> {
    #[account(mut)]
    pub payer: Signer<'info>,

    // Store results here
    #[account(
        init,
        payer = payer,
        space = 8 + 40,
        seeds = [b"ai_result", execution_id.as_bytes(), payer.key().as_ref()],
        bump
    )]
    pub ai_result: Account<'info, AiResult>,

    /// CHECK: Bonsol execution request PDA
    #[account(mut)]
    pub execution_request: AccountInfo<'info>,

    /// CHECK: Bonsol deployment account
    pub deployment_account: AccountInfo<'info>,

    #[account(executable, address = bonsol_interface::id())]
    pub bonsol_program: AccountInfo<'info>,

    pub system_program: Program<'info, System>,
}

```

### Step 3: Building the Client

The client coordinates PDAs, submits transactions, and polls for results.

#### 3.1: Deriving Program-Derived Addresses

To schedule a ZK job you typically need 3 accounts:

* the execution request account: this is where the execution request will be stored, and later picked up by provers
* the deployment account: this is the account that informs provers about your program’s deployment (where to download it from, what inputs it takes, etc.).
* the result account: This is optional but you’ll typically want to store your ZK program’s output somewhere.

```tsx
import { PublicKey } from "@solana/web3.js";
import keccak256 from "keccak256";

// Your result account
const [aiResultPda] = PublicKey.findProgramAddressSync(
  [Buffer.from("ai_result"), Buffer.from(executionId), payer.toBuffer()],
  AI_PROGRAM_ID
);

// Bonsol execution request account
const [executionRequestPda] = PublicKey.findProgramAddressSync(
  [Buffer.from("execution"), payer.toBuffer(), Buffer.from(executionId)],
  BONSOL_PROGRAM_ID
);

// Bonsol deployment account (from image ID)
const deriveDeploymentAccount = (imageIdSha256Hex: string): PublicKey => {
  const hash = keccak256(Buffer.from(imageIdSha256Hex));
  const [deploymentPda] = PublicKey.findProgramAddressSync(
    [Buffer.from("deployment"), hash],
    BONSOL_PROGRAM_ID
  );
  return deploymentPda;
};

```

#### 3.2: Submitting an Execution Request

After all the accounts are derived, we schedule a new job calling our program (which in turn will call Bonsol’s program).

```tsx
const executionId = `ocr_${Date.now()}_${wallet.publicKey.toString().substring(0, 8)}`;

const tx = await program.methods
  .doOcr(executionId, imageBits, new anchor.BN(tipLamports))
  .accounts({
    payer: wallet.publicKey,
    aiResult: aiResultPda,
    executionRequest: executionRequestPda,
    deploymentAccount: deriveDeploymentAccount(IMAGE_ID),
  })
  .rpc();

```

#### 3.3: Polling for Results

Since ZK proof generation happens off-chain asynchronously, you need to poll for results:

```tsx
const pollForAiResult = async (
  connection: Connection,
  wallet: AnchorWallet,
  executionId: string,
  maxDurationSeconds: number = 3600,
  pollIntervalSeconds: number = 10
): Promise<{ found: boolean; result?: number[] }> => {
  const startTime = Date.now();

  while (Date.now() - startTime < maxDurationSeconds * 1000) {
    try {
      const account = await program.account.aiResult.fetchNullable(aiResultPda);

      if (account && account.result.some(v => v !== 0)) {
        return { found: true, result: account.result };
      }
    } catch (e) {
      // Account not initialized yet
    }

    await new Promise(resolve => setTimeout(resolve, pollIntervalSeconds * 1000));
  }

  return { found: false };
};

```

### Complete Flow Example

The entire flow includes the following steps:

1. **User draws digit on canvas** → Exports as 98-byte bit array
2. **Client calls `doOcr()`** → Creates execution request on-chain
3. **Solana program calls Bonsol** → Schedules ZK job with image data
4. **Off-chain prover:**
   * Picks up job from Bonsol program
   * Downloads ZK program image
   * Executes ML inference in zkVM
   * Generates proof
   * Submits proof + output to Bonsol
5. **Bonsol verifies proof** → Calls your program's callback
6. **Callback stores results** → Writes to `ai_result` account
7. **Client polls and reads** → Displays recognized digit

<figure><img src="/files/S2Qs2LNTAA8Vv5ChYXlE" alt=""><figcaption><p>Revisiting the flow diagram for Bonsol AI OCR Example</p></figcaption></figure>

### Best Practices

**Execution IDs:** Use unique, descriptive identifiers. Include timestamps and user info to avoid collisions:

```tsx
const executionId = `${operation}_${Date.now()}_${wallet.publicKey.toString().slice(0, 8)}`;

```

**Tips:** Higher tips incentivize faster proof generation. Balance cost vs. speed based on your use case.

**Input Data:** Keep inputs small when possible, as they’re committed to on-chain transactions.

For large data, consider using hashes and storing data off-chain.

**Error Handling:** Always handle cases where proofs time out or fail. Provide feedback to users.

**Testing:** Use devnet for development. Start a local image server for rapid iteration.

### Summary

Bonsol lets you build powerful Solana applications that leverage off-chain computation while maintaining on-chain verification:

* **Write ZK programs** that perform complex computations
* **Deploy them** to accessible image servers
* **Schedule executions** from your Solana program
* **Receive verified results** via callbacks
* **Build UIs** that poll for results asynchronously

This pattern works for ML inference, complex algorithms, data processing, and any computation too expensive for on-chain execution but requiring cryptographic accountability.

For now, our proof of concept demo only works with numbers since training was done on the MNIST dataset with numbers only. To expand into other use cases like verifying characters, you simply have to train the AI model with a dataset such as the EMNIST dataset which includes letters, both lowercase and uppercase.


# Setup a prover node

{% content-ref url="/pages/pLNWl6BEfdtfNfKGIAVM" %}
[Manually Provision a Bonsol Node](/provers/setup-a-prover-node/manually-provision-a-bonsol-node)
{% endcontent-ref %}


# Manually Provision a Bonsol Node

Bonsol has a fully featured Docker image and Helm chart that can be used to run a Bonsol node on Kubernetes. For more information on how to run a Bonsol node on kubernetes check out the [Run a Bonsol Node on Kubernetes](https://bonsol.sh/docs/how-to-guides/run-a-bonsol-node-on-k8s) guide.

### Prerequisites <a href="#prerequisites" id="prerequisites"></a>

* A keypair for the node, you need some SOL to pay for the transactions
* A Dragons mouth compatible rpc provider endpoint [Dragons Mouth Docs](https://docs.triton.one/project-yellowstone/dragons-mouth-grpc-subscriptions) click here to get one from [Triton One](https://triton.one/triton-rpc/)
* Docker on your local machine (not required on the node)
* The node will do better if it has a gpu with cuda installed, which will require nvidia drivers and tools.

> **Note**: Ansible role coming soon

### Hardware Requirements

To run a Bonsol prover node effectively, you'll need:

**CPU**:

* Minimum: 4 cores / 8 threads
* Recommended: 8 cores / 16 threads for better proof generation performance
* Architecture: x86\_64

**Memory**:

* Minimum: 16 GB RAM
* Recommended: 32 GB RAM

**Storage**:

* Minimum: 100 GB SSD available space
* Recommended: 250 GB+ SSD for image caching

**GPU** (Optional but recommended):

* Minimum: GTX 1060 6GB or equivalent
* Recommended: RTX 3060 or better
* Required: CUDA 11.0+

**Network**:

* Stable internet connection with at least 100 Mbps bandwidth
* Low latency connection to your RPC provider

> **Note**: While a GPU is optional, nodes with CUDA-capable GPUs will have significantly better proof generation performance and may be more competitive in the network.

### Installing Deps <a href="#installing-deps" id="installing-deps"></a>

```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.81.0 -y
```

Ensure cargo is on the path

On your local machine, you will need to run a Docker image to get the needed Groth16 witness generator and snark binary.On your local machine, you will need to run a Docker image to get the needed Groth16 witness generator and snark binary. This script will download them from the internet and save them in the current directory use `--prefix` to change the output directory

```
./bin/setup.sh
```

You will have a director called snark with the binaries in it. You need to copy these binaries to the node and remember the path to the snark directory.

```
# on the node
sudo mkdir -p /opt/bonsol/stark
sudo chown -R ubuntu /opt/bonsol/stark
sudo mkdir -p /opt/bonsol/keys
sudo chown -R ubuntu /opt/bonsol/keys
```

```
# on your local computer

scp -i <your_ssh_key> -r stark/* <node_user>@<node ip>:/opt/bonsol/stark
```

You will put the path in the `stark_compression_tools_path` in the config file.

### Upload the keypair to the node <a href="#upload-the-keypair-to-the-node" id="upload-the-keypair-to-the-node"></a>

You will need to upload the keypair to the node.

```
scp -r <keypair path> <node ip>:/opt/bonsol/keys/
```

You will put the path in the section below of the config file.you will put the path in the below section of the config file.

```
[signer_config]
  KeypairFile = { path = "<your keypair path>" }
```

### Installing Bonsol <a href="#installing-bonsol" id="installing-bonsol"></a>

```
git clone --depth=1 https://github.com/anagrambuild/bonsol.git bonsol
cd bonsol/
cargo build -f cuda --release
```

### Configuring the Node <a href="#configuring-the-node" id="configuring-the-node"></a>

You will need to create a config file for the node. The config file is a `toml` file that contains the configuration for the node.

```
touch Node.toml
```

Here is an example of a config file.

```
risc0_image_folder = "/opt/bonsol/risc0_images"
max_input_size_mb = 10
image_download_timeout_secs = 60
input_download_timeout_secs = 60
maximum_concurrent_proofs = 1
max_image_size_mb = 4
image_compression_ttl_hours = 24
env = "dev"
stark_compression_tools_path = "<the path to the stark directory>"
missing_image_strategy = "DownloadAndClaim"
[metrics_config]
  Prometheus = {}
[ingester_config]
RpcBlockSubscription = { wss_rpc_url = "<your websockets endpoint>" }
[transaction_sender_config]
  Rpc = { rpc_url = "<your solana rpc endpoint>" }
[signer_config]
  KeypairFile = { path = "<your keypair path>" }
```

### Running the Node <a href="#running-the-node" id="running-the-node"></a>

After building the relay package, you can run the node with the following command.

```
ulimit -s unlimited //this is required for the c++ groth16 witness generator it will blow your stack without a huge stack size
#from within the bonsol root dir
./target/release/relay -f Node.toml
```

#### Running the Node with systemd <a href="#running-the-node-with-systemd" id="running-the-node-with-systemd"></a>

You can use the following systemd service file to run the node.

```
[Unit]
Description=Bonsol Node
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
User=ubuntu
Restart=always
RestartSec=1
LimitSTACK=infinity
LimitNOFILE=1000000
LogRateLimitIntervalSec=0
WorkingDirectory=/home/ubuntu/bonsol
ExecStart=/home/ubuntu/bonsol/target/release/bonsol-node -f Node.toml

# Create BACKTRACE only on panics
Environment="RUST_BACKTRACE=1"
Environment="RUST_LIB_BACKTRACE=0"

[Install]
WantedBy=multi-user.target
```

You will need to copy this file `/etc/systemd/system/bonsol.service` and then run the following command. After that, you can reload the systemd daemon and start the service with the following command.

```
systemctl daemon-reload
systemctl start bonsol
```

Installing Alloy is out of the scope of this guide, but you can follow the [Grafana Cloud docs](https://grafana.com/docs/alloy/latest/set-up/install/linux/) to install it.


# QCash

Quantum-Safe Private Transfer on Solana

<figure><img src="/files/m7hMK6DTTAWBsgGIBW3V" alt=""><figcaption></figcaption></figure>

Private cash today is built on a foundation of sand using cryptography that will inevitably fail, exposing identities, transaction paths, and ultimately enabling theft at scale once quantum computers arrive. QCash is designed as an answer to that failure: a quantum-safe private cash system on Solana that rethinks ownership, privacy, and security from first principles, before any breaks happen.

### What is QCash?

QCash is a private, anonymous, and quantum-secure value transfer system built on Solana. It is designed to remain secure even if today’s cryptographic assumptions fail. QCash treats quantum resistance as a fundamental requirement of privacy by implementing post-quantum cryptography from day one, and not retrofitting the protocol after keys or obfuscation primitives become vulnerable.

### What makes QCash different on Solana&#x20;

Most blockchains, including Solana, still depend on elliptic curve cryptography today. This leaves the entire stack, including the applications and protocols built on top of them, exposed to a single inflection point of the arrival of a cryptographically relevant quantum computer (CRQC) capable of breaking that foundation. When this happens (and it is a question of when, not if) private keys become hackable, proofs forgeable, and transactions shielded by classical cryptography may be retroactively exposed.&#x20;

Privacy is a particularly acute vulnerability when it comes to blockchain applications. Even a successful post-quantum migration cannot undo what has already been exposed. Anything once deemed private under classical assumptions must then be considered compromised. Indeed, many privacy protocols today stack vulnerable cryptography on top of itself, using zk-SNARKs built on ECDSA-based public key cryptography to “shield” addresses (e.g., ZCash). This is precisely why privacy cannot be migrated retroactively and **must be quantum-secure from day one**. QCash is designed under exactly this assumption: private payments must remain quantum secure long into the quantum era.

#### Key properties

* **Quantum Resistance**: Unlike Solana, which relies on vulnerable elliptic curve cryptography, QCash uses post-quantum cryptography (Kyber-768) to create quantum-safe accounts and zk-STARKs to prove ownership of those accounts, ensuring funds are safe in a world with a CRQC. All of this is deployed on Solana as it exists today, with no protocol changes required.
* **Signature-Free Transactions**: Spending authority is proven via Zero-Knowledge Proofs of Ownership, not digital signatures. Even if the underlying signature scheme of the blockchain were compromised, QCash assets would remain secure. This is a core concept behind QCash that allows us to get around the dependencies on traditional transaction flows.
* **Complete Privacy**: QCash leverages a UTXO-based model where the sender, receiver, and amount are cryptographically hidden with client-side proving. To support performance gains and regulatory oversight, Bonsol enables a spectrum of privacy with server-side proving infrastructure, where safeguards such as permissioned verifiers, compliance workflows, and proof segmentation can be implemented to limit data exposure.

Together, these properties make QCash a private cash system whose security does not depend on the long-term survival of elliptic curve cryptography.

<figure><img src="/files/k18ynTvjZfw1NI2WarNJ" alt=""><figcaption></figcaption></figure>

### Architecture overview

QCash is a private, quantum-secure value transfer system on Solana that uses a UTXO model (similar to Bitcoin) rather than Solana's native account model. The core innovation is that transactions are signatureless, ownership and authorization are proven through zero-knowledge proofs and KEM decryption, not through digital signatures.

#### Vault model

Funds are stored in private vaults using Solana's program-derived addresses (PDAs), which have no corresponding private key and derive their security from hashes, making them quantum-safe. Each vault represents a discrete unit of private value following UTXO-based accounting, not a running balance. Vaults form a linked list, with each new entry referencing the previous one, building an on-chain UTXO ledger from which balances can be derived. Vault and ledger state is minimal and prunable, revealing nothing about ownership or transfer history.

#### Private transfers

To send tokens, a user creates two new UTXOs: one encrypted with the recipient's public key (containing the amount sent) and one encrypted with the sender's own key (containing the change). The original UTXO is marked as spent. Because both outputs are encrypted, no observer can see amounts or link the sender to the recipient. Since there are no private key signatures proving ownership, instead, one proves that they can decrypt a UTXO, proving the funds are theirs.&#x20;

This is what QCash calls "Proof of Decryption." To spend funds, a user's ZK circuit scans the UTXO ledger from the tip backward, attempting to decrypt each entry. When it finds one it can decrypt, that's the user's unspent output. The proof demonstrates three things: (1) the scan started from the current ledger tip, (2) the user found and decrypted a valid UTXO addressed to them, and (3) the resulting new UTXOs are valid (no double-spending, no token creation from nothing).

#### Local proof generation

Proofs are generated locally by a Rust-based daemon running on the user’s machine. This keeps sensitive data off-chain and out of browser environments. Each proof scans the ledger from top to bottom and tracks spent and unspent states internally to enforce the validity of transactions.

For performance, we are actively exploring proof generation using GPU acceleration and specialized zkProvers. With a dedicated GPU, we aim to reduce proof generation to just a few seconds.

#### Off-chain verification

Since QCash uses zk-STARKs (which are quantum-safe but too heavy for on-chain verification on Solana), proof verification happens off-chain through a node network. Nodes fetch proofs, verify them, and cast votes on-chain. Once the proofs are verified as correct and enough votes are collected, the UTXO is considered valid. Nodes protect themselves against quantum attacks through key rotation. A node signs a vote, then publishes the hash of its next public key. Since only the hash is exposed (and hashes are considered quantum-safe), no public key sits on-chain long enough to be attacked.

<figure><img src="/files/2WjcfJ6aSdK0OdwjE5rL" alt=""><figcaption></figcaption></figure>

### Why this Matters

Privacy systems today are optimized against classical threats. Under a quantum threat model, this is a structural failure. Privacy that breaks later is not privacy at all. Encrypted value today is only as secure as the cryptography that protects it tomorrow.

QCash takes the opposite approach. By designing a private transfer system that replaces the assumption of ECDLP with lattice-based and hash-based post-quantum cryptography from the start, QCash ensures that the encrypted value remains encrypted and valuable even in the post-quantum era. Most importantly, QCash operates entirely within Solana’s existing runtime, meaning that quantum-safe privacy is available today.<br>


# Contributor guidelines

Thank you for your interest in contributing to Bonsol! This guide will help you understand our contribution workflow and requirements.

## Local Setup

Refer to [Setup a local environment](/developers/setup-a-local-environment)to get started with a local environment for contributing. This will allow you to build, run and make changes to Bonsol from source.

## Pull Requests

When submitting pull requests to Bonsol, please follow these guidelines:

1. **Check Existing Issues**: Before creating a new issue or PR, verify if an existing issue already addresses your concern.
2. **Issue References**: All PRs should reference a corresponding GitHub issue using closing keywords (example: `Closes #123`).
3. **Clear Descriptions**: Include a clear, concise description of your changes in the PR.
4. **Testing**: Add relevant tests that demonstrate your changes work as intended.
5. **Code Quality**:
   * Run `nix flake check` locally to verify your changes pass our quality checks
   * Format Rust code with `cargo +nightly fmt`
   * Format TOML files with `taplo fmt`
   * Check for lints with `cargo clippy`
6. **Dependencies**: Exercise caution when adding new dependencies to ensure they're well-maintained and secure.

## Commit Messages <a href="#commit-message-guidelines" id="commit-message-guidelines"></a>

We use **commitlint** to ensure that all commit messages follow a consistent style based on the [Conventional Commits](https://www.conventionalcommits.org) specification. This makes it easier to understand the history of the project and generate changelogs automatically.

#### Commit Message Format <a href="#commit-message-format" id="commit-message-format"></a>

Each commit message must be structured as follows:

**Type**

The type must be one of the following:

* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing or correcting existing tests
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, npm)
* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
* **chore**: Other changes that don't modify src or test files
* **revert**: Reverts a previous commit

**Scope**

The scope is optional and provides additional context about what the commit affects (e.g., `api`, `cli`, `frontend`, etc.).

**Description**

The description is a short, imperative summary of the change. It should start with a verb and be written in the present tense (e.g., "add feature," "fix bug").

**Body (optional)**

The body of the commit message provides additional details about the change. Use this when the change is not trivial and requires more explanation.

**Footer (optional)**

The footer should contain any relevant information about breaking changes or issues being closed:

* Breaking changes should start with the word `BREAKING CHANGE:`, followed by an explanation of what changed and why.
* Issues should be referenced using the `Closes` keyword, like so: `Closes #123`.

#### Example Commit Messages <a href="#example-commit-messages" id="example-commit-messages"></a>

```
feat(api): add user authentication
```

```
fix(auth): correct token expiration logic
```

```
docs: update README with new installation steps
```

```
chore: update dependencies
```


# Contributing to Documentation

This guide explains how to contribute to the Bonsol documentation through GitHub. All our documentation is stored in the `gitbook/` directory of our repository and synchronized with GitBook.

## Understanding the Documentation Structure

Our documentation follows this structure:

* `gitbook/README.md` - The main landing page of the documentation
* `gitbook/SUMMARY.md` - Defines the structure and navigation of the documentation
* `gitbook/core-concepts/` - Conceptual information about Bonsol
* `gitbook/getting-started/` - Guides for new users
* `gitbook/developers/` - Resources for developers
* `gitbook/provers/` - Information for provers
* `gitbook/contributing/` - Guidelines for contributors (including this document)

## How to Add or Update Documentation

### 1. Fork and Clone the Repository

1. Fork the Bonsol repository on GitHub
2. Clone your fork locally:

   ```bash
   git clone https://github.com/YOUR-USERNAME/bonsol.git
   cd bonsol
   ```

### 2. Create a New Branch

Create a new branch for your documentation changes:

```bash
git checkout -b docs/your-documentation-change
```

Use a descriptive name that indicates what you're documenting.

### 3. Making Documentation Changes

#### Adding a New Page

1. Create your new markdown file in the appropriate subdirectory in `gitbook/`
2. Add a reference to your new file in `gitbook/SUMMARY.md` to make it appear in the navigation

Example SUMMARY.md addition:

```markdown
## Getting Started

* [Installation](getting-started/installation.md)
* [Quickstart](getting-started/quickstart.md)
* [Your New Page](getting-started/your-new-page.md)
```

#### Updating Existing Content

Simply edit the relevant markdown files in the `gitbook/` directory.

#### Markdown Guidelines

* Use clear headings with proper hierarchy (# for title, ## for sections, etc.)
* Add code examples with proper syntax highlighting:

  ````markdown
  ```rust
  fn main() {
      println!("Hello, Bonsol!");
  }
  ```
  ````
* Use relative links when referencing other documentation pages
* Include screenshots or diagrams when they help explain concepts
* Follow our style guide for consistent documentation

### 4. Preview Your Changes

You can also use standard Markdown previewers to check your content.

### 5. Create a Pull Request

1. Commit your changes:

   ```bash
   git add gitbook/
   git commit -m "docs: add documentation for X feature"
   ```

   Follow our [commit message guidelines](/contributing/contributor-guidelines#commit-message-guidelines) with the type "docs".
2. Push to your fork:

   ```bash
   git push origin docs/your-documentation-change
   ```
3. Create a pull request on GitHub
   * Reference any related issues
   * Provide a clear description of what documentation you've added or updated
   * Request review from relevant team members

## Documentation Style Guide

To maintain consistent documentation:

* Use present tense and active voice
* Be concise but thorough
* Include examples where appropriate
* Use sentence case for headings
* Link to relevant documentation sections
* Keep paragraphs short and focused

## GitBook Specific Features

Our documentation takes advantage of several GitBook features:

### Page Icons

You can add an icon to your page by including this at the top of your markdown file:

```markdown
---
icon: name-of-icon
---
```

### Internal Page References

To reference another page in the documentation:

```markdown
[Title of Page](../path/to/page.md "mention")
```

## Questions?

If you have any questions about contributing to documentation, please open an issue on GitHub or contact the team through our community channels.

Thank you for helping improve Bonsol's documentation!


