Skip to content

Commit

Permalink
Merge branch 'main' into pending-task-list
Browse files Browse the repository at this point in the history
  • Loading branch information
smtmfft authored Oct 7, 2024
2 parents 7ae19e1 + 8ad5a6f commit f37cdf6
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 87 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ WORKDIR /opt/raiko
COPY . .
RUN cargo build --release ${BUILD_FLAGS} --features "sgx" --features "docker_build"

FROM gramineproject/gramine:1.6-jammy AS runtime
FROM gramineproject/gramine:1.7-jammy AS runtime
ENV DEBIAN_FRONTEND=noninteractive
WORKDIR /opt/raiko

Expand Down
2 changes: 1 addition & 1 deletion host/tests/proof_request.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#![cfg(feature = "integration")]
use crate::common::scenarios::{
test_v1_api_format, test_v2_api_response, test_v2_cancellation, test_v2_prune, test_v2_report,
};

mod common;

#[tokio::test]
#[cfg(feature = "integration")]
async fn run_scenarios_sequentially() -> anyhow::Result<()> {
test_v2_prune().await?;
test_v2_report().await?;
Expand Down
8 changes: 7 additions & 1 deletion provers/sgx/config/sgx-guest.docker.manifest.template
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,16 @@ fs.mounts = [
{ path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" },
{ path = "/usr/lib/ssl/certs/", uri = "file:/usr/lib/ssl/certs/" },
{ path = "/root/.config/raiko/config", uri = "file:/root/.config/raiko/config" },
{ path = "/proc/self/mountinfo", uri = "file:/proc/self/mountinfo" },
{ path = "/proc/self/cgroup", uri = "file:/proc/self/cgroup" },
{ path = "/sys/fs/cgroup/", uri = "file:/sys/fs/cgroup/" },
{ path = "/root/.config/raiko/secrets", uri = "file:/root/.config/raiko/secrets", type = "encrypted", key_name = "_sgx_mrenclave" },
]
sgx.allowed_files = [
"file:/root/.config/raiko/config",
"file:/proc/self/mountinfo",
"file:/proc/self/cgroup",
"file:/sys/fs/cgroup/",
]
sgx.debug = false
sgx.edmm_enable = {{ 'true' if env.get('EDMM', '1') == '1' else 'false' }}
Expand All @@ -34,7 +40,7 @@ sgx.trusted_files = [
"file:/usr/lib/ssl/certs/",
"file:sgx-guest",
]
sgx.max_threads = 32
sgx.max_threads = 512
sgx.remote_attestation = "dcap"
sys.enable_extra_runtime_domain_names_conf = true
sys.insecure__allow_eventfd = true
Expand Down
15 changes: 10 additions & 5 deletions provers/sp1/driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@ required-features = ["enable"]

[dependencies]
raiko-lib = { workspace = true, optional = true }
alloy-contract = { workspace = true, optional = true }
alloy-primitives = { workspace = true, optional = true }
alloy-provider = { workspace = true, optional = true }
alloy-sol-types = { workspace = true, optional = true }
alloy-eips = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
serde_json = { workspace = true, optional = true }
sp1-sdk = { workspace = true, optional = true }
anyhow = { workspace = true, optional = true }
once_cell = { workspace = true, optional = true }
sha3 = { workspace = true, optional = true, default-features = false}
sha3 = { workspace = true, optional = true, default-features = false }
serde_with = { workspace = true, optional = true }
dotenv = {workspace = true, optional = true}
cfg-if = {workspace = true }
bincode = {workspace = true }
dotenv = { workspace = true, optional = true }
cfg-if = { workspace = true }
bincode = { workspace = true }
reth-primitives = { workspace = true }
tokio = { workspace = true, optional = true }
tracing = { workspace = true, optional = true }
Expand All @@ -49,13 +51,16 @@ enable = [
"raiko-lib",
"sp1-sdk",
"anyhow",
"alloy-contract",
"alloy-primitives",
"alloy-provider",
"alloy-sol-types",
"once_cell",
"sha3",
"dotenv",
"serde_with",
"tokio",
"tracing"
"tracing",
]
neon = ["sp1-sdk?/neon"]
foundry-verify = []
93 changes: 14 additions & 79 deletions provers/sp1/driver/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![cfg(feature = "enable")]
#![feature(iter_advance_by)]

use once_cell::sync::Lazy;
use raiko_lib::{
input::{GuestInput, GuestOutput},
prover::{IdStore, IdWrite, Proof, ProofKey, Prover, ProverConfig, ProverError, ProverResult},
Expand All @@ -16,21 +15,15 @@ use sp1_sdk::{
proto::network::{ProofMode, UnclaimReason},
};
use sp1_sdk::{HashableKey, ProverClient, SP1Stdin};
use std::{
borrow::BorrowMut,
env, fs,
path::{Path, PathBuf},
};
use tracing::{debug, info};
use std::{borrow::BorrowMut, env};
use tracing::info;

mod proof_verify;
use proof_verify::remote_contract_verify::verify_sol_by_contract_call;

pub const ELF: &[u8] = include_bytes!("../../guest/elf/sp1-guest");
const SP1_PROVER_CODE: u8 = 1;
static FIXTURE_PATH: Lazy<PathBuf> =
Lazy::new(|| Path::new(env!("CARGO_MANIFEST_DIR")).join("../contracts/src/fixtures/"));
static CONTRACT_PATH: Lazy<PathBuf> =
Lazy::new(|| Path::new(env!("CARGO_MANIFEST_DIR")).join("../contracts/src/exports/"));

pub static VERIFIER: Lazy<Result<PathBuf, ProverError>> = Lazy::new(init_verifier);
#[serde_as]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Sp1Param {
Expand Down Expand Up @@ -164,12 +157,12 @@ impl Prover for Sp1Prover {
.public_values
.read::<[u8; 32]>();
let fixture = RaikoProofFixture {
vkey: vk.bytes32().to_string(),
public_values: B256::from_slice(&pi_hash).to_string(),
proof: reth_primitives::hex::encode_prefixed(&proof_bytes),
vkey: vk.bytes32(),
public_values: pi_hash.into(),
proof: proof_bytes.clone(),
};

verify_sol(&fixture)?;
verify_sol_by_contract_call(&fixture).await?;
time.stop_with("==> Verification complete");
}

Expand Down Expand Up @@ -232,66 +225,13 @@ fn get_env_mock() -> ProverMode {
}
}

fn init_verifier() -> Result<PathBuf, ProverError> {
// In cargo run, Cargo sets the working directory to the root of the workspace
let contract_path = &*CONTRACT_PATH;
info!("Contract dir: {:?}", contract_path);
let artifacts_dir = sp1_sdk::install::try_install_circuit_artifacts();
// Create the destination directory if it doesn't exist
fs::create_dir_all(&contract_path)?;

// Read the entries in the source directory
for entry in fs::read_dir(artifacts_dir)? {
let entry = entry?;
let src = entry.path();

// Check if the entry is a file and ends with .sol
if src.is_file() && src.extension().map(|s| s == "sol").unwrap_or(false) {
let out = contract_path.join(src.file_name().unwrap());
fs::copy(&src, &out)?;
println!("Copied: {:?}", src.file_name().unwrap());
}
}
Ok(contract_path.clone())
}

/// A fixture that can be used to test the verification of SP1 zkVM proofs inside Solidity.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct RaikoProofFixture {
vkey: String,
public_values: String,
proof: String,
}

fn verify_sol(fixture: &RaikoProofFixture) -> ProverResult<()> {
assert!(VERIFIER.is_ok());
debug!("===> Fixture: {:#?}", fixture);

// Save the fixture to a file.
let fixture_path = &*FIXTURE_PATH;
info!("Writing fixture to: {:?}", fixture_path);

if !fixture_path.exists() {
std::fs::create_dir_all(fixture_path).map_err(|e| {
ProverError::GuestError(format!("Failed to create fixture path: {}", e))
})?;
}
std::fs::write(
fixture_path.join("fixture.json"),
serde_json::to_string_pretty(&fixture).unwrap(),
)
.map_err(|e| ProverError::GuestError(format!("Failed to write fixture: {}", e)))?;

let child = std::process::Command::new("forge")
.arg("test")
.current_dir(&*CONTRACT_PATH)
.stdout(std::process::Stdio::inherit()) // Inherit the parent process' stdout
.spawn();
info!("Verification started {:?}", child);
child.map_err(|e| ProverError::GuestError(format!("Failed to run forge: {}", e)))?;

Ok(())
public_values: B256,
proof: Vec<u8>,
}

#[cfg(test)]
Expand All @@ -314,16 +254,11 @@ mod test {
prover: Some(ProverMode::Network),
verify: true,
};
let serialized = serde_json::to_value(&param).unwrap();
let serialized = serde_json::to_value(param).unwrap();
assert_eq!(json, serialized);

let deserialized: Sp1Param = serde_json::from_value(serialized).unwrap();
println!("{:?} {:?}", json, deserialized);
}

