Remove some CPU cycles (#1469)

* Amortize mload_packing

* Reduce stack overhead

* Amortize mstore_unpacking

* Speed-up stack operation in hash.asm

* Misc

* Small tweaks

* Misc small optims

* Fix comments

* Fix main access to withdrawals

* Fix stack description

* minor: rename label

* Comments

---------

Co-authored-by: Linda Guiga <lindaguiga3@gmail.com>
This commit is contained in:
Robin Salen 2024-01-16 12:00:55 -05:00 committed by GitHub
parent 30b4799826
commit 990eb34d96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 153 additions and 230 deletions

View File

@ -2,13 +2,13 @@ global sys_extcodehash:
// stack: kexit_info, address
SWAP1 %u256_to_addr
// stack: address, kexit_info
DUP1 %insert_accessed_addresses
// stack: cold_access, address, kexit_info
SWAP1
DUP2 %insert_accessed_addresses
// stack: cold_access, kexit_info, address
PUSH @GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS
MUL
PUSH @GAS_WARMACCESS
ADD
%stack (gas, address, kexit_info) -> (gas, kexit_info, address)
%charge_gas
// stack: kexit_info, address
@ -57,13 +57,13 @@ global sys_extcodesize:
// stack: kexit_info, address
SWAP1 %u256_to_addr
// stack: address, kexit_info
DUP1 %insert_accessed_addresses
// stack: cold_access, address, kexit_info
SWAP1
DUP2 %insert_accessed_addresses
// stack: cold_access, kexit_info, address
PUSH @GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS
MUL
PUSH @GAS_WARMACCESS
ADD
%stack (gas, address, kexit_info) -> (gas, kexit_info, address)
%charge_gas
// stack: kexit_info, address

View File

@ -2,13 +2,13 @@ global sys_balance:
// stack: kexit_info, address
SWAP1 %u256_to_addr
// stack: address, kexit_info
DUP1 %insert_accessed_addresses
// stack: cold_access, address, kexit_info
SWAP1
DUP2 %insert_accessed_addresses
// stack: cold_access, kexit_info, address
PUSH @GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS
MUL
PUSH @GAS_WARMACCESS
ADD
%stack (gas, address, kexit_info) -> (gas, kexit_info, address)
%charge_gas
// stack: kexit_info, address

View File

@ -38,20 +38,17 @@ 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) -> (@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, salt, code_hash, retdest)
ADD
%jump(mstore_unpacking)
get_create2_address_contd:
MSTORE_32BYTES_20
POP
%stack (salt, code_hash, retdest) -> (@SEGMENT_KERNEL_GENERAL, 21, salt, 32, get_create2_address_contd2, code_hash, retdest)
%stack (salt, code_hash, retdest) -> (@SEGMENT_KERNEL_GENERAL, 21, salt, code_hash, retdest)
ADD
%jump(mstore_unpacking)
get_create2_address_contd2:
MSTORE_32BYTES_32
POP
%stack (code_hash, retdest) -> (@SEGMENT_KERNEL_GENERAL, 53, code_hash, 32, get_create2_address_finish, retdest)
%stack (code_hash, retdest) -> (@SEGMENT_KERNEL_GENERAL, 53, code_hash, retdest)
ADD
%jump(mstore_unpacking)
get_create2_address_finish:
MSTORE_32BYTES_32
POP
%stack (retdest) -> (@SEGMENT_KERNEL_GENERAL, 85, retdest) // offset == context == 0
// addr, len, retdest

View File

@ -42,7 +42,7 @@ continue:
proof_ok:
// stack: i, ctx, final_pos, retdest
// We already know final_pos is a jumpdest
%stack (i, ctx, final_pos) -> (ctx, @SEGMENT_JUMPDEST_BITS, i)
%stack (i, ctx, final_pos) -> (ctx, @SEGMENT_JUMPDEST_BITS, final_pos)
%build_address
PUSH 1
MSTORE_GENERAL
@ -145,7 +145,7 @@ global write_table_if_jumpdest:
(proof_prefix_addr, ctx) ->
(ctx, proof_prefix_addr, 32, proof_prefix_addr, ctx)
ADD // combine context and offset to make an address (SEGMENT_CODE == 0)
%mload_packing
MLOAD_32BYTES
// packed_opcodes, proof_prefix_addr, ctx, jumpdest, retdest
DUP1 %shl_const(1)
DUP2 %shl_const(2)

