7Block Labs
Ethereum Development

ByAUJay

Summary: The Pectra upgrade for Ethereum on May 7, 2025, introduced native BLS12‑381 precompiles (EIP‑2537). This upgrade means that on-chain verification for BLS signatures, BLS-based SNARKs, and KZG-adjacent flows is now significantly quicker and less expensive. In this post, we'll break down what was included, how to use it in Solidity right now, the gas calculations you might want to consider, and some best practices we're adopting with clients to make it all work in production.

Faster Proof Verification on Ethereum: Using the EIP‑2537 BLS12‑381 Precompiles

Decision-makers diving into blockchain stacks have some exciting news on the Ethereum mainnet: there’s now top-notch, audited support for BLS12‑381 arithmetic right at the client level. This all kicked off with the Pectra upgrade (Prague × Electra) on May 7, 2025, at epoch 364032. Plus, its meta-EIP (EIP‑7600) nicely ties in with EIP‑2537.

So, what does this mean in real terms? Well, we now have seven fresh precompiled contracts ranging from 0x0b to 0x11 that make it super affordable to perform BLS additions, multi-scalar multiplications (MSM), mappings, and multi-pairing checks. These new features work hand in hand with the KZG point-evaluation precompile at 0x0a that was introduced with EIP‑4844. You can read more about it here.

Here’s a quick rundown of what’s out there, how much you'll need to spend, and tips on using it in real-world Solidity projects. We’ve included some handy copy-paste call patterns, along with how it might affect your choices in cryptography and product architecture.

What exactly shipped in Pectra for BLS12‑381

EIP‑2537 brings seven new precompiles to the Ethereum mainnet. When you call these precompiles, their addresses are 1-byte identifiers that get zero-padded to a full 20 bytes. Check it out here: (eips.ethereum.org).

  • 0x0b bls12_g1add -- Adding points in G1 will set you back 375 gas. (eips.ethereum.org)
  • 0x0c bls12_g1msm -- If you're into multi-scalar multiplication (Pippenger), the gas cost varies based on a discount table over k pairs. (eips.ethereum.org)
  • 0x0d bls12_g2add -- Want to add points in G2? That'll cost you 600 gas. (eips.ethereum.org)
  • 0x0e bls12_g2msm -- G2 MSM is discounted just like G1, so keep that in mind! (eips.ethereum.org)
  • 0x0f bls12_pairing_check -- This one checks if e(P1,Q1)…e(Pk,Qk) equals 1 and gives back 32 bytes, with the last byte being either 0x01 or 0x00. Gas is 37,700 + 32,600 × k. (eips.ethereum.org)
  • 0x10 bls12_map_fp_to_g1 -- Mapping Fp to G1 costs 5,500 gas. (eips.ethereum.org)
  • 0x11 bls12_map_fp2_to_g2 -- If you're mapping Fp2 to G2, be ready to spend 23,800 gas. (eips.ethereum.org)

You might have heard that EIP‑4844 (Dencun) has rolled out the KZG point‑evaluation precompile at 0x0a, which costs 50,000 gas. This is a handy feature for verifying blob proofs, and it works with BLS12‑381 too. With these tools in your toolbox, you’ve got a solid “native” setup for data availability (thanks to KZG) and you can also handle general BLS proof and signature checks (shoutout to EIP‑2537). Check it out for more details: (eips.ethereum.org)

Precompile Behavior Details for Audits and Incident Playbooks

  • The inputs use big-endian encodings. Just to break it down a bit: Fp is 64 bytes, Fp2 is two Fp’s stuck together (so that’s 128 bytes). G1 comes in at 128 bytes (x||y), while G2 is 256 bytes (x.c0||x.c1||y.c0||y.c1). If you see “Infinity,” remember it’s just all zeros of the right length. Check it out here: (eips.ethereum.org).
  • When dealing with MSMs and pairings, make sure they run subgroup checks and spit out an error if they fail. Just a heads up: addition precompiles skip these subgroup checks on purpose. More details available at (eips.ethereum.org).
  • If there’s an error, the precompile will burn all gas sent to the CALL/STATICCALL. So, always double-check lengths and ensure the field encodings are canonical before you go ahead with the call. For reference, see (eips.ethereum.org).

Pectra activation was synchronized across clients, with Geth v1.15.9 and Nethermind v1.31.9 being key releases that brought Prague to mainnet at the set timestamp. If you’re running infrastructure, be sure to check out their release notes--they're the go-to sources for all the details. (newreleases.io)

