Metadium Tech (KOR)
  • Navigation
    • Metadium Overview
    • Metadium Tech (ENG)
    • Metadium Tech (KOR)
  • METADIUM Info
    • Architecture
    • Network Structure
    • Consensus
    • Smart Contract
    • DID
    • EIP-1559
    • Fee Delegation
    • Roadmap
  • Developer
    • Node Start
      • gmet Binary
      • gmet Guide
      • Connect Node
      • Account
    • Install Node
      • End Node
        • Requirements
        • Install Gmet
      • BP Node
        • Requirements
        • Install Gmet
  • Smart Contract
    • Solidity
    • Precompiled Contracts
    • Sample Contracts
  • API Reference
    • API Info
    • Json-RPC
    • Explorer API
      • Accounts
      • Blocks
      • Contracts
      • Transactions
      • Event logs
      • Tokens
  • Wallet
    • Wallet Info
    • Fee
  • FAQ
  • Articles of Foundation
Powered by GitBook
On this page
  • ECDSA μ„œλͺ…μ˜ κ³΅κ°œν‚€ 볡ꡬ ν•¨μˆ˜
  • SHA256 ν•΄μ‹œ ν•¨μˆ˜
  • RIPEMD160 ν•΄μ‹œ ν•¨μˆ˜
  • Data Copy ν•¨μˆ˜
  • Modular Exponentiation ν•¨μˆ˜
  • 타원 곑선 μƒμ˜ 점에 λŒ€ν•œ λ§μ…ˆ ν•¨μˆ˜
  • 타원 곑선 μƒμ˜ 점에 λŒ€ν•œ κ³±μ…ˆ ν•¨μˆ˜
  • zkSNARK 검증을 μœ„ν•œ 타원곑선 νŽ˜μ–΄λ§ ν•¨μˆ˜
  1. Smart Contract

Precompiled Contracts

메타디움 블둝체인은 미리 μ»΄νŒŒμΌλ˜μ–΄ μžˆλŠ” μ»¨νŠΈλž™νŠΈλ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. 메타디움 λΈ”λ‘μ²΄μΈμ—λŠ” 사전에 컴파일된 μ»¨νŠΈλž™νŠΈκ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€. ν•΄λ‹Ή 컴파일된 μ»¨νŠΈλž™νŠΈλŠ” μ΄λ”λ¦¬μ›€μ—μ„œ 배포된 μ»¨νŠΈλž™νŠΈμ™€ λ©”νƒ€λ””μ›€μ—μ„œ μƒˆλ‘œ μ§€μ›ν•˜λŠ” μ»¨νŠΈλž™νŠΈκ°€ μ œκ³΅λ©λ‹ˆλ‹€.

ECDSA μ„œλͺ…μ˜ κ³΅κ°œν‚€ 볡ꡬ ν•¨μˆ˜