View File

@ -105,7 +105,7 @@ global precompile_blake2_f:
GET_CONTEXT
// 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
MLOAD_32BYTES
// stack: rounds, h_0..h_7, m_0..m_15, t_0, t_1, flag, blake2_f_contd, kexit_info
DUP1

View File

@ -14,32 +14,32 @@ global precompile_bn_add:
%charge_gas_const(@BN_ADD_GAS)
// Load x0, y0, x1, y1 from the call data using `mload_packing`.
// Load x0, y0, x1, y1 from the call data using `MLOAD_32BYTES`.
PUSH bn_add_return
// stack: bn_add_return, kexit_info
%stack () -> (@SEGMENT_CALLDATA, 96, 32)
GET_CONTEXT
// stack: ctx, @SEGMENT_CALLDATA, 96, 32, bn_add_return, kexit_info
%build_address
%mload_packing
MLOAD_32BYTES
// 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
MLOAD_32BYTES
// 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
MLOAD_32BYTES
// stack: y0, x1, y1, bn_add_return, kexit_info
%stack () -> (@SEGMENT_CALLDATA, 32)
GET_CONTEXT
// stack: ctx, @SEGMENT_CALLDATA, 32, y0, x1, y1, bn_add_return, kexit_info
%build_address_no_offset
%mload_packing
MLOAD_32BYTES
// stack: x0, y0, x1, y1, bn_add_return, kexit_info
%jump(bn_add)
bn_add_return:
@ -53,11 +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, x, 32, bn_add_contd6, parent_ctx, y)
%stack (parent_ctx, x, y) -> (parent_ctx, @SEGMENT_RETURNDATA, x, parent_ctx, y)
%build_address_no_offset
%jump(mstore_unpacking)
bn_add_contd6:
MSTORE_32BYTES_32
POP
%stack (parent_ctx, y) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, y, 32, pop_and_return_success)
%stack (parent_ctx, y) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, y)
%build_address
%jump(mstore_unpacking)
MSTORE_32BYTES_32
%jump(pop_and_return_success)

View File

@ -14,26 +14,26 @@ global precompile_bn_mul:
%charge_gas_const(@BN_MUL_GAS)
// Load x, y, n from the call data using `mload_packing`.
// Load x, y, n from the call data using `MLOAD_32BYTES`.
PUSH bn_mul_return
// stack: bn_mul_return, kexit_info
%stack () -> (@SEGMENT_CALLDATA, 64, 32)
GET_CONTEXT
// stack: ctx, @SEGMENT_CALLDATA, 64, 32, bn_mul_return, kexit_info
%build_address
%mload_packing
MLOAD_32BYTES
// 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
MLOAD_32BYTES
// stack: y, n, bn_mul_return, kexit_info
%stack () -> (@SEGMENT_CALLDATA, 32)
GET_CONTEXT
// stack: ctx, @SEGMENT_CALLDATA, 32, y, n, bn_mul_return, kexit_info
%build_address_no_offset
%mload_packing
MLOAD_32BYTES
// stack: x, y, n, bn_mul_return, kexit_info
%jump(bn_mul)
bn_mul_return:
@ -47,11 +47,12 @@ 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, Px, 32, bn_mul_contd6, parent_ctx, Py)
%stack (parent_ctx, Px, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, Px, parent_ctx, Py)
%build_address_no_offset
%jump(mstore_unpacking)
MSTORE_32BYTES_32
bn_mul_contd6:
POP
%stack (parent_ctx, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, Py, 32, pop_and_return_success)
%stack (parent_ctx, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, Py)
%build_address
%jump(mstore_unpacking)
MSTORE_32BYTES_32
%jump(pop_and_return_success)

View File

