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

Feature/fix sdk 241009 #27

Merged
merged 5 commits into from
Oct 10, 2024
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
26 changes: 26 additions & 0 deletions guest-program/revme/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[workspace]
[package]
name = "revme"
version = "0.1.0"
edition = "2021"

[dependencies]
zkm-runtime = { git = "https://github.com/zkMIPS/zkm", branch = "main" }
revm = { git = "https://github.com/powdr-labs/revm", branch = "serde-no-std", default-features = false, features = [ "serde" ] }

#models = { path = "../models" }
models = { git = "https://github.com/eigmax/powdr-revme", branch = "continuations", package = "models" }
serde = { version = "1.0", default-features = false, features = ["alloc", "derive", "rc"] }
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
k256 = { version = "0.13.3", features = ["ecdsa"], default-features = false }

# TODO can be removed once the powdr RISCV nightly is updated
ahash = { version = "=0.8.6", default-features = false }

libc = { version = "0.2" , features = ["extra_traits"] }

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"
4 changes: 4 additions & 0 deletions guest-program/revme/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[toolchain]
channel = "nightly-2023-03-06"
targets = ["mips-unknown-linux-musl"]
profile = "minimal"
190 changes: 190 additions & 0 deletions guest-program/revme/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#![no_std]
#![no_main]

use revm::{
db::CacheState,
interpreter::CreateScheme,
primitives::{calc_excess_blob_gas, keccak256, Bytecode, Env, SpecId, TransactTo, U256},
Evm,
};
extern crate libc;

use models::*;

mod utils;

use utils::recover_address;

extern crate alloc;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
use alloc::collections::BTreeMap;

zkm_runtime::entrypoint!(main);

pub fn main() {
ethereum_test();
}

fn ethereum_test() {
let input: Vec<u8> = zkm_runtime::io::read();
let suite = read_suite(&input);

assert!(execute_test_suite(suite).is_ok());
}

fn read_suite(s: &Vec<u8>) -> TestSuite {
let suite: TestUnit = serde_json::from_slice(s).map_err(|e| e).unwrap();
let mut btm = BTreeMap::new();
btm.insert("test".to_string(), suite);
TestSuite(btm)
}

