Skip to content
This repository was archived by the owner on Oct 28, 2021. It is now read-only.

Commit f57fa86

Browse files
authored
Implement EIP-152: Add Blake2 compression function F precompile (#5751)
Implement EIP-152: Add Blake2 compression function F precompile
2 parents 9aa1e6d + f2b08b7 commit f57fa86

File tree

7 files changed

+375
-2
lines changed

7 files changed

+375
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- Added: [#5701](https://github.com/ethereum/aleth/issues/5701) Outputs ENR text representation in admin.nodeInfo RPC.
2121
- Added: [#5705](https://github.com/ethereum/aleth/pull/5705) Istanbul support: EIP 1108 Reduce alt_bn128 precompile gas costs.
2222
- Added: [#5707](https://github.com/ethereum/aleth/pull/5707) Aleth waits for 2 seconds after sending disconnect to peer before closing socket.
23+
- Added: [#5751](https://github.com/ethereum/aleth/pull/5751) Istanbul support: EIP-152 Add BLAKE2 compression function `F` precompile.
2324
- Changed: [#5532](https://github.com/ethereum/aleth/pull/5532) The leveldb is upgraded to 1.22. This is breaking change on Windows and the old databases are not compatible.
2425
- Changed: [#5559](https://github.com/ethereum/aleth/pull/5559) Update peer validation error messages.
2526
- Changed: [#5568](https://github.com/ethereum/aleth/pull/5568) Improve rlpx handshake log messages and create new rlpx log channel.

libdevcrypto/Blake2.cpp

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/// Aleth: Ethereum C++ client, tools and libraries.
2+
// Copyright 2019 Aleth Authors.
3+
// Licensed under the GNU General Public License, Version 3.
4+
5+
#include "Blake2.h"
6+
7+
#include <libdevcore/Exceptions.h>
8+
9+
// The Blake 2 F compression function implemenation is based on the reference implementation,
10+
// see https://github.com/BLAKE2/BLAKE2/blob/master/ref/blake2b-ref.c
11+
// The changes in original code were done mostly to accommodate variable round number and to remove
12+
// unnecessary big endian support.
13+
14+
namespace dev
15+
{
16+
namespace crypto
17+
{
18+
namespace
19+
{
20+
DEV_SIMPLE_EXCEPTION(InvalidInputSize);
21+
22+
constexpr size_t BLAKE2B_BLOCKBYTES = 128;
23+
24+
struct blake2b_state
25+
{
26+
uint64_t h[8];
27+
uint64_t t[2];
28+
uint64_t f[2];
29+
uint8_t buf[BLAKE2B_BLOCKBYTES];
30+
size_t buflen;
31+
size_t outlen;
32+
uint8_t last_node;
33+
};
34+
35+
// clang-format off
36+
constexpr uint64_t blake2b_IV[8] =
37+
{
38+
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
39+
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
40+
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
41+
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
42+
};
43+
44+
constexpr uint8_t blake2b_sigma[12][16] =
45+
{
46+
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
47+
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
48+
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
49+
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
50+
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
51+
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
52+
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
53+
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
54+
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
55+
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
56+
};
57+
// clang-format on
58+
59+
inline uint64_t load64(const void* src) noexcept
60+
{
61+
uint64_t w;
62+
memcpy(&w, src, sizeof w);
63+
return w;
64+
}
65+
66+
inline constexpr uint64_t rotr64(uint64_t w, unsigned c) noexcept
67+
{
68+
return (w >> c) | (w << (64 - c));
69+
}
70+
71+
inline void G(uint8_t r, uint8_t i, uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d,
72+
const uint64_t* m) noexcept
73+
{
74+
a = a + b + m[blake2b_sigma[r][2 * i + 0]];
75+
d = rotr64(d ^ a, 32);
76+
c = c + d;
77+
b = rotr64(b ^ c, 24);
78+
a = a + b + m[blake2b_sigma[r][2 * i + 1]];
79+
d = rotr64(d ^ a, 16);
80+
c = c + d;
81+
b = rotr64(b ^ c, 63);
82+
}
83+
84+
inline void ROUND(uint32_t round, uint64_t* v, const uint64_t* m) noexcept
85+
{
86+
uint8_t const r = round % 10;
87+
G(r, 0, v[0], v[4], v[8], v[12], m);
88+
G(r, 1, v[1], v[5], v[9], v[13], m);
89+
G(r, 2, v[2], v[6], v[10], v[14], m);
90+
G(r, 3, v[3], v[7], v[11], v[15], m);
91+
G(r, 4, v[0], v[5], v[10], v[15], m);
92+
G(r, 5, v[1], v[6], v[11], v[12], m);
93+
G(r, 6, v[2], v[7], v[8], v[13], m);
94+
G(r, 7, v[3], v[4], v[9], v[14], m);
95+
}
96+
97+
98+
void blake2b_compress(
99+
uint32_t rounds, blake2b_state* S, const uint8_t block[BLAKE2B_BLOCKBYTES]) noexcept
100+
{
101+
uint64_t m[16];
102+
uint64_t v[16];
103+
104+
for (size_t i = 0; i < 16; ++i)
105+
m[i] = load64(block + i * sizeof(m[i]));
106+
107+
for (size_t i = 0; i < 8; ++i)
108+
v[i] = S->h[i];
109+
110+
v[8] = blake2b_IV[0];
111+
v[9] = blake2b_IV[1];
112+
v[10] = blake2b_IV[2];
113+
v[11] = blake2b_IV[3];
114+
v[12] = blake2b_IV[4] ^ S->t[0];
115+
v[13] = blake2b_IV[5] ^ S->t[1];
116+
v[14] = blake2b_IV[6] ^ S->f[0];
117+
v[15] = blake2b_IV[7] ^ S->f[1];
118+
119+
for (uint32_t r = 0; r < rounds; ++r)
120+
ROUND(r, v, m);
121+
122+
for (size_t i = 0; i < 8; ++i)
123+
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
124+
}
125+
126+
} // namespace
127+
128+
129+
bytes blake2FCompression(uint32_t _rounds, bytesConstRef _stateVector, bytesConstRef _t0,
130+
bytesConstRef _t1, bool _lastBlock, bytesConstRef _messageBlockVector)
131+
{
132+
if (_stateVector.size() != sizeof(blake2b_state::h))
133+
BOOST_THROW_EXCEPTION(InvalidInputSize());
134+
135+
blake2b_state s{};
136+
std::memcpy(&s.h, _stateVector.data(), _stateVector.size());
137+
138+
if (_t0.size() != sizeof(s.t[0]) || _t1.size() != sizeof(s.t[1]))
139+
BOOST_THROW_EXCEPTION(InvalidInputSize());
140+
141+
s.t[0] = load64(_t0.data());
142+
s.t[1] = load64(_t1.data());
143+
s.f[0] = _lastBlock ? std::numeric_limits<uint64_t>::max() : 0;
144+
145+
if (_messageBlockVector.size() != BLAKE2B_BLOCKBYTES)
146+
BOOST_THROW_EXCEPTION(InvalidInputSize());
147+
148+
uint8_t block[BLAKE2B_BLOCKBYTES];
149+
std::copy(_messageBlockVector.begin(), _messageBlockVector.end(), &block[0]);
150+
151+
blake2b_compress(_rounds, &s, block);
152+
153+
bytes result(sizeof(s.h));
154+
std::memcpy(&result[0], &s.h[0], result.size());
155+
156+
return result;
157+
}
158+
159+
} // namespace crypto
160+
} // namespace dev

libdevcrypto/Blake2.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// Aleth: Ethereum C++ client, tools and libraries.
2+
// Copyright 2019 Aleth Authors.
3+
// Licensed under the GNU General Public License, Version 3.
4+
5+
#pragma once
6+
7+
#include <libdevcore/Common.h>
8+
9+
namespace dev
10+
{
11+
namespace crypto
12+
{
13+
/// Calculates the compression function F used in the BLAKE2 cryptographic hashing algorithm
14+
/// Throws exception in case input data has incorrect size.
15+
/// @param _rounds the number of rounds
16+
/// @param _stateVector the state vector - 8 unsigned 64-bit little-endian words
17+
/// @param _t0, _t1 offset counters - unsigned 64-bit little-endian words
18+
/// @param _lastBlock the final block indicator flag
19+
/// @param _messageBlock the message block vector - 16 unsigned 64-bit little-endian words
20+
/// @returns updated state vector with unchanged encoding (little-endian)
21+
bytes blake2FCompression(uint32_t _rounds, bytesConstRef _stateVector, bytesConstRef _t0,
22+
bytesConstRef _t1, bool _lastBlock, bytesConstRef _messageBlock);
23+
}
24+
} // namespace dev

libethashseal/genesis/test/istanbulTest.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ R"E(
4848
"0000000000000000000000000000000000000005": { "precompiled": { "name": "modexp" } },
4949
"0000000000000000000000000000000000000006": { "precompiled": { "name": "alt_bn128_G1_add" } },
5050
"0000000000000000000000000000000000000007": { "precompiled": { "name": "alt_bn128_G1_mul" } },
51-
"0000000000000000000000000000000000000008": { "precompiled": { "name": "alt_bn128_pairing_product" } }
51+
"0000000000000000000000000000000000000008": { "precompiled": { "name": "alt_bn128_pairing_product" } },
52+
"0000000000000000000000000000000000000009": { "precompiled": { "name": "blake2_compression" } }
5253
}
5354
}
5455
)E";

libethashseal/genesis/test/istanbulTransitionTest.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ R"E(
4848
"0000000000000000000000000000000000000005": { "precompiled": { "name": "modexp" } },
4949
"0000000000000000000000000000000000000006": { "precompiled": { "name": "alt_bn128_G1_add" } },
5050
"0000000000000000000000000000000000000007": { "precompiled": { "name": "alt_bn128_G1_mul" } },
51-
"0000000000000000000000000000000000000008": { "precompiled": { "name": "alt_bn128_pairing_product"} }
51+
"0000000000000000000000000000000000000008": { "precompiled": { "name": "alt_bn128_pairing_product"} },
52+
"0000000000000000000000000000000000000009": { "precompiled": { "name": "blake2_compression", "startingBlock": "0x02" } }
5253
}
5354
}
5455
)E";

libethcore/Precompiled.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "ChainOperationParams.h"
2424
#include <libdevcore/Log.h>
2525
#include <libdevcore/SHA3.h>
26+
#include <libdevcrypto/Blake2.h>
2627
#include <libdevcrypto/Common.h>
2728
#include <libdevcrypto/Hash.h>
2829
#include <libdevcrypto/LibSnark.h>
@@ -219,4 +220,40 @@ ETH_REGISTER_PRECOMPILED_PRICER(alt_bn128_pairing_product)
219220
return _blockNumber < _chainParams.istanbulForkBlock ? 100000 + k * 80000 : 45000 + k * 34000;
220221
}
221222

223+
ETH_REGISTER_PRECOMPILED(blake2_compression)(bytesConstRef _in)
224+
{
225+
static constexpr size_t roundsSize = 4;
226+
static constexpr size_t stateVectorSize = 8 * 8;
227+
static constexpr size_t messageBlockSize = 16 * 8;
228+
static constexpr size_t offsetCounterSize = 8;
229+
static constexpr size_t finalBlockIndicatorSize = 1;
230+
static constexpr size_t totalInputSize = roundsSize + stateVectorSize + messageBlockSize +
231+
2 * offsetCounterSize + finalBlockIndicatorSize;
232+
233+
if (_in.size() != totalInputSize)
234+
return {false, {}};
235+
236+
auto const rounds = fromBigEndian<uint32_t>(_in.cropped(0, roundsSize));
237+
auto const stateVector = _in.cropped(roundsSize, stateVectorSize);
238+
auto const messageBlockVector = _in.cropped(roundsSize + stateVectorSize, messageBlockSize);
239+
auto const offsetCounter0 =
240+
_in.cropped(roundsSize + stateVectorSize + messageBlockSize, offsetCounterSize);
241+
auto const offsetCounter1 = _in.cropped(
242+
roundsSize + stateVectorSize + messageBlockSize + offsetCounterSize, offsetCounterSize);
243+
uint8_t const finalBlockIndicator =
244+
_in[roundsSize + stateVectorSize + messageBlockSize + 2 * offsetCounterSize];
245+
246+
if (finalBlockIndicator != 0 && finalBlockIndicator != 1)
247+
return {false, {}};
248+
249+
return {true, dev::crypto::blake2FCompression(rounds, stateVector, offsetCounter0,
250+
offsetCounter1, finalBlockIndicator, messageBlockVector)};
251+
}
252+
253+
ETH_REGISTER_PRECOMPILED_PRICER(blake2_compression)
254+
(bytesConstRef _in, ChainOperationParams const&, u256 const&)
255+
{
256+
auto const rounds = fromBigEndian<uint32_t>(_in.cropped(0, 4));
257+
return rounds;
258+
}
222259
}

0 commit comments

Comments
 (0)