From 563401b24d1af2714f3e2be2796c7988e1efdfcf Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sun, 17 Jul 2022 09:14:24 -0700 Subject: [PATCH 1/9] More basic ASM utility functions To be used in upcoming RLP code. --- evm/src/cpu/kernel/asm/assertions.asm | 74 ++++++++++++++++++++++++ evm/src/cpu/kernel/asm/basic_macros.asm | 77 +++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 evm/src/cpu/kernel/asm/assertions.asm diff --git a/evm/src/cpu/kernel/asm/assertions.asm b/evm/src/cpu/kernel/asm/assertions.asm new file mode 100644 index 00000000..2a7d845e --- /dev/null +++ b/evm/src/cpu/kernel/asm/assertions.asm @@ -0,0 +1,74 @@ +// It is convenient to have a single panic routine, which we can jump to from +// anywhere. +global panic: + JUMPDEST + PANIC + +// Consumes the top element and asserts that it is zero. +%macro assert_zero + %jumpi panic +%endmacro + +// Consumes the top element and asserts that it is nonzero. +%macro assert_nonzero + ISZERO + %jumpi panic +%endmacro + +%macro assert_eq + EQ + %assert_nonzero +%endmacro + +%macro assert_lt + LT + %assert_nonzero +%endmacro + +%macro assert_le + LE + %assert_nonzero +%endmacro + +%macro assert_gt + GT + %assert_nonzero +%endmacro + +%macro assert_ge + GE + %assert_nonzero +%endmacro + +%macro assert_eq_const(c) + %eq_const(c) + %assert_nonzero +%endmacro + +%macro assert_lt_const(c) + // %assert_zero is cheaper than %assert_nonzero, so we will leverage the + // fact that (x < c) == !(x >= c). + %ge_const(c) + %assert_zero +%endmacro + +%macro assert_le_const(c) + // %assert_zero is cheaper than %assert_nonzero, so we will leverage the + // fact that (x <= c) == !(x > c). + %gt_const(c) + %assert_zero +%endmacro + +%macro assert_gt_const(c) + // %assert_zero is cheaper than %assert_nonzero, so we will leverage the + // fact that (x > c) == !(x <= c). + %le_const(c) + %assert_zero +%endmacro + +%macro assert_ge_const(c) + // %assert_zero is cheaper than %assert_nonzero, so we will leverage the + // fact that (x >= c) == !(x < c). + %lt_const(c) + %assert_zero +%endmacro diff --git a/evm/src/cpu/kernel/asm/basic_macros.asm b/evm/src/cpu/kernel/asm/basic_macros.asm index 9e884fea..7230772d 100644 --- a/evm/src/cpu/kernel/asm/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/basic_macros.asm @@ -26,6 +26,83 @@ %endrep %endmacro +%macro add_const(c) + // stack: input, ... + PUSH $c + ADD + // stack: input + c, ... +%endmacro + +// Slightly inefficient as we need to swap the inputs. +// Consider avoiding this in performance-critical code. +%macro sub_const(c) + // stack: input, ... + PUSH $c + // stack: c, input, ... + SWAP1 + // stack: input, c, ... + SUB + // stack: input - c, ... +%endmacro + +%macro mul_const(c) + // stack: input, ... + PUSH $c + MUL + // stack: input * c, ... +%endmacro + +// Slightly inefficient as we need to swap the inputs. +// Consider avoiding this in performance-critical code. +%macro div_const(c) + // stack: input, ... + PUSH $c + // stack: c, input, ... + SWAP1 + // stack: input, c, ... + SUB + // stack: input / c, ... +%endmacro + +%macro eq_const(c) + // stack: input, ... + PUSH $c + EQ + // stack: input == c, ... +%endmacro + +%macro lt_const(c) + // stack: input, ... + PUSH $c + // stack: c, input, ... + GT // Check it backwards: (input < c) == (c > input) + // stack: input <= c, ... +%endmacro + +%macro le_const(c) + // stack: input, ... + PUSH $c + // stack: c, input, ... + GE // Check it backwards: (input <= c) == (c >= input) + // stack: input <= c, ... +%endmacro + +%macro gt_const(c) + // stack: input, ... + PUSH $c + // stack: c, input, ... + LT // Check it backwards: (input > c) == (c < input) + // stack: input >= c, ... +%endmacro + +%macro ge_const(c) + // stack: input, ... + PUSH $c + // stack: c, input, ... + LE // Check it backwards: (input >= c) == (c <= input) + // stack: input >= c, ... +%endmacro + // If pred is zero, yields z; otherwise, yields nz %macro select // stack: pred, nz, z From 36f1692ee5f06f4fbfd0ba40566f3408911201d4 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sun, 17 Jul 2022 09:23:37 -0700 Subject: [PATCH 2/9] tweaks --- evm/src/cpu/kernel/asm/assertions.asm | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/evm/src/cpu/kernel/asm/assertions.asm b/evm/src/cpu/kernel/asm/assertions.asm index 2a7d845e..a8e65036 100644 --- a/evm/src/cpu/kernel/asm/assertions.asm +++ b/evm/src/cpu/kernel/asm/assertions.asm @@ -21,23 +21,31 @@ global panic: %endmacro %macro assert_lt - LT - %assert_nonzero + // %assert_zero is cheaper than %assert_nonzero, so we will leverage the + // fact that (x < y) == !(x >= y). + GE + %assert_zero %endmacro %macro assert_le - LE - %assert_nonzero + // %assert_zero is cheaper than %assert_nonzero, so we will leverage the + // fact that (x <= y) == !(x > y). + GT + %assert_zero %endmacro %macro assert_gt - GT - %assert_nonzero + // %assert_zero is cheaper than %assert_nonzero, so we will leverage the + // fact that (x > y) == !(x <= y). + LE + %assert_zero %endmacro %macro assert_ge - GE - %assert_nonzero + // %assert_zero is cheaper than %assert_nonzero, so we will leverage the + // fact that (x >= y) == !(x < y). + LT + %assert_zero %endmacro %macro assert_eq_const(c) From 925483ed1eb0f6724ece0dde50c5b576377607e4 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sun, 17 Jul 2022 15:07:29 -0700 Subject: [PATCH 3/9] Add custom opcodes - `GET_STATE_ROOT` and `SET_STATE_ROOT` deal with the root of the state trie, and will be called from storage routines. Similarly `GET_RECEIPT_ROOT` and `SET_RECEIPT_ROOT` deal with the root of the receipt trie. - `PANIC` enables an unsatisfiable constraint, so no proof can be generated. - `GET_CONTEXT` and `SET_CONTEXT`, used when calling and returning - `CONSUME_GAS` charges the sender gas; useful for cases where gas calculations are nontrivial and best implemented in assembly. - `EXIT_KERNEL` simply clears the CPU flag indicating that we're in kernel mode; it would be used just before a jump to return to the (userspace) caller. - `MLOAD_GENERAL` and `MSTORE_GENERAL` are for reading and writing memory, but they're not limited to the main memory segment of the current context; they can access any context and any segment. I added a couple macros to show how the they would typically be used. There may be more later, but these are the ones I think we need for now. I tried to fill in smaller invalid sections of the decoder's tree, as Jacqui suggested, while keeping related opcodes together. We can fine tune it when the opcode list is more stable. These are all intended to be priviledged, i.e. they will be treated as invalid if used from userspace, for compatibility as well as (in some cases) security reasons. --- evm/src/cpu/columns.rs | 17 +++++++++----- evm/src/cpu/decode.rs | 37 ++++++++++++++++++------------- evm/src/cpu/kernel/asm/memory.asm | 27 ++++++++++++++++++++++ evm/src/cpu/kernel/interpreter.rs | 11 +++++++++ evm/src/cpu/kernel/opcodes.rs | 11 +++++++++ 5 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/memory.asm diff --git a/evm/src/cpu/columns.rs b/evm/src/cpu/columns.rs index f3a400c6..c79f9e9d 100644 --- a/evm/src/cpu/columns.rs +++ b/evm/src/cpu/columns.rs @@ -90,6 +90,10 @@ pub struct CpuColumnsView { pub is_msize: T, pub is_gas: T, pub is_jumpdest: T, + pub is_get_state_root: T, + pub is_set_state_root: T, + pub is_get_receipt_root: T, + pub is_set_receipt_root: T, pub is_push: T, pub is_dup: T, pub is_swap: T, @@ -98,13 +102,20 @@ pub struct CpuColumnsView { pub is_log2: T, pub is_log3: T, pub is_log4: T, + pub is_panic: T, pub is_create: T, pub is_call: T, pub is_callcode: T, pub is_return: T, pub is_delegatecall: T, pub is_create2: T, + pub is_get_context: T, + pub is_set_context: T, + pub is_consume_gas: T, + pub is_exit_kernel: T, pub is_staticcall: T, + pub is_mload_general: T, + pub is_mstore_general: T, pub is_revert: T, pub is_selfdestruct: T, @@ -124,12 +135,6 @@ pub struct CpuColumnsView { pub is_invalid_12: T, pub is_invalid_13: T, pub is_invalid_14: T, - pub is_invalid_15: T, - pub is_invalid_16: T, - pub is_invalid_17: T, - pub is_invalid_18: T, - pub is_invalid_19: T, - pub is_invalid_20: T, /// If CPU cycle: the opcode, broken up into bits in **big-endian** order. pub opcode_bits: [T; 8], diff --git a/evm/src/cpu/decode.rs b/evm/src/cpu/decode.rs index 0b091558..22a25dc6 100644 --- a/evm/src/cpu/decode.rs +++ b/evm/src/cpu/decode.rs @@ -15,7 +15,7 @@ use crate::cpu::columns::{CpuColumnsView, COL_MAP}; // - its start index is a multiple of its length (it is aligned) // These properties permit us to check if an opcode belongs to a block of length 2^n by checking its // top 8-n bits. -const OPCODES: [(u64, usize, usize); 102] = [ +const OPCODES: [(u64, usize, usize); 107] = [ // (start index of block, number of top bits to check (log2), flag column) (0x00, 0, COL_MAP.is_stop), (0x01, 0, COL_MAP.is_add), @@ -90,34 +90,39 @@ const OPCODES: [(u64, usize, usize); 102] = [ (0x59, 0, COL_MAP.is_msize), (0x5a, 0, COL_MAP.is_gas), (0x5b, 0, COL_MAP.is_jumpdest), - (0x5c, 2, COL_MAP.is_invalid_9), // 0x5c-0x5f - (0x60, 5, COL_MAP.is_push), // 0x60-0x7f - (0x80, 4, COL_MAP.is_dup), // 0x80-0x8f - (0x90, 4, COL_MAP.is_swap), // 0x90-0x9f + (0x5c, 0, COL_MAP.is_get_state_root), + (0x5d, 0, COL_MAP.is_set_state_root), + (0x5e, 0, COL_MAP.is_get_receipt_root), + (0x5f, 0, COL_MAP.is_set_receipt_root), + (0x60, 5, COL_MAP.is_push), // 0x60-0x7f + (0x80, 4, COL_MAP.is_dup), // 0x80-0x8f + (0x90, 4, COL_MAP.is_swap), // 0x90-0x9f (0xa0, 0, COL_MAP.is_log0), (0xa1, 0, COL_MAP.is_log1), (0xa2, 0, COL_MAP.is_log2), (0xa3, 0, COL_MAP.is_log3), (0xa4, 0, COL_MAP.is_log4), - (0xa5, 0, COL_MAP.is_invalid_10), - (0xa6, 1, COL_MAP.is_invalid_11), // 0xa6-0xa7 - (0xa8, 3, COL_MAP.is_invalid_12), // 0xa8-0xaf - (0xb0, 4, COL_MAP.is_invalid_13), // 0xb0-0xbf - (0xc0, 5, COL_MAP.is_invalid_14), // 0xc0-0xdf - (0xe0, 4, COL_MAP.is_invalid_15), // 0xe0-0xef + (0xa5, 0, COL_MAP.is_panic), + (0xa6, 1, COL_MAP.is_invalid_9), // 0xa6-0xa7 + (0xa8, 3, COL_MAP.is_invalid_10), // 0xa8-0xaf + (0xb0, 4, COL_MAP.is_invalid_11), // 0xb0-0xbf + (0xc0, 5, COL_MAP.is_invalid_12), // 0xc0-0xdf + (0xe0, 4, COL_MAP.is_invalid_13), // 0xe0-0xef (0xf0, 0, COL_MAP.is_create), (0xf1, 0, COL_MAP.is_call), (0xf2, 0, COL_MAP.is_callcode), (0xf3, 0, COL_MAP.is_return), (0xf4, 0, COL_MAP.is_delegatecall), (0xf5, 0, COL_MAP.is_create2), - (0xf6, 1, COL_MAP.is_invalid_16), // 0xf6-0xf7 - (0xf8, 1, COL_MAP.is_invalid_17), // 0xf8-0xf9 + (0xf6, 0, COL_MAP.is_get_context), + (0xf7, 0, COL_MAP.is_set_context), + (0xf8, 0, COL_MAP.is_consume_gas), + (0xf9, 0, COL_MAP.is_exit_kernel), (0xfa, 0, COL_MAP.is_staticcall), - (0xfb, 0, COL_MAP.is_invalid_18), - (0xfc, 0, COL_MAP.is_invalid_19), + (0xfb, 0, COL_MAP.is_mload_general), + (0xfc, 0, COL_MAP.is_mstore_general), (0xfd, 0, COL_MAP.is_revert), - (0xfe, 0, COL_MAP.is_invalid_20), + (0xfe, 0, COL_MAP.is_invalid_14), (0xff, 0, COL_MAP.is_selfdestruct), ]; diff --git a/evm/src/cpu/kernel/asm/memory.asm b/evm/src/cpu/kernel/asm/memory.asm new file mode 100644 index 00000000..c325ed9d --- /dev/null +++ b/evm/src/cpu/kernel/asm/memory.asm @@ -0,0 +1,27 @@ +// Load a byte from the given segment of the current context's memory space. +// Note that main memory values are one byte each, but in general memory values +// can be 256 bits. This macro deals with a single address (unlike MSTORE), so +// if it is used with main memory, it will load a single byte. +%macro mload_current(segment) + // stack: offset + PUSH $segment + // stack: segment, offset + CURRENT_CONTEXT + // stack: context, segment, offset + MLOAD_GENERAL + // stack: value +%endmacro + +// Store a byte to the given segment of the current context's memory space. +// Note that main memory values are one byte each, but in general memory values +// can be 256 bits. This macro deals with a single address (unlike MSTORE), so +// if it is used with main memory, it will store a single byte. +%macro mstore_current(segment) + // stack: offset, value + PUSH $segment + // stack: segment, offset, value + CURRENT_CONTEXT + // stack: context, segment, offset, value + MSTORE_GENERAL + // stack: (empty) +%endmacro diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 09e493b9..d18ef945 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -115,6 +115,10 @@ impl<'a> Interpreter<'a> { 0x59 => todo!(), // "MSIZE", 0x5a => todo!(), // "GAS", 0x5b => (), // "JUMPDEST", + 0x5c => todo!(), // "GET_STATE_ROOT", + 0x5d => todo!(), // "SET_STATE_ROOT", + 0x5e => todo!(), // "GET_RECEIPT_ROOT", + 0x5f => todo!(), // "SET_RECEIPT_ROOT", x if (0x60..0x80).contains(&x) => self.run_push(x - 0x5f), // "PUSH" x if (0x80..0x90).contains(&x) => self.run_dup(x - 0x7f), // "DUP" x if (0x90..0xa0).contains(&x) => self.run_swap(x - 0x8f), // "SWAP" @@ -123,13 +127,20 @@ impl<'a> Interpreter<'a> { 0xa2 => todo!(), // "LOG2", 0xa3 => todo!(), // "LOG3", 0xa4 => todo!(), // "LOG4", + 0xa5 => panic!("Executed PANIC"), // "PANIC", 0xf0 => todo!(), // "CREATE", 0xf1 => todo!(), // "CALL", 0xf2 => todo!(), // "CALLCODE", 0xf3 => todo!(), // "RETURN", 0xf4 => todo!(), // "DELEGATECALL", 0xf5 => todo!(), // "CREATE2", + 0xf6 => todo!(), // "GET_CONTEXT", + 0xf7 => todo!(), // "SET_CONTEXT", + 0xf8 => todo!(), // "CONSUME_GAS", + 0xf9 => todo!(), // "EXIT_KERNEL", 0xfa => todo!(), // "STATICCALL", + 0xfb => todo!(), // "MLOAD_GENERAL", + 0xfc => todo!(), // "MSTORE_GENERAL", 0xfd => todo!(), // "REVERT", 0xfe => todo!(), // "INVALID", 0xff => todo!(), // "SELFDESTRUCT", diff --git a/evm/src/cpu/kernel/opcodes.rs b/evm/src/cpu/kernel/opcodes.rs index b8633178..b9ef7d5e 100644 --- a/evm/src/cpu/kernel/opcodes.rs +++ b/evm/src/cpu/kernel/opcodes.rs @@ -71,6 +71,10 @@ pub(crate) fn get_opcode(mnemonic: &str) -> u8 { "MSIZE" => 0x59, "GAS" => 0x5a, "JUMPDEST" => 0x5b, + "GET_STATE_ROOT" => 0x5c, + "SET_STATE_ROOT" => 0x5d, + "GET_RECEIPT_ROOT" => 0x5e, + "SET_RECEIPT_ROOT" => 0x5f, "DUP1" => 0x80, "DUP2" => 0x81, "DUP3" => 0x82, @@ -108,13 +112,20 @@ pub(crate) fn get_opcode(mnemonic: &str) -> u8 { "LOG2" => 0xa2, "LOG3" => 0xa3, "LOG4" => 0xa4, + "PANIC" => 0xa5, "CREATE" => 0xf0, "CALL" => 0xf1, "CALLCODE" => 0xf2, "RETURN" => 0xf3, "DELEGATECALL" => 0xf4, "CREATE2" => 0xf5, + "GET_CONTEXT" => 0xf6, + "SET_CONTEXT" => 0xf7, + "CONSUME_GAS" => 0xf8, + "EXIT_KERNEL" => 0xf9, "STATICCALL" => 0xfa, + "MLOAD_GENERAL" => 0xfb, + "MSTORE_GENERAL" => 0xfc, "REVERT" => 0xfd, "INVALID" => 0xfe, "SELFDESTRUCT" => 0xff, From 4aaceabd18e039f4c0969b46cba211a011b79458 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sun, 17 Jul 2022 16:08:58 -0700 Subject: [PATCH 4/9] Include assertions, disabled for now --- evm/src/cpu/kernel/aggregator.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 28a9c597..c45f69c6 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -23,6 +23,7 @@ pub fn evm_constants() -> HashMap { #[allow(dead_code)] // TODO: Should be used once witness generation is done. pub(crate) fn combined_kernel() -> Kernel { let files = vec![ + // include_str!("asm/assertions.asm"), // TODO: Should work once PR 619 is merged. include_str!("asm/basic_macros.asm"), include_str!("asm/exp.asm"), include_str!("asm/curve_mul.asm"), From 0b7e3eca67e13dabe45351edb240a560ab8bd100 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 18 Jul 2022 08:58:11 -0700 Subject: [PATCH 5/9] PANIC returns error --- evm/src/cpu/kernel/interpreter.rs | 28 +++++++----- evm/src/cpu/kernel/tests/curve_ops.rs | 62 +++++++++++++-------------- evm/src/cpu/kernel/tests/ecrecover.rs | 4 +- evm/src/cpu/kernel/tests/exp.rs | 12 +++--- 4 files changed, 57 insertions(+), 49 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 33bc4327..a9507fde 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -1,3 +1,4 @@ +use anyhow::bail; use ethereum_types::{U256, U512}; /// Halt interpreter execution whenever a jump to this offset is done. @@ -51,7 +52,11 @@ pub(crate) struct Interpreter<'a> { running: bool, } -pub(crate) fn run(code: &[u8], initial_offset: usize, initial_stack: Vec) -> Interpreter { +pub(crate) fn run( + code: &[u8], + initial_offset: usize, + initial_stack: Vec, +) -> anyhow::Result { let mut interpreter = Interpreter { code, jumpdests: find_jumpdests(code), @@ -65,7 +70,7 @@ pub(crate) fn run(code: &[u8], initial_offset: usize, initial_stack: Vec) interpreter.run_opcode(); } - interpreter + Ok(interpreter) } impl<'a> Interpreter<'a> { @@ -89,7 +94,7 @@ impl<'a> Interpreter<'a> { self.stack.pop().expect("Pop on empty stack.") } - fn run_opcode(&mut self) { + fn run_opcode(&mut self) -> anyhow::Result<()> { let opcode = self.code.get(self.offset).copied().unwrap_or_default(); self.incr(1); match opcode { @@ -168,7 +173,7 @@ impl<'a> Interpreter<'a> { 0xa2 => todo!(), // "LOG2", 0xa3 => todo!(), // "LOG3", 0xa4 => todo!(), // "LOG4", - 0xa5 => panic!("Executed PANIC"), // "PANIC", + 0xa5 => bail!("Executed PANIC"), // "PANIC", 0xf0 => todo!(), // "CREATE", 0xf1 => todo!(), // "CALL", 0xf2 => todo!(), // "CALLCODE", @@ -183,10 +188,11 @@ impl<'a> Interpreter<'a> { 0xfb => todo!(), // "MLOAD_GENERAL", 0xfc => todo!(), // "MSTORE_GENERAL", 0xfd => todo!(), // "REVERT", - 0xfe => todo!(), // "INVALID", + 0xfe => bail!("Executed INVALID"), // "INVALID", 0xff => todo!(), // "SELFDESTRUCT", - _ => panic!("Unrecognized opcode {}.", opcode), + _ => bail!("Unrecognized opcode {}.", opcode), }; + Ok(()) } fn run_stop(&mut self) { @@ -381,15 +387,16 @@ mod tests { use crate::cpu::kernel::interpreter::{run, Interpreter}; #[test] - fn test_run() { + fn test_run() -> anyhow::Result<()> { 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![])?.stack, vec![0x3.into()]); + Ok(()) } #[test] - fn test_run_with_memory() { + fn test_run_with_memory() -> anyhow::Result<()> { // PUSH1 0xff // PUSH1 0 // MSTORE @@ -407,9 +414,10 @@ 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 run = run(&code, 0, vec![])?; let Interpreter { stack, memory, .. } = run; assert_eq!(stack, vec![0xff.into(), 0xff00.into()]); assert_eq!(&memory.memory, &hex!("00000000000000000000000000000000000000000000000000000000000000ff0000000000000042000000000000000000000000000000000000000000000000")); + Ok(()) } } diff --git a/evm/src/cpu/kernel/tests/curve_ops.rs b/evm/src/cpu/kernel/tests/curve_ops.rs index 7d7f042a..6d8c6696 100644 --- a/evm/src/cpu/kernel/tests/curve_ops.rs +++ b/evm/src/cpu/kernel/tests/curve_ops.rs @@ -43,76 +43,76 @@ 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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Multiple calls @@ -126,7 +126,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)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) @@ -176,55 +176,55 @@ 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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.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)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Multiple calls @@ -238,7 +238,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)?.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 5077d042..d6eac6f7 100644 --- a/evm/src/cpu/kernel/tests/ecrecover.rs +++ b/evm/src/cpu/kernel/tests/ecrecover.rs @@ -25,7 +25,7 @@ fn test_valid_ecrecover( ) -> Result<()> { let ecrecover = kernel.global_labels["ecrecover"]; let initial_stack = u256ify([s, r, v, hash])?; - let stack = run(&kernel.code, ecrecover, initial_stack).stack; + let stack = run(&kernel.code, ecrecover, initial_stack)?.stack; let got = pubkey_to_addr(stack[1], stack[0]); assert_eq!(got, hex::decode(&expected[2..]).unwrap()); @@ -35,7 +35,7 @@ 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)?.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 b12b943e..25c88623 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)?.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)?.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)?.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)?.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)?.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)?.stack; assert_eq!(stack_with_kernel, stack_with_opcode); Ok(()) From b29de2c46a78ad3c19244ee5c5506180aae43826 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 18 Jul 2022 09:29:21 -0700 Subject: [PATCH 6/9] tweak --- evm/src/cpu/kernel/asm/memory.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/memory.asm b/evm/src/cpu/kernel/asm/memory.asm index c325ed9d..e3af9954 100644 --- a/evm/src/cpu/kernel/asm/memory.asm +++ b/evm/src/cpu/kernel/asm/memory.asm @@ -1,6 +1,6 @@ // Load a byte from the given segment of the current context's memory space. // Note that main memory values are one byte each, but in general memory values -// can be 256 bits. This macro deals with a single address (unlike MSTORE), so +// can be 256 bits. This macro deals with a single address (unlike MLOAD), so // if it is used with main memory, it will load a single byte. %macro mload_current(segment) // stack: offset From 799d333a903488d30c775f60eb2238c874ab2bc4 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 18 Jul 2022 10:40:02 -0700 Subject: [PATCH 7/9] fix --- evm/src/cpu/kernel/interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index a9507fde..452acd93 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -67,7 +67,7 @@ pub(crate) fn run( }; while interpreter.running { - interpreter.run_opcode(); + interpreter.run_opcode()?; } Ok(interpreter) From 50144a638f7cdd09eddc9851f749c0b5fdf07e5f Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 18 Jul 2022 13:48:51 -0700 Subject: [PATCH 8/9] Enable assertions, now working --- evm/src/cpu/kernel/aggregator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 501edd3e..c6c47387 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -23,7 +23,7 @@ pub fn evm_constants() -> HashMap { #[allow(dead_code)] // TODO: Should be used once witness generation is done. pub(crate) fn combined_kernel() -> Kernel { let files = vec![ - // include_str!("asm/assertions.asm"), // TODO: Should work once PR 619 is merged. + include_str!("asm/assertions.asm"), include_str!("asm/basic_macros.asm"), include_str!("asm/exp.asm"), include_str!("asm/curve_mul.asm"), From 539364c87a597aaa6fe22c0d89d1ba26d11f5e1a Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 18 Jul 2022 21:53:31 -0700 Subject: [PATCH 9/9] clippy --- plonky2/src/gates/gate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plonky2/src/gates/gate.rs b/plonky2/src/gates/gate.rs index 2e6b36ef..781e0cbd 100644 --- a/plonky2/src/gates/gate.rs +++ b/plonky2/src/gates/gate.rs @@ -244,7 +244,7 @@ fn compute_filter(row: usize, group_range: Range, s: K, many_se debug_assert!(group_range.contains(&row)); group_range .filter(|&i| i != row) - .chain(many_selector.then(|| UNUSED_SELECTOR)) + .chain(many_selector.then_some(UNUSED_SELECTOR)) .map(|i| K::from_canonical_usize(i) - s) .product() } @@ -259,7 +259,7 @@ fn compute_filter_circuit, const D: usize>( debug_assert!(group_range.contains(&row)); let v = group_range .filter(|&i| i != row) - .chain(many_selectors.then(|| UNUSED_SELECTOR)) + .chain(many_selectors.then_some(UNUSED_SELECTOR)) .map(|i| { let c = builder.constant_extension(F::Extension::from_canonical_usize(i)); builder.sub_extension(c, s)