Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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"
20 changes: 20 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 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)
- [`cargo ceno build`](./ceno-cli/build.md)
- [`cargo ceno run`](./ceno-cli/run.md)
- [Raw Commands](./ceno-cli/raw.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.
- `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`. The next sections will explain the three core commands.
20 changes: 20 additions & 0 deletions docs/src/ceno-cli/build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# `cargo ceno build`

The `cargo ceno build` command compiles a Ceno program. It is a wrapper around the standard `cargo build` command, but it automatically sets the correct target and rustflags for building Ceno programs.

## Usage

```bash
cargo ceno build [OPTIONS]
```

## Options

The `build` command accepts all the same options as `cargo build`. Some of the most common options are:

- `--example <NAME>`: Build a specific example.
- `--release`: Build in release mode.
- `--package <NAME>` or `-p <NAME>`: Specify which package to build.
- `--workspace`: Build all packages in the workspace.

For a full list of options, run `cargo ceno build --help`.
33 changes: 33 additions & 0 deletions docs/src/ceno-cli/raw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Raw Commands

The `raw-run`, `raw-prove`, and `raw-keygen` commands are lower-level commands that operate on ELF files directly. These are useful for debugging and for integrating Ceno with other build systems.

## `cargo ceno raw-run`

Executes a pre-compiled ELF file in the Ceno ZKVM.

### Usage

```bash
cargo ceno raw-run <ELF_PATH>
```

## `cargo ceno raw-prove`

Generates a proof for a pre-compiled ELF file.

### Usage

```bash
cargo ceno raw-prove <ELF_PATH>
```

## `cargo ceno raw-keygen`

Generates a proving key and a verification key for a pre-compiled ELF file.

### Usage

```bash
cargo ceno raw-keygen <ELF_PATH>
```
30 changes: 30 additions & 0 deletions docs/src/ceno-cli/run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Run, prove, and keygen

The `run`, `prove`, and `keygen` commands are used to execute Ceno programs. They all share a similar set of options.

- `cargo ceno run`: Executes a Ceno program in the ZKVM.
- `cargo ceno prove`: Executes a Ceno program and generates a proof of its execution.
- `cargo ceno keygen`: Generates a proving key and a verification key for a Ceno program.

## Usage

```bash
cargo ceno run [OPTIONS]
cargo ceno prove [OPTIONS]
cargo ceno keygen [OPTIONS]
```

## Options

These commands accept all the same options as `cargo build`. Some of the most common options are:

- `--example <NAME>`: Run a specific example.
- `--release`: Run in release mode.
- `--package <NAME>` or `-p <NAME>`: Specify which package to run.

In addition, the `prove` and `keygen` commands have some Ceno-specific options:

- `--proof <PATH>`: Path to the output proof file (for `prove`). Defaults to `proof.bin`.
- `--out-vk <PATH>`: Path to the output verification key file (for `keygen`). Defaults to `vk.bin`.

For a full list of options, run `cargo ceno <COMMAND> --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
115 changes: 115 additions & 0 deletions docs/src/examples-walkthrough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Walkthroughs of Examples

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

## Fibonacci

The `fibonacci` example computes the `n`-th Fibonacci number, where `n` is a power of 2. The purpose of this example is to show how to perform a simple computation within the zkVM.

### Guest Code

The guest program for the `fibonacci` example is located at `examples/examples/fibonacci.rs`.

```rust
{{#include ../../examples/examples/fibonacci.rs}}
```

The guest program reads a private input `log_n` from the host. This input determines the number of iterations to perform. The program then calculates `n = 1 << log_n` and computes the `n`-th Fibonacci number using a standard iterative approach. To prevent the numbers from growing too large, the computation is performed modulo 7919. Finally, the program commits the result back to the host as a public output.

This example demonstrates the basic workflow of a Ceno zkVM program: reading private inputs, performing computations, and committing public outputs. It shows that you can write standard Rust code for the guest, and the zkVM will execute it.

## Is Prime

The `is_prime` example counts the number of prime numbers up to a given integer `n`. This example showcases a slightly more complex algorithm and control flow.

### Guest Code

The guest program for the `is_prime` example is located at `examples/examples/is_prime.rs`.

```rust
{{#include ../../examples/examples/is_prime.rs}}
```

The guest program reads an integer `n` from the host. It then iterates from 0 to `n`, checking if each number is prime using a helper function `is_prime`. The `is_prime` function implements the trial division method. The total count of prime numbers is accumulated in `cnt_primes`. If the count of primes exceeds a certain threshold, the program will panic. This demonstrates how to handle exceptional cases in the guest. The program does not commit any public output, but the proof generated by the zkVM still guarantees that the computation was performed correctly.

This example highlights the ability to define and use helper functions within the guest code, as well as the use of control flow constructs like loops and conditional statements.

## BN254 Curve Syscalls

The `bn254_curve_syscalls` example demonstrates the use of syscalls for elliptic curve operations on the BN254 curve. This is useful for cryptographic applications that require curve arithmetic.

### Guest Code

The guest program for the `bn254_curve_syscalls` example is located at `examples/examples/bn254_curve_syscalls.rs`.

```rust
{{#include ../../examples/examples/bn254_curve_syscalls.rs}}
```

The guest program initializes two points on the BN254 curve. It then uses the `syscall_bn254_add` syscall to add the two points and asserts that the result is correct by comparing it with a pre-computed value. It also demonstrates the use of the `syscall_bn254_double` syscall to double a point. The program includes helper functions to convert between different representations of curve points.

This example showcases how to leverage syscalls to perform complex and computationally expensive operations. By using syscalls, the guest can delegate these operations to the host, which can often execute them more efficiently. The guest can still verify the results of the syscalls to ensure the integrity of the computation.

## Ceno RT Alloc

The `ceno_rt_alloc` example shows how to use the allocator in the Ceno runtime to allocate memory on the heap.

### Guest Code

The guest program for the `ceno_rt_alloc` example is located at `examples/examples/ceno_rt_alloc.rs`.

```rust
{{#include ../../examples/examples/ceno_rt_alloc.rs}}
```

The guest program demonstrates three different memory operations. First, it writes to a global static variable. Second, it allocates a small `Vec` on the heap. Third, it allocates a much larger `Vec` on the heap and writes a value to an element in it. The `black_box` function is used to ensure that the compiler does not optimize away these memory operations.

This example is important for understanding how memory management works in the Ceno zkVM. It shows that the guest has access to both static memory and heap memory, and can perform dynamic memory allocation.

## Keccak Syscall

The `keccak_syscall` example demonstrates how to use a syscall to perform the Keccak permutation, which is the core of the Keccak hash function (used in SHA-3).

### Guest Code

The guest program for the `keccak_syscall` example is located at `examples/examples/keccak_syscall.rs`.

```rust
{{#include ../../examples/examples/keccak_syscall.rs}}
```

The guest program initializes a 25-word state and then enters a loop where it repeatedly applies the Keccak permutation to the state using the `syscall_keccak_permute` syscall. The `log_state` function is used to log the state after the first permutation, which can be useful for debugging.

This example further illustrates the power of syscalls. The Keccak permutation is a complex operation, and implementing it efficiently in the guest would be challenging. By providing it as a syscall, the Ceno platform makes it easy for guest programs to use this important cryptographic primitive.

## Median

The `median` example shows how to find the median of a list of numbers. It demonstrates a common pattern where the host provides a candidate answer, and the guest verifies it.

### Guest Code

The guest program for the `median` example is located at `examples/examples/median.rs`.

```rust
{{#include ../../examples/examples/median.rs}}
```

The guest program reads a list of numbers and a median candidate from the host. It then verifies that the candidate is indeed the median by counting the number of elements in the list that are smaller than the candidate. If the count is equal to half the length of the list, the assertion passes, and the program successfully completes.

This example showcases a powerful pattern for zkVM programming: verifiable computation. The host, which is not constrained by the limitations of the zkVM, can perform a complex computation (like finding the median of a large list) and then provide the answer to the guest. The guest's task is then to perform a much simpler computation to verify that the host's answer is correct. This allows for the verification of complex computations that would be too expensive to perform directly in the zkVM.

## Sorting

The `sorting` example demonstrates how to sort a list of numbers inside the guest.

### Guest Code

The guest program for the `sorting` example is located at `examples/examples/sorting.rs`.

```rust
{{#include ../../examples/examples/sorting.rs}}
```

The guest program reads a list of numbers from the host, creates a mutable copy of it, and then sorts the copy using the standard `sort` method from the Rust standard library. The `debug_println!` macro is used to print the first element of the sorted vector, which can be useful for debugging.

This example demonstrates that the Ceno zkVM supports a significant portion of the Rust standard library, including common data structures and algorithms. This makes it easy to write complex programs for the guest, as you can leverage the power and convenience of the standard library.
Loading