diff --git a/evm/spec/cpulogic.tex b/evm/spec/cpulogic.tex index df866daf1a..318e2db487 100644 --- a/evm/spec/cpulogic.tex +++ b/evm/spec/cpulogic.tex @@ -75,15 +75,14 @@ \subsection{Privileged instructions} \item[0x0F.] \texttt{SUBMOD}. Pops 3 elements from the stack, and pushes the modular difference of the first two elements of the stack by the third one. It is similar to the SUB instruction, with an extra pop for the custom modulus. - \item[0x21.] \texttt{KECCAK\_GENERAL}. Pops 4 elements (successively the context, segment, and offset portions of a Memory address, followed by a length $\ell$) - and pushes the hash of the memory portion starting at the constructed address and of length $\ell$. It is similar to KECCAK256 (0x20) instruction, but can be applied to - any memory section (i.e. even privileged ones). + \item[0x21.] \texttt{KECCAK\_GENERAL}. Pops 2 elements (a Memory address, followed by a length $\ell$) and pushes the hash of the memory portion starting at the + constructed address and of length $\ell$. It is similar to KECCAK256 (0x20) instruction, but can be applied to any memory section (i.e. even privileged ones). \item[0x49.] \texttt{PROVER\_INPUT}. Pushes a single prover input onto the stack. - \item[0xC0-0xDF.] \texttt{MSTORE\_32BYTES}. Pops 4 elements from the stack (successively the context, segment, and offset portions of a Memory address, and then a value), and pushes - a new offset' onto the stack. The value is being decomposed into bytes and written to memory, starting from the reconstructed address. The new offset being pushed is computed as the - initial address offset + the length of the byte sequence being written to memory. Note that similarly to PUSH (0x60-0x7F) instructions there are 31 MSTORE\_32BYTES instructions, each + \item[0xC0-0xDF.] \texttt{MSTORE\_32BYTES}. Pops 2 elements from the stack (a Memory address, and then a value), and pushes + a new address' onto the stack. The value is being decomposed into bytes and written to memory, starting from the fetched address. The new address being pushed is computed as the + initial address + the length of the byte sequence being written to memory. Note that similarly to PUSH (0x60-0x7F) instructions, there are 32 MSTORE\_32BYTES instructions, each corresponding to a target byte length (length 0 is ignored, for the same reasons as MLOAD\_32BYTES, see below). Writing to memory an integer fitting in $n$ bytes with a length $\ell < n$ will result in the integer being truncated. On the other hand, specifying a length $\ell$ greater than the byte size of the value being written will result in padding with zeroes. This process is heavily used when resetting memory sections (by calling MSTORE\_32BYTES\_32 with the value 0). @@ -93,29 +92,49 @@ \subsection{Privileged instructions} \item[0xF7.] \texttt{SET\_CONTEXT}. Pops the top element of the stack and updates the current context to this value. It is usually used when calling another contract or precompile, to distinguish the caller from the callee. - \item[0xF8.] \texttt{MLOAD\_32BYTES}. Pops 4 elements from the stack (successively the context, segment, and offset portions of a Memory address, and then a length $\ell$), and pushes - a value onto the stack. The pushed value corresponds to the U256 integer read from the big-endian sequence of length $\ell$ from the memory address being reconstructed. Note that an + \item[0xF8.] \texttt{MLOAD\_32BYTES}. Pops 2 elements from the stack (a Memory address, and then a length $\ell$), and pushes + a value onto the stack. The pushed value corresponds to the U256 integer read from the big-endian sequence of length $\ell$ from the memory address being fetched. Note that an empty length is not valid, nor is a length greater than 32 (as a U256 consists in at most 32 bytes). Missing these conditions will result in an unverifiable proof. \item[0xF9.] \texttt{EXIT\_KERNEL}. Pops 1 element from the stack. This instruction is used at the end of a syscall, before proceeding to the rest of the execution logic. The popped element, \textit{kexit\_info}, contains several pieces of information like the current program counter, the current amount of gas used, and whether we are in kernel (i.e. privileged) mode or not. - \item[0xFB.] \texttt{MLOAD\_GENERAL}. Pops 3 elements (successively the context, segment, and offset portions of a Memory address), and pushes the value stored at this memory + \item[0xFB.] \texttt{MLOAD\_GENERAL}. Pops 1 elements (a Memory address), and pushes the value stored at this memory address onto the stack. It can read any memory location, general (similarly to MLOAD (0x51) instruction) or privileged. - \item[0xFC.] \texttt{MSTORE\_GENERAL}. Pops 4 elements (successively a value, then the context, segment, and offset portions of a Memory address), and writes the popped value from - the stack at the reconstructed address. It can write to any memory location, general (similarly to MSTORE (0x52) / MSTORE8 (0x53) instructions) or privileged. - + \item[0xFC.] \texttt{MSTORE\_GENERAL}. Pops 2 elements (a value and a Memory address), and writes the popped value from + the stack at the fetched address. It can write to any memory location, general (similarly to MSTORE (0x52) / MSTORE8 (0x53) instructions) or privileged. \end{enumerate} +\subsection{Memory addresses} +\label{memoryaddresses} + +Kernel operations deal with memory addresses as single U256 elements. +However, when processing the operations to generate the proof witness, the CPU will decompose these into three components: + +\begin{itemize} + \item[context.] The context of the memory address. The Kernel context is special, and has value 0. + + \item[segment.] The segment of the memory address, corresponding to a specific section given a context (eg. MPT data, global metadata, etc.). + + \item[virtual.] The offset of the memory address, within a segment given a context. +\end{itemize} + +To easily retrieve these components, we scale them so that they can represent a memory address as: + +$$ \mathrm{addr} = 2^{64} \cdot \mathrm{context} + 2^{32} \cdot \mathrm{segment} + \mathrm{offset}$$ + +This allows to easily retrieve each component individually once a Memory address has been decomposed into 32-bit limbs. + + \subsection{Stack handling} \label{stackhandling} \subsubsection{Top of the stack} The majority of memory operations involve the stack. The stack is a segment in memory, and stack operations (popping or pushing) use the memory channels. -Every CPU instruction performs between 0 and 4 pops, and may push at most once. However, for efficiency purposes, we hold the top of the stack in +Every CPU instruction performs between 0 and 3 pops, and may push at most once. However, for efficiency purposes, we hold the top of the stack in the first memory channel \texttt{current\_row.mem\_channels[0]}, only writing it in memory if necessary. \paragraph*{Motivation:} diff --git a/evm/spec/zkevm.pdf b/evm/spec/zkevm.pdf index 4f4f0a00b0..97217d5d80 100644 Binary files a/evm/spec/zkevm.pdf and b/evm/spec/zkevm.pdf differ diff --git a/evm/src/cpu/byte_unpacking.rs b/evm/src/cpu/byte_unpacking.rs index 14518bfad9..39053141d6 100644 --- a/evm/src/cpu/byte_unpacking.rs +++ b/evm/src/cpu/byte_unpacking.rs @@ -16,8 +16,13 @@ pub(crate) fn eval_packed( // The MSTORE_32BYTES opcodes are differentiated from MLOAD_32BYTES // by the 5th bit set to 0. let filter = lv.op.m_op_32bytes * (lv.opcode_bits[5] - P::ONES); - let new_offset = nv.mem_channels[0].value; - let virt = lv.mem_channels[2].value[0]; + + // The address to write to is stored in the first memory channel. + // It contains virt, segment, ctx in its first 3 limbs, and 0 otherwise. + // The new address is identical, except for its `virtual` limb that is increased by the corresponding `len` offset. + let new_addr = nv.mem_channels[0].value; + let written_addr = lv.mem_channels[0].value; + // Read len from opcode bits and constrain the pushed new offset. let len_bits: P = lv.opcode_bits[..5] .iter() @@ -25,8 +30,16 @@ pub(crate) fn eval_packed( .map(|(i, &bit)| bit * P::Scalar::from_canonical_u64(1 << i)) .sum(); let len = len_bits + P::ONES; - yield_constr.constraint(filter * (new_offset[0] - virt - len)); - for &limb in &new_offset[1..] { + + // Check that `virt` is increased properly. + yield_constr.constraint(filter * (new_addr[0] - written_addr[0] - len)); + + // Check that `segment` and `ctx` do not change. + yield_constr.constraint(filter * (new_addr[1] - written_addr[1])); + yield_constr.constraint(filter * (new_addr[2] - written_addr[2])); + + // Check that the rest of the returned address is null. + for &limb in &new_addr[3..] { yield_constr.constraint(filter * limb); } } @@ -41,8 +54,13 @@ pub(crate) fn eval_ext_circuit, const D: usize>( // by the 5th bit set to 0. let filter = builder.mul_sub_extension(lv.op.m_op_32bytes, lv.opcode_bits[5], lv.op.m_op_32bytes); - let new_offset = nv.mem_channels[0].value; - let virt = lv.mem_channels[2].value[0]; + + // The address to write to is stored in the first memory channel. + // It contains virt, segment, ctx in its first 3 limbs, and 0 otherwise. + // The new address is identical, except for its `virtual` limb that is increased by the corresponding `len` offset. + let new_addr = nv.mem_channels[0].value; + let written_addr = lv.mem_channels[0].value; + // Read len from opcode bits and constrain the pushed new offset. let len_bits = lv.opcode_bits[..5].iter().enumerate().fold( builder.zero_extension(), @@ -50,11 +68,26 @@ pub(crate) fn eval_ext_circuit, const D: usize>( builder.mul_const_add_extension(F::from_canonical_u64(1 << i), bit, cumul) }, ); - let diff = builder.sub_extension(new_offset[0], virt); + + // Check that `virt` is increased properly. + let diff = builder.sub_extension(new_addr[0], written_addr[0]); let diff = builder.sub_extension(diff, len_bits); let constr = builder.mul_sub_extension(filter, diff, filter); yield_constr.constraint(builder, constr); - for &limb in &new_offset[1..] { + + // Check that `segment` and `ctx` do not change. + { + let diff = builder.sub_extension(new_addr[1], written_addr[1]); + let constr = builder.mul_extension(filter, diff); + yield_constr.constraint(builder, constr); + + let diff = builder.sub_extension(new_addr[2], written_addr[2]); + let constr = builder.mul_extension(filter, diff); + yield_constr.constraint(builder, constr); + } + + // Check that the rest of the returned address is null. + for &limb in &new_addr[3..] { let constr = builder.mul_extension(filter, limb); yield_constr.constraint(builder, constr); } diff --git a/evm/src/cpu/contextops.rs b/evm/src/cpu/contextops.rs index 2f0c72d433..0afc070f09 100644 --- a/evm/src/cpu/contextops.rs +++ b/evm/src/cpu/contextops.rs @@ -11,7 +11,8 @@ use super::membus::NUM_GP_CHANNELS; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cpu::columns::CpuColumnsView; use crate::cpu::kernel::constants::context_metadata::ContextMetadata; -use crate::memory::segments::Segment; +use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR}; +use crate::memory::VALUE_LIMBS; // If true, the instruction will keep the current context for the next row. // If false, next row's context is handled manually. @@ -83,8 +84,10 @@ fn eval_packed_get( // If the opcode is GET_CONTEXT, then lv.opcode_bits[0] = 0. let filter = lv.op.context_op * (P::ONES - lv.opcode_bits[0]); let new_stack_top = nv.mem_channels[0].value; - yield_constr.constraint(filter * (new_stack_top[0] - lv.context)); - for &limb in &new_stack_top[1..] { + // Context is scaled by 2^64, hence stored in the 3rd limb. + yield_constr.constraint(filter * (new_stack_top[2] - lv.context)); + + for (i, &limb) in new_stack_top.iter().enumerate().filter(|(i, _)| *i != 2) { yield_constr.constraint(filter * limb); } @@ -113,12 +116,14 @@ fn eval_ext_circuit_get, const D: usize>( let prod = builder.mul_extension(lv.op.context_op, lv.opcode_bits[0]); let filter = builder.sub_extension(lv.op.context_op, prod); let new_stack_top = nv.mem_channels[0].value; + // Context is scaled by 2^64, hence stored in the 3rd limb. { - let diff = builder.sub_extension(new_stack_top[0], lv.context); + let diff = builder.sub_extension(new_stack_top[2], lv.context); let constr = builder.mul_extension(filter, diff); yield_constr.constraint(builder, constr); } - for &limb in &new_stack_top[1..] { + + for (i, &limb) in new_stack_top.iter().enumerate().filter(|(i, _)| *i != 2) { let constr = builder.mul_extension(filter, limb); yield_constr.constraint(builder, constr); } @@ -155,13 +160,14 @@ fn eval_packed_set( let stack_top = lv.mem_channels[0].value; let write_old_sp_channel = lv.mem_channels[1]; let read_new_sp_channel = lv.mem_channels[2]; - let ctx_metadata_segment = P::Scalar::from_canonical_u64(Segment::ContextMetadata as u64); - let stack_size_field = P::Scalar::from_canonical_u64(ContextMetadata::StackSize as u64); + // We need to unscale the context metadata segment and related field. + let ctx_metadata_segment = P::Scalar::from_canonical_usize(Segment::ContextMetadata.unscale()); + let stack_size_field = P::Scalar::from_canonical_usize(ContextMetadata::StackSize.unscale()); let local_sp_dec = lv.stack_len - P::ONES; // The next row's context is read from stack_top. - yield_constr.constraint(filter * (stack_top[0] - nv.context)); - for &limb in &stack_top[1..] { + yield_constr.constraint(filter * (stack_top[2] - nv.context)); + for (i, &limb) in stack_top.iter().enumerate().filter(|(i, _)| *i != 2) { yield_constr.constraint(filter * limb); } @@ -220,22 +226,23 @@ fn eval_ext_circuit_set, const D: usize>( let stack_top = lv.mem_channels[0].value; let write_old_sp_channel = lv.mem_channels[1]; let read_new_sp_channel = lv.mem_channels[2]; - let ctx_metadata_segment = builder.constant_extension(F::Extension::from_canonical_u32( - Segment::ContextMetadata as u32, + // We need to unscale the context metadata segment and related field. + let ctx_metadata_segment = builder.constant_extension(F::Extension::from_canonical_usize( + Segment::ContextMetadata.unscale(), )); - let stack_size_field = builder.constant_extension(F::Extension::from_canonical_u32( - ContextMetadata::StackSize as u32, + let stack_size_field = builder.constant_extension(F::Extension::from_canonical_usize( + ContextMetadata::StackSize.unscale(), )); let one = builder.one_extension(); let local_sp_dec = builder.sub_extension(lv.stack_len, one); // The next row's context is read from stack_top. { - let diff = builder.sub_extension(stack_top[0], nv.context); + let diff = builder.sub_extension(stack_top[2], nv.context); let constr = builder.mul_extension(filter, diff); yield_constr.constraint(builder, constr); } - for &limb in &stack_top[1..] { + for (i, &limb) in stack_top.iter().enumerate().filter(|(i, _)| *i != 2) { let constr = builder.mul_extension(filter, limb); yield_constr.constraint(builder, constr); } @@ -368,7 +375,8 @@ pub(crate) fn eval_packed( yield_constr.constraint(new_filter * (channel.addr_context - nv.context)); // Same segment for both. yield_constr.constraint( - new_filter * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)), + new_filter + * (channel.addr_segment - P::Scalar::from_canonical_usize(Segment::Stack.unscale())), ); // The address is one less than stack_len. let addr_virtual = stack_len - P::ONES; @@ -429,7 +437,7 @@ pub(crate) fn eval_ext_circuit, const D: usize>( { let diff = builder.add_const_extension( channel.addr_segment, - -F::from_canonical_u64(Segment::Stack as u64), + -F::from_canonical_usize(Segment::Stack.unscale()), ); let constr = builder.mul_extension(new_filter, diff); yield_constr.constraint(builder, constr); diff --git a/evm/src/cpu/cpu_stark.rs b/evm/src/cpu/cpu_stark.rs index c93f1b8770..478dc9c2a6 100644 --- a/evm/src/cpu/cpu_stark.rs +++ b/evm/src/cpu/cpu_stark.rs @@ -21,7 +21,7 @@ use crate::cpu::{ }; use crate::cross_table_lookup::{Column, Filter, TableWithColumns}; use crate::evaluation_frame::{StarkEvaluationFrame, StarkFrame}; -use crate::memory::segments::Segment; +use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR}; use crate::memory::{NUM_CHANNELS, VALUE_LIMBS}; use crate::stark::Stark; @@ -29,15 +29,14 @@ use crate::stark::Stark; /// the CPU reads the output of the sponge directly from the `KeccakSpongeStark` table. pub(crate) fn ctl_data_keccak_sponge() -> Vec> { // When executing KECCAK_GENERAL, the GP memory channels are used as follows: - // GP channel 0: stack[-1] = context - // GP channel 1: stack[-2] = segment - // GP channel 2: stack[-3] = virt - // GP channel 3: stack[-4] = len + // GP channel 0: stack[-1] = addr (context, segment, virt) + // GP channel 1: stack[-2] = len // Next GP channel 0: pushed = outputs - let context = Column::single(COL_MAP.mem_channels[0].value[0]); - let segment = Column::single(COL_MAP.mem_channels[1].value[0]); - let virt = Column::single(COL_MAP.mem_channels[2].value[0]); - let len = Column::single(COL_MAP.mem_channels[3].value[0]); + let (context, segment, virt) = get_addr(&COL_MAP, 0); + let context = Column::single(context); + let segment = Column::single(segment); + let virt = Column::single(virt); + let len = Column::single(COL_MAP.mem_channels[1].value[0]); let num_channels = F::from_canonical_usize(NUM_CHANNELS); let timestamp = Column::linear_combination([(COL_MAP.clock, num_channels)]); @@ -149,27 +148,30 @@ pub(crate) fn ctl_data_byte_unpacking() -> Vec> { let is_read = Column::constant(F::ZERO); // When executing MSTORE_32BYTES, the GP memory channels are used as follows: - // GP channel 0: stack[-1] = context - // GP channel 1: stack[-2] = segment - // GP channel 2: stack[-3] = virt - // GP channel 3: stack[-4] = val + // GP channel 0: stack[-1] = addr (context, segment, virt) + // GP channel 1: stack[-2] = val // Next GP channel 0: pushed = new_offset (virt + len) - let context = Column::single(COL_MAP.mem_channels[0].value[0]); - let segment = Column::single(COL_MAP.mem_channels[1].value[0]); - let virt = Column::single(COL_MAP.mem_channels[2].value[0]); - let val = Column::singles(COL_MAP.mem_channels[3].value); + let (context, segment, virt) = get_addr(&COL_MAP, 0); + let mut res = vec![ + is_read, + Column::single(context), + Column::single(segment), + Column::single(virt), + ]; // len can be reconstructed as new_offset - virt. let len = Column::linear_combination_and_next_row_with_constant( - [(COL_MAP.mem_channels[2].value[0], -F::ONE)], + [(COL_MAP.mem_channels[0].value[0], -F::ONE)], [(COL_MAP.mem_channels[0].value[0], F::ONE)], F::ZERO, ); + res.push(len); let num_channels = F::from_canonical_usize(NUM_CHANNELS); let timestamp = Column::linear_combination([(COL_MAP.clock, num_channels)]); + res.push(timestamp); - let mut res = vec![is_read, context, segment, virt, len, timestamp]; + let val = Column::singles(COL_MAP.mem_channels[1].value); res.extend(val); res @@ -224,6 +226,20 @@ pub(crate) const MEM_CODE_CHANNEL_IDX: usize = 0; /// Index of the first general purpose memory channel. pub(crate) const MEM_GP_CHANNELS_IDX_START: usize = MEM_CODE_CHANNEL_IDX + 1; +/// Recover the three components of an address, given a CPU row and +/// a provided memory channel index. +/// The components are recovered as follows: +/// +/// - `context`, shifted by 2^64 (i.e. at index 2) +/// - `segment`, shifted by 2^32 (i.e. at index 1) +/// - `virtual`, not shifted (i.e. at index 0) +pub(crate) const fn get_addr(lv: &CpuColumnsView, mem_channel: usize) -> (T, T, T) { + let addr_context = lv.mem_channels[mem_channel].value[2]; + let addr_segment = lv.mem_channels[mem_channel].value[1]; + let addr_virtual = lv.mem_channels[mem_channel].value[0]; + (addr_context, addr_segment, addr_virtual) +} + /// Make the time/channel column for memory lookups. fn mem_time_and_channel(channel: usize) -> Column { let scalar = F::from_canonical_usize(NUM_CHANNELS); @@ -234,10 +250,10 @@ fn mem_time_and_channel(channel: usize) -> Column { /// Creates the vector of `Columns` corresponding to the contents of the code channel when reading code values. pub(crate) fn ctl_data_code_memory() -> Vec> { let mut cols = vec![ - Column::constant(F::ONE), // is_read - Column::single(COL_MAP.code_context), // addr_context - Column::constant(F::from_canonical_u64(Segment::Code as u64)), // addr_segment - Column::single(COL_MAP.program_counter), // addr_virtual + Column::constant(F::ONE), // is_read + Column::single(COL_MAP.code_context), // addr_context + Column::constant(F::from_canonical_usize(Segment::Code.unscale())), // addr_segment + Column::single(COL_MAP.program_counter), // addr_virtual ]; // Low limb of the value matches the opcode bits diff --git a/evm/src/cpu/dup_swap.rs b/evm/src/cpu/dup_swap.rs index 78e5891a90..44763fdc91 100644 --- a/evm/src/cpu/dup_swap.rs +++ b/evm/src/cpu/dup_swap.rs @@ -54,7 +54,7 @@ fn constrain_channel_packed( yield_constr.constraint(filter * (channel.is_read - P::Scalar::from_bool(is_read))); yield_constr.constraint(filter * (channel.addr_context - lv.context)); yield_constr.constraint( - filter * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)), + filter * (channel.addr_segment - P::Scalar::from_canonical_usize(Segment::Stack.unscale())), ); // Top of the stack is at `addr = lv.stack_len - 1`. let addr_virtual = lv.stack_len - P::ONES - offset; @@ -94,7 +94,7 @@ fn constrain_channel_ext_circuit, const D: usize>( { let constr = builder.arithmetic_extension( F::ONE, - -F::from_canonical_u64(Segment::Stack as u64), + -F::from_canonical_usize(Segment::Stack.unscale()), filter, channel.addr_segment, filter, diff --git a/evm/src/cpu/jumps.rs b/evm/src/cpu/jumps.rs index f2fd544c67..fd7fcfd962 100644 --- a/evm/src/cpu/jumps.rs +++ b/evm/src/cpu/jumps.rs @@ -87,7 +87,8 @@ pub(crate) fn eval_packed_jump_jumpi( yield_constr.constraint_transition(new_filter * (channel.is_read - P::ONES)); yield_constr.constraint_transition(new_filter * (channel.addr_context - nv.context)); yield_constr.constraint_transition( - new_filter * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)), + new_filter + * (channel.addr_segment - P::Scalar::from_canonical_usize(Segment::Stack.unscale())), ); let addr_virtual = nv.stack_len - P::ONES; yield_constr.constraint_transition(new_filter * (channel.addr_virtual - addr_virtual)); @@ -134,7 +135,7 @@ pub(crate) fn eval_packed_jump_jumpi( yield_constr.constraint( filter * (jumpdest_flag_channel.addr_segment - - P::Scalar::from_canonical_u64(Segment::JumpdestBits as u64)), + - P::Scalar::from_canonical_usize(Segment::JumpdestBits.unscale())), ); yield_constr.constraint(filter * (jumpdest_flag_channel.addr_virtual - dst[0])); @@ -205,7 +206,7 @@ pub(crate) fn eval_ext_circuit_jump_jumpi, const D: { let constr = builder.arithmetic_extension( F::ONE, - -F::from_canonical_u64(Segment::Stack as u64), + -F::from_canonical_usize(Segment::Stack.unscale()), new_filter, channel.addr_segment, new_filter, @@ -308,7 +309,7 @@ pub(crate) fn eval_ext_circuit_jump_jumpi, const D: { let constr = builder.arithmetic_extension( F::ONE, - -F::from_canonical_u64(Segment::JumpdestBits as u64), + -F::from_canonical_usize(Segment::JumpdestBits.unscale()), filter, jumpdest_flag_channel.addr_segment, filter, diff --git a/evm/src/cpu/kernel/asm/account_code.asm b/evm/src/cpu/kernel/asm/account_code.asm index 1a9262eea9..6aedbd2e39 100644 --- a/evm/src/cpu/kernel/asm/account_code.asm +++ b/evm/src/cpu/kernel/asm/account_code.asm @@ -86,6 +86,8 @@ global extcodesize: // Checks that the hash of the loaded code corresponds to the `codehash` in the state trie. // Pre stack: address, ctx, retdest // Post stack: code_size +// +// NOTE: The provided `dest` **MUST** have a virtual address of 0. global load_code: %stack (address, ctx, retdest) -> (extcodehash, address, load_code_ctd, ctx, retdest) JUMP @@ -94,8 +96,9 @@ load_code_ctd: DUP1 ISZERO %jumpi(load_code_non_existent_account) // Load the code non-deterministically in memory and return the length. PROVER_INPUT(account_code) - %stack (code_size, codehash, ctx, retdest) -> (ctx, @SEGMENT_CODE, 0, code_size, codehash, retdest, code_size) + %stack (code_size, codehash, ctx, retdest) -> (ctx, code_size, codehash, retdest, code_size) // Check that the hash of the loaded code equals `codehash`. + // ctx == DST, as SEGMENT_CODE == offset == 0. KECCAK_GENERAL // stack: shouldbecodehash, codehash, retdest, code_size %assert_eq @@ -103,9 +106,9 @@ load_code_ctd: JUMP load_code_non_existent_account: - // Write 0 at address 0 for soundness. - // stack: codehash, ctx, retdest - %stack (codehash, ctx, retdest) -> (0, ctx, @SEGMENT_CODE, 0, retdest, 0) + // Write 0 at address 0 for soundness: SEGMENT_CODE == 0, hence ctx == addr. + // stack: codehash, addr, retdest + %stack (codehash, addr, retdest) -> (0, addr, retdest, 0) MSTORE_GENERAL // stack: retdest, 0 JUMP @@ -120,10 +123,14 @@ global load_code_padded: %jump(load_code) load_code_padded_ctd: - %stack (code_size, ctx, retdest) -> (ctx, @SEGMENT_CODE, code_size, 0, ctx, retdest, code_size) + // SEGMENT_CODE == 0. + // stack: code_size, ctx, retdest + %stack (code_size, ctx, retdest) -> (ctx, code_size, 0, retdest, code_size) + ADD + // stack: addr, 0, retdest, code_size MSTORE_32BYTES_32 - // stack: last_offset, ctx, retdest, code_size - %stack (last_offset, ctx) -> (0, ctx, @SEGMENT_CODE, last_offset) + // stack: addr', retdest, code_size + PUSH 0 MSTORE_GENERAL // stack: retdest, code_size JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/util.asm b/evm/src/cpu/kernel/asm/bignum/util.asm index 7bd6e0dc33..0385deec2d 100644 --- a/evm/src/cpu/kernel/asm/bignum/util.asm +++ b/evm/src/cpu/kernel/asm/bignum/util.asm @@ -1,15 +1,21 @@ %macro memcpy_current_general // stack: dst, src, len - GET_CONTEXT - %stack (context, dst, src, len) -> (context, @SEGMENT_KERNEL_GENERAL, dst, context, @SEGMENT_KERNEL_GENERAL, src, len, %%after) + // DST and SRC are offsets, for the same memory segment + GET_CONTEXT PUSH @SEGMENT_KERNEL_GENERAL %build_address_no_offset + %stack (addr_no_offset, dst, src, len) -> (addr_no_offset, src, addr_no_offset, dst, len, %%after) + ADD + // stack: SRC, addr_no_offset, dst, len, %%after + SWAP2 + ADD + // stack: DST, SRC, len, %%after %jump(memcpy) %%after: %endmacro %macro clear_current_general // stack: dst, len - GET_CONTEXT - %stack (context, dst, len) -> (context, @SEGMENT_KERNEL_GENERAL, dst, len, %%after) + GET_CONTEXT PUSH @SEGMENT_KERNEL_GENERAL %build_address + %stack (DST, len) -> (DST, len, %%after) %jump(memset) %%after: %endmacro diff --git a/evm/src/cpu/kernel/asm/core/access_lists.asm b/evm/src/cpu/kernel/asm/core/access_lists.asm index b1b9fd5d5e..5019b6840e 100644 --- a/evm/src/cpu/kernel/asm/core/access_lists.asm +++ b/evm/src/cpu/kernel/asm/core/access_lists.asm @@ -120,14 +120,20 @@ insert_storage_key: // stack: i, len, addr, key, value, retdest DUP4 DUP4 %journal_add_storage_loaded // Add a journal entry for the loaded storage key. // stack: i, len, addr, key, value, retdest - DUP1 %increment - DUP1 %increment - %stack (i_plus_2, i_plus_1, i, len, addr, key, value) -> (i, addr, i_plus_1, key, i_plus_2, value, i_plus_2, value) - %mstore_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS) // Store new address at the end of the array. - %mstore_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS) // Store new key after that - %mstore_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS) // Store new value after that - // stack: i_plus_2, value, retdest - %increment + DUP1 + PUSH @SEGMENT_ACCESSED_STORAGE_KEYS + %build_kernel_address + + %stack(dst, i, len, addr, key, value) -> (addr, dst, dst, key, dst, value, i, value) + MSTORE_GENERAL // Store new address at the end of the array. + // stack: dst, key, dst, value, i, value, retdest + %increment SWAP1 + MSTORE_GENERAL // Store new key after that + // stack: dst, value, i, value, retdest + %add_const(2) SWAP1 + MSTORE_GENERAL // Store new value after that + // stack: i, value, retdest + %add_const(3) %mstore_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN) // Store new length. %stack (value, retdest) -> (retdest, 1, value) // Return 1 to indicate that the storage key was inserted. JUMP diff --git a/evm/src/cpu/kernel/asm/core/call.asm b/evm/src/cpu/kernel/asm/core/call.asm index 2e7d1d7345..aa8fbf0c05 100644 --- a/evm/src/cpu/kernel/asm/core/call.asm +++ b/evm/src/cpu/kernel/asm/core/call.asm @@ -1,4 +1,5 @@ // Handlers for call-like operations, namely CALL, CALLCODE, STATICCALL and DELEGATECALL. +// Reminder: All context metadata hardcoded offsets are already scaled by `Segment::ContextMetadata`. // Creates a new sub context and executes the code of the given account. global sys_call: @@ -271,7 +272,10 @@ call_too_deep: // because it will already be 0 by default. %macro set_static_true // stack: new_ctx - %stack (new_ctx) -> (1, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_STATIC, new_ctx) + DUP1 + %build_address_with_ctx_no_segment(@CTX_METADATA_STATIC) + PUSH 1 + // stack: 1, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro @@ -279,74 +283,90 @@ call_too_deep: // Set @CTX_METADATA_STATIC of the next context to the current value. %macro set_static // stack: new_ctx + DUP1 + %build_address_with_ctx_no_segment(@CTX_METADATA_STATIC) %mload_context_metadata(@CTX_METADATA_STATIC) - %stack (is_static, new_ctx) -> (is_static, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_STATIC, new_ctx) + // stack: is_static, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro %macro set_new_ctx_addr // stack: called_addr, new_ctx - %stack (called_addr, new_ctx) - -> (called_addr, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_ADDRESS, new_ctx) + DUP2 + %build_address_with_ctx_no_segment(@CTX_METADATA_ADDRESS) + SWAP1 + // stack: called_addr, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro %macro set_new_ctx_caller // stack: sender, new_ctx - %stack (sender, new_ctx) - -> (sender, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CALLER, new_ctx) + DUP2 + %build_address_with_ctx_no_segment(@CTX_METADATA_CALLER) + SWAP1 + // stack: sender, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro %macro set_new_ctx_value // stack: value, new_ctx - %stack (value, new_ctx) - -> (value, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CALL_VALUE, new_ctx) + DUP2 + %build_address_with_ctx_no_segment(@CTX_METADATA_CALL_VALUE) + SWAP1 + // stack: value, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro %macro set_new_ctx_code_size // stack: code_size, new_ctx - %stack (code_size, new_ctx) - -> (code_size, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CODE_SIZE, new_ctx) + DUP2 + %build_address_with_ctx_no_segment(@CTX_METADATA_CODE_SIZE) + SWAP1 + // stack: code_size, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro %macro set_new_ctx_calldata_size // stack: calldata_size, new_ctx - %stack (calldata_size, new_ctx) - -> (calldata_size, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CALLDATA_SIZE, new_ctx) + DUP2 + %build_address_with_ctx_no_segment(@CTX_METADATA_CALLDATA_SIZE) + SWAP1 + // stack: calldata_size, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro %macro set_new_ctx_gas_limit // stack: gas_limit, new_ctx - %stack (gas_limit, new_ctx) - -> (gas_limit, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_GAS_LIMIT, new_ctx) + DUP2 + %build_address_with_ctx_no_segment(@CTX_METADATA_GAS_LIMIT) + SWAP1 + // stack: gas_limit, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro %macro set_new_ctx_parent_ctx // stack: new_ctx - PUSH @CTX_METADATA_PARENT_CONTEXT - PUSH @SEGMENT_CONTEXT_METADATA - DUP3 // new_ctx + DUP1 + %build_address_with_ctx_no_segment(@CTX_METADATA_PARENT_CONTEXT) GET_CONTEXT + // stack: ctx, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro %macro set_new_ctx_parent_pc(label) // stack: new_ctx - %stack (new_ctx) - -> ($label, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_PARENT_PC, new_ctx) + DUP1 + %build_address_with_ctx_no_segment(@CTX_METADATA_PARENT_PC) + PUSH $label + // stack: label, addr, new_ctx MSTORE_GENERAL // stack: new_ctx %endmacro @@ -381,17 +401,18 @@ call_too_deep: %macro copy_mem_to_calldata // stack: new_ctx, args_offset, args_size GET_CONTEXT - %stack (ctx, new_ctx, args_offset, args_size) -> - ( - new_ctx, @SEGMENT_CALLDATA, 0, // DST - ctx, @SEGMENT_MAIN_MEMORY, args_offset, // SRC - args_size, %%after, // count, retdest - new_ctx, args_size - ) + %stack(ctx, new_ctx, args_offset, args_size) -> (ctx, @SEGMENT_MAIN_MEMORY, args_offset, args_size, %%after, new_ctx, args_size) + %build_address + // stack: SRC, args_size, %%after, new_ctx, args_size + DUP4 + %build_address_with_ctx_no_offset(@SEGMENT_CALLDATA) + // stack: DST, SRC, args_size, %%after, new_ctx, args_size %jump(memcpy_bytes) %%after: - %stack (new_ctx, args_size) -> - (args_size, new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CALLDATA_SIZE) + // stack: new_ctx, args_size + %build_address_with_ctx_no_segment(@CTX_METADATA_CALLDATA_SIZE) + // stack: addr, args_size + SWAP1 MSTORE_GENERAL // stack: (empty) %endmacro @@ -403,13 +424,12 @@ call_too_deep: // stack: returndata_size, ret_size, new_ctx, success, ret_offset, kexit_info %min GET_CONTEXT - %stack (ctx, n, new_ctx, success, ret_offset, kexit_info) -> - ( - ctx, @SEGMENT_MAIN_MEMORY, ret_offset, // DST - ctx, @SEGMENT_RETURNDATA, 0, // SRC - n, %%after, // count, retdest - kexit_info, success - ) + %stack (ctx, n, new_ctx, success, ret_offset, kexit_info) -> (ctx, @SEGMENT_RETURNDATA, @SEGMENT_MAIN_MEMORY, ret_offset, ctx, n, %%after, kexit_info, success) + %build_address_no_offset + // stack: SRC, @SEGMENT_MAIN_MEMORY, ret_offset, ctx, n, %%after, kexit_info, success + SWAP3 + %build_address + // stack: DST, SRC, n, %%after, kexit_info, success %jump(memcpy_bytes) %%after: %endmacro diff --git a/evm/src/cpu/kernel/asm/core/call_gas.asm b/evm/src/cpu/kernel/asm/core/call_gas.asm index 69e2796661..3961352139 100644 --- a/evm/src/cpu/kernel/asm/core/call_gas.asm +++ b/evm/src/cpu/kernel/asm/core/call_gas.asm @@ -9,7 +9,7 @@ // Charge gas for *call opcodes and return the sub-context gas limit. // Doesn't include memory expansion costs. global call_charge_gas: - // Compute C_aaccess + // Compute C_access // stack: is_call_or_callcode, is_call_or_staticcall, cold_access, address, gas, kexit_info, value, retdest SWAP2 // stack: cold_access, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest diff --git a/evm/src/cpu/kernel/asm/core/create.asm b/evm/src/cpu/kernel/asm/core/create.asm index 4756b40702..80f8f46188 100644 --- a/evm/src/cpu/kernel/asm/core/create.asm +++ b/evm/src/cpu/kernel/asm/core/create.asm @@ -57,6 +57,7 @@ global sys_create2: DUP5 // code_offset PUSH @SEGMENT_MAIN_MEMORY GET_CONTEXT + %build_address KECCAK_GENERAL // stack: hash, salt, create_common, value, code_offset, code_len, kexit_info @@ -99,11 +100,15 @@ global create_common: %set_new_ctx_code_size POP // Copy the code from memory to the new context's code segment. %stack (src_ctx, new_ctx, address, value, code_offset, code_len) - -> (new_ctx, @SEGMENT_CODE, 0, // DST - src_ctx, @SEGMENT_MAIN_MEMORY, code_offset, // SRC + -> (src_ctx, @SEGMENT_MAIN_MEMORY, code_offset, // SRC + new_ctx, // DST (SEGMENT_CODE == virt == 0) code_len, run_constructor, new_ctx, value, address) + %build_address + // stack: SRC, DST, code_len, run_constructor, new_ctx, value, address + SWAP1 + // stack: DST, SRC, code_len, run_constructor, new_ctx, value, address %jump(memcpy_bytes) run_constructor: @@ -144,7 +149,11 @@ after_constructor: POP // EIP-3541: Reject new contract code starting with the 0xEF byte - PUSH 0 %mload_current(@SEGMENT_RETURNDATA) %eq_const(0xEF) %jumpi(create_first_byte_ef) + PUSH @SEGMENT_RETURNDATA + GET_CONTEXT + %build_address_no_offset + MLOAD_GENERAL + %eq_const(0xEF) %jumpi(create_first_byte_ef) // Charge gas for the code size. // stack: leftover_gas, success, address, kexit_info @@ -160,9 +169,9 @@ after_constructor: %pop_checkpoint // Store the code hash of the new contract. - GET_CONTEXT %returndatasize - %stack (size, ctx) -> (ctx, @SEGMENT_RETURNDATA, 0, size) // context, segment, offset, len + PUSH @SEGMENT_RETURNDATA GET_CONTEXT %build_address_no_offset + // stack: addr, len KECCAK_GENERAL // stack: codehash, leftover_gas, success, address, kexit_info %observe_new_contract diff --git a/evm/src/cpu/kernel/asm/core/create_addresses.asm b/evm/src/cpu/kernel/asm/core/create_addresses.asm index 70f57b6f0b..1cd50f661a 100644 --- a/evm/src/cpu/kernel/asm/core/create_addresses.asm +++ b/evm/src/cpu/kernel/asm/core/create_addresses.asm @@ -14,10 +14,7 @@ global get_create_address: %encode_rlp_scalar // stack: rlp_pos, rlp_start, retdest %prepend_rlp_list_prefix - // stack: rlp_prefix_start, rlp_len, retdest - PUSH @SEGMENT_RLP_RAW - PUSH 0 // context - // stack: RLP_ADDR: 3, rlp_len, retdest + // stack: RLP_ADDR, rlp_len, retdest KECCAK_GENERAL // stack: hash, retdest %u256_to_addr @@ -41,19 +38,23 @@ global get_create_address: global get_create2_address: // stack: sender, code_hash, salt, retdest PUSH 0xff PUSH 0 %mstore_kernel_general - %stack (sender, code_hash, salt, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 1, sender, 20, get_create2_address_contd, salt, code_hash, retdest) + %stack (sender, code_hash, salt, retdest) -> (@SEGMENT_KERNEL_GENERAL, 1, sender, 20, get_create2_address_contd, salt, code_hash, retdest) + ADD %jump(mstore_unpacking) get_create2_address_contd: POP - %stack (salt, code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 21, salt, 32, get_create2_address_contd2, code_hash, retdest) + %stack (salt, code_hash, retdest) -> (@SEGMENT_KERNEL_GENERAL, 21, salt, 32, get_create2_address_contd2, code_hash, retdest) + ADD %jump(mstore_unpacking) get_create2_address_contd2: POP - %stack (code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 53, code_hash, 32, get_create2_address_finish, retdest) + %stack (code_hash, retdest) -> (@SEGMENT_KERNEL_GENERAL, 53, code_hash, 32, get_create2_address_finish, retdest) + ADD %jump(mstore_unpacking) get_create2_address_finish: POP - %stack (retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 0, 85, retdest) // context, segment, offset, len + %stack (retdest) -> (@SEGMENT_KERNEL_GENERAL, 85, retdest) // offset == context == 0 + // addr, len, retdest KECCAK_GENERAL // stack: hash, retdest %u256_to_addr diff --git a/evm/src/cpu/kernel/asm/core/create_receipt.asm b/evm/src/cpu/kernel/asm/core/create_receipt.asm index 16a4fcaaeb..9f7cb9f89d 100644 --- a/evm/src/cpu/kernel/asm/core/create_receipt.asm +++ b/evm/src/cpu/kernel/asm/core/create_receipt.asm @@ -55,8 +55,8 @@ process_receipt_after_bloom: %get_trie_data_size // stack: receipt_ptr, payload_len, status, new_cum_gas, txn_nb, new_cum_gas, txn_nb, num_nibbles, retdest // Write transaction type if necessary. RLP_RAW contains, at index 0, the current transaction type. - PUSH 0 - %mload_kernel(@SEGMENT_RLP_RAW) + PUSH @SEGMENT_RLP_RAW // ctx == virt == 0 + MLOAD_GENERAL // stack: first_txn_byte, receipt_ptr, payload_len, status, new_cum_gas, txn_nb, new_cum_gas, txn_nb, num_nibbles, retdest DUP1 %eq_const(1) %jumpi(receipt_nonzero_type) DUP1 %eq_const(2) %jumpi(receipt_nonzero_type) @@ -79,8 +79,10 @@ process_receipt_after_type: // stack: receipt_ptr, txn_nb, new_cum_gas, txn_nb, num_nibbles, retdest // Write Bloom filter. PUSH 256 // Bloom length. - PUSH 0 PUSH @SEGMENT_TXN_BLOOM PUSH 0 // Bloom memory address. - %get_trie_data_size PUSH @SEGMENT_TRIE_DATA PUSH 0 // MPT dest address. + PUSH @SEGMENT_TXN_BLOOM // ctx == virt == 0 + // stack: bloom_addr, 256, txn_nb, new_cum_gas, txn_nb, num_nibbles, retdest + %get_trie_data_size + PUSH @SEGMENT_TRIE_DATA ADD // MPT dest address. // stack: DST, SRC, 256, receipt_ptr, txn_nb, new_cum_gas, txn_nb, num_nibbles, retdest %memcpy_bytes // stack: receipt_ptr, txn_nb, new_cum_gas, txn_nb, num_nibbles, retdest @@ -204,16 +206,14 @@ process_receipt_after_write: %mpt_insert_receipt_trie // stack: new_cum_gas, txn_nb, num_nibbles, retdest // Now, we set the Bloom filter back to 0. We proceed by chunks of 32 bytes. - PUSH 0 + PUSH @SEGMENT_TXN_BLOOM // ctx == offset == 0 %rep 8 - // stack: counter, new_cum_gas, txn_nb, num_nibbles, retdest + // stack: addr, new_cum_gas, txn_nb, num_nibbles, retdest PUSH 0 // we will fill the memory segment with zeroes DUP2 - PUSH @SEGMENT_TXN_BLOOM - DUP3 // kernel context is 0 - // stack: ctx, segment, counter, 0, counter, new_cum_gas, txn_nb, num_nibbles, retdes + // stack: addr, 0, addr, new_cum_gas, txn_nb, num_nibbles, retdest MSTORE_32BYTES_32 - // stack: new_counter, counter, new_cum_gas, txn_nb, num_nibbles, retdest + // stack: new_addr, addr, new_cum_gas, txn_nb, num_nibbles, retdest SWAP1 POP %endrep POP diff --git a/evm/src/cpu/kernel/asm/core/jumpdest_analysis.asm b/evm/src/cpu/kernel/asm/core/jumpdest_analysis.asm index bda6f96e63..a43f301af4 100644 --- a/evm/src/cpu/kernel/asm/core/jumpdest_analysis.asm +++ b/evm/src/cpu/kernel/asm/core/jumpdest_analysis.asm @@ -14,7 +14,8 @@ loop: %jumpi(return) // stack: i, ctx, code_len, retdest - %stack (i, ctx) -> (ctx, @SEGMENT_CODE, i, i, ctx) + %stack (i, ctx) -> (ctx, i, i, ctx) + ADD // combine context and offset to make an address (SEGMENT_CODE == 0) MLOAD_GENERAL // stack: opcode, i, ctx, code_len, retdest @@ -26,7 +27,10 @@ loop: %jumpi(continue) // stack: JUMPDEST, i, ctx, code_len, retdest - %stack (JUMPDEST, i, ctx) -> (1, ctx, @SEGMENT_JUMPDEST_BITS, i, JUMPDEST, i, ctx) + %stack (JUMPDEST, i, ctx) -> (ctx, @SEGMENT_JUMPDEST_BITS, i, JUMPDEST, i, ctx) + %build_address + PUSH 1 + // stack: 1, addr, JUMPDEST, i, ctx MSTORE_GENERAL continue: diff --git a/evm/src/cpu/kernel/asm/core/precompiles/blake2_f.asm b/evm/src/cpu/kernel/asm/core/precompiles/blake2_f.asm index 01c027156f..500548eff5 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/blake2_f.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/blake2_f.asm @@ -29,7 +29,8 @@ global precompile_blake2_f: // stack: flag_addr, flag_addr, blake2_f_contd, kexit_info PUSH @SEGMENT_CALLDATA GET_CONTEXT - // stack: ctx, @SEGMENT_CALLDATA, flag_addr, flag_addr, blake2_f_contd, kexit_info + %build_address + // stack: addr, flag_addr, blake2_f_contd, kexit_info MLOAD_GENERAL // stack: flag, flag_addr, blake2_f_contd, kexit_info DUP1 @@ -45,6 +46,7 @@ global precompile_blake2_f: // stack: @SEGMENT_CALLDATA, t1_addr, t1_addr, flag, blake2_f_contd, kexit_info GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, t1_addr, t1_addr, flag, blake2_f_contd, kexit_info + %build_address %mload_packing_u64_LE // stack: t_1, t1_addr, flag, blake2_f_contd, kexit_info SWAP1 @@ -56,6 +58,7 @@ global precompile_blake2_f: // stack: @SEGMENT_CALLDATA, t0_addr, t0_addr, t_1, flag, blake2_f_contd, kexit_info GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, t0_addr, t0_addr, t_1, flag, blake2_f_contd, kexit_info + %build_address %mload_packing_u64_LE // stack: t_0, t0_addr, t_1, flag, blake2_f_contd, kexit_info SWAP1 @@ -71,6 +74,7 @@ global precompile_blake2_f: // stack: @SEGMENT_CALLDATA, m0_addr + 8 * (16 - i - 1), m0_addr + 8 * (16 - i - 1), m_(i+1), ..., m_15, t_0, t_1, flag, blake2_f_contd, kexit_info GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, m0_addr + 8 * (16 - i - 1), m0_addr + 8 * (16 - i - 1), m_(i+1), ..., m_15, t_0, t_1, flag, blake2_f_contd, kexit_info + %build_address %mload_packing_u64_LE // stack: m_i, m0_addr + 8 * (16 - i - 1), m_(i+1), ..., m_15, t_0, t_1, flag, blake2_f_contd, kexit_info SWAP1 @@ -88,6 +92,7 @@ global precompile_blake2_f: // stack: @SEGMENT_CALLDATA, h0_addr + 8 * (8 - i), h0_addr + 8 * (8 - i), h_(i+1), ..., h_7, m_0..m_15, t_0, t_1, flag, blake2_f_contd, kexit_info GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, h0_addr + 8 * (8 - i), h0_addr + 8 * (8 - i), h_(i+1), ..., h_7, m_0..m_15, t_0, t_1, flag, blake2_f_contd, kexit_info + %build_address %mload_packing_u64_LE // stack: h_i, h0_addr + 8 * (8 - i), h_(i+1), ..., h_7, m_0..m_15, t_0, t_1, flag, blake2_f_contd, kexit_info SWAP1 @@ -96,9 +101,10 @@ global precompile_blake2_f: // stack: h0_addr + 8 * 8 = 68, h_0, ..., h_7, m_0..m_15, t_0, t_1, flag, blake2_f_contd, kexit_info POP - %stack () -> (@SEGMENT_CALLDATA, 0, 4) + %stack () -> (@SEGMENT_CALLDATA, 4) GET_CONTEXT - // stack: ctx, @SEGMENT_CALLDATA, 0, 4, h_0..h_7, m_0..m_15, t_0, t_1, flag, blake2_f_contd, kexit_info + // stack: ctx, @SEGMENT_CALLDATA, 4, h_0..h_7, m_0..m_15, t_0, t_1, flag, blake2_f_contd, kexit_info + %build_address_no_offset %mload_packing // stack: rounds, h_0..h_7, m_0..m_15, t_0, t_1, flag, blake2_f_contd, kexit_info @@ -113,20 +119,20 @@ blake2_f_contd: // Store the result hash to the parent's return data using `mstore_unpacking_u64_LE`. %mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 64) - PUSH 0 - // stack: addr_0=0, h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', kexit_info + // stack: h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', kexit_info + PUSH @SEGMENT_RETURNDATA %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - // stack: parent_ctx, addr_0=0, h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', kexit_info + // stack: parent_ctx, segment, h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', kexit_info + %build_address_no_offset + // stack: addr0=0, h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', kexit_info %rep 8 - // stack: parent_ctx, addr_i, h_i', ..., h_7', kexit_info - %stack (ctx, addr, h_i) -> (ctx, @SEGMENT_RETURNDATA, addr, h_i, addr, ctx) + // stack: addri, h_i', ..., h_7', kexit_info + %stack (addr, h_i) -> (addr, h_i, addr) %mstore_unpacking_u64_LE - // stack: addr_i, parent_ctx, h_(i+1)', ..., h_7', kexit_info + // stack: addr_i, h_(i+1)', ..., h_7', kexit_info %add_const(8) - // stack: addr_(i+1), parent_ctx, h_(i+1)', ..., h_7', kexit_info - SWAP1 - // stack: parent_ctx, addr_(i+1), h_(i+1)', ..., h_7', kexit_info + // stack: addr_(i+1), h_(i+1)', ..., h_7', kexit_info %endrep // stack: kexit_info diff --git a/evm/src/cpu/kernel/asm/core/precompiles/bn_add.asm b/evm/src/cpu/kernel/asm/core/precompiles/bn_add.asm index 1dafbe8a43..dcd641a327 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/bn_add.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/bn_add.asm @@ -20,21 +20,25 @@ global precompile_bn_add: %stack () -> (@SEGMENT_CALLDATA, 96, 32) GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 96, 32, bn_add_return, kexit_info + %build_address %mload_packing // stack: y1, bn_add_return, kexit_info %stack () -> (@SEGMENT_CALLDATA, 64, 32) GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 64, 32, y1, bn_add_return, kexit_info + %build_address %mload_packing // stack: x1, y1, bn_add_return, kexit_info %stack () -> (@SEGMENT_CALLDATA, 32, 32) GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 32, 32, x1, y1, bn_add_return, kexit_info + %build_address %mload_packing // stack: y0, x1, y1, bn_add_return, kexit_info - %stack () -> (@SEGMENT_CALLDATA, 0, 32) + %stack () -> (@SEGMENT_CALLDATA, 32) GET_CONTEXT - // stack: ctx, @SEGMENT_CALLDATA, 0, 32, y0, x1, y1, bn_add_return, kexit_info + // stack: ctx, @SEGMENT_CALLDATA, 32, y0, x1, y1, bn_add_return, kexit_info + %build_address_no_offset %mload_packing // stack: x0, y0, x1, y1, bn_add_return, kexit_info %jump(bn_add) @@ -49,9 +53,11 @@ bn_add_return: // Store the result (x, y) to the parent's return data using `mstore_unpacking`. %mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 64) %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - %stack (parent_ctx, x, y) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, x, 32, bn_add_contd6, parent_ctx, y) + %stack (parent_ctx, x, y) -> (parent_ctx, @SEGMENT_RETURNDATA, x, 32, bn_add_contd6, parent_ctx, y) + %build_address_no_offset %jump(mstore_unpacking) bn_add_contd6: POP %stack (parent_ctx, y) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, y, 32, pop_and_return_success) + %build_address %jump(mstore_unpacking) diff --git a/evm/src/cpu/kernel/asm/core/precompiles/bn_mul.asm b/evm/src/cpu/kernel/asm/core/precompiles/bn_mul.asm index b3865506d8..df2e27e99f 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/bn_mul.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/bn_mul.asm @@ -20,16 +20,19 @@ global precompile_bn_mul: %stack () -> (@SEGMENT_CALLDATA, 64, 32) GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 64, 32, bn_mul_return, kexit_info + %build_address %mload_packing // stack: n, bn_mul_return, kexit_info %stack () -> (@SEGMENT_CALLDATA, 32, 32) GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 32, 32, n, bn_mul_return, kexit_info + %build_address %mload_packing // stack: y, n, bn_mul_return, kexit_info - %stack () -> (@SEGMENT_CALLDATA, 0, 32) + %stack () -> (@SEGMENT_CALLDATA, 32) GET_CONTEXT - // stack: ctx, @SEGMENT_CALLDATA, 0, 32, y, n, bn_mul_return, kexit_info + // stack: ctx, @SEGMENT_CALLDATA, 32, y, n, bn_mul_return, kexit_info + %build_address_no_offset %mload_packing // stack: x, y, n, bn_mul_return, kexit_info %jump(bn_mul) @@ -44,9 +47,11 @@ bn_mul_return: // Store the result (Px, Py) to the parent's return data using `mstore_unpacking`. %mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 64) %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - %stack (parent_ctx, Px, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, Px, 32, bn_mul_contd6, parent_ctx, Py) + %stack (parent_ctx, Px, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, Px, 32, bn_mul_contd6, parent_ctx, Py) + %build_address_no_offset %jump(mstore_unpacking) bn_mul_contd6: POP %stack (parent_ctx, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, Py, 32, pop_and_return_success) + %build_address %jump(mstore_unpacking) diff --git a/evm/src/cpu/kernel/asm/core/precompiles/ecrec.asm b/evm/src/cpu/kernel/asm/core/precompiles/ecrec.asm index b38307c4db..baa661962d 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/ecrec.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/ecrec.asm @@ -20,21 +20,25 @@ global precompile_ecrec: %stack () -> (@SEGMENT_CALLDATA, 96, 32) GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 96, 32, ecrec_return, kexit_info + %build_address %mload_packing // stack: s, ecrec_return, kexit_info %stack () -> (@SEGMENT_CALLDATA, 64, 32) GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 64, 32, s, ecrec_return, kexit_info + %build_address %mload_packing // stack: r, s, ecrec_return, kexit_info %stack () -> (@SEGMENT_CALLDATA, 32, 32) GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 32, 32, r, s, ecrec_return, kexit_info + %build_address %mload_packing // stack: v, r, s, ecrec_return, kexit_info - %stack () -> (@SEGMENT_CALLDATA, 0, 32) + %stack () -> (@SEGMENT_CALLDATA, 32) GET_CONTEXT - // stack: ctx, @SEGMENT_CALLDATA, 0, 32, v, r, s, ecrec_return, kexit_info + // stack: ctx, @SEGMENT_CALLDATA, 32, v, r, s, ecrec_return, kexit_info + %build_address_no_offset %mload_packing // stack: hash, v, r, s, ecrec_return, kexit_info %jump(ecrecover) @@ -45,7 +49,8 @@ ecrec_return: // Store the result address to the parent's return data using `mstore_unpacking`. %mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32) %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - %stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, address, 32, pop_and_return_success) + %stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, address, 32, pop_and_return_success) + %build_address_no_offset %jump(mstore_unpacking) // On bad input, return empty return data but still return success. diff --git a/evm/src/cpu/kernel/asm/core/precompiles/expmod.asm b/evm/src/cpu/kernel/asm/core/precompiles/expmod.asm index 2185ee2c9d..52bb220dab 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/expmod.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/expmod.asm @@ -11,43 +11,43 @@ // We pass around total_num_limbs and len for conveience, because we can't access them from the stack // if they're hidden behind the variable number of limbs. mload_bytes_as_limbs: - // stack: ctx, segment, offset, num_bytes, retdest, total_num_limbs, len, ..limbs - DUP4 - // stack: num_bytes, ctx, segment, offset, num_bytes, retdest, total_num_limbs, len, ..limbs + // stack: addr, num_bytes, retdest, total_num_limbs, len, ..limbs + DUP2 + // stack: num_bytes, addr, num_bytes, retdest, total_num_limbs, len, ..limbs %mod_16 - // stack: min(16, num_bytes), ctx, segment, offset, num_bytes, retdest, total_num_limbs, len, ..limbs - %stack (len, addr: 3) -> (addr, len, addr) - // stack: ctx, segment, offset, min(16, num_bytes), ctx, segment, offset, num_bytes, retdest, total_num_limbs, len, ..limbs + // stack: min(16, num_bytes), addr, num_bytes, retdest, total_num_limbs, len, ..limbs + DUP2 + // stack: addr, min(16, num_bytes), addr, num_bytes, retdest, total_num_limbs, len, ..limbs %mload_packing - // stack: new_limb, ctx, segment, offset, num_bytes, retdest, total_num_limbs, len, ..limbs - %stack (new, addr: 3, numb, ret, tot, len) -> (numb, addr, ret, tot, len, new) - // stack: num_bytes, ctx, segment, offset, retdest, total_num_limbs, len, new_limb, ..limbs + // stack: new_limb, addr, num_bytes, retdest, total_num_limbs, len, ..limbs + %stack (new, addr, numb, ret, tot, len) -> (numb, addr, ret, tot, len, new) + // stack: num_bytes, addr, retdest, total_num_limbs, len, new_limb, ..limbs DUP1 %mod_16 - // stack: num_bytes%16, num_bytes, ctx, segment, offset, retdest, total_num_limbs, len, new_limb, ..limbs + // stack: num_bytes%16, num_bytes, addr, retdest, total_num_limbs, len, new_limb, ..limbs DUP1 SWAP2 SUB - // stack:num_bytes_new, num_bytes%16, ctx, segment, offset, retdest, total_num_limbs, len, new_limb, ..limbs + // stack: num_bytes_new, num_bytes%16, addr, retdest, total_num_limbs, len, new_limb, ..limbs DUP1 ISZERO %jumpi(mload_bytes_return) SWAP1 - // stack: num_bytes%16, num_bytes_new, ctx, segment, offset, retdest, total_num_limbs, len, new_limb, ..limbs - DUP5 // offset - ADD - // stack: offset_new, num_bytes_new, ctx, segment, offset, retdest, total_num_limbs, len, new_limb, ..limbs - SWAP4 POP - // stack: num_bytes_new, ctx, segment, offset_new, retdest, total_num_limbs, len, new_limb, ..limbs - %stack (num, addr: 3) -> (addr, num) + // stack: num_bytes%16, num_bytes_new, addr, retdest, total_num_limbs, len, new_limb, ..limbs + DUP3 // addr + ADD // increment offset + // stack: addr_new, num_bytes_new, addr, retdest, total_num_limbs, len, new_limb, ..limbs + SWAP2 POP + // stack: num_bytes_new, addr_new, retdest, total_num_limbs, len, new_limb, ..limbs + SWAP1 %jump(mload_bytes_as_limbs) mload_bytes_return: - // stack: num_bytes_new, num_bytes%16, ctx, segment, offset, retdest, total_num_limbs, len, new_limb, ..limbs - %pop5 + // stack: num_bytes_new, num_bytes%16, addr, retdest, total_num_limbs, len, new_limb, ..limbs + %pop3 // stack: retdest, total_num_limbs, len, ..limbs JUMP %macro mload_bytes_as_limbs - %stack (ctx, segment, offset, num_bytes, total_num_limbs) -> (ctx, segment, offset, num_bytes, %%after, total_num_limbs) + %stack (addr, num_bytes, total_num_limbs) -> (addr, num_bytes, %%after, total_num_limbs) %jump(mload_bytes_as_limbs) %%after: %endmacro @@ -112,6 +112,7 @@ calculate_l_E_prime: // stack: 96 + l_B, 32, l_E, l_B, retdest PUSH @SEGMENT_CALLDATA GET_CONTEXT + %build_address %mload_packing // stack: i[96 + l_B..128 + l_B], l_E, l_B, retdest %log2_floor @@ -142,6 +143,7 @@ case_le_32: // stack: 96 + l_B, l_E, retdest PUSH @SEGMENT_CALLDATA GET_CONTEXT + %build_address %mload_packing // stack: E, retdest %log2_floor @@ -165,22 +167,25 @@ global precompile_expmod: // stack: kexit_info // Load l_B from i[0..32]. - %stack () -> (@SEGMENT_CALLDATA, 0, 32) - // stack: @SEGMENT_CALLDATA, 0, 32, kexit_info + %stack () -> (@SEGMENT_CALLDATA, 32) + // stack: @SEGMENT_CALLDATA, 32, kexit_info GET_CONTEXT - // stack: ctx, @SEGMENT_CALLDATA, 0, 32, kexit_info + // stack: ctx, @SEGMENT_CALLDATA, 32, kexit_info + %build_address_no_offset %mload_packing // stack: l_B, kexit_info // Load l_E from i[32..64]. %stack () -> (@SEGMENT_CALLDATA, 32, 32) GET_CONTEXT + %build_address %mload_packing // stack: l_E, l_B, kexit_info // Load l_M from i[64..96]. %stack () -> (@SEGMENT_CALLDATA, 64, 32) GET_CONTEXT + %build_address %mload_packing // stack: l_M, l_E, l_B, kexit_info DUP3 ISZERO DUP2 ISZERO @@ -247,6 +252,7 @@ l_E_prime_return: %stack () -> (@SEGMENT_CALLDATA, 96) GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 96, num_bytes, num_limbs, len, len, l_M, l_E, l_B, kexit_info + %build_address %mload_bytes_as_limbs // stack: num_limbs, len, limbs[num_limbs-1], .., limbs[0], len, l_M, l_E, l_B, kexit_info SWAP1 @@ -282,6 +288,7 @@ copy_b_end: PUSH @SEGMENT_CALLDATA GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 96 + l_B, num_bytes, num_limbs, len, len, l_M, l_E, l_B, kexit_info + %build_address %mload_bytes_as_limbs // stack: num_limbs, len, limbs[num_limbs-1], .., limbs[0], len, l_M, l_E, l_B, kexit_info SWAP1 @@ -316,6 +323,7 @@ copy_e_end: PUSH @SEGMENT_CALLDATA GET_CONTEXT // stack: ctx, @SEGMENT_CALLDATA, 96 + l_B + l_E, num_bytes, num_limbs, len, len, l_M, l_E, l_B, kexit_info + %build_address %mload_bytes_as_limbs // stack: num_limbs, len, limbs[num_limbs-1], .., limbs[0], len, l_M, l_E, l_B, kexit_info SWAP1 @@ -410,33 +418,33 @@ expmod_contd: DUP2 DUP2 ADD - // stack: cur_address=out+l_M_128-1, end_address=out-1, l_M_128, l_M%16, kexit_info + // stack: cur_offset=out+l_M_128-1, end_offset=out-1, l_M_128, l_M%16, kexit_info DUP1 %mload_current_general - %stack (cur_limb, cur_address, end_address, l_M_128, l_M_mod16, kexit_info) -> - (@SEGMENT_RETURNDATA, 0, cur_limb, l_M_mod16, cur_address, end_address, l_M_128, kexit_info) + %stack (cur_limb, cur_offset, end_offset, l_M_128, l_M_mod16, kexit_info) -> + (@SEGMENT_RETURNDATA, cur_limb, l_M_mod16, cur_offset, end_offset, l_M_128, kexit_info) %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) + %build_address_no_offset %mstore_unpacking - // stack: offset, cur_address, end_address, l_M_128, kexit_info + // stack: address, cur_offset, end_offset, l_M_128, kexit_info SWAP1 %decrement - // stack: cur_address, offset, end_address, l_M_128, kexit_info + // stack: cur_offset, address, end_offset, l_M_128, kexit_info // Store in big-endian format. expmod_store_loop: - // stack: cur_address, offset, end_address, l_M_128, kexit_info + // stack: cur_offset, address, end_offset, l_M_128, kexit_info DUP3 DUP2 EQ %jumpi(expmod_store_end) - // stack: cur_address, offset, end_address, l_M_128, kexit_info + // stack: cur_offset, address, end_offset, l_M_128, kexit_info DUP1 %mload_current_general - %stack (cur_limb, cur_address, offset, end_address, l_M_128, kexit_info) -> - (offset, cur_limb, cur_address, end_address, l_M_128, kexit_info) - %stack (offset, cur_limb) -> (@SEGMENT_RETURNDATA, offset, cur_limb, 16) - %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) + %stack (cur_limb, cur_offset, address, end_offset, l_M_128, kexit_info) -> + (address, cur_limb, cur_offset, end_offset, l_M_128, kexit_info) + %stack (address, cur_limb) -> (address, cur_limb, 16) %mstore_unpacking - // stack: offset', cur_address, end_address, l_M_128, kexit_info) + // stack: address', cur_offset, end_offset, l_M_128, kexit_info) SWAP1 %decrement - // stack: cur_address-1, offset', end_address, l_M_128, kexit_info) + // stack: cur_offset-1, address', end_offset, l_M_128, kexit_info) %jump(expmod_store_loop) expmod_store_end: - // stack: cur_address, offset, end_address, l_M_128, kexit_info + // stack: cur_offset, address, end_offset, l_M_128, kexit_info %pop4 the_end: // stack: kexit_info diff --git a/evm/src/cpu/kernel/asm/core/precompiles/id.asm b/evm/src/cpu/kernel/asm/core/precompiles/id.asm index 83cee0d042..a606ef4a85 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/id.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/id.asm @@ -24,14 +24,19 @@ global precompile_id: // Simply copy the call data to the parent's return data. %calldatasize DUP1 %mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE) + + PUSH id_contd SWAP1 + + PUSH @SEGMENT_CALLDATA GET_CONTEXT + %build_address_no_offset + // stack: SRC, size, id_contd + + PUSH @SEGMENT_RETURNDATA %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - %stack (parent_ctx, ctx, size) -> - ( - parent_ctx, @SEGMENT_RETURNDATA, 0, // DST - ctx, @SEGMENT_CALLDATA, 0, // SRC - size, id_contd // count, retdest - ) + %build_address_no_offset + + // stack: DST, SRC, size, id_contd %jump(memcpy_bytes) id_contd: diff --git a/evm/src/cpu/kernel/asm/core/precompiles/main.asm b/evm/src/cpu/kernel/asm/core/precompiles/main.asm index d6cb100bdc..b7c916e9c4 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/main.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/main.asm @@ -58,7 +58,9 @@ global handle_precompiles_from_eoa: %mload_txn_field(@TXN_FIELD_DATA_LEN) %stack (calldata_size, new_ctx) -> (calldata_size, new_ctx, calldata_size) %set_new_ctx_calldata_size - %stack (new_ctx, calldata_size) -> (new_ctx, @SEGMENT_CALLDATA, 0, 0, @SEGMENT_TXN_DATA, 0, calldata_size, handle_precompiles_from_eoa_finish, new_ctx) + %stack (new_ctx, calldata_size) -> (@SEGMENT_TXN_DATA, @SEGMENT_CALLDATA, new_ctx, calldata_size, handle_precompiles_from_eoa_finish, new_ctx) + SWAP2 %build_address_no_offset // DST + // stack: DST, SRC, calldata_size, handle_precompiles_from_eoa_finish, new_ctx %jump(memcpy_bytes) handle_precompiles_from_eoa_finish: diff --git a/evm/src/cpu/kernel/asm/core/precompiles/rip160.asm b/evm/src/cpu/kernel/asm/core/precompiles/rip160.asm index 0e5aee8cb1..0231baf0eb 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/rip160.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/rip160.asm @@ -25,27 +25,17 @@ global precompile_rip160: %calldatasize GET_CONTEXT - // The next block of code is equivalent to the following %stack macro call - // (unfortunately the macro call takes too long to expand dynamically). - // - // %stack (ctx, size) -> - // ( - // ctx, @SEGMENT_KERNEL_GENERAL, 200, // DST - // ctx, @SEGMENT_CALLDATA, 0, // SRC - // size, ripemd, // count, retdest - // 200, size, rip160_contd // ripemd input: virt, num_bytes, retdest - // ) - PUSH 200 - PUSH ripemd - DUP4 - PUSH 0 - PUSH @SEGMENT_CALLDATA - PUSH rip160_contd - SWAP7 - SWAP6 - PUSH 200 - PUSH @SEGMENT_KERNEL_GENERAL - DUP3 + %stack (ctx, size) -> + ( + ctx, @SEGMENT_CALLDATA, // SRC + ctx, + size, ripemd, // count, retdest + 200, size, rip160_contd // ripemd input: virt, num_bytes, retdest + ) + %build_address_no_offset + %stack(addr, ctx) -> (ctx, @SEGMENT_KERNEL_GENERAL, 200, addr) + %build_address + // stack: DST, SRC, count, retdest, virt, num_bytes, retdest %jump(memcpy_bytes) @@ -54,5 +44,6 @@ rip160_contd: // Store the result hash to the parent's return data using `mstore_unpacking`. %mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32) %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - %stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, hash, 32, pop_and_return_success) + %stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, hash, 32, pop_and_return_success) + %build_address_no_offset %jump(mstore_unpacking) diff --git a/evm/src/cpu/kernel/asm/core/precompiles/sha256.asm b/evm/src/cpu/kernel/asm/core/precompiles/sha256.asm index 6dad0745ba..b537cd4c7b 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/sha256.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/sha256.asm @@ -24,30 +24,18 @@ global precompile_sha256: // Copy the call data to the kernel general segment (sha2 expects it there) and call sha2. %calldatasize GET_CONTEXT - // stack: ctx, size - // The next block of code is equivalent to the following %stack macro call - // (unfortunately the macro call takes too long to expand dynamically). - // - // %stack (ctx, size) -> - // ( - // ctx, @SEGMENT_KERNEL_GENERAL, 1, // DST - // ctx, @SEGMENT_CALLDATA, 0, // SRC - // size, sha2, // count, retdest - // 0, size, sha256_contd // sha2 input: virt, num_bytes, retdest - // ) - // - PUSH 0 - PUSH sha2 - DUP4 - PUSH 0 - PUSH @SEGMENT_CALLDATA - PUSH sha256_contd - SWAP7 - SWAP6 - PUSH 1 - PUSH @SEGMENT_KERNEL_GENERAL - DUP3 + %stack (ctx, size) -> + ( + ctx, @SEGMENT_CALLDATA, // SRC + ctx, + size, sha2, // count, retdest + 0, size, sha256_contd // sha2 input: virt, num_bytes, retdest + ) + %build_address_no_offset + %stack(addr, ctx) -> (ctx, @SEGMENT_KERNEL_GENERAL, 1, addr) + %build_address + // stack: DST, SRC, count, retdest, virt, num_bytes, retdest %jump(memcpy_bytes) @@ -56,5 +44,6 @@ sha256_contd: // Store the result hash to the parent's return data using `mstore_unpacking`. %mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32) %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - %stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, hash, 32, pop_and_return_success) + %stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, hash, 32, pop_and_return_success) + %build_address_no_offset %jump(mstore_unpacking) diff --git a/evm/src/cpu/kernel/asm/core/precompiles/snarkv.asm b/evm/src/cpu/kernel/asm/core/precompiles/snarkv.asm index f128cd51ad..2d990d09d9 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/snarkv.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/snarkv.asm @@ -31,18 +31,21 @@ loading_loop: // stack: px, i, k, kexit_info GET_CONTEXT %stack (ctx, px) -> (ctx, @SEGMENT_CALLDATA, px, 32, loading_loop_contd, px) + %build_address %jump(mload_packing) loading_loop_contd: // stack: x, px, i, k, kexit_info SWAP1 %add_const(32) GET_CONTEXT %stack (ctx, py) -> (ctx, @SEGMENT_CALLDATA, py, 32, loading_loop_contd2, py) + %build_address %jump(mload_packing) loading_loop_contd2: // stack: y, py, x, i, k, kexit_info SWAP1 %add_const(32) GET_CONTEXT %stack (ctx, px_im) -> (ctx, @SEGMENT_CALLDATA, px_im, 32, loading_loop_contd3, px_im) + %build_address %jump(mload_packing) loading_loop_contd3: // stack: x_im, px_im, y, x, i, k, kexit_info @@ -50,6 +53,7 @@ loading_loop_contd3: // stack: px_re, x_im, y, x, i, k, kexit_info GET_CONTEXT %stack (ctx, px_re) -> (ctx, @SEGMENT_CALLDATA, px_re, 32, loading_loop_contd4, px_re) + %build_address %jump(mload_packing) loading_loop_contd4: // stack: x_re, px_re, x_im, y, x, i, k, kexit_info @@ -57,6 +61,7 @@ loading_loop_contd4: // stack: py_im, x_re, x_im, y, x, i, k, kexit_info GET_CONTEXT %stack (ctx, py_im) -> (ctx, @SEGMENT_CALLDATA, py_im, 32, loading_loop_contd5, py_im) + %build_address %jump(mload_packing) loading_loop_contd5: // stack: y_im, py_im, x_re, x_im, y, x, i, k, kexit_info @@ -64,6 +69,7 @@ loading_loop_contd5: // stack: py_re, y_im, x_re, x_im, y, x, i, k, kexit_info GET_CONTEXT %stack (ctx, py_re) -> (ctx, @SEGMENT_CALLDATA, py_re, 32, loading_loop_contd6) + %build_address %jump(mload_packing) loading_loop_contd6: // stack: y_re, y_im, x_re, x_im, y, x, i, k, kexit_info @@ -118,5 +124,6 @@ got_result: // Store the result bool (repr. by a U256) to the parent's return data using `mstore_unpacking`. %mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32) %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - %stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, address, 32, pop_and_return_success) + %stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, address, 32, pop_and_return_success) + %build_address_no_offset %jump(mstore_unpacking) diff --git a/evm/src/cpu/kernel/asm/core/process_txn.asm b/evm/src/cpu/kernel/asm/core/process_txn.asm index df39b9d814..c70287a6f9 100644 --- a/evm/src/cpu/kernel/asm/core/process_txn.asm +++ b/evm/src/cpu/kernel/asm/core/process_txn.asm @@ -12,11 +12,11 @@ global process_normalized_txn: // Compute this transaction's intrinsic gas and store it. %intrinsic_gas + DUP1 %mstore_txn_field(@TXN_FIELD_INTRINSIC_GAS) - // stack: retdest + // stack: intrinsic_gas, retdest // Assert gas_limit >= intrinsic_gas. - %mload_txn_field(@TXN_FIELD_INTRINSIC_GAS) %mload_txn_field(@TXN_FIELD_GAS_LIMIT) %assert_ge(invalid_txn) @@ -146,23 +146,20 @@ global process_contract_creation_txn: // Store constructor code length PUSH @CTX_METADATA_CODE_SIZE - PUSH @SEGMENT_CONTEXT_METADATA - // stack: segment, offset, new_ctx, address, retdest - DUP3 // new_ctx + // stack: offset, new_ctx, address, retdest + DUP2 // new_ctx + ADD // CTX_METADATA_CODE_SIZE is already scaled by its segment + // stack: addr, new_ctx, address, retdest %mload_txn_field(@TXN_FIELD_DATA_LEN) - // stack: data_len, new_ctx, segment, offset, new_ctx, address, retdest + // stack: data_len, addr, new_ctx, address, retdest MSTORE_GENERAL // stack: new_ctx, address, retdest // Copy the code from txdata to the new context's code segment. PUSH process_contract_creation_txn_after_code_loaded %mload_txn_field(@TXN_FIELD_DATA_LEN) - PUSH 0 // SRC.offset - PUSH @SEGMENT_TXN_DATA // SRC.segment - PUSH 0 // SRC.context - PUSH 0 // DST.offset - PUSH @SEGMENT_CODE // DST.segment - DUP8 // DST.context = new_ctx + PUSH @SEGMENT_TXN_DATA // SRC (context == offset == 0) + DUP4 // DST (segment == 0 (i.e. CODE), and offset == 0) %jump(memcpy_bytes) global process_contract_creation_txn_after_code_loaded: @@ -203,9 +200,11 @@ global process_contract_creation_txn_after_constructor: // Store the code hash of the new contract. // stack: leftover_gas, new_ctx, address, retdest, success - GET_CONTEXT %returndatasize - %stack (size, ctx) -> (ctx, @SEGMENT_RETURNDATA, 0, size) // context, segment, offset, len + PUSH @SEGMENT_RETURNDATA + GET_CONTEXT + %build_address_no_offset + // stack: addr, len KECCAK_GENERAL // stack: codehash, leftover_gas, new_ctx, address, retdest, success %observe_new_contract @@ -292,7 +291,8 @@ global process_message_txn_code_loaded: %mload_txn_field(@TXN_FIELD_DATA_LEN) %stack (calldata_size, new_ctx, retdest) -> (calldata_size, new_ctx, calldata_size, retdest) %set_new_ctx_calldata_size - %stack (new_ctx, calldata_size, retdest) -> (new_ctx, @SEGMENT_CALLDATA, 0, 0, @SEGMENT_TXN_DATA, 0, calldata_size, process_message_txn_code_loaded_finish, new_ctx, retdest) + %stack (new_ctx, calldata_size, retdest) -> (new_ctx, @SEGMENT_CALLDATA, @SEGMENT_TXN_DATA, calldata_size, process_message_txn_code_loaded_finish, new_ctx, retdest) + %build_address_no_offset // DST %jump(memcpy_bytes) process_message_txn_code_loaded_finish: diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index 0c5d5a8f3e..a9b9bc122a 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -33,18 +33,26 @@ return_after_gas: // Store the return data size in the parent context's metadata. %stack (parent_ctx, kexit_info, offset, size) -> - (size, parent_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_RETURNDATA_SIZE, offset, size, parent_ctx, kexit_info) + (parent_ctx, @CTX_METADATA_RETURNDATA_SIZE, size, offset, size, parent_ctx, kexit_info) + ADD // addr (CTX offsets are already scaled by their segment) + SWAP1 + // stack: size, addr, offset, size, parent_ctx, kexit_info MSTORE_GENERAL // stack: offset, size, parent_ctx, kexit_info // Store the return data in the parent context's returndata segment. + PUSH @SEGMENT_MAIN_MEMORY GET_CONTEXT - %stack (ctx, offset, size, parent_ctx, kexit_info) -> + %build_address + + %stack (addr, size, parent_ctx, kexit_info) -> ( - parent_ctx, @SEGMENT_RETURNDATA, 0, // DST - ctx, @SEGMENT_MAIN_MEMORY, offset, // SRC + parent_ctx, @SEGMENT_RETURNDATA, // DST + addr, // SRC size, sys_return_finish, kexit_info // count, retdest, ... ) + %build_address_no_offset + // stack: DST, SRC, size, sys_return_finish, kexit_info %jump(memcpy_bytes) sys_return_finish: @@ -133,18 +141,26 @@ revert_after_gas: // Store the return data size in the parent context's metadata. %stack (parent_ctx, kexit_info, offset, size) -> - (size, parent_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_RETURNDATA_SIZE, offset, size, parent_ctx, kexit_info) + (parent_ctx, @CTX_METADATA_RETURNDATA_SIZE, size, offset, size, parent_ctx, kexit_info) + ADD // addr (CTX offsets are already scaled by their segment) + SWAP1 + // stack: size, addr, offset, size, parent_ctx, kexit_info MSTORE_GENERAL // stack: offset, size, parent_ctx, kexit_info // Store the return data in the parent context's returndata segment. + PUSH @SEGMENT_MAIN_MEMORY GET_CONTEXT - %stack (ctx, offset, size, parent_ctx, kexit_info) -> + %build_address + + %stack (addr, size, parent_ctx, kexit_info) -> ( - parent_ctx, @SEGMENT_RETURNDATA, 0, // DST - ctx, @SEGMENT_MAIN_MEMORY, offset, // SRC + parent_ctx, @SEGMENT_RETURNDATA, // DST + addr, // SRC size, sys_revert_finish, kexit_info // count, retdest, ... ) + %build_address_no_offset + // stack: DST, SRC, size, sys_revert_finish, kexit_info %jump(memcpy_bytes) sys_revert_finish: diff --git a/evm/src/cpu/kernel/asm/core/util.asm b/evm/src/cpu/kernel/asm/core/util.asm index ee33ff26ca..a77329bd8c 100644 --- a/evm/src/cpu/kernel/asm/core/util.asm +++ b/evm/src/cpu/kernel/asm/core/util.asm @@ -11,7 +11,7 @@ %macro next_context_id // stack: (empty) %mload_global_metadata(@GLOBAL_METADATA_LARGEST_CONTEXT) - %increment + %add_const(0x10000000000000000) // scale each context by 2^64 // stack: new_ctx DUP1 %mstore_global_metadata(@GLOBAL_METADATA_LARGEST_CONTEXT) @@ -83,7 +83,6 @@ SET_CONTEXT // stack: (empty) // We can now read this stack length from memory. - push @CTX_METADATA_STACK_SIZE - %mload_current(@SEGMENT_CONTEXT_METADATA) + %mload_context_metadata(@CTX_METADATA_STACK_SIZE) // stack: stack_length %endmacro diff --git a/evm/src/cpu/kernel/asm/curve/wnaf.asm b/evm/src/cpu/kernel/asm/curve/wnaf.asm index a416d1ba79..f554bc649d 100644 --- a/evm/src/cpu/kernel/asm/curve/wnaf.asm +++ b/evm/src/cpu/kernel/asm/curve/wnaf.asm @@ -34,8 +34,12 @@ wnaf_loop_contd: DUP2 SWAP1 SUB %stack (n, m, segment, o, retdest) -> (129, o, m, o, segment, n, retdest) SUB + // stack: i, m, o, segment, n, retdest + DUP4 GET_CONTEXT - %stack (ctx, i, m, o, segment, n, retdest) -> (m, ctx, segment, i, o, segment, n, retdest) + %build_address + // stack: addr, m, o, segment, n, retdest + SWAP1 MSTORE_GENERAL // stack: o, segment, n, retdest DUP3 ISZERO %jumpi(wnaf_end) diff --git a/evm/src/cpu/kernel/asm/main.asm b/evm/src/cpu/kernel/asm/main.asm index b495d49947..42e326a0ab 100644 --- a/evm/src/cpu/kernel/asm/main.asm +++ b/evm/src/cpu/kernel/asm/main.asm @@ -2,9 +2,7 @@ global main: // First, hash the kernel code %mload_global_metadata(@GLOBAL_METADATA_KERNEL_LEN) PUSH 0 - PUSH 0 - PUSH 0 - // stack: context, segment, virt, len + // stack: addr, len KECCAK_GENERAL // stack: hash %mload_global_metadata(@GLOBAL_METADATA_KERNEL_HASH) @@ -13,6 +11,10 @@ global main: // Initialise the shift table %shift_table_init + + // Initialize the RLP DATA pointer to its initial position (ctx == virt == 0, segment = RLP) + PUSH @SEGMENT_RLP_RAW + %mstore_global_metadata(@GLOBAL_METADATA_RLP_DATA_SIZE) // Initialize the state, transaction and receipt trie root pointers. PROVER_INPUT(trie_ptr::state) diff --git a/evm/src/cpu/kernel/asm/memory/core.asm b/evm/src/cpu/kernel/asm/memory/core.asm index a4c99cec15..3a3a17a500 100644 --- a/evm/src/cpu/kernel/asm/memory/core.asm +++ b/evm/src/cpu/kernel/asm/memory/core.asm @@ -1,39 +1,31 @@ // Load a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0). %macro mload_u32 - // stack: context, segment, offset - %stack (addr: 3) -> (addr, 4, %%after) + // stack: addr + %stack (addr) -> (addr, 4, %%after) %jump(mload_packing) %%after: %endmacro // Load a little-endian u32, consisting of 4 bytes (c_0, c_1, c_2, c_3). %macro mload_u32_LE - // stack: context, segment, offset - DUP3 - DUP3 - DUP3 + // stack: addr + DUP1 MLOAD_GENERAL - // stack: c0, context, segment, offset - DUP4 + // stack: c0, addr + DUP2 %increment - DUP4 - DUP4 MLOAD_GENERAL %shl_const(8) ADD - // stack: c0 | (c1 << 8), context, segment, offset - DUP4 + // stack: c0 | (c1 << 8), addr + DUP2 %add_const(2) - DUP4 - DUP4 MLOAD_GENERAL %shl_const(16) ADD - // stack: c0 | (c1 << 8) | (c2 << 16), context, segment, offset - SWAP3 - %add_const(3) - SWAP2 + // stack: c0 | (c1 << 8) | (c2 << 16), addr SWAP1 + %add_const(3) MLOAD_GENERAL %shl_const(24) ADD // OR @@ -42,16 +34,12 @@ // Load a little-endian u64, consisting of 8 bytes (c_0, ..., c_7). %macro mload_u64_LE - // stack: context, segment, offset - DUP3 - DUP3 - DUP3 + // stack: addr + DUP1 %mload_u32_LE - // stack: lo, context, segment, offset - SWAP3 - %add_const(4) - SWAP2 + // stack: lo, addr SWAP1 + %add_const(4) %mload_u32_LE // stack: hi, lo %shl_const(32) @@ -62,16 +50,16 @@ // Load a big-endian u256. %macro mload_u256 - // stack: context, segment, offset - %stack (addr: 3) -> (addr, 32, %%after) + // stack: addr + %stack (addr) -> (addr, 32, %%after) %jump(mload_packing) %%after: %endmacro // Store a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0). %macro mstore_u32 - // stack: context, segment, offset, value - %stack (addr: 3, value) -> (addr, value, 4, %%after) + // stack: addr, value + %stack (addr, value) -> (addr, value, 4, %%after) %jump(mstore_unpacking) %%after: // stack: offset @@ -88,6 +76,7 @@ // stack: segment, offset GET_CONTEXT // stack: context, segment, offset + %build_address MLOAD_GENERAL // stack: value %endmacro @@ -102,7 +91,8 @@ // stack: segment, offset, value GET_CONTEXT // stack: context, segment, offset, value - %stack(context, segment, offset, value) -> (value, context, segment, offset) + %build_address + SWAP1 MSTORE_GENERAL // stack: (empty) %endmacro @@ -115,7 +105,8 @@ // stack: segment, offset, value GET_CONTEXT // stack: context, segment, offset, value - %stack(context, segment, offset, value) -> (value, context, segment, offset) + %build_address + SWAP1 MSTORE_GENERAL // stack: (empty) %endmacro @@ -123,7 +114,10 @@ // Load a single byte from user code. %macro mload_current_code // stack: offset - %mload_current(@SEGMENT_CODE) + // SEGMENT_CODE == 0 + GET_CONTEXT ADD + // stack: addr + MLOAD_GENERAL // stack: value %endmacro @@ -141,6 +135,7 @@ // stack: segment, offset GET_CONTEXT // stack: context, segment, offset + %build_address %mload_u32 // stack: value %endmacro @@ -152,6 +147,7 @@ // stack: segment, offset GET_CONTEXT // stack: context, segment, offset + %build_address %mload_u32_LE // stack: value %endmacro @@ -163,6 +159,7 @@ // stack: segment, offset GET_CONTEXT // stack: context, segment, offset + %build_address %mload_u64_LE // stack: value %endmacro @@ -174,6 +171,7 @@ // stack: segment, offset GET_CONTEXT // stack: context, segment, offset + %build_address %mload_u256 // stack: value %endmacro @@ -185,7 +183,8 @@ // stack: segment, offset, value GET_CONTEXT // stack: context, segment, offset, value - %stack(context, segment, offset, value) -> (value, context, segment, offset) + %build_address + SWAP1 MSTORE_GENERAL // stack: (empty) %endmacro @@ -205,6 +204,7 @@ // stack: segment, offset, value GET_CONTEXT // stack: context, segment, offset, value + %build_address %mstore_u32 // stack: (empty) %endmacro @@ -224,8 +224,7 @@ // stack: offset PUSH $segment // stack: segment, offset - PUSH 0 // kernel has context 0 - // stack: context, segment, offset + %build_kernel_address MLOAD_GENERAL // stack: value %endmacro @@ -235,9 +234,9 @@ // stack: offset, value PUSH $segment // stack: segment, offset, value - PUSH 0 // kernel has context 0 - // stack: context, segment, offset, value - %stack(context, segment, offset, value) -> (value, context, segment, offset) + %build_kernel_address + // stack: addr, value + SWAP1 MSTORE_GENERAL // stack: (empty) %endmacro @@ -249,9 +248,9 @@ // stack: offset, value PUSH $segment // stack: segment, offset, value - PUSH 0 // kernel has context 0 - // stack: context, segment, offset, value - %stack(context, segment, offset, value) -> (value, context, segment, offset) + %build_kernel_address + // stack: addr, value + SWAP1 MSTORE_GENERAL // stack: (empty) %endmacro @@ -261,8 +260,7 @@ // stack: offset PUSH $segment // stack: segment, offset - PUSH 0 // kernel has context 0 - // stack: context, segment, offset + %build_kernel_address %mload_u32 %endmacro @@ -271,8 +269,7 @@ // stack: offset PUSH $segment // stack: segment, offset - PUSH 0 // kernel has context 0 - // stack: context, segment, offset + %build_kernel_address %mload_u32_LE %endmacro @@ -281,8 +278,7 @@ // stack: offset PUSH $segment // stack: segment, offset - PUSH 0 // kernel has context 0 - // stack: context, segment, offset + %build_kernel_address %mload_u64_LE %endmacro @@ -291,8 +287,7 @@ // stack: offset PUSH $segment // stack: segment, offset - PUSH 0 // kernel has context 0 - // stack: context, segment, offset + %build_kernel_address %mload_u256 %endmacro @@ -302,15 +297,16 @@ // stack: offset, value PUSH $segment // stack: segment, offset, value - PUSH 0 // kernel has context 0 - // stack: context, segment, offset, value + %build_kernel_address + // stack: addr, value %mstore_u32 %endmacro // Load a single byte from kernel code. %macro mload_kernel_code // stack: offset - %mload_kernel(@SEGMENT_CODE) + // ctx == SEGMENT_CODE == 0 + MLOAD_GENERAL // stack: value %endmacro @@ -327,7 +323,8 @@ // from kernel code. %macro mload_kernel_code_u32 // stack: offset - %mload_kernel_u32(@SEGMENT_CODE) + // ctx == SEGMENT_CODE == 0 + %mload_u32 // stack: value %endmacro @@ -338,7 +335,8 @@ PUSH $label ADD // stack: offset - %mload_kernel_u32(@SEGMENT_CODE) + // ctx == SEGMENT_CODE == 0 + %mload_u32 // stack: value %endmacro @@ -383,7 +381,8 @@ // Load a u256 (big-endian) from kernel code. %macro mload_kernel_code_u256 // stack: offset - %mload_kernel_u256(@SEGMENT_CODE) + // ctx == SEGMENT_CODE == 0 + %mload_u256 // stack: value %endmacro @@ -397,7 +396,8 @@ // Store a single byte to kernel code. %macro mstore_kernel_code // stack: offset, value - %mstore_kernel(@SEGMENT_CODE) + // ctx == SEGMENT_CODE == 0 + MLOAD_GENERAL // stack: (empty) %endmacro @@ -405,13 +405,15 @@ // to kernel code. %macro mstore_kernel_code_u32 // stack: offset, value - %mstore_kernel_u32(@SEGMENT_CODE) + // ctx == SEGMENT_CODE == 0 + %mstore_u32 %endmacro // Store a single byte to @SEGMENT_RLP_RAW. %macro mstore_rlp - // stack: offset, value - %mstore_kernel(@SEGMENT_RLP_RAW) + // stack: addr, value + SWAP1 + MSTORE_GENERAL // stack: (empty) %endmacro diff --git a/evm/src/cpu/kernel/asm/memory/memcpy.asm b/evm/src/cpu/kernel/asm/memory/memcpy.asm index 9dd2305d8d..a7819bf6e8 100644 --- a/evm/src/cpu/kernel/asm/memory/memcpy.asm +++ b/evm/src/cpu/kernel/asm/memory/memcpy.asm @@ -1,25 +1,16 @@ -// Copies `count` values from -// SRC = (src_ctx, src_segment, src_addr) -// to -// DST = (dst_ctx, dst_segment, dst_addr). -// These tuple definitions are used for brevity in the stack comments below. +// Copies `count` values from SRC to DST. global memcpy: // stack: DST, SRC, count, retdest - DUP7 + DUP3 // stack: count, DST, SRC, count, retdest ISZERO // stack: count == 0, DST, SRC, count, retdest %jumpi(memcpy_finish) // stack: DST, SRC, count, retdest - DUP3 - DUP3 - DUP3 + DUP1 - // Copy the next value - // stack: DST, DST, SRC, count, retdest - DUP9 - DUP9 - DUP9 + // Copy the next value. + DUP3 // stack: SRC, DST, DST, SRC, count, retdest MLOAD_GENERAL // stack: value, DST, DST, SRC, count, retdest @@ -27,23 +18,19 @@ global memcpy: // stack: DST, SRC, count, retdest // Increment dst_addr. - SWAP2 %increment - SWAP2 // Increment src_addr. - SWAP5 + SWAP1 %increment - SWAP5 + SWAP1 // Decrement count. - SWAP6 - %decrement - SWAP6 + PUSH 1 DUP4 SUB SWAP3 POP // Continue the loop. %jump(memcpy) %macro memcpy - %stack (dst: 3, src: 3, count) -> (dst, src, count, %%after) + %stack (dst, src, count) -> (dst, src, count, %%after) %jump(memcpy) %%after: %endmacro @@ -53,7 +40,7 @@ global memcpy_bytes: // stack: DST, SRC, count, retdest // Handle small case - DUP7 + DUP3 // stack: count, DST, SRC, count, retdest %lt_const(0x21) // stack: count <= 32, DST, SRC, count, retdest @@ -61,31 +48,22 @@ global memcpy_bytes: // We will pack 32 bytes into a U256 from the source, and then unpack it at the destination. // Copy the next chunk of bytes. + // stack: DST, SRC, count, retdest PUSH 32 - DUP7 - DUP7 - DUP7 + DUP3 // stack: SRC, 32, DST, SRC, count, retdest MLOAD_32BYTES // stack: value, DST, SRC, count, retdest - DUP4 - DUP4 - DUP4 - // stack: DST, value, DST, SRC, count, retdest + SWAP1 + // stack: DST, value, SRC, count, retdest MSTORE_32BYTES_32 - // stack: new_offset, DST, SRC, count, retdest - // Increment dst_addr by 32. - SWAP3 - POP - // stack: DST, SRC, count, retdest - // Increment src_addr by 32. - SWAP5 + // stack: DST', SRC, count, retdest + // Increment SRC by 32. + SWAP1 %add_const(0x20) - SWAP5 + SWAP1 // Decrement count by 32. - SWAP6 - %sub_const(0x20) - SWAP6 + PUSH 32 DUP4 SUB SWAP3 POP // Continue the loop. %jump(memcpy_bytes) @@ -94,7 +72,7 @@ memcpy_bytes_finish: // stack: DST, SRC, count, retdest // Handle empty case - DUP7 + DUP3 // stack: count, DST, SRC, count, retdest ISZERO // stack: count == 0, DST, SRC, count, retdest @@ -103,17 +81,13 @@ memcpy_bytes_finish: // stack: DST, SRC, count, retdest // Copy the last chunk of `count` bytes. - DUP7 + DUP3 DUP1 - DUP8 - DUP8 - DUP8 + DUP4 // stack: SRC, count, count, DST, SRC, count, retdest MLOAD_32BYTES // stack: value, count, DST, SRC, count, retdest - DUP5 - DUP5 - DUP5 + DUP3 // stack: DST, value, count, DST, SRC, count, retdest %mstore_unpacking // stack: new_offset, DST, SRC, count, retdest @@ -121,12 +95,12 @@ memcpy_bytes_finish: memcpy_finish: // stack: DST, SRC, count, retdest - %pop7 + %pop3 // stack: retdest JUMP %macro memcpy_bytes - %stack (dst: 3, src: 3, count) -> (dst, src, count, %%after) + %stack (dst, src, count) -> (dst, src, count, %%after) %jump(memcpy_bytes) %%after: %endmacro diff --git a/evm/src/cpu/kernel/asm/memory/memset.asm b/evm/src/cpu/kernel/asm/memory/memset.asm index 97e5dae876..792aeabc68 100644 --- a/evm/src/cpu/kernel/asm/memory/memset.asm +++ b/evm/src/cpu/kernel/asm/memory/memset.asm @@ -1,11 +1,9 @@ -// Sets `count` values to 0 at -// DST = (dst_ctx, dst_segment, dst_addr). -// This tuple definition is used for brevity in the stack comments below. +// Sets `count` values to 0 at DST. global memset: // stack: DST, count, retdest // Handle small case - DUP4 + DUP2 // stack: count, DST, count, retdest %lt_const(0x21) // stack: count <= 32, DST, count, retdest @@ -13,20 +11,12 @@ global memset: // stack: DST, count, retdest PUSH 0 - DUP4 - DUP4 - DUP4 - // stack: DST, 0, DST, count, retdest + SWAP1 + // stack: DST, 0, count, retdest MSTORE_32BYTES_32 - // stack: new_offset, DST, count, retdest - - // Update dst_addr. - SWAP3 - POP + // stack: DST', count, retdest // Decrement count. - SWAP3 - %sub_const(0x20) - SWAP3 + PUSH 32 DUP3 SUB SWAP2 POP // Continue the loop. %jump(memset) @@ -35,27 +25,25 @@ memset_finish: // stack: DST, final_count, retdest // Handle empty case - DUP4 + DUP2 // stack: final_count, DST, final_count, retdest ISZERO // stack: final_count == 0, DST, final_count, retdest %jumpi(memset_bytes_empty) // stack: DST, final_count, retdest - DUP4 + DUP2 PUSH 0 - DUP5 - DUP5 - DUP5 + DUP3 // stack: DST, 0, final_count, DST, final_count, retdest %mstore_unpacking - // stack: new_offset, DST, final_count, retdest - %pop5 + // stack: DST, final_count, retdest + %pop3 // stack: retdest JUMP memset_bytes_empty: // stack: DST, 0, retdest - %pop4 + %pop2 // stack: retdest JUMP diff --git a/evm/src/cpu/kernel/asm/memory/metadata.asm b/evm/src/cpu/kernel/asm/memory/metadata.asm index 625b57f179..dfbfb6460b 100644 --- a/evm/src/cpu/kernel/asm/memory/metadata.asm +++ b/evm/src/cpu/kernel/asm/memory/metadata.asm @@ -1,62 +1,104 @@ // Load the given global metadata field from memory. %macro mload_global_metadata(field) + // Global metadata are already scaled by their corresponding segment, + // effectively making them the direct memory position to read from / + // write to. + // stack: (empty) PUSH $field - // stack: offset - %mload_kernel(@SEGMENT_GLOBAL_METADATA) + MLOAD_GENERAL // stack: value %endmacro // Store the given global metadata field to memory. %macro mstore_global_metadata(field) + // Global metadata are already scaled by their corresponding segment, + // effectively making them the direct memory position to read from / + // write to. + // stack: value PUSH $field - // stack: offset, value - %mstore_kernel(@SEGMENT_GLOBAL_METADATA) + SWAP1 + MSTORE_GENERAL // stack: (empty) %endmacro // Load the given context metadata field from memory. %macro mload_context_metadata(field) + // Context metadata are already scaled by their corresponding segment, + // effectively making them the direct memory position to read from / + // write to. + // stack: (empty) PUSH $field - // stack: offset - %mload_current(@SEGMENT_CONTEXT_METADATA) + GET_CONTEXT + ADD + // stack: addr + MLOAD_GENERAL // stack: value %endmacro // Store the given context metadata field to memory. %macro mstore_context_metadata(field) + // Context metadata are already scaled by their corresponding segment, + // effectively making them the direct memory position to read from / + // write to. + // stack: value PUSH $field - // stack: offset, value - %mstore_current(@SEGMENT_CONTEXT_METADATA) + GET_CONTEXT + ADD + // stack: addr, value + SWAP1 + MSTORE_GENERAL // stack: (empty) %endmacro // Store the given context metadata field to memory. %macro mstore_context_metadata(field, value) - PUSH $value + // Context metadata are already scaled by their corresponding segment, + // effectively making them the direct memory position to read from / + // write to. + PUSH $field - // stack: offset, value - %mstore_current(@SEGMENT_CONTEXT_METADATA) + GET_CONTEXT + ADD + // stack: addr + PUSH $value + // stack: value, addr + MSTORE_GENERAL // stack: (empty) %endmacro %macro mstore_parent_context_metadata(field) + // Context metadata are already scaled by their corresponding segment, + // effectively making them the direct memory position to read from / + // write to. + // stack: value %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - %stack (parent_ctx, value) -> - (value, parent_ctx, @SEGMENT_CONTEXT_METADATA, $field) + + // stack: parent_ctx, value + PUSH $field ADD + // stack: addr, value + SWAP1 MSTORE_GENERAL // stack: (empty) %endmacro %macro mstore_parent_context_metadata(field, value) + // Context metadata are already scaled by their corresponding segment, + // effectively making them the direct memory position to read from / + // write to. + // stack: (empty) %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) - %stack (parent_ctx) -> - ($value, parent_ctx, @SEGMENT_CONTEXT_METADATA, $field) + + // stack: parent_ctx + PUSH $field ADD + // stack: addr + PUSH $value + // stack: value, addr MSTORE_GENERAL // stack: (empty) %endmacro diff --git a/evm/src/cpu/kernel/asm/memory/packing.asm b/evm/src/cpu/kernel/asm/memory/packing.asm index 1feeeaf8fa..9b2d6cdd3b 100644 --- a/evm/src/cpu/kernel/asm/memory/packing.asm +++ b/evm/src/cpu/kernel/asm/memory/packing.asm @@ -2,11 +2,10 @@ // decoding bytes as integers. All big-endian. // Given a pointer to some bytes in memory, pack them into a word. Assumes 0 < len <= 32. -// Pre stack: addr: 3, len, retdest +// Pre stack: addr, len, retdest // Post stack: packed_value -// NOTE: addr: 3 denotes a (context, segment, virtual) tuple global mload_packing: - // stack: addr: 3, len, retdest + // stack: addr, len, retdest MLOAD_32BYTES // stack: packed_value, retdest SWAP1 @@ -14,50 +13,50 @@ global mload_packing: JUMP %macro mload_packing - %stack (addr: 3, len) -> (addr, len, %%after) + %stack (addr, len) -> (addr, len, %%after) %jump(mload_packing) %%after: %endmacro global mload_packing_u64_LE: - // stack: context, segment, offset, retdest - DUP3 DUP3 DUP3 MLOAD_GENERAL - DUP4 %add_const(1) DUP4 DUP4 MLOAD_GENERAL %shl_const( 8) ADD - DUP4 %add_const(2) DUP4 DUP4 MLOAD_GENERAL %shl_const(16) ADD - DUP4 %add_const(3) DUP4 DUP4 MLOAD_GENERAL %shl_const(24) ADD - DUP4 %add_const(4) DUP4 DUP4 MLOAD_GENERAL %shl_const(32) ADD - DUP4 %add_const(5) DUP4 DUP4 MLOAD_GENERAL %shl_const(40) ADD - DUP4 %add_const(6) DUP4 DUP4 MLOAD_GENERAL %shl_const(48) ADD - DUP4 %add_const(7) DUP4 DUP4 MLOAD_GENERAL %shl_const(56) ADD - %stack (value, context, segment, offset, retdest) -> (retdest, value) + // stack: addr, retdest + DUP1 MLOAD_GENERAL + DUP2 %add_const(1) MLOAD_GENERAL %shl_const( 8) ADD + DUP2 %add_const(2) MLOAD_GENERAL %shl_const(16) ADD + DUP2 %add_const(3) MLOAD_GENERAL %shl_const(24) ADD + DUP2 %add_const(4) MLOAD_GENERAL %shl_const(32) ADD + DUP2 %add_const(5) MLOAD_GENERAL %shl_const(40) ADD + DUP2 %add_const(6) MLOAD_GENERAL %shl_const(48) ADD + DUP2 %add_const(7) MLOAD_GENERAL %shl_const(56) ADD + %stack (value, addr, retdest) -> (retdest, value) JUMP %macro mload_packing_u64_LE - %stack (addr: 3) -> (addr, %%after) + %stack (addr) -> (addr, %%after) %jump(mload_packing_u64_LE) %%after: %endmacro -// Pre stack: context, segment, offset, value, len, retdest -// Post stack: offset' +// Pre stack: addr, value, len, retdest +// Post stack: addr' global mstore_unpacking: - // stack: context, segment, offset, value, len, retdest - DUP5 ISZERO - // stack: len == 0, context, segment, offset, value, len, retdest + // stack: addr, value, len, retdest + DUP3 ISZERO + // stack: len == 0, addr, value, len, retdest %jumpi(mstore_unpacking_empty) - %stack(context, segment, offset, value, len, retdest) -> (len, context, segment, offset, value, retdest) + %stack(addr, value, len, retdest) -> (len, addr, value, retdest) PUSH 3 - // stack: BYTES_PER_JUMP, len, context, segment, offset, value, retdest + // stack: BYTES_PER_JUMP, len, addr, value, retdest MUL - // stack: jump_offset, context, segment, offset, value, retdest + // stack: jump_offset, addr, value, retdest PUSH mstore_unpacking_0 - // stack: mstore_unpacking_0, jump_offset, context, segment, offset, value, retdest + // stack: mstore_unpacking_0, jump_offset, addr, value, retdest ADD - // stack: address_unpacking, context, segment, offset, value, retdest + // stack: address_unpacking, addr, value, retdest JUMP mstore_unpacking_empty: - %stack(context, segment, offset, value, len, retdest) -> (retdest, offset) + %stack(addr, value, len, retdest) -> (retdest, addr) JUMP // This case can never be reached. It's only here to offset the table correctly. @@ -66,274 +65,274 @@ mstore_unpacking_0: PANIC %endrep mstore_unpacking_1: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_1 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_2: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_2 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_3: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_3 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_4: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_4 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_5: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_5 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_6: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_6 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_7: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_7 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_8: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_8 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_9: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_9 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_10: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_10 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_11: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_11 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_12: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_12 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_13: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_13 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_14: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_14 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_15: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_15 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_16: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_16 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_17: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_17 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_18: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_18 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_19: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_19 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_20: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_20 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_21: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_21 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_22: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_22 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_23: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_23 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_24: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_24 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_25: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_25 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_26: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_26 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_27: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_27 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_28: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_28 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_29: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_29 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_30: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_30 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_31: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_31 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP mstore_unpacking_32: - // stack: context, segment, offset, value, retdest + // stack: addr, value, retdest MSTORE_32BYTES_32 - // stack: offset', retdest + // stack: addr', retdest SWAP1 - // stack: retdest, offset' + // stack: retdest, addr' JUMP %macro mstore_unpacking - %stack (addr: 3, value, len) -> (addr, value, len, %%after) + %stack (addr, value, len) -> (addr, value, len, %%after) %jump(mstore_unpacking) %%after: %endmacro -// Pre stack: context, segment, offset, value, retdest -// Post stack: offset' +// Pre stack: addr, value, retdest +// Post stack: addr' global mstore_unpacking_u64_LE: - %stack (context, segment, offset, value) -> (0xff, value, context, segment, offset, context, segment, offset, value) + %stack (addr, value) -> (0xff, value, addr, addr, value) AND MSTORE_GENERAL // First byte - DUP3 %add_const(1) - %stack (new_offset, context, segment, offset, value) -> (0xff00, value, context, segment, new_offset, context, segment, offset, value) + DUP1 %add_const(1) + %stack (new_addr, addr, value) -> (0xff00, value, new_addr, addr, value) AND %shr_const(8) MSTORE_GENERAL // Second byte - DUP3 %add_const(2) - %stack (new_offset, context, segment, offset, value) -> (0xff0000, value, context, segment, new_offset, context, segment, offset, value) + DUP1 %add_const(2) + %stack (new_addr, addr, value) -> (0xff0000, value, new_addr, addr, value) AND %shr_const(16) MSTORE_GENERAL // Third byte - DUP3 %add_const(3) - %stack (new_offset, context, segment, offset, value) -> (0xff000000, value, context, segment, new_offset, context, segment, offset, value) + DUP1 %add_const(3) + %stack (new_addr, addr, value) -> (0xff000000, value, new_addr, addr, value) AND %shr_const(24) MSTORE_GENERAL // Fourth byte - DUP3 %add_const(4) - %stack (new_offset, context, segment, offset, value) -> (0xff00000000, value, context, segment, new_offset, context, segment, offset, value) + DUP1 %add_const(4) + %stack (new_addr, addr, value) -> (0xff00000000, value, new_addr, addr, value) AND %shr_const(32) MSTORE_GENERAL // Fifth byte - DUP3 %add_const(5) - %stack (new_offset, context, segment, offset, value) -> (0xff0000000000, value, context, segment, new_offset, context, segment, offset, value) + DUP1 %add_const(5) + %stack (new_addr, addr, value) -> (0xff0000000000, value, new_addr, addr, value) AND %shr_const(40) MSTORE_GENERAL // Sixth byte - DUP3 %add_const(6) - %stack (new_offset, context, segment, offset, value) -> (0xff000000000000, value, context, segment, new_offset, context, segment, offset, value) + DUP1 %add_const(6) + %stack (new_addr, addr, value) -> (0xff000000000000, value, new_addr, addr, value) AND %shr_const(48) MSTORE_GENERAL // Seventh byte - DUP3 %add_const(7) - %stack (new_offset, context, segment, offset, value) -> (0xff00000000000000, value, context, segment, new_offset, context, segment, offset, value) + DUP1 %add_const(7) + %stack (new_addr, addr, value) -> (0xff00000000000000, value, new_addr, addr, value) AND %shr_const(56) MSTORE_GENERAL // Eighth byte - %pop4 JUMP + %pop2 JUMP %macro mstore_unpacking_u64_LE - %stack (addr: 3, value) -> (addr, value, %%after) + %stack (addr, value) -> (addr, value, %%after) %jump(mstore_unpacking_u64_LE) %%after: %endmacro diff --git a/evm/src/cpu/kernel/asm/memory/syscalls.asm b/evm/src/cpu/kernel/asm/memory/syscalls.asm index 9798f42474..a0af8b07db 100644 --- a/evm/src/cpu/kernel/asm/memory/syscalls.asm +++ b/evm/src/cpu/kernel/asm/memory/syscalls.asm @@ -11,7 +11,8 @@ global sys_mload: %stack(kexit_info, offset) -> (offset, 32, kexit_info) PUSH @SEGMENT_MAIN_MEMORY GET_CONTEXT - // stack: addr: 3, len, kexit_info + %build_address + // stack: addr, len, kexit_info MLOAD_32BYTES %stack (value, kexit_info) -> (kexit_info, value) EXIT_KERNEL @@ -29,7 +30,8 @@ global sys_mstore: %stack(kexit_info, offset, value) -> (offset, value, kexit_info) PUSH @SEGMENT_MAIN_MEMORY GET_CONTEXT - // stack: addr: 3, value, kexit_info + %build_address + // stack: addr, value, kexit_info MSTORE_32BYTES_32 POP // stack: kexit_info @@ -60,7 +62,8 @@ global sys_calldataload: LT %jumpi(calldataload_large_offset) %stack (kexit_info, i) -> (@SEGMENT_CALLDATA, i, 32, sys_calldataload_after_mload_packing, kexit_info) GET_CONTEXT - // stack: ADDR: 3, 32, sys_calldataload_after_mload_packing, kexit_info + %build_address + // stack: addr, 32, sys_calldataload_after_mload_packing, kexit_info %jump(mload_packing) sys_calldataload_after_mload_packing: // stack: value, kexit_info @@ -113,7 +116,10 @@ wcopy_within_bounds: // stack: segment, src_ctx, kexit_info, dest_offset, offset, size GET_CONTEXT %stack (context, segment, src_ctx, kexit_info, dest_offset, offset, size) -> - (context, @SEGMENT_MAIN_MEMORY, dest_offset, src_ctx, segment, offset, size, wcopy_after, kexit_info) + (src_ctx, segment, offset, @SEGMENT_MAIN_MEMORY, dest_offset, context, size, wcopy_after, kexit_info) + %build_address + SWAP3 %build_address + // stack: DST, SRC, size, wcopy_after, kexit_info %jump(memcpy_bytes) wcopy_empty: @@ -132,6 +138,7 @@ wcopy_large_offset: GET_CONTEXT %stack (context, kexit_info, dest_offset, offset, size) -> (context, @SEGMENT_MAIN_MEMORY, dest_offset, size, wcopy_after, kexit_info) + %build_address %jump(memset) wcopy_after: @@ -241,6 +248,9 @@ extcodecopy_contd: GET_CONTEXT %stack (context, new_dest_offset, copy_size, extra_size, segment, src_ctx, kexit_info, dest_offset, offset, size) -> - (context, @SEGMENT_MAIN_MEMORY, dest_offset, src_ctx, segment, offset, copy_size, wcopy_large_offset, kexit_info, new_dest_offset, offset, extra_size) + (src_ctx, segment, offset, @SEGMENT_MAIN_MEMORY, dest_offset, context, copy_size, wcopy_large_offset, kexit_info, new_dest_offset, offset, extra_size) + %build_address + SWAP3 %build_address + // stack: DST, SRC, copy_size, wcopy_large_offset, kexit_info, new_dest_offset, offset, extra_size %jump(memcpy_bytes) %endmacro diff --git a/evm/src/cpu/kernel/asm/memory/txn_fields.asm b/evm/src/cpu/kernel/asm/memory/txn_fields.asm index e4e6b87544..a8c1c0788f 100644 --- a/evm/src/cpu/kernel/asm/memory/txn_fields.asm +++ b/evm/src/cpu/kernel/asm/memory/txn_fields.asm @@ -1,18 +1,27 @@ // Load the given normalized transaction field from memory. %macro mload_txn_field(field) + // Transaction fields are already scaled by their corresponding segment, + // effectively making them the direct memory position to read from / + // write to. + // stack: (empty) PUSH $field - // stack: offset - %mload_kernel(@SEGMENT_NORMALIZED_TXN) + // stack: addr + MLOAD_GENERAL // stack: value %endmacro // Store the given normalized transaction field to memory. %macro mstore_txn_field(field) + // Transaction fields are already scaled by their corresponding segment, + // effectively making them the direct memory position to read from / + // write to. + // stack: value PUSH $field - // stack: offset, value - %mstore_kernel(@SEGMENT_NORMALIZED_TXN) + // stack: addr, value + SWAP1 + MSTORE_GENERAL // stack: (empty) %endmacro diff --git a/evm/src/cpu/kernel/asm/mpt/hash/hash.asm b/evm/src/cpu/kernel/asm/mpt/hash/hash.asm index df7e1d741d..dc1a9392eb 100644 --- a/evm/src/cpu/kernel/asm/mpt/hash/hash.asm +++ b/evm/src/cpu/kernel/asm/mpt/hash/hash.asm @@ -29,15 +29,13 @@ mpt_hash_hash_if_rlp: mpt_hash_hash_rlp: // stack: result, result_len, new_len, retdest %stack (result, result_len, new_len) - // context, segment, offset, value, len, trie_len, retdest - -> (0, @SEGMENT_RLP_RAW, 0, result, result_len, mpt_hash_hash_rlp_after_unpacking, new_len) + -> (@SEGMENT_RLP_RAW, result, result_len, mpt_hash_hash_rlp_after_unpacking, result_len, new_len) + // stack: addr, result, result_len, mpt_hash_hash_rlp_after_unpacking, result_len, new_len %jump(mstore_unpacking) mpt_hash_hash_rlp_after_unpacking: - // stack: result_len, new_len, retdest - PUSH 0 // offset - PUSH @SEGMENT_RLP_RAW // segment - PUSH 0 // context - // stack: result_addr: 3, result_len, new_len, retdest + // stack: result_addr, result_len, new_len, retdest + POP PUSH @SEGMENT_RLP_RAW // ctx == virt == 0 + // stack: result_addr, result_len, new_len, retdest KECCAK_GENERAL // stack: hash, new_len, retdest %stack(hash, new_len, retdest) -> (retdest, hash, new_len) @@ -80,23 +78,19 @@ encode_or_hash_concrete_node: %stack (node_type, node_ptr, encode_value, cur_len) -> (node_type, node_ptr, encode_value, cur_len, maybe_hash_node) %jump(encode_node) maybe_hash_node: - // stack: result_ptr, result_len, cur_len, retdest + // stack: result_addr, result_len, cur_len, retdest DUP2 %lt_const(32) %jumpi(pack_small_rlp) // result_len >= 32, so we hash the result. - // stack: result_ptr, result_len, cur_len, retdest - PUSH @SEGMENT_RLP_RAW // segment - PUSH 0 // context - // stack: result_addr: 3, result_len, cur_len, retdest + // stack: result_addr, result_len, cur_len, retdest KECCAK_GENERAL %stack (hash, cur_len, retdest) -> (retdest, hash, 32, cur_len) JUMP pack_small_rlp: // stack: result_ptr, result_len, cur_len, retdest %stack (result_ptr, result_len, cur_len) - -> (0, @SEGMENT_RLP_RAW, result_ptr, result_len, - after_packed_small_rlp, result_len, cur_len) + -> (result_ptr, result_len, after_packed_small_rlp, result_len, cur_len) %jump(mload_packing) after_packed_small_rlp: %stack (result, result_len, cur_len, retdest) -> (retdest, result, result_len, cur_len) @@ -130,13 +124,13 @@ global encode_node_empty: // An empty node is encoded as a single byte, 0x80, which is the RLP encoding of the empty string. // TODO: Write this byte just once to RLP memory, then we can always return (0, 1). %alloc_rlp_block - // stack: rlp_pos, cur_len, retdest + // stack: rlp_start, cur_len, retdest PUSH 0x80 - // stack: 0x80, rlp_pos, cur_len, retdest + // stack: 0x80, rlp_start, cur_len, retdest DUP2 - // stack: rlp_pos, 0x80, rlp_pos, cur_len, retdest + // stack: rlp_start, 0x80, rlp_start, cur_len, retdest %mstore_rlp - %stack (rlp_pos, cur_len, retdest) -> (retdest, rlp_pos, 1, cur_len) + %stack (rlp_start, cur_len, retdest) -> (retdest, rlp_start, 1, cur_len) JUMP global encode_node_branch: @@ -244,7 +238,7 @@ encode_node_branch_prepend_prefix: %stack (result_len, result, rlp_pos, rlp_start, base_offset, node_payload_ptr, encode_value, cur_len, retdest) -> (rlp_pos, result, result_len, %%after_unpacking, rlp_start, base_offset, node_payload_ptr, encode_value, cur_len, retdest) - %jump(mstore_unpacking_rlp) + %jump(mstore_unpacking) %%after_unpacking: // stack: rlp_pos', rlp_start, base_offset, node_payload_ptr, encode_value, cur_len, retdest %endmacro @@ -284,7 +278,7 @@ encode_node_extension_after_hex_prefix: encode_node_extension_unpack: %stack (rlp_pos, rlp_start, result, result_len, node_payload_ptr, cur_len) -> (rlp_pos, result, result_len, encode_node_extension_after_unpacking, rlp_start, cur_len) - %jump(mstore_unpacking_rlp) + %jump(mstore_unpacking) encode_node_extension_after_unpacking: // stack: rlp_pos, rlp_start, cur_len, retdest %prepend_rlp_list_prefix diff --git a/evm/src/cpu/kernel/asm/mpt/hash/hash_trie_specific.asm b/evm/src/cpu/kernel/asm/mpt/hash/hash_trie_specific.asm index 2ffefb7d5a..84fbb853e9 100644 --- a/evm/src/cpu/kernel/asm/mpt/hash/hash_trie_specific.asm +++ b/evm/src/cpu/kernel/asm/mpt/hash/hash_trie_specific.asm @@ -57,7 +57,7 @@ global mpt_hash_receipt_trie: %endmacro global encode_account: - // stack: rlp_pos, value_ptr, cur_len, retdest + // stack: rlp_addr, value_ptr, cur_len, retdest // First, we compute the length of the RLP data we're about to write. // We also update the length of the trie data segment. // The nonce and balance fields are variable-length, so we need to load them @@ -69,22 +69,22 @@ global encode_account: SWAP2 %add_const(4) SWAP2 // Now, we start the encoding. - // stack: rlp_pos, value_ptr, cur_len, retdest + // stack: rlp_addr, value_ptr, cur_len, retdest DUP2 %mload_trie_data // nonce = value[0] %rlp_scalar_len - // stack: nonce_rlp_len, rlp_pos, value_ptr, cur_len, retdest + // stack: nonce_rlp_len, rlp_addr, value_ptr, cur_len, retdest DUP3 %increment %mload_trie_data // balance = value[1] %rlp_scalar_len - // stack: balance_rlp_len, nonce_rlp_len, rlp_pos, value_ptr, cur_len, retdest + // stack: balance_rlp_len, nonce_rlp_len, rlp_addr, value_ptr, cur_len, retdest PUSH 66 // storage_root and code_hash fields each take 1 + 32 bytes ADD ADD - // stack: payload_len, rlp_pos, value_ptr, cur_len, retdest + // stack: payload_len, rlp_addr, value_ptr, cur_len, retdest SWAP1 - // stack: rlp_pos, payload_len, value_ptr, cur_len, retdest + // stack: rlp_addr, payload_len, value_ptr, cur_len, retdest DUP2 %rlp_list_len - // stack: list_len, rlp_pos, payload_len, value_ptr, cur_len, retdest + // stack: list_len, rlp_addr, payload_len, value_ptr, cur_len, retdest SWAP1 - // stack: rlp_pos, list_len, payload_len, value_ptr, cur_len, retdest + // stack: rlp_addr, list_len, payload_len, value_ptr, cur_len, retdest %encode_rlp_multi_byte_string_prefix // stack: rlp_pos_2, payload_len, value_ptr, cur_len, retdest %encode_rlp_list_prefix @@ -115,232 +115,237 @@ global encode_account: JUMP global encode_txn: - // stack: rlp_pos, value_ptr, cur_len, retdest + // stack: rlp_addr, value_ptr, cur_len, retdest // Load the txn_rlp_len which is at the beginning of value_ptr DUP2 %mload_trie_data - // stack: txn_rlp_len, rlp_pos, value_ptr, cur_len, retdest + // stack: txn_rlp_len, rlp_addr, value_ptr, cur_len, retdest // We need to add 1+txn_rlp_len to the length of the trie data. SWAP3 DUP4 %increment ADD - // stack: new_len, rlp_pos, value_ptr, txn_rlp_len, retdest + // stack: new_len, rlp_addr, value_ptr, txn_rlp_len, retdest SWAP3 SWAP2 %increment - // stack: txn_rlp_ptr=value_ptr+1, rlp_pos, txn_rlp_len, new_len, retdest + // stack: txn_rlp_ptr=value_ptr+1, rlp_addr, txn_rlp_len, new_len, retdest - %stack (txn_rlp_ptr, rlp_pos, txn_rlp_len) -> (rlp_pos, txn_rlp_len, txn_rlp_len, txn_rlp_ptr) + %stack (txn_rlp_ptr, rlp_addr, txn_rlp_len) -> (rlp_addr, txn_rlp_len, txn_rlp_len, txn_rlp_ptr) // Encode the txn rlp prefix - // stack: rlp_pos, txn_rlp_len, txn_rlp_len, txn_rlp_ptr, cur_len, retdest + // stack: rlp_addr, txn_rlp_len, txn_rlp_len, txn_rlp_ptr, cur_len, retdest %encode_rlp_multi_byte_string_prefix // copy txn_rlp to the new block - // stack: rlp_pos, txn_rlp_len, txn_rlp_ptr, new_len, retdest - %stack (rlp_pos, txn_rlp_len, txn_rlp_ptr) -> ( - 0, @SEGMENT_RLP_RAW, rlp_pos, // dest addr - 0, @SEGMENT_TRIE_DATA, txn_rlp_ptr, // src addr. Kernel has context 0 + // stack: rlp_addr, txn_rlp_len, txn_rlp_ptr, new_len, retdest + %stack (rlp_addr, txn_rlp_len, txn_rlp_ptr) -> ( + @SEGMENT_TRIE_DATA, txn_rlp_ptr, // src addr. Kernel has context 0 + rlp_addr, // dest addr txn_rlp_len, // mcpy len - txn_rlp_len, rlp_pos) + txn_rlp_len, rlp_addr) + %build_kernel_address + SWAP1 + // stack: DST, SRC, txn_rlp_len, txn_rlp_len, rlp_addr, new_len, retdest %memcpy_bytes ADD - // stack new_rlp_pos, new_len, retdest - %stack(new_rlp_pos, new_len, retdest) -> (retdest, new_rlp_pos, new_len) + // stack new_rlp_addr, new_len, retdest + %stack(new_rlp_addr, new_len, retdest) -> (retdest, new_rlp_addr, new_len) JUMP // We assume a receipt in memory is stored as: // [payload_len, status, cum_gas_used, bloom, logs_payload_len, num_logs, [logs]]. // A log is [payload_len, address, num_topics, [topics], data_len, [data]]. global encode_receipt: - // stack: rlp_pos, value_ptr, cur_len, retdest + // stack: rlp_addr, value_ptr, cur_len, retdest // First, we add 261 to the trie data length for all values before the logs besides the type. // These are: the payload length, the status, cum_gas_used, the bloom filter (256 elements), // the length of the logs payload and the length of the logs. SWAP2 %add_const(261) SWAP2 - // There is a double encoding! What we compute is: - // either RLP(RLP(receipt)) for Legacy transactions or RLP(txn_type||RLP(receipt)) for transactions of type 1 or 2. + // There is a double encoding! + // What we compute is: + // - either RLP(RLP(receipt)) for Legacy transactions + // - or RLP(txn_type||RLP(receipt)) for transactions of type 1 or 2. // First encode the wrapper prefix. DUP2 %mload_trie_data - // stack: first_value, rlp_pos, value_ptr, cur_len, retdest + // stack: first_value, rlp_addr, value_ptr, cur_len, retdest // The first value is either the transaction type or the payload length. // Since the receipt contains at least the 256-bytes long bloom filter, payload_len > 3. DUP1 %lt_const(3) %jumpi(encode_nonzero_receipt_type) // If we are here, then the first byte is the payload length. %rlp_list_len - // stack: rlp_receipt_len, rlp_pos, value_ptr, cur_len, retdest + // stack: rlp_receipt_len, rlp_addr, value_ptr, cur_len, retdest SWAP1 %encode_rlp_multi_byte_string_prefix - // stack: rlp_pos, value_ptr, cur_len, retdest + // stack: rlp_addr, value_ptr, cur_len, retdest encode_receipt_after_type: - // stack: rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, payload_len_ptr, cur_len, retdest // Then encode the receipt prefix. // `payload_ptr` is either `value_ptr` or `value_ptr+1`, depending on the transaction type. DUP2 %mload_trie_data - // stack: payload_len, rlp_pos, payload_len_ptr, cur_len, retdest + // stack: payload_len, rlp_addr, payload_len_ptr, cur_len, retdest SWAP1 %encode_rlp_list_prefix - // stack: rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, payload_len_ptr, cur_len, retdest // Encode status. DUP2 %increment %mload_trie_data - // stack: status, rlp_pos, payload_len_ptr, cur_len, retdest + // stack: status, rlp_addr, payload_len_ptr, cur_len, retdest SWAP1 %encode_rlp_scalar - // stack: rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, payload_len_ptr, cur_len, retdest // Encode cum_gas_used. DUP2 %add_const(2) %mload_trie_data - // stack: cum_gas_used, rlp_pos, payload_len_ptr, cur_len, retdest + // stack: cum_gas_used, rlp_addr, payload_len_ptr, cur_len, retdest SWAP1 %encode_rlp_scalar - // stack: rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, payload_len_ptr, cur_len, retdest // Encode bloom. PUSH 256 // Bloom length. - DUP3 %add_const(3) PUSH @SEGMENT_TRIE_DATA PUSH 0 // MPT src address. - DUP5 - // stack: rlp_pos, SRC, 256, rlp_pos, payload_len_ptr, cur_len, retdest + DUP3 %add_const(3) PUSH @SEGMENT_TRIE_DATA %build_kernel_address // MPT src address. + DUP3 + // stack: rlp_addr, SRC, 256, rlp_addr, payload_len_ptr, cur_len, retdest %encode_rlp_string - // stack: rlp_pos, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, old_rlp_pos, payload_len_ptr, cur_len, retdest SWAP1 POP - // stack: rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, payload_len_ptr, cur_len, retdest // Encode logs prefix. DUP2 %add_const(259) %mload_trie_data - // stack: logs_payload_len, rlp_pos, payload_len_ptr, cur_len, retdest + // stack: logs_payload_len, rlp_addr, payload_len_ptr, cur_len, retdest SWAP1 %encode_rlp_list_prefix - // stack: rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, payload_len_ptr, cur_len, retdest DUP2 %add_const(261) - // stack: logs_ptr, rlp_pos, payload_len_ptr, cur_len, retdest + // stack: logs_ptr, rlp_addr, payload_len_ptr, cur_len, retdest DUP3 %add_const(260) %mload_trie_data - // stack: num_logs, logs_ptr, rlp_pos, payload_len_ptr, cur_len, retdest + // stack: num_logs, logs_ptr, rlp_addr, payload_len_ptr, cur_len, retdest PUSH 0 encode_receipt_logs_loop: - // stack: i, num_logs, current_log_ptr, rlp_pos, payload_len_ptr, cur_len, retdest + // stack: i, num_logs, current_log_ptr, rlp_addr, payload_len_ptr, cur_len, retdest DUP2 DUP2 EQ - // stack: i == num_logs, i, num_logs, current_log_ptr, rlp_pos, payload_len_ptr, cur_len, retdest + // stack: i == num_logs, i, num_logs, current_log_ptr, rlp_addr, payload_len_ptr, cur_len, retdest %jumpi(encode_receipt_end) // We add 4 to the trie data length for the fixed size elements in the current log. SWAP5 %add_const(4) SWAP5 - // stack: i, num_logs, current_log_ptr, rlp_pos, payload_len_ptr, cur_len, retdest + // stack: i, num_logs, current_log_ptr, rlp_addr, payload_len_ptr, cur_len, retdest DUP3 DUP5 - // stack: rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest // Encode log prefix. DUP2 %mload_trie_data - // stack: payload_len, rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: payload_len, rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest SWAP1 %encode_rlp_list_prefix - // stack: rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest // Encode address. DUP2 %increment %mload_trie_data - // stack: address, rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: address, rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest SWAP1 %encode_rlp_160 - // stack: rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest DUP2 %add_const(2) %mload_trie_data - // stack: num_topics, rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: num_topics, rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest // Encode topics prefix. DUP1 %mul_const(33) - // stack: topics_payload_len, num_topics, rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: topics_payload_len, num_topics, rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest DUP3 %encode_rlp_list_prefix - // stack: new_rlp_pos, num_topics, rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: new_rlp_pos, num_topics, rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest SWAP2 POP - // stack: num_topics, rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest + // stack: num_topics, rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len, retdest // Add `num_topics` to the length of the trie data segment. DUP1 SWAP9 - // stack: cur_len, num_topics, rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, num_topics, retdest + // stack: cur_len, num_topics, rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, num_topics, retdest ADD SWAP8 - // stack: num_topics, rlp_pos, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: num_topics, rlp_addr, current_log_ptr, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest SWAP2 %add_const(3) - // stack: topics_ptr, rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: topics_ptr, rlp_addr, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest PUSH 0 encode_receipt_topics_loop: - // stack: j, topics_ptr, rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: j, topics_ptr, rlp_addr, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest DUP4 DUP2 EQ - // stack: j == num_topics, j, topics_ptr, rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: j == num_topics, j, topics_ptr, rlp_addr, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest %jumpi(encode_receipt_topics_end) - // stack: j, topics_ptr, rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: j, topics_ptr, rlp_addr, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest DUP2 DUP2 ADD %mload_trie_data - // stack: current_topic, j, topics_ptr, rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: current_topic, j, topics_ptr, rlp_addr, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest DUP4 - // stack: rlp_pos, current_topic, j, topics_ptr, rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: rlp_addr, current_topic, j, topics_ptr, rlp_addr, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest %encode_rlp_256 - // stack: new_rlp_pos, j, topics_ptr, rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: new_rlp_pos, j, topics_ptr, rlp_addr, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest SWAP3 POP // stack: j, topics_ptr, new_rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest %increment %jump(encode_receipt_topics_loop) encode_receipt_topics_end: - // stack: num_topics, topics_ptr, rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: num_topics, topics_ptr, rlp_addr, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest ADD - // stack: data_len_ptr, rlp_pos, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: data_len_ptr, rlp_addr, num_topics, i, num_logs, current_log_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest SWAP5 POP - // stack: rlp_pos, num_topics, i, num_logs, data_len_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest + // stack: rlp_addr, num_topics, i, num_logs, data_len_ptr, old_rlp_pos, payload_len_ptr, cur_len', retdest SWAP5 POP - // stack: num_topics, i, num_logs, data_len_ptr, rlp_pos, payload_len_ptr, cur_len', retdest + // stack: num_topics, i, num_logs, data_len_ptr, rlp_addr, payload_len_ptr, cur_len', retdest POP - // stack: i, num_logs, data_len_ptr, rlp_pos, payload_len_ptr, cur_len', retdest + // stack: i, num_logs, data_len_ptr, rlp_addr, payload_len_ptr, cur_len', retdest // Encode data prefix. DUP3 %mload_trie_data - // stack: data_len, i, num_logs, data_len_ptr, rlp_pos, payload_len_ptr, cur_len', retdest + // stack: data_len, i, num_logs, data_len_ptr, rlp_addr, payload_len_ptr, cur_len', retdest // Add `data_len` to the length of the trie data. DUP1 SWAP7 ADD SWAP6 - // stack: data_len, i, num_logs, data_len_ptr, rlp_pos, payload_len_ptr, cur_len'', retdest + // stack: data_len, i, num_logs, data_len_ptr, rlp_addr, payload_len_ptr, cur_len'', retdest DUP4 %increment DUP2 ADD - // stack: next_log_ptr, data_len, i, num_logs, data_len_ptr, rlp_pos, payload_len_ptr, cur_len'', retdest + // stack: next_log_ptr, data_len, i, num_logs, data_len_ptr, rlp_addr, payload_len_ptr, cur_len'', retdest SWAP4 %increment - // stack: data_ptr, data_len, i, num_logs, next_log_ptr, rlp_pos, payload_len_ptr, cur_len'', retdest - PUSH @SEGMENT_TRIE_DATA PUSH 0 - // stack: SRC, data_len, i, num_logs, next_log_ptr, rlp_pos, payload_len_ptr, cur_len'', retdest - DUP8 - // stack: rlp_pos, SRC, data_len, i, num_logs, next_log_ptr, rlp_pos, payload_len_ptr, cur_len'', retdest + // stack: data_ptr, data_len, i, num_logs, next_log_ptr, rlp_addr, payload_len_ptr, cur_len'', retdest + PUSH @SEGMENT_TRIE_DATA %build_kernel_address + // stack: SRC, data_len, i, num_logs, next_log_ptr, rlp_addr, payload_len_ptr, cur_len'', retdest + DUP6 + // stack: rlp_addr, SRC, data_len, i, num_logs, next_log_ptr, rlp_addr, payload_len_ptr, cur_len'', retdest %encode_rlp_string - // stack: new_rlp_pos, i, num_logs, next_log_ptr, rlp_pos, payload_len_ptr, cur_len'', retdest + // stack: new_rlp_pos, i, num_logs, next_log_ptr, rlp_addr, payload_len_ptr, cur_len'', retdest SWAP4 POP // stack: i, num_logs, next_log_ptr, new_rlp_pos, payload_len_ptr, cur_len'', retdest %increment %jump(encode_receipt_logs_loop) encode_receipt_end: - // stack: num_logs, num_logs, current_log_ptr, rlp_pos, payload_len_ptr, cur_len'', retdest + // stack: num_logs, num_logs, current_log_ptr, rlp_addr, payload_len_ptr, cur_len'', retdest %pop3 - // stack: rlp_pos, payload_len_ptr, cur_len'', retdest + // stack: rlp_addr, payload_len_ptr, cur_len'', retdest SWAP1 POP - // stack: rlp_pos, cur_len'', retdest - %stack(rlp_pos, new_len, retdest) -> (retdest, rlp_pos, new_len) + // stack: rlp_addr, cur_len'', retdest + %stack(rlp_addr, new_len, retdest) -> (retdest, rlp_addr, new_len) JUMP encode_nonzero_receipt_type: - // stack: txn_type, rlp_pos, value_ptr, cur_len, retdest + // stack: txn_type, rlp_addr, value_ptr, cur_len, retdest // We have a nonlegacy receipt, so the type is also stored in the trie data segment. SWAP3 %increment SWAP3 - // stack: txn_type, rlp_pos, value_ptr, cur_len, retdest + // stack: txn_type, rlp_addr, value_ptr, cur_len, retdest DUP3 %increment %mload_trie_data - // stack: payload_len, txn_type, rlp_pos, value_ptr, retdest + // stack: payload_len, txn_type, rlp_addr, value_ptr, retdest // The transaction type is encoded in 1 byte %increment %rlp_list_len - // stack: rlp_receipt_len, txn_type, rlp_pos, value_ptr, retdest + // stack: rlp_receipt_len, txn_type, rlp_addr, value_ptr, retdest DUP3 %encode_rlp_multi_byte_string_prefix - // stack: rlp_pos, txn_type, old_rlp_pos, value_ptr, retdest + // stack: rlp_addr, txn_type, old_rlp_addr, value_ptr, retdest DUP2 DUP2 %mstore_rlp %increment - // stack: rlp_pos, txn_type, old_rlp_pos, value_ptr, retdest - %stack (rlp_pos, txn_type, old_rlp_pos, value_ptr, retdest) -> (rlp_pos, value_ptr, retdest) + // stack: rlp_addr, txn_type, old_rlp_addr, value_ptr, retdest + %stack (rlp_addr, txn_type, old_rlp_addr, value_ptr, retdest) -> (rlp_addr, value_ptr, retdest) // We replace `value_ptr` with `paylaod_len_ptr` so we can encode the rest of the data more easily SWAP1 %increment SWAP1 - // stack: rlp_pos, payload_len_ptr, retdest + // stack: rlp_addr, payload_len_ptr, retdest %jump(encode_receipt_after_type) global encode_storage_value: - // stack: rlp_pos, value_ptr, cur_len, retdest + // stack: rlp_addr, value_ptr, cur_len, retdest SWAP1 %mload_trie_data SWAP1 // A storage value is a scalar, so we only need to add 1 to the trie data length. SWAP2 %increment SWAP2 - // stack: rlp_pos, value, cur_len, retdest + // stack: rlp_addr, value, cur_len, retdest // The YP says storage trie is a map "... to the RLP-encoded 256-bit integer values" // which seems to imply that this should be %encode_rlp_256. But %encode_rlp_scalar // causes the tests to pass, so it seems storage values should be treated as variable- // length after all. %doubly_encode_rlp_scalar - // stack: rlp_pos', cur_len, retdest - %stack (rlp_pos, cur_len, retdest) -> (retdest, rlp_pos, cur_len) + // stack: rlp_addr', cur_len, retdest + %stack (rlp_addr, cur_len, retdest) -> (retdest, rlp_addr, cur_len) JUMP diff --git a/evm/src/cpu/kernel/asm/mpt/hex_prefix.asm b/evm/src/cpu/kernel/asm/mpt/hex_prefix.asm index 5bb9fa9d88..7dd02c34f9 100644 --- a/evm/src/cpu/kernel/asm/mpt/hex_prefix.asm +++ b/evm/src/cpu/kernel/asm/mpt/hex_prefix.asm @@ -3,8 +3,8 @@ // given position, and returns the updated position, i.e. a pointer to the next // unused offset. // -// Pre stack: rlp_start_pos, num_nibbles, packed_nibbles, terminated, retdest -// Post stack: rlp_end_pos +// Pre stack: rlp_start_addr, num_nibbles, packed_nibbles, terminated, retdest +// Post stack: rlp_end_addr global hex_prefix_rlp: DUP2 %assert_lt_const(65) @@ -12,7 +12,7 @@ global hex_prefix_rlp: // Compute the length of the hex-prefix string, in bytes: // hp_len = num_nibbles / 2 + 1 = i + 1 %increment - // stack: hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest + // stack: hp_len, rlp_addr, num_nibbles, packed_nibbles, terminated, retdest // Write the RLP header. DUP1 %gt_const(55) %jumpi(rlp_header_large) @@ -21,113 +21,112 @@ global hex_prefix_rlp: // The hex-prefix is a single byte. It must be <= 127, since its first // nibble only has two bits. So this is the "small" RLP string case, where // the byte is its own RLP encoding. - // stack: hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest + // stack: hp_len, rlp_addr, num_nibbles, packed_nibbles, terminated, retdest POP first_byte: - // stack: rlp_pos, num_nibbles, packed_nibbles, terminated, retdest + // stack: rlp_addr, num_nibbles, packed_nibbles, terminated, retdest // get the first nibble, if num_nibbles is odd, or zero otherwise SWAP2 - // stack: packed_nibbles, num_nibbbles, rlp_pos, terminated, retdest + // stack: packed_nibbles, num_nibbbles, rlp_addr, terminated, retdest DUP2 DUP1 %mod_const(2) - // stack: parity, num_nibbles, packed_nibbles, num_nibbles, rlp_pos, terminated, retdest + // stack: parity, num_nibbles, packed_nibbles, num_nibbles, rlp_addr, terminated, retdest SWAP1 SUB %mul_const(4) SHR - // stack: first_nibble_or_zero, num_nibbles, rlp_pos, terminated, retdest + // stack: first_nibble_or_zero, num_nibbles, rlp_addr, terminated, retdest SWAP2 - // stack: rlp_pos, num_nibbles, first_nibble_or_zero, terminated, retdest + // stack: rlp_addr, num_nibbles, first_nibble_or_zero, terminated, retdest SWAP3 - // stack: terminated, num_nibbles, first_nibble_or_zero, rlp_pos, retdest + // stack: terminated, num_nibbles, first_nibble_or_zero, rlp_addr, retdest %mul_const(2) - // stack: terminated * 2, num_nibbles, first_nibble_or_zero, rlp_pos, retdest + // stack: terminated * 2, num_nibbles, first_nibble_or_zero, rlp_addr, retdest SWAP1 - // stack: num_nibbles, terminated * 2, first_nibble_or_zero, rlp_pos, retdest + // stack: num_nibbles, terminated * 2, first_nibble_or_zero, rlp_addr, retdest %mod_const(2) // parity ADD - // stack: parity + terminated * 2, first_nibble_or_zero, rlp_pos, retdest + // stack: parity + terminated * 2, first_nibble_or_zero, rlp_addr, retdest %mul_const(16) ADD - // stack: first_byte, rlp_pos, retdest + // stack: first_byte, rlp_addr, retdest DUP2 %mstore_rlp %increment - // stack: rlp_pos', retdest + // stack: rlp_addr', retdest SWAP1 JUMP remaining_bytes: - // stack: rlp_pos, num_nibbles, packed_nibbles, retdest + // stack: rlp_addr, num_nibbles, packed_nibbles, retdest SWAP2 PUSH @U256_MAX - // stack: U256_MAX, packed_nibbles, num_nibbles, rlp_pos, ret_dest + // stack: U256_MAX, packed_nibbles, num_nibbles, rlp_addr, ret_dest SWAP1 SWAP2 DUP1 %mod_const(2) - // stack: parity, num_nibbles, U256_MAX, packed_nibbles, rlp_pos, ret_dest + // stack: parity, num_nibbles, U256_MAX, packed_nibbles, rlp_addr, ret_dest SWAP1 SUB DUP1 - // stack: num_nibbles - parity, num_nibbles - parity, U256_MAX, packed_nibbles, rlp_pos, ret_dest + // stack: num_nibbles - parity, num_nibbles - parity, U256_MAX, packed_nibbles, rlp_addr, ret_dest %div_const(2) - // stack: rem_bytes, num_nibbles - parity, U256_MAX, packed_nibbles, rlp_pos, ret_dest + // stack: rem_bytes, num_nibbles - parity, U256_MAX, packed_nibbles, rlp_addr, ret_dest SWAP2 SWAP1 - // stack: num_nibbles - parity, U256_MAX, rem_bytes, packed_nibbles, rlp_pos, ret_dest + // stack: num_nibbles - parity, U256_MAX, rem_bytes, packed_nibbles, rlp_addr, ret_dest %mul_const(4) - // stack: 4*(num_nibbles - parity), U256_MAX, rem_bytes, packed_nibbles, rlp_pos, ret_dest + // stack: 4*(num_nibbles - parity), U256_MAX, rem_bytes, packed_nibbles, rlp_addr, ret_dest PUSH 256 SUB - // stack: 256 - 4*(num_nibbles - parity), U256_MAX, rem_bytes, packed_nibbles, rlp_pos, ret_dest + // stack: 256 - 4*(num_nibbles - parity), U256_MAX, rem_bytes, packed_nibbles, rlp_addr, ret_dest SHR - // stack: mask, rem_bytes, packed_nibbles, rlp_pos, ret_dest + // stack: mask, rem_bytes, packed_nibbles, rlp_addr, ret_dest SWAP1 SWAP2 AND - %stack - (remaining_nibbles, rem_bytes, rlp_pos) -> - (rlp_pos, remaining_nibbles, rem_bytes) - %mstore_unpacking_rlp + %stack(remaining_nibbles, rem_bytes, rlp_addr) -> (rlp_addr, remaining_nibbles, rem_bytes) + %mstore_unpacking SWAP1 JUMP rlp_header_medium: - // stack: hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest + // stack: hp_len, rlp_addr, num_nibbles, packed_nibbles, terminated, retdest %add_const(0x80) // value = 0x80 + hp_len - DUP2 // offset = rlp_pos + DUP2 %mstore_rlp - // stack: rlp_pos, num_nibbles, packed_nibbles, terminated, retdest - // rlp_pos += 1 + // stack: rlp_addr, num_nibbles, packed_nibbles, terminated, retdest + // rlp_addr += 1 %increment - // stack: rlp_pos, num_nibbles, packed_nibbles, terminated, retdest + // stack: rlp_addr, num_nibbles, packed_nibbles, terminated, retdest SWAP3 DUP3 DUP3 - // stack: num_nibbles, packed_nibbles, terminated, num_nibbles, packed_nibbles, rlp_pos, retdest + // stack: num_nibbles, packed_nibbles, terminated, num_nibbles, packed_nibbles, rlp_addr, retdest PUSH remaining_bytes - // stack: remaining_bytes, num_nibbles, packed_nibbles, terminated, num_nibbles, packed_nibbles, rlp_pos, retdest + // stack: remaining_bytes, num_nibbles, packed_nibbles, terminated, num_nibbles, packed_nibbles, rlp_addr, retdest SWAP4 SWAP5 SWAP6 - // stack: rlp_pos, num_nibbles, packed_nibbles, terminated, remaining_bytes, num_nibbles, packed_nibbles, retdest + // stack: rlp_addr, num_nibbles, packed_nibbles, terminated, remaining_bytes, num_nibbles, packed_nibbles, retdest %jump(first_byte) rlp_header_large: - // stack: hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest + // stack: hp_len, rlp_addr, num_nibbles, packed_nibbles, terminated, retdest // In practice hex-prefix length will never exceed 256, so the length of the // length will always be 1 byte in this case. PUSH 0xb8 // value = 0xb7 + len_of_len = 0xb8 - DUP3 // offset = rlp_pos + DUP3 %mstore_rlp + // stack: rlp_addr, value, hp_len, i, rlp_addr, num_nibbles, packed_nibbles, terminated, retdest - // stack: hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest - DUP2 %increment // offset = rlp_pos + 1 + // stack: hp_len, rlp_addr, num_nibbles, packed_nibbles, terminated, retdest + DUP2 %increment %mstore_rlp - // stack: rlp_pos, num_nibbles, packed_nibbles, terminated, retdest - // rlp_pos += 2 + // stack: rlp_addr, num_nibbles, packed_nibbles, terminated, retdest + // rlp_addr += 2 %add_const(2) - // stack: rlp_pos, num_nibbles, packed_nibbles, terminated, retdest + // stack: rlp_addr, num_nibbles, packed_nibbles, terminated, retdest SWAP3 DUP3 DUP3 - // stack: num_nibbles, packed_nibbles, terminated, num_nibbles, packed_nibbles, rlp_pos, retdest + // stack: num_nibbles, packed_nibbles, terminated, num_nibbles, packed_nibbles, rlp_addr, retdest PUSH remaining_bytes - // stack: remaining_bytes, num_nibbles, packed_nibbles, terminated, num_nibbles, packed_nibbles, rlp_pos, retdest + // stack: remaining_bytes, num_nibbles, packed_nibbles, terminated, num_nibbles, packed_nibbles, rlp_addr, retdest SWAP4 SWAP5 SWAP6 - // stack: rlp_pos, num_nibbles, packed_nibbles, terminated, remaining_bytes, num_nibbles, packed_nibbles, retdest + // stack: rlp_addr, num_nibbles, packed_nibbles, terminated, remaining_bytes, num_nibbles, packed_nibbles, retdest %jump(first_byte) diff --git a/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm b/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm index 1bf9f6f8fb..d21e917b28 100644 --- a/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm +++ b/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm @@ -71,18 +71,18 @@ mpt_insert_receipt_trie_save: global scalar_to_rlp: // stack: scalar, retdest %mload_global_metadata(@GLOBAL_METADATA_RLP_DATA_SIZE) - // stack: pos, scalar, retdest + // stack: init_addr, scalar, retdest SWAP1 DUP2 %encode_rlp_scalar - // stack: pos', init_pos, retdest + // stack: addr', init_addr, retdest // Now our rlp_encoding is in RlpRaw. // Set new RlpRaw data size DUP1 %mstore_global_metadata(@GLOBAL_METADATA_RLP_DATA_SIZE) DUP2 DUP2 SUB // len of the key - // stack: len, pos', init_pos, retdest - DUP3 PUSH @SEGMENT_RLP_RAW PUSH 0 // address where we get the key from + // stack: len, addr', init_addr, retdest + DUP3 %mload_packing - // stack: packed_key, pos', init_pos, retdest + // stack: packed_key, addr', init_addr, retdest SWAP2 %pop2 // stack: key, retdest SWAP1 diff --git a/evm/src/cpu/kernel/asm/rlp/decode.asm b/evm/src/cpu/kernel/asm/rlp/decode.asm index dd990bbd37..43c6627d6c 100644 --- a/evm/src/cpu/kernel/asm/rlp/decode.asm +++ b/evm/src/cpu/kernel/asm/rlp/decode.asm @@ -7,143 +7,141 @@ // assets. // Parse the length of a bytestring from RLP memory. The next len bytes after -// pos' will contain the string. +// rlp_addr' will contain the string. // -// Pre stack: pos, retdest -// Post stack: pos', len +// Pre stack: rlp_addr, retdest +// Post stack: rlp_addr', len global decode_rlp_string_len: - // stack: pos, retdest + // stack: rlp_addr, retdest DUP1 - %mload_kernel(@SEGMENT_RLP_RAW) - // stack: first_byte, pos, retdest + MLOAD_GENERAL + // stack: first_byte, rlp_addr, retdest DUP1 %gt_const(0xb7) - // stack: first_byte >= 0xb8, first_byte, pos, retdest + // stack: first_byte >= 0xb8, first_byte, rlp_addr, retdest %jumpi(decode_rlp_string_len_large) - // stack: first_byte, pos, retdest + // stack: first_byte, rlp_addr, retdest DUP1 %gt_const(0x7f) - // stack: first_byte >= 0x80, first_byte, pos, retdest + // stack: first_byte >= 0x80, first_byte, rlp_addr, retdest %jumpi(decode_rlp_string_len_medium) // String is a single byte in the range [0x00, 0x7f]. - %stack (first_byte, pos, retdest) -> (retdest, pos, 1) + %stack (first_byte, rlp_addr, retdest) -> (retdest, rlp_addr, 1) JUMP decode_rlp_string_len_medium: // String is 0-55 bytes long. First byte contains the len. - // stack: first_byte, pos, retdest + // stack: first_byte, rlp_addr, retdest %sub_const(0x80) - // stack: len, pos, retdest + // stack: len, rlp_addr, retdest SWAP1 %increment - // stack: pos', len, retdest - %stack (pos, len, retdest) -> (retdest, pos, len) + // stack: rlp_addr', len, retdest + %stack (rlp_addr, len, retdest) -> (retdest, rlp_addr, len) JUMP decode_rlp_string_len_large: // String is >55 bytes long. First byte contains the len of the len. - // stack: first_byte, pos, retdest + // stack: first_byte, rlp_addr, retdest %sub_const(0xb7) - // stack: len_of_len, pos, retdest + // stack: len_of_len, rlp_addr, retdest SWAP1 %increment - // stack: pos', len_of_len, retdest + // stack: rlp_addr', len_of_len, retdest %jump(decode_int_given_len) // Convenience macro to call decode_rlp_string_len and return where we left off. %macro decode_rlp_string_len - %stack (pos) -> (pos, %%after) + %stack (rlp_addr) -> (rlp_addr, %%after) %jump(decode_rlp_string_len) %%after: %endmacro // Parse a scalar from RLP memory. -// Pre stack: pos, retdest -// Post stack: pos', scalar +// Pre stack: rlp_addr, retdest +// Post stack: rlp_addr', scalar // // Scalars are variable-length, but this method assumes a max length of 32 // bytes, so that the result can be returned as a single word on the stack. // As per the spec, scalars must not have leading zeros. global decode_rlp_scalar: - // stack: pos, retdest + // stack: rlp_addr, retdest PUSH decode_int_given_len - // stack: decode_int_given_len, pos, retdest + // stack: decode_int_given_len, rlp_addr, retdest SWAP1 - // stack: pos, decode_int_given_len, retdest + // stack: rlp_addr, decode_int_given_len, retdest // decode_rlp_string_len will return to decode_int_given_len, at which point - // the stack will contain (pos', len, retdest), which are the proper args + // the stack will contain (rlp_addr', len, retdest), which are the proper args // to decode_int_given_len. %jump(decode_rlp_string_len) // Convenience macro to call decode_rlp_scalar and return where we left off. %macro decode_rlp_scalar - %stack (pos) -> (pos, %%after) + %stack (rlp_addr) -> (rlp_addr, %%after) %jump(decode_rlp_scalar) %%after: %endmacro // Parse the length of an RLP list from memory. -// Pre stack: pos, retdest -// Post stack: pos', len +// Pre stack: rlp_addr, retdest +// Post stack: rlp_addr', len global decode_rlp_list_len: - // stack: pos, retdest + // stack: rlp_addr, retdest DUP1 - %mload_kernel(@SEGMENT_RLP_RAW) - // stack: first_byte, pos, retdest + MLOAD_GENERAL + // stack: first_byte, rlp_addr, retdest SWAP1 - %increment // increment pos + %increment // increment rlp_addr SWAP1 - // stack: first_byte, pos', retdest + // stack: first_byte, rlp_addr', retdest // If first_byte is >= 0xf8, it's a > 55 byte list, and // first_byte - 0xf7 is the length of the length. DUP1 %gt_const(0xf7) // GT is native while GE is not, so compare to 0xf6 instead - // stack: first_byte >= 0xf7, first_byte, pos', retdest + // stack: first_byte >= 0xf7, first_byte, rlp_addr', retdest %jumpi(decode_rlp_list_len_big) // This is the "small list" case. // The list length is first_byte - 0xc0. - // stack: first_byte, pos', retdest + // stack: first_byte, rlp_addr', retdest %sub_const(0xc0) - // stack: len, pos', retdest - %stack (len, pos, retdest) -> (retdest, pos, len) + // stack: len, rlp_addr', retdest + %stack (len, rlp_addr, retdest) -> (retdest, rlp_addr, len) JUMP decode_rlp_list_len_big: // The length of the length is first_byte - 0xf7. - // stack: first_byte, pos', retdest + // stack: first_byte, rlp_addr', retdest %sub_const(0xf7) - // stack: len_of_len, pos', retdest + // stack: len_of_len, rlp_addr', retdest SWAP1 - // stack: pos', len_of_len, retdest + // stack: rlp_addr', len_of_len, retdest %jump(decode_int_given_len) // Convenience macro to call decode_rlp_list_len and return where we left off. %macro decode_rlp_list_len - %stack (pos) -> (pos, %%after) + %stack (rlp_addr) -> (rlp_addr, %%after) %jump(decode_rlp_list_len) %%after: %endmacro // Parse an integer of the given length. It is assumed that the integer will // fit in a single (256-bit) word on the stack. -// Pre stack: pos, len, retdest -// Post stack: pos', int +// Pre stack: rlp_addr, len, retdest +// Post stack: rlp_addr', int global decode_int_given_len: DUP2 ISZERO %jumpi(empty_int) - %stack (pos, len, retdest) -> (pos, len, pos, len, retdest) + %stack (rlp_addr, len, retdest) -> (rlp_addr, len, rlp_addr, len, retdest) ADD - %stack(pos_two, pos, len, retdest) -> (pos, len, pos_two, retdest) - PUSH @SEGMENT_RLP_RAW - PUSH 0 //context + %stack(rlp_addr_two, rlp_addr, len, retdest) -> (rlp_addr, len, rlp_addr_two, retdest) MLOAD_32BYTES - // stack: int, pos', retdest - %stack(int, pos, retdest) -> (retdest, pos, int) + // stack: int, rlp_addr', retdest + %stack(int, rlp_addr, retdest) -> (retdest, rlp_addr, int) JUMP empty_int: - // stack: pos, len, retdest - %stack(pos, len, retdest) -> (retdest, pos, 0) + // stack: rlp_addr, len, retdest + %stack(rlp_addr, len, retdest) -> (retdest, rlp_addr, 0) JUMP diff --git a/evm/src/cpu/kernel/asm/rlp/encode.asm b/evm/src/cpu/kernel/asm/rlp/encode.asm index 23b0db4635..2319e780b9 100644 --- a/evm/src/cpu/kernel/asm/rlp/encode.asm +++ b/evm/src/cpu/kernel/asm/rlp/encode.asm @@ -1,76 +1,76 @@ // RLP-encode a fixed-length 160 bit (20 byte) string. Assumes string < 2^160. -// Pre stack: pos, string, retdest -// Post stack: pos +// Pre stack: rlp_addr, string, retdest +// Post stack: rlp_addr global encode_rlp_160: PUSH 20 %jump(encode_rlp_fixed) // Convenience macro to call encode_rlp_160 and return where we left off. %macro encode_rlp_160 - %stack (pos, string) -> (pos, string, %%after) + %stack (rlp_addr, string) -> (rlp_addr, string, %%after) %jump(encode_rlp_160) %%after: %endmacro // RLP-encode a fixed-length 256 bit (32 byte) string. -// Pre stack: pos, string, retdest -// Post stack: pos +// Pre stack: rlp_addr, string, retdest +// Post stack: rlp_addr global encode_rlp_256: PUSH 32 %jump(encode_rlp_fixed) // Convenience macro to call encode_rlp_256 and return where we left off. %macro encode_rlp_256 - %stack (pos, string) -> (pos, string, %%after) + %stack (rlp_addr, string) -> (rlp_addr, string, %%after) %jump(encode_rlp_256) %%after: %endmacro // RLP-encode a fixed-length string with the given byte length. Assumes string < 2^(8 * len). global encode_rlp_fixed: - // stack: len, pos, string, retdest + // stack: len, rlp_addr, string, retdest DUP1 %add_const(0x80) - // stack: first_byte, len, pos, string, retdest + // stack: first_byte, len, rlp_addr, string, retdest DUP3 - // stack: pos, first_byte, len, pos, string, retdest + // stack: rlp_addr, first_byte, len, rlp_addr, string, retdest %mstore_rlp - // stack: len, pos, string, retdest + // stack: len, rlp_addr, string, retdest SWAP1 - %increment // increment pos - // stack: pos, len, string, retdest - %stack (pos, len, string) -> (pos, string, len, encode_rlp_fixed_finish) - // stack: pos, string, len, encode_rlp_fixed_finish, retdest - %jump(mstore_unpacking_rlp) + %increment // increment rlp_addr + // stack: rlp_addr, len, string, retdest + %stack (rlp_addr, len, string) -> (rlp_addr, string, len, encode_rlp_fixed_finish) + // stack: rlp_addr, string, len, encode_rlp_fixed_finish, retdest + %jump(mstore_unpacking) encode_rlp_fixed_finish: - // stack: pos', retdest + // stack: rlp_addr', retdest SWAP1 JUMP // Doubly-RLP-encode a fixed-length string with the given byte length. // I.e. writes encode(encode(string). Assumes string < 2^(8 * len). global doubly_encode_rlp_fixed: - // stack: len, pos, string, retdest + // stack: len, rlp_addr, string, retdest DUP1 %add_const(0x81) - // stack: first_byte, len, pos, string, retdest + // stack: first_byte, len, rlp_addr, string, retdest DUP3 - // stack: pos, first_byte, len, pos, string, retdest + // stack: rlp_addr, first_byte, len, rlp_addr, string, retdest %mstore_rlp - // stack: len, pos, string, retdest + // stack: len, rlp_addr, string, retdest DUP1 %add_const(0x80) - // stack: second_byte, len, original_pos, string, retdest + // stack: second_byte, len, original_rlp_addr, string, retdest DUP3 %increment - // stack: pos', second_byte, len, pos, string, retdest + // stack: rlp_addr', second_byte, len, rlp_addr, string, retdest %mstore_rlp - // stack: len, pos, string, retdest + // stack: len, rlp_addr, string, retdest SWAP1 %add_const(2) // advance past the two prefix bytes - // stack: pos'', len, string, retdest - %stack (pos, len, string) -> (pos, string, len, encode_rlp_fixed_finish) - // stack: context, segment, pos'', string, len, encode_rlp_fixed_finish, retdest - %jump(mstore_unpacking_rlp) + // stack: rlp_addr'', len, string, retdest + %stack (rlp_addr, len, string) -> (rlp_addr, string, len, encode_rlp_fixed_finish) + // stack: context, segment, rlp_addr'', string, len, encode_rlp_fixed_finish, retdest + %jump(mstore_unpacking) // Writes the RLP prefix for a string of the given length. This does not handle // the trivial encoding of certain single-byte strings, as handling that would @@ -78,156 +78,156 @@ global doubly_encode_rlp_fixed: // length. This method should generally be used only when we know a string // contains at least two bytes. // -// Pre stack: pos, str_len, retdest -// Post stack: pos' +// Pre stack: rlp_addr, str_len, retdest +// Post stack: rlp_addr' global encode_rlp_multi_byte_string_prefix: - // stack: pos, str_len, retdest + // stack: rlp_addr, str_len, retdest DUP2 %gt_const(55) - // stack: str_len > 55, pos, str_len, retdest + // stack: str_len > 55, rlp_addr, str_len, retdest %jumpi(encode_rlp_multi_byte_string_prefix_large) // Medium case; prefix is 0x80 + str_len. - // stack: pos, str_len, retdest + // stack: rlp_addr, str_len, retdest SWAP1 %add_const(0x80) - // stack: prefix, pos, retdest + // stack: prefix, rlp_addr, retdest DUP2 - // stack: pos, prefix, pos, retdest + // stack: rlp_addr, prefix, rlp_addr, retdest %mstore_rlp - // stack: pos, retdest + // stack: rlp_addr, retdest %increment - // stack: pos', retdest + // stack: rlp_addr', retdest SWAP1 JUMP encode_rlp_multi_byte_string_prefix_large: // Large case; prefix is 0xb7 + len_of_len, followed by str_len. - // stack: pos, str_len, retdest + // stack: rlp_addr, str_len, retdest DUP2 %num_bytes - // stack: len_of_len, pos, str_len, retdest + // stack: len_of_len, rlp_addr, str_len, retdest SWAP1 DUP2 // len_of_len %add_const(0xb7) - // stack: first_byte, pos, len_of_len, str_len, retdest + // stack: first_byte, rlp_addr, len_of_len, str_len, retdest DUP2 - // stack: pos, first_byte, pos, len_of_len, str_len, retdest + // stack: rlp_addr, first_byte, rlp_addr, len_of_len, str_len, retdest %mstore_rlp - // stack: pos, len_of_len, str_len, retdest + // stack: rlp_addr, len_of_len, str_len, retdest %increment - // stack: pos', len_of_len, str_len, retdest - %stack (pos, len_of_len, str_len) -> (pos, str_len, len_of_len) - %jump(mstore_unpacking_rlp) + // stack: rlp_addr', len_of_len, str_len, retdest + %stack (rlp_addr, len_of_len, str_len) -> (rlp_addr, str_len, len_of_len) + %jump(mstore_unpacking) %macro encode_rlp_multi_byte_string_prefix - %stack (pos, str_len) -> (pos, str_len, %%after) + %stack (rlp_addr, str_len) -> (rlp_addr, str_len, %%after) %jump(encode_rlp_multi_byte_string_prefix) %%after: %endmacro // Writes the RLP prefix for a list with the given payload length. // -// Pre stack: pos, payload_len, retdest -// Post stack: pos' +// Pre stack: rlp_addr, payload_len, retdest +// Post stack: rlp_addr' global encode_rlp_list_prefix: - // stack: pos, payload_len, retdest + // stack: rlp_addr, payload_len, retdest DUP2 %gt_const(55) %jumpi(encode_rlp_list_prefix_large) // Small case: prefix is just 0xc0 + length. - // stack: pos, payload_len, retdest + // stack: rlp_addr, payload_len, retdest SWAP1 %add_const(0xc0) - // stack: prefix, pos, retdest + // stack: prefix, rlp_addr, retdest DUP2 - // stack: pos, prefix, pos, retdest + // stack: rlp_addr, prefix, rlp_addr, retdest %mstore_rlp - // stack: pos, retdest + // stack: rlp_addr, retdest %increment SWAP1 JUMP encode_rlp_list_prefix_large: // Write 0xf7 + len_of_len. - // stack: pos, payload_len, retdest + // stack: rlp_addr, payload_len, retdest DUP2 %num_bytes - // stack: len_of_len, pos, payload_len, retdest + // stack: len_of_len, rlp_addr, payload_len, retdest DUP1 %add_const(0xf7) - // stack: first_byte, len_of_len, pos, payload_len, retdest - DUP3 // pos + // stack: first_byte, len_of_len, rlp_addr, payload_len, retdest + DUP3 // rlp_addr %mstore_rlp - // stack: len_of_len, pos, payload_len, retdest + // stack: len_of_len, rlp_addr, payload_len, retdest SWAP1 %increment - // stack: pos', len_of_len, payload_len, retdest - %stack (pos, len_of_len, payload_len) - -> (pos, payload_len, len_of_len, + // stack: rlp_addr', len_of_len, payload_len, retdest + %stack (rlp_addr, len_of_len, payload_len) + -> (rlp_addr, payload_len, len_of_len, encode_rlp_list_prefix_large_done_writing_len) - %jump(mstore_unpacking_rlp) + %jump(mstore_unpacking) encode_rlp_list_prefix_large_done_writing_len: - // stack: pos'', retdest + // stack: rlp_addr'', retdest SWAP1 JUMP %macro encode_rlp_list_prefix - %stack (pos, payload_len) -> (pos, payload_len, %%after) + %stack (rlp_addr, payload_len) -> (rlp_addr, payload_len, %%after) %jump(encode_rlp_list_prefix) %%after: %endmacro -// Given an RLP list payload which starts and ends at the given positions, -// prepend the appropriate RLP list prefix. Returns the updated start position, +// Given an RLP list payload which starts and ends at the given rlp_address, +// prepend the appropriate RLP list prefix. Returns the updated start rlp_address, // as well as the length of the RLP data (including the newly-added prefix). // -// Pre stack: end_pos, start_pos, retdest -// Post stack: prefix_start_pos, rlp_len +// Pre stack: end_rlp_addr, start_rlp_addr, retdest +// Post stack: prefix_start_rlp_addr, rlp_len global prepend_rlp_list_prefix: - // stack: end_pos, start_pos, retdest - DUP2 DUP2 SUB // end_pos - start_pos - // stack: payload_len, end_pos, start_pos, retdest + // stack: end_rlp_addr, start_rlp_addr, retdest + DUP2 DUP2 SUB // end_rlp_addr - start_rlp_addr + // stack: payload_len, end_rlp_addr, start_rlp_addr, retdest DUP1 %gt_const(55) %jumpi(prepend_rlp_list_prefix_big) - // If we got here, we have a small list, so we prepend 0xc0 + len at position 8. - // stack: payload_len, end_pos, start_pos, retdest + // If we got here, we have a small list, so we prepend 0xc0 + len at rlp_address 8. + // stack: payload_len, end_rlp_addr, start_rlp_addr, retdest DUP1 %add_const(0xc0) - // stack: prefix_byte, payload_len, end_pos, start_pos, retdest + // stack: prefix_byte, payload_len, end_rlp_addr, start_rlp_addr, retdest DUP4 %decrement // offset of prefix %mstore_rlp - // stack: payload_len, end_pos, start_pos, retdest + // stack: payload_len, end_rlp_addr, start_rlp_addr, retdest %increment - // stack: rlp_len, end_pos, start_pos, retdest + // stack: rlp_len, end_rlp_addr, start_rlp_addr, retdest SWAP2 %decrement - // stack: prefix_start_pos, end_pos, rlp_len, retdest - %stack (prefix_start_pos, end_pos, rlp_len, retdest) -> (retdest, prefix_start_pos, rlp_len) + // stack: prefix_start_rlp_addr, end_rlp_addr, rlp_len, retdest + %stack (prefix_start_rlp_addr, end_rlp_addr, rlp_len, retdest) -> (retdest, prefix_start_rlp_addr, rlp_len) JUMP prepend_rlp_list_prefix_big: - // We have a large list, so we prepend 0xf7 + len_of_len at position - // prefix_start_pos = start_pos - 1 - len_of_len + // We have a large list, so we prepend 0xf7 + len_of_len at rlp_address + // prefix_start_rlp_addr = start_rlp_addr - 1 - len_of_len // followed by the length itself. - // stack: payload_len, end_pos, start_pos, retdest + // stack: payload_len, end_rlp_addr, start_rlp_addr, retdest DUP1 %num_bytes - // stack: len_of_len, payload_len, end_pos, start_pos, retdest + // stack: len_of_len, payload_len, end_rlp_addr, start_rlp_addr, retdest DUP1 - DUP5 %decrement // start_pos - 1 + DUP5 %decrement // start_rlp_addr - 1 SUB - // stack: prefix_start_pos, len_of_len, payload_len, end_pos, start_pos, retdest - DUP2 %add_const(0xf7) DUP2 %mstore_rlp // rlp[prefix_start_pos] = 0xf7 + len_of_len - // stack: prefix_start_pos, len_of_len, payload_len, end_pos, start_pos, retdest - DUP1 %increment // start_len_pos = prefix_start_pos + 1 - %stack (start_len_pos, prefix_start_pos, len_of_len, payload_len, end_pos, start_pos, retdest) - -> (start_len_pos, payload_len, len_of_len, + // stack: prefix_start_rlp_addr, len_of_len, payload_len, end_rlp_addr, start_rlp_addr, retdest + DUP2 %add_const(0xf7) DUP2 %mstore_rlp // rlp[prefix_start_rlp_addr] = 0xf7 + len_of_len + // stack: prefix_start_rlp_addr, len_of_len, payload_len, end_rlp_addr, start_rlp_addr, retdest + DUP1 %increment // start_len_rlp_addr = prefix_start_rlp_addr + 1 + %stack (start_len_rlp_addr, prefix_start_rlp_addr, len_of_len, payload_len, end_rlp_addr, start_rlp_addr, retdest) + -> (start_len_rlp_addr, payload_len, len_of_len, prepend_rlp_list_prefix_big_done_writing_len, - prefix_start_pos, end_pos, retdest) - %jump(mstore_unpacking_rlp) + prefix_start_rlp_addr, end_rlp_addr, retdest) + %jump(mstore_unpacking) prepend_rlp_list_prefix_big_done_writing_len: - // stack: start_pos, prefix_start_pos, end_pos, retdest - %stack (start_pos, prefix_start_pos, end_pos) - -> (end_pos, prefix_start_pos, prefix_start_pos) - // stack: end_pos, prefix_start_pos, prefix_start_pos, retdest + // stack: start_rlp_addr, prefix_start_rlp_addr, end_rlp_addr, retdest + %stack (start_rlp_addr, prefix_start_rlp_addr, end_rlp_addr) + -> (end_rlp_addr, prefix_start_rlp_addr, prefix_start_rlp_addr) + // stack: end_rlp_addr, prefix_start_rlp_addr, prefix_start_rlp_addr, retdest SUB - // stack: rlp_len, prefix_start_pos, retdest - %stack (rlp_len, prefix_start_pos, retdest) -> (retdest, prefix_start_pos, rlp_len) + // stack: rlp_len, prefix_start_rlp_addr, retdest + %stack (rlp_len, prefix_start_rlp_addr, retdest) -> (retdest, prefix_start_rlp_addr, rlp_len) JUMP // Convenience macro to call prepend_rlp_list_prefix and return where we left off. %macro prepend_rlp_list_prefix - %stack (end_pos, start_pos) -> (end_pos, start_pos, %%after) + %stack (end_rlp_addr, start_rlp_addr) -> (end_rlp_addr, start_rlp_addr, %%after) %jump(prepend_rlp_list_prefix) %%after: %endmacro @@ -274,18 +274,3 @@ prepend_rlp_list_prefix_big_done_writing_len: ADD %%finish: %endmacro - -// Like mstore_unpacking, but specifically for the RLP segment. -// Pre stack: offset, value, len, retdest -// Post stack: offset' -global mstore_unpacking_rlp: - // stack: offset, value, len, retdest - PUSH @SEGMENT_RLP_RAW - PUSH 0 // context - %jump(mstore_unpacking) - -%macro mstore_unpacking_rlp - %stack (offset, value, len) -> (offset, value, len, %%after) - %jump(mstore_unpacking_rlp) -%%after: -%endmacro diff --git a/evm/src/cpu/kernel/asm/rlp/encode_rlp_scalar.asm b/evm/src/cpu/kernel/asm/rlp/encode_rlp_scalar.asm index cd4a837e31..8196a452ab 100644 --- a/evm/src/cpu/kernel/asm/rlp/encode_rlp_scalar.asm +++ b/evm/src/cpu/kernel/asm/rlp/encode_rlp_scalar.asm @@ -1,8 +1,8 @@ // RLP-encode a scalar, i.e. a variable-length integer. -// Pre stack: pos, scalar, retdest -// Post stack: pos +// Pre stack: rlp_addr, scalar, retdest +// Post stack: rlp_addr global encode_rlp_scalar: - // stack: pos, scalar, retdest + // stack: rlp_addr, scalar, retdest // If scalar > 0x7f, this is the "medium" case. DUP2 %gt_const(0x7f) @@ -12,12 +12,12 @@ global encode_rlp_scalar: DUP2 %jumpi(encode_rlp_scalar_small) // scalar = 0, so BE(scalar) is the empty string, which RLP encodes as a single byte 0x80. - // stack: pos, scalar, retdest - %stack (pos, scalar) -> (pos, 0x80, pos) - %mstore_rlp - // stack: pos, retdest + // stack: rlp_addr, scalar, retdest + %stack (rlp_addr, scalar) -> (0x80, rlp_addr, rlp_addr) + MSTORE_GENERAL + // stack: rlp_addr, retdest %increment - // stack: pos', retdest + // stack: rlp_addr', retdest SWAP1 JUMP @@ -26,17 +26,17 @@ encode_rlp_scalar_medium: // (big-endian) scalar bytes. We first compute the minimal number of bytes // needed to represent this scalar, then treat it as if it was a fixed- // length string with that length. - // stack: pos, scalar, retdest + // stack: rlp_addr, scalar, retdest DUP2 %num_bytes - // stack: scalar_bytes, pos, scalar, retdest + // stack: scalar_bytes, rlp_addr, scalar, retdest %jump(encode_rlp_fixed) // Doubly-RLP-encode a scalar, i.e. return encode(encode(scalar)). -// Pre stack: pos, scalar, retdest -// Post stack: pos +// Pre stack: rlp_addr, scalar, retdest +// Post stack: rlp_addr global doubly_encode_rlp_scalar: - // stack: pos, scalar, retdest + // stack: rlp_addr, scalar, retdest // If scalar > 0x7f, this is the "medium" case. DUP2 %gt_const(0x7f) @@ -46,15 +46,16 @@ global doubly_encode_rlp_scalar: DUP2 %jumpi(encode_rlp_scalar_small) // scalar = 0, so BE(scalar) is the empty string, encode(scalar) = 0x80, and encode(encode(scalar)) = 0x8180. - // stack: pos, scalar, retdest - %stack (pos, scalar) -> (pos, 0x81, pos, 0x80, pos) - %mstore_rlp - // stack: pos, 0x80, pos, retdest + // stack: rlp_addr, scalar, retdest + %stack (rlp_addr, scalar) -> (0x81, rlp_addr, rlp_addr) + MSTORE_GENERAL + // stack: rlp_addr, retdest %increment - %mstore_rlp - // stack: pos, retdest - %add_const(2) - // stack: pos, retdest + DUP1 PUSH 0x80 + MSTORE_GENERAL + // stack: rlp_addr, retdest + %increment + // stack: rlp_addr, retdest SWAP1 JUMP @@ -65,35 +66,35 @@ doubly_encode_rlp_scalar_medium: // encode(encode(scalar)) = [0x80 + len + 1] || [0x80 + len] || BE(scalar) // We first compute the length of the scalar with %num_bytes, then treat the scalar as if it was a // fixed-length string with that length. - // stack: pos, scalar, retdest + // stack: rlp_addr, scalar, retdest DUP2 %num_bytes - // stack: scalar_bytes, pos, scalar, retdest + // stack: scalar_bytes, rlp_addr, scalar, retdest %jump(doubly_encode_rlp_fixed) // The "small" case of RLP-encoding a scalar, where the value is its own encoding. // This can be used for both for singly encoding or doubly encoding, since encode(encode(x)) = encode(x) = x. encode_rlp_scalar_small: - // stack: pos, scalar, retdest - %stack (pos, scalar) -> (pos, scalar, pos) - // stack: pos, scalar, pos, retdest - %mstore_rlp - // stack: pos, retdest + // stack: rlp_addr, scalar, retdest + %stack (rlp_addr, scalar) -> (scalar, rlp_addr, rlp_addr) + // stack: scalar, rlp_addr, rlp_addr, retdest + MSTORE_GENERAL + // stack: rlp_addr, retdest %increment - // stack: pos', retdest + // stack: rlp_addr', retdest SWAP1 JUMP // Convenience macro to call encode_rlp_scalar and return where we left off. %macro encode_rlp_scalar - %stack (pos, scalar) -> (pos, scalar, %%after) + %stack (rlp_addr, scalar) -> (rlp_addr, scalar, %%after) %jump(encode_rlp_scalar) %%after: %endmacro // Convenience macro to call doubly_encode_rlp_scalar and return where we left off. %macro doubly_encode_rlp_scalar - %stack (pos, scalar) -> (pos, scalar, %%after) + %stack (rlp_addr, scalar) -> (rlp_addr, scalar, %%after) %jump(doubly_encode_rlp_scalar) %%after: %endmacro diff --git a/evm/src/cpu/kernel/asm/rlp/encode_rlp_string.asm b/evm/src/cpu/kernel/asm/rlp/encode_rlp_string.asm index 1c8bec9673..60174a9436 100644 --- a/evm/src/cpu/kernel/asm/rlp/encode_rlp_string.asm +++ b/evm/src/cpu/kernel/asm/rlp/encode_rlp_string.asm @@ -1,80 +1,79 @@ // Encodes an arbitrary string, given a pointer and length. -// Pre stack: pos, ADDR: 3, len, retdest -// Post stack: pos' +// Pre stack: rlp_addr, ADDR, len, retdest +// Post stack: rlp_addr' global encode_rlp_string: - // stack: pos, ADDR: 3, len, retdest - DUP5 %eq_const(1) - // stack: len == 1, pos, ADDR: 3, len, retdest - DUP5 DUP5 DUP5 // ADDR: 3 + // stack: rlp_addr, ADDR, len, retdest + DUP3 %eq_const(1) + // stack: len == 1, rlp_addr, ADDR, len, retdest + DUP3 MLOAD_GENERAL - // stack: first_byte, len == 1, pos, ADDR: 3, len, retdest + // stack: first_byte, len == 1, rlp_addr, ADDR, len, retdest %lt_const(128) MUL // cheaper than AND - // stack: single_small_byte, pos, ADDR: 3, len, retdest + // stack: single_small_byte, rlp_addr, ADDR, len, retdest %jumpi(encode_rlp_string_small_single_byte) - // stack: pos, ADDR: 3, len, retdest - DUP5 %gt_const(55) - // stack: len > 55, pos, ADDR: 3, len, retdest + // stack: rlp_addr, ADDR, len, retdest + DUP3 %gt_const(55) + // stack: len > 55, rlp_addr, ADDR, len, retdest %jumpi(encode_rlp_string_large) global encode_rlp_string_small: - // stack: pos, ADDR: 3, len, retdest - DUP5 // len + // stack: rlp_addr, ADDR, len, retdest + DUP1 + DUP4 // len %add_const(0x80) - // stack: first_byte, pos, ADDR: 3, len, retdest - DUP2 - // stack: pos, first_byte, pos, ADDR: 3, len, retdest - %mstore_rlp - // stack: pos, ADDR: 3, len, retdest + // stack: first_byte, rlp_addr, rlp_addr, ADDR, len, retdest + MSTORE_GENERAL + // stack: rlp_addr, ADDR, len, retdest %increment - // stack: pos', ADDR: 3, len, retdest - DUP5 DUP2 ADD // pos'' = pos' + len - // stack: pos'', pos', ADDR: 3, len, retdest - %stack (pos2, pos1, ADDR: 3, len, retdest) - -> (0, @SEGMENT_RLP_RAW, pos1, ADDR, len, retdest, pos2) + // stack: rlp_addr', ADDR, len, retdest + DUP3 DUP2 ADD // rlp_addr'' = rlp_addr' + len + // stack: rlp_addr'', rlp_addr', ADDR, len, retdest + %stack (rlp_addr2, rlp_addr1, ADDR, len, retdest) + -> (rlp_addr1, ADDR, len, retdest, rlp_addr2) %jump(memcpy_bytes) global encode_rlp_string_small_single_byte: - // stack: pos, ADDR: 3, len, retdest - %stack (pos, ADDR: 3, len) -> (ADDR, pos) + // stack: rlp_addr, ADDR, len, retdest + %stack (rlp_addr, ADDR, len) -> (ADDR, rlp_addr) MLOAD_GENERAL - // stack: byte, pos, retdest - DUP2 - %mstore_rlp - // stack: pos, retdest + // stack: byte, rlp_addr, retdest + DUP2 SWAP1 + MSTORE_GENERAL + // stack: rlp_addr, retdest %increment SWAP1 - // stack: retdest, pos' + // stack: retdest, rlp_addr' JUMP global encode_rlp_string_large: - // stack: pos, ADDR: 3, len, retdest - DUP5 %num_bytes - // stack: len_of_len, pos, ADDR: 3, len, retdest + // stack: rlp_addr, ADDR, len, retdest + DUP3 %num_bytes + // stack: len_of_len, rlp_addr, ADDR, len, retdest SWAP1 - DUP2 // len_of_len + DUP1 + // stack: rlp_addr, rlp_addr, len_of_len, ADDR, len, retdest + DUP3 // len_of_len %add_const(0xb7) - // stack: first_byte, pos, len_of_len, ADDR: 3, len, retdest - DUP2 - // stack: pos, first_byte, pos, len_of_len, ADDR: 3, len, retdest - %mstore_rlp - // stack: pos, len_of_len, ADDR: 3, len, retdest + // stack: first_byte, rlp_addr, rlp_addr, len_of_len, ADDR, len, retdest + MSTORE_GENERAL + // stack: rlp_addr, len_of_len, ADDR, len, retdest %increment - // stack: pos', len_of_len, ADDR: 3, len, retdest - %stack (pos, len_of_len, ADDR: 3, len) - -> (pos, len, len_of_len, encode_rlp_string_large_after_writing_len, ADDR, len) - %jump(mstore_unpacking_rlp) + // stack: rlp_addr', len_of_len, ADDR, len, retdest + %stack (rlp_addr, len_of_len, ADDR, len) + -> (rlp_addr, len, len_of_len, encode_rlp_string_large_after_writing_len, ADDR, len) + %jump(mstore_unpacking) global encode_rlp_string_large_after_writing_len: - // stack: pos'', ADDR: 3, len, retdest - DUP5 DUP2 ADD // pos''' = pos'' + len - // stack: pos''', pos'', ADDR: 3, len, retdest - %stack (pos3, pos2, ADDR: 3, len, retdest) - -> (0, @SEGMENT_RLP_RAW, pos2, ADDR, len, retdest, pos3) + // stack: rlp_addr'', ADDR, len, retdest + DUP3 DUP2 ADD // rlp_addr''' = rlp_addr'' + len + // stack: rlp_addr''', rlp_addr'', ADDR, len, retdest + %stack (rlp_addr3, rlp_addr2, ADDR, len, retdest) + -> (rlp_addr2, ADDR, len, retdest, rlp_addr3) %jump(memcpy_bytes) %macro encode_rlp_string - %stack (pos, ADDR: 3, len) -> (pos, ADDR, len, %%after) + %stack (rlp_addr, ADDR, len) -> (rlp_addr, ADDR, len, %%after) %jump(encode_rlp_string) %%after: %endmacro diff --git a/evm/src/cpu/kernel/asm/rlp/read_to_memory.asm b/evm/src/cpu/kernel/asm/rlp/read_to_memory.asm index 85a7817522..7593537194 100644 --- a/evm/src/cpu/kernel/asm/rlp/read_to_memory.asm +++ b/evm/src/cpu/kernel/asm/rlp/read_to_memory.asm @@ -8,29 +8,34 @@ global read_rlp_to_memory: // stack: retdest PROVER_INPUT(rlp) // Read the RLP blob length from the prover tape. // stack: len, retdest - PUSH 0 // initial position - // stack: pos, len, retdest + PUSH @SEGMENT_RLP_RAW + %build_kernel_address + + PUSH @SEGMENT_RLP_RAW // ctx == virt == 0 + // stack: addr, final_addr, retdest read_rlp_to_memory_loop: - // stack: pos, len, retdest + // stack: addr, final_addr, retdest DUP2 DUP2 EQ - // stack: pos == len, pos, len, retdest + // stack: addr == final_addr, addr, final_addr, retdest %jumpi(read_rlp_to_memory_finish) - // stack: pos, len, retdest + // stack: addr, len, retdest + DUP1 PROVER_INPUT(rlp) - // stack: byte, pos, len, retdest - DUP2 - // stack: pos, byte, pos, len, retdest - %mstore_kernel(@SEGMENT_RLP_RAW) - // stack: pos, len, retdest + // stack: byte, addr, addr, final_addr, retdest + MSTORE_GENERAL + // stack: addr, final_addr, retdest %increment - // stack: pos', len, retdest + // stack: addr', final_addr, retdest %jump(read_rlp_to_memory_loop) read_rlp_to_memory_finish: - // stack: pos, len, retdest - POP - // stack: len, retdest - SWAP1 JUMP + // stack: addr, final_addr, retdest + // we recover the offset here + PUSH @SEGMENT_RLP_RAW // ctx == virt == 0 + DUP2 SUB + // stack: pos, addr, final_addr, retdest + %stack(pos, addr, final_addr, retdest) -> (retdest, pos) + JUMP diff --git a/evm/src/cpu/kernel/asm/shift.asm b/evm/src/cpu/kernel/asm/shift.asm index 9040f1955b..ee9ccbfaea 100644 --- a/evm/src/cpu/kernel/asm/shift.asm +++ b/evm/src/cpu/kernel/asm/shift.asm @@ -2,21 +2,17 @@ /// /// Specifically, set SHIFT_TABLE_SEGMENT[i] = 2^i for i = 0..255. %macro shift_table_init - push 0 // initial offset is zero - push @SEGMENT_SHIFT_TABLE // segment - dup2 // kernel context is 0 + push @SEGMENT_SHIFT_TABLE // segment, ctx == virt == 0 push 1 // 2^0 %rep 255 - // stack: 2^i, context, segment, ost_i - dup4 + // stack: 2^i, addr_i + dup2 %increment - dup4 - dup4 - // stack: context, segment, ost_(i+1), 2^i, context, segment, ost_i - dup4 + // stack: addr_(i+1), 2^i, addr_i + dup2 dup1 add - // stack: 2^(i+1), context, segment, ost_(i+1), 2^i, context, segment, ost_i + // stack: 2^(i+1), addr_(i+1), 2^i, addr_i %endrep %rep 256 mstore_general diff --git a/evm/src/cpu/kernel/asm/transactions/common_decoding.asm b/evm/src/cpu/kernel/asm/transactions/common_decoding.asm index d4df7a6e57..4a8feccaa3 100644 --- a/evm/src/cpu/kernel/asm/transactions/common_decoding.asm +++ b/evm/src/cpu/kernel/asm/transactions/common_decoding.asm @@ -6,207 +6,206 @@ // Decode the chain ID and store it. %macro decode_and_store_chain_id - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, chain_id) -> (chain_id, pos) + %stack (rlp_addr, chain_id) -> (chain_id, rlp_addr) %mstore_txn_field(@TXN_FIELD_CHAIN_ID) - // stack: pos + // stack: rlp_addr %endmacro // Decode the nonce and store it. %macro decode_and_store_nonce - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, nonce) -> (nonce, pos) + %stack (rlp_addr, nonce) -> (nonce, rlp_addr) %mstore_txn_field(@TXN_FIELD_NONCE) - // stack: pos + // stack: rlp_addr %endmacro // Decode the gas price and, since this is for legacy txns, store it as both // TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS and TXN_FIELD_MAX_FEE_PER_GAS. %macro decode_and_store_gas_price_legacy - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, gas_price) -> (gas_price, gas_price, pos) + %stack (rlp_addr, gas_price) -> (gas_price, gas_price, rlp_addr) %mstore_txn_field(@TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS) %mstore_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS) - // stack: pos + // stack: rlp_addr %endmacro // Decode the max priority fee and store it. %macro decode_and_store_max_priority_fee - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, gas_price) -> (gas_price, pos) + %stack (rlp_addr, gas_price) -> (gas_price, rlp_addr) %mstore_txn_field(@TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS) - // stack: pos + // stack: rlp_addr %endmacro // Decode the max fee and store it. %macro decode_and_store_max_fee - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, gas_price) -> (gas_price, pos) + %stack (rlp_addr, gas_price) -> (gas_price, rlp_addr) %mstore_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS) - // stack: pos + // stack: rlp_addr %endmacro // Decode the gas limit and store it. %macro decode_and_store_gas_limit - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, gas_limit) -> (gas_limit, pos) + %stack (rlp_addr, gas_limit) -> (gas_limit, rlp_addr) %mstore_txn_field(@TXN_FIELD_GAS_LIMIT) - // stack: pos + // stack: rlp_addr %endmacro // Decode the "to" field and store it. // This field is either 160-bit or empty in the case of a contract creation txn. %macro decode_and_store_to - // stack: pos + // stack: rlp_addr %decode_rlp_string_len - // stack: pos, len + // stack: rlp_addr, len SWAP1 - // stack: len, pos + // stack: len, rlp_addr DUP1 ISZERO %jumpi(%%contract_creation) - // stack: len, pos + // stack: len, rlp_addr DUP1 %eq_const(20) ISZERO %jumpi(invalid_txn) // Address is 160-bit - %stack (len, pos) -> (pos, len, %%with_scalar) + %stack (len, rlp_addr) -> (rlp_addr, len, %%with_scalar) %jump(decode_int_given_len) %%with_scalar: - // stack: pos, int + // stack: rlp_addr, int SWAP1 %mstore_txn_field(@TXN_FIELD_TO) - // stack: pos + // stack: rlp_addr %jump(%%end) %%contract_creation: - // stack: len, pos + // stack: len, rlp_addr POP PUSH 1 %mstore_global_metadata(@GLOBAL_METADATA_CONTRACT_CREATION) - // stack: pos + // stack: rlp_addr %%end: %endmacro // Decode the "value" field and store it. %macro decode_and_store_value - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, value) -> (value, pos) + %stack (rlp_addr, value) -> (value, rlp_addr) %mstore_txn_field(@TXN_FIELD_VALUE) - // stack: pos + // stack: rlp_addr %endmacro // Decode the calldata field, store its length in @TXN_FIELD_DATA_LEN, and copy it to @SEGMENT_TXN_DATA. %macro decode_and_store_data - // stack: pos - // Decode the data length, store it, and compute new_pos after any data. + // stack: rlp_addr + // Decode the data length, store it, and compute new_rlp_addr after any data. %decode_rlp_string_len - %stack (pos, data_len) -> (data_len, pos, data_len, pos, data_len) + %stack (rlp_addr, data_len) -> (data_len, rlp_addr, data_len, rlp_addr, data_len) %mstore_txn_field(@TXN_FIELD_DATA_LEN) - // stack: pos, data_len, pos, data_len + // stack: rlp_addr, data_len, rlp_addr, data_len ADD - // stack: new_pos, old_pos, data_len + // stack: new_rlp_addr, old_rlp_addr, data_len // Memcpy the txn data from @SEGMENT_RLP_RAW to @SEGMENT_TXN_DATA. - %stack (new_pos, old_pos, data_len) -> (old_pos, data_len, %%after, new_pos) - PUSH @SEGMENT_RLP_RAW - GET_CONTEXT - PUSH 0 + %stack (new_rlp_addr, old_rlp_addr, data_len) -> (old_rlp_addr, data_len, %%after, new_rlp_addr) + // old_rlp_addr has context 0. We will call GET_CONTEXT and update it. + GET_CONTEXT ADD PUSH @SEGMENT_TXN_DATA - GET_CONTEXT - // stack: DST, SRC, data_len, %%after, new_pos + GET_CONTEXT ADD + // stack: DST, SRC, data_len, %%after, new_rlp_addr %jump(memcpy_bytes) %%after: - // stack: new_pos + // stack: new_rlp_addr %endmacro %macro decode_and_store_access_list - // stack: pos + // stack: rlp_addr DUP1 %mstore_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_START) %decode_rlp_list_len - %stack (pos, len) -> (len, len, pos, %%after) + %stack (rlp_addr, len) -> (len, len, rlp_addr, %%after) %jumpi(decode_and_store_access_list) - // stack: len, pos, %%after + // stack: len, rlp_addr, %%after POP SWAP1 POP - // stack: pos + // stack: rlp_addr %mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_START) DUP2 SUB %mstore_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN) %%after: %endmacro %macro decode_and_store_y_parity - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, y_parity) -> (y_parity, pos) + %stack (rlp_addr, y_parity) -> (y_parity, rlp_addr) %mstore_txn_field(@TXN_FIELD_Y_PARITY) - // stack: pos + // stack: rlp_addr %endmacro %macro decode_and_store_r - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, r) -> (r, pos) + %stack (rlp_addr, r) -> (r, rlp_addr) %mstore_txn_field(@TXN_FIELD_R) - // stack: pos + // stack: rlp_addr %endmacro %macro decode_and_store_s - // stack: pos + // stack: rlp_addr %decode_rlp_scalar - %stack (pos, s) -> (s, pos) + %stack (rlp_addr, s) -> (s, rlp_addr) %mstore_txn_field(@TXN_FIELD_S) - // stack: pos + // stack: rlp_addr %endmacro // The access list is of the form `[[{20 bytes}, [{32 bytes}...]]...]`. global decode_and_store_access_list: - // stack: len, pos + // stack: len, rlp_addr DUP2 ADD - // stack: end_pos, pos + // stack: end_rlp_addr, rlp_addr // Store the RLP length. %mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_START) DUP2 SUB %mstore_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN) SWAP1 decode_and_store_access_list_loop: - // stack: pos, end_pos + // stack: rlp_addr, end_rlp_addr DUP2 DUP2 EQ %jumpi(decode_and_store_access_list_finish) - // stack: pos, end_pos + // stack: rlp_addr, end_rlp_addr %decode_rlp_list_len // Should be a list `[{20 bytes}, [{32 bytes}...]]` - // stack: pos, internal_len, end_pos + // stack: rlp_addr, internal_len, end_rlp_addr SWAP1 POP // We don't need the length of this list. - // stack: pos, end_pos + // stack: rlp_addr, end_rlp_addr %decode_rlp_scalar // Address // TODO: Should panic when address is not 20 bytes? - // stack: pos, addr, end_pos + // stack: rlp_addr, addr, end_rlp_addr SWAP1 - // stack: addr, pos, end_pos + // stack: addr, rlp_addr, end_rlp_addr DUP1 %insert_accessed_addresses_no_return - // stack: addr, pos, end_pos + // stack: addr, rlp_addr, end_rlp_addr %add_address_cost - // stack: addr, pos, end_pos + // stack: addr, rlp_addr, end_rlp_addr SWAP1 - // stack: pos, addr, end_pos + // stack: rlp_addr, addr, end_rlp_addr %decode_rlp_list_len // Should be a list of storage keys `[{32 bytes}...]` - // stack: pos, sk_len, addr, end_pos + // stack: rlp_addr, sk_len, addr, end_rlp_addr SWAP1 DUP2 ADD - // stack: sk_end_pos, pos, addr, end_pos + // stack: sk_end_rlp_addr, rlp_addr, addr, end_rlp_addr SWAP1 - // stack: pos, sk_end_pos, addr, end_pos + // stack: rlp_addr, sk_end_rlp_addr, addr, end_rlp_addr sk_loop: DUP2 DUP2 EQ %jumpi(end_sk) - // stack: pos, sk_end_pos, addr, end_pos + // stack: rlp_addr, sk_end_rlp_addr, addr, end_rlp_addr %decode_rlp_scalar // Storage key // TODO: Should panic when key is not 32 bytes? - %stack (pos, key, sk_end_pos, addr, end_pos) -> - (addr, key, sk_loop_contd, pos, sk_end_pos, addr, end_pos) + %stack (rlp_addr, key, sk_end_rlp_addr, addr, end_rlp_addr) -> + (addr, key, sk_loop_contd, rlp_addr, sk_end_rlp_addr, addr, end_rlp_addr) %jump(insert_accessed_storage_keys_with_original_value) sk_loop_contd: - // stack: pos, sk_end_pos, addr, end_pos + // stack: rlp_addr, sk_end_rlp_addr, addr, end_rlp_addr %add_storage_key_cost %jump(sk_loop) end_sk: - %stack (pos, sk_end_pos, addr, end_pos) -> (pos, end_pos) + %stack (rlp_addr, sk_end_rlp_addr, addr, end_rlp_addr) -> (rlp_addr, end_rlp_addr) %jump(decode_and_store_access_list_loop) decode_and_store_access_list_finish: - %stack (pos, end_pos, retdest) -> (retdest, pos) + %stack (rlp_addr, end_rlp_addr, retdest) -> (retdest, rlp_addr) JUMP %macro add_address_cost diff --git a/evm/src/cpu/kernel/asm/transactions/router.asm b/evm/src/cpu/kernel/asm/transactions/router.asm index 109334dd0d..2ecccfe02b 100644 --- a/evm/src/cpu/kernel/asm/transactions/router.asm +++ b/evm/src/cpu/kernel/asm/transactions/router.asm @@ -20,15 +20,15 @@ read_txn_from_memory: // Type 0 (legacy) transactions have no such prefix, but their RLP will have a // first byte >= 0xc0, so there is no overlap. - PUSH 0 - %mload_kernel(@SEGMENT_RLP_RAW) + PUSH @SEGMENT_RLP_RAW // ctx == virt == 0 + MLOAD_GENERAL %eq_const(1) // stack: first_byte == 1, retdest %jumpi(process_type_1_txn) // stack: retdest - PUSH 0 - %mload_kernel(@SEGMENT_RLP_RAW) + PUSH @SEGMENT_RLP_RAW // ctx == virt == 0 + MLOAD_GENERAL %eq_const(2) // stack: first_byte == 2, retdest %jumpi(process_type_2_txn) @@ -53,10 +53,12 @@ global update_txn_trie: // and now copy txn_rlp to the new block %stack (rlp_start, txn_rlp_len, value_ptr, txn_counter, num_nibbles) -> ( - 0, @SEGMENT_TRIE_DATA, rlp_start, // dest addr - 0, @SEGMENT_RLP_RAW, 0, // src addr. Kernel has context 0 + @SEGMENT_RLP_RAW, // src addr. ctx == virt == 0 + rlp_start, @SEGMENT_TRIE_DATA, // swapped dest addr, ctx == 0 txn_rlp_len, // mcpy len txn_rlp_len, rlp_start, txn_counter, num_nibbles, value_ptr) + SWAP2 %build_kernel_address + // stack: DST, SRC, txn_rlp_len, txn_rlp_len, rlp_start, txn_counter, num_nibbles, value_ptr %memcpy_bytes ADD %set_trie_data_size diff --git a/evm/src/cpu/kernel/asm/transactions/type_0.asm b/evm/src/cpu/kernel/asm/transactions/type_0.asm index edd01e512d..0cd22c10f2 100644 --- a/evm/src/cpu/kernel/asm/transactions/type_0.asm +++ b/evm/src/cpu/kernel/asm/transactions/type_0.asm @@ -13,68 +13,68 @@ global process_type_0_txn: // stack: retdest - PUSH 0 // initial pos - // stack: pos, retdest + PUSH @SEGMENT_RLP_RAW // ctx == virt == 0 + // stack: rlp_addr, retdest %decode_rlp_list_len // We don't actually need the length. - %stack (pos, len) -> (pos) + %stack (rlp_addr, len) -> (rlp_addr) - // stack: pos, retdest + // stack: rlp_addr, retdest %decode_and_store_nonce %decode_and_store_gas_price_legacy %decode_and_store_gas_limit %decode_and_store_to %decode_and_store_value %decode_and_store_data - // stack: pos, retdest + // stack: rlp_addr, retdest // Parse the "v" field. - // stack: pos, retdest + // stack: rlp_addr, retdest %decode_rlp_scalar - // stack: pos, v, retdest + // stack: rlp_addr, v, retdest SWAP1 - // stack: v, pos, retdest + // stack: v, rlp_addr, retdest DUP1 %gt_const(28) - // stack: v > 28, v, pos, retdest + // stack: v > 28, v, rlp_addr, retdest %jumpi(process_v_new_style) // We have an old style v, so y_parity = v - 27. // No chain ID is present, so we can leave TXN_FIELD_CHAIN_ID_PRESENT and // TXN_FIELD_CHAIN_ID with their default values of zero. - // stack: v, pos, retdest + // stack: v, rlp_addr, retdest %sub_const(27) - %stack (y_parity, pos) -> (y_parity, pos) + %stack (y_parity, rlp_addr) -> (y_parity, rlp_addr) %mstore_txn_field(@TXN_FIELD_Y_PARITY) - // stack: pos, retdest + // stack: rlp_addr, retdest %jump(decode_r_and_s) process_v_new_style: - // stack: v, pos, retdest + // stack: v, rlp_addr, retdest // We have a new style v, so chain_id_present = 1, // chain_id = (v - 35) / 2, and y_parity = (v - 35) % 2. - %stack (v, pos) -> (1, v, pos) + %stack (v, rlp_addr) -> (1, v, rlp_addr) %mstore_txn_field(@TXN_FIELD_CHAIN_ID_PRESENT) - // stack: v, pos, retdest + // stack: v, rlp_addr, retdest %sub_const(35) DUP1 - // stack: v - 35, v - 35, pos, retdest + // stack: v - 35, v - 35, rlp_addr, retdest %div_const(2) - // stack: chain_id, v - 35, pos, retdest + // stack: chain_id, v - 35, rlp_addr, retdest %mstore_txn_field(@TXN_FIELD_CHAIN_ID) - // stack: v - 35, pos, retdest + // stack: v - 35, rlp_addr, retdest %mod_const(2) - // stack: y_parity, pos, retdest + // stack: y_parity, rlp_addr, retdest %mstore_txn_field(@TXN_FIELD_Y_PARITY) decode_r_and_s: - // stack: pos, retdest + // stack: rlp_addr, retdest %decode_and_store_r %decode_and_store_s - // stack: pos, retdest + // stack: rlp_addr, retdest POP // stack: retdest @@ -85,73 +85,68 @@ type_0_compute_signed_data: // keccak256(rlp([nonce, gas_price, gas_limit, to, value, data])) %alloc_rlp_block - // stack: rlp_start, retdest + // stack: rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_NONCE) - // stack: nonce, rlp_start, retdest + // stack: nonce, rlp_addr_start, retdest DUP2 - // stack: rlp_pos, nonce, rlp_start, retdest + // stack: rlp_addr, nonce, rlp_addr_start, retdest %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_GAS_LIMIT) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_TO) %mload_global_metadata(@GLOBAL_METADATA_CONTRACT_CREATION) %jumpi(zero_to) - // stack: to, rlp_pos, rlp_start, retdest + // stack: to, rlp_addr, rlp_addr_start, retdest SWAP1 %encode_rlp_160 %jump(after_to) zero_to: - // stack: to, rlp_pos, rlp_start, retdest + // stack: to, rlp_addr, rlp_addr_start, retdest SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest after_to: %mload_txn_field(@TXN_FIELD_VALUE) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest // Encode txn data. %mload_txn_field(@TXN_FIELD_DATA_LEN) - PUSH 0 // ADDR.virt PUSH @SEGMENT_TXN_DATA - PUSH 0 // ADDR.context - // stack: ADDR: 3, len, rlp_pos, rlp_start, retdest + // stack: ADDR, len, rlp_addr, rlp_addr_start, retdest PUSH after_serializing_txn_data - // stack: after_serializing_txn_data, ADDR: 3, len, rlp_pos, rlp_start, retdest - SWAP5 - // stack: rlp_pos, ADDR: 3, len, after_serializing_txn_data, rlp_start, retdest + // stack: after_serializing_txn_data, ADDR, len, rlp_addr, rlp_addr_start, retdest + SWAP3 + // stack: rlp_addr, ADDR, len, after_serializing_txn_data, rlp_addr_start, retdest %jump(encode_rlp_string) after_serializing_txn_data: - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_CHAIN_ID_PRESENT) ISZERO %jumpi(finish_rlp_list) - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_CHAIN_ID) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest PUSH 0 SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest PUSH 0 SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest finish_rlp_list: %prepend_rlp_list_prefix - // stack: prefix_start_pos, rlp_len, retdest - PUSH @SEGMENT_RLP_RAW - PUSH 0 // context - // stack: ADDR: 3, rlp_len, retdest + // stack: ADDR, rlp_len, retdest KECCAK_GENERAL // stack: hash, retdest diff --git a/evm/src/cpu/kernel/asm/transactions/type_1.asm b/evm/src/cpu/kernel/asm/transactions/type_1.asm index c9298b6617..f9142bd4a4 100644 --- a/evm/src/cpu/kernel/asm/transactions/type_1.asm +++ b/evm/src/cpu/kernel/asm/transactions/type_1.asm @@ -8,11 +8,14 @@ global process_type_1_txn: // stack: retdest - PUSH 1 // initial pos, skipping over the 0x01 byte - // stack: pos, retdest + // Initial rlp address offset of 1 (skipping over the 0x01 byte) + PUSH 1 + PUSH @SEGMENT_RLP_RAW + %build_kernel_address + // stack: rlp_addr, retdest %decode_rlp_list_len // We don't actually need the length. - %stack (pos, len) -> (pos) + %stack (rlp_addr, len) -> (rlp_addr) %store_chain_id_present_true %decode_and_store_chain_id @@ -27,7 +30,7 @@ global process_type_1_txn: %decode_and_store_r %decode_and_store_s - // stack: pos, retdest + // stack: rlp_addr, retdest POP // stack: retdest @@ -36,83 +39,79 @@ global process_type_1_txn: // over keccak256(0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList])). type_1_compute_signed_data: %alloc_rlp_block - // stack: rlp_start, retdest + // stack: rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_CHAIN_ID) - // stack: chain_id, rlp_start, retdest + // stack: chain_id, rlp_addr_start, retdest DUP2 - // stack: rlp_pos, chain_id, rlp_start, retdest + // stack: rlp_addr, chain_id, rlp_addr_start, retdest %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_NONCE) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_GAS_LIMIT) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_TO) %mload_global_metadata(@GLOBAL_METADATA_CONTRACT_CREATION) %jumpi(zero_to) - // stack: to, rlp_pos, rlp_start, retdest + // stack: to, rlp_addr, rlp_addr_start, retdest SWAP1 %encode_rlp_160 %jump(after_to) zero_to: - // stack: to, rlp_pos, rlp_start, retdest + // stack: to, rlp_addr, rlp_addr_start, retdest SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest after_to: %mload_txn_field(@TXN_FIELD_VALUE) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest // Encode txn data. %mload_txn_field(@TXN_FIELD_DATA_LEN) - PUSH 0 // ADDR.virt - PUSH @SEGMENT_TXN_DATA - PUSH 0 // ADDR.context - // stack: ADDR: 3, len, rlp_pos, rlp_start, retdest + PUSH @SEGMENT_TXN_DATA // ctx == virt == 0 + // stack: ADDR, len, rlp_addr, rlp_addr_start, retdest PUSH after_serializing_txn_data - // stack: after_serializing_txn_data, ADDR: 3, len, rlp_pos, rlp_start, retdest - SWAP5 - // stack: rlp_pos, ADDR: 3, len, after_serializing_txn_data, rlp_start, retdest + // stack: after_serializing_txn_data, ADDR, len, rlp_addr, rlp_addr_start, retdest + SWAP3 + // stack: rlp_addr, ADDR, len, after_serializing_txn_data, rlp_addr_start, retdest %jump(encode_rlp_string) after_serializing_txn_data: // Instead of manually encoding the access list, we just copy the raw RLP from the transaction. %mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_START) %mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN) - %stack (al_len, al_start, rlp_pos, rlp_start, retdest) -> + %stack (al_len, al_start, rlp_addr, rlp_addr_start, retdest) -> ( - 0, @SEGMENT_RLP_RAW, rlp_pos, - 0, @SEGMENT_RLP_RAW, al_start, + rlp_addr, + al_start, al_len, after_serializing_access_list, - rlp_pos, rlp_start, retdest) + rlp_addr, rlp_addr_start, retdest) %jump(memcpy_bytes) after_serializing_access_list: - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN) ADD - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_addr_start, retdest %prepend_rlp_list_prefix - // stack: prefix_start_pos, rlp_len, retdest + // stack: prefix_start_rlp_addr, rlp_len, retdest // Store a `1` in front of the RLP %decrement - %stack (pos) -> (1, 0, @SEGMENT_RLP_RAW, pos, pos) + %stack (rlp_addr) -> (1, rlp_addr, rlp_addr) MSTORE_GENERAL - // stack: pos, rlp_len, retdest + // stack: rlp_addr, rlp_len, retdest // Hash the RLP + the leading `1` SWAP1 %increment SWAP1 - PUSH @SEGMENT_RLP_RAW - PUSH 0 // context - // stack: ADDR: 3, len, retdest + // stack: ADDR, len, retdest KECCAK_GENERAL // stack: hash, retdest diff --git a/evm/src/cpu/kernel/asm/transactions/type_2.asm b/evm/src/cpu/kernel/asm/transactions/type_2.asm index b7f6e6c7d5..cd4f85e677 100644 --- a/evm/src/cpu/kernel/asm/transactions/type_2.asm +++ b/evm/src/cpu/kernel/asm/transactions/type_2.asm @@ -9,13 +9,16 @@ global process_type_2_txn: // stack: retdest - PUSH 1 // initial pos, skipping over the 0x02 byte - // stack: pos, retdest + // Initial rlp address offset of 1 (skipping over the 0x02 byte) + PUSH 1 + PUSH @SEGMENT_RLP_RAW + %build_kernel_address + // stack: rlp_addr, retdest %decode_rlp_list_len // We don't actually need the length. - %stack (pos, len) -> (pos) + %stack (rlp_addr, len) -> (rlp_addr) - // stack: pos, retdest + // stack: rlp_addr, retdest %store_chain_id_present_true %decode_and_store_chain_id %decode_and_store_nonce @@ -30,7 +33,7 @@ global process_type_2_txn: %decode_and_store_r %decode_and_store_s - // stack: pos, retdest + // stack: rlp_addr, retdest POP // stack: retdest @@ -39,87 +42,83 @@ global process_type_2_txn: // keccak256(0x02 || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list])) type_2_compute_signed_data: %alloc_rlp_block - // stack: rlp_start, retdest + // stack: rlp_addr_start, retdest %mload_txn_field(@TXN_FIELD_CHAIN_ID) // stack: chain_id, rlp_start, retdest DUP2 - // stack: rlp_pos, chain_id, rlp_start, retdest + // stack: rlp_addr, chain_id, rlp_start, retdest %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_start, retdest %mload_txn_field(@TXN_FIELD_NONCE) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_start, retdest %mload_txn_field(@TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_start, retdest %mload_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_start, retdest %mload_txn_field(@TXN_FIELD_GAS_LIMIT) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_start, retdest %mload_txn_field(@TXN_FIELD_TO) %mload_global_metadata(@GLOBAL_METADATA_CONTRACT_CREATION) %jumpi(zero_to) - // stack: to, rlp_pos, rlp_start, retdest + // stack: to, rlp_addr, rlp_start, retdest SWAP1 %encode_rlp_160 %jump(after_to) zero_to: - // stack: to, rlp_pos, rlp_start, retdest + // stack: to, rlp_addr, rlp_start, retdest SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_start, retdest after_to: %mload_txn_field(@TXN_FIELD_VALUE) SWAP1 %encode_rlp_scalar - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_start, retdest // Encode txn data. %mload_txn_field(@TXN_FIELD_DATA_LEN) - PUSH 0 // ADDR.virt - PUSH @SEGMENT_TXN_DATA - PUSH 0 // ADDR.context - // stack: ADDR: 3, len, rlp_pos, rlp_start, retdest + PUSH @SEGMENT_TXN_DATA // ctx == virt == 0 + // stack: ADDR, len, rlp_addr, rlp_start, retdest PUSH after_serializing_txn_data - // stack: after_serializing_txn_data, ADDR: 3, len, rlp_pos, rlp_start, retdest - SWAP5 - // stack: rlp_pos, ADDR: 3, len, after_serializing_txn_data, rlp_start, retdest + // stack: after_serializing_txn_data, ADDR, len, rlp_addr, rlp_start, retdest + SWAP3 + // stack: rlp_addr, ADDR, len, after_serializing_txn_data, rlp_start, retdest %jump(encode_rlp_string) after_serializing_txn_data: // Instead of manually encoding the access list, we just copy the raw RLP from the transaction. %mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_START) %mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN) - %stack (al_len, al_start, rlp_pos, rlp_start, retdest) -> + %stack (al_len, al_start, rlp_addr, rlp_start, retdest) -> ( - 0, @SEGMENT_RLP_RAW, rlp_pos, - 0, @SEGMENT_RLP_RAW, al_start, + rlp_addr, + al_start, al_len, after_serializing_access_list, - rlp_pos, rlp_start, retdest) + rlp_addr, rlp_start, retdest) %jump(memcpy_bytes) after_serializing_access_list: - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_start, retdest %mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN) ADD - // stack: rlp_pos, rlp_start, retdest + // stack: rlp_addr, rlp_start, retdest %prepend_rlp_list_prefix // stack: prefix_start_pos, rlp_len, retdest // Store a `2` in front of the RLP %decrement - %stack (pos) -> (2, 0, @SEGMENT_RLP_RAW, pos, pos) + %stack (rlp_addr) -> (2, rlp_addr, rlp_addr) MSTORE_GENERAL - // stack: pos, rlp_len, retdest + // stack: rlp_addr, rlp_len, retdest // Hash the RLP + the leading `2` SWAP1 %increment SWAP1 - PUSH @SEGMENT_RLP_RAW - PUSH 0 // context - // stack: ADDR: 3, len, retdest + // stack: ADDR, len, retdest KECCAK_GENERAL // stack: hash, retdest diff --git a/evm/src/cpu/kernel/asm/util/basic_macros.asm b/evm/src/cpu/kernel/asm/util/basic_macros.asm index fc2472b3b8..c331acb423 100644 --- a/evm/src/cpu/kernel/asm/util/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/util/basic_macros.asm @@ -410,3 +410,36 @@ ISZERO // stack: not b %endmacro + +%macro build_address + // stack: ctx, seg, off + ADD + ADD + // stack: addr +%endmacro + +%macro build_address_no_offset + // stack: ctx, seg + ADD + // stack: addr +%endmacro + +%macro build_kernel_address + // stack: seg, off + ADD + // stack: addr (ctx == 0) +%endmacro + +%macro build_address_with_ctx_no_offset(seg) + // stack: ctx + PUSH $seg + ADD + // stack: addr +%endmacro + +%macro build_address_with_ctx_no_segment(off) + // stack: ctx + PUSH $off + ADD + // stack: addr +%endmacro diff --git a/evm/src/cpu/kernel/asm/util/keccak.asm b/evm/src/cpu/kernel/asm/util/keccak.asm index 1a1f437287..8385ee59af 100644 --- a/evm/src/cpu/kernel/asm/util/keccak.asm +++ b/evm/src/cpu/kernel/asm/util/keccak.asm @@ -18,7 +18,8 @@ global sys_keccak256: %stack (kexit_info, offset, len) -> (offset, len, kexit_info) PUSH @SEGMENT_MAIN_MEMORY GET_CONTEXT - // stack: ADDR: 3, len, kexit_info + %build_address + // stack: ADDR, len, kexit_info KECCAK_GENERAL // stack: hash, kexit_info SWAP1 @@ -37,11 +38,12 @@ sys_keccak256_empty: %macro keccak256_word(num_bytes) // Since KECCAK_GENERAL takes its input from memory, we will first write // input_word's bytes to @SEGMENT_KERNEL_GENERAL[0..$num_bytes]. - %stack (word) -> (0, @SEGMENT_KERNEL_GENERAL, 0, word, $num_bytes, %%after_mstore) + %stack (word) -> (@SEGMENT_KERNEL_GENERAL, word, $num_bytes, %%after_mstore) %jump(mstore_unpacking) %%after_mstore: - // stack: offset - %stack (offset) -> (0, @SEGMENT_KERNEL_GENERAL, 0, $num_bytes) // context, segment, offset, len + // stack: addr + %stack(addr) -> (addr, $num_bytes, $num_bytes) + SUB KECCAK_GENERAL %endmacro @@ -53,12 +55,13 @@ sys_keccak256_empty: // Since KECCAK_GENERAL takes its input from memory, we will first write // a's bytes to @SEGMENT_KERNEL_GENERAL[0..32], then b's bytes to // @SEGMENT_KERNEL_GENERAL[32..64]. - %stack (a) -> (0, @SEGMENT_KERNEL_GENERAL, 0, a, 32, %%after_mstore_a) + %stack (a) -> (@SEGMENT_KERNEL_GENERAL, a, 32, %%after_mstore_a) %jump(mstore_unpacking) %%after_mstore_a: - %stack (offset, b) -> (0, @SEGMENT_KERNEL_GENERAL, 32, b, 32, %%after_mstore_b) + %stack (addr, b) -> (addr, b, 32, %%after_mstore_b) %jump(mstore_unpacking) %%after_mstore_b: - %stack (offset) -> (0, @SEGMENT_KERNEL_GENERAL, 0, 64) // context, segment, offset, len + %stack (addr) -> (addr, 64, 64) // reset the address offset + SUB KECCAK_GENERAL %endmacro diff --git a/evm/src/cpu/kernel/constants/context_metadata.rs b/evm/src/cpu/kernel/constants/context_metadata.rs index 664ce6e957..ffcc65387a 100644 --- a/evm/src/cpu/kernel/constants/context_metadata.rs +++ b/evm/src/cpu/kernel/constants/context_metadata.rs @@ -1,39 +1,51 @@ +use crate::memory::segments::Segment; + /// These metadata fields contain VM state specific to a particular context. +/// +/// Each value is directly scaled by the corresponding `Segment::ContextMetadata` value for faster +/// memory access in the kernel. +#[allow(clippy::enum_clike_unportable_variant)] +#[repr(usize)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)] pub(crate) enum ContextMetadata { /// The ID of the context which created this one. - ParentContext = 0, + ParentContext = Segment::ContextMetadata as usize, /// The program counter to return to when we return to the parent context. - ParentProgramCounter = 1, - CalldataSize = 2, - ReturndataSize = 3, + ParentProgramCounter, + CalldataSize, + ReturndataSize, /// The address of the account associated with this context. - Address = 4, + Address, /// The size of the code under the account associated with this context. /// While this information could be obtained from the state trie, it is best to cache it since /// the `CODESIZE` instruction is very cheap. - CodeSize = 5, + CodeSize, /// The address of the caller who spawned this context. - Caller = 6, + Caller, /// The value (in wei) deposited by the caller. - CallValue = 7, + CallValue, /// Whether this context was created by `STATICCALL`, in which case state changes are /// prohibited. - Static = 8, + Static, /// Pointer to the initial version of the state trie, at the creation of this context. Used when /// we need to revert a context. - StateTrieCheckpointPointer = 9, + StateTrieCheckpointPointer, /// Size of the active main memory, in (32 byte) words. - MemWords = 10, - StackSize = 11, + MemWords, + StackSize, /// The gas limit for this call (not the entire transaction). - GasLimit = 12, - ContextCheckpointsLen = 13, + GasLimit, + ContextCheckpointsLen, } impl ContextMetadata { pub(crate) const COUNT: usize = 14; + /// Unscales this virtual offset by their respective `Segment` value. + pub(crate) const fn unscale(&self) -> usize { + *self as usize - Segment::ContextMetadata as usize + } + pub(crate) const fn all() -> [Self; Self::COUNT] { [ Self::ParentContext, diff --git a/evm/src/cpu/kernel/constants/global_metadata.rs b/evm/src/cpu/kernel/constants/global_metadata.rs index 8b85c0b552..4669674efb 100644 --- a/evm/src/cpu/kernel/constants/global_metadata.rs +++ b/evm/src/cpu/kernel/constants/global_metadata.rs @@ -1,98 +1,110 @@ +use crate::memory::segments::Segment; + /// These metadata fields contain global VM state, stored in the `Segment::Metadata` segment of the /// kernel's context (which is zero). +/// +/// Each value is directly scaled by the corresponding `Segment::GlobalMetadata` value for faster +/// memory access in the kernel. +#[allow(clippy::enum_clike_unportable_variant)] +#[repr(usize)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)] pub(crate) enum GlobalMetadata { /// The largest context ID that has been used so far in this execution. Tracking this allows us /// give each new context a unique ID, so that its memory will be zero-initialized. - LargestContext = 0, + LargestContext = Segment::GlobalMetadata as usize, /// The size of active memory, in bytes. - MemorySize = 1, - /// The size of the `TrieData` segment, in bytes. In other words, the next address available for - /// appending additional trie data. - TrieDataSize = 2, + MemorySize, /// The size of the `TrieData` segment, in bytes. In other words, the next address available for /// appending additional trie data. - RlpDataSize = 3, + TrieDataSize, + /// The size of the `TrieData` segment, in bytes, represented as a whole address. + /// In other words, the next address available for appending additional trie data. + RlpDataSize, /// A pointer to the root of the state trie within the `TrieData` buffer. - StateTrieRoot = 4, + StateTrieRoot, /// A pointer to the root of the transaction trie within the `TrieData` buffer. - TransactionTrieRoot = 5, + TransactionTrieRoot, /// A pointer to the root of the receipt trie within the `TrieData` buffer. - ReceiptTrieRoot = 6, + ReceiptTrieRoot, // The root digests of each Merkle trie before these transactions. - StateTrieRootDigestBefore = 7, - TransactionTrieRootDigestBefore = 8, - ReceiptTrieRootDigestBefore = 9, + StateTrieRootDigestBefore, + TransactionTrieRootDigestBefore, + ReceiptTrieRootDigestBefore, // The root digests of each Merkle trie after these transactions. - StateTrieRootDigestAfter = 10, - TransactionTrieRootDigestAfter = 11, - ReceiptTrieRootDigestAfter = 12, + StateTrieRootDigestAfter, + TransactionTrieRootDigestAfter, + ReceiptTrieRootDigestAfter, /// The sizes of the `TrieEncodedChild` and `TrieEncodedChildLen` buffers. In other words, the /// next available offset in these buffers. - TrieEncodedChildSize = 13, + TrieEncodedChildSize, // Block metadata. - BlockBeneficiary = 14, - BlockTimestamp = 15, - BlockNumber = 16, - BlockDifficulty = 17, - BlockRandom = 18, - BlockGasLimit = 19, - BlockChainId = 20, - BlockBaseFee = 21, - BlockGasUsed = 22, + BlockBeneficiary, + BlockTimestamp, + BlockNumber, + BlockDifficulty, + BlockRandom, + BlockGasLimit, + BlockChainId, + BlockBaseFee, + BlockGasUsed, /// Before current transactions block values. - BlockGasUsedBefore = 23, + BlockGasUsedBefore, /// After current transactions block values. - BlockGasUsedAfter = 24, + BlockGasUsedAfter, /// Current block header hash - BlockCurrentHash = 25, + BlockCurrentHash, /// Gas to refund at the end of the transaction. - RefundCounter = 26, + RefundCounter, /// Length of the addresses access list. - AccessedAddressesLen = 27, + AccessedAddressesLen, /// Length of the storage keys access list. - AccessedStorageKeysLen = 28, + AccessedStorageKeysLen, /// Length of the self-destruct list. - SelfDestructListLen = 29, + SelfDestructListLen, /// Length of the bloom entry buffer. - BloomEntryLen = 30, + BloomEntryLen, /// Length of the journal. - JournalLen = 31, + JournalLen, /// Length of the `JournalData` segment. - JournalDataLen = 32, + JournalDataLen, /// Current checkpoint. - CurrentCheckpoint = 33, - TouchedAddressesLen = 34, + CurrentCheckpoint, + TouchedAddressesLen, // Gas cost for the access list in type-1 txns. See EIP-2930. - AccessListDataCost = 35, + AccessListDataCost, // Start of the access list in the RLP for type-1 txns. - AccessListRlpStart = 36, + AccessListRlpStart, // Length of the access list in the RLP for type-1 txns. - AccessListRlpLen = 37, + AccessListRlpLen, // Boolean flag indicating if the txn is a contract creation txn. - ContractCreation = 38, - IsPrecompileFromEoa = 39, - CallStackDepth = 40, + ContractCreation, + IsPrecompileFromEoa, + CallStackDepth, /// Transaction logs list length - LogsLen = 41, - LogsDataLen = 42, - LogsPayloadLen = 43, - TxnNumberBefore = 44, - TxnNumberAfter = 45, + LogsLen, + LogsDataLen, + LogsPayloadLen, + TxnNumberBefore, + TxnNumberAfter, - KernelHash = 46, - KernelLen = 47, + KernelHash, + KernelLen, } impl GlobalMetadata { pub(crate) const COUNT: usize = 48; + /// Unscales this virtual offset by their respective `Segment` value. + pub(crate) const fn unscale(&self) -> usize { + *self as usize - Segment::GlobalMetadata as usize + } + pub(crate) const fn all() -> [Self; Self::COUNT] { [ Self::LargestContext, diff --git a/evm/src/cpu/kernel/constants/mod.rs b/evm/src/cpu/kernel/constants/mod.rs index 6e2a0015d3..451d7bebf4 100644 --- a/evm/src/cpu/kernel/constants/mod.rs +++ b/evm/src/cpu/kernel/constants/mod.rs @@ -58,16 +58,19 @@ pub(crate) fn evm_constants() -> HashMap { c.insert(CALL_STACK_LIMIT.0.into(), U256::from(CALL_STACK_LIMIT.1)); for segment in Segment::all() { - c.insert(segment.var_name().into(), (segment as u32).into()); + c.insert(segment.var_name().into(), (segment as usize).into()); } for txn_field in NormalizedTxnField::all() { - c.insert(txn_field.var_name().into(), (txn_field as u32).into()); + // These offsets are already scaled by their respective segment. + c.insert(txn_field.var_name().into(), (txn_field as usize).into()); } for txn_field in GlobalMetadata::all() { - c.insert(txn_field.var_name().into(), (txn_field as u32).into()); + // These offsets are already scaled by their respective segment. + c.insert(txn_field.var_name().into(), (txn_field as usize).into()); } for txn_field in ContextMetadata::all() { - c.insert(txn_field.var_name().into(), (txn_field as u32).into()); + // These offsets are already scaled by their respective segment. + c.insert(txn_field.var_name().into(), (txn_field as usize).into()); } for trie_type in PartialTrieType::all() { c.insert(trie_type.var_name().into(), (trie_type as u32).into()); diff --git a/evm/src/cpu/kernel/constants/txn_fields.rs b/evm/src/cpu/kernel/constants/txn_fields.rs index d62159a225..0b74409b37 100644 --- a/evm/src/cpu/kernel/constants/txn_fields.rs +++ b/evm/src/cpu/kernel/constants/txn_fields.rs @@ -1,33 +1,46 @@ +use crate::memory::segments::Segment; + /// These are normalized transaction fields, i.e. not specific to any transaction type. +/// +/// Each value is directly scaled by the corresponding `Segment::TxnFields` value for faster +/// memory access in the kernel. +#[allow(dead_code)] +#[allow(clippy::enum_clike_unportable_variant)] +#[repr(usize)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)] pub(crate) enum NormalizedTxnField { /// Whether a chain ID was present in the txn data. Type 0 transaction with v=27 or v=28 have /// no chain ID. This affects what fields get signed. - ChainIdPresent = 0, - ChainId = 1, - Nonce = 2, - MaxPriorityFeePerGas = 3, - MaxFeePerGas = 4, - GasLimit = 6, - IntrinsicGas = 7, - To = 8, - Value = 9, + ChainIdPresent = Segment::TxnFields as usize, + ChainId, + Nonce, + MaxPriorityFeePerGas, + MaxFeePerGas, + GasLimit, + IntrinsicGas, + To, + Value, /// The length of the data field. The data itself is stored in another segment. - DataLen = 10, - YParity = 11, - R = 12, - S = 13, - Origin = 14, + DataLen, + YParity, + R, + S, + Origin, /// The actual computed gas price for this transaction in the block. /// This is not technically a transaction field, as it depends on the block's base fee. - ComputedFeePerGas = 15, - ComputedPriorityFeePerGas = 16, + ComputedFeePerGas, + ComputedPriorityFeePerGas, } impl NormalizedTxnField { pub(crate) const COUNT: usize = 16; + /// Unscales this virtual offset by their respective `Segment` value. + pub(crate) const fn unscale(&self) -> usize { + *self as usize - Segment::TxnFields as usize + } + pub(crate) const fn all() -> [Self; Self::COUNT] { [ Self::ChainIdPresent, diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index c437672113..4dc887dec1 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -19,12 +19,12 @@ use crate::extension_tower::BN_BASE; use crate::generation::prover_input::ProverInputFn; use crate::generation::state::GenerationState; use crate::generation::GenerationInputs; -use crate::memory::segments::Segment; +use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR}; use crate::util::u256_to_usize; use crate::witness::errors::{ProgramError, ProverInputError}; use crate::witness::gas::gas_to_charge; use crate::witness::memory::{MemoryAddress, MemoryContextState, MemorySegmentState, MemoryState}; -use crate::witness::operation::Operation; +use crate::witness::operation::{Operation, CONTEXT_SCALING_FACTOR}; use crate::witness::state::RegistersState; use crate::witness::transition::decode; use crate::witness::util::stack_peek; @@ -199,19 +199,20 @@ impl<'a> Interpreter<'a> { match op { InterpreterMemOpKind::Push(context) => { self.generation_state.memory.contexts[context].segments - [Segment::Stack as usize] - .content - .pop(); + [Segment::Stack.unscale()] + .content + .pop(); } InterpreterMemOpKind::Pop(value, context) => { self.generation_state.memory.contexts[context].segments - [Segment::Stack as usize] - .content - .push(value) + [Segment::Stack.unscale()] + .content + .push(value) } InterpreterMemOpKind::Write(value, context, segment, offset) => { - self.generation_state.memory.contexts[context].segments[segment].content - [offset] = value + self.generation_state.memory.contexts[context].segments + [segment >> SEGMENT_SCALING_FACTOR] // we need to unscale the segment value + .content[offset] = value } } } @@ -267,8 +268,8 @@ impl<'a> Interpreter<'a> { offset_name, self.stack(), self.generation_state.memory.contexts[0].segments - [Segment::KernelGeneral as usize] - .content, + [Segment::KernelGeneral.unscale()] + .content, ); } self.rollback(checkpoint); @@ -289,7 +290,7 @@ impl<'a> Interpreter<'a> { fn code(&self) -> &MemorySegmentState { // The context is 0 if we are in kernel mode. &self.generation_state.memory.contexts[(1 - self.is_kernel() as usize) * self.context()] - .segments[Segment::Code as usize] + .segments[Segment::Code.unscale()] } fn code_slice(&self, n: usize) -> Vec { @@ -301,52 +302,76 @@ impl<'a> Interpreter<'a> { } pub(crate) fn get_txn_field(&self, field: NormalizedTxnField) -> U256 { - self.generation_state.memory.contexts[0].segments[Segment::TxnFields as usize] - .get(field as usize) + // These fields are already scaled by their respective segment. + self.generation_state.memory.contexts[0].segments[Segment::TxnFields.unscale()] + .get(field.unscale()) } pub(crate) fn set_txn_field(&mut self, field: NormalizedTxnField, value: U256) { - self.generation_state.memory.contexts[0].segments[Segment::TxnFields as usize] - .set(field as usize, value); + // These fields are already scaled by their respective segment. + self.generation_state.memory.contexts[0].segments[Segment::TxnFields.unscale()] + .set(field.unscale(), value); } pub(crate) fn get_txn_data(&self) -> &[U256] { - &self.generation_state.memory.contexts[0].segments[Segment::TxnData as usize].content + &self.generation_state.memory.contexts[0].segments[Segment::TxnData.unscale()].content + } + + pub(crate) fn get_context_metadata_field(&self, ctx: usize, field: ContextMetadata) -> U256 { + // These fields are already scaled by their respective segment. + self.generation_state.memory.contexts[ctx].segments[Segment::ContextMetadata.unscale()] + .get(field.unscale()) + } + + pub(crate) fn set_context_metadata_field( + &mut self, + ctx: usize, + field: ContextMetadata, + value: U256, + ) { + // These fields are already scaled by their respective segment. + self.generation_state.memory.contexts[ctx].segments[Segment::ContextMetadata.unscale()] + .set(field.unscale(), value) } pub(crate) fn get_global_metadata_field(&self, field: GlobalMetadata) -> U256 { - self.generation_state.memory.contexts[0].segments[Segment::GlobalMetadata as usize] - .get(field as usize) + // These fields are already scaled by their respective segment. + let field = field.unscale(); + self.generation_state.memory.contexts[0].segments[Segment::GlobalMetadata.unscale()] + .get(field) } pub(crate) fn set_global_metadata_field(&mut self, field: GlobalMetadata, value: U256) { - self.generation_state.memory.contexts[0].segments[Segment::GlobalMetadata as usize] - .set(field as usize, value) + // These fields are already scaled by their respective segment. + let field = field.unscale(); + self.generation_state.memory.contexts[0].segments[Segment::GlobalMetadata.unscale()] + .set(field, value) } pub(crate) fn set_global_metadata_multi_fields(&mut self, metadata: &[(GlobalMetadata, U256)]) { for &(field, value) in metadata { - self.generation_state.memory.contexts[0].segments[Segment::GlobalMetadata as usize] - .set(field as usize, value); + let field = field.unscale(); + self.generation_state.memory.contexts[0].segments[Segment::GlobalMetadata.unscale()] + .set(field, value); } } pub(crate) fn get_trie_data(&self) -> &[U256] { - &self.generation_state.memory.contexts[0].segments[Segment::TrieData as usize].content + &self.generation_state.memory.contexts[0].segments[Segment::TrieData.unscale()].content } pub(crate) fn get_trie_data_mut(&mut self) -> &mut Vec { - &mut self.generation_state.memory.contexts[0].segments[Segment::TrieData as usize].content + &mut self.generation_state.memory.contexts[0].segments[Segment::TrieData.unscale()].content } pub(crate) fn get_memory_segment(&self, segment: Segment) -> Vec { - self.generation_state.memory.contexts[0].segments[segment as usize] + self.generation_state.memory.contexts[0].segments[segment.unscale()] .content .clone() } pub(crate) fn get_memory_segment_bytes(&self, segment: Segment) -> Vec { - self.generation_state.memory.contexts[0].segments[segment as usize] + self.generation_state.memory.contexts[0].segments[segment.unscale()] .content .iter() .map(|x| x.low_u32() as u8) @@ -355,9 +380,9 @@ impl<'a> Interpreter<'a> { pub(crate) fn get_current_general_memory(&self) -> Vec { self.generation_state.memory.contexts[self.context()].segments - [Segment::KernelGeneral as usize] - .content - .clone() + [Segment::KernelGeneral.unscale()] + .content + .clone() } pub(crate) fn get_kernel_general_memory(&self) -> Vec { @@ -370,16 +395,16 @@ impl<'a> Interpreter<'a> { pub(crate) fn set_current_general_memory(&mut self, memory: Vec) { let context = self.context(); - self.generation_state.memory.contexts[context].segments[Segment::KernelGeneral as usize] + self.generation_state.memory.contexts[context].segments[Segment::KernelGeneral.unscale()] .content = memory; } pub(crate) fn set_memory_segment(&mut self, segment: Segment, memory: Vec) { - self.generation_state.memory.contexts[0].segments[segment as usize].content = memory; + self.generation_state.memory.contexts[0].segments[segment.unscale()].content = memory; } pub(crate) fn set_memory_segment_bytes(&mut self, segment: Segment, memory: Vec) { - self.generation_state.memory.contexts[0].segments[segment as usize].content = + self.generation_state.memory.contexts[0].segments[segment.unscale()].content = memory.into_iter().map(U256::from).collect(); } @@ -395,7 +420,7 @@ impl<'a> Interpreter<'a> { .contexts .push(MemoryContextState::default()); } - self.generation_state.memory.contexts[context].segments[Segment::Code as usize].content = + self.generation_state.memory.contexts[context].segments[Segment::Code.unscale()].content = code.into_iter().map(U256::from).collect(); } @@ -406,7 +431,7 @@ impl<'a> Interpreter<'a> { } pub(crate) fn get_jumpdest_bits(&self, context: usize) -> Vec { - self.generation_state.memory.contexts[context].segments[Segment::JumpdestBits as usize] + self.generation_state.memory.contexts[context].segments[Segment::JumpdestBits.unscale()] .content .iter() .map(|x| x.bit(0)) @@ -421,9 +446,9 @@ impl<'a> Interpreter<'a> { match self.stack_len().cmp(&1) { Ordering::Greater => { let mut stack = self.generation_state.memory.contexts[self.context()].segments - [Segment::Stack as usize] - .content - .clone(); + [Segment::Stack.unscale()] + .content + .clone(); stack.truncate(self.stack_len() - 1); stack.push( self.stack_top() @@ -443,7 +468,7 @@ impl<'a> Interpreter<'a> { } fn stack_segment_mut(&mut self) -> &mut Vec { let context = self.context(); - &mut self.generation_state.memory.contexts[context].segments[Segment::Stack as usize] + &mut self.generation_state.memory.contexts[context].segments[Segment::Stack.unscale()] .content } @@ -642,8 +667,8 @@ impl<'a> Interpreter<'a> { if !self.is_kernel() { let gas_limit_address = MemoryAddress { context: self.context(), - segment: Segment::ContextMetadata as usize, - virt: ContextMetadata::GasLimit as usize, + segment: Segment::ContextMetadata.unscale(), + virt: ContextMetadata::GasLimit.unscale(), }; let gas_limit = u256_to_usize(self.generation_state.memory.get(gas_limit_address))? as u64; @@ -828,11 +853,11 @@ impl<'a> Interpreter<'a> { } fn run_keccak_general(&mut self) -> anyhow::Result<(), ProgramError> { - let context = self.pop()?.as_usize(); - let segment = Segment::all()[self.pop()?.as_usize()]; + let addr = self.pop()?; + let (context, segment, offset) = unpack_address!(addr); + // Not strictly needed but here to avoid surprises with MSIZE. assert_ne!(segment, Segment::MainMemory, "Call KECCAK256 instead."); - let offset = self.pop()?.as_usize(); let size = self.pop()?.as_usize(); let bytes = (offset..offset + size) .map(|i| { @@ -983,7 +1008,7 @@ impl<'a> Interpreter<'a> { let mem_write_op = InterpreterMemOpKind::Write( old_value, self.context(), - Segment::Stack as usize, + Segment::Stack.unscale(), len - n as usize - 1, ); self.memops.push(mem_write_op); @@ -992,16 +1017,17 @@ impl<'a> Interpreter<'a> { } fn run_get_context(&mut self) -> anyhow::Result<(), ProgramError> { - self.push(self.context().into()) + self.push(U256::from(self.context()) << CONTEXT_SCALING_FACTOR) } fn run_set_context(&mut self) -> anyhow::Result<(), ProgramError> { - let new_ctx = self.pop()?.as_usize(); + let x = self.pop()?; + let new_ctx = (x >> CONTEXT_SCALING_FACTOR).as_usize(); let sp_to_save = self.stack_len().into(); let old_ctx = self.context(); - let sp_field = ContextMetadata::StackSize as usize; + let sp_field = ContextMetadata::StackSize.unscale(); let old_sp_addr = MemoryAddress::new(old_ctx, Segment::ContextMetadata, sp_field); let new_sp_addr = MemoryAddress::new(new_ctx, Segment::ContextMetadata, sp_field); @@ -1011,8 +1037,8 @@ impl<'a> Interpreter<'a> { if new_sp > 0 { let new_stack_top = self.generation_state.memory.contexts[new_ctx].segments - [Segment::Stack as usize] - .content[new_sp - 1]; + [Segment::Stack.unscale()] + .content[new_sp - 1]; self.generation_state.registers.stack_top = new_stack_top; } self.set_context(new_ctx); @@ -1021,9 +1047,8 @@ impl<'a> Interpreter<'a> { } fn run_mload_general(&mut self) -> anyhow::Result<(), ProgramError> { - let context = self.pop()?.as_usize(); - let segment = Segment::all()[self.pop()?.as_usize()]; - let offset = self.pop()?.as_usize(); + let addr = self.pop()?; + let (context, segment, offset) = unpack_address!(addr); let value = self .generation_state .memory @@ -1033,9 +1058,8 @@ impl<'a> Interpreter<'a> { } fn run_mload_32bytes(&mut self) -> anyhow::Result<(), ProgramError> { - let context = self.pop()?.as_usize(); - let segment = Segment::all()[self.pop()?.as_usize()]; - let offset = self.pop()?.as_usize(); + let addr = self.pop()?; + let (context, segment, offset) = unpack_address!(addr); let len = self.pop()?.as_usize(); if len > 32 { return Err(ProgramError::IntegerTooLarge); @@ -1054,9 +1078,8 @@ impl<'a> Interpreter<'a> { fn run_mstore_general(&mut self) -> anyhow::Result<(), ProgramError> { let value = self.pop()?; - let context = self.pop()?.as_usize(); - let segment = Segment::all()[self.pop()?.as_usize()]; - let offset = self.pop()?.as_usize(); + let addr = self.pop()?; + let (context, segment, offset) = unpack_address!(addr); let memop = self .generation_state .memory @@ -1066,9 +1089,8 @@ impl<'a> Interpreter<'a> { } fn run_mstore_32bytes(&mut self, n: u8) -> anyhow::Result<(), ProgramError> { - let context = self.pop()?.as_usize(); - let segment = Segment::all()[self.pop()?.as_usize()]; - let offset = self.pop()?.as_usize(); + let addr = self.pop()?; + let (context, segment, offset) = unpack_address!(addr); let value = self.pop()?; let mut bytes = vec![0; 32]; @@ -1086,7 +1108,7 @@ impl<'a> Interpreter<'a> { self.memops.push(memop); } - self.push(U256::from(offset + n as usize)) + self.push(addr + U256::from(n)) } fn run_exit_kernel(&mut self) -> anyhow::Result<(), ProgramError> { @@ -1447,14 +1469,28 @@ fn get_mnemonic(opcode: u8) -> &'static str { } } +#[macro_use] +macro_rules! unpack_address { + ($addr:ident) => {{ + let offset = $addr.low_u32() as usize; + let segment = Segment::all()[($addr >> SEGMENT_SCALING_FACTOR).low_u32() as usize]; + let context = ($addr >> CONTEXT_SCALING_FACTOR).low_u32() as usize; + (context, segment, offset) + }}; +} +pub(crate) use unpack_address; + #[cfg(test)] mod tests { use std::collections::HashMap; + use ethereum_types::U256; + use crate::cpu::kernel::constants::context_metadata::ContextMetadata; use crate::cpu::kernel::interpreter::{run, Interpreter}; use crate::memory::segments::Segment; use crate::witness::memory::MemoryAddress; + use crate::witness::operation::CONTEXT_SCALING_FACTOR; #[test] fn test_run() -> anyhow::Result<()> { @@ -1491,8 +1527,9 @@ mod tests { interpreter.set_code(1, code.to_vec()); - interpreter.generation_state.memory.contexts[1].segments[Segment::ContextMetadata as usize] - .set(ContextMetadata::GasLimit as usize, 100_000.into()); + interpreter.generation_state.memory.contexts[1].segments + [Segment::ContextMetadata.unscale()] + .set(ContextMetadata::GasLimit.unscale(), 100_000.into()); // Set context and kernel mode. interpreter.set_context(1); interpreter.set_is_kernel(false); @@ -1501,7 +1538,7 @@ mod tests { MemoryAddress::new( 1, Segment::ContextMetadata, - ContextMetadata::ParentProgramCounter as usize, + ContextMetadata::ParentProgramCounter.unscale(), ), 0xdeadbeefu32.into(), ); @@ -1509,9 +1546,9 @@ mod tests { MemoryAddress::new( 1, Segment::ContextMetadata, - ContextMetadata::ParentContext as usize, + ContextMetadata::ParentContext.unscale(), ), - 1.into(), + U256::one() << CONTEXT_SCALING_FACTOR, ); interpreter.run()?; @@ -1522,12 +1559,12 @@ mod tests { assert_eq!(interpreter.stack(), &[0xff.into(), 0xff00.into()]); assert_eq!( - interpreter.generation_state.memory.contexts[1].segments[Segment::MainMemory as usize] + interpreter.generation_state.memory.contexts[1].segments[Segment::MainMemory.unscale()] .get(0x27), 0x42.into() ); assert_eq!( - interpreter.generation_state.memory.contexts[1].segments[Segment::MainMemory as usize] + interpreter.generation_state.memory.contexts[1].segments[Segment::MainMemory.unscale()] .get(0x1f), 0xff.into() ); diff --git a/evm/src/cpu/kernel/tests/account_code.rs b/evm/src/cpu/kernel/tests/account_code.rs index 20c98bf976..28b9ae7d97 100644 --- a/evm/src/cpu/kernel/tests/account_code.rs +++ b/evm/src/cpu/kernel/tests/account_code.rs @@ -17,6 +17,7 @@ use crate::generation::mpt::{load_all_mpts, AccountRlp}; use crate::generation::TrieInputs; use crate::memory::segments::Segment; use crate::witness::memory::MemoryAddress; +use crate::witness::operation::CONTEXT_SCALING_FACTOR; use crate::Node; pub(crate) fn initialize_mpts(interpreter: &mut Interpreter, trie_inputs: &TrieInputs) { @@ -24,27 +25,14 @@ pub(crate) fn initialize_mpts(interpreter: &mut Interpreter, trie_inputs: &TrieI let (trie_root_ptrs, trie_data) = load_all_mpts(trie_inputs).expect("Invalid MPT data for preinitialization"); - let state_addr = MemoryAddress::new( - 0, - Segment::GlobalMetadata, - GlobalMetadata::StateTrieRoot as usize, - ); - - let txn_addr = MemoryAddress::new( - 0, - Segment::GlobalMetadata, - GlobalMetadata::TransactionTrieRoot as usize, - ); - let receipts_addr = MemoryAddress::new( - 0, - Segment::GlobalMetadata, - GlobalMetadata::ReceiptTrieRoot as usize, - ); - let len_addr = MemoryAddress::new( - 0, - Segment::GlobalMetadata, - GlobalMetadata::TrieDataSize as usize, - ); + let state_addr = + MemoryAddress::new_bundle((GlobalMetadata::StateTrieRoot as usize).into()).unwrap(); + let txn_addr = + MemoryAddress::new_bundle((GlobalMetadata::TransactionTrieRoot as usize).into()).unwrap(); + let receipts_addr = + MemoryAddress::new_bundle((GlobalMetadata::ReceiptTrieRoot as usize).into()).unwrap(); + let len_addr = + MemoryAddress::new_bundle((GlobalMetadata::TrieDataSize as usize).into()).unwrap(); let to_set = [ (state_addr, trie_root_ptrs.state_root_ptr.into()), @@ -202,8 +190,8 @@ fn test_extcodecopy() -> Result<()> { let context = interpreter.context(); interpreter.generation_state.memory.contexts[context].segments - [Segment::ContextMetadata as usize] - .set(GasLimit as usize, U256::from(1000000000000u64)); + [Segment::ContextMetadata.unscale()] + .set(GasLimit.unscale(), U256::from(1000000000000u64)); let extcodecopy = KERNEL.global_labels["sys_extcodecopy"]; @@ -211,11 +199,11 @@ fn test_extcodecopy() -> Result<()> { let mut rng = thread_rng(); for i in 0..2000 { interpreter.generation_state.memory.contexts[context].segments - [Segment::MainMemory as usize] - .set(i, U256::from(rng.gen::())); + [Segment::MainMemory.unscale()] + .set(i, U256::from(rng.gen::())); interpreter.generation_state.memory.contexts[context].segments - [Segment::KernelAccountCode as usize] - .set(i, U256::from(rng.gen::())); + [Segment::KernelAccountCode.unscale()] + .set(i, U256::from(rng.gen::())); } // Random inputs @@ -251,8 +239,8 @@ fn test_extcodecopy() -> Result<()> { // Check that the code was correctly copied to memory. for i in 0..size { let memory = interpreter.generation_state.memory.contexts[context].segments - [Segment::MainMemory as usize] - .get(dest_offset + i); + [Segment::MainMemory.unscale()] + .get(dest_offset + i); assert_eq!( memory, code.get(offset + i).copied().unwrap_or_default().into() @@ -277,30 +265,23 @@ fn prepare_interpreter_all_accounts( // Switch context and initialize memory with the data we need for the tests. interpreter.generation_state.registers.program_counter = 0; interpreter.set_code(1, code.to_vec()); - interpreter.generation_state.memory.contexts[1].segments[Segment::ContextMetadata as usize] - .set( - ContextMetadata::Address as usize, - U256::from_big_endian(&addr), - ); - interpreter.generation_state.memory.contexts[1].segments[Segment::ContextMetadata as usize] - .set(ContextMetadata::GasLimit as usize, 100_000.into()); + interpreter.set_context_metadata_field( + 1, + ContextMetadata::Address, + U256::from_big_endian(&addr), + ); + interpreter.set_context_metadata_field(1, ContextMetadata::GasLimit, 100_000.into()); interpreter.set_context(1); interpreter.set_is_kernel(false); - interpreter.generation_state.memory.set( - MemoryAddress::new( - 1, - Segment::ContextMetadata, - ContextMetadata::ParentProgramCounter as usize, - ), + interpreter.set_context_metadata_field( + 1, + ContextMetadata::ParentProgramCounter, 0xdeadbeefu32.into(), ); - interpreter.generation_state.memory.set( - MemoryAddress::new( - 1, - Segment::ContextMetadata, - ContextMetadata::ParentContext as usize, - ), - 1.into(), + interpreter.set_context_metadata_field( + 1, + ContextMetadata::ParentContext, + U256::one() << CONTEXT_SCALING_FACTOR, // ctx = 1 ); Ok(()) diff --git a/evm/src/cpu/kernel/tests/add11.rs b/evm/src/cpu/kernel/tests/add11.rs index 9ba65db2c9..1e71d60dbe 100644 --- a/evm/src/cpu/kernel/tests/add11.rs +++ b/evm/src/cpu/kernel/tests/add11.rs @@ -16,7 +16,7 @@ use crate::cpu::kernel::tests::account_code::initialize_mpts; use crate::generation::mpt::{AccountRlp, LegacyReceiptRlp}; use crate::generation::rlp::all_rlp_prover_inputs_reversed; use crate::generation::TrieInputs; -use crate::memory::segments::Segment; +use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR}; use crate::proof::TrieRoots; use crate::util::h2u; @@ -199,8 +199,7 @@ fn test_add11_yml() { let route_txn_label = KERNEL.global_labels["hash_initial_tries"]; // Switch context and initialize memory with the data we need for the tests. interpreter.generation_state.registers.program_counter = route_txn_label; - interpreter.generation_state.memory.contexts[0].segments[Segment::ContextMetadata as usize] - .set(ContextMetadata::GasLimit as usize, 1_000_000.into()); + interpreter.set_context_metadata_field(0, ContextMetadata::GasLimit, 1_000_000.into()); interpreter.set_is_kernel(true); interpreter.run().expect("Proving add11 failed."); } @@ -331,8 +330,7 @@ fn test_add11_yml_with_exception() { let route_txn_label = KERNEL.global_labels["hash_initial_tries"]; // Switch context and initialize memory with the data we need for the tests. interpreter.generation_state.registers.program_counter = route_txn_label; - interpreter.generation_state.memory.contexts[0].segments[Segment::ContextMetadata as usize] - .set(ContextMetadata::GasLimit as usize, 1_000_000.into()); + interpreter.set_context_metadata_field(0, ContextMetadata::GasLimit, 1_000_000.into()); interpreter.set_is_kernel(true); interpreter .run() diff --git a/evm/src/cpu/kernel/tests/core/access_lists.rs b/evm/src/cpu/kernel/tests/core/access_lists.rs index c62d48656b..69dd2d27d4 100644 --- a/evm/src/cpu/kernel/tests/core/access_lists.rs +++ b/evm/src/cpu/kernel/tests/core/access_lists.rs @@ -9,7 +9,7 @@ use crate::cpu::kernel::constants::global_metadata::GlobalMetadata::{ AccessedAddressesLen, AccessedStorageKeysLen, }; use crate::cpu::kernel::interpreter::Interpreter; -use crate::memory::segments::Segment::{AccessedAddresses, AccessedStorageKeys, GlobalMetadata}; +use crate::memory::segments::Segment::{AccessedAddresses, AccessedStorageKeys}; use crate::witness::memory::MemoryAddress; #[test] @@ -42,17 +42,16 @@ fn test_insert_accessed_addresses() -> Result<()> { .set(MemoryAddress::new(0, AccessedAddresses, i), addr); } interpreter.generation_state.memory.set( - MemoryAddress::new(0, GlobalMetadata, AccessedAddressesLen as usize), + MemoryAddress::new_bundle(U256::from(AccessedAddressesLen as usize)).unwrap(), U256::from(n), ); interpreter.run()?; assert_eq!(interpreter.stack(), &[U256::zero()]); assert_eq!( - interpreter.generation_state.memory.get(MemoryAddress::new( - 0, - GlobalMetadata, - AccessedAddressesLen as usize - )), + interpreter + .generation_state + .memory + .get(MemoryAddress::new_bundle(U256::from(AccessedAddressesLen as usize)).unwrap()), U256::from(n) ); @@ -67,17 +66,16 @@ fn test_insert_accessed_addresses() -> Result<()> { .set(MemoryAddress::new(0, AccessedAddresses, i), addr); } interpreter.generation_state.memory.set( - MemoryAddress::new(0, GlobalMetadata, AccessedAddressesLen as usize), + MemoryAddress::new_bundle(U256::from(AccessedAddressesLen as usize)).unwrap(), U256::from(n), ); interpreter.run()?; assert_eq!(interpreter.stack(), &[U256::one()]); assert_eq!( - interpreter.generation_state.memory.get(MemoryAddress::new( - 0, - GlobalMetadata, - AccessedAddressesLen as usize - )), + interpreter + .generation_state + .memory + .get(MemoryAddress::new_bundle(U256::from(AccessedAddressesLen as usize)).unwrap()), U256::from(n + 1) ); assert_eq!( @@ -134,17 +132,16 @@ fn test_insert_accessed_storage_keys() -> Result<()> { ); } interpreter.generation_state.memory.set( - MemoryAddress::new(0, GlobalMetadata, AccessedStorageKeysLen as usize), + MemoryAddress::new_bundle(U256::from(AccessedStorageKeysLen as usize)).unwrap(), U256::from(3 * n), ); interpreter.run()?; assert_eq!(interpreter.stack(), &[storage_key_in_list.2, U256::zero()]); assert_eq!( - interpreter.generation_state.memory.get(MemoryAddress::new( - 0, - GlobalMetadata, - AccessedStorageKeysLen as usize - )), + interpreter + .generation_state + .memory + .get(MemoryAddress::new_bundle(U256::from(AccessedStorageKeysLen as usize)).unwrap()), U256::from(3 * n) ); @@ -172,7 +169,7 @@ fn test_insert_accessed_storage_keys() -> Result<()> { ); } interpreter.generation_state.memory.set( - MemoryAddress::new(0, GlobalMetadata, AccessedStorageKeysLen as usize), + MemoryAddress::new_bundle(U256::from(AccessedStorageKeysLen as usize)).unwrap(), U256::from(3 * n), ); interpreter.run()?; @@ -181,11 +178,10 @@ fn test_insert_accessed_storage_keys() -> Result<()> { &[storage_key_not_in_list.2, U256::one()] ); assert_eq!( - interpreter.generation_state.memory.get(MemoryAddress::new( - 0, - GlobalMetadata, - AccessedStorageKeysLen as usize - )), + interpreter + .generation_state + .memory + .get(MemoryAddress::new_bundle(U256::from(AccessedStorageKeysLen as usize)).unwrap()), U256::from(3 * (n + 1)) ); assert_eq!( diff --git a/evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs b/evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs index 022a18d729..1d686d623d 100644 --- a/evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs +++ b/evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs @@ -1,8 +1,10 @@ use anyhow::Result; +use ethereum_types::U256; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; use crate::cpu::kernel::opcodes::{get_opcode, get_push_opcode}; +use crate::witness::operation::CONTEXT_SCALING_FACTOR; #[test] fn test_jumpdest_analysis() -> Result<()> { @@ -28,7 +30,11 @@ fn test_jumpdest_analysis() -> Result<()> { let expected_jumpdest_bits = vec![false, true, false, false, false, true, false, true]; // Contract creation transaction. - let initial_stack = vec![0xDEADBEEFu32.into(), code.len().into(), CONTEXT.into()]; + let initial_stack = vec![ + 0xDEADBEEFu32.into(), + code.len().into(), + U256::from(CONTEXT) << CONTEXT_SCALING_FACTOR, + ]; let mut interpreter = Interpreter::new_with_kernel(jumpdest_analysis, initial_stack); interpreter.set_code(CONTEXT, code); interpreter.run()?; diff --git a/evm/src/cpu/kernel/tests/mpt/hex_prefix.rs b/evm/src/cpu/kernel/tests/mpt/hex_prefix.rs index c13b812220..e51e60ab46 100644 --- a/evm/src/cpu/kernel/tests/mpt/hex_prefix.rs +++ b/evm/src/cpu/kernel/tests/mpt/hex_prefix.rs @@ -1,7 +1,9 @@ use anyhow::Result; +use ethereum_types::U256; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; +use crate::memory::segments::Segment; #[test] fn hex_prefix_even_nonterminated() -> Result<()> { @@ -11,11 +13,11 @@ fn hex_prefix_even_nonterminated() -> Result<()> { let terminated = 0.into(); let packed_nibbles = 0xABCDEF.into(); let num_nibbles = 6.into(); - let rlp_pos = 0.into(); + let rlp_pos = U256::from(Segment::RlpRaw as usize); let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles, rlp_pos]; let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack); interpreter.run()?; - assert_eq!(interpreter.stack(), vec![5.into()]); + assert_eq!(interpreter.stack(), vec![rlp_pos + U256::from(5)]); assert_eq!( interpreter.get_rlp_memory(), @@ -39,11 +41,11 @@ fn hex_prefix_odd_terminated() -> Result<()> { let terminated = 1.into(); let packed_nibbles = 0xABCDE.into(); let num_nibbles = 5.into(); - let rlp_pos = 0.into(); + let rlp_pos = U256::from(Segment::RlpRaw as usize); let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles, rlp_pos]; let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack); interpreter.run()?; - assert_eq!(interpreter.stack(), vec![4.into()]); + assert_eq!(interpreter.stack(), vec![rlp_pos + U256::from(4)]); assert_eq!( interpreter.get_rlp_memory(), @@ -66,11 +68,14 @@ fn hex_prefix_odd_terminated_tiny() -> Result<()> { let terminated = 1.into(); let packed_nibbles = 0xA.into(); let num_nibbles = 1.into(); - let rlp_pos = 2.into(); + let rlp_pos = U256::from(Segment::RlpRaw as usize + 2); let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles, rlp_pos]; let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack); interpreter.run()?; - assert_eq!(interpreter.stack(), vec![3.into()]); + assert_eq!( + interpreter.stack(), + vec![U256::from(Segment::RlpRaw as usize + 3)] + ); assert_eq!( interpreter.get_rlp_memory(), diff --git a/evm/src/cpu/kernel/tests/packing.rs b/evm/src/cpu/kernel/tests/packing.rs index 43ca9b5fc2..5517001f0d 100644 --- a/evm/src/cpu/kernel/tests/packing.rs +++ b/evm/src/cpu/kernel/tests/packing.rs @@ -11,10 +11,8 @@ fn test_mload_packing_1_byte() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let len = 1.into(); - let offset = 2.into(); - let segment = (Segment::RlpRaw as u32).into(); - let context = 0.into(); - let initial_stack = vec![retdest, len, offset, segment, context]; + let addr = (Segment::RlpRaw as u64 + 2).into(); + let initial_stack = vec![retdest, len, addr]; let mut interpreter = Interpreter::new_with_kernel(mload_packing, initial_stack); interpreter.set_rlp_memory(vec![0, 0, 0xAB]); @@ -31,10 +29,8 @@ fn test_mload_packing_3_bytes() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let len = 3.into(); - let offset = 2.into(); - let segment = (Segment::RlpRaw as u32).into(); - let context = 0.into(); - let initial_stack = vec![retdest, len, offset, segment, context]; + let addr = (Segment::RlpRaw as u64 + 2).into(); + let initial_stack = vec![retdest, len, addr]; let mut interpreter = Interpreter::new_with_kernel(mload_packing, initial_stack); interpreter.set_rlp_memory(vec![0, 0, 0xAB, 0xCD, 0xEF]); @@ -51,10 +47,8 @@ fn test_mload_packing_32_bytes() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let len = 32.into(); - let offset = 0.into(); - let segment = (Segment::RlpRaw as u32).into(); - let context = 0.into(); - let initial_stack = vec![retdest, len, offset, segment, context]; + let addr = (Segment::RlpRaw as u64).into(); + let initial_stack = vec![retdest, len, addr]; let mut interpreter = Interpreter::new_with_kernel(mload_packing, initial_stack); interpreter.set_rlp_memory(vec![0xFF; 32]); @@ -72,15 +66,13 @@ fn test_mstore_unpacking() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let len = 4.into(); let value = 0xABCD1234u32.into(); - let offset = 0.into(); - let segment = (Segment::TxnData as u32).into(); - let context = 0.into(); - let initial_stack = vec![retdest, len, value, offset, segment, context]; + let addr = (Segment::TxnData as u64).into(); + let initial_stack = vec![retdest, len, value, addr]; let mut interpreter = Interpreter::new_with_kernel(mstore_unpacking, initial_stack); interpreter.run()?; - assert_eq!(interpreter.stack(), vec![4.into()]); + assert_eq!(interpreter.stack(), vec![addr + U256::from(4)]); assert_eq!( &interpreter.get_txn_data(), &[0xAB.into(), 0xCD.into(), 0x12.into(), 0x34.into()] diff --git a/evm/src/cpu/kernel/tests/rlp/decode.rs b/evm/src/cpu/kernel/tests/rlp/decode.rs index a1ca3609ad..1f3260e56f 100644 --- a/evm/src/cpu/kernel/tests/rlp/decode.rs +++ b/evm/src/cpu/kernel/tests/rlp/decode.rs @@ -1,20 +1,25 @@ use anyhow::Result; +use ethereum_types::U256; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; +use crate::memory::segments::Segment; #[test] fn test_decode_rlp_string_len_short() -> Result<()> { let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; - let initial_stack = vec![0xDEADBEEFu32.into(), 2.into()]; + let initial_stack = vec![ + 0xDEADBEEFu32.into(), + U256::from(Segment::RlpRaw as usize + 2), + ]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by "0x70" which is its own encoding. interpreter.set_rlp_memory(vec![123, 234, 0x70]); interpreter.run()?; - let expected_stack = vec![1.into(), 2.into()]; // len, pos + let expected_stack = vec![1.into(), U256::from(Segment::RlpRaw as usize + 2)]; // len, pos assert_eq!(interpreter.stack(), expected_stack); Ok(()) @@ -24,14 +29,17 @@ fn test_decode_rlp_string_len_short() -> Result<()> { fn test_decode_rlp_string_len_medium() -> Result<()> { let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; - let initial_stack = vec![0xDEADBEEFu32.into(), 2.into()]; + let initial_stack = vec![ + 0xDEADBEEFu32.into(), + U256::from(Segment::RlpRaw as usize + 2), + ]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // A couple dummy bytes, followed by the RLP encoding of "1 2 3 4 5". interpreter.set_rlp_memory(vec![123, 234, 0x85, 1, 2, 3, 4, 5]); interpreter.run()?; - let expected_stack = vec![5.into(), 3.into()]; // len, pos + let expected_stack = vec![5.into(), U256::from(Segment::RlpRaw as usize + 3)]; // len, pos assert_eq!(interpreter.stack(), expected_stack); Ok(()) @@ -41,7 +49,10 @@ fn test_decode_rlp_string_len_medium() -> Result<()> { fn test_decode_rlp_string_len_long() -> Result<()> { let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"]; - let initial_stack = vec![0xDEADBEEFu32.into(), 2.into()]; + let initial_stack = vec![ + 0xDEADBEEFu32.into(), + U256::from(Segment::RlpRaw as usize + 2), + ]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_string_len, initial_stack); // The RLP encoding of the string "1 2 3 ... 56". @@ -52,7 +63,7 @@ fn test_decode_rlp_string_len_long() -> Result<()> { ]); interpreter.run()?; - let expected_stack = vec![56.into(), 4.into()]; // len, pos + let expected_stack = vec![56.into(), U256::from(Segment::RlpRaw as usize + 4)]; // len, pos assert_eq!(interpreter.stack(), expected_stack); Ok(()) @@ -62,14 +73,14 @@ fn test_decode_rlp_string_len_long() -> Result<()> { fn test_decode_rlp_list_len_short() -> Result<()> { let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; - let initial_stack = vec![0xDEADBEEFu32.into(), 0.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), U256::from(Segment::RlpRaw as usize)]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, 2, [3, 4]]. interpreter.set_rlp_memory(vec![0xc5, 1, 2, 0xc2, 3, 4]); interpreter.run()?; - let expected_stack = vec![5.into(), 1.into()]; // len, pos + let expected_stack = vec![5.into(), U256::from(Segment::RlpRaw as usize + 1)]; // len, pos assert_eq!(interpreter.stack(), expected_stack); Ok(()) @@ -79,7 +90,7 @@ fn test_decode_rlp_list_len_short() -> Result<()> { fn test_decode_rlp_list_len_long() -> Result<()> { let decode_rlp_list_len = KERNEL.global_labels["decode_rlp_list_len"]; - let initial_stack = vec![0xDEADBEEFu32.into(), 0.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), U256::from(Segment::RlpRaw as usize)]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_list_len, initial_stack); // The RLP encoding of [1, ..., 56]. @@ -90,7 +101,7 @@ fn test_decode_rlp_list_len_long() -> Result<()> { ]); interpreter.run()?; - let expected_stack = vec![56.into(), 2.into()]; // len, pos + let expected_stack = vec![56.into(), U256::from(Segment::RlpRaw as usize + 2)]; // len, pos assert_eq!(interpreter.stack(), expected_stack); Ok(()) @@ -100,14 +111,14 @@ fn test_decode_rlp_list_len_long() -> Result<()> { fn test_decode_rlp_scalar() -> Result<()> { let decode_rlp_scalar = KERNEL.global_labels["decode_rlp_scalar"]; - let initial_stack = vec![0xDEADBEEFu32.into(), 0.into()]; + let initial_stack = vec![0xDEADBEEFu32.into(), U256::from(Segment::RlpRaw as usize)]; let mut interpreter = Interpreter::new_with_kernel(decode_rlp_scalar, initial_stack); // The RLP encoding of "12 34 56". interpreter.set_rlp_memory(vec![0x83, 0x12, 0x34, 0x56]); interpreter.run()?; - let expected_stack = vec![0x123456.into(), 4.into()]; // scalar, pos + let expected_stack = vec![0x123456.into(), U256::from(Segment::RlpRaw as usize + 4)]; // scalar, pos assert_eq!(interpreter.stack(), expected_stack); Ok(()) diff --git a/evm/src/cpu/kernel/tests/rlp/encode.rs b/evm/src/cpu/kernel/tests/rlp/encode.rs index 2771dea0f9..505c99df88 100644 --- a/evm/src/cpu/kernel/tests/rlp/encode.rs +++ b/evm/src/cpu/kernel/tests/rlp/encode.rs @@ -1,7 +1,9 @@ use anyhow::Result; +use ethereum_types::U256; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; +use crate::memory::segments::Segment; #[test] fn test_encode_rlp_scalar_small() -> Result<()> { @@ -9,12 +11,12 @@ fn test_encode_rlp_scalar_small() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let scalar = 42.into(); - let pos = 2.into(); + let pos = U256::from(Segment::RlpRaw as usize + 2); let initial_stack = vec![retdest, scalar, pos]; let mut interpreter = Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack); interpreter.run()?; - let expected_stack = vec![3.into()]; // pos' = pos + rlp_len = 2 + 1 + let expected_stack = vec![pos + U256::from(1)]; // pos' = pos + rlp_len = 2 + 1 let expected_rlp = vec![0, 0, 42]; assert_eq!(interpreter.stack(), expected_stack); assert_eq!(interpreter.get_rlp_memory(), expected_rlp); @@ -28,12 +30,12 @@ fn test_encode_rlp_scalar_medium() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let scalar = 0x12345.into(); - let pos = 2.into(); + let pos = U256::from(Segment::RlpRaw as usize + 2); let initial_stack = vec![retdest, scalar, pos]; let mut interpreter = Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack); interpreter.run()?; - let expected_stack = vec![6.into()]; // pos' = pos + rlp_len = 2 + 4 + let expected_stack = vec![pos + U256::from(4)]; // pos' = pos + rlp_len = 2 + 4 let expected_rlp = vec![0, 0, 0x80 + 3, 0x01, 0x23, 0x45]; assert_eq!(interpreter.stack(), expected_stack); assert_eq!(interpreter.get_rlp_memory(), expected_rlp); @@ -47,12 +49,12 @@ fn test_encode_rlp_160() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let string = 0x12345.into(); - let pos = 0.into(); + let pos = U256::from(Segment::RlpRaw as usize); let initial_stack = vec![retdest, string, pos]; let mut interpreter = Interpreter::new_with_kernel(encode_rlp_160, initial_stack); interpreter.run()?; - let expected_stack = vec![(1 + 20).into()]; // pos' + let expected_stack = vec![pos + U256::from(1 + 20)]; // pos' #[rustfmt::skip] let expected_rlp = vec![0x80 + 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x23, 0x45]; assert_eq!(interpreter.stack(), expected_stack); @@ -67,12 +69,12 @@ fn test_encode_rlp_256() -> Result<()> { let retdest = 0xDEADBEEFu32.into(); let string = 0x12345.into(); - let pos = 0.into(); + let pos = U256::from(Segment::RlpRaw as usize); let initial_stack = vec![retdest, string, pos]; let mut interpreter = Interpreter::new_with_kernel(encode_rlp_256, initial_stack); interpreter.run()?; - let expected_stack = vec![(1 + 32).into()]; // pos' + let expected_stack = vec![pos + U256::from(1 + 32)]; // pos' #[rustfmt::skip] let expected_rlp = vec![0x80 + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x23, 0x45]; assert_eq!(interpreter.stack(), expected_stack); @@ -86,8 +88,8 @@ fn test_prepend_rlp_list_prefix_small() -> Result<()> { let prepend_rlp_list_prefix = KERNEL.global_labels["prepend_rlp_list_prefix"]; let retdest = 0xDEADBEEFu32.into(); - let start_pos = 9.into(); - let end_pos = (9 + 5).into(); + let start_pos = U256::from(Segment::RlpRaw as usize + 9); + let end_pos = U256::from(Segment::RlpRaw as usize + 9 + 5); let initial_stack = vec![retdest, start_pos, end_pos]; let mut interpreter = Interpreter::new_with_kernel(prepend_rlp_list_prefix, initial_stack); interpreter.set_rlp_memory(vec![ @@ -100,7 +102,7 @@ fn test_prepend_rlp_list_prefix_small() -> Result<()> { interpreter.run()?; let expected_rlp_len = 6.into(); - let expected_start_pos = 8.into(); + let expected_start_pos = U256::from(Segment::RlpRaw as usize + 8); let expected_stack = vec![expected_rlp_len, expected_start_pos]; let expected_rlp = vec![0, 0, 0, 0, 0, 0, 0, 0, 0xc0 + 5, 1, 2, 3, 4, 5]; @@ -115,8 +117,8 @@ fn test_prepend_rlp_list_prefix_large() -> Result<()> { let prepend_rlp_list_prefix = KERNEL.global_labels["prepend_rlp_list_prefix"]; let retdest = 0xDEADBEEFu32.into(); - let start_pos = 9.into(); - let end_pos = (9 + 60).into(); + let start_pos = U256::from(Segment::RlpRaw as usize + 9); + let end_pos = U256::from(Segment::RlpRaw as usize + 9 + 60); let initial_stack = vec![retdest, start_pos, end_pos]; let mut interpreter = Interpreter::new_with_kernel(prepend_rlp_list_prefix, initial_stack); @@ -136,7 +138,7 @@ fn test_prepend_rlp_list_prefix_large() -> Result<()> { interpreter.run()?; let expected_rlp_len = 62.into(); - let expected_start_pos = 7.into(); + let expected_start_pos = U256::from(Segment::RlpRaw as usize + 7); let expected_stack = vec![expected_rlp_len, expected_start_pos]; #[rustfmt::skip] diff --git a/evm/src/cpu/memio.rs b/evm/src/cpu/memio.rs index 304bb3de1c..2073e182e1 100644 --- a/evm/src/cpu/memio.rs +++ b/evm/src/cpu/memio.rs @@ -5,23 +5,17 @@ use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; +use super::cpu_stark::get_addr; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cpu::columns::CpuColumnsView; -use crate::cpu::membus::NUM_GP_CHANNELS; use crate::cpu::stack; -use crate::memory::segments::Segment; +use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR}; const fn get_addr_load(lv: &CpuColumnsView) -> (T, T, T) { - let addr_context = lv.mem_channels[0].value[0]; - let addr_segment = lv.mem_channels[1].value[0]; - let addr_virtual = lv.mem_channels[2].value[0]; - (addr_context, addr_segment, addr_virtual) + get_addr(lv, 0) } const fn get_addr_store(lv: &CpuColumnsView) -> (T, T, T) { - let addr_context = lv.mem_channels[1].value[0]; - let addr_segment = lv.mem_channels[2].value[0]; - let addr_virtual = lv.mem_channels[3].value[0]; - (addr_context, addr_segment, addr_virtual) + get_addr(lv, 1) } /// Evaluates constraints for MLOAD_GENERAL. @@ -36,7 +30,7 @@ fn eval_packed_load( let (addr_context, addr_segment, addr_virtual) = get_addr_load(lv); // Check that we are loading the correct value from the correct address. - let load_channel = lv.mem_channels[3]; + let load_channel = lv.mem_channels[1]; yield_constr.constraint(filter * (load_channel.used - P::ONES)); yield_constr.constraint(filter * (load_channel.is_read - P::ONES)); yield_constr.constraint(filter * (load_channel.addr_context - addr_context)); @@ -53,7 +47,7 @@ fn eval_packed_load( } // Disable remaining memory channels, if any. - for &channel in &lv.mem_channels[4..NUM_GP_CHANNELS] { + for &channel in &lv.mem_channels[2..] { yield_constr.constraint(filter * channel.used); } yield_constr.constraint(filter * lv.partial_channel.used); @@ -83,7 +77,7 @@ fn eval_ext_circuit_load, const D: usize>( let (addr_context, addr_segment, addr_virtual) = get_addr_load(lv); // Check that we are loading the correct value from the correct channel. - let load_channel = lv.mem_channels[3]; + let load_channel = lv.mem_channels[1]; { let constr = builder.mul_sub_extension(filter, load_channel.used, filter); yield_constr.constraint(builder, constr); @@ -117,7 +111,7 @@ fn eval_ext_circuit_load, const D: usize>( } // Disable remaining memory channels, if any. - for &channel in &lv.mem_channels[4..] { + for &channel in &lv.mem_channels[2..] { let constr = builder.mul_extension(filter, channel.used); yield_constr.constraint(builder, constr); } @@ -157,13 +151,13 @@ fn eval_packed_store( yield_constr.constraint(filter * (store_channel.addr_virtual - addr_virtual)); // Disable remaining memory channels, if any. - for &channel in &lv.mem_channels[4..] { + for &channel in &lv.mem_channels[2..] { yield_constr.constraint(filter * channel.used); } // Stack constraints. // Pops. - for i in 1..4 { + for i in 1..2 { let channel = lv.mem_channels[i]; yield_constr.constraint(filter * (channel.used - P::ONES)); @@ -171,19 +165,21 @@ fn eval_packed_store( yield_constr.constraint(filter * (channel.addr_context - lv.context)); yield_constr.constraint( - filter * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)), + filter + * (channel.addr_segment + - P::Scalar::from_canonical_usize(Segment::Stack.unscale())), ); // Remember that the first read (`i == 1`) is for the second stack element at `stack[stack_len - 1]`. let addr_virtual = lv.stack_len - P::Scalar::from_canonical_usize(i + 1); yield_constr.constraint(filter * (channel.addr_virtual - addr_virtual)); } // Constrain `stack_inv_aux`. - let len_diff = lv.stack_len - P::Scalar::from_canonical_usize(4); + let len_diff = lv.stack_len - P::Scalar::from_canonical_usize(2); yield_constr.constraint( lv.op.m_op_general * (len_diff * lv.general.stack().stack_inv - lv.general.stack().stack_inv_aux), ); - // If stack_len != 4 and MSTORE, read new top of the stack in nv.mem_channels[0]. + // If stack_len != 2 and MSTORE, read new top of the stack in nv.mem_channels[0]. let top_read_channel = nv.mem_channels[0]; let is_top_read = lv.general.stack().stack_inv_aux * (P::ONES - lv.opcode_bits[0]); // Constrain `stack_inv_aux_2`. It contains `stack_inv_aux * opcode_bits[0]`. @@ -196,12 +192,11 @@ fn eval_packed_store( yield_constr.constraint_transition( new_filter * (top_read_channel.addr_segment - - P::Scalar::from_canonical_u64(Segment::Stack as u64)), + - P::Scalar::from_canonical_usize(Segment::Stack.unscale())), ); let addr_virtual = nv.stack_len - P::ONES; yield_constr.constraint_transition(new_filter * (top_read_channel.addr_virtual - addr_virtual)); - - // If stack_len == 4 or MLOAD, disable the channel. + // If stack_len == 2 or MLOAD, disable the channel. yield_constr.constraint( lv.op.m_op_general * (lv.general.stack().stack_inv_aux - P::ONES) * top_read_channel.used, ); @@ -245,14 +240,14 @@ fn eval_ext_circuit_store, const D: usize>( } // Disable remaining memory channels, if any. - for &channel in &lv.mem_channels[4..] { + for &channel in &lv.mem_channels[2..] { let constr = builder.mul_extension(filter, channel.used); yield_constr.constraint(builder, constr); } // Stack constraints // Pops. - for i in 1..4 { + for i in 1..2 { let channel = lv.mem_channels[i]; { @@ -271,7 +266,7 @@ fn eval_ext_circuit_store, const D: usize>( { let diff = builder.add_const_extension( channel.addr_segment, - -F::from_canonical_u64(Segment::Stack as u64), + -F::from_canonical_usize(Segment::Stack.unscale()), ); let constr = builder.mul_extension(filter, diff); yield_constr.constraint(builder, constr); @@ -285,7 +280,7 @@ fn eval_ext_circuit_store, const D: usize>( } // Constrain `stack_inv_aux`. { - let len_diff = builder.add_const_extension(lv.stack_len, -F::from_canonical_usize(4)); + let len_diff = builder.add_const_extension(lv.stack_len, -F::from_canonical_usize(2)); let diff = builder.mul_sub_extension( len_diff, lv.general.stack().stack_inv, @@ -294,7 +289,7 @@ fn eval_ext_circuit_store, const D: usize>( let constr = builder.mul_extension(lv.op.m_op_general, diff); yield_constr.constraint(builder, constr); } - // If stack_len != 4 and MSTORE, read new top of the stack in nv.mem_channels[0]. + // If stack_len != 2 and MSTORE, read new top of the stack in nv.mem_channels[0]. let top_read_channel = nv.mem_channels[0]; let is_top_read = builder.mul_extension(lv.general.stack().stack_inv_aux, lv.opcode_bits[0]); let is_top_read = builder.sub_extension(lv.general.stack().stack_inv_aux, is_top_read); @@ -321,7 +316,7 @@ fn eval_ext_circuit_store, const D: usize>( { let diff = builder.add_const_extension( top_read_channel.addr_segment, - -F::from_canonical_u64(Segment::Stack as u64), + -F::from_canonical_usize(Segment::Stack.unscale()), ); let constr = builder.mul_extension(new_filter, diff); yield_constr.constraint_transition(builder, constr); @@ -332,7 +327,7 @@ fn eval_ext_circuit_store, const D: usize>( let constr = builder.mul_extension(new_filter, diff); yield_constr.constraint_transition(builder, constr); } - // If stack_len == 4 or MLOAD, disable the channel. + // If stack_len == 2 or MLOAD, disable the channel. { let diff = builder.mul_sub_extension( lv.op.m_op_general, diff --git a/evm/src/cpu/shift.rs b/evm/src/cpu/shift.rs index 3d97c2f1a1..29baa5ea63 100644 --- a/evm/src/cpu/shift.rs +++ b/evm/src/cpu/shift.rs @@ -24,7 +24,7 @@ pub(crate) fn eval_packed( // let val = lv.mem_channels[0]; // let output = lv.mem_channels[NUM_GP_CHANNELS - 1]; - let shift_table_segment = P::Scalar::from_canonical_u64(Segment::ShiftTable as u64); + let shift_table_segment = P::Scalar::from_canonical_usize(Segment::ShiftTable.unscale()); // Only lookup the shifting factor when displacement is < 2^32. // two_exp.used is true (1) if the high limbs of the displacement are @@ -73,7 +73,7 @@ pub(crate) fn eval_ext_circuit, const D: usize>( let displacement = lv.mem_channels[0]; let two_exp = lv.mem_channels[2]; - let shift_table_segment = F::from_canonical_u64(Segment::ShiftTable as u64); + let shift_table_segment = F::from_canonical_usize(Segment::ShiftTable.unscale()); // Only lookup the shifting factor when displacement is < 2^32. // two_exp.used is true (1) if the high limbs of the displacement are diff --git a/evm/src/cpu/stack.rs b/evm/src/cpu/stack.rs index 0497b228a4..9acf1f3af0 100644 --- a/evm/src/cpu/stack.rs +++ b/evm/src/cpu/stack.rs @@ -83,13 +83,13 @@ pub(crate) const JUMPI_OP: Option = Some(StackBehavior { }); /// `StackBehavior` for MLOAD_GENERAL. pub(crate) const MLOAD_GENERAL_OP: Option = Some(StackBehavior { - num_pops: 3, + num_pops: 1, pushes: true, disable_other_channels: false, }); pub(crate) const KECCAK_GENERAL_OP: StackBehavior = StackBehavior { - num_pops: 4, + num_pops: 2, pushes: true, disable_other_channels: true, }; @@ -132,7 +132,7 @@ pub(crate) const STACK_BEHAVIORS: OpsColumnsView> = OpsCol dup_swap: None, context_op: None, m_op_32bytes: Some(StackBehavior { - num_pops: 4, + num_pops: 2, pushes: true, disable_other_channels: false, }), @@ -186,7 +186,8 @@ pub(crate) fn eval_packed_one( yield_constr.constraint(filter * (channel.addr_context - lv.context)); yield_constr.constraint( filter - * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)), + * (channel.addr_segment + - P::Scalar::from_canonical_usize(Segment::Stack.unscale())), ); // Remember that the first read (`i == 1`) is for the second stack element at `stack[stack_len - 1]`. let addr_virtual = lv.stack_len - P::Scalar::from_canonical_usize(i + 1); @@ -212,7 +213,8 @@ pub(crate) fn eval_packed_one( yield_constr.constraint_transition(new_filter * (channel.addr_context - nv.context)); yield_constr.constraint_transition( new_filter - * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)), + * (channel.addr_segment + - P::Scalar::from_canonical_usize(Segment::Stack.unscale())), ); let addr_virtual = nv.stack_len - P::ONES; yield_constr.constraint_transition(new_filter * (channel.addr_virtual - addr_virtual)); @@ -238,7 +240,8 @@ pub(crate) fn eval_packed_one( yield_constr.constraint(new_filter * (channel.addr_context - lv.context)); yield_constr.constraint( new_filter - * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)), + * (channel.addr_segment + - P::Scalar::from_canonical_usize(Segment::Stack.unscale())), ); let addr_virtual = lv.stack_len - P::ONES; yield_constr.constraint(new_filter * (channel.addr_virtual - addr_virtual)); @@ -343,7 +346,7 @@ pub(crate) fn eval_packed( yield_constr.constraint_transition( new_filter * (top_read_channel.addr_segment - - P::Scalar::from_canonical_u64(Segment::Stack as u64)), + - P::Scalar::from_canonical_usize(Segment::Stack.unscale())), ); let addr_virtual = nv.stack_len - P::ONES; yield_constr.constraint_transition(new_filter * (top_read_channel.addr_virtual - addr_virtual)); @@ -397,7 +400,7 @@ pub(crate) fn eval_ext_circuit_one, const D: usize> { let constr = builder.arithmetic_extension( F::ONE, - -F::from_canonical_u64(Segment::Stack as u64), + -F::from_canonical_usize(Segment::Stack.unscale()), filter, channel.addr_segment, filter, @@ -454,7 +457,7 @@ pub(crate) fn eval_ext_circuit_one, const D: usize> { let constr = builder.arithmetic_extension( F::ONE, - -F::from_canonical_u64(Segment::Stack as u64), + -F::from_canonical_usize(Segment::Stack.unscale()), new_filter, channel.addr_segment, new_filter, @@ -507,7 +510,7 @@ pub(crate) fn eval_ext_circuit_one, const D: usize> { let constr = builder.arithmetic_extension( F::ONE, - -F::from_canonical_u64(Segment::Stack as u64), + -F::from_canonical_usize(Segment::Stack.unscale()), new_filter, channel.addr_segment, new_filter, @@ -674,7 +677,7 @@ pub(crate) fn eval_ext_circuit, const D: usize>( { let diff = builder.add_const_extension( top_read_channel.addr_segment, - -F::from_canonical_u64(Segment::Stack as u64), + -F::from_canonical_usize(Segment::Stack.unscale()), ); let constr = builder.mul_extension(new_filter, diff); yield_constr.constraint_transition(builder, constr); diff --git a/evm/src/cpu/syscalls_exceptions.rs b/evm/src/cpu/syscalls_exceptions.rs index 45302b9e71..501b114ff7 100644 --- a/evm/src/cpu/syscalls_exceptions.rs +++ b/evm/src/cpu/syscalls_exceptions.rs @@ -45,7 +45,7 @@ pub(crate) fn eval_packed( } // Look up the handler in memory - let code_segment = P::Scalar::from_canonical_usize(Segment::Code as usize); + let code_segment = P::Scalar::from_canonical_usize(Segment::Code.unscale()); let opcode: P = lv .opcode_bits @@ -153,7 +153,7 @@ pub(crate) fn eval_ext_circuit, const D: usize>( } // Look up the handler in memory - let code_segment = F::from_canonical_usize(Segment::Code as usize); + let code_segment = F::from_canonical_usize(Segment::Code.unscale()); let opcode = lv .opcode_bits diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index d691d34e61..8ae487b0c0 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -155,7 +155,8 @@ fn apply_metadata_and_tries_memops, const D: usize> .map(|(field, val)| { mem_write_log( channel, - MemoryAddress::new(0, Segment::GlobalMetadata, field as usize), + // These fields are already scaled by their segment, and are in context 0 (kernel). + MemoryAddress::new_bundle(U256::from(field as usize)).unwrap(), state, val, ) diff --git a/evm/src/generation/prover_input.rs b/evm/src/generation/prover_input.rs index b2a8f0cea0..b60233d9d0 100644 --- a/evm/src/generation/prover_input.rs +++ b/evm/src/generation/prover_input.rs @@ -20,6 +20,7 @@ use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint, u256_to_usize}; use crate::witness::errors::ProgramError; use crate::witness::errors::ProverInputError::*; use crate::witness::memory::MemoryAddress; +use crate::witness::operation::CONTEXT_SCALING_FACTOR; use crate::witness::util::{current_context_peek, stack_peek}; /// Prover input function represented as a scoped function name. @@ -138,7 +139,7 @@ impl GenerationState { fn run_account_code(&mut self) -> Result { // stack: codehash, ctx, ... let codehash = stack_peek(self, 0)?; - let context = stack_peek(self, 1)?; + let context = stack_peek(self, 1)? >> CONTEXT_SCALING_FACTOR; let context = u256_to_usize(context)?; let mut address = MemoryAddress::new(context, Segment::Code, 0); let code = self @@ -189,11 +190,11 @@ impl GenerationState { m_start_loc: usize, ) -> (Vec, Vec) { let n = self.memory.contexts.len(); - let a = &self.memory.contexts[n - 1].segments[Segment::KernelGeneral as usize].content + let a = &self.memory.contexts[n - 1].segments[Segment::KernelGeneral.unscale()].content [a_start_loc..a_start_loc + len]; - let b = &self.memory.contexts[n - 1].segments[Segment::KernelGeneral as usize].content + let b = &self.memory.contexts[n - 1].segments[Segment::KernelGeneral.unscale()].content [b_start_loc..b_start_loc + len]; - let m = &self.memory.contexts[n - 1].segments[Segment::KernelGeneral as usize].content + let m = &self.memory.contexts[n - 1].segments[Segment::KernelGeneral.unscale()].content [m_start_loc..m_start_loc + len]; let a_biguint = mem_vec_to_biguint(a); diff --git a/evm/src/generation/state.rs b/evm/src/generation/state.rs index 89ff0c5af9..fec2e11ca8 100644 --- a/evm/src/generation/state.rs +++ b/evm/src/generation/state.rs @@ -57,7 +57,7 @@ impl GenerationState { let (trie_roots_ptrs, trie_data) = load_all_mpts(trie_inputs).expect("Invalid MPT data for preinitialization"); - self.memory.contexts[0].segments[Segment::TrieData as usize].content = trie_data; + self.memory.contexts[0].segments[Segment::TrieData.unscale()].content = trie_data; trie_roots_ptrs } @@ -131,13 +131,11 @@ impl GenerationState { } let ctx = self.registers.context; - let returndata_size_addr = MemoryAddress::new( - ctx, - Segment::ContextMetadata, - ContextMetadata::ReturndataSize as usize, - ); + let returndata_offset = ContextMetadata::ReturndataSize.unscale(); + let returndata_size_addr = + MemoryAddress::new(ctx, Segment::ContextMetadata, returndata_offset); let returndata_size = u256_to_usize(self.memory.get(returndata_size_addr))?; - let code = self.memory.contexts[ctx].segments[Segment::Returndata as usize].content + let code = self.memory.contexts[ctx].segments[Segment::Returndata.unscale()].content [..returndata_size] .iter() .map(|x| x.low_u32() as u8) diff --git a/evm/src/generation/trie_extractor.rs b/evm/src/generation/trie_extractor.rs index a7c97e1006..d55a1fbf98 100644 --- a/evm/src/generation/trie_extractor.rs +++ b/evm/src/generation/trie_extractor.rs @@ -58,7 +58,7 @@ pub(crate) fn read_trie_helper( ) -> Result<(), ProgramError> { let load = |offset| memory.get(MemoryAddress::new(0, Segment::TrieData, offset)); let load_slice_from = |init_offset| { - &memory.contexts[0].segments[Segment::TrieData as usize].content[init_offset..] + &memory.contexts[0].segments[Segment::TrieData.unscale()].content[init_offset..] }; let trie_type = PartialTrieType::all()[u256_to_usize(load(ptr))?]; diff --git a/evm/src/keccak_sponge/keccak_sponge_stark.rs b/evm/src/keccak_sponge/keccak_sponge_stark.rs index 2cfc3409ec..46ab717999 100644 --- a/evm/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm/src/keccak_sponge/keccak_sponge_stark.rs @@ -859,11 +859,7 @@ mod tests { let expected_output = keccak(&input); let op = KeccakSpongeOp { - base_address: MemoryAddress { - context: 0, - segment: Segment::Code as usize, - virt: 0, - }, + base_address: MemoryAddress::new(0, Segment::Code, 0), timestamp: 0, input, }; diff --git a/evm/src/memory/memory_stark.rs b/evm/src/memory/memory_stark.rs index c2af69b542..e596f421ea 100644 --- a/evm/src/memory/memory_stark.rs +++ b/evm/src/memory/memory_stark.rs @@ -368,7 +368,7 @@ impl, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark usize { + *self as usize >> SEGMENT_SCALING_FACTOR + } + pub(crate) const fn all() -> [Self; Self::COUNT] { [ Self::Code, diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 633a8d331d..5c10e3b3db 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -431,78 +431,94 @@ pub(crate) fn get_memory_extra_looking_sum_circuit, // Add metadata writes. let block_fields_scalars = [ ( - GlobalMetadata::BlockTimestamp as usize, + GlobalMetadata::BlockTimestamp, public_values.block_metadata.block_timestamp, ), ( - GlobalMetadata::BlockNumber as usize, + GlobalMetadata::BlockNumber, public_values.block_metadata.block_number, ), ( - GlobalMetadata::BlockDifficulty as usize, + GlobalMetadata::BlockDifficulty, public_values.block_metadata.block_difficulty, ), ( - GlobalMetadata::BlockGasLimit as usize, + GlobalMetadata::BlockGasLimit, public_values.block_metadata.block_gaslimit, ), ( - GlobalMetadata::BlockChainId as usize, + GlobalMetadata::BlockChainId, public_values.block_metadata.block_chain_id, ), ( - GlobalMetadata::BlockGasUsed as usize, + GlobalMetadata::BlockGasUsed, public_values.block_metadata.block_gas_used, ), ( - GlobalMetadata::BlockGasUsedBefore as usize, + GlobalMetadata::BlockGasUsedBefore, public_values.extra_block_data.gas_used_before, ), ( - GlobalMetadata::BlockGasUsedAfter as usize, + GlobalMetadata::BlockGasUsedAfter, public_values.extra_block_data.gas_used_after, ), ( - GlobalMetadata::TxnNumberBefore as usize, + GlobalMetadata::TxnNumberBefore, public_values.extra_block_data.txn_number_before, ), ( - GlobalMetadata::TxnNumberAfter as usize, + GlobalMetadata::TxnNumberAfter, public_values.extra_block_data.txn_number_after, ), ]; - let beneficiary_random_base_fee_cur_hash_fields: [(usize, &[Target]); 4] = [ + let beneficiary_random_base_fee_cur_hash_fields: [(GlobalMetadata, &[Target]); 4] = [ ( - GlobalMetadata::BlockBeneficiary as usize, + GlobalMetadata::BlockBeneficiary, &public_values.block_metadata.block_beneficiary, ), ( - GlobalMetadata::BlockRandom as usize, + GlobalMetadata::BlockRandom, &public_values.block_metadata.block_random, ), ( - GlobalMetadata::BlockBaseFee as usize, + GlobalMetadata::BlockBaseFee, &public_values.block_metadata.block_base_fee, ), ( - GlobalMetadata::BlockCurrentHash as usize, + GlobalMetadata::BlockCurrentHash, &public_values.block_hashes.cur_hash, ), ]; - let metadata_segment = builder.constant(F::from_canonical_u32(Segment::GlobalMetadata as u32)); + let metadata_segment = + builder.constant(F::from_canonical_usize(Segment::GlobalMetadata.unscale())); block_fields_scalars.map(|(field, target)| { // Each of those fields fit in 32 bits, hence in a single Target. - sum = add_data_write(builder, challenge, sum, metadata_segment, field, &[target]); + sum = add_data_write( + builder, + challenge, + sum, + metadata_segment, + field.unscale(), + &[target], + ); }); beneficiary_random_base_fee_cur_hash_fields.map(|(field, targets)| { - sum = add_data_write(builder, challenge, sum, metadata_segment, field, targets); + sum = add_data_write( + builder, + challenge, + sum, + metadata_segment, + field.unscale(), + targets, + ); }); // Add block hashes writes. - let block_hashes_segment = builder.constant(F::from_canonical_u32(Segment::BlockHashes as u32)); + let block_hashes_segment = + builder.constant(F::from_canonical_usize(Segment::BlockHashes.unscale())); for i in 0..256 { sum = add_data_write( builder, @@ -515,7 +531,8 @@ pub(crate) fn get_memory_extra_looking_sum_circuit, } // Add block bloom filters writes. - let bloom_segment = builder.constant(F::from_canonical_u32(Segment::GlobalBlockBloom as u32)); + let bloom_segment = + builder.constant(F::from_canonical_usize(Segment::GlobalBlockBloom.unscale())); for i in 0..8 { sum = add_data_write( builder, @@ -530,33 +547,40 @@ pub(crate) fn get_memory_extra_looking_sum_circuit, // Add trie roots writes. let trie_fields = [ ( - GlobalMetadata::StateTrieRootDigestBefore as usize, + GlobalMetadata::StateTrieRootDigestBefore, public_values.trie_roots_before.state_root, ), ( - GlobalMetadata::TransactionTrieRootDigestBefore as usize, + GlobalMetadata::TransactionTrieRootDigestBefore, public_values.trie_roots_before.transactions_root, ), ( - GlobalMetadata::ReceiptTrieRootDigestBefore as usize, + GlobalMetadata::ReceiptTrieRootDigestBefore, public_values.trie_roots_before.receipts_root, ), ( - GlobalMetadata::StateTrieRootDigestAfter as usize, + GlobalMetadata::StateTrieRootDigestAfter, public_values.trie_roots_after.state_root, ), ( - GlobalMetadata::TransactionTrieRootDigestAfter as usize, + GlobalMetadata::TransactionTrieRootDigestAfter, public_values.trie_roots_after.transactions_root, ), ( - GlobalMetadata::ReceiptTrieRootDigestAfter as usize, + GlobalMetadata::ReceiptTrieRootDigestAfter, public_values.trie_roots_after.receipts_root, ), ]; trie_fields.map(|(field, targets)| { - sum = add_data_write(builder, challenge, sum, metadata_segment, field, &targets); + sum = add_data_write( + builder, + challenge, + sum, + metadata_segment, + field.unscale(), + &targets, + ); }); // Add kernel hash and kernel length. @@ -567,7 +591,7 @@ pub(crate) fn get_memory_extra_looking_sum_circuit, challenge, sum, metadata_segment, - GlobalMetadata::KernelHash as usize, + GlobalMetadata::KernelHash.unscale(), &kernel_hash_targets, ); let kernel_len_target = builder.constant(F::from_canonical_usize(KERNEL.code.len())); @@ -576,7 +600,7 @@ pub(crate) fn get_memory_extra_looking_sum_circuit, challenge, sum, metadata_segment, - GlobalMetadata::KernelLen as usize, + GlobalMetadata::KernelLen.unscale(), &[kernel_len_target], ); diff --git a/evm/src/verifier.rs b/evm/src/verifier.rs index 7ca564f282..b69cd9274b 100644 --- a/evm/src/verifier.rs +++ b/evm/src/verifier.rs @@ -239,19 +239,22 @@ where (GlobalMetadata::KernelLen, KERNEL.code.len().into()), ]; - let segment = F::from_canonical_u32(Segment::GlobalMetadata as u32); + let segment = F::from_canonical_usize(Segment::GlobalMetadata.unscale()); - fields.map(|(field, val)| sum = add_data_write(challenge, segment, sum, field as usize, val)); + fields.map(|(field, val)| { + // These fields are already scaled by their segment, and are in context 0 (kernel). + sum = add_data_write(challenge, segment, sum, field.unscale(), val) + }); // Add block bloom writes. - let bloom_segment = F::from_canonical_u32(Segment::GlobalBlockBloom as u32); + let bloom_segment = F::from_canonical_usize(Segment::GlobalBlockBloom.unscale()); for index in 0..8 { let val = public_values.block_metadata.block_bloom[index]; sum = add_data_write(challenge, bloom_segment, sum, index, val); } // Add Blockhashes writes. - let block_hashes_segment = F::from_canonical_u32(Segment::BlockHashes as u32); + let block_hashes_segment = F::from_canonical_usize(Segment::BlockHashes.unscale()); for index in 0..256 { let val = h2u(public_values.block_hashes.prev_hashes[index]); sum = add_data_write(challenge, block_hashes_segment, sum, index, val); @@ -547,22 +550,22 @@ pub(crate) mod testutils { (GlobalMetadata::KernelLen, KERNEL.code.len().into()), ]; - let segment = F::from_canonical_u32(Segment::GlobalMetadata as u32); + let segment = F::from_canonical_usize(Segment::GlobalMetadata.unscale()); let mut extra_looking_rows = Vec::new(); fields.map(|(field, val)| { - extra_looking_rows.push(add_extra_looking_row(segment, field as usize, val)) + extra_looking_rows.push(add_extra_looking_row(segment, field.unscale(), val)) }); // Add block bloom writes. - let bloom_segment = F::from_canonical_u32(Segment::GlobalBlockBloom as u32); + let bloom_segment = F::from_canonical_usize(Segment::GlobalBlockBloom.unscale()); for index in 0..8 { let val = public_values.block_metadata.block_bloom[index]; extra_looking_rows.push(add_extra_looking_row(bloom_segment, index, val)); } // Add Blockhashes writes. - let block_hashes_segment = F::from_canonical_u32(Segment::BlockHashes as u32); + let block_hashes_segment = F::from_canonical_usize(Segment::BlockHashes.unscale()); for index in 0..256 { let val = h2u(public_values.block_hashes.prev_hashes[index]); extra_looking_rows.push(add_extra_looking_row(block_hashes_segment, index, val)); diff --git a/evm/src/witness/memory.rs b/evm/src/witness/memory.rs index 8cb7daf704..ff4c96149c 100644 --- a/evm/src/witness/memory.rs +++ b/evm/src/witness/memory.rs @@ -11,8 +11,9 @@ pub(crate) enum MemoryChannel { use MemoryChannel::{Code, GeneralPurpose, PartialChannel}; +use super::operation::CONTEXT_SCALING_FACTOR; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; -use crate::memory::segments::Segment; +use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR}; use crate::witness::errors::MemoryError::{ContextTooLarge, SegmentTooLarge, VirtTooLarge}; use crate::witness::errors::ProgramError; use crate::witness::errors::ProgramError::MemoryError; @@ -41,7 +42,8 @@ impl MemoryAddress { pub(crate) const fn new(context: usize, segment: Segment, virt: usize) -> Self { Self { context, - segment: segment as usize, + // segment is scaled + segment: segment.unscale(), virt, } } @@ -69,6 +71,17 @@ impl MemoryAddress { }) } + /// Creates a new `MemoryAddress` from a bundled address fitting a `U256`. + /// It will recover the virtual offset as the lowest 32-bit limb, the segment + /// as the next limb, and the context as the next one. + pub(crate) fn new_bundle(addr: U256) -> Result { + let virt = addr.low_u32().into(); + let segment = (addr >> SEGMENT_SCALING_FACTOR).low_u32().into(); + let context = (addr >> CONTEXT_SCALING_FACTOR).low_u32().into(); + + Self::new_u256s(context, segment, virt) + } + pub(crate) fn increment(&mut self) { self.virt = self.virt.saturating_add(1); } @@ -153,7 +166,7 @@ impl MemoryState { pub(crate) fn new(kernel_code: &[u8]) -> Self { let code_u256s = kernel_code.iter().map(|&x| x.into()).collect(); let mut result = Self::default(); - result.contexts[0].segments[Segment::Code as usize].content = code_u256s; + result.contexts[0].segments[Segment::Code.unscale()].content = code_u256s; result } @@ -204,12 +217,9 @@ impl MemoryState { self.contexts[address.context].segments[address.segment].set(address.virt, val); } + // These fields are already scaled by their respective segment. pub(crate) fn read_global_metadata(&self, field: GlobalMetadata) -> U256 { - self.get(MemoryAddress::new( - 0, - Segment::GlobalMetadata, - field as usize, - )) + self.get(MemoryAddress::new_bundle(U256::from(field as usize)).unwrap()) } } diff --git a/evm/src/witness/operation.rs b/evm/src/witness/operation.rs index 848dae8532..c9dea2307b 100644 --- a/evm/src/witness/operation.rs +++ b/evm/src/witness/operation.rs @@ -19,9 +19,8 @@ use crate::extension_tower::BN_BASE; use crate::generation::state::GenerationState; use crate::memory::segments::Segment; use crate::util::u256_to_usize; -use crate::witness::errors::MemoryError::{ContextTooLarge, SegmentTooLarge, VirtTooLarge}; +use crate::witness::errors::MemoryError::VirtTooLarge; use crate::witness::errors::ProgramError; -use crate::witness::errors::ProgramError::MemoryError; use crate::witness::memory::{MemoryAddress, MemoryChannel, MemoryOp, MemoryOpKind}; use crate::witness::operation::MemoryChannel::GeneralPurpose; use crate::witness::transition::fill_stack_fields; @@ -59,6 +58,10 @@ pub(crate) enum Operation { MstoreGeneral, } +// Contexts in the kernel are shifted by 2^64, so that they can be combined with +// the segment and virtual address components in a single U256 word. +pub(crate) const CONTEXT_SCALING_FACTOR: usize = 64; + /// Adds a CPU row filled with the two inputs and the output of a logic operation. /// Generates a new logic operation and adds it to the vector of operation in `LogicStark`. /// Adds three memory read operations to `MemoryStark`: for the two inputs and the output. @@ -129,11 +132,10 @@ pub(crate) fn generate_keccak_general( state: &mut GenerationState, mut row: CpuColumnsView, ) -> Result<(), ProgramError> { - let [(context, _), (segment, log_in1), (base_virt, log_in2), (len, log_in3)] = - stack_pop_with_log_and_fill::<4, _>(state, &mut row)?; + let [(addr, _), (len, log_in1)] = stack_pop_with_log_and_fill::<2, _>(state, &mut row)?; let len = u256_to_usize(len)?; - let base_address = MemoryAddress::new_u256s(context, segment, base_virt)?; + let base_address = MemoryAddress::new_bundle(addr)?; let input = (0..len) .map(|i| { let address = MemoryAddress { @@ -152,8 +154,6 @@ pub(crate) fn generate_keccak_general( keccak_sponge_log(state, base_address, input); state.traces.push_memory(log_in1); - state.traces.push_memory(log_in2); - state.traces.push_memory(log_in3); state.traces.push_cpu(row); Ok(()) } @@ -191,7 +191,7 @@ pub(crate) fn generate_pop( ) -> Result<(), ProgramError> { let [(_, _)] = stack_pop_with_log_and_fill::<1, _>(state, &mut row)?; - let diff = row.stack_len - F::from_canonical_usize(1); + let diff = row.stack_len - F::ONE; if let Some(inv) = diff.try_inverse() { row.general.stack_mut().stack_inv = inv; row.general.stack_mut().stack_inv_aux = F::ONE; @@ -352,7 +352,11 @@ pub(crate) fn generate_get_context( let res = mem_write_gp_log_and_fill(3, address, state, &mut row, state.registers.stack_top); Some(res) }; - push_no_write(state, state.registers.context.into()); + push_no_write( + state, + // The fetched value needs to be scaled before being pushed. + U256::from(state.registers.context) << CONTEXT_SCALING_FACTOR, + ); if let Some(log) = write { state.traces.push_memory(log); } @@ -369,9 +373,10 @@ pub(crate) fn generate_set_context( let sp_to_save = state.registers.stack_len.into(); let old_ctx = state.registers.context; - let new_ctx = u256_to_usize(ctx)?; + // The popped value needs to be scaled down. + let new_ctx = u256_to_usize(ctx >> CONTEXT_SCALING_FACTOR)?; - let sp_field = ContextMetadata::StackSize as usize; + let sp_field = ContextMetadata::StackSize.unscale(); let old_sp_addr = MemoryAddress::new(old_ctx, Segment::ContextMetadata, sp_field); let new_sp_addr = MemoryAddress::new(new_ctx, Segment::ContextMetadata, sp_field); @@ -390,7 +395,7 @@ pub(crate) fn generate_set_context( channel.used = F::ONE; channel.is_read = F::ONE; channel.addr_context = F::from_canonical_usize(new_ctx); - channel.addr_segment = F::from_canonical_usize(Segment::ContextMetadata as usize); + channel.addr_segment = F::from_canonical_usize(Segment::ContextMetadata.unscale()); channel.addr_virtual = F::from_canonical_usize(new_sp_addr.virt); let val_limbs: [u64; 4] = sp_to_save.0; for (i, limb) in val_limbs.into_iter().enumerate() { @@ -433,6 +438,7 @@ pub(crate) fn generate_set_context( state.traces.push_memory(log_write_old_sp); state.traces.push_memory(log_read_new_sp); state.traces.push_cpu(row); + Ok(()) } @@ -575,7 +581,7 @@ pub(crate) fn generate_not( // This is necessary for the stack constraints for POP, // since the two flags are combined. - let diff = row.stack_len - F::from_canonical_usize(1); + let diff = row.stack_len - F::ONE; if let Some(inv) = diff.try_inverse() { row.general.stack_mut().stack_inv = inv; row.general.stack_mut().stack_inv_aux = F::ONE; @@ -808,18 +814,16 @@ pub(crate) fn generate_mload_general( state: &mut GenerationState, mut row: CpuColumnsView, ) -> Result<(), ProgramError> { - let [(context, _), (segment, log_in1), (virt, log_in2)] = - stack_pop_with_log_and_fill::<3, _>(state, &mut row)?; + let [(addr, _)] = stack_pop_with_log_and_fill::<1, _>(state, &mut row)?; - let (val, log_read) = mem_read_gp_with_log_and_fill( - 3, - MemoryAddress::new_u256s(context, segment, virt)?, - state, - &mut row, - ); + let (val, log_read) = + mem_read_gp_with_log_and_fill(1, MemoryAddress::new_bundle(addr)?, state, &mut row); push_no_write(state, val); - let diff = row.stack_len - F::from_canonical_usize(4); + // Because MLOAD_GENERAL performs 1 pop and 1 push, it does not make use of the `stack_inv_aux` general columns. + // We hence can set the diff to 2 (instead of 1) so that the stack constraint for MSTORE_GENERAL applies to both + // operations, which are combined into a single CPU flag. + let diff = row.stack_len - F::TWO; if let Some(inv) = diff.try_inverse() { row.general.stack_mut().stack_inv = inv; row.general.stack_mut().stack_inv_aux = F::ONE; @@ -828,8 +832,6 @@ pub(crate) fn generate_mload_general( row.general.stack_mut().stack_inv_aux = F::ZERO; } - state.traces.push_memory(log_in1); - state.traces.push_memory(log_in2); state.traces.push_memory(log_read); state.traces.push_cpu(row); Ok(()) @@ -839,15 +841,14 @@ pub(crate) fn generate_mload_32bytes( state: &mut GenerationState, mut row: CpuColumnsView, ) -> Result<(), ProgramError> { - let [(context, _), (segment, log_in1), (base_virt, log_in2), (len, log_in3)] = - stack_pop_with_log_and_fill::<4, _>(state, &mut row)?; + let [(addr, _), (len, log_in1)] = stack_pop_with_log_and_fill::<2, _>(state, &mut row)?; let len = u256_to_usize(len)?; if len > 32 { // The call to `U256::from_big_endian()` would panic. return Err(ProgramError::IntegerTooLarge); } - let base_address = MemoryAddress::new_u256s(context, segment, base_virt)?; + let base_address = MemoryAddress::new_bundle(addr)?; if usize::MAX - base_address.virt < len { return Err(ProgramError::MemoryError(VirtTooLarge { virt: base_address.virt.into(), @@ -870,8 +871,6 @@ pub(crate) fn generate_mload_32bytes( byte_packing_log(state, base_address, bytes); state.traces.push_memory(log_in1); - state.traces.push_memory(log_in2); - state.traces.push_memory(log_in3); state.traces.push_cpu(row); Ok(()) } @@ -880,23 +879,12 @@ pub(crate) fn generate_mstore_general( state: &mut GenerationState, mut row: CpuColumnsView, ) -> Result<(), ProgramError> { - let [(val, _), (context, log_in1), (segment, log_in2), (virt, log_in3)] = - stack_pop_with_log_and_fill::<4, _>(state, &mut row)?; + let [(val, _), (addr, log_in1)] = stack_pop_with_log_and_fill::<2, _>(state, &mut row)?; - let address = MemoryAddress { - context: context - .try_into() - .map_err(|_| MemoryError(ContextTooLarge { context }))?, - segment: segment - .try_into() - .map_err(|_| MemoryError(SegmentTooLarge { segment }))?, - virt: virt - .try_into() - .map_err(|_| MemoryError(VirtTooLarge { virt }))?, - }; + let address = MemoryAddress::new_bundle(addr)?; let log_write = mem_write_partial_log_and_fill(address, state, &mut row, val); - let diff = row.stack_len - F::from_canonical_usize(4); + let diff = row.stack_len - F::TWO; if let Some(inv) = diff.try_inverse() { row.general.stack_mut().stack_inv = inv; row.general.stack_mut().stack_inv_aux = F::ONE; @@ -908,8 +896,6 @@ pub(crate) fn generate_mstore_general( } state.traces.push_memory(log_in1); - state.traces.push_memory(log_in2); - state.traces.push_memory(log_in3); state.traces.push_memory(log_write); state.traces.push_cpu(row); @@ -922,19 +908,16 @@ pub(crate) fn generate_mstore_32bytes( state: &mut GenerationState, mut row: CpuColumnsView, ) -> Result<(), ProgramError> { - let [(context, _), (segment, log_in1), (base_virt, log_in2), (val, log_in3)] = - stack_pop_with_log_and_fill::<4, _>(state, &mut row)?; + let [(addr, _), (val, log_in1)] = stack_pop_with_log_and_fill::<2, _>(state, &mut row)?; - let base_address = MemoryAddress::new_u256s(context, segment, base_virt)?; + let base_address = MemoryAddress::new_bundle(addr)?; byte_unpacking_log(state, base_address, val, n as usize); - let new_offset = base_virt + n; - push_no_write(state, new_offset); + let new_addr = addr + n; + push_no_write(state, new_addr); state.traces.push_memory(log_in1); - state.traces.push_memory(log_in2); - state.traces.push_memory(log_in3); state.traces.push_cpu(row); Ok(()) } diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index cf2e3bbeba..835ff59372 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -299,11 +299,11 @@ fn perform_op( state.registers.gas_used += gas_to_charge(op); - let gas_limit_address = MemoryAddress { - context: state.registers.context, - segment: Segment::ContextMetadata as usize, - virt: ContextMetadata::GasLimit as usize, - }; + let gas_limit_address = MemoryAddress::new( + state.registers.context, + Segment::ContextMetadata, + ContextMetadata::GasLimit.unscale(), // context offsets are already scaled + ); if !state.registers.is_kernel { let gas_limit = TryInto::::try_into(state.memory.get(gas_limit_address)); match gas_limit { @@ -345,14 +345,14 @@ pub(crate) fn fill_stack_fields( channel.used = F::ONE; channel.is_read = F::ONE; channel.addr_context = F::from_canonical_usize(state.registers.context); - channel.addr_segment = F::from_canonical_usize(Segment::Stack as usize); + channel.addr_segment = F::from_canonical_usize(Segment::Stack.unscale()); channel.addr_virtual = F::from_canonical_usize(state.registers.stack_len - 1); - let address = MemoryAddress { - context: state.registers.context, - segment: Segment::Stack as usize, - virt: state.registers.stack_len - 1, - }; + let address = MemoryAddress::new( + state.registers.context, + Segment::Stack, + state.registers.stack_len - 1, + ); let mem_op = MemoryOp::new( GeneralPurpose(0), @@ -494,7 +494,7 @@ pub(crate) fn transition(state: &mut GenerationState) -> anyhow::Re e, offset_name, state.stack(), - state.memory.contexts[0].segments[Segment::KernelGeneral as usize].content, + state.memory.contexts[0].segments[Segment::KernelGeneral.unscale()].content, ); } state.rollback(checkpoint); diff --git a/evm/tests/log_opcode.rs b/evm/tests/log_opcode.rs index 157b9fe6ad..78a472e37c 100644 --- a/evm/tests/log_opcode.rs +++ b/evm/tests/log_opcode.rs @@ -444,7 +444,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { // Preprocess all circuits. let all_circuits = AllRecursiveCircuits::::new( &all_stark, - &[16..17, 13..16, 15..18, 14..15, 9..10, 12..13, 17..20], + &[16..17, 13..16, 15..18, 14..15, 10..11, 12..13, 17..20], &config, );