@ -14,32 +14,32 @@ global precompile_ecrec:
%charge_gas_const(@ECREC_GAS)
// Load hash, v, r, s from the call data using `mload_packing`.
// Load hash, v, r, s from the call data using `MLOAD_32BYTES`.
PUSH ecrec_return
// stack: ecrec_return, kexit_info
%stack () -> (@SEGMENT_CALLDATA, 96, 32)
GET_CONTEXT
// stack: ctx, @SEGMENT_CALLDATA, 96, 32, ecrec_return, kexit_info
%build_address
%mload_packing
MLOAD_32BYTES
// 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
MLOAD_32BYTES
// 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
MLOAD_32BYTES
// stack: v, r, s, ecrec_return, kexit_info
%stack () -> (@SEGMENT_CALLDATA, 32)
GET_CONTEXT
// stack: ctx, @SEGMENT_CALLDATA, 32, v, r, s, ecrec_return, kexit_info
%build_address_no_offset
%mload_packing
MLOAD_32BYTES
// stack: hash, v, r, s, ecrec_return, kexit_info
%jump(ecrecover)
ecrec_return:
@ -49,9 +49,10 @@ 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, address, 32, pop_and_return_success)
%stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, address)
%build_address_no_offset
%jump(mstore_unpacking)
MSTORE_32BYTES_32
%jump(pop_and_return_success)
// On bad input, return empty return data but still return success.
ecrec_bad_input:

View File

@ -18,7 +18,7 @@ mload_bytes_as_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
MLOAD_32BYTES
// 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
@ -113,7 +113,7 @@ calculate_l_E_prime:
PUSH @SEGMENT_CALLDATA
GET_CONTEXT
%build_address
%mload_packing
MLOAD_32BYTES
// stack: i[96 + l_B..128 + l_B], l_E, l_B, retdest
%log2_floor
// stack: log2(i[96 + l_B..128 + l_B]), l_E, l_B, retdest
@ -144,7 +144,7 @@ case_le_32:
PUSH @SEGMENT_CALLDATA
GET_CONTEXT
%build_address
%mload_packing
MLOAD_32BYTES
// stack: E, retdest
%log2_floor
// stack: log2(E), retdest
@ -172,21 +172,21 @@ global precompile_expmod:
GET_CONTEXT
// stack: ctx, @SEGMENT_CALLDATA, 32, kexit_info
%build_address_no_offset
%mload_packing
MLOAD_32BYTES
// stack: l_B, kexit_info
// Load l_E from i[32..64].
%stack () -> (@SEGMENT_CALLDATA, 32, 32)
GET_CONTEXT
%build_address
%mload_packing
MLOAD_32BYTES
// 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
MLOAD_32BYTES
// stack: l_M, l_E, l_B, kexit_info
DUP3 ISZERO DUP2 ISZERO
MUL // AND

View File

@ -44,6 +44,7 @@ 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, hash, 32, pop_and_return_success)
%stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, hash)
%build_address_no_offset
%jump(mstore_unpacking)
MSTORE_32BYTES_32
%jump(pop_and_return_success)

View File

@ -44,6 +44,7 @@ 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, hash, 32, pop_and_return_success)
%stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, hash)
%build_address_no_offset
%jump(mstore_unpacking)
MSTORE_32BYTES_32
%jump(pop_and_return_success)

View File

