From 4c52d3754615214d3992123a0f89100a28795475 Mon Sep 17 00:00:00 2001 From: Jacqueline Nabaglo Date: Tue, 30 Aug 2022 13:06:03 -0700 Subject: [PATCH] Save columns by verifying invalid opcodes in software (#701) * Save columns by verifying invalid opcodes in software * Autogenerate invalid opcode bitfield (Daniel comment) * Remove unnecessary panic label --- evm/src/cpu/columns/mod.rs | 23 +- evm/src/cpu/decode.rs | 300 ++++++++++--------- evm/src/cpu/kernel/aggregator.rs | 1 + evm/src/cpu/kernel/asm/core/invalid.asm | 26 ++ evm/src/cpu/kernel/asm/memory/core.asm | 7 + evm/src/cpu/kernel/asm/util/basic_macros.asm | 14 + evm/src/cpu/kernel/constants.rs | 5 + evm/src/cpu/syscalls.rs | 10 +- 8 files changed, 216 insertions(+), 170 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/core/invalid.asm diff --git a/evm/src/cpu/columns/mod.rs b/evm/src/cpu/columns/mod.rs index 34a02837..ad0f6a95 100644 --- a/evm/src/cpu/columns/mod.rs +++ b/evm/src/cpu/columns/mod.rs @@ -137,28 +137,7 @@ pub struct CpuColumnsView { pub is_revert: T, pub is_selfdestruct: T, - // An instruction is invalid if _any_ of the below flags is 1. - pub is_invalid_0: T, - pub is_invalid_1: T, - pub is_invalid_2: T, - pub is_invalid_3: T, - pub is_invalid_4: T, - pub is_invalid_5: T, - pub is_invalid_6: T, - pub is_invalid_7: T, - pub is_invalid_8: T, - pub is_invalid_9: T, - pub is_invalid_10: T, - pub is_invalid_11: T, - 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, + pub is_invalid: T, /// If CPU cycle: the opcode, broken up into bits in little-endian order. pub opcode_bits: [T; 8], diff --git a/evm/src/cpu/decode.rs b/evm/src/cpu/decode.rs index e58b474d..7ca9a650 100644 --- a/evm/src/cpu/decode.rs +++ b/evm/src/cpu/decode.rs @@ -6,14 +6,6 @@ use plonky2::iop::ext_target::ExtensionTarget; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cpu::columns::{CpuColumnsView, COL_MAP}; -#[derive(PartialEq, Eq)] -enum Availability { - All, - User, - Kernel, -} -use Availability::{All, Kernel, User}; - /// List of opcode blocks /// Each block corresponds to exactly one flag, and each flag corresponds to exactly one block. /// Each block of opcodes: @@ -28,124 +20,132 @@ use Availability::{All, Kernel, User}; /// The exception is the PANIC instruction which is user-only without a corresponding kernel block. /// This makes the proof unverifiable when PANIC is executed in kernel mode, which is the intended /// behavior. -const OPCODES: [(u8, usize, Availability, usize); 113] = [ - // (start index of block, number of top bits to check (log2), availability, flag column) - (0x00, 0, All, COL_MAP.is_stop), - (0x01, 0, All, COL_MAP.is_add), - (0x02, 0, All, COL_MAP.is_mul), - (0x03, 0, All, COL_MAP.is_sub), - (0x04, 0, All, COL_MAP.is_div), - (0x05, 0, All, COL_MAP.is_sdiv), - (0x06, 0, All, COL_MAP.is_mod), - (0x07, 0, All, COL_MAP.is_smod), - (0x08, 0, All, COL_MAP.is_addmod), - (0x09, 0, All, COL_MAP.is_mulmod), - (0x0a, 0, All, COL_MAP.is_exp), - (0x0b, 0, All, COL_MAP.is_signextend), - (0x0c, 2, All, COL_MAP.is_invalid_0), // 0x0c-0x0f - (0x10, 0, All, COL_MAP.is_lt), - (0x11, 0, All, COL_MAP.is_gt), - (0x12, 0, All, COL_MAP.is_slt), - (0x13, 0, All, COL_MAP.is_sgt), - (0x14, 0, All, COL_MAP.is_eq), - (0x15, 0, All, COL_MAP.is_iszero), - (0x16, 0, All, COL_MAP.is_and), - (0x17, 0, All, COL_MAP.is_or), - (0x18, 0, All, COL_MAP.is_xor), - (0x19, 0, All, COL_MAP.is_not), - (0x1a, 0, All, COL_MAP.is_byte), - (0x1b, 0, All, COL_MAP.is_shl), - (0x1c, 0, All, COL_MAP.is_shr), - (0x1d, 0, All, COL_MAP.is_sar), - (0x1e, 1, All, COL_MAP.is_invalid_1), // 0x1e-0x1f - (0x20, 0, All, COL_MAP.is_keccak256), - (0x21, 0, All, COL_MAP.is_invalid_2), - (0x22, 1, All, COL_MAP.is_invalid_3), // 0x22-0x23 - (0x24, 2, All, COL_MAP.is_invalid_4), // 0x24-0x27 - (0x28, 3, All, COL_MAP.is_invalid_5), // 0x28-0x2f - (0x30, 0, All, COL_MAP.is_address), - (0x31, 0, All, COL_MAP.is_balance), - (0x32, 0, All, COL_MAP.is_origin), - (0x33, 0, All, COL_MAP.is_caller), - (0x34, 0, All, COL_MAP.is_callvalue), - (0x35, 0, All, COL_MAP.is_calldataload), - (0x36, 0, All, COL_MAP.is_calldatasize), - (0x37, 0, All, COL_MAP.is_calldatacopy), - (0x38, 0, All, COL_MAP.is_codesize), - (0x39, 0, All, COL_MAP.is_codecopy), - (0x3a, 0, All, COL_MAP.is_gasprice), - (0x3b, 0, All, COL_MAP.is_extcodesize), - (0x3c, 0, All, COL_MAP.is_extcodecopy), - (0x3d, 0, All, COL_MAP.is_returndatasize), - (0x3e, 0, All, COL_MAP.is_returndatacopy), - (0x3f, 0, All, COL_MAP.is_extcodehash), - (0x40, 0, All, COL_MAP.is_blockhash), - (0x41, 0, All, COL_MAP.is_coinbase), - (0x42, 0, All, COL_MAP.is_timestamp), - (0x43, 0, All, COL_MAP.is_number), - (0x44, 0, All, COL_MAP.is_difficulty), - (0x45, 0, All, COL_MAP.is_gaslimit), - (0x46, 0, All, COL_MAP.is_chainid), - (0x47, 0, All, COL_MAP.is_selfbalance), - (0x48, 0, All, COL_MAP.is_basefee), - (0x49, 0, User, COL_MAP.is_invalid_6), - (0x49, 0, Kernel, COL_MAP.is_prover_input), - (0x4a, 1, All, COL_MAP.is_invalid_7), // 0x4a-0x4b - (0x4c, 2, All, COL_MAP.is_invalid_8), // 0x4c-0x4f - (0x50, 0, All, COL_MAP.is_pop), - (0x51, 0, All, COL_MAP.is_mload), - (0x52, 0, All, COL_MAP.is_mstore), - (0x53, 0, All, COL_MAP.is_mstore8), - (0x54, 0, All, COL_MAP.is_sload), - (0x55, 0, All, COL_MAP.is_sstore), - (0x56, 0, All, COL_MAP.is_jump), - (0x57, 0, All, COL_MAP.is_jumpi), - (0x58, 0, All, COL_MAP.is_pc), - (0x59, 0, All, COL_MAP.is_msize), - (0x5a, 0, All, COL_MAP.is_gas), - (0x5b, 0, All, COL_MAP.is_jumpdest), - (0x5c, 2, User, COL_MAP.is_invalid_9), // 0x5c-5f - (0x5c, 0, Kernel, COL_MAP.is_get_state_root), - (0x5d, 0, Kernel, COL_MAP.is_set_state_root), - (0x5e, 0, Kernel, COL_MAP.is_get_receipt_root), - (0x5f, 0, Kernel, COL_MAP.is_set_receipt_root), - (0x60, 5, All, COL_MAP.is_push), // 0x60-0x7f - (0x80, 4, All, COL_MAP.is_dup), // 0x80-0x8f - (0x90, 4, All, COL_MAP.is_swap), // 0x90-0x9f - (0xa0, 0, All, COL_MAP.is_log0), - (0xa1, 0, All, COL_MAP.is_log1), - (0xa2, 0, All, COL_MAP.is_log2), - (0xa3, 0, All, COL_MAP.is_log3), - (0xa4, 0, All, COL_MAP.is_log4), - (0xa5, 0, User, COL_MAP.is_invalid_10), +/// Note: invalid opcodes are not represented here. _Any_ opcode is permitted to decode to +/// `is_invalid`. The kernel then verifies that the opcode was _actually_ invalid. +const OPCODES: [(u8, usize, bool, usize); 92] = [ + // (start index of block, number of top bits to check (log2), kernel-only, flag column) + (0x00, 0, false, COL_MAP.is_stop), + (0x01, 0, false, COL_MAP.is_add), + (0x02, 0, false, COL_MAP.is_mul), + (0x03, 0, false, COL_MAP.is_sub), + (0x04, 0, false, COL_MAP.is_div), + (0x05, 0, false, COL_MAP.is_sdiv), + (0x06, 0, false, COL_MAP.is_mod), + (0x07, 0, false, COL_MAP.is_smod), + (0x08, 0, false, COL_MAP.is_addmod), + (0x09, 0, false, COL_MAP.is_mulmod), + (0x0a, 0, false, COL_MAP.is_exp), + (0x0b, 0, false, COL_MAP.is_signextend), + (0x10, 0, false, COL_MAP.is_lt), + (0x11, 0, false, COL_MAP.is_gt), + (0x12, 0, false, COL_MAP.is_slt), + (0x13, 0, false, COL_MAP.is_sgt), + (0x14, 0, false, COL_MAP.is_eq), + (0x15, 0, false, COL_MAP.is_iszero), + (0x16, 0, false, COL_MAP.is_and), + (0x17, 0, false, COL_MAP.is_or), + (0x18, 0, false, COL_MAP.is_xor), + (0x19, 0, false, COL_MAP.is_not), + (0x1a, 0, false, COL_MAP.is_byte), + (0x1b, 0, false, COL_MAP.is_shl), + (0x1c, 0, false, COL_MAP.is_shr), + (0x1d, 0, false, COL_MAP.is_sar), + (0x20, 0, false, COL_MAP.is_keccak256), + (0x30, 0, false, COL_MAP.is_address), + (0x31, 0, false, COL_MAP.is_balance), + (0x32, 0, false, COL_MAP.is_origin), + (0x33, 0, false, COL_MAP.is_caller), + (0x34, 0, false, COL_MAP.is_callvalue), + (0x35, 0, false, COL_MAP.is_calldataload), + (0x36, 0, false, COL_MAP.is_calldatasize), + (0x37, 0, false, COL_MAP.is_calldatacopy), + (0x38, 0, false, COL_MAP.is_codesize), + (0x39, 0, false, COL_MAP.is_codecopy), + (0x3a, 0, false, COL_MAP.is_gasprice), + (0x3b, 0, false, COL_MAP.is_extcodesize), + (0x3c, 0, false, COL_MAP.is_extcodecopy), + (0x3d, 0, false, COL_MAP.is_returndatasize), + (0x3e, 0, false, COL_MAP.is_returndatacopy), + (0x3f, 0, false, COL_MAP.is_extcodehash), + (0x40, 0, false, COL_MAP.is_blockhash), + (0x41, 0, false, COL_MAP.is_coinbase), + (0x42, 0, false, COL_MAP.is_timestamp), + (0x43, 0, false, COL_MAP.is_number), + (0x44, 0, false, COL_MAP.is_difficulty), + (0x45, 0, false, COL_MAP.is_gaslimit), + (0x46, 0, false, COL_MAP.is_chainid), + (0x47, 0, false, COL_MAP.is_selfbalance), + (0x48, 0, false, COL_MAP.is_basefee), + (0x49, 0, true, COL_MAP.is_prover_input), + (0x50, 0, false, COL_MAP.is_pop), + (0x51, 0, false, COL_MAP.is_mload), + (0x52, 0, false, COL_MAP.is_mstore), + (0x53, 0, false, COL_MAP.is_mstore8), + (0x54, 0, false, COL_MAP.is_sload), + (0x55, 0, false, COL_MAP.is_sstore), + (0x56, 0, false, COL_MAP.is_jump), + (0x57, 0, false, COL_MAP.is_jumpi), + (0x58, 0, false, COL_MAP.is_pc), + (0x59, 0, false, COL_MAP.is_msize), + (0x5a, 0, false, COL_MAP.is_gas), + (0x5b, 0, false, COL_MAP.is_jumpdest), + (0x5c, 0, true, COL_MAP.is_get_state_root), + (0x5d, 0, true, COL_MAP.is_set_state_root), + (0x5e, 0, true, COL_MAP.is_get_receipt_root), + (0x5f, 0, true, COL_MAP.is_set_receipt_root), + (0x60, 5, false, COL_MAP.is_push), // 0x60-0x7f + (0x80, 4, false, COL_MAP.is_dup), // 0x80-0x8f + (0x90, 4, false, COL_MAP.is_swap), // 0x90-0x9f + (0xa0, 0, false, COL_MAP.is_log0), + (0xa1, 0, false, COL_MAP.is_log1), + (0xa2, 0, false, COL_MAP.is_log2), + (0xa3, 0, false, COL_MAP.is_log3), + (0xa4, 0, false, COL_MAP.is_log4), // Opcode 0xa5 is PANIC when Kernel. Make the proof unverifiable by giving it no flag to decode to. - (0xa6, 1, All, COL_MAP.is_invalid_11), // 0xa6-0xa7 - (0xa8, 3, All, COL_MAP.is_invalid_12), // 0xa8-0xaf - (0xb0, 4, All, COL_MAP.is_invalid_13), // 0xb0-0xbf - (0xc0, 5, All, COL_MAP.is_invalid_14), // 0xc0-0xdf - (0xe0, 4, All, COL_MAP.is_invalid_15), // 0xe0-0xef - (0xf0, 0, All, COL_MAP.is_create), - (0xf1, 0, All, COL_MAP.is_call), - (0xf2, 0, All, COL_MAP.is_callcode), - (0xf3, 0, All, COL_MAP.is_return), - (0xf4, 0, All, COL_MAP.is_delegatecall), - (0xf5, 0, All, COL_MAP.is_create2), - (0xf6, 1, User, COL_MAP.is_invalid_16), // 0xf6-0xf7 - (0xf6, 0, Kernel, COL_MAP.is_get_context), - (0xf7, 0, Kernel, COL_MAP.is_set_context), - (0xf8, 1, User, COL_MAP.is_invalid_17), // 0xf8-0xf9 - (0xf8, 0, Kernel, COL_MAP.is_consume_gas), - (0xf9, 0, Kernel, COL_MAP.is_exit_kernel), - (0xfa, 0, All, COL_MAP.is_staticcall), - (0xfb, 0, User, COL_MAP.is_invalid_18), - (0xfb, 0, Kernel, COL_MAP.is_mload_general), - (0xfc, 0, User, COL_MAP.is_invalid_19), - (0xfc, 0, Kernel, COL_MAP.is_mstore_general), - (0xfd, 0, All, COL_MAP.is_revert), - (0xfe, 0, All, COL_MAP.is_invalid_20), - (0xff, 0, All, COL_MAP.is_selfdestruct), + (0xf0, 0, false, COL_MAP.is_create), + (0xf1, 0, false, COL_MAP.is_call), + (0xf2, 0, false, COL_MAP.is_callcode), + (0xf3, 0, false, COL_MAP.is_return), + (0xf4, 0, false, COL_MAP.is_delegatecall), + (0xf5, 0, false, COL_MAP.is_create2), + (0xf6, 0, true, COL_MAP.is_get_context), + (0xf7, 0, true, COL_MAP.is_set_context), + (0xf8, 0, true, COL_MAP.is_consume_gas), + (0xf9, 0, true, COL_MAP.is_exit_kernel), + (0xfa, 0, false, COL_MAP.is_staticcall), + (0xfb, 0, true, COL_MAP.is_mload_general), + (0xfc, 0, true, COL_MAP.is_mstore_general), + (0xfd, 0, false, COL_MAP.is_revert), + (0xff, 0, false, COL_MAP.is_selfdestruct), ]; +/// Bitfield of invalid opcodes, in little-endian order. +pub(crate) const fn invalid_opcodes_user() -> [u8; 32] { + let mut res = [u8::MAX; 32]; // Start with all opcodes marked invalid. + + let mut i = 0; + while i < OPCODES.len() { + let (block_start, lb_block_len, kernel_only, _) = OPCODES[i]; + i += 1; + + if kernel_only { + continue; + } + + let block_len = 1 << lb_block_len; + let block_start = block_start as usize; + let block_end = block_start + block_len; + let mut j = block_start; + while j < block_end { + let byte = j / u8::BITS as usize; + let bit = j % u8::BITS as usize; + res[byte] &= !(1 << bit); // Mark opcode as invalid by zeroing the bit. + j += 1; + } + } + res +} + pub fn generate(lv: &mut CpuColumnsView) { let cycle_filter = lv.is_cpu_cycle; if cycle_filter == F::ZERO { @@ -184,15 +184,19 @@ pub fn generate(lv: &mut CpuColumnsView) { assert!(kernel <= 1); let kernel = kernel != 0; - for (oc, block_length, availability, col) in OPCODES { - let available = match availability { - All => true, - User => !kernel, - Kernel => kernel, - }; + let mut any_flag_set = false; + for (oc, block_length, kernel_only, col) in OPCODES { + let available = !kernel_only || kernel; let opcode_match = top_bits[8 - block_length] == oc; - lv[col] = F::from_bool(available && opcode_match); + let flag = available && opcode_match; + lv[col] = F::from_bool(flag); + if flag && any_flag_set { + panic!("opcode matched multiple flags"); + } + any_flag_set = any_flag_set || flag; } + // is_invalid is a catch-all for opcodes we can't decode. + lv.is_invalid = F::from_bool(!any_flag_set); } /// Break up an opcode (which is 8 bits long) into its eight bits. @@ -230,21 +234,22 @@ pub fn eval_packed_generic( let flag = lv[flag_col]; yield_constr.constraint(cycle_filter * flag * (flag - P::ONES)); } + yield_constr.constraint(cycle_filter * lv.is_invalid * (lv.is_invalid - P::ONES)); // Now check that exactly one is 1. let flag_sum: P = OPCODES .into_iter() .map(|(_, _, _, flag_col)| lv[flag_col]) - .sum(); + .sum::

() + + lv.is_invalid; yield_constr.constraint(cycle_filter * (P::ONES - flag_sum)); // Finally, classify all opcodes, together with the kernel flag, into blocks - for (oc, block_length, availability, col) in OPCODES { - // 0 if the block/flag is available to us (is always available, is user-only and we are in - // user mode, or kernel-only and we are in kernel mode) and 1 otherwise. - let unavailable = match availability { - All => P::ZEROS, - User => kernel_mode, - Kernel => P::ONES - kernel_mode, + for (oc, block_length, kernel_only, col) in OPCODES { + // 0 if the block/flag is available to us (is always available or we are in kernel mode) and + // 1 otherwise. + let unavailable = match kernel_only { + false => P::ZEROS, + true => P::ONES - kernel_mode, }; // 0 if all the opcode bits match, and something in {1, ..., 8}, otherwise. let opcode_mismatch: P = lv @@ -299,6 +304,11 @@ pub fn eval_ext_circuit, const D: usize>( let constr = builder.mul_extension(cycle_filter, constr); yield_constr.constraint(builder, constr); } + { + let constr = builder.mul_sub_extension(lv.is_invalid, lv.is_invalid, lv.is_invalid); + let constr = builder.mul_extension(cycle_filter, constr); + yield_constr.constraint(builder, constr); + } // Now check that exactly one is 1. { let mut constr = builder.one_extension(); @@ -306,18 +316,18 @@ pub fn eval_ext_circuit, const D: usize>( let flag = lv[flag_col]; constr = builder.sub_extension(constr, flag); } + constr = builder.sub_extension(constr, lv.is_invalid); constr = builder.mul_extension(cycle_filter, constr); yield_constr.constraint(builder, constr); } // Finally, classify all opcodes, together with the kernel flag, into blocks - for (oc, block_length, availability, col) in OPCODES { - // 0 if the block/flag is available to us (is always available, is user-only and we are in - // user mode, or kernel-only and we are in kernel mode) and 1 otherwise. - let unavailable = match availability { - All => builder.zero_extension(), - User => kernel_mode, - Kernel => builder.sub_extension(one, kernel_mode), + for (oc, block_length, kernel_only, col) in OPCODES { + // 0 if the block/flag is available to us (is always available or we are in kernel mode) and + // 1 otherwise. + let unavailable = match kernel_only { + false => builder.zero_extension(), + true => builder.sub_extension(one, kernel_mode), }; // 0 if all the opcode bits match, and something in {1, ..., 8}, otherwise. let opcode_mismatch = lv diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index eb55238b..dda006e6 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -15,6 +15,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/core/create.asm"), include_str!("asm/core/create_addresses.asm"), include_str!("asm/core/intrinsic_gas.asm"), + include_str!("asm/core/invalid.asm"), include_str!("asm/core/nonce.asm"), include_str!("asm/core/process_txn.asm"), include_str!("asm/core/terminate.asm"), diff --git a/evm/src/cpu/kernel/asm/core/invalid.asm b/evm/src/cpu/kernel/asm/core/invalid.asm new file mode 100644 index 00000000..6a7f4c17 --- /dev/null +++ b/evm/src/cpu/kernel/asm/core/invalid.asm @@ -0,0 +1,26 @@ +global handle_invalid: + // stack: trap_info + + // if the kernel is trying to execute an invalid instruction, then we've already screwed up and + // there's no chance of getting a useful proof, so we just panic + DUP1 + // stack: trap_info, trap_info + %shr_const(32) + // stack: is_kernel, trap_info + %jumpi(panic) + + // check if the opcode that triggered this trap is _actually_ invalid + // stack: program_counter (is_kernel == 0, so trap_info == program_counter) + %mload_current_code + // stack: opcode + PUSH @INVALID_OPCODES_USER + // stack: invalid_opcodes_user, opcode + SWAP1 + // stack: opcode, invalid_opcodes_user + SHR + %and_const(1) + // stack: opcode_is_invalid + // if the opcode is indeed invalid, then perform an exceptional exit + %jumpi(fault_exception) + // otherwise, panic because this trap should not have been entered + PANIC diff --git a/evm/src/cpu/kernel/asm/memory/core.asm b/evm/src/cpu/kernel/asm/memory/core.asm index 2c896345..73bafbee 100644 --- a/evm/src/cpu/kernel/asm/memory/core.asm +++ b/evm/src/cpu/kernel/asm/memory/core.asm @@ -26,6 +26,13 @@ // stack: (empty) %endmacro +// Load a single byte from user code. +%macro mload_current_code + // stack: offset + %mload_current(@SEGMENT_CODE) + // stack: value +%endmacro + // Load a single value from the given segment of kernel (context 0) memory. %macro mload_kernel(segment) // stack: offset diff --git a/evm/src/cpu/kernel/asm/util/basic_macros.asm b/evm/src/cpu/kernel/asm/util/basic_macros.asm index e8dd9eb8..13965e39 100644 --- a/evm/src/cpu/kernel/asm/util/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/util/basic_macros.asm @@ -44,6 +44,13 @@ %endrep %endmacro +%macro and_const(c) + // stack: input, ... + PUSH $c + AND + // stack: input & c, ... +%endmacro + %macro add_const(c) // stack: input, ... PUSH $c @@ -101,6 +108,13 @@ // stack: input << c, ... %endmacro +%macro shr_const(c) + // stack: input, ... + PUSH $c + SHR + // stack: input >> c, ... +%endmacro + %macro eq_const(c) // stack: input, ... PUSH $c diff --git a/evm/src/cpu/kernel/constants.rs b/evm/src/cpu/kernel/constants.rs index 5bc5908e..98fe57c6 100644 --- a/evm/src/cpu/kernel/constants.rs +++ b/evm/src/cpu/kernel/constants.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use ethereum_types::U256; use hex_literal::hex; +use crate::cpu::decode::invalid_opcodes_user; use crate::cpu::kernel::context_metadata::ContextMetadata; use crate::cpu::kernel::global_metadata::GlobalMetadata; use crate::cpu::kernel::txn_fields::NormalizedTxnField; @@ -29,6 +30,10 @@ pub fn evm_constants() -> HashMap { for txn_field in ContextMetadata::all() { c.insert(txn_field.var_name().into(), (txn_field as u32).into()); } + c.insert( + "INVALID_OPCODES_USER".into(), + U256::from_little_endian(&invalid_opcodes_user()), + ); c } diff --git a/evm/src/cpu/syscalls.rs b/evm/src/cpu/syscalls.rs index 116713ae..b0b63be8 100644 --- a/evm/src/cpu/syscalls.rs +++ b/evm/src/cpu/syscalls.rs @@ -13,12 +13,16 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer use crate::cpu::columns::{CpuColumnsView, COL_MAP}; use crate::cpu::kernel::aggregator::KERNEL; -const NUM_SYSCALLS: usize = 2; +const NUM_SYSCALLS: usize = 3; fn make_syscall_list() -> [(usize, usize); NUM_SYSCALLS] { let kernel = Lazy::force(&KERNEL); - [(COL_MAP.is_stop, "sys_stop"), (COL_MAP.is_exp, "sys_exp")] - .map(|(col_index, handler_name)| (col_index, kernel.global_labels[handler_name])) + [ + (COL_MAP.is_stop, "sys_stop"), + (COL_MAP.is_exp, "sys_exp"), + (COL_MAP.is_invalid, "handle_invalid"), + ] + .map(|(col_index, handler_name)| (col_index, kernel.global_labels[handler_name])) } static TRAP_LIST: Lazy<[(usize, usize); NUM_SYSCALLS]> = Lazy::new(make_syscall_list);