Skip to content

Commit 0ec33e3

Browse files
committed
precompiles: Implement bls g2 add
1 parent 525eb35 commit 0ec33e3

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
@@ -17,7 +17,7 @@ constexpr auto MAIN_SUBGROUP_ORDER =
1717

1818
/// Validates p1 affine point. Checks that point coordinates are from the BLS12-381 field and
1919
/// that the point is on curve. https://eips.ethereum.org/EIPS/eip-2537#abi-for-g1-addition
20-
[[nodiscard]] std::optional<blst_p1_affine> validate_point(
20+
[[nodiscard]] std::optional<blst_p1_affine> validate_point_g1(
2121
const uint8_t _x[64], const uint8_t _y[64]) noexcept
2222
{
2323
constexpr auto is_field_element = [](const uint8_t _p[64]) {
@@ -41,8 +41,39 @@ constexpr auto MAIN_SUBGROUP_ORDER =
4141
return p0_affine;
4242
}
4343

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

57106
[[nodiscard]] bool g1_add(uint8_t _rx[64], uint8_t _ry[64], const uint8_t _x0[64],
58107
const uint8_t _y0[64], const uint8_t _x1[64], const uint8_t _y1[64]) noexcept
59108
{
60-
const auto p0_affine = validate_point(_x0, _y0);
61-
const auto p1_affine = validate_point(_x1, _y1);
109+
const auto p0_affine = validate_point_g1(_x0, _y0);
110+
const auto p1_affine = validate_point_g1(_x1, _y1);
62111

63112
if (!p0_affine.has_value() || !p1_affine.has_value())
64113
return false;
@@ -69,7 +118,7 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
69118
blst_p1 out;
70119
blst_p1_add_or_double_affine(&out, &p0, &*p1_affine);
71120

72-
store_result(_rx, _ry, &out);
121+
store_result_g1(_rx, _ry, &out);
73122

74123
return true;
75124
}
@@ -81,7 +130,7 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
81130
blst_scalar scalar;
82131
blst_scalar_from_uint64(&scalar, as_words(c));
83132

84-
const auto p_affine = validate_point(_x, _y);
133+
const auto p_affine = validate_point_g1(_x, _y);
85134
if (!p_affine.has_value())
86135
return false;
87136

@@ -94,8 +143,29 @@ void store_result(uint8_t _rx[64], uint8_t _ry[64], const blst_p1* out) noexcept
94143
blst_p1 out;
95144
blst_p1_mult(&out, &p, scalar.b, BLS_MODULUS_BITS);
96145

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

99168
return true;
100169
}
170+
101171
} // 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)