0x01 μ£Όμ†Œμ—λŠ” 타원 곑선 λ””μ§€ν„Έ μ„œλͺ… μ•Œκ³ λ¦¬μ¦˜μ˜ κ³΅κ°œν‚€λ₯Ό λ³΅κ΅¬ν•˜λŠ” ν•¨μˆ˜κ°€ μ œκ³΅λ©λ‹ˆλ‹€. νŠΈλžœμž­μ…˜μ˜ ν•΄μ‹œκ°’κ³Ό v, r, s μ„œλͺ…값을 μž…λ ₯λ°›μ•„ μ£Όμ†Œλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. 메타디움 ν…ŒμŠ€νŠΈλ„·μ— 배포된 μ»¨νŠΈλž™νŠΈμ˜ μ£Όμ†ŒλŠ” 0x9AC3d2729e7e38949a5b7E9896C4b05B13765eaC으둜 ν…ŒμŠ€νŠΈλ„· μ΅μŠ€ν”Œλ‘œλŸ¬λ₯Ό 톡해 확인이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract Ecrecover {
    function test() public pure returns(bool) {
        address addressTest = 0x12Cb274aAD8251C875c0bf6872b67d9983E53fDd;
        bytes32 msgHash = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d50;
        uint8 v = 0x1b;
        bytes32 r = 0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef;
        bytes32 s = 0x7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb4;

        return (recoverSignature(msgHash, v, r, s) == (addressTest));
    }

    function recoverSignature(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public pure returns(address) {
        // Use ECRECOVER to verify address
        address addr = ecrecover(hash, v, r, s);
        require(addr != address(0), "signature is invalid");
        return addr;
    }
}

SHA256 ν•΄μ‹œ ν•¨μˆ˜

0x02 μ£Όμ†Œμ—λŠ” SHA-256 ν•΄μ‹œ ν•¨μˆ˜κ°€ μ œκ³΅λ©λ‹ˆλ‹€. 데이터λ₯Ό μž…λ ₯ν•˜λ©΄ 이에 ν•΄λ‹Ήν•˜λŠ” SHA-256 ν•΄μ‹œκ°’μ΄ λ°˜ν™˜λ©λ‹ˆλ‹€. 메타디움 ν…ŒμŠ€νŠΈλ„·μ— 배포된 μ»¨νŠΈλž™νŠΈ μ£Όμ†ŒλŠ” 0x1eFd33eaB481C903CB3e0766D71DAF4391B26043 으둜 ν…ŒμŠ€νŠΈλ„· μ΅μŠ€ν”Œλ‘œλŸ¬λ₯Ό 톡해 확인이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract HashSha256 {
    function test() public pure returns(bool) {
        bytes32 expectedHash = 0x7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069;
        string memory word = 'Hello World!';
        return (calculateHashSha256(word) == expectedHash);
    }

    function calculateHashSha256(string memory word) public pure returns (bytes32) {
        bytes32 hash = sha256(bytes (word));
        return hash;        
    }
}

RIPEMD160 ν•΄μ‹œ ν•¨μˆ˜

0x03 μ£Όμ†Œμ—λŠ” RIPEMD-160 ν•΄μ‹œ ν•¨μˆ˜κ°€ μ œκ³΅λ©λ‹ˆλ‹€. 데이터λ₯Ό μž…λ ₯ν•˜λ©΄ 이에 ν•΄λ‹Ήν•˜λŠ” RIPEMD-160 ν•΄μ‹œκ°’μ΄ λ°˜ν™˜λ©λ‹ˆλ‹€. 메타디움 ν…ŒμŠ€νŠΈλ„·μ— 배포된 μ»¨νŠΈλž™νŠΈ μ£Όμ†ŒλŠ” 0xf8C8cB0941b9A2fD511c87a73f9707D3c7Eb695c 으둜 ν…ŒμŠ€νŠΈλ„· μ΅μŠ€ν”Œλ‘œλŸ¬λ₯Ό 톡해 확인이 κ°€λŠ₯ν•©λ‹ˆλ‹€./

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract HashRipemd160 {
    function test() public pure returns(bool) {
        string memory word = 'Hello World!';
        bytes20 expectedHash = hex'8476ee4631b9b30ac2754b0ee0c47e161d3f724c';

        return (calculateHashRipemd160(word) == expectedHash);
    }

    function calculateHashRipemd160(string memory word) public pure returns (bytes20) {
        bytes20 hash = ripemd160(bytes(word));

        return hash;        
    }
}

Data Copy ν•¨μˆ˜

0x04 μ£Όμ†Œμ—λŠ” 데이터 볡사 ν•¨μˆ˜κ°€ μ œκ³΅λ©λ‹ˆλ‹€. 이 κΈ°λŠ₯은 λ©”λͺ¨λ¦¬μ— 데이터λ₯Ό λ³΅μ‚¬ν•˜λŠ” 더 μ €λ ΄ν•œ λ°©λ²•μœΌλ‘œ μ‚¬μš©λ©λ‹ˆλ‹€.ν˜„μž¬ Solidityμ—λŠ” dataCopy ν•¨μˆ˜ 지원이 μ—†μœΌλ―€λ‘œ 인라인 μ–΄μ…ˆλΈ”λ¦¬λ‘œ ν˜ΈμΆœν•΄μ•Ό ν•©λ‹ˆλ‹€. λ©”νƒ€λ””μŒ ν…ŒμŠ€νŠΈλ„·μ— 배포된 μ»¨νŠΈλž™νŠΈ μ£Όμ†ŒλŠ” 0xF1935F6236b6558d44aD2275B9d453082EBD9d68 으둜 ν…ŒμŠ€νŠΈλ„· μ΅μŠ€ν”Œλ‘œλŸ¬λ₯Ό 톡해 확인이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

contract Datacopy {
    event CallDatacopy(bytes data);

    function test() public returns(bool) {
        bytes memory expected = new bytes(5);
        expected[0] = 0x01;
        expected[1] = 0x23;
        expected[2] = 0x45;
        expected[3] = 0x67;
        expected[4] = 0x89;
        bytes memory results;
        results = callDatacopy(expected);
        for (uint256 i = 0; i < 5; i++) {
            if (results[i] != expected[i]) {
                return false;
            }
        }
        emit CallDatacopy(expected);
        return true;
    }

    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()
            }
        }
        return result;
    }
}