#[test]
fn test_init_verifier() {
VERIFIER.as_ref().expect("Failed to init verifier");
println!("{json:?} {deserialized:?}");
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions provers/sp1/driver/src/proof_verify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub(crate) mod forge_proof_verify;
pub(crate) mod remote_contract_verify;
82 changes: 82 additions & 0 deletions provers/sp1/driver/src/proof_verify/forge_proof_verify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#![cfg(feature = "foundry-verify")]

use once_cell::sync::Lazy;
use raiko_lib::prover::{ProverError, ProverResult};
use std::{
env, fs,
path::{Path, PathBuf},
};
use tracing::{debug, info};

use crate::RaikoProofFixture;

static FIXTURE_PATH: Lazy<PathBuf> =
Lazy::new(|| Path::new(env!("CARGO_MANIFEST_DIR")).join("../contracts/src/fixtures/"));
static CONTRACT_PATH: Lazy<PathBuf> =
Lazy::new(|| Path::new(env!("CARGO_MANIFEST_DIR")).join("../contracts/src/exports/"));

pub static VERIFIER: Lazy<Result<PathBuf, ProverError>> = Lazy::new(init_verifier);

fn init_verifier() -> Result<PathBuf, ProverError> {
// In cargo run, Cargo sets the working directory to the root of the workspace
let contract_path = &*CONTRACT_PATH;
info!("Contract dir: {contract_path:?}");
let artifacts_dir = sp1_sdk::install::try_install_circuit_artifacts();
// Create the destination directory if it doesn't exist
fs::create_dir_all(contract_path)?;

// Read the entries in the source directory
for entry in fs::read_dir(artifacts_dir)? {
let entry = entry?;
let src = entry.path();

// Check if the entry is a file and ends with .sol
if src.is_file() && src.extension().map(|s| s == "sol").unwrap_or(false) {
let out = contract_path.join(src.file_name().unwrap());
fs::copy(&src, &out)?;
println!("Copied: {:?}", src.file_name().unwrap());
}
}
Ok(contract_path.clone())
}

/// verify the proof by using forge test, which involves downloading the whole sp1 sdk &
/// starting a forge environment to run test.
pub(crate) fn verify_sol_by_forge_test(fixture: &RaikoProofFixture) -> ProverResult<()> {
assert!(VERIFIER.is_ok());
debug!("===> Fixture: {fixture:#?}");

// Save the fixture to a file.
let fixture_path = &*FIXTURE_PATH;
info!("Writing fixture to: {fixture_path:?}");

if !fixture_path.exists() {
std::fs::create_dir_all(fixture_path.clone())
.map_err(|e| ProverError::GuestError(format!("Failed to create fixture path: {e}")))?;
}
std::fs::write(
fixture_path.join("fixture.json"),
serde_json::to_string_pretty(&fixture).unwrap(),
)
.map_err(|e| ProverError::GuestError(format!("Failed to write fixture: {e}")))?;

let child = std::process::Command::new("forge")
.arg("test")
.current_dir(&*CONTRACT_PATH)
.stdout(std::process::Stdio::inherit()) // Inherit the parent process' stdout
.spawn();
info!("Verification started {:?}", child);
child.map_err(|e| ProverError::GuestError(format!("Failed to run forge: {e}")))?;

Ok(())
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_init_verifier() {
VERIFIER.as_ref().expect("Failed to init verifier");
}
}
57 changes: 57 additions & 0 deletions provers/sp1/driver/src/proof_verify/remote_contract_verify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use alloy_primitives::Address;
use alloy_provider::ProviderBuilder;
use alloy_sol_types::sol;
use raiko_lib::prover::ProverResult;
use reth_primitives::B256;
use sp1_sdk::proto::network::twirp::url::Url;
use std::{env, str::FromStr};
use tracing::{error, info};

use crate::RaikoProofFixture;

sol!(
#[sol(rpc)]
#[allow(dead_code)]
contract ISP1Verifier {
#[derive(Debug)]
function verifyProof(
bytes32 programVKey,
bytes calldata publicValues,
bytes calldata proofBytes
) external view;
}
);

/// using pre-deployed contract to verify the proof, the only problem is to double check the verification version.
pub(crate) async fn verify_sol_by_contract_call(fixture: &RaikoProofFixture) -> ProverResult<()> {
let sp1_verifier_rpc_url = env::var("SP1_VERIFIER_RPC_URL").expect("env SP1_VERIFIER_RPC_URL");
let sp1_verifier_addr = {
let addr = env::var("SP1_VERIFIER_ADDRESS").expect("env SP1_VERIFIER_RPC_URL");
Address::from_str(&addr).unwrap()
};

let provider = ProviderBuilder::new().on_http(Url::parse(&sp1_verifier_rpc_url).unwrap());
let program_key: B256 = B256::from_str(&fixture.vkey).unwrap();
let public_value = fixture.public_values;
let proof_bytes = fixture.proof.clone();

info!(
"verify sp1 proof with program key: {:?} public value: {:?} proof: {:?}",
program_key,
public_value,
reth_primitives::hex::encode(&proof_bytes)
);

let sp1_verifier = ISP1Verifier::new(sp1_verifier_addr, provider);
let call_builder =
sp1_verifier.verifyProof(program_key, public_value.into(), proof_bytes.into());
let verify_call_res = call_builder.call().await;

if verify_call_res.is_ok() {
info!("SP1 proof verified successfully using {sp1_verifier_addr:?}!");
} else {
error!("SP1 proof verification failed: {:?}!", verify_call_res);
}

Ok(())
}
Binary file modified provers/sp1/guest/elf/sp1-guest
Binary file not shown.

0 comments on commit f37cdf6

Please sign in to comment.