@maci-protocol/core 0.0.0-ci.669de5c → 0.0.0-ci.67c2573
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/MaciState.d.ts +4 -4
- package/build/ts/MaciState.d.ts.map +1 -1
- package/build/ts/MaciState.js +14 -14
- package/build/ts/MaciState.js.map +1 -1
- package/build/ts/Poll.d.ts +18 -18
- package/build/ts/Poll.d.ts.map +1 -1
- package/build/ts/Poll.js +110 -110
- package/build/ts/Poll.js.map +1 -1
- package/build/ts/index.d.ts +2 -2
- package/build/ts/index.d.ts.map +1 -1
- package/build/ts/index.js +5 -5
- package/build/ts/index.js.map +1 -1
- package/build/ts/utils/types.d.ts +18 -18
- package/build/ts/utils/types.d.ts.map +1 -1
- package/build/ts/utils/utils.d.ts +16 -16
- package/build/ts/utils/utils.d.ts.map +1 -1
- package/build/ts/utils/utils.js +21 -21
- package/build/ts/utils/utils.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
package/build/ts/Poll.js
CHANGED
|
@@ -29,7 +29,7 @@ class Poll {
|
|
|
29
29
|
this.commands = [];
|
|
30
30
|
this.encryptionPublicKeys = [];
|
|
31
31
|
this.stateCopied = false;
|
|
32
|
-
this.
|
|
32
|
+
this.publicKeys = [domainobjs_1.padKey];
|
|
33
33
|
// For message processing
|
|
34
34
|
this.numBatchesProcessed = 0;
|
|
35
35
|
this.sbSalts = {};
|
|
@@ -38,7 +38,7 @@ class Poll {
|
|
|
38
38
|
this.spentVoiceCreditSubtotalSalts = {};
|
|
39
39
|
// For vote tallying
|
|
40
40
|
this.tallyResult = [];
|
|
41
|
-
this.
|
|
41
|
+
this.perVoteOptionSpentVoiceCredits = [];
|
|
42
42
|
this.numBatchesTallied = 0;
|
|
43
43
|
this.totalSpentVoiceCredits = 0n;
|
|
44
44
|
// message chain hash
|
|
@@ -48,7 +48,7 @@ class Poll {
|
|
|
48
48
|
// Poll state tree leaves
|
|
49
49
|
this.pollStateLeaves = [domainobjs_1.blankStateLeaf];
|
|
50
50
|
// how many users signed up
|
|
51
|
-
this.
|
|
51
|
+
this.totalSignups = 0n;
|
|
52
52
|
/**
|
|
53
53
|
* Check if user has already joined the poll by checking if the nullifier is registered
|
|
54
54
|
*/
|
|
@@ -74,11 +74,11 @@ class Poll {
|
|
|
74
74
|
* Update a Poll with data from MaciState.
|
|
75
75
|
* This is the step where we copy the state from the MaciState instance,
|
|
76
76
|
* and set the number of signups we have so far.
|
|
77
|
-
* @note It should be called to generate the state for poll joining with
|
|
78
|
-
* the number of signups in the MaciState. For message processing, you should set
|
|
77
|
+
* @note It should be called to generate the state for poll joining with totalSignups set as
|
|
78
|
+
* the number of signups in the MaciState. For message processing, you should set totalSignups as
|
|
79
79
|
* the number of users who joined the poll.
|
|
80
80
|
*/
|
|
81
|
-
this.updatePoll = (
|
|
81
|
+
this.updatePoll = (totalSignups) => {
|
|
82
82
|
// there might be occasions where we fetch logs after new signups have been made
|
|
83
83
|
// logs are fetched (and MaciState/Poll created locally).
|
|
84
84
|
// If someone signs up after that and we fetch that record
|
|
@@ -86,14 +86,14 @@ class Poll {
|
|
|
86
86
|
// not match. For this, we must only copy up to the number of signups
|
|
87
87
|
// Copy the state tree, ballot tree, state leaves, and ballot leaves
|
|
88
88
|
// start by setting the number of signups
|
|
89
|
-
this.
|
|
90
|
-
// copy up to
|
|
91
|
-
this.
|
|
89
|
+
this.setTotalSignups(totalSignups);
|
|
90
|
+
// copy up to totalSignups state leaves
|
|
91
|
+
this.publicKeys = this.maciStateRef.publicKeys.slice(0, Number(this.totalSignups)).map((x) => x.copy());
|
|
92
92
|
// ensure we have the correct actual state tree depth value
|
|
93
|
-
this.actualStateTreeDepth = Math.max(1, Math.ceil(Math.log2(Number(this.
|
|
93
|
+
this.actualStateTreeDepth = Math.max(1, Math.ceil(Math.log2(Number(this.totalSignups))));
|
|
94
94
|
this.stateTree = new lean_imt_1.LeanIMT(crypto_1.hashLeanIMT);
|
|
95
95
|
// add all leaves
|
|
96
|
-
this.
|
|
96
|
+
this.publicKeys.forEach((publicKey) => {
|
|
97
97
|
this.stateTree?.insert(publicKey.hash());
|
|
98
98
|
});
|
|
99
99
|
// create a poll state tree
|
|
@@ -106,7 +106,7 @@ class Poll {
|
|
|
106
106
|
this.ballotTree = new crypto_1.IncrementalQuinTree(Number(this.treeDepths.stateTreeDepth), this.emptyBallotHash, constants_1.STATE_TREE_ARITY, crypto_1.hash2);
|
|
107
107
|
this.ballotTree.insert(this.emptyBallotHash);
|
|
108
108
|
// we fill the ballotTree with empty ballots hashes to match the number of signups in the tree
|
|
109
|
-
while (this.ballots.length < this.
|
|
109
|
+
while (this.ballots.length < this.publicKeys.length) {
|
|
110
110
|
this.ballotTree.insert(this.emptyBallotHash);
|
|
111
111
|
this.ballots.push(this.emptyBallot);
|
|
112
112
|
}
|
|
@@ -121,8 +121,8 @@ class Poll {
|
|
|
121
121
|
this.processMessage = (message, encryptionPublicKey, qv = true) => {
|
|
122
122
|
try {
|
|
123
123
|
// Decrypt the message
|
|
124
|
-
const sharedKey = domainobjs_1.Keypair.
|
|
125
|
-
const { command, signature } = domainobjs_1.
|
|
124
|
+
const sharedKey = domainobjs_1.Keypair.generateEcdhSharedKey(this.coordinatorKeypair.privateKey, encryptionPublicKey);
|
|
125
|
+
const { command, signature } = domainobjs_1.VoteCommand.decrypt(message, sharedKey);
|
|
126
126
|
const stateLeafIndex = command.stateIndex;
|
|
127
127
|
// If the state tree index in the command is invalid, do nothing
|
|
128
128
|
if (stateLeafIndex >= BigInt(this.ballots.length) ||
|
|
@@ -180,17 +180,17 @@ class Poll {
|
|
|
180
180
|
// calculate the path elements for the state tree given the original state tree (before any changes)
|
|
181
181
|
// changes could effectively be made by this new vote - either a key change or vote change
|
|
182
182
|
// would result in a different state leaf
|
|
183
|
-
const originalStateLeafPathElements = this.pollStateTree
|
|
183
|
+
const { pathElements: originalStateLeafPathElements } = this.pollStateTree.genProof(Number(stateLeafIndex));
|
|
184
184
|
// calculate the path elements for the ballot tree given the original ballot tree (before any changes)
|
|
185
185
|
// changes could effectively be made by this new ballot
|
|
186
|
-
const originalBallotPathElements = this.ballotTree
|
|
186
|
+
const { pathElements: originalBallotPathElements } = this.ballotTree.genProof(Number(stateLeafIndex));
|
|
187
187
|
// create a new quinary tree where we insert the votes of the origin (up until this message is processed) ballot
|
|
188
|
-
const
|
|
188
|
+
const voteTree = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
|
|
189
189
|
for (let i = 0; i < this.ballots[0].votes.length; i += 1) {
|
|
190
|
-
|
|
190
|
+
voteTree.insert(ballot.votes[i]);
|
|
191
191
|
}
|
|
192
192
|
// calculate the path elements for the vote option tree given the original vote option tree (before any changes)
|
|
193
|
-
const originalVoteWeightsPathElements =
|
|
193
|
+
const { pathElements: originalVoteWeightsPathElements } = voteTree.genProof(voteOptionIndex);
|
|
194
194
|
// we return the data which is then to be used in the processMessage circuit
|
|
195
195
|
// to generate a proof of processing
|
|
196
196
|
return {
|
|
@@ -222,11 +222,11 @@ class Poll {
|
|
|
222
222
|
* @param encryptionPublicKey - The public key used to encrypt the message
|
|
223
223
|
*/
|
|
224
224
|
this.publishMessage = (message, encryptionPublicKey) => {
|
|
225
|
-
(0, assert_1.default)(encryptionPublicKey.
|
|
225
|
+
(0, assert_1.default)(encryptionPublicKey.raw[0] < crypto_1.SNARK_FIELD_SIZE && encryptionPublicKey.raw[1] < crypto_1.SNARK_FIELD_SIZE, "The public key is not in the correct range");
|
|
226
226
|
message.data.forEach((d) => {
|
|
227
227
|
(0, assert_1.default)(d < crypto_1.SNARK_FIELD_SIZE, "The message data is not in the correct range");
|
|
228
228
|
});
|
|
229
|
-
// store the encryption
|
|
229
|
+
// store the encryption public key
|
|
230
230
|
this.encryptionPublicKeys.push(encryptionPublicKey);
|
|
231
231
|
// store the message locally
|
|
232
232
|
this.messages.push(message);
|
|
@@ -236,17 +236,17 @@ class Poll {
|
|
|
236
236
|
this.updateChainHash(messageHash);
|
|
237
237
|
// Decrypt the message and store the Command
|
|
238
238
|
// step 1. we generate the shared key
|
|
239
|
-
const sharedKey = domainobjs_1.Keypair.
|
|
239
|
+
const sharedKey = domainobjs_1.Keypair.generateEcdhSharedKey(this.coordinatorKeypair.privateKey, encryptionPublicKey);
|
|
240
240
|
try {
|
|
241
241
|
// step 2. we decrypt it
|
|
242
|
-
const { command } = domainobjs_1.
|
|
242
|
+
const { command } = domainobjs_1.VoteCommand.decrypt(message, sharedKey);
|
|
243
243
|
// step 3. we store it in the commands array
|
|
244
244
|
this.commands.push(command);
|
|
245
245
|
}
|
|
246
246
|
catch (e) {
|
|
247
247
|
// if there is an error we store an empty command
|
|
248
|
-
const
|
|
249
|
-
const command = new domainobjs_1.
|
|
248
|
+
const keypair = new domainobjs_1.Keypair();
|
|
249
|
+
const command = new domainobjs_1.VoteCommand(0n, keypair.publicKey, 0n, 0n, 0n, 0n, 0n);
|
|
250
250
|
this.commands.push(command);
|
|
251
251
|
}
|
|
252
252
|
};
|
|
@@ -386,7 +386,7 @@ class Poll {
|
|
|
386
386
|
throw new Error("You must update the poll with the correct data first");
|
|
387
387
|
}
|
|
388
388
|
// Generate circuit inputs
|
|
389
|
-
const circuitInputs = (0, crypto_1.stringifyBigInts)(this.
|
|
389
|
+
const circuitInputs = (0, crypto_1.stringifyBigInts)(this.generateProcessMessagesCircuitInputsPartial(this.currentMessageBatchIndex));
|
|
390
390
|
// we want to store the state leaves at this point in time
|
|
391
391
|
// and the path elements of the state tree
|
|
392
392
|
const currentStateLeaves = [];
|
|
@@ -411,23 +411,23 @@ class Poll {
|
|
|
411
411
|
encryptionPublicKey = this.encryptionPublicKeys[idx];
|
|
412
412
|
try {
|
|
413
413
|
// check if the command is valid
|
|
414
|
-
const
|
|
415
|
-
const index =
|
|
414
|
+
const { stateLeafIndex, originalStateLeaf, originalBallot, originalVoteWeight, originalVoteWeightsPathElements, originalStateLeafPathElements, originalBallotPathElements, newStateLeaf, newBallot, } = this.processMessage(message, encryptionPublicKey, qv);
|
|
415
|
+
const index = stateLeafIndex;
|
|
416
416
|
// we add at position 0 the original data
|
|
417
|
-
currentStateLeaves.unshift(
|
|
418
|
-
currentBallots.unshift(
|
|
419
|
-
currentVoteWeights.unshift(
|
|
420
|
-
currentVoteWeightsPathElements.unshift(
|
|
421
|
-
currentStateLeavesPathElements.unshift(
|
|
422
|
-
currentBallotsPathElements.unshift(
|
|
417
|
+
currentStateLeaves.unshift(originalStateLeaf);
|
|
418
|
+
currentBallots.unshift(originalBallot);
|
|
419
|
+
currentVoteWeights.unshift(originalVoteWeight);
|
|
420
|
+
currentVoteWeightsPathElements.unshift(originalVoteWeightsPathElements);
|
|
421
|
+
currentStateLeavesPathElements.unshift(originalStateLeafPathElements);
|
|
422
|
+
currentBallotsPathElements.unshift(originalBallotPathElements);
|
|
423
423
|
// update the state leaves with the new state leaf (result of processing the message)
|
|
424
|
-
this.pollStateLeaves[index] =
|
|
424
|
+
this.pollStateLeaves[index] = newStateLeaf.copy();
|
|
425
425
|
// we also update the state tree with the hash of the new state leaf
|
|
426
|
-
this.pollStateTree?.update(index,
|
|
426
|
+
this.pollStateTree?.update(index, newStateLeaf.hash());
|
|
427
427
|
// store the new ballot
|
|
428
|
-
this.ballots[index] =
|
|
428
|
+
this.ballots[index] = newBallot;
|
|
429
429
|
// update the ballot tree
|
|
430
|
-
this.ballotTree?.update(index,
|
|
430
|
+
this.ballotTree?.update(index, newBallot.hash());
|
|
431
431
|
}
|
|
432
432
|
catch (e) {
|
|
433
433
|
// if the error is not a ProcessMessageError we throw it and exit here
|
|
@@ -446,10 +446,10 @@ class Poll {
|
|
|
446
446
|
// which sends a message that when force decrypted on the circuit
|
|
447
447
|
// results in a valid state index thus forcing the circuit to look
|
|
448
448
|
// for a valid state leaf, and failing to generate a proof
|
|
449
|
-
//
|
|
450
|
-
const sharedKey = domainobjs_1.Keypair.
|
|
449
|
+
// generate shared key
|
|
450
|
+
const sharedKey = domainobjs_1.Keypair.generateEcdhSharedKey(this.coordinatorKeypair.privateKey, encryptionPublicKey);
|
|
451
451
|
// force decrypt it
|
|
452
|
-
const { command } = domainobjs_1.
|
|
452
|
+
const { command } = domainobjs_1.VoteCommand.decrypt(message, sharedKey, true);
|
|
453
453
|
// cache state leaf index
|
|
454
454
|
const stateLeafIndex = command.stateIndex;
|
|
455
455
|
// if the state leaf index is valid then use it
|
|
@@ -467,24 +467,24 @@ class Poll {
|
|
|
467
467
|
if (command.voteOptionIndex < this.voteOptions) {
|
|
468
468
|
currentVoteWeights.unshift(ballot.votes[Number(command.voteOptionIndex)]);
|
|
469
469
|
// create a new quinary tree and add all votes we have so far
|
|
470
|
-
const
|
|
470
|
+
const voteTree = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
|
|
471
471
|
// fill the vote option tree with the votes we have so far
|
|
472
472
|
for (let j = 0; j < this.ballots[0].votes.length; j += 1) {
|
|
473
|
-
|
|
473
|
+
voteTree.insert(ballot.votes[j]);
|
|
474
474
|
}
|
|
475
475
|
// get the path elements for the first vote leaf
|
|
476
|
-
currentVoteWeightsPathElements.unshift(
|
|
476
|
+
currentVoteWeightsPathElements.unshift(voteTree.genProof(Number(command.voteOptionIndex)).pathElements);
|
|
477
477
|
}
|
|
478
478
|
else {
|
|
479
479
|
currentVoteWeights.unshift(ballot.votes[0]);
|
|
480
480
|
// create a new quinary tree and add all votes we have so far
|
|
481
|
-
const
|
|
481
|
+
const voteTree = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
|
|
482
482
|
// fill the vote option tree with the votes we have so far
|
|
483
483
|
for (let j = 0; j < this.ballots[0].votes.length; j += 1) {
|
|
484
|
-
|
|
484
|
+
voteTree.insert(ballot.votes[j]);
|
|
485
485
|
}
|
|
486
486
|
// get the path elements for the first vote leaf
|
|
487
|
-
currentVoteWeightsPathElements.unshift(
|
|
487
|
+
currentVoteWeightsPathElements.unshift(voteTree.genProof(0).pathElements);
|
|
488
488
|
}
|
|
489
489
|
}
|
|
490
490
|
else {
|
|
@@ -496,10 +496,10 @@ class Poll {
|
|
|
496
496
|
// Since the command is invalid, we use a zero vote weight
|
|
497
497
|
currentVoteWeights.unshift(this.ballots[0].votes[0]);
|
|
498
498
|
// create a new quinary tree and add an empty vote
|
|
499
|
-
const
|
|
500
|
-
|
|
499
|
+
const voteTree = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
|
|
500
|
+
voteTree.insert(this.ballots[0].votes[0]);
|
|
501
501
|
// get the path elements for this empty vote weight leaf
|
|
502
|
-
currentVoteWeightsPathElements.unshift(
|
|
502
|
+
currentVoteWeightsPathElements.unshift(voteTree.genProof(0).pathElements);
|
|
503
503
|
}
|
|
504
504
|
}
|
|
505
505
|
else {
|
|
@@ -517,10 +517,10 @@ class Poll {
|
|
|
517
517
|
// Since the command is invalid, we use a zero vote weight
|
|
518
518
|
currentVoteWeights.unshift(this.ballots[0].votes[0]);
|
|
519
519
|
// create a new quinary tree and add an empty vote
|
|
520
|
-
const
|
|
521
|
-
|
|
520
|
+
const voteTree = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
|
|
521
|
+
voteTree.insert(this.ballots[0].votes[0]);
|
|
522
522
|
// get the path elements for this empty vote weight leaf
|
|
523
|
-
currentVoteWeightsPathElements.unshift(
|
|
523
|
+
currentVoteWeightsPathElements.unshift(voteTree.genProof(0).pathElements);
|
|
524
524
|
}
|
|
525
525
|
}
|
|
526
526
|
// store the data in the circuit inputs object
|
|
@@ -543,9 +543,9 @@ class Poll {
|
|
|
543
543
|
this.currentMessageBatchIndex -= 1;
|
|
544
544
|
}
|
|
545
545
|
// ensure newSbSalt differs from currentSbSalt
|
|
546
|
-
let newSbSalt = (0, crypto_1.
|
|
546
|
+
let newSbSalt = (0, crypto_1.generateRandomSalt)();
|
|
547
547
|
while (this.sbSalts[this.currentMessageBatchIndex] === newSbSalt) {
|
|
548
|
-
newSbSalt = (0, crypto_1.
|
|
548
|
+
newSbSalt = (0, crypto_1.generateRandomSalt)();
|
|
549
549
|
}
|
|
550
550
|
this.sbSalts[this.currentMessageBatchIndex] = newSbSalt;
|
|
551
551
|
// store the salt in the circuit inputs
|
|
@@ -572,7 +572,7 @@ class Poll {
|
|
|
572
572
|
* @param index - The index of the partial batch.
|
|
573
573
|
* @returns stringified partial circuit inputs
|
|
574
574
|
*/
|
|
575
|
-
this.
|
|
575
|
+
this.generateProcessMessagesCircuitInputsPartial = (index) => {
|
|
576
576
|
const { messageBatchSize } = this.batchSizes;
|
|
577
577
|
(0, assert_1.default)(index <= this.messages.length, "The index must be <= the number of messages");
|
|
578
578
|
// fill the messages array with a copy of the messages we have
|
|
@@ -582,17 +582,17 @@ class Poll {
|
|
|
582
582
|
// and no effect will take place
|
|
583
583
|
// create a random key
|
|
584
584
|
const key = new domainobjs_1.Keypair();
|
|
585
|
-
//
|
|
586
|
-
const ecdh = domainobjs_1.Keypair.
|
|
585
|
+
// generate ecdh key
|
|
586
|
+
const ecdh = domainobjs_1.Keypair.generateEcdhSharedKey(key.privateKey, this.coordinatorKeypair.publicKey);
|
|
587
587
|
// create an empty command with state index 0n
|
|
588
|
-
const emptyCommand = new domainobjs_1.
|
|
588
|
+
const emptyCommand = new domainobjs_1.VoteCommand(0n, key.publicKey, 0n, 0n, 0n, 0n, 0n);
|
|
589
589
|
// encrypt it
|
|
590
|
-
const
|
|
590
|
+
const emptyMessage = emptyCommand.encrypt(emptyCommand.sign(key.privateKey), ecdh);
|
|
591
591
|
// copy the messages to a new array
|
|
592
592
|
let messages = this.messages.map((x) => x.asCircuitInputs());
|
|
593
593
|
// pad with our state index 0 message
|
|
594
594
|
while (messages.length % messageBatchSize > 0) {
|
|
595
|
-
messages.push(
|
|
595
|
+
messages.push(emptyMessage.asCircuitInputs());
|
|
596
596
|
}
|
|
597
597
|
// copy the public keys, pad the array with the last keys if needed
|
|
598
598
|
let encryptionPublicKeys = this.encryptionPublicKeys.map((x) => x.copy());
|
|
@@ -623,7 +623,7 @@ class Poll {
|
|
|
623
623
|
const inputBatchHash = this.batchHashes[index - 1];
|
|
624
624
|
const outputBatchHash = this.batchHashes[index];
|
|
625
625
|
return (0, crypto_1.stringifyBigInts)({
|
|
626
|
-
|
|
626
|
+
totalSignups: BigInt(this.totalSignups),
|
|
627
627
|
batchEndIndex: BigInt(batchEndIndex),
|
|
628
628
|
index: BigInt(batchStartIndex),
|
|
629
629
|
inputBatchHash,
|
|
@@ -674,12 +674,12 @@ class Poll {
|
|
|
674
674
|
const batchStartIndex = this.numBatchesTallied * batchSize;
|
|
675
675
|
// get the salts needed for the commitments
|
|
676
676
|
const currentResultsRootSalt = batchStartIndex === 0 ? 0n : this.resultRootSalts[batchStartIndex - batchSize];
|
|
677
|
-
const
|
|
677
|
+
const currentPerVoteOptionSpentVoiceCreditsRootSalt = batchStartIndex === 0 ? 0n : this.preVOSpentVoiceCreditsRootSalts[batchStartIndex - batchSize];
|
|
678
678
|
const currentSpentVoiceCreditSubtotalSalt = batchStartIndex === 0 ? 0n : this.spentVoiceCreditSubtotalSalts[batchStartIndex - batchSize];
|
|
679
679
|
// generate a commitment to the current results
|
|
680
|
-
const currentResultsCommitment = (0, crypto_1.
|
|
681
|
-
// generate a commitment to the current per
|
|
682
|
-
const currentPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(
|
|
680
|
+
const currentResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, currentResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
|
|
681
|
+
// generate a commitment to the current per vote option spent voice credits
|
|
682
|
+
const currentPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(currentPerVoteOptionSpentVoiceCreditsRootSalt, batchStartIndex, true);
|
|
683
683
|
// generate a commitment to the current spent voice credits
|
|
684
684
|
const currentSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(currentSpentVoiceCreditSubtotalSalt, batchStartIndex, true);
|
|
685
685
|
// the current commitment for the first batch will be 0
|
|
@@ -698,7 +698,7 @@ class Poll {
|
|
|
698
698
|
]);
|
|
699
699
|
const ballots = [];
|
|
700
700
|
const currentResults = this.tallyResult.map((x) => BigInt(x.toString()));
|
|
701
|
-
const
|
|
701
|
+
const currentPerVoteOptionSpentVoiceCredits = this.perVoteOptionSpentVoiceCredits.map((x) => BigInt(x.toString()));
|
|
702
702
|
const currentSpentVoiceCreditSubtotal = BigInt(this.totalSpentVoiceCredits.toString());
|
|
703
703
|
// loop in normal order to tally the ballots one by one
|
|
704
704
|
for (let i = this.numBatchesTallied * batchSize; i < this.numBatchesTallied * batchSize + batchSize; i += 1) {
|
|
@@ -714,7 +714,7 @@ class Poll {
|
|
|
714
714
|
// the vote itself will be a quadratic vote (sqrt(voiceCredits))
|
|
715
715
|
this.tallyResult[j] += v;
|
|
716
716
|
// the per vote option spent voice credits will be the sum of the squares of the votes
|
|
717
|
-
this.
|
|
717
|
+
this.perVoteOptionSpentVoiceCredits[j] += v * v;
|
|
718
718
|
// the total spent voice credits will be the sum of the squares of the votes
|
|
719
719
|
this.totalSpentVoiceCredits += v * v;
|
|
720
720
|
}
|
|
@@ -725,19 +725,19 @@ class Poll {
|
|
|
725
725
|
ballots.push(emptyBallot);
|
|
726
726
|
}
|
|
727
727
|
// generate the new salts
|
|
728
|
-
const newResultsRootSalt = (0, crypto_1.
|
|
729
|
-
const
|
|
730
|
-
const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.
|
|
728
|
+
const newResultsRootSalt = (0, crypto_1.generateRandomSalt)();
|
|
729
|
+
const newPerVoteOptionSpentVoiceCreditsRootSalt = (0, crypto_1.generateRandomSalt)();
|
|
730
|
+
const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.generateRandomSalt)();
|
|
731
731
|
// and save them to be used in the next batch
|
|
732
732
|
this.resultRootSalts[batchStartIndex] = newResultsRootSalt;
|
|
733
|
-
this.preVOSpentVoiceCreditsRootSalts[batchStartIndex] =
|
|
733
|
+
this.preVOSpentVoiceCreditsRootSalts[batchStartIndex] = newPerVoteOptionSpentVoiceCreditsRootSalt;
|
|
734
734
|
this.spentVoiceCreditSubtotalSalts[batchStartIndex] = newSpentVoiceCreditSubtotalSalt;
|
|
735
735
|
// generate the new results commitment with the new salts and data
|
|
736
|
-
const newResultsCommitment = (0, crypto_1.
|
|
736
|
+
const newResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, newResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
|
|
737
737
|
// generate the new spent voice credits commitment with the new salts and data
|
|
738
738
|
const newSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(newSpentVoiceCreditSubtotalSalt, batchStartIndex + batchSize, true);
|
|
739
|
-
// generate the new per
|
|
740
|
-
const newPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(
|
|
739
|
+
// generate the new per vote option spent voice credits commitment with the new salts and data
|
|
740
|
+
const newPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(newPerVoteOptionSpentVoiceCreditsRootSalt, batchStartIndex + batchSize, true);
|
|
741
741
|
// generate the new tally commitment
|
|
742
742
|
const newTallyCommitment = (0, crypto_1.hash3)([
|
|
743
743
|
newResultsCommitment,
|
|
@@ -756,7 +756,7 @@ class Poll {
|
|
|
756
756
|
ballotRoot,
|
|
757
757
|
sbSalt,
|
|
758
758
|
index: BigInt(batchStartIndex),
|
|
759
|
-
|
|
759
|
+
totalSignups: BigInt(this.totalSignups),
|
|
760
760
|
sbCommitment,
|
|
761
761
|
currentTallyCommitment,
|
|
762
762
|
newTallyCommitment,
|
|
@@ -767,10 +767,10 @@ class Poll {
|
|
|
767
767
|
currentResultsRootSalt,
|
|
768
768
|
currentSpentVoiceCreditSubtotal,
|
|
769
769
|
currentSpentVoiceCreditSubtotalSalt,
|
|
770
|
-
|
|
771
|
-
|
|
770
|
+
currentPerVoteOptionSpentVoiceCredits,
|
|
771
|
+
currentPerVoteOptionSpentVoiceCreditsRootSalt,
|
|
772
772
|
newResultsRootSalt,
|
|
773
|
-
|
|
773
|
+
newPerVoteOptionSpentVoiceCreditsRootSalt,
|
|
774
774
|
newSpentVoiceCreditSubtotalSalt,
|
|
775
775
|
});
|
|
776
776
|
this.numBatchesTallied += 1;
|
|
@@ -789,7 +789,7 @@ class Poll {
|
|
|
789
789
|
const currentResultsRootSalt = batchStartIndex === 0 ? 0n : this.resultRootSalts[batchStartIndex - batchSize];
|
|
790
790
|
const currentSpentVoiceCreditSubtotalSalt = batchStartIndex === 0 ? 0n : this.spentVoiceCreditSubtotalSalts[batchStartIndex - batchSize];
|
|
791
791
|
// generate a commitment to the current results
|
|
792
|
-
const currentResultsCommitment = (0, crypto_1.
|
|
792
|
+
const currentResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, currentResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
|
|
793
793
|
// generate a commitment to the current spent voice credits
|
|
794
794
|
const currentSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(currentSpentVoiceCreditSubtotalSalt, batchStartIndex, false);
|
|
795
795
|
// the current commitment for the first batch will be 0
|
|
@@ -824,13 +824,13 @@ class Poll {
|
|
|
824
824
|
ballots.push(emptyBallot);
|
|
825
825
|
}
|
|
826
826
|
// generate the new salts
|
|
827
|
-
const newResultsRootSalt = (0, crypto_1.
|
|
828
|
-
const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.
|
|
827
|
+
const newResultsRootSalt = (0, crypto_1.generateRandomSalt)();
|
|
828
|
+
const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.generateRandomSalt)();
|
|
829
829
|
// and save them to be used in the next batch
|
|
830
830
|
this.resultRootSalts[batchStartIndex] = newResultsRootSalt;
|
|
831
831
|
this.spentVoiceCreditSubtotalSalts[batchStartIndex] = newSpentVoiceCreditSubtotalSalt;
|
|
832
832
|
// generate the new results commitment with the new salts and data
|
|
833
|
-
const newResultsCommitment = (0, crypto_1.
|
|
833
|
+
const newResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, newResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
|
|
834
834
|
// generate the new spent voice credits commitment with the new salts and data
|
|
835
835
|
const newSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(newSpentVoiceCreditSubtotalSalt, batchStartIndex + batchSize, false);
|
|
836
836
|
// generate the new tally commitment
|
|
@@ -847,7 +847,7 @@ class Poll {
|
|
|
847
847
|
ballotRoot,
|
|
848
848
|
sbSalt,
|
|
849
849
|
index: BigInt(batchStartIndex),
|
|
850
|
-
|
|
850
|
+
totalSignups: BigInt(this.totalSignups),
|
|
851
851
|
sbCommitment,
|
|
852
852
|
currentTallyCommitment,
|
|
853
853
|
newTallyCommitment,
|
|
@@ -907,7 +907,7 @@ class Poll {
|
|
|
907
907
|
leaves[j] += useQuadraticVoting ? v * v : v;
|
|
908
908
|
}
|
|
909
909
|
}
|
|
910
|
-
return (0, crypto_1.
|
|
910
|
+
return (0, crypto_1.generateTreeCommitment)(leaves, salt, this.treeDepths.voteOptionTreeDepth);
|
|
911
911
|
};
|
|
912
912
|
/**
|
|
913
913
|
* Create a deep copy of the Poll object.
|
|
@@ -922,7 +922,7 @@ class Poll {
|
|
|
922
922
|
tallyBatchSize: Number(this.batchSizes.tallyBatchSize.toString()),
|
|
923
923
|
messageBatchSize: Number(this.batchSizes.messageBatchSize.toString()),
|
|
924
924
|
}, this.maciStateRef, this.voteOptions);
|
|
925
|
-
copied.
|
|
925
|
+
copied.publicKeys = this.publicKeys.map((x) => x.copy());
|
|
926
926
|
copied.pollStateLeaves = this.pollStateLeaves.map((x) => x.copy());
|
|
927
927
|
copied.messages = this.messages.map((x) => x.copy());
|
|
928
928
|
copied.commands = this.commands.map((x) => x.copy());
|
|
@@ -934,7 +934,7 @@ class Poll {
|
|
|
934
934
|
copied.currentMessageBatchIndex = this.currentMessageBatchIndex;
|
|
935
935
|
copied.maciStateRef = this.maciStateRef;
|
|
936
936
|
copied.tallyResult = this.tallyResult.map((x) => BigInt(x.toString()));
|
|
937
|
-
copied.
|
|
937
|
+
copied.perVoteOptionSpentVoiceCredits = this.perVoteOptionSpentVoiceCredits.map((x) => BigInt(x.toString()));
|
|
938
938
|
copied.numBatchesProcessed = Number(this.numBatchesProcessed.toString());
|
|
939
939
|
copied.numBatchesTallied = Number(this.numBatchesTallied.toString());
|
|
940
940
|
copied.pollId = this.pollId;
|
|
@@ -956,34 +956,34 @@ class Poll {
|
|
|
956
956
|
copied.spentVoiceCreditSubtotalSalts[k] = BigInt(this.spentVoiceCreditSubtotalSalts[k].toString());
|
|
957
957
|
});
|
|
958
958
|
// update the number of signups
|
|
959
|
-
copied.
|
|
959
|
+
copied.setTotalSignups(this.totalSignups);
|
|
960
960
|
return copied;
|
|
961
961
|
};
|
|
962
962
|
/**
|
|
963
963
|
* Check if the Poll object is equal to another Poll object.
|
|
964
|
-
* @param
|
|
964
|
+
* @param poll - The Poll object to compare.
|
|
965
965
|
* @returns True if the two Poll objects are equal, false otherwise.
|
|
966
966
|
*/
|
|
967
|
-
this.equals = (
|
|
968
|
-
const result = this.coordinatorKeypair.equals(
|
|
969
|
-
this.treeDepths.intStateTreeDepth ===
|
|
970
|
-
this.treeDepths.voteOptionTreeDepth ===
|
|
971
|
-
this.batchSizes.tallyBatchSize ===
|
|
972
|
-
this.batchSizes.messageBatchSize ===
|
|
973
|
-
this.maxVoteOptions ===
|
|
974
|
-
this.messages.length ===
|
|
975
|
-
this.encryptionPublicKeys.length ===
|
|
976
|
-
this.
|
|
967
|
+
this.equals = (poll) => {
|
|
968
|
+
const result = this.coordinatorKeypair.equals(poll.coordinatorKeypair) &&
|
|
969
|
+
this.treeDepths.intStateTreeDepth === poll.treeDepths.intStateTreeDepth &&
|
|
970
|
+
this.treeDepths.voteOptionTreeDepth === poll.treeDepths.voteOptionTreeDepth &&
|
|
971
|
+
this.batchSizes.tallyBatchSize === poll.batchSizes.tallyBatchSize &&
|
|
972
|
+
this.batchSizes.messageBatchSize === poll.batchSizes.messageBatchSize &&
|
|
973
|
+
this.maxVoteOptions === poll.maxVoteOptions &&
|
|
974
|
+
this.messages.length === poll.messages.length &&
|
|
975
|
+
this.encryptionPublicKeys.length === poll.encryptionPublicKeys.length &&
|
|
976
|
+
this.totalSignups === poll.totalSignups;
|
|
977
977
|
if (!result) {
|
|
978
978
|
return false;
|
|
979
979
|
}
|
|
980
980
|
for (let i = 0; i < this.messages.length; i += 1) {
|
|
981
|
-
if (!this.messages[i].equals(
|
|
981
|
+
if (!this.messages[i].equals(poll.messages[i])) {
|
|
982
982
|
return false;
|
|
983
983
|
}
|
|
984
984
|
}
|
|
985
985
|
for (let i = 0; i < this.encryptionPublicKeys.length; i += 1) {
|
|
986
|
-
if (!this.encryptionPublicKeys[i].equals(
|
|
986
|
+
if (!this.encryptionPublicKeys[i].equals(poll.encryptionPublicKeys[i])) {
|
|
987
987
|
return false;
|
|
988
988
|
}
|
|
989
989
|
}
|
|
@@ -998,16 +998,16 @@ class Poll {
|
|
|
998
998
|
};
|
|
999
999
|
/**
|
|
1000
1000
|
* Set the number of signups to match the ones from the contract
|
|
1001
|
-
* @param
|
|
1001
|
+
* @param totalSignups - the number of signups
|
|
1002
1002
|
*/
|
|
1003
|
-
this.
|
|
1004
|
-
this.
|
|
1003
|
+
this.setTotalSignups = (totalSignups) => {
|
|
1004
|
+
this.totalSignups = totalSignups;
|
|
1005
1005
|
};
|
|
1006
1006
|
/**
|
|
1007
1007
|
* Get the number of signups
|
|
1008
1008
|
* @returns The number of signups
|
|
1009
1009
|
*/
|
|
1010
|
-
this.
|
|
1010
|
+
this.gettotalSignups = () => this.totalSignups;
|
|
1011
1011
|
this.pollEndTimestamp = pollEndTimestamp;
|
|
1012
1012
|
this.coordinatorKeypair = coordinatorKeypair;
|
|
1013
1013
|
this.treeDepths = treeDepths;
|
|
@@ -1023,7 +1023,7 @@ class Poll {
|
|
|
1023
1023
|
this.currentMessageBatchIndex = 0;
|
|
1024
1024
|
this.pollNullifiers = new Map();
|
|
1025
1025
|
this.tallyResult = new Array(this.maxVoteOptions).fill(0n);
|
|
1026
|
-
this.
|
|
1026
|
+
this.perVoteOptionSpentVoiceCredits = new Array(this.maxVoteOptions).fill(0n);
|
|
1027
1027
|
// we put a blank state leaf to prevent a DoS attack
|
|
1028
1028
|
this.emptyBallot = domainobjs_1.Ballot.genBlankBallot(this.maxVoteOptions, treeDepths.voteOptionTreeDepth);
|
|
1029
1029
|
this.ballots.push(this.emptyBallot);
|
|
@@ -1045,11 +1045,11 @@ class Poll {
|
|
|
1045
1045
|
ballots: this.ballots.map((ballot) => ballot.toJSON()),
|
|
1046
1046
|
encryptionPublicKeys: this.encryptionPublicKeys.map((encryptionPublicKey) => encryptionPublicKey.serialize()),
|
|
1047
1047
|
currentMessageBatchIndex: this.currentMessageBatchIndex,
|
|
1048
|
-
|
|
1048
|
+
publicKeys: this.publicKeys.map((leaf) => leaf.toJSON()),
|
|
1049
1049
|
pollStateLeaves: this.pollStateLeaves.map((leaf) => leaf.toJSON()),
|
|
1050
1050
|
results: this.tallyResult.map((result) => result.toString()),
|
|
1051
1051
|
numBatchesProcessed: this.numBatchesProcessed,
|
|
1052
|
-
|
|
1052
|
+
totalSignups: this.totalSignups.toString(),
|
|
1053
1053
|
chainHash: this.chainHash.toString(),
|
|
1054
1054
|
pollNullifiers: [...this.pollNullifiers.keys()].map((nullifier) => nullifier.toString()),
|
|
1055
1055
|
batchHashes: this.batchHashes.map((batchHash) => batchHash.toString()),
|
|
@@ -1068,7 +1068,7 @@ class Poll {
|
|
|
1068
1068
|
poll.ballots = json.ballots.map((ballot) => domainobjs_1.Ballot.fromJSON(ballot));
|
|
1069
1069
|
poll.encryptionPublicKeys = json.encryptionPublicKeys.map((key) => domainobjs_1.PublicKey.deserialize(key));
|
|
1070
1070
|
poll.messages = json.messages.map((message) => domainobjs_1.Message.fromJSON(message));
|
|
1071
|
-
poll.commands = json.commands.map((command) => domainobjs_1.
|
|
1071
|
+
poll.commands = json.commands.map((command) => domainobjs_1.VoteCommand.fromJSON(command));
|
|
1072
1072
|
poll.tallyResult = json.results.map((result) => BigInt(result));
|
|
1073
1073
|
poll.currentMessageBatchIndex = json.currentMessageBatchIndex;
|
|
1074
1074
|
poll.numBatchesProcessed = json.numBatchesProcessed;
|
|
@@ -1076,7 +1076,7 @@ class Poll {
|
|
|
1076
1076
|
poll.batchHashes = json.batchHashes.map((batchHash) => BigInt(batchHash));
|
|
1077
1077
|
poll.pollNullifiers = new Map(json.pollNullifiers.map((nullifier) => [BigInt(nullifier), true]));
|
|
1078
1078
|
// copy maci state
|
|
1079
|
-
poll.updatePoll(BigInt(json.
|
|
1079
|
+
poll.updatePoll(BigInt(json.totalSignups));
|
|
1080
1080
|
return poll;
|
|
1081
1081
|
}
|
|
1082
1082
|
}
|