Modular Exponentiation ν•¨μˆ˜

0x05 μ£Όμ†Œμ—λŠ” μ •μˆ˜ b(λ°‘μˆ˜)λ₯Ό e-제곱(μ§€μˆ˜)으둜 올리고 μ–‘μ˜ μ •μˆ˜ m(λͺ¨λ“ˆλŸ¬μŠ€)으둜 λ‚˜λˆŒ λ•Œ λ‚˜λ¨Έμ§€λ₯Ό κ³„μ‚°ν•˜λŠ” ν•¨μˆ˜λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. Solidity μ»΄νŒŒμΌλŸ¬λŠ” 이λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ 인라인 μ–΄μ…ˆλΈ”λ¦¬λ‘œ ν˜ΈμΆœν•΄μ•Ό ν•©λ‹ˆλ‹€. 메타디움 ν…ŒμŠ€νŠΈλ„·μ— 배포된 μ»¨νŠΈλž™νŠΈ μ£Όμ†ŒλŠ” 0xA41b9c323527b1214cE7276364465183385a67fF 으둜 ν…ŒμŠ€νŠΈλ„· μ΅μŠ€ν”Œλ‘œλŸ¬λ₯Ό 톡해 확인이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

contract ModExpCheck {
    event ModExp(uint256 _b, uint256 _e, uint256 _m, uint256 _r);

    // Function to Verify ModExp Result
    function test() public returns (bool) {
        uint _base = 5;
        uint _exp = 8;
        uint _modulus = 7;
        uint expected = 4;
        uint result = modExp(_base, _exp, _modulus);
        emit ModExp(_base, _exp, _modulus, result);
        return expected == result;
    }

    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(gas(), 0x05, 0, pointer, 0xc0, value, 0x20)) {
                revert(0, 0)
            }
            result := mload(value)
        }
    }
}

타원 곑선 μƒμ˜ 점에 λŒ€ν•œ λ§μ…ˆ ν•¨μˆ˜

