Ethereum precompiles behave like smart contracts built into the Ethereum protocol. These operations are desirable enough to have gas-efficient mechanism for doing them. Implementing these algorithms in Solidity would be considerably less gas efficient.
The idea was that led to precompiles was solving the problem of allowing complex cryptographic computations to be usable in the EVM without having to deal with EVM overhead.
The utility of precompiles falls into four categories
Precompiles do not execute inside a smart contract (they are not EVM bytecode), they are part of the Ethereum execution client specification.
Most precompiles don’t have a solidity wrapper (with ecrecover
being the sole exception). You’ll need to call the address directly with addressOfPrecompile.staticcall(…)
or use assembly.
Example:
function recoverSignature(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public view returns (address) {
address r = ecrecover(hash, v, r, s);
require(r != address(0), "signature is invalid");
}
This is the snippet of code directly from Geth (go-ethereum), the most famous Ethereum execution client, developed by the Ethereum Foundation.
// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
// contracts used in the Cancun release.
var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{20}): &kzgPointEvaluation{},
}
You can already see the newest precompile kzgPointEvaluation
that is going to be added in the Cancun release.
As you can read from the comments, a precompile contract just needs to implement the PrecompiledContract
interface (speaking of Geth).