Merge pull request #1006 from mir-protocol/blake_precompile

Blake2_f function and precompile call
This commit is contained in:
Nicholas Ward 2023-04-28 08:29:06 -07:00 committed by GitHub
commit 7ede443e80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 557 additions and 135 deletions

View File

@ -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"),

View File

@ -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)

View File

@ -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).

View File

@ -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

View 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

View File

@ -12,4 +12,4 @@ global blake2b:
%add_const(1)
%mstore_kernel_general
// stack: retdest
%jump(blake2b_compression)
%jump(blake2_compression)

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -88,3 +88,9 @@ mstore_unpacking_finish:
%pop3
%stack (offset, value, len, retdest) -> (retdest, offset)
JUMP
%macro mstore_unpacking
%stack (addr: 3, value, len) -> (addr, value, len, %%after)
%jump(mstore_unpacking)
%%after:
%endmacro

View File

@ -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] = [

View 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",
)
}

View File

@ -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)
// }

View File

@ -1,6 +1,7 @@
mod account_code;
mod balance;
mod bignum;
mod blake2_f;
mod bls381;
mod bn254;
mod core;