WEMIX3.0 블록체인에는 사전에 컴파일된 컨트랙트가 존재합니다. 해당 컴파일된 컨트랙트는 이더리움에서 배포된 컨트랙트와 WEMIX에서 새로 지원하는 컨트랙트가 제공됩니다.
ECDSA 서명의 공개키 복구 함수
0x01 주소에는 타원 곡선 디지털 서명 알고리즘의 공개키를 복구하는 함수가 제공됩니다. 트랜잭션의 해시값과 v, r, s 서명값을 입력받아 주소를 반환하게 됩니다.
WEMIX3.0 테스트넷에 배포된 컨트랙트의 주소는 0xD37d47514f46efaCa967fc191D040B3ee713110A 으로 테스트넷 익스플로러를 통해 확인이 가능합니다.
// 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 해시 함수
0x02 주소에는 SHA-256 해시 함수가 제공됩니다. 데이터를 입력하면 이에 해당하는 SHA-256 해시값이 반환됩니다.
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 해시 함수
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 함수
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 함수
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)
}
}
}
타원 곡선 상의 점에 대한 덧셈 함수
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)
}
}
}
}
타원 곡선 상의 점에 대한 곱셈 함수
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 검증을 위한 타원곡선 페어링 함수
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;
}
...
}