Skip to content
Draft
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ table_cache_dev_*
.DS_Store
.env
proptest-regressions/
docs/book

# ceno serialized files
*.bin
34 changes: 11 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,38 +23,26 @@ You will also need to install the Risc-V target for Rust. You can do this with t
rustup target add riscv32im-unknown-none-elf
```

## Try end-to-end with examples

A variety of [examples](https://github.com/scroll-tech/ceno/tree/master/examples/examples) are availables.
## Installing `cargo ceno`

To run an example in e2e, use the following command:
The `cargo ceno` command is the primary tool for interacting with the Ceno zkVM. You can install it by running the following command from the root of the repository:

```sh
# release mode
RUST_LOG=info cargo run --release --package ceno_zkvm --bin e2e -- \
--platform=ceno \
--hints=<hint value> \
--public-io=<pub io> \
examples/target/riscv32im-ceno-zkvm-elf/release/examples/<example name>

# run a guest program with debug output (e.g., `debug_print` / `debug_println` visible), works in non-release mode
RUST_LOG=info cargo run --package ceno_zkvm --bin e2e -- \
--platform=ceno \
--hints=<hint value> \
--public-io=<pub io> \
examples/target/riscv32im-ceno-zkvm-elf/debug/examples/<example name>
cargo install --path ceno_cli
```

The example will be automatically compiled before execution
## Try end-to-end with examples

For instance, with [fibonacci](https://github.com/scroll-tech/ceno/blob/master/examples/examples/fibonacci.rs)
Below example command runs **2^10 (1024) Fibonacci steps** via `--hints=10`.
The expected result is `4191`, which will be used as the `--public-io=4191`.
A variety of [examples](https://github.com/scroll-tech/ceno/tree/master/examples/examples) are availables.

To run an example, you first need to build it. You can run a specific example using the `cargo ceno run` command. For instance, to run the [fibonacci](https://github.com/scroll-tech/ceno/blob/master/examples/examples/fibonacci.rs) example, use the following command:

```sh
RUST_LOG=info cargo run --release --package ceno_zkvm --bin e2e -- --platform=ceno --hints=10 --public-io=4191 examples/target/riscv32im-ceno-zkvm-elf/release/examples/fibonacci
cargo ceno run --example fibonacci --hints=10 --public-io=4191
```

This command runs **2^10 (1024) Fibonacci steps** via `--hints=10`. The expected result is `4191`, which is verified against the `--public-io=4191` argument.

## Building Ceno and running tests

To run the tests, you can use the following command:
Expand Down Expand Up @@ -82,7 +70,7 @@ docker run -d ceno-runner

### Acknowledgements

Ceno stands on the shoulders of remarkable projects in the zero-knowledge ecosystem.
Ceno stands on the shoulders of remarkable projects in the zero-knowledge ecosystem.
We extend our appreciation to the following works, which have shaped Ceno's design and direction:

- [Plonky3](https://github.com/Plonky3/Plonky3) — Inspired by Plonky3’s modular architecture, enabling support for
Expand Down
5 changes: 5 additions & 0 deletions docs/book.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[book]
authors = ["Yuncong Zhang"]
language = "en"
src = "src"
title = "Ceno Docs"
17 changes: 17 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Summary

- [Overview](./overview.md)
- [Getting Started](./getting-started.md)
- [Your First ZK Program](./your-first-zk-program.md)
- [Host-Guest Interaction](./host-guest-interaction.md)
- [Generating and Verifying Proofs](./generating-and-verifying-proofs.md)
- [The `ceno` CLI](./ceno-cli.md)
- [Walkthroughs of Examples](./examples-walkthrough.md)
- [Advanced Topics](./advanced-topics.md)
- [Guest Programming (`ceno_rt`)](./guest-programming.md)
- [Accelerated Operations with Precompiles (Syscalls)](./precompiles.md)
- [Profiling & Performance](./profiling.md)
- [Differences from RISC-V](./differences-from-risc-v.md)
- [Integration with Ethereum](./integration-with-ethereum.md)
- [Prover Network](./prover-network.md)
- [On-chain verification](./on-chain-verification.md)
3 changes: 3 additions & 0 deletions docs/src/advanced-topics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Advanced Topics

This chapter is for developers who want to dive deeper into the internals of Ceno.
17 changes: 17 additions & 0 deletions docs/src/ceno-cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# The `ceno` CLI

The `ceno` command-line interface is the primary way to interact with the Ceno ZKVM. It allows you to build, run, and verify your ZK programs.

The available commands are:

- `cargo ceno build`: Compiles a guest program written in Rust into a RISC-V ELF file.
- `cargo ceno info`: Provides information about a compiled ELF file, such as its size and segments.
- `cargo ceno keygen`: Generates a proving key and a verification key for a guest program.
- `cargo ceno prove`: Compiles, runs, and proves a Ceno guest program in one go.
- `cargo ceno run`: Executes a guest program and generates a witness of its execution.
- `cargo ceno verify`: Verifies a proof generated by `cargo ceno prove`.
- `cargo ceno raw-keygen`: A lower-level command to generate keys from a compiled ELF file.
- `cargo ceno raw-prove`: A lower-level command to prove a program from a compiled ELF file and a witness.
- `cargo ceno raw-run`: A lower-level command to run a program without the full proof generation, useful for debugging.

For detailed usage of each command, you can use the `--help` flag, for example: `cargo ceno run --help`.
1 change: 1 addition & 0 deletions docs/src/differences-from-risc-v.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Differences from RISC-V
5 changes: 5 additions & 0 deletions docs/src/examples-walkthrough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Walkthroughs of Examples

This chapter will contain detailed walkthroughs of selected examples from the `examples/` directory.

*(Content to be added)*
123 changes: 123 additions & 0 deletions docs/src/generating-and-verifying-proofs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Generating and Verifying Proofs

The `cargo ceno` command provides a streamlined workflow for generating and verifying proofs of your ZK programs. This is handled primarily by the `keygen`, `prove` and `verify` subcommands.

Here's a more detailed look at the steps involved in generating a proof:

1. **Key Generation (`cargo ceno keygen`):** Before proving, you need a proving key and a verification key. The `keygen` command generates these keys for a given guest program.

```bash
cargo ceno keygen --example <GUEST_EXAMPLE_NAME> --out-vk <PATH_TO_VERIFICATION_KEY_FILE>
```

2. **Proof Generation (using the witness):** The final step is to use the proving key and the witness to generate the proof. The `prove` command automates this, but you can also perform this step manually using the lower-level `raw-prove` command if you have the ELF file, proving key, and witness.

By using `cargo ceno prove`, you get a simplified experience that handles these steps for you. For most use cases, `cargo ceno prove` and `cargo ceno verify` are the primary commands you will use.

```bash
cargo ceno prove --example <GUEST_EXAMPLE_NAME> --hints=<HINTS_SEPARATED_BY_COMMA> --public-io=<PUBLIC_IO> --out-vk <PATH_TO_VERIFICATION_KEY_FILE> --out-proof target/fibonacci.proof
```

## Concrete Example

You can use `ceno` to generate proofs for your own custom Rust programs. Let's walk through how to set up a new project and use `ceno` with it.

### 1. Project Setup

First, create a new binary crate with `cargo`:

```bash
cargo new my-ceno-program
cd my-ceno-program
```

Your project will have the following structure:

```
my-ceno-program/
├── Cargo.toml
└── src/
└── main.rs
```

### 2. Cargo.toml

Next, you need to add `ceno_rt` as a dependency in your `Cargo.toml`. `ceno_rt` provides the runtime environment and syscalls for guest programs.

```toml
[package]
name = "my-ceno-program"
version = "0.1.0"
edition = "2024"

