Skip to content

Commit 2824aa9

Browse files
committed
precompiles: Implement bls g2 add
1 parent acfc76d commit 2824aa9

File tree

5 files changed

+123
-11
lines changed

5 files changed

+123
-11
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
- collect_coverage_gcc
379380
- upload_coverage:
380381
flags: execution_spec_tests

lib/evmone_precompiles/bls.cpp

+77-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ constexpr auto FP_BYTES_OFFSET = 64 - 48;
1414

1515
/// Validates p1 affine point. Checks that point coordinates are from the BLS12-381 field and
1616
/// that the point is on curve. https://eips.ethereum.org/EIPS/eip-2537#abi-for-g1-addition
17-
[[nodiscard]] std::optional<blst_p1_affine> validate_point(
17+
[[nodiscard]] std::optional<blst_p1_affine> validate_p1(
1818
const uint8_t _x[64], const uint8_t _y[64]) noexcept
1919
{
2020
constexpr auto is_field_element = [](const uint8_t _p[64]) {
@@ -38,8 +38,39 @@ constexpr auto FP_BYTES_OFFSET = 64 - 48;
3838
return p0_affine;
3939
}
4040

41+
/// Validates p2 affine point. Checks that point coordinates are from the BLS12-381 field and
42+
/// that the point is on curve. https://eips.ethereum.org/EIPS/eip-2537#abi-for-g2-addition
43+
[[nodiscard]] std::optional<blst_p2_affine> validate_p2(
44+
const uint8_t _x[128], const uint8_t _y[128]) noexcept
45+
{
46+
constexpr auto is_field_element = [](const uint8_t _p[128]) {
47+
return intx::be::unsafe::load<intx::uint512>(_p) < BLS_FIELD_MODULUS &&
48+
intx::be::unsafe::load<intx::uint512>(&_p[64]) < BLS_FIELD_MODULUS;
49+
};
50+
51+
if (!is_field_element(_x))
52+
return std::nullopt;
53+
if (!is_field_element(_y))
54+
return std::nullopt;
55+
56+
blst_fp x0;
57+
blst_fp x1;
58+
blst_fp y0;
59+
blst_fp y1;
60+
blst_fp_from_bendian(&x0, &_x[FP_BYTES_OFFSET]);
61+
blst_fp_from_bendian(&x1, &_x[FP_BYTES_OFFSET + 64]);
62+
blst_fp_from_bendian(&y0, &_y[FP_BYTES_OFFSET]);
63+
blst_fp_from_bendian(&y1, &_y[FP_BYTES_OFFSET + 64]);
64+
65+
const blst_p2_affine p_affine{{x0, x1}, {y0, y1}};
66+
if (!blst_p2_affine_on_curve(&p_affine))
67+
return std::nullopt;
68+
69+
return p_affine;
70+
}
71+
4172
/// Stores p1 point in two 64-bytes arrays with big endian encoding zero padded.
42-
void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
73+
void store_result_g1(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
4374
{
4475
blst_p1_affine result;
4576
blst_p1_to_affine(&result, out);
@@ -49,13 +80,31 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
4980
std::memset(_ry, 0, FP_BYTES_OFFSET);
5081
blst_bendian_from_fp(&_ry[FP_BYTES_OFFSET], &result.y);
5182
}
83+
84+
/// Stores p2 point in two 128-bytes arrays with big endian encoding zero padded.
85+
void store_result_g2(uint8_t _rx[128], uint8_t _ry[128], const blst_p2* out) noexcept
86+
{
87+
blst_p2_affine result;
88+
blst_p2_to_affine(&result, out);
89+
90+
std::memset(_rx, 0, FP_BYTES_OFFSET);
91+
blst_bendian_from_fp(&_rx[FP_BYTES_OFFSET], &result.x.fp[0]);
92+
std::memset(&_rx[64], 0, FP_BYTES_OFFSET);
93+
blst_bendian_from_fp(&_rx[FP_BYTES_OFFSET + 64], &result.x.fp[1]);
94+
95+
std::memset(_ry, 0, FP_BYTES_OFFSET);
96+
blst_bendian_from_fp(&_ry[FP_BYTES_OFFSET], &result.y.fp[0]);
97+
std::memset(&_ry[64], 0, FP_BYTES_OFFSET);
98+
blst_bendian_from_fp(&_ry[FP_BYTES_OFFSET + 64], &result.y.fp[1]);
99+
}
100+
52101
} // namespace
53102

54103
[[nodiscard]] bool g1_add(uint8_t _rx[64], uint8_t _ry[64], const uint8_t _x0[64],
55104
const uint8_t _y0[64], const uint8_t _x1[64], const uint8_t _y1[64]) noexcept
56105
{
57-
const auto p0_affine = validate_point(_x0, _y0);
58-
const auto p1_affine = validate_point(_x1, _y1);
106+
const auto p0_affine = validate_p1(_x0, _y0);
107+
const auto p1_affine = validate_p1(_x1, _y1);
59108

60109
if (!p0_affine.has_value() || !p1_affine.has_value())
61110
return false;
@@ -66,7 +115,7 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
66115
blst_p1 out;
67116
blst_p1_add_or_double_affine(&out, &p0, &*p1_affine);
68117

69-
store_result(_rx, _ry, &out);
118+
store_result_g1(_rx, _ry, &out);
70119

71120
return true;
72121
}
@@ -77,7 +126,7 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
77126
blst_scalar scalar;
78127
blst_scalar_from_bendian(&scalar, _c);
79128

80-
const auto p_affine = validate_point(_x, _y);
129+
const auto p_affine = validate_p1(_x, _y);
81130
if (!p_affine.has_value())
82131
return false;
83132

@@ -90,8 +139,29 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
90139
blst_p1 out;
91140
blst_p1_mult(&out, &p, scalar.b, 256);
92141

93-
store_result(_rx, _ry, &out);
142+
store_result_g1(_rx, _ry, &out);
143+
144+
return true;
145+
}
146+
147+
[[nodiscard]] bool g2_add(uint8_t _rx[128], uint8_t _ry[128], const uint8_t _x0[128],
148+
const uint8_t _y0[128], const uint8_t _x1[128], const uint8_t _y1[128]) noexcept
149+
{
150+
const auto p0_affine = validate_p2(_x0, _y0);
151+
const auto p1_affine = validate_p2(_x1, _y1);
152+
153+
if (!p0_affine.has_value() || !p1_affine.has_value())
154+
return false;
155+
156+
blst_p2 p0;
157+
blst_p2_from_affine(&p0, &*p0_affine);
158+
159+
blst_p2 out;
160+
blst_p2_add_or_double_affine(&out, &p0, &*p1_affine);
161+
162+
store_result_g2(_rx, _ry, &out);
94163

95164
return true;
96165
}
166+
97167
} // namespace evmone::crypto::bls

lib/evmone_precompiles/bls.hpp

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

25+
/// Addition in BLS12-381 curve group over G2 extension field.
26+
///
27+
/// Computes P ⊕ Q for two points in affine coordinates on the BLS12-381 curve over G2 extension
28+
/// field,
29+
[[nodiscard]] bool g2_add(uint8_t _rx[128], uint8_t _ry[128], const uint8_t _x0[128],
30+
const uint8_t _y0[128], const uint8_t _x1[128], const uint8_t _y1[128]) noexcept;
31+
2532
} // 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)