Skip to content

Commit

Permalink
Reuse txn rlp (#547)
Browse files Browse the repository at this point in the history
* Reuse RLP for txn signature checking

* Apply comment

* Change comments
  • Loading branch information
hratoanina authored Aug 26, 2024
1 parent 9529cf8 commit 4ac1f5d
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 283 deletions.
98 changes: 32 additions & 66 deletions evm_arithmetization/src/cpu/kernel/asm/transactions/type_0.asm
Original file line number Diff line number Diff line change
Expand Up @@ -18,131 +18,97 @@ global process_type_0_txn:
%stack (rlp_addr, len) -> (rlp_addr)

// stack: rlp_addr, retdest
// Keep track of the nonce position.
DUP1
// stack: rlp_addr, nonce_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: rlp_addr, retdest
// stack: rlp_addr, nonce_addr, retdest
DUP1

// Parse the "v" field.
// stack: rlp_addr, retdest
// stack: rlp_addr, after_data_addr, nonce_addr, retdest
%decode_rlp_scalar
// stack: rlp_addr, v, retdest
// stack: rlp_addr, v, after_data_addr, nonce_addr, retdest
SWAP1
// stack: v, rlp_addr, retdest
// stack: v, rlp_addr, after_data_addr, nonce_addr, retdest
DUP1
%gt_const(28)
// stack: v > 28, v, rlp_addr, retdest
// stack: v > 28, v, rlp_addr, after_data_addr, nonce_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, rlp_addr, retdest
// stack: v, rlp_addr, after_data_addr, nonce_addr, retdest
%sub_const(27)
%stack (y_parity, rlp_addr) -> (y_parity, rlp_addr)
%mstore_txn_field(@TXN_FIELD_Y_PARITY)

// stack: rlp_addr, retdest
// stack: rlp_addr, after_data_addr, nonce_addr, retdest
%jump(decode_r_and_s)

process_v_new_style:
// stack: v, rlp_addr, retdest
// stack: v, rlp_addr, after_data_addr, nonce_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, rlp_addr) -> (1, v, rlp_addr)
%mstore_txn_field(@TXN_FIELD_CHAIN_ID_PRESENT)

// stack: v, rlp_addr, retdest
// stack: v, rlp_addr, after_data_addr, nonce_addr, retdest
%sub_const(35)
DUP1
// stack: v - 35, v - 35, rlp_addr, retdest
// stack: v - 35, v - 35, rlp_addr, after_data_addr, nonce_addr, retdest
%div2
// stack: chain_id, v - 35, rlp_addr, retdest
// stack: chain_id, v - 35, rlp_addr, after_data_addr, nonce_addr, retdest
%mstore_txn_field(@TXN_FIELD_CHAIN_ID)

// stack: v - 35, rlp_addr, retdest
// stack: v - 35, rlp_addr, after_data_addr, nonce_addr, retdest
%mod_const(2)
// stack: y_parity, rlp_addr, retdest
// stack: y_parity, rlp_addr, after_data_addr, nonce_addr, retdest
%mstore_txn_field(@TXN_FIELD_Y_PARITY)

decode_r_and_s:
// stack: rlp_addr, retdest
// stack: rlp_addr, after_data_addr, nonce_addr, retdest
%decode_and_store_r
%decode_and_store_s
// stack: rlp_addr, retdest
// stack: rlp_addr, after_data_addr, nonce_addr, retdest
POP
// stack: retdest
// stack: after_data_addr, nonce_addr, retdest

type_0_compute_signed_data:
// If a chain_id is present in v, the signed data is
// keccak256(rlp([nonce, gas_price, gas_limit, to, value, data, chain_id, 0, 0]))
// otherwise, it is
// keccak256(rlp([nonce, gas_price, gas_limit, to, value, data]))
// We know that [nonce, gas_price, gas_limit, to, value, data] is already encoded
// at `nonce_addr`.

%alloc_rlp_block
// stack: rlp_addr_start, retdest
%mload_txn_field(@TXN_FIELD_NONCE)
// stack: nonce, rlp_addr_start, retdest
DUP2
// stack: rlp_addr, nonce, rlp_addr_start, retdest
%encode_rlp_scalar
// stack: rlp_addr, rlp_addr_start, retdest

%mload_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest

%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
%encode_rlp_scalar_swapped_inputs
// 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_addr, rlp_addr_start, retdest
SWAP1 %encode_rlp_160
%jump(after_to)
zero_to:
// stack: to, rlp_addr, rlp_addr_start, retdest
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest

after_to:
%mload_txn_field(@TXN_FIELD_VALUE)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest

// Encode txn data.
%mload_txn_field(@TXN_FIELD_DATA_LEN)
PUSH @SEGMENT_TXN_DATA
// stack: ADDR, len, rlp_addr, rlp_addr_start, retdest
PUSH after_serializing_txn_data
// 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_addr, rlp_addr_start, retdest
// If there is a `chain_id`, we append it at the end. This will overwrite `v`, `r` and `s`
// but the transaction has already been inserted in the MPT so it's not an issue.
// stack: after_data_addr, nonce_addr, retdest
%mload_txn_field(@TXN_FIELD_CHAIN_ID_PRESENT)
ISZERO %jumpi(finish_rlp_list)
// stack: rlp_addr, rlp_addr_start, retdest

// stack: after_data_addr, nonce_addr, retdest
%mload_txn_field(@TXN_FIELD_CHAIN_ID)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest
// stack: rlp_signed_end_addr, nonce_addr, retdest

PUSH 0
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest
// stack: rlp_signed_end_addr, rlp_addr_start, retdest

PUSH 0
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest
// stack: rlp_signed_end_addr, rlp_addr_start, retdest

finish_rlp_list:
// stack: rlp_signed_end_addr, rlp_addr_start, retdest
// We will overwrite the original transaction RLP prefix. This is fine since we don't need the
// original encoding anymore.
%prepend_rlp_list_prefix
// stack: ADDR, rlp_len, retdest
KECCAK_GENERAL
Expand Down
77 changes: 13 additions & 64 deletions evm_arithmetization/src/cpu/kernel/asm/transactions/type_1.asm
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ global process_type_1_txn:
%stack (rlp_addr, len) -> (rlp_addr)

%store_chain_id_present_true
// stack: rlp_addr, retdest
// Keep track of the chain id position.
DUP1
// stack: rlp_addr, chain_id_addr, retdest
%decode_and_store_chain_id
%decode_and_store_nonce
%decode_and_store_gas_price_legacy
Expand All @@ -24,80 +28,25 @@ global process_type_1_txn:
%decode_and_store_value
%decode_and_store_data
%decode_and_store_access_list
// stack: rlp_addr, chain_id_addr, retdest
DUP1
// stack: rlp_addr, after_access_list_addr, chain_id_addr, retdest
%decode_and_store_y_parity
%decode_and_store_r
%decode_and_store_s

// stack: rlp_addr, retdest
// stack: rlp_addr, after_access_list_addr, chain_id_addr, retdest
POP
// stack: retdest
// stack: after_access_list_addr, chain_id_addr, retdest

// From EIP-2930:
// The signatureYParity, signatureR, signatureS elements of this transaction represent a secp256k1 signature
// over keccak256(0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList])).
// We know that [chainId, nonce, gasPrice, gasLimit, to, value, data, accessList] is already encoded
// at `chain_id_addr`; we just need to overwrite the existing RLP prefix. This is fine since we don't
// need the original encoding anymore.
type_1_compute_signed_data:
%alloc_rlp_block
// stack: rlp_addr_start, retdest
%mload_txn_field(@TXN_FIELD_CHAIN_ID)
// stack: chain_id, rlp_addr_start, retdest
DUP2
// stack: rlp_addr, chain_id, rlp_addr_start, retdest
%encode_rlp_scalar
// stack: rlp_addr, rlp_addr_start, retdest

%mload_txn_field(@TXN_FIELD_NONCE)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest

%mload_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest

%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
%encode_rlp_scalar_swapped_inputs
// 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_addr, rlp_addr_start, retdest
SWAP1 %encode_rlp_160
%jump(after_to)
zero_to:
// stack: to, rlp_addr, rlp_addr_start, retdest
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest

after_to:
%mload_txn_field(@TXN_FIELD_VALUE)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_addr_start, retdest

// Encode txn data.
%mload_txn_field(@TXN_FIELD_DATA_LEN)
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, 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_addr, rlp_addr_start, retdest) ->
(
rlp_addr,
al_start,
al_len,
after_serializing_access_list,
rlp_addr, rlp_addr_start, retdest)
%jump(memcpy_bytes)
after_serializing_access_list:
// stack: rlp_addr, rlp_addr_start, retdest
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN) ADD
// stack: rlp_addr, rlp_addr_start, retdest
// stack: after_access_list_addr, chain_id_addr, retdest
%prepend_rlp_list_prefix
// stack: prefix_start_rlp_addr, rlp_len, retdest

