Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement check_code for pure-rust verify #258

Merged
merged 2 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:
crate: cargo-sort
version: "1.0"
- run: cargo test --release
- run: cargo test --release --features pure-prove
- run: cargo check --benches
- run: cargo fmt --all -- --check
- run: cargo sort --workspace --check
25 changes: 0 additions & 25 deletions .vscode/tasks.json

This file was deleted.

6 changes: 2 additions & 4 deletions risc0/zkp/rust/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! Core module used to implement a zk-STARK prover and verifier.

#![deny(missing_docs)]
//! Core objects used by the zk-STARK prover
//! and verifier.
#![doc = include_str!("README.md")]

extern crate alloc;
Expand All @@ -24,8 +24,6 @@ use rand::Rng;
/// This transitional "fp4" module will remain until ZKP has been genericized to
/// work with multiple fields. This module includes the base field of order
/// 15*2^27 + 1).
///
/// # Example
pub mod fp {
pub use crate::field::baby_bear::Elem as Fp;
}
Expand Down
1 change: 1 addition & 0 deletions risc0/zkp/rust/src/core/sha_rng.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

//! A SHA-256 based CRNG used in Fiat-Shamir.

use rand::{Error, RngCore};
use rand_core::impls;

Expand Down
5 changes: 3 additions & 2 deletions risc0/zkp/rust/src/field/baby_bear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! Baby bear field.
//! Support for the base finite field modulo `15 * 2^27 + 1`.

use alloc::fmt;
use core::ops;

use bytemuck::{Pod, Zeroable};

/// ! Baby bear field.
/// ! Support for the base finite field modulo 15*2^27 + 1
use crate::field::{self, Elem as FieldElem};

/// Definition of this field for operations that operate on the baby
Expand Down
5 changes: 3 additions & 2 deletions risc0/zkp/rust/src/field/goldilocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! Goldilocks field.
//! Support for the base finite field modulo `2^64 - 2^32 + 1`.

use core::ops;

use bytemuck::{Pod, Zeroable};

/// ! Goldilocks field.
/// ! Support for the base finite field modulo 2^64 - 2^32 + 1
use crate::field::{self, Elem as FieldElem};

/// The Goldilocks class is an element of the finite field F_p, where P is the
Expand Down
1 change: 1 addition & 0 deletions risc0/zkp/rust/src/field/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

//! Defines field extension (and base fields) used for finite field-based
//! operations across the RISC Zero zkVM architecture

use core::{cmp, fmt::Debug, ops};

/// A pair of fields, one of which is an extension field of the other.
Expand Down
3 changes: 2 additions & 1 deletion risc0/zkp/rust/src/hal/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! Hardware abstraction layer for RISC Zero zkVM
//! CPU implementation of the HAL.