@ -30,47 +30,47 @@ loading_loop:
DUP1 %mul_const(192)
// stack: px, i, k, kexit_info
GET_CONTEXT
%stack (ctx, px) -> (ctx, @SEGMENT_CALLDATA, px, 32, loading_loop_contd, px)
%stack (ctx, px) -> (ctx, @SEGMENT_CALLDATA, px, 32, px)
%build_address
%jump(mload_packing)
MLOAD_32BYTES
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)
%stack (ctx, py) -> (ctx, @SEGMENT_CALLDATA, py, 32, py)
%build_address
%jump(mload_packing)
MLOAD_32BYTES
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)
%stack (ctx, px_im) -> (ctx, @SEGMENT_CALLDATA, px_im, 32, px_im)
%build_address
%jump(mload_packing)
MLOAD_32BYTES
loading_loop_contd3:
// stack: x_im, px_im, y, x, i, k, kexit_info
SWAP1 %add_const(32)
// 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)
%stack (ctx, px_re) -> (ctx, @SEGMENT_CALLDATA, px_re, 32, px_re)
%build_address
%jump(mload_packing)
MLOAD_32BYTES
loading_loop_contd4:
// stack: x_re, px_re, x_im, y, x, i, k, kexit_info
SWAP1 %add_const(32)
// 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)
%stack (ctx, py_im) -> (ctx, @SEGMENT_CALLDATA, py_im, 32, py_im)
%build_address
%jump(mload_packing)
MLOAD_32BYTES
loading_loop_contd5:
// stack: y_im, py_im, x_re, x_im, y, x, i, k, kexit_info
SWAP1 %add_const(32)
// 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)
%stack (ctx, py_re) -> (ctx, @SEGMENT_CALLDATA, py_re, 32)
%build_address
%jump(mload_packing)
MLOAD_32BYTES
loading_loop_contd6:
// stack: y_re, y_im, x_re, x_im, y, x, i, k, kexit_info
SWAP1 // the EVM serializes the imaginary part first
@ -124,6 +124,7 @@ 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, address, 32, pop_and_return_success)
%stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, address)
%build_address_no_offset
%jump(mstore_unpacking)
MSTORE_32BYTES_32
%jump(pop_and_return_success)

View File

@ -47,14 +47,15 @@ global start_txn:
// is handled outside of the kernel.
%mload_global_metadata(@GLOBAL_METADATA_TXN_NUMBER_BEFORE)
// stack: txn_nb
%mload_global_metadata(@GLOBAL_METADATA_BLOCK_GAS_USED_BEFORE)
// stack: init_used_gas, txn_nb
DUP2 %scalar_to_rlp
// stack: txn_counter, init_gas_used, txn_nb
DUP1 %scalar_to_rlp
// stack: txn_counter, txn_nb
DUP1 %num_bytes %mul_const(2)
// stack: num_nibbles, txn_counter, init_gas_used, txn_nb
SWAP2
// stack: init_gas_used, txn_counter, num_nibbles, txn_nb
// stack: num_nibbles, txn_counter, txn_nb
%increment_bounded_rlp
// stack: txn_counter, num_nibbles, next_txn_counter, next_num_nibbles, txn_nb
%mload_global_metadata(@GLOBAL_METADATA_BLOCK_GAS_USED_BEFORE)
// stack: init_gas_used, txn_counter, num_nibbles, next_txn_counter, next_num_nibbles, txn_nb
// If the prover has no txn for us to process, halt.
PROVER_INPUT(no_txn)
@ -62,9 +63,9 @@ global start_txn:
// Call route_txn. When we return, we will process the txn receipt.
PUSH txn_after
// stack: retdest, prev_gas_used, txn_counter, num_nibbles, txn_nb
DUP4 DUP4 %increment_bounded_rlp
%stack (next_txn_counter, next_num_nibbles, retdest, prev_gas_used, txn_counter, num_nibbles) -> (txn_counter, num_nibbles, retdest, prev_gas_used, txn_counter, num_nibbles, next_txn_counter, next_num_nibbles)
// stack: retdest, prev_gas_used, txn_counter, num_nibbles, next_txn_counter, next_num_nibbles, txn_nb
DUP4 DUP4
%jump(route_txn)
global txn_after:
@ -72,10 +73,14 @@ global txn_after:
%process_receipt
// stack: new_cum_gas, txn_counter, num_nibbles, txn_nb
SWAP3 %increment SWAP3
%jump(execute_withdrawals_post_stack_op)
global execute_withdrawals:
// stack: cum_gas, txn_counter, num_nibbles, txn_nb
// stack: cum_gas, txn_counter, num_nibbles, next_txn_counter, next_num_nibbles, txn_nb
%stack (cum_gas, txn_counter, num_nibbles, next_txn_counter, next_num_nibbles) -> (cum_gas, txn_counter, num_nibbles)
execute_withdrawals_post_stack_op:
%withdrawals
global hash_final_tries:
// stack: cum_gas, txn_counter, num_nibbles, txn_nb
// Check that we end up with the correct `cum_gas`, `txn_nb` and bloom filter.

View File

