Writing Programs: Basics

A zero-knowledge proof generally proves that some function f when applied to some input x produces some output y (i.e. f(x) = y). In the context of the SP1 zkVM:

  • f is written in normal Rust code.
  • x are bytes that can be serialized / deserialized into objects
  • y are bytes that can be serialized / deserialized into objects

To make this more concrete, let's walk through a simple example of writing a Fibonacci program inside the zkVM.

Fibonacci

This program is from the examples directory in the SP1 repo which contains several example programs of varying complexity.

//! A simple program that takes a number `n` as input, and writes the `n-1`th and `n`th fibonacci
//! number as an output.

// These two lines are necessary for the program to properly compile.
//
// Under the hood, we wrap your main function with some extra code so that it behaves properly
// inside the zkVM.
#![no_main]
sp1_zkvm::entrypoint!(main);

pub fn main() {
    // Read an input to the program.
    //
    // Behind the scenes, this compiles down to a custom system call which handles reading inputs
    // from the prover.
    let n = sp1_zkvm::io::read::<u32>();

    // Write n to public input
    sp1_zkvm::io::commit(&n);

    // Compute the n'th fibonacci number, using normal Rust code.
    let mut nums = vec![1, 1];
    for _ in 0..n {
        let mut c = nums[nums.len() - 1] + nums[nums.len() - 2];
        c %= 7919;
        nums.push(c);
    }

    // Write the output of the program.
    //
    // Behind the scenes, this also compiles down to a custom system call which handles writing
    // outputs to the prover.
    sp1_zkvm::io::commit(&nums[nums.len() - 2]);
    sp1_zkvm::io::commit(&nums[nums.len() - 1]);
}

As you can see, writing programs is as simple as writing normal Rust. To read more about how inputs and outputs work, refer to the section on Inputs & Outputs.