fn execute_test_suite(suite: TestSuite) -> Result<(), String> {
for (_name, unit) in suite.0 {
// Create database and insert cache
let mut cache_state = CacheState::new(false);
for (address, info) in unit.pre {
let acc_info = revm::primitives::AccountInfo {
balance: info.balance,
code_hash: keccak256(&info.code),
code: Some(Bytecode::new_raw(info.code)),
nonce: info.nonce,
};
cache_state.insert_account_with_storage(address, acc_info, info.storage);
}

let mut env = Env::default();
// for mainnet
env.cfg.chain_id = 1;
// env.cfg.spec_id is set down the road

// block env
env.block.number = unit.env.current_number;
env.block.coinbase = unit.env.current_coinbase;
env.block.timestamp = unit.env.current_timestamp;
env.block.gas_limit = unit.env.current_gas_limit;
env.block.basefee = unit.env.current_base_fee.unwrap_or_default();
env.block.difficulty = unit.env.current_difficulty;
// after the Merge prevrandao replaces mix_hash field in block and replaced difficulty opcode in EVM.
env.block.prevrandao = unit.env.current_random;
// EIP-4844
if let (Some(parent_blob_gas_used), Some(parent_excess_blob_gas)) = (
unit.env.parent_blob_gas_used,
unit.env.parent_excess_blob_gas,
) {
env.block
.set_blob_excess_gas_and_price(calc_excess_blob_gas(
parent_blob_gas_used.to(),
parent_excess_blob_gas.to(),
));
}

// tx env
env.tx.caller = match unit.transaction.sender {
Some(address) => address,
_ => recover_address(unit.transaction.secret_key.as_slice())
.ok_or_else(|| String::new())?,
};
env.tx.gas_price = unit
.transaction
.gas_price
.or(unit.transaction.max_fee_per_gas)
.unwrap_or_default();
env.tx.gas_priority_fee = unit.transaction.max_priority_fee_per_gas;
// EIP-4844
env.tx.blob_hashes = unit.transaction.blob_versioned_hashes;
env.tx.max_fee_per_blob_gas = unit.transaction.max_fee_per_blob_gas;

// post and execution
for (spec_name, tests) in unit.post {
if matches!(
spec_name,
SpecName::ByzantiumToConstantinopleAt5
| SpecName::Constantinople
| SpecName::Unknown
) {
continue;
}

let spec_id = spec_name.to_spec_id();

for (_index, test) in tests.into_iter().enumerate() {
env.tx.gas_limit = unit.transaction.gas_limit[test.indexes.gas].saturating_to();

env.tx.data = unit
.transaction
.data
.get(test.indexes.data)
.unwrap()
.clone();
env.tx.value = unit.transaction.value[test.indexes.value];

env.tx.access_list = unit
.transaction
.access_lists
.get(test.indexes.data)
.and_then(Option::as_deref)
.unwrap_or_default()
.iter()
.map(|item| {
(
item.address,
item.storage_keys
.iter()
.map(|key| U256::from_be_bytes(key.0))
.collect::<Vec<_>>(),
)
})
.collect();

let to = match unit.transaction.to {
Some(add) => TransactTo::Call(add),
None => TransactTo::Create(CreateScheme::Create),
};
env.tx.transact_to = to;

let mut cache = cache_state.clone();
cache.set_state_clear_flag(SpecId::enabled(
spec_id,
revm::primitives::SpecId::SPURIOUS_DRAGON,
));
let mut state = revm::db::State::builder()
.with_cached_prestate(cache)
.with_bundle_update()
.build();
let mut evm = Evm::builder()
.with_db(&mut state)
.modify_env(|e| *e = env.clone())
.spec_id(spec_id)
.build();

// do the deed
//let timer = Instant::now();
let mut check = || {
let exec_result = evm.transact_commit();

match (&test.expect_exception, &exec_result) {
// do nothing
(None, Ok(_)) => (),
// return okay, exception is expected.
(Some(_), Err(_e)) => {
return Ok(());
}
_ => {
let s = exec_result.clone().err().map(|e| e.to_string()).unwrap();
return Err(s);
}
}
Ok(())
};

let Err(e) = check() else { continue };

return Err(e);
}
}
}
Ok(())
}
25 changes: 25 additions & 0 deletions guest-program/revme/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use k256::ecdsa::SigningKey;
use revm::primitives::Address;

/// Recover the address from a private key (SigningKey).
pub fn recover_address(private_key: &[u8]) -> Option<Address> {
let key = SigningKey::from_slice(private_key).ok()?;
let public_key = key.verifying_key().to_encoded_point(false);
Some(Address::from_raw_public_key(&public_key.as_bytes()[1..]))
}