0x06 μ£Όμ†Œμ—λŠ” 타원 곑선 μƒμ˜ 점에 λŒ€ν•œ λ§μ…ˆ 연산을 κ΅¬ν˜„ν•œ ν•¨μˆ˜κ°€ μ œκ³΅λ©λ‹ˆλ‹€. 이 연산은 타원 곑선 bn256 μƒμ˜ μœ νš¨ν•œ 두점 (ax,ay)와 (bx,by)λ₯Ό μž…λ ₯λ°›μ•„ 타원 κ³‘μ„ μœ„μ˜ 점 (ax,ay)+(bx,by)λ₯Ό 결과둜 λ°˜ν™˜ν•©λ‹ˆλ‹€. Solidity μ»΄νŒŒμΌλŸ¬λŠ” 이 ν•¨μˆ˜λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ 인라인 μ–΄μ…ˆλΈ”λ¦¬λ‘œ ν˜ΈμΆœν•΄μ•Ό ν•©λ‹ˆλ‹€. λ©”νƒ€λ””μŒ ν…ŒμŠ€νŠΈλ„·μ— 배포된 μ»¨νŠΈλž™νŠΈ μ£Όμ†ŒλŠ” 0xa6a7c21EbB8af0e7514daB6de8E8143E5E780e83 으둜 ν…ŒμŠ€νŠΈλ„· μ΅μŠ€ν”Œλ‘œλŸ¬λ₯Ό 톡해 확인이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

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 μ»΄νŒŒμΌλŸ¬λŠ” 이 ν•¨μˆ˜λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ 인라인 μ–΄μ…ˆλΈ”λ¦¬λ‘œ ν˜ΈμΆœν•΄μ•Ό ν•©λ‹ˆλ‹€. λ©”νƒ€λ””μŒ ν…ŒμŠ€νŠΈλ„·μ— 배포된 μ»¨νŠΈλž™νŠΈ μ£Όμ†ŒλŠ” 0xa424E85E2930375626612EaC99D6574eF59F090b 으둜 ν…ŒμŠ€νŠΈλ„· μ΅μŠ€ν”Œλ‘œλŸ¬λ₯Ό 톡해 확인이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

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

zkSNARK 검증을 μœ„ν•œ 타원곑선 νŽ˜μ–΄λ§ ν•¨μˆ˜

0x08 μ£Όμ†Œμ—λŠ” EIP-197에 μ œμ•ˆλœ zkSNARK κ²€μ¦ν•˜κΈ° μœ„ν•œ 타원 곑선 페이링 연산에 λŒ€ν•œ ν•¨μˆ˜κ°€ μ œκ³΅λ©λ‹ˆλ‹€. Solidity μ»΄νŒŒμΌλŸ¬λŠ” 이 ν•¨μˆ˜λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ 인라인 μ–΄μ…ˆλΈ”λ¦¬λ‘œ ν˜ΈμΆœν•΄μ•Ό ν•©λ‹ˆλ‹€. λ©”νƒ€λ””μŒ ν…ŒμŠ€νŠΈλ„·μ— 배포된 μ»¨νŠΈλž™νŠΈ μ£Όμ†ŒλŠ” 0x405b7c971c2Ae9F1f79BD43ef59C680811B1612A 으둜 ν…ŒμŠ€νŠΈλ„· μ΅μŠ€ν”Œλ‘œλŸ¬λ₯Ό 톡해 확인이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

// File: contracts/Pairing.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

