Skip to content

FairgateLabs/rust-bitvmx-zk-proof

Repository files navigation

Build BitVMX ZK-Proof

This project is allows to generate a Zero Knowledge Proof to be used with BitVMX. For this we have some tools that allows to split the three phases of a ZKP.

  1. Setup
  2. Proving
  3. Verification

⚠️ Disclaimer

This library is currently under development and may not be fully stable. It is not production-ready, has not been audited, and future updates may introduce breaking changes without preserving backward compatibility.

The Program to Verify

This repo contains a dummy example of a ZKP using RISC0. The proof is inside methods/guest/src

Inside host/src is the enviornment that allows to get the information required for the setup, execute the proof and verifiy it.

The first proof is a Stark, that is later converted into a Snark (groth16).

Steps

Requirements

Currently RISC0 support for Groth16 is only available on x86/x64. Also some of the scripts are aimed to run in linux, and Docker is required to be installed.

This steps where tested on WSL (Ubuntu 20.04) on Windows 11 and also in Azure Standard E4as v4

To make docker to be accesible from wsl follow this instructions

Clone repo

clone git@github.com:FairgateLabs/rust-bitvmx-zk-proof.git

Install docker

sudo snap install docker

Install rust

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh Option: (1) standard installation

bash (or logout/login to update paths)

build tools

sudo apt-get update

sudo apt -y install build-essential

sudo apt -y install pkg-config libssl-dev

install risczero

curl -L https://risczero.com/install | bash

source ~/.bashrc (to update path)

cargo install cargo-binstall

cargo binstall cargo-risczero --version 2.0.1

rzup install

Risc0 Guest Build

Running this command will, among other things, builds the guest program. cargo build --release

Check these resources to better understand the remaining of this section:

  • Risc0 article on embed_methods
  • build.rs: that generates the ./target/<debug|release>/build/methods-xxx/out/methods.rs file. This file contains some constants representing the image_id and elf for the guest code (more in this below)
  • lib.rs: that includes the methods.rs file mentioned above, making its constants available to import

Image ID

During the build process, Risc0 generates the guest's unique and secure identifier (image_id), which is injected in the mentioned methods.rs file as the constant <PKG_NAME>_ID. Using the included guest_sample as an example, the image_id will be made available through the constant BITVMX_ID, since the package name is bitvmx.

ELF

During the build process, Risc0 also generates the guest's ELF file, which is injected in the mentioned methods.rs file as the constants <PKG_NAME>_PATH (the elf file path) and <PKG_NAME>_ELF (elf bytes). Using also guest_sample as an example, the elf will be made available through the constants BITVMX_PATH and BITVMX_ELF.

Using these constants

We can check or use the generated constants in two ways:

  1. We can manually check them in the generated methods.rs (./target/<debug|release>/build/methods-xxx/out/methods.rs). If you have built the guest_sample, then a methods.rs should exist containing its image_id and elf constants.
  2. We can define the guest crate as a dependency on a client crate and import the constant. Using the included guest_sample as an example, we should define it as a dependency and import the constant with use guest_sample::<CONSTANT_NAME>;

Setup Phase

To dump the guest's image_id to a file for later usage, we can serialize it with cli_serde::serialize_image_id(<PKG_NAME>_ID) (from cli_serde crate in this repository) and then use the output of this call as parameter for the following command:

cargo run --release --bin host -- dump-id -i <serialized_image_id> -o image_id.json

The following command will use the identifier and the expected result as the journal parameter (in this case, the bytes of a 1 in u32 representation)

cargo run --release --bin verifier -- generate-claim -i image_id.json --journal 1,0,0,0

Proving

STARK proof

The first step is to generate the stark proof, passing the expected input written in a file (TODO: maybe we can make this more generic so a file is not needed for basic types and alike). Serialising the data or not depends on the use case, and it is the client who decides: it should be the one that, when needed, serialises the data when building the input and provides a guest that deserializes it when reading from env.

To generate the STARK proof, run the following command where:

  • <input_file> is the input to the guest program
  • <elf_file_path> is the path to the ELF file generated by Risc0 as explained above