@ -1,9 +1,8 @@
// Load a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0).
%macro mload_u32
// stack: addr
%stack (addr) -> (addr, 4, %%after)
%jump(mload_packing)
%%after:
%stack (addr) -> (addr, 4)
MLOAD_32BYTES
%endmacro
// Load a little-endian u32, consisting of 4 bytes (c_0, c_1, c_2, c_3).
@ -51,17 +50,14 @@
// Load a big-endian u256.
%macro mload_u256
// stack: addr
%stack (addr) -> (addr, 32, %%after)
%jump(mload_packing)
%%after:
%stack (addr) -> (addr, 32)
MLOAD_32BYTES
%endmacro
// Store a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0).
%macro mstore_u32
// stack: addr, value
%stack (addr, value) -> (addr, value, 4, %%after)
%jump(mstore_unpacking)
%%after:
MSTORE_32BYTES_4
// stack: offset
POP
%endmacro

View File

@ -1,22 +1,5 @@
// Methods for encoding integers as bytes in memory, as well as the reverse,
// 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, len, retdest
// Post stack: packed_value
global mload_packing:
// stack: addr, len, retdest
MLOAD_32BYTES
// stack: packed_value, retdest
SWAP1
// stack: retdest, packed_value
JUMP
%macro mload_packing
%stack (addr, len) -> (addr, len, %%after)
%jump(mload_packing)
%%after:
%endmacro
// decoding bytes as integers. All big-endian unless specified.
global mload_packing_u64_LE:
// stack: addr, retdest

View File

@ -60,11 +60,11 @@ global sys_calldataload:
%mload_context_metadata(@CTX_METADATA_CALLDATA_SIZE)
%stack (calldata_size, kexit_info, i) -> (calldata_size, i, kexit_info, i)
LT %jumpi(calldataload_large_offset)
%stack (kexit_info, i) -> (@SEGMENT_CALLDATA, i, 32, sys_calldataload_after_mload_packing, kexit_info)
%stack (kexit_info, i) -> (@SEGMENT_CALLDATA, i, 32, kexit_info)
GET_CONTEXT
%build_address
// stack: addr, 32, sys_calldataload_after_mload_packing, kexit_info
%jump(mload_packing)
// stack: addr, 32, kexit_info
MLOAD_32BYTES
sys_calldataload_after_mload_packing:
// stack: value, kexit_info
SWAP1

View File