[dependencies]
ceno_rt = { git = "https://github.com/scroll-tech/ceno.git" }
rkyv = { version = "0.8", default-features = false, features = [
"alloc",
"bytecheck",
] }
```
Copy link
Collaborator

@hero78119 hero78119 Sep 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to add rust-toolchain.toml

[toolchain]
channel = "nightly-2025-03-25"
targets = ["riscv32im-unknown-none-elf"]
# We need the sources for build-std.
components = ["rust-src"]

specify as nightly build as currently we rely on some features not in stable channel. Otherwise it will suffer build failed


_Note: For local development, you can use a path dependency: `ceno_rt = { path = "../ceno/ceno_rt" }`_

### 3. Writing the Guest Program

Now, let's write a simple guest program in `src/main.rs`. This program will read one `u32` values from the input, add a constant to it, and write the result to the output.

```rust
extern crate ceno_rt;
use rkyv::Archived;

fn main() {
let a: &Archived<u32> = ceno_rt::read();
let a: u32 = a.into();
let b: u32 = 3;
let c = a.wrapping_add(b);

ceno_rt::commit::<Archived<u32>, _>(&c);
}
```

### 4. Building, Proving, and Verifying

With your custom program ready, you can use `ceno` to manage the workflow. These commands are typically run from the root of your project (`my-ceno-program`).

1. **Build the program:**

The `build` command compiles your guest program into a RISC-V ELF file.

```bash
cargo ceno build
```

This will create an ELF file at `target/riscv32im-ceno-zkvm-elf/debug/my-ceno-program`.

2. **Generate Keys:**

Next, generate the proving and verification keys.

```bash
cargo ceno keygen --out-vk vk.bin
```

This will save the keys in a `keys` directory.

3. **Generate a Proof:**

Now, run the program and generate a proof. You can provide input via the `--stdin` flag.

```bash
cargo ceno prove --hints=5 --public-io=8 --out-proof proof.bin
```

This command executes the ELF, generates a proof, and saves it as `proof.bin`. The output of the program will be printed to your console.

4. **Verify the Proof:**

Finally, verify the generated proof.

```bash
cargo ceno verify --vk vk.bin --proof proof.bin
```

If the proof is valid, you'll see a success message. This workflow allows you to integrate `ceno`'s proving capabilities into your own Rust projects.
60 changes: 60 additions & 0 deletions docs/src/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Getting Started

This chapter will guide you through setting up your local development environment for Ceno and running your first zero-knowledge program.

## Local Build Requirements

Ceno is built in Rust, so you must [install the Rust toolchain](https://www.rust-lang.org/tools/install) first.

We also use `cargo-make` to orchestrate the build process. You can install it with the following command:

```sh
cargo install cargo-make
```

Ceno executes RISC-V instructions, so you will also need to install the Risc-V target for Rust. You can do this with the following command:

```sh
rustup target add riscv32im-ceno-zkvm-elf
```

## Installing `cargo ceno`

The `cargo ceno` command is the primary tool for interacting with the Ceno zkVM. You can install it by running the following command from the root of the repository:

```sh
cargo install --path ceno_cli
```

## Building the Examples

The Ceno project includes a variety of [examples](https://github.com/scroll-tech/ceno/tree/master/examples/examples) to help you get started.

You can build all the examples using the `cargo ceno` command-line tool. Execute the following command in the Ceno repository root directory:

```sh
cargo ceno build --example fibonacci
```

This command will compile the example `fibonacci` located in the `examples/examples` directory and place the resulting ELF files in the `examples/target/riscv32im-ceno-zkvm-elf/release` directory.

## Running an Example

Once the examples are built, you can run any of them using the `cargo ceno run` command. We will run the Fibonacci example.

This example calculates the `n`-th Fibonacci number, where `n` is determined by a hint value provided at runtime. For this guide, we will calculate the 1024-th number (corresponding to hint value `10` as `2^10=1024`) in the sequence.

Execute the following command in the Ceno repository root directory to run the Fibonacci example:

```sh
cargo ceno run --example fibonacci --hints=10 --public-io=4191
```

Let's break down the command:

- `cargo ceno run`: This is the command to run a Ceno program.
- `--example fibonacci`: This specifies that we want to run the `fibonacci` example.
- `--hints=10`: This is a private input to our program. In this case, it tells the program to run 2^10 (1024) Fibonacci steps.
- `--public-io=4191`: This is the expected public output. The program will verify that the result of the computation matches this value.

If the command runs successfully, you have just run your first ZK program with Ceno! The next chapter will dive into the code for this example.
12 changes: 12 additions & 0 deletions docs/src/guest-programming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Guest Programming (`ceno_rt`)

The `ceno_rt` crate provides the runtime environment for guest programs running inside the Ceno ZKVM. It offers essential functionalities for interacting with the host and the ZKVM environment.

Key features of `ceno_rt` include:

- **I/O:** Functions for reading input from the host and writing output. See the `ceno_rt::io` module.
- **Memory Management:** A simple allocator for dynamic memory allocation within the guest. See the `ceno_rt::allocator` module.
- **Syscalls:** Low-level functions to access precompiled operations for performance-critical tasks. See the `ceno_rt::syscalls` module and the "Accelerated Operations with Precompiles" chapter.
- **Panicking:** Macros and functions for handling unrecoverable errors in the guest.

When writing a guest program, you will typically include `ceno_rt` as a dependency in your `Cargo.toml`.
57 changes: 57 additions & 0 deletions docs/src/host-guest-interaction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Host-Guest Interaction

A critical aspect of developing ZK applications is understanding how the "host" (the machine running the prover) and the "guest" (the ZK program running inside the vm) communicate with each other.

In Ceno, this communication happens in two main ways:
1. **Private Inputs (Hints)**: The host can pass private data to the guest.
2. **Public Inputs/Outputs (I/O)**: The guest can receive public data and commit to public outputs that the host can verify.

We saw both of these in the command used to run the Fibonacci example:

```sh
cargo ceno run --example fibonacci --hints=10 --public-io=4191
```

## Private Inputs (Hints)

Private inputs, which Ceno refers to as "hints," are data known only to the host and the guest. They are not revealed publicly and do not become part of the final proof. This is the primary way to provide secret inputs to your ZK program.

In the guest code, you use the `ceno_rt::read()` function to access this data.

**Guest Code:**
```rust
// Reads the private hint value provided by the host.
let log_n: &Archived<u32> = ceno_rt::read();
let log_n: u32 = log_n.into();
```

**Host Command:**
```sh
... --hints=10 ...
```

In this interaction, the value `10` is passed from the host to the guest. The guest program reads this value and uses it to determine how many Fibonacci iterations to perform. This input remains private.

## Public Inputs and Outputs

Public I/O is data that is known to both the host and the verifier. It is part of the public record and is used to ensure the ZK program is performing the correct computation on the correct public data.

In Ceno, the guest program can commit data to the public record using the `ceno_rt::commit()` function.

**Guest Code:**
```rust
// Commits the final result `b` to the public output.
ceno_rt::commit::<Archived<u32>, _>(&b);
```

**Host Command:**
```sh
... --public-io=4191 ...
```

Here, the guest calculates the final Fibonacci number and commits the result `b`. The Ceno host environment then checks that this committed value is equal to the value provided in the `--public-io` argument (`4191`). If they do not match, the proof will fail, indicating an incorrect computation or a different result than expected.

This mechanism is crucial for creating verifiable computations. You can use public I/O to:

- Provide public inputs that the program must use.
- Assert that the program produces a specific, known public output.
1 change: 1 addition & 0 deletions docs/src/integration-with-ethereum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Integration with Ethereum
1 change: 1 addition & 0 deletions docs/src/on-chain-verification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# On-chain verification
Loading