Skip to content

Commit ed377a1

Browse files
committed
precompiles: Implement bls g2 add
Change `store` helpers naming
1 parent 07c8a0e commit ed377a1

File tree

5 files changed

+136
-17
lines changed

5 files changed

+136
-17
lines changed

circle.yml

+1
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ jobs:
375375
prague/eip2537_bls_12_381_precompiles/bls12_precompiles_before_fork
376376
prague/eip2537_bls_12_381_precompiles/bls12_g1add
377377
prague/eip2537_bls_12_381_precompiles/bls12_g1mul
378+
prague/eip2537_bls_12_381_precompiles/bls12_g2add
378379
- run:
379380
name: "Execution spec tests (develop, blockchain_tests)"
380381
# Tests for in-development EVM revision currently passing.

lib/evmone_precompiles/bls.cpp

+89-13
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ constexpr auto FP_BYTES_OFFSET = 64 - 48;
1212

1313
/// Validates p1 affine point. Checks that point coordinates are from the BLS12-381 field and
1414
/// that the point is on curve. https://eips.ethereum.org/EIPS/eip-2537#abi-for-g1-addition
15-
[[nodiscard]] std::optional<blst_p1_affine> validate_point(
15+
[[nodiscard]] std::optional<blst_p1_affine> validate_p1(
1616
const uint8_t _x[64], const uint8_t _y[64]) noexcept
1717
{
1818
constexpr auto is_field_element = [](const uint8_t _p[64]) {
@@ -36,24 +36,72 @@ constexpr auto FP_BYTES_OFFSET = 64 - 48;
3636
return p0_affine;
3737
}
3838

39-
/// Stores p1 point in two 64-bytes arrays with big endian encoding zero padded.
40-
void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
39+
/// Validates p2 affine point. Checks that point coordinates are from the BLS12-381 field and
40+
/// that the point is on curve. https://eips.ethereum.org/EIPS/eip-2537#abi-for-g2-addition
41+
[[nodiscard]] std::optional<blst_p2_affine> validate_p2(
42+
const uint8_t _x[128], const uint8_t _y[128]) noexcept
4143
{
42-
blst_p1_affine result;
43-
blst_p1_to_affine(&result, out);
44+
constexpr auto is_field_element = [](const uint8_t _p[128]) {
45+
return intx::be::unsafe::load<intx::uint512>(_p) < BLS_FIELD_MODULUS &&
46+
intx::be::unsafe::load<intx::uint512>(&_p[64]) < BLS_FIELD_MODULUS;
47+
};
48+
49+
if (!is_field_element(_x))
50+
return std::nullopt;
51+
if (!is_field_element(_y))
52+
return std::nullopt;
4453

54+
blst_fp x0;
55+
blst_fp x1;
56+
blst_fp y0;
57+
blst_fp y1;
58+
blst_fp_from_bendian(&x0, &_x[FP_BYTES_OFFSET]);
59+
blst_fp_from_bendian(&x1, &_x[FP_BYTES_OFFSET + 64]);
60+
blst_fp_from_bendian(&y0, &_y[FP_BYTES_OFFSET]);
61+
blst_fp_from_bendian(&y1, &_y[FP_BYTES_OFFSET + 64]);
62+
63+
const blst_p2_affine p_affine{{x0, x1}, {y0, y1}};
64+
if (!blst_p2_affine_on_curve(&p_affine))
65+
return std::nullopt;
66+
67+
return p_affine;
68+
}
69+
70+
/// Stores fp in 64-bytes array with big endian encoding zero padded.
71+
void store(uint8_t _rx[64], const blst_fp* _x) noexcept
72+
{
4573
std::memset(_rx, 0, FP_BYTES_OFFSET);
46-
blst_bendian_from_fp(&_rx[FP_BYTES_OFFSET], &result.x);
47-
std::memset(_ry, 0, FP_BYTES_OFFSET);
48-
blst_bendian_from_fp(&_ry[FP_BYTES_OFFSET], &result.y);
74+
blst_bendian_from_fp(&_rx[FP_BYTES_OFFSET], _x);
75+
}
76+
77+
/// Stores fp2 in 128-bytes array with big endian encoding zero padded.
78+
void store(uint8_t _rx[128], const blst_fp2* _x) noexcept
79+
{
80+
store(_rx, &_x->fp[0]);
81+
store(&_rx[64], &_x->fp[1]);
4982
}
83+
84+
/// Stores p1 affine point in two 64-bytes arrays with big endian encoding zero padded.
85+
void store(uint8_t _rx[64], uint8_t _ry[64], const blst_p1_affine* in) noexcept
86+
{
87+
store(_rx, &in->x);
88+
store(_ry, &in->y);
89+
}
90+
91+
/// Stores p2 affine point in two 128-bytes arrays with big endian encoding zero padded.
92+
void store(uint8_t _rx[128], uint8_t _ry[128], const blst_p2_affine* in) noexcept
93+
{
94+
store(_rx, &in->x);
95+
store(_ry, &in->y);
96+
}
97+
5098
} // namespace
5199

52100
[[nodiscard]] bool g1_add(uint8_t _rx[64], uint8_t _ry[64], const uint8_t _x0[64],
53101
const uint8_t _y0[64], const uint8_t _x1[64], const uint8_t _y1[64]) noexcept
54102
{
55-
const auto p0_affine = validate_point(_x0, _y0);
56-
const auto p1_affine = validate_point(_x1, _y1);
103+
const auto p0_affine = validate_p1(_x0, _y0);
104+
const auto p1_affine = validate_p1(_x1, _y1);
57105

58106
if (!p0_affine.has_value() || !p1_affine.has_value())
59107
return false;
@@ -64,7 +112,9 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
64112
blst_p1 out;
65113
blst_p1_add_or_double_affine(&out, &p0, &*p1_affine);
66114

67-
store_result(_rx, _ry, &out);
115+
blst_p1_affine result;
116+
blst_p1_to_affine(&result, &out);
117+
store(_rx, _ry, &result);
68118

69119
return true;
70120
}
@@ -75,7 +125,7 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
75125
blst_scalar scalar;
76126
blst_scalar_from_bendian(&scalar, _c);
77127

78-
const auto p_affine = validate_point(_x, _y);
128+
const auto p_affine = validate_p1(_x, _y);
79129
if (!p_affine.has_value())
80130
return false;
81131

@@ -88,8 +138,34 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
88138
blst_p1 out;
89139
blst_p1_mult(&out, &p, scalar.b, 256);
90140

91-
store_result(_rx, _ry, &out);
141+
blst_p1_affine result;
142+
blst_p1_to_affine(&result, &out);
143+
store(_rx, _ry, &result);
144+
145+
return true;
146+
}
147+
148+
[[nodiscard]] bool g2_add(uint8_t _rx[128], uint8_t _ry[128], const uint8_t _x0[128],
149+
const uint8_t _y0[128], const uint8_t _x1[128], const uint8_t _y1[128]) noexcept
150+
{
151+
const auto p0_affine = validate_p2(_x0, _y0);
152+
const auto p1_affine = validate_p2(_x1, _y1);
153+
154+
if (!p0_affine.has_value() || !p1_affine.has_value())
155+
return false;
156+
157+
blst_p2 p0;
158+
blst_p2_from_affine(&p0, &*p0_affine);
159+
160+
blst_p2 out;
161+
blst_p2_add_or_double_affine(&out, &p0, &*p1_affine);
162+
163+
blst_p2_affine result;
164+
blst_p2_to_affine(&result, &out);
165+
166+
store(_rx, _ry, &result);
92167

93168
return true;
94169
}
170+
95171
} // namespace evmone::crypto::bls

