Skip to content

Commit

Permalink
Support multiple risc0 version in no-std
Browse files Browse the repository at this point in the history
  • Loading branch information
la10736 committed Dec 10, 2024
1 parent d4f1d37 commit 3d815e4
Show file tree
Hide file tree
Showing 236 changed files with 91,462 additions and 246 deletions.
10 changes: 10 additions & 0 deletions .cargo/audit.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[advisories]
ignore = [
"RUSTSEC-2024-0388", # Just linked in test from risc0-zkvm for groth16
"RUSTSEC-2024-0370", # Just linked in test from risc0-zkvm for bonsai-sdk
]
informational_warnings = ["unmaintained", "unsound"]

[output]
deny = ["warnings", "unsound", "yanked"]
quiet = false
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/target
/Cargo.lock
lcov.info
lcov.info
resources/cases/temp
flamegraph*
35 changes: 30 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "risc0-verifier"
version = "0.2.0"
version = "0.3.0"
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/HorizenLabs/risc0-verifier"
Expand All @@ -9,13 +9,38 @@ description = "A Rust library to verify risc0 STARK proofs"
keywords = ["crypto", "no-std", "blockchain", "cryptography", "risc0"]

[dependencies]
risc0-zkvm = { version = "=1.0.1", default-features = false }
risc0-zkp = "=1.0.1"
bincode = "1.3"
snafu = { version = "0.8.5", default-features = false }
serde = { version = "1.0.215", default-features = false, features = ["derive"] }
ciborium = { version = "0.2.2", default-features = false }
risc0-core = { version = "1.2.0", default-features = false }
risc0-zkp = { version = "1.2.0", default-features = false }
risc0-binfmt = { version = "1.2.0", default-features = false }
risc0-circuit-rv32im = { version = "1.2.0", default-features = false }
risc0-circuit-recursion = { version = "1.2.0", default-features = false }
anyhow = { version = "1.0.93", default-features = false }
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
bytemuck = { version = "1.20.0", default-features = false }
log = { version = "0.4.22", default-features = false }
digest = { version = "0.10", features = ["oid"] }

[dev-dependencies]
snafu = { version = "0.8.5", default-features = false }
serde_json = "1.0.114"
serde = "1.0.197"
hex = "0.4.3"
rstest = "0.23.0"
anyhow = "1.0.93"
ciborium = "0.2.2"
rand = "0.8.5"
bincode = "1.3"
risc0-zkvm = "1.2.0"
risc0-zkp = "1.0"
divan = "0.1.17"
rstest_reuse = "0.7.0"
hex-literal = "0.4.1"

[[bench]]
name = "base"
harness = false

[profile.bench]
debug = true
1 change: 1 addition & 0 deletions HEADER-APACHE2
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2024, Horizen Labs, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
36 changes: 23 additions & 13 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ workspace = false
command = "cargo"
args = ["clean"]

[tasks.install-bare-metal]
command = "rustup"
args = ["target", "add", "thumbv7em-none-eabi"]

[tasks.build-bare-metal]
dependencies = ["install-bare-metal"]
command = "cargo"
args = ["build", "--no-default-features", "--target", "thumbv7em-none-eabi"]

[tasks.build]
command = "cargo"
args = ["build"]
Expand Down Expand Up @@ -38,13 +47,19 @@ dependencies = ["clippy-inst"]
command = "cargo"
args = ["clippy", "--", "--deny", "warnings"]

[tasks.compile-header-fix]
command = "cargo"
args = ["build", "--manifest-path", "header-fix/Cargo.toml", "--release"]

[tasks.header-add]
script = { file = "./scripts/add_header_if_missing.sh" }
args = ["HEADER-APACHE2", "./!(target)/**/*.rs"]
dependencies = ["compile-header-fix"]
command = "./header-fix/target/release/header-fix"
args = ["--glob", "**/*.rs", "HEADER-APACHE2"]

[tasks.header-check]
env = { CHECK_DIRTY = "true", DRY_RUN = "true" }
run_task = "header-add"
dependencies = ["compile-header-fix"]
command = "./header-fix/target/release/header-fix"
args = ["--check", "--glob", "**/*.rs", "HEADER-APACHE2"]

