The five precompiles

Addresses, standards, gas, input framing and return values, live on mainnet.

Docs / Post-quantum / The five precompiles

Five precompiled contracts verify NIST post-quantum signatures and hashes inside the EVM. They are active on mainnet from block 9,189,161 and callable by any contract with a plain staticcall.

The five

AddressFunctionStandardGasInputOutput
0x0AE1Falcon-512 verifyNIST Falcon round 340,000 flat`pk(897) \\sm`32-byte word: …01 valid, …00 invalid
0x0AE2Falcon-1024 verifyNIST Falcon round 375,000 flat`pk(1793) \\sm`same
0x0AE3ML-DSA-44 verifyFIPS 20455,000 flat`pk(1312) \\sig(2420) \\message`same
0x0AE4SLH-DSA-SHA2-128s verifyFIPS 205350,000 flat`pk(32) \\sig(7856) \\message`same
0x0AE5SHAKE256 XOFFIPS 20260 + 12 per 32-byte word of input plus output32-byte big-endian output length, then dataoutLen bytes

Gas is flat, not size-dependent, for the four verifiers.

They never revert

A verification precompile does not revert on malformed input. It returns the 32-byte zero word. That means a caller cannot distinguish "the signature is invalid" from "I framed the input wrongly" by catching a revert. Both come back as zero.

This is the single most common integration failure, and it is why Falcon input framing is a page of its own. Write a positive control into your test: verify a signature you know is good, with framing you know is right, in the same run. If that returns zero, no other zero in that run means anything.

Calling one from Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

library Falcon512 {
    address internal constant PRECOMPILE = address(0x0AE1);

    /// @param input pk(897) || sigLen(2 BE) || nonce(40) || message || esig
    function verify(bytes memory input) internal view returns (bool) {
        (bool ok, bytes memory out) = PRECOMPILE.staticcall(input);
        return ok && out.length == 32 && uint256(bytes32(out)) == 1;
    }
}

Checking them against the live chain

The five pass the official NIST Known-Answer Tests on chain. You can run one yourself against the public endpoint with eth_call, which costs nothing:

curl -s -X POST -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x0000000000000000000000000000000000000ae5","data":"0x0000000000000000000000000000000000000000000000000000000000000020616263"},"latest"]}' \
  https://rpc.aere.network

That asks 0x0AE5 for 32 bytes of SHAKE256 over the three bytes abc, and the answer is the FIPS 202 value for that input.

Not on mainnet

0x0AE6 (ML-KEM-768 deterministic encapsulation, FIPS 203) and 0x0AE7 exist on the public testnet only. Do not build mainnet code against them.

The caveat that matters

Having these does not make an account post-quantum secure. See Overview, stated precisely for why, in one paragraph, before you build on top of them.