Precompile Summary

AddressNameGasInputOutputIntroducedBehavior
0x0EBLS12_G2MSM (G2 multi-scalar multiplication)Variable. For k pairs: gas = floor(k * 22500 * discount(k) / 1000), where discount(k) is the G2 Pippenger discount table from EIP-2537 (distinct from G1). G2 base multiply cost is 22,500 gas per pair before discount. For k = 1: 22,500 gas. For k = 2: 22500 * 2 * 1000 / 1000 = 45,000 — the G2 table uses 1000 for both k = 1 and k = 2, so there is no discount at two pairs (MSM is not cheaper than two naive multiplies at very small k for G2). Maximum discount factor is 524 for k > 128. Example: k = 12822500 * 128 * 524 / 1000 = 1,509,120 gas (~1.51M).288 * k bytes with k ≥ 1. Each 288-byte slice is G2 point (256 bytes) concatenated with scalar (32 bytes, big-endian). k is derived from input length; see Edge Cases. Scalars are not required to be less than the subgroup order q.256 bytes: the resulting G2 point s1·P1 + s2·P2 + … + sk·Pk in the same G2 encoding as input points.Pectra hard fork (EIP-2537, May 2025)Computes multi-scalar multiplication in G2 using Pippenger’s algorithm (per spec intent). Performs subgroup checks on every input G2 point — unlike BLS12_G2ADD (0x0D), which does not check subgroup membership. Points must be on the G2 curve and in the prime-order subgroup; G2’s large cofactor makes this check essential for safe use. There is no dedicated G2MUL precompile; k = 1 MSM is the idiomatic single scalar multiply. On any error, all gas forwarded to the precompile is burned.

Threat Surface

BLS12_G2MSM is a consensus-critical, high-cost cryptographic primitive over Fp2: it aggregates many G2 points with independent scalars in one call. G2 operations are materially more expensive than G1 (22,500 vs 12,000 gas per multiply at the base tier), and the G2 discount schedule differs from G1 — including no effective discount at k = 2 — so economic and griefing analysis cannot be copied from G1MSM without re-deriving gas.

The dominant security story for G2 is the cofactor: unlike G1 (cofactor 1), G2 admits a vast set of valid curve points outside the prime-order subgroup. G2MSM enforces subgroup checks and therefore rejects such points. That is correct cryptographically, but it creates a sharp behavioral cliff next to G2ADD, which accepts non-subgroup curve points. Any pipeline that adds with G2ADD and then multiplies with G2MSM can fail at the MSM step even when every step “looked” valid after ADD.

Additional surface includes variable gas (user-controlled k and input length), the 288-byte per-pair encoding (larger and easier to mis-serialize than G1’s 160-byte pairs), unbounded 32-byte scalars (same semantics as G1MSM: mathematically equivalent to reduction mod q, but not enforced in calldata), and burn-all-gas-on-error — which hurts more when the baseline call is already expensive.

At the protocol layer, G2 MSM pricing depends on a discount table that differs from G1. A client that applies the wrong table misprices execution relative to the specification, risking consensus faults or DoS if not caught by tests. G2’s more complex field and point operations also increase cross-client divergence risk (serialization, infinity, subgroup check ordering, failure modes), in line with historical BN254/BLS implementation issues.

Smart Contract Threats

T1: Subgroup Check Is Essential for G2 (High)

  • G2MSM enforces subgroup checks on all input points. On BLS12-381 G2, the cofactor is enormous; points on the G2 curve but outside the prime-order subgroup are abundant and dangerous in pairing-based protocols.
  • The precompile rejects non-subgroup points. That is the intended and safe behavior for MSM.
  • Developers must not assume that any G2 bytes accepted elsewhere are valid MSM inputs. In particular, outputs of G2ADD are not subgroup-validated; feeding G2ADD output into G2MSM without an independent subgroup guarantee can yield unexpected failures (see T5).

Why it matters: Correctness and liveness of verifiers depend on understanding that “accepted by G2ADD” ≠ “accepted by G2MSM.” Treat MSM as the subgroup gate for G2 points in mixed pipelines.

T2: Gas Cost Complexity (High)

  • G2 MSM is significantly more expensive than G1 MSM per pair (22,500 vs 12,000 base gas).
  • The G2 discount table starts at 1000 for k = 1 and k = 2, so there is no discount for two pairs — reflecting that MSM is not a win over naive multiplication at the smallest sizes for G2.
  • For large k, per-pair gas falls with discount, but total gas still grows with k (e.g. k = 128 → on the order of ~1.5M gas with max discount 524).
  • Contracts that accept user-controlled MSM inputs without strict bounds on k and without stipends tied to the EIP gas function face stronger griefing than comparable G1 code paths.