@ -63,15 +63,16 @@ global encode_or_hash_node:
// Load the hash and return (hash, 32).
// stack: node_type, node_ptr, encode_value, cur_len, retdest
POP
// Update the length of the `TrieData` segment: there are only two
// elements in a hash node.
SWAP2 %add_const(2) SWAP2
// stack: node_ptr, encode_value, cur_len, retdest
%increment // Skip over node type prefix
// stack: hash_ptr, encode_value, cur_len, retdest
%mload_trie_data
// stack: hash, encode_value, cur_len, retdest
%stack (hash, encode_value, cur_len, retdest) -> (retdest, hash, 32, cur_len)
// Update the length of the `TrieData` segment: there are only two
// elements in a hash node.
SWAP2 %add_const(2)
%stack (cur_len, encode_value, hash, retdest) -> (retdest, hash, 32, cur_len)
JUMP
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)
@ -89,8 +90,8 @@ maybe_hash_node:
pack_small_rlp:
// stack: result_ptr, result_len, cur_len, retdest
%stack (result_ptr, result_len, cur_len)
-> (result_ptr, result_len, after_packed_small_rlp, result_len, cur_len)
%jump(mload_packing)
-> (result_ptr, result_len, result_len, cur_len)
MLOAD_32BYTES
after_packed_small_rlp:
%stack (result, result_len, cur_len, retdest) -> (retdest, result, result_len, cur_len)
JUMP
@ -182,22 +183,21 @@ encode_node_branch_prepend_prefix:
// stack: node_payload_ptr, encode_value, cur_len, %%after_encode, rlp_pos, rlp_start, node_payload_ptr, encode_value, cur_len, retdest
%add_const($i) %mload_trie_data
// stack: child_i_ptr, encode_value, cur_len, %%after_encode, rlp_pos, rlp_start, node_payload_ptr, encode_value, cur_len, retdest
%stack
(child_i_ptr, encode_value, cur_len, after_encode, rlp_pos, rlp_start, node_payload_ptr, encode_value, cur_len, retdest) ->
(child_i_ptr, encode_value, cur_len, after_encode, rlp_pos, rlp_start, node_payload_ptr, encode_value, retdest)
%jump(encode_or_hash_node)
%%after_encode:
// stack: result, result_len, cur_len, rlp_pos, rlp_start, node_payload_ptr, encode_value, retdest
// stack: result, result_len, cur_len, rlp_pos, rlp_start, node_payload_ptr, encode_value, old_len, retdest
// If result_len != 32, result is raw RLP, with an appropriate RLP prefix already.
SWAP1 DUP1 %sub_const(32) %jumpi(%%unpack)
SWAP1
PUSH 32 DUP2 SUB
%jumpi(%%unpack)
// Otherwise, result is a hash, and we need to add the prefix 0x80 + 32 = 160.
// stack: result_len, result, cur_len, rlp_pos, rlp_start, node_payload_ptr, encode_value, retdest
// stack: result_len, result, cur_len, rlp_pos, rlp_start, node_payload_ptr, encode_value, old_len, retdest
DUP4 // rlp_pos
PUSH 160
MSTORE_GENERAL
SWAP3 %increment SWAP3 // rlp_pos += 1
%%unpack:
%stack (result_len, result, cur_len, rlp_pos, rlp_start, node_payload_ptr, encode_value, retdest)
%stack (result_len, result, cur_len, rlp_pos, rlp_start, node_payload_ptr, encode_value, old_len, retdest)
-> (rlp_pos, result, result_len, %%after_unpacking,
rlp_start, node_payload_ptr, encode_value, cur_len, retdest)
%jump(mstore_unpacking)
@ -231,7 +231,8 @@ encode_node_extension_after_encode_child:
encode_node_extension_after_hex_prefix:
// stack: rlp_pos, rlp_start, result, result_len, node_payload_ptr, cur_len, retdest
// If result_len != 32, result is raw RLP, with an appropriate RLP prefix already.
DUP4 %sub_const(32) %jumpi(encode_node_extension_unpack)
PUSH 32 DUP5 SUB
%jumpi(encode_node_extension_unpack)
// Otherwise, result is a hash, and we need to add the prefix 0x80 + 32 = 160.
DUP1 // rlp_pos
PUSH 160
@ -250,11 +251,6 @@ encode_node_extension_after_unpacking:
global encode_node_leaf:
// stack: node_type, node_payload_ptr, encode_value, cur_len, retdest
// `TrieData` holds the node type, the number of nibbles, the nibbles,
// the pointer to the value and the value.
// First, we add 4 for the node type, the number of nibbles, the nibbles
// and the pointer to the value.
SWAP3 %add_const(4) SWAP3
POP
// stack: node_payload_ptr, encode_value, cur_len, retdest
%alloc_rlp_block
@ -280,7 +276,12 @@ encode_node_leaf_after_hex_prefix:
JUMP
encode_node_leaf_after_encode_value:
// stack: rlp_end_pos, cur_len, rlp_start, retdest
%stack(rlp_end_pos, cur_len, rlp_start, retdest) -> (rlp_end_pos, rlp_start, cur_len, retdest)
// `TrieData` holds the node type, the number of nibbles, the nibbles,
// the pointer to the value and the value.
// We add 4 for the node type, the number of nibbles, the nibbles
// and the pointer to the value.
SWAP1 %add_const(4)
%stack(cur_len, rlp_end_pos, rlp_start, retdest) -> (rlp_end_pos, rlp_start, cur_len, retdest)
%prepend_rlp_list_prefix
%stack (rlp_prefix_start_pos, rlp_len, cur_len, retdest)
-> (retdest, rlp_prefix_start_pos, rlp_len, cur_len)

View File

