Merge pull request #956 from mir-protocol/doubly_encode_storage_values

Doubly RLP-encode storage values
This commit is contained in:
Daniel Lubarov 2023-04-04 07:40:11 -07:00 committed by GitHub
commit 9690b60b80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 131 additions and 61 deletions

View File

@ -109,6 +109,7 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/mpt/util.asm"),
include_str!("asm/rlp/decode.asm"),
include_str!("asm/rlp/encode.asm"),
include_str!("asm/rlp/encode_rlp_scalar.asm"),
include_str!("asm/rlp/encode_rlp_string.asm"),
include_str!("asm/rlp/num_bytes.asm"),
include_str!("asm/rlp/read_to_memory.asm"),

View File

@ -19,7 +19,7 @@ global mpt_hash_storage_trie:
%jump(mpt_hash)
%macro mpt_hash_storage_trie
PUSH %%after
%stack (node_ptr) -> (node_ptr, %%after)
%jump(mpt_hash_storage_trie)
%%after:
%endmacro
@ -83,12 +83,9 @@ global encode_account:
// stack: balance, rlp_pos_4, value_ptr, retdest
SWAP1 %encode_rlp_scalar
// stack: rlp_pos_5, value_ptr, retdest
PUSH encode_account_after_hash_storage_trie
PUSH encode_storage_value
DUP4 %add_const(2) %mload_trie_data // storage_root_ptr = value[2]
// stack: storage_root_ptr, encode_storage_value, encode_account_after_hash_storage_trie, rlp_pos_5, value_ptr, retdest
%jump(mpt_hash)
encode_account_after_hash_storage_trie:
DUP2 %add_const(2) %mload_trie_data // storage_root_ptr = value[2]
// stack: storage_root_ptr, rlp_pos_5, value_ptr, retdest
%mpt_hash_storage_trie
// stack: storage_root_digest, rlp_pos_5, value_ptr, retdest
SWAP1 %encode_rlp_256
// stack: rlp_pos_6, value_ptr, retdest
@ -113,7 +110,7 @@ global encode_storage_value:
// which seems to imply that this should be %encode_rlp_256. But %encode_rlp_scalar
// causes the tests to pass, so it seems storage values should be treated as variable-
// length after all.
%encode_rlp_scalar
%doubly_encode_rlp_scalar
// stack: rlp_pos', retdest
SWAP1
JUMP

View File

@ -1,55 +1,3 @@
// RLP-encode a scalar, i.e. a variable-length integer.
// Pre stack: pos, scalar, retdest
// Post stack: pos
global encode_rlp_scalar:
// stack: pos, scalar, retdest
// If scalar > 0x7f, this is the "medium" case.
DUP2
%gt_const(0x7f)
%jumpi(encode_rlp_scalar_medium)
// Else, if scalar != 0, this is the "small" case, where the value is its own encoding.
DUP2 %jumpi(encode_rlp_scalar_small)
// scalar = 0, so BE(scalar) is the empty string, which RLP encodes as a single byte 0x80.
// stack: pos, scalar, retdest
%stack (pos, scalar) -> (pos, 0x80, pos)
%mstore_rlp
// stack: pos, retdest
%increment
// stack: pos', retdest
SWAP1
JUMP
encode_rlp_scalar_small:
// stack: pos, scalar, retdest
%stack (pos, scalar) -> (pos, scalar, pos)
// stack: pos, scalar, pos, retdest
%mstore_rlp
// stack: pos, retdest
%increment
// stack: pos', retdest
SWAP1
JUMP
encode_rlp_scalar_medium:
// This is the "medium" case, where we write 0x80 + len followed by the
// (big-endian) scalar bytes. We first compute the minimal number of bytes
// needed to represent this scalar, then treat it as if it was a fixed-
// length string with that length.
// stack: pos, scalar, retdest
DUP2
%num_bytes
// stack: scalar_bytes, pos, scalar, retdest
%jump(encode_rlp_fixed)
// Convenience macro to call encode_rlp_scalar and return where we left off.
%macro encode_rlp_scalar
%stack (pos, scalar) -> (pos, scalar, %%after)
%jump(encode_rlp_scalar)
%%after:
%endmacro
// RLP-encode a fixed-length 160 bit (20 byte) string. Assumes string < 2^160.
// Pre stack: pos, string, retdest
// Post stack: pos
@ -79,7 +27,7 @@ global encode_rlp_256:
%endmacro
// RLP-encode a fixed-length string with the given byte length. Assumes string < 2^(8 * len).
encode_rlp_fixed:
global encode_rlp_fixed:
// stack: len, pos, string, retdest
DUP1
%add_const(0x80)
@ -99,6 +47,31 @@ encode_rlp_fixed_finish:
SWAP1
JUMP
// 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, pos, string, retdest
DUP1
%add_const(0x81)
// stack: first_byte, len, pos, string, retdest
DUP3
// stack: pos, first_byte, len, pos, string, retdest
%mstore_rlp
// stack: len, pos, string, retdest
DUP1
%add_const(0x80)
// stack: second_byte, len, original_pos, string, retdest
DUP3 %increment
// stack: pos', second_byte, len, pos, string, retdest
%mstore_rlp
// stack: len, pos, string, retdest
SWAP1
%add_const(2) // advance past the two prefix bytes
// stack: pos'', len, string, retdest
%stack (pos, len, string) -> (pos, string, len, encode_rlp_fixed_finish)
// stack: context, segment, pos'', string, len, encode_rlp_fixed_finish, retdest
%jump(mstore_unpacking_rlp)
// 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