cargo run --release --bin host -- prove-stark --input <input_file> --elf <elf_file_path> --output stark-proof.bin

For example, to test the guest_sample provided:

  1. create an <input_file> with just a number written on it: any input below 100 will output a journal with 1, and zero otherwise. The guest code is not deserialising, so no need to serialize the input.
  2. find the guest_sample ELF path as explained above

SNARK proof

The second step is to generate the snark proof for the stark proof (for the stark-proof.bin generated on the previous step)

Check running docker works fine. In that case run this command: cargo run --release --bin host -- prove-snark --input stark-proof.bin --json output.json

If not, try runnign it in this way: sudo RISC0_WORK_DIR=./ RUST_LOG=debug ./target/release/host prove-snark --input stark-proof.bin --output snark-seal.json

Verifiying

cargo run --release --bin verifier -- verify -i image_id.json --journal 1,0,0,0 --seal snark-seal.json

Execution Preparation

We have two ways to prepare the proof for its program execution

Template Proof

If the proof will be inserted in the constants.h directly run: cargo run --release --bin verifier -- template-setup --image-id image_id.json --template ../bitvmx-zk-verifier/templates/constants_template.h -o intermediate.h and cargo run --release --bin verifier -- template-proof --journal 1,0,0,0 --seal snark-seal.json -t intermediate.h -o constants.h

Now take note of the path to the constants.h file, as it will be used later on.

Proof to Input Hex

If the proof will be provided as input to the program: cargo run --release --bin verifier -- template-setup --image-id image_id.json --template ../bitvmx-zk-verifier/templates/constants_template.h -o constants.h --zero-proof and cargo run --release --bin verifier -- proof-as-input --journal 1,0,0,0 --seal snark-seal.json

Now take note of the printed hex string and the path to the constants.h file, as they will be used later on.

Execution

To execute the program, we have to follow two other README files:

  1. bitvmx-docker-riscv32 to create the Verifier's ELF (zkverifier-new-mul.elf) that will be run in the BitVMX-CPU. NOTE: if I'm not mistaken, this is a one-time step, no need to re-run it for future program executions
  2. BitVMX-CPU to run the Verifier's ELF (zkverifier-new-mul.elf) in the CPU with the input that we built in the previous Execution Preparation step.

Below are the steps as a reference, but bear in mind that the up-to-date instructions are in the respective README files mentioned above.

  1. Clone the BitVMX-CPU repository.
  2. In BitVMX-CPU repo, let's set the verifier:
    1. if not done yet, initialise docker-riscv32 submodule (it points to bitvmx-docker-riscv32)
    2. from docker-riscv32 submodule run ./docker-build.sh. This step takes a while, but it is run just once, no need to re-run it again, neither for this Template (image_id) nor for a new one.
    3. copy constants.sh generated before to docker-riscv32/verifier, it will be used by docker-riscv32/verifier/build.sh and internally by bitvmx-docker-riscv32.
    4. from docker-riscv32 submodule run ./docker-run.sh verifier verifier/build.sh --with-mul. This will create the zkverifier-new-mul.elf file in the docker-riscv32/verifier/build folder. This step is necessary only once for each Template (image_id).
  3. Now depending on the input preparation you did on the Execution Preparation step, you have to run the following:
    1. Template Proof. Since the input is already in the constants.h file, we can directly run the emulator without input.
      1. within BitVMX-CPU repository run: cargo run --release -p emulator execute --elf ./docker-riscv32/verifier/build/zkverifier-new-mul.elf --no-hash --debug
    2. Proof as Input. Now we will use the hex generated on Proof to Input Hex step as input, because constants.h does not contain it.
      1. within BitVMX-CPU repository run: cargo run --release -p emulator execute --elf ./docker-riscv32/verifier/build/zkverifier-new-mul.elf --input <output-from-proof-to-input-hex-step> --no-hash --debug

License

This project is licensed under the MIT License - see LICENSE file for details.


🧩 Part of the BitVMX Ecosystem

This repository is a component of the BitVMX Ecosystem, an open platform for disputable computation secured by Bitcoin.
You can find the index of all BitVMX open-source components at FairgateLabs/BitVMX.


About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 6