lib/evmone_precompiles/bls.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,12 @@ inline constexpr auto BLS_FIELD_MODULUS =
2323
[[nodiscard]] bool g1_mul(uint8_t _rx[64], uint8_t _ry[64], const uint8_t _x[64],
2424
const uint8_t _y[64], const uint8_t _c[32]) noexcept;
2525

26+
/// Addition in BLS12-381 curve group over G2 extension field.
27+
///
28+
/// Computes P ⊕ Q for two points in affine coordinates on the BLS12-381 curve over G2 extension
29+
/// field, performs subgroup checks for both points according to spec
30+
/// https://eips.ethereum.org/EIPS/eip-2537#abi-for-g2-addition
31+
[[nodiscard]] bool g2_add(uint8_t _rx[128], uint8_t _ry[128], const uint8_t _x0[128],
32+
const uint8_t _y0[128], const uint8_t _x1[128], const uint8_t _y1[128]) noexcept;
33+
2634
} // namespace evmone::crypto::bls

test/state/precompiles.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ PrecompileAnalysis bls12_g1msm_analyze(bytes_view, evmc_revision) noexcept
174174

175175
PrecompileAnalysis bls12_g2add_analyze(bytes_view, evmc_revision) noexcept
176176
{
177-
// TODO: Implement
178-
return {GasCostMax, 0};
177+
static constexpr auto BLS12_G2ADD_PRECOMPILE_GAS = 800;
178+
return {BLS12_G2ADD_PRECOMPILE_GAS, 256};
179179
}
180180

