arnaucube
arnaucube/snarkjsPublic Self-hosted repository
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