Why it matters: Auditors and libraries must use G2-specific gas math; reusing G1 constants or intuition under-budgets calls and invites DoS or repeated gas burn on failure.

T3: Scalar Not Bounded by Group Order (Medium)

  • Scalars are 32-byte big-endian integers; they are not required to satisfy scalar < q.
  • Group law implies the mathematical result matches using scalar mod q, but implementations may differ in internal work for huge scalars.

Why it matters: Protocols that require canonical reduced scalars, deterministic hash-to-scalar pipelines, or uniform timing assumptions must enforce reduction or domain separation outside the precompile.

T4: Gas Burning on Error (Medium)

  • Like other BLS12 precompiles, all gas forwarded to G2MSM is consumed on error (invalid encoding, wrong length, off-curve, wrong subgroup, etc.).
  • Because G2 operations have higher base costs, a mis-sized or malicious input can burn more than the G1 analogue for the same logical mistake.

Why it matters: Prefer tight stipends derived from k, validate 288 * k lengths before CALL, and always check staticcall success and return length (256 bytes).

T5: Pipeline from G2ADD to G2MSM (High)

  • G2ADD does not perform subgroup checks; G2MSM does.
  • A contract may sum G2 points with G2ADD, then pass the result (or intermediate points) into G2MSM. Points that G2ADD accepted as on-curve may still be rejected by MSM as not in the subgroup.
  • Failures show up as verification failure or revert at the MSM step, which teams may misattribute to “bad signature” rather than invalid aggregation pipeline.

Why it matters: Architectures must either ensure subgroup membership before MSM (e.g. only MSM/map-to-curve outputs, or explicit checks off-chain / in-contract where feasible) or avoid mixing unchecked ADD outputs into MSM without a clear security proof.

Protocol-Level Threats

P1: G2 Discount Table Must Not Be Confused with G1

Implementations and tooling must apply the G2 discount table and 22,500 base multiplier. Using G1’s table or 12,000 base gas for G2 MSM breaks gas estimation, stipends, and economic analysis, and can cause systematic underpayment or client/test mismatches if any layer hardcodes the wrong schedule.

P2: Fp2 Complexity and Cross-Client Divergence Risk

G2 arithmetic lives over Fp2; encodings are 256 bytes per point (vs 128 for G1). More deserialization steps, more field operations, and more room for library edge-case differences across clients. Consensus requires identical acceptance/rejection and identical outputs; performance may differ, but validation rules must not.

P3: 288-Byte Pair Layout Increases Construction Errors

Each pair is G2 point (256) || scalar (32). Wider calldata and Fp2 point layout raise the chance of off-by-one, swapped coordinates, or wrong slice boundaries, especially when concatenating dynamic user input. Many failures burn all forwarded gas without a diagnostic return.

Edge Cases

Edge CaseBehaviorSecurity / ops note
k = 0 (empty input)Error; precompile gas component 0, but call fails; forwarded gas burnedNot “free”; CALL overhead and stipend handling still matter
k = 1Single G2 scalar multiply; 22,500 gas (discount factor 1000)No separate G2MUL — use MSM with one pair
len(input) % 288 ≠ 0Gas computed for k = floor(len / 288) pairs; precompile errorsSame floor-length griefing pattern as G1MSM with stride 288
Point on G2 curve but not in prime-order subgroupREJECTEDUnlike G2ADD; MSM is the subgroup gate
Scalar 0Contribution is point at infinity (per encoding rules)Downstream logic must handle infinity
Very large kTotal gas grows; discount capped (factor 524 for k > 128)Block gas limit and stipends bound practicality; still a DoS knob if k is user-controlled

Real-World Exploits

No public, attributed smart-contract exploit chain specific to BLS12_G2MSM (0x0E) has been catalogued here as of this writing. The precompile shipped with Pectra (EIP-2537). Risk is driven by class-level issues: G2ADD vs G2MSM validation asymmetry, variable high gas, length floor mismatch, and historical precedent for curve precompile validation bugs in other curves (e.g. BN254 / CVE-2025-30147). Track EIP-2537 errata, execution-spec-tests, and client release notes post-Pectra.

Attack Scenarios

Scenario A: Contract accepting variable G2MSM inputs without gas bounds

