Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

precompiles: Implement BLS pairing check #1016

Merged
merged 1 commit into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -372,15 +372,7 @@ jobs:
working_directory: ~/spec-tests/fixtures/state_tests
command: >
~/build/bin/evmone-statetest
prague/eip2537_bls_12_381_precompiles/bls12_precompiles_before_fork
prague/eip2537_bls_12_381_precompiles/bls12_g1add
prague/eip2537_bls_12_381_precompiles/bls12_g1mul
prague/eip2537_bls_12_381_precompiles/bls12_g2add
prague/eip2537_bls_12_381_precompiles/bls12_g2mul
prague/eip2537_bls_12_381_precompiles/bls12_g1msm
prague/eip2537_bls_12_381_precompiles/bls12_g2msm
prague/eip2537_bls_12_381_precompiles/bls12_map_fp_to_g1
prague/eip2537_bls_12_381_precompiles/bls12_map_fp2_to_g2
prague/eip2537_bls_12_381_precompiles
- run:
name: "Execution spec tests (develop, blockchain_tests)"
# Tests for in-development EVM revision currently passing.
Expand Down
59 changes: 59 additions & 0 deletions lib/evmone_precompiles/bls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,4 +356,63 @@ void store(uint8_t _rx[128], const blst_fp2& _x) noexcept
return true;
}

[[nodiscard]] bool pairing_check(uint8_t _r[32], const uint8_t* _pairs, size_t size) noexcept
{
static constexpr auto FP_SIZE = 64;
static constexpr auto FP2_SIZE = 2 * FP_SIZE;
static constexpr auto P1_SIZE = 2 * FP_SIZE;
static constexpr auto P2_SIZE = 2 * FP2_SIZE;
static constexpr auto PAIR_SIZE = P1_SIZE + P2_SIZE;
assert(size % PAIR_SIZE == 0);

const auto npairs = size / PAIR_SIZE;
auto ptr = _pairs;
auto has_inf = false;
blst_fp12 acc = *blst_fp12_one();

const auto Qlines = std::make_unique_for_overwrite<blst_fp6[]>(68);

for (size_t i = 0; i < npairs; ++i)
{
const auto P_affine = validate_p1(ptr, &ptr[FP_SIZE]);
if (!P_affine.has_value())
return false;

const auto Q_affine = validate_p2(&ptr[P1_SIZE], &ptr[P1_SIZE + FP2_SIZE]);
if (!Q_affine.has_value())
return false;

if (!blst_p1_affine_in_g1(&*P_affine))
return false;

if (!blst_p2_affine_in_g2(&*Q_affine))
return false;

if (blst_p1_affine_is_inf(&*P_affine) || blst_p2_affine_is_inf(&*Q_affine))
has_inf = true;

if (!has_inf)
{
blst_precompute_lines(Qlines.get(), &*Q_affine);

blst_fp12 ml_res;
blst_miller_loop_lines(&ml_res, Qlines.get(), &*P_affine);
blst_fp12_mul(&acc, &acc, &ml_res);
}

ptr += PAIR_SIZE;
}

bool result = true;
if (!has_inf) // if any point-at-infinity encountered the answer is 1, so skip final exp.
{
blst_final_exp(&acc, &acc);
result = blst_fp12_is_one(&acc);
}

std::memset(_r, 0, 31);
_r[31] = result ? 1 : 0;
return true;
}

} // namespace evmone::crypto::bls
6 changes: 6 additions & 0 deletions lib/evmone_precompiles/bls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,10 @@ inline constexpr auto BLS_FIELD_MODULUS =
[[nodiscard]] bool map_fp2_to_g2(
uint8_t _rx[128], uint8_t _ry[128], const uint8_t _fp[128]) noexcept;

/// Computes pairing for pairs of P and Q point from G1 and G2 accordingly.
///
/// Performs filed and groups check for both input points. Returns 'false' if any of requirement is
/// not met according to spec https://eips.ethereum.org/EIPS/eip-2537#abi-for-pairing-check
[[nodiscard]] bool pairing_check(uint8_t _r[32], const uint8_t* _pairs, size_t size) noexcept;

} // namespace evmone::crypto::bls
29 changes: 24 additions & 5 deletions test/state/precompiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,20 @@ PrecompileAnalysis bls12_g2msm_analyze(bytes_view input, evmc_revision) noexcept
return {bls_msm_cost(input.size() / 288, BLS12_G2MUL_PRECOMPILE_GAS), 256};
}

PrecompileAnalysis bls12_pairing_check_analyze(bytes_view, evmc_revision) noexcept
PrecompileAnalysis bls12_pairing_check_analyze(bytes_view input, evmc_revision) noexcept
{
// TODO: Implement
return {GasCostMax, 0};
static constexpr auto PAIR_SIZE = 384;

if (input.empty() || input.size() % PAIR_SIZE != 0)
return {GasCostMax, 0};

const auto npairs = static_cast<int64_t>(input.size()) / PAIR_SIZE;

static constexpr auto BLS12_PAIRING_CHECK_BASE_FEE_PRECOMPILE_GAS = 65000;
static constexpr auto BLS12_PAIRING_CHECK_FEE_PRECOMPILE_GAS = 43000;
return {BLS12_PAIRING_CHECK_BASE_FEE_PRECOMPILE_GAS +
BLS12_PAIRING_CHECK_FEE_PRECOMPILE_GAS * npairs,
32};
}

PrecompileAnalysis bls12_map_fp_to_g1_analyze(bytes_view, evmc_revision) noexcept
Expand Down Expand Up @@ -456,9 +466,18 @@ ExecutionResult bls12_g2msm_execute(const uint8_t* input, size_t input_size, uin
return {EVMC_SUCCESS, 256};
}

ExecutionResult bls12_pairing_check_execute(const uint8_t*, size_t, uint8_t*, size_t) noexcept
ExecutionResult bls12_pairing_check_execute(const uint8_t* input, size_t input_size,
uint8_t* output, [[maybe_unused]] size_t output_size) noexcept
{
return {EVMC_PRECOMPILE_FAILURE, 0};
if (input_size % 384 != 0)
return {EVMC_PRECOMPILE_FAILURE, 0};

assert(output_size == 32);

if (!crypto::bls::pairing_check(output, input, input_size))
return {EVMC_PRECOMPILE_FAILURE, 0};

return {EVMC_SUCCESS, 32};
}

ExecutionResult bls12_map_fp_to_g1_execute(const uint8_t* input, size_t input_size, uint8_t* output,
Expand Down
14 changes: 14 additions & 0 deletions test/unittests/precompiles_bls_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,17 @@ TEST(bls, map_fp2_to_g2)
EXPECT_EQ(evmc::bytes_view(rx, sizeof rx), expected_x);
EXPECT_EQ(evmc::bytes_view(ry, sizeof ry), expected_y);
}

TEST(bls, paring_check)
{
using namespace evmc::literals;
auto input =
"0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a2100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000a40300ce2dec9888b60690e9a41d3004fda4886854573974fab73b046d3147ba5b7a5bde85279ffede1b45b3918d82d0000000000000000000000000000000006d3d887e9f53b9ec4eb6cedf5607226754b07c01ace7834f57f3e7315faefb739e59018e22c492006190fba4a87002500000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed"_hex;
uint8_t r[32];

EXPECT_TRUE(evmone::crypto::bls::pairing_check(r, input.data(), input.size()));

const auto expected = "0000000000000000000000000000000000000000000000000000000000000001"_hex;

EXPECT_EQ(evmc::bytes_view(r, sizeof r), expected);
}