@maci-protocol/core 0.0.0-ci.b21eaba → 0.0.0-ci.b4d036c

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/build/ts/Poll.js CHANGED
@@ -7,6 +7,7 @@ exports.Poll = void 0;
7
7
  const crypto_1 = require("@maci-protocol/crypto");
8
8
  const domainobjs_1 = require("@maci-protocol/domainobjs");
9
9
  const lean_imt_1 = require("@zk-kit/lean-imt");
10
+ const omit_1 = __importDefault(require("lodash/omit"));
10
11
  const assert_1 = __importDefault(require("assert"));
11
12
  const constants_1 = require("./utils/constants");
12
13
  const errors_1 = require("./utils/errors");
@@ -23,22 +24,22 @@ class Poll {
23
24
  * @param maciStateRef - The reference to the MACI state.
24
25
  * @param pollId - The poll id
25
26
  */
26
- constructor(pollEndTimestamp, coordinatorKeypair, treeDepths, batchSizes, maciStateRef, voteOptions) {
27
+ constructor(pollEndTimestamp, coordinatorKeypair, treeDepths, batchSizes, maciStateRef, voteOptions, mode) {
27
28
  this.ballots = [];
28
29
  this.messages = [];
29
30
  this.commands = [];
30
- this.encPubKeys = [];
31
+ this.encryptionPublicKeys = [];
31
32
  this.stateCopied = false;
32
- this.pubKeys = [domainobjs_1.padKey];
33
+ this.publicKeys = [domainobjs_1.padKey];
33
34
  // For message processing
34
- this.numBatchesProcessed = 0;
35
+ this.totalBatchesProcessed = 0;
35
36
  this.sbSalts = {};
36
37
  this.resultRootSalts = {};
37
- this.preVOSpentVoiceCreditsRootSalts = {};
38
+ this.perVoteOptionSpentVoiceCreditsRootSalts = {};
38
39
  this.spentVoiceCreditSubtotalSalts = {};
39
40
  // For vote tallying
40
41
  this.tallyResult = [];
41
- this.perVOSpentVoiceCredits = [];
42
+ this.perVoteOptionSpentVoiceCredits = [];
42
43
  this.numBatchesTallied = 0;
43
44
  this.totalSpentVoiceCredits = 0n;
44
45
  // message chain hash
@@ -48,7 +49,7 @@ class Poll {
48
49
  // Poll state tree leaves
49
50
  this.pollStateLeaves = [domainobjs_1.blankStateLeaf];
50
51
  // how many users signed up
51
- this.numSignups = 0n;
52
+ this.totalSignups = 0n;
52
53
  /**
53
54
  * Check if user has already joined the poll by checking if the nullifier is registered
54
55
  */
@@ -56,12 +57,12 @@ class Poll {
56
57
  /**
57
58
  * Join the anonymous user to the Poll (to the tree)
58
59
  * @param nullifier - Hashed private key used as nullifier
59
- * @param pubKey - The poll public key.
60
+ * @param publicKey - The poll public key.
60
61
  * @param newVoiceCreditBalance - New voice credit balance of the user.
61
62
  * @returns The index of added state leaf
62
63
  */
63
- this.joinPoll = (nullifier, pubKey, newVoiceCreditBalance) => {
64
- const stateLeaf = new domainobjs_1.StateLeaf(pubKey, newVoiceCreditBalance);
64
+ this.joinPoll = (nullifier, publicKey, newVoiceCreditBalance) => {
65
+ const stateLeaf = new domainobjs_1.StateLeaf(publicKey, newVoiceCreditBalance);
65
66
  if (this.hasJoined(nullifier)) {
66
67
  throw new Error("UserAlreadyJoined");
67
68
  }
@@ -74,11 +75,11 @@ class Poll {
74
75
  * Update a Poll with data from MaciState.
75
76
  * This is the step where we copy the state from the MaciState instance,
76
77
  * and set the number of signups we have so far.
77
- * @note It should be called to generate the state for poll joining with numSignups set as
78
- * the number of signups in the MaciState. For message processing, you should set numSignups as
78
+ * @note It should be called to generate the state for poll joining with totalSignups set as
79
+ * the number of signups in the MaciState. For message processing, you should set totalSignups as
79
80
  * the number of users who joined the poll.
80
81
  */
81
- this.updatePoll = (numSignups) => {
82
+ this.updatePoll = (totalSignups) => {
82
83
  // there might be occasions where we fetch logs after new signups have been made
83
84
  // logs are fetched (and MaciState/Poll created locally).
84
85
  // If someone signs up after that and we fetch that record
@@ -86,15 +87,15 @@ class Poll {
86
87
  // not match. For this, we must only copy up to the number of signups
87
88
  // Copy the state tree, ballot tree, state leaves, and ballot leaves
88
89
  // start by setting the number of signups
89
- this.setNumSignups(numSignups);
90
- // copy up to numSignups state leaves
91
- this.pubKeys = this.maciStateRef.pubKeys.slice(0, Number(this.numSignups)).map((x) => x.copy());
90
+ this.setTotalSignups(totalSignups);
91
+ // copy up to totalSignups state leaves
92
+ this.publicKeys = this.maciStateRef.publicKeys.slice(0, Number(this.totalSignups)).map((x) => x.copy());
92
93
  // ensure we have the correct actual state tree depth value
93
- this.actualStateTreeDepth = Math.max(1, Math.ceil(Math.log2(Number(this.numSignups))));
94
+ this.actualStateTreeDepth = Math.max(1, Math.ceil(Math.log2(Number(this.totalSignups))));
94
95
  this.stateTree = new lean_imt_1.LeanIMT(crypto_1.hashLeanIMT);
95
96
  // add all leaves
96
- this.pubKeys.forEach((pubKey) => {
97
- this.stateTree?.insert(pubKey.hash());
97
+ this.publicKeys.forEach((publicKey) => {
98
+ this.stateTree?.insert(publicKey.hash());
98
99
  });
99
100
  // create a poll state tree
100
101
  this.pollStateTree = new crypto_1.IncrementalQuinTree(this.actualStateTreeDepth, domainobjs_1.blankStateLeafHash, constants_1.STATE_TREE_ARITY, crypto_1.hash2);
@@ -103,10 +104,10 @@ class Poll {
103
104
  });
104
105
  // Create as many ballots as state leaves
105
106
  this.emptyBallotHash = this.emptyBallot.hash();
106
- this.ballotTree = new crypto_1.IncrementalQuinTree(this.stateTreeDepth, this.emptyBallotHash, constants_1.STATE_TREE_ARITY, crypto_1.hash2);
107
+ this.ballotTree = new crypto_1.IncrementalQuinTree(Number(this.treeDepths.stateTreeDepth), this.emptyBallotHash, constants_1.STATE_TREE_ARITY, crypto_1.hash2);
107
108
  this.ballotTree.insert(this.emptyBallotHash);
108
109
  // we fill the ballotTree with empty ballots hashes to match the number of signups in the tree
109
- while (this.ballots.length < this.pubKeys.length) {
110
+ while (this.ballots.length < this.publicKeys.length) {
110
111
  this.ballotTree.insert(this.emptyBallotHash);
111
112
  this.ballots.push(this.emptyBallot);
112
113
  }
@@ -115,14 +116,14 @@ class Poll {
115
116
  /**
116
117
  * Process one message.
117
118
  * @param message - The message to process.
118
- * @param encPubKey - The public key associated with the encryption private key.
119
+ * @param encryptionPublicKey - The public key associated with the encryption private key.
119
120
  * @returns A number of variables which will be used in the zk-SNARK circuit.
120
121
  */
121
- this.processMessage = (message, encPubKey, qv = true) => {
122
+ this.processMessage = (message, encryptionPublicKey) => {
122
123
  try {
123
124
  // Decrypt the message
124
- const sharedKey = domainobjs_1.Keypair.genEcdhSharedKey(this.coordinatorKeypair.privKey, encPubKey);
125
- const { command, signature } = domainobjs_1.PCommand.decrypt(message, sharedKey);
125
+ const sharedKey = domainobjs_1.Keypair.generateEcdhSharedKey(this.coordinatorKeypair.privateKey, encryptionPublicKey);
126
+ const { command, signature } = domainobjs_1.VoteCommand.decrypt(message, sharedKey);
126
127
  const stateLeafIndex = command.stateIndex;
127
128
  // If the state tree index in the command is invalid, do nothing
128
129
  if (stateLeafIndex >= BigInt(this.ballots.length) ||
@@ -135,7 +136,7 @@ class Poll {
135
136
  // The ballot to update (or not)
136
137
  const ballot = this.ballots[Number(stateLeafIndex)];
137
138
  // If the signature is invalid, do nothing
138
- if (!command.verifySignature(signature, stateLeaf.pubKey)) {
139
+ if (!command.verifySignature(signature, stateLeaf.publicKey)) {
139
140
  throw new errors_1.ProcessMessageError(errors_1.ProcessMessageErrors.InvalidSignature);
140
141
  }
141
142
  // If the nonce is invalid, do nothing
@@ -148,49 +149,48 @@ class Poll {
148
149
  }
149
150
  const voteOptionIndex = Number(command.voteOptionIndex);
150
151
  const originalVoteWeight = ballot.votes[voteOptionIndex];
151
- // the voice credits left are:
152
- // voiceCreditsBalance (how many the user has) +
153
- // voiceCreditsPreviouslySpent (the original vote weight for this option) ** 2 -
154
- // command.newVoteWeight ** 2 (the new vote weight squared)
155
- // basically we are replacing the previous vote weight for this
156
- // particular vote option with the new one
157
- // but we need to ensure that we are not going >= balance
158
- // @note that above comment is valid for quadratic voting
159
- // for non quadratic voting, we simply remove the exponentiation
160
- const voiceCreditsLeft = qv
161
- ? stateLeaf.voiceCreditBalance +
162
- originalVoteWeight * originalVoteWeight -
163
- command.newVoteWeight * command.newVoteWeight
164
- : stateLeaf.voiceCreditBalance + originalVoteWeight - command.newVoteWeight;
152
+ const voiceCreditsLeft = this.getVoiceCreditsLeft({
153
+ stateLeaf,
154
+ originalVoteWeight,
155
+ newVoteWeight: command.newVoteWeight,
156
+ mode: this.mode,
157
+ });
165
158
  // If the remaining voice credits is insufficient, do nothing
166
159
  if (voiceCreditsLeft < 0n) {
167
160
  throw new errors_1.ProcessMessageError(errors_1.ProcessMessageErrors.InsufficientVoiceCredits);
168
161
  }
162
+ // If there are some voice credits left for full credits mode, do nothing
163
+ if (this.mode === constants_1.EMode.FULL && voiceCreditsLeft > 0n) {
164
+ throw new errors_1.ProcessMessageError(errors_1.ProcessMessageErrors.InvalidVoiceCredits);
165
+ }
169
166
  // Deep-copy the state leaf and update its attributes
170
167
  const newStateLeaf = stateLeaf.copy();
171
168
  newStateLeaf.voiceCreditBalance = voiceCreditsLeft;
172
169
  // if the key changes, this is effectively a key-change message too
173
- newStateLeaf.pubKey = command.newPubKey.copy();
170
+ newStateLeaf.publicKey = command.newPublicKey.copy();
174
171
  // Deep-copy the ballot and update its attributes
175
172
  const newBallot = ballot.copy();
176
173
  // increase the nonce
177
174
  newBallot.nonce += 1n;
178
175
  // we change the vote for this exact vote option
179
176
  newBallot.votes[voteOptionIndex] = command.newVoteWeight;
177
+ if (this.mode === constants_1.EMode.FULL) {
178
+ newBallot.votes = newBallot.votes.map((votes, index) => (voteOptionIndex === index ? votes : 0n));
179
+ }
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?.genProof(Number(stateLeafIndex)).pathElements;
183
+ const { pathElements: originalStateLeafPathElements } = this.pollStateTree.generateProof(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?.genProof(Number(stateLeafIndex)).pathElements;
186
+ const { pathElements: originalBallotPathElements } = this.ballotTree.generateProof(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 vt = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
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
- vt.insert(ballot.votes[i]);
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 = vt.genProof(voteOptionIndex).pathElements;
193
+ const { pathElements: originalVoteWeightsPathElements } = voteTree.generateProof(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 {
@@ -219,40 +219,40 @@ class Poll {
219
219
  * Inserts a Message and the corresponding public key used to generate the
220
220
  * ECDH shared key which was used to encrypt said message.
221
221
  * @param message - The message to insert
222
- * @param encPubKey - The public key used to encrypt the message
222
+ * @param encryptionPublicKey - The public key used to encrypt the message
223
223
  */
224
- this.publishMessage = (message, encPubKey) => {
225
- (0, assert_1.default)(encPubKey.rawPubKey[0] < crypto_1.SNARK_FIELD_SIZE && encPubKey.rawPubKey[1] < crypto_1.SNARK_FIELD_SIZE, "The public key is not in the correct range");
224
+ this.publishMessage = (message, 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 pub key
230
- this.encPubKeys.push(encPubKey);
229
+ // store the encryption public key
230
+ this.encryptionPublicKeys.push(encryptionPublicKey);
231
231
  // store the message locally
232
232
  this.messages.push(message);
233
233
  // add the message hash to the message tree
234
- const messageHash = message.hash(encPubKey);
234
+ const messageHash = message.hash(encryptionPublicKey);
235
235
  // update chain hash
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.genEcdhSharedKey(this.coordinatorKeypair.privKey, encPubKey);
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.PCommand.decrypt(message, sharedKey);
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 keyPair = new domainobjs_1.Keypair();
249
- const command = new domainobjs_1.PCommand(0n, keyPair.pubKey, 0n, 0n, 0n, 0n, 0n);
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
  };
253
253
  /**
254
254
  * Updates message chain hash
255
- * @param messageHash hash of message with encPubKey
255
+ * @param messageHash hash of message with encryptionPublicKey
256
256
  */
257
257
  this.updateChainHash = (messageHash) => {
258
258
  this.chainHash = (0, crypto_1.hash2)([this.chainHash, messageHash]);
@@ -266,16 +266,16 @@ class Poll {
266
266
  * @param args Poll joining circuit inputs
267
267
  * @returns stringified circuit inputs
268
268
  */
269
- this.joiningCircuitInputs = ({ maciPrivKey, stateLeafIndex, pollPubKey, }) => {
269
+ this.joiningCircuitInputs = ({ maciPrivateKey, stateLeafIndex, pollPublicKey, }) => {
270
270
  // calculate the path elements for the state tree given the original state tree
271
271
  const { siblings, index } = this.stateTree.generateProof(Number(stateLeafIndex));
272
272
  const siblingsLength = siblings.length;
273
273
  // The index must be converted to a list of indices, 1 for each tree level.
274
- // The circuit tree depth is this.stateTreeDepth, so the number of siblings must be this.stateTreeDepth,
274
+ // The circuit tree depth is this.treeDepths.stateTreeDepth, so the number of siblings must be this.treeDepths.stateTreeDepth,
275
275
  // even if the tree depth is actually 3. The missing siblings can be set to 0, as they
276
276
  // won't be used to calculate the root in the circuit.
277
277
  const indices = [];
278
- for (let i = 0; i < this.stateTreeDepth; i += 1) {
278
+ for (let i = 0; i < this.treeDepths.stateTreeDepth; i += 1) {
279
279
  // eslint-disable-next-line no-bitwise
280
280
  indices.push(BigInt((index >> i) & 1));
281
281
  if (i >= siblingsLength) {
@@ -284,15 +284,15 @@ class Poll {
284
284
  }
285
285
  const siblingsArray = siblings.map((sibling) => [sibling]);
286
286
  // Create nullifier from private key
287
- const inputNullifier = BigInt(maciPrivKey.asCircuitInputs());
287
+ const inputNullifier = BigInt(maciPrivateKey.asCircuitInputs());
288
288
  const nullifier = (0, crypto_1.poseidon)([inputNullifier, this.pollId]);
289
289
  // Get state tree's root
290
290
  const stateRoot = this.stateTree.root;
291
291
  // Set actualStateTreeDepth as number of initial siblings length
292
292
  const actualStateTreeDepth = BigInt(siblingsLength);
293
293
  const circuitInputs = {
294
- privKey: maciPrivKey.asCircuitInputs(),
295
- pollPubKey: pollPubKey.asCircuitInputs(),
294
+ privateKey: maciPrivateKey.asCircuitInputs(),
295
+ pollPublicKey: pollPublicKey.asCircuitInputs(),
296
296
  siblings: siblingsArray,
297
297
  indices,
298
298
  nullifier,
@@ -307,18 +307,18 @@ class Poll {
307
307
  * @param args Poll joined circuit inputs
308
308
  * @returns stringified circuit inputs
309
309
  */
310
- this.joinedCircuitInputs = ({ maciPrivKey, stateLeafIndex, voiceCreditsBalance, }) => {
310
+ this.joinedCircuitInputs = ({ maciPrivateKey, stateLeafIndex, voiceCreditsBalance, }) => {
311
311
  // calculate the path elements for the state tree given the original state tree
312
- const { root: stateRoot, pathElements, pathIndices } = this.pollStateTree.genProof(Number(stateLeafIndex));
312
+ const { root: stateRoot, pathElements, pathIndices } = this.pollStateTree.generateProof(Number(stateLeafIndex));
313
313
  const elementsLength = pathIndices.length;
314
- for (let i = 0; i < this.stateTreeDepth; i += 1) {
314
+ for (let i = 0; i < this.treeDepths.stateTreeDepth; i += 1) {
315
315
  if (i >= elementsLength) {
316
316
  pathElements[i] = [0n];
317
317
  pathIndices[i] = 0;
318
318
  }
319
319
  }
320
320
  const circuitInputs = {
321
- privKey: maciPrivKey.asCircuitInputs(),
321
+ privateKey: maciPrivateKey.asCircuitInputs(),
322
322
  pathElements: pathElements.map((item) => item.toString()),
323
323
  voiceCreditsBalance: voiceCreditsBalance.toString(),
324
324
  pathIndices: pathIndices.map((item) => item.toString()),
@@ -346,7 +346,7 @@ class Poll {
346
346
  if (this.messages.length > batchSize && this.messages.length % batchSize > 0) {
347
347
  totalBatches += 1;
348
348
  }
349
- return this.numBatchesProcessed < totalBatches;
349
+ return this.totalBatchesProcessed < totalBatches;
350
350
  };
351
351
  /**
352
352
  * Process _batchSize messages starting from the saved index. This
@@ -362,10 +362,10 @@ class Poll {
362
362
  * @param quiet - Whether to log errors or not
363
363
  * @returns stringified circuit inputs
364
364
  */
365
- this.processMessages = (pollId, qv = true, quiet = true) => {
365
+ this.processMessages = (pollId, quiet = true) => {
366
366
  (0, assert_1.default)(this.hasUnprocessedMessages(), "No more messages to process");
367
367
  const batchSize = this.batchSizes.messageBatchSize;
368
- if (this.numBatchesProcessed === 0) {
368
+ if (this.totalBatchesProcessed === 0) {
369
369
  // Prevent other polls from being processed until this poll has
370
370
  // been fully processed
371
371
  this.maciStateRef.pollBeingProcessed = true;
@@ -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.genProcessMessagesCircuitInputsPartial(this.currentMessageBatchIndex));
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 = [];
@@ -405,29 +405,29 @@ class Poll {
405
405
  const idx = this.currentMessageBatchIndex * batchSize - i - 1;
406
406
  (0, assert_1.default)(idx >= 0, "The message index must be >= 0");
407
407
  let message;
408
- let encPubKey;
408
+ let encryptionPublicKey;
409
409
  if (idx < this.messages.length) {
410
410
  message = this.messages[idx];
411
- encPubKey = this.encPubKeys[idx];
411
+ encryptionPublicKey = this.encryptionPublicKeys[idx];
412
412
  try {
413
413
  // check if the command is valid
414
- const r = this.processMessage(message, encPubKey, qv);
415
- const index = r.stateLeafIndex;
414
+ const { stateLeafIndex, originalStateLeaf, originalBallot, originalVoteWeight, originalVoteWeightsPathElements, originalStateLeafPathElements, originalBallotPathElements, newStateLeaf, newBallot, } = this.processMessage(message, encryptionPublicKey);
415
+ const index = stateLeafIndex;
416
416
  // we add at position 0 the original data
417
- currentStateLeaves.unshift(r.originalStateLeaf);
418
- currentBallots.unshift(r.originalBallot);
419
- currentVoteWeights.unshift(r.originalVoteWeight);
420
- currentVoteWeightsPathElements.unshift(r.originalVoteWeightsPathElements);
421
- currentStateLeavesPathElements.unshift(r.originalStateLeafPathElements);
422
- currentBallotsPathElements.unshift(r.originalBallotPathElements);
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] = r.newStateLeaf.copy();
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, r.newStateLeaf.hash());
426
+ this.pollStateTree?.update(index, newStateLeaf.hash());
427
427
  // store the new ballot
428
- this.ballots[index] = r.newBallot;
428
+ this.ballots[index] = newBallot;
429
429
  // update the ballot tree
430
- this.ballotTree?.update(index, r.newBallot.hash());
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,20 +446,20 @@ 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
- // gen shared key
450
- const sharedKey = domainobjs_1.Keypair.genEcdhSharedKey(this.coordinatorKeypair.privKey, encPubKey);
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.PCommand.decrypt(message, sharedKey, true);
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
456
456
  if (stateLeafIndex < this.pollStateLeaves.length) {
457
457
  currentStateLeaves.unshift(this.pollStateLeaves[Number(stateLeafIndex)].copy());
458
- currentStateLeavesPathElements.unshift(this.pollStateTree.genProof(Number(stateLeafIndex)).pathElements);
458
+ currentStateLeavesPathElements.unshift(this.pollStateTree.generateProof(Number(stateLeafIndex)).pathElements);
459
459
  // copy the ballot
460
460
  const ballot = this.ballots[Number(stateLeafIndex)].copy();
461
461
  currentBallots.unshift(ballot);
462
- currentBallotsPathElements.unshift(this.ballotTree.genProof(Number(stateLeafIndex)).pathElements);
462
+ currentBallotsPathElements.unshift(this.ballotTree.generateProof(Number(stateLeafIndex)).pathElements);
463
463
  // @note we check that command.voteOptionIndex is valid so < voteOptions
464
464
  // this might be unnecessary but we do it to prevent a possible DoS attack
465
465
  // from voters who could potentially encrypt a message in such as way that
@@ -467,39 +467,39 @@ 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 vt = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
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
- vt.insert(ballot.votes[j]);
473
+ voteTree.insert(ballot.votes[j]);
474
474
  }
475
475
  // get the path elements for the first vote leaf
476
- currentVoteWeightsPathElements.unshift(vt.genProof(Number(command.voteOptionIndex)).pathElements);
476
+ currentVoteWeightsPathElements.unshift(voteTree.generateProof(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 vt = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
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
- vt.insert(ballot.votes[j]);
484
+ voteTree.insert(ballot.votes[j]);
485
485
  }
486
486
  // get the path elements for the first vote leaf
487
- currentVoteWeightsPathElements.unshift(vt.genProof(0).pathElements);
487
+ currentVoteWeightsPathElements.unshift(voteTree.generateProof(0).pathElements);
488
488
  }
489
489
  }
490
490
  else {
491
491
  // just use state leaf index 0
492
492
  currentStateLeaves.unshift(this.pollStateLeaves[0].copy());
493
- currentStateLeavesPathElements.unshift(this.pollStateTree.genProof(0).pathElements);
493
+ currentStateLeavesPathElements.unshift(this.pollStateTree.generateProof(0).pathElements);
494
494
  currentBallots.unshift(this.ballots[0].copy());
495
- currentBallotsPathElements.unshift(this.ballotTree.genProof(0).pathElements);
495
+ currentBallotsPathElements.unshift(this.ballotTree.generateProof(0).pathElements);
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 vt = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
500
- vt.insert(this.ballots[0].votes[0]);
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(vt.genProof(0).pathElements);
502
+ currentVoteWeightsPathElements.unshift(voteTree.generateProof(0).pathElements);
503
503
  }
504
504
  }
505
505
  else {
@@ -510,17 +510,17 @@ class Poll {
510
510
  else {
511
511
  // Since we don't have a command at that position, use a blank state leaf
512
512
  currentStateLeaves.unshift(this.pollStateLeaves[0].copy());
513
- currentStateLeavesPathElements.unshift(this.pollStateTree.genProof(0).pathElements);
513
+ currentStateLeavesPathElements.unshift(this.pollStateTree.generateProof(0).pathElements);
514
514
  // since the command is invliad we use the blank ballot
515
515
  currentBallots.unshift(this.ballots[0].copy());
516
- currentBallotsPathElements.unshift(this.ballotTree.genProof(0).pathElements);
516
+ currentBallotsPathElements.unshift(this.ballotTree.generateProof(0).pathElements);
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 vt = new crypto_1.IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, constants_1.VOTE_OPTION_TREE_ARITY, crypto_1.hash5);
521
- vt.insert(this.ballots[0].votes[0]);
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(vt.genProof(0).pathElements);
523
+ currentVoteWeightsPathElements.unshift(voteTree.generateProof(0).pathElements);
524
524
  }
525
525
  }
526
526
  // store the data in the circuit inputs object
@@ -528,7 +528,7 @@ class Poll {
528
528
  // we need to fill the array with 0s to match the length of the state leaves
529
529
  // eslint-disable-next-line @typescript-eslint/prefer-for-of
530
530
  for (let i = 0; i < currentStateLeavesPathElements.length; i += 1) {
531
- while (currentStateLeavesPathElements[i].length < this.stateTreeDepth) {
531
+ while (currentStateLeavesPathElements[i].length < this.treeDepths.stateTreeDepth) {
532
532
  currentStateLeavesPathElements[i].push([0n]);
533
533
  }
534
534
  }
@@ -538,14 +538,14 @@ class Poll {
538
538
  circuitInputs.currentVoteWeights = currentVoteWeights;
539
539
  circuitInputs.currentVoteWeightsPathElements = currentVoteWeightsPathElements;
540
540
  // record that we processed one batch
541
- this.numBatchesProcessed += 1;
541
+ this.totalBatchesProcessed += 1;
542
542
  if (this.currentMessageBatchIndex > 0) {
543
543
  this.currentMessageBatchIndex -= 1;
544
544
  }
545
545
  // ensure newSbSalt differs from currentSbSalt
546
- let newSbSalt = (0, crypto_1.genRandomSalt)();
546
+ let newSbSalt = (0, crypto_1.generateRandomSalt)();
547
547
  while (this.sbSalts[this.currentMessageBatchIndex] === newSbSalt) {
548
- newSbSalt = (0, crypto_1.genRandomSalt)();
548
+ newSbSalt = (0, crypto_1.generateRandomSalt)();
549
549
  }
550
550
  this.sbSalts[this.currentMessageBatchIndex] = newSbSalt;
551
551
  // store the salt in the circuit inputs
@@ -555,9 +555,9 @@ class Poll {
555
555
  // create a commitment to the state and ballot tree roots
556
556
  // this will be the hash of the roots with a salt
557
557
  circuitInputs.newSbCommitment = (0, crypto_1.hash3)([newStateRoot, newBallotRoot, newSbSalt]);
558
- const coordinatorPublicKeyHash = this.coordinatorKeypair.pubKey.hash();
558
+ const coordinatorPublicKeyHash = this.coordinatorKeypair.publicKey.hash();
559
559
  // If this is the last batch, release the lock
560
- if (this.numBatchesProcessed * batchSize >= this.messages.length) {
560
+ if (this.totalBatchesProcessed * batchSize >= this.messages.length) {
561
561
  this.maciStateRef.pollBeingProcessed = false;
562
562
  }
563
563
  // ensure we pass the dynamic tree depth
@@ -572,33 +572,33 @@ class Poll {
572
572
  * @param index - The index of the partial batch.
573
573
  * @returns stringified partial circuit inputs
574
574
  */
575
- this.genProcessMessagesCircuitInputsPartial = (index) => {
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
- // fill the msgs array with a copy of the messages we have
578
+ // fill the messages array with a copy of the messages we have
579
579
  // plus empty messages to fill the batch
580
580
  // @note create a message with state index 0 to add as padding
581
581
  // this way the message will look for state leaf 0
582
582
  // and no effect will take place
583
583
  // create a random key
584
584
  const key = new domainobjs_1.Keypair();
585
- // gen ecdh key
586
- const ecdh = domainobjs_1.Keypair.genEcdhSharedKey(key.privKey, this.coordinatorKeypair.pubKey);
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.PCommand(0n, key.pubKey, 0n, 0n, 0n, 0n, 0n);
588
+ const emptyCommand = new domainobjs_1.VoteCommand(0n, key.publicKey, 0n, 0n, 0n, 0n, 0n);
589
589
  // encrypt it
590
- const msg = emptyCommand.encrypt(emptyCommand.sign(key.privKey), ecdh);
590
+ const emptyMessage = emptyCommand.encrypt(emptyCommand.sign(key.privateKey), ecdh);
591
591
  // copy the messages to a new array
592
- let msgs = this.messages.map((x) => x.asCircuitInputs());
592
+ let messages = this.messages.map((x) => x.asCircuitInputs());
593
593
  // pad with our state index 0 message
594
- while (msgs.length % messageBatchSize > 0) {
595
- msgs.push(msg.asCircuitInputs());
594
+ while (messages.length % messageBatchSize > 0) {
595
+ messages.push(emptyMessage.asCircuitInputs());
596
596
  }
597
597
  // copy the public keys, pad the array with the last keys if needed
598
- let encPubKeys = this.encPubKeys.map((x) => x.copy());
599
- while (encPubKeys.length % messageBatchSize > 0) {
598
+ let encryptionPublicKeys = this.encryptionPublicKeys.map((x) => x.copy());
599
+ while (encryptionPublicKeys.length % messageBatchSize > 0) {
600
600
  // pad with the public key used to encrypt the message with state index 0 (padding)
601
- encPubKeys.push(key.pubKey.copy());
601
+ encryptionPublicKeys.push(key.publicKey.copy());
602
602
  }
603
603
  // validate that the batch index is correct, if not fix it
604
604
  // this means that the end will be the last message
@@ -608,11 +608,11 @@ class Poll {
608
608
  }
609
609
  const batchStartIndex = index > 0 ? (index - 1) * messageBatchSize : 0;
610
610
  // we only take the messages we need for this batch
611
- // it slice msgs array from index of first message in current batch to
611
+ // it slice messages array from index of first message in current batch to
612
612
  // index of last message in current batch
613
- msgs = msgs.slice(batchStartIndex, index * messageBatchSize);
613
+ messages = messages.slice(batchStartIndex, index * messageBatchSize);
614
614
  // then take the ones part of this batch
615
- encPubKeys = encPubKeys.slice(batchStartIndex, index * messageBatchSize);
615
+ encryptionPublicKeys = encryptionPublicKeys.slice(batchStartIndex, index * messageBatchSize);
616
616
  // cache tree roots
617
617
  const currentStateRoot = this.pollStateTree.root;
618
618
  const currentBallotRoot = this.ballotTree.root;
@@ -623,15 +623,15 @@ 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
- numSignUps: BigInt(this.numSignups),
626
+ totalSignups: BigInt(this.totalSignups),
627
627
  batchEndIndex: BigInt(batchEndIndex),
628
628
  index: BigInt(batchStartIndex),
629
629
  inputBatchHash,
630
630
  outputBatchHash,
631
- msgs,
631
+ messages,
632
632
  actualStateTreeDepth: BigInt(this.actualStateTreeDepth),
633
- coordPrivKey: this.coordinatorKeypair.privKey.asCircuitInputs(),
634
- encPubKeys: encPubKeys.map((x) => x.asCircuitInputs()),
633
+ coordinatorPrivateKey: this.coordinatorKeypair.privateKey.asCircuitInputs(),
634
+ encryptionPublicKeys: encryptionPublicKeys.map((x) => x.asCircuitInputs()),
635
635
  currentStateRoot,
636
636
  currentBallotRoot,
637
637
  currentSbCommitment,
@@ -661,7 +661,8 @@ class Poll {
661
661
  this.hasUntalliedBallots = () => this.numBatchesTallied * this.batchSizes.tallyBatchSize < this.ballots.length;
662
662
  /**
663
663
  * This method tallies a ballots and updates the tally results.
664
- * @returns the circuit inputs for the TallyVotes circuit.
664
+ *
665
+ * @returns the circuit inputs for the VoteTally circuit.
665
666
  */
666
667
  this.tallyVotes = () => {
667
668
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -674,133 +675,40 @@ class Poll {
674
675
  const batchStartIndex = this.numBatchesTallied * batchSize;
675
676
  // get the salts needed for the commitments
676
677
  const currentResultsRootSalt = batchStartIndex === 0 ? 0n : this.resultRootSalts[batchStartIndex - batchSize];
677
- const currentPerVOSpentVoiceCreditsRootSalt = batchStartIndex === 0 ? 0n : this.preVOSpentVoiceCreditsRootSalts[batchStartIndex - batchSize];
678
+ const currentPerVoteOptionSpentVoiceCreditsRootSalt = batchStartIndex === 0 ? 0n : this.perVoteOptionSpentVoiceCreditsRootSalts[batchStartIndex - batchSize];
678
679
  const currentSpentVoiceCreditSubtotalSalt = batchStartIndex === 0 ? 0n : this.spentVoiceCreditSubtotalSalts[batchStartIndex - batchSize];
679
680
  // generate a commitment to the current results
680
- const currentResultsCommitment = (0, crypto_1.genTreeCommitment)(this.tallyResult, currentResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
681
- // generate a commitment to the current per VO spent voice credits
682
- const currentPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(currentPerVOSpentVoiceCreditsRootSalt, batchStartIndex, true);
681
+ const currentResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, currentResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
682
+ // generate a commitment to the current per vote option spent voice credits
683
+ const currentPerVoteOptionSpentVoiceCreditsCommitment = this.generatePerVoteOptionSpentVoiceCreditsCommitment(currentPerVoteOptionSpentVoiceCreditsRootSalt, batchStartIndex, this.mode);
683
684
  // generate a commitment to the current spent voice credits
684
- const currentSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(currentSpentVoiceCreditSubtotalSalt, batchStartIndex, true);
685
+ const currentSpentVoiceCreditsCommitment = this.generateSpentVoiceCreditSubtotalCommitment(currentSpentVoiceCreditSubtotalSalt, batchStartIndex, this.mode);
685
686
  // the current commitment for the first batch will be 0
686
687
  // otherwise calculate as
687
688
  // hash([
688
689
  // currentResultsCommitment,
689
690
  // currentSpentVoiceCreditsCommitment,
690
- // currentPerVOSpentVoiceCreditsCommitment
691
691
  // ])
692
- const currentTallyCommitment = batchStartIndex === 0
692
+ // or for QV
693
+ // hash([
694
+ // currentResultsCommitment,
695
+ // currentSpentVoiceCreditsCommitment,
696
+ // currentPerVoteOptionSpentVoiceCreditsCommitment
697
+ // ])
698
+ const currentTallyCommitmentQv = this.mode !== constants_1.EMode.QV || batchStartIndex === 0
693
699
  ? 0n
694
700
  : (0, crypto_1.hash3)([
695
701
  currentResultsCommitment,
696
702
  currentSpentVoiceCreditsCommitment,
697
- currentPerVOSpentVoiceCreditsCommitment,
703
+ currentPerVoteOptionSpentVoiceCreditsCommitment,
698
704
  ]);
705
+ const currentTallyCommitmentNonQv = this.mode === constants_1.EMode.QV || batchStartIndex === 0
706
+ ? 0n
707
+ : (0, crypto_1.hashLeftRight)(currentResultsCommitment, currentSpentVoiceCreditsCommitment);
708
+ const currentTallyCommitment = currentTallyCommitmentNonQv || currentTallyCommitmentQv;
699
709
  const ballots = [];
700
710
  const currentResults = this.tallyResult.map((x) => BigInt(x.toString()));
701
- const currentPerVOSpentVoiceCredits = this.perVOSpentVoiceCredits.map((x) => BigInt(x.toString()));
702
- const currentSpentVoiceCreditSubtotal = BigInt(this.totalSpentVoiceCredits.toString());
703
- // loop in normal order to tally the ballots one by one
704
- for (let i = this.numBatchesTallied * batchSize; i < this.numBatchesTallied * batchSize + batchSize; i += 1) {
705
- // we stop if we have no more ballots to tally
706
- if (i >= this.ballots.length) {
707
- break;
708
- }
709
- // save to the local ballot array
710
- ballots.push(this.ballots[i]);
711
- // for each possible vote option we loop and calculate
712
- for (let j = 0; j < this.maxVoteOptions; j += 1) {
713
- const v = this.ballots[i].votes[j];
714
- // the vote itself will be a quadratic vote (sqrt(voiceCredits))
715
- this.tallyResult[j] += v;
716
- // the per vote option spent voice credits will be the sum of the squares of the votes
717
- this.perVOSpentVoiceCredits[j] += v * v;
718
- // the total spent voice credits will be the sum of the squares of the votes
719
- this.totalSpentVoiceCredits += v * v;
720
- }
721
- }
722
- const emptyBallot = new domainobjs_1.Ballot(this.maxVoteOptions, this.treeDepths.voteOptionTreeDepth);
723
- // pad the ballots array
724
- while (ballots.length < batchSize) {
725
- ballots.push(emptyBallot);
726
- }
727
- // generate the new salts
728
- const newResultsRootSalt = (0, crypto_1.genRandomSalt)();
729
- const newPerVOSpentVoiceCreditsRootSalt = (0, crypto_1.genRandomSalt)();
730
- const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.genRandomSalt)();
731
- // and save them to be used in the next batch
732
- this.resultRootSalts[batchStartIndex] = newResultsRootSalt;
733
- this.preVOSpentVoiceCreditsRootSalts[batchStartIndex] = newPerVOSpentVoiceCreditsRootSalt;
734
- this.spentVoiceCreditSubtotalSalts[batchStartIndex] = newSpentVoiceCreditSubtotalSalt;
735
- // generate the new results commitment with the new salts and data
736
- const newResultsCommitment = (0, crypto_1.genTreeCommitment)(this.tallyResult, newResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
737
- // generate the new spent voice credits commitment with the new salts and data
738
- const newSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(newSpentVoiceCreditSubtotalSalt, batchStartIndex + batchSize, true);
739
- // generate the new per VO spent voice credits commitment with the new salts and data
740
- const newPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(newPerVOSpentVoiceCreditsRootSalt, batchStartIndex + batchSize, true);
741
- // generate the new tally commitment
742
- const newTallyCommitment = (0, crypto_1.hash3)([
743
- newResultsCommitment,
744
- newSpentVoiceCreditsCommitment,
745
- newPerVOSpentVoiceCreditsCommitment,
746
- ]);
747
- // cache vars
748
- const stateRoot = this.pollStateTree.root;
749
- const ballotRoot = this.ballotTree.root;
750
- const sbSalt = this.sbSalts[this.currentMessageBatchIndex];
751
- const sbCommitment = (0, crypto_1.hash3)([stateRoot, ballotRoot, sbSalt]);
752
- const ballotSubrootProof = this.ballotTree?.genSubrootProof(batchStartIndex, batchStartIndex + batchSize);
753
- const votes = ballots.map((x) => x.votes);
754
- const circuitInputs = (0, crypto_1.stringifyBigInts)({
755
- stateRoot,
756
- ballotRoot,
757
- sbSalt,
758
- index: BigInt(batchStartIndex),
759
- numSignUps: BigInt(this.numSignups),
760
- sbCommitment,
761
- currentTallyCommitment,
762
- newTallyCommitment,
763
- ballots: ballots.map((x) => x.asCircuitInputs()),
764
- ballotPathElements: ballotSubrootProof.pathElements,
765
- votes,
766
- currentResults,
767
- currentResultsRootSalt,
768
- currentSpentVoiceCreditSubtotal,
769
- currentSpentVoiceCreditSubtotalSalt,
770
- currentPerVOSpentVoiceCredits,
771
- currentPerVOSpentVoiceCreditsRootSalt,
772
- newResultsRootSalt,
773
- newPerVOSpentVoiceCreditsRootSalt,
774
- newSpentVoiceCreditSubtotalSalt,
775
- });
776
- this.numBatchesTallied += 1;
777
- return circuitInputs;
778
- };
779
- this.tallyVotesNonQv = () => {
780
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
781
- if (this.sbSalts[this.currentMessageBatchIndex] === undefined) {
782
- throw new Error("You must process the messages first");
783
- }
784
- const batchSize = this.batchSizes.tallyBatchSize;
785
- (0, assert_1.default)(this.hasUntalliedBallots(), "No more ballots to tally");
786
- // calculate where we start tallying next
787
- const batchStartIndex = this.numBatchesTallied * batchSize;
788
- // get the salts needed for the commitments
789
- const currentResultsRootSalt = batchStartIndex === 0 ? 0n : this.resultRootSalts[batchStartIndex - batchSize];
790
- const currentSpentVoiceCreditSubtotalSalt = batchStartIndex === 0 ? 0n : this.spentVoiceCreditSubtotalSalts[batchStartIndex - batchSize];
791
- // generate a commitment to the current results
792
- const currentResultsCommitment = (0, crypto_1.genTreeCommitment)(this.tallyResult, currentResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
793
- // generate a commitment to the current spent voice credits
794
- const currentSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(currentSpentVoiceCreditSubtotalSalt, batchStartIndex, false);
795
- // the current commitment for the first batch will be 0
796
- // otherwise calculate as
797
- // hash([
798
- // currentResultsCommitment,
799
- // currentSpentVoiceCreditsCommitment,
800
- // ])
801
- const currentTallyCommitment = batchStartIndex === 0 ? 0n : (0, crypto_1.hashLeftRight)(currentResultsCommitment, currentSpentVoiceCreditsCommitment);
802
- const ballots = [];
803
- const currentResults = this.tallyResult.map((x) => BigInt(x.toString()));
711
+ const currentPerVoteOptionSpentVoiceCredits = this.perVoteOptionSpentVoiceCredits.map((x) => BigInt(x.toString()));
804
712
  const currentSpentVoiceCreditSubtotal = BigInt(this.totalSpentVoiceCredits.toString());
805
713
  // loop in normal order to tally the ballots one by one
806
714
  for (let i = this.numBatchesTallied * batchSize; i < this.numBatchesTallied * batchSize + batchSize; i += 1) {
@@ -812,10 +720,18 @@ class Poll {
812
720
  ballots.push(this.ballots[i]);
813
721
  // for each possible vote option we loop and calculate
814
722
  for (let j = 0; j < this.maxVoteOptions; j += 1) {
815
- const v = this.ballots[i].votes[j];
816
- this.tallyResult[j] += v;
817
- // the total spent voice credits will be the sum of the votes
818
- this.totalSpentVoiceCredits += v;
723
+ const votes = this.ballots[i].votes[j];
724
+ this.tallyResult[j] += votes;
725
+ if (this.mode === constants_1.EMode.QV) {
726
+ // the per vote option spent voice credits will be the sum of the squares of the votes
727
+ this.perVoteOptionSpentVoiceCredits[j] += votes * votes;
728
+ // the total spent voice credits will be the sum of the squares of the votes
729
+ this.totalSpentVoiceCredits += votes * votes;
730
+ }
731
+ else {
732
+ // the total spent voice credits will be the sum of the votes
733
+ this.totalSpentVoiceCredits += votes;
734
+ }
819
735
  }
820
736
  }
821
737
  const emptyBallot = new domainobjs_1.Ballot(this.maxVoteOptions, this.treeDepths.voteOptionTreeDepth);
@@ -824,30 +740,36 @@ class Poll {
824
740
  ballots.push(emptyBallot);
825
741
  }
826
742
  // generate the new salts
827
- const newResultsRootSalt = (0, crypto_1.genRandomSalt)();
828
- const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.genRandomSalt)();
743
+ const newResultsRootSalt = (0, crypto_1.generateRandomSalt)();
744
+ const newPerVoteOptionSpentVoiceCreditsRootSalt = (0, crypto_1.generateRandomSalt)();
745
+ const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.generateRandomSalt)();
829
746
  // and save them to be used in the next batch
830
747
  this.resultRootSalts[batchStartIndex] = newResultsRootSalt;
748
+ this.perVoteOptionSpentVoiceCreditsRootSalts[batchStartIndex] = newPerVoteOptionSpentVoiceCreditsRootSalt;
831
749
  this.spentVoiceCreditSubtotalSalts[batchStartIndex] = newSpentVoiceCreditSubtotalSalt;
832
750
  // generate the new results commitment with the new salts and data
833
- const newResultsCommitment = (0, crypto_1.genTreeCommitment)(this.tallyResult, newResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
751
+ const newResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, newResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
834
752
  // generate the new spent voice credits commitment with the new salts and data
835
- const newSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(newSpentVoiceCreditSubtotalSalt, batchStartIndex + batchSize, false);
753
+ const newSpentVoiceCreditsCommitment = this.generateSpentVoiceCreditSubtotalCommitment(newSpentVoiceCreditSubtotalSalt, batchStartIndex + batchSize, this.mode);
754
+ // generate the new per vote option spent voice credits commitment with the new salts and data
755
+ const newPerVoteOptionSpentVoiceCreditsCommitment = this.generatePerVoteOptionSpentVoiceCreditsCommitment(newPerVoteOptionSpentVoiceCreditsRootSalt, batchStartIndex + batchSize, this.mode);
836
756
  // generate the new tally commitment
837
- const newTallyCommitment = (0, crypto_1.hashLeftRight)(newResultsCommitment, newSpentVoiceCreditsCommitment);
757
+ const newTallyCommitment = this.mode === constants_1.EMode.QV
758
+ ? (0, crypto_1.hash3)([newResultsCommitment, newSpentVoiceCreditsCommitment, newPerVoteOptionSpentVoiceCreditsCommitment])
759
+ : (0, crypto_1.hashLeftRight)(newResultsCommitment, newSpentVoiceCreditsCommitment);
838
760
  // cache vars
839
761
  const stateRoot = this.pollStateTree.root;
840
762
  const ballotRoot = this.ballotTree.root;
841
763
  const sbSalt = this.sbSalts[this.currentMessageBatchIndex];
842
764
  const sbCommitment = (0, crypto_1.hash3)([stateRoot, ballotRoot, sbSalt]);
843
- const ballotSubrootProof = this.ballotTree?.genSubrootProof(batchStartIndex, batchStartIndex + batchSize);
765
+ const ballotSubrootProof = this.ballotTree?.generateSubrootProof(batchStartIndex, batchStartIndex + batchSize);
844
766
  const votes = ballots.map((x) => x.votes);
845
- const circuitInputs = (0, crypto_1.stringifyBigInts)({
767
+ const circuitInputs = (0, crypto_1.stringifyBigInts)((0, omit_1.default)({
846
768
  stateRoot,
847
769
  ballotRoot,
848
770
  sbSalt,
849
771
  index: BigInt(batchStartIndex),
850
- numSignUps: BigInt(this.numSignups),
772
+ totalSignups: BigInt(this.totalSignups),
851
773
  sbCommitment,
852
774
  currentTallyCommitment,
853
775
  newTallyCommitment,
@@ -858,9 +780,18 @@ class Poll {
858
780
  currentResultsRootSalt,
859
781
  currentSpentVoiceCreditSubtotal,
860
782
  currentSpentVoiceCreditSubtotalSalt,
783
+ currentPerVoteOptionSpentVoiceCredits,
784
+ currentPerVoteOptionSpentVoiceCreditsRootSalt,
785
+ newPerVoteOptionSpentVoiceCreditsRootSalt,
861
786
  newResultsRootSalt,
862
787
  newSpentVoiceCreditSubtotalSalt,
863
- });
788
+ }, this.mode !== constants_1.EMode.QV
789
+ ? [
790
+ "currentPerVoteOptionSpentVoiceCredits",
791
+ "currentPerVoteOptionSpentVoiceCreditsRootSalt",
792
+ "newPerVoteOptionSpentVoiceCreditsRootSalt",
793
+ ]
794
+ : []));
864
795
  this.numBatchesTallied += 1;
865
796
  return circuitInputs;
866
797
  };
@@ -869,19 +800,19 @@ class Poll {
869
800
  *
870
801
  * This is the hash of the total spent voice credits and a salt, computed as Poseidon([totalCredits, _salt]).
871
802
  * @param salt - The salt used in the hash function.
872
- * @param numBallotsToCount - The number of ballots to count for the calculation.
873
- * @param useQuadraticVoting - Whether to use quadratic voting or not. Default is true.
803
+ * @param ballotsToCount - The number of ballots to count for the calculation.
804
+ * @param mode - Voting mode, default is QV.
874
805
  * @returns Returns the hash of the total spent voice credits and a salt, computed as Poseidon([totalCredits, _salt]).
875
806
  */
876
- this.genSpentVoiceCreditSubtotalCommitment = (salt, numBallotsToCount, useQuadraticVoting = true) => {
807
+ this.generateSpentVoiceCreditSubtotalCommitment = (salt, ballotsToCount, mode = constants_1.EMode.QV) => {
877
808
  let subtotal = 0n;
878
- for (let i = 0; i < numBallotsToCount; i += 1) {
809
+ for (let i = 0; i < ballotsToCount; i += 1) {
879
810
  if (this.ballots.length <= i) {
880
811
  break;
881
812
  }
882
813
  for (let j = 0; j < this.tallyResult.length; j += 1) {
883
- const v = BigInt(`${this.ballots[i].votes[j]}`);
884
- subtotal += useQuadraticVoting ? v * v : v;
814
+ const vote = BigInt(`${this.ballots[i].votes[j]}`);
815
+ subtotal += mode === constants_1.EMode.QV ? vote * vote : vote;
885
816
  }
886
817
  }
887
818
  return (0, crypto_1.hashLeftRight)(subtotal, salt);
@@ -891,23 +822,23 @@ class Poll {
891
822
  *
892
823
  * This is the hash of the Merkle root of the spent voice credits per vote option and a salt, computed as Poseidon([root, _salt]).
893
824
  * @param salt - The salt used in the hash function.
894
- * @param numBallotsToCount - The number of ballots to count for the calculation.
895
- * @param useQuadraticVoting - Whether to use quadratic voting or not. Default is true.
825
+ * @param ballotsToCount - The number of ballots to count for the calculation.
826
+ * @param mode - Voting mode, default is QV.
896
827
  * @returns Returns the hash of the Merkle root of the spent voice credits per vote option and a salt, computed as Poseidon([root, _salt]).
897
828
  */
898
- this.genPerVOSpentVoiceCreditsCommitment = (salt, numBallotsToCount, useQuadraticVoting = true) => {
829
+ this.generatePerVoteOptionSpentVoiceCreditsCommitment = (salt, ballotsToCount, mode = constants_1.EMode.QV) => {
899
830
  const leaves = Array(this.tallyResult.length).fill(0n);
900
- for (let i = 0; i < numBallotsToCount; i += 1) {
831
+ for (let i = 0; i < ballotsToCount; i += 1) {
901
832
  // check that is a valid index
902
833
  if (i >= this.ballots.length) {
903
834
  break;
904
835
  }
905
836
  for (let j = 0; j < this.tallyResult.length; j += 1) {
906
- const v = this.ballots[i].votes[j];
907
- leaves[j] += useQuadraticVoting ? v * v : v;
837
+ const vote = this.ballots[i].votes[j];
838
+ leaves[j] += mode === constants_1.EMode.QV ? vote * vote : vote;
908
839
  }
909
840
  }
910
- return (0, crypto_1.genTreeCommitment)(leaves, salt, this.treeDepths.voteOptionTreeDepth);
841
+ return (0, crypto_1.generateTreeCommitment)(leaves, salt, this.treeDepths.voteOptionTreeDepth);
911
842
  };
912
843
  /**
913
844
  * Create a deep copy of the Poll object.
@@ -915,32 +846,33 @@ class Poll {
915
846
  */
916
847
  this.copy = () => {
917
848
  const copied = new Poll(BigInt(this.pollEndTimestamp.toString()), this.coordinatorKeypair.copy(), {
918
- intStateTreeDepth: Number(this.treeDepths.intStateTreeDepth),
849
+ tallyProcessingStateTreeDepth: Number(this.treeDepths.tallyProcessingStateTreeDepth),
919
850
  voteOptionTreeDepth: Number(this.treeDepths.voteOptionTreeDepth),
851
+ stateTreeDepth: Number(this.treeDepths.stateTreeDepth),
920
852
  }, {
921
853
  tallyBatchSize: Number(this.batchSizes.tallyBatchSize.toString()),
922
854
  messageBatchSize: Number(this.batchSizes.messageBatchSize.toString()),
923
- }, this.maciStateRef, this.voteOptions);
924
- copied.pubKeys = this.pubKeys.map((x) => x.copy());
855
+ }, this.maciStateRef, this.voteOptions, this.mode);
856
+ copied.publicKeys = this.publicKeys.map((x) => x.copy());
925
857
  copied.pollStateLeaves = this.pollStateLeaves.map((x) => x.copy());
926
858
  copied.messages = this.messages.map((x) => x.copy());
927
859
  copied.commands = this.commands.map((x) => x.copy());
928
860
  copied.ballots = this.ballots.map((x) => x.copy());
929
- copied.encPubKeys = this.encPubKeys.map((x) => x.copy());
861
+ copied.encryptionPublicKeys = this.encryptionPublicKeys.map((x) => x.copy());
930
862
  if (this.ballotTree) {
931
863
  copied.ballotTree = this.ballotTree.copy();
932
864
  }
933
865
  copied.currentMessageBatchIndex = this.currentMessageBatchIndex;
934
866
  copied.maciStateRef = this.maciStateRef;
935
867
  copied.tallyResult = this.tallyResult.map((x) => BigInt(x.toString()));
936
- copied.perVOSpentVoiceCredits = this.perVOSpentVoiceCredits.map((x) => BigInt(x.toString()));
937
- copied.numBatchesProcessed = Number(this.numBatchesProcessed.toString());
868
+ copied.perVoteOptionSpentVoiceCredits = this.perVoteOptionSpentVoiceCredits.map((x) => BigInt(x.toString()));
869
+ copied.totalBatchesProcessed = Number(this.totalBatchesProcessed.toString());
938
870
  copied.numBatchesTallied = Number(this.numBatchesTallied.toString());
939
871
  copied.pollId = this.pollId;
940
872
  copied.totalSpentVoiceCredits = BigInt(this.totalSpentVoiceCredits.toString());
941
873
  copied.sbSalts = {};
942
874
  copied.resultRootSalts = {};
943
- copied.preVOSpentVoiceCreditsRootSalts = {};
875
+ copied.perVoteOptionSpentVoiceCreditsRootSalts = {};
944
876
  copied.spentVoiceCreditSubtotalSalts = {};
945
877
  Object.keys(this.sbSalts).forEach((k) => {
946
878
  copied.sbSalts[k] = BigInt(this.sbSalts[k].toString());
@@ -948,41 +880,41 @@ class Poll {
948
880
  Object.keys(this.resultRootSalts).forEach((k) => {
949
881
  copied.resultRootSalts[k] = BigInt(this.resultRootSalts[k].toString());
950
882
  });
951
- Object.keys(this.preVOSpentVoiceCreditsRootSalts).forEach((k) => {
952
- copied.preVOSpentVoiceCreditsRootSalts[k] = BigInt(this.preVOSpentVoiceCreditsRootSalts[k].toString());
883
+ Object.keys(this.perVoteOptionSpentVoiceCreditsRootSalts).forEach((k) => {
884
+ copied.perVoteOptionSpentVoiceCreditsRootSalts[k] = BigInt(this.perVoteOptionSpentVoiceCreditsRootSalts[k].toString());
953
885
  });
954
886
  Object.keys(this.spentVoiceCreditSubtotalSalts).forEach((k) => {
955
887
  copied.spentVoiceCreditSubtotalSalts[k] = BigInt(this.spentVoiceCreditSubtotalSalts[k].toString());
956
888
  });
957
889
  // update the number of signups
958
- copied.setNumSignups(this.numSignups);
890
+ copied.setTotalSignups(this.totalSignups);
959
891
  return copied;
960
892
  };
961
893
  /**
962
894
  * Check if the Poll object is equal to another Poll object.
963
- * @param p - The Poll object to compare.
895
+ * @param poll - The Poll object to compare.
964
896
  * @returns True if the two Poll objects are equal, false otherwise.
965
897
  */
966
- this.equals = (p) => {
967
- const result = this.coordinatorKeypair.equals(p.coordinatorKeypair) &&
968
- this.treeDepths.intStateTreeDepth === p.treeDepths.intStateTreeDepth &&
969
- this.treeDepths.voteOptionTreeDepth === p.treeDepths.voteOptionTreeDepth &&
970
- this.batchSizes.tallyBatchSize === p.batchSizes.tallyBatchSize &&
971
- this.batchSizes.messageBatchSize === p.batchSizes.messageBatchSize &&
972
- this.maxVoteOptions === p.maxVoteOptions &&
973
- this.messages.length === p.messages.length &&
974
- this.encPubKeys.length === p.encPubKeys.length &&
975
- this.numSignups === p.numSignups;
898
+ this.equals = (poll) => {
899
+ const result = this.coordinatorKeypair.equals(poll.coordinatorKeypair) &&
900
+ this.treeDepths.tallyProcessingStateTreeDepth === poll.treeDepths.tallyProcessingStateTreeDepth &&
901
+ this.treeDepths.voteOptionTreeDepth === poll.treeDepths.voteOptionTreeDepth &&
902
+ this.batchSizes.tallyBatchSize === poll.batchSizes.tallyBatchSize &&
903
+ this.batchSizes.messageBatchSize === poll.batchSizes.messageBatchSize &&
904
+ this.maxVoteOptions === poll.maxVoteOptions &&
905
+ this.messages.length === poll.messages.length &&
906
+ this.encryptionPublicKeys.length === poll.encryptionPublicKeys.length &&
907
+ this.totalSignups === poll.totalSignups;
976
908
  if (!result) {
977
909
  return false;
978
910
  }
979
911
  for (let i = 0; i < this.messages.length; i += 1) {
980
- if (!this.messages[i].equals(p.messages[i])) {
912
+ if (!this.messages[i].equals(poll.messages[i])) {
981
913
  return false;
982
914
  }
983
915
  }
984
- for (let i = 0; i < this.encPubKeys.length; i += 1) {
985
- if (!this.encPubKeys[i].equals(p.encPubKeys[i])) {
916
+ for (let i = 0; i < this.encryptionPublicKeys.length; i += 1) {
917
+ if (!this.encryptionPublicKeys[i].equals(poll.encryptionPublicKeys[i])) {
986
918
  return false;
987
919
  }
988
920
  }
@@ -993,20 +925,20 @@ class Poll {
993
925
  * @param serializedPrivateKey - the serialized private key
994
926
  */
995
927
  this.setCoordinatorKeypair = (serializedPrivateKey) => {
996
- this.coordinatorKeypair = new domainobjs_1.Keypair(domainobjs_1.PrivKey.deserialize(serializedPrivateKey));
928
+ this.coordinatorKeypair = new domainobjs_1.Keypair(domainobjs_1.PrivateKey.deserialize(serializedPrivateKey));
997
929
  };
998
930
  /**
999
931
  * Set the number of signups to match the ones from the contract
1000
- * @param numSignups - the number of signups
932
+ * @param totalSignups - the number of signups
1001
933
  */
1002
- this.setNumSignups = (numSignups) => {
1003
- this.numSignups = numSignups;
934
+ this.setTotalSignups = (totalSignups) => {
935
+ this.totalSignups = totalSignups;
1004
936
  };
1005
937
  /**
1006
938
  * Get the number of signups
1007
939
  * @returns The number of signups
1008
940
  */
1009
- this.getNumSignups = () => this.numSignups;
941
+ this.gettotalSignups = () => this.totalSignups;
1010
942
  this.pollEndTimestamp = pollEndTimestamp;
1011
943
  this.coordinatorKeypair = coordinatorKeypair;
1012
944
  this.treeDepths = treeDepths;
@@ -1018,22 +950,52 @@ class Poll {
1018
950
  this.maxVoteOptions = constants_1.VOTE_OPTION_TREE_ARITY ** treeDepths.voteOptionTreeDepth;
1019
951
  this.maciStateRef = maciStateRef;
1020
952
  this.pollId = BigInt(maciStateRef.polls.size);
1021
- this.stateTreeDepth = maciStateRef.stateTreeDepth;
1022
- this.actualStateTreeDepth = maciStateRef.stateTreeDepth;
953
+ this.actualStateTreeDepth = treeDepths.stateTreeDepth;
1023
954
  this.currentMessageBatchIndex = 0;
955
+ this.mode = mode;
1024
956
  this.pollNullifiers = new Map();
1025
957
  this.tallyResult = new Array(this.maxVoteOptions).fill(0n);
1026
- this.perVOSpentVoiceCredits = new Array(this.maxVoteOptions).fill(0n);
958
+ this.perVoteOptionSpentVoiceCredits = new Array(this.maxVoteOptions).fill(0n);
1027
959
  // we put a blank state leaf to prevent a DoS attack
1028
- this.emptyBallot = domainobjs_1.Ballot.genBlankBallot(this.maxVoteOptions, treeDepths.voteOptionTreeDepth);
960
+ this.emptyBallot = domainobjs_1.Ballot.generateBlank(this.maxVoteOptions, treeDepths.voteOptionTreeDepth);
1029
961
  this.ballots.push(this.emptyBallot);
1030
962
  }
963
+ /**
964
+ * Get voice credits left for the voting command.
965
+ *
966
+ * @param args - arguments for getting voice credits
967
+ * @returns voice credits left
968
+ */
969
+ getVoiceCreditsLeft({ stateLeaf, originalVoteWeight, newVoteWeight, mode }) {
970
+ switch (mode) {
971
+ case constants_1.EMode.QV: {
972
+ // the voice credits left are:
973
+ // voiceCreditsBalance (how many the user has) +
974
+ // voiceCreditsPreviouslySpent (the original vote weight for this option) ** 2 -
975
+ // command.newVoteWeight ** 2 (the new vote weight squared)
976
+ // basically we are replacing the previous vote weight for this
977
+ // particular vote option with the new one
978
+ // but we need to ensure that we are not going >= balance
979
+ return stateLeaf.voiceCreditBalance + originalVoteWeight * originalVoteWeight - newVoteWeight * newVoteWeight;
980
+ }
981
+ case constants_1.EMode.NON_QV:
982
+ case constants_1.EMode.FULL: {
983
+ // for non quadratic voting, we simply remove the exponentiation
984
+ // for full credits voting, it will be zero
985
+ return stateLeaf.voiceCreditBalance + originalVoteWeight - newVoteWeight;
986
+ }
987
+ default: {
988
+ throw new Error("Voting mode is not supported");
989
+ }
990
+ }
991
+ }
1031
992
  /**
1032
993
  * Serialize the Poll object to a JSON object
1033
994
  * @returns a JSON object
1034
995
  */
1035
996
  toJSON() {
1036
997
  return {
998
+ stateTreeDepth: Number(this.treeDepths.stateTreeDepth),
1037
999
  pollEndTimestamp: this.pollEndTimestamp.toString(),
1038
1000
  treeDepths: this.treeDepths,
1039
1001
  batchSizes: this.batchSizes,
@@ -1042,16 +1004,17 @@ class Poll {
1042
1004
  messages: this.messages.map((message) => message.toJSON()),
1043
1005
  commands: this.commands.map((command) => command.toJSON()),
1044
1006
  ballots: this.ballots.map((ballot) => ballot.toJSON()),
1045
- encPubKeys: this.encPubKeys.map((encPubKey) => encPubKey.serialize()),
1007
+ encryptionPublicKeys: this.encryptionPublicKeys.map((encryptionPublicKey) => encryptionPublicKey.serialize()),
1046
1008
  currentMessageBatchIndex: this.currentMessageBatchIndex,
1047
- pubKeys: this.pubKeys.map((leaf) => leaf.toJSON()),
1009
+ publicKeys: this.publicKeys.map((leaf) => leaf.toJSON()),
1048
1010
  pollStateLeaves: this.pollStateLeaves.map((leaf) => leaf.toJSON()),
1049
1011
  results: this.tallyResult.map((result) => result.toString()),
1050
- numBatchesProcessed: this.numBatchesProcessed,
1051
- numSignups: this.numSignups.toString(),
1012
+ totalBatchesProcessed: this.totalBatchesProcessed,
1013
+ totalSignups: this.totalSignups.toString(),
1052
1014
  chainHash: this.chainHash.toString(),
1053
1015
  pollNullifiers: [...this.pollNullifiers.keys()].map((nullifier) => nullifier.toString()),
1054
1016
  batchHashes: this.batchHashes.map((batchHash) => batchHash.toString()),
1017
+ mode: this.mode,
1055
1018
  };
1056
1019
  }
1057
1020
  /**
@@ -1061,21 +1024,21 @@ class Poll {
1061
1024
  * @returns a new Poll instance
1062
1025
  */
1063
1026
  static fromJSON(json, maciState) {
1064
- const poll = new Poll(BigInt(json.pollEndTimestamp), new domainobjs_1.Keypair(), json.treeDepths, json.batchSizes, maciState, BigInt(json.voteOptions));
1027
+ const poll = new Poll(BigInt(json.pollEndTimestamp), new domainobjs_1.Keypair(), json.treeDepths, json.batchSizes, maciState, BigInt(json.voteOptions), json.mode);
1065
1028
  // set all properties
1066
1029
  poll.pollStateLeaves = json.pollStateLeaves.map((leaf) => domainobjs_1.StateLeaf.fromJSON(leaf));
1067
1030
  poll.ballots = json.ballots.map((ballot) => domainobjs_1.Ballot.fromJSON(ballot));
1068
- poll.encPubKeys = json.encPubKeys.map((key) => domainobjs_1.PubKey.deserialize(key));
1031
+ poll.encryptionPublicKeys = json.encryptionPublicKeys.map((key) => domainobjs_1.PublicKey.deserialize(key));
1069
1032
  poll.messages = json.messages.map((message) => domainobjs_1.Message.fromJSON(message));
1070
- poll.commands = json.commands.map((command) => domainobjs_1.PCommand.fromJSON(command));
1033
+ poll.commands = json.commands.map((command) => domainobjs_1.VoteCommand.fromJSON(command));
1071
1034
  poll.tallyResult = json.results.map((result) => BigInt(result));
1072
1035
  poll.currentMessageBatchIndex = json.currentMessageBatchIndex;
1073
- poll.numBatchesProcessed = json.numBatchesProcessed;
1036
+ poll.totalBatchesProcessed = json.totalBatchesProcessed;
1074
1037
  poll.chainHash = BigInt(json.chainHash);
1075
1038
  poll.batchHashes = json.batchHashes.map((batchHash) => BigInt(batchHash));
1076
1039
  poll.pollNullifiers = new Map(json.pollNullifiers.map((nullifier) => [BigInt(nullifier), true]));
1077
1040
  // copy maci state
1078
- poll.updatePoll(BigInt(json.numSignups));
1041
+ poll.updatePoll(BigInt(json.totalSignups));
1079
1042
  return poll;
1080
1043
  }
1081
1044
  }