-
Notifications
You must be signed in to change notification settings - Fork 286
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add native implementation of BLAKE2bf precompile (#857)
- Adds the implementation of the BLAKE2b compress function F following the [RFC 7693](https://datatracker.ietf.org/doc/html/rfc7693). - Implements [EIP-152](https://eips.ethereum.org/EIPS/eip-152) "BLAKE2 compression function `F` precompile" by exposing the `evmone::crypto::blake2b_compress()`. - Do not cache this precompile.
- Loading branch information
Showing
10 changed files
with
217 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// evmone: Fast Ethereum Virtual Machine implementation | ||
// Copyright 2024 The evmone Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#include "blake2b.hpp" | ||
#include <array> | ||
#include <bit> | ||
|
||
namespace evmone::crypto | ||
{ | ||
void blake2b_compress( | ||
uint32_t rounds, uint64_t h[8], const uint64_t m[16], const uint64_t t[2], bool last) noexcept | ||
{ | ||
// Message Schedule SIGMA. | ||
// https://datatracker.ietf.org/doc/html/rfc7693#section-2.7 | ||
static constexpr uint8_t sigma[10][16]{ | ||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, | ||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, | ||
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, | ||
{7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, | ||
{9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, | ||
{2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, | ||
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, | ||
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, | ||
{6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, | ||
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, | ||
}; | ||
|
||
// Mixing Function G. | ||
// https://datatracker.ietf.org/doc/html/rfc7693#section-3.1 | ||
// | ||
// The G primitive function mixes two input words, "x" and "y", into | ||
// four words indexed by "a", "b", "c", and "d" in the working vector v[0..15]. | ||
static constexpr auto g = [](uint64_t v[16], size_t a, size_t b, size_t c, size_t d, uint64_t x, | ||
uint64_t y) noexcept { | ||
v[a] = v[a] + v[b] + x; | ||
v[d] = std::rotr(v[d] ^ v[a], 32); | ||
v[c] = v[c] + v[d]; | ||
v[b] = std::rotr(v[b] ^ v[c], 24); | ||
v[a] = v[a] + v[b] + y; | ||
v[d] = std::rotr(v[d] ^ v[a], 16); | ||
v[c] = v[c] + v[d]; | ||
v[b] = std::rotr(v[b] ^ v[c], 63); | ||
}; | ||
|
||
// Initialize local work vector v[0..15]. | ||
uint64_t v[16]{h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], // First half from state. | ||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, // Second half from IV. | ||
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, | ||
0x510e527fade682d1 ^ t[0], // Low word of the offset. | ||
0x9b05688c2b3e6c1f ^ t[1], // High word. | ||
0x1f83d9abfb41bd6b ^ (0 - uint64_t{last}), // Last block flag? Invert all bits. | ||
0x5be0cd19137e2179}; | ||
|
||
// Cryptographic mixing. | ||
for (size_t i = 0; i < rounds; ++i) | ||
{ | ||
// Message word selection permutation for this round. | ||
const auto& s = sigma[i % std::size(sigma)]; | ||
|
||
g(v, 0, 4, 8, 12, m[s[0]], m[s[1]]); | ||
g(v, 1, 5, 9, 13, m[s[2]], m[s[3]]); | ||
g(v, 2, 6, 10, 14, m[s[4]], m[s[5]]); | ||
g(v, 3, 7, 11, 15, m[s[6]], m[s[7]]); | ||
g(v, 0, 5, 10, 15, m[s[8]], m[s[9]]); | ||
g(v, 1, 6, 11, 12, m[s[10]], m[s[11]]); | ||
g(v, 2, 7, 8, 13, m[s[12]], m[s[13]]); | ||
g(v, 3, 4, 9, 14, m[s[14]], m[s[15]]); | ||
} | ||
|
||
for (size_t i = 0; i < 8; ++i) // XOR the two halves. | ||
h[i] ^= v[i] ^ v[i + 8]; | ||
} | ||
} // namespace evmone::crypto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// evmone: Fast Ethereum Virtual Machine implementation | ||
// Copyright 2024 The evmone Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
#pragma once | ||
#include <cstddef> | ||
#include <cstdint> | ||
|
||
namespace evmone::crypto | ||
{ | ||
/// BLAKE2b compress function F. | ||
/// https://datatracker.ietf.org/doc/html/rfc7693#section-3.2 | ||
/// | ||
/// @param rounds the number of rounds to perform | ||
/// @param[in,out] h the state vector | ||
/// @param m the block vector | ||
/// @param t the 128-bit offset counter, {low word, high word} | ||
/// @param last the final block indicator flag "f" | ||
void blake2b_compress( | ||
uint32_t rounds, uint64_t h[8], const uint64_t m[16], const uint64_t t[2], bool last) noexcept; | ||
} // namespace evmone::crypto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// evmone: Fast Ethereum Virtual Machine implementation | ||
// Copyright 2024 The evmone Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#include "../utils/utils.hpp" | ||
#include <evmc/hex.hpp> | ||
#include <evmone_precompiles/blake2b.hpp> | ||
#include <gtest/gtest.h> | ||
#include <array> | ||
#include <cstring> | ||
|
||
using evmone::crypto::blake2b_compress; | ||
|
||
// Initialization Vector. | ||
// https://datatracker.ietf.org/doc/html/rfc7693#appendix-C.2 | ||
constexpr std::array<uint64_t, 8> blake2b_iv{ | ||
0x6a09e667f3bcc908, | ||
0xbb67ae8584caa73b, | ||
0x3c6ef372fe94f82b, | ||
0xa54ff53a5f1d36f1, | ||
0x510e527fade682d1, | ||
0x9b05688c2b3e6c1f, | ||
0x1f83d9abfb41bd6b, | ||
0x5be0cd19137e2179, | ||
}; | ||
|
||
TEST(blake2b_compress, reference_test) | ||
{ | ||
// The reference test from the RFC. | ||
// https://datatracker.ietf.org/doc/html/rfc7693#appendix-A | ||
// with some extensions by modifying the "rounds" and "last" values. | ||
|
||
auto h_init = blake2b_iv; | ||
h_init[0] ^= 0x01010000 ^ /*outlen = */ 64; | ||
|
||
const std::string_view data = "abc"; | ||
uint64_t m[16]{}; | ||
std::memcpy(m, data.data(), data.size()); | ||
|
||
const uint64_t t[2]{data.size(), 0}; | ||
|
||
auto h = h_init; | ||
blake2b_compress(12, h.data(), m, t, true); | ||
EXPECT_EQ(hex({reinterpret_cast<const uint8_t*>(h.data()), sizeof(h)}), | ||
"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1" | ||
"7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"); | ||
|
||
// https://github.com/ethereum/tests/blob/v13.2/src/GeneralStateTestsFiller/stPreCompiledContracts/blake2BFiller.yml#L301-L302 | ||
h = h_init; | ||
blake2b_compress(12, h.data(), m, t, false); | ||
EXPECT_EQ(hex({reinterpret_cast<const uint8_t*>(h.data()), sizeof(h)}), | ||
"75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d28752" | ||
"98743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735"); | ||
|
||
// https://github.com/ethereum/tests/blob/v13.2/src/GeneralStateTestsFiller/stPreCompiledContracts/blake2BFiller.yml#L268-L269 | ||
h = h_init; | ||
blake2b_compress(0, h.data(), m, t, true); | ||
EXPECT_EQ(hex({reinterpret_cast<const uint8_t*>(h.data()), sizeof(h)}), | ||
"08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5" | ||
"d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b"); | ||
|
||
// this gives the same result because the xor zeros out the "last" flag | ||
h = h_init; | ||
blake2b_compress(0, h.data(), m, t, false); | ||
EXPECT_EQ(hex({reinterpret_cast<const uint8_t*>(h.data()), sizeof(h)}), | ||
"08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5" | ||
"d282e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b"); | ||
} | ||
|
||
TEST(blake2b_compress, null_input) | ||
{ | ||
std::array<uint64_t, 8> h{}; | ||
const uint64_t t[2]{}; | ||
|
||
// the data block is unused so be pass nullptr. | ||
blake2b_compress(0, h.data(), nullptr, t, false); | ||
|
||
// For null input you get the IV as the result. | ||
EXPECT_EQ(h, blake2b_iv); | ||
} |