Skip to content

feat(core/vm,params): implement EIP-2537 BLS12-381 precompiles #30978 - #2668

Merged
gzliudan merged 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:feat-eip2537
Oct 3, 2026
Merged

gzliudan merged 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:feat-eip2537

Conversation

@gzliudan

@gzliudan gzliudan commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

Proposed changes

Implement the EIP-2537 BLS12-381 precompiles 0x0b-0x11 (G1ADD, G1MSM, G2ADD, G2MSM, PAIRING, MAP_FP_TO_G1, MAP_FP_TO_G2), ported from go-ethereum ethereum#30978.

On chains where Prague is active, 0x0b-0x11 were unreachable. #2666 has since added PrecompiledContractsPrague and registered it in both the activePrecompiledContracts and the ActivePrecompiles switch, but that set stops at 0x0a: the seven BLS12-381 addresses were ordinary empty accounts, so a call to one succeeded with empty output instead of running the precompile, even though EIP-7702, EIP-7623 and EIP-2935 are live in the same block.

This adds the seven entries to PrecompiledContractsPrague and the same seven to PrecompiledContractsOsaka, so both buckets hold the address list upstream registers them under. The BLS gas constants and the two multi-exponentiation discount tables go into params/protocol_params.go.

Deliberately out of scope: the 0x0a KZG point evaluation implementation (this fork has no blob ecosystem) and the 0x100 p256Verify precompile. 0x0a therefore keeps the always-failing stub #2666 registers, which burns the frame's gas instead of computing anything, and the Osaka set still has no 0x100 entry. The upstream Cacheable/NormalizeInput helpers are dropped because the fork has no precompile result cache.

The ported vectors rely on the JSON vector plumbing that landed with #2664: precompiledTest and precompiledFailureTest only became JSON-loadable once #2664 exported their fields and added the gas assertion, so before it the vectors were unmarshalled into zero-valued cases and passed vacuously. #2664 is merged into dev-upgrade and this branch is rebased onto it, so the vectors assert real values. The branch is now rebased onto b00b45141, which includes #2666: both buckets hold the union of that PR's entries and this change, and git diff dev-upgrade..HEAD still shows only this change.

The gnark-crypto bump from #2664 is not a build requirement of this change, which was checked while that PR was still open: with gnark-crypto rolled back to the fork's previous v0.10.0, core/vm still builds and all nine ported BLS12-381 vectors pass, because v0.10.0 already provides MapToG1/MapToG2/PairingCheck and the same fp.BigEndian marshalling these precompiles use. It is in the base branch because #2664 aligned that dependency with go-ethereum, not because the precompiles need the newer version.

Types of changes

Put an ✅ in the boxes that apply

  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Changes that don't change source code or tests
  • docs: Documentation only changes
  • feat: A new feature
  • fix: A bug fix
  • perf: A code change that improves performance
  • refactor: A code change that neither fixes a bug nor adds a feature
  • revert: Revert something
  • style: Changes that do not affect the meaning of the code
  • test: Adding missing tests or correcting existing tests

Impacted Components

Which parts of the codebase does this PR touch?

Put an ✅ in the boxes that apply

  • Consensus
  • Account
  • Network
  • Geth
  • Smart Contract
  • External components
  • Not sure (Please specify below)

Checklist

Put an ✅ in the boxes once you have confirmed below actions (or provide reasons on not doing so) that

  • This PR has sufficient test coverage (unit/integration test) OR I have provided reason in the PR description for not having test coverage
  • Tested on a private network from the genesis block and monitored the chain operating correctly for multiple epochs.
  • Provide an end-to-end test plan in the PR description on how to manually test it on the devnet/testnet.
  • Tested the backwards compatibility.
  • Tested with XDC nodes running this version co-exist with those running the previous version.
  • Relevant documentation has been updated as part of this PR
  • N/A

Reasons for the unchecked boxes above:

  • Test coverage: core/vm/precompile_sets_test.go pins the membership of every precompile set — the classic 0x01-0x09 entries, the 0x0a failing stub (expected in the two buckets that schedule Prague and in no earlier one) and the EIP-2537 addresses — so a future bucket cannot silently fall back to an older one. The XDCx precompiles are counted in the two buckets that hold them and are deliberately left unasserted in the later ones, where their absence is a pre-existing gap. The upstream vectors (including the failure vectors) are ported under core/vm/testdata/precompiles, and FuzzPrecompiledBLS12381 seeds itself from those vectors — 139 seeds, 130 distinct: two successful cases and one rejected case per precompile, plus the off-length inputs around every accepted length, which exercise the gas calculation and are then turned away by the length gate. Plain go test runs all of them, and the rejected paths are covered on their own by the nine *Fail vector tests. Verified after the rebase onto b00b45141 with make all, make quick-test (124 packages ok, 0 failures) and an explicit run of 23 cases: the nine TestPrecompiledBLS12381* vectors, their nine *Fail counterparts, TestPrecompileSetsByFork, FuzzPrecompiledBLS12381, and fix(core/vm,params): fail 0x0a calls instead of faking success #2666's TestKZGPointEvaluationStubSet, TestKZGPointEvaluationStubFails and TestPraguePrecompilesExtendActivatedSet, which together confirm the seven new entries and the 0x0a stub coexist in both buckets.
  • Private-network multi-epoch run: not done here, because this change adds precompile set entries only and does not touch any fork activation schedule. On the devnet the new set takes effect at the existing pragueBlock 50000, so a genesis-to-multi-epoch run re-verifies the fork schedule rather than this set.
  • End-to-end plan on devnet: after the fork block, call 0x0b-0x11 on a devnet node through eth_call and confirm the BLS operations return their expected output instead of an empty result, and that an invalid BLS input consumes gas and reverts.
  • Backwards compatibility: the EIP-1559 bucket and every earlier bucket are byte-for-byte unchanged, so no existing network changes behaviour; only the Prague and Osaka buckets gain entries.
  • Co-existence with older nodes: not tested, and it cannot be, because Prague precompiles are consensus-critical: a node without this change treats 0x0b-0x11 as empty accounts and will diverge at the first block that uses them. This must be released as a mandatory upgrade before Prague activates on any network.
  • Documentation: no doc update, the precompile addresses are standard EIP-2537 addresses.

