diff --git a/contracts/verifiers/local/verifier_groth.sol b/contracts/Groth16Verifier.sol similarity index 99% rename from contracts/verifiers/local/verifier_groth.sol rename to contracts/Groth16Verifier.sol index 8d71e95..c999974 100644 --- a/contracts/verifiers/local/verifier_groth.sol +++ b/contracts/Groth16Verifier.sol @@ -143,7 +143,7 @@ library Pairing { return pairing(p1, p2); } } -contract Verifier { +contract Groth16Verifier { using Pairing for *; uint256 constant private snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; VerifyingKey private verifyingKey; diff --git a/package.json b/package.json index b52fc11..0ea66dc 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "test": "npm run lint && hardhat test", "fuzz": "hardhat compile && fuzzing/fuzz.sh", "start": "hardhat node --export deployment-localhost.json", - "preprocess": "node verifier/preprocess.mjs", "compile": "hardhat compile", "format": "prettier --write contracts/**/*.sol test/**/*.js", "lint": "solhint contracts/**.sol", diff --git a/test/Proofs.test.js b/test/Proofs.test.js index 0e7f12a..f3472dd 100644 --- a/test/Proofs.test.js +++ b/test/Proofs.test.js @@ -30,9 +30,7 @@ describe("Proofs", function () { await snapshot() await ensureMinimumBlockHeight(256) const Proofs = await ethers.getContractFactory("TestProofs") - const Verifier = await ethers.getContractFactory( - "contracts/verifiers/local/verifier_groth.sol:Verifier" - ) + const Verifier = await ethers.getContractFactory("Groth16Verifier") const verifier = await Verifier.deploy(loadVerificationKey("local")) proofs = await Proofs.deploy( { period, timeout, downtime }, diff --git a/verifier/preprocess.mjs b/verifier/preprocess.mjs deleted file mode 100644 index fd1f6b7..0000000 --- a/verifier/preprocess.mjs +++ /dev/null @@ -1,57 +0,0 @@ -import { readdir, readFile, mkdir, writeFile } from 'node:fs/promises' -import { dirname, join } from 'node:path' -import { fileURLToPath } from 'node:url' - -const __dirname = dirname(fileURLToPath(import.meta.url)) - -const contractFile = 'verifier_groth.sol' -const verificationKeyFile = 'proof_main_verification_key.json' -const templatePath = join(__dirname, 'template', contractFile) -const networksPath = join(__dirname, 'networks') - -const template = await readFile(templatePath, { encoding: 'utf-8' }) - -function G1ToSolidity(point) { - return point[0] + ', ' + point[1] -} - -function G2ToSolidity(point) { - return '[' + point[0][1] + ',' + point[0][0] + ']' + - ', ' + - '[' + point[1][1] + ',' + point[1][0] + ']' -} - -for (const network of await readdir(networksPath)) { - const networkPath = join(networksPath, network) - const verificationKeyPath = join(networkPath, 'verification-key', verificationKeyFile) - const verificationKey = JSON.parse(await readFile(verificationKeyPath)) - - const alpha1 = G1ToSolidity(verificationKey['vk_alpha_1']) - const beta2 = G2ToSolidity(verificationKey['vk_beta_2']) - const gamma2 = G2ToSolidity(verificationKey['vk_gamma_2']) - const delta2 = G2ToSolidity(verificationKey['vk_delta_2']) - const icLength = verificationKey['IC'].length - let icParts = '' - for (let index = 0; index < icLength; index++) { - if (index > 0) { - icParts = icParts + '\n ' - } - let ic = verificationKey['IC'][index] - icParts = icParts + 'verifyingKey.IC.push(Pairing.G1Point(' + G1ToSolidity(ic) + '));' - } - const inputLength = verificationKey['nPublic'] - - const contract = template - .replaceAll('<%vk_alpha1%>', alpha1) - .replaceAll('<%vk_beta2%>', beta2) - .replaceAll('<%vk_gamma2%>', gamma2) - .replaceAll('<%vk_delta2%>', delta2) - .replaceAll('<%vk_ic_length%>', icLength) - .replaceAll('<%vk_ic_pts%>', icParts) - .replaceAll('<%vk_input_length%>', inputLength) - - const preprocessedPath = join(__dirname, '..', 'contracts', 'verifiers', network) - await mkdir(preprocessedPath, { recursive: true }) - const contractPath = join(preprocessedPath, contractFile) - await writeFile(contractPath, contract) -} diff --git a/verifier/template/verifier_groth.sol b/verifier/template/verifier_groth.sol deleted file mode 100644 index 8d71e95..0000000 --- a/verifier/template/verifier_groth.sol +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2017 Christian Reitwiessner -// Copyright 2019 OKIMS -// Copyright 2024 Codex -// 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. -// SPDX-License-Identifier: MIT -pragma solidity 0.8.23; -library Pairing { - // The prime q in the base field F_q for G1 - uint constant private q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - struct G1Point { - uint x; - uint y; - } - // Encoding of field elements is: x[0] * z + x[1] - struct G2Point { - uint[2] x; - uint[2] y; - } - /// The negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory) { - if (p.x == 0 && p.y == 0) - return G1Point(0, 0); - return G1Point(p.x, q - (p.y % q)); - } - /// The sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[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 - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// The product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[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"); - } - /// The result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].x; - input[i * 6 + 1] = p1[i].y; - input[i * 6 + 2] = p2[i].x[0]; - input[i * 6 + 3] = p2[i].x[1]; - input[i * 6 + 4] = p2[i].y[0]; - input[i * 6 + 5] = p2[i].y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - 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; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } -} -contract Verifier { - using Pairing for *; - uint256 constant private snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey private verifyingKey; - struct VerifyingKey { - Pairing.G1Point alpha1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - constructor(VerifyingKey memory key) { - verifyingKey.alpha1 = key.alpha1; - verifyingKey.beta2 = key.beta2; - verifyingKey.gamma2 = key.gamma2; - verifyingKey.delta2 = key.delta2; - for (uint i=0; i