Precompiled Contracts

In this Wormhole I am exploring the existing precompiled contract currently supported by the Ethereum clients. Not only I am going to review which are the contracts/functionalities supported but also, I’m going to research on when are they used, and how to call them.

I’m taking the opportunity to explore how gas calculations are made and if the MetaMask gasAPI is returning correct values for these type of calls.

Arguments to Perform External Calls

  1. gas : amount of gas to send to the sub context to execute. The gas that is
    not used by the sub context is returned to this one.
  2. address : the account which context to execute.
  3. value : value in wei to send to the account.
  4. argsOffset : byte offset in the memory in bytes, the calldata of the
    sub context.
  5. argsSize : byte size to copy (size of the calldata).
  6. retOffset : byte offset in the memory in bytes, where to store the return
    data of the sub context.
  7. retSize : byte size to copy (size of the return data).

List of Precompiled Contracts

In the Geth repository we can find the list of existing pre-compiled contracts and their addresses. For example, in the case we would like to call bn256Add, we would need to specify the contract address 0x06 and so on.

  • 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{},
  • common.BytesToAddress([]byte{6}): &bn256Add{},
  • common.BytesToAddress([]byte{7}): &bn256ScalarMul{},
  • common.BytesToAddress([]byte{8}): &bn256Pairing{},

Using Precompiled Contracts

Elliptic Curve Addition

contract PrecompiledCall {

    event precompiledResult(bytes32[2]);
    
    function callBn256Add(bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by) public {
        bytes32[2] memory result;
        bytes32[4] memory input;
        input[0] = ax;
        input[1] = ay;
        input[2] = bx;
        input[3] = by;

        // ECADD address 0x06
        assembly {
            let success := call
            (5000000000000, 0x06, 0, input, 0x80, result, 0x40)
            switch success
            case 0 {
                revert(0,0)
            }
            mstore(0x0, result)
        }

        emit precompiledResult(result);
    }

Sources

  • https://blog.qtum.org/precompiled-contracts-and-confidential-assets-55f2b47b231d