diff --git a/contracts/contracts/snarkVerifiers/BatchUpdateStateTreeVerifier32Batch16.sol b/contracts/contracts/snarkVerifiers/BatchUpdateStateTreeVerifier32Batch16.sol new file mode 100644 index 000000000..7450710a4 --- /dev/null +++ b/contracts/contracts/snarkVerifiers/BatchUpdateStateTreeVerifier32Batch16.sol @@ -0,0 +1,270 @@ +// 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.12; + +library Pairing { + + uint256 constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + struct G1Point { + uint256 X; + uint256 Y; + } + + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint256[2] X; + uint256[2] Y; + } + + /* + * @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 + if (p.X == 0 && p.Y == 0) { + return G1Point(0, 0); + } else { + return G1Point(p.X, PRIME_Q - (p.Y % PRIME_Q)); + } + } + + /* + * @return The sum of two points of G1 + */ + function plus( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + + 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 + 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"); + } + + /* + * @return The product of a point on G1 and a scalar, i.e. + * p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all + * points p. + */ + 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"); + } + + /* @return 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 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[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, 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; + } +} + +contract BatchUpdateStateTreeVerifier32Batch16 { + + 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[41] 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(17564466972987208178905070198019717960990774560424996549632340406571921270135),uint256(6212564911154525198736769572109918484573926992228075175561121911305420747892)); + vk.beta2 = Pairing.G2Point([uint256(19862806046850266517918019458699375042492414007810580051130360096409146797114),uint256(18968182867766566527308258731979440721408347503223170931357675093063900018998)], [uint256(15869963506744343382954688098759615756353669448820636651988694593208220260541),uint256(17415631041899920918759548249552784090262638044632769170520738845364398275366)]); + vk.gamma2 = Pairing.G2Point([uint256(11257253160245273080869306676658832074325489738113181602057846648381137371076),uint256(397473356291690562654977459050659929392435262209846402221339197403868900174)], [uint256(15964627439216663086041856051177544908720747472786343019771626700991693030486),uint256(6022076246583820501204467975945998225634462297953032723555607903078152261782)]); + vk.delta2 = Pairing.G2Point([uint256(8960304480954470322423292821010723559000712087743155784344677845709031842356),uint256(4733214216315583653992596764777849980658452927149554703439675897776902590030)], [uint256(5883145061333084001583838147325844327393273269643138829803996465957380959561),uint256(6556416943678009124760019244975816690522642072024061675141905579498114037881)]); + vk.IC[0] = Pairing.G1Point(uint256(20573688474783321846811030145444435978946625455817040976400110171429717762313),uint256(14219795410675122323711179893760742300342532333476317858787056167262160908937)); + vk.IC[1] = Pairing.G1Point(uint256(16042051692957428703650515029444172293895511179110788253133560310150814316357),uint256(17413331071024005080031335036071091790041478145914042688818908877361537279793)); + vk.IC[2] = Pairing.G1Point(uint256(4469309738798192251990686173604159186219995479238540395764540658446930749145),uint256(11574488575927551819587207552625323277821402181373682396813667332531657122576)); + vk.IC[3] = Pairing.G1Point(uint256(13663215469207902744973802514353956563905823199937005483772920223690579405487),uint256(14871215385058895610722549990927147904343728800816746147041918066710584226713)); + vk.IC[4] = Pairing.G1Point(uint256(3489292745098913386172335587317749246980343597777688754173176571645664598569),uint256(16900666770697929965250780969454193347188841711403509395696012994572983674828)); + vk.IC[5] = Pairing.G1Point(uint256(2945290910588501179672392707111211440991551718469541150674976815500282424963),uint256(14598879565524130705374188049646292346600280808118113951050422637050501514200)); + vk.IC[6] = Pairing.G1Point(uint256(1743907228984471502641556290643648078257956018892523942117108222472161514139),uint256(13546457107687734244831126558572113644917121420356142865411127965095244393366)); + vk.IC[7] = Pairing.G1Point(uint256(16239926623460462478853653011219290924924349984217262572113572728526722183948),uint256(6389572798636712055906110008459033979858910590912048163453532204275624832591)); + vk.IC[8] = Pairing.G1Point(uint256(4530655587139374397780646343900207609123290875354646335164468398273552121272),uint256(14128028354444670871720348761393076419788117867224991521747385291768930733900)); + vk.IC[9] = Pairing.G1Point(uint256(2084130186412291868004808742213302933245412886080440295285131766970403857381),uint256(13804644315777078738867680048258647864123013819623348345307968440653417669189)); + vk.IC[10] = Pairing.G1Point(uint256(18709486436861021941485824601602744556543964540298118932107637038300041246452),uint256(6227388549172304522473912467840752177496736905518667301640567961284075418436)); + vk.IC[11] = Pairing.G1Point(uint256(19122006749333320301608897562376816558619150023714623953742504350126075003788),uint256(1363782165044296870545293244929009318232323707960615856401281654383175898692)); + vk.IC[12] = Pairing.G1Point(uint256(5364413641687847338151532060627376981772485264434472923538886778626702553325),uint256(15629906454889243991306438607174696870420819153196924767318221349043732920137)); + vk.IC[13] = Pairing.G1Point(uint256(359121925809342098662374393566383044710271325511783297443508988005252057893),uint256(10811152193314929697376755563378270957694626213124806939092423550685049711334)); + vk.IC[14] = Pairing.G1Point(uint256(17981051144466785906880479913215952997275376146299543204378412051670626574122),uint256(9186797238560565226322431760068041435141486516483393586811312602762508934600)); + vk.IC[15] = Pairing.G1Point(uint256(6365374263154884818000869700803640946567044106549610402459455159852388744718),uint256(11797546156554134645751011447880999714231910885220716843380510034965755651040)); + vk.IC[16] = Pairing.G1Point(uint256(10032451025857463031715146956483534885580387223837889532345041361533387806339),uint256(3387493870558732227389076524589538808644245211636504330892809177455235677785)); + vk.IC[17] = Pairing.G1Point(uint256(2410612158467426620067995137390208949985066150538147153449069937898731808572),uint256(18521287304374984854388998234185412497698792859563570797864631992955274102818)); + vk.IC[18] = Pairing.G1Point(uint256(1813841176463493988104135613769097659002362073379920872551589566744485729425),uint256(6358940015006101246169889831008910886341927609866160536081376191976735620689)); + vk.IC[19] = Pairing.G1Point(uint256(19847081327301917802071509303149389020431564544248328496360668988278832485136),uint256(5211553418968503163058788485400452950515983724722138311061753467468280712633)); + vk.IC[20] = Pairing.G1Point(uint256(3426067802106052552538239688068111098552336356878690064196584551340276343362),uint256(16164134703700162701548772292563817322744059513730556911486018167068452826168)); + vk.IC[21] = Pairing.G1Point(uint256(8668312818069908501493412489204108759565349640063306306478085197244829974013),uint256(13810982784687518301385299461854703917878448472895644674481777667257255651320)); + vk.IC[22] = Pairing.G1Point(uint256(981077468077602291838374553840063429865380290334026656328300299263444718358),uint256(9119368190311983873098621061906337470424090352798797307268722991397740756160)); + vk.IC[23] = Pairing.G1Point(uint256(12527168323265871598354886691498363541846438222537709625367385945449773211746),uint256(2917118573022600221023372381853434922615408196327449576428539574935065403243)); + vk.IC[24] = Pairing.G1Point(uint256(10930278986094694298133371790221234279985134460531943692403668317610232742941),uint256(5862695788973409172672967320590899199162083486531717036727412479032235988065)); + vk.IC[25] = Pairing.G1Point(uint256(19143840440293111384177720404724681785293925298123626495518125552351038037165),uint256(7856520125014358900158196027676468930009418746941329024543565879388665656381)); + vk.IC[26] = Pairing.G1Point(uint256(6775239578044551661567862976069748513078619995670391427056172891956633265071),uint256(9284560981899345091778250628921565052467457991819815198504467006412459015751)); + vk.IC[27] = Pairing.G1Point(uint256(5437988353950279901669028370215493448328043979559724253975191086761262229143),uint256(8176067762582906031719418628593932629618591280530549530843556225763407224284)); + vk.IC[28] = Pairing.G1Point(uint256(14419631426965159557658781212186643724248390035688706768554749807493869120240),uint256(20829049296989859000251091454357109695901711580992440150395839575453171214015)); + vk.IC[29] = Pairing.G1Point(uint256(19608141634472932940433918240261639952962553934341785939122543569039402409141),uint256(13202356373118919099990439264234752617330284072473003408798579312466654945225)); + vk.IC[30] = Pairing.G1Point(uint256(6721446556587383910935961059312054388432394977522853801119708229959202737436),uint256(18874416278004109801516351556023467746164986339155152231450545308976800785800)); + vk.IC[31] = Pairing.G1Point(uint256(1121297910398623972014321595193328729838277331998467353747864490201136608978),uint256(5479532420089283113354607976800616803141032716983446523858749471234109786252)); + vk.IC[32] = Pairing.G1Point(uint256(467086760777282035652878041333579903278580939332416688170241256808993547575),uint256(13756152367683309448429375410787943224591772034678008033485038211776826923105)); + vk.IC[33] = Pairing.G1Point(uint256(544588907891071733780736623354853251736286846455666159919529736335009172121),uint256(19814174389629121597516552220557392671724772880943104553900974211505364673700)); + vk.IC[34] = Pairing.G1Point(uint256(9718043170262637281912309305033913756397788551277481886761502969350964449209),uint256(9928286376606476192337438359582609228172024954515187888460390683064495863566)); + vk.IC[35] = Pairing.G1Point(uint256(8833241059924366760602716054754193491983227264165402284693696886993482375792),uint256(20217437076969561492960066126914621838511190476542843609181381577334240082262)); + vk.IC[36] = Pairing.G1Point(uint256(21691301249544308137330827386088690246733997944828733953042133363071032775561),uint256(8416731669909969552797133391600423980357220150298256151928192993549593014572)); + vk.IC[37] = Pairing.G1Point(uint256(18591239855619987960480421772799014085639022706413599497355173036346631326229),uint256(19557170727169515145077122571593152129100237734331890620470088472162864118761)); + vk.IC[38] = Pairing.G1Point(uint256(3862906872967117807500943404548237031139970973065025611287515004824373974308),uint256(14763824391416574387650349848092354763656539119581187921054485482268328744531)); + vk.IC[39] = Pairing.G1Point(uint256(4581382328791187996308811405974001991040756459205750759173122039179987836596),uint256(14577738635095065315453864617647694757772478953718921634232796382928686688380)); + vk.IC[40] = Pairing.G1Point(uint256(17187231740479352852864198251137151477227537702159385928600612471898233918627),uint256(835160958364646681144544132626099284400020971025799680904837349622297335830)); + + } + + /* + * @returns Whether the proof is valid given the hardcoded verifying key + * above and the public inputs + */ + function verifyProof( + uint256[2] memory a, + uint256[2][2] memory b, + uint256[2] memory c, + uint256[] memory input + ) public view returns (bool) { + + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + + 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 + require(proof.A.X < PRIME_Q, "verifier-aX-gte-prime-q"); + require(proof.A.Y < PRIME_Q, "verifier-aY-gte-prime-q"); + + require(proof.B.X[0] < PRIME_Q, "verifier-bX0-gte-prime-q"); + require(proof.B.Y[0] < PRIME_Q, "verifier-bY0-gte-prime-q"); + + require(proof.B.X[1] < PRIME_Q, "verifier-bX1-gte-prime-q"); + require(proof.B.Y[1] < PRIME_Q, "verifier-bY1-gte-prime-q"); + + require(proof.C.X < PRIME_Q, "verifier-cX-gte-prime-q"); + require(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 < 40; 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])); + } + + 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 + ); + } +} diff --git a/contracts/contracts/snarkVerifiers/QuadVoteTallyVerifier32Batch16.sol b/contracts/contracts/snarkVerifiers/QuadVoteTallyVerifier32Batch16.sol new file mode 100644 index 000000000..4c0cb2f1f --- /dev/null +++ b/contracts/contracts/snarkVerifiers/QuadVoteTallyVerifier32Batch16.sol @@ -0,0 +1,240 @@ +// 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.12; + +library Pairing { + + uint256 constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + struct G1Point { + uint256 X; + uint256 Y; + } + + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint256[2] X; + uint256[2] Y; + } + + /* + * @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 + if (p.X == 0 && p.Y == 0) { + return G1Point(0, 0); + } else { + return G1Point(p.X, PRIME_Q - (p.Y % PRIME_Q)); + } + } + + /* + * @return The sum of two points of G1 + */ + function plus( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + + 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 + 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"); + } + + /* + * @return The product of a point on G1 and a scalar, i.e. + * p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all + * points p. + */ + 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"); + } + + /* @return 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 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[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, 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; + } +} + +contract QuadVoteTallyVerifier32Batch16 { + + 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[11] 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(3931802286032916768722587566330261370902955393767942929056531203487688137529),uint256(10293105233586296031473050653492052327805448683376110761534611791713915549265)); + vk.beta2 = Pairing.G2Point([uint256(21113959492300078886023582393043413128535975125428858805958839308822991748856),uint256(12222282698476210310273536080661281164688722800089362655366747391082242682958)], [uint256(20739573447354048976161197946493569928714465565589532971602923073536082697608),uint256(12941541312444627642958656716514029404685754754869818026526533196090365546374)]); + vk.gamma2 = Pairing.G2Point([uint256(14670836137271604202540255380769830849745744579684969689183516705496317922507),uint256(12178657156513808651243577987886528335149661869282225179912079606061386989744)], [uint256(1125902728883689137508324551765647737011904363437526425591650949891310723812),uint256(15919834918458423371681379777897287057084498811382451098590568497815773165692)]); + vk.delta2 = Pairing.G2Point([uint256(2231852960373618563799433391860999041123211180191070579878255252716013298732),uint256(14291274065364399133654336098495355501982202302398283580502954673818060696633)], [uint256(3168628806727684542778047539988455291220201924183716864807010176642260685841),uint256(12606002808572759608577415926932586006638023328815450374325080704700677189688)]); + vk.IC[0] = Pairing.G1Point(uint256(12848020380718535565089853534681145843006092696634142199856299025847321502371),uint256(6468756580219346512614969481554956146762400832923090074339557565951026058536)); + vk.IC[1] = Pairing.G1Point(uint256(789092430114940371944840041796419370450123967868354406244601329700742570445),uint256(11703230415288173665088837798624967250284180660322246777462631600764972864812)); + vk.IC[2] = Pairing.G1Point(uint256(16252197430844492890521435281772316410665185290137018091020232186750112907512),uint256(20861485175504002710376158881527553699531789728793309486150649246737774028347)); + vk.IC[3] = Pairing.G1Point(uint256(16969171625806775801891191965047460974818115969312194891897374689668597542196),uint256(14389419046525510722177847778450425484834864589330386321604392542455541983572)); + vk.IC[4] = Pairing.G1Point(uint256(13928883789499754049998767198742842124977905594692254232979837689918838899511),uint256(6757216204221511030872544186493375503384465407204524181513380457112801460878)); + vk.IC[5] = Pairing.G1Point(uint256(12615105472464956174046705416720445236758313003314061110048664932376957788951),uint256(1115476865907623432334995719744390855110066393577587591466560011685797098103)); + vk.IC[6] = Pairing.G1Point(uint256(12126180897004602060892141406139130628195608764592739755066384985876875328223),uint256(837414672224275155302376389224725114262382901229023048656048324984574980028)); + vk.IC[7] = Pairing.G1Point(uint256(721442001352764820041409242091349606527760014067614573870735409795650532250),uint256(5871690341119940542207233131936464616602051666920986699510353544932455895913)); + vk.IC[8] = Pairing.G1Point(uint256(11936590707137322489603100954274435093115715779097755089203405884503252799861),uint256(5832382048375298946996376174464817616061448358844675910441699738844607159400)); + vk.IC[9] = Pairing.G1Point(uint256(1150487096467611973629613424410317323826245588905051816727229632029031650443),uint256(19621934380117246037511579161242972091034040331100068879508644849318614270487)); + vk.IC[10] = Pairing.G1Point(uint256(14447725242028063610944438927433683612461991907837633029384208510392253681728),uint256(15642702797143402072429225245488363130997179355079100914641555016655302069615)); + + } + + /* + * @returns Whether the proof is valid given the hardcoded verifying key + * above and the public inputs + */ + function verifyProof( + uint256[2] memory a, + uint256[2][2] memory b, + uint256[2] memory c, + uint256[] memory input + ) public view returns (bool) { + + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + + 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 + require(proof.A.X < PRIME_Q, "verifier-aX-gte-prime-q"); + require(proof.A.Y < PRIME_Q, "verifier-aY-gte-prime-q"); + + require(proof.B.X[0] < PRIME_Q, "verifier-bX0-gte-prime-q"); + require(proof.B.Y[0] < PRIME_Q, "verifier-bY0-gte-prime-q"); + + require(proof.B.X[1] < PRIME_Q, "verifier-bX1-gte-prime-q"); + require(proof.B.Y[1] < PRIME_Q, "verifier-bY1-gte-prime-q"); + + require(proof.C.X < PRIME_Q, "verifier-cX-gte-prime-q"); + require(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 < 10; 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])); + } + + 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 + ); + } +} diff --git a/contracts/e2e/index.ts b/contracts/e2e/index.ts index 536abde35..eb65d5c0e 100644 --- a/contracts/e2e/index.ts +++ b/contracts/e2e/index.ts @@ -68,13 +68,14 @@ describe('End-to-end Tests', function () { const poseidonT6 = await deployContract(deployer, ':PoseidonT6') const batchUstVerifier = await deployContract( deployer, - 'BatchUpdateStateTreeVerifier32' + 'BatchUpdateStateTreeVerifier32Batch16' ) const qvtVerifier = await deployContract( deployer, - 'QuadVoteTallyVerifier32' + 'QuadVoteTallyVerifier32Batch16' ) - const maciFactory = await deployMaciFactory(deployer, 'x32', { + const circuit = 'prod' + const maciFactory = await deployMaciFactory(deployer, circuit, { poseidonT3, poseidonT6, batchUstVerifier, diff --git a/contracts/scripts/deploy.ts b/contracts/scripts/deploy.ts index cdd23ee92..c86f68acc 100644 --- a/contracts/scripts/deploy.ts +++ b/contracts/scripts/deploy.ts @@ -7,8 +7,8 @@ import { deployMaciFactory } from '../utils/deployment' async function main() { const [deployer] = await ethers.getSigners() console.log(`Deploying from address: ${deployer.address}`) - - const maciFactory = await deployMaciFactory(deployer) + const circuit = 'prod' + const maciFactory = await deployMaciFactory(deployer, circuit) await maciFactory.deployTransaction.wait() console.log(`MACIFactory deployed: ${maciFactory.address}`) diff --git a/contracts/scripts/deployRound.ts b/contracts/scripts/deployRound.ts index 91e71e8a5..ad7589752 100644 --- a/contracts/scripts/deployRound.ts +++ b/contracts/scripts/deployRound.ts @@ -12,8 +12,8 @@ async function main() { console.log('*******************') const [deployer] = await ethers.getSigners() console.log('deployer.address: ', deployer.address) - - let maciFactory = await deployMaciFactory(deployer) + const circuit = 'prod' + let maciFactory = await deployMaciFactory(deployer, circuit) await maciFactory.deployTransaction.wait() console.log('maciFactory.address: ', maciFactory.address) diff --git a/contracts/tests/deployer.ts b/contracts/tests/deployer.ts index 219b31011..4e6ceffa6 100644 --- a/contracts/tests/deployer.ts +++ b/contracts/tests/deployer.ts @@ -27,7 +27,8 @@ describe('Clr fund deployer', () => { const coordinatorPubKey = new Keypair().pubKey.asContractParam() beforeEach(async () => { - maciFactory = await deployMaciFactory(deployer) + const circuit = 'prod' + maciFactory = await deployMaciFactory(deployer, circuit) maciParameters = await MaciParameters.read(maciFactory) factoryTemplate = await deployContract(deployer, 'ClrFund') diff --git a/contracts/tests/factory.ts b/contracts/tests/factory.ts index 63c6c658f..527aaf0b0 100644 --- a/contracts/tests/factory.ts +++ b/contracts/tests/factory.ts @@ -25,7 +25,8 @@ describe('Funding Round Factory', () => { const coordinatorPubKey = new Keypair().pubKey.asContractParam() beforeEach(async () => { - maciFactory = await deployMaciFactory(deployer) + const circuit = 'prod' + maciFactory = await deployMaciFactory(deployer, circuit) maciParameters = await MaciParameters.read(maciFactory) factory = await deployContract(deployer, 'FundingRoundFactory', [ diff --git a/contracts/tests/maciFactory.ts b/contracts/tests/maciFactory.ts index d9b32d610..8c7bd0772 100644 --- a/contracts/tests/maciFactory.ts +++ b/contracts/tests/maciFactory.ts @@ -22,7 +22,8 @@ describe('MACI factory', () => { const coordinatorPubKey = new Keypair().pubKey.asContractParam() beforeEach(async () => { - maciFactory = await deployMaciFactory(deployer) + const circuit = 'prod' + maciFactory = await deployMaciFactory(deployer, circuit) expect(await getGasUsage(maciFactory.deployTransaction)).lessThan(5600000) maciParameters = await MaciParameters.read(maciFactory) diff --git a/contracts/tests/round.ts b/contracts/tests/round.ts index 0915e47f5..ce40e1423 100644 --- a/contracts/tests/round.ts +++ b/contracts/tests/round.ts @@ -79,7 +79,8 @@ describe('Funding Round', () => { recipientRegistry.address, coordinator.address ) - const maciFactory = await deployMaciFactory(deployer) + const circuit = 'prod' + const maciFactory = await deployMaciFactory(deployer, circuit) const maciDeployed = await maciFactory.deployMaci( fundingRound.address, fundingRound.address, diff --git a/contracts/utils/deployment.ts b/contracts/utils/deployment.ts index 21f6cdc8b..adb9d5152 100644 --- a/contracts/utils/deployment.ts +++ b/contracts/utils/deployment.ts @@ -3,7 +3,7 @@ import { Libraries } from 'hardhat/types/runtime' import { Signer, Contract } from 'ethers' import { link } from 'ethereum-waffle' -import { MaciParameters } from './maci' +import { MaciParameters, ProdMaciParameters } from './maci' export function linkBytecode( bytecode: string, @@ -54,6 +54,35 @@ const CIRCUITS: { [name: string]: any } = { voteOptionTreeDepth: 3, }, }, + prod: { + batchUstVerifier: 'BatchUpdateStateTreeVerifier32Batch16', + qvtVerifier: 'QuadVoteTallyVerifier32Batch16', + treeDepths: { + stateTreeDepth: 32, + messageTreeDepth: 32, + voteOptionTreeDepth: 3, + }, + }, +} +const PARAMS = ( + circuit: string, + batchUstVerifier: string, + qvtVerifier: string +) => { + switch (circuit) { + case 'prod': + return new ProdMaciParameters({ + batchUstVerifier, + qvtVerifier, + ...CIRCUITS[circuit].treeDepths, + }) + default: + return new MaciParameters({ + batchUstVerifier, + qvtVerifier, + ...CIRCUITS[circuit].treeDepths, + }) + } } export async function deployContract( @@ -83,6 +112,7 @@ export async function deployMaciFactory( qvtVerifier, }: MaciFactoryDependencies = {} ): Promise { + let maciParameters: MaciParameters | ProdMaciParameters if (!poseidonT3) { const PoseidonT3 = await ethers.getContractFactory(':PoseidonT3', account) poseidonT3 = await PoseidonT3.deploy() @@ -115,11 +145,12 @@ export async function deployMaciFactory( signer: account, libraries: maciLibraries, }) - const maciParameters = new MaciParameters({ - batchUstVerifier: batchUstVerifier.address, - qvtVerifier: qvtVerifier.address, - ...CIRCUITS[circuit].treeDepths, - }) + + maciParameters = PARAMS( + circuit, + batchUstVerifier.address, + qvtVerifier.address + ) const maciFactory = await MACIFactory.deploy(...maciParameters.values()) await maciFactory.deployTransaction.wait() diff --git a/contracts/utils/maci.ts b/contracts/utils/maci.ts index 475f3a8ff..23863e4d8 100644 --- a/contracts/utils/maci.ts +++ b/contracts/utils/maci.ts @@ -60,6 +60,64 @@ export class MaciParameters { } } +export class ProdMaciParameters { + stateTreeDepth = 32 + messageTreeDepth = 32 + voteOptionTreeDepth = 3 + tallyBatchSize = 16 + messageBatchSize = 16 + batchUstVerifier!: string + qvtVerifier!: string + signUpDuration = 7 * 86400 + votingDuration = 7 * 86400 + + constructor(parameters: { [name: string]: any } = {}) { + this.update(parameters) + } + + update(parameters: { [name: string]: any }) { + for (const [name, value] of Object.entries(parameters)) { + ;(this as any)[name] = value + } + } + + values(): any[] { + // To be passed to setMaciParameters() + return [ + this.stateTreeDepth, + this.messageTreeDepth, + this.voteOptionTreeDepth, + this.tallyBatchSize, + this.messageBatchSize, + this.batchUstVerifier, + this.qvtVerifier, + this.signUpDuration, + this.votingDuration, + ] + } + + static async read(maciFactory: Contract): Promise { + const { stateTreeDepth, messageTreeDepth, voteOptionTreeDepth } = + await maciFactory.treeDepths() + const { tallyBatchSize, messageBatchSize } = await maciFactory.batchSizes() + const batchUstVerifier = await maciFactory.batchUstVerifier() + const qvtVerifier = await maciFactory.qvtVerifier() + const signUpDuration = (await maciFactory.signUpDuration()).toNumber() + const votingDuration = (await maciFactory.votingDuration()).toNumber() + return new MaciParameters({ + stateTreeDepth, + messageTreeDepth, + voteOptionTreeDepth, + tallyBatchSize, + messageBatchSize, + batchUstVerifier, + qvtVerifier, + signUpDuration, + votingDuration, + }) + } +} + export function bnSqrt(a: BigNumber): BigNumber { // Take square root from a big number // https://stackoverflow.com/a/52468569/1868395