library Pairing {
    struct G1Point {
        uint X;
        uint Y;
    }

    // Encoding of field elements is: X[0] * z + X[1]
    struct G2Point {
        uint[2] X;
        uint[2] Y;
    }

    /// @return the generator of G1
    function P1() pure internal returns (G1Point memory) {
        return G1Point(1, 2);
    }

    /// @return the generator of G2
    function P2() pure internal returns (G2Point memory) {
        // Original code point
        return G2Point(
            [11559732032986387107991004021392285783925812861821192530917403151452391805634,
             10857046999023057135944570762232829481370756359578518086990519993285655852781],
            [4082367875863433681332203403145435568316851327593401208105741076214120093531,
             8495653923123431417604973247489272438418190587263600148770280649306958101930]
        );
    }

    // @return the negation of p, i.e. p.addition(p.negate()) should be zero.
    function negate(G1Point memory p) pure internal returns (G1Point memory r) {
        // The prime q in the base field F_q for G1
        uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
        if (p.X == 0 && p.Y == 0)
            return G1Point(0, 0);
        return G1Point(p.X, q - (p.Y % q));
    }

    // @return the sum of two points of G1
    function addition(G1Point memory p1, G1Point memory p2) public returns (G1Point memory result) {
        uint[4] memory input;
        input[0] = p1.X;
        input[1] = p1.Y;
        input[2] = p2.X;
        input[3] = p2.Y;

        assembly {
            let success := call(gas(), 0x06, 0, input, 0x80, result, 0x40)
            switch success
            case 0 { invalid() }
        }
    }

    // @return the product of a point on G1 and a scalar, i.e.
    // p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
    function scalar_mul(G1Point memory p, uint scalar) public returns (G1Point memory result) {
        uint[3] memory input;
        input[0] = p.X;
        input[1] = p.Y;
        input[2] = scalar;

        assembly {
            let success := call(gas(), 0x07, 0, input, 0x60, result, 0x40)
            switch success
            case 0 { invalid() }
        }
    }

    // @return the result of computing the pairing check
    // e(p1[0], p2[0]) *  .... * e(p1[n], p2[n]) == 1
    // For example pairing([P1(), P1().negate()], [P2(), P2()]) should
    // return true.
    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 {
            //let memPtr := mload(0x40)
            success := call(gas(), 0x08, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
            switch success
            case 0 {
                invalid()
            }
        }
        require(success);
        return out[0] != 0;
    }
    
    /// Convenience method for a pairing check for two pairs.
    function pairingProd2(
            G1Point memory a1, G2Point memory a2, 
            G1Point memory b1, G2Point memory b2
    ) public returns (bool) {
        G1Point[] memory p1 = new G1Point[](2);
        G2Point[] memory p2 = new G2Point[](2);
        p1[0] = a1;
        p1[1] = b1;
        p2[0] = a2;
        p2[1] = b2;
        return pairing(p1, p2);
    }

    /// Convenience method for a pairing check for three pairs.
    function pairingProd3(
            G1Point memory a1, G2Point memory a2,
            G1Point memory b1, G2Point memory b2,
            G1Point memory c1, G2Point memory c2
    ) public returns (bool) {
        G1Point[] memory p1 = new G1Point[](3);
        G2Point[] memory p2 = new G2Point[](3);
        p1[0] = a1;
        p1[1] = b1;
        p1[2] = c1;
        p2[0] = a2;
        p2[1] = b2;
        p2[2] = c2;
        return pairing(p1, p2);
    }

    /// Convenience method for a pairing check for four pairs.
    function pairingProd4(
            G1Point memory a1, G2Point memory a2,
            G1Point memory b1, G2Point memory b2,
            G1Point memory c1, G2Point memory c2,
            G1Point memory d1, G2Point memory d2
    ) public returns (bool) {
        G1Point[] memory p1 = new G1Point[](4);
        G2Point[] memory p2 = new G2Point[](4);
        p1[0] = a1;
        p1[1] = b1;
        p1[2] = c1;
        p1[3] = d1;
        p2[0] = a2;
        p2[1] = b2;
        p2[2] = c2;
        p2[3] = d2;
        return pairing(p1, p2);
    }
}

// File: contracts/BnPairingCheck.sol

pragma solidity ^0.8.10;


