diff --git a/evm_arithmetization/src/cpu/kernel/asm/transactions/type_0.asm b/evm_arithmetization/src/cpu/kernel/asm/transactions/type_0.asm index d0d68b57d..5907cc24b 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/transactions/type_0.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/transactions/type_0.asm @@ -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 diff --git a/evm_arithmetization/src/cpu/kernel/asm/transactions/type_1.asm b/evm_arithmetization/src/cpu/kernel/asm/transactions/type_1.asm index 3b386ce6f..e98b3fa40 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/transactions/type_1.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/transactions/type_1.asm @@ -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 @@ -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 diff --git a/evm_arithmetization/src/cpu/kernel/asm/transactions/type_2.asm b/evm_arithmetization/src/cpu/kernel/asm/transactions/type_2.asm index 150ebac7e..5fbea33c1 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/transactions/type_2.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/transactions/type_2.asm @@ -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 @@ -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 diff --git a/evm_arithmetization/src/cpu/kernel/asm/transactions/type_3.asm b/evm_arithmetization/src/cpu/kernel/asm/transactions/type_3.asm index 5899e2cb9..fb551fb76 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/transactions/type_3.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/transactions/type_3.asm @@ -17,6 +17,10 @@ global process_type_3_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 @@ -28,100 +32,24 @@ global process_type_3_txn: %decode_and_store_access_list %decode_and_store_max_fee_per_blob_gas %decode_and_store_blob_versioned_hashes + // stack: rlp_addr, chain_id_addr, retdest + DUP1 + // stack: rlp_addr, after_blob_hashes_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_blob_hashes_addr, chain_id_addr, retdest POP - // stack: retdest + // stack: after_blob_hashes_addr, chain_id_addr, retdest // From EIP-4844: // The signature_y_parity, signature_r, signature_s elements of this transaction represent a secp256k1 signature over // keccak256(0x03 || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_blob_gas, blob_versioned_hashes])) +// We know that [chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_blob_gas, blob_versioned_hashes] 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_3_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 - - // As per EIP-4844, blob transactions cannot have the form of a create transaction. - %mload_txn_field(@TXN_FIELD_TO) - %mload_global_metadata(@GLOBAL_METADATA_CONTRACT_CREATION) %jumpi(panic) - // stack: to, rlp_addr, rlp_start, retdest - SWAP1 %encode_rlp_160 - // stack: rlp_addr, rlp_start, retdest - - %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 - - %mload_txn_field(@TXN_FIELD_MAX_FEE_PER_BLOB_GAS) - %encode_rlp_scalar_swapped_inputs - // stack: rlp_addr, rlp_start, retdest - - // Instead of manually encoding the blob versioned hashes, we just copy the raw RLP from the transaction. - %mload_global_metadata(@GLOBAL_METADATA_BLOB_VERSIONED_HASHES_RLP_START) - %mload_global_metadata(@GLOBAL_METADATA_BLOB_VERSIONED_HASHES_RLP_LEN) - %stack (bvh_len, bvh_start, rlp_addr, rlp_start, retdest) -> - ( - rlp_addr, - bvh_start, - bvh_len, - after_serializing_blob_versioned_hashes, - rlp_addr, rlp_start, retdest) - %jump(memcpy_bytes) -after_serializing_blob_versioned_hashes: - // stack: rlp_addr, rlp_start, retdest - %mload_global_metadata(@GLOBAL_METADATA_BLOB_VERSIONED_HASHES_RLP_LEN) ADD - // stack: rlp_addr, rlp_start, retdest + // stack: after_blob_hashes_addr, chain_id_addr, retdest %prepend_rlp_list_prefix // stack: prefix_start_pos, rlp_len, retdest