#[cfg(test)]
mod tests {
use super::*;
use revm::primitives::{address, hex};

#[test]
fn sanity_test() {
assert_eq!(
Some(address!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b")),
recover_address(&hex!(
"45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
))
)
}
}
3 changes: 2 additions & 1 deletion host-program/run-local-proving.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
if [ $# -lt 1 ]; then
echo "usage: ./run_local_proving sha2-go [or sha2-rust or mem-alloc-vec]"
echo "usage: ./run_local_proving sha2-go [or sha2-rust or mem-alloc-vec or revme]"
exit 1
fi

Expand All @@ -12,6 +12,7 @@ export RUST_LOG=info
export SEG_SIZE=262144
export ARGS="711e9609339e92b03ddc0a211827dba421f38f9ed8b9d806e1ffdd8c15ffa03d world!"
export ELF_PATH=${BASEDIR}/../guest-program/$program/target/mips-unknown-linux-musl/release/$program
export JSON_PATH=${BASEDIR}/test-vectors/test.json
export EXECUTE_ONLY=false

echo "Compile guest-program ${program}"
Expand Down
3 changes: 2 additions & 1 deletion host-program/run-network-proving.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
if [ $# -lt 1 ]; then
echo "usage: ./run_network_proving sha2-go [or sha2-rust or mem-alloc-vec]"
echo "usage: ./run_network_proving sha2-go [or sha2-rust or mem-alloc-vec or revme]"
exit 1
fi

Expand All @@ -15,6 +15,7 @@ export RUST_LOG=info
export SEG_SIZE=262144
export ARGS="711e9609339e92b03ddc0a211827dba421f38f9ed8b9d806e1ffdd8c15ffa03d world!"
export ELF_PATH=${BASEDIR}/../guest-program/$program/target/mips-unknown-linux-musl/release/$program
export JSON_PATH=${BASEDIR}/test-vectors/test.json
export EXECUTE_ONLY=false

echo "Compile guest-program ${program}"
Expand Down
15 changes: 15 additions & 0 deletions host-program/src/bin/zkm-prove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
"sha2-go" => set_sha2_go_intput(seg_size2, execute_only2).expect("set sha2-go input error"),
"mem-alloc-vec" => set_mem_alloc_vec_intput(seg_size2, execute_only2)
.expect("set mem-alloc-vec input error"),
"revme" => set_revme_input(seg_size2, execute_only2).expect("set revme input error"),
_ => {
helper();
ProverInput {
Expand Down Expand Up @@ -248,3 +249,17 @@ fn set_mem_alloc_vec_intput(seg_size_u: u32, execute_only_b: bool) -> anyhow::Re

Ok(input)
}

fn set_revme_input(seg_size_u: u32, execute_only_b: bool) -> anyhow::Result<ProverInput> {
let elf_path = env::var("ELF_PATH").expect("ELF PATH is missed");
let json_path = env::var("JSON_PATH").expect("JSON PATH is missing");
let input = ProverInput {
elf: read(elf_path).unwrap(),
public_inputstream: read(json_path).unwrap(),
private_inputstream: "".into(),
seg_size: seg_size_u,
execute_only: execute_only_b,
};

Ok(input)
}
Binary file added host-program/test-vectors/test.json
Binary file not shown.
2 changes: 2 additions & 0 deletions sdk/src/local/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ impl ProverTask {
.unwrap();
result.solidity_verifier =
std::fs::read(format!("{}/verifier.sol", outputdir)).unwrap();
result.public_values =
std::fs::read(format!("{}/public_values.json", inputdir)).unwrap();
} else {
log::error!("Failed to generate snark proof.");
}
Expand Down
6 changes: 5 additions & 1 deletion sdk/src/local/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ pub fn prove_multi_seg_common(
}

let (block_proof, _block_public_values) =
all_circuits.prove_block(None, &agg_proof, updated_agg_public_values)?;
all_circuits.prove_block(None, &agg_proof, updated_agg_public_values.clone())?;

log::info!(
"proof size: {:?}",
Expand All @@ -217,6 +217,10 @@ pub fn prove_multi_seg_common(
let wrapped_proof = wrapped_circuit.prove(&block_proof)?;
wrapped_proof.save(outdir)?;

let outdir_path = std::path::Path::new(outdir);
let public_values_file = File::create(outdir_path.join("public_values.json"))?;
serde_json::to_writer(&public_values_file, &updated_agg_public_values)?;

total_timing.filter(Duration::from_millis(100)).print();
result
}
6 changes: 6 additions & 0 deletions sdk/src/network/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ impl Prover for NetworkProver {
proof_with_public_inputs: get_status_response.proof_with_public_inputs,
stark_proof: vec![],
solidity_verifier: vec![],
public_values: vec![],
};
if !get_status_response.stark_proof_url.is_empty() {
proof_result.stark_proof =
Expand All @@ -158,6 +159,11 @@ impl Prover for NetworkProver {
)
.await?;
}
if !get_status_response.public_values_url.is_empty() {
proof_result.public_values =
NetworkProver::download_file(&get_status_response.public_values_url)
.await?;
}
return Ok(Some(proof_result));
}
_ => {
Expand Down
2 changes: 2 additions & 0 deletions sdk/src/proto/stage.proto
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ message GenerateProofResponse {
string stark_proof_url = 5;
string solidity_verifier_url = 6;
bytes output_stream = 7;
string public_values_url = 8;
}

message GetStatusRequest {
Expand All @@ -71,4 +72,5 @@ message GetStatusResponse {
string solidity_verifier_url = 6;
bytes output_stream = 7;
int32 step = 8; // Step
string public_values_url = 9;
}
1 change: 1 addition & 0 deletions sdk/src/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct ProverResult {
pub proof_with_public_inputs: Vec<u8>,
pub stark_proof: Vec<u8>,
pub solidity_verifier: Vec<u8>,
pub public_values: Vec<u8>,
}

#[async_trait]
Expand Down
Loading