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

Add missing docs/test to the Risc0 adapter #920

Merged
merged 6 commits into from
Oct 10, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions adapters/risc0/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ sov-rollup-interface = { path = "../../rollup-interface", version = "0.2" }
default = []
native = ["risc0-zkvm/prove", "dep:risc0-zkp", "dep:risc0-circuit-rv32im"]
bench = ["once_cell", "parking_lot", "native", "sov-zk-cycle-utils/native"]

[[test]]
name = "native"
required-features = ["native"]
6 changes: 3 additions & 3 deletions adapters/risc0/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Risc0 Adapter

This package adapts Risc0 version 0.14 to work as a ZKVM for the Sovereign SDK.
This package adapts Risc0 version 0.18 to work as a zkVM for the Sovereign SDK.

## Limitations

Since recursion is not included in the 0.14 release, this adapter is currently limited - individual "slots" may
be proven, but those proofs cannot be recursively combined to facilitate bridging or ultra-fast sync.
Since in-VM recursion is not included in the 0.18 release, this adapter is currently limited. Individual "slots" may
bkolad marked this conversation as resolved.
Show resolved Hide resolved
be proven, but those proofs cannot be recursively combined to facilitate bridging or ultra-fast sync ("user recursion" is not supported).

## Warning

Expand Down
9 changes: 9 additions & 0 deletions adapters/risc0/src/guest.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! This module implements the `ZkvmGuest` trait for the RISC0 VM.
#[cfg(not(target_os = "zkvm"))]
use std::ops::DerefMut;

Expand Down Expand Up @@ -64,6 +65,10 @@ impl WordRead for Hints {
}
}

/// A guest for the RISC0 VM. When running in the Risc0 environment, this struct
/// implements the `ZkvmGuest` trait in terms of Risc0's env::read and env::commit functions.
/// When running in any other environment, the struct uses interior mutability to emulate
/// the same functionality.
#[derive(Default)]
pub struct Risc0Guest {
#[cfg(not(target_os = "zkvm"))]
Expand All @@ -73,10 +78,14 @@ pub struct Risc0Guest {
}

impl Risc0Guest {
/// Constructs a new Risc0 Guest
pub fn new() -> Self {
Self::default()
}

/// Constructs a new Risc0 Guest with the provided hints.
///
/// This function is only available outside of Risc0's environment.
#[cfg(not(target_os = "zkvm"))]
pub fn with_hints(hints: Vec<u32>) -> Self {
Self {
Expand Down
7 changes: 7 additions & 0 deletions adapters/risc0/src/host.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! This module implements the `ZkvmHost` trait for the RISC0 VM.
use std::sync::Mutex;

use risc0_zkvm::serde::to_vec;
Expand All @@ -13,6 +14,8 @@ use crate::guest::Risc0Guest;
use crate::metrics::metrics_callback;
use crate::Risc0MethodId;

/// A Risc0Host stores a binary to execute in the Risc0 VM, and accumulates hints to be
/// provided to its execution.
pub struct Risc0Host<'a> {
env: Mutex<Vec<u32>>,
elf: &'a [u8],
Expand All @@ -36,6 +39,7 @@ fn add_benchmarking_callbacks(mut env: ExecutorEnvBuilder<'_>) -> ExecutorEnvBui
}

impl<'a> Risc0Host<'a> {
/// Create a new Risc0Host to prove the given binary.
pub fn new(elf: &'a [u8]) -> Self {
Self {
env: Default::default(),
Expand Down Expand Up @@ -107,6 +111,7 @@ impl<'host> Zkvm for Risc0Host<'host> {
}
}

/// A verifier for Risc0 proofs.
pub struct Risc0Verifier;

impl Zkvm for Risc0Verifier {
Expand Down Expand Up @@ -150,6 +155,8 @@ fn verify_from_slice<'a>(
/// data. This allows us to avoid one unnecessary copy during proof verification.
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Risc0Proof<'a> {
/// The cryptographic data certifying the execution of the program.
pub receipt: InnerReceipt,
/// The public outputs produced by the program execution.
pub journal: &'a [u8],
}
7 changes: 7 additions & 0 deletions adapters/risc0/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#![deny(missing_docs)]
//! # RISC0 Adapter
//!
//! This crate contains an adapter allowing the Risc0 to be used as a proof system for
//! Sovereign SDK rollups.
use risc0_zkvm::sha::Digest;
use serde::{Deserialize, Serialize};
use sov_rollup_interface::zk::Matches;
Expand All @@ -9,6 +14,8 @@ pub mod host;
#[cfg(feature = "bench")]
pub mod metrics;

/// Uniquely identifies a Risc0 binary. Roughly equivalent to
/// the hash of the ELF file.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Risc0MethodId([u32; 8]);

Expand Down
15 changes: 13 additions & 2 deletions adapters/risc0/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
//! Defines utilities for collecting runtime metrics from inside a Risc0 VM
use std::collections::HashMap;

use anyhow::Context;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use risc0_zkvm::Bytes;

/// A global hashmap mapping metric names to their values.
pub static GLOBAL_HASHMAP: Lazy<Mutex<HashMap<String, (u64, u64)>>> =
Lazy::new(|| Mutex::new(HashMap::new()));

pub fn add_value(metric: String, value: u64) {
/// Increments the requested metric by the given value, creating a
/// new entry in the global map if necessary.
fn add_value(metric: String, value: u64) {
let mut hashmap = GLOBAL_HASHMAP.lock();
hashmap
.entry(metric)
Expand All @@ -19,7 +23,9 @@ pub fn add_value(metric: String, value: u64) {
.or_insert((value, 1));
}

pub fn deserialize_custom(serialized: Bytes) -> Result<(String, u64), anyhow::Error> {
/// Deserialize a `Bytes` into a null-separated `(String, u64)` tuple. This function
/// expects its arguments to match the format of arguments to Risc0's io callbacks.
fn deserialize_custom(serialized: Bytes) -> Result<(String, u64), anyhow::Error> {
let null_pos = serialized
.iter()
.position(|&b| b == 0)
Expand All @@ -31,6 +37,11 @@ pub fn deserialize_custom(serialized: Bytes) -> Result<(String, u64), anyhow::Er
Ok((string, size))
}

/// A custom callback for extracting metrics from the Risc0 zkvm.
///
/// When the "bench" feature is enabled, this callback is registered as a syscall
/// in the Risc0 VM and invoked whenever a function annotated with the [`sov-zk-cycle-utils::cycle_tracker`]
/// macro is invoked.
pub fn metrics_callback(input: risc0_zkvm::Bytes) -> Result<Bytes, anyhow::Error> {
let met_tuple = deserialize_custom(input)?;
add_value(met_tuple.0, met_tuple.1);
Expand Down
24 changes: 24 additions & 0 deletions adapters/risc0/tests/native.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use serde::{Deserialize, Serialize};
use sov_risc0_adapter::host::Risc0Host;
use sov_rollup_interface::zk::{ZkvmGuest, ZkvmHost};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct TestStruct {
ints: Vec<i32>,
string: String,
}

#[test]
fn test_hints_roundtrip() {
let hint = TestStruct {
ints: vec![1, 2, 3, 4, 5],
string: "hello".to_string(),
};
let mut host = Risc0Host::new(&[]);

host.add_hint(&hint);

let guest = host.simulate_with_hints();
let received = guest.read_from_host();
assert_eq!(hint, received);
}