From 18d317b9cf2f859206e4b3ca939ed799e7aef294 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Wed, 5 Apr 2023 06:35:52 -0400 Subject: [PATCH 01/16] Implement sdiv in interpreter. --- evm/src/cpu/kernel/interpreter.rs | 108 +++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 3f699260..49ff2222 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -1,5 +1,6 @@ //! An EVM interpreter for testing and debugging purposes. +use core::cmp::Ordering; use std::collections::HashMap; use std::ops::Range; @@ -305,7 +306,7 @@ impl<'a> Interpreter<'a> { 0x02 => self.run_mul(), // "MUL", 0x03 => self.run_sub(), // "SUB", 0x04 => self.run_div(), // "DIV", - 0x05 => todo!(), // "SDIV", + 0x05 => self.run_sdiv(), // "SDIV", 0x06 => self.run_mod(), // "MOD", 0x07 => todo!(), // "SMOD", 0x08 => self.run_addmod(), // "ADDMOD", @@ -467,6 +468,41 @@ impl<'a> Interpreter<'a> { self.push(if y.is_zero() { U256::zero() } else { x / y }); } + fn run_sdiv(&mut self) { + let mut x = self.pop(); + let mut y = self.pop(); + + let y_is_zero = y.is_zero(); + + if y_is_zero { + self.push(U256::zero()); + } else if y.eq(&MINUS_ONE) && x.eq(&MIN_VALUE) { + self.push(MIN_VALUE); + } else { + let x_is_pos = x.eq(&(x & SIGN_MASK)); + let y_is_pos = y.eq(&(y & SIGN_MASK)); + + // We compute the absolute quotient first, + // then adapt its sign based on the operands. + if !x_is_pos { + x = two_complement(x); + } + if !y_is_pos { + y = two_complement(y); + } + let div = x / y; + if div.eq(&U256::zero()) { + self.push(U256::zero()); + } + + self.push(if x_is_pos == y_is_pos { + div + } else { + two_complement(div) + }); + } + } + fn run_mod(&mut self) { let x = self.pop(); let y = self.pop(); @@ -837,6 +873,76 @@ impl<'a> Interpreter<'a> { } } +// Computes the two's complement of the given integer. +fn two_complement(x: U256) -> U256 { + let flipped_bits = x ^ MINUS_ONE; + flipped_bits.overflowing_add(U256::one()).0 +} + +fn signed_cmp(x: U256, y: U256) -> Ordering { + let x_is_zero = x.is_zero(); + let y_is_zero = y.is_zero(); + + if x_is_zero && y_is_zero { + return Ordering::Equal; + } + + let x_is_pos = x.eq(&(x & SIGN_MASK)); + let y_is_pos = y.eq(&(y & SIGN_MASK)); + + if x_is_zero { + if y_is_pos { + return Ordering::Less; + } else { + return Ordering::Greater; + } + }; + + if y_is_zero { + if x_is_pos { + return Ordering::Greater; + } else { + return Ordering::Less; + } + }; + + match (x_is_pos, y_is_pos) { + (true, true) => x.cmp(&y), + (true, false) => Ordering::Greater, + (false, true) => Ordering::Less, + (false, false) => x.cmp(&y).reverse(), + } +} + +const MINUS_ZERO: U256 = U256([ + 0x0000000000000001, + 0x0000000000000000, + 0x0000000000000000, + 0x8000000000000000, +]); + +const MINUS_ONE: U256 = U256([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, +]); + +/// -2^255 in two's complement representation consists in the MSB set to 1. +const MIN_VALUE: U256 = U256([ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x8000000000000000, +]); + +const SIGN_MASK: U256 = U256([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0x7fffffffffffffff, +]); + /// Return the (ordered) JUMPDEST offsets in the code. fn find_jumpdests(code: &[u8]) -> Vec { let mut offset = 0; From 232832e34dccf6d2781307244cf6e620a766fd39 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Thu, 6 Apr 2023 16:46:10 -0400 Subject: [PATCH 02/16] Implement smod in interpreter --- evm/src/cpu/kernel/interpreter.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 49ff2222..ede6aece 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -308,7 +308,7 @@ impl<'a> Interpreter<'a> { 0x04 => self.run_div(), // "DIV", 0x05 => self.run_sdiv(), // "SDIV", 0x06 => self.run_mod(), // "MOD", - 0x07 => todo!(), // "SMOD", + 0x07 => self.run_smod(), // "SMOD", 0x08 => self.run_addmod(), // "ADDMOD", 0x09 => self.run_mulmod(), // "MULMOD", 0x0a => self.run_exp(), // "EXP", @@ -509,6 +509,34 @@ impl<'a> Interpreter<'a> { self.push(if y.is_zero() { U256::zero() } else { x % y }); } + fn run_smod(&mut self) { + let mut x = self.pop(); + let mut y = self.pop(); + + if y.is_zero() { + self.push(U256::zero()); + } else { + let x_is_pos = x.eq(&(x & SIGN_MASK)); + let y_is_pos = y.eq(&(y & SIGN_MASK)); + + // We compute the absolute remainder first, + // then adapt its sign based on the operands. + if !x_is_pos { + x = two_complement(x); + } + if !y_is_pos { + y = two_complement(y); + } + let rem = x % y; + if rem.eq(&U256::zero()) { + self.push(U256::zero()); + } + + // Remainder always has the same sign as the dividend. + self.push(if x_is_pos { rem } else { two_complement(rem) }); + } + } + fn run_addmod(&mut self) { let x = U512::from(self.pop()); let y = U512::from(self.pop()); From ac2ccc1eb9f821bccc5222d8eafe8fbe6cc8a8b2 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Thu, 6 Apr 2023 16:58:21 -0400 Subject: [PATCH 03/16] Implement slt in interpreter --- evm/src/cpu/kernel/interpreter.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index ede6aece..64d2d0b8 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -318,7 +318,7 @@ impl<'a> Interpreter<'a> { 0x0e => self.run_subfp254(), // "SUBFP254", 0x10 => self.run_lt(), // "LT", 0x11 => self.run_gt(), // "GT", - 0x12 => todo!(), // "SLT", + 0x12 => self.run_slt(), // "SLT", 0x13 => todo!(), // "SGT", 0x14 => self.run_eq(), // "EQ", 0x15 => self.run_iszero(), // "ISZERO", @@ -577,6 +577,12 @@ impl<'a> Interpreter<'a> { self.push_bool(x > y); } + fn run_slt(&mut self) { + let x = self.pop(); + let y = self.pop(); + self.push_bool(signed_cmp(x, y) == Ordering::Less); + } + fn run_eq(&mut self) { let x = self.pop(); let y = self.pop(); @@ -942,13 +948,7 @@ fn signed_cmp(x: U256, y: U256) -> Ordering { } } -const MINUS_ZERO: U256 = U256([ - 0x0000000000000001, - 0x0000000000000000, - 0x0000000000000000, - 0x8000000000000000, -]); - +/// -1 in two's complement representation consists in all bits set to 1. const MINUS_ONE: U256 = U256([ 0xffffffffffffffff, 0xffffffffffffffff, From 4db004417cfc1417f6984633347929aa7f6407a4 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Thu, 6 Apr 2023 16:59:19 -0400 Subject: [PATCH 04/16] Implement sgt in interpreter --- evm/src/cpu/kernel/interpreter.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 64d2d0b8..108ed133 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -319,7 +319,7 @@ impl<'a> Interpreter<'a> { 0x10 => self.run_lt(), // "LT", 0x11 => self.run_gt(), // "GT", 0x12 => self.run_slt(), // "SLT", - 0x13 => todo!(), // "SGT", + 0x13 => self.run_sgt(), // "SGT", 0x14 => self.run_eq(), // "EQ", 0x15 => self.run_iszero(), // "ISZERO", 0x16 => self.run_and(), // "AND", @@ -583,6 +583,12 @@ impl<'a> Interpreter<'a> { self.push_bool(signed_cmp(x, y) == Ordering::Less); } + fn run_sgt(&mut self) { + let x = self.pop(); + let y = self.pop(); + self.push_bool(signed_cmp(x, y) == Ordering::Greater); + } + fn run_eq(&mut self) { let x = self.pop(); let y = self.pop(); From b943ddb0d20e7fba50f101fbae22d97573bee9ab Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Thu, 6 Apr 2023 17:11:44 -0400 Subject: [PATCH 05/16] Implement signextend in interpreter --- evm/src/cpu/kernel/interpreter.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 108ed133..1506ba1e 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -312,7 +312,7 @@ impl<'a> Interpreter<'a> { 0x08 => self.run_addmod(), // "ADDMOD", 0x09 => self.run_mulmod(), // "MULMOD", 0x0a => self.run_exp(), // "EXP", - 0x0b => todo!(), // "SIGNEXTEND", + 0x0b => self.run_signextend(), // "SIGNEXTEND", 0x0c => self.run_addfp254(), // "ADDFP254", 0x0d => self.run_mulfp254(), // "MULFP254", 0x0e => self.run_subfp254(), // "SUBFP254", @@ -589,6 +589,31 @@ impl<'a> Interpreter<'a> { self.push_bool(signed_cmp(x, y) == Ordering::Greater); } + fn run_signextend(&mut self) { + let n = self.pop(); + let x = self.pop(); + if n > U256::from(31) { + self.push(x); + } else { + let n = n.low_u64() as usize; + let num_bytes_prepend = 31 - n; + + let mut x_bytes = [0u8; 32]; + x.to_big_endian(&mut x_bytes); + let mut x_bytes = x_bytes[num_bytes_prepend..].to_vec(); + let sign_bit = x_bytes[0] >> 7; + + self.push(if sign_bit == 0 { + x_bytes.extend_from_slice(&vec![0; num_bytes_prepend]); + U256::from_big_endian(&x_bytes) + } else { + let mut tmp = vec![0xff; num_bytes_prepend]; + tmp.extend_from_slice(&x_bytes); + U256::from_big_endian(&tmp) + }); + } + } + fn run_eq(&mut self) { let x = self.pop(); let y = self.pop(); From 3da8efa6ba59681d5696f2eb21cc26c9d45dfbe7 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Thu, 6 Apr 2023 17:21:18 -0400 Subject: [PATCH 06/16] Implement sar in interpreter --- evm/src/cpu/kernel/interpreter.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 1506ba1e..5dd346ec 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -329,7 +329,7 @@ impl<'a> Interpreter<'a> { 0x1a => self.run_byte(), // "BYTE", 0x1b => self.run_shl(), // "SHL", 0x1c => self.run_shr(), // "SHR", - 0x1d => todo!(), // "SAR", + 0x1d => self.run_sar(), // "SAR", 0x20 => self.run_keccak256(), // "KECCAK256", 0x21 => self.run_keccak_general(), // "KECCAK_GENERAL", 0x30 => todo!(), // "ADDRESS", @@ -675,6 +675,30 @@ impl<'a> Interpreter<'a> { self.push(value >> shift); } + fn run_sar(&mut self) { + let shift = self.pop(); + let value = self.pop(); + let value_is_neg = !value.eq(&(value & SIGN_MASK)); + + if shift < U256::from(256usize) { + let shift = shift.low_u64() as usize; + let mask = !(MINUS_ONE >> shift); + let value_shifted = value >> shift; + + if value_is_neg { + self.push(value_shifted | mask); + } else { + self.push(value_shifted); + }; + } else { + self.push(if value_is_neg { + MINUS_ONE + } else { + U256::zero() + }); + } + } + fn run_keccak256(&mut self) { let offset = self.pop().as_usize(); let size = self.pop().as_usize(); From 5b1fd5f2af3779133acf3daaf2ff73f60d94a6ec Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 11 Apr 2023 08:41:45 +0200 Subject: [PATCH 07/16] CALL gas (#969) * (Non)ZeroValue_CALL pass * Memory expansion costs (callcall_00 pass) * Cleaning * Minor * PR feedback --- evm/src/cpu/kernel/asm/core/call.asm | 104 ++++++++++++++++++++++++--- evm/src/cpu/kernel/asm/core/util.asm | 2 +- 2 files changed, 94 insertions(+), 12 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/call.asm b/evm/src/cpu/kernel/asm/core/call.asm index 2777b8a8..e181246a 100644 --- a/evm/src/cpu/kernel/asm/core/call.asm +++ b/evm/src/cpu/kernel/asm/core/call.asm @@ -3,15 +3,22 @@ // Creates a new sub context and executes the code of the given account. global sys_call: // stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size - // TODO: Charge gas. SWAP2 // stack: address, gas, kexit_info, value, args_offset, args_size, ret_offset, ret_size %u256_to_addr // Truncate to 160 bits - DUP1 %insert_accessed_addresses POP // TODO: Use return value in gas calculation. - SWAP2 - // stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size + DUP1 %insert_accessed_addresses + + %call_charge_gas + + %stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (args_size, args_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %checked_mem_expansion + %stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (ret_size, ret_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %checked_mem_expansion + %create_context - // stack: new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size + // stack: new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size // TODO: Consider call depth // Each line in the block below does not change the stack. @@ -20,15 +27,15 @@ global sys_call: DUP5 %set_new_ctx_value DUP5 DUP5 %address %transfer_eth %jumpi(panic) // TODO: Fix this panic. %set_new_ctx_parent_pc(after_call_instruction) - DUP3 %set_new_ctx_gas_limit // TODO: This is not correct in most cases. Use C_callgas as in the YP. + DUP3 %set_new_ctx_gas_limit DUP4 %set_new_ctx_code - %stack (new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) -> - (new_ctx, args_offset, args_size, new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) + %stack (new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (new_ctx, args_offset, args_size, new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) %copy_mem_to_calldata - // stack: new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size - %stack (new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) + // stack: new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size + %stack (new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> (new_ctx, kexit_info, ret_offset, ret_size) %enter_new_ctx @@ -117,7 +124,7 @@ global after_call_instruction: SWAP3 // stack: kexit_info, leftover_gas, new_ctx, success, ret_offset, ret_size // Add the leftover gas into the appropriate bits of kexit_info. - SWAP1 %shl_const(192) ADD + SWAP1 %shl_const(192) SWAP1 SUB // stack: kexit_info, new_ctx, success, ret_offset, ret_size // The callee's terminal instruction will have populated RETURNDATA. @@ -250,3 +257,78 @@ global after_call_instruction: %jump(memcpy) %%after: %endmacro + +// Charge gas for *call opcodes and return the sub-context gas limit. +// Doesn't include memory expansion costs. +%macro call_charge_gas + // Compute C_aaccess + // stack: cold_access, address, gas, kexit_info, value, args_offset, args_size, ret_offset, ret_size + %mul_const(@GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS) + %add_const(@GAS_WARMACCESS) + + // Compute C_xfer + // stack: Caaccess, address, gas, kexit_info, value + DUP5 ISZERO PUSH 1 SUB + // stack: value≠0, Caaccess, address, gas, kexit_info, value + DUP1 + %mul_const(@GAS_CALLVALUE) + + // Compute C_new + // stack: Cxfer, value≠0, Caaccess, address, gas, kexit_info, value + SWAP1 + // stack: value≠0, Cxfer, Caaccess, address, gas, kexit_info, value + DUP4 %is_dead MUL + // stack: is_dead(address) and value≠0, Cxfer, Caaccess, address, gas, kexit_info, value + %mul_const(@GAS_NEWACCOUNT) + // stack: Cnew, Cxfer, Caaccess, address, gas, kexit_info, value + + // Compute C_extra + ADD ADD + + // Compute C_gascap + // stack: Cextra, address, gas, kexit_info, value + DUP4 %leftover_gas + // stack: leftover_gas, Cextra, address, gas, kexit_info, value + DUP2 DUP2 LT + // stack: leftover_gas=Cextra, (leftover_gas=Cextra, (leftover_gas=Cextra, (leftover_gas (Cextra, Cgascap, Cgascap) + ADD + %stack (C_call, Cgascap, address, gas, kexit_info, value) -> + (C_call, kexit_info, Cgascap, address, gas, value) + %charge_gas + + // Compute C_callgas + %stack (kexit_info, Cgascap, address, gas, value) -> + (Cgascap, address, gas, kexit_info, value) + DUP5 ISZERO PUSH 1 SUB + // stack: value!=0, Cgascap, address, gas, kexit_info, value + %mul_const(@GAS_CALLSTIPEND) ADD + %stack (C_callgas, address, gas, kexit_info, value) -> + (kexit_info, C_callgas, address, value) +%endmacro + +// Checked memory expansion. +%macro checked_mem_expansion + // stack: size, offset, kexit_info + DUP1 ISZERO %jumpi(%%zero) + ADD // TODO: check for overflow + // stack: expanded_num_bytes, kexit_info + DUP1 %ensure_reasonable_offset + %update_mem_bytes + %jump(%%after) +%%zero: + %pop2 +%%after: +%endmacro diff --git a/evm/src/cpu/kernel/asm/core/util.asm b/evm/src/cpu/kernel/asm/core/util.asm index de3dfb70..a8e41a7b 100644 --- a/evm/src/cpu/kernel/asm/core/util.asm +++ b/evm/src/cpu/kernel/asm/core/util.asm @@ -66,4 +66,4 @@ DUP1 %is_non_existent SWAP1 %is_empty ADD // OR -%endmacro \ No newline at end of file +%endmacro From 011ea8e49bc0ce6015bb230c093ebe7ca887385b Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 11 Apr 2023 07:41:33 -0400 Subject: [PATCH 08/16] Fix from review --- evm/src/cpu/kernel/interpreter.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 5dd346ec..fa3788cf 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -600,17 +600,17 @@ impl<'a> Interpreter<'a> { let mut x_bytes = [0u8; 32]; x.to_big_endian(&mut x_bytes); - let mut x_bytes = x_bytes[num_bytes_prepend..].to_vec(); + let x_bytes = x_bytes[num_bytes_prepend..].to_vec(); let sign_bit = x_bytes[0] >> 7; - self.push(if sign_bit == 0 { - x_bytes.extend_from_slice(&vec![0; num_bytes_prepend]); - U256::from_big_endian(&x_bytes) + let mut bytes = if sign_bit == 0 { + vec![0; num_bytes_prepend] } else { - let mut tmp = vec![0xff; num_bytes_prepend]; - tmp.extend_from_slice(&x_bytes); - U256::from_big_endian(&tmp) - }); + vec![0xff; num_bytes_prepend] + }; + bytes.extend_from_slice(&x_bytes); + + self.push(U256::from_big_endian(&bytes)); } } From 18d27d2f55714a6b9c1a7508524c02fc22f24b6f Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 11 Apr 2023 08:05:50 -0400 Subject: [PATCH 09/16] Remove is_final_block column in KeccakSpongeStark --- evm/src/keccak_sponge/columns.rs | 4 -- evm/src/keccak_sponge/keccak_sponge_stark.rs | 53 +++++++++----------- 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/evm/src/keccak_sponge/columns.rs b/evm/src/keccak_sponge/columns.rs index 440c59ab..d15e0e4b 100644 --- a/evm/src/keccak_sponge/columns.rs +++ b/evm/src/keccak_sponge/columns.rs @@ -17,10 +17,6 @@ pub(crate) struct KeccakSpongeColumnsView { /// not a padding byte; 0 otherwise. pub is_full_input_block: T, - /// 1 if this row represents the final block of a sponge, in which case some or all of the bytes - /// in the block will be padding bytes; 0 otherwise. - pub is_final_block: T, - // The base address at which we will read the input block. pub context: T, pub segment: T, diff --git a/evm/src/keccak_sponge/keccak_sponge_stark.rs b/evm/src/keccak_sponge/keccak_sponge_stark.rs index 6c8f7f0d..c43d8949 100644 --- a/evm/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm/src/keccak_sponge/keccak_sponge_stark.rs @@ -128,7 +128,7 @@ pub(crate) fn ctl_looking_logic(i: usize) -> Vec> { pub(crate) fn ctl_looked_filter() -> Column { // The CPU table is only interested in our final-block rows, since those contain the final // sponge output. - Column::single(KECCAK_SPONGE_COL_MAP.is_final_block) + Column::sum(KECCAK_SPONGE_COL_MAP.is_final_input_len) } /// CTL filter for reading the `i`th byte of input from memory. @@ -143,12 +143,12 @@ pub(crate) fn ctl_looking_memory_filter(i: usize) -> Column { /// CTL filter for looking at XORs in the logic table. pub(crate) fn ctl_looking_logic_filter() -> Column { let cols = KECCAK_SPONGE_COL_MAP; - Column::sum([cols.is_full_input_block, cols.is_final_block]) + Column::sum(once(&cols.is_full_input_block).chain(&cols.is_final_input_len)) } pub(crate) fn ctl_looking_keccak_filter() -> Column { let cols = KECCAK_SPONGE_COL_MAP; - Column::sum([cols.is_full_input_block, cols.is_final_block]) + Column::sum(once(&cols.is_full_input_block).chain(&cols.is_final_input_len)) } /// Information about a Keccak sponge operation needed for witness generation. @@ -269,10 +269,7 @@ impl, const D: usize> KeccakSpongeStark { ) -> KeccakSpongeColumnsView { assert_eq!(already_absorbed_bytes + final_inputs.len(), op.input.len()); - let mut row = KeccakSpongeColumnsView { - is_final_block: F::ONE, - ..Default::default() - }; + let mut row = KeccakSpongeColumnsView::default(); for (block_byte, input_byte) in row.block_bytes.iter_mut().zip(final_inputs) { *block_byte = F::from_canonical_u8(*input_byte); @@ -372,7 +369,7 @@ impl, const D: usize> Stark for KeccakSpongeS let is_full_input_block = local_values.is_full_input_block; yield_constr.constraint(is_full_input_block * (is_full_input_block - P::ONES)); - let is_final_block = local_values.is_final_block; + let is_final_block: P = local_values.is_final_input_len.iter().copied().sum(); yield_constr.constraint(is_final_block * (is_final_block - P::ONES)); for &is_final_len in local_values.is_final_input_len.iter() { @@ -382,12 +379,8 @@ impl, const D: usize> Stark for KeccakSpongeS // Ensure that full-input block and final block flags are not set to 1 at the same time. yield_constr.constraint(is_final_block * is_full_input_block); - // Sum of is_final_input_len should equal is_final_block (which will be 0 or 1). - let is_final_input_len_sum: P = local_values.is_final_input_len.iter().copied().sum(); - yield_constr.constraint(is_final_input_len_sum - is_final_block); - // If this is a full-input block, is_final_input_len should contain all 0s. - yield_constr.constraint(is_full_input_block * is_final_input_len_sum); + yield_constr.constraint(is_full_input_block * is_final_block); // If this is the first row, the original sponge state should be 0 and already_absorbed_bytes = 0. let already_absorbed_bytes = local_values.already_absorbed_bytes; @@ -447,8 +440,9 @@ impl, const D: usize> Stark for KeccakSpongeS // A dummy row is always followed by another dummy row, so the prover can't put dummy rows "in between" to avoid the above checks. let is_dummy = P::ONES - is_full_input_block - is_final_block; + let next_is_final_block: P = next_values.is_final_input_len.iter().copied().sum(); yield_constr.constraint_transition( - is_dummy * (next_values.is_full_input_block + next_values.is_final_block), + is_dummy * (next_values.is_full_input_block + next_is_final_block), ); // If this is a final block, is_final_input_len implies `len - already_absorbed == i`. @@ -479,7 +473,13 @@ impl, const D: usize> Stark for KeccakSpongeS ); yield_constr.constraint(builder, constraint); - let is_final_block = local_values.is_final_block; + let mut is_final_block = builder.add_extension( + local_values.is_final_input_len[0], + local_values.is_final_input_len[1], + ); + for &input_len in local_values.is_final_input_len.iter().skip(2) { + is_final_block = builder.add_extension(is_final_block, input_len); + } let constraint = builder.mul_sub_extension(is_final_block, is_final_block, is_final_block); yield_constr.constraint(builder, constraint); @@ -492,19 +492,8 @@ impl, const D: usize> Stark for KeccakSpongeS let constraint = builder.mul_extension(is_final_block, is_full_input_block); yield_constr.constraint(builder, constraint); - // Sum of is_final_input_len should equal is_final_block (which will be 0 or 1). - let mut is_final_input_len_sum = builder.add_extension( - local_values.is_final_input_len[0], - local_values.is_final_input_len[1], - ); - for &input_len in local_values.is_final_input_len.iter().skip(2) { - is_final_input_len_sum = builder.add_extension(is_final_input_len_sum, input_len); - } - let constraint = builder.sub_extension(is_final_input_len_sum, is_final_block); - yield_constr.constraint(builder, constraint); - // If this is a full-input block, is_final_input_len should contain all 0s. - let constraint = builder.mul_extension(is_full_input_block, is_final_input_len_sum); + let constraint = builder.mul_extension(is_full_input_block, is_final_block); yield_constr.constraint(builder, constraint); // If this is the first row, the original sponge state should be 0 and already_absorbed_bytes = 0. @@ -580,9 +569,15 @@ impl, const D: usize> Stark for KeccakSpongeS let tmp = builder.sub_extension(one, is_final_block); builder.sub_extension(tmp, is_full_input_block) }; + let mut next_is_final_block = builder.add_extension( + next_values.is_final_input_len[0], + next_values.is_final_input_len[1], + ); + for &input_len in next_values.is_final_input_len.iter().skip(2) { + next_is_final_block = builder.add_extension(next_is_final_block, input_len); + } let constraint = { - let tmp = - builder.add_extension(next_values.is_final_block, next_values.is_full_input_block); + let tmp = builder.add_extension(next_is_final_block, next_values.is_full_input_block); builder.mul_extension(is_dummy, tmp) }; yield_constr.constraint_transition(builder, constraint); From 29726f92578ef628fbe553ba70d0aab86d317a87 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 11 Apr 2023 17:34:31 -0400 Subject: [PATCH 10/16] Apply review --- evm/src/keccak_sponge/keccak_sponge_stark.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/evm/src/keccak_sponge/keccak_sponge_stark.rs b/evm/src/keccak_sponge/keccak_sponge_stark.rs index c43d8949..1401dcaf 100644 --- a/evm/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm/src/keccak_sponge/keccak_sponge_stark.rs @@ -473,13 +473,7 @@ impl, const D: usize> Stark for KeccakSpongeS ); yield_constr.constraint(builder, constraint); - let mut is_final_block = builder.add_extension( - local_values.is_final_input_len[0], - local_values.is_final_input_len[1], - ); - for &input_len in local_values.is_final_input_len.iter().skip(2) { - is_final_block = builder.add_extension(is_final_block, input_len); - } + let is_final_block = builder.add_many_extension(local_values.is_final_input_len); let constraint = builder.mul_sub_extension(is_final_block, is_final_block, is_final_block); yield_constr.constraint(builder, constraint); @@ -569,13 +563,7 @@ impl, const D: usize> Stark for KeccakSpongeS let tmp = builder.sub_extension(one, is_final_block); builder.sub_extension(tmp, is_full_input_block) }; - let mut next_is_final_block = builder.add_extension( - next_values.is_final_input_len[0], - next_values.is_final_input_len[1], - ); - for &input_len in next_values.is_final_input_len.iter().skip(2) { - next_is_final_block = builder.add_extension(next_is_final_block, input_len); - } + let next_is_final_block = builder.add_many_extension(next_values.is_final_input_len); let constraint = { let tmp = builder.add_extension(next_is_final_block, next_values.is_full_input_block); builder.mul_extension(is_dummy, tmp) From 1e57ef96cb97ee2234cae6daaaa459350eee8915 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 11 Apr 2023 17:46:48 -0400 Subject: [PATCH 11/16] Remove unnecessary constraint --- evm/src/keccak_sponge/keccak_sponge_stark.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/evm/src/keccak_sponge/keccak_sponge_stark.rs b/evm/src/keccak_sponge/keccak_sponge_stark.rs index 1401dcaf..4c91d6fd 100644 --- a/evm/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm/src/keccak_sponge/keccak_sponge_stark.rs @@ -379,9 +379,6 @@ impl, const D: usize> Stark for KeccakSpongeS // Ensure that full-input block and final block flags are not set to 1 at the same time. yield_constr.constraint(is_final_block * is_full_input_block); - // If this is a full-input block, is_final_input_len should contain all 0s. - yield_constr.constraint(is_full_input_block * is_final_block); - // If this is the first row, the original sponge state should be 0 and already_absorbed_bytes = 0. let already_absorbed_bytes = local_values.already_absorbed_bytes; yield_constr.constraint_first_row(already_absorbed_bytes); @@ -486,10 +483,6 @@ impl, const D: usize> Stark for KeccakSpongeS let constraint = builder.mul_extension(is_final_block, is_full_input_block); yield_constr.constraint(builder, constraint); - // If this is a full-input block, is_final_input_len should contain all 0s. - let constraint = builder.mul_extension(is_full_input_block, is_final_block); - yield_constr.constraint(builder, constraint); - // If this is the first row, the original sponge state should be 0 and already_absorbed_bytes = 0. let already_absorbed_bytes = local_values.already_absorbed_bytes; yield_constr.constraint_first_row(builder, already_absorbed_bytes); From 142be4e11444322acb35898e4c206f296af6eb6e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 12 Apr 2023 08:04:39 +0200 Subject: [PATCH 12/16] Implement rest of *CALL opcodes (#972) * Implement rest of *CALL opcodes * Use set_new_ctx_code_size macro --- evm/src/cpu/kernel/asm/core/call.asm | 91 ++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/call.asm b/evm/src/cpu/kernel/asm/core/call.asm index e181246a..acb10f11 100644 --- a/evm/src/cpu/kernel/asm/core/call.asm +++ b/evm/src/cpu/kernel/asm/core/call.asm @@ -43,25 +43,38 @@ global sys_call: // given account. In particular the storage remains the same. global sys_callcode: // stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size - // TODO: Charge gas. SWAP2 // stack: address, gas, kexit_info, value, args_offset, args_size, ret_offset, ret_size %u256_to_addr // Truncate to 160 bits - DUP1 %insert_accessed_addresses POP // TODO: Use return value in gas calculation. - SWAP2 - // stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size + DUP1 %insert_accessed_addresses + + %call_charge_gas + + %stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (args_size, args_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %checked_mem_expansion + %stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (ret_size, ret_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %checked_mem_expansion + + // stack: kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size %create_context - // stack: new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size + // stack: new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size // Each line in the block below does not change the stack. %address %set_new_ctx_addr %address %set_new_ctx_caller DUP5 %set_new_ctx_value - DUP5 DUP5 %address %transfer_eth %jumpi(panic) // TODO: Fix this panic. %set_new_ctx_parent_pc(after_call_instruction) + DUP3 %set_new_ctx_gas_limit + DUP4 %set_new_ctx_code - // stack: new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size - %stack (new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) + %stack (new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (new_ctx, args_offset, args_size, new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %copy_mem_to_calldata + + // stack: new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size + %stack (new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> (new_ctx, kexit_info, ret_offset, ret_size) %enter_new_ctx @@ -72,15 +85,25 @@ global sys_callcode: // CALL if the value sent is not 0. global sys_staticcall: // stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size - // TODO: Charge gas. SWAP2 // stack: address, gas, kexit_info, args_offset, args_size, ret_offset, ret_size %u256_to_addr // Truncate to 160 bits - DUP1 %insert_accessed_addresses POP // TODO: Use return value in gas calculation. - SWAP2 - // stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size + DUP1 %insert_accessed_addresses + + // Add a value of 0 to the stack. Slightly inefficient but that way we can reuse %call_charge_gas. + %stack (cold_access, address, gas, kexit_info) -> (cold_access, address, gas, kexit_info, 0) + %call_charge_gas + + %stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (args_size, args_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %checked_mem_expansion + %stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (ret_size, ret_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %checked_mem_expansion + + // stack: kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size %create_context - // stack: new_ctx, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size + // stack: new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size // Each line in the block below does not change the stack. %set_static_true @@ -88,8 +111,14 @@ global sys_staticcall: %address %set_new_ctx_caller PUSH 0 %set_new_ctx_value %set_new_ctx_parent_pc(after_call_instruction) + DUP3 %set_new_ctx_gas_limit + DUP4 %set_new_ctx_code - %stack (new_ctx, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size) + %stack (new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (new_ctx, args_offset, args_size, new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %copy_mem_to_calldata + + %stack (new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> (new_ctx, kexit_info, ret_offset, ret_size) %enter_new_ctx @@ -98,23 +127,39 @@ global sys_staticcall: // value remain the same. global sys_delegatecall: // stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size - // TODO: Charge gas. SWAP2 // stack: address, gas, kexit_info, args_offset, args_size, ret_offset, ret_size %u256_to_addr // Truncate to 160 bits - DUP1 %insert_accessed_addresses POP // TODO: Use return value in gas calculation. - SWAP2 - // stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size + DUP1 %insert_accessed_addresses + + // Add a value of 0 to the stack. Slightly inefficient but that way we can reuse %call_charge_gas. + %stack (cold_access, address, gas, kexit_info) -> (cold_access, address, gas, kexit_info, 0) + %call_charge_gas + + %stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (args_size, args_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %checked_mem_expansion + %stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (ret_size, ret_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %checked_mem_expansion + + // stack: kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size %create_context - // stack: new_ctx, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size + // stack: new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size // Each line in the block below does not change the stack. %address %set_new_ctx_addr %caller %set_new_ctx_caller %callvalue %set_new_ctx_value %set_new_ctx_parent_pc(after_call_instruction) + DUP3 %set_new_ctx_gas_limit + DUP4 %set_new_ctx_code - %stack (new_ctx, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size) + %stack (new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) -> + (new_ctx, args_offset, args_size, new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) + %copy_mem_to_calldata + + %stack (new_ctx, kexit_info, callgas, address, args_offset, args_size, ret_offset, ret_size) -> (new_ctx, kexit_info, ret_offset, ret_size) %enter_new_ctx @@ -210,9 +255,7 @@ global after_call_instruction: %stack (address, new_ctx) -> (address, new_ctx, @SEGMENT_CODE, %%after, new_ctx) %jump(load_code) %%after: - %stack (code_size, new_ctx) - -> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CODE_SIZE, code_size, new_ctx) - MSTORE_GENERAL + %set_new_ctx_code_size // stack: new_ctx %endmacro @@ -262,7 +305,7 @@ global after_call_instruction: // Doesn't include memory expansion costs. %macro call_charge_gas // Compute C_aaccess - // stack: cold_access, address, gas, kexit_info, value, args_offset, args_size, ret_offset, ret_size + // stack: cold_access, address, gas, kexit_info, value %mul_const(@GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS) %add_const(@GAS_WARMACCESS) From c7e60073f01fc8c4e7781aac737f278788d14860 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 12 Apr 2023 08:24:33 +0200 Subject: [PATCH 13/16] Check if context is static for state-changing opcodes (#973) * Check if context is static for state-changing opcodes * PR feedback --- evm/src/cpu/kernel/asm/core/call.asm | 14 +++++++++++--- evm/src/cpu/kernel/asm/core/create.asm | 2 ++ evm/src/cpu/kernel/asm/core/syscall_stubs.asm | 5 +++++ evm/src/cpu/kernel/asm/core/terminate.asm | 1 + evm/src/cpu/kernel/asm/memory/metadata.asm | 7 +++++++ .../cpu/kernel/asm/mpt/storage/storage_write.asm | 1 + evm/src/cpu/kernel/asm/util/basic_macros.asm | 6 ++---- 7 files changed, 29 insertions(+), 7 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/call.asm b/evm/src/cpu/kernel/asm/core/call.asm index acb10f11..dcebb231 100644 --- a/evm/src/cpu/kernel/asm/core/call.asm +++ b/evm/src/cpu/kernel/asm/core/call.asm @@ -2,7 +2,15 @@ // Creates a new sub context and executes the code of the given account. global sys_call: + // Check that the value is zero if the context is static. // stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size + DUP4 ISZERO %not_bit + // stack: value≠0, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size + %mload_context_metadata(@CTX_METADATA_STATIC) + // stack: is_static, value≠0, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size + MUL // Cheaper than AND + %jumpi(fault_exception) + SWAP2 // stack: address, gas, kexit_info, value, args_offset, args_size, ret_offset, ret_size %u256_to_addr // Truncate to 160 bits @@ -311,7 +319,7 @@ global after_call_instruction: // Compute C_xfer // stack: Caaccess, address, gas, kexit_info, value - DUP5 ISZERO PUSH 1 SUB + DUP5 ISZERO %not_bit // stack: value≠0, Caaccess, address, gas, kexit_info, value DUP1 %mul_const(@GAS_CALLVALUE) @@ -336,7 +344,7 @@ global after_call_instruction: // stack: leftover_gas=Cextra, (leftover_gas=Cextra, (leftover_gas (Cgascap, address, gas, kexit_info, value) - DUP5 ISZERO PUSH 1 SUB + DUP5 ISZERO %not_bit // stack: value!=0, Cgascap, address, gas, kexit_info, value %mul_const(@GAS_CALLSTIPEND) ADD %stack (C_callgas, address, gas, kexit_info, value) -> diff --git a/evm/src/cpu/kernel/asm/core/create.asm b/evm/src/cpu/kernel/asm/core/create.asm index 3cc457d9..866e482c 100644 --- a/evm/src/cpu/kernel/asm/core/create.asm +++ b/evm/src/cpu/kernel/asm/core/create.asm @@ -4,6 +4,7 @@ // Pre stack: kexit_info, value, code_offset, code_len // Post stack: address global sys_create: + %check_static // stack: kexit_info, value, code_offset, code_len // TODO: Charge gas. %stack (kexit_info, value, code_offset, code_len) @@ -25,6 +26,7 @@ sys_create_got_address: // Pre stack: kexit_info, value, code_offset, code_len, salt // Post stack: address global sys_create2: + %check_static // stack: kexit_info, value, code_offset, code_len, salt // TODO: Charge gas. SWAP4 diff --git a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm index 95b50b0b..42dc73ad 100644 --- a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm +++ b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm @@ -16,12 +16,17 @@ global sys_chainid: SWAP1 EXIT_KERNEL global sys_log0: + %check_static PANIC global sys_log1: + %check_static PANIC global sys_log2: + %check_static PANIC global sys_log3: + %check_static PANIC global sys_log4: + %check_static PANIC diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index 5d9ed853..a46bbf0f 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -45,6 +45,7 @@ sys_return_finish: %jump(terminate_common) global sys_selfdestruct: + %check_static // stack: kexit_info, recipient SWAP1 %u256_to_addr %address DUP1 %balance diff --git a/evm/src/cpu/kernel/asm/memory/metadata.asm b/evm/src/cpu/kernel/asm/memory/metadata.asm index 4941f8d6..8f8e9881 100644 --- a/evm/src/cpu/kernel/asm/memory/metadata.asm +++ b/evm/src/cpu/kernel/asm/memory/metadata.asm @@ -283,3 +283,10 @@ global sys_basefee: %jumpi(fault_exception) // stack: (empty) %endmacro + +// Convenience macro for checking if the current context is static. +// Called before state-changing opcodes. +%macro check_static + %mload_context_metadata(@CTX_METADATA_STATIC) + %jumpi(fault_exception) +%endmacro diff --git a/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm index 90fb0e0b..6da8f567 100644 --- a/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm +++ b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm @@ -4,6 +4,7 @@ // Post stack: (empty) global sys_sstore: + %check_static %stack (kexit_info, slot, value) -> (slot, kexit_info, slot, value) %address %insert_accessed_storage_keys POP // TODO: Use return value in gas calculation. // TODO: Assuming a cold zero -> nonzero write for now. diff --git a/evm/src/cpu/kernel/asm/util/basic_macros.asm b/evm/src/cpu/kernel/asm/util/basic_macros.asm index c57f0649..279d449a 100644 --- a/evm/src/cpu/kernel/asm/util/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/util/basic_macros.asm @@ -360,8 +360,6 @@ %macro not_bit // stack: b - PUSH 1 - // stack: 1, b - SUB - // stack: 1 - b + ISZERO + // stack: not b %endmacro From 475b2ba0cbdd84952f6d3c75102c1cd6574daa9c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 12 Apr 2023 16:41:36 +0200 Subject: [PATCH 14/16] Fix copy_returndata_to_mem (#976) --- evm/src/cpu/kernel/asm/core/call.asm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/call.asm b/evm/src/cpu/kernel/asm/core/call.asm index dcebb231..51827d3d 100644 --- a/evm/src/cpu/kernel/asm/core/call.asm +++ b/evm/src/cpu/kernel/asm/core/call.asm @@ -297,12 +297,16 @@ global after_call_instruction: %macro copy_returndata_to_mem // stack: kexit_info, new_ctx, success, ret_offset, ret_size + SWAP4 + %returndatasize + // stack: returndata_size, ret_size, new_ctx, success, ret_offset, kexit_info + %min GET_CONTEXT - %stack (ctx, kexit_info, new_ctx, success, ret_offset, ret_size) -> + %stack (ctx, n, new_ctx, success, ret_offset, kexit_info) -> ( ctx, @SEGMENT_MAIN_MEMORY, ret_offset, // DST ctx, @SEGMENT_RETURNDATA, 0, // SRC - ret_size, %%after, // count, retdest + n, %%after, // count, retdest kexit_info, success ) %jump(memcpy) From ba844a24033f9b655c395ccbc938f3a7cf45b644 Mon Sep 17 00:00:00 2001 From: 4l0n50 Date: Wed, 12 Apr 2023 17:35:32 +0200 Subject: [PATCH 15/16] Change shl/shr behavior as well as BASIC_TERNARY_OP --- evm/src/cpu/cpu_stark.rs | 4 ++-- evm/src/cpu/stack.rs | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/evm/src/cpu/cpu_stark.rs b/evm/src/cpu/cpu_stark.rs index 09c7d576..74e8fbd7 100644 --- a/evm/src/cpu/cpu_stark.rs +++ b/evm/src/cpu/cpu_stark.rs @@ -156,7 +156,7 @@ impl, const D: usize> Stark for CpuStark, const D: usize> Stark for CpuStark = Some(StackBehavior { disable_other_channels: true, }); const BASIC_TERNARY_OP: Option = Some(StackBehavior { - num_pops: 2, + num_pops: 3, pushes: true, disable_other_channels: true, }); @@ -60,8 +60,16 @@ const STACK_BEHAVIORS: OpsColumnsView> = OpsColumnsView { xor: BASIC_BINARY_OP, not: BASIC_UNARY_OP, byte: BASIC_BINARY_OP, - shl: BASIC_BINARY_OP, - shr: BASIC_BINARY_OP, + shl: Some(StackBehavior { + num_pops: 2, + pushes: true, + disable_other_channels: false, + }), + shr: Some(StackBehavior { + num_pops: 2, + pushes: true, + disable_other_channels: false, + }), keccak_general: None, // TODO prover_input: None, // TODO pop: None, // TODO From 92d94dc60d3d854285fac9ea8101fc3cc9bf813b Mon Sep 17 00:00:00 2001 From: Hamy Ratoanina Date: Wed, 12 Apr 2023 11:40:40 -0400 Subject: [PATCH 16/16] Use Block chain id for sys_chainid --- evm/src/cpu/kernel/asm/core/syscall_stubs.asm | 9 --------- evm/src/cpu/kernel/asm/memory/metadata.asm | 13 +++++++++++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm index 95b50b0b..4cb3a6d0 100644 --- a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm +++ b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm @@ -6,15 +6,6 @@ global sys_blockhash: global sys_prevrandao: // TODO: What semantics will this have for Edge? PANIC -global sys_chainid: - // TODO: Return the block's chain ID instead of the txn's, even though they should match. - // stack: kexit_info - %charge_gas_const(@GAS_BASE) - // stack: kexit_info - %mload_txn_field(@TXN_FIELD_CHAIN_ID) - // stack: chain_id, kexit_info - SWAP1 - EXIT_KERNEL global sys_log0: PANIC global sys_log1: diff --git a/evm/src/cpu/kernel/asm/memory/metadata.asm b/evm/src/cpu/kernel/asm/memory/metadata.asm index 4941f8d6..a297ac40 100644 --- a/evm/src/cpu/kernel/asm/memory/metadata.asm +++ b/evm/src/cpu/kernel/asm/memory/metadata.asm @@ -200,6 +200,19 @@ global sys_gaslimit: SWAP1 EXIT_KERNEL +%macro blockchainid + %mload_global_metadata(@GLOBAL_METADATA_BLOCK_CHAIN_ID) +%endmacro + +global sys_chainid: + // stack: kexit_info + %charge_gas_const(@GAS_BASE) + // stack: kexit_info + %blockchainid + // stack: chain_id, kexit_info + SWAP1 + EXIT_KERNEL + %macro basefee %mload_global_metadata(@GLOBAL_METADATA_BLOCK_BASE_FEE) %endmacro