From 48493547cea03ebd9123d547520b73a7eb9dbb2f Mon Sep 17 00:00:00 2001 From: eigmax Date: Mon, 12 Oct 2026 14:00:38 +0000 Subject: [PATCH 1/8] Prepare consecutive EthProofs blocks in parallel --- bin/eth-proofs/src/cli.rs | 2 +- bin/eth-proofs/src/consecutive.rs | 293 ++++++++++++++++++++++++++++++ bin/eth-proofs/src/main.rs | 174 +++++++++--------- bin/eth-proofs/src/state.rs | 24 +++ 4 files changed, 410 insertions(+), 83 deletions(-) create mode 100644 bin/eth-proofs/src/consecutive.rs diff --git a/bin/eth-proofs/src/cli.rs b/bin/eth-proofs/src/cli.rs index b92b76d..ad71299 100644 --- a/bin/eth-proofs/src/cli.rs +++ b/bin/eth-proofs/src/cli.rs @@ -87,7 +87,7 @@ pub struct Args { #[clap(long)] pub start_block: Option, - /// Witness preparation concurrency (1 or 2 in latest mode; GPU proving remains serial). + /// Witness preparation concurrency (1 or 2; consecutive results are delivered in order). #[clap(long, default_value_t = 1)] pub prepare_concurrency: usize, diff --git a/bin/eth-proofs/src/consecutive.rs b/bin/eth-proofs/src/consecutive.rs new file mode 100644 index 0000000..b128c6b --- /dev/null +++ b/bin/eth-proofs/src/consecutive.rs @@ -0,0 +1,293 @@ +//! Bounded preparation of consecutive blocks with ordered, durable publication. +use futures::{channel::mpsc, pin_mut, SinkExt, Stream, StreamExt}; +use std::{future::Future, time::Duration}; +use tokio::sync::watch; + +pub async fn run( + blocks: S, + concurrency: usize, + mut output: mpsc::Sender<(u64, T)>, + mut shutdown: watch::Receiver, + mut prepare: P, + mut persist: C, +) -> eyre::Result<()> +where + S: Stream>, + P: FnMut(u64) -> PF, + PF: Future>, + C: FnMut(u64, &T) -> eyre::Result<()>, +{ + eyre::ensure!(concurrency > 0, "preparation concurrency must be positive"); + let prepared = blocks + .map(move |number| { + let pending = number.map(|number| (number, prepare(number))); + async move { + let (number, future) = pending?; + Ok::<_, eyre::Report>((number, future.await?)) + } + }) + .buffered(concurrency); + pin_mut!(prepared); + loop { + if *shutdown.borrow() { + return Ok(()); + } + let next = tokio::select! { + biased; + _ = shutdown.changed() => return Ok(()), + next = prepared.next() => next, + }; + let Some(next) = next else { return Ok(()) }; + let (number, input) = next?; + // Later completions cannot be persisted or published ahead of this block. + persist(number, &input)?; + tokio::select! { + biased; + _ = shutdown.changed() => return Ok(()), + result = output.send((number, input)) => { + if result.is_err() { return Ok(()) } + }, + } + } +} + +/// A preparation failure occupies its original slot until the same block succeeds. +pub async fn retry( + number: u64, + delay: Duration, + mut prepare: P, + mut on_error: E, +) -> T +where + P: FnMut(u64) -> PF, + PF: Future>, + E: FnMut(u64, eyre::Report) -> EF, + EF: Future, +{ + loop { + match prepare(number).await { + Ok(input) => return input, + Err(error) => { + on_error(number, error).await; + tokio::time::sleep(delay).await; + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use futures::{stream, FutureExt}; + use std::sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, Mutex, + }; + use tokio::sync::Semaphore; + + #[tokio::test] + async fn overlaps_preparation_but_persists_and_delivers_in_block_order() { + let first = Arc::new(Semaphore::new(0)); + let second = Arc::new(Semaphore::new(0)); + let started = Arc::new(Mutex::new(Vec::new())); + let finished = Arc::new(Mutex::new(Vec::new())); + let persisted = Arc::new(Mutex::new(Vec::new())); + let (tx, mut rx) = mpsc::channel(4); + let (_stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let first = first.clone(); + let second = second.clone(); + let started = started.clone(); + let finished = finished.clone(); + let persisted = persisted.clone(); + async move { + run( + stream::iter((100..104).map(Ok)), + 2, + tx, + shutdown, + move |number| { + let first = first.clone(); + let second = second.clone(); + let started = started.clone(); + let finished = finished.clone(); + async move { + started.lock().unwrap().push(number); + if number == 100 { + first.acquire().await.unwrap().forget(); + } + if number == 101 { + second.acquire().await.unwrap().forget(); + } + finished.lock().unwrap().push(number); + Ok(number) + } + }, + move |number, _| { + persisted.lock().unwrap().push(number); + Ok(()) + }, + ) + .await + } + }); + tokio::time::timeout(Duration::from_secs(2), async { + while started.lock().unwrap().len() < 2 { + tokio::task::yield_now().await; + } + }) + .await + .unwrap(); + assert_eq!(*started.lock().unwrap(), vec![100, 101]); + second.add_permits(1); + tokio::time::timeout(Duration::from_secs(2), async { + while !finished.lock().unwrap().contains(&101) { + tokio::task::yield_now().await; + } + }) + .await + .unwrap(); + assert!(rx.next().now_or_never().is_none()); + assert!(persisted.lock().unwrap().is_empty()); + first.add_permits(1); + let mut received = Vec::new(); + while let Some((number, value)) = rx.next().await { + assert_eq!(number, value); + received.push(number); + } + task.await.unwrap().unwrap(); + assert_eq!(received, vec![100, 101, 102, 103]); + assert_eq!(*persisted.lock().unwrap(), received); + } + + #[tokio::test] + async fn retries_a_failed_block_before_delivering_its_ready_successor() { + let attempts = Arc::new(AtomicUsize::new(0)); + let failures = Arc::new(Mutex::new(Vec::new())); + let (tx, mut rx) = mpsc::channel(4); + let (_stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let attempts = attempts.clone(); + let failures = failures.clone(); + async move { + run( + stream::iter([Ok(100), Ok(101)]), + 2, + tx, + shutdown, + move |number| { + let attempts = attempts.clone(); + let failures = failures.clone(); + async move { + Ok(retry( + number, + Duration::from_millis(10), + move |number| { + let failed = number == 100 && + attempts.fetch_add(1, Ordering::SeqCst) == 0; + std::future::ready(if failed { + Err(eyre::eyre!("witness unavailable")) + } else { + Ok(number) + }) + }, + move |number, _| { + failures.lock().unwrap().push(number); + std::future::ready(()) + }, + ) + .await) + } + }, + |_, _| Ok(()), + ) + .await + } + }); + assert_eq!(rx.next().await, Some((100, 100))); + assert_eq!(rx.next().await, Some((101, 101))); + task.await.unwrap().unwrap(); + assert_eq!(*failures.lock().unwrap(), vec![100]); + assert_eq!(attempts.load(Ordering::SeqCst), 2); + } + + #[tokio::test] + async fn shutdown_cancels_pending_work_without_persisting_later_results() { + let started = Arc::new(AtomicUsize::new(0)); + let persisted = Arc::new(AtomicUsize::new(0)); + let (tx, _rx) = mpsc::channel(1); + let (stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let started = started.clone(); + let persisted = persisted.clone(); + async move { + run( + stream::iter((100..110).map(Ok)), + 2, + tx, + shutdown, + move |number| { + started.fetch_add(1, Ordering::SeqCst); + async move { + if number == 100 { + std::future::pending::<()>().await; + } + Ok(number) + } + }, + move |_, _| { + persisted.fetch_add(1, Ordering::SeqCst); + Ok(()) + }, + ) + .await + } + }); + tokio::time::timeout(Duration::from_secs(2), async { + while started.load(Ordering::SeqCst) < 2 { + tokio::task::yield_now().await; + } + }) + .await + .unwrap(); + stop.send(true).unwrap(); + tokio::time::timeout(Duration::from_secs(2), task).await.unwrap().unwrap().unwrap(); + assert_eq!(started.load(Ordering::SeqCst), 2); + assert_eq!(persisted.load(Ordering::SeqCst), 0); + } + + #[tokio::test] + async fn paused_consumer_bounds_preparation_and_shutdown_interrupts_backpressure() { + let started = Arc::new(AtomicUsize::new(0)); + let (tx, _rx) = mpsc::channel(1); + let (stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let started = started.clone(); + async move { + run( + stream::iter((100..200).map(Ok)), + 2, + tx, + shutdown, + move |number| { + started.fetch_add(1, Ordering::SeqCst); + std::future::ready(Ok(number)) + }, + |_, _| Ok(()), + ) + .await + } + }); + tokio::time::timeout(Duration::from_secs(2), async { + while started.load(Ordering::SeqCst) < 2 { + tokio::task::yield_now().await; + } + }) + .await + .unwrap(); + tokio::time::sleep(Duration::from_millis(20)).await; + assert!(started.load(Ordering::SeqCst) <= 5, "producer ran past its bounded queue"); + stop.send(true).unwrap(); + tokio::time::timeout(Duration::from_secs(2), task).await.unwrap().unwrap().unwrap(); + } +} diff --git a/bin/eth-proofs/src/main.rs b/bin/eth-proofs/src/main.rs index 6cf9658..5b8f382 100644 --- a/bin/eth-proofs/src/main.rs +++ b/bin/eth-proofs/src/main.rs @@ -9,7 +9,7 @@ use alloy_provider::{Provider, ProviderBuilder, WsConnect}; use clap::Parser; use cli::Args; use eth_proofs::EthProofsClient; -use futures::{channel::mpsc, future::ready, FutureExt, SinkExt, StreamExt}; +use futures::{channel::mpsc, future::ready, FutureExt, StreamExt}; use host_executor::{ alerting::AlertingClient, create_eth_block_execution_strategy_factory, EthExecutorComponents, FullExecutor, @@ -20,6 +20,7 @@ use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, Env use zkm_sdk::{include_elf, ProverClient}; mod cli; +mod consecutive; mod latest; mod state; @@ -57,10 +58,6 @@ async fn main() -> eyre::Result<()> { (1..=2).contains(&args.prepare_concurrency) && args.prefetch_depth > 0, "preparation concurrency must be 1 or 2 and queue depth must be positive" ); - eyre::ensure!( - args.latest_block || args.prepare_concurrency == 1, - "parallel preparation requires --latest-block" - ); let elf = match &args.elf_file { Some(path) => std::fs::read(path)?, None => include_elf!("reth").to_vec(), @@ -162,7 +159,7 @@ async fn main() -> eyre::Result<()> { None }; let head_shutdown = shutdown.clone(); - let mut stream = if state.is_some() { + let stream = if state.is_some() { futures::stream::unfold( (http_provider.clone(), None, head_shutdown), |(provider, mut previous, shutdown)| async move { @@ -231,7 +228,7 @@ async fn main() -> eyre::Result<()> { // idle for the RPC round trips. let executor = Arc::new(executor); let alerting_client = Arc::new(alerting_client); - let (mut tx, mut rx) = mpsc::channel(args.prefetch_depth.max(1)); + let (tx, mut rx) = mpsc::channel(args.prefetch_depth.max(1)); let (latest_tx, mut latest_rx) = tokio::sync::watch::channel(None); // Recover a completed proof before choosing a fresh head. Only this prover // owns the durable cursor; preparations never advance or delete its inputs. @@ -243,7 +240,7 @@ async fn main() -> eyre::Result<()> { } } } - let fetcher = { + let mut fetcher = { let executor = executor.clone(); let alerting_client = alerting_client.clone(); let max_lag = args.max_lag; @@ -277,89 +274,99 @@ async fn main() -> eyre::Result<()> { ) .await; } - // The subscription is only a wake-up: it says how far the chain - // is. Which block to prepare next is a cursor that advances by - // `block_interval`, so falling behind never skips a block — the - // backlog is worked through in order (unless `max_lag` says to - // drop it). A header stream that lags drops headers; the cursor - // does not. - let mut head = 0u64; - let mut next = state.as_ref().and_then(|s| s.next_block()).unwrap_or(0); - loop { - if *preparation_shutdown.borrow() { - break; - } - if next == 0 || next > head { - match stream.next().await { - Some(header) => { - head = head.max(header); - if next == 0 { - // The stream only delivers this instance's - // residue class, so the cursor starts aligned. - next = header - - ((header + block_interval - block_residue) % block_interval); - if let Some(state) = &state { - state.initialize(next)?; + // Headers bound how far ahead we may prepare. The durable cursor is + // advanced only by the prover, after committing each ordered output. + let next = state.as_ref().and_then(|s| s.next_block()).unwrap_or(0); + let blocks = futures::stream::try_unfold((0u64, next, stream), { + let state = state.clone(); + move |(mut head, mut next, mut stream)| { + let state = state.clone(); + async move { + loop { + if next == 0 || next > head { + match stream.next().await { + Some(header) => { + head = head.max(header); + if next == 0 { + next = header - + ((header + block_interval - block_residue) % + block_interval); + if let Some(state) = &state { + state.initialize(next)?; + } + } + continue; + } + None => return Ok::<_, eyre::Report>(None), } } - continue; - } - None => break, - } - } - // Absorb whatever headers are already queued so `head` is fresh. - while let Some(Some(header)) = stream.next().now_or_never() { - head = head.max(header); - } - - let number = next; - next += block_interval; - if max_lag > 0 && head - number > max_lag { - warn!("skipping block {number}: {} behind the newest header", head - number); - continue; - } - - if let Some(state) = &state { - if state.is_committed(number)? { - if tx.send((number, None)).await.is_err() { - break; + while let Some(Some(header)) = stream.next().now_or_never() { + head = head.max(header); + } + let number = next; + next = next + .checked_add(block_interval) + .ok_or_else(|| eyre::eyre!("preparation block cursor overflow"))?; + if max_lag > 0 && head - number > max_lag { + warn!( + "skipping block {number}: {} behind the newest header", + head - number + ); + continue; + } + return Ok(Some((number, (head, next, stream)))); } - continue; } } - // Retry the same block; a transient preparation failure must not skip it. - loop { - let prepared = match executor.wait_for_block(number).await { - Ok(()) => { - if let Some(state) = &state { - match state.input(number)? { - Some(bytes) => Ok(bincode::deserialize(&bytes)?), - None => executor.prepare(number).await, - } - } else { - executor.prepare(number).await - } - } - Err(err) => Err(err), - }; - match prepared { - Ok(client_input) => { - if let Some(state) = &state { - state.save_input(number, &bincode::serialize(&client_input)?)?; + }) + .boxed(); + let persist_state = state.clone(); + consecutive::run( + blocks, + prepare_concurrency, + tx, + preparation_shutdown, + move |number| { + let executor = executor.clone(); + let state = state.clone(); + let alerting_client = alerting_client.clone(); + async move { + if let Some(state) = &state { + if state.is_committed(number)? { + return Ok(None); } - if tx.send((number, Some(client_input))).await.is_err() { - return Ok::<(), eyre::Report>(()); + if let Some(bytes) = state.input(number)? { + return Ok(Some(bincode::deserialize(&bytes)?)); } - break; - } - Err(err) => { - report_error(&alerting_client, number, err).await; - tokio::time::sleep(Duration::from_secs(5)).await; } + let input = consecutive::retry( + number, + Duration::from_secs(5), + move |number| { + let executor = executor.clone(); + async move { + executor.wait_for_block(number).await?; + executor.prepare(number).await + } + }, + move |number, err| { + let alerting_client = alerting_client.clone(); + async move { report_error(&alerting_client, number, err).await } + }, + ) + .await; + Ok(Some(input)) } - } - } - Ok::<(), eyre::Report>(()) + .boxed() + }, + move |number, input| { + if let (Some(state), Some(input)) = (&persist_state, input) { + state.save_input(number, &bincode::serialize(input)?)?; + } + Ok(()) + }, + ) + .await }) }; @@ -440,6 +447,8 @@ async fn main() -> eyre::Result<()> { tokio::time::sleep(Duration::from_secs(3)).await; }; if block.header.hash != client_input.current_block.header.hash_slow() { + fetcher.abort(); + let _ = (&mut fetcher).await; state.discard_inputs_from(number)?; eyre::bail!( "prepared inputs invalidated by a reorg; restart from durable cursor" @@ -463,6 +472,7 @@ async fn main() -> eyre::Result<()> { } if *shutdown.borrow() { fetcher.abort(); + let _ = fetcher.await; } else { fetcher.await??; } diff --git a/bin/eth-proofs/src/state.rs b/bin/eth-proofs/src/state.rs index 571aaad..3cb4146 100644 --- a/bin/eth-proofs/src/state.rs +++ b/bin/eth-proofs/src/state.rs @@ -383,4 +383,28 @@ mod tests { assert!(state.is_committed(10).is_err()); assert!(state.advance(11, true).is_err()); } + + #[test] + fn restart_preserves_prefetch_and_reorg_discards_all_future_inputs() { + let root = tempfile::tempdir().unwrap(); + let state = State::open(root.path(), identity(), Some(10)).unwrap(); + for block in 10..14 { + state.save_input(block, &[block as u8]).unwrap(); + } + state.commit(10, b"proof", b"values", serde_json::json!({"block_number":10})).unwrap(); + state.advance(10, true).unwrap(); + drop(state); + let state = State::open(root.path(), identity(), None).unwrap(); + assert_eq!(state.next_block(), Some(11)); + for block in 11..14 { + assert_eq!(state.input(block).unwrap().unwrap(), [block as u8]); + } + state.discard_inputs_from(11).unwrap(); + assert_eq!(state.next_block(), Some(11)); + for block in 11..14 { + assert!(state.input(block).unwrap().is_none()); + } + assert!(state.is_committed(10).unwrap()); + assert_eq!(state.pending_count().unwrap(), 1); + } } From f30cf7d8951761e0330ca3ad5dca0fa9dd04b869 Mon Sep 17 00:00:00 2001 From: eigmax Date: Thu, 15 Oct 2026 01:18:08 +0000 Subject: [PATCH 2/8] guest: the optimised guest line in the Ziren 2.0 EthProofs worker The Fleet worker (48493547, chore/ziren-v2-stateless + fix/ethproofs-consecutive) forked from the guest optimisation line at 9215aa6 and shipped the older guest: no in-guest JUMPDEST table (the host's revm JumpTable was trusted under a code hash that covers only the code bytes), no zkVM syscalls for 256-bit arithmetic and the curves, no arena tries. This squashes perf/guest-hashed-key-memo (7147f4e: feat/guest-syscalls 4a15fee plus the trie-key memo and the checked logs bloom). Resolution: - bin/eth-proofs, the root Cargo.toml and Cargo.lock: the worker's. The worker keeps the git-locked Ziren 2.0 graph; the opt line's sibling-checkout [patch] section is dropped. - Guest, mpt and the witness RPC db: the opt line's. The worker's 2c0245a (preserve untouched storage roots, remove empty accounts) was already in ArenaState::update; its 41317cd (omitted storage of an absent account or an authenticated empty storage root reads zero, any other missing storage trie is an error) is now ArenaState::storage, with its three tests. a75cb33 (verified bytecode recovery) is the opt line's complete_account_code; the duplicated structured-header decoder is kept once. - bin/guest keeps the opt line's graph (precompile forks); its zkm-zkvm/zkm-lib [patch] points at the sibling Ziren checkout, whose guest-side crates (crates/zkvm, crates/build) are identical to 0dd65a15 and 31f6e8eb. Validation: - cargo test -p mpt: 24 passed (the arena storage rule and the update rule). - host (this tree) fetched and executed 26184581-26184583 natively: 278.70M, 269.57M, 52.72M cycles, block hashes as the chain's. - GPU, one card through Fleet (image e786dd = Ziren 31f6e8eb), guest 941629f6: 53.73/53.40/18.01 s, every proof verified against a 31f6e8eb client, public values identical to the deployed guest's (334b45b8: 73.97/73.64/20.61 s on the same blocks, -24.5% overall). --- Cargo.lock | 7 + bin/guest/Cargo.lock | 1261 +++++++-------- bin/guest/Cargo.toml | 28 +- bin/guest/src/main.rs | 10 +- crates/executor/guest/Cargo.toml | 4 + .../executor/guest/examples/convert_input.rs | 54 + crates/executor/guest/src/custom.rs | 79 +- crates/executor/guest/src/error.rs | 2 + crates/executor/guest/src/executor.rs | 46 +- crates/executor/guest/src/hashed_keys.rs | 72 + crates/executor/guest/src/into_primitives.rs | 23 +- crates/executor/guest/src/io.rs | 255 +-- crates/executor/guest/src/lib.rs | 2 + crates/executor/guest/src/precompiles.rs | 563 +++++++ .../executor/host/examples/witness_census.rs | 127 ++ crates/executor/host/src/full_executor.rs | 27 +- crates/executor/host/src/host_executor.rs | 62 +- crates/mpt/Cargo.toml | 1 + crates/mpt/src/arena.rs | 1364 +++++++++++++++++ crates/mpt/src/lib.rs | 58 +- crates/mpt/src/mpt.rs | 64 +- .../storage/rpc-db/src/execution_witness.rs | 580 ++++--- 22 files changed, 3583 insertions(+), 1106 deletions(-) create mode 100644 crates/executor/guest/examples/convert_input.rs create mode 100644 crates/executor/guest/src/hashed_keys.rs create mode 100644 crates/executor/guest/src/precompiles.rs create mode 100644 crates/executor/host/examples/witness_census.rs create mode 100644 crates/mpt/src/arena.rs diff --git a/Cargo.lock b/Cargo.lock index 7af1efd..5decd45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1461,8 +1461,10 @@ version = "0.8.0" source = "git+https://github.com/ziren-patches/bls12_381?branch=patch-0.8.0#bcf9397426410acc171ad625416b508dc913be8e" dependencies = [ "cfg-if", + "digest 0.10.7", "ff 0.13.1", "group 0.13.0", + "hex", "pairing 0.23.0", "rand_core 0.6.4", "subtle", @@ -2932,7 +2934,9 @@ dependencies = [ "alloy-network", "alloy-primitives", "alloy-rpc-types", + "aurora-engine-modexp", "bincode", + "bls12_381 0.8.0", "itertools 0.13.0", "kzg-rs", "mpt", @@ -2959,7 +2963,9 @@ dependencies = [ "serde", "serde_json", "serde_with", + "substrate-bn", "thiserror 1.0.69", + "zkm-lib", ] [[package]] @@ -4112,6 +4118,7 @@ dependencies = [ "alloy-rpc-types", "alloy-rpc-types-debug", "hex-literal", + "reth-primitives-traits", "reth-trie", "rlp", "serde", diff --git a/bin/guest/Cargo.lock b/bin/guest/Cargo.lock index 489896c..948e655 100644 --- a/bin/guest/Cargo.lock +++ b/bin/guest/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addchain" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e33f6a175ec6a9e0aca777567f9ff7c3deefc255660df887e7fa3585e9801d8" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" dependencies = [ "num-bigint 0.3.3", "num-integer", @@ -33,9 +33,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.34" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e0378e959aa6a885897522080a990e80eb317f1e9a222a604492ea50e13096" +checksum = "35d744058a9daa51a8cf22a3009607498fcf82d3cf4c5444dd8056cdf651f471" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -46,16 +46,41 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.8.3" +version = "1.0.41" +source = "git+https://github.com/ziren-patches/alloy?branch=patch-1.0.41#08557d4e5f4ca766194a45c1925d8f1625258793" +dependencies = [ + "alloy-eips 1.0.41", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 1.0.41", + "alloy-trie", + "alloy-tx-macros 1.0.41", + "auto_impl", + "c-kzg", + "derive_more", + "either", + "k256", + "once_cell", + "rand 0.8.5", + "secp256k1", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.17", +] + +[[package]] +name = "alloy-consensus" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f16daaf7e1f95f62c6c3bf8a3fc3d78b08ae9777810c0bb5e94966c7cd57ef0" +checksum = "2e318e25fb719e747a7e8db1654170fc185024f3ed5b10f86c08d448a912f6e2" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "alloy-trie", - "alloy-tx-macros", + "alloy-tx-macros 1.1.3", "auto_impl", "borsh", "c-kzg", @@ -63,25 +88,25 @@ dependencies = [ "either", "k256", "once_cell", - "rand 0.8.6", + "rand 0.8.5", "secp256k1", "serde", "serde_json", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "alloy-consensus-any" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "118998d9015332ab1b4720ae1f1e3009491966a0349938a1f43ff45a8a4c6299" +checksum = "364380a845193a317bcb7a5398fc86cdb66c47ebe010771dde05f6869bf9e64a" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "serde", ] @@ -95,7 +120,7 @@ dependencies = [ "alloy-rlp", "crc", "serde", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -122,36 +147,42 @@ dependencies = [ "k256", "serde", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] -name = "alloy-eip7928" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b827a6d7784fe3eb3489d40699407a4cdcce74271421a01bdffe60cf573bb16" +name = "alloy-eips" +version = "1.0.41" +source = "git+https://github.com/ziren-patches/alloy?branch=patch-1.0.41#08557d4e5f4ca766194a45c1925d8f1625258793" dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", "alloy-primitives", "alloy-rlp", - "borsh", - "once_cell", + "alloy-serde 1.0.41", + "auto_impl", + "c-kzg", + "derive_more", + "either", "serde", - "thiserror 2.0.18", + "serde_with", + "sha2", + "thiserror 2.0.17", ] [[package]] name = "alloy-eips" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ef28c9fdad22d4eec52d894f5f2673a0895f1e5ef196734568e68c0f6caca8" +checksum = "a4c4d7c5839d9f3a467900c625416b24328450c65702eb3d8caff8813e4d1d33" dependencies = [ "alloy-eip2124", "alloy-eip2930", "alloy-eip7702", - "alloy-eip7928", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "auto_impl", "borsh", "c-kzg", @@ -160,6 +191,7 @@ dependencies = [ "serde", "serde_with", "sha2", + "thiserror 2.0.17", ] [[package]] @@ -168,26 +200,26 @@ version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527b47dc39850c6168002ddc1f7a2063e15d26137c1bb5330f6065a7524c1aa9" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-hardforks", "alloy-primitives", "alloy-sol-types", "auto_impl", "derive_more", "revm", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "alloy-genesis" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbf9480307b09d22876efb67d30cadd9013134c21f3a17ec9f93fd7536d38024" +checksum = "1ba4b1be0988c11f0095a2380aa596e35533276b8fa6c9e06961bbfe0aebcac5" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-primitives", - "alloy-serde", + "alloy-serde 1.1.3", "alloy-trie", "borsh", "serde", @@ -196,9 +228,9 @@ dependencies = [ [[package]] name = "alloy-hardforks" -version = "0.4.7" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ba208044232d14d4adbfa77e57d6329f51bc1acc21f5667bb7db72d88a0831" +checksum = "2d9a33550fc21fd77a3f8b63e99969d17660eec8dcc50a95a80f7c9964f7680b" dependencies = [ "alloy-chains", "alloy-eip2124", @@ -221,34 +253,34 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422d110f1c40f1f8d0e5562b0b649c35f345fccb7093d9f02729943dcd1eef71" +checksum = "f72cf87cda808e593381fb9f005ffa4d2475552b7a6c5ac33d087bf77d82abd0" dependencies = [ "alloy-primitives", "alloy-sol-types", "http", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", "tracing", ] [[package]] name = "alloy-network" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7197a66d94c4de1591cdc16a9bcea5f8cccd0da81b865b49aef97b1b4016e0fa" +checksum = "12aeb37b6f2e61b93b1c3d34d01ee720207c76fe447e2a2c217e433ac75b17f5" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-consensus-any", - "alloy-eips", + "alloy-eips 1.1.3", "alloy-json-rpc", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-any", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.1.3", "alloy-signer", "alloy-sol-types", "async-trait", @@ -257,41 +289,41 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "alloy-network-primitives" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb82711d59a43fdfd79727c99f270b974c784ec4eb5728a0d0d22f26716c87ef" +checksum = "abd29ace62872083e30929cd9b282d82723196d196db589f3ceda67edcc05552" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", - "alloy-serde", + "alloy-serde 1.1.3", "serde", ] [[package]] name = "alloy-primitives" version = "1.4.1" -source = "git+https://github.com/ziren-patches/core.git?branch=patch-alloy-primitives-1.4.1#59313700f710f1373a5b4cdc05c51dc3227d8064" +source = "git+https://github.com/ziren-patches/core.git?branch=patch-alloy-primitives-1.4.1-hasher#8846a1c3b6f6595020ab4189034a6f463ffbffc7" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", "derive_more", - "foldhash 0.2.0", + "foldhash", "hashbrown 0.16.1", - "indexmap 2.14.0", + "indexmap 2.12.1", "itoa", "k256", "keccak-asm", "paste", "proptest", - "rand 0.9.4", + "rand 0.9.2", "ruint", "rustc-hash", "serde", @@ -302,9 +334,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.15" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc90b1e703d3c03f4ff7f48e82dd0bc1c8211ab7d079cd836a06fcfeb06651cb" +checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -313,43 +345,43 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.15" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36834a5c0a2fa56e171bf256c34d70fca07d0c0031583edea1c4946b7889c9e" +checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "alloy-rpc-types" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4faad925d3a669ffc15f43b3deec7fbdf2adeb28a4d6f9cf4bc661698c0f8f4b" +checksum = "39cf1398cb33aacb139a960fa3d8cf8b1202079f320e77e952a0b95967bf7a9f" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.1.3", "serde", ] [[package]] name = "alloy-rpc-types-any" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3823026d1ed239a40f12364fac50726c8daf1b6ab8077a97212c5123910429ed" +checksum = "6a63fb40ed24e4c92505f488f9dd256e2afaed17faa1b7a221086ebba74f4122" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.1.3", ] [[package]] name = "alloy-rpc-types-debug" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2145138f3214928f08cd13da3cb51ef7482b5920d8ac5a02ecd4e38d1a8f6d1e" +checksum = "4936f579d9d10eae01772b2ab3497f9d568684f05f26f8175e12f9a1a2babc33" dependencies = [ "alloy-primitives", "derive_more", @@ -359,12 +391,12 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb9b97b6e7965679ad22df297dda809b11cebc13405c1b537e5cffecc95834fa" +checksum = "4c60bdce3be295924122732b7ecd0b2495ce4790bedc5370ca7019c08ad3f26e" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", "derive_more", @@ -373,30 +405,40 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c095f92c4e1ff4981d89e9aa02d5f98c762a1980ab66bec49c44be11349da2" +checksum = "9eae0c7c40da20684548cbc8577b6b7447f7bf4ddbac363df95e3da220e41e72" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-consensus-any", - "alloy-eips", + "alloy-eips 1.1.3", "alloy-network-primitives", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "alloy-sol-types", "itertools 0.14.0", "serde", "serde_json", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", +] + +[[package]] +name = "alloy-serde" +version = "1.0.41" +source = "git+https://github.com/ziren-patches/alloy?branch=patch-1.0.41#08557d4e5f4ca766194a45c1925d8f1625258793" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", ] [[package]] name = "alloy-serde" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ece63b89294b8614ab3f483560c08d016930f842bf36da56bf0b764a15c11e" +checksum = "c0df1987ed0ff2d0159d76b52e7ddfc4e4fbddacc54d2fbee765e0d14d7c01b5" dependencies = [ "alloy-primitives", "serde", @@ -405,9 +447,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f447aefab0f1c0649f71edc33f590992d4e122bc35fb9cdbbf67d4421ace85" +checksum = "6ff69deedee7232d7ce5330259025b868c5e6a52fa8dffda2c861fb3a5889b24" dependencies = [ "alloy-primitives", "async-trait", @@ -415,46 +457,46 @@ dependencies = [ "either", "elliptic-curve", "k256", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "alloy-sol-macro" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab81bab693da9bb79f7a95b64b394718259fdd7e41dceeced4cad57cb71c4f6a" +checksum = "f3ce480400051b5217f19d6e9a82d9010cdde20f1ae9c00d53591e4a1afbb312" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "alloy-sol-macro-expander" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489f1620bb7e2483fb5819ed01ab6edc1d2f93939dce35a5695085a1afd1d699" +checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.14.0", + "indexmap 2.12.1", "proc-macro-error2", "proc-macro2", "quote", - "sha3", - "syn 2.0.117", + "syn 2.0.111", "syn-solidity", + "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56cef806ad22d4392c5fc83cf8f2089f988eb99c7067b4e0c6f1971fc1cca318" +checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" dependencies = [ "const-hex", "dunce", @@ -462,18 +504,18 @@ dependencies = [ "macro-string", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6df77fea9d6a2a75c0ef8d2acbdfd92286cc599983d3175ccdc170d3433d249" +checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" dependencies = [ "serde", - "winnow 0.7.15", + "winnow", ] [[package]] @@ -490,30 +532,42 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.9.5" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f14b5d9b2c2173980202c6ff470d96e7c5e202c65a9f67884ad565226df7fbb" +checksum = "e3412d52bb97c6c6cc27ccc28d4e6e8cf605469101193b50b0bd5813b1f990b5" dependencies = [ "alloy-primitives", "alloy-rlp", + "arrayvec", "derive_more", "nybbles", "serde", "smallvec", - "thiserror 2.0.18", "tracing", ] [[package]] name = "alloy-tx-macros" -version = "1.8.3" +version = "1.0.41" +source = "git+https://github.com/ziren-patches/alloy?branch=patch-1.0.41#08557d4e5f4ca766194a45c1925d8f1625258793" +dependencies = [ + "alloy-primitives", + "darling", + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "alloy-tx-macros" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69722eddcdf1ce096c3ab66cf8116999363f734eb36fe94a148f4f71c85da84" +checksum = "333544408503f42d7d3792bfc0f7218b643d968a03d2c0ed383ae558fb4a76d0" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -525,12 +579,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - [[package]] name = "ark-bls12-381" version = "0.5.0" @@ -660,7 +708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -698,7 +746,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -758,7 +806,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -768,7 +816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.5", ] [[package]] @@ -778,7 +826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.5", ] [[package]] @@ -788,7 +836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.5", ] [[package]] @@ -802,6 +850,9 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] [[package]] name = "async-trait" @@ -811,7 +862,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -832,7 +883,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -855,9 +906,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.3" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" [[package]] name = "bincode" @@ -901,9 +952,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.11.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ "serde_core", ] @@ -949,8 +1000,10 @@ version = "0.8.0" source = "git+https://github.com/ziren-patches/bls12_381?branch=patch-0.8.0#bcf9397426410acc171ad625416b508dc913be8e" dependencies = [ "cfg-if", + "digest 0.10.7", "ff", "group", + "hex", "pairing", "rand_core 0.6.4", "subtle", @@ -971,42 +1024,32 @@ dependencies = [ [[package]] name = "borsh" -version = "1.6.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ "borsh-derive", - "bytes", "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "1.6.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", + "syn 2.0.111", ] [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byte-slice-cast" @@ -1016,9 +1059,9 @@ checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] @@ -1031,7 +1074,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1042,18 +1085,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" dependencies = [ "serde", ] [[package]] name = "c-kzg" -version = "2.1.7" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6648ed1e4ea8e8a1a4a2c78e1cda29a3fd500bc622899c340d8525ea9a76b24a" +checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" dependencies = [ "blst", "cc", @@ -1066,9 +1109,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.2.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" dependencies = [ "find-msvc-tools", "jobserver", @@ -1090,9 +1133,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", "num-traits", @@ -1102,9 +1145,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.19.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20d9a563d167a9cce0f94153382b33cb6eded6dfabff03c69ad65a28ea1514e0" +checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ "cfg-if", "cpufeatures 0.2.17", @@ -1120,12 +1163,11 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.36" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ "const_format_proc_macros", - "konst", ] [[package]] @@ -1189,9 +1231,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "critical-section" @@ -1254,9 +1296,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.23.0" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ "darling_core", "darling_macro", @@ -1264,27 +1306,28 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.23.0" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ + "fnv", "ident_case", "proc-macro2", "quote", "serde", "strsim", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "darling_macro" -version = "0.23.0" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1299,9 +1342,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.8" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", @@ -1320,35 +1363,35 @@ dependencies = [ [[package]] name = "derive-where" -version = "1.6.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "derive_more" -version = "2.1.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.1.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.117", + "syn 2.0.111", "unicode-xid", ] @@ -1381,7 +1424,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1419,7 +1462,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1469,7 +1512,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1500,9 +1543,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.4.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -1555,9 +1598,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "fixed-hash" @@ -1566,7 +1609,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand 0.8.6", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -1577,12 +1620,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -1606,26 +1643,26 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-task", "pin-project-lite", - "slab", + "pin-utils", ] [[package]] @@ -1647,9 +1684,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -1664,21 +1701,8 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi 5.3.0", - "wasip2", -] - -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", + "r-efi", "wasip2", - "wasip3", ] [[package]] @@ -1702,12 +1726,14 @@ dependencies = [ name = "guest-executor" version = "0.1.0" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-evm", "alloy-network", "alloy-primitives", "alloy-rpc-types", + "aurora-engine-modexp", "bincode", + "bls12_381", "itertools 0.13.0", "kzg-rs", "mpt", @@ -1728,7 +1754,9 @@ dependencies = [ "serde", "serde_json", "serde_with", + "substrate-bn", "thiserror 1.0.69", + "zkm-lib", ] [[package]] @@ -1744,7 +1772,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", - "foldhash 0.1.5", ] [[package]] @@ -1753,17 +1780,11 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "foldhash 0.2.0", + "foldhash", "serde", "serde_core", ] -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - [[package]] name = "heck" version = "0.5.0" @@ -1821,9 +1842,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.65" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1845,13 +1866,12 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", - "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1859,9 +1879,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1872,9 +1892,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1886,15 +1906,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -1906,15 +1926,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", @@ -1925,12 +1945,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -1950,9 +1964,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1975,7 +1989,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1997,12 +2011,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.14.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.17.1", + "hashbrown 0.16.1", "serde", "serde_core", ] @@ -2036,9 +2050,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.18" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" @@ -2052,12 +2066,10 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.98" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ - "cfg-if", - "futures-util", "once_cell", "wasm-bindgen", ] @@ -2079,38 +2091,23 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.6" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures 0.2.17", ] [[package]] name = "keccak-asm" -version = "0.1.6" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa468878266ad91431012b3e5ef1bf9b170eab22883503a318d46857afa4579a" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" dependencies = [ "digest 0.10.7", "sha3-asm", ] -[[package]] -name = "konst" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" -dependencies = [ - "konst_macro_rules", -] - -[[package]] -name = "konst_macro_rules" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" - [[package]] name = "kzg-rs" version = "0.2.7" @@ -2133,35 +2130,29 @@ dependencies = [ "spin 0.9.8", ] -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "libc" -version = "0.2.186" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libm" -version = "0.2.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "linux-raw-sys" -version = "0.12.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -2186,14 +2177,14 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "memchr" -version = "2.8.0" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "modular-bitfield" @@ -2276,9 +2267,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" @@ -2333,9 +2324,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.6" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -2343,20 +2334,20 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.6" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "nybbles" -version = "0.4.8" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" +checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" dependencies = [ "alloy-rlp", "cfg-if", @@ -2368,9 +2359,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.4" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" dependencies = [ "critical-section", "portable-atomic", @@ -2382,15 +2373,15 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726da827358a547be9f1e37c2a756b9e3729cb0350f43408164794b370cad8ae" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "derive_more", "serde", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -2443,7 +2434,7 @@ dependencies = [ "p3-maybe-rayon", "p3-util", "paste", - "rand 0.10.3", + "rand 0.10.2", "serde", "tracing", ] @@ -2460,7 +2451,7 @@ dependencies = [ "p3-poseidon1", "p3-poseidon2", "p3-symmetric", - "rand 0.10.3", + "rand 0.10.2", ] [[package]] @@ -2472,7 +2463,7 @@ dependencies = [ "p3-field", "p3-maybe-rayon", "p3-util", - "rand 0.10.3", + "rand 0.10.2", "serde", "tracing", ] @@ -2491,7 +2482,7 @@ dependencies = [ "p3-field", "p3-symmetric", "p3-util", - "rand 0.10.3", + "rand 0.10.2", ] [[package]] @@ -2511,7 +2502,7 @@ dependencies = [ "p3-symmetric", "p3-util", "paste", - "rand 0.10.3", + "rand 0.10.2", "serde", "spin 0.10.1", "tracing", @@ -2524,7 +2515,7 @@ source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c dependencies = [ "p3-field", "p3-symmetric", - "rand 0.10.3", + "rand 0.10.2", ] [[package]] @@ -2536,7 +2527,7 @@ dependencies = [ "p3-mds", "p3-symmetric", "p3-util", - "rand 0.10.3", + "rand 0.10.2", ] [[package]] @@ -2593,7 +2584,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -2610,9 +2601,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.6" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" dependencies = [ "memchr", "ucd-trie", @@ -2649,7 +2640,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -2663,9 +2654,15 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs8" @@ -2679,21 +2676,21 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.33" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -2713,16 +2710,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - [[package]] name = "primeorder" version = "0.13.1" @@ -2746,7 +2733,7 @@ dependencies = [ name = "primitives" version = "0.1.0" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-genesis", "alloy-rpc-types", "eyre", @@ -2759,9 +2746,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.5.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ "toml_edit", ] @@ -2785,29 +2772,29 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.11.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", "bitflags", "num-traits", - "rand 0.9.4", + "rand 0.9.2", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -2824,9 +2811,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.45" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -2837,12 +2824,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - [[package]] name = "radium" version = "0.7.0" @@ -2851,9 +2832,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -2863,20 +2844,20 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.4" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.5", + "rand_core 0.9.3", "serde", ] [[package]] name = "rand" -version = "0.10.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ "rand_core 0.10.1", ] @@ -2898,7 +2879,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.5", + "rand_core 0.9.3", ] [[package]] @@ -2907,14 +2888,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.2.16", ] [[package]] name = "rand_core" -version = "0.9.5" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.4", "serde", @@ -2932,14 +2913,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.5", + "rand_core 0.9.3", ] [[package]] name = "rayon" -version = "1.12.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -2972,14 +2953,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reth" @@ -2998,8 +2979,8 @@ version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ "alloy-chains", - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-evm", "alloy-genesis", "alloy-primitives", @@ -3017,8 +2998,8 @@ name = "reth-codecs" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-genesis", "alloy-primitives", "alloy-trie", @@ -3037,7 +3018,7 @@ source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea8 dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -3045,12 +3026,12 @@ name = "reth-consensus" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-primitives", "auto_impl", "reth-execution-types", "reth-primitives-traits", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3058,8 +3039,8 @@ name = "reth-consensus-common" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "reth-chainspec", "reth-consensus", "reth-primitives-traits", @@ -3070,7 +3051,7 @@ name = "reth-db-models" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-primitives", "reth-primitives-traits", ] @@ -3083,7 +3064,7 @@ dependencies = [ "reth-consensus", "reth-execution-errors", "reth-storage-errors", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3091,8 +3072,8 @@ name = "reth-ethereum-consensus" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "reth-chainspec", "reth-consensus", @@ -3119,12 +3100,12 @@ name = "reth-ethereum-primitives" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.1.3", "reth-codecs", "reth-primitives-traits", "serde", @@ -3136,8 +3117,8 @@ name = "reth-evm" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-evm", "alloy-primitives", "auto_impl", @@ -3157,8 +3138,8 @@ name = "reth-evm-ethereum" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-evm", "alloy-primitives", "alloy-rpc-types-engine", @@ -3182,7 +3163,7 @@ dependencies = [ "alloy-rlp", "nybbles", "reth-storage-errors", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3190,8 +3171,8 @@ name = "reth-execution-types" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-evm", "alloy-primitives", "derive_more", @@ -3209,7 +3190,7 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", "url", ] @@ -3218,8 +3199,8 @@ name = "reth-primitives-traits" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-genesis", "alloy-primitives", "alloy-rlp", @@ -3237,7 +3218,7 @@ dependencies = [ "secp256k1", "serde", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3248,7 +3229,7 @@ dependencies = [ "alloy-primitives", "derive_more", "strum", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3276,8 +3257,8 @@ name = "reth-storage-api" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rpc-types-engine", "auto_impl", @@ -3298,7 +3279,7 @@ name = "reth-storage-errors" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", "derive_more", @@ -3306,7 +3287,7 @@ dependencies = [ "reth-prune-types", "reth-static-file-types", "revm-database-interface", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3314,8 +3295,8 @@ name = "reth-trie" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", "alloy-trie", @@ -3336,7 +3317,7 @@ name = "reth-trie-common" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-primitives", "alloy-rlp", "alloy-trie", @@ -3375,8 +3356,7 @@ dependencies = [ [[package]] name = "revm" version = "31.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb67a5223602113cae59a305acde2d9936bc18f2478dda879a6124b267cebfb6" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ "revm-bytecode", "revm-context", @@ -3394,8 +3374,7 @@ dependencies = [ [[package]] name = "revm-bytecode" version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2c6b5e6e8dd1e28a4a60e5f46615d4ef0809111c9e63208e55b5c7058200fb0" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ "bitvec", "phf", @@ -3406,9 +3385,9 @@ dependencies = [ [[package]] name = "revm-context" version = "11.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92850e150f4f99d46c05a20ad0cd09286a7ad4ee21866fffb87101de6e602231" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ + "alloy-consensus 1.0.41", "bitvec", "cfg-if", "derive-where", @@ -3423,9 +3402,9 @@ dependencies = [ [[package]] name = "revm-context-interface" version = "12.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d701e2c2347d65216b066489ab22a0a8e1f7b2568256110d73a7d5eff3385c" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ + "alloy-consensus 1.0.41", "alloy-eip2930", "alloy-eip7702", "auto_impl", @@ -3439,10 +3418,9 @@ dependencies = [ [[package]] name = "revm-database" version = "9.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980d8d6bba78c5dd35b83abbb6585b0b902eb25ea4448ed7bfba6283b0337191" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ - "alloy-eips", + "alloy-eips 1.0.41", "revm-bytecode", "revm-database-interface", "revm-primitives", @@ -3453,8 +3431,7 @@ dependencies = [ [[package]] name = "revm-database-interface" version = "8.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cce03e3780287b07abe58faf4a7f5d8be7e81321f93ccf3343c8f7755602bae" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ "auto_impl", "either", @@ -3466,8 +3443,7 @@ dependencies = [ [[package]] name = "revm-handler" version = "12.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45418ed95cfdf0cb19effdbb7633cf2144cab7fb0e6ffd6b0eb9117a50adff6" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ "auto_impl", "derive-where", @@ -3485,8 +3461,7 @@ dependencies = [ [[package]] name = "revm-inspector" version = "12.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c99801eac7da06cc112df2244bd5a64024f4ef21240e923b26e73c4b4a0e5da6" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ "auto_impl", "either", @@ -3502,8 +3477,7 @@ dependencies = [ [[package]] name = "revm-interpreter" version = "29.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22789ce92c5808c70185e3bc49732f987dc6fd907f77828c8d3470b2299c9c65" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ "revm-bytecode", "revm-context-interface", @@ -3515,8 +3489,7 @@ dependencies = [ [[package]] name = "revm-precompile" version = "29.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968b124028960201abf6d6bf8e223f15fadebb4307df6b7dc9244a0aab5d2d05" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -3537,8 +3510,7 @@ dependencies = [ [[package]] name = "revm-primitives" version = "21.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e161db429d465c09ba9cbff0df49e31049fe6b549e28eb0b7bd642fcbd4412" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ "alloy-primitives", "num_enum", @@ -3549,8 +3521,7 @@ dependencies = [ [[package]] name = "revm-state" version = "8.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d8be953b7e374dbdea0773cf360debed8df394ea8d82a8b240a6b5da37592fc" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" dependencies = [ "bitflags", "revm-bytecode", @@ -3588,9 +3559,8 @@ dependencies = [ [[package]] name = "ruint" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0298da754d1395046b0afdc2f20ee76d29a8ae310cd30ffa84ed42acba9cb12a" +version = "1.17.0" +source = "git+https://github.com/ziren-patches/ruint?branch=patch-1.17.0#572265b0666ae9b1ce749b0f0ce051108ec7253c" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -3605,26 +3575,26 @@ dependencies = [ "parity-scale-codec", "primitive-types", "proptest", - "rand 0.8.6", - "rand 0.9.4", + "rand 0.8.5", + "rand 0.9.2", "rlp", "ruint-macro", "serde_core", "valuable", "zeroize", + "zkm-lib", ] [[package]] name = "ruint-macro" version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +source = "git+https://github.com/ziren-patches/ruint?branch=patch-1.17.0#572265b0666ae9b1ce749b0f0ce051108ec7253c" [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-hex" @@ -3647,14 +3617,14 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.28", + "semver 1.0.27", ] [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", @@ -3681,6 +3651,12 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + [[package]] name = "schemars" version = "0.9.0" @@ -3695,9 +3671,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" dependencies = [ "dyn-clone", "ref-cast", @@ -3733,7 +3709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "rand 0.8.6", + "rand 0.8.5", "secp256k1-sys", "serde", ] @@ -3758,9 +3734,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.28" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "semver-parser" @@ -3807,36 +3783,35 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", + "ryu", "serde", "serde_core", - "zmij", ] [[package]] name = "serde_with" -version = "3.20.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ "base64", - "bs58", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.14.0", + "indexmap 2.12.1", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.1.0", "serde_core", "serde_json", "serde_with_macros", @@ -3845,14 +3820,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.20.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -3877,9 +3852,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.9" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", "keccak", @@ -3887,9 +3862,9 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.6" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59cbb88c189d6352cc8ae96a39d19c7ecad8f7330b29461187f2587fdc2988d5" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" dependencies = [ "cc", "cfg-if", @@ -3913,15 +3888,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" - -[[package]] -name = "slab" -version = "0.4.12" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" @@ -3999,13 +3968,13 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "substrate-bn" version = "0.6.0" -source = "git+https://github.com/ziren-patches/bn?branch=patch-0.6.0#aba71380457d798039111e6cc0fdf2e0718c6766" +source = "git+https://github.com/ziren-patches/bn?branch=patch-0.6.0#0dfeeb1b7bfc21941b6e4964d678abd094a54a6f" dependencies = [ "bytemuck", "byteorder", @@ -4013,7 +3982,7 @@ dependencies = [ "crunchy", "lazy_static", "num-bigint 0.4.6", - "rand 0.8.6", + "rand 0.8.5", "rustc-hex", "zkm-lib", ] @@ -4037,9 +4006,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -4048,14 +4017,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f425ae0b12e2f5ae65542e00898d500d4d318b4baf09f40fd0d410454e9947" +checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4066,7 +4035,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4077,12 +4046,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.27.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.3.4", "once_cell", "rustix", "windows-sys", @@ -4099,11 +4068,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.17", ] [[package]] @@ -4114,18 +4083,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4139,30 +4108,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde_core", + "serde", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -4179,57 +4148,42 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", ] -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml_datetime" -version = "1.1.1+spec-1.1.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.23.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832" dependencies = [ - "indexmap 2.14.0", + "indexmap 2.12.1", "toml_datetime", "toml_parser", - "winnow 1.0.2", + "winnow", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "winnow 1.0.2", + "winnow", ] [[package]] @@ -4251,7 +4205,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4275,9 +4229,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.20.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -4305,15 +4259,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-xid" @@ -4323,9 +4277,9 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "url" -version = "2.5.8" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", @@ -4367,27 +4321,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.3+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" -dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen 0.51.0", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.121" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -4398,9 +4343,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.121" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4408,60 +4353,26 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.121" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.121" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.14.0", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap 2.14.0", - "semver 1.0.28", -] - [[package]] name = "windows-core" version = "0.62.2" @@ -4483,7 +4394,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4494,7 +4405,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4532,121 +4443,24 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "1.0.2" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap 2.14.0", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap 2.14.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.14.0", - "log", - "semver 1.0.28", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wyz" @@ -4659,9 +4473,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -4670,54 +4484,54 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "zerofrom" -version = "0.1.8" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", "synstructure", ] @@ -4732,20 +4546,20 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -4754,9 +4568,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -4765,19 +4579,18 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "zkm-lib" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" dependencies = [ "bincode", "cfg-if", @@ -4790,7 +4603,6 @@ dependencies = [ [[package]] name = "zkm-primitives" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" dependencies = [ "bincode", "blake3", @@ -4810,26 +4622,19 @@ dependencies = [ [[package]] name = "zkm-zkvm" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" dependencies = [ "bincode", "cfg-if", - "getrandom 0.2.17", + "getrandom 0.2.16", "lazy_static", "libm", - "rand 0.8.6", + "rand 0.8.5", "serde", "sha2", "zkm-lib", "zkm-primitives", ] -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - [[package]] name = "zstd" version = "0.13.3" diff --git a/bin/guest/Cargo.toml b/bin/guest/Cargo.toml index c4ddad3..8522181 100644 --- a/bin/guest/Cargo.toml +++ b/bin/guest/Cargo.toml @@ -26,9 +26,33 @@ log = { version = "0.4", features = ["max_level_off", "release_max_level_off"] } tracing = { version = "0.1", features = ["max_level_off", "release_max_level_off"] } [patch.crates-io] -# Precompile patches +ruint = { git = "https://github.com/ziren-patches/ruint", branch = "patch-1.17.0" } +revm = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-bytecode = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-context = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-context-interface = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-database = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-database-interface = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-handler = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-inspector = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-interpreter = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-precompile = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-primitives = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm-state = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +# Precompile patches, and the revm workspace with its 32-bit interpreter +# fast paths (gas, stack exchange, memory words). sha2 = { git = "https://github.com/ziren-patches/RustCrypto-hashes", branch = "patch-sha2-0.10.9", package = "sha2" } bn = { git = "https://github.com/ziren-patches/bn", branch = "patch-0.6.0", package = "substrate-bn" } k256 = { git = "https://github.com/ziren-patches/elliptic-curves", branch = "patch-k256-0.13.4" } p256 = { git = "https://github.com/ziren-patches/elliptic-curves", branch = "patch-p256-0.13.2" } -alloy-primitives-v1-4-1 = { git = "https://github.com/ziren-patches/core.git", package = "alloy-primitives", branch = "patch-alloy-primitives-1.4.1" } +alloy-primitives-v1-4-1 = { git = "https://github.com/ziren-patches/core.git", package = "alloy-primitives", branch = "patch-alloy-primitives-1.4.1-hasher" } + +# The guest's zkvm crates come from the canonical Ziren checkout next to this +# repo (its `main` tip), the same way the GPU prover consumes it: every +# zkm-zkvm / zkm-lib in the graph (the precompile patches declare their own, +# unbranched, which cargo cannot redirect to another branch of the same URL) +# resolves to this one source, so there is exactly one global allocator and +# the word-wise memcmp / zero-copy keccak reach every caller. +[patch."https://github.com/ProjectZKM/Ziren"] +zkm-zkvm = { path = "../../../Ziren/crates/zkvm/entrypoint" } +zkm-lib = { path = "../../../Ziren/crates/zkvm/lib" } diff --git a/bin/guest/src/main.rs b/bin/guest/src/main.rs index 15832d3..8c147d6 100644 --- a/bin/guest/src/main.rs +++ b/bin/guest/src/main.rs @@ -5,10 +5,14 @@ use guest_executor::verify_block; use std::sync::Arc; pub fn main() { - // Read the input. - let input = zkm_zkvm::io::read_vec(); + // Read the input. Leaked on purpose: the witness byte streams inside it + // are deserialised as borrows of this buffer rather than copies of it + // (`mpt::arena::input_bytes`), so it has to outlive the whole run. The + // vector is leaked as read: its capacity is the length rounded up to a + // word, and shrinking it to a boxed slice copied the whole input. + let input: &'static [u8] = Vec::leak(zkm_zkvm::io::read_vec()); - let (block_hash, _, _) = verify_block(&input); + let (block_hash, _, _) = verify_block(input); // Commit the block hash. zkm_zkvm::io::commit(&block_hash); diff --git a/crates/executor/guest/Cargo.toml b/crates/executor/guest/Cargo.toml index a3a8692..33a4591 100644 --- a/crates/executor/guest/Cargo.toml +++ b/crates/executor/guest/Cargo.toml @@ -52,6 +52,10 @@ op-alloy-network = { workspace = true, optional = true } op-alloy-rpc-types = { workspace = true, optional = true } kzg-rs.workspace = true +bls12_381 = { git = "https://github.com/ziren-patches/bls12_381", branch = "patch-0.8.0", default-features = false, features = ["groups", "pairings", "alloc", "experimental"] } +aurora-engine-modexp = "1.2.0" +zkm-lib = { git = "https://github.com/ProjectZKM/Ziren" } +bn = { git = "https://github.com/ziren-patches/bn", branch = "patch-0.6.0", package = "substrate-bn" } [features] diff --git a/crates/executor/guest/examples/convert_input.rs b/crates/executor/guest/examples/convert_input.rs new file mode 100644 index 0000000..5f3c78c --- /dev/null +++ b/crates/executor/guest/examples/convert_input.rs @@ -0,0 +1,54 @@ +use alloy_consensus::{Block, Header}; +use alloy_primitives::{Address, B256}; +use guest_executor::io::{EthClientExecutorInput, RawCode}; +use mpt::WitnessState; +use primitives::genesis::Genesis; +use reth_ethereum_primitives::TransactionSigned; +use revm::state::Bytecode; +use serde::Deserialize; +use serde_with::serde_as; + +#[serde_as] +#[derive(Deserialize)] +struct OldInput { + #[serde_as( + as = "reth_primitives_traits::serde_bincode_compat::Block<'_, TransactionSigned, Header>" + )] + current_block: Block, + #[serde_as(as = "Vec")] + ancestor_headers: Vec
, + parent_state: WitnessState, + bytecodes: Vec, + code_hashes: Vec, + genesis: Genesis, + custom_beneficiary: Option
, + opcode_tracking: bool, +} + +fn main() { + let args: Vec = std::env::args().collect(); + let old: OldInput = bincode::deserialize(&std::fs::read(&args[1]).unwrap()).unwrap(); + let old_codes = old.bytecodes.clone(); + let new = EthClientExecutorInput { + current_block: old.current_block, + ancestor_headers: old.ancestor_headers, + parent_state: old.parent_state, + bytecodes: old.bytecodes.iter().map(|b| RawCode::new(b.original_byte_slice())).collect(), + code_hashes: old.code_hashes, + genesis: old.genesis, + custom_beneficiary: old.custom_beneficiary, + opcode_tracking: old.opcode_tracking, + }; + for (old, new) in old_codes.iter().zip(&new.bytecodes) { + let analyzed = new.analyze(); + assert_eq!(old.original_byte_slice(), analyzed.original_byte_slice()); + assert_eq!( + old.legacy_jump_table().map(|j| j.as_slice().to_vec()), + analyzed.legacy_jump_table().map(|j| j.as_slice().to_vec()), + "jump table" + ); + } + let bytes = bincode::serialize(&new).unwrap(); + std::fs::write(&args[2], &bytes).unwrap(); + println!("wrote {} bytes", bytes.len()); +} diff --git a/crates/executor/guest/src/custom.rs b/crates/executor/guest/src/custom.rs index 3487bdb..236d9c4 100644 --- a/crates/executor/guest/src/custom.rs +++ b/crates/executor/guest/src/custom.rs @@ -6,7 +6,7 @@ //! configuring the custom CustomEvmConfig precompiles and instructions. use alloy_evm::{precompiles::PrecompilesMap, EthEvm}; -use kzg_rs::{Bytes32, Bytes48, KzgProof, KzgSettings}; +use kzg_rs::KzgSettings; use reth_evm::{eth::EthEvmBuilder, Database, EvmEnv, EvmFactory}; use revm::{ bytecode::opcode::OpCode, @@ -18,7 +18,10 @@ use revm::{ interpreter_types::{Jumps, LoopControl}, Interpreter, InterpreterTypes, }, - precompile::{Crypto, PrecompileError, PrecompileSpecId, Precompiles}, + precompile::{ + bls12_381::{G1Point, G1PointScalar, G2Point, G2PointScalar}, + Crypto, PrecompileError, PrecompileSpecId, Precompiles, + }, Context, Inspector, }; use revm_primitives::{hardfork::SpecId, Address}; @@ -157,18 +160,73 @@ impl Inspector for OpCodeTrackingInspect } } -#[derive(Debug)] pub struct CustomCrypto { - kzg_settings: KzgSettings, + kzg: crate::precompiles::KzgVerifier, +} + +impl Debug for CustomCrypto { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("CustomCrypto") + } } impl Default for CustomCrypto { fn default() -> Self { - Self { kzg_settings: KzgSettings::load_trusted_setup_file().unwrap() } + let settings = KzgSettings::load_trusted_setup_file().unwrap(); + Self { kzg: crate::precompiles::KzgVerifier::new(&settings) } } } impl Crypto for CustomCrypto { + fn bn254_g1_add(&self, p1: &[u8], p2: &[u8]) -> Result<[u8; 64], PrecompileError> { + crate::precompiles::bn254_g1_add(p1, p2) + } + + fn bn254_g1_mul(&self, point: &[u8], scalar: &[u8]) -> Result<[u8; 64], PrecompileError> { + crate::precompiles::bn254_g1_mul(point, scalar) + } + + fn bls12_381_g1_add(&self, a: G1Point, b: G1Point) -> Result<[u8; 96], PrecompileError> { + crate::precompiles::bls12_381_g1_add(a, b) + } + + fn bls12_381_g1_msm( + &self, + pairs: &mut dyn Iterator>, + ) -> Result<[u8; 96], PrecompileError> { + crate::precompiles::bls12_381_g1_msm(pairs) + } + + fn bls12_381_g2_add(&self, a: G2Point, b: G2Point) -> Result<[u8; 192], PrecompileError> { + crate::precompiles::bls12_381_g2_add(a, b) + } + + fn bls12_381_g2_msm( + &self, + pairs: &mut dyn Iterator>, + ) -> Result<[u8; 192], PrecompileError> { + crate::precompiles::bls12_381_g2_msm(pairs) + } + + fn bls12_381_pairing_check( + &self, + pairs: &[(G1Point, G2Point)], + ) -> Result { + crate::precompiles::bls12_381_pairing_check(pairs) + } + + fn bls12_381_fp_to_g1(&self, fp: &[u8; 48]) -> Result<[u8; 96], PrecompileError> { + crate::precompiles::bls12_381_fp_to_g1(fp) + } + + fn bls12_381_fp2_to_g2(&self, fp2: ([u8; 48], [u8; 48])) -> Result<[u8; 192], PrecompileError> { + crate::precompiles::bls12_381_fp2_to_g2(fp2) + } + + fn modexp(&self, base: &[u8], exp: &[u8], modulus: &[u8]) -> Result, PrecompileError> { + Ok(crate::precompiles::modexp(base, exp, modulus)) + } + fn verify_kzg_proof( &self, z: &[u8; 32], @@ -176,18 +234,9 @@ impl Crypto for CustomCrypto { commitment: &[u8; 48], proof: &[u8; 48], ) -> Result<(), PrecompileError> { - if !KzgProof::verify_kzg_proof( - &Bytes48(*commitment), - &Bytes32(*z), - &Bytes32(*y), - &Bytes48(*proof), - &self.kzg_settings, - ) - .map_err(|err| PrecompileError::other(err.to_string()))? - { + if !self.kzg.verify(z, y, commitment, proof)? { return Err(PrecompileError::BlobVerifyKzgProofFailed); } - Ok(()) } } diff --git a/crates/executor/guest/src/error.rs b/crates/executor/guest/src/error.rs index 557bd8e..23153c0 100644 --- a/crates/executor/guest/src/error.rs +++ b/crates/executor/guest/src/error.rs @@ -11,6 +11,8 @@ pub enum ClientError { MismatchedStateRoot, #[error("Mismatched storage root after executing the block")] MismatchedStorageRoot, + #[error("Invalid state witness: {0}")] + InvalidWitness(String), #[error("unknown chain ID: {}", .0)] UnknownChainId(u64), #[error("Missing bytecode for account {}", .0)] diff --git a/crates/executor/guest/src/executor.rs b/crates/executor/guest/src/executor.rs index 3e4dca8..a5bd665 100644 --- a/crates/executor/guest/src/executor.rs +++ b/crates/executor/guest/src/executor.rs @@ -11,13 +11,13 @@ use reth_evm::{ use reth_evm_ethereum::EthEvmConfig; use reth_execution_types::ExecutionOutcome; use reth_primitives_traits::Block; -use reth_trie::KeccakKeyHasher; use revm::{database::WrapDatabaseRef, install_crypto}; use revm_primitives::Address; use crate::{ custom::{CustomCrypto, CustomEvmFactory}, error::ClientError, + hashed_keys::MemoKeyHasher, into_primitives::FromInput, io::{ClientExecutorInput, TrieDB, WitnessInput}, tracking::OpCodesTrackingBlockExecutor, @@ -52,15 +52,17 @@ where { pub fn execute( &self, - mut input: ClientExecutorInput, + input: ClientExecutorInput, ) -> Result<(Header, B256), ClientError> { let sealed_headers = input.sealed_headers().collect::>(); - // Initialize the witnessed database with verified storage proofs. - let db = profile_report!(INIT_WITNESS_DB, { - let trie_db = input.witness_db(&sealed_headers).unwrap(); - WrapDatabaseRef(trie_db) - }); + // Materialise the witnessed state (every node hash-checked) and wrap it + // as the execution database. + let mut state = profile_report!(INIT_WITNESS_DB, { + mpt::ArenaState::from_witness(&input.parent_state) + .map_err(|e| ClientError::InvalidWitness(e.to_string())) + })?; + let db = WrapDatabaseRef(input.witness_db(&state, &sealed_headers)?); let chain_id: u64 = (&input.genesis).try_into().expect("convert chain id err"); @@ -77,7 +79,7 @@ where profile_report!(BLOCK_EXECUTION, { block_executor.execute(&block) })?; // Validate the block post execution. - profile_report!(VALIDATE_EXECUTION, { + let checked_bloom = profile_report!(VALIDATE_EXECUTION, { C::Primitives::validate_block_post_execution( &block, self.chain_spec.clone(), @@ -85,13 +87,21 @@ where ) })?; - // Accumulate the logs bloom. - let mut logs_bloom = Bloom::default(); - profile_report!(ACCRUE_LOG_BLOOM, { - execution_output.result.receipts.iter().for_each(|r| { - logs_bloom.accrue_bloom(&r.bloom()); - }) - }); + // The logs bloom: the one validation checked against the receipts, + // else accumulated here. A receipt bloom hashes every log address and + // topic, so accumulating it again cost a keccak per log entry. + let logs_bloom = match checked_bloom { + Some(bloom) => bloom, + None => { + let mut logs_bloom = Bloom::default(); + profile_report!(ACCRUE_LOG_BLOOM, { + execution_output.result.receipts.iter().for_each(|r| { + logs_bloom.accrue_bloom(&r.bloom()); + }) + }); + logs_bloom + } + }; // Convert the output to an execution outcome. let executor_outcome = ExecutionOutcome::new( @@ -101,12 +111,12 @@ where vec![execution_output.result.requests], ); - let parent_state_root = input.parent_state.state_root(); + let parent_state_root = input.parent_state.state_root; // Verify the state root. let state_root = profile_report!(COMPUTE_STATE_ROOT, { - input.parent_state.update(&executor_outcome.hash_state_slow::()); - input.parent_state.state_root() + state.update(&executor_outcome.hash_state_slow::()); + state.state_root() }); if state_root != input.current_block.header().state_root() { diff --git a/crates/executor/guest/src/hashed_keys.rs b/crates/executor/guest/src/hashed_keys.rs new file mode 100644 index 0000000..5cae19f --- /dev/null +++ b/crates/executor/guest/src/hashed_keys.rs @@ -0,0 +1,72 @@ +//! Memoised keccak of trie keys. +//! +//! A block hashes the same account addresses and storage slots many times: +//! [`TrieDB`](crate::io::TrieDB) hashes both on every read, and the post-state +//! root pass hashes every changed account and slot again. In the zkVM each of +//! those is a KeccakSponge precompile call, and that chip is about a third of a +//! block's proving area, so a repeat costs far more than the map probe that +//! avoids it (block 25955640: 17,311 of its 22,298 address and slot hashes were +//! repeats). +//! +//! The memo only ever holds digests this execution computed itself, so a hit +//! returns exactly what a fresh keccak would. Off the zkVM the functions hash +//! directly: the host runs one block after another in one process, where a +//! per-thread memo would only grow. + +use alloy_primitives::{keccak256, Address, B256}; +use reth_trie::KeyHasher; + +#[cfg(target_os = "zkvm")] +mod memo { + use std::cell::RefCell; + + use alloy_primitives::{keccak256, map::HashMap, Address, B256}; + + thread_local! { + static ADDRESSES: RefCell> = RefCell::new(HashMap::default()); + static SLOTS: RefCell> = RefCell::new(HashMap::default()); + } + + pub(super) fn address(address: Address) -> B256 { + ADDRESSES.with(|m| *m.borrow_mut().entry(address).or_insert_with(|| keccak256(address))) + } + + pub(super) fn slot(slot: B256) -> B256 { + SLOTS.with(|m| *m.borrow_mut().entry(slot).or_insert_with(|| keccak256(slot))) + } +} + +/// `keccak256(address)`, the account's key in the state trie. +#[inline] +pub fn hashed_address(address: Address) -> B256 { + #[cfg(target_os = "zkvm")] + return memo::address(address); + #[cfg(not(target_os = "zkvm"))] + keccak256(address) +} + +/// `keccak256(slot)`, the slot's key in its storage trie. +#[inline] +pub fn hashed_slot(slot: B256) -> B256 { + #[cfg(target_os = "zkvm")] + return memo::slot(slot); + #[cfg(not(target_os = "zkvm"))] + keccak256(slot) +} + +/// [`KeccakKeyHasher`](reth_trie::KeccakKeyHasher) through the memo: the +/// post-state pass hands it 20-byte addresses and 32-byte slots. +#[derive(Clone, Debug, Default)] +pub struct MemoKeyHasher; + +impl KeyHasher for MemoKeyHasher { + #[inline] + fn hash_key>(bytes: T) -> B256 { + let bytes = bytes.as_ref(); + match bytes.len() { + 20 => hashed_address(Address::from_slice(bytes)), + 32 => hashed_slot(B256::from_slice(bytes)), + _ => keccak256(bytes), + } + } +} diff --git a/crates/executor/guest/src/into_primitives.rs b/crates/executor/guest/src/into_primitives.rs index d074190..c160869 100644 --- a/crates/executor/guest/src/into_primitives.rs +++ b/crates/executor/guest/src/into_primitives.rs @@ -1,8 +1,9 @@ use std::sync::Arc; -use alloy_consensus::{Block, Header, TxEnvelope}; +use alloy_consensus::{Block, BlockHeader, Header, TxEnvelope}; use alloy_network::{Ethereum, Network}; -use reth_chainspec::{ChainSpec, EthChainSpec, NamedChain}; +use alloy_primitives::Bloom; +use reth_chainspec::{ChainSpec, EthChainSpec, EthereumHardforks, NamedChain}; use reth_consensus::HeaderValidator; use reth_consensus_common::validation::validate_body_against_header; use reth_errors::ConsensusError; @@ -39,11 +40,14 @@ pub trait BlockValidator: NodePrimitives { chain_spec: Arc, ) -> Result<(), ConsensusError>; + /// Validates the execution output against the block, and returns the + /// logs bloom that validation checked equal to the receipts' blooms, if + /// it checked one, so the caller need not accumulate it again. fn validate_block_post_execution( block: &RecoveredBlock, chain_spec: Arc, execution_output: &BlockExecutionOutput, - ) -> Result<(), ConsensusError>; + ) -> Result, ConsensusError>; } impl IntoPrimitives for EthPrimitives { @@ -104,13 +108,17 @@ impl BlockValidator for EthPrimitives { block: &RecoveredBlock, chain_spec: Arc, execution_output: &BlockExecutionOutput, - ) -> Result<(), ConsensusError> { + ) -> Result, ConsensusError> { reth_ethereum_consensus::validate_block_post_execution( block, &chain_spec, &execution_output.result.receipts, &execution_output.result.requests, - ) + )?; + // From Byzantium on, `verify_receipts` has compared the bloom of the + // receipts with the header's. + let header = block.header(); + Ok(chain_spec.is_byzantium_active_at_block(header.number()).then(|| header.logs_bloom())) } } @@ -184,12 +192,13 @@ impl BlockValidator block: &RecoveredBlock, chain_spec: Arc, execution_output: &BlockExecutionOutput, - ) -> Result<(), ConsensusError> { + ) -> Result, ConsensusError> { reth_optimism_consensus::validate_block_post_execution( block.header(), &chain_spec, &execution_output.result, - ) + )?; + Ok(None) } } diff --git a/crates/executor/guest/src/io.rs b/crates/executor/guest/src/io.rs index 110f7f4..ad95480 100644 --- a/crates/executor/guest/src/io.rs +++ b/crates/executor/guest/src/io.rs @@ -3,21 +3,24 @@ use std::iter::once; use alloy_consensus::{Block, BlockHeader, Header}; use alloy_primitives::map::HashMap; use itertools::Itertools; -use mpt::EthereumState; +use mpt::{ArenaState, WitnessState}; use primitives::genesis::Genesis; use reth_errors::ProviderError; use reth_ethereum_primitives::EthPrimitives; use reth_primitives_traits::{NodePrimitives, SealedHeader}; -use reth_trie::{TrieAccount, EMPTY_ROOT_HASH}; use revm::{ + bytecode::{eip7702::EIP7702_MAGIC_BYTES, JumpTable, LegacyAnalyzedBytecode}, state::{AccountInfo, Bytecode}, DatabaseRef, }; -use revm_primitives::{keccak256, Address, B256, U256}; +use revm_primitives::{keccak256, Address, Bytes, B256, U256}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use crate::error::ClientError; +use crate::{ + error::ClientError, + hashed_keys::{hashed_address, hashed_slot}, +}; pub type EthClientExecutorInput = ClientExecutorInput; @@ -41,10 +44,19 @@ pub struct ClientExecutorInput { /// to provide the parent state root. #[serde_as(as = "Vec")] pub ancestor_headers: Vec
, - /// Network state as of the parent block. - pub parent_state: EthereumState, - /// Account bytecodes. - pub bytecodes: Vec, + /// Network state as of the parent block, in witness form (root hashes and + /// preorder streams of raw RLP nodes); the guest materialises it into an + /// [`ArenaState`], checking every node against the digest that references it. + pub parent_state: WitnessState, + /// Account bytecodes, as deployed: the guest derives the jump table + /// itself, since one taken from the host would decide which jumps are + /// valid without being bound by the code hash. + pub bytecodes: Vec, + /// The code hash the host claims for each entry of `bytecodes`; the guest + /// checks a claim the first time that code executes, so code that is only + /// shipped (touched accounts that never run) is never hashed. + #[serde(default)] + pub code_hashes: Vec, /// The genesis block, as a json string. pub genesis: Genesis, /// The genesis block, as a json string. @@ -60,15 +72,19 @@ impl ClientExecutorInput