Why it matters: security level, gas, and calldata

  • Security: BLS12‑381 offers about 128-bit security, which is a nice upgrade from the older BN254 (alt_bn128) precompiles that sit around 80-bit. With EIP‑2537, you can easily shift verifiers and signature checks to a more modern curve without the hassle of coding a custom precompile. Check it out here: (eips.ethereum.org).
  • Gas: If you're looking at costs, a single BLS12‑381 pairing “pair” hits around 32,600 gas, plus a base of 37,700. So, if k=1, you’re looking at 70,300 gas; if k=2--like in a typical BLS signature verification (more on that below)--it jumps to 102,900 gas. For BN254 (after EIP‑1108), the math works out to 34,000×k + 45,000, meaning it’s 79,000 gas for k=1 and 113,000 for k=2. Surprisingly, BLS12‑381 pairing checks are actually cheaper per pair on L1 nowadays! (eips.ethereum.org)
  • Calldata: Thanks to Pectra’s EIP‑7623, the floor price for data-heavy transactions has gone up a notch. Keep in mind that BLS12‑381 points are bigger (G1=128 bytes, G2=256 bytes), so the smart move is to aggregate off‑chain. Use MSM/pairings to check one aggregated proof or signature on‑chain. This way, you can keep your calldata and pairing count nice and low! (eips.ethereum.org)

Common on‑chain tasks you can now do efficiently

1) Verify a Single BLS Signature

Alright, let’s dive into verifying a single BLS signature using the Ethereum consensus ciphersuite. Here’s how you can get it done:

  • Hash that message to Fp2 with the RFC 9380 hash-to-curve method. After that, you'll need to map it to G2 using 0x11. This process typically costs around 23,800 gas. Just a heads up, the precompile handles the whole “field→curve” mapping for you. However, you’ll still need to implement the hash_to_field as per RFC 9380 in Solidity. If you're feeling confident about your inputs, you could pass field elements via calldata. Check out the details here.
  • Now, for the pairing check with k=2: You want to ensure that e(PK, H(m)) · e(−G1, σ) equals 1. For this pairing operation, plan on using about 102,900 gas. Don’t forget to account for the mapping cost and any calldata. More info on this can be found here.
  1. To check an aggregate signature when everyone signs the same message (“fast aggregate verify”), you can combine the public keys off-chain (which keeps costs low) or use G1 addition/MSM. After that, you just run the same k=2 pairing using the aggregate public key. The gas used will be roughly the same as what you’d spend for a single signature. (eips.ethereum.org)
  2. Check n distinct-message signatures all at once: just pass n+1 pairs into a single 0x0f call. So if n=10, that's 11 pairs, which would cost you 37,700 + 32,600 × 11 = 396,300 gas. Way cheaper than verifying each signature separately in different calls. (eips.ethereum.org)
  3. If you want to verify a Groth16/PLONK proof using BLS12‑381 instead of BN254, you’ll notice a difference in gas costs. Typically, a Groth16 verifier needs 3 pairings. For BLS12‑381, the pairing cost adds up to 37,700 + 32,600×3, which totals around 135,500 gas. In comparison, BN254 runs about 147,000 gas. Plus, choosing BLS12‑381 gives you the bonus of stronger security. For more details, check out EIP-2537.
  4. Using 4844 blobs/KZG: the point-evaluation precompile at 0x0a lets you verify KZG proofs for blobs, costing just 50,000 gas each. If your application requires BLS arithmetic for signatures or other validations, you can handle it all natively on L1 now, without needing to dive into custom cryptography in Solidity. Check it out here: (eips.ethereum.org)

Solidity: minimal wrappers you can ship

Here are some call patterns you can easily integrate into your contracts. We’ve kept them straightforward on purpose--steering clear of any ABI-heavy abstractions that might muddy the encoding rules or lead to gas issues.

Note on Addresses

Just a heads up: precompiles are zero-padded. So, if you see something like 0x0f, it’s actually represented as 0x000000000000000000000000000000000000000f.

1) Pairing check (0x0f) for BLS verifies

The input consists of k concatenations of a 128-byte G1 followed by a 256-byte G2. When you run the precompile, it gives back 32 bytes, and if the product of the pairings equals 1, the last byte will be 0x01.

