diff --git a/contracts/Verifier.sol b/contracts/Verifier.sol index c395e93..54c7251 100644 --- a/contracts/Verifier.sol +++ b/contracts/Verifier.sol @@ -1,4 +1,8 @@ -// https://tornado.cash +/** + *Submitted for verification at Etherscan.io on 2020-05-12 +*/ + +// https://tornado.cash Verifier.sol generated by trusted setup ceremony. /* * d888888P dP a88888b. dP * 88 88 d8' `88 88 @@ -8,8 +12,26 @@ * dP `88888P' dP dP dP `88888P8 `88888P8 `88888P' 88 Y88888P' `88888P8 `88888P' dP dP * ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo */ - // SPDX-License-Identifier: MIT +// Copyright 2017 Christian Reitwiessner +// 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: +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// 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. + +// 2019 OKIMS + pragma solidity ^0.6.0; library Pairing { @@ -27,7 +49,7 @@ library Pairing { } /* - * @return The negation of p, i.e. p.plus(p.negate()) should be zero + * @return The negation of p, i.e. p.plus(p.negate()) should be zero. */ function negate(G1Point memory p) internal pure returns (G1Point memory) { // The prime q in the base field F_q for G1 @@ -45,10 +67,11 @@ library Pairing { G1Point memory p1, G1Point memory p2 ) internal view returns (G1Point memory r) { - uint256[4] memory input = [ - p1.X, p1.Y, - p2.X, p2.Y - ]; + uint256[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; bool success; // solium-disable-next-line security/no-inline-assembly @@ -63,20 +86,21 @@ library Pairing { /* * @return r the product of a point on G1 and a scalar, i.e. - * p == p.scalarMul(1) and p.plus(p) == p.scalarMul(2) for all + * p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all * points p. */ - function scalarMul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) { - uint256[3] memory input = [p.X, p.Y, s]; + function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) { + uint256[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; bool success; - // solium-disable-next-line security/no-inline-assembly assembly { success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) // Use "invalid" to make gas estimation work switch success case 0 { invalid() } } - require(success, "pairing-mul-failed"); } @@ -95,23 +119,34 @@ library Pairing { G1Point memory d1, G2Point memory d2 ) internal view returns (bool) { - uint256[24] memory input = [ - a1.X, a1.Y, a2.X[0], a2.X[1], a2.Y[0], a2.Y[1], - b1.X, b1.Y, b2.X[0], b2.X[1], b2.Y[0], b2.Y[1], - c1.X, c1.Y, c2.X[0], c2.X[1], c2.Y[0], c2.Y[1], - d1.X, d1.Y, d2.X[0], d2.X[1], d2.Y[0], d2.Y[1] - ]; + G1Point[4] memory p1 = [a1, b1, c1, d1]; + G2Point[4] memory p2 = [a2, b2, c2, d2]; + + uint256 inputSize = 24; + uint256[] memory input = new uint256[](inputSize); + + for (uint256 i = 0; i < 4; i++) { + uint256 j = i * 6; + input[j + 0] = p1[i].X; + input[j + 1] = p1[i].Y; + input[j + 2] = p2[i].X[0]; + input[j + 3] = p2[i].X[1]; + input[j + 4] = p2[i].Y[0]; + input[j + 5] = p2[i].Y[1]; + } + uint256[1] memory out; bool success; // solium-disable-next-line security/no-inline-assembly assembly { - success := staticcall(sub(gas(), 2000), 8, input, mul(24, 0x20), out, 0x20) + success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) // Use "invalid" to make gas estimation work switch success case 0 { invalid() } } require(success, "pairing-opcode-failed"); + return out[0] != 0; } } @@ -129,6 +164,12 @@ contract Verifier { Pairing.G1Point[7] IC; } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { vk.alfa1 = Pairing.G1Point(uint256(20692898189092739278193869274495556617788530808486270118371701516666252877969), uint256(11713062878292653967971378194351968039596396853904572879488166084231740557279)); vk.beta2 = Pairing.G2Point([uint256(12168528810181263706895252315640534818222943348193302139358377162645029937006), uint256(281120578337195720357474965979947690431622127986816839208576358024608803542)], [uint256(16129176515713072042442734839012966563817890688785805090011011570989315559913), uint256(9011703453772030375124466642203641636825223906145908770308724549646909480510)]); @@ -153,31 +194,37 @@ contract Verifier { uint256[6] memory input ) public view returns (bool) { uint256[8] memory p = abi.decode(proof, (uint256[8])); + + // Make sure that each element in the proof is less than the prime q for (uint8 i = 0; i < p.length; i++) { - // Make sure that each element in the proof is less than the prime q require(p[i] < PRIME_Q, "verifier-proof-element-gte-prime-q"); } - Pairing.G1Point memory proofA = Pairing.G1Point(p[0], p[1]); - Pairing.G2Point memory proofB = Pairing.G2Point([p[2], p[3]], [p[4], p[5]]); - Pairing.G1Point memory proofC = Pairing.G1Point(p[6], p[7]); + + Proof memory _proof; + _proof.A = Pairing.G1Point(p[0], p[1]); + _proof.B = Pairing.G2Point([p[2], p[3]], [p[4], p[5]]); + _proof.C = Pairing.G1Point(p[6], p[7]); VerifyingKey memory vk = verifyingKey(); - // Compute the linear combination vkX - Pairing.G1Point memory vkX = vk.IC[0]; + + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + vk_x = Pairing.plus(vk_x, vk.IC[0]); + + // Make sure that every input is less than the snark scalar field for (uint256 i = 0; i < input.length; i++) { - // Make sure that every input is less than the snark scalar field - require(input[i] < SNARK_SCALAR_FIELD, "verifier-input-gte-snark-scalar-field"); - vkX = Pairing.plus(vkX, Pairing.scalarMul(vk.IC[i + 1], input[i])); + require(input[i] < SNARK_SCALAR_FIELD, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.plus(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); } return Pairing.pairing( - Pairing.negate(proofA), - proofB, + Pairing.negate(_proof.A), + _proof.B, vk.alfa1, vk.beta2, - vkX, + vk_x, vk.gamma2, - proofC, + _proof.C, vk.delta2 ); }