Precompile Summary
| Address | Name | Gas | Input | Output | Introduced | Behavior |
|---|---|---|---|---|---|---|
| 0x10 | BLS12_MAP_FP_TO_G1 | 5,500 (fixed) | 64 bytes: a single base field element Fp (big-endian). The top 16 bytes must be zero; the integer value must be strictly < p (BLS12-381 base field modulus). | 128 bytes: G1 affine point — 64-byte big-endian x, then 64-byte big-endian y (Fp coordinates, same canonical limb layout as other EIP-2537 G1 points). | Pectra hardfork (EIP-2537, May 2025) | Maps an Fp element to a point on BLS12-381 G1 using the SWU (Shallue–van de Woestijne–Ulas) map as defined in the EIP-2537 companion document. The returned point is on the G1 curve and lies in the prime-order subgroup (cofactor clearing is implicit for G1 because h₁ = 1). This precompile is not a full hash-to-curve primitive: it only implements Fp → G1. Callers that need bytes → G1 (for example, BLS message hashing) must first derive one or more Fp elements from the message in EVM (or off-chain), then compose maps and curve arithmetic as required by their protocol. On invalid input length or invalid field encoding (non-zero top 16 bytes, value ≥ p), all gas forwarded to the precompile is burned. |
Threat Surface
BLS12_MAP_FP_TO_G1 is a low-level field-to-curve map: it assumes the caller has already chosen a concrete Fp representative and only answers whether that 64-byte encoding is canonical and what G1 point the enshrined SWU construction yields. It does not bind to application domains, message semantics, or random-oracle narratives — those are entirely caller-defined.
The dominant risks are cryptographic composition and strict encoding:
1. Incomplete hash-to-curve pipelines. Many developers want “hash message to G1” in one call. EIP-2537 intentionally omits bytes → Fp from this precompile because that step admits multiple standards and can be done efficiently in Solidity. That correct layering decision moves all responsibility for uniformity, domain separation, and multi-limb constructions to the contract author. Treating a single MAP_FP_TO_G1 invocation as the entire hash-to-curve — after a naive or single-limb field reduction of a digest — yields biased message points and breaks assumptions behind standard BLS security arguments (which typically rely on RFC 9380-style pipelines with two field elements mapped and combined).
2. Non-uniformity of a single SWU map. One SWU image point is not uniformly distributed on G1. For protocols that model the map as a random oracle, a single map is insufficient; the bias may be small but is cryptographically meaningful when proofs depend on uniform G1 challenges.
3. Canonical Fp encoding and failure economics. Like other BLS12 precompiles under EIP-2537, 64-byte big-endian limbs require 16 high zero bytes and value < p. Zero is valid and maps to a well-defined point. Any violation burns all forwarded gas — a smaller absolute stipend than pairing (5,500 gas) but still exploitable in tight loops or when contracts forward large gas budgets.
4. Cross-client determinism of SWU / square roots. Implementations must agree on every branch of SWU, including Fp square root (for example Tonelli–Shanks versus the p ≡ 3 (mod 4) fast path for BLS12-381). Divergence is a consensus fault class, separate from application-level misuse.
Smart Contract Threats
T1: Incomplete Hash-to-Curve Pipeline (High)
- MAP_FP_TO_G1 is not a complete hash-to-curve function. It maps Fp → G1 only; it does not map arbitrary bytes → Fp.
- A full hash-to-curve generally requires: (1) expand/hash the message to one or more field elements (with domain separation and correct length handling), (2) map each element to the curve (here via SWU), and (3) combine results (for G1, explicit cofactor clearing is not needed because h₁ = 1).
- RFC 9380 hash-to-curve for BLS12-381 G1 typically uses two Fp elements, each passed through a map, then added — giving a distribution appropriate for random-oracle analyses.
- Using one MAP_FP_TO_G1 call on a single field element derived from a hash (without the standard two-map construction) produces non-uniform points on G1, weakening the effective message hash in BLS-style schemes.
- Safer pattern (conceptual): derive two canonical Fp encodings from the message per your protocol’s hash-to-field rules, call MAP_FP_TO_G1 twice, then BLS12_G1ADD to combine — matching the spirit of RFC 9380 / EIP-2537 usage guidance.
Why it matters: Miscomposed “hash-to-curve” breaks the algebraic and statistical assumptions auditors and proofs attach to BLS signatures and pairing-based protocols. The failure mode is often silent (no revert) while cryptographic strength drops.
T2: Non-Uniform Distribution for Single-Call Usage (Medium)
- A single SWU map does not induce a uniform distribution on G1.
- Security proofs that treat the message point as output of a random oracle are misaligned with single-map usage.
- The bias can be subtle but matters wherever algebraic generic models assume uniform independent G1 points.
Why it matters: Protocol designers may underestimate the gap between “we called the map precompile” and “we implemented RFC 9380 hash-to-curve.” That gap becomes a design-level vulnerability in BLS deployments.
T3: Field Element Encoding Validation (Medium)
- 64-byte big-endian Fp: top 16 bytes must be zero; interpreted integer must be < p.
- Value = 0 is valid and maps to a specific G1 point (not a special-case error).
- Value ≥ p fails even if lower limbs look plausible; non-zero high 16 bytes fail regardless of magnitude.
- On any encoding error: all gas forwarded to 0x10 is burned.
Why it matters: Manual packing from uint256, keccak limbs, or off-chain tooling without mod p reduction and zero-extension produces bricked calls and griefing when paired with large forwarded gas. It also encourages unchecked call patterns that read stale buffers on failure.
T4: Gas Burning on Error (Low)
- 5,500 gas is moderate; a single malicious input is rarely catastrophic alone.
- In loops over many candidate field elements, cumulative burn and revert cascades can degrade liveness or DoS verification paths.
- Contracts that use
staticcall(gas(), 0x10, …)on untrusted encodings still risk disproportionate loss versus a capped stipend.
Why it matters: Error economics under EIP-2537 reward cheap client-side or on-chain pre-checks (length 64, limb shape, < p) before invoking the precompile.
Protocol-Level Threats
P1: Bytes-to-Field Left to the Caller (EIP Design)
EIP-2537 states that this mapping does not perform bytes → Fp because that step can be implemented many ways and can be done efficiently in the EVM. That split is correct for a minimal consensus interface but concentrates protocol risk in application code: every deployment must specify exactly how messages become Fp limbs, including domain separation and multi-output hashing where required.
P2: Deterministic SWU and Square-Root Semantics Across Clients
All execution clients must implement identical SWU behavior, including Fp square root branch selection. Different internal strategies (Tonelli–Shanks vs p ≡ 3 (mod 4) exponentiation) must agree on bit-identical outputs for all inputs. Any discrepancy is a consensus hazard, independent of Solidity misuse.
P3: Subgroup and On-Curve Guarantees for G1
The precompile’s output is specified to be on-curve and in the prime-order G1 subgroup. For BLS12-381 G1, cofactor 1 means there is no separate small-subgroup class on the curve image — the interesting subgroup story remains on G2 and in pairing entry points, not in MAP_FP_TO_G1 outputs themselves.
Edge Cases
| Edge Case | Behavior | Security Implication |
|---|---|---|
| Input 64 zero bytes (u = 0) | Valid; maps to a defined G1 point per spec | Callers must not assume “zero input” means error; protocol logic must treat 0 ∈ Fp like any other field element |
| Input represents p − 1 | Valid if encoding is canonical (< p) | Extreme field values stress SWU / sqrt paths — rely on execution-spec-tests and client parity |
| Integer value ≥ p | Error; all forwarded gas burned | Requires mod p reduction before fixed-width serialization |
| Top 16 bytes non-zero | Error; gas burned | Common bug when concatenating ABI words without zeroing high limbs |
| Input length < 64 bytes | Error; gas burned | Strict length — no implicit padding |
| Input length > 64 bytes | Error; gas burned | Extra suffix bytes are not ignored |
| Valid Fp, boundary bit-length | Success returns 128-byte G1 point | Downstream G1ADD / MSM / pairing still impose their own encoding rules |
Real-World Exploits
No public, confirmed exploits targeting BLS12_MAP_FP_TO_G1 are known as of early 2026. The precompile shipped with Pectra (EIP-2537, May 2025) and has limited mainnet history compared to long-lived precompiles. The SWU map and hash-to-curve standards (RFC 9380) are well-studied; residual risk clusters in composition mistakes (single-map “hash-to-curve”) and in client implementation parity, not in a novel on-chain attack brand.
Precedent: Other curve precompiles have seen consensus-level validation bugs (for example CVE-2025-30147 on BN254 — different curve, same lesson: encoding and arithmetic paths must match the executable spec everywhere).
Attack Scenarios
Scenario A: Single MAP_FP_TO_G1 Used as Entire “Hash-to-Curve” for BLS
// VULNERABLE PATTERN: one field element, one map — not RFC 9380 / standard BLS message hash
pragma solidity ^0.8.0;
contract BiasedMessageMap {
address internal constant MAP_FP_TO_G1 = address(0x10);
/// @notice WRONG for production BLS: derives a single Fp from keccak256, maps once.
function messageToG1(bytes32 domain, bytes calldata message)
external
view
returns (bytes memory g1Point)
{
bytes32 h = keccak256(abi.encodePacked(domain, message));
bytes memory fp64 = new bytes(64);
// Pretend 32-byte hash left-padded to 64 bytes is a valid Fp encoding (still must be < p)
assembly {
mstore(add(fp64, 32), h) // lower 32 bytes; upper 32 bytes zero in this naive example
}
g1Point = new bytes(128);
bool ok;
assembly {
ok := staticcall(
gas(),
MAP_FP_TO_G1,
add(fp64, 32),
64,
add(g1Point, 32),
128
)
}
require(ok && returndatasize() == 128, "map failed");
// Cryptographic issue: single-map pipeline → biased G1 message point vs two-map + add.
}
}
// Failure / attack mode:
// 1. Signatures verify under this ad-hoc scheme but security proof assumptions fail.
// 2. Adversary may gain advantage vs protocols that assume uniform message points / ROM.
// Mitigation: implement proper hash-to-field (two limbs) + two MAP_FP_TO_G1 + BLS12_G1ADD (0x0B).Scenario B: No Cheap Validation Before Precompile — Wasted Gas on Bad Encodings
// VULNERABLE PATTERN: unvalidated user-supplied "Fp" limb forwarded with huge gas stipend
pragma solidity ^0.8.0;
contract MapWithoutChecks {
address internal constant MAP_FP_TO_G1 = address(0x10);
function mapUntrusted(bytes calldata allegedFp64) external view returns (bytes memory out) {
require(allegedFp64.length == 64, "length");
out = new bytes(128);
bool ok;
assembly {
ok := staticcall(
gas(), // uncapped — burns all on EIP-2537 precompile error
MAP_FP_TO_G1,
allegedFp64.offset,
64,
add(out, 32),
128
)
}
require(ok, "map failed");
}
}
// Failure / attack mode:
// 1. Attacker supplies 64 bytes with top limbs non-zero or value >= p.
// 2. Precompile burns all gas forwarded to 0x10; nested calls may OOG.
// Mitigation: cap stipend (~5500 + overhead); validate top-16-zero and < p when economical.Mitigations
| Threat | Mitigation | Implementation |
|---|---|---|
| T1: Incomplete hash-to-curve | Follow RFC 9380-style construction: two Fp outputs from hash-to-field, two MAP_FP_TO_G1 calls, BLS12_G1ADD | Spec the exact transcript hash; centralize in one audited library; cross-check test vectors against execution-spec-tests |
| T2: Single-map non-uniformity | Do not rely on one SWU image as a random oracle | Security reviews explicitly label “hash-to-curve” vs “field map” steps |
| T3: Bad Fp encoding | Enforce len == 64, top 16 bytes == 0, value < p before staticcall when gas analysis favors it | Shared Fp serialization helpers; fuzz round-trip encodings |
| T4: Gas burning | Cap forwarded gas near 5,500 + overhead; avoid staticcall(gas(), 0x10, …) on untrusted input | Wrapper contract with fixed stipend |
| P1: Caller-defined bytes→Fp | Document domain separation and suite ID (if using RFC 9380 expand/message variants) | Off-chain spec + on-chain comments at precompile call sites |
| P2: Client parity | Run multi-client nodes on testnets; monitor advisories | Same operational posture as other EIP-2537 primitives |
Compiler/EIP-Based Protections
- EIP-2537 (Pectra, May 2025): Defines BLS12_MAP_FP_TO_G1 at 0x10, 5,500 gas, strict 64-byte input and 128-byte G1 output, SWU map semantics, and burn all forwarded gas on failure.
- Companion specification (referenced by EIP-2537): Canonical SWU and Fp decoding rules — implementations must match bit-for-bit across clients.
- Solidity / Yul: No compiler-enforced hash-to-curve correctness; staticcall success,
returndatasize == 128, and gas stipends are programmatic obligations.
Severity Summary
| Threat ID | Category | Severity | Likelihood | Notes |
|---|---|---|---|---|
| T1 | Smart contract / Cryptography | High | Medium | Biased message points when MAP_FP_TO_G1 substitutes for full hash-to-curve |
| T2 | Smart contract / Proof assumptions | Medium | Medium | ROM / uniformity mismatch for single-map usage |
| T3 | Smart contract / Encoding | Medium | Medium | Non-canonical Fp and ≥ p values; gas burn on error |
| T4 | Smart contract / Economics | Low | Low–Medium | 5,500 gas cap per call limits single-shot damage; loops amplify cost |
| P1 | Protocol / API layering | Medium | N/A | Bytes→Fp complexity shifted to callers — correct but hazardous if misunderstood |
| P2 | Protocol / Client implementation | High | Low | SWU / sqrt divergence → consensus fault (no known MAP_FP_TO_G1-specific incident) |
| P3 | Protocol / Curve semantics | Low | N/A | G1 cofactor 1 simplifies subgroup story vs G2 |
Related Precompiles
| Precompile | Relationship |
|---|---|
| BLS12_MAP_FP2_TO_G2 (0x11) | Fp² → G2 analogue; same caller-side hash-to-curve composition concerns on G2 |
| BLS12_G1ADD (0x0B) | Combines two G1 points — used after two field maps in standard hash-to-curve patterns |
| BLS12_G1MSM (0x0C) | G1 multi-scalar multiplication; different validation rules vs bare G1ADD |
| BLS12_PAIRING_CHECK (0x0F) | Consumes G1/G2 points from full verification pipelines that may include mapped points |