1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 9× 36× 36× 9× 9× | // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Pairing} from '../libraries/Pairing.sol'; contract EpochKeyVerifier { using Pairing for *; uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint256 constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; struct VerifyingKey { Pairing.G1Point alpha1; Pairing.G2Point beta2; Pairing.G2Point gamma2; Pairing.G2Point delta2; Pairing.G1Point[5] IC; } struct Proof { Pairing.G1Point A; Pairing.G2Point B; Pairing.G1Point C; } function verifyingKey() internal pure returns (VerifyingKey memory vk) { vk.alpha1 = Pairing.G1Point(uint256(20491192805390485299153009773594534940189261866228447918068658471970481763042),uint256(9383485363053290200918347156157836566562967994039712273449902621266178545958)); vk.beta2 = Pairing.G2Point([uint256(4252822878758300859123897981450591353533073413197771768651442665752259397132),uint256(6375614351688725206403948262868962793625744043794305715222011528459656738731)], [uint256(21847035105528745403288232691147584728191162732299865338377159692350059136679),uint256(10505242626370262277552901082094356697409835680220590971873171140371331206856)]); vk.gamma2 = Pairing.G2Point([uint256(11559732032986387107991004021392285783925812861821192530917403151452391805634),uint256(10857046999023057135944570762232829481370756359578518086990519993285655852781)], [uint256(4082367875863433681332203403145435568316851327593401208105741076214120093531),uint256(8495653923123431417604973247489272438418190587263600148770280649306958101930)]); vk.delta2 = Pairing.G2Point([uint256(11036023721833031883801916060749707180101304665787390297398717480277083678006),uint256(20506102537583736416568857232289854317556218504380913501502763248385215747067)], [uint256(6156412093816815912833988033023150814431863202290594877245948571295050214599),uint256(18893612679612141614504311099664890530988795938785182703959443431419716952507)]); vk.IC[0] = Pairing.G1Point(uint256(16522125026527724919850051555969934864914814611340882929908352457479470395518),uint256(14690631327637151030584715440113230769041552512948382493818222640309801220082)); vk.IC[1] = Pairing.G1Point(uint256(17791406475323274372513343599001936829663518044403242365828710188138017404248),uint256(15839080694591915610720854918333956781668751663865236678150950857179669743240)); vk.IC[2] = Pairing.G1Point(uint256(12293172391700986620149768181207456277246872613593431952077556483634463794137),uint256(12363006643442751151150755271897992154783504596533163697502138102935558525128)); vk.IC[3] = Pairing.G1Point(uint256(6586518317677683877201826812683238597486479859203331772217420468071710576347),uint256(1960768800449453794738045084073352993039445323214182377659820091522369702096)); vk.IC[4] = Pairing.G1Point(uint256(17804927503147317173963524521044869814580471862330624211521519126502198200823),uint256(4232532485018976259506863838410417675162084652550587586611902946731393605158)); } /* * @returns Whether the proof is valid given the hardcoded verifying key * above and the public inputs */ function verifyProof( uint256[] calldata input, uint256[8] calldata _proof ) public view returns (bool) { Proof memory proof; proof.A = Pairing.G1Point(_proof[0], _proof[1]); proof.B = Pairing.G2Point([_proof[2], _proof[3]], [_proof[4], _proof[5]]); proof.C = Pairing.G1Point(_proof[6], _proof[7]); VerifyingKey memory vk = verifyingKey(); // Compute the linear combination vk_x Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); // Make sure that proof.A, B, and C are each less than the prime q Erequire(proof.A.X < PRIME_Q, "verifier-aX-gte-prime-q"); Erequire(proof.A.Y < PRIME_Q, "verifier-aY-gte-prime-q"); Erequire(proof.B.X[0] < PRIME_Q, "verifier-bX0-gte-prime-q"); Erequire(proof.B.Y[0] < PRIME_Q, "verifier-bY0-gte-prime-q"); Erequire(proof.B.X[1] < PRIME_Q, "verifier-bX1-gte-prime-q"); Erequire(proof.B.Y[1] < PRIME_Q, "verifier-bY1-gte-prime-q"); Erequire(proof.C.X < PRIME_Q, "verifier-cX-gte-prime-q"); Erequire(proof.C.Y < PRIME_Q, "verifier-cY-gte-prime-q"); // Make sure that every input is less than the snark scalar field //for (uint256 i = 0; i < input.length; i++) { for (uint256 i = 0; i < 4; i++) { Erequire(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])); } vk_x = Pairing.plus(vk_x, vk.IC[0]); return Pairing.pairing( Pairing.negate(proof.A), proof.B, vk.alpha1, vk.beta2, vk_x, vk.gamma2, proof.C, vk.delta2 ); } } |