Skip to content

Precompiled contracts

Precompiles are contracts implemented natively by the client rather than in EVM bytecode. They live at fixed low addresses, take raw bytes with no ABI encoding and no function selector, and are priced by their own gas formulas instead of by opcode.

Frost runs the Osaka rules from genesis, so it has every precompile Ethereum mainnet has, plus 2 of its own: the ML-DSA post-quantum signature verifiers at 0x14 and 0x15. Those two are what make post-quantum accounts affordable — verifying a lattice signature in Solidity would cost millions of gas, while the precompile does it for the price of a handful of ECDSA recoveries.

AddressNameMin gasInputOutputDescription
0x01ECREC3,000128 bytes32 bytes, or empty on failureRecover the address that produced an ECDSA signature over a 32-byte hash.
0x02SHA25660variable32 bytesSHA2-256 hash of the input.
0x03RIPEMD160600variable32 bytesRIPEMD-160 hash of the input, left-padded to 32 bytes.
0x04ID15variablesame as inputReturn the input unchanged — the cheapest way to copy memory.
0x05MODEXP500variable, 96-byte header + operandsmodLen bytesArbitrary-precision modular exponentiation: base^exponent mod modulus.
0x06BN254_ADD150128 bytes64 bytesPoint addition on the alt_bn128 (BN254) curve.
0x07BN254_MUL6,00096 bytes64 bytesScalar multiplication on the alt_bn128 (BN254) curve.
0x08BN254_PAIRING45,000a multiple of 192 bytes32 bytesOptimal ate pairing check on alt_bn128 — the workhorse of most zkSNARK verifiers.
0x09BLAKE2F0213 bytes64 bytesThe BLAKE2b compression function F, run for a caller-specified number of rounds.
0x0aKZG_POINT_EVALUATION50,000192 bytes64 bytesVerify a KZG proof that a blob polynomial evaluates to a claimed value at a point.
0x0bBLS12_G1ADD375256 bytes128 bytesPoint addition in the BLS12-381 G1 group.
0x0cBLS12_G1MSM12,000a multiple of 160 bytes128 bytesMulti-scalar multiplication in the BLS12-381 G1 group.
0x0dBLS12_G2ADD600512 bytes256 bytesPoint addition in the BLS12-381 G2 group.
0x0eBLS12_G2MSM22,500a multiple of 288 bytes256 bytesMulti-scalar multiplication in the BLS12-381 G2 group.
0x0fBLS12_PAIRING_CHECK37,700a multiple of 384 bytes32 bytesPairing check on BLS12-381.
0x10BLS12_MAP_FP_TO_G15,50064 bytes128 bytesMap a base field element to a point in G1.
0x11BLS12_MAP_FP2_TO_G223,800128 bytes256 bytesMap an extension field element to a point in G2.
0x14VERIFY_MLDSA65 PQ16,0005293 bytes (exact)32 bytes, alwaysVerify an ML-DSA-65 (FIPS 204) post-quantum signature.
0x15VERIFY_MLDSA44 PQ10,5003764 bytes (exact)32 bytes, alwaysVerify an ML-DSA-44 (FIPS 204) post-quantum signature.
0x0100P256VERIFY6,900160 bytes (exact)32 bytes, or empty on failureVerify a secp256r1 (NIST P-256) ECDSA signature.

How precompile calls work

A precompile is invoked like any other contract, usually with staticcall. Three things differ from a normal call:

  • No ABI. The input is a flat byte string laid out at fixed offsets. There is no 4-byte selector and no 32-byte padding of arguments unless the layout says so.
  • Gas is charged up front. The client computes the cost from the input before running anything, and the call fails with out-of-gas if you supplied less. You pay the full price whether or not the operation succeeds.
  • Failure is not uniform. Some precompiles revert, some return a zero word, and some return empty data with no error. That last group is the dangerous one — see below.

Failure conventions

Three different conventions coexist, and mixing them up is a real source of bugs:

ConventionPrecompilesWhat a naive caller does wrong
Reverts0x05, 0x060x09, 0x0a0x11Nothing — the call bubbles up a failure you cannot miss.
Returns empty data, no error0x01 ECREC, 0x0100 P256VERIFYReads a stale or zeroed memory slot as a successful result. You must check the returned data length.
Returns a 32-byte 0 or 1, always0x14, 0x15 (Frost)Nothing. This is deliberate: there is no empty-return case to misread.

Frost's verifiers were specified into the third group on purpose. A verifier that can return empty on malformed input invites a caller to treat "no output" as "verified", which is the difference between an account that checks a signature and an account that anyone can spend from. 0x14 and 0x15 return exactly one 32-byte word on every path, including wrong-length input.

Address space

Frost leaves a deliberate gap: standard Ethereum precompiles occupy 0x010x11, Frost's post-quantum verifiers sit at 0x14 and 0x15, and 0x0100 holds P256VERIFY per EIP-7951. The gap at 0x120x13 is reserved and unoccupied.

Precompiles are not the whole address map. Frost also ships several predeploys and system contracts — real accounts with real bytecode at fixed addresses, including the CREATE2 factory that counterfactual account addresses are derived against.