library BLS12Pairing {
    address constant PAIR_ADDR = address(0x0f);

    // Returns true if e(P1,Q1)*...*e(Pk,Qk) == 1
    function pairing(bytes memory input) internal view returns (bool ok) {
        bytes32[1] memory out; // 32 bytes
        bool success;
        assembly {
            // staticcall gas forwarding; adjust if you want a hard cap
            success := staticcall(gas(), PAIR_ADDR, add(input, 0x20), mload(input), out, 0x20)
        }
        // success covers precompile presence & no error; out[0]’s last byte covers math result
        return success && (uint8(bytes1(out[0])) == 0x01);
    }
}

Usage for a Single Signature (MinPk):

  • First up, prepare two pairs: (pubkeyG1, H(m)G2) and (−G1, signatureG2).
  • To negate G1, you just need to keep the x coordinate as is, and then set y = p − y (mod p). Here, p refers to the BLS12‑381 base field modulus as outlined in the EIP. It’s a good idea to precompute and store −G1 in your library for easy access. (eips.ethereum.org)

2) Map Fp2 → G2 (0x11) and Fp → G1 (0x10)

You send over the canonical field elements (in big-endian format, where the top 16 bytes are zero in each 64-byte Fp) and get back an uncompressed point.

library BLS12Map {
    address constant MAP_G1 = address(0x10);
    address constant MAP_G2 = address(0x11);

    function mapFpToG1(bytes32[2] memory fp) internal view returns (bytes memory g1) {
        g1 = new bytes(128);
        bool success;
        assembly {
            // Input is 64 bytes (two 32‑byte words); output 128 bytes
            success := staticcall(gas(), MAP_G1, fp, 0x40, add(g1,0x20), 0x80)
        }
        require(success, "mapFp->G1 failed");
    }

    function mapFp2ToG2(bytes32[4] memory fp2) internal view returns (bytes memory g2) {
        g2 = new bytes(256);
        bool success;
        assembly {
            // Input is 128 bytes (four 32‑byte words); output 256 bytes
            success := staticcall(gas(), MAP_G2, fp2, 0x80, add(g2,0x20), 0x100)
        }
        require(success, "mapFp2->G2 failed");
    }
}

Important: EIP‑2537 doesn’t include hash_to_field on purpose. Instead, you should use RFC 9380 (like XMD:SHA‑256, SSWU) along with a unique DST. For Ethereum-style BLS (MinPk, POP), the go-to ciphersuite is BLS_SIG_BLS12381G2_XMD:SHA‑256_SSWU_RO_POP_. You can check it out here.

3) G1/G2 MSM (0x0c / 0x0e)

MSM takes in k slices of (point || scalar) and gives you back a single point. When it comes to gas costs, there's a discount table in play; for G1, the cost per pair is about k×12,000×discount/1000. It's a smart move to use MSM when your scalars are all over the place. But if you're just adding points together (like when all scalars are 1), you might want to stick with repeated G1ADDs since they're way cheaper, only costing 375 gas each. You can check more details on eips.ethereum.org.

library BLS12MSM {
    address constant G1MSM = address(0x0c);
    address constant G2MSM = address(0x0e);

    // inputG1: concat of k*(128-bytes point || 32-bytes scalar)
    function g1msm(bytes memory inputG1) internal view returns (bytes memory outPoint) {
        outPoint = new bytes(128);
        bool success;
        assembly {
            success := staticcall(gas(), G1MSM, add(inputG1,0x20), mload(inputG1), add(outPoint,0x20), 0x80)
        }
        require(success, "G1MSM failed");
    }
}

4) KZG point evaluation (0x0a) refresher

For blob commitments, the 0x0a precompile uses 192 bytes (which includes the versioned hash, z, y, commitment, and proof) and will return some constants if everything checks out. Each call will set you back 50,000 gas--this is separate from, but works well alongside, EIP‑2537. You can check out more details here.

Gas budgets you can plan for (real numbers)

  • Single BLS signature (MinPk, POP):

    • When using hash_to_field (RFC 9380) in Solidity, your gas usage will depend on how you handle SHA‑256 and the size of your DST, so budget a few thousand gas for that.
    • Mapping from Fp2 to G2 will cost you about 23,800 gas.
    • For pairing with k=2, you’re looking at around 102,900 gas.
    • When you put it all together (excluding calldata), you’re roughly in the ballpark of 125-135k gas. (eips.ethereum.org)
  • Fast‑aggregate verify (same message, aggregated pubkey):

    • The gas costs here are pretty much the same as above. You can do the aggregation either off-chain or on-chain by repeatedly using G1ADD, which costs 375 gas each time. (eips.ethereum.org)
  • Distinct‑message aggregate verify of n signers:

    • For this, you’ll need a single 0x0f call with k=n+1 pairs. For example, if you've got n=10, you’re looking at about 396,300 gas (plus additional mapping per message if you go the on-chain route). (eips.ethereum.org)
  • Groth16 over BLS12‑381 verifier:

    • This one will cost you about 135,500 gas for 3 pairings (and don’t forget about your field ops and calldata). Just as a comparison, the BN254 equivalent comes in at around 147,000 gas--so BLS12‑381 is not only stronger but also a bit cheaper per pairing now. (eips.ethereum.org)