@ -28,8 +28,8 @@ first_byte:
// get the first nibble, if num_nibbles is odd, or zero otherwise
SWAP2
// stack: packed_nibbles, num_nibbles, rlp_addr, terminated, retdest
DUP2 DUP1
%mod_const(2)
DUP2
PUSH 2 DUP2 MOD
// stack: parity, num_nibbles, packed_nibbles, num_nibbles, rlp_addr, terminated, retdest
SWAP1 SUB
%mul_const(4)
@ -61,12 +61,12 @@ remaining_bytes:
SWAP2
PUSH @U256_MAX
// stack: U256_MAX, packed_nibbles, num_nibbles, rlp_addr, ret_dest
SWAP1 SWAP2 DUP1
%mod_const(2)
SWAP1 SWAP2
PUSH 2 DUP2 MOD
// 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_addr, ret_dest
%div_const(2)
%div2
// 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_addr, ret_dest

View File

@ -81,7 +81,7 @@ global scalar_to_rlp:
DUP2 DUP2 SUB // len of the key
// stack: len, addr', init_addr, retdest
DUP3
%mload_packing
MLOAD_32BYTES
// stack: packed_key, addr', init_addr, retdest
SWAP2 %pop2
// stack: key, retdest

View File

@ -158,9 +158,9 @@
DUP3 DUP6 MUL ISZERO %jumpi(%%return)
// first_nib_2 = (key_2 >> (bits_2 - 4)) & 0xF
DUP6 DUP6 %sub_const(4) SHR %and_const(0xF)
DUP6 PUSH 4 DUP7 SUB SHR %and_const(0xF)
// first_nib_1 = (key_1 >> (bits_1 - 4)) & 0xF
DUP5 DUP5 %sub_const(4) SHR %and_const(0xF)
DUP5 PUSH 4 DUP6 SUB SHR %and_const(0xF)
// stack: first_nib_1, first_nib_2, len_common, key_common, bits_1, key_1, bits_2, key_2
// if first_nib_1 != first_nib_2: break
@ -204,8 +204,8 @@
%pop2
%%return:
// stack: len_common, key_common, bits_1, key_1, bits_2, key_2
SWAP2 %div_const(4) SWAP2 // bits_1 -> len_1 (in nibbles)
SWAP4 %div_const(4) SWAP4 // bits_2 -> len_2 (in nibbles)
SWAP2 %shr_const(2) SWAP2 // bits_1 -> len_1 (in nibbles)
SWAP4 %shr_const(2) SWAP4 // bits_2 -> len_2 (in nibbles)
// stack: len_common, key_common, len_1, key_1, len_2, key_2
%endmacro

View File

@ -1,28 +1,20 @@
// RLP-encode a fixed-length 160 bit (20 byte) string. Assumes string < 2^160.
// Convenience macro to RLP-encode a fixed-length 160 bit (20 byte) string
// and return where we left off. Assumes string < 2^160.
// 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 (rlp_addr, string) -> (rlp_addr, string, %%after)
%jump(encode_rlp_160)
%stack (rlp_addr, string) -> (20, rlp_addr, string, %%after)
%jump(encode_rlp_fixed)
%%after:
%endmacro
// RLP-encode a fixed-length 256 bit (32 byte) string.
// Convenience macro to RLP-encode a fixed-length 256 bit (32 byte) string
// and return where we left off.
// 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 (rlp_addr, string) -> (rlp_addr, string, %%after)
%jump(encode_rlp_256)
%stack (rlp_addr, string) -> (32, rlp_addr, string, %%after)
%jump(encode_rlp_fixed)
%%after:
%endmacro

View File