{ self.ancestor_headers.last().unwrap() } - /// Creates a [`WitnessDb`]. - pub fn witness_db(&self, sealed_headers: &[SealedHeader]) -> Result, ClientError> { - ::witness_db(self, sealed_headers) + /// Creates a [`TrieDB`] over the materialised `state`. + pub fn witness_db<'a>( + &'a self, + state: &'a ArenaState, + sealed_headers: &[SealedHeader], + ) -> Result, ClientError> { + ::witness_db(self, state, sealed_headers) } } impl WitnessInput for ClientExecutorInput

{ #[inline(always)] - fn state(&self) -> &EthereumState { + fn state(&self) -> &WitnessState { &self.parent_state } @@ -78,10 +94,15 @@ impl WitnessInput for ClientExecutorInput

{ } #[inline(always)] - fn bytecodes(&self) -> impl Iterator { + fn bytecodes(&self) -> impl Iterator { self.bytecodes.iter() } + #[inline(always)] + fn code_hashes(&self) -> &[B256] { + &self.code_hashes + } + #[inline(always)] fn sealed_headers(&self) -> impl Iterator { self.ancestor_headers @@ -91,20 +112,98 @@ impl WitnessInput for ClientExecutorInput

{ } } +/// A contract's code as deployed followed by [`RawCode::PADDING`] zero +/// bytes, read from the input without a copy. The zeros are the `STOP`s the +/// interpreter runs into past the end of the code, at most a 32-byte push +/// operand and one `STOP`. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct RawCode(#[serde(deserialize_with = "mpt::input_bytes")] pub Bytes); + +impl RawCode { + pub const PADDING: usize = 33; + + /// `code` with its padding. + pub fn new(code: &[u8]) -> Self { + let mut padded = Vec::with_capacity(code.len() + Self::PADDING); + padded.extend_from_slice(code); + padded.resize(code.len() + Self::PADDING, 0); + Self(padded.into()) + } + + /// The code as deployed. + pub fn code(&self) -> &[u8] { + &self.0[..self.0.len() - Self::PADDING] + } + + /// The analyzed bytecode: its jump table derived here, the padding + /// checked to be zeros. + /// + /// # Panics + /// Panics if the padding is missing or not zero. + pub fn analyze(&self) -> Bytecode { + let len = self.0.len().checked_sub(Self::PADDING).expect("code padding"); + assert!(self.0[len..].iter().all(|&b| b == 0), "code padding is not zero"); + let code = &self.0[..len]; + if code.starts_with(&EIP7702_MAGIC_BYTES) { + return Bytecode::new_raw(self.0.slice(..len)); + } + let jump_table = JumpTable::from_bytes(jump_table(&self.0, len).into(), len); + Bytecode::LegacyAnalyzed(LegacyAnalyzedBytecode::new(self.0.clone(), len, jump_table)) + } +} + +/// Bytes an opcode spans, its own byte included: `n + 1` for `PUSHn`, else 1. +const OPCODE_SPAN: [u8; 256] = { + let mut span = [1u8; 256]; + let mut n = 1; + while n <= 32 { + span[0x5f + n] = n as u8 + 1; + n += 1; + } + span +}; + +/// The `JUMPDEST` bitmap of the first `len` bytes of `padded`, bit `i & 7` of +/// byte `i >> 3` set when byte `i` starts an instruction and is `0x5b`. +/// +/// The walk reads only bytes below `len`; a push operand may carry the +/// cursor up to 32 bytes past it, which ends the walk. The raw pointers are +/// sound because the cursor is compared against the end before every read +/// and `i >> 3 < ⌈len/8⌉` for every `i < len`. +fn jump_table(padded: &[u8], len: usize) -> Vec { + assert!(len <= padded.len()); + let mut table = vec![0u8; len.div_ceil(8)]; + let base = padded.as_ptr(); + let end = base.wrapping_add(len); + let mut p = base; + while p < end { + let op = unsafe { *p }; + if op == revm::bytecode::opcode::JUMPDEST { + let i = p as usize - base as usize; + unsafe { *table.get_unchecked_mut(i >> 3) |= 1 << (i & 7) }; + } + p = p.wrapping_add(OPCODE_SPAN[op as usize] as usize); + } + table +} + #[derive(Debug)] pub struct TrieDB<'a> { - inner: &'a EthereumState, + inner: &'a ArenaState, block_hashes: HashMap, - bytecode_by_hash: HashMap, + /// Keyed by the host's CLAIMED hash; a claim is trusted only after + /// `verified_code` holds its analysis. + bytecode_by_hash: HashMap, + verified_code: core::cell::RefCell>, } impl<'a> TrieDB<'a> { pub fn new( - inner: &'a EthereumState, + inner: &'a ArenaState, block_hashes: HashMap, - bytecode_by_hash: HashMap, + bytecode_by_hash: HashMap, ) -> Self { - Self { inner, block_hashes, bytecode_by_hash } + Self { inner, block_hashes, bytecode_by_hash, verified_code: Default::default() } } } @@ -122,10 +221,10 @@ impl DatabaseRef for TrieDB<'_> { return Ok(Some(AccountInfo::default())) } - let hashed_address = keccak256(address); + let hashed_address = hashed_address(address); let hashed_address = hashed_address.as_slice(); - let account_in_trie = self.inner.state_trie.get_rlp::(hashed_address).unwrap(); + let account_in_trie = self.inner.account(hashed_address).unwrap(); let account = account_in_trie.map(|account_in_trie| AccountInfo { balance: account_in_trie.balance, @@ -138,35 +237,28 @@ impl DatabaseRef for TrieDB<'_> { } /// Get account code by its hash. + /// + /// The claimed hash is checked, and the jump table derived, the first time + /// the code is used; a wrong claim aborts the execution. fn code_by_hash_ref(&self, hash: B256) -> Result { - Ok(self.bytecode_by_hash.get(&hash).map(|code| (*code).clone()).unwrap()) + if let Some(code) = self.verified_code.borrow().get(&hash) { + return Ok(code.clone()); + } + let raw = *self.bytecode_by_hash.get(&hash).expect("bytecode for hash must be provided"); + assert_eq!(keccak256(raw.code()), hash, "bytecode does not match its claimed hash"); + let code = raw.analyze(); + self.verified_code.borrow_mut().insert(hash, code.clone()); + Ok(code) } /// Get storage value of address at index. fn storage_ref(&self, address: Address, index: U256) -> Result { - let hashed_address = keccak256(address); - let hashed_address = hashed_address.as_slice(); - - let storage_trie = match self.inner.storage_tries.get(hashed_address) { - Some(trie) => trie, - None => { - // A witness may omit storage for an absent account or an account - // whose authenticated storage root is empty. Never substitute - // zero for an unresolved account proof or non-empty storage. - let account = self.inner.state_trie.get_rlp::(hashed_address) - .map_err(|err| ProviderError::TrieWitnessError(err.to_string()))?; - if account.map_or(EMPTY_ROOT_HASH, |a| a.storage_root) == EMPTY_ROOT_HASH { - return Ok(U256::ZERO); - } - return Err(ProviderError::TrieWitnessError(format!( - "missing non-empty storage trie for {address}" - ))); - } - }; + let hashed_address = hashed_address(address); - Ok(storage_trie - .get_rlp::(keccak256(index.to_be_bytes::<32>()).as_slice()) - .expect("Can get from MPT") + Ok(self + .inner + .storage(&hashed_address, hashed_slot(B256::from(index.to_be_bytes::<32>())).as_slice()) + .map_err(|err| ProviderError::TrieWitnessError(err.to_string()))? .unwrap_or_default()) } @@ -181,15 +273,18 @@ impl DatabaseRef for TrieDB<'_> { /// A trait for constructing [`WitnessDb`]. pub trait WitnessInput { - /// Gets a reference to the state from which account info and storage slots are loaded. - fn state(&self) -> &EthereumState; + /// Gets the witness state from which account info and storage slots are loaded. + fn state(&self) -> &WitnessState; /// Gets the state trie root hash that the state referenced by /// [state()](trait.WitnessInput#tymethod.state) must conform to. fn state_anchor(&self) -> B256; - /// Gets an iterator over account bytecodes. - fn bytecodes(&self) -> impl Iterator; + /// Gets an iterator over account bytecodes, as deployed. + fn bytecodes(&self) -> impl Iterator; + + /// The claimed code hash of each bytecode, in the same order. + fn code_hashes(&self) -> &[B256]; /// Gets an iterator over references to a consecutive, reverse-chronological block headers /// starting from the current block header. @@ -203,24 +298,29 @@ pub trait WitnessInput { /// implementing this trait causes a zkVM run to cost over 5M cycles more. To avoid this, define /// a method inside the type that calls this trait method instead. #[inline(always)] - fn witness_db(&self, sealed_headers: &[SealedHeader]) -> Result, ClientError> { - let state = self.state(); - - if self.state_anchor() != state.state_root() { + fn witness_db<'a>( + &'a self, + state: &'a ArenaState, + sealed_headers: &[SealedHeader], + ) -> Result, ClientError> { + // `state` was built from `self.state()`: every node keccak-checked + // against its parent's digest, the state trie against + // `state_root`, every storage trie against its account's storage + // root. What remains is binding that root to the parent header. + if self.state_anchor() != self.state().state_root { return Err(ClientError::MismatchedStateRoot); } - for (hashed_address, storage_trie) in state.storage_tries.iter() { - let account = - state.state_trie.get_rlp::(hashed_address.as_slice()).unwrap(); - let storage_root = account.map_or(EMPTY_ROOT_HASH, |a| a.storage_root); - if storage_root != storage_trie.hash() { - return Err(ClientError::MismatchedStorageRoot); - } + // Bytecodes are indexed by the host's claimed hash and verified on + // first use (see `TrieDB::code_by_hash_ref`); hashing every shipped + // contract up front was ~8 M cycles on a reth block, much of it for + // code that never runs. + let claimed = self.code_hashes(); + if claimed.len() != self.bytecodes().count() { + return Err(ClientError::InvalidWitness("code_hashes/bytecodes length mismatch".into())); } - let bytecodes_by_hash = - self.bytecodes().map(|code| (code.hash_slow(), code)).collect::>(); + claimed.iter().copied().zip(self.bytecodes()).collect::>(); // Verify and build block hashes let mut block_hashes: HashMap = HashMap::with_hasher(Default::default()); @@ -246,38 +346,3 @@ pub trait WitnessInput { Ok(TrieDB::new(state, block_hashes, bytecodes_by_hash)) } } - -#[cfg(test)] -mod tests { - use super::*; - - fn state() -> EthereumState { - EthereumState { state_trie: Default::default(), storage_tries: HashMap::default() } - } - - #[test] - fn omitted_storage_for_absent_account_is_zero() { - let state = state(); - let db = TrieDB::new(&state, HashMap::default(), HashMap::default()); - assert_eq!(db.storage_ref(Address::repeat_byte(1), U256::from(7)).unwrap(), U256::ZERO); - } - - #[test] - fn omitted_storage_with_authenticated_empty_root_is_zero() { - let mut state = state(); - let address = Address::repeat_byte(2); - state.state_trie.insert_rlp(keccak256(address).as_slice(), TrieAccount::default()).unwrap(); - let db = TrieDB::new(&state, HashMap::default(), HashMap::default()); - assert_eq!(db.storage_ref(address, U256::from(7)).unwrap(), U256::ZERO); - } - - #[test] - fn omitted_non_empty_storage_is_rejected() { - let mut state = state(); - let address = Address::repeat_byte(3); - let account = TrieAccount { storage_root: B256::repeat_byte(4), ..Default::default() }; - state.state_trie.insert_rlp(keccak256(address).as_slice(), account).unwrap(); - let db = TrieDB::new(&state, HashMap::default(), HashMap::default()); - assert!(db.storage_ref(address, U256::from(7)).is_err()); - } -} diff --git a/crates/executor/guest/src/lib.rs b/crates/executor/guest/src/lib.rs index bb754b7..06b6fe6 100644 --- a/crates/executor/guest/src/lib.rs +++ b/crates/executor/guest/src/lib.rs @@ -7,6 +7,8 @@ mod utils; pub mod custom; pub mod error; pub mod executor; +pub mod hashed_keys; +pub mod precompiles; pub mod tracking; mod into_primitives; diff --git a/crates/executor/guest/src/precompiles.rs b/crates/executor/guest/src/precompiles.rs new file mode 100644 index 0000000..be57eac --- /dev/null +++ b/crates/executor/guest/src/precompiles.rs @@ -0,0 +1,563 @@ +//! Precompile arithmetic over the zkVM's curve and field syscalls. +//! +//! revm's default `Crypto` backends run bn254 scalar multiplication in +//! Jacobian coordinates and every BLS12-381 operation on arkworks' pure +//! Montgomery arithmetic, both of which are ordinary MIPS code in the guest. +//! These routines take the same byte inputs and compute with the `bn` +//! fork's affine syscalls and the `bls12_381` fork's syscall-backed field. + +use bls12_381::{ + fp::Fp, fp2::Fp2, hash_to_curve::MapToCurve, multi_miller_loop, G1Affine, G1Projective, + G2Affine, G2Prepared, G2Projective, Gt, Scalar, +}; +use kzg_rs::{ + kzg_proof::{safe_g1_affine_from_bytes, safe_scalar_affine_from_bytes}, + Bytes32, Bytes48, KzgSettings, +}; +use revm::precompile::PrecompileError; + +const FP: usize = 48; + +// --------------------------------------------------------------------------- +// bn254 + +/// The `ecAdd` precompile on two 64-byte points. +pub fn bn254_g1_add(p1: &[u8], p2: &[u8]) -> Result<[u8; 64], PrecompileError> { + let a = bn254::point(p1)?; + let b = bn254::point(p2)?; + Ok(bn254::encode(bn254::add(a, b))) +} + +/// The `ecMul` precompile on a 64-byte point and a 32-byte big-endian scalar. +pub fn bn254_g1_mul(point: &[u8], scalar: &[u8]) -> Result<[u8; 64], PrecompileError> { + let p = bn254::point(point)?; + Ok(bn254::encode(bn254::mul(p, scalar))) +} + +/// bn254 G1 in affine coordinates over the zkVM's curve precompiles, which +/// add two distinct finite points and double a finite point; infinity and +/// the equal-`x` cases are decided here. A point is `x || y` as 32-bit +/// little-endian words, the layout the precompiles read. +#[cfg(target_os = "zkvm")] +mod bn254 { + use revm::precompile::PrecompileError; + use zkm_lib::{syscall_bn254_add, syscall_bn254_double, syscall_uint256_mulmod}; + + type Words = [u32; 8]; + pub type Point = [u32; 16]; + + /// The base field modulus `p`, little-endian words. + const P: Words = [ + 0xd87cfd47, 0x3c208c16, 0x6871ca8d, 0x97816a91, 0x8181585d, 0xb85045b6, 0xe131a029, + 0x30644e72, + ]; + /// The group order `n`, little-endian words. + const N: Words = [ + 0xf0000001, 0x43e1f593, 0x79b97091, 0x2833e848, 0x8181585d, 0xb85045b6, 0xe131a029, + 0x30644e72, + ]; + const ONE: Words = [1, 0, 0, 0, 0, 0, 0, 0]; + const THREE: Words = [3, 0, 0, 0, 0, 0, 0, 0]; + + fn words(be: &[u8]) -> Words { + let mut w = [0u32; 8]; + for (i, word) in w.iter_mut().enumerate() { + *word = u32::from_be_bytes(be[28 - 4 * i..32 - 4 * i].try_into().expect("4 bytes")); + } + w + } + + fn bytes(w: &Words, be: &mut [u8]) { + for (i, word) in w.iter().enumerate() { + be[28 - 4 * i..32 - 4 * i].copy_from_slice(&word.to_be_bytes()); + } + } + + fn lt(a: &Words, b: &Words) -> bool { + for i in (0..8).rev() { + if a[i] != b[i] { + return a[i] < b[i]; + } + } + false + } + + /// `(a · b) mod m` through the 256-bit multiplier, which reads `b` and + /// `m` as one 16-word block. + fn mul_mod(a: &Words, b: &Words, m: &Words) -> Words { + let mut x = *a; + let mut bm = [0u32; 16]; + bm[..8].copy_from_slice(b); + bm[8..].copy_from_slice(m); + unsafe { syscall_uint256_mulmod(&mut x, bm.as_ptr().cast()) }; + x + } + + /// `(a + b) mod p` for `a, b < p`. + fn add_mod_p(a: &Words, b: &Words) -> Words { + let mut r = [0u32; 8]; + let mut carry = 0u64; + for i in 0..8 { + let s = a[i] as u64 + b[i] as u64 + carry; + r[i] = s as u32; + carry = s >> 32; + } + if carry != 0 || !lt(&r, &P) { + let mut borrow = 0i64; + for i in 0..8 { + let d = r[i] as i64 - P[i] as i64 - borrow; + r[i] = d as u32; + borrow = (d < 0) as i64; + } + } + r + } + + /// A point from its 64-byte big-endian `x || y` encoding, `None` for + /// `(0, 0)`; the coordinates must be canonical and on `y² = x³ + 3`. + pub fn point(be: &[u8]) -> Result, PrecompileError> { + let x = words(&be[..32]); + let y = words(&be[32..64]); + if !lt(&x, &P) || !lt(&y, &P) { + return Err(PrecompileError::Bn254FieldPointNotAMember); + } + if x == [0; 8] && y == [0; 8] { + return Ok(None); + } + let lhs = mul_mod(&y, &y, &P); + let rhs = add_mod_p(&mul_mod(&mul_mod(&x, &x, &P), &x, &P), &THREE); + if lhs != rhs { + return Err(PrecompileError::Bn254AffineGFailedToCreate); + } + let mut p = [0u32; 16]; + p[..8].copy_from_slice(&x); + p[8..].copy_from_slice(&y); + Ok(Some(p)) + } + + pub fn encode(p: Option) -> [u8; 64] { + let mut out = [0u8; 64]; + if let Some(p) = p { + bytes(p[..8].try_into().expect("8 words"), &mut out[..32]); + bytes(p[8..].try_into().expect("8 words"), &mut out[32..]); + } + out + } + + fn double(mut p: Point) -> Point { + unsafe { syscall_bn254_double(&mut p) }; + p + } + + /// `a + b`: equal points are doubled, opposite points (equal `x`) cancel. + pub fn add(a: Option, b: Option) -> Option { + match (a, b) { + (None, b) => b, + (a, None) => a, + (Some(mut a), Some(b)) => { + if a[..8] == b[..8] { + if a[8..] == b[8..] { + Some(double(a)) + } else { + None + } + } else { + unsafe { syscall_bn254_add(&mut a, &b) }; + Some(a) + } + } + } + } + + /// `k · p` by double-and-add. `k` is reduced modulo `n` first, so no + /// partial sum `k' · p` with `k' ≤ k / 2 < n - 1` equals `-p`, the one + /// case the addition cannot take; the partial sum `p` itself is only + /// ever doubled. + pub fn mul(p: Option, k: &[u8]) -> Option { + let p = p?; + let k = mul_mod(&words(k), &ONE, &N); + let mut acc: Option = None; + for i in (0..8).rev() { + for j in (0..32).rev() { + if let Some(a) = acc { + acc = Some(double(a)); + } + if (k[i] >> j) & 1 == 1 { + acc = add(acc, Some(p)); + } + } + } + acc + } +} + +/// bn254 G1 off the zkVM, through the `bn` crate. +#[cfg(not(target_os = "zkvm"))] +mod bn254 { + use bn::{AffineG1, Fq, Fr, G1}; + use revm::precompile::PrecompileError; + + pub type Point = G1; + + pub fn point(be: &[u8]) -> Result, PrecompileError> { + let x = + Fq::from_slice(&be[..32]).map_err(|_| PrecompileError::Bn254FieldPointNotAMember)?; + let y = + Fq::from_slice(&be[32..64]).map_err(|_| PrecompileError::Bn254FieldPointNotAMember)?; + if x.is_zero() && y.is_zero() { + return Ok(None); + } + AffineG1::new(x, y) + .map(|p| Some(p.into())) + .map_err(|_| PrecompileError::Bn254AffineGFailedToCreate) + } + + pub fn encode(p: Option) -> [u8; 64] { + let mut out = [0u8; 64]; + if let Some(p) = p.and_then(AffineG1::from_jacobian) { + p.x().to_big_endian(&mut out[..32]).expect("32 bytes"); + p.y().to_big_endian(&mut out[32..]).expect("32 bytes"); + } + out + } + + pub fn add(a: Option, b: Option) -> Option { + match (a, b) { + (None, b) => b, + (a, None) => a, + (Some(a), Some(b)) => Some(a + b), + } + } + + pub fn mul(p: Option, k: &[u8]) -> Option { + let k = Fr::from_slice(k).expect("32 bytes"); + p.map(|p| p * k) + } +} + +// --------------------------------------------------------------------------- +// BLS12-381 + +fn is_zero(bytes: &[u8]) -> bool { + bytes.iter().all(|&b| b == 0) +} + +fn fp(bytes: &[u8; FP]) -> Result { + Option::from(Fp::from_bytes(bytes)).ok_or(PrecompileError::NonCanonicalFp) +} + +fn fp2(c0: &[u8; FP], c1: &[u8; FP]) -> Result { + Ok(Fp2 { c0: fp(c0)?, c1: fp(c1)? }) +} + +/// A G1 point from its EIP-2537 coordinates, `(0, 0)` being the identity; +/// checked to be canonical and on the curve, and in the subgroup when asked. +fn g1(x: &[u8; FP], y: &[u8; FP], subgroup: bool) -> Result { + if is_zero(x) && is_zero(y) { + return Ok(G1Affine::identity()); + } + let mut bytes = [0u8; 2 * FP]; + bytes[..FP].copy_from_slice(x); + bytes[FP..].copy_from_slice(y); + let p: G1Affine = Option::from(G1Affine::from_uncompressed_unchecked(&bytes)) + .ok_or(PrecompileError::NonCanonicalFp)?; + if !bool::from(p.is_on_curve()) { + return Err(PrecompileError::Bls12381G1NotOnCurve); + } + if subgroup && !bool::from(p.is_torsion_free()) { + return Err(PrecompileError::Bls12381G1NotInSubgroup); + } + Ok(p) +} + +/// A G2 point from its EIP-2537 coordinates `(x0, x1, y0, y1)`. The +/// library's uncompressed form orders each Fp2 as `c1 || c0`. +fn g2( + x0: &[u8; FP], + x1: &[u8; FP], + y0: &[u8; FP], + y1: &[u8; FP], + subgroup: bool, +) -> Result { + if is_zero(x0) && is_zero(x1) && is_zero(y0) && is_zero(y1) { + return Ok(G2Affine::identity()); + } + let mut bytes = [0u8; 4 * FP]; + bytes[..FP].copy_from_slice(x1); + bytes[FP..2 * FP].copy_from_slice(x0); + bytes[2 * FP..3 * FP].copy_from_slice(y1); + bytes[3 * FP..].copy_from_slice(y0); + let p: G2Affine = Option::from(G2Affine::from_uncompressed_unchecked(&bytes)) + .ok_or(PrecompileError::NonCanonicalFp)?; + if !bool::from(p.is_on_curve()) { + return Err(PrecompileError::Bls12381G2NotOnCurve); + } + if subgroup && !bool::from(p.is_torsion_free()) { + return Err(PrecompileError::Bls12381G2NotInSubgroup); + } + Ok(p) +} + +/// The EIP-2537 encoding of a G1 point, zeros for the identity. +fn encode_g1(p: &G1Affine) -> [u8; 2 * FP] { + if bool::from(p.is_identity()) { + return [0u8; 2 * FP]; + } + p.to_uncompressed() +} + +/// The EIP-2537 encoding `x0 || x1 || y0 || y1` of a G2 point. +fn encode_g2(p: &G2Affine) -> [u8; 4 * FP] { + let mut out = [0u8; 4 * FP]; + if bool::from(p.is_identity()) { + return out; + } + let lib = p.to_uncompressed(); + out[..FP].copy_from_slice(&lib[FP..2 * FP]); + out[FP..2 * FP].copy_from_slice(&lib[..FP]); + out[2 * FP..3 * FP].copy_from_slice(&lib[3 * FP..]); + out[3 * FP..].copy_from_slice(&lib[2 * FP..3 * FP]); + out +} + +/// A scalar from 32 big-endian bytes, reduced modulo the group order as +/// EIP-2537 asks. +fn scalar(bytes: &[u8; 32]) -> Scalar { + let mut wide = [0u8; 64]; + for (i, &b) in bytes.iter().enumerate() { + wide[31 - i] = b; + } + Scalar::from_bytes_wide(&wide) +} + +pub type G1Point = ([u8; FP], [u8; FP]); +pub type G2Point = ([u8; FP], [u8; FP], [u8; FP], [u8; FP]); + +pub fn bls12_381_g1_add(a: G1Point, b: G1Point) -> Result<[u8; 2 * FP], PrecompileError> { + let a = g1(&a.0, &a.1, false)?; + let b = g1(&b.0, &b.1, false)?; + Ok(encode_g1(&G1Affine::from(G1Projective::from(a) + b))) +} + +pub fn bls12_381_g2_add(a: G2Point, b: G2Point) -> Result<[u8; 4 * FP], PrecompileError> { + let a = g2(&a.0, &a.1, &a.2, &a.3, false)?; + let b = g2(&b.0, &b.1, &b.2, &b.3, false)?; + Ok(encode_g2(&G2Affine::from(G2Projective::from(a) + b))) +} + +pub fn bls12_381_g1_msm( + pairs: &mut dyn Iterator>, +) -> Result<[u8; 2 * FP], PrecompileError> { + let mut acc = G1Projective::identity(); + for pair in pairs { + let ((x, y), k) = pair?; + let p = g1(&x, &y, true)?; + if bool::from(p.is_identity()) || is_zero(&k) { + continue; + } + acc += p * scalar(&k); + } + Ok(encode_g1(&G1Affine::from(acc))) +} + +pub fn bls12_381_g2_msm( + pairs: &mut dyn Iterator>, +) -> Result<[u8; 4 * FP], PrecompileError> { + let mut acc = G2Projective::identity(); + for pair in pairs { + let ((x0, x1, y0, y1), k) = pair?; + let p = g2(&x0, &x1, &y0, &y1, true)?; + if bool::from(p.is_identity()) || is_zero(&k) { + continue; + } + acc += p * scalar(&k); + } + Ok(encode_g2(&G2Affine::from(acc))) +} + +/// Whether the product of the pairings is the identity. Every point is +/// validated (subgroup included); a pair with an identity contributes the +/// identity and is left out of the Miller loop. +pub fn bls12_381_pairing_check(pairs: &[(G1Point, G2Point)]) -> Result { + let mut g1s = Vec::with_capacity(pairs.len()); + let mut g2s = Vec::with_capacity(pairs.len()); + for ((x, y), (x0, x1, y0, y1)) in pairs { + let p = g1(x, y, true)?; + let q = g2(x0, x1, y0, y1, true)?; + if bool::from(p.is_identity()) || bool::from(q.is_identity()) { + continue; + } + g1s.push(p); + g2s.push(G2Prepared::from(q)); + } + if g1s.is_empty() { + return Ok(true); + } + let terms: Vec<(&G1Affine, &G2Prepared)> = g1s.iter().zip(&g2s).collect(); + Ok(multi_miller_loop(&terms).final_exponentiation() == Gt::identity()) +} + +pub fn bls12_381_fp_to_g1(bytes: &[u8; FP]) -> Result<[u8; 2 * FP], PrecompileError> { + let u = fp(bytes)?; + let p = G1Projective::map_to_curve(&u).clear_h(); + Ok(encode_g1(&G1Affine::from(p))) +} + +pub fn bls12_381_fp2_to_g2(c: ([u8; FP], [u8; FP])) -> Result<[u8; 4 * FP], PrecompileError> { + let u = fp2(&c.0, &c.1)?; + let p = G2Projective::map_to_curve(&u).clear_h(); + Ok(encode_g2(&G2Affine::from(p))) +} + +// --------------------------------------------------------------------------- +// KZG point evaluation + +/// The pairing check of the KZG point-evaluation precompile with its two +/// G2 arguments fixed, so both are prepared once: +/// +/// `e(P - y·G1, G2) · e(-π, τ·G2 - z·G2) = 1` is, by bilinearity, +/// `e(P - y·G1 + z·π, G2) · e(-π, τ·G2) = 1`, +/// +/// which moves the only scalar multiplication to G1, where it is one joint +/// double-and-add over `y` and `z`, and leaves the G2 side constant. +pub struct KzgVerifier { + g2: G2Prepared, + tau_g2: G2Prepared, +} + +impl KzgVerifier { + pub fn new(settings: &KzgSettings) -> Self { + Self { + g2: G2Prepared::from(G2Affine::generator()), + tau_g2: G2Prepared::from(settings.g2_points[1]), + } + } + + /// Whether `proof` opens `commitment` at `z` to `y`; the points are + /// decoded with kzg-rs's checks (canonical, on the curve, in the + /// subgroup), the scalars must be canonical. + pub fn verify( + &self, + z: &[u8; 32], + y: &[u8; 32], + commitment: &[u8; 48], + proof: &[u8; 48], + ) -> Result { + let other = |err: kzg_rs::KzgError| PrecompileError::other(err.to_string()); + let z = safe_scalar_affine_from_bytes(&Bytes32(*z)).map_err(other)?; + let y = safe_scalar_affine_from_bytes(&Bytes32(*y)).map_err(other)?; + let commitment = safe_g1_affine_from_bytes(&Bytes48(*commitment)).map_err(other)?; + let proof = safe_g1_affine_from_bytes(&Bytes48(*proof)).map_err(other)?; + + let minus_g1 = -G1Affine::generator(); + let a = + G1Affine::from(linear_combination(&minus_g1, &y, &proof, &z).add_mixed(&commitment)); + let minus_proof = -proof; + let mut terms: Vec<(&G1Affine, &G2Prepared)> = Vec::with_capacity(2); + if !bool::from(a.is_identity()) { + terms.push((&a, &self.g2)); + } + if !bool::from(minus_proof.is_identity()) { + terms.push((&minus_proof, &self.tau_g2)); + } + if terms.is_empty() { + return Ok(true); + } + Ok(multi_miller_loop(&terms).final_exponentiation() == Gt::identity()) + } +} + +/// `s·a + t·b` by one double-and-add over both scalars (Straus), with +/// `a + b` precomputed; nothing here is secret, so the walk is not +/// constant-time. +fn linear_combination(a: &G1Affine, s: &Scalar, b: &G1Affine, t: &Scalar) -> G1Projective { + let ab = G1Affine::from(G1Projective::from(*a).add_mixed(b)); + let s = s.to_bytes(); + let t = t.to_bytes(); + let mut acc = G1Projective::identity(); + let mut started = false; + for i in (0..256).rev() { + if started { + acc = acc.double(); + } + let sb = (s[i / 8] >> (i % 8)) & 1 == 1; + let tb = (t[i / 8] >> (i % 8)) & 1 == 1; + match (sb, tb) { + (true, true) => acc = acc.add_mixed(&ab), + (true, false) => acc = acc.add_mixed(a), + (false, true) => acc = acc.add_mixed(b), + (false, false) => {} + } + started |= sb | tb; + } + acc +} + +// --------------------------------------------------------------------------- +// modexp + +/// `base^exp mod modulus` as big-endian bytes, at most `modulus.len()` of +/// them. Operands of up to 256 bits run as a square-and-multiply ladder on +/// the uint256 multiplier; anything wider takes the generic implementation. +pub fn modexp(base: &[u8], exp: &[u8], modulus: &[u8]) -> Vec { + #[cfg(target_os = "zkvm")] + if base.len() <= 32 && modulus.len() <= 32 { + return modexp256::modexp(base, exp, modulus); + } + aurora_engine_modexp::modexp(base, exp, modulus) +} + +#[cfg(target_os = "zkvm")] +mod modexp256 { + use zkm_lib::syscall_uint256_mulmod; + + type Words = [u32; 8]; + + /// Big-endian bytes (at most 32) as little-endian words. + fn words(be: &[u8]) -> Words { + let mut padded = [0u8; 32]; + padded[32 - be.len()..].copy_from_slice(be); + let mut w = [0u32; 8]; + for (i, word) in w.iter_mut().enumerate() { + *word = u32::from_be_bytes(padded[28 - 4 * i..32 - 4 * i].try_into().expect("4 bytes")); + } + w + } + + /// `(a · b) mod m` for `m ≠ 0`; the multiplier reads `b` and `m` as one + /// 16-word block. + fn mul_mod(a: &Words, b: &Words, m: &Words) -> Words { + let mut x = *a; + let mut bm = [0u32; 16]; + bm[..8].copy_from_slice(b); + bm[8..].copy_from_slice(m); + unsafe { syscall_uint256_mulmod(&mut x, bm.as_ptr().cast()) }; + x + } + + pub fn modexp(base: &[u8], exp: &[u8], modulus: &[u8]) -> Vec { + let m = words(modulus); + if m == [0; 8] || m == [1, 0, 0, 0, 0, 0, 0, 0] { + return Vec::new(); + } + let b = mul_mod(&words(base), &[1, 0, 0, 0, 0, 0, 0, 0], &m); + let mut r: Words = [1, 0, 0, 0, 0, 0, 0, 0]; + let mut started = false; + for &byte in exp { + for j in (0..8).rev() { + if started { + r = mul_mod(&r, &r, &m); + } + if (byte >> j) & 1 == 1 { + r = mul_mod(&r, &b, &m); + started = true; + } + } + } + let mut out = [0u8; 32]; + for (i, word) in r.iter().enumerate() { + out[28 - 4 * i..32 - 4 * i].copy_from_slice(&word.to_be_bytes()); + } + out[32 - modulus.len()..].to_vec() + } +} diff --git a/crates/executor/host/examples/witness_census.rs b/crates/executor/host/examples/witness_census.rs new file mode 100644 index 0000000..34ee4eb --- /dev/null +++ b/crates/executor/host/examples/witness_census.rs @@ -0,0 +1,127 @@ +//! Native census of a cached client input's witness: how many trie nodes of +//! each kind the guest's arena loader walks, how many bytes, and how long the +//! native load takes. `cargo run --release --example witness_census -- ` +use std::time::Instant; + +use guest_executor::io::EthClientExecutorInput; +use mpt::ArenaState; + +const TAG_DIGEST: u8 = 0; +const TAG_NODE: u8 = 1; + +#[derive(Default, Debug)] +struct Census { + nodes: usize, + nulls: usize, + digests: usize, + leaves: usize, + extensions: usize, + branches: usize, + inline_children: usize, + node_bytes: usize, + keccak_blocks: usize, +} + +fn varint(buf: &[u8], pos: &mut usize) -> usize { + let (mut v, mut shift) = (0usize, 0); + loop { + let b = buf[*pos]; + *pos += 1; + v |= ((b & 0x7f) as usize) << shift; + if b & 0x80 == 0 { + return v; + } + shift += 7; + } +} + +fn items(payload: &[u8]) -> usize { + let mut rest = payload; + let mut n = 0; + while !rest.is_empty() { + let h = alloy_rlp::Header::decode(&mut rest).unwrap(); + rest = &rest[h.payload_length..]; + n += 1; + } + n +} + +fn walk(stream: &[u8], c: &mut Census) { + let mut pos = 0; + while pos < stream.len() { + let tag = stream[pos]; + pos += 1; + match tag { + TAG_DIGEST => c.digests += 1, + TAG_NODE => { + let len = varint(stream, &mut pos); + let node = &stream[pos..pos + len]; + pos += len; + c.nodes += 1; + c.node_bytes += len; + c.keccak_blocks += len.div_ceil(136); + let mut b = node; + let h = alloy_rlp::Header::decode(&mut b).unwrap(); + let payload = &b[..h.payload_length]; + if !h.list { + c.nulls += 1; + continue; + } + match items(payload) { + 2 => { + let mut r = payload; + let ph = alloy_rlp::Header::decode(&mut r).unwrap(); + let path = &r[..ph.payload_length]; + if path[0] & 0x20 == 0 { + c.extensions += 1 + } else { + c.leaves += 1 + } + } + 17 => { + c.branches += 1; + let mut r = payload; + for _ in 0..16 { + let ch = alloy_rlp::Header::decode(&mut r).unwrap(); + if ch.list { + c.inline_children += 1; + } + r = &r[ch.payload_length..]; + } + } + n => panic!("node with {n} items"), + } + } + _ => panic!("bad tag"), + } + } +} + +fn main() { + let path = std::env::args().nth(1).expect("input.bin"); + let bytes = std::fs::read(&path).unwrap(); + let t = Instant::now(); + let input: EthClientExecutorInput = bincode::deserialize(&bytes).unwrap(); + println!("input {} B, bincode decode {:?}", bytes.len(), t.elapsed()); + let w = &input.parent_state; + let mut state = Census::default(); + walk(&w.state_nodes, &mut state); + println!("state trie: {} B stream, {state:?}", w.state_nodes.len()); + let mut storage = Census::default(); + let mut storage_bytes = 0; + for sw in &w.storage { + storage_bytes += sw.nodes.len(); + walk(&sw.nodes, &mut storage); + } + println!("storage tries: {} tries, {storage_bytes} B streams, {storage:?}", w.storage.len()); + println!( + "bytecodes: {} ({} code bytes), txs {}", + input.bytecodes.len(), + input.bytecodes.iter().map(|b| b.code().len()).sum::(), + input.current_block.body.transactions.len() + ); + let t = Instant::now(); + let st = ArenaState::from_witness(w).unwrap(); + println!("native ArenaState::from_witness: {:?}", t.elapsed()); + std::hint::black_box(st); +} diff --git a/crates/executor/host/src/full_executor.rs b/crates/executor/host/src/full_executor.rs index 72c810a..1a5ffc6 100644 --- a/crates/executor/host/src/full_executor.rs +++ b/crates/executor/host/src/full_executor.rs @@ -113,10 +113,25 @@ pub trait BlockExecutor { info!("cycles: {:?}", proof_with_cycles.1); - let proving_duration = proving_start.elapsed(); + // Prefer the prover's own measure when it has one. This process + // times the whole call, which with a pipelined caller includes the + // request waiting in the prover's queue; the prover times only the + // proving. Everything downstream — the eth-proofs submission + // among it — should report proving, not queueing. + let proving_duration = self + .client() + .take_prove_ms() + .map(Duration::from_millis) + .unwrap_or_else(|| proving_start.elapsed()); let proof_bytes = bincode::serialize(&proof_with_cycles.0.proof).unwrap(); let public_values_bytes = bincode::serialize(&proof_with_cycles.0.public_values).unwrap(); + // Size census: dump the exact bytes that get submitted so the + // proof's composition can be measured offline. + if let Ok(path) = std::env::var("ZIREN_COMPRESS_PROOF_OUT") { + std::fs::write(&path, &proof_bytes)?; + info!("wrote {} proof bytes to {path}", proof_bytes.len()); + } hooks .on_proving_end( @@ -485,7 +500,15 @@ fn try_load_input_from_cache( if cache_path.exists() { // TODO: prune the cache if invalid instead let mut cache_file = std::fs::File::open(cache_path)?; - let client_input = bincode::deserialize_from(&mut cache_file)?; + let client_input = match bincode::deserialize_from(&mut cache_file) { + Ok(input) => input, + Err(err) => { + tracing::warn!( + "cached input for block {block_number} is unreadable ({err}); refetching" + ); + return Ok(None); + } + }; Ok(Some(client_input)) } else { diff --git a/crates/executor/host/src/host_executor.rs b/crates/executor/host/src/host_executor.rs index 421e69b..8c24c67 100644 --- a/crates/executor/host/src/host_executor.rs +++ b/crates/executor/host/src/host_executor.rs @@ -76,22 +76,41 @@ impl HostExecutor { let chain_id: u64 = (&genesis).try_into().unwrap(); tracing::debug!("chain id: {}", chain_id); - // Fetch the current block and the previous block from the provider. + // Fetch the current block, the previous block and (with the + // execution-witness feature) the witness concurrently. Only the + // witness DB construction needs the parent's state root; the three RPC + // round trips themselves are independent, and run serially they were + // ~4 s of the ~4.2 s an uncached block spends before proving starts. tracing::info!("[{}] fetching the current block and the previous block", block_number); - let rpc_block = provider - .get_block_by_number(block_number.into()) - .full() - .await? - .ok_or(HostError::ExpectedBlock(block_number))?; + let fetch_current = async { + provider + .get_block_by_number(block_number.into()) + .full() + .await? + .ok_or(HostError::ExpectedBlock(block_number)) + }; + let fetch_previous = async { + provider + .get_block_by_number((block_number - 1).into()) + .full() + .await? + .ok_or(HostError::ExpectedBlock(block_number)) + .map(C::Primitives::into_primitive_block) + }; - let current_block = C::Primitives::into_primitive_block(rpc_block.clone()); + #[cfg(not(feature = "execution-witness"))] + let (rpc_block, previous_block) = futures::try_join!(fetch_current, fetch_previous)?; + #[cfg(feature = "execution-witness")] + let (rpc_block, previous_block, execution_witness) = { + let fetch_witness = async { + rpc_db::ExecutionWitnessRpcDb::<_, N>::fetch_witness(debug_provider, block_number) + .await + .map_err(HostError::from) + }; + futures::try_join!(fetch_current, fetch_previous, fetch_witness)? + }; - let previous_block = provider - .get_block_by_number((block_number - 1).into()) - .full() - .await? - .ok_or(HostError::ExpectedBlock(block_number)) - .map(C::Primitives::into_primitive_block)?; + let current_block = C::Primitives::into_primitive_block(rpc_block.clone()); tracing::info!("[{}] create rpc db", block_number); #[cfg(not(feature = "execution-witness"))] @@ -101,12 +120,12 @@ impl HostExecutor { previous_block.header().state_root(), ); #[cfg(feature = "execution-witness")] - let rpc_db = rpc_db::ExecutionWitnessRpcDb::new( + let rpc_db = rpc_db::ExecutionWitnessRpcDb::from_witness( debug_provider, block_number, previous_block.header().state_root(), - ) - .await?; + execution_witness, + ); tracing::info!("[{}] create rpc db done", block_number); let cache_db = CacheDB::new(&rpc_db); @@ -216,8 +235,15 @@ impl HostExecutor { let client_input = ClientExecutorInput { current_block: C::Primitives::into_input_block(current_block), ancestor_headers, - parent_state: state, - bytecodes: rpc_db.bytecodes(), + // Witness form: root hashes + preorder streams of raw RLP nodes; the + // guest builds its arena tries from it, hash-checking every node. + parent_state: state.to_witness_state(), + code_hashes: rpc_db.bytecodes().iter().map(|b| b.hash_slow()).collect(), + bytecodes: rpc_db + .bytecodes() + .iter() + .map(|b| guest_executor::io::RawCode::new(b.original_byte_slice())) + .collect(), genesis, custom_beneficiary, opcode_tracking, diff --git a/crates/mpt/Cargo.toml b/crates/mpt/Cargo.toml index f54e51c..c340c70 100644 --- a/crates/mpt/Cargo.toml +++ b/crates/mpt/Cargo.toml @@ -23,6 +23,7 @@ alloy-rpc-types-debug = {workspace = true, optional = true } [dev-dependencies] hex-literal.workspace = true +reth-primitives-traits.workspace = true [features] default = ["execution-witness"] diff --git a/crates/mpt/src/arena.rs b/crates/mpt/src/arena.rs new file mode 100644 index 0000000..0211249 --- /dev/null +++ b/crates/mpt/src/arena.rs @@ -0,0 +1,1364 @@ +//! Arena-backed Merkle Patricia trie for the guest. +//! +//! The guest used to deserialize the witness as a tree of boxed [`MptNode`]s +//! (one heap allocation and two ~112-byte copies per node, 16 of them per +//! branch) and then RLP-encode and keccak every node again to check the state +//! root. On a reth block that was ~37 M cycles of decoding plus ~31 M of +//! hashing for ~9.6 K nodes — a third of the block. +//! +//! Here the host ships each trie as a *preorder stream* of raw RLP nodes +//! ([`WitnessState`]), and the guest builds an [`ArenaTrie`] from it in one +//! pass: nodes live in one `Vec`, children are indices, every node is +//! keccak-checked exactly once against the digest its parent carries (the +//! root against the anchor), and the verified digest is kept as the node's +//! reference so the state-root pass only re-hashes what the block mutated. +//! No per-node allocation of children, no hash-map lookups. +//! +//! [`MptNode`] stays the host-side representation; it is also the test +//! oracle for this module. + +use alloy_primitives::{map::HashMap, Bytes, B256, U256}; +use alloy_rlp::Encodable; +use core::mem; +use reth_trie::{HashedPostState, HashedStorage, TrieAccount, EMPTY_ROOT_HASH}; +use serde::{Deserialize, Serialize}; + +use super::mpt::{ + keccak, lcp, prefix_nibs, to_encoded_path, Error, MptNode, MptNodeData, MptNodeReference, + RlpBytes, EMPTY_ROOT, +}; + +/// Stream tag: the referenced node is not part of the witness (stays a digest). +/// The RLP prefix of a 32-byte string: how a trie node references a child +/// that lives outside it. +const DIGEST_STRING_CODE: u8 = alloy_rlp::EMPTY_STRING_CODE + 32; + +const TAG_DIGEST: u8 = 0; +/// Stream tag: a node follows as `varint(len) || rlp`. +const TAG_NODE: u8 = 1; + +/// The state tries in witness form: for the state trie and every storage +/// trie, the root hash and a preorder stream of raw RLP nodes. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct WitnessState { + pub state_root: B256, + #[serde(deserialize_with = "input_bytes")] + pub state_nodes: Bytes, + /// One entry per storage trie, sorted by hashed address so the input + /// bytes are reproducible. + pub storage: Vec, +} + +/// One account's storage trie in witness form: its hashed address, its root +/// and the preorder stream of its raw RLP nodes. +/// +/// Bincode writes a struct as its fields in order, so this is byte-identical +/// to the `(B256, B256, Bytes)` tuple it replaced and cached inputs stay +/// readable. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct StorageWitness { + pub hashed_address: B256, + pub root: B256, + #[serde(deserialize_with = "input_bytes")] + pub nodes: Bytes, +} + +/// Deserialise a byte string into `Bytes` without copying it in the guest. +/// +/// The program input is read once and leaked by `main`, so it outlives the +/// run and bincode's borrowed slices of it can be kept as they are: the +/// witness streams are 6-7 MB per reth block, and copying them out of the +/// input buffer cost ~7 M cycles. Off the zkVM the bytes are copied. +pub fn input_bytes<'de, D: serde::Deserializer<'de>>(d: D) -> Result { + struct V; + impl<'de> serde::de::Visitor<'de> for V { + type Value = Bytes; + + fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str("a byte string") + } + + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result { + #[cfg(target_os = "zkvm")] + { + // SAFETY: the guest leaks its input buffer (bin/guest/src/main.rs), + // so every slice of it lives as long as the program. + let v: &'static [u8] = + unsafe { core::mem::transmute::<&'de [u8], &'static [u8]>(v) }; + Ok(Bytes::from_static(v)) + } + #[cfg(not(target_os = "zkvm"))] + { + Ok(Bytes::copy_from_slice(v)) + } + } + + fn visit_bytes(self, v: &[u8]) -> Result { + Ok(Bytes::copy_from_slice(v)) + } + + fn visit_byte_buf(self, v: Vec) -> Result { + Ok(Bytes::from(v)) + } + + fn visit_seq>(self, mut seq: A) -> Result { + let mut out = Vec::with_capacity(seq.size_hint().unwrap_or(0)); + while let Some(b) = seq.next_element::()? { + out.push(b); + } + Ok(Bytes::from(out)) + } + } + d.deserialize_bytes(V) +} + +// --------------------------------------------------------------------------- +// Host side: MptNode -> preorder stream +// --------------------------------------------------------------------------- + +fn put_varint(out: &mut Vec, mut v: usize) { + while v >= 0x80 { + out.push((v as u8) | 0x80); + v >>= 7; + } + out.push(v as u8); +} + +fn is_hashed(node: &MptNode) -> bool { + matches!(node.reference(), MptNodeReference::Digest(_)) +} + +/// Emit `node` (which its parent references by digest, or the root) and, +/// recursively, every digest-referenced descendant, in preorder. Children +/// inlined in their parent's RLP need no entry: an inline node cannot carry a +/// digest child, so its whole subtree is inside the parent's bytes. +fn emit_node(node: &MptNode, out: &mut Vec) { + match node.as_data() { + MptNodeData::Digest(_) => out.push(TAG_DIGEST), + _ => { + let rlp = node.to_rlp(); + out.push(TAG_NODE); + put_varint(out, rlp.len()); + out.extend_from_slice(&rlp); + emit_children(node, out); + } + } +} + +fn emit_children(node: &MptNode, out: &mut Vec) { + match node.as_data() { + MptNodeData::Branch(children) => { + for child in children.iter().flatten() { + if is_hashed(child) { + emit_node(child, out); + } else { + emit_children(child, out); + } + } + } + MptNodeData::Extension(_, child) => { + if is_hashed(child) { + emit_node(child, out); + } else { + emit_children(child, out); + } + } + _ => {} + } +} + +/// The preorder node stream of a trie rooted at `root`. +pub fn witness_stream(root: &MptNode) -> Bytes { + let mut out = Vec::new(); + emit_node(root, &mut out); + out.into() +} + +// --------------------------------------------------------------------------- +// Guest side: arena trie +// --------------------------------------------------------------------------- + +type NodeId = u32; +const NONE: NodeId = u32::MAX; + +#[derive(Debug, Clone, PartialEq, Eq)] +enum Node { + Null, + /// Compact-encoded path (as in the RLP) and the value, both slices of + /// the witness stream for a node read from it. + Leaf(Bytes, Bytes), + /// Compact-encoded path and the child. + Extension(Bytes, NodeId), + Branch([NodeId; 16]), + Digest(B256), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +enum Ref { + /// Encodings shorter than 32 bytes are inlined by the parent. + Bytes(Vec), + Digest(B256), +} + +impl Ref { + fn encode(&self, out: &mut Vec) { + match self { + Ref::Bytes(b) => out.extend_from_slice(b), + Ref::Digest(d) => push_digest(out, &d.0), + } + } + fn length(&self) -> usize { + match self { + Ref::Bytes(b) => b.len(), + Ref::Digest(_) => 33, + } + } +} + +/// Appends the RLP of a 32-byte string, `0xa0` then `digest`, to `out`. +/// +/// The digest is moved as eight unaligned words rather than byte by byte: +/// a reth block's state-root pass writes ~100 K of them. The writes are +/// sound because `out` has room for 33 bytes after the reservation, every +/// word of `digest` is in bounds, and the length is set to what was written. +#[inline] +fn push_digest(out: &mut Vec, digest: &[u8; 32]) { + out.reserve(33); + let len = out.len(); + unsafe { + let dst = out.as_mut_ptr().add(len); + *dst = DIGEST_STRING_CODE; + let src = digest.as_ptr().cast::(); + let dst = dst.add(1).cast::(); + for w in 0..8 { + dst.add(w).write_unaligned(src.add(w).read_unaligned()); + } + out.set_len(len + 33); + } +} + +/// A child slot whose top bit is set holds no node: the low bits are the +/// byte offset, in `ArenaTrie::stream`, of the 32-byte digest the parent's +/// RLP references (a sibling outside the witness). The witness carries far +/// more such digests than nodes (a reth block: ~160 K digests against ~20 K +/// nodes), and materialising each as a node cost two arena pushes and a +/// reallocation or two per trie. +const DIGEST_BIT: NodeId = 1 << 31; + +/// A Merkle Patricia trie whose nodes live in one arena. +#[derive(Debug, Clone)] +pub struct ArenaTrie { + nodes: Vec, + /// Cached reference of each node; `None` after a mutation on its path. + refs: Vec>, + root: NodeId, + /// The witness stream the digest slots point into (empty for a trie + /// built by insertion). + stream: Bytes, +} + +impl Default for ArenaTrie { + fn default() -> Self { + Self { nodes: vec![Node::Null], refs: vec![None], root: 0, stream: Bytes::new() } + } +} + +struct Stream<'a> { + buf: &'a [u8], + pos: usize, +} + +impl<'a> Stream<'a> { + #[inline] + fn peek(&self) -> Option { + self.buf.get(self.pos).copied() + } + fn byte(&mut self) -> Result { + let b = *self.buf.get(self.pos).ok_or(Error::WitnessFormat("truncated stream"))?; + self.pos += 1; + Ok(b) + } + fn varint(&mut self) -> Result { + let mut v = 0usize; + let mut shift = 0; + loop { + let b = self.byte()?; + v |= ((b & 0x7f) as usize) << shift; + if b & 0x80 == 0 { + return Ok(v); + } + shift += 7; + if shift > 28 { + return Err(Error::WitnessFormat("varint too long")); + } + } + } + fn node(&mut self) -> Result<&'a [u8], Error> { + let len = self.varint()?; + let bytes = + self.buf.get(self.pos..self.pos + len).ok_or(Error::WitnessFormat("truncated node"))?; + self.pos += len; + Ok(bytes) + } +} + +/// Split one RLP item off the front of `buf`: (header, payload, whole item). +#[inline] +fn take_item<'a>( + buf: &mut &'a [u8], +) -> Result<(alloy_rlp::Header, &'a [u8], &'a [u8]), alloy_rlp::Error> { + // Fast paths. Nearly every item inside a witness trie node is either an + // absent child (`0x80`) or a 32-byte digest (`0xa0 ..`), and there are + // ~200 K of them per reth block: the generic header decoder's bounds + // checks and length arithmetic are most of what the witness load spends. + match buf.first() { + Some(&alloy_rlp::EMPTY_STRING_CODE) => { + let (whole, rest) = buf.split_at(1); + *buf = rest; + return Ok((alloy_rlp::Header { list: false, payload_length: 0 }, &whole[1..], whole)); + } + Some(&DIGEST_STRING_CODE) if buf.len() >= 33 => { + let (whole, rest) = buf.split_at(33); + *buf = rest; + return Ok((alloy_rlp::Header { list: false, payload_length: 32 }, &whole[1..], whole)); + } + _ => {} + } + let start = *buf; + let header = alloy_rlp::Header::decode(buf)?; + let payload = buf.get(..header.payload_length).ok_or(alloy_rlp::Error::InputTooShort)?; + *buf = &buf[header.payload_length..]; + let whole = &start[..start.len() - buf.len()]; + Ok((header, payload, whole)) +} + +impl ArenaTrie { + /// Build the trie from its root hash and preorder node stream, checking + /// every node's keccak against the digest that references it. + pub fn from_stream(root: B256, stream: Bytes) -> Result { + // Real nodes only: a witnessed node is a few hundred bytes on average + // (branches dominate), so this never reallocates. + let cap = stream.len() / 96 + 8; + let mut trie = ArenaTrie { + nodes: Vec::with_capacity(cap), + refs: Vec::with_capacity(cap), + root: NONE, + stream: stream.clone(), + }; + let mut s = Stream { buf: &stream, pos: 0 }; + let id = trie.build(&mut s, root, None)?; + if s.pos != stream.len() { + return Err(Error::WitnessFormat("trailing bytes")); + } + trie.root = id; + Ok(trie) + } + + #[inline] + fn is_digest(id: NodeId) -> bool { + id != NONE && id & DIGEST_BIT != 0 + } + + /// The digest a digest slot references. + #[inline] + fn digest_at(&self, id: NodeId) -> B256 { + let off = (id & !DIGEST_BIT) as usize; + B256::from_slice(&self.stream[off..off + 32]) + } + + #[inline] + fn push(&mut self, node: Node, r: Option) -> NodeId { + let id = self.nodes.len() as NodeId; + self.nodes.push(node); + self.refs.push(r); + id + } + + /// Next stream entry, which the parent references by `expected`. A + /// digest entry becomes `slot` when the parent offers one (the offset of + /// the digest in its own RLP), else a `Node::Digest` (the root). + fn build( + &mut self, + s: &mut Stream<'_>, + expected: B256, + slot: Option, + ) -> Result { + match s.byte()? { + TAG_DIGEST => Ok(match slot { + Some(id) => id, + None => self.push(Node::Digest(expected), Some(Ref::Digest(expected))), + }), + TAG_NODE => { + let bytes = s.node()?; + if !eq32(&keccak(bytes), &expected.0) { + return Err(Error::WitnessNodeMismatch(expected)); + } + let r = if bytes.len() < 32 { + Ref::Bytes(bytes.to_vec()) + } else { + Ref::Digest(expected) + }; + let mut buf = bytes; + let (header, payload, _) = take_item(&mut buf)?; + if !buf.is_empty() { + return Err(Error::WitnessFormat("node has trailing bytes")); + } + self.decode_item(header, payload, r, s) + } + _ => Err(Error::WitnessFormat("bad tag")), + } + } + + /// A child item inside a node's RLP: absent, a digest (whose node is the + /// next stream entry), or an inline node. + fn child( + &mut self, + header: alloy_rlp::Header, + payload: &[u8], + whole: &[u8], + s: &mut Stream<'_>, + ) -> Result { + if header.list { + return self.decode_item(header, payload, Ref::Bytes(whole.to_vec()), s); + } + match payload.len() { + 0 => Ok(NONE), + 32 => { + // Where this digest sits in the stream, for a digest slot. + let off = payload.as_ptr() as usize - self.stream.as_ptr() as usize; + self.build(s, B256::from_slice(payload), Some(DIGEST_BIT | off as NodeId)) + } + _ => Err(alloy_rlp::Error::UnexpectedLength.into()), + } + } + + /// A child item already split off its node: absent and digest-of-digest + /// children are resolved without a call, the rest through `child`. + #[inline] + fn common_child( + &mut self, + header: alloy_rlp::Header, + payload: &[u8], + whole: &[u8], + s: &mut Stream<'_>, + ) -> Result { + if !header.list { + if payload.is_empty() { + return Ok(NONE); + } + if payload.len() == 32 && s.peek() == Some(TAG_DIGEST) { + s.pos += 1; + let off = payload.as_ptr() as usize - self.stream.as_ptr() as usize; + return Ok(DIGEST_BIT | off as NodeId); + } + } + self.child(header, payload, whole, s) + } + + /// Decode one node item into the arena. + fn decode_item( + &mut self, + header: alloy_rlp::Header, + payload: &[u8], + r: Ref, + s: &mut Stream<'_>, + ) -> Result { + if !header.list { + return match payload.len() { + 0 => Ok(self.push(Node::Null, Some(r))), + _ => Err(alloy_rlp::Error::UnexpectedString.into()), + }; + } + // ONE pass. A node is either 2 items (leaf or extension) or 17 (a + // branch), and the first two tell them apart: a second item that does + // not end the payload means a branch. Counting the items first, as + // this did, parsed every node twice. + let mut rest = payload; + let (h0, p0, w0) = take_item(&mut rest)?; + let (h1, p1, w1) = take_item(&mut rest)?; + if rest.is_empty() { + // Item 0 is the compact-encoded path; its high nibble says whether + // item 1 is a value (leaf) or a child (extension). + if h0.list || p0.is_empty() { + return Err(alloy_rlp::Error::UnexpectedList.into()); + } + return if p0[0] & 0x20 == 0 { + let child = self.child(h1, p1, w1, s)?; + if child == NONE { + return Err(Error::WitnessFormat("extension without child")); + } + let prefix = self.stream.slice_ref(p0); + Ok(self.push(Node::Extension(prefix, child), Some(r))) + } else { + if h1.list { + return Err(alloy_rlp::Error::UnexpectedList.into()); + } + let (prefix, value) = (self.stream.slice_ref(p0), self.stream.slice_ref(p1)); + Ok(self.push(Node::Leaf(prefix, value), Some(r))) + }; + } + // A branch: 16 children then an empty value. The children are walked + // in order because `child` may consume the next stream entry. The + // two common children, absent (`0x80`) and a digest (`0xa0 ..`) whose + // stream entry is itself a digest, are handled here without the + // generic item split and the two calls behind it: they are ~95% of + // the ~160 K branch children of a reth block. + let mut children = [NONE; 16]; + children[0] = self.common_child(h0, p0, w0, s)?; + children[1] = self.common_child(h1, p1, w1, s)?; + for slot in children[2..].iter_mut() { + match rest.first() { + Some(&alloy_rlp::EMPTY_STRING_CODE) => { + rest = &rest[1..]; + } + Some(&DIGEST_STRING_CODE) if rest.len() >= 33 && s.peek() == Some(TAG_DIGEST) => { + s.pos += 1; + let off = rest.as_ptr() as usize + 1 - self.stream.as_ptr() as usize; + *slot = DIGEST_BIT | off as NodeId; + rest = &rest[33..]; + } + _ => { + let (h, item, whole) = take_item(&mut rest)?; + *slot = self.child(h, item, whole, s)?; + } + } + } + let (h, value, _) = take_item(&mut rest)?; + if h.list || !value.is_empty() { + return Err(Error::WitnessFormat("branch node with value")); + } + if !rest.is_empty() { + return Err(alloy_rlp::Error::UnexpectedLength.into()); + } + Ok(self.push(Node::Branch(children), Some(r))) + } + + // -- reads --------------------------------------------------------------- + + /// The value stored under `key`, if any. + pub fn get(&self, key: &[u8]) -> Result, Error> { + let (nibs, n) = nibbles(key); + self.get_internal(self.root, &nibs[..n]) + } + + /// The RLP-decoded value stored under `key`, if any. + pub fn get_rlp(&self, key: &[u8]) -> Result, Error> { + match self.get(key)? { + Some(mut bytes) => Ok(Some(T::decode(&mut bytes)?)), + None => Ok(None), + } + } + + fn get_internal(&self, id: NodeId, key_nibs: &[u8]) -> Result, Error> { + if Self::is_digest(id) { + return Err(Error::NodeNotResolved(self.digest_at(id))); + } + match &self.nodes[id as usize] { + Node::Null => Ok(None), + Node::Branch(children) => match key_nibs.split_first() { + Some((i, tail)) => match children[*i as usize] { + NONE => Ok(None), + child => self.get_internal(child, tail), + }, + None => Ok(None), + }, + Node::Leaf(prefix, value) => { + if strip_prefix_nibs(key_nibs, prefix) == Some(&[][..]) { + Ok(Some(&value[..])) + } else { + Ok(None) + } + } + Node::Extension(prefix, child) => match strip_prefix_nibs(key_nibs, prefix) { + Some(tail) => self.get_internal(*child, tail), + None => Ok(None), + }, + Node::Digest(digest) => Err(Error::NodeNotResolved(*digest)), + } + } + + /// Whether the trie holds no key. + pub fn is_empty(&self) -> bool { + matches!(self.nodes[self.root as usize], Node::Null) + } + + /// Remove every key. + pub fn clear(&mut self) { + self.nodes[self.root as usize] = Node::Null; + self.refs[self.root as usize] = None; + } + + // -- hashing ------------------------------------------------------------- + + /// The root hash. + pub fn hash(&mut self) -> B256 { + match self.nodes[self.root as usize] { + Node::Null => EMPTY_ROOT, + _ => match self.reference(self.root) { + Ref::Digest(d) => d, + Ref::Bytes(b) => keccak(b).into(), + }, + } + } + + fn reference(&mut self, id: NodeId) -> Ref { + if Self::is_digest(id) { + return Ref::Digest(self.digest_at(id)); + } + self.ensure_reference(id); + self.refs[id as usize].clone().expect("the reference is cached") + } + + /// Caches the reference of the node `id` (not a digest slot). + fn ensure_reference(&mut self, id: NodeId) { + if self.refs[id as usize].is_some() { + return; + } + let r = match &self.nodes[id as usize] { + Node::Null => Ref::Bytes(vec![alloy_rlp::EMPTY_STRING_CODE]), + Node::Digest(d) => Ref::Digest(*d), + _ => { + let encoded = self.encode(id); + if encoded.len() < 32 { + Ref::Bytes(encoded) + } else { + Ref::Digest(keccak(&encoded).into()) + } + } + }; + self.refs[id as usize] = Some(r); + } + + fn reference_length(&mut self, id: NodeId) -> usize { + if Self::is_digest(id) { + return 33; + } + self.ensure_reference(id); + self.refs[id as usize].as_ref().expect("the reference is cached").length() + } + + /// Writes the RLP reference of `id` to `out`: a digest slot's 32 bytes + /// from the witness stream, else the cached (or now computed) reference. + fn write_reference(&mut self, id: NodeId, out: &mut Vec) { + if Self::is_digest(id) { + let off = (id & !DIGEST_BIT) as usize; + let digest: &[u8; 32] = self.stream[off..off + 32].try_into().expect("32 bytes"); + push_digest(out, digest); + return; + } + self.ensure_reference(id); + self.refs[id as usize].as_ref().expect("the reference is cached").encode(out); + } + + fn encode(&mut self, id: NodeId) -> Vec { + match &self.nodes[id as usize] { + Node::Null => vec![alloy_rlp::EMPTY_STRING_CODE], + Node::Digest(d) => d.to_rlp(), + Node::Leaf(prefix, value) => { + let payload = prefix[..].length() + value[..].length(); + let mut out = Vec::with_capacity(payload + 3); + alloy_rlp::Header { list: true, payload_length: payload }.encode(&mut out); + prefix[..].encode(&mut out); + value[..].encode(&mut out); + out + } + Node::Extension(prefix, child) => { + let child = *child; + let prefix_len = prefix[..].length(); + let payload = prefix_len + self.reference_length(child); + let mut out = Vec::with_capacity(payload + 3); + alloy_rlp::Header { list: true, payload_length: payload }.encode(&mut out); + let Node::Extension(prefix, _) = &self.nodes[id as usize] else { + unreachable!("the node is an extension") + }; + prefix[..].encode(&mut out); + self.write_reference(child, &mut out); + out + } + Node::Branch(children) => { + let children = *children; + // Two passes over the children, sizing then writing, so a + // digest slot never has to become a `Ref`: its 32 bytes are + // copied straight from the witness stream into the output. + let mut payload = 1; // the empty value + for child in children.iter() { + payload += if *child == NONE { 1 } else { self.reference_length(*child) }; + } + let mut out = Vec::with_capacity(payload + 3); + alloy_rlp::Header { list: true, payload_length: payload }.encode(&mut out); + for child in children.iter() { + if *child == NONE { + out.push(alloy_rlp::EMPTY_STRING_CODE); + } else { + self.write_reference(*child, &mut out); + } + } + out.push(alloy_rlp::EMPTY_STRING_CODE); + out + } + } + } + + // -- writes -------------------------------------------------------------- + + /// Insert or update `key`; `true` if the trie changed. + pub fn insert(&mut self, key: &[u8], value: Vec) -> Result { + assert!(!value.is_empty(), "value must not be empty"); + let (nibs, n) = nibbles(key); + self.insert_internal(self.root, &nibs[..n], value.into()) + } + + /// Insert or update `key` with the RLP encoding of `value`. + pub fn insert_rlp(&mut self, key: &[u8], value: impl Encodable) -> Result { + let (nibs, n) = nibbles(key); + self.insert_internal(self.root, &nibs[..n], value.to_rlp().into()) + } + + #[inline] + fn leaf(&mut self, nibs: &[u8], value: Bytes) -> NodeId { + self.push(Node::Leaf(to_encoded_path(nibs, true).into(), value), None) + } + + fn insert_internal( + &mut self, + id: NodeId, + key_nibs: &[u8], + value: Bytes, + ) -> Result { + if Self::is_digest(id) { + return Err(Error::NodeNotResolved(self.digest_at(id))); + } + let changed = match &mut self.nodes[id as usize] { + Node::Null => { + self.nodes[id as usize] = Node::Leaf(to_encoded_path(key_nibs, true).into(), value); + true + } + Node::Branch(children) => { + let Some((i, tail)) = key_nibs.split_first() else { + return Err(Error::ValueInBranch); + }; + let child = children[*i as usize]; + if child != NONE { + if !self.insert_internal(child, tail, value)? { + return Ok(false); + } + } else { + let (i, tail) = (*i as usize, tail.to_vec()); + let leaf = self.leaf(&tail, value); + if let Node::Branch(children) = &mut self.nodes[id as usize] { + children[i] = leaf; + } + } + true + } + Node::Leaf(prefix, old_value) => { + let self_nibs = prefix_nibs(prefix); + let common_len = lcp(&self_nibs, key_nibs); + if common_len == self_nibs.len() && common_len == key_nibs.len() { + if *old_value == value { + return Ok(false); + } + *old_value = value; + } else if common_len == self_nibs.len() || common_len == key_nibs.len() { + return Err(Error::ValueInBranch); + } else { + let old_value = mem::take(old_value); + let split = common_len + 1; + let mut children = [NONE; 16]; + children[self_nibs[common_len] as usize] = + self.leaf(&self_nibs[split..], old_value); + children[key_nibs[common_len] as usize] = self.leaf(&key_nibs[split..], value); + self.replace_with_branch(id, &self_nibs[..common_len], children); + } + true + } + Node::Extension(prefix, existing_child) => { + let existing_child = *existing_child; + let self_nibs = prefix_nibs(prefix); + let common_len = lcp(&self_nibs, key_nibs); + if common_len == self_nibs.len() { + if !self.insert_internal(existing_child, &key_nibs[common_len..], value)? { + return Ok(false); + } + } else if common_len == key_nibs.len() { + return Err(Error::ValueInBranch); + } else { + let split = common_len + 1; + let mut children = [NONE; 16]; + children[self_nibs[common_len] as usize] = if split < self_nibs.len() { + self.push( + Node::Extension( + to_encoded_path(&self_nibs[split..], false).into(), + existing_child, + ), + None, + ) + } else { + existing_child + }; + children[key_nibs[common_len] as usize] = self.leaf(&key_nibs[split..], value); + self.replace_with_branch(id, &self_nibs[..common_len], children); + } + true + } + Node::Digest(digest) => return Err(Error::NodeNotResolved(*digest)), + }; + if changed { + self.refs[id as usize] = None; + } + Ok(changed) + } + + /// Node `id` becomes `branch`, under an extension for `prefix_nibs` when + /// that is non-empty. + fn replace_with_branch(&mut self, id: NodeId, prefix_nibs: &[u8], children: [NodeId; 16]) { + if prefix_nibs.is_empty() { + self.nodes[id as usize] = Node::Branch(children); + } else { + let branch = self.push(Node::Branch(children), None); + self.nodes[id as usize] = + Node::Extension(to_encoded_path(prefix_nibs, false).into(), branch); + } + } + + /// Delete `key`; `true` if it was present. + pub fn delete(&mut self, key: &[u8]) -> Result { + let (nibs, n) = nibbles(key); + self.delete_internal(self.root, &nibs[..n]) + } + + fn delete_internal(&mut self, id: NodeId, key_nibs: &[u8]) -> Result { + if Self::is_digest(id) { + return Err(Error::NodeNotResolved(self.digest_at(id))); + } + match &self.nodes[id as usize] { + Node::Null => return Ok(false), + Node::Branch(children) => { + let Some((i, tail)) = key_nibs.split_first() else { + return Err(Error::ValueInBranch); + }; + let child = children[*i as usize]; + if child == NONE || !self.delete_internal(child, tail)? { + return Ok(false); + } + let i = *i as usize; + if matches!(self.nodes[child as usize], Node::Null) { + if let Node::Branch(children) = &mut self.nodes[id as usize] { + children[i] = NONE; + } + } + let Node::Branch(children) = &self.nodes[id as usize] else { unreachable!() }; + let mut remaining = children.iter().enumerate().filter(|(_, c)| **c != NONE); + // there is always at least one child left + let (index, orphan) = remaining.next().map(|(i, c)| (i, *c)).unwrap(); + if remaining.next().is_none() { + // one child left: the branch collapses into it + let new = if Self::is_digest(orphan) { + // a digest slot has no node: the branch becomes an + // extension to the digest + Node::Extension(to_encoded_path(&[index as u8], false).into(), orphan) + } else { + match mem::replace(&mut self.nodes[orphan as usize], Node::Null) { + Node::Leaf(prefix, value) => { + let mut nibs = vec![index as u8]; + nibs.extend(prefix_nibs(&prefix)); + Node::Leaf(to_encoded_path(&nibs, true).into(), value) + } + Node::Extension(prefix, child) => { + let mut nibs = vec![index as u8]; + nibs.extend(prefix_nibs(&prefix)); + Node::Extension(to_encoded_path(&nibs, false).into(), child) + } + node @ (Node::Branch(_) | Node::Digest(_)) => { + // the orphan keeps its slot; the branch becomes an extension to it + self.nodes[orphan as usize] = node; + Node::Extension( + to_encoded_path(&[index as u8], false).into(), + orphan, + ) + } + Node::Null => unreachable!(), + } + }; + self.nodes[id as usize] = new; + } + } + Node::Leaf(prefix, _) => { + if strip_prefix_nibs(key_nibs, prefix) != Some(&[][..]) { + return Ok(false); + } + self.nodes[id as usize] = Node::Null; + } + Node::Extension(prefix, child) => { + let child = *child; + let mut self_nibs = prefix_nibs(prefix); + let Some(tail) = strip_prefix_nibs(key_nibs, prefix) else { return Ok(false) }; + if !self.delete_internal(child, tail)? { + return Ok(false); + } + // an extension points to a branch or digest; re-establish that + let new = match mem::replace(&mut self.nodes[child as usize], Node::Null) { + Node::Null => Some(Node::Null), + Node::Leaf(prefix, value) => { + self_nibs.extend(prefix_nibs(&prefix)); + Some(Node::Leaf(to_encoded_path(&self_nibs, true).into(), value)) + } + Node::Extension(prefix, grandchild) => { + self_nibs.extend(prefix_nibs(&prefix)); + Some(Node::Extension(to_encoded_path(&self_nibs, false).into(), grandchild)) + } + node @ (Node::Branch(_) | Node::Digest(_)) => { + self.nodes[child as usize] = node; + None + } + }; + if let Some(new) = new { + self.nodes[id as usize] = new; + } + } + Node::Digest(digest) => return Err(Error::NodeNotResolved(*digest)), + } + self.refs[id as usize] = None; + Ok(true) + } +} + +/// 32-byte equality as eight word compares: the generic `memcmp` takes the +/// byte loop for these stack arrays. +#[inline] +fn eq32(a: &[u8; 32], b: &[u8; 32]) -> bool { + let mut acc = 0u32; + for i in (0..32).step_by(4) { + acc |= u32::from_ne_bytes([a[i], a[i + 1], a[i + 2], a[i + 3]]) ^ + u32::from_ne_bytes([b[i], b[i + 1], b[i + 2], b[i + 3]]); + } + acc == 0 +} + +/// The nibbles of `key` in a stack buffer, and how many: keys are 32-byte +/// hashes, so the buffer needs no allocation. +/// +/// # Panics +/// Panics if `key` is longer than 64 bytes. +#[inline] +fn nibbles(key: &[u8]) -> ([u8; 128], usize) { + assert!(key.len() <= 64, "key too long"); + let mut out = [0u8; 128]; + for (i, b) in key.iter().enumerate() { + out[2 * i] = b >> 4; + out[2 * i + 1] = b & 0xf; + } + (out, 2 * key.len()) +} + +/// `key_nibs` with a compact-encoded `prefix` stripped off the front, without +/// materialising the prefix's nibbles. +fn strip_prefix_nibs<'a>(key_nibs: &'a [u8], prefix: &[u8]) -> Option<&'a [u8]> { + let (first, tail) = prefix.split_first()?; + let mut rest = key_nibs; + if first & 0x10 != 0 { + let (k, r) = rest.split_first()?; + if *k != first & 0xf { + return None; + } + rest = r; + } + for byte in tail { + let (k, r) = rest.split_first_chunk::<2>()?; + if k[0] != byte >> 4 || k[1] != byte & 0xf { + return None; + } + rest = r; + } + Some(rest) +} + +// --------------------------------------------------------------------------- +// The guest's state: arena tries + the update logic of `EthereumState` +// --------------------------------------------------------------------------- + +/// State and storage tries materialised from a [`WitnessState`]. +#[derive(Debug, Clone, Default)] +pub struct ArenaState { + pub state_trie: ArenaTrie, + pub storage_tries: HashMap, +} + +impl ArenaState { + /// Build every trie, checking each node against the digest that references + /// it and each trie against its root; the state root is checked against + /// `witness.state_root`, the storage roots against the account leaves. + pub fn from_witness(witness: &WitnessState) -> Result { + let state_trie = ArenaTrie::from_stream(witness.state_root, witness.state_nodes.clone())?; + let mut storage_tries = + HashMap::with_capacity_and_hasher(witness.storage.len(), Default::default()); + for StorageWitness { hashed_address, root, nodes } in &witness.storage { + let expected = state_trie + .get_rlp::(hashed_address.as_slice())? + .map_or(EMPTY_ROOT_HASH, |a| a.storage_root); + if *root != expected { + return Err(Error::WitnessNodeMismatch(expected)); + } + storage_tries.insert(*hashed_address, ArenaTrie::from_stream(*root, nodes.clone())?); + } + Ok(Self { state_trie, storage_tries }) + } + + /// The account under `hashed_address`, if any. + pub fn account(&self, hashed_address: &[u8]) -> Result, Error> { + self.state_trie.get_rlp::(hashed_address) + } + + /// The storage slot `hashed_slot` of `hashed_address`, if set. + /// + /// A witness may omit the storage trie of an absent account or of one + /// whose authenticated storage root is empty; their slots are zero. Any + /// other missing trie is an unresolved storage root, never a zero. + pub fn storage( + &self, + hashed_address: &B256, + hashed_slot: &[u8], + ) -> Result, Error> { + match self.storage_tries.get(hashed_address) { + Some(trie) => trie.get_rlp::(hashed_slot), + None => { + let root = self + .account(hashed_address.as_slice())? + .map_or(EMPTY_ROOT_HASH, |account| account.storage_root); + if root == EMPTY_ROOT_HASH { + Ok(None) + } else { + Err(Error::NodeNotResolved(root)) + } + } + } + } + + /// Apply the post-state diff (same semantics as `EthereumState::update`). + pub fn update(&mut self, post_state: &HashedPostState) { + let no_storage = HashedStorage::new(false); + for (hashed_address, account) in post_state.accounts.iter() { + match account { + Some(account) => { + let state_storage = + post_state.storages.get(hashed_address).unwrap_or(&no_storage); + let storage_root = + self.storage_root_after_update(*hashed_address, state_storage); + + if account.is_empty() && storage_root == EMPTY_ROOT_HASH { + self.state_trie.delete(hashed_address.as_slice()).unwrap(); + self.storage_tries.remove(hashed_address); + continue; + } + + let state_account = TrieAccount { + nonce: account.nonce, + balance: account.balance, + storage_root, + code_hash: account.get_bytecode_hash(), + }; + self.state_trie.insert_rlp(hashed_address.as_slice(), state_account).unwrap(); + } + None => { + self.state_trie.delete(hashed_address.as_slice()).unwrap(); + self.storage_tries.remove(hashed_address); + } + } + } + } + + fn storage_root_after_update( + &mut self, + hashed_address: B256, + state_storage: &HashedStorage, + ) -> B256 { + if state_storage.is_empty() { + if let Some(storage_trie) = self.storage_tries.get_mut(&hashed_address) { + return storage_trie.hash(); + } + return self + .state_trie + .get_rlp::(hashed_address.as_slice()) + .unwrap() + .map(|account| account.storage_root) + .unwrap_or(EMPTY_ROOT_HASH); + } + + let storage_trie = self.storage_tries.entry(hashed_address).or_default(); + if state_storage.wiped { + storage_trie.clear(); + } + for (key, value) in state_storage.storage.iter() { + let key = key.as_slice(); + if value.is_zero() { + storage_trie.delete(key).unwrap(); + } else { + storage_trie.insert_rlp(key, *value).unwrap(); + } + } + storage_trie.hash() + } + + /// The state root. + pub fn state_root(&mut self) -> B256 { + self.state_trie.hash() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::EthereumState; + use alloy_primitives::{keccak256, U256}; + use reth_trie::Nibbles; + + fn state_with(account: Option<(B256, TrieAccount)>) -> ArenaState { + let mut state = ArenaState::default(); + if let Some((hashed_address, account)) = account { + state.state_trie.insert_rlp(hashed_address.as_slice(), account).unwrap(); + } + state + } + + #[test] + fn omitted_storage_for_absent_account_is_zero() { + let state = state_with(None); + let slot = keccak256(U256::from(7).to_be_bytes::<32>()); + assert_eq!(state.storage(&B256::repeat_byte(1), slot.as_slice()).unwrap(), None); + } + + #[test] + fn omitted_storage_with_authenticated_empty_root_is_zero() { + let hashed_address = B256::repeat_byte(2); + let state = state_with(Some((hashed_address, TrieAccount::default()))); + let slot = keccak256(U256::from(7).to_be_bytes::<32>()); + assert_eq!(state.storage(&hashed_address, slot.as_slice()).unwrap(), None); + } + + #[test] + fn omitted_non_empty_storage_is_rejected() { + let hashed_address = B256::repeat_byte(3); + let account = TrieAccount { storage_root: B256::repeat_byte(4), ..Default::default() }; + let state = state_with(Some((hashed_address, account))); + let slot = keccak256(U256::from(7).to_be_bytes::<32>()); + assert!(state.storage(&hashed_address, slot.as_slice()).is_err()); + } + + fn key(i: u64) -> B256 { + keccak256(i.to_be_bytes()) + } + + fn rng(state: &mut u64) -> u64 { + *state ^= *state << 13; + *state ^= *state >> 7; + *state ^= *state << 17; + *state + } + + fn oracle_trie(n: u64, seed: u64) -> MptNode { + let mut trie = MptNode::default(); + let mut s = seed | 1; + for i in 0..n { + trie.insert_rlp(key(i).as_slice(), U256::from(rng(&mut s))).unwrap(); + } + trie + } + + fn arena_of(trie: &MptNode) -> ArenaTrie { + ArenaTrie::from_stream(trie.hash(), witness_stream(trie)).unwrap() + } + + #[test] + fn stream_roundtrip_matches_oracle() { + for &n in &[0u64, 1, 2, 3, 17, 300, 2000] { + let oracle = oracle_trie(n, 7 + n); + let mut arena = arena_of(&oracle); + assert_eq!(arena.hash(), oracle.hash(), "n={n}"); + for i in 0..n + 50 { + let k = key(i); + assert_eq!( + arena.get(k.as_slice()).unwrap(), + oracle.get(k.as_slice()).unwrap(), + "n={n} key {i}" + ); + } + } + } + + #[test] + fn mutations_match_oracle() { + let mut oracle = oracle_trie(400, 99); + let mut arena = arena_of(&oracle); + let mut s = 12345u64; + for step in 0..3000u64 { + let r = rng(&mut s); + let i = r % 700; // hits existing (0..400) and fresh keys + let k = key(i); + match r % 5 { + 0 | 1 => { + let v = U256::from(rng(&mut s)); + let a = arena.insert_rlp(k.as_slice(), v).unwrap(); + let b = oracle.insert_rlp(k.as_slice(), v).unwrap(); + assert_eq!(a, b, "insert step {step}"); + } + 2 | 3 => { + let a = arena.delete(k.as_slice()).unwrap(); + let b = oracle.delete(k.as_slice()).unwrap(); + assert_eq!(a, b, "delete step {step}"); + } + _ => { + assert_eq!(arena.get(k.as_slice()).unwrap(), oracle.get(k.as_slice()).unwrap()); + } + } + if step % 97 == 0 { + assert_eq!(arena.hash(), oracle.hash(), "root after step {step}"); + } + } + assert_eq!(arena.hash(), oracle.hash()); + assert_eq!(arena.is_empty(), oracle.is_empty()); + } + + /// Replace the child at `nibble` of the root branch (after descending any + /// root extension) with an unresolved digest, like a partial witness. + fn plant_digest(trie: &mut MptNode, nibble: usize) -> bool { + let mut node = trie; + loop { + match node.data_mut() { + MptNodeData::Extension(_, child) => node = child, + MptNodeData::Branch(children) => { + return match &mut children[nibble] { + Some(child) => { + let h = child.hash(); + *child.data_mut() = MptNodeData::Digest(h); + true + } + None => false, + } + } + _ => return false, + } + } + } + + #[test] + fn unresolved_subtrees_match_oracle() { + let mut oracle = oracle_trie(600, 5); + let full_root = oracle.hash(); + assert!(plant_digest(&mut oracle, 3)); + assert!(plant_digest(&mut oracle, 11)); + assert_eq!(oracle.hash(), full_root, "digest planting keeps the root"); + let mut arena = arena_of(&oracle); + assert_eq!(arena.hash(), full_root); + let mut resolved = 0; + let mut unresolved = 0; + for i in 0..600u64 { + let k = key(i); + match (arena.get(k.as_slice()), oracle.get(k.as_slice())) { + (Ok(a), Ok(b)) => { + assert_eq!(a, b); + resolved += 1; + } + (Err(Error::NodeNotResolved(a)), Err(Error::NodeNotResolved(b))) => { + assert_eq!(a, b); + unresolved += 1; + } + (a, b) => panic!("key {i}: {a:?} vs {b:?}"), + } + } + assert!(resolved > 0 && unresolved > 0, "{resolved} {unresolved}"); + // mutations on resolved paths still agree + for i in 0..600u64 { + let k = key(i); + if arena.get(k.as_slice()).is_ok() { + let v = U256::from(i * 31 + 7); + arena.insert_rlp(k.as_slice(), v).unwrap(); + oracle.insert_rlp(k.as_slice(), v).unwrap(); + } + } + assert_eq!(arena.hash(), oracle.hash()); + } + + #[test] + fn tampered_node_is_rejected() { + let oracle = oracle_trie(50, 3); + let mut stream = witness_stream(&oracle).to_vec(); + // flip a byte inside the first node's payload + let last = stream.len() - 1; + stream[last] ^= 1; + assert!(matches!( + ArenaTrie::from_stream(oracle.hash(), Bytes::from(stream.clone())), + Err(Error::WitnessNodeMismatch(_)) + )); + assert!(ArenaTrie::from_stream(B256::ZERO, witness_stream(&oracle)).is_err()); + } + + #[test] + fn state_update_matches_oracle() { + use reth_primitives_traits::Account; + let mut s = 777u64; + let mut eager = EthereumState::default(); + for i in 0..120u64 { + let addr = key(i); + let mut storage = MptNode::default(); + for j in 0..(i % 9) { + storage + .insert_rlp(key(1000 + i * 10 + j).as_slice(), U256::from(rng(&mut s))) + .unwrap(); + } + let account = TrieAccount { + nonce: i, + balance: U256::from(rng(&mut s)), + storage_root: storage.hash(), + code_hash: key(5000 + i), + }; + eager.state_trie.insert_rlp(addr.as_slice(), account).unwrap(); + eager.storage_tries.insert(addr, storage); + } + let witness = eager.to_witness_state(); + let mut arena = ArenaState::from_witness(&witness).unwrap(); + assert_eq!(arena.state_root(), eager.state_root()); + + let mut post = HashedPostState::default(); + for i in 0..120u64 { + let addr = key(i); + match i % 4 { + 0 => { + post.accounts.insert(addr, None); + } + 1 => { + post.accounts.insert( + addr, + Some(Account { + nonce: i + 1, + balance: U256::from(rng(&mut s)), + bytecode_hash: Some(key(5000 + i)), + }), + ); + let mut hs = HashedStorage::new(false); + for j in 0..6u64 { + let v = if j % 2 == 0 { U256::ZERO } else { U256::from(rng(&mut s)) }; + hs.storage.insert(key(1000 + i * 10 + j), v); + } + post.storages.insert(addr, hs); + } + 2 => { + post.accounts.insert( + addr, + Some(Account { nonce: 0, balance: U256::ZERO, bytecode_hash: None }), + ); + post.storages.insert(addr, HashedStorage::new(true)); + } + _ => { + post.accounts.insert( + key(9000 + i), + Some(Account { nonce: 1, balance: U256::from(5), bytecode_hash: None }), + ); + } + } + } + eager.update(&post); + arena.update(&post); + assert_eq!(arena.state_root(), eager.state_root()); + let _ = Nibbles::default(); + } +} diff --git a/crates/mpt/src/lib.rs b/crates/mpt/src/lib.rs index 3f3415b..45a77e4 100644 --- a/crates/mpt/src/lib.rs +++ b/crates/mpt/src/lib.rs @@ -8,16 +8,19 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "execution-witness")] mod execution_witness; +/// Arena-backed trie built from a preorder RLP witness stream (the guest's form). +mod arena; /// Module containing MPT code adapted from `zeth`. mod mpt; +pub use arena::{input_bytes, witness_stream, ArenaState, ArenaTrie, StorageWitness, WitnessState}; pub use mpt::Error; use mpt::{ - mpt_from_proof, parse_proof, proofs_to_tries, resolve_nodes, transition_proofs_to_tries, - MptNode, + extend_trie_from_proof, mpt_from_proof, node_from_digest, parse_proof, proofs_to_tries, + resolve_nodes, transition_proofs_to_tries, MptNode, }; /// Ethereum state trie and account storage tries. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct EthereumState { pub state_trie: MptNode, pub storage_tries: HashMap, @@ -72,6 +75,25 @@ impl EthereumState { Ok(state) } + /// Resolves missing account trie nodes from an EIP-1186 account proof. + pub fn extend_from_account_proof( + &mut self, + proof: &EIP1186AccountProofResponse, + ) -> Result<(), FromProofError> { + self.state_trie = extend_trie_from_proof(&self.state_trie, &proof.account_proof)?; + let hashed_address = keccak256(proof.address); + for storage_proof in &proof.storage_proof { + let storage_trie = self + .storage_tries + .entry(hashed_address) + .or_insert_with(|| node_from_digest(proof.storage_hash)); + if !storage_proof.proof.is_empty() { + *storage_trie = extend_trie_from_proof(storage_trie, &storage_proof.proof)?; + } + } + Ok(()) + } + #[cfg(feature = "execution-witness")] pub fn from_execution_witness( witness: &alloy_rpc_types_debug::ExecutionWitness, @@ -158,6 +180,27 @@ impl EthereumState { pub fn state_root(&self) -> B256 { self.state_trie.hash() } + + /// The witness form the guest consumes: root hashes plus preorder streams + /// of raw RLP nodes for the state trie and every storage trie (sorted by + /// hashed address so the bytes are reproducible). + pub fn to_witness_state(&self) -> WitnessState { + let mut storage: Vec = self + .storage_tries + .iter() + .map(|(addr, trie)| StorageWitness { + hashed_address: *addr, + root: trie.hash(), + nodes: witness_stream(trie), + }) + .collect(); + storage.sort_by(|a, b| a.hashed_address.cmp(&b.hashed_address)); + WitnessState { + state_root: self.state_trie.hash(), + state_nodes: witness_stream(&self.state_trie), + storage, + } + } } #[derive(Debug, thiserror::Error)] @@ -180,6 +223,7 @@ pub enum FromProofError { #[cfg(test)] mod tests { use alloy_primitives::{b256, U256}; + use reth_primitives_traits::Account; use super::*; @@ -217,10 +261,10 @@ mod tests { }, ) .unwrap(); - let mut post_state = HashedPostState::default() - .with_accounts([(hashed_address, Some(Default::default()))]); - post_state.accounts.get_mut(&hashed_address).unwrap().as_mut().unwrap().balance = - U256::from(2); + let post_state = HashedPostState::default().with_accounts([( + hashed_address, + Some(Account { nonce: 0, balance: U256::from(2), bytecode_hash: None }), + )]); state.update(&post_state); diff --git a/crates/mpt/src/mpt.rs b/crates/mpt/src/mpt.rs index 39ed00a..5b3a577 100644 --- a/crates/mpt/src/mpt.rs +++ b/crates/mpt/src/mpt.rs @@ -141,6 +141,12 @@ pub enum Error { /// value provides details about the unresolved node. #[error("reached an unresolved node: {0:#}")] NodeNotResolved(B256), + /// A witness node's keccak does not match the digest that references it. + #[error("witness node does not match digest {0}")] + WitnessNodeMismatch(B256), + /// The witness node stream is malformed. + #[error("malformed witness stream: {0}")] + WitnessFormat(&'static str), /// Occurs when a value is unexpectedly found in a branch node. #[error("branch node with value")] ValueInBranch, @@ -339,6 +345,12 @@ impl MptNode { rlp::decode(bytes.as_ref()).map_err(Error::from) } + /// Mutable access to the node data (tests plant unresolved digests with it). + pub(crate) fn data_mut(&mut self) -> &mut MptNodeData { + self.invalidate_ref_cache(); + &mut self.data + } + /// Retrieves the underlying data of the node. /// /// This method provides a reference to the node's data, allowing for inspection and @@ -770,7 +782,7 @@ impl MptNode { Ok(true) } - fn invalidate_ref_cache(&mut self) { + pub(crate) fn invalidate_ref_cache(&mut self) { self.cached_reference.lock().unwrap().take(); } @@ -879,7 +891,7 @@ pub fn to_encoded_path(mut nibs: &[u8], is_leaf: bool) -> Vec { } /// Returns the length of the common prefix. -fn lcp(a: &[u8], b: &[u8]) -> usize { +pub(crate) fn lcp(a: &[u8], b: &[u8]) -> usize { for (i, (a, b)) in iter::zip(a, b).enumerate() { if a != b { return i; @@ -888,7 +900,7 @@ fn lcp(a: &[u8], b: &[u8]) -> usize { cmp::min(a.len(), b.len()) } -fn prefix_nibs(prefix: &[u8]) -> Vec { +pub(crate) fn prefix_nibs(prefix: &[u8]) -> Vec { let (extension, tail) = prefix.split_first().unwrap(); // the first bit of the first nibble denotes the parity let is_odd = extension & (1 << 4) != 0; @@ -993,6 +1005,24 @@ pub fn resolve_nodes(root: &MptNode, node_store: &HashMap], +) -> Result { + let proof_nodes = parse_proof(proof)?; + let proof_trie = mpt_from_proof(&proof_nodes)?; + if proof_trie.hash() != root.hash() { + return Err(FromProofError::MismatchedStateRoot(proof_trie.hash(), root.hash())) + } + + let mut node_store = HashMap::with_hasher(Default::default()); + proof_nodes.into_iter().for_each(|node| { + node_store.insert(node.reference(), node); + }); + + Ok(resolve_nodes(root, &node_store)) +} + /// Returns a list of all possible nodes that can be created by shortening the path of the /// given node. /// When nodes in an MPT are deleted, leaves or extensions may be extended. To still be @@ -1203,7 +1233,7 @@ fn add_orphaned_leafs( } /// Creates a new MPT node from a digest. -fn node_from_digest(digest: B256) -> MptNode { +pub(crate) fn node_from_digest(digest: B256) -> MptNode { match digest { EMPTY_ROOT | B256::ZERO => MptNode::default(), _ => MptNodeData::Digest(digest).into(), @@ -1344,6 +1374,32 @@ mod tests { trie.get(b"a0").unwrap_err(); } + #[test] + pub fn test_extend_trie_from_proof_resolves_digest_child() { + let mut full_trie = MptNode::default(); + full_trie.insert_rlp(b"aa", 0u8).unwrap(); + full_trie.insert_rlp(b"ab", 1u8).unwrap(); + full_trie.insert_rlp(b"ba", 2u8).unwrap(); + + let expected_hash = full_trie.hash(); + let mut partial_trie = full_trie.clone(); + let MptNodeData::Extension(_, node) = &mut partial_trie.data else { + panic!("extension expected") + }; + let missing_node = (**node).clone(); + **node = MptNodeData::Digest(missing_node.hash()).into(); + + partial_trie.get(b"aa").unwrap_err(); + + let proof = vec![full_trie.to_rlp(), missing_node.to_rlp()]; + let resolved_trie = extend_trie_from_proof(&partial_trie, &proof).unwrap(); + + assert_eq!(resolved_trie.hash(), expected_hash); + assert_eq!(resolved_trie.get_rlp::(b"aa").unwrap(), Some(0)); + assert_eq!(resolved_trie.get_rlp::(b"ab").unwrap(), Some(1)); + assert_eq!(resolved_trie.get_rlp::(b"ba").unwrap(), Some(2)); + } + #[test] pub fn test_branch_value() { let mut trie = MptNode::default(); diff --git a/crates/storage/rpc-db/src/execution_witness.rs b/crates/storage/rpc-db/src/execution_witness.rs index 8e1c2e4..db45dab 100644 --- a/crates/storage/rpc-db/src/execution_witness.rs +++ b/crates/storage/rpc-db/src/execution_witness.rs @@ -1,4 +1,8 @@ -use std::{collections::BTreeMap, marker::PhantomData, sync::RwLock}; +use std::{ + collections::BTreeMap, + marker::PhantomData, + sync::{Arc, RwLock}, +}; use alloy_consensus::Header; use alloy_eips::BlockNumberOrTag; @@ -7,7 +11,7 @@ use alloy_provider::{Network, Provider}; use alloy_rlp::{Decodable, Encodable}; use alloy_rpc_types::Header as RpcHeader; use alloy_rpc_types_debug::ExecutionWitness; -use alloy_trie::TrieAccount; +use alloy_trie::{TrieAccount, EMPTY_ROOT_HASH}; use async_trait::async_trait; use mpt::EthereumState; use reth_storage_errors::{db::DatabaseError, ProviderError}; @@ -22,12 +26,12 @@ use crate::{RpcDb, RpcDbError}; pub struct ExecutionWitnessRpcDb { /// The provider which fetches data. pub provider: P, - /// Parent block used to fetch bytecode omitted from the execution witness. + /// The block to fetch missing pre-state proofs from. pub state_block_number: u64, /// The cached state. - pub state: EthereumState, + pub state: Arc>, /// The cached bytecodes. - pub codes: RwLock>, + pub codes: Arc>>, pub ancestor_headers: BTreeMap, @@ -37,10 +41,31 @@ pub struct ExecutionWitnessRpcDb { impl + Clone, N: Network> ExecutionWitnessRpcDb { /// Create a new [`ExecutionWitnessRpcDb`]. pub async fn new(provider: P, block_number: u64, state_root: B256) -> Result { + let execution_witness = Self::fetch_witness(&provider, block_number).await?; + Ok(Self::from_witness(provider, block_number, state_root, execution_witness)) + } + + /// Fetch the execution witness on its own. It depends only on the block + /// number, so the host can run it concurrently with the block fetches + /// and pass the result to [`Self::from_witness`] once the parent's state + /// root is known — the three RPC round trips were strictly serial before. + pub async fn fetch_witness( + provider: &P, + block_number: u64, + ) -> Result { tracing::info!("Fetching execution witness for block {}", block_number); - let execution_witness = fetch_execution_witness(&provider, block_number).await?; + let execution_witness = fetch_execution_witness(provider, block_number).await?; tracing::info!("Fetched execution witness for block done {}", block_number); + Ok(execution_witness) + } + /// Build the database from an already-fetched witness. + pub fn from_witness( + provider: P, + block_number: u64, + state_root: B256, + execution_witness: ExecutionWitness, + ) -> Self { let state = EthereumState::from_execution_witness(&execution_witness, state_root); let codes = execution_witness @@ -59,56 +84,137 @@ impl + Clone, N: Network> ExecutionWitnessRpcDb { let db = Self { provider, state_block_number: block_number.saturating_sub(1), - state, - codes: RwLock::new(codes), + state: Arc::new(RwLock::new(state)), + codes: Arc::new(RwLock::new(codes)), ancestor_headers, phantom: PhantomData, }; - Ok(db) + db + } + + /// Fetches and merges a missing account proof into the cached pre-state trie. + async fn fetch_missing_account_proof(&self, address: Address) -> Result<(), RpcDbError> { + tracing::warn!( + "Fetching missing account proof for address {} at block {}", + address, + self.state_block_number + ); + let proof = self + .provider + .get_proof(address, vec![]) + .number(self.state_block_number) + .await + .map_err(|err| RpcDbError::GetProofError(address, err.to_string()))?; + + self.state.write().map_err(|_| RpcDbError::Poisoned)?.extend_from_account_proof(&proof)?; + + Ok(()) } - fn account_code( + /// Fetches and merges a missing storage proof into the cached pre-state trie. + async fn fetch_missing_storage_proof( &self, address: Address, - expected_hash: B256, - ) -> Result, ProviderError> { - if expected_hash == KECCAK_EMPTY || expected_hash == B256::ZERO { - return Ok(None) - } - if let Some(code) = self - .codes - .read() - .map_err(|_| ProviderError::TrieWitnessError("bytecode cache lock poisoned".into()))? - .get(&expected_hash) - .cloned() - { - return Ok(Some(code)) - } + index: StorageKey, + ) -> Result<(), RpcDbError> { + tracing::warn!( + "Fetching missing storage proof for address {} slot {} at block {}", + address, + B256::from(index), + self.state_block_number + ); + let proof = self + .provider + .get_proof(address, vec![B256::from(index)]) + .number(self.state_block_number) + .await + .map_err(|err| RpcDbError::GetProofError(address, err.to_string()))?; + + self.state.write().map_err(|_| RpcDbError::Poisoned)?.extend_from_account_proof(&proof)?; + + Ok(()) + } - tracing::warn!(%address, %expected_hash, block = self.state_block_number, - "Fetching bytecode omitted from execution witness"); + fn fetch_missing_account_proof_blocking(&self, address: Address) -> Result<(), ProviderError> { let handle = tokio::runtime::Handle::try_current().map_err(|_| { - ProviderError::Database(DatabaseError::Other("no tokio runtime found".into())) + ProviderError::Database(DatabaseError::Other("no tokio runtime found".to_string())) })?; - let code = tokio::task::block_in_place(|| { - handle.block_on(async { - self.provider.get_code_at(address).number(self.state_block_number).await - }) + tokio::task::block_in_place(|| handle.block_on(self.fetch_missing_account_proof(address))) + .map_err(|err| ProviderError::Database(DatabaseError::Other(err.to_string()))) + } + + fn fetch_missing_storage_proof_blocking( + &self, + address: Address, + index: StorageKey, + ) -> Result<(), ProviderError> { + let handle = tokio::runtime::Handle::try_current().map_err(|_| { + ProviderError::Database(DatabaseError::Other("no tokio runtime found".to_string())) + })?; + tokio::task::block_in_place(|| { + handle.block_on(self.fetch_missing_storage_proof(address, index)) }) - .map_err(|err| ProviderError::Database(DatabaseError::Other(err.to_string())))?; - let actual_hash = keccak256(&code); - if actual_hash != expected_hash { - return Err(ProviderError::TrieWitnessError(format!( - "Fetched code hash mismatch for {address}: expected {expected_hash}, got {actual_hash}" - ))) + .map_err(|err| ProviderError::Database(DatabaseError::Other(err.to_string()))) + } + + async fn fetch_account_code(&self, address: Address) -> Result { + let code = self + .provider + .get_code_at(address) + .number(self.state_block_number) + .await + .map_err(|err| RpcDbError::GetCodeError(address, err.to_string()))?; + + Ok(Bytecode::new_raw(code)) + } + + fn fetch_account_code_blocking( + &self, + address: Address, + expected_hash: B256, + ) -> Result { + let handle = tokio::runtime::Handle::try_current().map_err(|_| { + ProviderError::Database(DatabaseError::Other("no tokio runtime found".to_string())) + })?; + let bytecode = + tokio::task::block_in_place(|| handle.block_on(self.fetch_account_code(address))) + .map_err(|err| ProviderError::Database(DatabaseError::Other(err.to_string())))?; + + cache_verified_code(&self.codes, address, expected_hash, bytecode) + } + + fn complete_account_code( + &self, + address: Address, + account: Option, + ) -> Result, ProviderError> { + let Some(mut account) = account else { return Ok(None) }; + + if account.code.is_none() && should_fetch_code(account.code_hash) { + if let Some(code) = cached_code(&self.codes, account.code_hash)? { + account.code = Some(code); + } else { + tracing::warn!( + "Code {} not found in execution witness for address {}; fetching fallback code", + account.code_hash, + address + ); + account.code = Some(self.fetch_account_code_blocking(address, account.code_hash)?); + } } - let bytecode = Bytecode::new_raw(code); - self.codes + + Ok(Some(account)) + } + + fn ensure_empty_storage_trie(&self, hashed_address: B256) -> Result<(), ProviderError> { + self.state .write() - .map_err(|_| ProviderError::TrieWitnessError("bytecode cache lock poisoned".into()))? - .insert(expected_hash, bytecode.clone()); - Ok(Some(bytecode)) + .map_err(|_| poisoned_provider_error())? + .storage_tries + .entry(hashed_address) + .or_default(); + Ok(()) } } @@ -175,6 +281,155 @@ impl FlexibleExecutionWitnessHeader { const SYSTEM_ADDRESS: Address = alloy_primitives::address!("0xfffffffffffffffffffffffffffffffffffffffe"); +#[derive(Debug)] +enum AccountReadError { + Trie(mpt::Error), + Provider(ProviderError), +} + +impl AccountReadError { + fn unresolved_node(&self) -> Option { + match self { + Self::Trie(mpt::Error::NodeNotResolved(digest)) => Some(*digest), + Self::Trie(_) | Self::Provider(_) => None, + } + } + + fn into_provider_error(self) -> ProviderError { + match self { + Self::Trie(err) => ProviderError::TrieWitnessError(err.to_string()), + Self::Provider(err) => err, + } + } +} + +fn read_account_info_from_state( + state: &EthereumState, + address_hash: B256, + codes: &HashMap, +) -> Result, AccountReadError> { + if let Some(mut bytes) = + state.state_trie.get(address_hash.as_ref()).map_err(AccountReadError::Trie)? + { + let account = TrieAccount::decode(&mut bytes) + .map_err(ProviderError::from) + .map_err(AccountReadError::Provider)?; + let account_info = + account_info_from_trie_account(codes, account).map_err(AccountReadError::Provider)?; + + Ok(Some(account_info)) + } else { + Ok(None) + } +} + +fn account_info_from_trie_account( + codes: &HashMap, + account: TrieAccount, +) -> Result { + Ok(AccountInfo { + balance: account.balance, + nonce: account.nonce, + code_hash: account.code_hash, + code: codes.get(&account.code_hash).cloned(), + }) +} + +fn cached_code( + codes: &RwLock>, + code_hash: B256, +) -> Result, ProviderError> { + Ok(codes.read().map_err(|_| poisoned_provider_error())?.get(&code_hash).cloned()) +} + +fn cache_verified_code( + codes: &RwLock>, + address: Address, + expected_hash: B256, + bytecode: Bytecode, +) -> Result { + let actual_hash = bytecode.hash_slow(); + if actual_hash != expected_hash { + return Err(ProviderError::TrieWitnessError(format!( + "Fetched code hash mismatch for {address}: expected {expected_hash}, got {actual_hash}" + ))) + } + codes.write().map_err(|_| poisoned_provider_error())?.insert(expected_hash, bytecode.clone()); + + Ok(bytecode) +} + +fn should_fetch_code(code_hash: B256) -> bool { + code_hash != KECCAK_EMPTY && code_hash != B256::ZERO +} + +#[derive(Debug)] +enum StorageRead { + Value(StorageValue), + MissingEmptyTrie, +} + +#[derive(Debug)] +enum StorageReadError { + Trie(mpt::Error), + Provider(ProviderError), + MissingTrie { storage_root: B256 }, +} + +impl StorageReadError { + fn unresolved_node(&self) -> Option { + match self { + Self::Trie(mpt::Error::NodeNotResolved(digest)) => Some(*digest), + Self::Trie(_) | Self::Provider(_) | Self::MissingTrie { .. } => None, + } + } + + fn into_provider_error(self) -> ProviderError { + match self { + Self::Trie(err) => ProviderError::TrieWitnessError(err.to_string()), + Self::Provider(err) => err, + Self::MissingTrie { storage_root } => ProviderError::TrieWitnessError(format!( + "storage trie not found for root {storage_root}" + )), + } + } +} + +fn read_storage_from_state( + state: &EthereumState, + hashed_address: B256, + hashed_slot: B256, +) -> Result { + if let Some(storage_trie) = state.storage_tries.get(&hashed_address) { + if let Some(mut value) = + storage_trie.get(hashed_slot.as_slice()).map_err(StorageReadError::Trie)? + { + return U256::decode(&mut value) + .map(StorageRead::Value) + .map_err(ProviderError::from) + .map_err(StorageReadError::Provider) + } + + return Ok(StorageRead::Value(U256::ZERO)) + } + + let storage_root = state + .state_trie + .get_rlp::(hashed_address.as_slice()) + .map_err(StorageReadError::Trie)? + .map_or(EMPTY_ROOT_HASH, |account| account.storage_root); + + if storage_root == EMPTY_ROOT_HASH || storage_root == B256::ZERO { + Ok(StorageRead::MissingEmptyTrie) + } else { + Err(StorageReadError::MissingTrie { storage_root }) + } +} + +fn poisoned_provider_error() -> ProviderError { + ProviderError::Database(DatabaseError::Other("poisoned lock".to_string())) +} + impl + Clone, N: Network> DatabaseRef for ExecutionWitnessRpcDb { type Error = ProviderError; @@ -184,30 +439,41 @@ impl + Clone, N: Network> DatabaseRef for ExecutionWitnessRpcDb

