plonky2/evm/src/cpu/kernel/asm/rlp/encode.asm

271 lines
9.7 KiB
NASM
Raw Normal View History

2022-08-14 09:12:16 -07:00
// RLP-encode a fixed-length 160 bit (20 byte) string. Assumes string < 2^160.
// Pre stack: rlp_addr, string, retdest
// Post stack: rlp_addr
global encode_rlp_160:
2022-08-14 09:12:16 -07:00
PUSH 20
%jump(encode_rlp_fixed)
2022-08-14 09:12:16 -07:00
// 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)
2022-08-14 09:12:16 -07:00
%jump(encode_rlp_160)
%%after:
%endmacro
// RLP-encode a fixed-length 256 bit (32 byte) string.
// Pre stack: rlp_addr, string, retdest
// Post stack: rlp_addr
global encode_rlp_256:
2022-08-14 09:12:16 -07:00
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)
2022-08-14 09:12:16 -07:00
%jump(encode_rlp_256)
%%after:
%endmacro
// RLP-encode a fixed-length string with the given byte length. Assumes string < 2^(8 * len).
2023-04-03 21:35:08 -07:00
global encode_rlp_fixed:
// stack: len, rlp_addr, string, retdest
DUP2
DUP2
2022-08-14 09:12:16 -07:00
%add_const(0x80)
// stack: first_byte, rlp_addr, len, rlp_addr, string, retdest
MSTORE_GENERAL
// stack: len, rlp_addr, string, retdest
2022-08-14 09:12:16 -07:00
SWAP1
%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)
2022-08-14 09:12:16 -07:00
encode_rlp_fixed_finish:
// stack: rlp_addr', retdest
2022-08-14 09:12:16 -07:00
SWAP1
JUMP
2023-04-03 21:35:08 -07:00
// 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, rlp_addr, string, retdest
DUP2
DUP2
2023-04-03 21:35:08 -07:00
%add_const(0x81)
// stack: first_byte, rlp_addr, len, rlp_addr, string, retdest
MSTORE_GENERAL
// stack: len, rlp_addr, string, retdest
DUP2 %increment
DUP2
2023-04-03 21:35:08 -07:00
%add_const(0x80)
// stack: second_byte, rlp_addr', len, original_rlp_addr, string, retdest
MSTORE_GENERAL
// stack: len, rlp_addr, string, retdest
2023-04-03 21:35:08 -07:00
SWAP1
%add_const(2) // advance past the two prefix bytes
// 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)
2023-04-03 21:35:08 -07:00
2022-10-04 15:12:44 -07:00
// 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
// require access to the actual string, while this method only accesses its
// length. This method should generally be used only when we know a string
// contains at least two bytes.
//
// Pre stack: rlp_addr, str_len, retdest
// Post stack: rlp_addr'
2022-10-04 15:12:44 -07:00
global encode_rlp_multi_byte_string_prefix:
// stack: rlp_addr, str_len, retdest
2022-10-04 15:12:44 -07:00
DUP2 %gt_const(55)
// stack: str_len > 55, rlp_addr, str_len, retdest
2022-10-04 15:12:44 -07:00
%jumpi(encode_rlp_multi_byte_string_prefix_large)
// Medium case; prefix is 0x80 + str_len.
// stack: rlp_addr, str_len, retdest
DUP1
SWAP2 %add_const(0x80)
// stack: prefix, rlp_addr, rlp_addr, retdest
MSTORE_GENERAL
// stack: rlp_addr, retdest
2022-10-04 15:12:44 -07:00
%increment
// stack: rlp_addr', retdest
2022-10-04 15:12:44 -07:00
SWAP1
JUMP
encode_rlp_multi_byte_string_prefix_large:
// Large case; prefix is 0xb7 + len_of_len, followed by str_len.
// stack: rlp_addr, str_len, retdest
2022-10-04 15:12:44 -07:00
DUP2
%num_bytes
// stack: len_of_len, rlp_addr, str_len, retdest
2022-10-04 15:12:44 -07:00
SWAP1
DUP1 // rlp_addr
DUP3 // len_of_len
2022-10-04 15:12:44 -07:00
%add_const(0xb7)
// stack: first_byte, rlp_addr, rlp_addr, len_of_len, str_len, retdest
MSTORE_GENERAL
// stack: rlp_addr, len_of_len, str_len, retdest
2022-10-04 15:12:44 -07:00
%increment
// 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)
2022-10-04 15:12:44 -07:00
%macro encode_rlp_multi_byte_string_prefix
%stack (rlp_addr, str_len) -> (rlp_addr, str_len, %%after)
2022-10-04 15:12:44 -07:00
%jump(encode_rlp_multi_byte_string_prefix)
%%after:
%endmacro
// Writes the RLP prefix for a list with the given payload length.
//
// Pre stack: rlp_addr, payload_len, retdest
// Post stack: rlp_addr'
2022-10-01 21:55:47 -07:00
global encode_rlp_list_prefix:
// stack: rlp_addr, payload_len, retdest
2022-10-01 21:55:47 -07:00
DUP2 %gt_const(55)
%jumpi(encode_rlp_list_prefix_large)
// Small case: prefix is just 0xc0 + length.
// stack: rlp_addr, payload_len, retdest
DUP1
SWAP2
2022-10-01 21:55:47 -07:00
%add_const(0xc0)
// stack: prefix, rlp_addr, rlp_addr, retdest
MSTORE_GENERAL
// stack: rlp_addr, retdest
%increment
2022-10-01 21:55:47 -07:00
SWAP1
JUMP
encode_rlp_list_prefix_large:
// Write 0xf7 + len_of_len.
// stack: rlp_addr, payload_len, retdest
2022-10-01 21:55:47 -07:00
DUP2 %num_bytes
// stack: len_of_len, rlp_addr, payload_len, retdest
DUP2
DUP2 %add_const(0xf7)
// stack: first_byte, rlp_addr, len_of_len, rlp_addr, payload_len, retdest
MSTORE_GENERAL
// stack: len_of_len, rlp_addr, payload_len, retdest
SWAP1 %increment
// stack: rlp_addr', len_of_len, payload_len, retdest
%stack (rlp_addr, len_of_len, payload_len)
-> (rlp_addr, payload_len, len_of_len,
2022-10-04 15:12:44 -07:00
encode_rlp_list_prefix_large_done_writing_len)
%jump(mstore_unpacking)
2022-10-01 21:55:47 -07:00
encode_rlp_list_prefix_large_done_writing_len:
// stack: rlp_addr'', retdest
2022-10-01 21:55:47 -07:00
SWAP1
JUMP
%macro encode_rlp_list_prefix
%stack (rlp_addr, payload_len) -> (rlp_addr, payload_len, %%after)
2022-10-01 21:55:47 -07:00
%jump(encode_rlp_list_prefix)
%%after:
%endmacro
// 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,
2023-03-18 09:29:31 -07:00
// as well as the length of the RLP data (including the newly-added prefix).
2022-10-01 10:33:05 -07:00
//
// Pre stack: end_rlp_addr, start_rlp_addr, retdest
// Post stack: prefix_start_rlp_addr, rlp_len
2022-10-01 10:33:05 -07:00
global prepend_rlp_list_prefix:
// 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
2022-10-01 10:33:05 -07:00
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 rlp_address 8.
// stack: payload_len, end_rlp_addr, start_rlp_addr, retdest
DUP3 %decrement // offset of prefix
DUP2 %add_const(0xc0)
// stack: prefix_byte, start_rlp_addr-1, payload_len, end_rlp_addr, start_rlp_addr, retdest
MSTORE_GENERAL
// stack: payload_len, end_rlp_addr, start_rlp_addr, retdest
2023-03-18 09:29:31 -07:00
%increment
// stack: rlp_len, end_rlp_addr, start_rlp_addr, retdest
2023-03-18 09:29:31 -07:00
SWAP2 %decrement
// 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)
2022-10-01 10:33:05 -07:00
JUMP
prepend_rlp_list_prefix_big:
// 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
2023-03-18 09:29:31 -07:00
// followed by the length itself.
// stack: payload_len, end_rlp_addr, start_rlp_addr, retdest
2022-10-01 10:33:05 -07:00
DUP1 %num_bytes
// stack: len_of_len, payload_len, end_rlp_addr, start_rlp_addr, retdest
2022-10-01 10:33:05 -07:00
DUP1
DUP5 %decrement // start_rlp_addr - 1
2022-10-01 10:33:05 -07:00
SUB
// stack: prefix_start_rlp_addr, len_of_len, payload_len, end_rlp_addr, start_rlp_addr, retdest
DUP2 %add_const(0xf7) DUP2 %swap_mstore // 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,
2022-10-01 10:33:05 -07:00
prepend_rlp_list_prefix_big_done_writing_len,
prefix_start_rlp_addr, end_rlp_addr, retdest)
%jump(mstore_unpacking)
2022-10-01 10:33:05 -07:00
prepend_rlp_list_prefix_big_done_writing_len:
// 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
2022-10-01 10:33:05 -07:00
SUB
// stack: rlp_len, prefix_start_rlp_addr, retdest
%stack (rlp_len, prefix_start_rlp_addr, retdest) -> (retdest, prefix_start_rlp_addr, rlp_len)
2022-10-01 10:33:05 -07:00
JUMP
// Convenience macro to call prepend_rlp_list_prefix and return where we left off.
%macro prepend_rlp_list_prefix
%stack (end_rlp_addr, start_rlp_addr) -> (end_rlp_addr, start_rlp_addr, %%after)
2022-10-01 10:33:05 -07:00
%jump(prepend_rlp_list_prefix)
%%after:
%endmacro
2022-10-01 21:55:47 -07:00
// Given some scalar, compute the number of bytes used in its RLP encoding,
// including any length prefix.
2022-10-04 15:12:44 -07:00
%macro rlp_scalar_len
2022-10-01 21:55:47 -07:00
// stack: scalar
// Since the scalar fits in a word, we can't hit the large (>55 byte)
// case, so we just check for small vs medium.
DUP1 %gt_const(0x7f)
// stack: is_medium, scalar
%jumpi(%%medium)
// Small case; result is 1.
%stack (scalar) -> (1)
2022-10-04 15:12:44 -07:00
%jump(%%finish)
2022-10-01 21:55:47 -07:00
%%medium:
// stack: scalar
%num_bytes
// stack: scalar_bytes
%increment // Account for the length prefix.
2022-10-01 21:55:47 -07:00
// stack: rlp_len
2022-10-04 15:12:44 -07:00
%%finish:
%endmacro
// Given some list with the given payload length, compute the number of bytes
// used in its RLP encoding, including the list prefix.
%macro rlp_list_len
// stack: payload_len
DUP1 %gt_const(55)
// stack: is_large, payload_len
%jumpi(%%large)
// Small case; prefix is a single byte.
%increment
// stack: 1 + payload_len
%jump(%%finish)
%%large:
// Prefix is 1 byte containing len_of_len, followed by len_of_len bytes containing len.
// stack: payload_len
DUP1 %num_bytes
// stack: len_of_len, payload_len
%increment
// stack: prefix_len, payload_len
ADD
%%finish:
2022-10-01 21:55:47 -07:00
%endmacro