# Ethereum Precompiled Contracts

The Bifrost Network supports the standard precompiled contract installed on the Ethereum mainnet. The following is the table of addresses of the implemented precompiled contracts.

#### ECRECOVER

It returns the signer address of the ecdsa signature (v, r, s) if the signature is valid. It can be called directly in Solidity code.

```solidity
// contract address: 0x0000000000000000000000000000000000000001
function ecrecover(bytes32 data, bytes32 v, bytes32 r, bytes32 s) returns (address);
```

#### SHA256

It returns the keccak-hash value of the data. It can be called directly in Solidity code.

```solidity
// contract address: 0x0000000000000000000000000000000000000002
function sha256(bytes data) returns (bytes32);
```

#### RIPEMD160

It returns the ripemd160-hash value of the data. It can be called directly in Solidity code.

```solidity
// contract address: 0x0000000000000000000000000000000000000003
function ripemd160(bytes data) returns (bytes32);
```

#### Identity

Also known as datacopy, this function serves as a cost-efficient way to copy data in memory. Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000004
contract Identity{

    bytes public memoryStored;

    function callDatacopy(bytes memory data) public returns (bytes memory) {
        bytes memory result = new bytes(data.length);
        assembly {
            let len := mload(data)
            if iszero(call(gas(), 0x04, 0, add(data, 0x20), len, add(result,0x20), len)) {
                invalid()
            }
        }

        memoryStored = result;

        return result;
    }
}
```

#### Modular Exponentiation

This function calculates the remainder when an integer `b`(base) is raised to the `e`-th power(the exponent) and is divided by a positive integer `m`(the modulus). Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000005
contract ModularCheck {

    uint public checkResult;

    // Function to Verify ModExp Result
    function verify( uint _base, uint _exp, uint _modulus) public {
        checkResult = modExp(_base, _exp, _modulus);
    }

    function modExp(uint256 _b, uint256 _e, uint256 _m) public returns (uint256 result) {
        assembly {
            // Free memory pointer
            let pointer := mload(0x40)
            // Define length of base, exponent and modulus. 0x20 == 32 bytes
            mstore(pointer, 0x20)
            mstore(add(pointer, 0x20), 0x20)
            mstore(add(pointer, 0x40), 0x20)
            // Define variables base, exponent and modulus
            mstore(add(pointer, 0x60), _b)
            mstore(add(pointer, 0x80), _e)
            mstore(add(pointer, 0xa0), _m)
            // Store the result
            let value := mload(0xc0)
            // Call the precompiled contract 0x05 = bigModExp
            if iszero(call(not(0), 0x05, 0, pointer, 0xc0, value, 0x20)) {
                revert(0, 0)
            }
            result := mload(value)
        }
    }
}
```

#### BN128Add

The `BN128Add` precompiled contract implements a native elliptic curve point addition. It returns an elliptic curve point representing `(ax, ay) + (bx, by)` such that `(ax, ay)` and `(bx, by)` are valid points on the curve `BN256`. Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000006
contract Precompiles {
    function callBn256Add(bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by) public returns (bytes32[2] memory result) {
        bytes32[4] memory input;
        input[0] = ax;
        input[1] = ay;
        input[2] = bx;
        input[3] = by;
        assembly {
            let success := call(gas, 0x06, 0, input, 0x80, result, 0x40)
            switch success
            case 0 {
                revert(0,0)
            }
        }
    }
}
```

#### BN128Mul

The `BN128Mul` precompiled contract implements a native elliptic curve multiplication with a scalar value. It returns an elliptic curve point representing `scalar * (x, y)` such that `(x, y)` is a valid curve point on the curve `BN256`. Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000007
contract Precompiles {
    function callBn256ScalarMul(bytes32 x, bytes32 y, bytes32 scalar) public returns (bytes32[2] memory result) {
        bytes32[3] memory input;
        input[0] = x;
        input[1] = y;
        input[2] = scalar;
        assembly {
            let success := call(gas, 0x07, 0, input, 0x60, result, 0x40)
            switch success
            case 0 {
                revert(0,0)
            }
        }
    }
}
```

#### BN128Pairing

The `BN128Pairing` precompile implements elliptic curve paring operation to perform zkSNARK verification. For more information, check out the [EIP-197 standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md). Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000008
contract Precompiles {
    function callBn256Pairing(bytes memory input) public returns (bytes32 result) {
        // input is a serialized bytes stream of (a1, b1, a2, b2, ..., ak, bk) from (G_1 x G_2)^k
        uint256 len = input.length;
        require(len % 192 == 0);
        assembly {
            let memPtr := mload(0x40)
            let success := call(gas, 0x08, 0, add(input, 0x20), len, memPtr, 0x20)
            switch success
            case 0 {
                revert(0,0)
            } default {
                result := mload(memPtr)
            }
        }
    }
}
```

#### Blake2F

This EIP will enable the `BLAKE2b` hash function and other higher-round 64-bit `BLAKE2` variants to run cost-effectively on the EVM, allowing easier interoperability between Ethereum and Zcash or any other Equihash-based PoW coin. For more information, check out the [EIP-152 standard](https://eips.ethereum.org/EIPS/eip-152). Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000009
function callBlake2F(uint32 rounds, bytes32[2] memory h, bytes32[4] memory m, bytes8[2] memory t, bool f) public view returns (bytes32[2] memory) {
    bytes32[2] memory output;

    bytes memory args = abi.encodePacked(rounds, h[0], h[1], m[0], m[1], m[2], m[3], t[0], t[1], f);

    assembly {
        if iszero(staticcall(not(0), 0x09, add(args, 32), 0xd5, output, 0x40)) {
            revert(0, 0)
        }
    }

    return output;
}
```
