237 lines
7.8 KiB
NASM
Raw Normal View History

%macro mload_trie_data
// stack: virtual
%mload_kernel(@SEGMENT_TRIE_DATA)
// stack: value
%endmacro
%macro mstore_trie_data
// stack: virtual, value
%mstore_kernel(@SEGMENT_TRIE_DATA)
// stack: (empty)
%endmacro
2022-09-22 20:09:48 -07:00
%macro initialize_rlp_segment
// Write the encoding of the empty node to address 0 leaving 9 bytes for a prefix
// TODO: Do we need a prefix?
PUSH 0x80
PUSH 0x1000
%mstore_rlp
PUSH 0x1000 // TODO: use 10?
%mstore_global_metadata(@GLOBAL_METADATA_RLP_DATA_SIZE)
%endmacro
2023-03-18 09:29:31 -07:00
%macro alloc_rlp_block
// stack: (empty)
%mload_global_metadata(@GLOBAL_METADATA_RLP_DATA_SIZE)
// stack: block_start
// In our model it's fine to use memory in a sparse way, as long as the gaps aren't larger than
// 2^16 or so. So instead of the caller specifying the size of the block they need, we'll just
// allocate 0x10000 = 2^16 bytes, much larger than any RLP blob the EVM could possibly create.
DUP1 %add_const(0x10000)
// stack: block_end, block_start
%mstore_global_metadata(@GLOBAL_METADATA_RLP_DATA_SIZE)
// stack: block_start
// We leave an extra 9 bytes, so that callers can later prepend a prefix before block_start.
// (9 is the length of the longest possible RLP list prefix.)
%add_const(9)
// stack: block_start
%endmacro
2022-09-22 20:09:48 -07:00
%macro get_trie_data_size
// stack: (empty)
%mload_global_metadata(@GLOBAL_METADATA_TRIE_DATA_SIZE)
// stack: trie_data_size
%endmacro
%macro set_trie_data_size
// stack: trie_data_size
%mstore_global_metadata(@GLOBAL_METADATA_TRIE_DATA_SIZE)
// stack: (empty)
%endmacro
// Equivalent to: trie_data[trie_data_size++] = value
%macro append_to_trie_data
// stack: value
%get_trie_data_size
// stack: trie_data_size, value
DUP1
%increment
2022-09-22 20:09:48 -07:00
// stack: trie_data_size', trie_data_size, value
%set_trie_data_size
// stack: trie_data_size, value
%mstore_trie_data
// stack: (empty)
%endmacro
2022-09-24 22:23:24 -07:00
// Split off the first nibble from a key part. Roughly equivalent to
// def split_first_nibble(num_nibbles, key):
// num_nibbles -= 1
// num_nibbles_x4 = num_nibbles * 4
// first_nibble = (key >> num_nibbles_x4) & 0xF
// key -= (first_nibble << num_nibbles_x4)
// return (first_nibble, num_nibbles, key)
%macro split_first_nibble
// stack: num_nibbles, key
%decrement // num_nibbles -= 1
2022-09-24 22:23:24 -07:00
// stack: num_nibbles, key
DUP2
// stack: key, num_nibbles, key
DUP2 %mul_const(4)
// stack: num_nibbles_x4, key, num_nibbles, key
SHR
// stack: key >> num_nibbles_x4, num_nibbles, key
%and_const(0xF)
// stack: first_nibble, num_nibbles, key
DUP1
// stack: first_nibble, first_nibble, num_nibbles, key
DUP3 %mul_const(4)
// stack: num_nibbles_x4, first_nibble, first_nibble, num_nibbles, key
SHL
// stack: first_nibble << num_nibbles_x4, first_nibble, num_nibbles, key
DUP1
// stack: junk, first_nibble << num_nibbles_x4, first_nibble, num_nibbles, key
SWAP4
// stack: key, first_nibble << num_nibbles_x4, first_nibble, num_nibbles, junk
SUB
// stack: key, first_nibble, num_nibbles, junk
SWAP3
// stack: junk, first_nibble, num_nibbles, key
POP
// stack: first_nibble, num_nibbles, key
%endmacro
2022-10-09 11:32:01 -07:00
// Remove the first `k` nibbles from a key part.
// def truncate_nibbles(k, num_nibbles, key):
// num_nibbles -= k
// num_nibbles_x4 = num_nibbles * 4
// lead_nibbles = key >> num_nibbles_x4
// key -= (lead_nibbles << num_nibbles_x4)
// return (num_nibbles, key)
%macro truncate_nibbles
// stack: k, num_nibbles, key
SWAP1 SUB
// stack: num_nibbles, key
DUP1 %mul_const(4)
%stack (num_nibbles_x4, num_nibbles, key) -> (num_nibbles_x4, key, num_nibbles_x4, num_nibbles, key)
SHR
%stack (lead_nibbles, num_nibbles_x4, num_nibbles, key) -> (num_nibbles_x4, lead_nibbles, key, num_nibbles)
SHL SWAP1 SUB
// stack: key, num_nibbles
SWAP1
%endmacro
2022-10-09 21:37:46 -07:00
// Split off the common prefix among two key parts.
//
// Pre stack: len_1, key_1, len_2, key_2
// Post stack: len_common, key_common, len_1, key_1, len_2, key_2
//
// Roughly equivalent to
2022-10-09 11:32:01 -07:00
// def split_common_prefix(len_1, key_1, len_2, key_2):
// bits_1 = len_1 * 4
// bits_2 = len_2 * 4
// len_common = 0
// key_common = 0
// while True:
// if bits_1 * bits_2 == 0:
// break
// first_nib_1 = (key_1 >> (bits_1 - 4)) & 0xF
// first_nib_2 = (key_2 >> (bits_2 - 4)) & 0xF
// if first_nib_1 != first_nib_2:
// break
// len_common += 1
// key_common = key_common * 16 + first_nib_1
// bits_1 -= 4
// bits_2 -= 4
// key_1 -= (first_nib_1 << bits_1)
// key_2 -= (first_nib_2 << bits_2)
// len_1 = bits_1 // 4
// len_2 = bits_2 // 4
// return (len_common, key_common, len_1, key_1, len_2, key_2)
%macro split_common_prefix
// stack: len_1, key_1, len_2, key_2
%mul_const(4)
SWAP2 %mul_const(4) SWAP2
// stack: bits_1, key_1, bits_2, key_2
PUSH 0
PUSH 0
%%loop:
// stack: len_common, key_common, bits_1, key_1, bits_2, key_2
// if bits_1 * bits_2 == 0: break
DUP3 DUP6 MUL ISZERO %jumpi(%%return)
// first_nib_2 = (key_2 >> (bits_2 - 4)) & 0xF
DUP6 DUP6 %sub_const(4) SHR %and_const(0xF)
// first_nib_1 = (key_1 >> (bits_1 - 4)) & 0xF
DUP5 DUP5 %sub_const(4) 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
DUP2 DUP2 SUB %jumpi(%%return_with_first_nibs)
// len_common += 1
SWAP2 %increment SWAP2
// key_common = key_common * 16 + first_nib_1
SWAP3
%mul_const(16)
DUP4 ADD
SWAP3
// stack: first_nib_1, first_nib_2, len_common, key_common, bits_1, key_1, bits_2, key_2
// bits_1 -= 4
SWAP4 %sub_const(4) SWAP4
// bits_2 -= 4
SWAP6 %sub_const(4) SWAP6
// stack: first_nib_1, first_nib_2, len_common, key_common, bits_1, key_1, bits_2, key_2
// key_1 -= (first_nib_1 << bits_1)
DUP5 SHL
// stack: first_nib_1 << bits_1, first_nib_2, len_common, key_common, bits_1, key_1, bits_2, key_2
DUP6 SUB
// stack: key_1, first_nib_2, len_common, key_common, bits_1, key_1_old, bits_2, key_2
SWAP5 POP
// stack: first_nib_2, len_common, key_common, bits_1, key_1, bits_2, key_2
// key_2 -= (first_nib_2 << bits_2)
DUP6 SHL
// stack: first_nib_2 << bits_2, len_common, key_common, bits_1, key_1, bits_2, key_2
DUP7 SUB
// stack: key_2, len_common, key_common, bits_1, key_1, bits_2, key_2_old
SWAP6 POP
// stack: len_common, key_common, bits_1, key_1, bits_2, key_2
%jump(%%loop)
%%return_with_first_nibs:
// stack: first_nib_1, first_nib_2, len_common, key_common, bits_1, key_1, bits_2, key_2
%pop2
%%return:
2022-10-09 21:37:46 -07:00
// 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)
2022-10-09 11:32:01 -07:00
// stack: len_common, key_common, len_1, key_1, len_2, key_2
%endmacro
2022-10-17 11:31:08 -07:00
// Remove the first `k` nibbles from a key part.
// def merge_nibbles(front_len, front_key, back_len, back_key):
// return (front_len + back_len, (front_key<<(back_len*4)) + back_key)
%macro merge_nibbles
// stack: front_len, front_key, back_len, back_key
%stack (front_len, front_key, back_len, back_key) -> (back_len, front_key, back_key, back_len, front_len)
%mul_const(4) SHL ADD
// stack: new_key, back_len, front_len
SWAP2 ADD
%endmacro
2022-10-17 11:31:08 -07:00
// Computes state_key = Keccak256(addr). Clobbers @SEGMENT_KERNEL_GENERAL.
%macro addr_to_state_key
%keccak256_word(20)
%endmacro
// Given a storage slot (a 256-bit integer), computes storage_key = Keccak256(slot).
// Clobbers @SEGMENT_KERNEL_GENERAL.
%macro slot_to_storage_key
%keccak256_word(32)
%endmacro