Skip to content

Commit 8e74169

Browse files
committed
Merge branch 'develop' into staking-round
2 parents 25db19f + 08adfa1 commit 8e74169

11 files changed

+621
-17
lines changed

contracts/contracts/snarkVerifiers/BatchUpdateStateTreeVerifier32Batch16.sol

Lines changed: 270 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
// Copyright 2017 Christian Reitwiessner
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to
6+
// deal in the Software without restriction, including without limitation the
7+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8+
// sell copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18+
// IN THE SOFTWARE.
19+
20+
// 2019 OKIMS
21+
22+
pragma solidity ^0.6.12;
23+
24+
library Pairing {
25+
26+
uint256 constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
27+
28+
struct G1Point {
29+
uint256 X;
30+
uint256 Y;
31+
}
32+
33+
// Encoding of field elements is: X[0] * z + X[1]
34+
struct G2Point {
35+
uint256[2] X;
36+
uint256[2] Y;
37+
}
38+
39+
/*
40+
* @return The negation of p, i.e. p.plus(p.negate()) should be zero.
41+
*/
42+
function negate(G1Point memory p) internal pure returns (G1Point memory) {
43+
44+
// The prime q in the base field F_q for G1
45+
if (p.X == 0 && p.Y == 0) {
46+
return G1Point(0, 0);
47+
} else {
48+
return G1Point(p.X, PRIME_Q - (p.Y % PRIME_Q));
49+
}
50+
}
51+
52+
/*
53+
* @return The sum of two points of G1
54+
*/
55+
function plus(
56+
G1Point memory p1,
57+
G1Point memory p2
58+
) internal view returns (G1Point memory r) {
59+
60+
uint256[4] memory input;
61+
input[0] = p1.X;
62+
input[1] = p1.Y;
63+
input[2] = p2.X;
64+
input[3] = p2.Y;
65+
bool success;
66+
67+
// solium-disable-next-line security/no-inline-assembly
68+
assembly {
69+
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
70+
// Use "invalid" to make gas estimation work
71+
switch success case 0 { invalid() }
72+
}
73+
74+
require(success,"pairing-add-failed");
75+
}
76+
77+
/*
78+
* @return The product of a point on G1 and a scalar, i.e.
79+
* p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all
80+
* points p.
81+
*/
82+
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
83+
84+
uint256[3] memory input;
85+
input[0] = p.X;
86+
input[1] = p.Y;
87+
input[2] = s;
88+
bool success;
89+
// solium-disable-next-line security/no-inline-assembly
90+
assembly {
91+
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
92+
// Use "invalid" to make gas estimation work
93+
switch success case 0 { invalid() }
94+
}
95+
require (success,"pairing-mul-failed");
96+
}
97+
98+
/* @return The result of computing the pairing check
99+
* e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
100+
* For example,
101+
* pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
102+
*/
103+
function pairing(
104+
G1Point memory a1,
105+
G2Point memory a2,
106+
G1Point memory b1,
107+
G2Point memory b2,
108+
G1Point memory c1,
109+
G2Point memory c2,
110+
G1Point memory d1,
111+
G2Point memory d2
112+
) internal view returns (bool) {
113+
114+
G1Point[4] memory p1 = [a1, b1, c1, d1];
115+
G2Point[4] memory p2 = [a2, b2, c2, d2];
116+
117+
uint256 inputSize = 24;
118+
uint256[] memory input = new uint256[](inputSize);
119+
120+
for (uint256 i = 0; i < 4; i++) {
121+
uint256 j = i * 6;
122+
input[j + 0] = p1[i].X;
123+
input[j + 1] = p1[i].Y;
124+
input[j + 2] = p2[i].X[0];
125+
input[j + 3] = p2[i].X[1];
126+
input[j + 4] = p2[i].Y[0];
127+
input[j + 5] = p2[i].Y[1];
128+
}
129+
130+
uint256[1] memory out;
131+
bool success;
132+
133+
// solium-disable-next-line security/no-inline-assembly
134+
assembly {
135+
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
136+
// Use "invalid" to make gas estimation work
137+
switch success case 0 { invalid() }
138+
}
139+
140+
require(success,"pairing-opcode-failed");
141+
142+
return out[0] != 0;
143+
}
144+
}
145+
146+
contract QuadVoteTallyVerifier32Batch16 {
147+
148+
using Pairing for *;
149+
150+
uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
151+
uint256 constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
152+
153+
struct VerifyingKey {
154+
Pairing.G1Point alpha1;
155+
Pairing.G2Point beta2;
156+
Pairing.G2Point gamma2;
157+
Pairing.G2Point delta2;
158+
Pairing.G1Point[11] IC;
159+
}
160+
161+
struct Proof {
162+
Pairing.G1Point A;
163+
Pairing.G2Point B;
164+
Pairing.G1Point C;
165+
}
166+
167+
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
168+
vk.alpha1 = Pairing.G1Point(uint256(3931802286032916768722587566330261370902955393767942929056531203487688137529),uint256(10293105233586296031473050653492052327805448683376110761534611791713915549265));
169+
vk.beta2 = Pairing.G2Point([uint256(21113959492300078886023582393043413128535975125428858805958839308822991748856),uint256(12222282698476210310273536080661281164688722800089362655366747391082242682958)], [uint256(20739573447354048976161197946493569928714465565589532971602923073536082697608),uint256(12941541312444627642958656716514029404685754754869818026526533196090365546374)]);
170+
vk.gamma2 = Pairing.G2Point([uint256(14670836137271604202540255380769830849745744579684969689183516705496317922507),uint256(12178657156513808651243577987886528335149661869282225179912079606061386989744)], [uint256(1125902728883689137508324551765647737011904363437526425591650949891310723812),uint256(15919834918458423371681379777897287057084498811382451098590568497815773165692)]);
171+
vk.delta2 = Pairing.G2Point([uint256(2231852960373618563799433391860999041123211180191070579878255252716013298732),uint256(14291274065364399133654336098495355501982202302398283580502954673818060696633)], [uint256(3168628806727684542778047539988455291220201924183716864807010176642260685841),uint256(12606002808572759608577415926932586006638023328815450374325080704700677189688)]);
172+
vk.IC[0] = Pairing.G1Point(uint256(12848020380718535565089853534681145843006092696634142199856299025847321502371),uint256(6468756580219346512614969481554956146762400832923090074339557565951026058536));
173+
vk.IC[1] = Pairing.G1Point(uint256(789092430114940371944840041796419370450123967868354406244601329700742570445),uint256(11703230415288173665088837798624967250284180660322246777462631600764972864812));
174+
vk.IC[2] = Pairing.G1Point(uint256(16252197430844492890521435281772316410665185290137018091020232186750112907512),uint256(20861485175504002710376158881527553699531789728793309486150649246737774028347));
175+
vk.IC[3] = Pairing.G1Point(uint256(16969171625806775801891191965047460974818115969312194891897374689668597542196),uint256(14389419046525510722177847778450425484834864589330386321604392542455541983572));
176+
vk.IC[4] = Pairing.G1Point(uint256(13928883789499754049998767198742842124977905594692254232979837689918838899511),uint256(6757216204221511030872544186493375503384465407204524181513380457112801460878));
177+
vk.IC[5] = Pairing.G1Point(uint256(12615105472464956174046705416720445236758313003314061110048664932376957788951),uint256(1115476865907623432334995719744390855110066393577587591466560011685797098103));
178+
vk.IC[6] = Pairing.G1Point(uint256(12126180897004602060892141406139130628195608764592739755066384985876875328223),uint256(837414672224275155302376389224725114262382901229023048656048324984574980028));
179+
vk.IC[7] = Pairing.G1Point(uint256(721442001352764820041409242091349606527760014067614573870735409795650532250),uint256(5871690341119940542207233131936464616602051666920986699510353544932455895913));
180+
vk.IC[8] = Pairing.G1Point(uint256(11936590707137322489603100954274435093115715779097755089203405884503252799861),uint256(5832382048375298946996376174464817616061448358844675910441699738844607159400));
181+
vk.IC[9] = Pairing.G1Point(uint256(1150487096467611973629613424410317323826245588905051816727229632029031650443),uint256(19621934380117246037511579161242972091034040331100068879508644849318614270487));
182+
vk.IC[10] = Pairing.G1Point(uint256(14447725242028063610944438927433683612461991907837633029384208510392253681728),uint256(15642702797143402072429225245488363130997179355079100914641555016655302069615));
183+
184+
}
185+
186+
/*
187+
* @returns Whether the proof is valid given the hardcoded verifying key
188+
* above and the public inputs
189+
*/
190+
function verifyProof(
191+
uint256[2] memory a,
192+
uint256[2][2] memory b,
193+
uint256[2] memory c,
194+
uint256[] memory input
195+
) public view returns (bool) {
196+
197+
Proof memory proof;
198+
proof.A = Pairing.G1Point(a[0], a[1]);
199+
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
200+
proof.C = Pairing.G1Point(c[0], c[1]);
201+
202+
VerifyingKey memory vk = verifyingKey();
203+
204+
// Compute the linear combination vk_x
205+
Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
206+
207+
// Make sure that proof.A, B, and C are each less than the prime q
208+
require(proof.A.X < PRIME_Q, "verifier-aX-gte-prime-q");
209+
require(proof.A.Y < PRIME_Q, "verifier-aY-gte-prime-q");
210+
211+
require(proof.B.X[0] < PRIME_Q, "verifier-bX0-gte-prime-q");
212+
require(proof.B.Y[0] < PRIME_Q, "verifier-bY0-gte-prime-q");
213+
214+
require(proof.B.X[1] < PRIME_Q, "verifier-bX1-gte-prime-q");
215+
require(proof.B.Y[1] < PRIME_Q, "verifier-bY1-gte-prime-q");
216+
217+
require(proof.C.X < PRIME_Q, "verifier-cX-gte-prime-q");
218+
require(proof.C.Y < PRIME_Q, "verifier-cY-gte-prime-q");
219+
220+
// Make sure that every input is less than the snark scalar field
221+
//for (uint256 i = 0; i < input.length; i++) {
222+
for (uint256 i = 0; i < 10; i++) {
223+
require(input[i] < SNARK_SCALAR_FIELD,"verifier-gte-snark-scalar-field");
224+
vk_x = Pairing.plus(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
225+
}
226+
227+
vk_x = Pairing.plus(vk_x, vk.IC[0]);
228+
229+
return Pairing.pairing(
230+
Pairing.negate(proof.A),
231+
proof.B,
232+
vk.alpha1,
233+
vk.beta2,
234+
vk_x,
235+
vk.gamma2,
236+
proof.C,
237+
vk.delta2
238+
);
239+
}
240+
}