View File

@ -0,0 +1,99 @@
// RLP-encode a scalar, i.e. a variable-length integer.
// Pre stack: pos, scalar, retdest
// Post stack: pos
global encode_rlp_scalar:
// stack: pos, scalar, retdest
// If scalar > 0x7f, this is the "medium" case.
DUP2
%gt_const(0x7f)
%jumpi(encode_rlp_scalar_medium)
// Else, if scalar != 0, this is the "small" case, where the value is its own encoding.
DUP2 %jumpi(encode_rlp_scalar_small)
// scalar = 0, so BE(scalar) is the empty string, which RLP encodes as a single byte 0x80.
// stack: pos, scalar, retdest
%stack (pos, scalar) -> (pos, 0x80, pos)
%mstore_rlp
// stack: pos, retdest
%increment
// stack: pos', retdest
SWAP1
JUMP
encode_rlp_scalar_medium:
// This is the "medium" case, where we write 0x80 + len followed by the
// (big-endian) scalar bytes. We first compute the minimal number of bytes
// needed to represent this scalar, then treat it as if it was a fixed-
// length string with that length.
// stack: pos, scalar, retdest
DUP2
%num_bytes
// stack: scalar_bytes, pos, scalar, retdest
%jump(encode_rlp_fixed)
// Doubly-RLP-encode a scalar, i.e. return encode(encode(scalar)).
// Pre stack: pos, scalar, retdest
// Post stack: pos
global doubly_encode_rlp_scalar:
// stack: pos, scalar, retdest
// If scalar > 0x7f, this is the "medium" case.
DUP2
%gt_const(0x7f)
%jumpi(doubly_encode_rlp_scalar_medium)
// Else, if scalar != 0, this is the "small" case, where the value is its own encoding.
DUP2 %jumpi(encode_rlp_scalar_small)
// scalar = 0, so BE(scalar) is the empty string, encode(scalar) = 0x80, and encode(encode(scalar)) = 0x8180.
// stack: pos, scalar, retdest
%stack (pos, scalar) -> (pos, 0x81, pos, 0x80, pos)
%mstore_rlp
// stack: pos, 0x80, pos, retdest
%increment
%mstore_rlp
// stack: pos, retdest
%increment
// stack: pos, retdest
SWAP1
JUMP
doubly_encode_rlp_scalar_medium:
// This is the "medium" case, where
// encode(scalar) = [0x80 + len] || BE(scalar)
// and so
// encode(encode(scalar)) = [0x80 + len + 1] || [0x80 + len] || BE(scalar)
// We first compute the length of the scalar with %num_bytes, then treat the scalar as if it was a
// fixed-length string with that length.
// stack: pos, scalar, retdest
DUP2
%num_bytes
// stack: scalar_bytes, pos, scalar, retdest
%jump(doubly_encode_rlp_fixed)
// The "small" case of RLP-encoding a scalar, where the value is its own encoding.
// This can be used for both for singly encoding or doubly encoding, since encode(encode(x)) = encode(x) = x.
encode_rlp_scalar_small:
// stack: pos, scalar, retdest
%stack (pos, scalar) -> (pos, scalar, pos)
// stack: pos, scalar, pos, retdest
%mstore_rlp
// stack: pos, retdest
%increment
// stack: pos', retdest
SWAP1
JUMP
// Convenience macro to call encode_rlp_scalar and return where we left off.
%macro encode_rlp_scalar
%stack (pos, scalar) -> (pos, scalar, %%after)
%jump(encode_rlp_scalar)
%%after:
%endmacro
// Convenience macro to call doubly_encode_rlp_scalar and return where we left off.
%macro doubly_encode_rlp_scalar
%stack (pos, scalar) -> (pos, scalar, %%after)
%jump(doubly_encode_rlp_scalar)
%%after:
%endmacro