[tasks.audit-inst]
command = "cargo"
Expand All @@ -68,16 +83,11 @@ dependencies = ["udeps-inst"]
command = "cargo"
args = ["udeps", "--all-targets"]

[tasks.ci-common]
dependencies = ["build", "build-bare-metal", "test", "clippy", "audit"]

[tasks.ci]
dependencies = ["build", "test", "format", "header-add", "clippy", "audit"]
dependencies = ["format", "header-add", "ci-common"]

[tasks.ci-remote]
dependencies = [
"build",
"test",
"format-check",
"header-check",
"clippy",
"audit",
]
dependencies = ["format-check", "header-check", "ci-common"]
92 changes: 80 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,89 @@
# risc0-verifier

A verifier for [RISC-Zero](https://github.com/risc0/risc0) STARK proofs.
A `no-std` verifier for [RISC-Zero](https://github.com/risc0/risc0) STARK proofs.

This crate provides a way for deserializing the proof and the verification key (aka image id) and a function to check if the proof is correct:
This crate provides a way for deserializing

- `Proof` (aka risc0 receipt)
- the verification key `Vk` (aka risc0 image id)
- public inputs `Journal` (aka risc0 journal):

```rust
use risc0_verifier::{verify};
use risc0_verifier::*;
use std::path::PathBuf;
use serde::Deserialize;
use std::fs::File;

#[derive(Deserialize)]
struct Data {
vk: [u32; 8],
proof: String,
pubs: String,
pub struct Case {
pub receipt_path: PathBuf,
pub journal: Journal,
pub vk: Vk,
}

let Data { vk, proof, pubs } =
serde_json::from_reader(std::fs::File::open("./resources/valid_proof_1.json").unwrap()).unwrap();
let Case { receipt_path, journal, vk } =
serde_json::from_reader(
std::fs::File::open("./resources/cases/prover_1.2.0/vm_1.2.0/poseidon2_22.json").unwrap()
).unwrap();

let proof = <Vec<u8>>::try_from(hex::decode(proof).unwrap()).unwrap();
let pubs = <Vec<u8>>::try_from(hex::decode(pubs).unwrap()).unwrap();
let proof = ciborium::from_reader(File::open(receipt_path).unwrap()).unwrap();

assert!(verify(vk.into(), &proof, &pubs).is_ok());
assert!(verify(vk, proof, journal).is_ok());
```

## Save a risc0 receipt

`risc0-verifier` accepts _any_ **serde** serialized risc0 `Receipt` that doesn't
contain groth16 proof. So, is you have a risc0's `Receipt` you can just serialize it
with `serde` in your preferred format (i.e. `ciborium` or `json`) and the deserialize
it to use with `risc0-verifier`. You can do the same thing with the `Journal` because the
serialized risc0's `Journal` can be deserialized for `risc0-verifier` as well. For the
`Vk` the risc0 image key bytes can be used directly to build it:

```rust
use risc0_verifier::Vk;
let vk : Vk = hex_literal::hex!("9db9988d9fbcacadf2bd29fc7c60b98bc4234342fe536eb983169eb6cc248009").into();
let r0 : risc0_zkp::core::digest::Digest = [
2375596445,
2913778847,
4230594034,
2344181884,
1111696324,
3111015422,
3063813763,
159392972
].into();

assert_eq!(vk.as_words(), r0.as_words());
assert_eq!(vk.as_bytes(), r0.as_bytes());
```

## Verify a proof generate with an old risc0 version

If you need to verify a proof generated with an old risc0 prover version, for instance the `1.1.3`,
you can use [`verify_with_context`] instead:

```rust
use risc0_verifier::*;
use std::path::PathBuf;
use serde::Deserialize;
use std::fs::File;

#[derive(Deserialize)]
pub struct Case {
pub receipt_path: PathBuf,
pub journal: Journal,
pub vk: Vk,
}

let Case { receipt_path, journal, vk } =
serde_json::from_reader(
std::fs::File::open("./resources/cases/prover_1.1.3/vm_1.1.3/poseidon2_22.json").unwrap()
).unwrap();

let proof = ciborium::from_reader(File::open(receipt_path).unwrap()).unwrap();

assert!(verify_with_context(&VerifierContext::v1_1(), vk, proof, journal).is_ok());
```

## Develop
Expand All @@ -38,6 +100,12 @@ to run all CI's steps. You can also use `makers ci` and bypass `cargo` wrapper.
Another useful defined task is `coverage` that executes tests and compute code
coverage file `lcov.info`.

## Generate the proofs

In `generate_proofs` you can find a both a simple risc0 method and a program that
generate several proofs (different configurations) for a given compiled methods. You
can find some notes about how to generate sample proofs in the file `generate_proofs/notes.md`

## License

These crates are released under the [APACHE 2.0 license](LICENSE-APACHE2)
127 changes: 127 additions & 0 deletions benches/base.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright Copyright 2024, Horizen Labs, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

fn main() {
// Run registered benchmarks.
divan::main();
}

use risc0_verifier::{Digestible as _, VerifierContext};

use utils::*;

mod utils;

pub mod sha {
use super::*;

#[divan::bench]
fn verify_1_2_0_16() {
let ctx = VerifierContext::v1_2();
let case: Case = read_json("resources/cases/prover_1.2.0/vm_1.2.0/sha_16.json").unwrap();
let proof = read_bin(case.receipt_path).unwrap();

compute(
divan::black_box(&ctx),
divan::black_box(&proof),
divan::black_box(case.vk),
divan::black_box(case.journal.digest()),
)
}

#[divan::bench]
fn verify_1_2_0_22() {
let ctx = VerifierContext::v1_2();
let case: Case = read_json("resources/cases/prover_1.2.0/vm_1.2.0/sha_22.json").unwrap();
let proof = read_bin(case.receipt_path).unwrap();

compute(
divan::black_box(&ctx),
divan::black_box(&proof),
divan::black_box(case.vk),
divan::black_box(case.journal.digest()),
)
}
}

pub mod poseidon2 {
use super::*;

#[divan::bench]
fn verify_1_2_0_16() {
let ctx = VerifierContext::v1_2();
let case: Case =
read_json("resources/cases/prover_1.2.0/vm_1.2.0/poseidon2_16.json").unwrap();
let proof = read_bin(case.receipt_path).unwrap();

compute(
divan::black_box(&ctx),
divan::black_box(&proof),
divan::black_box(case.vk),
divan::black_box(case.journal.digest()),
)
}

#[divan::bench]
fn verify_1_2_0_22() {
let ctx = VerifierContext::v1_2();
let case: Case =
read_json("resources/cases/prover_1.2.0/vm_1.2.0/poseidon2_22.json").unwrap();
let proof = read_bin(case.receipt_path).unwrap();

compute(
divan::black_box(&ctx),
divan::black_box(&proof),
divan::black_box(case.vk),
divan::black_box(case.journal.digest()),
)
}
}

pub mod succinct {
use super::*;

#[divan::bench]
fn verify_1_2_0_16() {
let ctx = VerifierContext::v1_2();
let case: Case =
read_json("resources/cases/prover_1.2.0/vm_1.2.0/succinct_16.json").unwrap();
let proof = read_bin(case.receipt_path).unwrap();

compute(
divan::black_box(&ctx),
divan::black_box(&proof),
divan::black_box(case.vk),
divan::black_box(case.journal.digest()),
)
}

#[divan::bench]
fn verify_1_2_0_22() {
let ctx = VerifierContext::v1_2();
let case: Case =
read_json("resources/cases/prover_1.2.0/vm_1.2.0/succinct_22.json").unwrap();
let proof = read_bin(case.receipt_path).unwrap();

compute(
divan::black_box(&ctx),
divan::black_box(&proof),
divan::black_box(case.vk),
divan::black_box(case.journal.digest()),
)
}
}
Loading

0 comments on commit 3d815e4

Please sign in to comment.