An adversary chooses a large k (or a malformed length) to force expensive calls or burn a generous stipend. G2’s higher per-pair cost amplifies impact versus G1.

// Illustrative: user-controlled blob, no cap on k = len/288, no stipend from EIP schedule
pragma solidity ^0.8.0;
 
contract G2MsmUnbounded {
    address constant BLS12_G2MSM = address(0x0E);
 
    function msmUserSupplied(bytes calldata data) external view returns (bytes memory) {
        // BUG: no upper bound on data.length / 288; no gas computed from EIP schedule
        (bool ok, bytes memory out) = BLS12_G2MSM.staticcall{gas: gasleft()}(data);
        require(ok && out.length == 256);
        return out;
    }
}

Scenario B: Mixing G2ADD output with G2MSM (unexpected failures)

A contract aggregates G2 points with G2ADD, then uses G2MSM on inputs that include non-subgroup curve points. MSM rejects them; the call fails and burns forwarded gas.

pragma solidity ^0.8.0;
 
contract AddThenMsmPipeline {
    address constant BLS12_G2ADD = address(0x0D);
    address constant BLS12_G2MSM = address(0x0E);
 
    // Illustrative: assumes G2ADD output is always safe for MSM — false for non-subgroup points
    function addThenMsm(
        bytes calldata p512, // two G2 points for G2ADD
        bytes calldata msmTail // remaining pairs: each 288 bytes point||scalar
    ) external view returns (bytes memory) {
        (bool okAdd, bytes memory sum) = BLS12_G2ADD.staticcall(p512);
        require(okAdd && sum.length == 256);
        bytes memory msmIn = abi.encodePacked(sum, msmTail);
        require(msmIn.length >= 288 && msmIn.length % 288 == 0);
        (bool okMsm, bytes memory out) = BLS12_G2MSM.staticcall{gas: gasleft()}(msmIn);
        require(okMsm && out.length == 256);
        return out;
    }
}

Mitigations

ThreatMitigationImplementation
T1 / T5Treat G2ADD and G2MSM as different trust levelsDocument pipelines; only feed MSM points known subgroup-safe or produced by MSM / map-to-G2 / pairing-checked paths
T2Cap k, compute gas from EIP-2537 G2 MSM formulak = len / 288 with exact divisibility check; stipend ≥ schedule; avoid fixed small stipends for arbitrary calldata
T2 / floor mismatchReject len % 288 != 0 before CALLPrevents paying for floor(k) then failing
T3Reduce scalars mod q when protocol requires canonical formOff-chain or in-contract uint256 mod after bytes32 interpretation
T4Minimize forwarded gas; check success and returndatasize == 256require(ok && returndatasize() == 256) before copying
GeneralCentralize BLS12 precompile accessOne module for lengths, gas, success, and return sizes

Compiler/EIP-Based Protections

  • EIP-2537 (Pectra): Defines G2MSM encoding, subgroup checks for MSM, G2 gas schedule (22,500 base and G2 discount table), and failure semantics (burn all forwarded gas on error).
  • Solidity / Yul: No compiler-enforced crypto validation — explicit staticcall, returndatasize, and length checks are required.
  • Testing: Fuzz malformed 288-byte boundaries, non-subgroup vectors (where MSM must fail), k = 1 vs large k, and stipend vs schedule alignment across forks.

Severity Summary

Threat IDCategorySeverityLikelihoodNotes
T1Smart contract / G2 subgroupHighMediumMSM enforces subgroup; misunderstanding enables wrong threat models
T2Smart contract / economicsHighMediumHigh G2 gas + variable kgriefing / DoS
T3Smart contract / crypto hygieneMediumLow–MediumUnreduced scalars vs protocol assumptions
T4Smart contract / UXMediumMediumBurn-all gas on error hurts more at G2 prices
T5Smart contract / pipelineHighMediumG2ADDG2MSM mismatch causes subtle failures
P1Protocol / gas specMediumOngoingG2 vs G1 table confusion
P2Protocol / clientsLow (perf) / Critical if validation divergedLowFp2 complexity
P3Protocol / encodingMediumMedium288-byte pairs easier to get wrong
PrecompileRelationship
BLS12_G2ADD (0x0D)G2 addition without subgroup check — do not assume its outputs are MSM-safe
BLS12_G1MSM (0x0C)G1 analogue; different base gas and discount table
BLS12_PAIRING_CHECK (0x0F)Pairing check with G1/G2 inputs; often ends pipelines that use MSM
BN256MUL (0x07)Legacy alt_bn128 multiply — compare pricing and validation idioms