Expand Down
83 changes: 14 additions & 69 deletions evm_arithmetization/src/cpu/kernel/asm/transactions/type_2.asm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ global process_type_2_txn:

// stack: rlp_addr, retdest
%store_chain_id_present_true
// stack: rlp_addr, retdest
// Keep track of the chain id position.
DUP1
// stack: rlp_addr, chain_id_addr, retdest
%decode_and_store_chain_id
%decode_and_store_nonce
%decode_and_store_max_priority_fee
Expand All @@ -27,84 +31,25 @@ global process_type_2_txn:
%decode_and_store_value
%decode_and_store_data
%decode_and_store_access_list
// stack: rlp_addr, chain_id_addr, retdest
DUP1
// stack: rlp_addr, after_access_list_addr, chain_id_addr, retdest
%decode_and_store_y_parity
%decode_and_store_r
%decode_and_store_s

// stack: rlp_addr, retdest
// stack: rlp_addr, after_access_list_addr, chain_id_addr, retdest
POP
// stack: retdest
// stack: after_access_list_addr, chain_id_addr, retdest

// From EIP-1559:
// The signature_y_parity, signature_r, signature_s elements of this transaction represent a secp256k1 signature over
// keccak256(0x02 || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list]))
// keccak256(0x02 || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list])).
// We know that [chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list] is already encoded
// at `chain_id_addr`; we just need to overwrite the existing RLP prefix. This is fine since we don't
// need the original encoding anymore.
type_2_compute_signed_data:
%alloc_rlp_block
// stack: rlp_addr_start, retdest
%mload_txn_field(@TXN_FIELD_CHAIN_ID)
// stack: chain_id, rlp_start, retdest
DUP2
// stack: rlp_addr, chain_id, rlp_start, retdest
%encode_rlp_scalar
// stack: rlp_addr, rlp_start, retdest

