mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-28 18:43:12 +00:00
Merge branch 'main' into expmod_precompile
This commit is contained in:
commit
031fe6ed90
@ -76,14 +76,15 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/curve/wnaf.asm"),
|
||||
include_str!("asm/exp.asm"),
|
||||
include_str!("asm/halt.asm"),
|
||||
include_str!("asm/hash/blake2b/addresses.asm"),
|
||||
include_str!("asm/hash/blake2b/compression.asm"),
|
||||
include_str!("asm/hash/blake2b/g_functions.asm"),
|
||||
include_str!("asm/hash/blake2b/hash.asm"),
|
||||
include_str!("asm/hash/blake2b/iv.asm"),
|
||||
include_str!("asm/hash/blake2b/main.asm"),
|
||||
include_str!("asm/hash/blake2b/ops.asm"),
|
||||
include_str!("asm/hash/blake2b/permutations.asm"),
|
||||
include_str!("asm/hash/blake2/addresses.asm"),
|
||||
include_str!("asm/hash/blake2/blake2_f.asm"),
|
||||
// include_str!("asm/hash/blake2/blake2b.asm"),
|
||||
// include_str!("asm/hash/blake2/compression.asm"),
|
||||
include_str!("asm/hash/blake2/g_functions.asm"),
|
||||
include_str!("asm/hash/blake2/hash.asm"),
|
||||
include_str!("asm/hash/blake2/iv.asm"),
|
||||
include_str!("asm/hash/blake2/ops.asm"),
|
||||
include_str!("asm/hash/blake2/permutations.asm"),
|
||||
include_str!("asm/hash/ripemd/box.asm"),
|
||||
include_str!("asm/hash/ripemd/compression.asm"),
|
||||
include_str!("asm/hash/ripemd/constants.asm"),
|
||||
|
||||
@ -54,49 +54,55 @@ insert_accessed_addresses_found:
|
||||
|
||||
|
||||
%macro insert_accessed_storage_keys
|
||||
%stack (addr, key) -> (addr, key, %%after)
|
||||
%stack (addr, key, value) -> (addr, key, value, %%after)
|
||||
%jump(insert_accessed_storage_keys)
|
||||
%%after:
|
||||
// stack: cold_access
|
||||
%endmacro
|
||||
|
||||
/// Inserts the storage key into the access list if it is not already present.
|
||||
/// Return 1 if the storage key was inserted, 0 if it was already present.
|
||||
/// Inserts the storage key and value into the access list if it is not already present.
|
||||
/// `value` should be the current storage value at the slot `(addr, key)`.
|
||||
/// Return `1, original_value` if the storage key was inserted, `0, original_value` if it was already present.
|
||||
global insert_accessed_storage_keys:
|
||||
// stack: addr, key, retdest
|
||||
// stack: addr, key, value, retdest
|
||||
%mload_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN)
|
||||
// stack: len, addr, key, retdest
|
||||
// stack: len, addr, key, value, retdest
|
||||
PUSH 0
|
||||
insert_accessed_storage_keys_loop:
|
||||
%stack (i, len, addr, key, retdest) -> (i, len, i, len, addr, key, retdest)
|
||||
%stack (i, len, addr, key, value, retdest) -> (i, len, i, len, addr, key, value, retdest)
|
||||
EQ %jumpi(insert_storage_key)
|
||||
// stack: i, len, addr, key, retdest
|
||||
// stack: i, len, addr, key, value, retdest
|
||||
DUP1 %increment %mload_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
|
||||
// stack: loaded_key, i, len, addr, key, retdest
|
||||
// stack: loaded_key, i, len, addr, key, value, retdest
|
||||
DUP2 %mload_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
|
||||
// stack: loaded_addr, loaded_key, i, len, addr, key, retdest
|
||||
// stack: loaded_addr, loaded_key, i, len, addr, key, value, retdest
|
||||
DUP5 EQ
|
||||
// stack: loaded_addr==addr, loaded_key, i, len, addr, key, retdest
|
||||
// stack: loaded_addr==addr, loaded_key, i, len, addr, key, value, retdest
|
||||
SWAP1 DUP6 EQ
|
||||
// stack: loaded_key==key, loaded_addr==addr, i, len, addr, key, retdest
|
||||
// stack: loaded_key==key, loaded_addr==addr, i, len, addr, key, value, retdest
|
||||
MUL // AND
|
||||
%jumpi(insert_accessed_storage_keys_found)
|
||||
// stack: i, len, addr, key, retdest
|
||||
%add_const(2)
|
||||
// stack: i, len, addr, key, value, retdest
|
||||
%add_const(3)
|
||||
%jump(insert_accessed_storage_keys_loop)
|
||||
|
||||
insert_storage_key:
|
||||
// stack: i, len, addr, key, retdest
|
||||
// stack: i, len, addr, key, value, retdest
|
||||
DUP1 %increment
|
||||
%stack (i_plus_1, i, len, addr, key, retdest) -> (i, addr, i_plus_1, key, i_plus_1, retdest)
|
||||
DUP1 %increment
|
||||
%stack (i_plus_2, i_plus_1, i, len, addr, key, value) -> (i, addr, i_plus_1, key, i_plus_2, value, i_plus_2, value)
|
||||
%mstore_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS) // Store new address at the end of the array.
|
||||
%mstore_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS) // Store new key after that
|
||||
// stack: i_plus_1, retdest
|
||||
%mstore_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS) // Store new value after that
|
||||
// stack: i_plus_2, value, retdest
|
||||
%increment
|
||||
%mstore_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN) // Store new length in front of the array.
|
||||
PUSH 1 // Return 1 to indicate that the storage key was inserted.
|
||||
SWAP1 JUMP
|
||||
%mstore_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN) // Store new length.
|
||||
%stack (value, retdest) -> (retdest, 1, value) // Return 1 to indicate that the storage key was inserted.
|
||||
JUMP
|
||||
|
||||
insert_accessed_storage_keys_found:
|
||||
%stack (i, len, addr, key, retdest) -> (retdest, 0) // Return 0 to indicate that the storage key was already present.
|
||||
// stack: i, len, addr, key, value, retdest
|
||||
%add_const(2)
|
||||
%mload_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
|
||||
%stack (original_value, len, addr, key, value, retdest) -> (retdest, 0, original_value) // Return 0 to indicate that the storage key was already present.
|
||||
JUMP
|
||||
|
||||
@ -1,3 +1,136 @@
|
||||
global precompile_blake2_f:
|
||||
// TODO
|
||||
PANIC
|
||||
// stack: retdest, new_ctx, (old stack)
|
||||
POP
|
||||
// stack: new_ctx, (old stack)
|
||||
DUP1
|
||||
SET_CONTEXT
|
||||
// stack: (empty)
|
||||
PUSH 0x100000000 // = 2^32 (is_kernel = true)
|
||||
// stack: kexit_info
|
||||
|
||||
PUSH blake2_f_contd
|
||||
// stack: blake2_f_contd, kexit_info
|
||||
|
||||
// Load inputs from calldata memory into stack.
|
||||
|
||||
%calldatasize
|
||||
// stack: calldatasize, blake2_f_contd, kexit_info
|
||||
DUP1
|
||||
// stack: calldatasize, calldatasize, blake2_f_contd, kexit_info
|
||||
%eq_const(213) ISZERO %jumpi(fault_exception)
|
||||
// stack: calldatasize, blake2_f_contd, kexit_info
|
||||
%decrement
|
||||
// stack: flag_addr=212, blake2_f_contd, kexit_info
|
||||
DUP1
|
||||
// stack: flag_addr, flag_addr, blake2_f_contd, kexit_info
|
||||
PUSH @SEGMENT_CALLDATA
|
||||
GET_CONTEXT
|
||||
// stack: ctx, @SEGMENT_CALLDATA, flag_addr, flag_addr, blake2_f_contd, kexit_info
|
||||
MLOAD_GENERAL
|
||||
// stack: flag, flag_addr, blake2_f_contd, kexit_info
|
||||
DUP1
|
||||
// stack: flag, flag, flag_addr, blake2_f_contd, kexit_info
|
||||
%gt_const(1) %jumpi(fault_exception) // Check flag < 2 (flag = 0 or flag = 1)
|
||||
// stack: flag, flag_addr, blake2_f_contd, kexit_info
|
||||
SWAP1
|
||||
// stack: flag_addr, flag, blake2_f_contd, kexit_info
|
||||
%sub_const(8)
|
||||
// stack: t1_addr=flag_addr-8, flag, blake2_f_contd, kexit_info
|
||||
|
||||
%stack (t1_addr) -> (@SEGMENT_CALLDATA, t1_addr, 8, t1_addr)
|
||||
// stack: @SEGMENT_CALLDATA, t1_addr, 8, t1_addr, flag, blake2_f_contd, kexit_info
|
||||
GET_CONTEXT
|
||||
// stack: ctx, @SEGMENT_CALLDATA, t1_addr, 8, t1_addr, flag, blake2_f_contd, kexit_info
|
||||
%mload_packing
|
||||
// stack: t_1, t1_addr, flag, blake2_f_contd, kexit_info
|
||||
SWAP1
|
||||
// stack: t1_addr, t_1, flag, blake2_f_contd, kexit_info
|
||||
%sub_const(8)
|
||||
// stack: t0_addr=t1_addr-8, t_1, flag, blake2_f_contd, kexit_info
|
||||
|
||||
%stack (t0_addr) -> (@SEGMENT_CALLDATA, t0_addr, 8, t0_addr)
|
||||
// stack: @SEGMENT_CALLDATA, t0_addr, 8, t0_addr, t_1, flag, blake2_f_contd, kexit_info
|
||||
GET_CONTEXT
|
||||
// stack: ctx, @SEGMENT_CALLDATA, t0_addr, 8, t0_addr, t_1, flag, blake2_f_contd, kexit_info
|
||||
%mload_packing
|
||||
// stack: t_0, t0_addr, t_1, flag, blake2_f_contd, kexit_info
|
||||
SWAP1
|
||||
// stack: t0_addr, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
%sub_const(128) // 16 * 8
|
||||
// stack: m0_addr=t0_addr-128, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
|
||||
%rep 16
|
||||
// stack: 68 + 8 * i, m_(i-1), ..., m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
PUSH 8
|
||||
// stack: 8, 68 + 8 * i, m_(i-1), ..., m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
DUP2
|
||||
// stack: 68 + 8 * i, 8, 68 + 8 * i, m_(i-1), ..., m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
PUSH @SEGMENT_CALLDATA
|
||||
// stack: @SEGMENT_CALLDATA, 68 + 8 * i, 8, 68 + 8 * i, m_(i-1), ..., m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
GET_CONTEXT
|
||||
// stack: ctx, @SEGMENT_CALLDATA, 68 + 8 * i, 8, 68 + 8 * i, m_(i-1), ..., m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
%mload_packing
|
||||
// stack: m_i, 68 + 8 * i, m_(i-1), ..., m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
SWAP1
|
||||
// stack: 68 + 8 * i, m_i, m_(i-1), ..., m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
%add_const(8)
|
||||
%endrep
|
||||
// stack: 68 + 8 * 16 = 196, m_15, ..., m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
%sub_const(192) // 16 * 8 (m values) + 8 * 8 (h values)
|
||||
// stack: h0_addr, m_15, ..., m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
|
||||
%rep 8
|
||||
// stack: 4 + 8 * i, h_(i-1), ..., h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
PUSH 8
|
||||
// stack: 8, 4 + 8 * i, h_(i-1), ..., h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
DUP2
|
||||
// stack: 4 + 8 * i, 8, 4 + 8 * i, h_(i-1), ..., h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
PUSH @SEGMENT_CALLDATA
|
||||
// stack: @SEGMENT_CALLDATA, 4 + 8 * i, 8, 4 + 8 * i, h_(i-1), ..., h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
GET_CONTEXT
|
||||
// stack: ctx, @SEGMENT_CALLDATA, 4 + 8 * i, 8, 4 + 8 * i, h_(i-1), ..., h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
%mload_packing
|
||||
// stack: h_i, 4 + 8 * i, h_(i-1), ..., h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
SWAP1
|
||||
// stack: 4 + 8 * i, h_i, h_(i-1), ..., h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
%add_const(8)
|
||||
%endrep
|
||||
// stack: 4 + 8 * 8 = 68, h_7, ..., h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
POP
|
||||
|
||||
%stack () -> (@SEGMENT_CALLDATA, 0, 4)
|
||||
GET_CONTEXT
|
||||
// stack: ctx, @SEGMENT_CALLDATA, 0, 4, h_7..h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
%mload_packing
|
||||
// stack: rounds, h_7..h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
|
||||
DUP1
|
||||
// stack: rounds, rounds, h_7..h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
%charge_gas
|
||||
|
||||
// stack: rounds, h_7..h_0, m_15..m_0, t_0, t_1, flag, blake2_f_contd, kexit_info
|
||||
%jump(blake2_f)
|
||||
blake2_f_contd:
|
||||
// stack: h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', kexit_info
|
||||
// Store the result hash to the parent's return data using `mstore_unpacking`.
|
||||
|
||||
%mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32)
|
||||
PUSH 0
|
||||
// stack: addr_0=0, h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', kexit_info
|
||||
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
|
||||
// stack: parent_ctx, addr_0=0, h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', kexit_info
|
||||
|
||||
%rep 8
|
||||
// stack: parent_ctx, addr_i, h_i', ..., h_7', kexit_info
|
||||
%stack (ctx, addr, h_i) -> (ctx, @SEGMENT_RETURNDATA, addr, h_i, 4, addr, ctx)
|
||||
// stack: parent_ctx, @SEGMENT_RETURNDATA, addr_i, h_i', 4, addr_i, parent_ctx, h_(i+1)', ..., h_7', kexit_info
|
||||
%mstore_unpacking
|
||||
// stack: addr_i, parent_ctx, h_(i+1)', ..., h_7', kexit_info
|
||||
%add_const(4)
|
||||
// stack: addr_(i+1), parent_ctx, h_(i+1)', ..., h_7', kexit_info
|
||||
SWAP1
|
||||
// stack: parent_ctx, addr_(i+1), h_(i+1)', ..., h_7', kexit_info
|
||||
%endrep
|
||||
|
||||
// stack: kexit_info
|
||||
%jump(pop_and_return_success)
|
||||
|
||||
@ -35,9 +35,7 @@ global pop_and_return_success:
|
||||
// stack: retdest
|
||||
%mload_txn_field(@TXN_FIELD_TO)
|
||||
// stack: addr, retdest
|
||||
DUP1 %ge_const(@ECREC) DUP2 %le_const(@BLAKE2_F)
|
||||
// stack: addr<=9, addr>=1, addr, retdest
|
||||
MUL // Cheaper than AND
|
||||
DUP1 %is_precompile
|
||||
%jumpi(handle_precompiles_from_eoa)
|
||||
// stack: addr, retdest
|
||||
POP
|
||||
|
||||
@ -23,6 +23,7 @@ global precompile_sha256:
|
||||
// Copy the call data to the kernel general segment (sha2 expects it there) and call sha2.
|
||||
%calldatasize
|
||||
GET_CONTEXT
|
||||
// stack: ctx, size
|
||||
|
||||
// The next block of code is equivalent to the following %stack macro call
|
||||
// (unfortunately the macro call takes too long to expand dynamically).
|
||||
|
||||
@ -28,11 +28,24 @@
|
||||
// stack: to == 0
|
||||
%endmacro
|
||||
|
||||
%macro is_precompile
|
||||
// stack: addr
|
||||
DUP1 %ge_const(@ECREC) SWAP1 %le_const(@BLAKE2_F)
|
||||
// stack: addr>=1, addr<=9
|
||||
MUL // Cheaper than AND
|
||||
%endmacro
|
||||
|
||||
// Returns 1 if the account is non-existent, 0 otherwise.
|
||||
%macro is_non_existent
|
||||
// stack: addr
|
||||
%mpt_read_state_trie
|
||||
ISZERO
|
||||
DUP1
|
||||
// stack: addr, addr
|
||||
%mpt_read_state_trie ISZERO
|
||||
SWAP1
|
||||
// stack: addr, zero_state_trie
|
||||
%is_precompile ISZERO
|
||||
// stack: not_precompile, zero_state_trie
|
||||
MUL // Cheaper than AND
|
||||
%endmacro
|
||||
|
||||
// Returns 1 if the account is empty, 0 otherwise.
|
||||
@ -65,5 +78,5 @@
|
||||
// stack: addr
|
||||
DUP1 %is_non_existent
|
||||
SWAP1 %is_empty
|
||||
ADD // OR
|
||||
OR
|
||||
%endmacro
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// Address where the working version of the hash value is stored.
|
||||
%macro blake2b_hash_value_addr
|
||||
%macro blake2_hash_value_addr
|
||||
PUSH 0
|
||||
// stack: 0
|
||||
%mload_kernel_general
|
||||
@ -10,14 +10,14 @@
|
||||
%endmacro
|
||||
|
||||
// Address where the working version of the compression internal state is stored.
|
||||
%macro blake2b_internal_state_addr
|
||||
%blake2b_hash_value_addr
|
||||
%macro blake2_internal_state_addr
|
||||
%blake2_hash_value_addr
|
||||
%add_const(8)
|
||||
%endmacro
|
||||
|
||||
// Address where the current message block is stored.
|
||||
%macro blake2b_message_addr
|
||||
%blake2b_internal_state_addr
|
||||
%macro blake2_message_addr
|
||||
%blake2_internal_state_addr
|
||||
%add_const(16)
|
||||
%endmacro
|
||||
|
||||
143
evm/src/cpu/kernel/asm/hash/blake2/blake2_f.asm
Normal file
143
evm/src/cpu/kernel/asm/hash/blake2/blake2_f.asm
Normal file
@ -0,0 +1,143 @@
|
||||
global blake2_f:
|
||||
// stack: rounds, h0...h7, m0...m15, t0, t1, flag, retdest
|
||||
|
||||
// Store the hash values.
|
||||
%blake2_hash_value_addr
|
||||
// stack: addr, rounds, h0...h7, m0...m15, t0, t1, flag, retdest
|
||||
%rep 8
|
||||
// stack: addr, rounds, h_i, ...
|
||||
%stack (addr, rounds, h_i) -> (addr, h_i, addr, rounds)
|
||||
// stack: addr, h_i, addr, rounds, ...
|
||||
%mstore_kernel_general
|
||||
%increment
|
||||
%endrep
|
||||
|
||||
// stack: addr, rounds, m0...m15, t0, t1, flag, retdest
|
||||
POP
|
||||
// stack: rounds, m0...m15, t0, t1, flag, retdest
|
||||
|
||||
// Save the message to the message working space.
|
||||
%blake2_message_addr
|
||||
// stack: message_addr, rounds, m0...m15, t0, t1, flag, retdest
|
||||
%rep 16
|
||||
// stack: message_addr, rounds, m_i, ...
|
||||
%stack (message_addr, rounds, m_i) -> (message_addr, m_i, message_addr, rounds)
|
||||
// stack: message_addr, m_i, message_addr, rounds, ...
|
||||
%mstore_kernel_general
|
||||
%increment
|
||||
%endrep
|
||||
|
||||
// stack: message_addr, rounds, t0, t1, flag, retdest
|
||||
POP
|
||||
// stack: rounds, t0, t1, flag, retdest
|
||||
|
||||
%blake2_hash_value_addr
|
||||
%add_const(7)
|
||||
%rep 8
|
||||
// stack: addr, ...
|
||||
DUP1
|
||||
// stack: addr, addr, ...
|
||||
%mload_kernel_general
|
||||
// stack: val, addr, ...
|
||||
SWAP1
|
||||
// stack: addr, val, ...
|
||||
%decrement
|
||||
%endrep
|
||||
// stack: addr, h_0, ..., h_7, rounds, t0, t1, flag, retdest
|
||||
POP
|
||||
// stack: h_0, ..., h_7, rounds, t0, t1, flag, retdest
|
||||
|
||||
// Store the initial 16 values of the internal state.
|
||||
%blake2_internal_state_addr
|
||||
// stack: start, h_0, ..., h_7, rounds, t0, t1, flag, retdest
|
||||
|
||||
// First eight words of the internal state: current hash value h_0, ..., h_7.
|
||||
%rep 8
|
||||
SWAP1
|
||||
DUP2
|
||||
%mstore_kernel_general
|
||||
%increment
|
||||
%endrep
|
||||
// stack: start + 8, rounds, t0, t1, flag, retdest
|
||||
|
||||
// Next four values of the internal state: first four IV values.
|
||||
PUSH 0
|
||||
// stack: 0, start + 8, rounds, t0, t1, flag, retdest
|
||||
%rep 4
|
||||
// stack: i, loc, ...
|
||||
DUP1
|
||||
// stack: i, i, loc, ...
|
||||
%blake2_iv
|
||||
// stack: IV_i, i, loc, ...
|
||||
DUP3
|
||||
// stack: loc, IV_i, i, loc, ...
|
||||
%mstore_kernel_general
|
||||
// stack: i, loc, ...
|
||||
%increment
|
||||
SWAP1
|
||||
%increment
|
||||
SWAP1
|
||||
// stack: i + 1, loc + 1,...
|
||||
%endrep
|
||||
// stack: 4, start + 12, rounds, t0, t1, flag, retdest
|
||||
POP
|
||||
// stack: start + 12, rounds, t0, t1, flag, retdest
|
||||
SWAP4
|
||||
// stack: flag, rounds, t0, t1, start + 12, retdest
|
||||
%mul_const(0xFFFFFFFFFFFFFFFF)
|
||||
// stack: invert_if_flag, rounds, t0, t1, start + 12, retdest
|
||||
%stack (inv, r, t0, t1, s) -> (4, s, t0, t1, inv, 0, r)
|
||||
// stack: 4, start + 12, t0, t1, invert_if_flag, 0, rounds, retdest
|
||||
|
||||
// Last four values of the internal state: last four IV values, XOR'd with
|
||||
// the values (t0, t1, invert_if_flag, 0).
|
||||
%rep 4
|
||||
// stack: i, loc, val, next_val,...
|
||||
DUP1
|
||||
// stack: i, i, loc, val, next_val,...
|
||||
%blake2_iv
|
||||
// stack: IV_i, i, loc, val, next_val,...
|
||||
DUP4
|
||||
// stack: val, IV_i, i, loc, val, next_val,...
|
||||
XOR
|
||||
// stack: val ^ IV_i, i, loc, val, next_val,...
|
||||
DUP3
|
||||
// stack: loc, val ^ IV_i, i, loc, val, next_val,...
|
||||
%mstore_kernel_general
|
||||
// stack: i, loc, val, next_val,...
|
||||
%increment
|
||||
// stack: i + 1, loc, val, next_val,...
|
||||
SWAP2
|
||||
// stack: val, loc, i + 1, next_val,...
|
||||
POP
|
||||
// stack: loc, i + 1, next_val,...
|
||||
%increment
|
||||
// stack: loc + 1, i + 1, next_val,...
|
||||
SWAP1
|
||||
// stack: i + 1, loc + 1, next_val,...
|
||||
%endrep
|
||||
// stack: 8, start + 16, rounds, retdest
|
||||
%pop2
|
||||
// stack: rounds, retdest
|
||||
|
||||
// Run rounds of G functions.
|
||||
PUSH g_functions_return
|
||||
// stack: g_functions_return, rounds, retdest
|
||||
SWAP1
|
||||
// stack: rounds, g_functions_return, retdest
|
||||
%blake2_internal_state_addr
|
||||
// stack: start, rounds, g_functions_return, retdest
|
||||
PUSH 0
|
||||
// stack: current_round=0, start, rounds, g_functions_return, retdest
|
||||
%jump(run_rounds_g_function)
|
||||
g_functions_return:
|
||||
// Finalize hash value.
|
||||
// stack: retdest
|
||||
PUSH hash_generate_return
|
||||
// stack: hash_generate_return, retdest
|
||||
%jump(blake2_generate_all_hash_values)
|
||||
hash_generate_return:
|
||||
// stack: h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', retdest
|
||||
%stack (h: 8, retdest) -> (retdest, h)
|
||||
// stack: retdest, h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7'
|
||||
JUMP
|
||||
@ -11,4 +11,4 @@ global blake2b:
|
||||
%add_const(1)
|
||||
%mstore_kernel_general
|
||||
// stack: retdest
|
||||
%jump(blake2b_compression)
|
||||
%jump(blake2_compression)
|
||||
@ -1,15 +1,15 @@
|
||||
global blake2b_compression:
|
||||
global blake2_compression:
|
||||
// stack: retdest
|
||||
PUSH 0
|
||||
// stack: cur_block = 0, retdest
|
||||
PUSH compression_loop
|
||||
// stack: compression_loop, cur_block, retdest
|
||||
%jump(blake2b_initial_hash_value)
|
||||
%jump(blake2_initial_hash_value)
|
||||
compression_loop:
|
||||
// stack: h_0, ..., h_7, cur_block, retdest
|
||||
|
||||
// Store the hash values.
|
||||
%blake2b_hash_value_addr
|
||||
%blake2_hash_value_addr
|
||||
// stack: addr, h_0, ..., h_7, cur_block, retdest
|
||||
%rep 8
|
||||
SWAP1
|
||||
@ -63,7 +63,7 @@ compression_loop:
|
||||
// stack: cur_block_start_byte, t, cur_block, is_last_block, retdest
|
||||
|
||||
// Copy the message from the input space to the message working space.
|
||||
%blake2b_message_addr
|
||||
%blake2_message_addr
|
||||
// stack: message_addr, cur_block_start_byte, t, cur_block, is_last_block, retdest
|
||||
%rep 16
|
||||
// stack: cur_message_addr, cur_block_byte, ...
|
||||
@ -93,7 +93,7 @@ compression_loop:
|
||||
// stack: is_last_block, t, cur_block, retdest
|
||||
%mul_const(0xFFFFFFFFFFFFFFFF)
|
||||
// stack: invert_if_last_block, t, cur_block, retdest
|
||||
%blake2b_hash_value_addr
|
||||
%blake2_hash_value_addr
|
||||
%add_const(7)
|
||||
%rep 8
|
||||
// stack: addr, ...
|
||||
@ -110,7 +110,7 @@ compression_loop:
|
||||
// stack: h_0, ..., h_7, invert_if_last_block, t, cur_block, retdest
|
||||
|
||||
// Store the initial 16 values of the internal state.
|
||||
%blake2b_internal_state_addr
|
||||
%blake2_internal_state_addr
|
||||
// stack: start, h_0, ..., h_7, invert_if_last_block, t, cur_block, retdest
|
||||
|
||||
// First eight words of the internal state: current hash value h_0, ..., h_7.
|
||||
@ -129,7 +129,7 @@ compression_loop:
|
||||
// stack: i, loc, ...
|
||||
DUP1
|
||||
// stack: i, i, loc, ...
|
||||
%blake2b_iv
|
||||
%blake2_iv
|
||||
// stack: IV_i, i, loc, ...
|
||||
DUP3
|
||||
// stack: loc, IV_i, i, loc, ...
|
||||
@ -159,7 +159,7 @@ compression_loop:
|
||||
// stack: i, loc, val, next_val,...
|
||||
DUP1
|
||||
// stack: i, i, loc, val, next_val,...
|
||||
%blake2b_iv
|
||||
%blake2_iv
|
||||
// stack: IV_i, i, loc, val, next_val,...
|
||||
DUP4
|
||||
// stack: val, IV_i, i, loc, val, next_val,...
|
||||
@ -187,15 +187,18 @@ compression_loop:
|
||||
// Run 12 rounds of G functions.
|
||||
PUSH g_functions_return
|
||||
// stack: g_functions_return, cur_block, retdest
|
||||
%blake2b_internal_state_addr
|
||||
// stack: start, g_functions_return, cur_block, retdest
|
||||
%jump(run_12_rounds_g_function)
|
||||
PUSH 12
|
||||
%blake2_internal_state_addr
|
||||
// stack: start, 12, g_functions_return, cur_block, retdest
|
||||
PUSH 0
|
||||
// stack: current_round=0, start, 12, g_functions_return, cur_block, retdest
|
||||
%jump(run_rounds_g_function)
|
||||
g_functions_return:
|
||||
// Finalize hash value.
|
||||
// stack: cur_block, retdest
|
||||
PUSH hash_generate_return
|
||||
// stack: hash_generate_return, cur_block, retdest
|
||||
%jump(blake2b_generate_all_hash_values)
|
||||
%jump(blake2_generate_all_hash_values)
|
||||
hash_generate_return:
|
||||
// stack: h_0', h_1', h_2', h_3', h_4', h_5', h_6', h_7', cur_block, retdest
|
||||
DUP9
|
||||
@ -1,4 +1,4 @@
|
||||
%macro blake2b_g_function
|
||||
%macro blake2_g_function
|
||||
// Function to mix two input words, x and y, into the four words indexed by a, b, c, d (which
|
||||
// are in the range 0..16) in the internal state.
|
||||
// The internal state is stored in memory starting at the address start.
|
||||
@ -104,23 +104,23 @@
|
||||
%mstore_kernel_general
|
||||
%endmacro
|
||||
|
||||
%macro call_blake2b_g_function(a, b, c, d, x_idx, y_idx)
|
||||
%macro call_blake2_g_function(a, b, c, d, x_idx, y_idx)
|
||||
// stack: round, start
|
||||
PUSH $y_idx
|
||||
DUP2
|
||||
// stack: round, y_idx, round, start
|
||||
%blake2b_permutation
|
||||
%blake2_permutation
|
||||
// stack: s[y_idx], round, start
|
||||
%blake2b_message_addr
|
||||
%blake2_message_addr
|
||||
ADD
|
||||
%mload_kernel_general
|
||||
// stack: m[s[y_idx]], round, start
|
||||
PUSH $x_idx
|
||||
DUP3
|
||||
// stack: round, 2, m[s[y_idx]], round, start
|
||||
%blake2b_permutation
|
||||
%blake2_permutation
|
||||
// stack: s[x_idx], m[s[y_idx]], round, start
|
||||
%blake2b_message_addr
|
||||
%blake2_message_addr
|
||||
ADD
|
||||
%mload_kernel_general
|
||||
// stack: m[s[x_idx]], m[s[y_idx]], round, start
|
||||
@ -131,48 +131,45 @@
|
||||
PUSH $b
|
||||
PUSH $a
|
||||
// stack: a, b, c, d, m[s[x_idx]], m[s[y_idx]], start, round, start
|
||||
%blake2b_g_function
|
||||
%blake2_g_function
|
||||
// stack: round, start
|
||||
%endmacro
|
||||
|
||||
run_g_function_round:
|
||||
// stack: round, start, retdest
|
||||
%call_blake2b_g_function(0, 4, 8, 12, 0, 1)
|
||||
%call_blake2b_g_function(1, 5, 9, 13, 2, 3)
|
||||
%call_blake2b_g_function(2, 6, 10, 14, 4, 5)
|
||||
%call_blake2b_g_function(3, 7, 11, 15, 6, 7)
|
||||
%call_blake2b_g_function(0, 5, 10, 15, 8, 9)
|
||||
%call_blake2b_g_function(1, 6, 11, 12, 10, 11)
|
||||
%call_blake2b_g_function(2, 7, 8, 13, 12, 13)
|
||||
%call_blake2b_g_function(3, 4, 9, 14, 14, 15)
|
||||
%call_blake2_g_function(0, 4, 8, 12, 0, 1)
|
||||
%call_blake2_g_function(1, 5, 9, 13, 2, 3)
|
||||
%call_blake2_g_function(2, 6, 10, 14, 4, 5)
|
||||
%call_blake2_g_function(3, 7, 11, 15, 6, 7)
|
||||
%call_blake2_g_function(0, 5, 10, 15, 8, 9)
|
||||
%call_blake2_g_function(1, 6, 11, 12, 10, 11)
|
||||
%call_blake2_g_function(2, 7, 8, 13, 12, 13)
|
||||
%call_blake2_g_function(3, 4, 9, 14, 14, 15)
|
||||
%stack (r, s, ret) -> (ret, r, s)
|
||||
// stack: retdest, round, start
|
||||
JUMP
|
||||
|
||||
global run_12_rounds_g_function:
|
||||
// stack: start, retdest
|
||||
PUSH 0
|
||||
// stack: round=0, start, retdest
|
||||
run_next_round_g_function:
|
||||
// stack: round, start, retdest
|
||||
PUSH run_next_round_g_function_return
|
||||
// stack: run_next_round_g_function_return, round, start, retdest
|
||||
SWAP2
|
||||
// stack: start, round, run_next_round_g_function_return, retdest
|
||||
SWAP1
|
||||
// stack: round, start, run_next_round_g_function_return, retdest
|
||||
global run_rounds_g_function:
|
||||
// stack: current_round, start, rounds, retdest
|
||||
DUP3
|
||||
// stack: rounds, current_round, start, rounds, retdest
|
||||
DUP2
|
||||
// stack: current_round, rounds, current_round, start, rounds, retdest
|
||||
EQ
|
||||
%jumpi(run_rounds_g_function_end)
|
||||
// stack: current_round, start, rounds, retdest
|
||||
PUSH run_rounds_g_function_return
|
||||
// stack: run_rounds_g_function_return, current_round, start, rounds, retdest
|
||||
%stack (ret, r, s) -> (r, s, ret)
|
||||
// stack: current_round, start, run_rounds_g_function_return, rounds, retdest
|
||||
%jump(run_g_function_round)
|
||||
run_next_round_g_function_return:
|
||||
// stack: round, start, retdest
|
||||
run_rounds_g_function_return:
|
||||
// stack: round, start, rounds, retdest
|
||||
%increment
|
||||
// stack: round+1, start, retdest
|
||||
DUP1
|
||||
// stack: round+1, round+1, start, retdest
|
||||
%lt_const(12)
|
||||
// stack: round+1 < 12, round+1, start, retdest
|
||||
%jumpi(run_next_round_g_function)
|
||||
// stack: round+1, start, retdest
|
||||
%pop2
|
||||
// stack: round + 1, start, rounds, retdest
|
||||
%jump(run_rounds_g_function)
|
||||
run_rounds_g_function_end:
|
||||
// stack: current_round, start, rounds, retdest
|
||||
%pop3
|
||||
// stack: retdest
|
||||
JUMP
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
blake2b_generate_new_hash_value:
|
||||
// Generate a new hash value from the previous hash value and two elements of the internal state.
|
||||
blake2_generate_new_hash_value:
|
||||
// stack: i, retdest
|
||||
%blake2b_hash_value_addr
|
||||
%blake2_hash_value_addr
|
||||
// stack: addr, i, retdest
|
||||
DUP2
|
||||
ADD
|
||||
%mload_kernel_general
|
||||
// stack: h_i, i, retdest
|
||||
%blake2b_internal_state_addr
|
||||
%blake2_internal_state_addr
|
||||
// stack: addr, h_i, i, retdest
|
||||
DUP3
|
||||
ADD
|
||||
%mload_kernel_general
|
||||
// stack: v_i, h_i, i, retdest
|
||||
%blake2b_internal_state_addr
|
||||
%blake2_internal_state_addr
|
||||
// stack: addr, v_i, h_i, i, retdest
|
||||
SWAP1
|
||||
// stack: v_i, addr, h_i, i, retdest
|
||||
@ -28,26 +29,26 @@ blake2b_generate_new_hash_value:
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
global blake2b_generate_all_hash_values:
|
||||
global blake2_generate_all_hash_values:
|
||||
// stack: retdest
|
||||
PUSH 8
|
||||
// stack: i=8, retdest
|
||||
blake2b_generate_hash_loop:
|
||||
blake2_generate_hash_loop:
|
||||
// stack: i, h_i', ..., h_7', retdest
|
||||
%decrement
|
||||
// stack: i-1, h_i', ..., h_7', retdest
|
||||
PUSH blake2b_generate_hash_return
|
||||
// stack: blake2b_generate_hash_return, i-1, h_i', ..., h_7', retdest
|
||||
PUSH blake2_generate_hash_return
|
||||
// stack: blake2_generate_hash_return, i-1, h_i', ..., h_7', retdest
|
||||
DUP2
|
||||
// stack: i-1, blake2b_generate_hash_return, i-1, h_i', ..., h_7', retdest
|
||||
%jump(blake2b_generate_new_hash_value)
|
||||
blake2b_generate_hash_return:
|
||||
// stack: i-1, blake2_generate_hash_return, i-1, h_i', ..., h_7', retdest
|
||||
%jump(blake2_generate_new_hash_value)
|
||||
blake2_generate_hash_return:
|
||||
// stack: h_(i-1)', i-1, h_i', ..., h_7', retdest
|
||||
SWAP1
|
||||
// stack: i-1, h_(i-1)', h_i', ..., h_7', retdest
|
||||
DUP1
|
||||
// stack: i-1, i-1, h_(i-1)', ..., h_7', retdest
|
||||
%jumpi(blake2b_generate_hash_loop)
|
||||
%jumpi(blake2_generate_hash_loop)
|
||||
// stack: i-1=0, h_0', ..., h_7', retdest
|
||||
%stack (i, h: 8, ret) -> (ret, h)
|
||||
// stack: retdest, h_0'...h_7'
|
||||
@ -1,4 +1,4 @@
|
||||
global blake2b_iv_const:
|
||||
global blake2_iv_const:
|
||||
// IV constants (big-endian)
|
||||
|
||||
// IV_0
|
||||
@ -33,19 +33,19 @@ global blake2b_iv_const:
|
||||
BYTES 91, 224, 205, 25
|
||||
BYTES 19, 126, 33, 121
|
||||
|
||||
global blake2b_iv:
|
||||
global blake2_iv:
|
||||
// stack: i, retdest
|
||||
PUSH blake2b_iv_const
|
||||
// stack: blake2b_iv_const, i, retdest
|
||||
PUSH blake2_iv_const
|
||||
// stack: blake2_iv_const, i, retdest
|
||||
SWAP1
|
||||
// stack: i, blake2b_iv_const, retdest
|
||||
// stack: i, blake2_iv_const, retdest
|
||||
%mul_const(8)
|
||||
ADD
|
||||
// stack: blake2b_iv_const + 2 * i, retdest
|
||||
// stack: blake2_iv_const + 2 * i, retdest
|
||||
DUP1
|
||||
// stack: blake2b_iv_const + 2 * i, blake2b_iv_const + 2 * i, retdest
|
||||
// stack: blake2_iv_const + 2 * i, blake2_iv_const + 2 * i, retdest
|
||||
%add_const(4)
|
||||
// stack: blake2b_iv_const + 2 * i + 1, blake2b_iv_const + 2 * i, retdest
|
||||
// stack: blake2_iv_const + 2 * i + 1, blake2_iv_const + 2 * i, retdest
|
||||
%mload_kernel_code_u32
|
||||
SWAP1
|
||||
%mload_kernel_code_u32
|
||||
@ -57,33 +57,33 @@ global blake2b_iv:
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
%macro blake2b_iv
|
||||
%macro blake2_iv
|
||||
%stack (i) -> (i, %%after)
|
||||
%jump(blake2b_iv)
|
||||
%jump(blake2_iv)
|
||||
%%after:
|
||||
%endmacro
|
||||
|
||||
// Load the initial hash value (the IV, but with params XOR'd into the first word).
|
||||
global blake2b_initial_hash_value:
|
||||
global blake2_initial_hash_value:
|
||||
// stack: retdest
|
||||
PUSH 8
|
||||
// stack: i=8, retdest
|
||||
blake2b_initial_hash_loop:
|
||||
blake2_initial_hash_loop:
|
||||
// stack: i, IV_i, ..., IV_7, retdest
|
||||
%decrement
|
||||
// stack: i-1, IV_i, ..., IV_7, retdest
|
||||
PUSH blake2b_initial_hash_return
|
||||
// stack: blake2b_initial_hash_return, i-1, IV_i, ..., IV_7, retdest
|
||||
PUSH blake2_initial_hash_return
|
||||
// stack: blake2_initial_hash_return, i-1, IV_i, ..., IV_7, retdest
|
||||
DUP2
|
||||
// stack: i-1, blake2b_initial_hash_return, i-1, IV_i, ..., IV_7, retdest
|
||||
%jump(blake2b_iv)
|
||||
blake2b_initial_hash_return:
|
||||
// stack: i-1, blake2_initial_hash_return, i-1, IV_i, ..., IV_7, retdest
|
||||
%jump(blake2_iv)
|
||||
blake2_initial_hash_return:
|
||||
// stack: IV_(i-1), i-1, IV_i, ..., IV_7, retdest
|
||||
SWAP1
|
||||
// stack: i-1, IV_(i-1), IV_i, ..., IV_7, retdest
|
||||
DUP1
|
||||
// stack: i-1, i-1, IV_(i-1), ..., IV_7, retdest
|
||||
%jumpi(blake2b_initial_hash_loop)
|
||||
%jumpi(blake2_initial_hash_loop)
|
||||
// stack: i-1=0, IV_0, ..., IV_7, retdest
|
||||
POP
|
||||
// stack: IV_0, ..., IV_7, retdest
|
||||
@ -58,7 +58,7 @@ global permutation_9_constants:
|
||||
BYTES 15, 11, 9, 14
|
||||
BYTES 3, 12, 13, 0
|
||||
|
||||
global blake2b_permutation:
|
||||
global blake2_permutation:
|
||||
// stack: i, round, retdest
|
||||
PUSH permutation_0_constants
|
||||
// stack: permutation_0_constants, i, round, retdest
|
||||
@ -74,12 +74,12 @@ global blake2b_permutation:
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
%macro blake2b_permutation
|
||||
%macro blake2_permutation
|
||||
// stack: round, i
|
||||
PUSH %%after
|
||||
// stack: %%after, round, i
|
||||
SWAP2
|
||||
// stack: i, round, %%after
|
||||
%jump(blake2b_permutation)
|
||||
%jump(blake2_permutation)
|
||||
%%after:
|
||||
%endmacro
|
||||
@ -93,4 +93,4 @@ mstore_unpacking_finish:
|
||||
%stack (addr: 3, value, len) -> (addr, value, len, %%after)
|
||||
%jump(mstore_unpacking)
|
||||
%%after:
|
||||
%endmacro
|
||||
%endmacro
|
||||
|
||||
@ -1,3 +1,34 @@
|
||||
%macro sload_current
|
||||
%stack (slot) -> (slot, %%after)
|
||||
%jump(sload_current)
|
||||
%%after:
|
||||
%endmacro
|
||||
|
||||
global sload_current:
|
||||
%stack (slot) -> (slot, after_storage_read)
|
||||
%slot_to_storage_key
|
||||
// stack: storage_key, after_storage_read
|
||||
PUSH 64 // storage_key has 64 nibbles
|
||||
%current_storage_trie
|
||||
// stack: storage_root_ptr, 64, storage_key, after_storage_read
|
||||
%jump(mpt_read)
|
||||
|
||||
global after_storage_read:
|
||||
// stack: value_ptr, retdest
|
||||
DUP1 %jumpi(storage_key_exists)
|
||||
|
||||
// Storage key not found. Return default value_ptr = 0,
|
||||
// which derefs to 0 since @SEGMENT_TRIE_DATA[0] = 0.
|
||||
%stack (value_ptr, retdest) -> (retdest, 0)
|
||||
JUMP
|
||||
|
||||
global storage_key_exists:
|
||||
// stack: value_ptr, retdest
|
||||
%mload_trie_data
|
||||
// stack: value, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
// Read a word from the current account's storage trie.
|
||||
//
|
||||
// Pre stack: kexit_info, slot
|
||||
@ -6,38 +37,20 @@
|
||||
global sys_sload:
|
||||
// stack: kexit_info, slot
|
||||
SWAP1
|
||||
// stack: slot, kexit_info
|
||||
DUP1 %address
|
||||
// stack: addr, slot, slot, kexit_info
|
||||
%insert_accessed_storage_keys PUSH @GAS_COLDSLOAD_MINUS_WARMACCESS
|
||||
MUL
|
||||
PUSH @GAS_WARMACCESS
|
||||
ADD
|
||||
%stack (gas, slot, kexit_info) -> (gas, kexit_info, slot)
|
||||
DUP1
|
||||
// stack: slot, slot, kexit_info
|
||||
%sload_current
|
||||
|
||||
%stack (value, slot, kexit_info) -> (slot, value, kexit_info, value)
|
||||
%address
|
||||
// stack: addr, slot, value, kexit_info, value
|
||||
%insert_accessed_storage_keys
|
||||
// stack: cold_access, old_value, kexit_info, value
|
||||
SWAP1 POP
|
||||
// stack: cold_access, kexit_info, value
|
||||
%mul_const(@GAS_COLDSLOAD_MINUS_WARMACCESS)
|
||||
%add_const(@GAS_WARMACCESS)
|
||||
%charge_gas
|
||||
// stack: kexit_info, slot
|
||||
|
||||
SWAP1
|
||||
%stack (slot) -> (slot, after_storage_read)
|
||||
%slot_to_storage_key
|
||||
// stack: storage_key, after_storage_read, kexit_info
|
||||
PUSH 64 // storage_key has 64 nibbles
|
||||
%current_storage_trie
|
||||
// stack: storage_root_ptr, 64, storage_key, after_storage_read, kexit_info
|
||||
%jump(mpt_read)
|
||||
|
||||
after_storage_read:
|
||||
// stack: value_ptr, kexit_info
|
||||
DUP1 %jumpi(storage_key_exists)
|
||||
|
||||
// Storage key not found. Return default value_ptr = 0,
|
||||
// which derefs to 0 since @SEGMENT_TRIE_DATA[0] = 0.
|
||||
%stack (value_ptr, kexit_info) -> (kexit_info, 0)
|
||||
// stack: kexit_info, value
|
||||
EXIT_KERNEL
|
||||
|
||||
storage_key_exists:
|
||||
// stack: value_ptr, kexit_info
|
||||
%mload_trie_data
|
||||
// stack: value, kexit_info
|
||||
SWAP1
|
||||
EXIT_KERNEL
|
||||
|
||||
@ -6,14 +6,42 @@
|
||||
global sys_sstore:
|
||||
%check_static
|
||||
%stack (kexit_info, slot, value) -> (slot, kexit_info, slot, value)
|
||||
%address %insert_accessed_storage_keys POP // TODO: Use return value in gas calculation.
|
||||
// TODO: Assuming a cold zero -> nonzero write for now.
|
||||
PUSH @GAS_COLDSLOAD
|
||||
PUSH @GAS_SSET
|
||||
ADD
|
||||
%sload_current
|
||||
%address
|
||||
%stack (addr, current_value, kexit_info, slot, value) -> (addr, slot, current_value, current_value, kexit_info, slot, value)
|
||||
%insert_accessed_storage_keys
|
||||
// stack: cold_access, original_value, current_value, kexit_info, slot, value
|
||||
%mul_const(@GAS_COLDSLOAD)
|
||||
|
||||
// Check for warm access.
|
||||
%stack (gas, original_value, current_value, kexit_info, slot, value) ->
|
||||
(value, current_value, current_value, original_value, gas, original_value, current_value, kexit_info, slot, value)
|
||||
EQ SWAP2 EQ ISZERO
|
||||
// stack: current_value==original_value, value==current_value, gas, original_value, current_value, kexit_info, slot, value)
|
||||
ADD // OR
|
||||
%jumpi(sstore_warm)
|
||||
|
||||
// Check for sset (set a zero storage slot to a non-zero value).
|
||||
// stack: gas, original_value, current_value, kexit_info, slot, value
|
||||
DUP2 ISZERO %mul_const(@GAS_SSET) ADD
|
||||
|
||||
// Check for sreset (set a non-zero storage slot to a non-zero value).
|
||||
// stack: gas, original_value, current_value, kexit_info, slot, value
|
||||
DUP2 ISZERO ISZERO %mul_const(@GAS_SRESET) ADD
|
||||
%jump(sstore_charge_gas)
|
||||
|
||||
sstore_warm:
|
||||
// stack: gas, original_value, current_value, kexit_info, slot, value)
|
||||
%add_const(@GAS_WARMACCESS)
|
||||
|
||||
sstore_charge_gas:
|
||||
%stack (gas, original_value, current_value, kexit_info, slot, value) -> (gas, kexit_info, current_value, slot, value)
|
||||
%charge_gas
|
||||
|
||||
%stack (kexit_info, slot, value) -> (slot, value, kexit_info)
|
||||
// Check if `value` is equal to `current_value`, and if so exit the kernel early.
|
||||
%stack (kexit_info, current_value, slot, value) -> (value, current_value, slot, value, kexit_info)
|
||||
EQ %jumpi(sstore_noop)
|
||||
|
||||
// TODO: If value = 0, delete the key instead of inserting 0.
|
||||
// stack: slot, value, kexit_info
|
||||
|
||||
@ -57,3 +85,8 @@ after_storage_insert:
|
||||
after_state_insert:
|
||||
// stack: kexit_info
|
||||
EXIT_KERNEL
|
||||
|
||||
sstore_noop:
|
||||
// stack: slot, value, kexit_info
|
||||
%pop2
|
||||
EXIT_KERNEL
|
||||
|
||||
@ -229,7 +229,7 @@ const PRECOMPILES_GAS: [(&str, u16); 13] = [
|
||||
("BN_MUL_GAS", 6_000),
|
||||
("SNARKV_STATIC_GAS", 45_000),
|
||||
("SNARKV_DYNAMIC_GAS", 34_000),
|
||||
("BLAKE2_F_DYNAMIC_GAS", 1),
|
||||
("BLAKE2_F__GAS", 1),
|
||||
];
|
||||
|
||||
const CODE_SIZE_LIMIT: [(&str, u64); 3] = [
|
||||
|
||||
132
evm/src/cpu/kernel/tests/blake2_f.rs
Normal file
132
evm/src/cpu/kernel/tests/blake2_f.rs
Normal file
@ -0,0 +1,132 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::cpu::kernel::interpreter::{
|
||||
run_interpreter_with_memory, InterpreterMemoryInitialization,
|
||||
};
|
||||
use crate::memory::segments::Segment::KernelGeneral;
|
||||
|
||||
fn reverse_bytes_u64(input: u64) -> u64 {
|
||||
let mut result = 0;
|
||||
for i in 0..8 {
|
||||
result |= ((input >> (i * 8)) & 0xff) << ((7 - i) * 8);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn convert_input(input: &str) -> Result<(u32, [u64; 8], [u64; 16], u64, u64, bool)> {
|
||||
let rounds = u32::from_str_radix(&input[..8], 16).unwrap();
|
||||
|
||||
let mut h = [0u64; 8];
|
||||
for i in 0..8 {
|
||||
h[i] = reverse_bytes_u64(
|
||||
u64::from_str_radix(&input[8 + i * 16..8 + (i + 1) * 16], 16).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut m = [0u64; 16];
|
||||
for i in 0..16 {
|
||||
m[i] = reverse_bytes_u64(
|
||||
u64::from_str_radix(&input[136 + i * 16..136 + (i + 1) * 16], 16).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let t_0 = reverse_bytes_u64(u64::from_str_radix(&input[392..408], 16).unwrap());
|
||||
let t_1 = reverse_bytes_u64(u64::from_str_radix(&input[408..424], 16).unwrap());
|
||||
let flag = u8::from_str_radix(&input[424..426], 16).unwrap() != 0;
|
||||
|
||||
Ok((rounds, h, m, t_0, t_1, flag))
|
||||
}
|
||||
|
||||
fn convert_output(output: [u64; 8]) -> String {
|
||||
output
|
||||
.iter()
|
||||
.map(|&x| format!("{:016x}", reverse_bytes_u64(x)))
|
||||
.collect::<Vec<_>>()
|
||||
.join("")
|
||||
}
|
||||
|
||||
fn run_blake2_f(
|
||||
rounds: u32,
|
||||
h: [u64; 8],
|
||||
m: [u64; 16],
|
||||
t_0: u64,
|
||||
t_1: u64,
|
||||
flag: bool,
|
||||
) -> Result<[u64; 8]> {
|
||||
let mut stack = vec![];
|
||||
stack.push(rounds.into());
|
||||
stack.append(&mut h.iter().map(|&x| x.into()).collect());
|
||||
stack.append(&mut m.iter().map(|&x| x.into()).collect());
|
||||
stack.push(t_0.into());
|
||||
stack.push(t_1.into());
|
||||
stack.push(u8::from(flag).into());
|
||||
stack.push(0xDEADBEEFu32.into());
|
||||
|
||||
let interpreter_setup = InterpreterMemoryInitialization {
|
||||
label: "blake2_f".to_string(),
|
||||
stack,
|
||||
segment: KernelGeneral,
|
||||
memory: vec![],
|
||||
};
|
||||
|
||||
let result = run_interpreter_with_memory(interpreter_setup).unwrap();
|
||||
let mut hash = result.stack().to_vec();
|
||||
hash.reverse();
|
||||
|
||||
Ok(hash
|
||||
.iter()
|
||||
.map(|&x| x.as_u64())
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap())
|
||||
}
|
||||
|
||||
// Test data from EIP-152.
|
||||
|
||||
fn test_blake2_f_eip(input: &str, output: &str) -> Result<()> {
|
||||
let (rounds, h, m, t_0, t_1, flag) = convert_input(input).unwrap();
|
||||
let result = run_blake2_f(rounds, h, m, t_0, t_1, flag).unwrap();
|
||||
assert_eq!(convert_output(result), output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2_f_4() -> Result<()> {
|
||||
test_blake2_f_eip(
|
||||
"0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||
"08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2_f_5() -> Result<()> {
|
||||
test_blake2_f_eip(
|
||||
"0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||
"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2_f_6() -> Result<()> {
|
||||
test_blake2_f_eip(
|
||||
"0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000",
|
||||
"75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2_f_7() -> Result<()> {
|
||||
test_blake2_f_eip(
|
||||
"0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||
"b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421",
|
||||
)
|
||||
}
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn test_blake2_f_8() -> Result<()> {
|
||||
test_blake2_f_eip(
|
||||
"ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||
"fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615",
|
||||
)
|
||||
}
|
||||
@ -99,12 +99,12 @@ fn test_insert_accessed_storage_keys() -> Result<()> {
|
||||
let mut rng = thread_rng();
|
||||
let n = rng.gen_range(1..10);
|
||||
let storage_keys = (0..n)
|
||||
.map(|_| (rng.gen::<Address>(), U256(rng.gen())))
|
||||
.map(|_| (rng.gen::<Address>(), U256(rng.gen()), U256(rng.gen())))
|
||||
.collect::<HashSet<_>>()
|
||||
.into_iter()
|
||||
.collect::<Vec<(Address, U256)>>();
|
||||
.collect::<Vec<(Address, U256, U256)>>();
|
||||
let storage_key_in_list = storage_keys[rng.gen_range(0..n)];
|
||||
let storage_key_not_in_list = (rng.gen::<Address>(), U256(rng.gen()));
|
||||
let storage_key_not_in_list = (rng.gen::<Address>(), U256(rng.gen()), U256(rng.gen()));
|
||||
assert!(
|
||||
!storage_keys.contains(&storage_key_not_in_list),
|
||||
"Cosmic luck or bad RNG?"
|
||||
@ -113,6 +113,7 @@ fn test_insert_accessed_storage_keys() -> Result<()> {
|
||||
// Test for storage key already in list.
|
||||
let initial_stack = vec![
|
||||
retaddr,
|
||||
storage_key_in_list.2,
|
||||
storage_key_in_list.1,
|
||||
U256::from(storage_key_in_list.0 .0.as_slice()),
|
||||
];
|
||||
@ -122,30 +123,35 @@ fn test_insert_accessed_storage_keys() -> Result<()> {
|
||||
interpreter
|
||||
.generation_state
|
||||
.memory
|
||||
.set(MemoryAddress::new(0, AccessedStorageKeys, 2 * i), addr);
|
||||
.set(MemoryAddress::new(0, AccessedStorageKeys, 3 * i), addr);
|
||||
interpreter.generation_state.memory.set(
|
||||
MemoryAddress::new(0, AccessedStorageKeys, 2 * i + 1),
|
||||
MemoryAddress::new(0, AccessedStorageKeys, 3 * i + 1),
|
||||
storage_keys[i].1,
|
||||
);
|
||||
interpreter.generation_state.memory.set(
|
||||
MemoryAddress::new(0, AccessedStorageKeys, 3 * i + 2),
|
||||
storage_keys[i].2,
|
||||
);
|
||||
}
|
||||
interpreter.generation_state.memory.set(
|
||||
MemoryAddress::new(0, GlobalMetadata, AccessedStorageKeysLen as usize),
|
||||
U256::from(2 * n),
|
||||
U256::from(3 * n),
|
||||
);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), &[U256::zero()]);
|
||||
assert_eq!(interpreter.stack(), &[storage_key_in_list.2, U256::zero()]);
|
||||
assert_eq!(
|
||||
interpreter.generation_state.memory.get(MemoryAddress::new(
|
||||
0,
|
||||
GlobalMetadata,
|
||||
AccessedStorageKeysLen as usize
|
||||
)),
|
||||
U256::from(2 * n)
|
||||
U256::from(3 * n)
|
||||
);
|
||||
|
||||
// Test for storage key not in list.
|
||||
let initial_stack = vec![
|
||||
retaddr,
|
||||
storage_key_not_in_list.2,
|
||||
storage_key_not_in_list.1,
|
||||
U256::from(storage_key_not_in_list.0 .0.as_slice()),
|
||||
];
|
||||
@ -155,41 +161,56 @@ fn test_insert_accessed_storage_keys() -> Result<()> {
|
||||
interpreter
|
||||
.generation_state
|
||||
.memory
|
||||
.set(MemoryAddress::new(0, AccessedStorageKeys, 2 * i), addr);
|
||||
.set(MemoryAddress::new(0, AccessedStorageKeys, 3 * i), addr);
|
||||
interpreter.generation_state.memory.set(
|
||||
MemoryAddress::new(0, AccessedStorageKeys, 2 * i + 1),
|
||||
MemoryAddress::new(0, AccessedStorageKeys, 3 * i + 1),
|
||||
storage_keys[i].1,
|
||||
);
|
||||
interpreter.generation_state.memory.set(
|
||||
MemoryAddress::new(0, AccessedStorageKeys, 3 * i + 2),
|
||||
storage_keys[i].2,
|
||||
);
|
||||
}
|
||||
interpreter.generation_state.memory.set(
|
||||
MemoryAddress::new(0, GlobalMetadata, AccessedStorageKeysLen as usize),
|
||||
U256::from(2 * n),
|
||||
U256::from(3 * n),
|
||||
);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), &[U256::one()]);
|
||||
assert_eq!(
|
||||
interpreter.stack(),
|
||||
&[storage_key_not_in_list.2, U256::one()]
|
||||
);
|
||||
assert_eq!(
|
||||
interpreter.generation_state.memory.get(MemoryAddress::new(
|
||||
0,
|
||||
GlobalMetadata,
|
||||
AccessedStorageKeysLen as usize
|
||||
)),
|
||||
U256::from(2 * (n + 1))
|
||||
U256::from(3 * (n + 1))
|
||||
);
|
||||
assert_eq!(
|
||||
interpreter
|
||||
.generation_state
|
||||
.memory
|
||||
.get(MemoryAddress::new(0, AccessedStorageKeys, 2 * n,)),
|
||||
.get(MemoryAddress::new(0, AccessedStorageKeys, 3 * n,)),
|
||||
U256::from(storage_key_not_in_list.0 .0.as_slice())
|
||||
);
|
||||
assert_eq!(
|
||||
interpreter.generation_state.memory.get(MemoryAddress::new(
|
||||
0,
|
||||
AccessedStorageKeys,
|
||||
2 * n + 1,
|
||||
3 * n + 1,
|
||||
)),
|
||||
storage_key_not_in_list.1
|
||||
);
|
||||
assert_eq!(
|
||||
interpreter.generation_state.memory.get(MemoryAddress::new(
|
||||
0,
|
||||
AccessedStorageKeys,
|
||||
3 * n + 2,
|
||||
)),
|
||||
storage_key_not_in_list.2
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use blake2::Blake2b512;
|
||||
use ethereum_types::{U256, U512};
|
||||
// use blake2::Blake2b512;
|
||||
use ethereum_types::U256;
|
||||
use rand::{thread_rng, Rng};
|
||||
use ripemd::{Digest, Ripemd160};
|
||||
use sha2::Sha256;
|
||||
@ -10,13 +10,6 @@ use crate::cpu::kernel::interpreter::{
|
||||
};
|
||||
use crate::memory::segments::Segment::KernelGeneral;
|
||||
|
||||
/// Standard Blake2b implementation.
|
||||
fn blake2b(input: Vec<u8>) -> U512 {
|
||||
let mut hasher = Blake2b512::new();
|
||||
hasher.update(input);
|
||||
U512::from(&hasher.finalize()[..])
|
||||
}
|
||||
|
||||
/// Standard RipeMD implementation.
|
||||
fn ripemd(input: Vec<u8>) -> U256 {
|
||||
let mut hasher = Ripemd160::new();
|
||||
@ -58,10 +51,6 @@ fn make_interpreter_setup(
|
||||
}
|
||||
}
|
||||
|
||||
fn combine_u256s(hi: U256, lo: U256) -> U512 {
|
||||
U512::from(lo) + (U512::from(hi) << 256)
|
||||
}
|
||||
|
||||
fn prepare_test<T>(
|
||||
hash_fn_label: &str,
|
||||
hash_input_virt: (usize, usize),
|
||||
@ -99,28 +88,6 @@ fn test_hash_256(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn test_hash_512(
|
||||
hash_fn_label: &str,
|
||||
hash_input_virt: (usize, usize),
|
||||
standard_implementation: &dyn Fn(Vec<u8>) -> U512,
|
||||
) -> Result<()> {
|
||||
let (expected, result_stack) =
|
||||
prepare_test(hash_fn_label, hash_input_virt, standard_implementation).unwrap();
|
||||
|
||||
// Extract the final output.
|
||||
let actual = combine_u256s(result_stack[0], result_stack[1]);
|
||||
|
||||
// Check that the result is correct.
|
||||
assert_eq!(expected, actual);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2b() -> Result<()> {
|
||||
test_hash_512("blake2b", (0, 2), &blake2b)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ripemd() -> Result<()> {
|
||||
test_hash_256("ripemd", (200, 200), &ripemd)
|
||||
@ -130,3 +97,40 @@ fn test_ripemd() -> Result<()> {
|
||||
fn test_sha2() -> Result<()> {
|
||||
test_hash_256("sha2", (0, 1), &sha2)
|
||||
}
|
||||
|
||||
// Since the Blake precompile requires only the blake2_f compression function instead of the full blake2b hash,
|
||||
// the full hash function is not included in the kernel. To include it, blake2/compression.asm and blake2/main.asm
|
||||
// must be added to the kernel.
|
||||
|
||||
// /// Standard Blake2b implementation.
|
||||
// fn blake2b(input: Vec<u8>) -> U512 {
|
||||
// let mut hasher = Blake2b512::new();
|
||||
// hasher.update(input);
|
||||
// U512::from(&hasher.finalize()[..])
|
||||
// }
|
||||
|
||||
// fn combine_u256s(hi: U256, lo: U256) -> U512 {
|
||||
// U512::from(lo) + (U512::from(hi) << 256)
|
||||
// }
|
||||
|
||||
// fn test_hash_512(
|
||||
// hash_fn_label: &str,
|
||||
// hash_input_virt: (usize, usize),
|
||||
// standard_implementation: &dyn Fn(Vec<u8>) -> U512,
|
||||
// ) -> Result<()> {
|
||||
// let (expected, result_stack) =
|
||||
// prepare_test(hash_fn_label, hash_input_virt, standard_implementation).unwrap();
|
||||
|
||||
// // Extract the final output.
|
||||
// let actual = combine_u256s(result_stack[0], result_stack[1]);
|
||||
|
||||
// // Check that the result is correct.
|
||||
// assert_eq!(expected, actual);
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn test_blake2b() -> Result<()> {
|
||||
// test_hash_512("blake2b", (0, 2), &blake2b)
|
||||
// }
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
mod account_code;
|
||||
mod balance;
|
||||
mod bignum;
|
||||
mod blake2_f;
|
||||
mod bls381;
|
||||
mod bn254;
|
||||
mod core;
|
||||
|
||||
@ -31,6 +31,7 @@ plonky2_util = { version = "0.1.0", default-features = false }
|
||||
rand = { version = "0.8.4", default-features = false }
|
||||
rand_chacha = { version = "0.3.1", optional = true, default-features = false }
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
static_assertions = { version = "1.1.0", default-features = false }
|
||||
unroll = { version = "0.1.5", default-features = false }
|
||||
|
||||
|
||||
79
plonky2/examples/fibonacci_serialization.rs
Normal file
79
plonky2/examples/fibonacci_serialization.rs
Normal file
@ -0,0 +1,79 @@
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
use std::fs;
|
||||
|
||||
use anyhow::Result;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
/// An example of using Plonky2 to prove a statement of the form
|
||||
/// "I know the 100th element of the Fibonacci sequence, starting with constants a and b."
|
||||
/// When a == 0 and b == 1, this is proving knowledge of the 100th (standard) Fibonacci number.
|
||||
/// This example also serializes the circuit data and proof to JSON files.
|
||||
fn main() -> Result<()> {
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
// The arithmetic circuit.
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
let mut prev_target = initial_a;
|
||||
let mut cur_target = initial_b;
|
||||
for _ in 0..99 {
|
||||
let temp = builder.add(prev_target, cur_target);
|
||||
prev_target = cur_target;
|
||||
cur_target = temp;
|
||||
}
|
||||
|
||||
// Public inputs are the two initial values (provided below) and the result (which is generated).
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(cur_target);
|
||||
|
||||
// Provide initial values.
|
||||
let mut pw = PartialWitness::new();
|
||||
pw.set_target(initial_a, F::ZERO);
|
||||
pw.set_target(initial_b, F::ONE);
|
||||
|
||||
let data = builder.build::<C>();
|
||||
|
||||
let common_circuit_data_serialized = serde_json::to_string(&data.common).unwrap();
|
||||
fs::write("common_circuit_data.json", common_circuit_data_serialized)
|
||||
.expect("Unable to write file");
|
||||
|
||||
let verifier_only_circuit_data_serialized = serde_json::to_string(&data.verifier_only).unwrap();
|
||||
fs::write(
|
||||
"verifier_only_circuit_data.json",
|
||||
verifier_only_circuit_data_serialized,
|
||||
)
|
||||
.expect("Unable to write file");
|
||||
|
||||
let proof = data.prove(pw)?;
|
||||
|
||||
let proof_serialized = serde_json::to_string(&proof).unwrap();
|
||||
fs::write("proof_with_public_inputs.json", proof_serialized).expect("Unable to write file");
|
||||
|
||||
let proof_challenges = proof
|
||||
.get_challenges(
|
||||
proof.get_public_inputs_hash(),
|
||||
&data.verifier_only.circuit_digest,
|
||||
&data.common,
|
||||
)
|
||||
.unwrap();
|
||||
let proof_challenges_serialized = serde_json::to_string(&proof_challenges).unwrap();
|
||||
fs::write("proof_challenges.json", proof_challenges_serialized).expect("Unable to write file");
|
||||
|
||||
println!(
|
||||
"100th Fibonacci number mod |F| (starting with {}, {}) is: {}",
|
||||
proof.public_inputs[0], proof.public_inputs[1], proof.public_inputs[2]
|
||||
);
|
||||
|
||||
data.verify(proof)
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::fri::reduction_strategies::FriReductionStrategy;
|
||||
|
||||
mod challenges;
|
||||
@ -13,7 +15,7 @@ mod validate_shape;
|
||||
pub mod verifier;
|
||||
pub mod witness_util;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||
pub struct FriConfig {
|
||||
/// `rate = 2^{-rate_bits}`.
|
||||
pub rate_bits: usize,
|
||||
@ -56,7 +58,7 @@ impl FriConfig {
|
||||
|
||||
/// FRI parameters, including generated parameters which are specific to an instance size, in
|
||||
/// contrast to `FriConfig` which is user-specified and independent of instance size.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||
pub struct FriParams {
|
||||
/// User-specified FRI configuration.
|
||||
pub config: FriConfig,
|
||||
|
||||
@ -393,6 +393,7 @@ impl<F: RichField + Extendable<D>, HCO: HashConfig, H: Hasher<F, HCO>, const D:
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct FriChallenges<F: RichField + Extendable<D>, const D: usize> {
|
||||
// Scaling factor to combine polynomials.
|
||||
pub fri_alpha: F::Extension,
|
||||
|
||||
@ -4,9 +4,10 @@ use alloc::vec::Vec;
|
||||
use std::time::Instant;
|
||||
|
||||
use log::debug;
|
||||
use serde::Serialize;
|
||||
|
||||
/// A method for deciding what arity to use at each reduction layer.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||
pub enum FriReductionStrategy {
|
||||
/// Specifies the exact sequence of arities (expressed in bits) to use.
|
||||
Fixed(Vec<usize>),
|
||||
|
||||
@ -2,6 +2,8 @@ use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{format, vec};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::field::extension::Extendable;
|
||||
use crate::field::packed::PackedField;
|
||||
use crate::gates::gate::Gate;
|
||||
@ -18,7 +20,7 @@ use crate::plonk::vars::{
|
||||
use crate::util::serialization::{Buffer, IoResult, Read, Write};
|
||||
|
||||
/// A gate which takes a single constant parameter and outputs that value.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ConstantGate {
|
||||
pub(crate) num_consts: usize,
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ use core::hash::{Hash, Hasher};
|
||||
use core::ops::Range;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use crate::field::batch_util::batch_multiply_inplace;
|
||||
use crate::field::extension::{Extendable, FieldExtension};
|
||||
@ -239,6 +240,12 @@ impl<F: RichField + Extendable<D>, const D: usize> Debug for GateRef<F, D> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> Serialize for GateRef<F, D> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
serializer.serialize_str(&self.0.id())
|
||||
}
|
||||
}
|
||||
|
||||
/// Map between gate parameters and available slots.
|
||||
/// An available slot is of the form `(row, op)`, meaning the current available slot
|
||||
/// is at gate index `row` in the `op`-th operation.
|
||||
|
||||
@ -2,6 +2,8 @@ use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::Range;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::field::extension::Extendable;
|
||||
use crate::field::polynomial::PolynomialValues;
|
||||
use crate::gates::gate::{GateInstance, GateRef};
|
||||
@ -10,7 +12,7 @@ use crate::hash::hash_types::RichField;
|
||||
/// Placeholder value to indicate that a gate doesn't use a selector polynomial.
|
||||
pub(crate) const UNUSED_SELECTOR: usize = u32::MAX as usize;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||
pub struct SelectorsInfo {
|
||||
pub(crate) selector_indices: Vec<usize>,
|
||||
pub(crate) groups: Vec<Range<usize>>,
|
||||
|
||||
@ -4,6 +4,7 @@ use alloc::vec::Vec;
|
||||
use core::ops::{Range, RangeFrom};
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::field::extension::Extendable;
|
||||
use crate::field::fft::FftRootTable;
|
||||
@ -35,7 +36,7 @@ use crate::util::serialization::{
|
||||
};
|
||||
use crate::util::timing::TimingTree;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct CircuitConfig {
|
||||
pub num_wires: usize,
|
||||
pub num_routed_wires: usize,
|
||||
@ -347,7 +348,7 @@ pub struct ProverOnlyCircuitData<
|
||||
}
|
||||
|
||||
/// Circuit data required by the verifier, but not the prover.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||
pub struct VerifierOnlyCircuitData<C: GenericConfig<D>, const D: usize> {
|
||||
/// A commitment to each constant polynomial and each permutation polynomial.
|
||||
pub constants_sigmas_cap: MerkleCap<C::F, C::HCO, C::Hasher>,
|
||||
@ -370,7 +371,7 @@ impl<C: GenericConfig<D>, const D: usize> VerifierOnlyCircuitData<C, D> {
|
||||
}
|
||||
|
||||
/// Circuit data required by both the prover and the verifier.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||
pub struct CommonCircuitData<F: RichField + Extendable<D>, const D: usize> {
|
||||
pub config: CircuitConfig,
|
||||
|
||||
|
||||
@ -117,7 +117,7 @@ impl HashConfig for PoseidonHashConfig {
|
||||
const WIDTH: usize = 12;
|
||||
}
|
||||
/// Configuration using Poseidon over the Goldilocks field.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize)]
|
||||
pub struct PoseidonGoldilocksConfig;
|
||||
impl GenericConfig<2> for PoseidonGoldilocksConfig {
|
||||
type F = GoldilocksField;
|
||||
|
||||
@ -94,7 +94,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
}
|
||||
|
||||
/// Computes all Fiat-Shamir challenges used in the Plonk proof.
|
||||
pub(crate) fn get_challenges(
|
||||
pub fn get_challenges(
|
||||
&self,
|
||||
public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F, C::HCI>>::Hash,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F, C::HCO>>::Hash,
|
||||
|
||||
@ -102,7 +102,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_public_inputs_hash(
|
||||
pub fn get_public_inputs_hash(
|
||||
&self,
|
||||
) -> <<C as GenericConfig<D>>::InnerHasher as Hasher<F, C::HCI>>::Hash
|
||||
where
|
||||
@ -276,7 +276,8 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ProofChallenges<F: RichField + Extendable<D>, const D: usize> {
|
||||
#[derive(Serialize)]
|
||||
pub struct ProofChallenges<F: RichField + Extendable<D>, const D: usize> {
|
||||
/// Random values used in Plonk's permutation argument.
|
||||
pub plonk_betas: Vec<F>,
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user