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}