snarkjs/templates/verifier.sol
templates/verifier.solRaw
1//
2// Copyright 2017 Christian Reitwiessner
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6pragma solidity ^0.4.14;
7library Pairing {
8 struct G1Point {
9 uint X;
10 uint Y;
11 }
12 // Encoding of field elements is: X[0] * z + X[1]
13 struct G2Point {
14 uint[2] X;
15 uint[2] Y;
16 }
17 /// @return the generator of G1
18 function P1() pure internal returns (G1Point) {
19 return G1Point(1, 2);
20 }
21 /// @return the generator of G2
22 function P2() pure internal returns (G2Point) {
23 // Original code point
24 return G2Point(
25 [11559732032986387107991004021392285783925812861821192530917403151452391805634,
26 10857046999023057135944570762232829481370756359578518086990519993285655852781],
27 [4082367875863433681332203403145435568316851327593401208105741076214120093531,
28 8495653923123431417604973247489272438418190587263600148770280649306958101930]
29 );
30
31/*
32 // Changed by Jordi point
33 return G2Point(
34 [10857046999023057135944570762232829481370756359578518086990519993285655852781,
35 11559732032986387107991004021392285783925812861821192530917403151452391805634],
36 [8495653923123431417604973247489272438418190587263600148770280649306958101930,
37 4082367875863433681332203403145435568316851327593401208105741076214120093531]
38 );
39*/
40 }
41 /// @return the negation of p, i.e. p.addition(p.negate()) should be zero.
42 function negate(G1Point p) pure internal returns (G1Point) {
43 // The prime q in the base field F_q for G1
44 uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
45 if (p.X == 0 && p.Y == 0)
46 return G1Point(0, 0);
47 return G1Point(p.X, q - (p.Y % q));
48 }
49 /// @return the sum of two points of G1
50 function addition(G1Point p1, G1Point p2) view internal returns (G1Point r) {
51 uint[4] memory input;
52 input[0] = p1.X;
53 input[1] = p1.Y;
54 input[2] = p2.X;
55 input[3] = p2.Y;
56 bool success;
57 assembly {
58 success := staticcall(sub(gas, 2000), 6, input, 0xc0, r, 0x60)
59 // Use "invalid" to make gas estimation work
60 switch success case 0 { invalid() }
61 }
62 require(success);
63 }
64 /// @return the product of a point on G1 and a scalar, i.e.
65 /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
66 function scalar_mul(G1Point p, uint s) view internal returns (G1Point r) {
67 uint[3] memory input;
68 input[0] = p.X;
69 input[1] = p.Y;
70 input[2] = s;
71 bool success;
72 assembly {
73 success := staticcall(sub(gas, 2000), 7, input, 0x80, r, 0x60)
74 // Use "invalid" to make gas estimation work
75 switch success case 0 { invalid() }
76 }
77 require (success);
78 }
79 /// @return the result of computing the pairing check
80 /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
81 /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
82 /// return true.
83 function pairing(G1Point[] p1, G2Point[] p2) view internal returns (bool) {
84 require(p1.length == p2.length);
85 uint elements = p1.length;
86 uint inputSize = elements * 6;
87 uint[] memory input = new uint[](inputSize);
88 for (uint i = 0; i < elements; i++)
89 {
90 input[i * 6 + 0] = p1[i].X;
91 input[i * 6 + 1] = p1[i].Y;
92 input[i * 6 + 2] = p2[i].X[0];
93 input[i * 6 + 3] = p2[i].X[1];
94 input[i * 6 + 4] = p2[i].Y[0];
95 input[i * 6 + 5] = p2[i].Y[1];
96 }
97 uint[1] memory out;
98 bool success;
99 assembly {
100 success := staticcall(sub(gas, 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
101 // Use "invalid" to make gas estimation work
102 switch success case 0 { invalid() }
103 }
104 require(success);
105 return out[0] != 0;
106 }
107 /// Convenience method for a pairing check for two pairs.
108 function pairingProd2(G1Point a1, G2Point a2, G1Point b1, G2Point b2) view internal returns (bool) {
109 G1Point[] memory p1 = new G1Point[](2);
110 G2Point[] memory p2 = new G2Point[](2);
111 p1[0] = a1;
112 p1[1] = b1;
113 p2[0] = a2;
114 p2[1] = b2;
115 return pairing(p1, p2);
116 }
117 /// Convenience method for a pairing check for three pairs.
118 function pairingProd3(
119 G1Point a1, G2Point a2,
120 G1Point b1, G2Point b2,
121 G1Point c1, G2Point c2
122 ) view internal returns (bool) {
123 G1Point[] memory p1 = new G1Point[](3);
124 G2Point[] memory p2 = new G2Point[](3);
125 p1[0] = a1;
126 p1[1] = b1;
127 p1[2] = c1;
128 p2[0] = a2;
129 p2[1] = b2;
130 p2[2] = c2;
131 return pairing(p1, p2);
132 }
133 /// Convenience method for a pairing check for four pairs.
134 function pairingProd4(
135 G1Point a1, G2Point a2,
136 G1Point b1, G2Point b2,
137 G1Point c1, G2Point c2,
138 G1Point d1, G2Point d2
139 ) view internal returns (bool) {
140 G1Point[] memory p1 = new G1Point[](4);
141 G2Point[] memory p2 = new G2Point[](4);
142 p1[0] = a1;
143 p1[1] = b1;
144 p1[2] = c1;
145 p1[3] = d1;
146 p2[0] = a2;
147 p2[1] = b2;
148 p2[2] = c2;
149 p2[3] = d2;
150 return pairing(p1, p2);
151 }
152}
153contract Verifier {
154 using Pairing for *;
155 struct VerifyingKey {
156 Pairing.G2Point A;
157 Pairing.G1Point B;
158 Pairing.G2Point C;
159 Pairing.G2Point gamma;
160 Pairing.G1Point gammaBeta1;
161 Pairing.G2Point gammaBeta2;
162 Pairing.G2Point Z;
163 Pairing.G1Point[] IC;
164 }
165 struct Proof {
166 Pairing.G1Point A;
167 Pairing.G1Point A_p;
168 Pairing.G2Point B;
169 Pairing.G1Point B_p;
170 Pairing.G1Point C;
171 Pairing.G1Point C_p;
172 Pairing.G1Point K;
173 Pairing.G1Point H;
174 }
175 function verifyingKey() pure internal returns (VerifyingKey vk) {
176 vk.A = Pairing.G2Point(<%vk_a%>);
177 vk.B = Pairing.G1Point(<%vk_b%>);
178 vk.C = Pairing.G2Point(<%vk_c%>);
179 vk.gamma = Pairing.G2Point(<%vk_g%>);
180 vk.gammaBeta1 = Pairing.G1Point(<%vk_gb1%>);
181 vk.gammaBeta2 = Pairing.G2Point(<%vk_gb2%>);
182 vk.Z = Pairing.G2Point(<%vk_z%>);
183 vk.IC = new Pairing.G1Point[](<%vk_ic_length%>);
184 <%vk_ic_pts%>
185 }
186 function verify(uint[] input, Proof proof) view internal returns (uint) {
187 VerifyingKey memory vk = verifyingKey();
188 require(input.length + 1 == vk.IC.length);
189 // Compute the linear combination vk_x
190 Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
191 for (uint i = 0; i < input.length; i++)
192 vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
193 vk_x = Pairing.addition(vk_x, vk.IC[0]);
194 if (!Pairing.pairingProd2(proof.A, vk.A, Pairing.negate(proof.A_p), Pairing.P2())) return 1;
195 if (!Pairing.pairingProd2(vk.B, proof.B, Pairing.negate(proof.B_p), Pairing.P2())) return 2;
196 if (!Pairing.pairingProd2(proof.C, vk.C, Pairing.negate(proof.C_p), Pairing.P2())) return 3;
197 if (!Pairing.pairingProd3(
198 proof.K, vk.gamma,
199 Pairing.negate(Pairing.addition(vk_x, Pairing.addition(proof.A, proof.C))), vk.gammaBeta2,
200 Pairing.negate(vk.gammaBeta1), proof.B
201 )) return 4;
202 if (!Pairing.pairingProd3(
203 Pairing.addition(vk_x, proof.A), proof.B,
204 Pairing.negate(proof.H), vk.Z,
205 Pairing.negate(proof.C), Pairing.P2()
206 )) return 5;
207 return 0;
208 }
209 function verifyProof(
210 uint[2] a,
211 uint[2] a_p,
212 uint[2][2] b,
213 uint[2] b_p,
214 uint[2] c,
215 uint[2] c_p,
216 uint[2] h,
217 uint[2] k,
218 uint[<%vk_input_length%>] input
219 ) view public returns (bool r) {
220 Proof memory proof;
221 proof.A = Pairing.G1Point(a[0], a[1]);
222 proof.A_p = Pairing.G1Point(a_p[0], a_p[1]);
223 proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
224 proof.B_p = Pairing.G1Point(b_p[0], b_p[1]);
225 proof.C = Pairing.G1Point(c[0], c[1]);
226 proof.C_p = Pairing.G1Point(c_p[0], c_p[1]);
227 proof.H = Pairing.G1Point(h[0], h[1]);
228 proof.K = Pairing.G1Point(k[0], k[1]);
229 uint[] memory inputValues = new uint[](input.length);
230 for(uint i = 0; i < input.length; i++){
231 inputValues[i] = input[i];
232 }
233 if (verify(inputValues, proof) == 0) {
234 return true;
235 } else {
236 return false;
237 }
238 }
239}
240
241
242
243