@ -2,8 +2,8 @@
// its number of nibbles when required. Shouldn't be
// called with rlp_index > 0x82 ff ff
global increment_bounded_rlp:
// stack: rlp_index, num_nibbles, retdest
DUP1
// stack: num_nibbles, rlp_index, retdest
DUP2
%eq_const(0x80)
%jumpi(case_0x80)
DUP1
@ -14,19 +14,19 @@ global increment_bounded_rlp:
%jumpi(case_0x81ff)
// If rlp_index != 0x80 and rlp_index != 0x7f and rlp_index != 0x81ff
// we only need to add one and keep the number of nibbles
%increment
%stack (rlp_index, num_nibbles, retdest) -> (retdest, rlp_index, num_nibbles)
DUP2 %increment DUP2
%stack (next_num_nibbles, next_rlp_index, num_nibbles, rlp_index, retdest) -> (retdest, rlp_index, num_nibbles, next_rlp_index, next_num_nibbles)
JUMP
case_0x80:
%stack (rlp_index, num_nibbles, retdest) -> (retdest, 0x01, 2)
%stack (num_nibbles, rlp_index, retdest) -> (retdest, 0x80, 2, 0x01, 2)
JUMP
case_0x7f:
%stack (rlp_index, num_nibbles, retdest) -> (retdest, 0x8180, 4)
%stack (num_nibbles, rlp_index, retdest) -> (retdest, 0x7f, 2, 0x8180, 4)
JUMP
case_0x81ff:
%stack (rlp_index, num_nibbles, retdest) -> (retdest, 0x820100, 6)
%stack (num_nibbles, rlp_index, retdest) -> (retdest, 0x81ff, 4, 0x820100, 6)
JUMP

View File

@ -55,12 +55,10 @@ 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) -> (@SEGMENT_KERNEL_GENERAL, a, 32, %%after_mstore_a)
%jump(mstore_unpacking)
%%after_mstore_a:
%stack (addr, b) -> (addr, b, 32, %%after_mstore_b)
%jump(mstore_unpacking)
%%after_mstore_b:
%stack (a) -> (@SEGMENT_KERNEL_GENERAL, a)
MSTORE_32BYTES_32
// stack: addr, b
MSTORE_32BYTES_32
%stack (addr) -> (addr, 64, 64) // reset the address offset
SUB
KECCAK_GENERAL

View File

@ -5,60 +5,6 @@ use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::interpreter::Interpreter;
use crate::memory::segments::Segment;
#[test]
fn test_mload_packing_1_byte() -> Result<()> {
let mload_packing = KERNEL.global_labels["mload_packing"];
let retdest = 0xDEADBEEFu32.into();
let len = 1.into();
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]);
interpreter.run()?;
assert_eq!(interpreter.stack(), vec![0xAB.into()]);
Ok(())
}
#[test]
fn test_mload_packing_3_bytes() -> Result<()> {
let mload_packing = KERNEL.global_labels["mload_packing"];
let retdest = 0xDEADBEEFu32.into();
let len = 3.into();
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]);
interpreter.run()?;
assert_eq!(interpreter.stack(), vec![0xABCDEF.into()]);
Ok(())
}
#[test]
fn test_mload_packing_32_bytes() -> Result<()> {
let mload_packing = KERNEL.global_labels["mload_packing"];
let retdest = 0xDEADBEEFu32.into();
let len = 32.into();
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]);
interpreter.run()?;
assert_eq!(interpreter.stack(), vec![U256::MAX]);
Ok(())
}
#[test]
fn test_mstore_unpacking() -> Result<()> {
let mstore_unpacking = KERNEL.global_labels["mstore_unpacking"];

View File

@ -45,13 +45,13 @@ fn test_encode_rlp_scalar_medium() -> Result<()> {
#[test]
fn test_encode_rlp_160() -> Result<()> {
let encode_rlp_160 = KERNEL.global_labels["encode_rlp_160"];
let encode_rlp_fixed = KERNEL.global_labels["encode_rlp_fixed"];
let retdest = 0xDEADBEEFu32.into();
let string = 0x12345.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);
let initial_stack = vec![retdest, string, pos, U256::from(20)];
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_fixed, initial_stack);
interpreter.run()?;
let expected_stack = vec![pos + U256::from(1 + 20)]; // pos'
@ -65,13 +65,13 @@ fn test_encode_rlp_160() -> Result<()> {
#[test]
fn test_encode_rlp_256() -> Result<()> {
let encode_rlp_256 = KERNEL.global_labels["encode_rlp_256"];
let encode_rlp_fixed = KERNEL.global_labels["encode_rlp_fixed"];
let retdest = 0xDEADBEEFu32.into();
let string = 0x12345.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);
let initial_stack = vec![retdest, string, pos, U256::from(32)];
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_fixed, initial_stack);
interpreter.run()?;
let expected_stack = vec![pos + U256::from(1 + 32)]; // pos'