contract BnPairingCheck {
    using Pairing for *;

    bool public result = false;

    struct VerifyingKey {
        Pairing.G2Point A;
        Pairing.G1Point B;
        Pairing.G2Point C;
        Pairing.G2Point gamma;
        Pairing.G1Point gammaBeta1;
        Pairing.G2Point gammaBeta2;
        Pairing.G2Point Z;
        Pairing.G1Point[] IC;
    }

    struct Proof {
        Pairing.G1Point A;
        Pairing.G1Point A_p;
        Pairing.G2Point B;
        Pairing.G1Point B_p;
        Pairing.G1Point C;
        Pairing.G1Point C_p;
        Pairing.G1Point K;
        Pairing.G1Point H;
    }

    function verifyingKey() pure internal returns (VerifyingKey memory vk) {
        vk.A = Pairing.G2Point([16610027721320090851672124826930543804510863425028512395206306928317475535804,8936789845922544559097602524648054597031330865008407381460968729887808214434], [2278578217592196498969542612994107970434638305320265550173445225942027074854,18336449124045676471393750622290479431334440531824730522288602977607157240650]);
        vk.B = Pairing.G1Point(1984924168632842141759455341627143753024960974027438898638858975972756407564,10991053238332375915565380359166789463201591761740938272761726473772838859618);
        vk.C = Pairing.G2Point([10660728934017853141365044466918475010597411890641229655657848436103395876116,3996391662237560225890291735380647896924014963474714424016445511172825791389], [5221331779058503178196633838312686055158887166644266661901185854029433298779,12183448649224206996148652487149426507910593413372228701177454061805688094675]);
        vk.gamma = Pairing.G2Point([19004037734259218065220057650211328986997252342301116788268586579684875932598,18093848281567039857436784662151682189745312020865996311429156694186522940309], [5377856403552463400841775516298918127240964967532295209455188775179474313786,2889539749595311565918940419300442407947814810042015422814827877135693568505]);
        vk.gammaBeta1 = Pairing.G1Point(7796626316580434743798382369107477206221192049125686546210621144964120983689,7934884528679805498299923633957794379202307702360555586276991024938091670488);
        vk.gammaBeta2 = Pairing.G2Point([4487005664450616024577102016311266690760571702764152553013463219021170678312,372268767343205135890641734006927513939290443891671725490699149337509414363], [8727588333078631340262914721329976700431073842680933627593659695896604918915,5027865297535949490479385388683367202474878200260477572501220964101178956894]);
        vk.Z = Pairing.G2Point([10162018577464408960423216104240658562943290569546240862381635704410977689235,15750847760428609853592351550031388692358090666989687368017823231947603993362], [13703537493621251480372183323146309058645469102580923196624726955632303691613,10133848043702140632001179191067180047829615626613968726429425860753144960369]);
        vk.IC = new Pairing.G1Point[](2);
        vk.IC[0] = Pairing.G1Point(10205875104072397627386129936295372804967786394340262122517620344193853862704,3108802252545217304319096845192350237223097046684036942919565176050064079266);
        vk.IC[1] = Pairing.G1Point(19450223878547003131641146404062695786601341609154957657760980302351711435043,2090278837353290546550331589621169669090493301065290400727820127066575899332);
 
    }

    function verify(uint[] memory input, Proof memory proof) public returns (uint ret) {
        VerifyingKey memory vk = verifyingKey();
        require(input.length + 1 == vk.IC.length);
        // Compute the linear combination vk_x
        Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
        for (uint i = 0; i < input.length; i++)
            vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
        vk_x = Pairing.addition(vk_x, vk.IC[0]);
        if (!Pairing.pairingProd2(proof.A, vk.A, Pairing.negate(proof.A_p), Pairing.P2())) return 1;
        if (!Pairing.pairingProd2(vk.B, proof.B, Pairing.negate(proof.B_p), Pairing.P2())) return 2;
        if (!Pairing.pairingProd2(proof.C, vk.C, Pairing.negate(proof.C_p), Pairing.P2())) return 3;
        if (!Pairing.pairingProd3(
            proof.K, vk.gamma,
            Pairing.negate(Pairing.addition(vk_x, Pairing.addition(proof.A, proof.C))), vk.gammaBeta2,
            Pairing.negate(vk.gammaBeta1), proof.B
        )) return 4;
        if (!Pairing.pairingProd3(
                Pairing.addition(vk_x, proof.A), proof.B,
                Pairing.negate(proof.H), vk.Z,
                Pairing.negate(proof.C), Pairing.P2()
        )) return 5;
        return 0;
    }

    function verifyProof(
            uint[2] memory a,
            uint[2] memory a_p,
            uint[2][2] memory b,
            uint[2] memory b_p,
            uint[2] memory c,
            uint[2] memory c_p,
            uint[2] memory h,
            uint[2] memory k,
            uint[1] memory input
        ) public returns (bool r) {
        Proof memory proof;
        proof.A = Pairing.G1Point(a[0], a[1]);
        proof.A_p = Pairing.G1Point(a_p[0], a_p[1]);
        proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
        proof.B_p = Pairing.G1Point(b_p[0], b_p[1]);
        proof.C = Pairing.G1Point(c[0], c[1]);
        proof.C_p = Pairing.G1Point(c_p[0], c_p[1]);
        proof.H = Pairing.G1Point(h[0], h[1]);
        proof.K = Pairing.G1Point(k[0], k[1]);
        uint[] memory inputValues = new uint[](input.length);
        for(uint i = 0; i < input.length; i++){
            inputValues[i] = input[i];
        }

        if (verify(inputValues, proof) == 0) {
            return true;
        } else {
            return false;
        }
    }
 
    function test0() public returns(bool) {
        result = verifyProof(
            /* a */ [uint(0), uint(0)],
            /* ap */ [uint(0), uint(0)],
            /* b */ [[uint(0), uint(0)],
             [uint(0), uint(0)]],
            /* bp */[uint(0), uint(0)],
            /* c */ [uint(0), uint(0)],
            /* cp */ [uint(0), uint(0)],
            /* h */[uint(0), uint(0)],
            /* k*/[uint(0), uint(0)],
            [uint(0)]
        );
        return result;
    }
 
    function test1() public returns(bool) {
        result = verifyProof(
            /* a */ [2718095278949549179404065840476808091497056756728594798546953443174968085826, 6822245515525308836376340038348001955735763358906191705690804179787195477339],
            /* ap */ [7962916779937813326271929941948123357638224433531051619920345691927094697341, 21602782423350364400160182139945359886597092844703295668648735242500045407956],
            /* b */ [[8709267585010911413120517213461511437508385177818224549274052467927652980944, 19632384762601388343074878513416079515099688438290666177847273314001684795253],
             [17954051800382421030408553656518095452830038658837501416087917013452810023812, 9313407443169062170332246002789350394219940180217974180983075689645346151558]],
            /* bp */[9635209788867086759474994015521126137037843808855500775255711247474353341942, 10532357498625738653781203652235407445504418461844494535410725185262967725536],
            /* c */ [2979082982449319418800994115689753411721779945253248515532569378637518482124, 3143567336181932302511851756760472718883118738818983203961850684965916083031],
            /* cp */ [11182798853760866712100529614936626355599675889193406642506513786597302995359, 21503918186037221985951496509528138040813374125019591054416463010791565738112],
            /* h */[4633883772453921040686106381946310074681701049370649431093501227658192420448, 21021275022297515067274628176614711148054587207810962211311080345928349346190],
            /* k*/[20481961466655736077506474649847772957810447411263729097818993207697766925974, 18134245132528824771900871678480123127745757902738189746990901944851179135138],
            [6301007345864501926049365915105502481566397466935164158686624182392111092001]
        );
        return result;
    }
 
    function test2() public returns(bool) {
        result = verifyProof(
            /* a */ [16483647994083632042653019342376493617507292244409483767011999030917568268646, 14894910552958451837608824090793975141071530720863443570081513964969682749237],
            /* ap */ [7069277083124752480589269138496991668756747028035402285843178020131615294350, 9769833532751559998465267694651537664145336267300309123767160432711724831666],
            /* b */ [
                [10396820912983820590012141974278057713805439603448882846227355198709322789238, 4215149779965623264519391521256199140559499990271137375702176633421893610383],
                [7168677908279967661582166035120849421362854198112972513633076412090253938046, 7939490528358177281807348800807384862458498738673302498496997520510790421465]
            ],
            /* bp */[7292093587831110061576671664967603794360646367363057619801314532700018122737, 10723124365185779888153587187015081260999880730039480846573969372689234107375],
            /* c */ [20110710583089424502944360852129601455489734470597967975354770536748481794282, 3145757061004047107401063345908323315455945293305604627001670605409827213671],
            /* cp */ [6105559872747339441542380675491167877666447243500071222034839405367679925851, 17725653028994652750960303183103332283186984823200422907924350712276575028588],
            /* h */[10049851113757098751686276929149014031557853631351627054447767136629148270384, 17909597939692457233922845451343003254610968728013606609824460021235534590306],
            /* k*/[5996023988124922181895500924586855924244464998893492209549740999859637471335, 18044112761446177853237991684844833615435851238016207034759388984418696008767],
            [uint(33)]
        );
        return result;
    }
}
PreviousSolidityNextSample Contracts

Last updated 1 month ago