From 710225c9e0ac5822b2965ce74951cf000bbb8a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Gonz=C3=A1lez?= Date: Tue, 13 Feb 2024 17:53:52 +0100 Subject: [PATCH] Simulate jumpdest data with the interpreter (#1489) * Simulate jumpdest data with the interpreter * Fix mising type paramenter on some tests * Refactor simulation and fix some intepreter bugs * Fix bug in interpreter * Apply suggestions from code review Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> * Address remaining reviews * [WIP] Fixing memory issue * [WIP] Fixed memory issue but erc20 failing * Fix interpreter halting issue * Restore transition.rs * Minor * Adress reviews * Address reviews * Missing fix --------- Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> --- evm/src/cpu/kernel/interpreter.rs | 233 +++++++++++++----- evm/src/cpu/kernel/mod.rs | 3 +- evm/src/cpu/kernel/tests/account_code.rs | 23 +- evm/src/cpu/kernel/tests/add11.rs | 5 +- evm/src/cpu/kernel/tests/balance.rs | 8 +- evm/src/cpu/kernel/tests/bignum/mod.rs | 3 +- evm/src/cpu/kernel/tests/blake2_f.rs | 3 +- evm/src/cpu/kernel/tests/block_hash.rs | 13 +- evm/src/cpu/kernel/tests/bls381.rs | 3 +- evm/src/cpu/kernel/tests/bn254.rs | 17 +- evm/src/cpu/kernel/tests/core/access_lists.rs | 13 +- .../cpu/kernel/tests/core/create_addresses.rs | 7 +- .../cpu/kernel/tests/core/intrinsic_gas.rs | 7 +- .../kernel/tests/core/jumpdest_analysis.rs | 71 ++++-- evm/src/cpu/kernel/tests/ecc/curve_ops.rs | 108 +++++--- evm/src/cpu/kernel/tests/ecc/ecrecover.rs | 9 +- evm/src/cpu/kernel/tests/exp.rs | 9 +- evm/src/cpu/kernel/tests/hash.rs | 5 +- evm/src/cpu/kernel/tests/log.rs | 9 +- evm/src/cpu/kernel/tests/mpt/delete.rs | 3 +- evm/src/cpu/kernel/tests/mpt/hash.rs | 3 +- evm/src/cpu/kernel/tests/mpt/hex_prefix.rs | 7 +- evm/src/cpu/kernel/tests/mpt/insert.rs | 3 +- evm/src/cpu/kernel/tests/mpt/load.rs | 13 +- evm/src/cpu/kernel/tests/mpt/read.rs | 3 +- evm/src/cpu/kernel/tests/packing.rs | 4 +- evm/src/cpu/kernel/tests/receipt.rs | 13 +- evm/src/cpu/kernel/tests/rlp/decode.rs | 19 +- evm/src/cpu/kernel/tests/rlp/encode.rs | 19 +- evm/src/cpu/kernel/tests/rlp/num_bytes.rs | 7 +- evm/src/cpu/kernel/tests/signed_syscalls.rs | 3 +- .../transaction_parsing/parse_type_0_txn.rs | 4 +- evm/src/generation/mod.rs | 84 ------- evm/src/generation/prover_input.rs | 91 ++++--- 34 files changed, 512 insertions(+), 313 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index cdd2e99f..a8937cf2 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -9,8 +9,11 @@ use eth_trie_utils::partial_trie::PartialTrie; use ethereum_types::{BigEndianHash, H160, H256, U256, U512}; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; use super::assembler::BYTES_PER_OFFSET; +use super::utils::u256_from_bool; +use crate::cpu::halt; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::context_metadata::ContextMetadata; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; @@ -23,7 +26,7 @@ use crate::generation::rlp::all_rlp_prover_inputs_reversed; use crate::generation::state::{all_withdrawals_prover_inputs_reversed, GenerationState}; use crate::generation::GenerationInputs; use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR}; -use crate::util::{h2u, u256_to_usize}; +use crate::util::{h2u, u256_to_u8, u256_to_usize}; use crate::witness::errors::{ProgramError, ProverInputError}; use crate::witness::gas::gas_to_charge; use crate::witness::memory::{MemoryAddress, MemoryContextState, MemorySegmentState, MemoryState}; @@ -32,8 +35,6 @@ use crate::witness::state::RegistersState; use crate::witness::transition::decode; use crate::witness::util::stack_peek; -type F = GoldilocksField; - /// Halt interpreter execution whenever a jump to this offset is done. const DEFAULT_HALT_OFFSET: usize = 0xdeadbeef; @@ -55,14 +56,17 @@ impl MemoryState { } } -pub(crate) struct Interpreter<'a> { +pub(crate) struct Interpreter<'a, F: Field> { pub(crate) generation_state: GenerationState, prover_inputs_map: &'a HashMap, pub(crate) halt_offsets: Vec, + // The interpreter will halt only if the current context matches halt_context + halt_context: Option, pub(crate) debug_offsets: Vec, running: bool, opcode_count: [usize; 0x100], memops: Vec, + jumpdest_table: HashMap>, } /// Structure storing the state of the interpreter's registers. @@ -80,10 +84,10 @@ struct InterpreterCheckpoint { mem_len: usize, } -pub(crate) fn run_interpreter( +pub(crate) fn run_interpreter( initial_offset: usize, initial_stack: Vec, -) -> anyhow::Result> { +) -> anyhow::Result> { run( &KERNEL.code, initial_offset, @@ -100,9 +104,9 @@ pub(crate) struct InterpreterMemoryInitialization { pub memory: Vec<(usize, Vec)>, } -pub(crate) fn run_interpreter_with_memory( +pub(crate) fn run_interpreter_with_memory( memory_init: InterpreterMemoryInitialization, -) -> anyhow::Result> { +) -> anyhow::Result> { let label = KERNEL.global_labels[&memory_init.label]; let mut stack = memory_init.stack; stack.reverse(); @@ -119,17 +123,47 @@ pub(crate) fn run_interpreter_with_memory( Ok(interpreter) } -pub(crate) fn run<'a>( +pub(crate) fn run<'a, F: Field>( code: &'a [u8], initial_offset: usize, initial_stack: Vec, prover_inputs: &'a HashMap, -) -> anyhow::Result> { +) -> anyhow::Result> { let mut interpreter = Interpreter::new(code, initial_offset, initial_stack, prover_inputs); interpreter.run()?; Ok(interpreter) } +/// Simulates the CPU execution from `state` until the program counter reaches `final_label` +/// in the current context. +pub(crate) fn simulate_cpu_and_get_user_jumps( + final_label: &str, + state: &GenerationState, +) -> Option>> { + match state.jumpdest_table { + Some(_) => None, + None => { + let halt_pc = KERNEL.global_labels[final_label]; + let initial_context = state.registers.context; + let mut interpreter = + Interpreter::new_with_state_and_halt_condition(state, halt_pc, initial_context); + + log::debug!("Simulating CPU for jumpdest analysis."); + + interpreter.run(); + + log::debug!("jdt = {:?}", interpreter.jumpdest_table); + + interpreter + .generation_state + .set_jumpdest_analysis_inputs(interpreter.jumpdest_table); + + log::debug!("Simulated CPU for jumpdest analysis halted."); + interpreter.generation_state.jumpdest_table + } + } +} + /// Different types of Memory operations in the interpreter, and the data required to revert them. enum InterpreterMemOpKind { /// We need to provide the context. @@ -140,7 +174,7 @@ enum InterpreterMemOpKind { Write(U256, usize, usize, usize), } -impl<'a> Interpreter<'a> { +impl<'a, F: Field> Interpreter<'a, F> { pub(crate) fn new_with_kernel(initial_offset: usize, initial_stack: Vec) -> Self { let mut result = Self::new( &KERNEL.code, @@ -177,10 +211,12 @@ impl<'a> Interpreter<'a> { // `DEFAULT_HALT_OFFSET` is used as a halting point for the interpreter, // while the label `halt` is the halting label in the kernel. halt_offsets: vec![DEFAULT_HALT_OFFSET, KERNEL.global_labels["halt"]], + halt_context: None, debug_offsets: vec![], running: false, opcode_count: [0; 256], memops: vec![], + jumpdest_table: HashMap::new(), }; result.generation_state.registers.program_counter = initial_offset; let initial_stack_len = initial_stack.len(); @@ -194,6 +230,24 @@ impl<'a> Interpreter<'a> { result } + pub(crate) fn new_with_state_and_halt_condition( + state: &GenerationState, + halt_offset: usize, + halt_context: usize, + ) -> Self { + Self { + generation_state: state.soft_clone(), + prover_inputs_map: &KERNEL.prover_inputs, + halt_offsets: vec![halt_offset], + halt_context: Some(halt_context), + debug_offsets: vec![], + running: false, + opcode_count: [0; 256], + memops: vec![], + jumpdest_table: HashMap::new(), + } + } + /// Initializes the interpreter state given `GenerationInputs`, using the KERNEL code. pub(crate) fn initialize_interpreter_state_with_kernel(&mut self, inputs: GenerationInputs) { self.initialize_interpreter_state(inputs, KERNEL.code_hash, KERNEL.code.len()); @@ -399,9 +453,18 @@ impl<'a> Interpreter<'a> { self.running = true; while self.running { let pc = self.generation_state.registers.program_counter; - if self.is_kernel() && self.halt_offsets.contains(&pc) { + + if let Some(halt_context) = self.halt_context { + if self.is_kernel() + && self.halt_offsets.contains(&pc) + && halt_context == self.generation_state.registers.context + { + self.running = false; + return Ok(()); + } + } else if self.halt_offsets.contains(&pc) { return Ok(()); - }; + } let checkpoint = self.checkpoint(); let result = self.run_opcode(); @@ -426,13 +489,16 @@ impl<'a> Interpreter<'a> { } }?; } - println!("Opcode count:"); - for i in 0..0x100 { - if self.opcode_count[i] > 0 { - println!("{}: {}", get_mnemonic(i as u8), self.opcode_count[i]) + #[cfg(debug_assertions)] + { + println!("Opcode count:"); + for i in 0..0x100 { + if self.opcode_count[i] > 0 { + println!("{}: {}", get_mnemonic(i as u8), self.opcode_count[i]) + } } + println!("Total: {}", self.opcode_count.into_iter().sum::()); } - println!("Total: {}", self.opcode_count.into_iter().sum::()); Ok(()) } @@ -587,14 +653,6 @@ impl<'a> Interpreter<'a> { } } - pub(crate) fn get_jumpdest_bits(&self, context: usize) -> Vec { - self.generation_state.memory.contexts[context].segments[Segment::JumpdestBits.unscale()] - .content - .iter() - .map(|x| x.bit(0)) - .collect() - } - pub(crate) fn set_jumpdest_analysis_inputs(&mut self, jumps: HashMap>) { self.generation_state.set_jumpdest_analysis_inputs(jumps); } @@ -685,12 +743,42 @@ impl<'a> Interpreter<'a> { } fn run_opcode(&mut self) -> Result<(), ProgramError> { + // Jumpdest analysis is performed natively by the interpreter and not + // using the non-deterministic Kernel assembly code. + if self.is_kernel() + && self.generation_state.registers.program_counter + == KERNEL.global_labels["jumpdest_analysis"] + { + self.generation_state.registers.program_counter = + KERNEL.global_labels["jumpdest_analysis_end"]; + self.generation_state + .set_jumpdest_bits(&self.generation_state.get_current_code()?); + } + let opcode = self .code() .get(self.generation_state.registers.program_counter) .byte(0); self.opcode_count[opcode as usize] += 1; self.incr(1); + + let op = decode(self.generation_state.registers, opcode)?; + self.generation_state.registers.gas_used += gas_to_charge(op); + + #[cfg(debug_assertions)] + if !self.is_kernel() { + println!( + "User instruction {:?}, stack = {:?}, ctx = {}", + op, + { + let mut stack = self.stack(); + stack.reverse(); + stack + }, + self.generation_state.registers.context + ); + } + match opcode { 0x00 => self.run_syscall(opcode, 0, false), // "STOP", 0x01 => self.run_add(), // "ADD", @@ -811,20 +899,16 @@ impl<'a> Interpreter<'a> { } }?; + #[cfg(debug_assertions)] if self .debug_offsets .contains(&self.generation_state.registers.program_counter) { - println!("At {}, stack={:?}", self.offset_name(), self.stack()); + println!("At {},", self.offset_name()); } else if let Some(label) = self.offset_label() { println!("At {label}"); } - let op = decode(self.generation_state.registers, opcode) - // We default to prover inputs, as those are kernel-only instructions that charge nothing. - .unwrap_or(Operation::ProverInput); - self.generation_state.registers.gas_used += gas_to_charge(op); - if !self.is_kernel() { let gas_limit_address = MemoryAddress { context: self.context(), @@ -1027,6 +1111,7 @@ impl<'a> Interpreter<'a> { .byte(0) }) .collect::>(); + #[cfg(debug_assertions)] println!("Hashing {:?}", &bytes); let hash = keccak(bytes); self.push(U256::from_big_endian(hash.as_bytes())) @@ -1087,51 +1172,75 @@ impl<'a> Interpreter<'a> { self.push(syscall_info) } - fn set_jumpdest_bit(&mut self, x: U256) -> U256 { + fn get_jumpdest_bit(&self, offset: usize) -> U256 { if self.generation_state.memory.contexts[self.context()].segments [Segment::JumpdestBits.unscale()] .content .len() - > x.low_u32() as usize + > offset { self.generation_state.memory.get(MemoryAddress { context: self.context(), segment: Segment::JumpdestBits.unscale(), - virt: x.low_u32() as usize, + virt: offset, }) } else { 0.into() } } - fn run_jump(&mut self) -> anyhow::Result<(), ProgramError> { - let x = self.pop()?; - let jumpdest_bit = self.set_jumpdest_bit(x); + pub(crate) fn get_jumpdest_bits(&self, context: usize) -> Vec { + self.generation_state.memory.contexts[context].segments[Segment::JumpdestBits.unscale()] + .content + .iter() + .map(|x| x.bit(0)) + .collect() + } + + fn add_jumpdest_offset(&mut self, offset: usize) { + if let Some(jumpdest_table) = self + .jumpdest_table + .get_mut(&self.generation_state.registers.context) + { + jumpdest_table.insert(offset); + } else { + self.jumpdest_table.insert( + self.generation_state.registers.context, + BTreeSet::from([offset]), + ); + } + } + + fn run_jump(&mut self) -> anyhow::Result<(), ProgramError> { + let offset = self.pop()?; // Check that the destination is valid. - let x: u32 = x - .try_into() - .map_err(|_| ProgramError::InvalidJumpDestination)?; + let offset: usize = u256_to_usize(offset)?; + + let jumpdest_bit = self.get_jumpdest_bit(offset); if !self.is_kernel() && jumpdest_bit != U256::one() { return Err(ProgramError::InvalidJumpDestination); } - self.jump_to(x as usize, false) + self.jump_to(offset, false) } fn run_jumpi(&mut self) -> anyhow::Result<(), ProgramError> { - let x = self.pop()?; - let b = self.pop()?; - if !b.is_zero() { - let x: u32 = x - .try_into() - .map_err(|_| ProgramError::InvalidJumpiDestination)?; - self.jump_to(x as usize, true)?; - } - let jumpdest_bit = self.set_jumpdest_bit(x); + let offset = self.pop()?; + let cond = self.pop()?; - if !b.is_zero() && !self.is_kernel() && jumpdest_bit != U256::one() { + let offset: usize = offset + .try_into() + .map_err(|_| ProgramError::InvalidJumpiDestination)?; + + let jumpdest_bit = self.get_jumpdest_bit(offset); + + if !cond.is_zero() && (self.is_kernel() || jumpdest_bit == U256::one()) { + self.jump_to(offset, true)?; + } + + if !cond.is_zero() && !self.is_kernel() && jumpdest_bit != U256::one() { return Err(ProgramError::InvalidJumpiDestination); } Ok(()) @@ -1167,9 +1276,10 @@ impl<'a> Interpreter<'a> { self.generation_state.observe_contract(tip_h256)?; } - if self.halt_offsets.contains(&offset) { - self.running = false; + if !self.is_kernel() { + self.add_jumpdest_offset(offset); } + Ok(()) } @@ -1237,6 +1347,7 @@ impl<'a> Interpreter<'a> { } self.set_context(new_ctx); self.generation_state.registers.stack_len = new_sp; + Ok(()) } @@ -1603,8 +1714,16 @@ pub(crate) use unpack_address; #[cfg(test)] mod tests { - use super::*; + use std::collections::HashMap; + + use ethereum_types::U256; + use plonky2::field::goldilocks_field::GoldilocksField as F; + + use crate::cpu::kernel::constants::context_metadata::ContextMetadata; + use crate::cpu::kernel::interpreter::{run, Interpreter}; use crate::memory::segments::Segment; + use crate::witness::memory::MemoryAddress; + use crate::witness::operation::CONTEXT_SCALING_FACTOR; #[test] fn test_run() -> anyhow::Result<()> { @@ -1612,7 +1731,7 @@ mod tests { 0x60, 0x1, 0x60, 0x2, 0x1, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56, ]; // PUSH1, 1, PUSH1, 2, ADD, PUSH4 deadbeef, JUMP assert_eq!( - run(&code, 0, vec![], &HashMap::new())?.stack(), + run::(&code, 0, vec![], &HashMap::new())?.stack(), &[0x3.into()], ); Ok(()) @@ -1637,7 +1756,7 @@ mod tests { 0x60, 0xff, 0x60, 0x0, 0x52, 0x60, 0, 0x51, 0x60, 0x1, 0x51, 0x60, 0x42, 0x60, 0x27, 0x53, ]; - let mut interpreter = Interpreter::new_with_kernel(0, vec![]); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, vec![]); interpreter.set_code(1, code.to_vec()); diff --git a/evm/src/cpu/kernel/mod.rs b/evm/src/cpu/kernel/mod.rs index e8247491..5a6717f2 100644 --- a/evm/src/cpu/kernel/mod.rs +++ b/evm/src/cpu/kernel/mod.rs @@ -10,8 +10,7 @@ mod parser; pub mod stack; mod utils; -#[cfg(test)] -mod interpreter; +pub(crate) mod interpreter; #[cfg(test)] mod tests; diff --git a/evm/src/cpu/kernel/tests/account_code.rs b/evm/src/cpu/kernel/tests/account_code.rs index 5e2dddca..b3a075cf 100644 --- a/evm/src/cpu/kernel/tests/account_code.rs +++ b/evm/src/cpu/kernel/tests/account_code.rs @@ -6,6 +6,8 @@ use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{Address, BigEndianHash, H256, U256}; use hex_literal::hex; use keccak_hash::keccak; +use plonky2::field::goldilocks_field::GoldilocksField as F; +use plonky2::field::types::Field; use rand::{thread_rng, Rng}; use crate::cpu::kernel::aggregator::KERNEL; @@ -20,7 +22,10 @@ use crate::witness::memory::MemoryAddress; use crate::witness::operation::CONTEXT_SCALING_FACTOR; use crate::Node; -pub(crate) fn initialize_mpts(interpreter: &mut Interpreter, trie_inputs: &TrieInputs) { +pub(crate) fn initialize_mpts( + interpreter: &mut Interpreter, + trie_inputs: &TrieInputs, +) { // Load all MPTs. let (trie_root_ptrs, trie_data) = load_all_mpts(trie_inputs).expect("Invalid MPT data for preinitialization"); @@ -70,8 +75,8 @@ fn random_code() -> Vec { // Stolen from `tests/mpt/insert.rs` // Prepare the interpreter by inserting the account in the state trie. -fn prepare_interpreter( - interpreter: &mut Interpreter, +fn prepare_interpreter( + interpreter: &mut Interpreter, address: Address, account: &AccountRlp, ) -> Result<()> { @@ -151,7 +156,7 @@ fn test_extcodesize() -> Result<()> { let code = random_code(); let account = test_account(&code); - let mut interpreter = Interpreter::new_with_kernel(0, vec![]); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, vec![]); let address: Address = thread_rng().gen(); // Prepare the interpreter by inserting the account in the state trie. prepare_interpreter(&mut interpreter, address, &account)?; @@ -183,7 +188,7 @@ fn test_extcodecopy() -> Result<()> { let code = random_code(); let account = test_account(&code); - let mut interpreter = Interpreter::new_with_kernel(0, vec![]); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, vec![]); let address: Address = thread_rng().gen(); // Prepare the interpreter by inserting the account in the state trie. prepare_interpreter(&mut interpreter, address, &account)?; @@ -252,8 +257,8 @@ fn test_extcodecopy() -> Result<()> { /// Prepare the interpreter for storage tests by inserting all necessary accounts /// in the state trie, adding the code we want to context 1 and switching the context. -fn prepare_interpreter_all_accounts( - interpreter: &mut Interpreter, +fn prepare_interpreter_all_accounts( + interpreter: &mut Interpreter, trie_inputs: TrieInputs, addr: [u8; 20], code: &[u8], @@ -318,7 +323,7 @@ fn sstore() -> Result<()> { }; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); // Prepare the interpreter by inserting the account in the state trie. prepare_interpreter_all_accounts(&mut interpreter, trie_inputs, addr, &code)?; @@ -407,7 +412,7 @@ fn sload() -> Result<()> { }; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); // Prepare the interpreter by inserting the account in the state trie. prepare_interpreter_all_accounts(&mut interpreter, trie_inputs, addr, &code)?; diff --git a/evm/src/cpu/kernel/tests/add11.rs b/evm/src/cpu/kernel/tests/add11.rs index c5eb2939..de5450c5 100644 --- a/evm/src/cpu/kernel/tests/add11.rs +++ b/evm/src/cpu/kernel/tests/add11.rs @@ -6,6 +6,7 @@ use eth_trie_utils::partial_trie::{HashedPartialTrie, Node, PartialTrie}; use ethereum_types::{Address, BigEndianHash, H256}; use hex_literal::hex; use keccak_hash::keccak; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::context_metadata::ContextMetadata; @@ -155,7 +156,7 @@ fn test_add11_yml() { }; let initial_stack = vec![]; - let mut interpreter = + let mut interpreter: Interpreter = Interpreter::new_with_generation_inputs_and_kernel(0, initial_stack, tries_inputs); let route_txn_label = KERNEL.global_labels["main"]; @@ -297,7 +298,7 @@ fn test_add11_yml_with_exception() { }; let initial_stack = vec![]; - let mut interpreter = + let mut interpreter: Interpreter = Interpreter::new_with_generation_inputs_and_kernel(0, initial_stack, tries_inputs); let route_txn_label = KERNEL.global_labels["main"]; diff --git a/evm/src/cpu/kernel/tests/balance.rs b/evm/src/cpu/kernel/tests/balance.rs index b393c05c..af190ae4 100644 --- a/evm/src/cpu/kernel/tests/balance.rs +++ b/evm/src/cpu/kernel/tests/balance.rs @@ -2,6 +2,8 @@ use anyhow::Result; use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{Address, BigEndianHash, H256, U256}; use keccak_hash::keccak; +use plonky2::field::goldilocks_field::GoldilocksField as F; +use plonky2::field::types::Field; use rand::{thread_rng, Rng}; use crate::cpu::kernel::aggregator::KERNEL; @@ -24,8 +26,8 @@ fn test_account(balance: U256) -> AccountRlp { // Stolen from `tests/mpt/insert.rs` // Prepare the interpreter by inserting the account in the state trie. -fn prepare_interpreter( - interpreter: &mut Interpreter, +fn prepare_interpreter( + interpreter: &mut Interpreter, address: Address, account: &AccountRlp, ) -> Result<()> { @@ -107,7 +109,7 @@ fn test_balance() -> Result<()> { let balance = U256(rng.gen()); let account = test_account(balance); - let mut interpreter = Interpreter::new_with_kernel(0, vec![]); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, vec![]); let address: Address = rng.gen(); // Prepare the interpreter by inserting the account in the state trie. prepare_interpreter(&mut interpreter, address, &account)?; diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index 0cc6f0dc..cc0e47af 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -8,6 +8,7 @@ use ethereum_types::U256; use itertools::Itertools; use num::{BigUint, One, Zero}; use num_bigint::RandBigInt; +use plonky2::field::goldilocks_field::GoldilocksField as F; use plonky2_util::ceil_div_usize; use rand::Rng; @@ -99,7 +100,7 @@ fn run_test(fn_label: &str, memory: Vec, stack: Vec) -> Result<(Vec< initial_stack.push(retdest); initial_stack.reverse(); - let mut interpreter = Interpreter::new_with_kernel(fn_label, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(fn_label, initial_stack); interpreter.set_current_general_memory(memory); interpreter.run()?; diff --git a/evm/src/cpu/kernel/tests/blake2_f.rs b/evm/src/cpu/kernel/tests/blake2_f.rs index c5d800c5..7d9349c7 100644 --- a/evm/src/cpu/kernel/tests/blake2_f.rs +++ b/evm/src/cpu/kernel/tests/blake2_f.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::interpreter::{ run_interpreter_with_memory, InterpreterMemoryInitialization, @@ -71,7 +72,7 @@ fn run_blake2_f( memory: vec![], }; - let result = run_interpreter_with_memory(interpreter_setup).unwrap(); + let result = run_interpreter_with_memory::(interpreter_setup).unwrap(); let mut hash = result.stack().to_vec(); hash.reverse(); diff --git a/evm/src/cpu/kernel/tests/block_hash.rs b/evm/src/cpu/kernel/tests/block_hash.rs index 23ba2337..9c77951d 100644 --- a/evm/src/cpu/kernel/tests/block_hash.rs +++ b/evm/src/cpu/kernel/tests/block_hash.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::{H256, U256}; +use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::{thread_rng, Rng}; use crate::cpu::kernel::aggregator::KERNEL; @@ -19,7 +20,8 @@ fn test_correct_block_hash() -> Result<()> { let hashes: Vec = vec![U256::from_big_endian(&thread_rng().gen::().0); 257]; - let mut interpreter = Interpreter::new_with_kernel(blockhash_label, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(blockhash_label, initial_stack); interpreter.set_memory_segment(Segment::BlockHashes, hashes[0..256].to_vec()); interpreter.set_global_metadata_field(GlobalMetadata::BlockCurrentHash, hashes[256]); interpreter.set_global_metadata_field(GlobalMetadata::BlockNumber, 256.into()); @@ -48,7 +50,8 @@ fn test_big_index_block_hash() -> Result<()> { let hashes: Vec = vec![U256::from_big_endian(&thread_rng().gen::().0); 257]; - let mut interpreter = Interpreter::new_with_kernel(blockhash_label, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(blockhash_label, initial_stack); interpreter.set_memory_segment(Segment::BlockHashes, hashes[0..256].to_vec()); interpreter.set_global_metadata_field(GlobalMetadata::BlockCurrentHash, hashes[256]); interpreter.set_global_metadata_field(GlobalMetadata::BlockNumber, cur_block_number.into()); @@ -78,7 +81,8 @@ fn test_small_index_block_hash() -> Result<()> { let hashes: Vec = vec![U256::from_big_endian(&thread_rng().gen::().0); 257]; - let mut interpreter = Interpreter::new_with_kernel(blockhash_label, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(blockhash_label, initial_stack); interpreter.set_memory_segment(Segment::BlockHashes, hashes[0..256].to_vec()); interpreter.set_global_metadata_field(GlobalMetadata::BlockCurrentHash, hashes[256]); interpreter.set_global_metadata_field(GlobalMetadata::BlockNumber, cur_block_number.into()); @@ -106,7 +110,8 @@ fn test_block_hash_with_overflow() -> Result<()> { let hashes: Vec = vec![U256::from_big_endian(&thread_rng().gen::().0); 257]; - let mut interpreter = Interpreter::new_with_kernel(blockhash_label, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(blockhash_label, initial_stack); interpreter.set_memory_segment(Segment::BlockHashes, hashes[0..256].to_vec()); interpreter.set_global_metadata_field(GlobalMetadata::BlockCurrentHash, hashes[256]); interpreter.set_global_metadata_field(GlobalMetadata::BlockNumber, cur_block_number.into()); diff --git a/evm/src/cpu/kernel/tests/bls381.rs b/evm/src/cpu/kernel/tests/bls381.rs index aeba6fbd..1ffa7115 100644 --- a/evm/src/cpu/kernel/tests/bls381.rs +++ b/evm/src/cpu/kernel/tests/bls381.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::Rng; use crate::cpu::kernel::interpreter::{ @@ -23,7 +24,7 @@ fn test_bls_fp2_mul() -> Result<()> { segment: KernelGeneral, memory: vec![], }; - let interpreter = run_interpreter_with_memory(setup).unwrap(); + let interpreter = run_interpreter_with_memory::(setup).unwrap(); let stack: Vec = interpreter.stack().iter().rev().cloned().collect(); let output = Fp2::::from_stack(&stack); diff --git a/evm/src/cpu/kernel/tests/bn254.rs b/evm/src/cpu/kernel/tests/bn254.rs index 8a90ff24..efe2ed9f 100644 --- a/evm/src/cpu/kernel/tests/bn254.rs +++ b/evm/src/cpu/kernel/tests/bn254.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::Rng; use crate::cpu::kernel::interpreter::{ @@ -23,7 +24,7 @@ fn run_bn_mul_fp6(f: Fp6, g: Fp6, label: &str) -> Fp6 { segment: BnPairing, memory: vec![], }; - let interpreter = run_interpreter_with_memory(setup).unwrap(); + let interpreter = run_interpreter_with_memory::(setup).unwrap(); let output: Vec = interpreter.stack().iter().rev().cloned().collect(); Fp6::::from_stack(&output) } @@ -63,7 +64,7 @@ fn run_bn_mul_fp12(f: Fp12, g: Fp12, label: &str) -> Fp12 { segment: BnPairing, memory: vec![(in0, f.to_stack().to_vec()), (in1, g.to_stack().to_vec())], }; - let interpreter = run_interpreter_with_memory(setup).unwrap(); + let interpreter = run_interpreter_with_memory::(setup).unwrap(); let output = interpreter.extract_kernel_memory(BnPairing, out..out + 12); Fp12::::from_stack(&output) } @@ -93,7 +94,7 @@ fn run_bn_frob_fp6(n: usize, f: Fp6) -> Fp6 { segment: BnPairing, memory: vec![], }; - let interpreter: Interpreter = run_interpreter_with_memory(setup).unwrap(); + let interpreter: Interpreter = run_interpreter_with_memory(setup).unwrap(); let output: Vec = interpreter.stack().iter().rev().cloned().collect(); Fp6::::from_stack(&output) } @@ -117,7 +118,7 @@ fn run_bn_frob_fp12(f: Fp12, n: usize) -> Fp12 { segment: BnPairing, memory: vec![(ptr, f.to_stack().to_vec())], }; - let interpreter: Interpreter = run_interpreter_with_memory(setup).unwrap(); + let interpreter: Interpreter = run_interpreter_with_memory(setup).unwrap(); let output: Vec = interpreter.extract_kernel_memory(BnPairing, ptr..ptr + 12); Fp12::::from_stack(&output) } @@ -147,7 +148,7 @@ fn test_bn_inv_fp12() -> Result<()> { segment: BnPairing, memory: vec![(ptr, f.to_stack().to_vec())], }; - let interpreter: Interpreter = run_interpreter_with_memory(setup).unwrap(); + let interpreter: Interpreter = run_interpreter_with_memory(setup).unwrap(); let output: Vec = interpreter.extract_kernel_memory(BnPairing, inv..inv + 12); let output = Fp12::::from_stack(&output); @@ -175,7 +176,7 @@ fn test_bn_final_exponent() -> Result<()> { memory: vec![(ptr, f.to_stack().to_vec())], }; - let interpreter: Interpreter = run_interpreter_with_memory(setup).unwrap(); + let interpreter: Interpreter = run_interpreter_with_memory(setup).unwrap(); let output: Vec = interpreter.extract_kernel_memory(BnPairing, ptr..ptr + 12); let expected: Vec = bn_final_exponent(f).to_stack(); @@ -202,7 +203,7 @@ fn test_bn_miller() -> Result<()> { segment: BnPairing, memory: vec![(ptr, input)], }; - let interpreter = run_interpreter_with_memory(setup).unwrap(); + let interpreter = run_interpreter_with_memory::(setup).unwrap(); let output: Vec = interpreter.extract_kernel_memory(BnPairing, out..out + 12); let expected = bn_miller_loop(p, q).to_stack(); @@ -246,7 +247,7 @@ fn test_bn_pairing() -> Result<()> { segment: BnPairing, memory: vec![(ptr, input)], }; - let interpreter = run_interpreter_with_memory(setup).unwrap(); + let interpreter = run_interpreter_with_memory::(setup).unwrap(); assert_eq!(interpreter.stack()[0], U256::one()); Ok(()) } diff --git a/evm/src/cpu/kernel/tests/core/access_lists.rs b/evm/src/cpu/kernel/tests/core/access_lists.rs index 69dd2d27..4ee38e92 100644 --- a/evm/src/cpu/kernel/tests/core/access_lists.rs +++ b/evm/src/cpu/kernel/tests/core/access_lists.rs @@ -2,6 +2,7 @@ use std::collections::HashSet; use anyhow::Result; use ethereum_types::{Address, U256}; +use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::{thread_rng, Rng}; use crate::cpu::kernel::aggregator::KERNEL; @@ -33,7 +34,8 @@ fn test_insert_accessed_addresses() -> Result<()> { // Test for address already in list. let initial_stack = vec![retaddr, U256::from(addr_in_list.0.as_slice())]; - let mut interpreter = Interpreter::new_with_kernel(insert_accessed_addresses, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(insert_accessed_addresses, initial_stack); for i in 0..n { let addr = U256::from(addresses[i].0.as_slice()); interpreter @@ -57,7 +59,8 @@ fn test_insert_accessed_addresses() -> Result<()> { // Test for address not in list. let initial_stack = vec![retaddr, U256::from(addr_not_in_list.0.as_slice())]; - let mut interpreter = Interpreter::new_with_kernel(insert_accessed_addresses, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(insert_accessed_addresses, initial_stack); for i in 0..n { let addr = U256::from(addresses[i].0.as_slice()); interpreter @@ -115,7 +118,8 @@ fn test_insert_accessed_storage_keys() -> Result<()> { storage_key_in_list.1, U256::from(storage_key_in_list.0 .0.as_slice()), ]; - let mut interpreter = Interpreter::new_with_kernel(insert_accessed_storage_keys, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(insert_accessed_storage_keys, initial_stack); for i in 0..n { let addr = U256::from(storage_keys[i].0 .0.as_slice()); interpreter @@ -152,7 +156,8 @@ fn test_insert_accessed_storage_keys() -> Result<()> { storage_key_not_in_list.1, U256::from(storage_key_not_in_list.0 .0.as_slice()), ]; - let mut interpreter = Interpreter::new_with_kernel(insert_accessed_storage_keys, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(insert_accessed_storage_keys, initial_stack); for i in 0..n { let addr = U256::from(storage_keys[i].0 .0.as_slice()); interpreter diff --git a/evm/src/cpu/kernel/tests/core/create_addresses.rs b/evm/src/cpu/kernel/tests/core/create_addresses.rs index 3f316578..339e2182 100644 --- a/evm/src/cpu/kernel/tests/core/create_addresses.rs +++ b/evm/src/cpu/kernel/tests/core/create_addresses.rs @@ -4,6 +4,7 @@ use anyhow::Result; use ethereum_types::{H256, U256}; use hex_literal::hex; use keccak_hash::keccak; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -19,7 +20,8 @@ fn test_get_create_address() -> Result<()> { let expected_addr = U256::from_big_endian(&hex!("3f09c73a5ed19289fb9bdc72f1742566df146f56")); let initial_stack = vec![retaddr, nonce, sender]; - let mut interpreter = Interpreter::new_with_kernel(get_create_address, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(get_create_address, initial_stack); interpreter.run()?; assert_eq!(interpreter.stack(), &[expected_addr]); @@ -105,7 +107,8 @@ fn test_get_create2_address() -> Result<()> { } in create2_test_cases() { let initial_stack = vec![retaddr, salt, U256::from(code_hash.0), sender]; - let mut interpreter = Interpreter::new_with_kernel(get_create2_address, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(get_create2_address, initial_stack); interpreter.run()?; assert_eq!(interpreter.stack(), &[expected_addr]); diff --git a/evm/src/cpu/kernel/tests/core/intrinsic_gas.rs b/evm/src/cpu/kernel/tests/core/intrinsic_gas.rs index d8badef9..ee9db0df 100644 --- a/evm/src/cpu/kernel/tests/core/intrinsic_gas.rs +++ b/evm/src/cpu/kernel/tests/core/intrinsic_gas.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; @@ -15,13 +16,15 @@ fn test_intrinsic_gas() -> Result<()> { // Contract creation transaction. let initial_stack = vec![0xdeadbeefu32.into()]; - let mut interpreter = Interpreter::new_with_kernel(intrinsic_gas, initial_stack.clone()); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(intrinsic_gas, initial_stack.clone()); interpreter.set_global_metadata_field(GlobalMetadata::ContractCreation, U256::one()); interpreter.run()?; assert_eq!(interpreter.stack(), vec![(GAS_TX + GAS_TXCREATE).into()]); // Message transaction. - let mut interpreter = Interpreter::new_with_kernel(intrinsic_gas, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(intrinsic_gas, initial_stack); interpreter.set_txn_field(NormalizedTxnField::To, 123.into()); interpreter.run()?; assert_eq!(interpreter.stack(), vec![GAS_TX.into()]); diff --git a/evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs b/evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs index d704cc19..7923997d 100644 --- a/evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs +++ b/evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs @@ -2,6 +2,8 @@ use std::collections::{BTreeSet, HashMap}; use anyhow::Result; use ethereum_types::U256; +use itertools::Itertools; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -10,7 +12,10 @@ use crate::witness::operation::CONTEXT_SCALING_FACTOR; #[test] fn test_jumpdest_analysis() -> Result<()> { - let jumpdest_analysis = KERNEL.global_labels["jumpdest_analysis"]; + // By default the interpreter will skip jumpdest analysis asm and compute + // the jumpdest table bits natively. We avoid that starting 1 line after + // performing the missing first PROVER_INPUT "by hand" + let jumpdest_analysis = KERNEL.global_labels["jumpdest_analysis"] + 1; const CONTEXT: usize = 3; // arbitrary let add = get_opcode("ADD"); @@ -18,7 +23,7 @@ fn test_jumpdest_analysis() -> Result<()> { let jumpdest = get_opcode("JUMPDEST"); #[rustfmt::skip] - let code: Vec = vec![ + let mut code: Vec = vec![ add, jumpdest, push2, @@ -28,16 +33,24 @@ fn test_jumpdest_analysis() -> Result<()> { add, jumpdest, ]; + code.extend( + (0..32) + .rev() + .map(get_push_opcode) + .chain(std::iter::once(jumpdest)), + ); - let jumpdest_bits = vec![false, true, false, false, false, true, false, true]; + let mut jumpdest_bits = vec![false, true, false, false, false, true, false, true]; + // Add 32 falses and 1 true + jumpdest_bits.extend( + std::iter::repeat(false) + .take(32) + .chain(std::iter::once(true)), + ); + + let mut interpreter: Interpreter = Interpreter::new_with_kernel(jumpdest_analysis, vec![]); + let code_len = code.len(); - // Contract creation transaction. - let initial_stack = vec![ - 0xDEADBEEFu32.into(), - code.len().into(), - U256::from(CONTEXT) << CONTEXT_SCALING_FACTOR, - ]; - let mut interpreter = Interpreter::new_with_kernel(jumpdest_analysis, initial_stack); interpreter.set_code(CONTEXT, code); interpreter.set_jumpdest_analysis_inputs(HashMap::from([( 3, @@ -50,31 +63,47 @@ fn test_jumpdest_analysis() -> Result<()> { ), )])); + // The `set_jumpdest_analysis_inputs` method is never used. assert_eq!( interpreter.generation_state.jumpdest_table, // Context 3 has jumpdest 1, 5, 7. All have proof 0 and hence - // the list [proof_0, jumpdest_0, ... ] is [0, 1, 0, 5, 0, 7] - Some(HashMap::from([(3, vec![0, 1, 0, 5, 0, 7])])) + // the list [proof_0, jumpdest_0, ... ] is [0, 1, 0, 5, 0, 7, 8, 40] + Some(HashMap::from([(3, vec![0, 1, 0, 5, 0, 7, 8, 40])])) ); + // Run jumpdest analysis with context = 3 + interpreter.generation_state.registers.context = CONTEXT; + interpreter.push(0xDEADBEEFu32.into()); + interpreter.push(code_len.into()); + interpreter.push(U256::from(CONTEXT) << CONTEXT_SCALING_FACTOR); + + // We need to manually pop the jumpdest_table and push its value on the top of the stack + interpreter + .generation_state + .jumpdest_table + .as_mut() + .unwrap() + .get_mut(&CONTEXT) + .unwrap() + .pop(); + interpreter.push(U256::one()); + interpreter.run()?; assert_eq!(interpreter.stack(), vec![]); - assert_eq!(jumpdest_bits, interpreter.get_jumpdest_bits(3)); + assert_eq!(jumpdest_bits, interpreter.get_jumpdest_bits(CONTEXT)); Ok(()) } #[test] fn test_packed_verification() -> Result<()> { - let jumpdest_analysis = KERNEL.global_labels["jumpdest_analysis"]; + let write_table_if_jumpdest = KERNEL.global_labels["write_table_if_jumpdest"]; const CONTEXT: usize = 3; // arbitrary let add = get_opcode("ADD"); let jumpdest = get_opcode("JUMPDEST"); - // The last push(i=0) is 0x5f which is not a valid opcode. However, this - // is still meaningful for the test and makes things easier let mut code: Vec = std::iter::once(add) .chain( (0..=31) @@ -92,10 +121,12 @@ fn test_packed_verification() -> Result<()> { // Contract creation transaction. let initial_stack = vec![ 0xDEADBEEFu32.into(), - code.len().into(), U256::from(CONTEXT) << CONTEXT_SCALING_FACTOR, + 33.into(), + U256::one(), ]; - let mut interpreter = Interpreter::new_with_kernel(jumpdest_analysis, initial_stack.clone()); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(write_table_if_jumpdest, initial_stack.clone()); interpreter.set_code(CONTEXT, code.clone()); interpreter.generation_state.jumpdest_table = Some(HashMap::from([(3, vec![1, 33])])); @@ -106,8 +137,8 @@ fn test_packed_verification() -> Result<()> { // If we add 1 to each opcode the jumpdest at position 32 is never a valid jumpdest for i in 1..=32 { code[i] += 1; - let mut interpreter = - Interpreter::new_with_kernel(jumpdest_analysis, initial_stack.clone()); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(write_table_if_jumpdest, initial_stack.clone()); interpreter.set_code(CONTEXT, code.clone()); interpreter.generation_state.jumpdest_table = Some(HashMap::from([(3, vec![1, 33])])); diff --git a/evm/src/cpu/kernel/tests/ecc/curve_ops.rs b/evm/src/cpu/kernel/tests/ecc/curve_ops.rs index f107d8be..ed37401f 100644 --- a/evm/src/cpu/kernel/tests/ecc/curve_ops.rs +++ b/evm/src/cpu/kernel/tests/ecc/curve_ops.rs @@ -2,6 +2,7 @@ mod bn { use anyhow::Result; use ethereum_types::U256; + use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::{run_interpreter, Interpreter}; @@ -43,76 +44,110 @@ mod bn { // Standard addition #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point1.1, point1.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point2.1, point2.0])?); // Standard addition #2 let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, point0.1, point0.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point2.1, point2.0])?); // Standard doubling #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point0.1, point0.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #2 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0])?; - let stack = run_interpreter(ec_double, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_double, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #3 let initial_stack = u256ify(["0xdeadbeef", "0x2", point0.1, point0.0])?; - let stack = run_interpreter(ec_mul, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_mul, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point3.1, point3.0])?); // Addition with identity #1 let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, point1.1, point1.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point1.1, point1.0])?); // Addition with identity #2 let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, identity.1, identity.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point1.1, point1.0])?); // Addition with identity #3 let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, identity.1, identity.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([identity.1, identity.0])?); // Addition with invalid point(s) #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, invalid.1, invalid.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Addition with invalid point(s) #2 let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, point0.1, point0.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Addition with invalid point(s) #3 let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, identity.1, identity.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Addition with invalid point(s) #4 let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, invalid.1, invalid.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Scalar multiplication #1 let initial_stack = u256ify(["0xdeadbeef", s, point0.1, point0.0])?; - let stack = run_interpreter(ec_mul, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_mul, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point4.1, point4.0])?); // Scalar multiplication #2 let initial_stack = u256ify(["0xdeadbeef", "0x0", point0.1, point0.0])?; - let stack = run_interpreter(ec_mul, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_mul, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #3 let initial_stack = u256ify(["0xdeadbeef", "0x1", point0.1, point0.0])?; - let stack = run_interpreter(ec_mul, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_mul, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point0.1, point0.0])?); // Scalar multiplication #4 let initial_stack = u256ify(["0xdeadbeef", s, identity.1, identity.0])?; - let stack = run_interpreter(ec_mul, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_mul, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #5 let initial_stack = u256ify(["0xdeadbeef", s, invalid.1, invalid.0])?; - let stack = run_interpreter(ec_mul, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_mul, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Multiple calls @@ -126,7 +161,9 @@ mod bn { point0.1, point0.0, ])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) @@ -147,7 +184,8 @@ mod bn { let mut initial_stack = u256ify(["0xdeadbeef"])?; initial_stack.push(k); - let mut int = Interpreter::new(&KERNEL.code, glv, initial_stack, &KERNEL.prover_inputs); + let mut int: Interpreter = + Interpreter::new(&KERNEL.code, glv, initial_stack, &KERNEL.prover_inputs); int.run()?; assert_eq!(line, int.stack()); @@ -165,7 +203,7 @@ mod bn { "0x10d7cf0621b6e42c1dbb421f5ef5e1936ca6a87b38198d1935be31e28821d171", "0x11b7d55f16aaac07de9a0ed8ac2e8023570dbaa78571fc95e553c4b3ba627689", ])?; - let mut int = Interpreter::new( + let mut int: Interpreter = Interpreter::new( &KERNEL.code, precompute, initial_stack, @@ -227,6 +265,7 @@ mod bn { mod secp { use anyhow::Result; use ethereum_types::U256; + use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::{combined_kernel, KERNEL}; use crate::cpu::kernel::interpreter::{run, run_interpreter, Interpreter}; @@ -260,36 +299,48 @@ mod secp { // Standard addition #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point1.1, point1.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point2.1, point2.0])?); // Standard addition #2 let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)? + let stack = run::(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)? .stack() .to_vec(); assert_eq!(stack, u256ify([point2.1, point2.0])?); // Standard doubling #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point0.1, point0.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #2 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0])?; - let stack = run_interpreter(ec_double, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_double, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point3.1, point3.0])?); // Addition with identity #1 let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, point1.1, point1.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point1.1, point1.0])?); // Addition with identity #2 let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, identity.1, identity.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([point1.1, point1.0])?); // Addition with identity #3 let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, identity.1, identity.0])?; - let stack = run_interpreter(ec_add, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ec_add, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, u256ify([identity.1, identity.0])?); Ok(()) @@ -310,7 +361,8 @@ mod secp { let mut initial_stack = u256ify(["0xdeadbeef"])?; initial_stack.push(k); - let mut int = Interpreter::new(&KERNEL.code, glv, initial_stack, &KERNEL.prover_inputs); + let mut int: Interpreter = + Interpreter::new(&KERNEL.code, glv, initial_stack, &KERNEL.prover_inputs); int.run()?; assert_eq!(line, int.stack()); diff --git a/evm/src/cpu/kernel/tests/ecc/ecrecover.rs b/evm/src/cpu/kernel/tests/ecc/ecrecover.rs index 2453ab1a..baf003d9 100644 --- a/evm/src/cpu/kernel/tests/ecc/ecrecover.rs +++ b/evm/src/cpu/kernel/tests/ecc/ecrecover.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use anyhow::Result; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::run_interpreter; @@ -10,7 +11,9 @@ use crate::cpu::kernel::tests::u256ify; fn test_valid_ecrecover(hash: &str, v: &str, r: &str, s: &str, expected: &str) -> Result<()> { let ecrecover = KERNEL.global_labels["ecrecover"]; let initial_stack = u256ify(["0xdeadbeef", s, r, v, hash])?; - let stack = run_interpreter(ecrecover, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ecrecover, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack[0], U256::from_str(expected).unwrap()); Ok(()) @@ -19,7 +22,9 @@ fn test_valid_ecrecover(hash: &str, v: &str, r: &str, s: &str, expected: &str) - fn test_invalid_ecrecover(hash: &str, v: &str, r: &str, s: &str) -> Result<()> { let ecrecover = KERNEL.global_labels["ecrecover"]; let initial_stack = u256ify(["0xdeadbeef", s, r, v, hash])?; - let stack = run_interpreter(ecrecover, initial_stack)?.stack().to_vec(); + let stack = run_interpreter::(ecrecover, initial_stack)? + .stack() + .to_vec(); assert_eq!(stack, vec![U256::MAX]); Ok(()) diff --git a/evm/src/cpu/kernel/tests/exp.rs b/evm/src/cpu/kernel/tests/exp.rs index 482c6b72..28d840f8 100644 --- a/evm/src/cpu/kernel/tests/exp.rs +++ b/evm/src/cpu/kernel/tests/exp.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::{thread_rng, Rng}; use crate::cpu::kernel::aggregator::KERNEL; @@ -15,16 +16,16 @@ fn test_exp() -> Result<()> { // Random input let initial_stack = vec![0xDEADBEEFu32.into(), b, a]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack.clone()); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack.clone()); - let stack_with_kernel = run_interpreter(exp, initial_stack)?.stack(); + let stack_with_kernel = run_interpreter::(exp, initial_stack)?.stack(); let expected_exp = a.overflowing_pow(b).0; assert_eq!(stack_with_kernel, vec![expected_exp]); // 0 base let initial_stack = vec![0xDEADBEEFu32.into(), b, U256::zero()]; - let stack_with_kernel = run_interpreter(exp, initial_stack)?.stack(); + let stack_with_kernel = run_interpreter::(exp, initial_stack)?.stack(); let expected_exp = U256::zero().overflowing_pow(b).0; assert_eq!(stack_with_kernel, vec![expected_exp]); @@ -33,7 +34,7 @@ fn test_exp() -> Result<()> { let initial_stack = vec![0xDEADBEEFu32.into(), U256::zero(), a]; interpreter.set_is_kernel(true); interpreter.set_context(0); - let stack_with_kernel = run_interpreter(exp, initial_stack)?.stack(); + let stack_with_kernel = run_interpreter::(exp, initial_stack)?.stack(); let expected_exp = 1.into(); assert_eq!(stack_with_kernel, vec![expected_exp]); diff --git a/evm/src/cpu/kernel/tests/hash.rs b/evm/src/cpu/kernel/tests/hash.rs index 6371f0a8..672aa5d1 100644 --- a/evm/src/cpu/kernel/tests/hash.rs +++ b/evm/src/cpu/kernel/tests/hash.rs @@ -1,12 +1,13 @@ use anyhow::Result; // use blake2::Blake2b512; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::{thread_rng, Rng}; use ripemd::{Digest, Ripemd160}; use sha2::Sha256; use crate::cpu::kernel::interpreter::{ - run_interpreter_with_memory, InterpreterMemoryInitialization, + run_interpreter_with_memory, Interpreter, InterpreterMemoryInitialization, }; use crate::memory::segments::Segment::KernelGeneral; @@ -66,7 +67,7 @@ fn prepare_test( let interpreter_setup = make_interpreter_setup(message, hash_fn_label, hash_input_virt); // Run the interpreter - let result = run_interpreter_with_memory(interpreter_setup).unwrap(); + let result: Interpreter = run_interpreter_with_memory(interpreter_setup).unwrap(); Ok((expected, result.stack().to_vec())) } diff --git a/evm/src/cpu/kernel/tests/log.rs b/evm/src/cpu/kernel/tests/log.rs index 406fba0c..9c80b426 100644 --- a/evm/src/cpu/kernel/tests/log.rs +++ b/evm/src/cpu/kernel/tests/log.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::{Address, U256}; +use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::{thread_rng, Rng}; use crate::cpu::kernel::aggregator::KERNEL; @@ -25,7 +26,7 @@ fn test_log_0() -> Result<()> { U256::from_big_endian(&address.to_fixed_bytes()), ]; - let mut interpreter = Interpreter::new_with_kernel(logs_entry, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(logs_entry, initial_stack); interpreter.set_global_metadata_field(GlobalMetadata::LogsLen, 0.into()); interpreter.set_global_metadata_field(GlobalMetadata::LogsDataLen, 0.into()); @@ -68,7 +69,7 @@ fn test_log_2() -> Result<()> { U256::from_big_endian(&address.to_fixed_bytes()), ]; - let mut interpreter = Interpreter::new_with_kernel(logs_entry, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(logs_entry, initial_stack); interpreter.set_global_metadata_field(GlobalMetadata::LogsLen, 2.into()); interpreter.set_global_metadata_field(GlobalMetadata::LogsDataLen, 5.into()); @@ -129,7 +130,7 @@ fn test_log_4() -> Result<()> { U256::from_big_endian(&address.to_fixed_bytes()), ]; - let mut interpreter = Interpreter::new_with_kernel(logs_entry, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(logs_entry, initial_stack); interpreter.set_global_metadata_field(GlobalMetadata::LogsLen, 2.into()); interpreter.set_global_metadata_field(GlobalMetadata::LogsDataLen, 5.into()); @@ -189,7 +190,7 @@ fn test_log_5() -> Result<()> { U256::from_big_endian(&address.to_fixed_bytes()), ]; - let mut interpreter = Interpreter::new_with_kernel(logs_entry, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(logs_entry, initial_stack); interpreter.set_global_metadata_field(GlobalMetadata::LogsLen, 0.into()); interpreter.set_global_metadata_field(GlobalMetadata::LogsDataLen, 0.into()); diff --git a/evm/src/cpu/kernel/tests/mpt/delete.rs b/evm/src/cpu/kernel/tests/mpt/delete.rs index 0d4d5e71..34bc0d66 100644 --- a/evm/src/cpu/kernel/tests/mpt/delete.rs +++ b/evm/src/cpu/kernel/tests/mpt/delete.rs @@ -2,6 +2,7 @@ use anyhow::Result; use eth_trie_utils::nibbles::Nibbles; use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{BigEndianHash, H256, U512}; +use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::random; use crate::cpu::kernel::aggregator::KERNEL; @@ -98,7 +99,7 @@ fn test_state_trie( let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"]; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); diff --git a/evm/src/cpu/kernel/tests/mpt/hash.rs b/evm/src/cpu/kernel/tests/mpt/hash.rs index a06dd2a0..e9a7ebde 100644 --- a/evm/src/cpu/kernel/tests/mpt/hash.rs +++ b/evm/src/cpu/kernel/tests/mpt/hash.rs @@ -1,6 +1,7 @@ use anyhow::Result; use eth_trie_utils::partial_trie::PartialTrie; use ethereum_types::{BigEndianHash, H256}; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -111,7 +112,7 @@ fn test_state_trie(trie_inputs: TrieInputs) -> Result<()> { let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"]; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); diff --git a/evm/src/cpu/kernel/tests/mpt/hex_prefix.rs b/evm/src/cpu/kernel/tests/mpt/hex_prefix.rs index e51e60ab..37077e40 100644 --- a/evm/src/cpu/kernel/tests/mpt/hex_prefix.rs +++ b/evm/src/cpu/kernel/tests/mpt/hex_prefix.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -15,7 +16,7 @@ fn hex_prefix_even_nonterminated() -> Result<()> { let num_nibbles = 6.into(); let rlp_pos = U256::from(Segment::RlpRaw as usize); let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles, rlp_pos]; - let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack); interpreter.run()?; assert_eq!(interpreter.stack(), vec![rlp_pos + U256::from(5)]); @@ -43,7 +44,7 @@ fn hex_prefix_odd_terminated() -> Result<()> { let num_nibbles = 5.into(); let rlp_pos = U256::from(Segment::RlpRaw as usize); let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles, rlp_pos]; - let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack); interpreter.run()?; assert_eq!(interpreter.stack(), vec![rlp_pos + U256::from(4)]); @@ -70,7 +71,7 @@ fn hex_prefix_odd_terminated_tiny() -> Result<()> { let num_nibbles = 1.into(); let rlp_pos = U256::from(Segment::RlpRaw as usize + 2); let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles, rlp_pos]; - let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack); interpreter.run()?; assert_eq!( interpreter.stack(), diff --git a/evm/src/cpu/kernel/tests/mpt/insert.rs b/evm/src/cpu/kernel/tests/mpt/insert.rs index 19b82f74..cbb13b9b 100644 --- a/evm/src/cpu/kernel/tests/mpt/insert.rs +++ b/evm/src/cpu/kernel/tests/mpt/insert.rs @@ -2,6 +2,7 @@ use anyhow::Result; use eth_trie_utils::nibbles::Nibbles; use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{BigEndianHash, H256}; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; @@ -173,7 +174,7 @@ fn test_state_trie( let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"]; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); diff --git a/evm/src/cpu/kernel/tests/mpt/load.rs b/evm/src/cpu/kernel/tests/mpt/load.rs index bff1d8cb..85c023f0 100644 --- a/evm/src/cpu/kernel/tests/mpt/load.rs +++ b/evm/src/cpu/kernel/tests/mpt/load.rs @@ -5,6 +5,7 @@ use eth_trie_utils::nibbles::Nibbles; use eth_trie_utils::partial_trie::HashedPartialTrie; use ethereum_types::{BigEndianHash, H256, U256}; use hex_literal::hex; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::cpu::kernel::constants::trie_type::PartialTrieType; @@ -24,7 +25,7 @@ fn load_all_mpts_empty() -> Result<()> { }; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); @@ -61,7 +62,7 @@ fn load_all_mpts_leaf() -> Result<()> { }; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); @@ -107,7 +108,7 @@ fn load_all_mpts_hash() -> Result<()> { }; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); @@ -145,7 +146,7 @@ fn load_all_mpts_empty_branch() -> Result<()> { }; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); @@ -197,7 +198,7 @@ fn load_all_mpts_ext_to_leaf() -> Result<()> { }; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); @@ -243,7 +244,7 @@ fn load_mpt_txn_trie() -> Result<()> { }; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); diff --git a/evm/src/cpu/kernel/tests/mpt/read.rs b/evm/src/cpu/kernel/tests/mpt/read.rs index 16206d13..a86bab85 100644 --- a/evm/src/cpu/kernel/tests/mpt/read.rs +++ b/evm/src/cpu/kernel/tests/mpt/read.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::BigEndianHash; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; @@ -20,7 +21,7 @@ fn mpt_read() -> Result<()> { let mpt_read = KERNEL.global_labels["mpt_read"]; let initial_stack = vec![]; - let mut interpreter = Interpreter::new_with_kernel(0, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, initial_stack); initialize_mpts(&mut interpreter, &trie_inputs); assert_eq!(interpreter.stack(), vec![]); diff --git a/evm/src/cpu/kernel/tests/packing.rs b/evm/src/cpu/kernel/tests/packing.rs index 0eb09cf7..ba72f658 100644 --- a/evm/src/cpu/kernel/tests/packing.rs +++ b/evm/src/cpu/kernel/tests/packing.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -15,7 +16,8 @@ fn test_mstore_unpacking() -> Result<()> { let addr = (Segment::TxnData as u64).into(); let initial_stack = vec![retdest, len, value, addr]; - let mut interpreter = Interpreter::new_with_kernel(mstore_unpacking, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(mstore_unpacking, initial_stack); interpreter.run()?; assert_eq!(interpreter.stack(), vec![addr + U256::from(4)]); diff --git a/evm/src/cpu/kernel/tests/receipt.rs b/evm/src/cpu/kernel/tests/receipt.rs index 7d00cb27..cf9f6389 100644 --- a/evm/src/cpu/kernel/tests/receipt.rs +++ b/evm/src/cpu/kernel/tests/receipt.rs @@ -2,6 +2,7 @@ use anyhow::Result; use ethereum_types::{Address, U256}; use hex_literal::hex; use keccak_hash::keccak; +use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::{thread_rng, Rng}; use crate::cpu::kernel::aggregator::KERNEL; @@ -47,7 +48,8 @@ fn test_process_receipt() -> Result<()> { leftover_gas, success, ]; - let mut interpreter = Interpreter::new_with_kernel(process_receipt, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(process_receipt, initial_stack); interpreter.set_memory_segment( Segment::LogsData, vec![ @@ -128,7 +130,8 @@ fn test_receipt_encoding() -> Result<()> { let expected_rlp = rlp::encode(&rlp::encode(&receipt_1)); let initial_stack: Vec = vec![retdest, 0.into(), 0.into(), 0.into()]; - let mut interpreter = Interpreter::new_with_kernel(encode_receipt, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(encode_receipt, initial_stack); // Write data to memory. let expected_bloom_bytes = vec![ @@ -248,7 +251,7 @@ fn test_receipt_bloom_filter() -> Result<()> { // Set logs memory and initialize TxnBloom and BlockBloom segments. let initial_stack: Vec = vec![retdest]; - let mut interpreter = Interpreter::new_with_kernel(logs_bloom, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(logs_bloom, initial_stack); let mut logs = vec![ 0.into(), // unused addr, @@ -408,7 +411,7 @@ fn test_mpt_insert_receipt() -> Result<()> { receipt.push(num_logs.into()); // num_logs receipt.extend(logs_0.clone()); - let mut interpreter = Interpreter::new_with_kernel(0, vec![]); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(0, vec![]); initialize_mpts(&mut interpreter, &trie_inputs); // If TrieData is empty, we need to push 0 because the first value is always 0. @@ -562,7 +565,7 @@ fn test_bloom_two_logs() -> Result<()> { ] .into(), ]; - let mut interpreter = Interpreter::new_with_kernel(logs_bloom, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(logs_bloom, initial_stack); interpreter.set_memory_segment(Segment::TxnBloom, vec![0.into(); 256]); // Initialize transaction Bloom filter. interpreter.set_memory_segment(Segment::LogsData, logs); interpreter.set_memory_segment(Segment::Logs, vec![0.into(), 4.into()]); diff --git a/evm/src/cpu/kernel/tests/rlp/decode.rs b/evm/src/cpu/kernel/tests/rlp/decode.rs index 1f3260e5..6a749f5c 100644 --- a/evm/src/cpu/kernel/tests/rlp/decode.rs +++ b/evm/src/cpu/kernel/tests/rlp/decode.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -13,7 +14,8 @@ fn test_decode_rlp_string_len_short() -> Result<()> { 0xDEADBEEFu32.into(), U256::from(Segment::RlpRaw as usize + 2), ]; - let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by "0x70" which is its own encoding. interpreter.set_rlp_memory(vec![123, 234, 0x70]); @@ -33,7 +35,8 @@ fn test_decode_rlp_string_len_medium() -> Result<()> { 0xDEADBEEFu32.into(), U256::from(Segment::RlpRaw as usize + 2), ]; - let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by the RLP encoding of "1 2 3 4 5". interpreter.set_rlp_memory(vec![123, 234, 0x85, 1, 2, 3, 4, 5]); @@ -53,7 +56,8 @@ fn test_decode_rlp_string_len_long() -> Result<()> { 0xDEADBEEFu32.into(), U256::from(Segment::RlpRaw as usize + 2), ]; - let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // The RLP encoding of the string "1 2 3 ... 56". interpreter.set_rlp_memory(vec![ @@ -74,7 +78,8 @@ fn test_decode_rlp_list_len_short() -> Result<()> { let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; let initial_stack = vec![0xDEADBEEFu32.into(), U256::from(Segment::RlpRaw as usize)]; - let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, 2, [3, 4]]. interpreter.set_rlp_memory(vec![0xc5, 1, 2, 0xc2, 3, 4]); @@ -91,7 +96,8 @@ fn test_decode_rlp_list_len_long() -> Result<()> { let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; let initial_stack = vec![0xDEADBEEFu32.into(), U256::from(Segment::RlpRaw as usize)]; - let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, ..., 56]. interpreter.set_rlp_memory(vec![ @@ -112,7 +118,8 @@ fn test_decode_rlp_scalar() -> Result<()> { let decode_rlp_scalar = KERNEL.global_labels["decode_rlp_scalar"]; let initial_stack = vec![0xDEADBEEFu32.into(), U256::from(Segment::RlpRaw as usize)]; - let mut interpreter = Interpreter::new_with_kernel(decode_rlp_scalar, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(decode_rlp_scalar, initial_stack); // The RLP encoding of "12 34 56". interpreter.set_rlp_memory(vec![0x83, 0x12, 0x34, 0x56]); diff --git a/evm/src/cpu/kernel/tests/rlp/encode.rs b/evm/src/cpu/kernel/tests/rlp/encode.rs index d28a763f..75464235 100644 --- a/evm/src/cpu/kernel/tests/rlp/encode.rs +++ b/evm/src/cpu/kernel/tests/rlp/encode.rs @@ -1,5 +1,6 @@ use anyhow::Result; use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -13,7 +14,8 @@ fn test_encode_rlp_scalar_small() -> Result<()> { let scalar = 42.into(); let pos = U256::from(Segment::RlpRaw as usize + 2); let initial_stack = vec![retdest, scalar, pos]; - let mut interpreter = Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack); interpreter.run()?; let expected_stack = vec![pos + U256::from(1)]; // pos' = pos + rlp_len = 2 + 1 @@ -32,7 +34,8 @@ fn test_encode_rlp_scalar_medium() -> Result<()> { let scalar = 0x12345.into(); let pos = U256::from(Segment::RlpRaw as usize + 2); let initial_stack = vec![retdest, scalar, pos]; - let mut interpreter = Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack); interpreter.run()?; let expected_stack = vec![pos + U256::from(4)]; // pos' = pos + rlp_len = 2 + 4 @@ -51,7 +54,8 @@ fn test_encode_rlp_160() -> Result<()> { let string = 0x12345.into(); let pos = U256::from(Segment::RlpRaw as usize); let initial_stack = vec![retdest, string, pos, U256::from(20)]; - let mut interpreter = Interpreter::new_with_kernel(encode_rlp_fixed, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(encode_rlp_fixed, initial_stack); interpreter.run()?; let expected_stack = vec![pos + U256::from(1 + 20)]; // pos' @@ -71,7 +75,8 @@ fn test_encode_rlp_256() -> Result<()> { let string = 0x12345.into(); let pos = U256::from(Segment::RlpRaw as usize); let initial_stack = vec![retdest, string, pos, U256::from(32)]; - let mut interpreter = Interpreter::new_with_kernel(encode_rlp_fixed, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(encode_rlp_fixed, initial_stack); interpreter.run()?; let expected_stack = vec![pos + U256::from(1 + 32)]; // pos' @@ -91,7 +96,8 @@ fn test_prepend_rlp_list_prefix_small() -> Result<()> { let start_pos = U256::from(Segment::RlpRaw as usize + 9); let end_pos = U256::from(Segment::RlpRaw as usize + 9 + 5); let initial_stack = vec![retdest, start_pos, end_pos]; - let mut interpreter = Interpreter::new_with_kernel(prepend_rlp_list_prefix, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(prepend_rlp_list_prefix, initial_stack); interpreter.set_rlp_memory(vec![ // Nine 0s to leave room for the longest possible RLP list prefix. 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -120,7 +126,8 @@ fn test_prepend_rlp_list_prefix_large() -> Result<()> { let start_pos = U256::from(Segment::RlpRaw as usize + 9); let end_pos = U256::from(Segment::RlpRaw as usize + 9 + 60); let initial_stack = vec![retdest, start_pos, end_pos]; - let mut interpreter = Interpreter::new_with_kernel(prepend_rlp_list_prefix, initial_stack); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(prepend_rlp_list_prefix, initial_stack); #[rustfmt::skip] interpreter.set_rlp_memory(vec![ diff --git a/evm/src/cpu/kernel/tests/rlp/num_bytes.rs b/evm/src/cpu/kernel/tests/rlp/num_bytes.rs index fa4066fe..b02175d0 100644 --- a/evm/src/cpu/kernel/tests/rlp/num_bytes.rs +++ b/evm/src/cpu/kernel/tests/rlp/num_bytes.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -10,7 +11,7 @@ fn test_num_bytes_0() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let x = 0.into(); let initial_stack = vec![retdest, x]; - let mut interpreter = Interpreter::new_with_kernel(num_bytes, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(num_bytes, initial_stack); interpreter.run()?; assert_eq!(interpreter.stack(), vec![1.into()]); @@ -24,7 +25,7 @@ fn test_num_bytes_small() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let x = 42.into(); let initial_stack = vec![retdest, x]; - let mut interpreter = Interpreter::new_with_kernel(num_bytes, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(num_bytes, initial_stack); interpreter.run()?; assert_eq!(interpreter.stack(), vec![1.into()]); @@ -38,7 +39,7 @@ fn test_num_bytes_medium() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let x = 0xAABBCCDDu32.into(); let initial_stack = vec![retdest, x]; - let mut interpreter = Interpreter::new_with_kernel(num_bytes, initial_stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(num_bytes, initial_stack); interpreter.run()?; assert_eq!(interpreter.stack(), vec![4.into()]); diff --git a/evm/src/cpu/kernel/tests/signed_syscalls.rs b/evm/src/cpu/kernel/tests/signed_syscalls.rs index 74b3524b..993b8e03 100644 --- a/evm/src/cpu/kernel/tests/signed_syscalls.rs +++ b/evm/src/cpu/kernel/tests/signed_syscalls.rs @@ -1,4 +1,5 @@ use ethereum_types::U256; +use plonky2::field::goldilocks_field::GoldilocksField as F; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -117,7 +118,7 @@ fn run_test(fn_label: &str, expected_fn: fn(U256, U256) -> U256, opname: &str) { for &x in &inputs { for &y in &inputs { let stack = vec![retdest, y, x]; - let mut interpreter = Interpreter::new_with_kernel(fn_label, stack); + let mut interpreter: Interpreter = Interpreter::new_with_kernel(fn_label, stack); interpreter.run().unwrap(); assert_eq!(interpreter.stack_len(), 1usize, "unexpected stack size"); let output = interpreter diff --git a/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs b/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs index 5976acaf..8415b47b 100644 --- a/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs +++ b/evm/src/cpu/kernel/tests/transaction_parsing/parse_type_0_txn.rs @@ -1,6 +1,7 @@ use anyhow::Result; use ethereum_types::U256; use hex_literal::hex; +use plonky2::field::goldilocks_field::GoldilocksField as F; use NormalizedTxnField::*; use crate::cpu::kernel::aggregator::KERNEL; @@ -13,7 +14,8 @@ fn process_type_0_txn() -> Result<()> { let process_normalized_txn = KERNEL.global_labels["process_normalized_txn"]; let retaddr = 0xDEADBEEFu32.into(); - let mut interpreter = Interpreter::new_with_kernel(process_type_0_txn, vec![retaddr]); + let mut interpreter: Interpreter = + Interpreter::new_with_kernel(process_type_0_txn, vec![retaddr]); // When we reach process_normalized_txn, we're done with parsing and normalizing. // Processing normalized transactions is outside the scope of this test. diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index 6da0e38b..105fb6a9 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -333,87 +333,3 @@ fn simulate_cpu(state: &mut GenerationState) -> anyhow::Result<()> transition(state)?; } } - -fn simulate_cpu_between_labels_and_get_user_jumps( - initial_label: &str, - final_label: &str, - state: &mut GenerationState, -) -> Option>> { - if state.jumpdest_table.is_some() { - None - } else { - const JUMP_OPCODE: u8 = 0x56; - const JUMPI_OPCODE: u8 = 0x57; - - let halt_pc = KERNEL.global_labels[final_label]; - let mut jumpdest_addresses: HashMap<_, BTreeSet> = HashMap::new(); - - state.registers.program_counter = KERNEL.global_labels[initial_label]; - let initial_clock = state.traces.clock(); - let initial_context = state.registers.context; - - log::debug!("Simulating CPU for jumpdest analysis."); - - loop { - // skip jumpdest table validations in simulations - if state.registers.is_kernel - && state.registers.program_counter == KERNEL.global_labels["jumpdest_analysis"] - { - state.registers.program_counter = KERNEL.global_labels["jumpdest_analysis_end"] - } - let pc = state.registers.program_counter; - let context = state.registers.context; - let halt = state.registers.is_kernel - && pc == halt_pc - && state.registers.context == initial_context; - let Ok(opcode) = u256_to_u8(state.memory.get(MemoryAddress::new( - context, - Segment::Code, - state.registers.program_counter, - ))) else { - log::debug!( - "Simulated CPU for jumpdest analysis halted after {} cycles", - state.traces.clock() - initial_clock - ); - return Some(jumpdest_addresses); - }; - let cond = if let Ok(cond) = stack_peek(state, 1) { - cond != U256::zero() - } else { - false - }; - if !state.registers.is_kernel - && (opcode == JUMP_OPCODE || (opcode == JUMPI_OPCODE && cond)) - { - // Avoid deeper calls to abort - let Ok(jumpdest) = u256_to_usize(state.registers.stack_top) else { - log::debug!( - "Simulated CPU for jumpdest analysis halted after {} cycles", - state.traces.clock() - initial_clock - ); - return Some(jumpdest_addresses); - }; - state.memory.set( - MemoryAddress::new(context, Segment::JumpdestBits, jumpdest), - U256::one(), - ); - let jumpdest_opcode = - state - .memory - .get(MemoryAddress::new(context, Segment::Code, jumpdest)); - if let Some(ctx_addresses) = jumpdest_addresses.get_mut(&context) { - ctx_addresses.insert(jumpdest); - } else { - jumpdest_addresses.insert(context, BTreeSet::from([jumpdest])); - } - } - if halt || transition(state).is_err() { - log::debug!( - "Simulated CPU for jumpdest analysis halted after {} cycles", - state.traces.clock() - initial_clock - ); - return Some(jumpdest_addresses); - } - } - } -} diff --git a/evm/src/generation/prover_input.rs b/evm/src/generation/prover_input.rs index 9662d6b6..e6fb4dbf 100644 --- a/evm/src/generation/prover_input.rs +++ b/evm/src/generation/prover_input.rs @@ -10,12 +10,14 @@ use plonky2::field::types::Field; use serde::{Deserialize, Serialize}; use crate::cpu::kernel::constants::context_metadata::ContextMetadata; +use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; +use crate::cpu::kernel::interpreter::simulate_cpu_and_get_user_jumps; +use crate::cpu::kernel::opcodes::get_push_opcode; use crate::extension_tower::{FieldExt, Fp12, BLS381, BN254}; use crate::generation::prover_input::EvmField::{ Bls381Base, Bls381Scalar, Bn254Base, Bn254Scalar, Secp256k1Base, Secp256k1Scalar, }; use crate::generation::prover_input::FieldOp::{Inverse, Sqrt}; -use crate::generation::simulate_cpu_between_labels_and_get_user_jumps; use crate::generation::state::GenerationState; use crate::memory::segments::Segment; use crate::memory::segments::Segment::BnPairing; @@ -250,6 +252,7 @@ impl GenerationState { if self.jumpdest_table.is_none() { self.generate_jumpdest_table()?; + log::debug!("jdt = {:?}", self.jumpdest_table); } let Some(jumpdest_table) = &mut self.jumpdest_table else { @@ -258,12 +261,19 @@ impl GenerationState { )); }; + let jd_len = jumpdest_table.len(); + if let Some(ctx_jumpdest_table) = jumpdest_table.get_mut(&context) && let Some(next_jumpdest_address) = ctx_jumpdest_table.pop() { + log::debug!( + "jumpdest_table_len = {:?}, ctx_jumpdest_table.len = {:?}", + jd_len, + ctx_jumpdest_table.len() + ); Ok((next_jumpdest_address + 1).into()) } else { - self.jumpdest_table = None; + jumpdest_table.remove(&context); Ok(U256::zero()) } } @@ -276,9 +286,17 @@ impl GenerationState { ProverInputError::InvalidJumpdestSimulation, )); }; + + let jd_len = jumpdest_table.len(); + if let Some(ctx_jumpdest_table) = jumpdest_table.get_mut(&context) && let Some(next_jumpdest_proof) = ctx_jumpdest_table.pop() { + log::debug!( + "jumpdest_table_len = {:?}, ctx_jumpdest_table.len = {:?}", + jd_len, + ctx_jumpdest_table.len() + ); Ok(next_jumpdest_proof.into()) } else { Err(ProgramError::ProverInputError( @@ -292,24 +310,9 @@ impl GenerationState { /// Simulate the user's code and store all the jump addresses with their respective contexts. fn generate_jumpdest_table(&mut self) -> Result<(), ProgramError> { let checkpoint = self.checkpoint(); - let memory = self.memory.clone(); // Simulate the user's code and (unnecessarily) part of the kernel code, skipping the validate table call - let Some(jumpdest_table) = simulate_cpu_between_labels_and_get_user_jumps( - "jumpdest_analysis_end", - "terminate_common", - self, - ) else { - self.jumpdest_table = Some(HashMap::new()); - return Ok(()); - }; - - // Return to the state before starting the simulation - self.rollback(checkpoint); - self.memory = memory; - - // Find proofs for all contexts - self.set_jumpdest_analysis_inputs(jumpdest_table); + self.jumpdest_table = simulate_cpu_and_get_user_jumps("terminate_common", self); Ok(()) } @@ -333,6 +336,10 @@ impl GenerationState { ))); } + pub(crate) fn get_current_code(&self) -> Result, ProgramError> { + self.get_code(self.registers.context) + } + fn get_code(&self, context: usize) -> Result, ProgramError> { let code_len = self.get_code_len(context)?; let code = (0..code_len) @@ -354,12 +361,28 @@ impl GenerationState { )))?; Ok(code_len) } + + fn get_current_code_len(&self) -> Result { + self.get_code_len(self.registers.context) + } + + pub(crate) fn set_jumpdest_bits(&mut self, code: &[u8]) { + const JUMPDEST_OPCODE: u8 = 0x5b; + for (pos, opcode) in CodeIterator::new(code) { + if opcode == JUMPDEST_OPCODE { + self.memory.set( + MemoryAddress::new(self.registers.context, Segment::JumpdestBits, pos), + U256::one(), + ); + } + } + } } -/// For all address in `jumpdest_table`, each bounded by `largest_address`, +/// For all address in `jumpdest_table` smaller than `largest_address`, /// this function searches for a proof. A proof is the closest address /// for which none of the previous 32 bytes in the code (including opcodes -/// and pushed bytes) are PUSHXX and the address is in its range. It returns +/// and pushed bytes) is a PUSHXX and the address is in its range. It returns /// a vector of even size containing proofs followed by their addresses. fn get_proofs_and_jumpdests( code: &[u8], @@ -370,30 +393,24 @@ fn get_proofs_and_jumpdests( const PUSH32_OPCODE: u8 = 0x7f; let (proofs, _) = CodeIterator::until(code, largest_address + 1).fold( (vec![], 0), - |(mut proofs, acc), (pos, _opcode)| { - let has_prefix = if let Some(prefix_start) = pos.checked_sub(32) { - code[prefix_start..pos] + |(mut proofs, last_proof), (addr, opcode)| { + let has_prefix = if let Some(prefix_start) = addr.checked_sub(32) { + code[prefix_start..addr] .iter() - .enumerate() - .fold(true, |acc, (prefix_pos, &byte)| { - let cond1 = byte > PUSH32_OPCODE; - let cond2 = (prefix_start + prefix_pos) as i32 - + (byte as i32 - PUSH1_OPCODE as i32) - + 1 - < pos as i32; - acc && (cond1 || cond2) - }) + .rev() + .zip(0..32) + .all(|(&byte, i)| byte > PUSH32_OPCODE || byte < PUSH1_OPCODE + i) } else { false }; - let acc = if has_prefix { pos - 32 } else { acc }; - if jumpdest_table.contains(&pos) { + let last_proof = if has_prefix { addr - 32 } else { last_proof }; + if jumpdest_table.contains(&addr) { // Push the proof - proofs.push(acc); + proofs.push(last_proof); // Push the address - proofs.push(pos); + proofs.push(addr); } - (proofs, acc) + (proofs, last_proof) }, ); proofs