diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index f2fb276a..c9d52cff 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -1,7 +1,11 @@ +use std::collections::HashMap; + use anyhow::{anyhow, bail}; use ethereum_types::{BigEndianHash, U256, U512}; use keccak_hash::keccak; +use crate::cpu::kernel::prover_input::ProverInputFn; + /// Halt interpreter execution whenever a jump to this offset is done. const HALT_OFFSET: usize = 0xdeadbeef; @@ -55,29 +59,16 @@ pub(crate) struct Interpreter<'a> { offset: usize, pub(crate) stack: Vec, pub(crate) memory: EvmMemory, - /// Non-deterministic prover inputs, stored backwards so that popping the last item gives the - /// next prover input. - prover_inputs: Vec, + prover_inputs: &'a HashMap, running: bool, } -pub(crate) fn run( - code: &[u8], +pub(crate) fn run<'a>( + code: &'a [u8], initial_offset: usize, initial_stack: Vec, -) -> anyhow::Result { - run_with_input(code, initial_offset, initial_stack, vec![]) -} - -pub(crate) fn run_with_input( - code: &[u8], - initial_offset: usize, - initial_stack: Vec, - mut prover_inputs: Vec, -) -> anyhow::Result { - // Prover inputs are stored backwards, so that popping the last item gives the next input. - prover_inputs.reverse(); - + prover_inputs: &'a HashMap, +) -> anyhow::Result> { let mut interpreter = Interpreter { code, jumpdests: find_jumpdests(code), @@ -337,11 +328,12 @@ impl<'a> Interpreter<'a> { } fn run_prover_input(&mut self) -> anyhow::Result<()> { - let input = self + let prover_input_fn = self .prover_inputs - .pop() - .ok_or_else(|| anyhow!("Out of prover inputs"))?; - self.stack.push(input); + .get(&(self.offset - 1)) + .ok_or_else(|| anyhow!("Offset not in prover inputs."))?; + let output = prover_input_fn.run(self.stack.clone()); + self.stack.push(output); Ok(()) } @@ -424,6 +416,8 @@ fn find_jumpdests(code: &[u8]) -> Vec { #[cfg(test)] mod tests { + use std::collections::HashMap; + use hex_literal::hex; use crate::cpu::kernel::interpreter::{run, Interpreter}; @@ -433,7 +427,10 @@ mod tests { let code = vec![ 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![])?.stack, vec![0x3.into()]); + assert_eq!( + run(&code, 0, vec![], &HashMap::new())?.stack, + vec![0x3.into()], + ); Ok(()) } @@ -456,7 +453,8 @@ mod tests { 0x60, 0xff, 0x60, 0x0, 0x52, 0x60, 0, 0x51, 0x60, 0x1, 0x51, 0x60, 0x42, 0x60, 0x27, 0x53, ]; - let run = run(&code, 0, vec![])?; + let pis = HashMap::new(); + let run = run(&code, 0, vec![], &pis)?; let Interpreter { stack, memory, .. } = run; assert_eq!(stack, vec![0xff.into(), 0xff00.into()]); assert_eq!(&memory.memory, &hex!("00000000000000000000000000000000000000000000000000000000000000ff0000000000000042000000000000000000000000000000000000000000000000")); diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs index 79a8483d..c9cb8821 100644 --- a/evm/src/cpu/kernel/prover_input.rs +++ b/evm/src/cpu/kernel/prover_input.rs @@ -17,7 +17,7 @@ impl From> for ProverInputFn { } impl ProverInputFn { - pub(crate) fn run(&self, mut stack: Vec) -> U256 { + pub(crate) fn run(&self, stack: Vec) -> U256 { match self.0[0].as_str() { "ff" => self.run_ff(stack), "storage" => todo!(), diff --git a/evm/src/cpu/kernel/tests/curve_ops.rs b/evm/src/cpu/kernel/tests/curve_ops.rs index 6d8c6696..72e4169b 100644 --- a/evm/src/cpu/kernel/tests/curve_ops.rs +++ b/evm/src/cpu/kernel/tests/curve_ops.rs @@ -43,76 +43,82 @@ mod bn { // Standard addition #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point1.1, point1.0])?; - let stack = run(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #2 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_double, initial_stack)?.stack; + let stack = run( + &kernel.code, + ec_double, + initial_stack, + &kernel.prover_inputs, + )? + .stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #3 let initial_stack = u256ify(["0xdeadbeef", "0x2", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Scalar multiplication #1 let initial_stack = u256ify(["0xdeadbeef", s, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); // Scalar multiplication #2 let initial_stack = u256ify(["0xdeadbeef", "0x0", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #3 let initial_stack = u256ify(["0xdeadbeef", "0x1", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point0.1, point0.0])?); // Scalar multiplication #4 let initial_stack = u256ify(["0xdeadbeef", s, identity.1, identity.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #5 let initial_stack = u256ify(["0xdeadbeef", s, invalid.1, invalid.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Multiple calls @@ -126,7 +132,7 @@ mod bn { point0.1, point0.0, ])?; - let stack = run(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) @@ -176,55 +182,61 @@ mod secp { // Standard addition #1 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point1.1, point1.0])?; - let stack = run(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #2 let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_double, initial_stack)?.stack; + let stack = run( + &kernel.code, + ec_double, + initial_stack, + &kernel.prover_inputs, + )? + .stack; assert_eq!(stack, u256ify([point3.1, point3.0])?); // Standard doubling #3 let initial_stack = u256ify(["0xdeadbeef", "0x2", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; 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(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #1 let initial_stack = u256ify(["0xdeadbeef", s, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); // Scalar multiplication #2 let initial_stack = u256ify(["0xdeadbeef", "0x0", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #3 let initial_stack = u256ify(["0xdeadbeef", "0x1", point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point0.1, point0.0])?); // Scalar multiplication #4 let initial_stack = u256ify(["0xdeadbeef", s, identity.1, identity.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Multiple calls @@ -238,7 +250,7 @@ mod secp { point0.1, point0.0, ])?; - let stack = run(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) diff --git a/evm/src/cpu/kernel/tests/ecrecover.rs b/evm/src/cpu/kernel/tests/ecrecover.rs index 78bdea3e..790a4a2c 100644 --- a/evm/src/cpu/kernel/tests/ecrecover.rs +++ b/evm/src/cpu/kernel/tests/ecrecover.rs @@ -18,7 +18,13 @@ fn test_valid_ecrecover( ) -> Result<()> { let ecrecover = kernel.global_labels["ecrecover"]; let initial_stack = u256ify(["0xdeadbeef", s, r, v, hash])?; - let stack = run(&kernel.code, ecrecover, initial_stack)?.stack; + let stack = run( + &kernel.code, + ecrecover, + initial_stack, + &kernel.prover_inputs, + )? + .stack; assert_eq!(stack[0], U256::from_str(expected).unwrap()); Ok(()) @@ -27,7 +33,13 @@ fn test_valid_ecrecover( fn test_invalid_ecrecover(hash: &str, v: &str, r: &str, s: &str, kernel: &Kernel) -> Result<()> { let ecrecover = kernel.global_labels["ecrecover"]; let initial_stack = u256ify(["0xdeadbeef", s, r, v, hash])?; - let stack = run(&kernel.code, ecrecover, initial_stack)?.stack; + let stack = run( + &kernel.code, + ecrecover, + initial_stack, + &kernel.prover_inputs, + )? + .stack; 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 25c88623..0858c37c 100644 --- a/evm/src/cpu/kernel/tests/exp.rs +++ b/evm/src/cpu/kernel/tests/exp.rs @@ -18,26 +18,26 @@ fn test_exp() -> Result<()> { // Random input let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, a]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack)?.stack; + let stack_with_kernel = run(&kernel.code, exp, initial_stack, &kernel.prover_inputs)?.stack; let initial_stack = vec![b, a]; let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP - let stack_with_opcode = run(&code, 0, initial_stack)?.stack; + let stack_with_opcode = run(&code, 0, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack_with_kernel, stack_with_opcode); // 0 base let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, U256::zero()]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack)?.stack; + let stack_with_kernel = run(&kernel.code, exp, initial_stack, &kernel.prover_inputs)?.stack; let initial_stack = vec![b, U256::zero()]; let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP - let stack_with_opcode = run(&code, 0, initial_stack)?.stack; + let stack_with_opcode = run(&code, 0, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack_with_kernel, stack_with_opcode); // 0 exponent let initial_stack = vec![U256::from_str("0xdeadbeef")?, U256::zero(), a]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack)?.stack; + let stack_with_kernel = run(&kernel.code, exp, initial_stack, &kernel.prover_inputs)?.stack; let initial_stack = vec![U256::zero(), a]; let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP - let stack_with_opcode = run(&code, 0, initial_stack)?.stack; + let stack_with_opcode = run(&code, 0, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack_with_kernel, stack_with_opcode); Ok(())