use core::{
cell::{Ref, RefMut},
marker::PhantomData,
Expand Down
3 changes: 2 additions & 1 deletion risc0/zkp/rust/src/hal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! Hardware abstraction layer for RISC Zero zkVM
//! Hardware Abstraction Layer (HAL) for accelerating the ZKP system.

pub mod cpu;

use crate::{
Expand Down
6 changes: 5 additions & 1 deletion risc0/zkp/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub mod adapter;
pub mod core;
#[cfg(feature = "hal")]
pub mod hal;
#[cfg(any(feature = "prove", feature = "verify"))]
mod merkle;
#[cfg(feature = "prove")]
pub mod prove;
Expand All @@ -40,8 +41,11 @@ pub const ZK_CYCLES: usize = QUERIES;
pub const MIN_PO2: usize = core::log2_ceil(1 + ZK_CYCLES);

pub const INV_RATE: usize = 4;
#[cfg(any(feature = "prove", feature = "verify"))]
const FRI_FOLD_PO2: usize = 4;
#[cfg(any(feature = "prove", feature = "verify"))]
const FRI_FOLD: usize = 1 << FRI_FOLD_PO2;
#[cfg(any(feature = "prove", feature = "verify"))]
const FRI_MIN_DEGREE: usize = 256;

#[cfg(any(feature = "prove", feature = "verify"))]
const CHECK_SIZE: usize = INV_RATE * core::fp4::EXT_SIZE;
13 changes: 2 additions & 11 deletions risc0/zkp/rust/src/verify/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,10 @@ use alloc::vec::Vec;

use crate::{
adapter::{CircuitInfo, PolyExt, PolyExtContext, TapsProvider},
core::{
fp::Fp,
fp4::Fp4,
sha::{Digest, Sha},
},
core::{fp::Fp, fp4::Fp4, sha::Sha},
field::Elem,
taps::TapSet,
verify::{read_iop::ReadIOP, Circuit, VerificationError},
verify::{read_iop::ReadIOP, Circuit},
};

pub struct VerifyAdapter<'a, C: CircuitInfo + PolyExt + TapsProvider> {
Expand Down Expand Up @@ -72,11 +68,6 @@ impl<'a, C: CircuitInfo + PolyExt + TapsProvider> Circuit for VerifyAdapter<'a,
self.po2
}

fn check_code(&self, _root: &Digest) -> Result<(), VerificationError> {
// TODO: check code merkle tree
Ok(())
}

fn compute_polynomial(&self, u: &[Fp4], poly_mix: Fp4) -> Fp4 {
let ctx = PolyExtContext { mix: poly_mix };
let args: &[&[Fp]] = &[&self.out, &self.mix];
Expand Down
19 changes: 12 additions & 7 deletions risc0/zkp/rust/src/verify/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use core::fmt;
use crate::{
core::{
fp::Fp,
fp4::{Fp4, EXT_SIZE},
fp4::Fp4,
log2_ceil,
poly::poly_eval,
rou::{ROU_FWD, ROU_REV},
Expand All @@ -33,11 +33,9 @@ use crate::{
field::Elem,
taps::{RegisterGroup, TapSet},
verify::{fri::fri_verify, merkle::MerkleTreeVerifier, read_iop::ReadIOP},
INV_RATE, MAX_CYCLES_PO2, QUERIES,
CHECK_SIZE, INV_RATE, MAX_CYCLES_PO2, QUERIES,
};

const CHECK_SIZE: usize = INV_RATE * EXT_SIZE;

#[derive(Debug)]
pub enum VerificationError {
ReceiptFormatError,
Expand Down Expand Up @@ -66,14 +64,19 @@ pub trait Circuit {
fn execute<S: Sha>(&mut self, iop: &mut ReadIOP<S>);
fn accumulate<S: Sha>(&mut self, iop: &mut ReadIOP<S>);
fn po2(&self) -> u32;
fn check_code(&self, root: &Digest) -> Result<(), VerificationError>;
fn compute_polynomial(&self, u: &[Fp4], mix: Fp4) -> Fp4;
}

pub fn verify<S, C>(sha: &S, circuit: &mut C, seal: &[u32]) -> Result<(), VerificationError>
pub fn verify<S, C, F>(
sha: &S,
circuit: &mut C,
seal: &[u32],
check_code: F,
) -> Result<(), VerificationError>
where
S: Sha,
C: Circuit,
F: Fn(u32, &Digest) -> bool,
{
if seal.len() == 0 {
return Err(VerificationError::ReceiptFormatError);
Expand Down Expand Up @@ -106,7 +109,9 @@ where
// debug!("dataRoot = {}", data_merkle.root());

// Verify code is valid
circuit.check_code(code_merkle.root())?;
if !check_code(po2, code_merkle.root()) {
return Err(VerificationError::MethodVerificationError);
}

// Prep accumulation
circuit.accumulate(&mut iop);
Expand Down
1 change: 1 addition & 0 deletions risc0/zkvm/sdk/rust/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ risc0_rust_library_pair(
],
host_features = [
"bazel",
"circuit",
"host",
"prove",
"std",
Expand Down
2 changes: 1 addition & 1 deletion risc0/zkvm/sdk/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ prove = ["circuit", "risc0-zkp/prove"]
std = ["risc0-zkp/std", "serde/std"]
verify = ["circuit", "risc0-zkp/verify"]
# Run rust-based prover instead of FFI-based prover.
pure-prove = ["prove", "std"]
pure-prove = ["prove", "std", "risc0-zkvm-platform/pure-prove"]

[[bench]]
name = "guest_run"
Expand Down
6 changes: 3 additions & 3 deletions risc0/zkvm/sdk/rust/benches/guest_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

//! `guest_run' runs benchmarks on various guest tasks. The purpose
//! of these benchmarks is to gather performance data on code compiled
//! for the guest, as opposed to performance data on the prover As
//! for the guest, as opposed to performance data on the prover. As
//! such, they do not generate seals, and these performance numbers
//! are not indicitive of performance with cryptographically secure
//! proofs.
Expand Down Expand Up @@ -45,7 +45,7 @@ fn run_guest(spec: SpecWithIters) -> Duration {
ProverOpts::default().with_skip_seal(true),
)
.unwrap();
prover.add_input(input_data.as_slice()).unwrap();
prover.add_input_u32_slice(input_data.as_slice());

let start = Instant::now();
black_box(prover.run().unwrap());
Expand Down Expand Up @@ -179,6 +179,6 @@ pub fn bench(c: &mut Criterion) {
}

criterion_group!(name = benches;
config = Criterion::default();//
config = Criterion::default();
targets = bench);
criterion_main!(benches);
4 changes: 4 additions & 0 deletions risc0/zkvm/sdk/rust/build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ serde = { version = "1.0", default-features = false, features = ["derive"] }
serde_json = "1.0"
sha2 = "0.10"
zip = "0.6"

[features]
# Run rust-based prover instead of FFI-based prover.
pure-prove = []
28 changes: 24 additions & 4 deletions risc0/zkvm/sdk/rust/build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ use std::{
};

use cargo_metadata::{MetadataCommand, Package};
#[cfg(not(feature = "pure-prove"))]
use risc0_zkvm::host::{MethodId, DEFAULT_METHOD_ID_LIMIT};
#[cfg(feature = "pure-prove")]
use risc0_zkvm::method_id::{MethodId, DEFAULT_METHOD_ID_LIMIT};
use risc0_zkvm_platform_sys::LINKER_SCRIPT;
use serde::Deserialize;
use sha2::{Digest, Sha256};
Expand Down Expand Up @@ -67,7 +70,13 @@ impl Risc0Method {
let method_id_path = self.elf_path.with_extension("id");
let elf_sha_path = self.elf_path.with_extension("sha");
let elf_contents = std::fs::read(&self.elf_path).unwrap();
let (elf_sha, elf_sha_hex) = sha_digest_with_hex(&elf_contents);
// This HACK is in place to ensure that MethodIDs are considered distinct
// between pure-prove and C++ provers.
#[cfg(not(feature = "pure-prove"))]
let label = "";
#[cfg(feature = "pure-prove")]
let label = "pure-prove";
let (elf_sha, elf_sha_hex) = sha_digest_with_hex(&elf_contents, label);
if method_id_path.exists() {
if let Ok(cached_sha) = std::fs::read(&elf_sha_path) {
if cached_sha == elf_sha.as_slice() {
Expand Down Expand Up @@ -124,8 +133,11 @@ const RUST_LIB_MAP : &[ZipMapEntry] = &[
dst_prefix: "library/backtrace"},
];

fn sha_digest_with_hex(data: &[u8]) -> (Vec<u8>, String) {
let bin_sha = Sha256::new().chain_update(data).finalize();
fn sha_digest_with_hex(data: &[u8], label: &str) -> (Vec<u8>, String) {
let bin_sha = Sha256::new()
.chain_update(data)
.chain_update(label)
.finalize();
(
bin_sha.to_vec(),
bin_sha
Expand Down Expand Up @@ -224,7 +236,7 @@ where

// Rust standard library. If any of the RUST_LIB_MAP changed, we
// want to have a different hash so that we make sure we recompile.
let (_, src_id_hash) = sha_digest_with_hex(format!("{:?}", RUST_LIB_MAP).as_bytes());
let (_, src_id_hash) = sha_digest_with_hex(format!("{:?}", RUST_LIB_MAP).as_bytes(), "");
let rust_lib_path = out_dir.as_ref().join(format!("rust-std_{}", src_id_hash));
if !rust_lib_path.exists() {
println!(
Expand Down Expand Up @@ -315,6 +327,10 @@ fn build_guest_package<P>(
"--target-dir",
target_dir.as_ref().to_str().unwrap(),
];
#[cfg(feature = "pure-prove")]
let mut features = features.clone();
#[cfg(feature = "pure-prove")]
features.push("pure-prove".to_string());
let features_str = features.join(",");
if !features.is_empty() {
args.push("--features");
Expand Down Expand Up @@ -398,6 +414,10 @@ impl Default for GuestOptions {
/// Specify custom options for a guest package by defining its [GuestOptions].
/// See [embed_methods].
pub fn embed_methods_with_options(mut guest_pkg_to_options: HashMap<&str, GuestOptions>) {
if env::var("RISC0_SKIP_BUILD").is_ok() {
return;
}

let out_dir_env = env::var_os("OUT_DIR").unwrap();
let out_dir = Path::new(&out_dir_env);

Expand Down
2 changes: 2 additions & 0 deletions risc0/zkvm/sdk/rust/guest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ risc0-build = { version = "0.11", path = "../build" }
bazel = []
default = ["std"]
doc = ["std"]
# Run rust-based prover instead of FFI-based prover.
pure-prove = ["risc0-zkvm-platform/pure-prove"]
std = ["risc0-zkp/std", "serde/std"]

[workspace]
2 changes: 2 additions & 0 deletions risc0/zkvm/sdk/rust/methods/inner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ release = false

[features]
default = ["std"]
# Run rust-based prover instead of FFI-based prover.
pure-prove = ["risc0-zkvm-guest/pure-prove"]
std = []
test_feature1 = []
test_feature2 = []
2 changes: 2 additions & 0 deletions risc0/zkvm/sdk/rust/platform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ core = { optional = true, package = "rustc-std-workspace-core", version = "1.0.0

[features]
default = ["bytemuck/derive"]
# Run rust-based prover instead of FFI-based prover.
pure-prove = []
rustc-dep-of-std = ["core", "compiler_builtins"]
8 changes: 8 additions & 0 deletions risc0/zkvm/sdk/rust/platform/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,15 @@ pub const HEAP: Region = Region::new(0x00A0_0000, mb(20));
pub const INPUT: Region = Region::new(0x01E0_0000, mb(1));
pub const GPIO: Region = Region::new(0x01F0_0000, mb(1));
pub const PROG: Region = Region::new(0x0200_0000, mb(10));
#[cfg(not(feature = "pure-prove"))]
pub const SHA: Region = Region::new(0x02A0_0000, mb(1));
#[cfg(feature = "pure-prove")]
// This HACK will cause the SHA accelerator to be skipped.
// This is intended as a temporary workaround for bugs in the SHA circuit.
// The hash will still be computed on the host via a GPIO signal,
// but the polynomial constraints will not be applied to the ZKP.
// *DO NOT USE IN PRODUCTION*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, but yeah, I guess when we make pure-prove the default we'll notice this when we go to remote the feature.

pub const SHA: Region = Region::new(0x02A0_0004, mb(1));
pub const WOM: Region = Region::new(0x02B0_0000, mb(21));
pub const OUTPUT: Region = Region::new(0x02B0_0000, mb(20));
pub const COMMIT: Region = Region::new(0x03F0_0000, mb(1));