contracts/e2e/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,14 @@ describe('End-to-end Tests', function () {
6868
const poseidonT6 = await deployContract(deployer, ':PoseidonT6')
6969
const batchUstVerifier = await deployContract(
7070
deployer,
71-
'BatchUpdateStateTreeVerifier32'
71+
'BatchUpdateStateTreeVerifier32Batch16'
7272
)
7373
const qvtVerifier = await deployContract(
7474
deployer,
75-
'QuadVoteTallyVerifier32'
75+
'QuadVoteTallyVerifier32Batch16'
7676
)
77-
const maciFactory = await deployMaciFactory(deployer, 'x32', {
77+
const circuit = 'prod'
78+
const maciFactory = await deployMaciFactory(deployer, circuit, {
7879
poseidonT3,
7980
poseidonT6,
8081
batchUstVerifier,

contracts/scripts/deploy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { deployMaciFactory } from '../utils/deployment'
77
async function main() {
88
const [deployer] = await ethers.getSigners()
99
console.log(`Deploying from address: ${deployer.address}`)
10-
11-
const maciFactory = await deployMaciFactory(deployer)
10+
const circuit = 'prod'
11+
const maciFactory = await deployMaciFactory(deployer, circuit)
1212
await maciFactory.deployTransaction.wait()
1313
console.log(`MACIFactory deployed: ${maciFactory.address}`)
1414

contracts/scripts/deployRound.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ async function main() {
1212
console.log('*******************')
1313
const [deployer] = await ethers.getSigners()
1414
console.log('deployer.address: ', deployer.address)
15-
16-
let maciFactory = await deployMaciFactory(deployer)
15+
const circuit = 'prod'
16+
let maciFactory = await deployMaciFactory(deployer, circuit)
1717
await maciFactory.deployTransaction.wait()
1818
console.log('maciFactory.address: ', maciFactory.address)
1919

contracts/tests/deployer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ describe('Clr fund deployer', () => {
2727
const coordinatorPubKey = new Keypair().pubKey.asContractParam()
2828

2929
beforeEach(async () => {
30-
maciFactory = await deployMaciFactory(deployer)
30+
const circuit = 'prod'
31+
maciFactory = await deployMaciFactory(deployer, circuit)
3132
maciParameters = await MaciParameters.read(maciFactory)
3233

3334
factoryTemplate = await deployContract(deployer, 'ClrFund')

contracts/tests/factory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ describe('Funding Round Factory', () => {
2525
const coordinatorPubKey = new Keypair().pubKey.asContractParam()
2626

2727
beforeEach(async () => {
28-
maciFactory = await deployMaciFactory(deployer)
28+
const circuit = 'prod'
29+
maciFactory = await deployMaciFactory(deployer, circuit)
2930
maciParameters = await MaciParameters.read(maciFactory)
3031

3132
factory = await deployContract(deployer, 'FundingRoundFactory', [

contracts/tests/maciFactory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ describe('MACI factory', () => {
2222
const coordinatorPubKey = new Keypair().pubKey.asContractParam()
2323

2424
beforeEach(async () => {
25-
maciFactory = await deployMaciFactory(deployer)
25+
const circuit = 'prod'
26+
maciFactory = await deployMaciFactory(deployer, circuit)
2627
expect(await getGasUsage(maciFactory.deployTransaction)).lessThan(5600000)
2728
maciParameters = await MaciParameters.read(maciFactory)
2829

contracts/tests/round.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ describe('Funding Round', () => {
7979
recipientRegistry.address,
8080
coordinator.address
8181
)
82-
const maciFactory = await deployMaciFactory(deployer)
82+
const circuit = 'prod'
83+
const maciFactory = await deployMaciFactory(deployer, circuit)
8384
const maciDeployed = await maciFactory.deployMaci(
8485
fundingRound.address,
8586
fundingRound.address,

contracts/utils/deployment.ts

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Libraries } from 'hardhat/types/runtime'
33
import { Signer, Contract } from 'ethers'
44
import { link } from 'ethereum-waffle'
55

6-
import { MaciParameters } from './maci'
6+
import { MaciParameters, ProdMaciParameters } from './maci'
77

88
export function linkBytecode(
99
bytecode: string,
@@ -54,6 +54,35 @@ const CIRCUITS: { [name: string]: any } = {
5454
voteOptionTreeDepth: 3,
5555
},
5656
},
57+
prod: {
58+
batchUstVerifier: 'BatchUpdateStateTreeVerifier32Batch16',
59+
qvtVerifier: 'QuadVoteTallyVerifier32Batch16',
60+
treeDepths: {
61+
stateTreeDepth: 32,
62+
messageTreeDepth: 32,
63+
voteOptionTreeDepth: 3,
64+
},
65+
},
66+
}
67+
const PARAMS = (
68+
circuit: string,
69+
batchUstVerifier: string,
70+
qvtVerifier: string
71+
) => {
72+
switch (circuit) {
73+
case 'prod':
74+
return new ProdMaciParameters({
75+
batchUstVerifier,
76+
qvtVerifier,
77+
...CIRCUITS[circuit].treeDepths,
78+
})
79+
default:
80+
return new MaciParameters({
81+
batchUstVerifier,
82+
qvtVerifier,
83+
...CIRCUITS[circuit].treeDepths,
84+
})
85+
}
5786
}
5887

5988
export async function deployContract(
@@ -83,6 +112,7 @@ export async function deployMaciFactory(
83112
qvtVerifier,
84113
}: MaciFactoryDependencies = {}
85114
): Promise<Contract> {
115+
let maciParameters: MaciParameters | ProdMaciParameters
86116
if (!poseidonT3) {
87117
const PoseidonT3 = await ethers.getContractFactory(':PoseidonT3', account)
88118
poseidonT3 = await PoseidonT3.deploy()
@@ -115,11 +145,12 @@ export async function deployMaciFactory(
115145
signer: account,
116146
libraries: maciLibraries,
117147
})
118-
const maciParameters = new MaciParameters({
119-
batchUstVerifier: batchUstVerifier.address,
120-
qvtVerifier: qvtVerifier.address,
121-
...CIRCUITS[circuit].treeDepths,
122-
})
148+
149+
maciParameters = PARAMS(
150+
circuit,
151+
batchUstVerifier.address,
152+
qvtVerifier.address
153+
)
123154

124155
const maciFactory = await MACIFactory.deploy(...maciParameters.values())
125156
await maciFactory.deployTransaction.wait()

0 commit comments

Comments
 (0)