> For the complete documentation index, see [llms.txt](https://docs.wemix.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.wemix.com/ko/dapp-developer/smart-contract/precompiled-contracts.md).

# Precompiled Contracts

WEMIX3.0 블록체인에는 사전에 컴파일된 컨트랙트가 존재합니다. 해당 컴파일된 컨트랙트는 이더리움에서 배포된 컨트랙트와 WEMIX에서 새로 지원하는 컨트랙트가 제공됩니다.

## ECDSA 서명의 공개키 복구 함수  <a href="#recovery-of-ecdsa-signature" id="recovery-of-ecdsa-signature"></a>

0x01 주소에는 타원 곡선 디지털 서명 알고리즘의 공개키를 복구하는 함수가 제공됩니다. 트랜잭션의 해시값과 v, r, s 서명값을 입력받아 주소를 반환하게 됩니다.

WEMIX3.0 테스트넷에 배포된 컨트랙트의 주소는 0xD37d47514f46efaCa967fc191D040B3ee713110A 으로 테스트넷 익스플로러를 통해 확인이 가능합니다. &#x20;

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract Ecrecover {
    address addressTest = 0x12Cb274aAD8251C875c0bf6872b67d9983E53fDd;
    bytes32 msgHash = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d50;
    uint8 v = 0x1b;
    bytes32 r = 0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef;
    bytes32 s = 0x7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb4;


    function verify() public view returns(bool) {
        // Use ECRECOVER to verify address
        return (ecrecover(msgHash, v, r, s) == (addressTest));
    }
}
```

## SHA256 해시 함수 <a href="#sha256-hash-function" id="sha256-hash-function"></a>

0x02 주소에는 SHA-256 해시 함수가 제공됩니다. 데이터를 입력하면 이에 해당하는 SHA-256 해시값이 반환됩니다.&#x20;

WEMIX3.0 테스트넷에 배포된 컨트랙트 주소는 0xdbec92984EE8508e3A47C150C5BDBF02B8928A72 으로 테스트넷 익스플로러를 통해 확인이 가능합니다.

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract Sha256hash {
    bytes32 public expectedHash = 0x7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069;

    function calculateHash() internal pure returns (bytes32) {
        string memory word = 'Hello World!';
        bytes32 hash = sha256(bytes (word));

        return hash;        
    }

    function checkHash() public view returns(bool) {
        return (calculateHash() == expectedHash);
    }
}

```

## RIPEMD160 해시 함수 <a href="#ripemd160-hash-function" id="ripemd160-hash-function"></a>

0x03 주소에는 RIPEMD-160 해시 함수가 제공됩니다. 데이터를 입력하면 이에 해당하는 RIPEMD-160 해시값이 반환됩니다.

WEMIX3.0 테스트넷에 배포된 컨트랙트 주소는 0x39b2CB921353097993e72e811A5FC4992b72e926 으로 테스트넷 익스플로러를 통해 확인이 가능합니다.

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract Ripmd160 {
    bytes20 public expectedHash = hex'8476ee4631b9b30ac2754b0ee0c47e161d3f724c';

    function calculateHash() internal pure returns (bytes20) {
        string memory word = 'Hello World!';
        bytes20 hash = ripemd160(bytes (word));

        return hash;        
    }

    function checkHash() public view returns(bool) {
        return (calculateHash() == expectedHash);
    }
}
```

## Data Copy 함수 <a href="#data-copy-function" id="data-copy-function"></a>

0x04 주소에는 데이터 복사 함수가 제공됩니다. 이 기능은 메모리에 데이터를 복사하는 더 저렴한 방법으로 사용됩니다.

현재 Solidity에는 dataCopy 함수 지원이 없으므로 인라인 어셈블리로 호출해야 합니다.

WEMIX3.0 테스트넷에 배포된 컨트랙트 주소는 0x709Ba0DD7055BC61B781Ddda31F5Df0018F33391 으로 테스트넷 익스플로러를 통해 확인이 가능합니다.

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract Datacopy {
    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 함수 <a href="#modular-exponentiation-function" id="modular-exponentiation-function"></a>

0x05 주소에는 정수 `b`(밑수)를 `e-`제곱(지수)으로 올리고 양의 정수 `m`(모듈러스)로 나눌 때 나머지를 계산하는 함수를 제공합니다.

Solidity 컴파일러는 이를 지원하지 않으므로 인라인 어셈블리로 호출해야 합니다.

WEMIX3.0 테스트넷에 배포된 컨트랙트 주소는 0x370AF3a491f1D7cc08D7cc590bB2a746E612a216 으로 테스트넷 익스플로러를 통해 확인이 가능합니다.

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

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)
        }
    }
}
```

## 타원 곡선 상의 점에 대한 덧셈 함수 <a href="#point-addition-on-elliptic-curve" id="point-addition-on-elliptic-curve"></a>

0x06 주소에는 타원 곡선 상의 점에 대한 덧셈 연산을 구현한 함수가 제공됩니다. 이 연산은 타원 곡선 bn256 상의 유효한 두점 (ax,ay)와 (bx,by)를 입력받아 타원 곡선위의 점 (ax,ay)+(bx,by)를 결과로 반환합니다.

Solidity 컴파일러는 이 함수를 지원하지 않으므로 인라인 어셈블리로 호출해야 합니다.

WEMIX3.0 테스트넷에 배포된 컨트랙트 주소는 0x557359e169E56aAcb0d1E5FA9A7E8717967FcEbD 으로 테스트넷 익스플로러를 통해 확인이 가능합니다.

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract BnAddCheck {
    bytes32[2] public checkResult;

    // Function to Verify ModExp Result
    function verify(uint ax, uint ay, uint bx, uint by) public {
        bytes32[4] memory input;
        input[0] = bytes32(ax);
        input[1] = bytes32(ay);
        input[2] = bytes32(bx);
        input[3] = bytes32(by);
        checkResult = callBn256Add(input[0], input[1], input[2], input[3]);
    }

    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)
            }
        }
    }
}
```

## 타원 곡선 상의 점에 대한 곱셈 함수 <a href="#point-multiplication-on-elliptic-curve" id="point-multiplication-on-elliptic-curve"></a>

0x07 주소에는 스칼라 값으로 표현된 타원 곡선 상의 점에 대한 곱셈 연산을 구현한 함수가 제공됩니다. 이 연산은 타원 곡선 bn256 상의 유효한 점 (x,y)를 입력받아 타원 곡선 위의 점 scalar \* (x,y)를 결과로 반환합니다.

Solidity 컴파일러는 이 함수를 지원하지 않으므로 인라인 어셈블리로 호출해야 합니다.

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract BnMulCheck {
    bytes32[2] public checkResult;

    // Function to Verify ModExp Result
    function verify(uint x, uint y, uint scalar) public {
        bytes32[3] memory input;
        input[0] = bytes32(x);
        input[1] = bytes32(y);
        input[2] = bytes32(scalar);
        checkResult = callBn256ScalarMul(input[0], input[1], input[2]);
    }

    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(not(0), 0x07, 0, input, 0x60, result, 0x40)
            switch success
            case 0 {
                revert(0,0)
            }
        }
    }
}
```

