Precompile Summary
| Address | Name | Gas | Input | Output | Introduced | Behavior |
|---|---|---|---|---|---|---|
| 0x0B | BLS12_G1ADD | 375 (fixed) | 256 bytes: two G1 affine points (128 bytes each). Each point is 64-byte big-endian x followed by 64-byte big-endian y (Fp elements). The top 16 bytes of each 64-byte coordinate must be zero (canonical limb layout for BLS12-381 base field). | 128 bytes: resulting G1 point: 64-byte x, then 64-byte y. The point at infinity is 128 zero bytes. | Pectra hardfork (EIP-2537, May 2025) | Performs point addition on the BLS12-381 G1 curve. Input points must lie on G1 or represent the point at infinity (all 128 zero bytes for that operand). No subgroup check is performed — this is by design per EIP-2537. On error (invalid encoding, point not on G1 and not infinity, wrong input length), all gas forwarded to the precompile is burned. On success, returns exactly 128 bytes. |
Threat Surface
BLS12_G1ADD is a consensus-critical elliptic-curve primitive: it adds two affine G1 points on BLS12-381 and returns their sum. It does not interpret application semantics — no domains, authorization context, or proof-system binding — so correctness, failure handling, and cryptographic assumptions must be enforced by callers and by protocols that consume the outputs.
The threat surface has four dominant themes:
1. Punishing failure economics. Under EIP-2537, BLS12 precompiles burn all gas forwarded to the call on any error. That departs sharply from older patterns (for example, ECRECOVER returns empty on failure; BN256ADD returns empty with bounded gas). Contracts that forward large stipends — especially staticcall(gas(), 0x0B, …) — without cheap pre-validation can lose their entire remaining execution budget on a single malformed or off-curve input. Error handling is no longer “cheap failure”; it is a griefing and reliability lever.
2. Strict field encoding. Coordinates are 64-byte big-endian Fp elements with 16 high zero bytes and values strictly < p (the BLS12-381 base field modulus, 381 bits). A value can satisfy the zero high limbs yet still be ≥ p and remain invalid. Manual construction in Solidity, scripts, or off-chain signers that pad without canonical reduction is a recurring source of gas-burning failures and of logic bugs when callers assume any 256-byte blob is acceptable.
3. Subgroup policy versus developer mental models. EIP-2537 deliberately omits subgroup checks on G1ADD. For BLS12-381 G1, the curve cofactor is 1, so every point on the G1 curve lies in the prime-order subgroup; the omission is mathematically sound for pure G1 curve arithmetic and does not admit a small-subgroup point class on G1 the way G2 does. The risk is semantic: teams may treat “passed BLS12_G1ADD” as a blanket “BLS-safe / pairing-ready” guarantee. MSM and pairing paths under EIP-2537 apply different validation rules; copying G1 assumptions to G2ADD (cofactor ≠ 1) is especially dangerous (see 0x0D-BLS12_G2ADD).
4. Client and library maturity. As of March 2026, this family has roughly ten months of Ethereum mainnet history — far less than BN254 precompiles. CVE-2025-30147 showed that curve pipelines can ship subtle validation bugs that become consensus faults. BLS12-381 stacks (blst, gnark-crypto, arkworks, and others) are widely used but the Ethereum precompile binding layer is newer; parsing, infinity handling, and strict Fp checks must stay aligned with execution-spec-tests across all clients.
Smart Contract Threats
T1: No Subgroup Check by Design (High)
EIP-2537 deliberately omits subgroup checking for BLS12_G1ADD. The precompile accepts any validly encoded point on the G1 curve (plus the canonical infinity encoding).
- G1 cofactor is 1. On BLS12-381 G1, every curve point is in the correct prime-order subgroup, so the lack of an explicit subgroup check does not create a small-subgroup input class on G1.
- False sense of validation. Application code may infer “precompile validated my point” and feed outputs into components that expect points validated the same way as MSM or pairing entry points — those assumptions can be wrong and produce subtle integration bugs.
- Asymmetry with MSM and pairing. BLS12_G1MSM performs subgroup checks on input points; G1ADD does not. Mixed pipelines that assume uniform validation without reading the spec are a recurring audit theme.
- G1 versus G2 pattern porting. G2ADD shares the “no subgroup check” API shape but G2 has cofactor ≠ 1; the security story differs materially (see 0x0D-BLS12_G2ADD).
Why it matters: On G1 this is not a direct small-subgroup exploit surface, but it is a high-impact confusion hazard: wrong abstractions propagate into composite protocols and cross-curve copy-paste errors.
T2: Invalid Curve Point Handling (Medium)
Points not on the BLS12-381 G1 curve (and not the all-zero 128-byte infinity encoding for that point) are rejected. The call fails and all forwarded gas is burned.
- Return handling is mandatory. Callers must check
staticcallsuccess andreturndatasize == 128on success. Ignoring failure and reading an output buffer yields stale memory — the same class of bug as unchecked BN256ADD calls. - Infinity encoding is strict. Only the canonical 128 zero bytes represent infinity; other “almost zero” encodings fail validation and burn gas.
Why it matters: Silent use of bogus curve data corrupts commitments, hashes, and downstream pairing inputs, breaking verifier soundness and enabling denial or manipulation of higher-level logic.
T3: Field Element Encoding Validation (Medium)
Each coordinate is a 64-byte big-endian Fp element: top 16 bytes zero, value < p. Values ≥ p are invalid even if high limbs are zero.
- Non-canonical high limbs fail even when the mathematical integer could be reduced mod p.
- Manual encoders must reduce mod p before fixed-width serialization; “pad to 64 bytes” without reduction is unsafe.
Why it matters: Encoding mistakes cause gas-burning failures and, when combined with poor error handling, stale-output misuse; adversaries can also grief with cheap-to-craft invalid encodings if calls use large forwarded gas.
T4: Gas Burning on Error (Medium)
Unlike ECRECOVER (empty return) or BN256ADD (empty return, fixed low gas), BLS12 precompiles under EIP-2537 burn all gas forwarded to the precompile on error.
staticcall(gas(), …)with attacker-controlled curve data can wipe the callee’s remaining gas on failure.- Contracts should validate length and encoding before the call, or cap the stipend (for example, 375 plus overhead) instead of forwarding unbounded gas.
Why it matters: Failure cost scales with forwarded gas, enabling griefing and breaking contracts that assumed precompile failures are inexpensive.
Protocol-Level Threats
P1: Newest Precompile Family — Limited Mainnet Battle-Testing
BLS12_G1ADD shipped with Pectra (EIP-2537, May 2025). Compared to BN254 precompiles, operational history on Ethereum mainnet is short — on the order of ten months as of March 2026. Latent client bugs, spec-edge discoveries under fuzzing, and cross-client divergence are more plausible in early deployment years than for decade-old primitives, even with strong execution-spec-tests coverage.
P2: Implementation and Library Risk (CVE-2025-30147 Precedent)
CVE-2025-30147 on BN254 precompiles showed that curve operation implementations can confuse subgroup checks with on-curve validation (or otherwise mishandle points), producing consensus-critical divergence in a client. BLS12-381 libraries are mature in isolation, but the EVM precompile integration path is newer; refactors, optimizations, or library swaps in clients reopen the same validation risk class.
P3: No-Subgroup-Check Precedent and G1/G2 Confusion
The EIP-2537 choice is correct for G1 given cofactor 1, but it is easy to over-generalize when porting patterns to G2 or to off-chain BLS APIs that do perform cofactor clearing. Documentation and audits must distinguish on-curve, subgroup-checked, and pairing-ready points — failures here are specification-understanding bugs at protocol scale.
Edge Cases
| Edge Case | Behavior | Security Implication |
|---|---|---|
| Point at infinity (128 zero bytes) + P | Returns P (identity) | Callers must treat all-zero 128 bytes as infinity, not unconstrained zeros |
| P + (−P) | Returns point at infinity (128 zero bytes) | Valid; downstream logic must accept infinity where the math allows |
| P + P (doubling) | Handled as addition of identical affine points | Must match EIP-2537 and client tests; exercise doubling vectors in CI |
| Input length < 256 bytes | Error; all forwarded gas burned | Strict length — no silent padding |
| Input length > 256 bytes | Error; all forwarded gas burned | Extra bytes are not ignored |
| Coordinate ≥ field modulus | Error; gas burned | Canonical Fp reduction required before encoding |
| Top 16 bytes of a coordinate non-zero | Error; gas burned | Violates canonical Fp encoding |
| Point on G1 “wrong subgroup” | Not checked — and for G1, cofactor 1 makes this a non-issue | Safe for G1 arithmetic; confusing when compared to G2 or to MSM subgroup checks |
| Empty input (0 bytes) | Error; gas burned | Invalid length |
| Valid encoding, point not on G1 | Error; gas burned | Separate encoding validity from curve membership |
Real-World Exploits
Exploit 1: No Known Exploits Specific to BLS12_G1ADD (as of Early 2026)
Root cause: N/A — there is no public, confirmed exploit chain targeting BLS12_G1ADD specifically. The precompile is new; on-chain usage is still growing.
Details: Ethereum execution-spec-tests include extensive vectors for EIP-2537 curve operations. Multiple client teams and auditors have reviewed BLS12-381 integrations. The absence of known exploits is not a proof of absence of bugs — BN254 precompiles operated for years before CVE-2025-30147 highlighted validation divergence across libraries.
Precompile’s role: BLS12_G1ADD is a building block for on-chain BLS12-381 arithmetic. A future client bug in addition/encoding could affect any protocol that depends on 0x0B for verifier or aggregation logic.
Impact: No confirmed mainnet theft or split attributed to G1ADD to date; potential impact would mirror other consensus-critical precompiles (verifier unsoundness or network divergence).
References:
Exploit 2: CVE-2025-30147 — BN254 Validation Bug as Precedent for BLS12 Client Risk
Root cause: A client implementation (Hyperledger Besu, affected versions 24.7.1–25.2.2) did not fully validate BN254 precompile inputs before arithmetic, while other major clients did. Off-curve points could yield incorrect curve results, producing state root divergence (CVSS 4.0 score 8.7). Fixed in Besu 25.3.0 / besu-native 1.3.0.
Details: The defect concerned alt_bn128 precompiles, not BLS12-381. The lesson transfers: curve precompile code paths must match the executable spec for encoding, on-curve checks, and infinity handling — any skew is a consensus hazard. BLS12-381 has a larger field and different serialization than BN254, widening parsing and reduction surface area if clients disagree.
Precompile’s role: BLS12_G1ADD was not involved in CVE-2025-30147. It is cited as the closest real-world precedent for “curve precompile + validation mistake → divergence.”
Impact: Consensus / split risk on networks dominated by a buggy client; on heterogeneous Ethereum mainnet, enshrined divergence was limited, but the vulnerability class is practical, not theoretical.
References:
Attack Scenarios
Scenario A: Large Forwarded Gas to BLS12_G1ADD Without Cheap Validation
// VULNERABLE PATTERN: forwards all remaining gas; malformed input burns it all (EIP-2537)
pragma solidity ^0.8.0;
contract RiskyG1Add {
address internal constant BLS12_G1ADD = address(0x0B);
function addG1(bytes calldata input) external returns (bytes memory) {
require(input.length == 256, "length"); // length alone does not imply valid Fp / on-curve
bytes memory out = new bytes(128);
bool ok;
assembly {
ok := staticcall(
gas(), // forwards entire remaining gas — dangerous on EIP-2537 failure
BLS12_G1ADD,
input.offset,
256,
add(out, 32),
128
)
}
require(ok, "g1add failed");
// Also assert returndatasize() == 128 in assembly-heavy code paths.
return out;
}
}
// Failure / attack mode:
// 1. Attacker supplies 256 bytes with invalid Fp limbs or off-curve coordinates.
// 2. Precompile errors; all gas forwarded to 0x0B is burned.
// 3. Victims may OOG; griefing scales with gas limit and uncapped stipend.
// Mitigation: cap stipend (~375 + overhead); validate encodings before call where economical.Scenario B: Ignoring Return Status and Using Stale Memory
// VULNERABLE PATTERN: ignores staticcall success and effective return length
pragma solidity ^0.8.0;
contract UnsafeG1Add {
address internal constant BLS12_G1ADD = address(0x0B);
function addG1Unchecked(
bytes32 x1_hi, bytes32 x1_lo,
bytes32 y1_hi, bytes32 y1_lo,
bytes32 x2_hi, bytes32 x2_lo,
bytes32 y2_hi, bytes32 y2_lo
) external view returns (bytes32 ox_hi, bytes32 ox_lo, bytes32 oy_hi, bytes32 oy_lo) {
bytes memory input = abi.encodePacked(
x1_hi, x1_lo, y1_hi, y1_lo,
x2_hi, x2_lo, y2_hi, y2_lo
);
bytes memory output = new bytes(128);
assembly {
pop(staticcall(
gas(),
BLS12_G1ADD,
add(input, 32),
256,
add(output, 32),
128
))
// BUG: success ignored. On failure, returndata may be empty; buffer may be stale/zero.
}
assembly {
ox_hi := mload(add(output, 32))
ox_lo := mload(add(output, 64))
oy_hi := mload(add(output, 96))
oy_lo := mload(add(output, 128))
}
}
}
// Failure mode:
// 1. Provide off-curve or invalidly encoded coordinates (still 256 bytes).
// 2. Precompile fails; gas burned; staticcall success = false.
// 3. Contract still reads `output` as a valid G1 point and continues verification.Mitigations
| Threat | Mitigation | Implementation |
|---|---|---|
| T1: Subgroup / API confusion | Document G1 cofactor = 1 vs G2; never assume G1ADD implies the same checks as MSM or pairing | Architecture reviews; explicit comments at call sites; read EIP-2537 for per-precompile rules |
| T2: Stale output | Check success and returndatasize == 128 | require(ok); assembly returndatasize() check; returndatacopy into a fresh buffer |
| T3: Bad Fp encoding | Enforce top-zero limbs and < p before call when economical | Shared serialization helpers; property tests against execution-spec-tests vectors |
| T4: Gas burning | Cap forwarded gas (375 + small overhead) | Avoid staticcall(gas(), 0x0B, …) for untrusted input; validate length 256 before call |
| P1–P2: Client risk | Diversify clients on critical networks; track security advisories | Same operational response pattern as post-CVE-2025-30147 |
| General | Centralize BLS12 calls in one audited module | Single wrapper for G1ADD / G1MSM / pairing with uniform error and gas policy |
Compiler/EIP-Based Protections
- EIP-2537 (Pectra, May 2025): Defines BLS12_G1ADD at 0x0B, 375 gas, input/output layouts, infinity encoding, no subgroup check on G1ADD, and burn all forwarded gas on failure.
- Execution-spec-tests: Conformance vectors for cross-client agreement; they do not substitute for client version hygiene or operational monitoring.
- Solidity / Yul: No compiler-enforced check of precompile success or return length — mitigations are purely programmatic (
staticcallresult,returndatasize, gas stipends).
Severity Summary
| Threat ID | Category | Severity | Likelihood | Real-World Precedent |
|---|---|---|---|---|
| T1 | Smart Contract / Spec understanding | High | Medium | No G1 small-subgroup exploit (cofactor 1); BLS API confusion is a recurring audit theme |
| T2 | Smart Contract | Medium | Medium | Unchecked precompile calls — stale memory (BN256ADD pattern) |
| T3 | Smart Contract | Medium | Medium | Non-canonical Fp encodings and ≥ p values with zero high limbs |
| T4 | Smart Contract / Economics | Medium | Medium | EIP-2537 gas burn on error — griefing with high stipends |
| P1 | Protocol / Operational | Medium | N/A (time-dependent) | ~10 months mainnet exposure as of March 2026 vs BN254 |
| P2 | Protocol / Client | High | Low | CVE-2025-30147 (BN254 / Besu) — validation bugs → consensus divergence |
| P3 | Protocol / Education | Medium | Medium | G1 vs G2 cofactor asymmetry — pattern-porting bugs |
Related Precompiles
| Precompile | Relationship |
|---|---|
| BLS12_G1MSM (0x0C) | Multi-scalar multiplication on G1; performs subgroup checks on points — different trust assumptions than G1ADD |
| BLS12_G2ADD (0x0D) | G2 addition; cofactor ≠ 1 — no subgroup check is far more dangerous than on G1 |
| BLS12_PAIRING_CHECK (0x0F) | Pairing-based verification consuming G1/G2 points from broader pipelines |
| BN256ADD (0x06) | Earlier curve addition on alt_bn128; empty return and different gas semantics vs EIP-2537 burn-on-error |
| BLS12_MAP_FP_TO_G1 (0x10) | Field-to-G1 map; outputs may feed G1ADD in hash-to-curve constructions |