Calldata note: points are sent in an uncompressed format. The EIP mentions that doing "decompression" on-chain is more expensive than just sending the full coordinates, so it’s better to stick with uncompressed encodings and keep the number of pairs you pass to a minimum. Pectra’s calldata repricing (EIP‑7623) also encourages aggregation to help keep data sizes down. (eips.ethereum.org)

Production checklist and gotchas we’re seeing

  • Validate encodings before calls:

    • Make sure your Fp elements are strictly less than p (the top 16 bytes should be zero). It's better to catch any malformed inputs early on to prevent wasting gas on precompile errors. Check out more details here.
  • Subgroup checks:

    • So, addition precompiles don’t really do subgroup checks, but pairings and MSM do. If you're adding points on-chain and then passing them to pairing/MSM later, you’re in the clear. Just remember, if you’re exposing add operations externally, document your invariants and think about throwing in a cheap “MSM with k=1” in your critical code paths for security. More info is available here.
  • Choose the right BLS ciphersuite:

    • For that Ethereum-style Proof of Possession (POP), stick with MinPk (you'll want G1 keys and G2 signatures) and use the RFC 9380 hashing method. Also, don't forget to set a unique DST for your app. You can check out the specifics here.
  • Negative points for pairings:

    • The standard verification process uses the formula e(PK, H(m)) · e(−G1, σ) == 1. It’s worth precomputing −G1 (where y = p − y) once and keeping it stored as a constant to dodge the heavy Fp arithmetic in Solidity. You can find p in the EIP details here.
  • Detecting support:

    • After Pectra on mainnet, you can pretty much assume availability. For Layer 2s, be sure to check their release notes (like the OP Stack “Support Pectra” tracking) and hard-fail if the 0x0f calls don’t return a 32-byte boolean. Just a heads up: don’t rely on EXTCODESIZE since precompiles don’t have actual code. For more discussion, look here.
  • Calldata optimization:

    • EIP‑7623 is bumping up the floor cost for data-heavy transactions. A smart move is to aggregate public keys and signatures off-chain and send one aggregated proof/signature instead of a bunch of individual points. More on this here.
  • KZG + BLS together:

    • When working with rollup bridges, DA attestations, or data-availability proofs, pair the 0x0a KZG verification with BLS signatures from your attesters--all on L1, which means you won’t need any custom cryptography in Solidity. For further details, you can check this out here.

Migration playbook: BN254 → BLS12‑381 verifiers

If you're in the process of verifying Groth16 proofs or dealing with pairing-based signatures over BN254 (EIP-196/197/1108), here's a straightforward approach for you:

  1. Parameter switch:

    • We're swapping out the curve parameters and encodings for BLS12‑381 (where Fp is 64 bytes, and G1/G2 are 128/256 bytes). Don't forget to update the calldata marshalling! (eips.ethereum.org)
  2. Pairing calls:

    • It's time to replace 0x08 (which corresponds to BN254 pairing) with 0x0f for the BLS12‑381 pairing. Also, let’s make sure to update the cost model for gas budgeting--BLS12‑381 comes in at 37,700 + 32,600×k. (eips.ethereum.org)
  3. Proof/key format:

    • We need to re-generate those verifying keys and proofs using BLS12‑381. For Groth16, the algebra and check structure stay the same; the only changes are in the curve and the encodings.
  4. Security review:

    • Let's take some time to document the upgrade in security level (from 80-bit to about 128-bit) and the difference in pairing costs. This will definitely help get stakeholders on board with the changes. (eips.ethereum.org)
  5. Calldata & EIP‑7623:

    • Be ready for those larger point encodings. We should trim any redundancy in public inputs and reduce the number of pairs by using aggregation where it makes sense. (eips.ethereum.org)

Where this unlocks product capabilities

  • Aggregated signer sets on L1: With bridges, governance, and MPC/DVT committees, we can use one aggregated BLS signature for each decision. This means L1 verification costs about 130k gas instead of dealing with multiple ECDSAs. The cool part? You can verify multiple distinct-message signatures with just a single 0x0f call, making it super cost-effective to handle “N notarizations per block.” Check it out here.
  • Stronger-security SNARK verifiers: You can now roll out BLS12-381 Groth16 today without needing to create custom precompiles. Plus, this setup aligns nicely with the preferred curve families of many modern proof systems. Learn more about it here.
  • Better DA/settlement hygiene: Take KZG 0x0a for blob proofs and pair it with EIP-2537 for policy-driven attestations around your data pipelines. It’s a great way to enhance your system's integrity. More details can be found here.

Emerging practices we recommend (and implement for clients)

  • Stick with MinPk + POP using RFC 9380 hashing. This way, you'll have a ciphersuite-specific DST that helps keep cross-protocol attacks at bay. You can check out more details here: (rfc-editor.org).
  • Always make sure to check input lengths and those pesky “top-16-zero-bytes” for Fp/Fp2. If you come across any non-canonical field encodings, reject them before the precompile call. This can save you from wasting your entire gas stipend on a failed attempt. For more info, hit this link: (eips.ethereum.org).
  • Go for MSM only when the scalars are different; when it comes to “sum of points,” using batch G1ADD is the more cost-effective choice.
  • Think of pairing input as an append-only buffer and try to reuse it across calls. This little trick can really help cut down on memory operations in those hot paths.
  • Keep an eye on L2 deployments: not all rollups are rolling out Pectra at the same time. Make sure to track any support issues related to Pectra (like with OP Stack) and adjust those feature flags in your deployment config accordingly. You can find more on this topic here: (github.com).

Appendix: constants you’ll actually need

  • Precompiled addresses: 0x0a for KZG and 0x0b-0x11 for BLS12‑381 operations. Check it out here.
  • Pairing gas costs are as follows: BLS12‑381 runs at 37,700 + 32,600×k, while BN254 is at 45,000 + 34,000×k (after EIP‑1108). More details can be found here.
  • If you’re looking for the G1 generator (H1) coordinates and modulus p, you can find them in EIP‑2537. Make sure you precompute −G1 once (y := p − y) to save time. More info here.
  • About calldata repricing (EIP‑7623): they’re planning to introduce a higher minimum cost for transactions that are heavy on data. Just remember, aggregation pays for itself! Learn more here.
  • Mark your calendars for Pectra activation on mainnet: it’s happening at epoch 364032 on 2025‑05‑07 at 10:05:11 UTC. For all the operational details, take a peek at the EF announcements and client release notes. More details here.

What’s next

Now that Pectra is wrapped up, we’re moving forward with the ecosystem work on EOF and PeerDAS. Keep an eye out for the wider adoption of the same precompile set across Layer 2 solutions (think OP Stack and more) along with some new cryptographic precompiles like secp256r1. Just a heads up, the successors to RIP-7212 and EIP-7951 are currently in Last Call, so there’s some exciting stuff happening that could really expand wallet integration options.

In terms of strategies for cross-app cryptography as we gear up for the 2026 upgrades, it’s a good idea to set aside some time for EOF migrations and to boost your PeerDAS capacity. These will definitely impact how you handle your calldata and blob usage moving forward. For more information, check out (pectra.org).


If you’re looking to have a reference implementation reviewed or need help with the BN254→BLS12‑381 migration (including things like dst/ciphersuite hardening, calldata minimization under EIP‑7623, and verifier rewrites), 7Block Labs has got you covered. We can put together an audit-ready package and provide KPI-backed gas benchmarks in just one sprint.

References:

  • EIP‑7600 (Pectra meta), along with the EF testnet and mainnet posts, which cover activation details and a comprehensive EIP list. Check it out here.
  • EIP‑2537 (addresses, encodings, gas) and EIP‑4844 (KZG precompile 0x0a). You can dive into the details here.
  • EIP‑196/197/1108 (BN254 legacy and gas) plus EIP‑7623 (calldata repricing) offer some interesting insights. Find more information here.
  • RFC 9380 (hash‑to‑curve) and the BLS IRTF draft (ciphersuites) are also worth a look. Check it out here.

Like what you're reading? Let's build together.

Get a free 30-minute consultation with our engineering team.

7BlockLabs

Full-stack blockchain product studio: DeFi, dApps, audits, integrations.

7Block Labs is a trading name of JAYANTH TECHNOLOGIES LIMITED.

Registered in England and Wales (Company No. 16589283).

Registered Office address: Office 13536, 182-184 High Street North, East Ham, London, E6 2JA.

© 2026 7BlockLabs. All rights reserved.