@maci-protocol/circuits 0.0.0-ci.f9da2fc → 0.0.0-ci.fc91dc9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -2
- package/build/ts/{genZkeys.d.ts → generateZkeys.d.ts} +1 -1
- package/build/ts/generateZkeys.d.ts.map +1 -0
- package/build/ts/{genZkeys.js → generateZkeys.js} +1 -1
- package/build/ts/generateZkeys.js.map +1 -0
- package/build/ts/types.d.ts +8 -8
- package/build/ts/types.d.ts.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/circom/circuits.json +7 -7
- package/circom/coordinator/non-qv/processMessages.circom +98 -95
- package/circom/coordinator/non-qv/tallyVotes.circom +38 -32
- package/circom/coordinator/qv/processMessages.circom +99 -93
- package/circom/coordinator/qv/tallyVotes.circom +39 -37
- package/circom/utils/{calculateTotal.circom → CalculateTotal.circom} +2 -0
- package/circom/utils/{verifySignature.circom → EdDSAPoseidonVerifier.circom} +40 -66
- package/circom/utils/MessageHasher.circom +57 -0
- package/circom/utils/MessageToCommand.circom +107 -0
- package/circom/utils/PoseidonHasher.circom +29 -0
- package/circom/utils/{privToPubKey.circom → PrivateToPublicKey.circom} +11 -9
- package/circom/utils/VerifySignature.circom +39 -0
- package/circom/utils/non-qv/{messageValidator.circom → MessageValidator.circom} +13 -11
- package/circom/utils/non-qv/{stateLeafAndBallotTransformer.circom → StateLeafAndBallotTransformer.circom} +32 -32
- package/circom/utils/qv/{messageValidator.circom → MessageValidator.circom} +13 -11
- package/circom/utils/qv/{stateLeafAndBallotTransformer.circom → StateLeafAndBallotTransformer.circom} +32 -32
- package/circom/utils/trees/BinaryMerkleRoot.circom +62 -0
- package/circom/utils/trees/CheckRoot.circom +49 -0
- package/circom/utils/trees/LeafExists.circom +27 -0
- package/circom/utils/trees/MerklePathIndicesGenerator.circom +44 -0
- package/circom/utils/trees/MerkleTreeInclusionProof.circom +50 -0
- package/circom/utils/trees/incrementalQuinaryTree.circom +2 -2
- package/circom/voter/PollJoined.circom +43 -0
- package/circom/voter/PollJoining.circom +54 -0
- package/package.json +12 -11
- package/build/ts/genZkeys.d.ts.map +0 -1
- package/build/ts/genZkeys.js.map +0 -1
- package/circom/utils/hashers.circom +0 -78
- package/circom/utils/messageToCommand.circom +0 -78
- package/circom/utils/trees/incrementalMerkleTree.circom +0 -198
- package/circom/voter/poll.circom +0 -91
|
@@ -5,12 +5,17 @@ include "./mux1.circom";
|
|
|
5
5
|
// zk-kit imports
|
|
6
6
|
include "./safe-comparators.circom";
|
|
7
7
|
// local imports
|
|
8
|
-
include "../../utils/
|
|
9
|
-
include "../../utils/
|
|
10
|
-
include "../../utils/
|
|
11
|
-
include "../../utils/
|
|
8
|
+
include "../../utils/PoseidonHasher.circom";
|
|
9
|
+
include "../../utils/MessageHasher.circom";
|
|
10
|
+
include "../../utils/MessageToCommand.circom";
|
|
11
|
+
include "../../utils/PrivateToPublicKey.circom";
|
|
12
|
+
include "../../utils/qv/StateLeafAndBallotTransformer.circom";
|
|
12
13
|
include "../../utils/trees/incrementalQuinaryTree.circom";
|
|
13
|
-
include "../../utils/trees/
|
|
14
|
+
include "../../utils/trees/MerkleTreeInclusionProof.circom";
|
|
15
|
+
include "../../utils/trees/LeafExists.circom";
|
|
16
|
+
include "../../utils/trees/CheckRoot.circom";
|
|
17
|
+
include "../../utils/trees/MerklePathIndicesGenerator.circom";
|
|
18
|
+
include "../../utils/trees/BinaryMerkleRoot.circom";
|
|
14
19
|
|
|
15
20
|
/**
|
|
16
21
|
* Proves the correctness of processing a batch of MACI messages.
|
|
@@ -30,31 +35,31 @@ template ProcessMessages(
|
|
|
30
35
|
var VOTE_OPTION_TREE_ARITY = 5;
|
|
31
36
|
// Default for binary trees.
|
|
32
37
|
var STATE_TREE_ARITY = 2;
|
|
33
|
-
var
|
|
34
|
-
var
|
|
38
|
+
var MESSAGE_LENGTH = 10;
|
|
39
|
+
var PACKED_COMMAND_LENGTH = 4;
|
|
35
40
|
var STATE_LEAF_LENGTH = 3;
|
|
36
41
|
var BALLOT_LENGTH = 2;
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
var
|
|
42
|
+
var BALLOT_NONCE_INDEX = 0;
|
|
43
|
+
var BALLOT_VOTE_OPTION_ROOT_INDEX = 1;
|
|
44
|
+
var STATE_LEAF_PUBLIC_X_INDEX = 0;
|
|
45
|
+
var STATE_LEAF_PUBLIC_Y_INDEX = 1;
|
|
46
|
+
var STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX = 2;
|
|
47
|
+
var MESSAGE_TREE_ZERO_VALUE = 8370432830353022751713833565135785980866757267633941821328460903436894336785;
|
|
43
48
|
// Number of options for this poll.
|
|
44
49
|
var maxVoteOptions = VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth;
|
|
45
50
|
|
|
46
51
|
// Number of users that have completed the sign up.
|
|
47
|
-
signal input
|
|
52
|
+
signal input totalSignups;
|
|
48
53
|
// Value of chainHash at beginning of batch
|
|
49
54
|
signal input inputBatchHash;
|
|
50
55
|
// Value of chainHash at end of batch
|
|
51
56
|
signal input outputBatchHash;
|
|
52
57
|
// The messages.
|
|
53
|
-
signal input
|
|
58
|
+
signal input messages[batchSize][MESSAGE_LENGTH];
|
|
54
59
|
// The coordinator's private key.
|
|
55
|
-
signal input
|
|
60
|
+
signal input coordinatorPrivateKey;
|
|
56
61
|
// The ECDH public key per message.
|
|
57
|
-
signal input
|
|
62
|
+
signal input encryptionPublicKeys[batchSize][2];
|
|
58
63
|
// The current state root (before the processing).
|
|
59
64
|
signal input currentStateRoot;
|
|
60
65
|
// The actual tree depth (might be <= stateTreeDepth).
|
|
@@ -117,10 +122,10 @@ template ProcessMessages(
|
|
|
117
122
|
var voteOptionsValid = LessEqThan(32)([voteOptions, VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth]);
|
|
118
123
|
voteOptionsValid === 1;
|
|
119
124
|
|
|
120
|
-
// Check
|
|
125
|
+
// Check totalSignups <= the max number of users (i.e., number of state leaves
|
|
121
126
|
// that can fit the state tree).
|
|
122
|
-
var
|
|
123
|
-
|
|
127
|
+
var totalSignupsValid = LessEqThan(32)([totalSignups, STATE_TREE_ARITY ** stateTreeDepth]);
|
|
128
|
+
totalSignupsValid === 1;
|
|
124
129
|
|
|
125
130
|
// Hash each Message to check their existence in the Message tree.
|
|
126
131
|
var computedMessageHashers[batchSize];
|
|
@@ -130,7 +135,7 @@ template ProcessMessages(
|
|
|
130
135
|
|
|
131
136
|
for (var i = 0; i < batchSize; i++) {
|
|
132
137
|
// calculate message hash
|
|
133
|
-
computedMessageHashers[i] = MessageHasher()(
|
|
138
|
+
computedMessageHashers[i] = MessageHasher()(messages[i], encryptionPublicKeys[i]);
|
|
134
139
|
// check if message is valid or not (if index of message is less than index of last valid message in batch)
|
|
135
140
|
var batchStartIndexValid = SafeLessThan(32)([index + i, batchEndIndex]);
|
|
136
141
|
// calculate chain hash if message is valid
|
|
@@ -154,38 +159,38 @@ template ProcessMessages(
|
|
|
154
159
|
// Ensure that the coordinator's public key from the contract is correct
|
|
155
160
|
// based on the given private key - that is, the prover knows the
|
|
156
161
|
// coordinator's private key.
|
|
157
|
-
var
|
|
158
|
-
var
|
|
159
|
-
|
|
162
|
+
var derivedPublicKey[2] = PrivateToPublicKey()(coordinatorPrivateKey);
|
|
163
|
+
var derivedPublicKeyHash = PoseidonHasher(2)(derivedPublicKey);
|
|
164
|
+
derivedPublicKeyHash === coordinatorPublicKeyHash;
|
|
160
165
|
|
|
161
166
|
// Decrypt each Message into a Command.
|
|
162
167
|
// The command i-th is composed by the following fields.
|
|
163
168
|
// e.g., command 0 is made of commandsStateIndex[0],
|
|
164
|
-
//
|
|
169
|
+
// commandsNewPublicKey[0], ..., commandsPackedCommandOut[0]
|
|
165
170
|
var computedCommandsStateIndex[batchSize];
|
|
166
|
-
var
|
|
171
|
+
var computedCommandsNewPublicKey[batchSize][2];
|
|
167
172
|
var computedCommandsVoteOptionIndex[batchSize];
|
|
168
173
|
var computedCommandsNewVoteWeight[batchSize];
|
|
169
174
|
var computedCommandsNonce[batchSize];
|
|
170
175
|
var computedCommandsPollId[batchSize];
|
|
171
176
|
var computedCommandsSalt[batchSize];
|
|
172
|
-
var
|
|
173
|
-
var
|
|
174
|
-
var computedCommandsPackedCommandOut[batchSize][
|
|
177
|
+
var computedCommandsSignaturePoint[batchSize][2];
|
|
178
|
+
var computedCommandsSignatureScalar[batchSize];
|
|
179
|
+
var computedCommandsPackedCommandOut[batchSize][PACKED_COMMAND_LENGTH];
|
|
175
180
|
|
|
176
181
|
for (var i = 0; i < batchSize; i++) {
|
|
177
182
|
(
|
|
178
183
|
computedCommandsStateIndex[i],
|
|
179
|
-
|
|
184
|
+
computedCommandsNewPublicKey[i],
|
|
180
185
|
computedCommandsVoteOptionIndex[i],
|
|
181
186
|
computedCommandsNewVoteWeight[i],
|
|
182
187
|
computedCommandsNonce[i],
|
|
183
188
|
computedCommandsPollId[i],
|
|
184
189
|
computedCommandsSalt[i],
|
|
185
|
-
|
|
186
|
-
|
|
190
|
+
computedCommandsSignaturePoint[i],
|
|
191
|
+
computedCommandsSignatureScalar[i],
|
|
187
192
|
computedCommandsPackedCommandOut[i]
|
|
188
|
-
) = MessageToCommand()(
|
|
193
|
+
) = MessageToCommand()(messages[i], coordinatorPrivateKey, encryptionPublicKeys[i]);
|
|
189
194
|
}
|
|
190
195
|
|
|
191
196
|
// Process messages in reverse order.
|
|
@@ -218,7 +223,7 @@ template ProcessMessages(
|
|
|
218
223
|
}
|
|
219
224
|
|
|
220
225
|
(computedNewVoteStateRoot[i], computedNewVoteBallotRoot[i]) = ProcessOne(stateTreeDepth, voteOptionTreeDepth)(
|
|
221
|
-
|
|
226
|
+
totalSignups,
|
|
222
227
|
stateRoots[i + 1],
|
|
223
228
|
ballotRoots[i + 1],
|
|
224
229
|
actualStateTreeDepth,
|
|
@@ -229,14 +234,14 @@ template ProcessMessages(
|
|
|
229
234
|
currentVoteWeights[i],
|
|
230
235
|
currentVoteWeightsPathElement,
|
|
231
236
|
computedCommandsStateIndex[i],
|
|
232
|
-
|
|
237
|
+
computedCommandsNewPublicKey[i],
|
|
233
238
|
computedCommandsVoteOptionIndex[i],
|
|
234
239
|
computedCommandsNewVoteWeight[i],
|
|
235
240
|
computedCommandsNonce[i],
|
|
236
241
|
computedCommandsPollId[i],
|
|
237
242
|
computedCommandsSalt[i],
|
|
238
|
-
|
|
239
|
-
|
|
243
|
+
computedCommandsSignaturePoint[i],
|
|
244
|
+
computedCommandsSignatureScalar[i],
|
|
240
245
|
computedCommandsPackedCommandOut[i],
|
|
241
246
|
voteOptions
|
|
242
247
|
);
|
|
@@ -261,24 +266,24 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
261
266
|
// Constants defining the structure and size of state and ballots.
|
|
262
267
|
var STATE_LEAF_LENGTH = 3;
|
|
263
268
|
var BALLOT_LENGTH = 2;
|
|
264
|
-
var
|
|
265
|
-
var
|
|
269
|
+
var MESSAGE_LENGTH = 10;
|
|
270
|
+
var PACKED_COMMAND_LENGTH = 4;
|
|
266
271
|
var VOTE_OPTION_TREE_ARITY = 5;
|
|
267
272
|
var STATE_TREE_ARITY = 2;
|
|
268
|
-
var
|
|
269
|
-
// Ballot vote option (
|
|
270
|
-
var
|
|
273
|
+
var BALLOT_NONCE_INDEX = 0;
|
|
274
|
+
// Ballot vote option (vote option) root index.
|
|
275
|
+
var BALLOT_VOTE_OPTION_ROOT_INDEX = 1;
|
|
271
276
|
|
|
272
277
|
// Indices for elements within a state leaf.
|
|
273
278
|
// Public key.
|
|
274
|
-
var
|
|
275
|
-
var
|
|
279
|
+
var STATE_LEAF_PUBLIC_X_INDEX = 0;
|
|
280
|
+
var STATE_LEAF_PUBLIC_Y_INDEX = 1;
|
|
276
281
|
// Voice Credit balance.
|
|
277
|
-
var
|
|
278
|
-
var
|
|
282
|
+
var STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX = 2;
|
|
283
|
+
var NUMBER_BITS = 252;
|
|
279
284
|
|
|
280
285
|
// Number of users that have completed the sign up.
|
|
281
|
-
signal input
|
|
286
|
+
signal input totalSignups;
|
|
282
287
|
// The current value of the state tree root.
|
|
283
288
|
signal input currentStateRoot;
|
|
284
289
|
// The current value of the ballot tree root.
|
|
@@ -300,16 +305,16 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
300
305
|
signal input currentVoteWeightsPathElements[voteOptionTreeDepth][VOTE_OPTION_TREE_ARITY - 1];
|
|
301
306
|
|
|
302
307
|
// Inputs related to the command being processed.
|
|
303
|
-
signal input
|
|
304
|
-
signal input
|
|
305
|
-
signal input
|
|
306
|
-
signal input
|
|
307
|
-
signal input
|
|
308
|
-
signal input
|
|
309
|
-
signal input
|
|
310
|
-
signal input
|
|
311
|
-
signal input
|
|
312
|
-
signal input
|
|
308
|
+
signal input commandStateIndex;
|
|
309
|
+
signal input commandPublicKey[2];
|
|
310
|
+
signal input commandVoteOptionIndex;
|
|
311
|
+
signal input commandNewVoteWeight;
|
|
312
|
+
signal input commandNonce;
|
|
313
|
+
signal input commandPollId;
|
|
314
|
+
signal input commandSalt;
|
|
315
|
+
signal input commandSignaturePoint[2];
|
|
316
|
+
signal input commandSignatureScalar;
|
|
317
|
+
signal input packedCommand[PACKED_COMMAND_LENGTH];
|
|
313
318
|
|
|
314
319
|
// The number of valid vote options for the poll.
|
|
315
320
|
signal input voteOptions;
|
|
@@ -320,37 +325,37 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
320
325
|
// Intermediate signals.
|
|
321
326
|
// currentVoteWeight * currentVoteWeight.
|
|
322
327
|
signal currentVoteWeightSquare;
|
|
323
|
-
//
|
|
324
|
-
signal
|
|
325
|
-
// equal to
|
|
328
|
+
// commandNewVoteWeight * commandNewVoteWeight.
|
|
329
|
+
signal commandNewVoteWeightSquare;
|
|
330
|
+
// equal to newBallotVoteOptionRootMux (Mux1).
|
|
326
331
|
signal newBallotVoRoot;
|
|
327
332
|
|
|
328
333
|
// 1. Transform a state leaf and a ballot with a command.
|
|
329
334
|
// The result is a new state leaf, a new ballot, and an isValid signal (0 or 1).
|
|
330
|
-
var
|
|
331
|
-
(
|
|
332
|
-
|
|
335
|
+
var computedNewstateLeafPublicKey[2], computedNewBallotNonce, computedIsValid, computedIsStateLeafIndexValid, computedIsVoteOptionIndexValid;
|
|
336
|
+
(computedNewstateLeafPublicKey, computedNewBallotNonce, computedIsValid, computedIsStateLeafIndexValid, computedIsVoteOptionIndexValid) = StateLeafAndBallotTransformer()(
|
|
337
|
+
totalSignups,
|
|
333
338
|
voteOptions,
|
|
334
|
-
[stateLeaf[
|
|
335
|
-
stateLeaf[
|
|
336
|
-
ballot[
|
|
339
|
+
[stateLeaf[STATE_LEAF_PUBLIC_X_INDEX], stateLeaf[STATE_LEAF_PUBLIC_Y_INDEX]],
|
|
340
|
+
stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX],
|
|
341
|
+
ballot[BALLOT_NONCE_INDEX],
|
|
337
342
|
currentVoteWeight,
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
343
|
+
commandStateIndex,
|
|
344
|
+
commandPublicKey,
|
|
345
|
+
commandVoteOptionIndex,
|
|
346
|
+
commandNewVoteWeight,
|
|
347
|
+
commandNonce,
|
|
348
|
+
commandPollId,
|
|
349
|
+
commandSalt,
|
|
350
|
+
commandSignaturePoint,
|
|
351
|
+
commandSignatureScalar,
|
|
352
|
+
packedCommand
|
|
348
353
|
);
|
|
349
354
|
|
|
350
355
|
// 2. If computedIsStateLeafIndexValid is equal to zero, generate indices for leaf zero.
|
|
351
356
|
// Otherwise, generate indices for command.stateIndex.
|
|
352
|
-
var stateIndexMux = Mux1()([0,
|
|
353
|
-
var computedStateLeafPathIndices[stateTreeDepth] =
|
|
357
|
+
var stateIndexMux = Mux1()([0, commandStateIndex], computedIsStateLeafIndexValid);
|
|
358
|
+
var computedStateLeafPathIndices[stateTreeDepth] = MerklePathIndicesGenerator(stateTreeDepth)(stateIndexMux);
|
|
354
359
|
|
|
355
360
|
// 3. Verify that the original state leaf exists in the given state root.
|
|
356
361
|
var stateLeafHash = PoseidonHasher(3)(stateLeaf);
|
|
@@ -365,8 +370,8 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
365
370
|
|
|
366
371
|
// 4. Verify that the original ballot exists in the given ballot root.
|
|
367
372
|
var computedBallot = PoseidonHasher(2)([
|
|
368
|
-
ballot[
|
|
369
|
-
ballot[
|
|
373
|
+
ballot[BALLOT_NONCE_INDEX],
|
|
374
|
+
ballot[BALLOT_VOTE_OPTION_ROOT_INDEX]
|
|
370
375
|
]);
|
|
371
376
|
|
|
372
377
|
var computedBallotQip = MerkleTreeInclusionProof(stateTreeDepth)(
|
|
@@ -378,12 +383,12 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
378
383
|
computedBallotQip === currentBallotRoot;
|
|
379
384
|
|
|
380
385
|
// 5. Verify that currentVoteWeight exists in the ballot's vote option root
|
|
381
|
-
// at
|
|
386
|
+
// at commandVoteOptionIndex.
|
|
382
387
|
currentVoteWeightSquare <== currentVoteWeight * currentVoteWeight;
|
|
383
|
-
|
|
388
|
+
commandNewVoteWeightSquare <== commandNewVoteWeight * commandNewVoteWeight;
|
|
384
389
|
|
|
385
|
-
var
|
|
386
|
-
var computedCurrentVoteWeightPathIndices[voteOptionTreeDepth] = QuinGeneratePathIndices(voteOptionTreeDepth)(
|
|
390
|
+
var commandVoteOptionIndexMux = Mux1()([0, commandVoteOptionIndex], computedIsVoteOptionIndexValid);
|
|
391
|
+
var computedCurrentVoteWeightPathIndices[voteOptionTreeDepth] = QuinGeneratePathIndices(voteOptionTreeDepth)(commandVoteOptionIndexMux);
|
|
387
392
|
|
|
388
393
|
var computedCurrentVoteWeightQip = QuinTreeInclusionProof(voteOptionTreeDepth)(
|
|
389
394
|
currentVoteWeight,
|
|
@@ -391,13 +396,13 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
391
396
|
currentVoteWeightsPathElements
|
|
392
397
|
);
|
|
393
398
|
|
|
394
|
-
computedCurrentVoteWeightQip === ballot[
|
|
399
|
+
computedCurrentVoteWeightQip === ballot[BALLOT_VOTE_OPTION_ROOT_INDEX];
|
|
395
400
|
|
|
396
|
-
var voteWeightMux = Mux1()([currentVoteWeight,
|
|
401
|
+
var voteWeightMux = Mux1()([currentVoteWeight, commandNewVoteWeight], computedIsValid);
|
|
397
402
|
var voiceCreditBalanceMux = Mux1()(
|
|
398
403
|
[
|
|
399
|
-
stateLeaf[
|
|
400
|
-
stateLeaf[
|
|
404
|
+
stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX],
|
|
405
|
+
stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX] + currentVoteWeightSquare - commandNewVoteWeightSquare
|
|
401
406
|
],
|
|
402
407
|
computedIsValid
|
|
403
408
|
);
|
|
@@ -410,17 +415,17 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
410
415
|
);
|
|
411
416
|
|
|
412
417
|
// The new vote option root in the ballot
|
|
413
|
-
var
|
|
414
|
-
[ballot[
|
|
418
|
+
var newBallotVoteOptionRootMux = Mux1()(
|
|
419
|
+
[ballot[BALLOT_VOTE_OPTION_ROOT_INDEX], computedNewVoteOptionTreeQip],
|
|
415
420
|
computedIsValid
|
|
416
421
|
);
|
|
417
422
|
|
|
418
|
-
newBallotVoRoot <==
|
|
423
|
+
newBallotVoRoot <== newBallotVoteOptionRootMux;
|
|
419
424
|
|
|
420
425
|
// 6. Generate a new state root.
|
|
421
426
|
var computedNewStateLeafhash = PoseidonHasher(3)([
|
|
422
|
-
|
|
423
|
-
|
|
427
|
+
computedNewstateLeafPublicKey[STATE_LEAF_PUBLIC_X_INDEX],
|
|
428
|
+
computedNewstateLeafPublicKey[STATE_LEAF_PUBLIC_Y_INDEX],
|
|
424
429
|
voiceCreditBalanceMux
|
|
425
430
|
]);
|
|
426
431
|
|
|
@@ -443,3 +448,4 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
443
448
|
|
|
444
449
|
newBallotRoot <== computedNewBallotQip;
|
|
445
450
|
}
|
|
451
|
+
|
|
@@ -5,10 +5,12 @@ include "./comparators.circom";
|
|
|
5
5
|
// zk-kit import
|
|
6
6
|
include "./unpack-element.circom";
|
|
7
7
|
// local imports
|
|
8
|
-
include "../../utils/trees/
|
|
8
|
+
include "../../utils/trees/CheckRoot.circom";
|
|
9
|
+
include "../../utils/trees/MerklePathIndicesGenerator.circom";
|
|
10
|
+
include "../../utils/trees/LeafExists.circom";
|
|
9
11
|
include "../../utils/trees/incrementalQuinaryTree.circom";
|
|
10
|
-
include "../../utils/
|
|
11
|
-
include "../../utils/
|
|
12
|
+
include "../../utils/CalculateTotal.circom";
|
|
13
|
+
include "../../utils/PoseidonHasher.circom";
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Processes batches of votes and verifies their validity in a Merkle tree structure.
|
|
@@ -33,16 +35,16 @@ template TallyVotes(
|
|
|
33
35
|
// The number of ballots processed at once, determined by the depth of the intermediate state tree.
|
|
34
36
|
var batchSize = BALLOT_TREE_ARITY ** intStateTreeDepth;
|
|
35
37
|
// Number of voting options available, determined by the depth of the vote option tree.
|
|
36
|
-
var
|
|
38
|
+
var totalVoteOptions = TREE_ARITY ** voteOptionTreeDepth;
|
|
37
39
|
|
|
38
40
|
// Number of elements in each ballot.
|
|
39
41
|
var BALLOT_LENGTH = 2;
|
|
40
42
|
// Index for the nonce in the ballot array.
|
|
41
|
-
var
|
|
43
|
+
var BALLOT_NONCE_INDEX = 0;
|
|
42
44
|
// Index for the voting option root in the ballot array.
|
|
43
|
-
var
|
|
45
|
+
var BALLOT_VOTE_OPTION_ROOT_INDEX = 1;
|
|
44
46
|
// Difference in tree depths, used in path calculations.
|
|
45
|
-
var
|
|
47
|
+
var STATE_INT_TREE_DEPTH_DIFFERENCE = stateTreeDepth - intStateTreeDepth;
|
|
46
48
|
|
|
47
49
|
// Root of the state Merkle tree, representing the overall state before voting.
|
|
48
50
|
signal input stateRoot;
|
|
@@ -59,13 +61,13 @@ template TallyVotes(
|
|
|
59
61
|
// Start index of given batch
|
|
60
62
|
signal input index;
|
|
61
63
|
// Number of users that signup
|
|
62
|
-
signal input
|
|
64
|
+
signal input totalSignups;
|
|
63
65
|
// Ballots and their corresponding path elements for verification in the tree.
|
|
64
66
|
signal input ballots[batchSize][BALLOT_LENGTH];
|
|
65
|
-
signal input ballotPathElements[
|
|
66
|
-
signal input votes[batchSize][
|
|
67
|
+
signal input ballotPathElements[STATE_INT_TREE_DEPTH_DIFFERENCE][BALLOT_TREE_ARITY - 1];
|
|
68
|
+
signal input votes[batchSize][totalVoteOptions];
|
|
67
69
|
// Current results for each vote option.
|
|
68
|
-
signal input currentResults[
|
|
70
|
+
signal input currentResults[totalVoteOptions];
|
|
69
71
|
// Salt for the root of the current results.
|
|
70
72
|
signal input currentResultsRootSalt;
|
|
71
73
|
// Total voice credits spent so far.
|
|
@@ -73,7 +75,7 @@ template TallyVotes(
|
|
|
73
75
|
// Salt for the total spent voice credits.
|
|
74
76
|
signal input currentSpentVoiceCreditSubtotalSalt;
|
|
75
77
|
// Spent voice credits per vote option.
|
|
76
|
-
signal input currentPerVOSpentVoiceCredits[
|
|
78
|
+
signal input currentPerVOSpentVoiceCredits[totalVoteOptions];
|
|
77
79
|
// Salt for the root of spent credits per option.
|
|
78
80
|
signal input currentPerVOSpentVoiceCreditsRootSalt;
|
|
79
81
|
// Salt for the root of the new results.
|
|
@@ -88,21 +90,21 @@ template TallyVotes(
|
|
|
88
90
|
computedSbCommitment === sbCommitment;
|
|
89
91
|
|
|
90
92
|
// Validates that the index is within the valid range of sign-ups.
|
|
91
|
-
var
|
|
92
|
-
|
|
93
|
+
var totalSignupsValid = LessEqThan(50)([index, totalSignups]);
|
|
94
|
+
totalSignupsValid === 1;
|
|
93
95
|
|
|
94
96
|
// Hashes each ballot for subroot generation, and checks the existence of the leaf in the Merkle tree.
|
|
95
97
|
var computedBallotHashers[batchSize];
|
|
96
98
|
|
|
97
99
|
for (var i = 0; i < batchSize; i++) {
|
|
98
|
-
computedBallotHashers[i] = PoseidonHasher(2)([ballots[i][
|
|
100
|
+
computedBallotHashers[i] = PoseidonHasher(2)([ballots[i][BALLOT_NONCE_INDEX], ballots[i][BALLOT_VOTE_OPTION_ROOT_INDEX]]);
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
var computedBallotSubroot = CheckRoot(intStateTreeDepth)(computedBallotHashers);
|
|
102
|
-
var computedBallotPathIndices[
|
|
104
|
+
var computedBallotPathIndices[STATE_INT_TREE_DEPTH_DIFFERENCE] = MerklePathIndicesGenerator(STATE_INT_TREE_DEPTH_DIFFERENCE)(index / batchSize);
|
|
103
105
|
|
|
104
106
|
// Verifies each ballot's existence within the ballot tree.
|
|
105
|
-
LeafExists(
|
|
107
|
+
LeafExists(STATE_INT_TREE_DEPTH_DIFFERENCE)(
|
|
106
108
|
computedBallotSubroot,
|
|
107
109
|
ballotPathElements,
|
|
108
110
|
computedBallotPathIndices,
|
|
@@ -113,7 +115,7 @@ template TallyVotes(
|
|
|
113
115
|
var computedVoteTree[batchSize];
|
|
114
116
|
for (var i = 0; i < batchSize; i++) {
|
|
115
117
|
computedVoteTree[i] = QuinCheckRoot(voteOptionTreeDepth)(votes[i]);
|
|
116
|
-
computedVoteTree[i] === ballots[i][
|
|
118
|
+
computedVoteTree[i] === ballots[i][BALLOT_VOTE_OPTION_ROOT_INDEX];
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
// Calculates new results and spent voice credits based on the current and incoming votes.
|
|
@@ -121,8 +123,8 @@ template TallyVotes(
|
|
|
121
123
|
var computedIsZero = IsZero()(computedIsFirstBatch);
|
|
122
124
|
|
|
123
125
|
// Tally the new results.
|
|
124
|
-
var computedCalculateTotalResult[
|
|
125
|
-
for (var i = 0; i <
|
|
126
|
+
var computedCalculateTotalResult[totalVoteOptions];
|
|
127
|
+
for (var i = 0; i < totalVoteOptions; i++) {
|
|
126
128
|
var numsRC[batchSize + 1];
|
|
127
129
|
numsRC[batchSize] = currentResults[i] * computedIsZero;
|
|
128
130
|
for (var j = 0; j < batchSize; j++) {
|
|
@@ -133,20 +135,20 @@ template TallyVotes(
|
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
// Tally the new spent voice credit total.
|
|
136
|
-
var numsSVC[batchSize *
|
|
137
|
-
numsSVC[batchSize *
|
|
138
|
+
var numsSVC[batchSize * totalVoteOptions + 1];
|
|
139
|
+
numsSVC[batchSize * totalVoteOptions] = currentSpentVoiceCreditSubtotal * computedIsZero;
|
|
138
140
|
for (var i = 0; i < batchSize; i++) {
|
|
139
|
-
for (var j = 0; j <
|
|
140
|
-
numsSVC[i *
|
|
141
|
+
for (var j = 0; j < totalVoteOptions; j++) {
|
|
142
|
+
numsSVC[i * totalVoteOptions + j] = votes[i][j] * votes[i][j];
|
|
141
143
|
}
|
|
142
144
|
}
|
|
143
145
|
|
|
144
|
-
var computedNewSpentVoiceCreditSubtotal = CalculateTotal(batchSize *
|
|
146
|
+
var computedNewSpentVoiceCreditSubtotal = CalculateTotal(batchSize * totalVoteOptions + 1)(numsSVC);
|
|
145
147
|
|
|
146
148
|
// Tally the spent voice credits per vote option.
|
|
147
|
-
var computedNewPerVOSpentVoiceCredits[
|
|
149
|
+
var computedNewPerVOSpentVoiceCredits[totalVoteOptions];
|
|
148
150
|
|
|
149
|
-
for (var i = 0; i <
|
|
151
|
+
for (var i = 0; i < totalVoteOptions; i++) {
|
|
150
152
|
var computedNumsSVC[batchSize + 1];
|
|
151
153
|
computedNumsSVC[batchSize] = currentPerVOSpentVoiceCredits[i] * computedIsZero;
|
|
152
154
|
for (var j = 0; j < batchSize; j++) {
|
|
@@ -185,7 +187,7 @@ template ResultCommitmentVerifier(voteOptionTreeDepth) {
|
|
|
185
187
|
// Number of children per node in the tree, defining the tree's branching factor.
|
|
186
188
|
var TREE_ARITY = 5;
|
|
187
189
|
// Number of voting options available, determined by the depth of the vote option tree.
|
|
188
|
-
var
|
|
190
|
+
var totalVoteOptions = TREE_ARITY ** voteOptionTreeDepth;
|
|
189
191
|
|
|
190
192
|
// Equal to 1 if this is the first batch, otherwise 0.
|
|
191
193
|
signal input isFirstBatch;
|
|
@@ -195,12 +197,12 @@ template ResultCommitmentVerifier(voteOptionTreeDepth) {
|
|
|
195
197
|
signal input newTallyCommitment;
|
|
196
198
|
|
|
197
199
|
// Current results for each vote option.
|
|
198
|
-
signal input currentResults[
|
|
200
|
+
signal input currentResults[totalVoteOptions];
|
|
199
201
|
// Salt for the root of the current results.
|
|
200
202
|
signal input currentResultsRootSalt;
|
|
201
203
|
|
|
202
204
|
// New results for each vote option.
|
|
203
|
-
signal input newResults[
|
|
205
|
+
signal input newResults[totalVoteOptions];
|
|
204
206
|
// Salt for the root of the new results.
|
|
205
207
|
signal input newResultsRootSalt;
|
|
206
208
|
|
|
@@ -215,12 +217,12 @@ template ResultCommitmentVerifier(voteOptionTreeDepth) {
|
|
|
215
217
|
signal input newSpentVoiceCreditSubtotalSalt;
|
|
216
218
|
|
|
217
219
|
// Spent voice credits per vote option.
|
|
218
|
-
signal input currentPerVOSpentVoiceCredits[
|
|
220
|
+
signal input currentPerVOSpentVoiceCredits[totalVoteOptions];
|
|
219
221
|
// Salt for the root of spent credits per option.
|
|
220
222
|
signal input currentPerVOSpentVoiceCreditsRootSalt;
|
|
221
223
|
|
|
222
224
|
// New spent voice credits per vote option.
|
|
223
|
-
signal input newPerVOSpentVoiceCredits[
|
|
225
|
+
signal input newPerVOSpentVoiceCredits[totalVoteOptions];
|
|
224
226
|
// Salt for the root of new spent credits per option.
|
|
225
227
|
signal input newPerVOSpentVoiceCreditsRootSalt;
|
|
226
228
|
|
|
@@ -249,11 +251,11 @@ template ResultCommitmentVerifier(voteOptionTreeDepth) {
|
|
|
249
251
|
// computedIsZero.out is 0 if this is the first batch.
|
|
250
252
|
var computedIsZero = IsZero()(isFirstBatch);
|
|
251
253
|
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
signal
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
// isFirstCommitment is 0 if this is the first batch, currentTallyCommitment should be 0 if this is the first batch.
|
|
255
|
+
// isFirstCommitment is 1 if this is not the first batch, currentTallyCommitment should not be 0 if this is the first batch.
|
|
256
|
+
signal isFirstCommitment;
|
|
257
|
+
isFirstCommitment <== computedIsZero * computedCurrentTallyCommitment;
|
|
258
|
+
isFirstCommitment === currentTallyCommitment;
|
|
257
259
|
|
|
258
260
|
// Compute the root of the new results.
|
|
259
261
|
var computedNewResultsRoot = QuinCheckRoot(voteOptionTreeDepth)(newResults);
|