Skip to content

Commit

Permalink
Update docs for Risc0 adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
citizen-stig committed Sep 26, 2023
1 parent 052a3a3 commit d2110f9
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 18 deletions.
6 changes: 3 additions & 3 deletions adapters/risc0/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Risc0 Adapter

This package adapts Risc0 version 0.14 to work as a ZKVM for the Sovereign SDK.
This package adapts the [Risc0](https://www.risczero.com/) 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
Since recursion is not included in the 0.18 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.

## Warning
## ⚠️ Warning

Risc0 is currently under active development and has not been audited. This adapter has also not been audited. Do not
deploy in production
14 changes: 11 additions & 3 deletions adapters/risc0/src/guest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ struct Hints {
position: usize,
}

/// A helper structure used in non-"zkVM" environments to assist with the serialization
/// and deserialization processes by keeping track of provided hints and their positions.
#[cfg(not(target_os = "zkvm"))]
impl Hints {
pub fn with_hints(hints: Vec<u32>) -> Self {
fn with_hints(hints: Vec<u32>) -> Self {
Hints {
values: hints,
position: 0,
}
}
pub fn remaining(&self) -> usize {
fn remaining(&self) -> usize {
self.values.len() - self.position
}
}
Expand All @@ -64,6 +66,7 @@ impl WordRead for Hints {
}
}

/// Control struct for Risc0 guest.
#[derive(Default)]
pub struct Risc0Guest {
#[cfg(not(target_os = "zkvm"))]
Expand All @@ -73,10 +76,13 @@ pub struct Risc0Guest {
}

impl Risc0Guest {
/// Creates and returns a new `Risc0Guest` instance with default values.
pub fn new() -> Self {
Self::default()
}

/// Creates and returns a new `Risc0Guest` instance initialized with provided hints.
/// Only available in non-"zkVM" environments.
#[cfg(not(target_os = "zkvm"))]
pub fn with_hints(hints: Vec<u32>) -> Self {
Self {
Expand All @@ -86,6 +92,8 @@ impl Risc0Guest {
}
}

/// This trait implementation allows `Risc0Guest` to interact with the Risc0 virtual machine,
/// offering mechanisms to read data from the host and commit data back to it.
#[cfg(not(target_os = "zkvm"))]
impl ZkvmGuest for Risc0Guest {
fn read_from_host<T: serde::de::DeserializeOwned>(&self) -> T {
Expand All @@ -110,7 +118,7 @@ impl Zkvm for Risc0Guest {
_serialized_proof: &'a [u8],
_code_commitment: &Self::CodeCommitment,
) -> Result<&'a [u8], Self::Error> {
// Implement this method once risc0 supports recursion: issue #633
// Implement this method once Risc0 supports recursion: issue #633
todo!("Implement once risc0 supports recursion: https://github.com/Sovereign-Labs/sovereign-sdk/issues/633")
}

Expand Down
23 changes: 16 additions & 7 deletions adapters/risc0/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ use crate::guest::Risc0Guest;
use crate::metrics::metrics_callback;
use crate::Risc0MethodId;

/// The 'host' of a Risc0 zkVM.
/// Generates a SNARK by running the target code on a virtual RISC-V CPU.
/// The host is responsible for sending the "witness" data to the zkVM guest.
pub struct Risc0Host<'a> {
env: Mutex<Vec<u32>>,
elf: &'a [u8],
Expand All @@ -36,15 +39,16 @@ fn add_benchmarking_callbacks(mut env: ExecutorEnvBuilder<'_>) -> ExecutorEnvBui
}

impl<'a> Risc0Host<'a> {
/// Creates a new `Risc0Host` instance to prove the execution of the provided ELF file.
pub fn new(elf: &'a [u8]) -> Self {
Self {
env: Default::default(),
elf,
}
}

/// Run a computation in the zkvm without generating a receipt.
/// This creates the "Session" trace without invoking the heavy cryptographic machinery.
/// Run a computation in the zkVM without generating a receipt.
/// This creates the [`Session`] trace without invoking the heavy cryptographic machinery.
pub fn run_without_proving(&mut self) -> anyhow::Result<Session> {
let env = add_benchmarking_callbacks(ExecutorEnvBuilder::default())
.add_input(&self.env.lock().unwrap())
Expand All @@ -53,21 +57,22 @@ impl<'a> Risc0Host<'a> {
let mut executor = Executor::from_elf(env, self.elf)?;
executor.run()
}
/// Run a computation in the zkvm and generate a receipt.

/// Executes a computation in the zkVM, subsequently generating a [`Receipt`].
pub fn run(&mut self) -> anyhow::Result<Receipt> {
let session = self.run_without_proving()?;
session.prove()
}
}

impl<'a> ZkvmHost for Risc0Host<'a> {
type Guest = Risc0Guest;

fn add_hint<T: serde::Serialize>(&self, item: T) {
let serialized = to_vec(&item).expect("Serialization to vec is infallible");
self.env.lock().unwrap().extend_from_slice(&serialized[..]);
}

type Guest = Risc0Guest;

fn simulate_with_hints(&mut self) -> Self::Guest {
Risc0Guest::with_hints(std::mem::take(&mut self.env.lock().unwrap()))
}
Expand Down Expand Up @@ -107,6 +112,8 @@ impl<'host> Zkvm for Risc0Host<'host> {
}
}

/// A structure responsible for verifying Risc0 proofs.
///
pub struct Risc0Verifier;

impl Zkvm for Risc0Verifier {
Expand Down Expand Up @@ -146,10 +153,12 @@ fn verify_from_slice<'a>(
Ok(journal)
}

/// A convenience type which contains the same data a Risc0 [`Receipt`] but borrows the journal
/// data. This allows us to avoid one unnecessary copy during proof verification.
/// A convenience type containing the same data as a Risc0 [`Receipt`], but borrows the journal
/// data instead. This design avoids an unnecessary data copy during proof verification.
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Risc0Proof<'a> {
/// The [`InnerReceipt`] which was generated by the Risc0 zkVM.
pub receipt: InnerReceipt,
/// Reference to the journal data which was generated by the Risc0 zkVM.
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,14 +1,21 @@
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]

use risc0_zkvm::sha::Digest;
use serde::{Deserialize, Serialize};
use sov_rollup_interface::zk::Matches;

/// Guest module, that runs inside zkVM
pub mod guest;
/// Host module, that runs natively
#[cfg(feature = "native")]
pub mod host;

/// Metrics used for benchmarking
#[cfg(feature = "bench")]
pub mod metrics;

/// Risc0 implementation of a commitment to the zkVM program which is being proven.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Risc0MethodId([u32; 8]);

Expand Down
13 changes: 8 additions & 5 deletions adapters/risc0/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ use std::collections::HashMap;
use anyhow::Context;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use risc0_zkvm::Bytes;

/// Global hashmap for storing metrics
pub static GLOBAL_HASHMAP: Lazy<Mutex<HashMap<String, (u64, u64)>>> =
Lazy::new(|| Mutex::new(HashMap::new()));

pub fn add_value(metric: String, value: u64) {
/// Adds metric to the global hashmap
fn add_value(metric: String, value: u64) {
let mut hashmap = GLOBAL_HASHMAP.lock();
hashmap
.entry(metric)
Expand All @@ -19,7 +20,8 @@ pub fn add_value(metric: String, value: u64) {
.or_insert((value, 1));
}

pub fn deserialize_custom(serialized: Bytes) -> Result<(String, u64), anyhow::Error> {
/// Deserializes custom [`risc0_zkvm::Bytes`] into a tuple of (metric, value)
fn deserialize_custom(serialized: risc0_zkvm::Bytes) -> Result<(String, u64), anyhow::Error> {
let null_pos = serialized
.iter()
.position(|&b| b == 0)
Expand All @@ -31,8 +33,9 @@ pub fn deserialize_custom(serialized: Bytes) -> Result<(String, u64), anyhow::Er
Ok((string, size))
}

pub fn metrics_callback(input: risc0_zkvm::Bytes) -> Result<Bytes, anyhow::Error> {
/// Track metric provided as raw bytes. The bytes are expected to be a tuple of (metric, value)
pub fn metrics_callback(input: risc0_zkvm::Bytes) -> Result<risc0_zkvm::Bytes, anyhow::Error> {
let met_tuple = deserialize_custom(input)?;
add_value(met_tuple.0, met_tuple.1);
Ok(Bytes::new())
Ok(risc0_zkvm::Bytes::new())
}

0 comments on commit d2110f9

Please sign in to comment.