miksi-core/contracts/deposit-verifier.sol
contracts/deposit-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.
6//
7// 2019 OKIMS
8// ported to solidity 0.5
9// fixed linter warnings
10// added requiere error messages
11//
12pragma solidity ^0.6.0;
13library DepositPairing {
14 struct G1Point {
15 uint X;
16 uint Y;
17 }
18 // Encoding of field elements is: X[0] * z + X[1]
19 struct G2Point {
20 uint[2] X;
21 uint[2] Y;
22 }
23 /// @return the generator of G1
24 function P1() internal pure returns (G1Point memory) {
25 return G1Point(1, 2);
26 }
27 /// @return the generator of G2
28 function P2() internal pure returns (G2Point memory) {
29 // Original code point
30 return G2Point(
31 [11559732032986387107991004021392285783925812861821192530917403151452391805634,
32 10857046999023057135944570762232829481370756359578518086990519993285655852781],
33 [4082367875863433681332203403145435568316851327593401208105741076214120093531,
34 8495653923123431417604973247489272438418190587263600148770280649306958101930]
35 );
36
37/*
38 // Changed by Jordi point
39 return G2Point(
40 [10857046999023057135944570762232829481370756359578518086990519993285655852781,
41 11559732032986387107991004021392285783925812861821192530917403151452391805634],
42 [8495653923123431417604973247489272438418190587263600148770280649306958101930,
43 4082367875863433681332203403145435568316851327593401208105741076214120093531]
44 );
45*/
46 }
47 /// @return the negation of p, i.e. p.addition(p.negate()) should be zero.
48 function negate(G1Point memory p) internal pure returns (G1Point memory) {
49 // The prime q in the base field F_q for G1
50 uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
51 if (p.X == 0 && p.Y == 0)
52 return G1Point(0, 0);
53 return G1Point(p.X, q - (p.Y % q));
54 }
55 /// @return r the sum of two points of G1
56 function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
57 uint[4] memory input;
58 input[0] = p1.X;
59 input[1] = p1.Y;
60 input[2] = p2.X;
61 input[3] = p2.Y;
62 bool success;
63 // solium-disable-next-line security/no-inline-assembly
64 assembly {
65 success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
66 // Use "invalid" to make gas() estimation work
67 switch success case 0 { invalid() }
68 }
69 require(success,"pairing-add-failed");
70 }
71 /// @return r the product of a point on G1 and a scalar, i.e.
72 /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
73 function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) {
74 uint[3] memory input;
75 input[0] = p.X;
76 input[1] = p.Y;
77 input[2] = s;
78 bool success;
79 // solium-disable-next-line security/no-inline-assembly
80 assembly {
81 success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
82 // Use "invalid" to make gas() estimation work
83 switch success case 0 { invalid() }
84 }
85 require (success,"pairing-mul-failed");
86 }
87 /// @return the result of computing the pairing check
88 /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
89 /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
90 /// return true.
91 function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) {
92 require(p1.length == p2.length,"pairing-lengths-failed");
93 uint elements = p1.length;
94 uint inputSize = elements * 6;
95 uint[] memory input = new uint[](inputSize);
96 for (uint i = 0; i < elements; i++)
97 {
98 input[i * 6 + 0] = p1[i].X;
99 input[i * 6 + 1] = p1[i].Y;
100 input[i * 6 + 2] = p2[i].X[0];
101 input[i * 6 + 3] = p2[i].X[1];
102 input[i * 6 + 4] = p2[i].Y[0];
103 input[i * 6 + 5] = p2[i].Y[1];
104 }
105 uint[1] memory out;
106 bool success;
107 // solium-disable-next-line security/no-inline-assembly
108 assembly {
109 success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
110 // Use "invalid" to make gas() estimation work
111 switch success case 0 { invalid() }
112 }
113 require(success,"pairing-opcode-failed");
114 return out[0] != 0;
115 }
116 /// Convenience method for a pairing check for two pairs.
117 function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) {
118 G1Point[] memory p1 = new G1Point[](2);
119 G2Point[] memory p2 = new G2Point[](2);
120 p1[0] = a1;
121 p1[1] = b1;
122 p2[0] = a2;
123 p2[1] = b2;
124 return pairing(p1, p2);
125 }
126 /// Convenience method for a pairing check for three pairs.
127 function pairingProd3(
128 G1Point memory a1, G2Point memory a2,
129 G1Point memory b1, G2Point memory b2,
130 G1Point memory c1, G2Point memory c2
131 ) internal view returns (bool) {
132 G1Point[] memory p1 = new G1Point[](3);
133 G2Point[] memory p2 = new G2Point[](3);
134 p1[0] = a1;
135 p1[1] = b1;
136 p1[2] = c1;
137 p2[0] = a2;
138 p2[1] = b2;
139 p2[2] = c2;
140 return pairing(p1, p2);
141 }
142 /// Convenience method for a pairing check for four pairs.
143 function pairingProd4(
144 G1Point memory a1, G2Point memory a2,
145 G1Point memory b1, G2Point memory b2,
146 G1Point memory c1, G2Point memory c2,
147 G1Point memory d1, G2Point memory d2
148 ) internal view returns (bool) {
149 G1Point[] memory p1 = new G1Point[](4);
150 G2Point[] memory p2 = new G2Point[](4);
151 p1[0] = a1;
152 p1[1] = b1;
153 p1[2] = c1;
154 p1[3] = d1;
155 p2[0] = a2;
156 p2[1] = b2;
157 p2[2] = c2;
158 p2[3] = d2;
159 return pairing(p1, p2);
160 }
161}
162contract DepositVerifier {
163 using DepositPairing for *;
164 struct VerifyingKey {
165 DepositPairing.G1Point alfa1;
166 DepositPairing.G2Point beta2;
167 DepositPairing.G2Point gamma2;
168 DepositPairing.G2Point delta2;
169 DepositPairing.G1Point[] IC;
170 }
171 struct Proof {
172 DepositPairing.G1Point A;
173 DepositPairing.G2Point B;
174 DepositPairing.G1Point C;
175 }
176 function verifyingKey() internal pure returns (VerifyingKey memory vk) {
177 vk.alfa1 = DepositPairing.G1Point(5430763209380891082112219774590965073812438071785553545512843412766074378589,8483294202769323983386844586172367254189941367220716956010972527412596130486);
178 vk.beta2 = DepositPairing.G2Point([4461224104052879207048084476396712261168351663641098793015529057949505506609,9544040136419068455629331025948917346266663192627992632868522840394806969434], [16229298110477119094923221927578042298710597226211404598826305561649600112085,3174991076926426123044998896038938058491203360109109874700070586926990826975]);
179 vk.gamma2 = DepositPairing.G2Point([1763786592992476076824494282837308182336334498741564210939328007472877590979,16095557635581589565592692999561395560887484535347243882788725384363056509081], [20099281874123119981340699313574751066255843720218059754888786799205480145816,4128178975141199585947537534509943631531896570605638201475406072073346159927]);
180 vk.delta2 = DepositPairing.G2Point([1112445599982071272946700233620225941838681071449287021880935553274281891149,21852125798450609179424969354919823595751481354419855759397333465513526523951], [4650598210775335626309400977090729715816375400747238833715263844489768409735,9506265809207721234821155999410463212069459307612220343268944197887451805661]);
181 vk.IC = new DepositPairing.G1Point[](7);
182 vk.IC[0] = DepositPairing.G1Point(10918150886880635497175603837243938291795608025578156706199987503133910943501,3820501207457478037242281915371943430490491637056890884843289615136736661276);
183 vk.IC[1] = DepositPairing.G1Point(14765455611714785904910505920382976888742011688321426790246638636748913644575,1970327576944768331068346214501841357599829193384396384398512475234228192550);
184 vk.IC[2] = DepositPairing.G1Point(4575326419654501917969297303051407724371861645581023746738038587958659360147,14512901306272734695398492530853628160305148151587715082363147054390984379306);
185 vk.IC[3] = DepositPairing.G1Point(10149717886730624284680109616859329799115550276739239226023596802725094047583,16806116621949942919292056712799700002885850181824427798105720780153968785723);
186 vk.IC[4] = DepositPairing.G1Point(9663169403303410535343713305536179107413370694230955213715276420971109292352,19907010787536566810941780928736434067835793051624423083300240671493191288122);
187 vk.IC[5] = DepositPairing.G1Point(21069023849778352967265174506861061426513291386845863979546966635979962598349,12327162753516489818246989808695117002665024166967891733423875235072870943654);
188 vk.IC[6] = DepositPairing.G1Point(21288113989150604365711743161787017824926800547410591057826128522328249297383,13847158925758944149197960029039819643318140529826181314997576920991438276946);
189
190 }
191 function verify(uint[] memory input, Proof memory proof) internal view returns (uint) {
192 uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
193 VerifyingKey memory vk = verifyingKey();
194 require(input.length + 1 == vk.IC.length,"verifier-bad-input");
195 // Compute the linear combination vk_x
196 DepositPairing.G1Point memory vk_x = DepositPairing.G1Point(0, 0);
197 for (uint i = 0; i < input.length; i++) {
198 require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field");
199 vk_x = DepositPairing.addition(vk_x, DepositPairing.scalar_mul(vk.IC[i + 1], input[i]));
200 }
201 vk_x = DepositPairing.addition(vk_x, vk.IC[0]);
202 if (!DepositPairing.pairingProd4(
203 DepositPairing.negate(proof.A), proof.B,
204 vk.alfa1, vk.beta2,
205 vk_x, vk.gamma2,
206 proof.C, vk.delta2
207 )) return 1;
208 return 0;
209 }
210 function verifyProof(
211 uint[2] memory a,
212 uint[2][2] memory b,
213 uint[2] memory c,
214 uint[6] memory input
215 ) public view returns (bool r) {
216 Proof memory proof;
217 proof.A = DepositPairing.G1Point(a[0], a[1]);
218 proof.B = DepositPairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
219 proof.C = DepositPairing.G1Point(c[0], c[1]);
220 uint[] memory inputValues = new uint[](input.length);
221 for(uint i = 0; i < input.length; i++){
222 inputValues[i] = input[i];
223 }
224 if (verify(inputValues, proof) == 0) {
225 return true;
226 } else {
227 return false;
228 }
229 }
230}