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, q)) {
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}