Precompile Summary
| Property | Value |
|---|---|
| Address | 0x11 |
| Name | BLS12_MAP_FP2_TO_G2 |
| Gas | 23,800 (fixed) |
| Input | 128 bytes: one Fp2 element encoded as c0 (64 bytes) ‖ c1 (64 bytes), representing c0 + c1·v where v is the formal square root of the quadratic non-residue in the BLS12-381 tower. Each 64-byte component is a big-endian Fp element whose top 16 bytes must be zero and whose integer value must be strictly less than the field modulus p. |
| Output | 256 bytes: a G2 affine point as 128-byte x (Fp2) followed by 128-byte y (Fp2), using the same c0 ‖ c1 convention per coordinate. The result lies on the BLS12-381 G2 curve and, after internal cofactor clearing, in the prime-order G2 subgroup. |
| Introduced | Pectra hardfork (EIP-2537, May 2025) |
| Behavior | Maps the given Fp2 element to a point on the BLS12-381 G2 curve using the Simplified Shallue–van de Woestijne–Ulas (SWU) map defined in the EIP. The precompile does not implement a full hash-to-curve pipeline: the caller is responsible for any message expansion, domain separation, and conversion from arbitrary bytes to canonical Fp2 field elements. Cofactor clearing is performed inside the precompile so the output is in the correct prime-order subgroup (unlike raw G2 curve points from G2ADD, which carry no subgroup guarantee). On error (wrong input length, non-canonical Fp encoding, component ≥ p, invalid top-zero padding), the precompile burns all gas forwarded to the call. On success, returns exactly 256 bytes. |
Threat Surface
BLS12_MAP_FP2_TO_G2 is a field-to-curve primitive over the Fp2 extension: it turns a single structured field element into a G2 point with subgroup membership enforced by the implementation. It does not interpret application semantics — no domains, no message hashing, no proof-system binding — so protocol designers must supply the full cryptographic pipeline around it.
The surface is larger and more sensitive than MAP_FP_TO_G1 (0x10) for several reasons:
1. G2 is where many BLS deployments place public keys. In Ethereum’s consensus-oriented BLS12-381 usage, signatures are commonly hashed to G1 and public keys live in G2. Any incorrect or non-standard “hash-to-G2” construction that feeds key derivation, registry enrollment, or verification inputs can therefore break assumptions at the identity layer of the signature scheme, not merely at a message-encoding detail.
2. This precompile is not hash-to-curve. RFC 9380–style hash-to-G2 requires expanding a message to field elements, mapping, and often combining multiple map outputs. A single MAP_FP2_TO_G2 call on one expanded Fp2 value yields a valid subgroup point but generally not the uniform distribution that a full hash-to-curve suite guarantees. Misusing the precompile as “the hash” step is a design-level failure mode.
3. Fp2 encoding doubles the limb count and ordering risk. Each Fp2 input has two 64-byte Fp components. Swapping c0 and c1 yields another valid Fp2 element and maps to a different G2 point; the precompile cannot detect intent. Combined with off-chain tooling that may use different serialization conventions, silent wrong-point bugs are plausible.
4. Implementation complexity and consensus alignment. SWU over Fp2 involves extension-field arithmetic and square roots in Fp2, which are strictly more intricate than the Fp case. Cofactor clearing on G2 must match the EIP’s prescribed method exactly across clients; alternative mathematically valid clearing strategies could otherwise diverge on outputs for the same input.
5. Economics of failure. At 23,800 fixed gas — the highest fixed cost among the BLS12 precompiles except pairing and MSM families — each failed call wastes more budget than MAP_FP_TO_G1 (5,500 gas). Loops or griefing patterns that trigger errors burn correspondingly more.
Smart Contract Threats
T1: Incomplete Hash-to-Curve Pipeline — More Critical for G2 (High)
Using MAP_FP2_TO_G2 alone as “hash to G2” omits steps that modern standards require for a secure hash-to-curve construction.
- RFC 9380 hash-to-G2 (BLS12-381 suite) conceptually expands a message to two Fp2 elements, applies MAP_FP2_TO_G2 to each, then adds the resulting points (e.g., via BLS12_G2ADD), with proper domain separation and expand-message rules.
- A single MAP_FP2_TO_G2 call produces a well-formed subgroup point but typically not the target distribution or binding properties of full hash-to-curve.
- In schemes that only hash messages to G1, this precompile may appear rarely; for G2-targeted derivation (keys, commitments, custom proofs), the non-uniformity and missing second-map/add structure is a direct cryptographic concern.
Why it matters: Incorrect hash-to-curve pipelines break unpredictability and binding assumptions. On G2, those mistakes often intersect public-key and aggregator logic, where errors are harder to detect than a failed signature check on a single message.
T2: Cofactor Clearing Complexity (Medium)
G2 has a large cofactor h₂. The precompile must clear cofactor so the output lies in the prime-order subgroup.
- Multiple valid mathematical approaches to cofactor clearing exist in the literature; only the EIP-specified algorithm is consensus-valid.
- Implementation variance (if any client used a different clearing path) could in principle yield different valid subgroup points for the same Fp2 input — a consensus fault class, not merely an application bug.
Why it matters: Developers rely on byte-identical outputs across nodes. Cofactor clearing is the subtle step where “mathematically equivalent” methods are not interchangeable on-chain.
T3: Fp2 Element Encoding — c0 / c1 Ordering (Medium)
The input encodes one Fp2 value as c0 ‖ c1 for c0 + c1·v.
- Swapping
c0andc1defines a different Fp2 element and maps to a different G2 point. - Both orderings can be canonically valid field elements; the precompile has no way to infer the developer’s intent.
Why it matters: This is a silent logic bug when tooling or hand-rolled serialization disagrees with EIP-2537’s ordering — wrong keys, wrong commitments, and passing tests that only check “some” point on-curve.
T4: High Gas Cost (Low)
23,800 gas is the largest fixed gas among the BLS12 precompiles excluding pairing and MSM.
- Errors burn all forwarded gas; failed calls are more expensive than MAP_FP_TO_G1 failures (5,500 gas).
- Tight loops invoking MAP_FP2_TO_G2 can dominate block gas usage or enable griefing when an adversary supplies inputs that fail validation after a high stipend.
Why it matters: Economic and DoS-margin effects for contracts that batch-map many field elements without strict pre-validation or gas caps.
Protocol-Level Threats
P1: Fp2 SWU and Square-Root Edge Cases
G2 mapping operates over Fp2. The SWU pipeline includes square roots in the extension field, which admit more structural cases than square roots in Fp alone. Client implementations must match the EIP’s branch and constant selections exactly so that all valid inputs converge on the same output bytes.
P2: Cofactor Clearing Must Be Identical Across Clients
Different cofactor-clearing strategies can be mathematically sound yet produce different representative subgroup points. EIP-2537 pins down one algorithm for MAP_FP2_TO_G2; any deviation is a consensus risk, not an optional optimization.
P3: Gas Schedule Reflects Fp2 Work and Clearing
The 23,800 gas cost is roughly 4.3× MAP_FP_TO_G1’s 5,500, reflecting additional Fp2 arithmetic and cofactor clearing on G2. Protocols should budget accordingly and avoid treating G1 and G2 mapping as interchangeable in cost models.
Edge Cases
| Edge Case | Behavior | Security Implication |
|---|---|---|
Input Fp2 = (0, 0) (c0 and c1 both zero) | Valid field element; maps to a specific G2 point per EIP | Not an error; callers must not assume “zero input → error” |
c0 = 0, c1 ≠ 0 | Valid Fp2 element | Legitimate input; test vectors and bounds checks should allow |
c0 ≠ 0, c1 = 0 | Valid Fp2 (“pure real” component) | Legitimate input; same as above |
c0 or c1 ≥ p | Error; all forwarded gas burned | Canonical Fp requirement; must validate off-chain or before high-stipend calls |
| Input length < 128 bytes | Error; gas burned | Strict length; no padding semantics |
| Input length > 128 bytes | Error; gas burned | Surplus bytes are not ignored |
| Top 16 bytes of either 64-byte component non-zero | Error; gas burned | Violates canonical BLS12-381 Fp limb layout |
| Successful return | 256 bytes; point on G2 curve and in prime-order subgroup (cofactor cleared internally) | Do not re-clear cofactor unless your protocol layer explicitly requires a different representation — follow EIP for interoperability |
Real-World Exploits
No Known Exploits Specific to MAP_FP2_TO_G2
The precompile is very new (Pectra, May 2025). There is no public catalog of mainnet incidents targeting 0x11 as of early 2026.
Broader Precedent: Hash-to-Curve and Precompile Correctness
- RFC 9380 and prior hash-to-curve standards codify that full suites (expand + map + combine) are required for standard security goals; single-map misuse is a design failure class rather than a novel attack type.
- CVE-2025-30147 (Besu / BN256) showed that curve precompile implementation mistakes can become consensus divergence. The analogy for BLS12 G2 is implementation alignment on Fp2 SWU and cofactor clearing, not a known live exploit against MAP_FP2_TO_G2.
References:
- EIP-2537: BLS12-381 Curve Operations
- RFC 9380 — Hashing to Elliptic Curves
- CVE-2025-30147 — Ethereum Foundation Blog
Attack Scenarios
Scenario A: BLS Key Derivation Using a Single MAP_FP2_TO_G2 Instead of Two-Point Construction
// VULNERABLE PATTERN: treating one MAP_FP2_TO_G2 call as "hash to G2"
// for key material. RFC 9380-style hash-to-G2 uses TWO maps + G2ADD.
pragma solidity ^0.8.0;
contract WeakG2KeyDerivation {
address internal constant BLS12_MAP_FP2_TO_G2 = address(0x11);
// Derives a "public key" or commitment point from a single expanded Fp2.
// WRONG for standard hash-to-G2: should expand to TWO Fp2 values, map each,
// then BLS12_G2ADD — not a single map.
function deriveG2FromOneFp2(bytes calldata fp2_128) external view returns (bytes memory) {
require(fp2_128.length == 128, "length");
bytes memory out = new bytes(256);
bool ok;
assembly {
ok := staticcall(
gas(),
BLS12_MAP_FP2_TO_G2,
fp2_128.offset,
128,
add(out, 32),
256
)
}
require(ok && out.length == 256, "map failed");
return out;
}
}
// Attack / failure mode:
// 1. Protocol assumes deriveG2FromOneFp2 implements RFC 9380 hash-to-G2.
// 2. Distribution and binding properties do not match the standard suite.
// 3. Downstream proofs, multisig registration, or KDF security claims are false.
//
// Mitigation: implement full RFC 9380 hash-to-G2 (expand + double map + G2ADD)
// with correct domain separation; or use audited off-chain hashing and only
// verify on-chain with PAIRING_CHECK / G2MSM as appropriate.Scenario B: Fp2 Encoding with Swapped c0 / c1 Producing the Wrong G2 Point Silently
// VULNERABLE PATTERN: off-chain tooling writes imaginary limb first, on-chain
// expects EIP-2537 order c0 || c1 — both can be canonical Fp values < p.
pragma solidity ^0.8.0;
contract FragileFp2Encoding {
address internal constant BLS12_MAP_FP2_TO_G2 = address(0x11);
function mapFp2(bytes calldata c0_c1_128) external view returns (bytes memory) {
require(c0_c1_128.length == 128, "length");
// No reordering check possible: precompile cannot know caller intent.
bytes memory out = new bytes(256);
bool ok;
assembly {
ok := staticcall(25000, BLS12_MAP_FP2_TO_G2, c0_c1_128.offset, 128, add(out, 32), 256)
}
require(ok, "map failed");
return out;
}
}
// Failure mode:
// 1. Library A serializes Fp2 as (c1, c0) or labels limbs differently.
// 2. Contract passes 128 bytes with swapped 64-byte halves — still valid Fp limbs.
// 3. MAP_FP2_TO_G2 succeeds and returns a legitimate subgroup point — wrong semantics.
//
// Mitigation: pin serialization in specs; cross-test against execution-spec vectors;
// property tests that round-trip expected RFC/EIP test vectors end-to-end.Mitigations
| Threat | Mitigation | Implementation |
|---|---|---|
| T1: Incomplete hash-to-curve | Implement full RFC 9380 hash-to-G2 (expand, two maps, G2ADD) with domain tags | Follow RFC 9380 BLS12-381 G2 suite; never equate one MAP_FP2_TO_G2 with “the hash” |
| T2: Cofactor clearing variance | Rely on EIP-2537 test vectors; monitor client advisories | Consensus clients must ship identical clearing; auditors focus on Fp2 SWU + clearing paths |
T3: c0/c1 swap | Document and test Fp2 byte order; align all tooling to c0 ‖ c1 | CI against official vectors; reject ambiguous library defaults |
| T4: High gas / burn on error | Validate length (128), padding, and < p before call; cap staticcall gas | Use explicit stipend (~23,800 + overhead) instead of gas() where possible |
| P1–P3: Protocol alignment | Treat G2 map as non-interchangeable with G1 map in cost and spec | Budget gas separately; track EIP-2537 errata |
Compiler/EIP-Based Protections
- EIP-2537 (Pectra, May 2025): Defines BLS12_MAP_FP2_TO_G2 at 0x11, 23,800 fixed gas, 128-byte Fp2 input, 256-byte G2 output, SWU map, internal cofactor clearing to the prime-order subgroup, canonical Fp encoding rules, and all forwarded gas burned on failure.
- Execution-spec-tests / reference vectors: Cross-client conformance for MAP_FP2_TO_G2; operators still need version hygiene and client diversity.
- Solidity / Yul: No compiler-enforced hash-to-curve or Fp2 layout checks — use explicit
staticcallsuccess,returndatasize == 256, gas stipends, and off-chain test vectors.
Severity Summary
| Threat ID | Category | Severity | Likelihood | Notes |
|---|---|---|---|---|
| T1 | Smart contract / Cryptographic misuse | High | Medium | Single-map-as-hash breaks standard hash-to-G2; worse when G2 carries identity (e.g., pubkeys) |
| T2 | Protocol / Client implementation | Medium | Low | Consensus-critical if any client diverged on clearing — no known live exploit |
| T3 | Smart contract / Encoding | Medium | Medium | Silent wrong point when c0/c1 order disagrees with EIP |
| T4 | Smart contract / Economics & DoS | Low | Medium | Higher fixed gas and burn than G1 map; batching without validation amplifies cost |
| P1 | Protocol / Algorithm complexity | High | N/A (structural) | Fp2 SWU + sqrt correctness must match EIP exactly |
| P2 | Protocol / Spec alignment | High | N/A (structural) | Cofactor clearing algorithm is normative across clients |
| P3 | Protocol / Resource model | Medium | N/A (structural) | 23,800 gas reflects Fp2 work; affects protocol budgeting |
Related Precompiles
| Precompile | Relationship |
|---|---|
| BLS12_MAP_FP_TO_G1 (0x10) | G1 field-to-curve map over Fp; lower fixed gas (5,500); same “not full hash-to-curve” caveat, but G1/G2 roles differ in typical BLS deployments |
| BLS12_G2ADD (0x0D) | Adds two G2 points; no subgroup check on inputs — contrast with MAP_FP2_TO_G2’s subgroup output |
| BLS12_G2MSM (0x0E) | G2 multi-scalar multiplication; subgroup checks on points per EIP-2537 — use when combining mapped points with scalars |
| BLS12_PAIRING_CHECK (0x0F) | Pairing verification; enforces subgroup checks on G2 inputs — typical gate for trusting G2 points in BLS verification |