mirror of
https://github.com/eth-act/ere.git
synced 2026-04-25 03:00:10 -04:00
Refactor docs and make Input API more explicit (#235)
This commit is contained in:
@@ -34,16 +34,16 @@ ere-zisk = { workspace = true, features = ["zkvm"], optional = true }
|
||||
ere-zkvm-interface = { workspace = true, features = ["clap"] }
|
||||
|
||||
[dev-dependencies]
|
||||
prost-build.workspace = true
|
||||
tempfile.workspace = true
|
||||
twirp-build.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
prost-build.workspace = true
|
||||
twirp-build.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["client"]
|
||||
client = []
|
||||
server = ["dep:clap", "dep:tower-http", "dep:tracing", "dep:tracing-subscriber", "tokio/macros", "tokio/rt-multi-thread", "tokio/signal"]
|
||||
|
||||
# zkVM
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
prost_build::Config::new()
|
||||
.type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]") // enable support for JSON encoding
|
||||
.service_generator(twirp_build::service_generator())
|
||||
.compile_protos(&["./proto/api.proto"], &["./proto"])
|
||||
.expect("error compiling protos");
|
||||
Ok(())
|
||||
}
|
||||
278
crates/dockerized/server/src/api.rs
Normal file
278
crates/dockerized/server/src/api.rs
Normal file
@@ -0,0 +1,278 @@
|
||||
// This file is @generated by prost-build.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ExecuteRequest {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub input_stdin: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes = "vec", optional, tag = "2")]
|
||||
pub input_proofs: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ExecuteResponse {
|
||||
#[prost(oneof = "execute_response::Result", tags = "1, 2")]
|
||||
pub result: ::core::option::Option<execute_response::Result>,
|
||||
}
|
||||
/// Nested message and enum types in `ExecuteResponse`.
|
||||
pub mod execute_response {
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Result {
|
||||
#[prost(message, tag = "1")]
|
||||
Ok(super::ExecuteOk),
|
||||
#[prost(string, tag = "2")]
|
||||
Err(::prost::alloc::string::String),
|
||||
}
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ExecuteOk {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub public_values: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub report: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ProveRequest {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub input_stdin: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes = "vec", optional, tag = "2")]
|
||||
pub input_proofs: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
|
||||
#[prost(enumeration = "ProofKind", tag = "3")]
|
||||
pub proof_kind: i32,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ProveResponse {
|
||||
#[prost(oneof = "prove_response::Result", tags = "1, 2")]
|
||||
pub result: ::core::option::Option<prove_response::Result>,
|
||||
}
|
||||
/// Nested message and enum types in `ProveResponse`.
|
||||
pub mod prove_response {
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Result {
|
||||
#[prost(message, tag = "1")]
|
||||
Ok(super::ProveOk),
|
||||
#[prost(string, tag = "2")]
|
||||
Err(::prost::alloc::string::String),
|
||||
}
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ProveOk {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub public_values: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub proof: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes = "vec", tag = "3")]
|
||||
pub report: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct VerifyRequest {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub proof: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(enumeration = "ProofKind", tag = "2")]
|
||||
pub proof_kind: i32,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct VerifyResponse {
|
||||
#[prost(oneof = "verify_response::Result", tags = "1, 2")]
|
||||
pub result: ::core::option::Option<verify_response::Result>,
|
||||
}
|
||||
/// Nested message and enum types in `VerifyResponse`.
|
||||
pub mod verify_response {
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Result {
|
||||
#[prost(message, tag = "1")]
|
||||
Ok(super::VerifyOk),
|
||||
#[prost(string, tag = "2")]
|
||||
Err(::prost::alloc::string::String),
|
||||
}
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct VerifyOk {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub public_values: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum ProofKind {
|
||||
Compressed = 0,
|
||||
Groth16 = 1,
|
||||
}
|
||||
impl ProofKind {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
///
|
||||
/// The values are not transformed in any way and thus are considered stable
|
||||
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||
pub fn as_str_name(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Compressed => "Compressed",
|
||||
Self::Groth16 => "Groth16",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||
match value {
|
||||
"Compressed" => Some(Self::Compressed),
|
||||
"Groth16" => Some(Self::Groth16),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub use twirp;
|
||||
#[twirp::async_trait::async_trait]
|
||||
pub trait ZkvmService: Send + Sync {
|
||||
async fn execute(
|
||||
&self,
|
||||
req: twirp::Request<ExecuteRequest>,
|
||||
) -> twirp::Result<twirp::Response<ExecuteResponse>>;
|
||||
async fn prove(
|
||||
&self,
|
||||
req: twirp::Request<ProveRequest>,
|
||||
) -> twirp::Result<twirp::Response<ProveResponse>>;
|
||||
async fn verify(
|
||||
&self,
|
||||
req: twirp::Request<VerifyRequest>,
|
||||
) -> twirp::Result<twirp::Response<VerifyResponse>>;
|
||||
}
|
||||
#[twirp::async_trait::async_trait]
|
||||
impl<T> ZkvmService for std::sync::Arc<T>
|
||||
where
|
||||
T: ZkvmService + Sync + Send,
|
||||
{
|
||||
async fn execute(
|
||||
&self,
|
||||
req: twirp::Request<ExecuteRequest>,
|
||||
) -> twirp::Result<twirp::Response<ExecuteResponse>> {
|
||||
T::execute(&*self, req).await
|
||||
}
|
||||
async fn prove(
|
||||
&self,
|
||||
req: twirp::Request<ProveRequest>,
|
||||
) -> twirp::Result<twirp::Response<ProveResponse>> {
|
||||
T::prove(&*self, req).await
|
||||
}
|
||||
async fn verify(
|
||||
&self,
|
||||
req: twirp::Request<VerifyRequest>,
|
||||
) -> twirp::Result<twirp::Response<VerifyResponse>> {
|
||||
T::verify(&*self, req).await
|
||||
}
|
||||
}
|
||||
pub fn router<T>(api: T) -> twirp::Router
|
||||
where
|
||||
T: ZkvmService + Clone + Send + Sync + 'static,
|
||||
{
|
||||
twirp::details::TwirpRouterBuilder::new("/api.ZkvmService", api)
|
||||
.route(
|
||||
"/Execute",
|
||||
|api: T, req: twirp::Request<ExecuteRequest>| async move {
|
||||
api.execute(req).await
|
||||
},
|
||||
)
|
||||
.route(
|
||||
"/Prove",
|
||||
|api: T, req: twirp::Request<ProveRequest>| async move {
|
||||
api.prove(req).await
|
||||
},
|
||||
)
|
||||
.route(
|
||||
"/Verify",
|
||||
|api: T, req: twirp::Request<VerifyRequest>| async move {
|
||||
api.verify(req).await
|
||||
},
|
||||
)
|
||||
.build()
|
||||
}
|
||||
#[twirp::async_trait::async_trait]
|
||||
impl ZkvmService for twirp::client::Client {
|
||||
async fn execute(
|
||||
&self,
|
||||
req: twirp::Request<ExecuteRequest>,
|
||||
) -> twirp::Result<twirp::Response<ExecuteResponse>> {
|
||||
self.request("api.ZkvmService/Execute", req).await
|
||||
}
|
||||
async fn prove(
|
||||
&self,
|
||||
req: twirp::Request<ProveRequest>,
|
||||
) -> twirp::Result<twirp::Response<ProveResponse>> {
|
||||
self.request("api.ZkvmService/Prove", req).await
|
||||
}
|
||||
async fn verify(
|
||||
&self,
|
||||
req: twirp::Request<VerifyRequest>,
|
||||
) -> twirp::Result<twirp::Response<VerifyResponse>> {
|
||||
self.request("api.ZkvmService/Verify", req).await
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub mod handler {
|
||||
use super::*;
|
||||
pub struct ZkvmServiceHandler {
|
||||
inner: std::sync::Arc<dyn ZkvmService>,
|
||||
}
|
||||
impl ZkvmServiceHandler {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new<M: ZkvmService + 'static>(inner: M) -> Self {
|
||||
Self {
|
||||
inner: std::sync::Arc::new(inner),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[twirp::async_trait::async_trait]
|
||||
impl twirp::client::DirectHandler for ZkvmServiceHandler {
|
||||
fn service(&self) -> &str {
|
||||
"api.ZkvmService"
|
||||
}
|
||||
async fn handle(
|
||||
&self,
|
||||
method: &str,
|
||||
req: twirp::reqwest::Request,
|
||||
) -> twirp::Result<twirp::reqwest::Response> {
|
||||
match method {
|
||||
"Execute" => {
|
||||
twirp::details::encode_response(
|
||||
self
|
||||
.inner
|
||||
.execute(twirp::details::decode_request(req).await?)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
"Prove" => {
|
||||
twirp::details::encode_response(
|
||||
self
|
||||
.inner
|
||||
.prove(twirp::details::decode_request(req).await?)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
"Verify" => {
|
||||
twirp::details::encode_response(
|
||||
self
|
||||
.inner
|
||||
.verify(twirp::details::decode_request(req).await?)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
Err(
|
||||
twirp::bad_route(
|
||||
format!(
|
||||
"unknown rpc `{method}` for service `{}`, url: {:?}",
|
||||
"api.ZkvmService", req.url()
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
pub mod client;
|
||||
#[rustfmt::skip]
|
||||
pub mod api;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) mod api {
|
||||
include!(concat!(env!("OUT_DIR"), "/api.rs"));
|
||||
}
|
||||
#[cfg(feature = "client")]
|
||||
pub mod client;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
28
crates/dockerized/server/src/test.rs
Normal file
28
crates/dockerized/server/src/test.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use std::{env, fs, path::PathBuf};
|
||||
|
||||
/// To sync generated `api.rs`, run:
|
||||
///
|
||||
/// ```
|
||||
/// cargo test --package ere-server --no-default-features --lib -- test::api_generation --exact
|
||||
/// ```
|
||||
#[test]
|
||||
fn api_generation() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
|
||||
prost_build::Config::new()
|
||||
.out_dir(tempdir.path())
|
||||
.type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]") // enable support for JSON encoding
|
||||
.service_generator(twirp_build::service_generator())
|
||||
.compile_protos(&[dir.join("proto").join("api.proto")], &[dir.join("proto")])
|
||||
.unwrap();
|
||||
|
||||
let latest = tempdir.path().join("api.rs");
|
||||
let current = dir.join("src").join("api.rs");
|
||||
|
||||
// If it's in CI env, don't overwrite but only check if it's up-to-date.
|
||||
if env::var_os("GITHUB_ACTIONS").is_none() {
|
||||
fs::copy(&latest, ¤t).unwrap();
|
||||
}
|
||||
assert_eq!(fs::read(&latest).unwrap(), fs::read(¤t).unwrap());
|
||||
}
|
||||
@@ -49,7 +49,7 @@
|
||||
//! let zkvm = DockerizedzkVM::new(zkvm_kind, program, resource)?;
|
||||
//!
|
||||
//! // Serialize input
|
||||
//! let input = Input::new(42u32.to_le_bytes().to_vec());
|
||||
//! let input = Input::new().with_stdin(42u32.to_le_bytes().to_vec());
|
||||
//!
|
||||
//! // Execute program
|
||||
//! let (public_values, execution_report) = zkvm.execute(&input)?;
|
||||
|
||||
@@ -406,7 +406,7 @@ mod test {
|
||||
"basic",
|
||||
[BasicProgram::<BincodeLegacy>::valid_test_case().into_output_sha256()],
|
||||
[
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input()
|
||||
]
|
||||
);
|
||||
@@ -420,7 +420,7 @@ mod test {
|
||||
"basic",
|
||||
[BasicProgram::<BincodeLegacy>::valid_test_case()],
|
||||
[
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input()
|
||||
]
|
||||
);
|
||||
@@ -434,7 +434,7 @@ mod test {
|
||||
"basic",
|
||||
[BasicProgram::<BincodeLegacy>::valid_test_case()],
|
||||
[
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input()
|
||||
]
|
||||
);
|
||||
@@ -448,7 +448,7 @@ mod test {
|
||||
"basic",
|
||||
[BasicProgram::<BincodeLegacy>::valid_test_case().into_output_sha256()],
|
||||
[
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input()
|
||||
]
|
||||
);
|
||||
@@ -462,7 +462,7 @@ mod test {
|
||||
"basic",
|
||||
[BasicProgram::<BincodeLegacy>::valid_test_case()],
|
||||
[
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input()
|
||||
]
|
||||
);
|
||||
@@ -476,7 +476,7 @@ mod test {
|
||||
"basic",
|
||||
[BasicProgram::<BincodeLegacy>::valid_test_case()],
|
||||
[
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input()
|
||||
]
|
||||
);
|
||||
@@ -490,7 +490,7 @@ mod test {
|
||||
"basic",
|
||||
[BasicProgram::<BincodeLegacy>::valid_test_case()],
|
||||
[
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input()
|
||||
]
|
||||
);
|
||||
@@ -504,7 +504,7 @@ mod test {
|
||||
"basic",
|
||||
[BasicProgram::<BincodeLegacy>::valid_test_case()],
|
||||
[
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input()
|
||||
]
|
||||
);
|
||||
@@ -518,7 +518,7 @@ mod test {
|
||||
"basic_rust",
|
||||
[BasicProgram::<BincodeLegacy>::valid_test_case()],
|
||||
[
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input()
|
||||
]
|
||||
);
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{error::Error, fmt::Debug};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod serde;
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pub use sha2::Sha256;
|
||||
@@ -84,7 +84,7 @@ impl<P: Program> Deref for ProgramTestCase<P> {
|
||||
|
||||
impl<P: Program> TestCase for ProgramTestCase<P> {
|
||||
fn input(&self) -> Input {
|
||||
Input::new(P::Io::serialize_input(&self.input).unwrap())
|
||||
Input::new().with_prefixed_stdin(P::Io::serialize_input(&self.input).unwrap())
|
||||
}
|
||||
|
||||
fn assert_output(&self, public_values: &[u8]) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod guest;
|
||||
pub mod program;
|
||||
|
||||
#[cfg(feature = "host")]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use ere_io::Io;
|
||||
use ere_platform_trait::Platform;
|
||||
use ere_platform_trait::{OutputHashedPlatform, Platform};
|
||||
use sha2::Sha256;
|
||||
|
||||
pub mod basic;
|
||||
|
||||
@@ -16,4 +17,8 @@ pub trait Program {
|
||||
let output_bytes = Self::Io::serialize_output(&output).unwrap();
|
||||
P::write_whole_output(&output_bytes);
|
||||
}
|
||||
|
||||
fn run_output_sha256<P: Platform>() {
|
||||
Self::run::<OutputHashedPlatform<P, Sha256>>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,20 @@
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{marker::PhantomData, ops::Deref};
|
||||
|
||||
pub mod output_hasher;
|
||||
pub use digest::Digest;
|
||||
|
||||
/// Platform dependent methods.
|
||||
pub trait Platform {
|
||||
/// Reads the whole input at once from host.
|
||||
///
|
||||
/// The stdin passed must have a LE u32 length prefix, because some zkVMs
|
||||
/// don't provide access to the stdin length.
|
||||
/// Use `Input::new().with_prefixed_stdin(stdin)` for convenience.
|
||||
///
|
||||
/// Note that this function should only be called once.
|
||||
fn read_whole_input() -> Vec<u8>;
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]>;
|
||||
|
||||
/// Writes the whole output at once to host.
|
||||
///
|
||||
@@ -54,3 +59,78 @@ pub trait Platform {
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for `Platform` implementation that hashes output before calling
|
||||
/// the inner `P::write_whole_output`.
|
||||
pub struct OutputHashedPlatform<P, D>(PhantomData<(P, D)>);
|
||||
|
||||
impl<P, D> Platform for OutputHashedPlatform<P, D>
|
||||
where
|
||||
P: Platform,
|
||||
D: Digest,
|
||||
{
|
||||
#[inline]
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
P::read_whole_input()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
P::write_whole_output(&D::digest(output));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn print(message: &str) {
|
||||
P::print(message);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cycle_count() -> u64 {
|
||||
P::cycle_count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cycle_scope_start(name: &str) {
|
||||
P::cycle_scope_start(name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cycle_scope_end(name: &str) {
|
||||
P::cycle_scope_end(name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cycle_scope<T>(name: &str, f: impl FnOnce() -> T) -> T {
|
||||
P::cycle_scope(name, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Stdin with a LE u32 length prefix.
|
||||
///
|
||||
/// Dereferencing it returns slice to the actual data.
|
||||
pub struct LengthPrefixedStdin(Vec<u8>);
|
||||
|
||||
impl Deref for LengthPrefixedStdin {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0[4..]
|
||||
}
|
||||
}
|
||||
|
||||
impl LengthPrefixedStdin {
|
||||
pub fn new(stdin: Vec<u8>) -> Self {
|
||||
assert!(
|
||||
stdin.len() >= 4,
|
||||
"stdin must have a LE u32 length prefix; use Input::with_prefixed_length(stdin) on the host side"
|
||||
);
|
||||
let len = u32::from_le_bytes(stdin[..4].try_into().unwrap()) as usize;
|
||||
assert_eq!(
|
||||
len,
|
||||
stdin.len() - 4,
|
||||
"Length mismatch: stdin length prefix indicated {len} bytes, but got {} bytes; use Input::with_prefixed_length(stdin) on the host side",
|
||||
stdin.len() - 4
|
||||
);
|
||||
Self(stdin)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
use core::{marker::PhantomData, ops::Deref};
|
||||
use digest::{
|
||||
Digest, Output, OutputSizeUser,
|
||||
generic_array::{ArrayLength, GenericArray},
|
||||
};
|
||||
|
||||
pub use digest;
|
||||
|
||||
/// A hasher that given the output, returns a hash of it.
|
||||
pub trait OutputHasher {
|
||||
type Hash<'a>: Deref<Target = [u8]>;
|
||||
|
||||
fn output_hash(output: &[u8]) -> Self::Hash<'_>;
|
||||
}
|
||||
|
||||
/// A hasher that given the output, returns a fixed-size hash of it.
|
||||
pub trait FixedOutputHasher: OutputHasher + OutputSizeUser {}
|
||||
|
||||
impl<T: OutputHasher + OutputSizeUser> FixedOutputHasher for T {}
|
||||
|
||||
/// A marker used to mark [`IdentityOutput`] to accept unsized output.
|
||||
pub struct Unsized;
|
||||
|
||||
/// [`OutputHasher`] implementation that returns output as is.
|
||||
///
|
||||
/// By setting generic `U = Unsized` it takes output with any size.
|
||||
///
|
||||
/// By setting generic `U = typenum::U{SIZE}` it expects the output to match
|
||||
/// the `SIZE`.
|
||||
pub struct IdentityOutput<U = Unsized>(PhantomData<U>);
|
||||
|
||||
impl OutputHasher for IdentityOutput<Unsized> {
|
||||
type Hash<'a> = &'a [u8];
|
||||
|
||||
fn output_hash(output: &[u8]) -> Self::Hash<'_> {
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl<U: ArrayLength<u8> + 'static> OutputSizeUser for IdentityOutput<U> {
|
||||
type OutputSize = U;
|
||||
}
|
||||
|
||||
impl<U: ArrayLength<u8> + 'static> OutputHasher for IdentityOutput<U> {
|
||||
type Hash<'a> = GenericArray<u8, U>;
|
||||
|
||||
fn output_hash(output: &[u8]) -> Self::Hash<'_> {
|
||||
assert!(
|
||||
output.len() == Self::output_size(),
|
||||
"output length should be equal to {}",
|
||||
Self::output_size()
|
||||
);
|
||||
let mut hash = Output::<Self>::default();
|
||||
hash.copy_from_slice(output);
|
||||
hash
|
||||
}
|
||||
}
|
||||
|
||||
/// [`OutputHasher`] implementation that returns output with 0s padding.
|
||||
///
|
||||
/// By setting generic `U = typenum::U{SIZE}` it expects the output to be less
|
||||
/// than or equal to the `SIZE`.
|
||||
pub struct PaddedOutput<U>(PhantomData<U>);
|
||||
|
||||
impl<U: ArrayLength<u8> + 'static> OutputSizeUser for PaddedOutput<U> {
|
||||
type OutputSize = U;
|
||||
}
|
||||
|
||||
impl<U: ArrayLength<u8> + 'static> OutputHasher for PaddedOutput<U> {
|
||||
type Hash<'a> = GenericArray<u8, U>;
|
||||
|
||||
fn output_hash(output: &[u8]) -> Self::Hash<'_> {
|
||||
assert!(
|
||||
output.len() <= Self::output_size(),
|
||||
"output length should be less than or equal to {}",
|
||||
Self::output_size()
|
||||
);
|
||||
let mut hash = Output::<Self>::default();
|
||||
hash[..output.len()].copy_from_slice(output);
|
||||
hash
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Digest> OutputHasher for D {
|
||||
type Hash<'a> = Output<D>;
|
||||
|
||||
fn output_hash(output: &[u8]) -> Self::Hash<'_> {
|
||||
D::digest(output)
|
||||
}
|
||||
}
|
||||
@@ -22,10 +22,10 @@ pub struct Input {
|
||||
}
|
||||
|
||||
impl Input {
|
||||
/// Creates a new `Input` with the given stdin.
|
||||
pub fn new(stdin: Vec<u8>) -> Self {
|
||||
/// Creates a new `Input` with the empty stdin.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
stdin,
|
||||
stdin: Vec::new(),
|
||||
proofs: None,
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,23 @@ impl Input {
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets stdin and returns a new `Input`.
|
||||
pub fn with_stdin(mut self, stdin: Vec<u8>) -> Self {
|
||||
self.stdin = stdin;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets stdin with a LE u32 length prefix and returns a new `Input`.
|
||||
///
|
||||
/// The `Platform::read_whole_input` requires stdin to have a LE u32 length
|
||||
/// prefix for efficiency reason.
|
||||
pub fn with_prefixed_stdin(mut self, stdin: Vec<u8>) -> Self {
|
||||
self.stdin = Vec::with_capacity(4 + stdin.len());
|
||||
self.stdin.extend((stdin.len() as u32).to_le_bytes());
|
||||
self.stdin.extend(stdin);
|
||||
self
|
||||
}
|
||||
|
||||
/// Serializes the given proofs and returns a new `Input` with them set.
|
||||
///
|
||||
/// Consumes `self` and returns an error if serialization fails.
|
||||
|
||||
@@ -3,42 +3,39 @@
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{array, iter::repeat_with, marker::PhantomData};
|
||||
use ere_platform_trait::output_hasher::FixedOutputHasher;
|
||||
use core::{array, iter::repeat_with, ops::Deref};
|
||||
|
||||
pub use airbender_riscv_common as riscv_common;
|
||||
pub use ere_platform_trait::{
|
||||
Platform,
|
||||
output_hasher::{IdentityOutput, PaddedOutput, digest::typenum::U32},
|
||||
};
|
||||
pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
|
||||
|
||||
/// Airbender [`Platform`] implementation.
|
||||
///
|
||||
/// Because Airbender only support public values up to 32 bytes, so
|
||||
/// - If the guest has output bytes more than 32 bytes, it should use a
|
||||
/// cryptographic hash function for the generic `H` (for example `Sha256`).
|
||||
/// - If the guest has output bytes less than 32 bytes, it should use
|
||||
/// [`PaddedOutput`] for the generic `H`
|
||||
pub struct AirbenderPlatform<H>(PhantomData<H>);
|
||||
/// Note that the maximum output size is 32 bytes, and output less than 32
|
||||
/// bytes will be padded to 32 bytes.
|
||||
pub struct AirbenderPlatform;
|
||||
|
||||
impl<H: FixedOutputHasher<OutputSize = U32>> Platform for AirbenderPlatform<H> {
|
||||
fn read_whole_input() -> Vec<u8> {
|
||||
impl Platform for AirbenderPlatform {
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
let len = riscv_common::csr_read_word() as usize;
|
||||
repeat_with(riscv_common::csr_read_word)
|
||||
.take(len.div_ceil(4))
|
||||
.flat_map(u32::to_le_bytes)
|
||||
.take(len)
|
||||
.collect()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
let hash = H::output_hash(output);
|
||||
let words = array::from_fn(|i| u32::from_le_bytes(array::from_fn(|j| hash[4 * i + j])));
|
||||
assert!(
|
||||
output.len() <= 32,
|
||||
"Maximum output size is 32 bytes, got {} bytes",
|
||||
output.len()
|
||||
);
|
||||
let words = array::from_fn(|i| u32::from_le_bytes(array::from_fn(|j| output[4 * i + j])));
|
||||
riscv_common::zksync_os_finish_success(&words);
|
||||
}
|
||||
|
||||
fn print(message: &str) {
|
||||
fn print(_message: &str) {
|
||||
#[cfg(feature = "uart")]
|
||||
core::fmt::Write::write_str(&mut riscv_common::QuasiUART::new(), message).unwrap();
|
||||
core::fmt::Write::write_str(&mut riscv_common::QuasiUART::new(), _message).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,48 @@
|
||||
//! Airbender [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # Requirements
|
||||
//!
|
||||
//! To install all requirements, run [`install_airbender_sdk.sh`] from the Ere
|
||||
//! repository at the same git revision as your `ere-airbender` dependency.
|
||||
//!
|
||||
//! To install `airbender-cli` with GPU proving support, make sure CUDA 12.9 is
|
||||
//! installed, and run [`install_airbender_sdk.sh`] with env `CUDA=1` set.
|
||||
//!
|
||||
//! ## `Compiler` requirements
|
||||
//!
|
||||
//! The `Compiler` implementation requires external tools installed and
|
||||
//! available in `PATH`:
|
||||
//!
|
||||
//! - `rust-objcopy` - Used by compiler to convert ELF to binary
|
||||
//!
|
||||
//! ## `zkVM` requirements
|
||||
//!
|
||||
//! The `zkVM` implementation requires external tools installed and available in
|
||||
//! `PATH`:
|
||||
//!
|
||||
//! - Installation via [`install_airbender_sdk.sh`] - `airbender-cli` used by
|
||||
//! `zkVM::execute` and `zkVM::prove`
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target |
|
||||
//! | ------------- | :------: | ----------------------------- |
|
||||
//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | Yes |
|
||||
//! | `Network` | No |
|
||||
//!
|
||||
//! [`install_airbender_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_airbender_sdk.sh
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -149,7 +149,7 @@ mod tests {
|
||||
let zkvm = EreAirbender::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.execute(&input).unwrap_err();
|
||||
@@ -171,7 +171,7 @@ mod tests {
|
||||
let zkvm = EreAirbender::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
|
||||
@@ -4,7 +4,7 @@ use airbender_execution_utils::{
|
||||
universal_circuit_verifier_vk, verify_recursion_log_23_layer,
|
||||
};
|
||||
use ere_zkvm_interface::zkvm::{CommonError, PublicValues};
|
||||
use std::{array, fs, io::BufRead, iter, process::Command};
|
||||
use std::{array, fs, io::BufRead, process::Command};
|
||||
use tempfile::tempdir;
|
||||
|
||||
/// Verification key hash chain.
|
||||
@@ -217,8 +217,8 @@ impl AirbenderSdk {
|
||||
|
||||
/// Encode input with length prefixed to hex string for `airbender-cli`.
|
||||
fn encode_input(input: &[u8]) -> String {
|
||||
iter::once((input.len() as u32).to_le_bytes().as_slice())
|
||||
.chain(input.chunks(4))
|
||||
input
|
||||
.chunks(4)
|
||||
.map(|chunk| {
|
||||
let mut bytes = [0u8; 4];
|
||||
bytes[..chunk.len()].copy_from_slice(chunk);
|
||||
|
||||
@@ -2,14 +2,9 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{marker::PhantomData, slice};
|
||||
use ere_platform_trait::output_hasher::OutputHasher;
|
||||
use core::{marker::PhantomData, ops::Deref};
|
||||
|
||||
pub use ere_platform_trait::{
|
||||
Platform,
|
||||
output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
|
||||
};
|
||||
pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
|
||||
pub use jolt_sdk as jolt;
|
||||
|
||||
// FIXME: Because the crate `jolt-common` is not `no_std` compatible, so we have
|
||||
@@ -70,30 +65,37 @@ impl JoltMemoryConfig for DefaulJoltMemoryConfig {
|
||||
}
|
||||
|
||||
/// Jolt [`Platform`] implementation.
|
||||
pub struct JoltPlatform<C = DefaulJoltMemoryConfig, H = IdentityOutput>(PhantomData<(C, H)>);
|
||||
pub struct JoltPlatform<C = DefaulJoltMemoryConfig>(PhantomData<C>);
|
||||
|
||||
impl<C: JoltMemoryConfig, H: OutputHasher> Platform for JoltPlatform<C, H> {
|
||||
fn read_whole_input() -> Vec<u8> {
|
||||
impl<C: JoltMemoryConfig> Platform for JoltPlatform<C> {
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
let memory_layout = C::memory_layout();
|
||||
let input_ptr = memory_layout.input_start as *const u8;
|
||||
let max_input_len = memory_layout.max_input_size as usize;
|
||||
let input_slice = unsafe { slice::from_raw_parts(input_ptr, max_input_len) };
|
||||
let (input, _) = jolt::postcard::take_from_bytes(input_slice).unwrap();
|
||||
input
|
||||
assert!(max_input_len > 4);
|
||||
let len_bytes = unsafe { core::slice::from_raw_parts(input_ptr, 4) };
|
||||
let len = u32::from_le_bytes(len_bytes.try_into().unwrap()) as usize;
|
||||
assert!(
|
||||
len <= max_input_len - 4,
|
||||
"Maximum input size is {} bytes, got {len}",
|
||||
max_input_len - 4,
|
||||
);
|
||||
unsafe { core::slice::from_raw_parts(input_ptr.add(4), len) }.to_vec()
|
||||
}
|
||||
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
let hash = H::output_hash(output);
|
||||
let memory_layout = C::memory_layout();
|
||||
let output_ptr = memory_layout.output_start as *mut u8;
|
||||
let max_output_len = memory_layout.max_output_size as usize;
|
||||
let output_slice = unsafe { core::slice::from_raw_parts_mut(output_ptr, max_output_len) };
|
||||
jolt::postcard::to_slice(&*hash, output_slice).unwrap_or_else(|err| match err {
|
||||
jolt::postcard::Error::SerializeBufferFull => {
|
||||
panic!("Maximum output size is {max_output_len} bytes")
|
||||
}
|
||||
err => panic!("`postcard::to_slice` failed: {err:?}"),
|
||||
});
|
||||
let len = output.len();
|
||||
assert!(
|
||||
len <= max_output_len - 4,
|
||||
"Maximum output size is {} bytes, got {len}",
|
||||
max_output_len - 4,
|
||||
);
|
||||
let output_slice = unsafe { core::slice::from_raw_parts_mut(output_ptr, len + 4) };
|
||||
output_slice[..4].copy_from_slice(&(output.len() as u32).to_le_bytes());
|
||||
output_slice[4..].copy_from_slice(&output);
|
||||
}
|
||||
|
||||
fn print(message: &str) {
|
||||
|
||||
@@ -78,6 +78,6 @@ mod tests {
|
||||
let program = RustRv64imac.compile(&guest_directory).unwrap();
|
||||
let zkvm = EreJolt::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
zkvm.execute(&Input::default()).unwrap();
|
||||
zkvm.execute(&Input::new()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,36 @@
|
||||
//! Jolt [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # Requirements
|
||||
//!
|
||||
//! To install all requirements, run [`install_jolt_sdk.sh`] from the Ere
|
||||
//! repository at the same git revision as your `ere-jolt` dependency.
|
||||
//!
|
||||
//! ## `Compiler` requirements
|
||||
//!
|
||||
//! - `jolt`
|
||||
//! - Install custom Rust toolchain via `jolt install-toolchain` - Used by `RustRv64imaCustomized`
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target | Note |
|
||||
//! | ------------------------- | :------: | ------------------------------ | ------------------ |
|
||||
//! | `RustRv64imacCustomized` | Rust | `riscv64imac-jolt-zkvm-elf` | With `std` support |
|
||||
//! | `RustRv64imac` | Rust | `riscv64imac-unknown-none-elf` | |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | No |
|
||||
//! | `Network` | No |
|
||||
//!
|
||||
//! [`install_jolt_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_jolt_sdk.sh
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -153,7 +153,7 @@ mod tests {
|
||||
let zkvm = EreJolt::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.execute(&input).unwrap_err();
|
||||
@@ -179,7 +179,7 @@ mod tests {
|
||||
let _guard = PROVE_LOCK.lock().unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
|
||||
@@ -7,6 +7,9 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
CommonError(#[from] CommonError),
|
||||
|
||||
#[error("Output is expected to have length prefix")]
|
||||
InvalidOutput,
|
||||
|
||||
// Execute
|
||||
#[error("Execution panics")]
|
||||
ExecutionPanic,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::zkvm::Error;
|
||||
use core::cmp::min;
|
||||
use ere_zkvm_interface::zkvm::{CommonError, PublicValues};
|
||||
use core::{array::from_fn, cmp::min};
|
||||
use ere_zkvm_interface::zkvm::PublicValues;
|
||||
use jolt_ark_serialize::{self as ark_serialize, CanonicalDeserialize, CanonicalSerialize};
|
||||
use jolt_common::constants::{
|
||||
DEFAULT_MAX_INPUT_SIZE, DEFAULT_MAX_OUTPUT_SIZE, DEFAULT_MAX_TRACE_LENGTH, DEFAULT_MEMORY_SIZE,
|
||||
@@ -14,7 +14,6 @@ use jolt_sdk::{
|
||||
F, Jolt, JoltDevice, JoltProverPreprocessing, JoltRV64IMAC, JoltVerifierPreprocessing,
|
||||
MemoryConfig, MemoryLayout, PCS,
|
||||
guest::program::{decode, trace},
|
||||
postcard,
|
||||
};
|
||||
|
||||
#[derive(CanonicalSerialize, CanonicalDeserialize)]
|
||||
@@ -64,25 +63,20 @@ impl JoltSdk {
|
||||
}
|
||||
|
||||
pub fn execute(&self, input: &[u8]) -> Result<(PublicValues, u64), Error> {
|
||||
let (cycles, _, io) = trace(
|
||||
&self.elf,
|
||||
None,
|
||||
&serialize_input(input)?,
|
||||
&self.memory_config,
|
||||
);
|
||||
let (cycles, _, io) = trace(&self.elf, None, input, &self.memory_config);
|
||||
if io.panic {
|
||||
return Err(Error::ExecutionPanic);
|
||||
}
|
||||
let public_values = deserialize_output(&io.outputs)?;
|
||||
let public_values = extract_public_values(&io.outputs)?;
|
||||
Ok((public_values, cycles.len() as _))
|
||||
}
|
||||
|
||||
pub fn prove(&self, input: &[u8]) -> Result<(PublicValues, JoltProof), Error> {
|
||||
let (proof, io, _) = JoltRV64IMAC::prove(&self.pk, &self.elf, &serialize_input(input)?);
|
||||
let (proof, io, _) = JoltRV64IMAC::prove(&self.pk, &self.elf, input);
|
||||
if io.panic {
|
||||
return Err(Error::ExecutionPanic);
|
||||
}
|
||||
let public_values = deserialize_output(&io.outputs)?;
|
||||
let public_values = extract_public_values(&io.outputs)?;
|
||||
let proof = JoltProof {
|
||||
proof,
|
||||
inputs: io.inputs,
|
||||
@@ -103,28 +97,26 @@ impl JoltSdk {
|
||||
},
|
||||
None,
|
||||
)?;
|
||||
let public_values = deserialize_output(&proof.outputs)?;
|
||||
let public_values = extract_public_values(&proof.outputs)?;
|
||||
Ok(public_values)
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_input(bytes: &[u8]) -> Result<Vec<u8>, Error> {
|
||||
Ok(postcard::to_stdvec(bytes)
|
||||
.map_err(|err| CommonError::serialize("input", "postcard", err))?)
|
||||
}
|
||||
|
||||
fn deserialize_output(output: &[u8]) -> Result<Vec<u8>, Error> {
|
||||
// Note taht for execute the bytes are padded to size of multiple of 8, but for
|
||||
// prove the bytes are truncated.
|
||||
fn extract_public_values(output: &[u8]) -> Result<Vec<u8>, Error> {
|
||||
Ok(if output.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
let (len, bytes) = postcard::take_from_bytes::<u64>(output)
|
||||
.map_err(|err| CommonError::deserialize("output", "postcard", err))?;
|
||||
let mut output = vec![0; len as usize];
|
||||
// For execute the bytes are padded to size of multiple of 8, but for
|
||||
// prove the bytes are truncated if there are trailing zeros, so here we
|
||||
// take the min.
|
||||
let len = min(bytes.len(), output.len());
|
||||
output[..len].copy_from_slice(&bytes[..len]);
|
||||
output
|
||||
let len = u32::from_le_bytes(from_fn(|i| output.get(i).copied().unwrap_or(0))) as usize;
|
||||
if output.len() > (len + 4).next_multiple_of(8) {
|
||||
return Err(Error::InvalidOutput);
|
||||
}
|
||||
let mut public_values = vec![0; len];
|
||||
if let Some((_, output)) = output.split_at_checked(4) {
|
||||
let len = min(len, output.len());
|
||||
public_values[..len].copy_from_slice(&output[..len]);
|
||||
}
|
||||
public_values
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
//! Miden [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target |
|
||||
//! | ---------- | :------------: | ---------- |
|
||||
//! | `MidenAsm` | Miden Assembly | Miden MAST |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | No |
|
||||
//! | `Network` | No |
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -175,7 +175,7 @@ pub fn felts_to_bytes(felts: &[Felt]) -> Vec<u8> {
|
||||
|
||||
/// Convert bytes into Miden field elements.
|
||||
pub fn bytes_to_felts(bytes: &[u8]) -> Result<Vec<Felt>, Error> {
|
||||
if bytes.len() % 8 != 0 {
|
||||
if !bytes.len().is_multiple_of(8) {
|
||||
let err = anyhow::anyhow!(
|
||||
"Invalid bytes length {}, expected multiple of 8",
|
||||
bytes.len()
|
||||
@@ -218,11 +218,11 @@ mod tests {
|
||||
let const_b = Felt::ONE / Felt::ONE.double();
|
||||
let expected_sum = const_a + const_b;
|
||||
|
||||
let input = felts_to_bytes(&[const_a, const_b]);
|
||||
let stdin = felts_to_bytes(&[const_a, const_b]);
|
||||
|
||||
// Prove
|
||||
let (prover_public_values, proof, _) = zkvm
|
||||
.prove(&Input::new(input), ProofKind::default())
|
||||
.prove(&Input::new().with_stdin(stdin), ProofKind::default())
|
||||
.unwrap();
|
||||
|
||||
// Verify
|
||||
@@ -242,11 +242,11 @@ mod tests {
|
||||
let n_iterations = 50u32;
|
||||
let expected_fib = Felt::try_from(12_586_269_025u64).unwrap();
|
||||
|
||||
let input = felts_to_bytes(&[Felt::from(0u32), Felt::from(1u32), Felt::from(n_iterations)]);
|
||||
let stdin = felts_to_bytes(&[Felt::from(0u32), Felt::from(1u32), Felt::from(n_iterations)]);
|
||||
|
||||
// Prove
|
||||
let (prover_public_values, proof, _) = zkvm
|
||||
.prove(&Input::new(input), ProofKind::default())
|
||||
.prove(&Input::new().with_stdin(stdin), ProofKind::default())
|
||||
.unwrap();
|
||||
|
||||
// Verify
|
||||
@@ -263,10 +263,10 @@ mod tests {
|
||||
let program = load_miden_program("add");
|
||||
let zkvm = EreMiden::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
let empty_inputs = Input::new(Vec::new());
|
||||
let empty_inputs = Input::new();
|
||||
assert!(zkvm.execute(&empty_inputs).is_err());
|
||||
|
||||
let insufficient_inputs = Input::new(felts_to_bytes(&[Felt::from(5u32)]));
|
||||
let insufficient_inputs = Input::new().with_stdin(felts_to_bytes(&[Felt::from(5u32)]));
|
||||
assert!(zkvm.execute(&insufficient_inputs).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,27 +2,22 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
use ere_platform_trait::output_hasher::OutputHasher;
|
||||
use core::ops::Deref;
|
||||
use ere_platform_trait::LengthPrefixedStdin;
|
||||
|
||||
pub use ere_platform_trait::{
|
||||
Platform,
|
||||
output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
|
||||
};
|
||||
pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
|
||||
pub use nexus_rt;
|
||||
|
||||
/// Nexus [`Platform`] implementation.
|
||||
pub struct NexusPlatform<H = IdentityOutput>(PhantomData<H>);
|
||||
pub struct NexusPlatform;
|
||||
|
||||
impl<H: OutputHasher> Platform for NexusPlatform<H> {
|
||||
fn read_whole_input() -> Vec<u8> {
|
||||
nexus_rt::read_private_input().unwrap()
|
||||
impl Platform for NexusPlatform {
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
LengthPrefixedStdin::new(nexus_rt::read_private_input().unwrap())
|
||||
}
|
||||
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
let hash = H::output_hash(output);
|
||||
nexus_rt::write_public_output(&*hash).unwrap()
|
||||
nexus_rt::write_public_output(output).unwrap()
|
||||
}
|
||||
|
||||
fn print(message: &str) {
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
//! Nexus [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target |
|
||||
//! | ------------ | :------: | --------------------------- |
|
||||
//! | `RustRv32i` | Rust | `riscv32i-unknown-none-elf` |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | No |
|
||||
//! | `Network` | No |
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -205,7 +205,7 @@ mod tests {
|
||||
let zkvm = EreNexus::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.execute(&input).unwrap_err();
|
||||
@@ -227,7 +227,7 @@ mod tests {
|
||||
let zkvm = EreNexus::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
|
||||
@@ -2,33 +2,30 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{marker::PhantomData, ops::Deref};
|
||||
use ere_platform_trait::output_hasher::FixedOutputHasher;
|
||||
use core::{array::from_fn, ops::Deref};
|
||||
use ere_platform_trait::LengthPrefixedStdin;
|
||||
|
||||
pub use ere_platform_trait::{
|
||||
Platform,
|
||||
output_hasher::{IdentityOutput, PaddedOutput, digest::typenum::U32},
|
||||
};
|
||||
pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
|
||||
pub use openvm;
|
||||
|
||||
/// OpenVM [`Platform`] implementation.
|
||||
///
|
||||
/// Because OpenVM only support public values up to 32 bytes, so
|
||||
/// - If the guest has output bytes more than 32 bytes, it should use a
|
||||
/// cryptographic hash function for the generic `H` (for example `Sha256`).
|
||||
/// - If the guest has output bytes less than 32 bytes, it should use
|
||||
/// [`PaddedOutput`] for the generic `H`
|
||||
pub struct OpenVMPlatform<H>(PhantomData<H>);
|
||||
/// Note that the maximum output size is 32 bytes, and output less than 32
|
||||
/// bytes will be padded to 32 bytes.
|
||||
pub struct OpenVMPlatform;
|
||||
|
||||
impl<H: FixedOutputHasher<OutputSize = U32>> Platform for OpenVMPlatform<H> {
|
||||
fn read_whole_input() -> Vec<u8> {
|
||||
openvm::io::read_vec()
|
||||
impl Platform for OpenVMPlatform {
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
LengthPrefixedStdin::new(openvm::io::read_vec())
|
||||
}
|
||||
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
let hash = H::output_hash(output).deref().try_into().unwrap();
|
||||
openvm::io::reveal_bytes32(hash);
|
||||
assert!(
|
||||
output.len() <= 32,
|
||||
"Maximum output size is 32 bytes, got {} bytes",
|
||||
output.len()
|
||||
);
|
||||
openvm::io::reveal_bytes32(from_fn(|i| output.get(i).copied().unwrap_or(0)));
|
||||
}
|
||||
|
||||
fn print(message: &str) {
|
||||
|
||||
@@ -79,6 +79,6 @@ mod tests {
|
||||
let program = RustRv32ima.compile(&guest_directory).unwrap();
|
||||
let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
zkvm.execute(&Input::default()).unwrap();
|
||||
zkvm.execute(&Input::new()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,40 @@
|
||||
//! OpenVM [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # Requirements
|
||||
//!
|
||||
//! To install all requirements, run [`install_openvm_sdk.sh`] from the Ere
|
||||
//! repository at the same git revision as your `ere-openvm` dependency.
|
||||
//!
|
||||
//! To use with GPU proving support, make sure CUDA 12.9 is installed, and turn
|
||||
//! on the `cuda` feature.
|
||||
//!
|
||||
//! ## `zkVM` requirements
|
||||
//!
|
||||
//! - `cargo-openvm`
|
||||
//! - Setup via `cargo openvm setup` - Setup aggregation keys used by
|
||||
//! `zkVM::prove`
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target | Note |
|
||||
//! | ----------------------- | :------: | ----------------------------- | ------------------ |
|
||||
//! | `RustRv32imaCustomized` | Rust | `riscv32im-risc0-zkvm-elf` | With `std` support |
|
||||
//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` | |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | Yes |
|
||||
//! | `Network` | No |
|
||||
//!
|
||||
//! [`install_openvm_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_openvm_sdk.sh
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -292,7 +292,7 @@ mod tests {
|
||||
let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.execute(&input).unwrap_err();
|
||||
@@ -314,7 +314,7 @@ mod tests {
|
||||
let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
|
||||
@@ -2,27 +2,23 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{format, vec::Vec};
|
||||
use core::marker::PhantomData;
|
||||
use ere_platform_trait::output_hasher::OutputHasher;
|
||||
use alloc::format;
|
||||
use core::ops::Deref;
|
||||
use ere_platform_trait::LengthPrefixedStdin;
|
||||
|
||||
pub use ere_platform_trait::{
|
||||
Platform,
|
||||
output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
|
||||
};
|
||||
pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
|
||||
pub use pico_sdk;
|
||||
|
||||
/// Pico [`Platform`] implementation.
|
||||
pub struct PicoPlatform<H = IdentityOutput>(PhantomData<H>);
|
||||
pub struct PicoPlatform;
|
||||
|
||||
impl<H: OutputHasher> Platform for PicoPlatform<H> {
|
||||
fn read_whole_input() -> Vec<u8> {
|
||||
pico_sdk::io::read_vec()
|
||||
impl Platform for PicoPlatform {
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
LengthPrefixedStdin::new(pico_sdk::io::read_vec())
|
||||
}
|
||||
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
let hash = H::output_hash(output);
|
||||
pico_sdk::io::commit_bytes(&hash);
|
||||
pico_sdk::io::commit_bytes(output);
|
||||
}
|
||||
|
||||
fn print(message: &str) {
|
||||
|
||||
@@ -70,6 +70,6 @@ mod tests {
|
||||
let program = RustRv32ima.compile(&guest_directory).unwrap();
|
||||
let zkvm = ErePico::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
zkvm.execute(&Input::default()).unwrap();
|
||||
zkvm.execute(&Input::new()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,35 @@
|
||||
//! Pico [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # Requirements
|
||||
//!
|
||||
//! To install all requirements, run [`install_pico_sdk.sh`] from the Ere
|
||||
//! repository at the same git revision as your `ere-pico` dependency.
|
||||
//!
|
||||
//! ## `Compiler` requirements
|
||||
//!
|
||||
//! - `cargo-pico` - Used by `RustRv32imaCustomized`
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target | Note |
|
||||
//! | ----------------------- | :------: | ----------------------------- | ------------------ |
|
||||
//! | `RustRv32imaCustomized` | Rust | `riscv32im-risc0-zkvm-elf` | With `std` support |
|
||||
//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` | |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | No |
|
||||
//! | `Network` | No |
|
||||
//!
|
||||
//! [`install_pico_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_pico_sdk.sh
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -225,7 +225,7 @@ mod tests {
|
||||
let zkvm = ErePico::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.execute(&input).unwrap_err();
|
||||
@@ -247,7 +247,7 @@ mod tests {
|
||||
let zkvm = ErePico::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
|
||||
@@ -2,35 +2,30 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{vec, vec::Vec};
|
||||
use core::marker::PhantomData;
|
||||
use ere_platform_trait::output_hasher::OutputHasher;
|
||||
use alloc::vec;
|
||||
use core::{ops::Deref, slice};
|
||||
use risc0_zkvm::guest::env::Write;
|
||||
|
||||
pub use ere_platform_trait::{
|
||||
Platform,
|
||||
output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
|
||||
};
|
||||
pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
|
||||
pub use risc0_zkvm;
|
||||
|
||||
/// Risc0 [`Platform`] implementation.
|
||||
pub struct Risc0Platform<H = IdentityOutput>(PhantomData<H>);
|
||||
pub struct Risc0Platform;
|
||||
|
||||
impl<H: OutputHasher> Platform for Risc0Platform<H> {
|
||||
fn read_whole_input() -> Vec<u8> {
|
||||
impl Platform for Risc0Platform {
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
let len = {
|
||||
let mut bytes = [0; 4];
|
||||
risc0_zkvm::guest::env::read_slice(&mut bytes);
|
||||
u32::from_le_bytes(bytes)
|
||||
u32::from_le_bytes(bytes) as usize
|
||||
};
|
||||
let mut input = vec![0u8; len as usize];
|
||||
let mut input = vec![0u8; len];
|
||||
risc0_zkvm::guest::env::read_slice(&mut input);
|
||||
input
|
||||
}
|
||||
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
let hash = H::output_hash(output);
|
||||
risc0_zkvm::guest::env::commit_slice(&hash);
|
||||
risc0_zkvm::guest::env::commit_slice(output);
|
||||
}
|
||||
|
||||
fn print(message: &str) {
|
||||
|
||||
@@ -82,6 +82,6 @@ mod tests {
|
||||
let program = RustRv32ima.compile(&guest_directory).unwrap();
|
||||
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
zkvm.execute(&Input::default()).unwrap();
|
||||
zkvm.execute(&Input::new()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,48 @@
|
||||
//! Risc0 [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # Requirements
|
||||
//!
|
||||
//! To install all requirements, run [`install_risc0_sdk.sh`] from the Ere
|
||||
//! repository at the same git revision as your `ere-risc0` dependency.
|
||||
//!
|
||||
//! To install `r0vm-cuda` (with GPU proving support), make sure CUDA 12.9 is
|
||||
//! installed, run [`install_risc0_sdk.sh`] with env `CUDA=1` set.
|
||||
//!
|
||||
//! ## `Compiler` requirements
|
||||
//!
|
||||
//! - [`rzup`]
|
||||
//! - Installation via `rzup install` - Custom Rust toolchain used by `RustRv32imaCustomized`
|
||||
//!
|
||||
//! ## `zkVM` requirements
|
||||
//!
|
||||
//! - [`rzup`]
|
||||
//! - Installation via `rzup install`
|
||||
//! - `r0vm-cuda` - Used by `zkVM::prove` if `ProverResourceType::Gpu` is
|
||||
//! selected
|
||||
//! - `docker` - Used by `zkVM::prove` if `ProofKind::Groth16` is selected
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target | Note |
|
||||
//! | ----------------------- | :------: | ----------------------------- | ------------------ |
|
||||
//! | `RustRv32imaCustomized` | Rust | `riscv32im-risc0-zkvm-elf` | With `std` support |
|
||||
//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` | |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | Yes |
|
||||
//! | `Network` | No |
|
||||
//!
|
||||
//! [`install_risc0_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_risc0_sdk.sh
|
||||
//! [`rzup`]: https://risczero.com/install
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -213,8 +213,7 @@ impl EreRisc0 {
|
||||
env.segment_limit_po2(self.segment_po2 as _)
|
||||
.keccak_max_po2(self.keccak_po2 as _)
|
||||
.expect("keccak_po2 in valid range");
|
||||
env.write_slice(&(input.stdin().len() as u32).to_le_bytes())
|
||||
.write_slice(input.stdin());
|
||||
env.write_slice(input.stdin());
|
||||
if let Some(receipts) = input.proofs() {
|
||||
for receipt in receipts.map_err(Error::DeserializeInputProofs)? {
|
||||
env.add_assumption(AssumptionReceipt::Proven(receipt));
|
||||
@@ -265,7 +264,7 @@ mod tests {
|
||||
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.execute(&input).unwrap_err();
|
||||
@@ -287,7 +286,7 @@ mod tests {
|
||||
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
@@ -303,7 +302,7 @@ mod tests {
|
||||
for i in 1..=16_u32 {
|
||||
let zkvm = EreRisc0::new(program.clone(), ProverResourceType::Cpu).unwrap();
|
||||
|
||||
let input = Input::new(i.to_le_bytes().to_vec());
|
||||
let input = Input::new().with_stdin(i.to_le_bytes().to_vec());
|
||||
|
||||
if i.is_power_of_two() {
|
||||
zkvm.execute(&input)
|
||||
|
||||
@@ -2,27 +2,23 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{format, vec::Vec};
|
||||
use core::marker::PhantomData;
|
||||
use ere_platform_trait::output_hasher::OutputHasher;
|
||||
use alloc::format;
|
||||
use core::ops::Deref;
|
||||
use ere_platform_trait::LengthPrefixedStdin;
|
||||
|
||||
pub use ere_platform_trait::{
|
||||
Platform,
|
||||
output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
|
||||
};
|
||||
pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
|
||||
pub use sp1_zkvm;
|
||||
|
||||
/// SP1 [`Platform`] implementation.
|
||||
pub struct SP1Platform<H = IdentityOutput>(PhantomData<H>);
|
||||
pub struct SP1Platform;
|
||||
|
||||
impl<H: OutputHasher> Platform for SP1Platform<H> {
|
||||
fn read_whole_input() -> Vec<u8> {
|
||||
sp1_zkvm::io::read_vec()
|
||||
impl Platform for SP1Platform {
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
LengthPrefixedStdin::new(sp1_zkvm::io::read_vec())
|
||||
}
|
||||
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
let hash = H::output_hash(output);
|
||||
sp1_zkvm::io::commit_slice(&hash);
|
||||
sp1_zkvm::io::commit_slice(output);
|
||||
}
|
||||
|
||||
fn print(message: &str) {
|
||||
|
||||
@@ -70,6 +70,6 @@ mod tests {
|
||||
let program = RustRv32ima.compile(&guest_directory).unwrap();
|
||||
let zkvm = EreSP1::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
zkvm.execute(&Input::default()).unwrap();
|
||||
zkvm.execute(&Input::new()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,41 @@
|
||||
//! SP1 [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # Requirements
|
||||
//!
|
||||
//! To install all requirements, run [`install_sp1_sdk.sh`] from the Ere
|
||||
//! repository at the same git revision as your `ere-sp1` dependency.
|
||||
//!
|
||||
//! ## `Compiler` requirements
|
||||
//!
|
||||
//! - Installation via [`sp1up`] - Custom Rust toolchain used by `RustRv32imaCustomized`
|
||||
//! - `cargo-prove` - Used by `RustRv32imaCustomized`
|
||||
//!
|
||||
//! ## `zkVM` requirements
|
||||
//!
|
||||
//! - `docker` - Used by `zkVM::prove` if `ProverResourceType::Gpu` is selected
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target | Note |
|
||||
//! | ----------------------- | :------: | ----------------------------- | ------------------ |
|
||||
//! | `RustRv32imaCustomized` | Rust | `riscv32im-succinct-zkvm-elf` | With `std` support |
|
||||
//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` | |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | Yes |
|
||||
//! | `Network` | Yes |
|
||||
//!
|
||||
//! [`install_sp1_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_sp1_sdk.sh
|
||||
//! [`sp1up`]: https://sp1up.succinct.xyz
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -225,7 +225,7 @@ mod tests {
|
||||
let zkvm = EreSP1::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.execute(&input).unwrap_err();
|
||||
@@ -247,7 +247,7 @@ mod tests {
|
||||
let zkvm = EreSP1::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
|
||||
@@ -2,27 +2,22 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
use ere_platform_trait::output_hasher::OutputHasher;
|
||||
use core::ops::Deref;
|
||||
use ere_platform_trait::LengthPrefixedStdin;
|
||||
|
||||
pub use ere_platform_trait::{
|
||||
Platform,
|
||||
output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
|
||||
};
|
||||
pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
|
||||
pub use zkm_zkvm;
|
||||
|
||||
/// Ziren [`Platform`] implementation.
|
||||
pub struct ZirenPlatform<H = IdentityOutput>(PhantomData<H>);
|
||||
pub struct ZirenPlatform;
|
||||
|
||||
impl<H: OutputHasher> Platform for ZirenPlatform<H> {
|
||||
fn read_whole_input() -> Vec<u8> {
|
||||
zkm_zkvm::io::read_vec()
|
||||
impl Platform for ZirenPlatform {
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
LengthPrefixedStdin::new(zkm_zkvm::io::read_vec())
|
||||
}
|
||||
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
let hash = H::output_hash(output);
|
||||
zkm_zkvm::io::commit_slice(&hash);
|
||||
zkm_zkvm::io::commit_slice(output);
|
||||
}
|
||||
|
||||
fn print(message: &str) {
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
//! Ziren [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # Requirements
|
||||
//!
|
||||
//! To install all requirements, run [`install_ziren_sdk.sh`] from the Ere
|
||||
//! repository at the same git revision as your `ere-ziren` dependency.
|
||||
//!
|
||||
//! ## `Compiler` requirements
|
||||
//!
|
||||
//! - Installation via [`install_ziren_sdk.sh`] - Custom Rust toolchain used by `RustMips32r2Customized`
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target | Note |
|
||||
//! | ------------------------ | :------: | --------------------- | ------------------ |
|
||||
//! | `RustMips32r2Customized` | Rust | `mipsel-zkm-zkvm-elf` | With `std` support |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | No |
|
||||
//! | `Network` | No |
|
||||
//!
|
||||
//! [`install_ziren_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_ziren_sdk.sh
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -190,7 +190,7 @@ mod tests {
|
||||
let zkvm = EreZiren::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.execute(&input).unwrap_err();
|
||||
@@ -212,7 +212,7 @@ mod tests {
|
||||
let zkvm = EreZiren::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
|
||||
@@ -2,32 +2,31 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{array::from_fn, marker::PhantomData};
|
||||
use ere_platform_trait::output_hasher::OutputHasher;
|
||||
use core::{array::from_fn, ops::Deref};
|
||||
use ere_platform_trait::LengthPrefixedStdin;
|
||||
use ziskos::ziskos_definitions::ziskos_config::UART_ADDR;
|
||||
|
||||
pub use ere_platform_trait::{
|
||||
Platform,
|
||||
output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
|
||||
};
|
||||
pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
|
||||
pub use ziskos;
|
||||
|
||||
/// ZisK [`Platform`] implementation.
|
||||
///
|
||||
/// Note that the maximum output size is 256 bytes, and output size will be
|
||||
/// padded to multiple of 4.
|
||||
pub struct ZiskPlatform<H = IdentityOutput>(PhantomData<H>);
|
||||
pub struct ZiskPlatform;
|
||||
|
||||
impl<H: OutputHasher> Platform for ZiskPlatform<H> {
|
||||
fn read_whole_input() -> Vec<u8> {
|
||||
ziskos::read_input()
|
||||
impl Platform for ZiskPlatform {
|
||||
fn read_whole_input() -> impl Deref<Target = [u8]> {
|
||||
LengthPrefixedStdin::new(ziskos::read_input())
|
||||
}
|
||||
|
||||
fn write_whole_output(output: &[u8]) {
|
||||
let hash = H::output_hash(output);
|
||||
assert!(hash.len() <= 256, "Maximum output size is 256 bytes");
|
||||
hash.chunks(4).enumerate().for_each(|(idx, chunk)| {
|
||||
assert!(
|
||||
output.len() <= 256,
|
||||
"Maximum output size is 256 bytes, got {}",
|
||||
output.len()
|
||||
);
|
||||
output.chunks(4).enumerate().for_each(|(idx, chunk)| {
|
||||
let value = u32::from_le_bytes(from_fn(|i| chunk.get(i).copied().unwrap_or_default()));
|
||||
ziskos::set_output(idx, value)
|
||||
});
|
||||
|
||||
@@ -1,3 +1,47 @@
|
||||
//! ZisK [`Compiler`] and [`zkVM`] implementation.
|
||||
//!
|
||||
//! # Requirements
|
||||
//!
|
||||
//! To install all requirements, run [`install_zisk_sdk.sh`] from the Ere
|
||||
//! repository at the same git revision as your `ere-zisk` dependency.
|
||||
//!
|
||||
//! To install `cargo-zisk-cuda` (with GPU proving support), make sure CUDA 12.9
|
||||
//! is installed, run [`install_zisk_sdk.sh`] with env `CUDA=1` set.
|
||||
//!
|
||||
//! ## `Compiler` requirements
|
||||
//!
|
||||
//! - Installation via [`ziskup`] - Custom Rust toolchain used by `RustRv64imaCustomized`
|
||||
//! - Installation via [`install_tamago.sh`] - Custom Go toolchain used by `GoCustomized`
|
||||
//!
|
||||
//! ## `zkVM` requirements
|
||||
//!
|
||||
//! - Installation via [`ziskup`]
|
||||
//! - `cargo-zisk-cuda` - Used by `zkVM::prove` if `ProverResourceType::Gpu` is
|
||||
//! selected
|
||||
//!
|
||||
//! # `Compiler` implementation
|
||||
//!
|
||||
//! ## Available compilers
|
||||
//!
|
||||
//! | Compiler | Language | Target | Note |
|
||||
//! | ----------------------- | :------: | -------------------------- | ------------------ |
|
||||
//! | `RustRv64imaCustomized` | Rust | `riscv64ima-zisk-zkvm-elf` | With `std` support |
|
||||
//! | `GoCustomized` | Go | `riscv64` | |
|
||||
//!
|
||||
//! # `zkVM` implementation
|
||||
//!
|
||||
//! ## Supported `ProverResourceType`
|
||||
//!
|
||||
//! | Resource | Supported |
|
||||
//! | --------- | :-------: |
|
||||
//! | `Cpu` | Yes |
|
||||
//! | `Gpu` | Yes |
|
||||
//! | `Network` | No |
|
||||
//!
|
||||
//! [`install_zisk_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_zisk_sdk.sh
|
||||
//! [`install_tamago.sh`]: https://github.com/eth-act/ere/blob/master/scripts/install_tamago.sh
|
||||
//! [`ziskup`]: https://raw.githubusercontent.com/0xPolygonHermez/zisk/main/ziskup/install.sh
|
||||
|
||||
#![cfg_attr(
|
||||
all(not(test), feature = "compiler", feature = "zkvm"),
|
||||
warn(unused_crate_dependencies)
|
||||
|
||||
@@ -188,7 +188,7 @@ mod tests {
|
||||
let zkvm = EreZisk::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.execute(&input).unwrap_err();
|
||||
@@ -214,7 +214,7 @@ mod tests {
|
||||
let _guard = PROVE_LOCK.lock().unwrap();
|
||||
|
||||
for input in [
|
||||
Input::default(),
|
||||
Input::new(),
|
||||
BasicProgram::<BincodeLegacy>::invalid_test_case().input(),
|
||||
] {
|
||||
zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
|
||||
Reference in New Issue
Block a user