self.complete_account_code(address, account), + Err(err) => { + let Some(digest) = err.unresolved_node() else { + return Err(err.into_provider_error()) + }; + + tracing::warn!( + "Account trie reached unresolved node {} for address {}; fetching fallback proof", + digest, + address + ); + self.fetch_missing_account_proof_blocking(address)?; + + let account = { + let state = self.state.read().map_err(|_| poisoned_provider_error())?; + let codes = self.codes.read().map_err(|_| poisoned_provider_error())?; + read_account_info_from_state(&state, hash, &codes) + .map_err(AccountReadError::into_provider_error)? + }; + self.complete_account_code(address, account) + } } } fn code_by_hash_ref(&self, code_hash: B256) -> Result { self.codes .read() - .map_err(|_| ProviderError::TrieWitnessError("bytecode cache lock poisoned".into()))? + .map_err(|_| poisoned_provider_error())? .get(&code_hash) .ok_or_else(|| { ProviderError::TrieWitnessError(format!("Code not found for {code_hash}")) @@ -223,15 +489,51 @@ impl + Clone, N: Network> DatabaseRef for ExecutionWitnessRpcDb

Ok(value), + Ok(StorageRead::MissingEmptyTrie) => { + self.ensure_empty_storage_trie(hashed_address)?; + Ok(U256::ZERO) + } + Err(err) => { + if let Some(digest) = err.unresolved_node() { + tracing::warn!( + "Storage trie reached unresolved node {} for address {} slot {}; fetching fallback proof", + digest, + address, + slot + ); + } else if let StorageReadError::MissingTrie { storage_root } = err { + tracing::warn!( + "Storage trie with root {} is missing for address {} slot {}; fetching fallback proof", + storage_root, + address, + slot + ); + } else { + return Err(err.into_provider_error()) + } + + self.fetch_missing_storage_proof_blocking(address, index)?; + + let state = self.state.read().map_err(|_| poisoned_provider_error())?; + match read_storage_from_state(&state, hashed_address, hashed_slot) + .map_err(StorageReadError::into_provider_error)? + { + StorageRead::Value(value) => Ok(value), + StorageRead::MissingEmptyTrie => { + drop(state); + self.ensure_empty_storage_trie(hashed_address)?; + Ok(U256::ZERO) + } + } + } } } @@ -251,11 +553,11 @@ where N: Network, { async fn state(&self, _bundle_state: &BundleState) -> Result { - Ok(self.state.clone()) + Ok(self.state.read().map_err(|_| RpcDbError::Poisoned)?.clone()) } fn bytecodes(&self) -> Vec { - self.codes.read().expect("bytecode cache lock poisoned").values().cloned().collect() + self.codes.read().expect("codes lock poisoned").values().cloned().collect() } async fn ancestor_headers(&self) -> Result, RpcDbError> { @@ -265,148 +567,12 @@ where #[cfg(test)] mod tests { - use std::{ - io::{Read, Write}, - net::TcpListener, - thread, - time::{Duration, Instant}, - }; - use alloy_consensus::Header; use alloy_primitives::hex::FromHex; use alloy_rlp::Decodable; use super::*; - fn code_rpc(code: &str) -> (String, thread::JoinHandle) { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let url = format!("http://{}", listener.local_addr().unwrap()); - listener.set_nonblocking(true).unwrap(); - let code = code.to_string(); - let worker = thread::spawn(move || { - let deadline = Instant::now() + Duration::from_secs(5); - let mut stream = loop { - match listener.accept() { - Ok((stream, _)) => break stream, - Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { - assert!(Instant::now() < deadline, "no bytecode RPC request received"); - thread::sleep(Duration::from_millis(5)); - } - Err(err) => panic!("{err}"), - } - }; - stream.set_read_timeout(Some(Duration::from_secs(5))).unwrap(); - let mut bytes = Vec::new(); - let request = loop { - let mut buffer = [0u8; 1024]; - let count = stream.read(&mut buffer).unwrap(); - assert!(count > 0); - bytes.extend_from_slice(&buffer[..count]); - if let Some(end) = bytes.windows(4).position(|w| w == b"\r\n\r\n") { - let headers = String::from_utf8_lossy(&bytes[..end]); - let length: usize = headers - .lines() - .find_map(|line| { - line.to_ascii_lowercase() - .strip_prefix("content-length:") - .map(|value| value.trim().parse().unwrap()) - }) - .unwrap(); - if bytes.len() >= end + 4 + length { - break serde_json::from_slice::( - &bytes[end + 4..end + 4 + length], - ) - .unwrap() - } - } - }; - let response = - serde_json::json!({"jsonrpc": "2.0", "id": request["id"], "result": code}) - .to_string(); - write!(stream, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}", response.len(), response).unwrap(); - request - }); - (url, worker) - } - - #[tokio::test(flavor = "multi_thread")] - async fn missing_code_uses_parent_block_and_is_cached_for_guest_input() { - let (url, worker) = code_rpc("0x6000"); - let code = Bytecode::new_raw(alloy_primitives::bytes!("6000")); - let hash = code.hash_slow(); - let address = Address::repeat_byte(0x11); - let mut db = ExecutionWitnessRpcDb { - provider: alloy_provider::ProviderBuilder::new().connect_http(url.parse().unwrap()), - state_block_number: 26_167_641, - state: EthereumState { - state_trie: Default::default(), - storage_tries: HashMap::default(), - }, - codes: RwLock::new(HashMap::default()), - ancestor_headers: BTreeMap::new(), - phantom: PhantomData, - }; - db.state - .state_trie - .insert_rlp( - keccak256(address).as_slice(), - TrieAccount { - nonce: 1, - balance: U256::from(1), - code_hash: hash, - ..Default::default() - }, - ) - .unwrap(); - - assert_eq!(db.basic_ref(address).unwrap().unwrap().code, Some(code.clone())); - let request = worker.join().unwrap(); - assert_eq!(request["method"], "eth_getCode"); - assert_eq!(request["params"], serde_json::json!([address, "0x18f4959"])); - // The RPC listener is gone: both paths must use the verified cache. - assert_eq!(db.basic_ref(address).unwrap().unwrap().code, Some(code.clone())); - assert_eq!(db.code_by_hash_ref(hash).unwrap(), code.clone()); - assert_eq!(db.bytecodes(), vec![code]); - assert!(db.basic_ref(Address::repeat_byte(0x22)).unwrap().is_none()); - assert!(db.account_code(address, KECCAK_EMPTY).unwrap().is_none()); - } - - #[tokio::test(flavor = "multi_thread")] - async fn wrong_fallback_code_is_rejected_and_not_exported() { - let (url, worker) = code_rpc("0x6001"); - let expected_hash = keccak256(alloy_primitives::bytes!("6000")); - let address = Address::repeat_byte(0x11); - let mut db = ExecutionWitnessRpcDb { - provider: alloy_provider::ProviderBuilder::new().connect_http(url.parse().unwrap()), - state_block_number: 26_167_641, - state: EthereumState { - state_trie: Default::default(), - storage_tries: HashMap::default(), - }, - codes: RwLock::new(HashMap::default()), - ancestor_headers: BTreeMap::new(), - phantom: PhantomData, - }; - db.state - .state_trie - .insert_rlp( - keccak256(address).as_slice(), - TrieAccount { - nonce: 1, - balance: U256::from(1), - code_hash: expected_hash, - ..Default::default() - }, - ) - .unwrap(); - - let error = db.basic_ref(address).unwrap_err(); - worker.join().unwrap(); - assert!(error.to_string().contains("Fetched code hash mismatch")); - assert!(db.bytecodes().is_empty()); - assert!(db.code_by_hash_ref(expected_hash).is_err()); - } - #[test] fn execution_witness_accepts_rpc_header_objects_and_null_keys() { let json = r#"{ From 4451fa75881ae2b6be538a568f34e6348699d23b Mon Sep 17 00:00:00 2001 From: eigmax Date: Thu, 15 Oct 2026 11:04:59 +0800 Subject: [PATCH 3/8] perf(guest): bind the chain to mainnet, gate the precompile tracker The proof commits only the block hash, so the chain spec and the beneficiary override in the input came from the prover unchecked. The guest now accepts mainnet inputs only, with no custom beneficiary. The cycle-tracker wrapper around every precompile call turned the precompile set into a map probed on each call. It is now behind the precompile-tracking feature, for profiling builds. Measured on the executor (blocks 26184948 / 26184949, same committed hashes): cycles -0.19% / -0.28%, main-trace area -0.11% / -0.16%. --- crates/executor/guest/Cargo.toml | 3 +++ crates/executor/guest/src/custom.rs | 2 +- crates/executor/guest/src/lib.rs | 11 +++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/crates/executor/guest/Cargo.toml b/crates/executor/guest/Cargo.toml index 33a4591..8c32341 100644 --- a/crates/executor/guest/Cargo.toml +++ b/crates/executor/guest/Cargo.toml @@ -59,6 +59,9 @@ bn = { git = "https://github.com/ziren-patches/bn", branch = "patch-0.6.0", pack [features] +# Cycle-tracker spans around every precompile call in the zkVM (profiling only: +# the wrapper turns the precompile set into a map probed on every call). +precompile-tracking = [] optimism = [ "dep:op-alloy-network", "dep:op-alloy-rpc-types", diff --git a/crates/executor/guest/src/custom.rs b/crates/executor/guest/src/custom.rs index 236d9c4..def27d9 100644 --- a/crates/executor/guest/src/custom.rs +++ b/crates/executor/guest/src/custom.rs @@ -73,7 +73,7 @@ impl EvmFactory for CustomEvmFactory { PrecompileSpecId::from_spec_id(input.cfg_env.spec), )); - #[cfg(target_os = "zkvm")] + #[cfg(all(target_os = "zkvm", feature = "precompile-tracking"))] precompiles.map_precompiles(|address, p| { use alloy_evm::precompiles::Precompile; use reth_evm::precompiles::PrecompileInput; diff --git a/crates/executor/guest/src/lib.rs b/crates/executor/guest/src/lib.rs index 06b6fe6..764c52d 100644 --- a/crates/executor/guest/src/lib.rs +++ b/crates/executor/guest/src/lib.rs @@ -19,10 +19,21 @@ use executor::{EthClientExecutor, DESERIALZE_INPUTS}; use io::EthClientExecutorInput; use std::sync::Arc; +/// Verifies an Ethereum mainnet block and returns its hash, its state root and +/// its parent's. +/// +/// The proof commits only the block hash, so the rules the block runs under +/// must not come from the prover: the input's chain must be mainnet, with no +/// beneficiary override (a Clique-only setting that redirects block rewards). pub fn verify_block(input: &[u8]) -> (B256, B256, B256) { println!("cycle-tracker-report-start: {DESERIALZE_INPUTS}"); let input = bincode::deserialize::(input).unwrap(); println!("cycle-tracker-report-end: {DESERIALZE_INPUTS}"); + assert!( + matches!(input.genesis, primitives::genesis::Genesis::Mainnet), + "the guest verifies Ethereum mainnet blocks only" + ); + assert!(input.custom_beneficiary.is_none(), "mainnet blocks pay the header's beneficiary"); // Execute the block. let executor = EthClientExecutor::eth( From 95a76aee2e89a3f8c38d3787d722ef3a8103c5d1 Mon Sep 17 00:00:00 2001 From: eigmax Date: Thu, 15 Oct 2026 11:26:23 +0800 Subject: [PATCH 4/8] perf(guest): walk the JUMPDEST map in assembly on the zkVM The guest derives every executed code's jump table itself, a walk over ~3 M opcodes per mainnet block. Compiled, the walk is nine instructions per opcode, two of them nops in branch delay slots. jumpdest.s fills the slots (the cursor advance, and the next opcode's load, which reads at most 32 bytes into the code's zero padding): six per opcode. Off the zkVM the Rust walk stays. Checked in the executor against the Rust walk on every code of two mainnet blocks and 2,000 random codes. Measured (blocks 26184948 / 26184949, same committed hashes): cycles -1.39% / -1.79%, main-trace area -0.80% / -1.00%. --- crates/executor/guest/src/io.rs | 40 +++++++++++++--- crates/executor/guest/src/jumpdest.s | 71 ++++++++++++++++++++++++++++ crates/executor/guest/src/lib.rs | 1 + 3 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 crates/executor/guest/src/jumpdest.s diff --git a/crates/executor/guest/src/io.rs b/crates/executor/guest/src/io.rs index ad95480..75c0caa 100644 --- a/crates/executor/guest/src/io.rs +++ b/crates/executor/guest/src/io.rs @@ -163,16 +163,45 @@ const OPCODE_SPAN: [u8; 256] = { span }; +#[cfg(target_os = "zkvm")] +core::arch::global_asm!(include_str!("jumpdest.s")); + +#[cfg(target_os = "zkvm")] +extern "C" { + /// [`jump_table_walk`] in assembly (`jumpdest.s`): `code` readable up to + /// `len + 32`, `table` holding `⌈len/8⌉` zeroed bytes. + fn reth_jumpdest_scan(code: *const u8, len: usize, table: *mut u8); +} + /// The `JUMPDEST` bitmap of the first `len` bytes of `padded`, bit `i & 7` of /// byte `i >> 3` set when byte `i` starts an instruction and is `0x5b`. /// -/// The walk reads only bytes below `len`; a push operand may carry the -/// cursor up to 32 bytes past it, which ends the walk. The raw pointers are -/// sound because the cursor is compared against the end before every read -/// and `i >> 3 < ⌈len/8⌉` for every `i < len`. +/// `padded` holds the code's [`RawCode::PADDING`] bytes past `len`. The walk +/// is six cycles per opcode in the zkVM against nine compiled, which saves +/// ~5.6 M of the ~400 M cycles of a mainnet block (~3 M opcodes walked). fn jump_table(padded: &[u8], len: usize) -> Vec { - assert!(len <= padded.len()); + assert!(len + RawCode::PADDING <= padded.len()); let mut table = vec![0u8; len.div_ceil(8)]; + // SAFETY: `padded` is readable up to `len + 32` and `table` holds + // `⌈len/8⌉` zeroed bytes, as the walk requires. + #[cfg(target_os = "zkvm")] + unsafe { + reth_jumpdest_scan(padded.as_ptr(), len, table.as_mut_ptr()) + }; + #[cfg(not(target_os = "zkvm"))] + jump_table_walk(padded, len, &mut table); + table +} + +/// The walk of [`jump_table`] in Rust. +/// +/// It reads only bytes below `len`; a push operand may carry the cursor up to +/// 32 bytes past it, which ends the walk. The raw pointers are sound because +/// the cursor is compared against the end before every read and +/// `i >> 3 < ⌈len/8⌉` for every `i < len`. +#[cfg_attr(target_os = "zkvm", allow(dead_code))] +fn jump_table_walk(padded: &[u8], len: usize, table: &mut [u8]) { + assert!(len <= padded.len() && table.len() == len.div_ceil(8)); let base = padded.as_ptr(); let end = base.wrapping_add(len); let mut p = base; @@ -184,7 +213,6 @@ fn jump_table(padded: &[u8], len: usize) -> Vec { } p = p.wrapping_add(OPCODE_SPAN[op as usize] as usize); } - table } #[derive(Debug)] diff --git a/crates/executor/guest/src/jumpdest.s b/crates/executor/guest/src/jumpdest.s new file mode 100644 index 0000000..0bc12a9 --- /dev/null +++ b/crates/executor/guest/src/jumpdest.s @@ -0,0 +1,71 @@ +// reth_jumpdest_scan(code: *const u8, len: usize, table: *mut u8) +// +// The JUMPDEST bitmap of `code[..len]` for the zkVM guest: bit `i & 7` of +// `table[i >> 3]` is set when byte `i` starts an instruction and is 0x5b. +// `table` holds ceil(len / 8) zeroed bytes, and `code` must be readable up to +// `len + 32`: the RawCode padding, which the walk reads ahead into. +// +// The compiled walk spends nine instructions per opcode, two of them nops in +// branch delay slots. Here the slots carry work: the cursor advance sits in +// the JUMPDEST test's slot and the next opcode's load in the loop branch's, +// six instructions per opcode. The load ahead reads at most 32 bytes past +// `len` (a PUSH32 at `len - 1`), inside the padding. + .section .rodata.reth_jumpdest_span,"a",@progbits + .p2align 2 +.Lreth_jumpdest_span: + # bytes an opcode spans: n + 1 for PUSHn (0x60..0x7f), else 1 + .fill 96, 1, 1 + .byte 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 + .byte 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 + .fill 128, 1, 1 + + .text + .globl reth_jumpdest_scan + .p2align 2 + .type reth_jumpdest_scan,@function + .set nomicromips + .set nomips16 + .ent reth_jumpdest_scan +reth_jumpdest_scan: + .frame $sp,0,$ra + .set noreorder + .set nomacro + .set noat + beqz $5, .Lreth_jumpdest_done + addu $9, $4, $5 + lui $10, %hi(.Lreth_jumpdest_span) + addiu $10, $10, %lo(.Lreth_jumpdest_span) + addiu $11, $zero, 0x5b + move $12, $4 + lbu $13, 0($12) +.Lreth_jumpdest_loop: + # $12 cursor, $13 the opcode under it, $9 end + addu $14, $10, $13 + lbu $14, 0($14) + beq $13, $11, .Lreth_jumpdest_mark + addu $12, $12, $14 +.Lreth_jumpdest_next: + sltu $1, $12, $9 + bnez $1, .Lreth_jumpdest_loop + lbu $13, 0($12) +.Lreth_jumpdest_done: + jr $ra + nop +.Lreth_jumpdest_mark: + # the cursor is one past the JUMPDEST: its index is $12 - 1 - code + subu $14, $12, $4 + addiu $14, $14, -1 + srl $15, $14, 3 + addu $15, $6, $15 + lbu $24, 0($15) + andi $14, $14, 7 + addiu $25, $zero, 1 + sllv $25, $25, $14 + or $24, $24, $25 + b .Lreth_jumpdest_next + sb $24, 0($15) + .set at + .set macro + .set reorder + .end reth_jumpdest_scan + .size reth_jumpdest_scan, .-reth_jumpdest_scan diff --git a/crates/executor/guest/src/lib.rs b/crates/executor/guest/src/lib.rs index 764c52d..3fcaa1c 100644 --- a/crates/executor/guest/src/lib.rs +++ b/crates/executor/guest/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(target_os = "zkvm", feature(asm_experimental_arch))] /// Client program input data types. pub mod io; From 0440b2c14c431d9691854219c4888a575445432e Mon Sep 17 00:00:00 2001 From: eigmax Date: Thu, 15 Oct 2026 11:43:29 +0800 Subject: [PATCH 5/8] perf(guest): revm fork with cheaper dispatch and jumps Moves the guest to the fork's patch-31.0.2-mips32-dispatch branch, which adds to the 32-bit fast paths: static gas charged on the low word of the remaining gas, JUMPDEST folded into the taken jump that lands on it, and PUSH2 + JUMP / JUMPI run as one instruction. Measured on the executor (blocks 26184948 / 26184949, same committed hashes): cycles -3.20% / -3.44%, main-trace area -2.06% / -2.16%. --- bin/guest/Cargo.lock | 24 ++++++++++++------------ bin/guest/Cargo.toml | 27 ++++++++++++++------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/bin/guest/Cargo.lock b/bin/guest/Cargo.lock index 948e655..08854b3 100644 --- a/bin/guest/Cargo.lock +++ b/bin/guest/Cargo.lock @@ -3356,7 +3356,7 @@ dependencies = [ [[package]] name = "revm" version = "31.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "revm-bytecode", "revm-context", @@ -3374,7 +3374,7 @@ dependencies = [ [[package]] name = "revm-bytecode" version = "7.1.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "bitvec", "phf", @@ -3385,7 +3385,7 @@ dependencies = [ [[package]] name = "revm-context" version = "11.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "alloy-consensus 1.0.41", "bitvec", @@ -3402,7 +3402,7 @@ dependencies = [ [[package]] name = "revm-context-interface" version = "12.0.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "alloy-consensus 1.0.41", "alloy-eip2930", @@ -3418,7 +3418,7 @@ dependencies = [ [[package]] name = "revm-database" version = "9.0.6" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "alloy-eips 1.0.41", "revm-bytecode", @@ -3431,7 +3431,7 @@ dependencies = [ [[package]] name = "revm-database-interface" version = "8.0.5" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "auto_impl", "either", @@ -3443,7 +3443,7 @@ dependencies = [ [[package]] name = "revm-handler" version = "12.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "auto_impl", "derive-where", @@ -3461,7 +3461,7 @@ dependencies = [ [[package]] name = "revm-inspector" version = "12.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "auto_impl", "either", @@ -3477,7 +3477,7 @@ dependencies = [ [[package]] name = "revm-interpreter" version = "29.0.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "revm-bytecode", "revm-context-interface", @@ -3489,7 +3489,7 @@ dependencies = [ [[package]] name = "revm-precompile" version = "29.0.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -3510,7 +3510,7 @@ dependencies = [ [[package]] name = "revm-primitives" version = "21.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "alloy-primitives", "num_enum", @@ -3521,7 +3521,7 @@ dependencies = [ [[package]] name = "revm-state" version = "8.1.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32#ba1a5f64fb2469481550a268d4b032097a3e3d8b" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" dependencies = [ "bitflags", "revm-bytecode", diff --git a/bin/guest/Cargo.toml b/bin/guest/Cargo.toml index 8522181..490c366 100644 --- a/bin/guest/Cargo.toml +++ b/bin/guest/Cargo.toml @@ -27,20 +27,21 @@ tracing = { version = "0.1", features = ["max_level_off", "release_max_level_off [patch.crates-io] ruint = { git = "https://github.com/ziren-patches/ruint", branch = "patch-1.17.0" } -revm = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-bytecode = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-context = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-context-interface = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-database = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-database-interface = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-handler = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-inspector = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-interpreter = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-precompile = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-primitives = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } -revm-state = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32" } +revm = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-bytecode = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-context = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-context-interface = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-database = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-database-interface = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-handler = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-inspector = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-interpreter = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-precompile = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-primitives = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-state = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } # Precompile patches, and the revm workspace with its 32-bit interpreter -# fast paths (gas, stack exchange, memory words). +# fast paths (gas, stack exchange, memory words) and cheaper jumps (JUMPDEST +# folded into the jump, PUSH2 + JUMP / JUMPI run as one instruction). sha2 = { git = "https://github.com/ziren-patches/RustCrypto-hashes", branch = "patch-sha2-0.10.9", package = "sha2" } bn = { git = "https://github.com/ziren-patches/bn", branch = "patch-0.6.0", package = "substrate-bn" } k256 = { git = "https://github.com/ziren-patches/elliptic-curves", branch = "patch-k256-0.13.4" } From 7a051b994b308ffb9d304c7aa0c3e3f9e72785b5 Mon Sep 17 00:00:00 2001 From: eigmax Date: Thu, 15 Oct 2026 12:15:31 +0800 Subject: [PATCH 6/8] deps: Ziren from perf/shamir-msm Every Ziren dependency now names the perf/shamir-msm branch (Ziren #562: Shamir's trick in the zkVM lib's two-point MSM, which ECDSA recovery runs per transaction), and the guest's comment says the Ziren checkout next to this repo, which its zkvm crates come from, is to be on that branch. The precompile patches still declare Ziren unbranched, and cargo cannot redirect a git source to another branch of it, so the lockfile also keeps their main-branch zkm-lib, zkm-primitives and zkm-zkvm. Those edges exist only for the zkVM target, where the guest's path patch replaces both with the one checkout. Back to main when #562 lands. Measured on the executor (blocks 26184948 / 26184949, same committed hashes): main-trace area -1.83% / -1.71%, cycles -1.05% / -1.00%. --- Cargo.lock | 119 ++++++++++++++++++++++--------- Cargo.toml | 10 +-- bin/guest/Cargo.toml | 13 ++-- crates/executor/guest/Cargo.toml | 2 +- 4 files changed, 97 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5decd45..e35bbbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -340,7 +340,7 @@ dependencies = [ "serde", "sha3", "tiny-keccak", - "zkm-zkvm", + "zkm-zkvm 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -1468,7 +1468,7 @@ dependencies = [ "pairing 0.23.0", "rand_core 0.6.4", "subtle", - "zkm-lib", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -2965,7 +2965,7 @@ dependencies = [ "serde_with", "substrate-bn", "thiserror 1.0.69", - "zkm-lib", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] @@ -3803,7 +3803,7 @@ dependencies = [ "serdect", "sha2", "signature", - "zkm-lib", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -4541,7 +4541,7 @@ dependencies = [ "hex", "primeorder", "sha2", - "zkm-lib", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -7403,7 +7403,7 @@ dependencies = [ "num-bigint 0.4.6", "rand 0.8.5", "rustc-hex", - "zkm-lib", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -8992,7 +8992,7 @@ dependencies = [ [[package]] name = "zkm-build" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "anyhow", "cargo_metadata", @@ -9003,7 +9003,7 @@ dependencies = [ [[package]] name = "zkm-core-executor" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "anyhow", "bincode", @@ -9041,13 +9041,13 @@ dependencies = [ "zkm-core-jit", "zkm-curves", "zkm-pcs", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-core-jit" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "dynasmrt", "hashbrown 0.14.5", @@ -9064,7 +9064,7 @@ dependencies = [ [[package]] name = "zkm-core-machine" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "bincode", "cfg-if", @@ -9110,13 +9110,13 @@ dependencies = [ "zkm-curves", "zkm-derive", "zkm-pcs", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-cuda" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "bincode", "ctrlc", @@ -9134,7 +9134,7 @@ dependencies = [ [[package]] name = "zkm-curves" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "cfg-if", "curve25519-dalek", @@ -9152,19 +9152,32 @@ dependencies = [ "tracing", "typenum", "zkm-poly", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-derive" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "zkm-lib" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +dependencies = [ + "bincode", + "cfg-if", + "elliptic-curve", + "serde", + "sha2", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", +] + [[package]] name = "zkm-lib" version = "2.0.0" @@ -9175,13 +9188,13 @@ dependencies = [ "elliptic-curve", "serde", "sha2", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] name = "zkm-pcs" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "arrayref", "bincode", @@ -9219,19 +9232,39 @@ dependencies = [ "tracing-subscriber", "zkm-derive", "zkm-poly", - "zkm-primitives", - "zkm-zkvm", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-zkvm 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-poly" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "itertools 0.13.0", "p3-field", ] +[[package]] +name = "zkm-primitives" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +dependencies = [ + "bincode", + "blake3", + "hex", + "lazy_static", + "num-bigint 0.4.6", + "p3-field", + "p3-koala-bear", + "p3-monty-31", + "p3-poseidon2", + "p3-symmetric", + "serde", + "sha2", + "tracing", +] + [[package]] name = "zkm-primitives" version = "2.0.0" @@ -9255,7 +9288,7 @@ dependencies = [ [[package]] name = "zkm-prover" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "anyhow", "bincode", @@ -9285,7 +9318,7 @@ dependencies = [ "zkm-core-executor", "zkm-core-machine", "zkm-pcs", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-recursion-circuit", "zkm-recursion-compiler", "zkm-recursion-core", @@ -9295,7 +9328,7 @@ dependencies = [ [[package]] name = "zkm-recursion-circuit" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "hashbrown 0.14.5", "itertools 0.13.0", @@ -9319,7 +9352,7 @@ dependencies = [ "zkm-core-machine", "zkm-derive", "zkm-pcs", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-recursion-compiler", "zkm-recursion-core", "zkm-recursion-gnark-ffi", @@ -9328,7 +9361,7 @@ dependencies = [ [[package]] name = "zkm-recursion-compiler" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "backtrace", "itertools 0.13.0", @@ -9341,7 +9374,7 @@ dependencies = [ "vec_map", "zkm-core-machine", "zkm-pcs", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-recursion-core", "zkm-recursion-derive", ] @@ -9349,7 +9382,7 @@ dependencies = [ [[package]] name = "zkm-recursion-core" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "backtrace", "bincode", @@ -9382,13 +9415,13 @@ dependencies = [ "zkm-core-machine", "zkm-derive", "zkm-pcs", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-recursion-derive" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "quote", "syn 1.0.109", @@ -9397,7 +9430,7 @@ dependencies = [ [[package]] name = "zkm-recursion-gnark-ffi" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "anyhow", "bincode", @@ -9421,7 +9454,7 @@ dependencies = [ [[package]] name = "zkm-sdk" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" dependencies = [ "alloy-primitives", "anyhow", @@ -9461,10 +9494,26 @@ dependencies = [ "zkm-core-machine", "zkm-cuda", "zkm-pcs", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-prover", ] +[[package]] +name = "zkm-zkvm" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +dependencies = [ + "bincode", + "cfg-if", + "getrandom 0.2.16", + "lazy_static", + "rand 0.8.5", + "serde", + "sha2", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", +] + [[package]] name = "zkm-zkvm" version = "2.0.0" @@ -9478,8 +9527,8 @@ dependencies = [ "rand 0.8.5", "serde", "sha2", - "zkm-lib", - "zkm-primitives", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8c9332b..85a1fdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,11 +47,11 @@ primitives = { path = "./crates/primitives" } provider = { path = "./crates/provider" } # Ziren -zkm-build = { git = "https://github.com/ProjectZKM/Ziren" } -zkm-core-executor = { git = "https://github.com/ProjectZKM/Ziren" } -zkm-prover = { git = "https://github.com/ProjectZKM/Ziren" } -zkm-cuda = { git = "https://github.com/ProjectZKM/Ziren" } -zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren" } +zkm-build = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-core-executor = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-prover = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-cuda = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } # reth reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", default-features = false } diff --git a/bin/guest/Cargo.toml b/bin/guest/Cargo.toml index 490c366..6a07ceb 100644 --- a/bin/guest/Cargo.toml +++ b/bin/guest/Cargo.toml @@ -18,7 +18,7 @@ bincode = "1.3.3" guest-executor = { path = "../../crates/executor/guest" } # Ziren -zkm-zkvm = { git = "https://github.com/ProjectZKM/Ziren" } +zkm-zkvm = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } # zkm-zkvm = { path = "../../../Ziren/crates/zkvm/entrypoint" } # Statically turns off logging @@ -49,11 +49,12 @@ p256 = { git = "https://github.com/ziren-patches/elliptic-curves", branch = "pat alloy-primitives-v1-4-1 = { git = "https://github.com/ziren-patches/core.git", package = "alloy-primitives", branch = "patch-alloy-primitives-1.4.1-hasher" } # The guest's zkvm crates come from the canonical Ziren checkout next to this -# repo (its `main` tip), the same way the GPU prover consumes it: every -# zkm-zkvm / zkm-lib in the graph (the precompile patches declare their own, -# unbranched, which cargo cannot redirect to another branch of the same URL) -# resolves to this one source, so there is exactly one global allocator and -# the word-wise memcmp / zero-copy keccak reach every caller. +# repo, the same way the GPU prover consumes it; check it out at the Ziren +# branch the dependencies above name. Every zkm-zkvm / zkm-lib in the graph +# (the precompile patches declare their own, unbranched, and cargo cannot +# redirect a git source to another branch of the same URL) resolves to this +# one source, so there is exactly one global allocator and the word-wise +# memcmp / zero-copy keccak reach every caller. [patch."https://github.com/ProjectZKM/Ziren"] zkm-zkvm = { path = "../../../Ziren/crates/zkvm/entrypoint" } zkm-lib = { path = "../../../Ziren/crates/zkvm/lib" } diff --git a/crates/executor/guest/Cargo.toml b/crates/executor/guest/Cargo.toml index 8c32341..7b77915 100644 --- a/crates/executor/guest/Cargo.toml +++ b/crates/executor/guest/Cargo.toml @@ -54,7 +54,7 @@ op-alloy-rpc-types = { workspace = true, optional = true } kzg-rs.workspace = true bls12_381 = { git = "https://github.com/ziren-patches/bls12_381", branch = "patch-0.8.0", default-features = false, features = ["groups", "pairings", "alloc", "experimental"] } aurora-engine-modexp = "1.2.0" -zkm-lib = { git = "https://github.com/ProjectZKM/Ziren" } +zkm-lib = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } bn = { git = "https://github.com/ziren-patches/bn", branch = "patch-0.6.0", package = "substrate-bn" } From eb3957b85fc45f81d85c94cb54a33c33abc8bbdb Mon Sep 17 00:00:00 2001 From: eigmax Date: Thu, 15 Oct 2026 17:05:26 +0800 Subject: [PATCH 7/8] deps: Ziren from perf/glv-msm, revm compare + PUSH2 + JUMPI fusion Ziren moves to perf/glv-msm (Ziren #563, stacked on #562): the zkVM lib's secp256k1 two-point MSM uses the GLV endomorphism, about half the doublings and two thirds of the additions per signature recovery, each a precompile call. The guest's revm fork moves to 2a9844a0 on patch-31.0.2-mips32-dispatch (ziren-patches/revm#4): ISZERO / EQ / LT / GT + PUSH2 + JUMPI run as one instruction, and the stack pushes in place. The lock also picks up the bn patch's newer branch tip, whose only change is its zkm-lib dependency losing a pinned tag; the guest path-patches zkm-lib, so its code is unchanged. Measured on the executor (blocks 26184948 / 26184949, same committed hashes) against the previous commit: cycles +0.46% / +0.34%, main-trace cells -0.23% / -0.26%. On one GPU, with every proof verified, proving time is -1.4% / -5.6% (GLV alone -2.5% / -5.0%): a secp256k1 precompile call costs about 30 us there, far more than its cells suggest. --- Cargo.lock | 66 ++++++++++++++++---------------- Cargo.toml | 10 ++--- bin/guest/Cargo.lock | 26 ++++++------- bin/guest/Cargo.toml | 2 +- crates/executor/guest/Cargo.toml | 2 +- 5 files changed, 53 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e35bbbf..b7386fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2965,7 +2965,7 @@ dependencies = [ "serde_with", "substrate-bn", "thiserror 1.0.69", - "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", ] [[package]] @@ -8992,7 +8992,7 @@ dependencies = [ [[package]] name = "zkm-build" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "cargo_metadata", @@ -9003,7 +9003,7 @@ dependencies = [ [[package]] name = "zkm-core-executor" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "bincode", @@ -9041,13 +9041,13 @@ dependencies = [ "zkm-core-jit", "zkm-curves", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", ] [[package]] name = "zkm-core-jit" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "dynasmrt", "hashbrown 0.14.5", @@ -9064,7 +9064,7 @@ dependencies = [ [[package]] name = "zkm-core-machine" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "cfg-if", @@ -9110,13 +9110,13 @@ dependencies = [ "zkm-curves", "zkm-derive", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", ] [[package]] name = "zkm-cuda" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "ctrlc", @@ -9134,7 +9134,7 @@ dependencies = [ [[package]] name = "zkm-curves" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "cfg-if", "curve25519-dalek", @@ -9152,13 +9152,13 @@ dependencies = [ "tracing", "typenum", "zkm-poly", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", ] [[package]] name = "zkm-derive" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "proc-macro2", "quote", @@ -9168,14 +9168,14 @@ dependencies = [ [[package]] name = "zkm-lib" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "cfg-if", "elliptic-curve", "serde", "sha2", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", ] [[package]] @@ -9194,7 +9194,7 @@ dependencies = [ [[package]] name = "zkm-pcs" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "arrayref", "bincode", @@ -9232,14 +9232,14 @@ dependencies = [ "tracing-subscriber", "zkm-derive", "zkm-poly", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", - "zkm-zkvm 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-zkvm 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", ] [[package]] name = "zkm-poly" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "itertools 0.13.0", "p3-field", @@ -9248,7 +9248,7 @@ dependencies = [ [[package]] name = "zkm-primitives" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "blake3", @@ -9288,7 +9288,7 @@ dependencies = [ [[package]] name = "zkm-prover" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "bincode", @@ -9318,7 +9318,7 @@ dependencies = [ "zkm-core-executor", "zkm-core-machine", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", "zkm-recursion-circuit", "zkm-recursion-compiler", "zkm-recursion-core", @@ -9328,7 +9328,7 @@ dependencies = [ [[package]] name = "zkm-recursion-circuit" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "hashbrown 0.14.5", "itertools 0.13.0", @@ -9352,7 +9352,7 @@ dependencies = [ "zkm-core-machine", "zkm-derive", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", "zkm-recursion-compiler", "zkm-recursion-core", "zkm-recursion-gnark-ffi", @@ -9361,7 +9361,7 @@ dependencies = [ [[package]] name = "zkm-recursion-compiler" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "backtrace", "itertools 0.13.0", @@ -9374,7 +9374,7 @@ dependencies = [ "vec_map", "zkm-core-machine", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", "zkm-recursion-core", "zkm-recursion-derive", ] @@ -9382,7 +9382,7 @@ dependencies = [ [[package]] name = "zkm-recursion-core" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "backtrace", "bincode", @@ -9415,13 +9415,13 @@ dependencies = [ "zkm-core-machine", "zkm-derive", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", ] [[package]] name = "zkm-recursion-derive" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "quote", "syn 1.0.109", @@ -9430,7 +9430,7 @@ dependencies = [ [[package]] name = "zkm-recursion-gnark-ffi" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "bincode", @@ -9454,7 +9454,7 @@ dependencies = [ [[package]] name = "zkm-sdk" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "alloy-primitives", "anyhow", @@ -9494,14 +9494,14 @@ dependencies = [ "zkm-core-machine", "zkm-cuda", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", "zkm-prover", ] [[package]] name = "zkm-zkvm" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#b2a2e287752c19c77c790ca42ed8403688e395d1" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "cfg-if", @@ -9510,8 +9510,8 @@ dependencies = [ "rand 0.8.5", "serde", "sha2", - "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 85a1fdb..1f22537 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,11 +47,11 @@ primitives = { path = "./crates/primitives" } provider = { path = "./crates/provider" } # Ziren -zkm-build = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } -zkm-core-executor = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } -zkm-prover = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } -zkm-cuda = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } -zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-build = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } +zkm-core-executor = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } +zkm-prover = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } +zkm-cuda = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } +zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } # reth reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", default-features = false } diff --git a/bin/guest/Cargo.lock b/bin/guest/Cargo.lock index 08854b3..26a1a2f 100644 --- a/bin/guest/Cargo.lock +++ b/bin/guest/Cargo.lock @@ -3356,7 +3356,7 @@ dependencies = [ [[package]] name = "revm" version = "31.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "revm-bytecode", "revm-context", @@ -3374,7 +3374,7 @@ dependencies = [ [[package]] name = "revm-bytecode" version = "7.1.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "bitvec", "phf", @@ -3385,7 +3385,7 @@ dependencies = [ [[package]] name = "revm-context" version = "11.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "alloy-consensus 1.0.41", "bitvec", @@ -3402,7 +3402,7 @@ dependencies = [ [[package]] name = "revm-context-interface" version = "12.0.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "alloy-consensus 1.0.41", "alloy-eip2930", @@ -3418,7 +3418,7 @@ dependencies = [ [[package]] name = "revm-database" version = "9.0.6" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "alloy-eips 1.0.41", "revm-bytecode", @@ -3431,7 +3431,7 @@ dependencies = [ [[package]] name = "revm-database-interface" version = "8.0.5" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "auto_impl", "either", @@ -3443,7 +3443,7 @@ dependencies = [ [[package]] name = "revm-handler" version = "12.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "auto_impl", "derive-where", @@ -3461,7 +3461,7 @@ dependencies = [ [[package]] name = "revm-inspector" version = "12.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "auto_impl", "either", @@ -3477,7 +3477,7 @@ dependencies = [ [[package]] name = "revm-interpreter" version = "29.0.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "revm-bytecode", "revm-context-interface", @@ -3489,7 +3489,7 @@ dependencies = [ [[package]] name = "revm-precompile" version = "29.0.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -3510,7 +3510,7 @@ dependencies = [ [[package]] name = "revm-primitives" version = "21.0.2" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "alloy-primitives", "num_enum", @@ -3521,7 +3521,7 @@ dependencies = [ [[package]] name = "revm-state" version = "8.1.1" -source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#66e8f7c45a5145e2b842c1d06c651e6d0e66a307" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "bitflags", "revm-bytecode", @@ -3974,7 +3974,7 @@ dependencies = [ [[package]] name = "substrate-bn" version = "0.6.0" -source = "git+https://github.com/ziren-patches/bn?branch=patch-0.6.0#0dfeeb1b7bfc21941b6e4964d678abd094a54a6f" +source = "git+https://github.com/ziren-patches/bn?branch=patch-0.6.0#509192f90ef14511bfa64681b2d7c8333df13979" dependencies = [ "bytemuck", "byteorder", diff --git a/bin/guest/Cargo.toml b/bin/guest/Cargo.toml index 6a07ceb..3644214 100644 --- a/bin/guest/Cargo.toml +++ b/bin/guest/Cargo.toml @@ -18,7 +18,7 @@ bincode = "1.3.3" guest-executor = { path = "../../crates/executor/guest" } # Ziren -zkm-zkvm = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-zkvm = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } # zkm-zkvm = { path = "../../../Ziren/crates/zkvm/entrypoint" } # Statically turns off logging diff --git a/crates/executor/guest/Cargo.toml b/crates/executor/guest/Cargo.toml index 7b77915..fcd881c 100644 --- a/crates/executor/guest/Cargo.toml +++ b/crates/executor/guest/Cargo.toml @@ -54,7 +54,7 @@ op-alloy-rpc-types = { workspace = true, optional = true } kzg-rs.workspace = true bls12_381 = { git = "https://github.com/ziren-patches/bls12_381", branch = "patch-0.8.0", default-features = false, features = ["groups", "pairings", "alloc", "experimental"] } aurora-engine-modexp = "1.2.0" -zkm-lib = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-lib = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } bn = { git = "https://github.com/ziren-patches/bn", branch = "patch-0.6.0", package = "substrate-bn" } From 7a1fcbef77117ef1cc010f524e3fddabc8d7c670 Mon Sep 17 00:00:00 2001 From: eigmax Date: Thu, 15 Oct 2026 18:36:05 +0800 Subject: [PATCH 8/8] deps: Ziren from perf/shamir-msm (Ziren #562) The Ziren optimizations are one pull request now, #562 on perf/shamir-msm, so every Ziren dependency names that branch. The lock stays at 8a9ab4fe, the GLV commit this guest was built and measured with: the branch goes on to change the keccak AIR, which the client must not pick up before the GPU prover does. The guest ELF is unchanged (766ff6ce). --- Cargo.lock | 72 ++++++++++++++++---------------- Cargo.toml | 10 ++--- bin/guest/Cargo.toml | 2 +- crates/executor/guest/Cargo.toml | 2 +- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b7386fd..00bd78d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,7 +518,7 @@ dependencies = [ "alloy-rlp", "alloy-serde", "alloy-sol-types", - "itertools 0.14.0", + "itertools 0.13.0", "serde", "serde_json", "serde_with", @@ -2965,7 +2965,7 @@ dependencies = [ "serde_with", "substrate-bn", "thiserror 1.0.69", - "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] @@ -5380,7 +5380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ "heck", - "itertools 0.14.0", + "itertools 0.10.5", "log", "multimap", "once_cell", @@ -5413,7 +5413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.111", @@ -8992,7 +8992,7 @@ dependencies = [ [[package]] name = "zkm-build" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "cargo_metadata", @@ -9003,7 +9003,7 @@ dependencies = [ [[package]] name = "zkm-core-executor" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "bincode", @@ -9041,13 +9041,13 @@ dependencies = [ "zkm-core-jit", "zkm-curves", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-core-jit" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "dynasmrt", "hashbrown 0.14.5", @@ -9064,7 +9064,7 @@ dependencies = [ [[package]] name = "zkm-core-machine" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "cfg-if", @@ -9110,13 +9110,13 @@ dependencies = [ "zkm-curves", "zkm-derive", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-cuda" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "ctrlc", @@ -9134,7 +9134,7 @@ dependencies = [ [[package]] name = "zkm-curves" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "cfg-if", "curve25519-dalek", @@ -9152,13 +9152,13 @@ dependencies = [ "tracing", "typenum", "zkm-poly", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-derive" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "proc-macro2", "quote", @@ -9168,14 +9168,14 @@ dependencies = [ [[package]] name = "zkm-lib" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "cfg-if", "elliptic-curve", "serde", "sha2", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] @@ -9194,7 +9194,7 @@ dependencies = [ [[package]] name = "zkm-pcs" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "arrayref", "bincode", @@ -9232,14 +9232,14 @@ dependencies = [ "tracing-subscriber", "zkm-derive", "zkm-poly", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", - "zkm-zkvm 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-zkvm 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-poly" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "itertools 0.13.0", "p3-field", @@ -9248,7 +9248,7 @@ dependencies = [ [[package]] name = "zkm-primitives" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "blake3", @@ -9288,7 +9288,7 @@ dependencies = [ [[package]] name = "zkm-prover" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "bincode", @@ -9318,7 +9318,7 @@ dependencies = [ "zkm-core-executor", "zkm-core-machine", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-recursion-circuit", "zkm-recursion-compiler", "zkm-recursion-core", @@ -9328,7 +9328,7 @@ dependencies = [ [[package]] name = "zkm-recursion-circuit" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "hashbrown 0.14.5", "itertools 0.13.0", @@ -9352,7 +9352,7 @@ dependencies = [ "zkm-core-machine", "zkm-derive", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-recursion-compiler", "zkm-recursion-core", "zkm-recursion-gnark-ffi", @@ -9361,7 +9361,7 @@ dependencies = [ [[package]] name = "zkm-recursion-compiler" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "backtrace", "itertools 0.13.0", @@ -9374,7 +9374,7 @@ dependencies = [ "vec_map", "zkm-core-machine", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-recursion-core", "zkm-recursion-derive", ] @@ -9382,7 +9382,7 @@ dependencies = [ [[package]] name = "zkm-recursion-core" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "backtrace", "bincode", @@ -9415,13 +9415,13 @@ dependencies = [ "zkm-core-machine", "zkm-derive", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-recursion-derive" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "quote", "syn 1.0.109", @@ -9430,7 +9430,7 @@ dependencies = [ [[package]] name = "zkm-recursion-gnark-ffi" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "bincode", @@ -9454,7 +9454,7 @@ dependencies = [ [[package]] name = "zkm-sdk" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "alloy-primitives", "anyhow", @@ -9494,14 +9494,14 @@ dependencies = [ "zkm-core-machine", "zkm-cuda", "zkm-pcs", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-prover", ] [[package]] name = "zkm-zkvm" version = "2.0.0" -source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "cfg-if", @@ -9510,8 +9510,8 @@ dependencies = [ "rand 0.8.5", "serde", "sha2", - "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", - "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fglv-msm)", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1f22537..85a1fdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,11 +47,11 @@ primitives = { path = "./crates/primitives" } provider = { path = "./crates/provider" } # Ziren -zkm-build = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } -zkm-core-executor = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } -zkm-prover = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } -zkm-cuda = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } -zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } +zkm-build = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-core-executor = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-prover = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-cuda = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } # reth reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", default-features = false } diff --git a/bin/guest/Cargo.toml b/bin/guest/Cargo.toml index 3644214..6a07ceb 100644 --- a/bin/guest/Cargo.toml +++ b/bin/guest/Cargo.toml @@ -18,7 +18,7 @@ bincode = "1.3.3" guest-executor = { path = "../../crates/executor/guest" } # Ziren -zkm-zkvm = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } +zkm-zkvm = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } # zkm-zkvm = { path = "../../../Ziren/crates/zkvm/entrypoint" } # Statically turns off logging diff --git a/crates/executor/guest/Cargo.toml b/crates/executor/guest/Cargo.toml index fcd881c..7b77915 100644 --- a/crates/executor/guest/Cargo.toml +++ b/crates/executor/guest/Cargo.toml @@ -54,7 +54,7 @@ op-alloy-rpc-types = { workspace = true, optional = true } kzg-rs.workspace = true bls12_381 = { git = "https://github.com/ziren-patches/bls12_381", branch = "patch-0.8.0", default-features = false, features = ["groups", "pairings", "alloc", "experimental"] } aurora-engine-modexp = "1.2.0" -zkm-lib = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/glv-msm" } +zkm-lib = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } bn = { git = "https://github.com/ziren-patches/bn", branch = "patch-0.6.0", package = "substrate-bn" }