@coderabbitai

coderabbitai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 21c7d7c9-4efb-4e4a-9c0e-234684bb5bff

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The consensus-critical activation requires final human review and coordinated network-upgrade validation.

Review effort: Balanced
Findings: None

What changed in this PR

Implements EIP-2537 BLS12-381 precompiles for Prague and Osaka.

Changes:

  • Adds seven BLS precompile implementations and gas schedules.
  • Registers addresses 0x0b–0x11.
  • Adds success, failure, fork-membership, benchmark, and fuzz coverage.
File Description
params/​protocol_params.go Adds BLS gas constants and discount tables.
core/​vm/​contracts.go Registers BLS precompiles.
core/​vm/​contracts_bls12381.go Implements BLS operations and encoding.
core/​vm/​contracts_test.go Adds vector runners and benchmarks.
core/​vm/​precompile_sets_test.go Tests fork-specific registration.
core/​vm/​contracts_bls12381_fuzz_test.go Adds precompile fuzz coverage.
core/​vm/​testdata/​precompiles/​blsG1Add.json G1 addition vectors.
core/​vm/​testdata/​precompiles/​blsG1Mul.json G1 multiplication vectors.
core/​vm/​testdata/​precompiles/​blsG1MultiExp.json G1 MSM vectors.
core/​vm/​testdata/​precompiles/​blsG2Add.json G2 addition vectors.
core/​vm/​testdata/​precompiles/​blsG2Mul.json G2 multiplication vectors.
core/​vm/​testdata/​precompiles/​blsG2MultiExp.json G2 MSM vectors.
core/​vm/​testdata/​precompiles/​blsPairing.json Pairing vectors.
core/​vm/​testdata/​precompiles/​blsMapG1.json G1 mapping vectors.
core/​vm/​testdata/​precompiles/​blsMapG2.json G2 mapping vectors.
core/​vm/​testdata/​precompiles/​fail-blsG1Add.json Invalid G1 addition vectors.
core/​vm/​testdata/​precompiles/​fail-blsG1Mul.json Invalid G1 multiplication vectors.
core/​vm/​testdata/​precompiles/​fail-blsG1MultiExp.json Invalid G1 MSM vectors.
core/​vm/​testdata/​precompiles/​fail-blsG2Add.json Invalid G2 addition vectors.
core/​vm/​testdata/​precompiles/​fail-blsG2Mul.json Invalid G2 multiplication vectors.
core/​vm/​testdata/​precompiles/​fail-blsG2MultiExp.json Invalid G2 MSM vectors.
core/​vm/​testdata/​precompiles/​fail-blsPairing.json Invalid pairing vectors.
core/​vm/​testdata/​precompiles/​fail-blsMapG1.json Invalid G1 mapping vectors.
core/​vm/​testdata/​precompiles/​fail-blsMapG2.json Invalid G2 mapping vectors.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

…um#30978

Port the EIP-2537 precompiles (0x0b-0x11) from go-ethereum: G1ADD, G1MSM,
G2ADD, G2MSM, PAIRING, MAP_FP_TO_G1 and MAP_FP_TO_G2, along with the
Bls12381 gas constants and the multi-exponentiation discount tables.

ported from geth ethereum#21018, ethereum#29441, ethereum#29445, ethereum#29552, ethereum#30978

The precompiles are added to PrecompiledContractsPrague and to
PrecompiledContractsOsaka, the two buckets upstream registers them in. Both
buckets already exist on dev-upgrade: XinFinOrg#2666 introduced
PrecompiledContractsPrague holding the always-failing 0x0a stub, so 0x0b-0x11
were still empty accounts under Prague rules. The upstream-only
Cacheable/NormalizeInput helpers are dropped because this fork has no
precompile result cache. The 0x0a point evaluation precompile itself is
deliberately not ported, since XDC has no blob ecosystem: the address keeps
the failing stub XinFinOrg#2666 registered, and the 0x100 p256Verify precompile is
still absent.

Test vectors and cases are taken from upstream, including the failure
vectors (testJsonFail/loadJsonFail are introduced for them).
@gzliudan
gzliudan merged commit 9a7c0e5 into XinFinOrg:dev-upgrade Oct 3, 2026
10 checks passed
@gzliudan
gzliudan deleted the feat-eip2537 branch October 3, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants