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