arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/solidity-verifiers/templates/groth16_verifier.askama.sol
solidity-verifiers/templates/groth16_verifier.askama.solRaw
  1/*
  2    Copyright 2021 0KIMS association.
  3
  4    * `solidity-verifiers` added comment
  5        This file is a template built out of [snarkJS](https://github.com/iden3/snarkjs) groth16 verifier.
  6        See the original ejs template [here](https://github.com/iden3/snarkjs/blob/master/templates/verifier_groth16.sol.ejs)
  7    *
  8
  9    snarkJS is a free software: you can redistribute it and/or modify it
 10    under the terms of the GNU General Public License as published by
 11    the Free Software Foundation, either version 3 of the License, or
 12    (at your option) any later version.
 13
 14    snarkJS is distributed in the hope that it will be useful, but WITHOUT
 15    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 16    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
 17    License for more details.
 18
 19    You should have received a copy of the GNU General Public License
 20    along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
 21*/
 22
 23contract Groth16Verifier {
 24    // Scalar field size
 25    uint256 constant r    = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
 26    // Base field size
 27    uint256 constant q   = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
 28
 29    // Verification Key data
 30    uint256 constant alphax  = {{ vkey_alpha_g1.0[0]    }};
 31    uint256 constant alphay  = {{ vkey_alpha_g1.0[1]    }};
 32    uint256 constant betax1  = {{ vkey_beta_g2.0[0][1]  }};
 33    uint256 constant betax2  = {{ vkey_beta_g2.0[0][0]  }};
 34    uint256 constant betay1  = {{ vkey_beta_g2.0[1][1]  }};
 35    uint256 constant betay2  = {{ vkey_beta_g2.0[1][0]  }};
 36    uint256 constant gammax1 = {{ vkey_gamma_g2.0[0][1] }};
 37    uint256 constant gammax2 = {{ vkey_gamma_g2.0[0][0] }};
 38    uint256 constant gammay1 = {{ vkey_gamma_g2.0[1][1] }};
 39    uint256 constant gammay2 = {{ vkey_gamma_g2.0[1][0] }};
 40    uint256 constant deltax1 = {{ vkey_delta_g2.0[0][1] }};
 41    uint256 constant deltax2 = {{ vkey_delta_g2.0[0][0] }};
 42    uint256 constant deltay1 = {{ vkey_delta_g2.0[1][1] }};
 43    uint256 constant deltay2 = {{ vkey_delta_g2.0[1][0] }};
 44
 45    {% for (i, point) in gamma_abc_g1.iter().enumerate() %}
 46    uint256 constant IC{{i}}x = {{ point.0[0] }};
 47    uint256 constant IC{{i}}y = {{ point.0[1] }};
 48    {% endfor %}
 49    
 50    // Memory data
 51    uint16 constant pVk = 0;
 52    uint16 constant pPairing = 128;
 53
 54    uint16 constant pLastMem = 896;
 55
 56    function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[{{ gamma_abc_len - 1 }}] calldata _pubSignals) public view returns (bool) {
 57        assembly {
 58            function checkField(v) {
 59                if iszero(lt(v, r)) {
 60                    mstore(0, 0)
 61                    return(0, 0x20)
 62                }
 63            }
 64            
 65            // G1 function to multiply a G1 value(x,y) to value in an address
 66            function g1_mulAccC(pR, x, y, s) {
 67                let success
 68                let mIn := mload(0x40)
 69                mstore(mIn, x)
 70                mstore(add(mIn, 32), y)
 71                mstore(add(mIn, 64), s)
 72
 73                success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
 74
 75                if iszero(success) {
 76                    mstore(0, 0)
 77                    return(0, 0x20)
 78                }
 79
 80                mstore(add(mIn, 64), mload(pR))
 81                mstore(add(mIn, 96), mload(add(pR, 32)))
 82
 83                success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
 84
 85                if iszero(success) {
 86                    mstore(0, 0)
 87                    return(0, 0x20)
 88                }
 89            }
 90
 91            function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
 92                let _pPairing := add(pMem, pPairing)
 93                let _pVk := add(pMem, pVk)
 94
 95                mstore(_pVk, IC0x)
 96                mstore(add(_pVk, 32), IC0y)
 97
 98                // Compute the linear combination vk_x
 99                {% for (i, _) in gamma_abc_g1.iter().enumerate() %}
100                {% if loop.first -%}
101                {%- else -%}
102                g1_mulAccC(_pVk, IC{{i}}x, IC{{i}}y, calldataload(add(pubSignals, {{(i-1)*32}})))
103                {%- endif -%}
104                {% endfor %}
105
106                // -A
107                mstore(_pPairing, calldataload(pA))
108                mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))
109
110                // B
111                mstore(add(_pPairing, 64), calldataload(pB))
112                mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
113                mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
114                mstore(add(_pPairing, 160), calldataload(add(pB, 96)))
115
116                // alpha1
117                mstore(add(_pPairing, 192), alphax)
118                mstore(add(_pPairing, 224), alphay)
119
120                // beta2
121                mstore(add(_pPairing, 256), betax1)
122                mstore(add(_pPairing, 288), betax2)
123                mstore(add(_pPairing, 320), betay1)
124                mstore(add(_pPairing, 352), betay2)
125
126                // vk_x
127                mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
128                mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))
129
130
131                // gamma2
132                mstore(add(_pPairing, 448), gammax1)
133                mstore(add(_pPairing, 480), gammax2)
134                mstore(add(_pPairing, 512), gammay1)
135                mstore(add(_pPairing, 544), gammay2)
136
137                // C
138                mstore(add(_pPairing, 576), calldataload(pC))
139                mstore(add(_pPairing, 608), calldataload(add(pC, 32)))
140
141                // delta2
142                mstore(add(_pPairing, 640), deltax1)
143                mstore(add(_pPairing, 672), deltax2)
144                mstore(add(_pPairing, 704), deltay1)
145                mstore(add(_pPairing, 736), deltay2)
146
147
148                let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)
149
150                isOk := and(success, mload(_pPairing))
151            }
152
153            let pMem := mload(0x40)
154            mstore(0x40, add(pMem, pLastMem))
155
156            // Validate that all evaluations ∈ F
157            {% for (i, _) in gamma_abc_g1.iter().enumerate() %}
158            checkField(calldataload(add(_pubSignals, {{i*32}})))
159            {% endfor %}
160
161            // Validate all evaluations
162            let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
163
164            mstore(0, isValid)
165            
166            return(0, 0x20)
167        }
168    }
169}