Compiling Programs
Once you have written an SP1 program, you must compile it to an ELF file that can be executed in the zkVM. The cargo prove
CLI tool (downloaded during installation) provides convenient commands for compiling SP1 programs.
Development Builds
WARNING: This may not generate a reproducible ELF which is necessary for verifying that your binary corresponds to given source code.
Use the reproducible build system for production builds.
To build a program while developing, simply run the following command in the crate that contains your SP1 program:
cargo prove build
This will compile the ELF that can be executed in the zkVM. The output from the command will look something like this:
[sp1] Compiling version_check v0.9.4
[sp1] Compiling proc-macro2 v1.0.86
[sp1] Compiling unicode-ident v1.0.12
[sp1] Compiling cfg-if v1.0.0
...
[sp1] Compiling sp1-lib v1.0.1
[sp1] Compiling sp1-zkvm v1.0.1
[sp1] Compiling fibonacci-program v0.1.0 (/Users/username/Documents/fibonacci/program)
[sp1] Finished `release` profile [optimized] target(s) in 8.33s
Under the hood, this CLI command calls cargo build
with the riscv32im-succinct-zkvm-elf
target and other required environment variables and flags. The logic for this command is defined in the sp1-build crate.
Advanced Build Options
You can pass additional arguments to the cargo prove build
command to customize the build process, like configuring what features are enabled, customizing the output directory and more. To see all available options, run cargo prove build --help
. Many of these options mirror the options available in the cargo build
command.
Production Builds
For production builds of programs, you can build your program inside a Docker container which will generate a reproducible ELF on all platforms. To do so, just use the --docker
flag and optionally the --tag
flag with the release version you want to use (defaults to latest
). For example:
cargo prove build --docker --tag v1.0.1
To verify that your build is reproducible, you can compute the SHA-512 hash of the ELF on different platforms and systems with:
$ shasum -a 512 elf/riscv32im-succinct-zkvm-elf
f9afb8caaef10de9a8aad484c4dd3bfa54ba7218f3fc245a20e8a03ed40b38c617e175328515968aecbd3c38c47b2ca034a99e6dbc928512894f20105b03a203
Build Script
If you want your program crate to be built automatically whenever you build/run your script crate, you can add a build.rs
file inside of script/
(at the same level as Cargo.toml
of your script crate) that utilizes the sp1-build
crate:
fn main() {
sp1_build::build_program("../program");
}
The path passed in to build_program
should point to the directory containing the Cargo.toml
file for your program. Make sure to also add sp1-build
as a build dependency in script/Cargo.toml
:
[build-dependencies]
sp1-build = "3.0.0"
You will see output like the following from the build script if the program has changed, indicating that the program was rebuilt:
[fibonacci-script 0.1.0] cargo:rerun-if-changed=../program/src
[fibonacci-script 0.1.0] cargo:rerun-if-changed=../program/Cargo.toml
[fibonacci-script 0.1.0] cargo:rerun-if-changed=../program/Cargo.lock
[fibonacci-script 0.1.0] cargo:warning=fibonacci-program built at 2024-03-02 22:01:26
[fibonacci-script 0.1.0] [sp1] Compiling fibonacci-program v0.1.0 (/Users/umaroy/Documents/fibonacci/program)
[fibonacci-script 0.1.0] [sp1] Finished release [optimized] target(s) in 0.15s
warning: fibonacci-script@0.1.0: fibonacci-program built at 2024-03-02 22:01:26
The above output was generated by running RUST_LOG=info cargo run --release -vv
for the script
folder of the Fibonacci example.
Advanced Build Options
To configure the build process when using the sp1-build
crate, you can pass a BuildArgs
struct to to the build_program_with_args
function. The build arguments are the same as the ones available from the cargo prove build
command.
As an example, you could use the following code to build the Fibonacci example with the docker
flag set to true
and a custom output directory for the generated ELF:
use sp1_build::{build_program_with_args, BuildArgs};
fn main() {
let args = BuildArgs {
docker: true,
output_directory: "./fibonacci-program".to_string(),
..Default::default()
};
build_program_with_args("../program", &args);
}
Note: If you want reproducible builds with the build.rs
approach, you should use the docker
flag and the build_program_with_args
function, as shown in the example above.