181181
PrecompileAnalysis bls12_g2mul_analyze(bytes_view, evmc_revision) noexcept
@@ -380,9 +380,18 @@ ExecutionResult bls12_g1msm_execute(const uint8_t*, size_t, uint8_t*, size_t) no
380380
return {EVMC_PRECOMPILE_FAILURE, 0};
381381
}
382382

383-
ExecutionResult bls12_g2add_execute(const uint8_t*, size_t, uint8_t*, size_t) noexcept
383+
ExecutionResult bls12_g2add_execute(const uint8_t* input, size_t input_size, uint8_t* output,
384+
[[maybe_unused]] size_t output_size) noexcept
384385
{
385-
return {EVMC_PRECOMPILE_FAILURE, 0};
386+
if (input_size != 512)
387+
return {EVMC_PRECOMPILE_FAILURE, 0};
388+
389+
assert(output_size == 256);
390+
391+
if (!crypto::bls::g2_add(output, &output[128], input, &input[128], &input[256], &input[384]))
392+
return {EVMC_PRECOMPILE_FAILURE, 0};
393+
394+
return {EVMC_SUCCESS, 256};
386395
}
387396

388397
ExecutionResult bls12_g2mul_execute(const uint8_t*, size_t, uint8_t*, size_t) noexcept

test/unittests/precompiles_bls_test.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,28 @@ TEST(bls, g1_mul)
9292
EXPECT_EQ(evmc::bytes_view(rx, sizeof rx), expected_x);
9393
EXPECT_EQ(evmc::bytes_view(ry, sizeof ry), expected_y);
9494
}
95+
96+
TEST(bls, g2_add)
97+
{
98+
const auto x0 =
99+
"00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e"_hex;
100+
const auto y0 =
101+
"000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be"_hex;
102+
const auto x1 =
103+
"00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68"_hex;
104+
const auto y1 =
105+
"000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451"_hex;
106+
107+
uint8_t rx[128];
108+
uint8_t ry[128];
109+
110+
EXPECT_TRUE(evmone::crypto::bls::g2_add(rx, ry, x0.data(), y0.data(), x1.data(), y1.data()));
111+
112+
const auto expected_x =
113+
"000000000000000000000000000000000b54a8a7b08bd6827ed9a797de216b8c9057b3a9ca93e2f88e7f04f19accc42da90d883632b9ca4dc38d013f71ede4db00000000000000000000000000000000077eba4eecf0bd764dce8ed5f45040dd8f3b3427cb35230509482c14651713282946306247866dfe39a8e33016fcbe52"_hex;
114+
const auto expected_y =
115+
"0000000000000000000000000000000014e60a76a29ef85cbd69f251b9f29147b67cfe3ed2823d3f9776b3a0efd2731941d47436dc6d2b58d9e65f8438bad073000000000000000000000000000000001586c3c910d95754fef7a732df78e279c3d37431c6a2b77e67a00c7c130a8fcd4d19f159cbeb997a178108fffffcbd20"_hex;
116+
117+
EXPECT_EQ(evmc::bytes_view(rx, sizeof rx), expected_x);
118+
EXPECT_EQ(evmc::bytes_view(ry, sizeof ry), expected_y);
119+
}

0 commit comments

Comments
 (0)