%mload_txn_field(@TXN_FIELD_NONCE)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_start, retdest

%mload_txn_field(@TXN_FIELD_MAX_PRIORITY_FEE_PER_GAS)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_start, retdest

%mload_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_start, retdest

%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
%encode_rlp_scalar_swapped_inputs
// 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_addr, rlp_start, retdest
SWAP1 %encode_rlp_160
%jump(after_to)
zero_to:
// stack: to, rlp_addr, rlp_start, retdest
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_start, retdest

after_to:
%mload_txn_field(@TXN_FIELD_VALUE)
%encode_rlp_scalar_swapped_inputs
// stack: rlp_addr, rlp_start, retdest

// Encode txn data.
%mload_txn_field(@TXN_FIELD_DATA_LEN)
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, 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_addr, rlp_start, retdest) ->
(
rlp_addr,
al_start,
al_len,
after_serializing_access_list,
rlp_addr, rlp_start, retdest)
%jump(memcpy_bytes)
after_serializing_access_list:
// stack: rlp_addr, rlp_start, retdest
%mload_global_metadata(@GLOBAL_METADATA_ACCESS_LIST_RLP_LEN) ADD
// stack: rlp_addr, rlp_start, retdest
// stack: after_access_list_addr, chain_id_addr, retdest
%prepend_rlp_list_prefix
// stack: prefix_start_pos, rlp_len, retdest

Expand Down
Loading

0 comments on commit 4ac1f5d

Please sign in to comment.