@maci-protocol/core 0.0.0-ci.f4bc8a6 → 0.0.0-ci.f4e2c46

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