## zkSNARK 검증을 위한 타원곡선 페어링 함수 <a href="#elliptic-curve-pairing-function-for-zksnark-validation" id="elliptic-curve-pairing-function-for-zksnark-validation"></a>

0x08 주소에는 EIP-197에 제안된 zkSNARK 검증하기 위한 타원 곡선 페이링 연산에 대한 함수가 제공됩니다.

Solidity 컴파일러는 이 함수를 지원하지 않으므로 인라인 어셈블리로 호출해야 합니다.

```
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract BnPairingCheck {

    ...
    function pairing(G1Point[] memory p1, G2Point[] memory p2) public returns (bool) {
        require(p1.length == p2.length);
        uint elements = p1.length;
        uint inputSize = elements * 6;
        uint[] memory input = new uint[](inputSize);
        for (uint i = 0; i < elements; i++)
        {
            input[i * 6 + 0] = p1[i].X;
            input[i * 6 + 1] = p1[i].Y;
            input[i * 6 + 2] = p2[i].X[0];
            input[i * 6 + 3] = p2[i].X[1];
            input[i * 6 + 4] = p2[i].Y[0];
            input[i * 6 + 5] = p2[i].Y[1];
        }
        uint[1] memory out;
        bool success;
        assembly {
            success := call(gas(), 0x08, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
            switch success
            case 0 {
                invalid()
            }
        }
        require(success);
        return out[0] != 0;
    }
    ...
}
```
