@maci-protocol/core 0.0.0-ci.98aa65d → 0.0.0-ci.9acdf3f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -2
- package/build/ts/MaciState.d.ts +7 -7
- package/build/ts/MaciState.d.ts.map +1 -1
- package/build/ts/MaciState.js +17 -17
- package/build/ts/MaciState.js.map +1 -1
- package/build/ts/Poll.d.ts +28 -30
- package/build/ts/Poll.d.ts.map +1 -1
- package/build/ts/Poll.js +159 -162
- package/build/ts/Poll.js.map +1 -1
- package/build/ts/index.d.ts +2 -2
- package/build/ts/index.d.ts.map +1 -1
- package/build/ts/index.js +5 -5
- package/build/ts/index.js.map +1 -1
- package/build/ts/utils/constants.d.ts +1 -0
- package/build/ts/utils/constants.d.ts.map +1 -1
- package/build/ts/utils/constants.js +2 -1
- package/build/ts/utils/constants.js.map +1 -1
- package/build/ts/utils/types.d.ts +32 -32
- package/build/ts/utils/types.d.ts.map +1 -1
- package/build/ts/utils/utils.d.ts +16 -16
- package/build/ts/utils/utils.d.ts.map +1 -1
- package/build/ts/utils/utils.js +21 -21
- package/build/ts/utils/utils.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +5 -5
package/build/ts/Poll.js
CHANGED
|
@@ -27,9 +27,9 @@ class Poll {
|
|
|
27
27
|
this.ballots = [];
|
|
28
28
|
this.messages = [];
|
|
29
29
|
this.commands = [];
|
|
30
|
-
this.
|
|
30
|
+
this.encryptionPublicKeys = [];
|
|
31
31
|
this.stateCopied = false;
|
|
32
|
-
this.
|
|
32
|
+
this.publicKeys = [domainobjs_1.padKey];
|
|
33
33
|
// For message processing
|
|
34
34
|
this.numBatchesProcessed = 0;
|
|
35
35
|
this.sbSalts = {};
|
|
@@ -38,7 +38,7 @@ class Poll {
|
|
|
38
38
|
this.spentVoiceCreditSubtotalSalts = {};
|
|
39
39
|
// For vote tallying
|
|
40
40
|
this.tallyResult = [];
|
|
41
|
-
this.
|
|
41
|
+
this.perVoteOptionSpentVoiceCredits = [];
|
|
42
42
|
this.numBatchesTallied = 0;
|
|
43
43
|
this.totalSpentVoiceCredits = 0n;
|
|
44
44
|
// message chain hash
|
|
@@ -48,7 +48,7 @@ class Poll {
|
|
|
48
48
|
// Poll state tree leaves
|
|
49
49
|
this.pollStateLeaves = [domainobjs_1.blankStateLeaf];
|
|
50
50
|
// how many users signed up
|
|
51
|
-
this.
|
|
51
|
+
this.totalSignups = 0n;
|
|
52
52
|
/**
|
|
53
53
|
* Check if user has already joined the poll by checking if the nullifier is registered
|
|
54
54
|
*/
|
|
@@ -56,13 +56,12 @@ class Poll {
|
|
|
56
56
|
/**
|
|
57
57
|
* Join the anonymous user to the Poll (to the tree)
|
|
58
58
|
* @param nullifier - Hashed private key used as nullifier
|
|
59
|
-
* @param
|
|
59
|
+
* @param publicKey - The poll public key.
|
|
60
60
|
* @param newVoiceCreditBalance - New voice credit balance of the user.
|
|
61
|
-
* @param timestamp - The timestamp of the sign-up.
|
|
62
61
|
* @returns The index of added state leaf
|
|
63
62
|
*/
|
|
64
|
-
this.joinPoll = (nullifier,
|
|
65
|
-
const stateLeaf = new domainobjs_1.StateLeaf(
|
|
63
|
+
this.joinPoll = (nullifier, publicKey, newVoiceCreditBalance) => {
|
|
64
|
+
const stateLeaf = new domainobjs_1.StateLeaf(publicKey, newVoiceCreditBalance);
|
|
66
65
|
if (this.hasJoined(nullifier)) {
|
|
67
66
|
throw new Error("UserAlreadyJoined");
|
|
68
67
|
}
|
|
@@ -75,11 +74,11 @@ class Poll {
|
|
|
75
74
|
* Update a Poll with data from MaciState.
|
|
76
75
|
* This is the step where we copy the state from the MaciState instance,
|
|
77
76
|
* and set the number of signups we have so far.
|
|
78
|
-
* @note It should be called to generate the state for poll joining with
|
|
79
|
-
* the number of signups in the MaciState. For message processing, you should set
|
|
77
|
+
* @note It should be called to generate the state for poll joining with totalSignups set as
|
|
78
|
+
* the number of signups in the MaciState. For message processing, you should set totalSignups as
|
|
80
79
|
* the number of users who joined the poll.
|
|
81
80
|
*/
|
|
82
|
-
this.updatePoll = (
|
|
81
|
+
this.updatePoll = (totalSignups) => {
|
|
83
82
|
// there might be occasions where we fetch logs after new signups have been made
|
|
84
83
|
// logs are fetched (and MaciState/Poll created locally).
|
|
85
84
|
// If someone signs up after that and we fetch that record
|
|
@@ -87,15 +86,15 @@ class Poll {
|
|
|
87
86
|
// not match. For this, we must only copy up to the number of signups
|
|
88
87
|
// Copy the state tree, ballot tree, state leaves, and ballot leaves
|
|
89
88
|
// start by setting the number of signups
|
|
90
|
-
this.
|
|
91
|
-
// copy up to
|
|
92
|
-
this.
|
|
89
|
+
this.setTotalSignups(totalSignups);
|
|
90
|
+
// copy up to totalSignups state leaves
|
|
91
|
+
this.publicKeys = this.maciStateRef.publicKeys.slice(0, Number(this.totalSignups)).map((x) => x.copy());
|
|
93
92
|
// ensure we have the correct actual state tree depth value
|
|
94
|
-
this.actualStateTreeDepth = Math.max(1, Math.ceil(Math.log2(Number(this.
|
|
93
|
+
this.actualStateTreeDepth = Math.max(1, Math.ceil(Math.log2(Number(this.totalSignups))));
|
|
95
94
|
this.stateTree = new lean_imt_1.LeanIMT(crypto_1.hashLeanIMT);
|
|
96
95
|
// add all leaves
|
|
97
|
-
this.
|
|
98
|
-
this.stateTree?.insert(
|
|
96
|
+
this.publicKeys.forEach((publicKey) => {
|
|
97
|
+
this.stateTree?.insert(publicKey.hash());
|
|
99
98
|
});
|
|
100
99
|
// create a poll state tree
|
|
101
100
|
this.pollStateTree = new crypto_1.IncrementalQuinTree(this.actualStateTreeDepth, domainobjs_1.blankStateLeafHash, constants_1.STATE_TREE_ARITY, crypto_1.hash2);
|
|
@@ -104,10 +103,10 @@ class Poll {
|
|
|
104
103
|
});
|
|
105
104
|
// Create as many ballots as state leaves
|
|
106
105
|
this.emptyBallotHash = this.emptyBallot.hash();
|
|
107
|
-
this.ballotTree = new crypto_1.IncrementalQuinTree(this.stateTreeDepth, this.emptyBallotHash, constants_1.STATE_TREE_ARITY, crypto_1.hash2);
|
|
106
|
+
this.ballotTree = new crypto_1.IncrementalQuinTree(Number(this.treeDepths.stateTreeDepth), this.emptyBallotHash, constants_1.STATE_TREE_ARITY, crypto_1.hash2);
|
|
108
107
|
this.ballotTree.insert(this.emptyBallotHash);
|
|
109
108
|
// we fill the ballotTree with empty ballots hashes to match the number of signups in the tree
|
|
110
|
-
while (this.ballots.length < this.
|
|
109
|
+
while (this.ballots.length < this.publicKeys.length) {
|
|
111
110
|
this.ballotTree.insert(this.emptyBallotHash);
|
|
112
111
|
this.ballots.push(this.emptyBallot);
|
|
113
112
|
}
|
|
@@ -116,14 +115,14 @@ class Poll {
|
|
|
116
115
|
/**
|
|
117
116
|
* Process one message.
|
|
118
117
|
* @param message - The message to process.
|
|
119
|
-
* @param
|
|
118
|
+
* @param encryptionPublicKey - The public key associated with the encryption private key.
|
|
120
119
|
* @returns A number of variables which will be used in the zk-SNARK circuit.
|
|
121
120
|
*/
|
|
122
|
-
this.processMessage = (message,
|
|
121
|
+
this.processMessage = (message, encryptionPublicKey, qv = true) => {
|
|
123
122
|
try {
|
|
124
123
|
// Decrypt the message
|
|
125
|
-
const sharedKey = domainobjs_1.Keypair.
|
|
126
|
-
const { command, signature } = domainobjs_1.
|
|
124
|
+
const sharedKey = domainobjs_1.Keypair.generateEcdhSharedKey(this.coordinatorKeypair.privateKey, encryptionPublicKey);
|
|
125
|
+
const { command, signature } = domainobjs_1.VoteCommand.decrypt(message, sharedKey);
|
|
127
126
|
const stateLeafIndex = command.stateIndex;
|
|
128
127
|
// If the state tree index in the command is invalid, do nothing
|
|
129
128
|
if (stateLeafIndex >= BigInt(this.ballots.length) ||
|
|
@@ -136,7 +135,7 @@ class Poll {
|
|
|
136
135
|
// The ballot to update (or not)
|
|
137
136
|
const ballot = this.ballots[Number(stateLeafIndex)];
|
|
138
137
|
// If the signature is invalid, do nothing
|
|
139
|
-
if (!command.verifySignature(signature, stateLeaf.
|
|
138
|
+
if (!command.verifySignature(signature, stateLeaf.publicKey)) {
|
|
140
139
|
throw new errors_1.ProcessMessageError(errors_1.ProcessMessageErrors.InvalidSignature);
|
|
141
140
|
}
|
|
142
141
|
// If the nonce is invalid, do nothing
|
|
@@ -171,7 +170,7 @@ class Poll {
|
|
|
171
170
|
const newStateLeaf = stateLeaf.copy();
|
|
172
171
|
newStateLeaf.voiceCreditBalance = voiceCreditsLeft;
|
|
173
172
|
// if the key changes, this is effectively a key-change message too
|
|
174
|
-
newStateLeaf.
|
|
173
|
+
newStateLeaf.publicKey = command.newPublicKey.copy();
|
|
175
174
|
// Deep-copy the ballot and update its attributes
|
|
176
175
|
const newBallot = ballot.copy();
|
|
177
176
|
// increase the nonce
|
|
@@ -181,17 +180,17 @@ class Poll {
|
|
|
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
|
|
183
|
+
const { pathElements: originalStateLeafPathElements } = this.pollStateTree.genProof(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
|
|
186
|
+
const { pathElements: originalBallotPathElements } = this.ballotTree.genProof(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
|
|
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
|
-
|
|
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 =
|
|
193
|
+
const { pathElements: originalVoteWeightsPathElements } = voteTree.genProof(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
|
|
222
|
+
* @param encryptionPublicKey - The public key used to encrypt the message
|
|
224
223
|
*/
|
|
225
|
-
this.publishMessage = (message,
|
|
226
|
-
(0, assert_1.default)(
|
|
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
|
|
231
|
-
this.
|
|
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(
|
|
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.
|
|
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.
|
|
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
|
|
250
|
-
const command = new domainobjs_1.
|
|
248
|
+
const keypair = new domainobjs_1.Keypair();
|
|
249
|
+
const command = new domainobjs_1.VoteCommand(0n, keypair.publicKey, 0n, 0n, 0n, 0n, 0n);
|
|
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
|
|
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 = ({
|
|
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(
|
|
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
|
-
|
|
296
|
-
|
|
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 = ({
|
|
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.genProof(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
|
-
|
|
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,
|
|
@@ -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.
|
|
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
|
|
408
|
+
let encryptionPublicKey;
|
|
413
409
|
if (idx < this.messages.length) {
|
|
414
410
|
message = this.messages[idx];
|
|
415
|
-
|
|
411
|
+
encryptionPublicKey = this.encryptionPublicKeys[idx];
|
|
416
412
|
try {
|
|
417
413
|
// check if the command is valid
|
|
418
|
-
const
|
|
419
|
-
const index =
|
|
414
|
+
const { stateLeafIndex, originalStateLeaf, originalBallot, originalVoteWeight, originalVoteWeightsPathElements, originalStateLeafPathElements, originalBallotPathElements, newStateLeaf, newBallot, } = this.processMessage(message, encryptionPublicKey, qv);
|
|
415
|
+
const index = stateLeafIndex;
|
|
420
416
|
// we add at position 0 the original data
|
|
421
|
-
currentStateLeaves.unshift(
|
|
422
|
-
currentBallots.unshift(
|
|
423
|
-
currentVoteWeights.unshift(
|
|
424
|
-
currentVoteWeightsPathElements.unshift(
|
|
425
|
-
currentStateLeavesPathElements.unshift(
|
|
426
|
-
currentBallotsPathElements.unshift(
|
|
417
|
+
currentStateLeaves.unshift(originalStateLeaf);
|
|
418
|
+
currentBallots.unshift(originalBallot);
|
|
419
|
+
currentVoteWeights.unshift(originalVoteWeight);
|
|
420
|
+
currentVoteWeightsPathElements.unshift(originalVoteWeightsPathElements);
|
|
421
|
+
currentStateLeavesPathElements.unshift(originalStateLeafPathElements);
|
|
422
|
+
currentBallotsPathElements.unshift(originalBallotPathElements);
|
|
427
423
|
// update the state leaves with the new state leaf (result of processing the message)
|
|
428
|
-
this.pollStateLeaves[index] =
|
|
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,
|
|
426
|
+
this.pollStateTree?.update(index, newStateLeaf.hash());
|
|
431
427
|
// store the new ballot
|
|
432
|
-
this.ballots[index] =
|
|
428
|
+
this.ballots[index] = newBallot;
|
|
433
429
|
// update the ballot tree
|
|
434
|
-
this.ballotTree?.update(index,
|
|
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,10 +446,10 @@ 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
|
-
//
|
|
454
|
-
const sharedKey = domainobjs_1.Keypair.
|
|
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.
|
|
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
|
|
@@ -471,24 +467,24 @@ 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
|
|
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
|
-
|
|
473
|
+
voteTree.insert(ballot.votes[j]);
|
|
478
474
|
}
|
|
479
475
|
// get the path elements for the first vote leaf
|
|
480
|
-
currentVoteWeightsPathElements.unshift(
|
|
476
|
+
currentVoteWeightsPathElements.unshift(voteTree.genProof(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
|
|
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
|
-
|
|
484
|
+
voteTree.insert(ballot.votes[j]);
|
|
489
485
|
}
|
|
490
486
|
// get the path elements for the first vote leaf
|
|
491
|
-
currentVoteWeightsPathElements.unshift(
|
|
487
|
+
currentVoteWeightsPathElements.unshift(voteTree.genProof(0).pathElements);
|
|
492
488
|
}
|
|
493
489
|
}
|
|
494
490
|
else {
|
|
@@ -500,10 +496,10 @@ class Poll {
|
|
|
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
|
|
504
|
-
|
|
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(
|
|
502
|
+
currentVoteWeightsPathElements.unshift(voteTree.genProof(0).pathElements);
|
|
507
503
|
}
|
|
508
504
|
}
|
|
509
505
|
else {
|
|
@@ -521,10 +517,10 @@ class Poll {
|
|
|
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
|
|
525
|
-
|
|
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(
|
|
523
|
+
currentVoteWeightsPathElements.unshift(voteTree.genProof(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
|
}
|
|
@@ -547,9 +543,9 @@ class Poll {
|
|
|
547
543
|
this.currentMessageBatchIndex -= 1;
|
|
548
544
|
}
|
|
549
545
|
// ensure newSbSalt differs from currentSbSalt
|
|
550
|
-
let newSbSalt = (0, crypto_1.
|
|
546
|
+
let newSbSalt = (0, crypto_1.generateRandomSalt)();
|
|
551
547
|
while (this.sbSalts[this.currentMessageBatchIndex] === newSbSalt) {
|
|
552
|
-
newSbSalt = (0, crypto_1.
|
|
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,7 +555,7 @@ 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.
|
|
558
|
+
const coordinatorPublicKeyHash = this.coordinatorKeypair.publicKey.hash();
|
|
563
559
|
// If this is the last batch, release the lock
|
|
564
560
|
if (this.numBatchesProcessed * batchSize >= this.messages.length) {
|
|
565
561
|
this.maciStateRef.pollBeingProcessed = false;
|
|
@@ -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.
|
|
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
|
|
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
|
-
//
|
|
590
|
-
const ecdh = domainobjs_1.Keypair.
|
|
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.
|
|
588
|
+
const emptyCommand = new domainobjs_1.VoteCommand(0n, key.publicKey, 0n, 0n, 0n, 0n, 0n);
|
|
593
589
|
// encrypt it
|
|
594
|
-
const
|
|
590
|
+
const emptyMessage = emptyCommand.encrypt(emptyCommand.sign(key.privateKey), ecdh);
|
|
595
591
|
// copy the messages to a new array
|
|
596
|
-
let
|
|
592
|
+
let messages = this.messages.map((x) => x.asCircuitInputs());
|
|
597
593
|
// pad with our state index 0 message
|
|
598
|
-
while (
|
|
599
|
-
|
|
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
|
|
603
|
-
while (
|
|
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
|
-
|
|
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
|
|
611
|
+
// it slice messages array from index of first message in current batch to
|
|
616
612
|
// index of last message in current batch
|
|
617
|
-
|
|
613
|
+
messages = messages.slice(batchStartIndex, index * messageBatchSize);
|
|
618
614
|
// then take the ones part of this batch
|
|
619
|
-
|
|
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
|
-
|
|
626
|
+
totalSignups: BigInt(this.totalSignups),
|
|
631
627
|
batchEndIndex: BigInt(batchEndIndex),
|
|
632
628
|
index: BigInt(batchStartIndex),
|
|
633
629
|
inputBatchHash,
|
|
634
630
|
outputBatchHash,
|
|
635
|
-
|
|
631
|
+
messages,
|
|
636
632
|
actualStateTreeDepth: BigInt(this.actualStateTreeDepth),
|
|
637
|
-
|
|
638
|
-
|
|
633
|
+
coordinatorPrivateKey: this.coordinatorKeypair.privateKey.asCircuitInputs(),
|
|
634
|
+
encryptionPublicKeys: encryptionPublicKeys.map((x) => x.asCircuitInputs()),
|
|
639
635
|
currentStateRoot,
|
|
640
636
|
currentBallotRoot,
|
|
641
637
|
currentSbCommitment,
|
|
@@ -678,12 +674,12 @@ class Poll {
|
|
|
678
674
|
const batchStartIndex = this.numBatchesTallied * batchSize;
|
|
679
675
|
// get the salts needed for the commitments
|
|
680
676
|
const currentResultsRootSalt = batchStartIndex === 0 ? 0n : this.resultRootSalts[batchStartIndex - batchSize];
|
|
681
|
-
const
|
|
677
|
+
const currentPerVoteOptionSpentVoiceCreditsRootSalt = batchStartIndex === 0 ? 0n : this.preVOSpentVoiceCreditsRootSalts[batchStartIndex - batchSize];
|
|
682
678
|
const currentSpentVoiceCreditSubtotalSalt = batchStartIndex === 0 ? 0n : this.spentVoiceCreditSubtotalSalts[batchStartIndex - batchSize];
|
|
683
679
|
// generate a commitment to the current results
|
|
684
|
-
const currentResultsCommitment = (0, crypto_1.
|
|
685
|
-
// generate a commitment to the current per
|
|
686
|
-
const currentPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(
|
|
680
|
+
const currentResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, currentResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
|
|
681
|
+
// generate a commitment to the current per vote option spent voice credits
|
|
682
|
+
const currentPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(currentPerVoteOptionSpentVoiceCreditsRootSalt, batchStartIndex, true);
|
|
687
683
|
// generate a commitment to the current spent voice credits
|
|
688
684
|
const currentSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(currentSpentVoiceCreditSubtotalSalt, batchStartIndex, true);
|
|
689
685
|
// the current commitment for the first batch will be 0
|
|
@@ -702,7 +698,7 @@ class Poll {
|
|
|
702
698
|
]);
|
|
703
699
|
const ballots = [];
|
|
704
700
|
const currentResults = this.tallyResult.map((x) => BigInt(x.toString()));
|
|
705
|
-
const
|
|
701
|
+
const currentPerVoteOptionSpentVoiceCredits = this.perVoteOptionSpentVoiceCredits.map((x) => BigInt(x.toString()));
|
|
706
702
|
const currentSpentVoiceCreditSubtotal = BigInt(this.totalSpentVoiceCredits.toString());
|
|
707
703
|
// loop in normal order to tally the ballots one by one
|
|
708
704
|
for (let i = this.numBatchesTallied * batchSize; i < this.numBatchesTallied * batchSize + batchSize; i += 1) {
|
|
@@ -718,7 +714,7 @@ class Poll {
|
|
|
718
714
|
// the vote itself will be a quadratic vote (sqrt(voiceCredits))
|
|
719
715
|
this.tallyResult[j] += v;
|
|
720
716
|
// the per vote option spent voice credits will be the sum of the squares of the votes
|
|
721
|
-
this.
|
|
717
|
+
this.perVoteOptionSpentVoiceCredits[j] += v * v;
|
|
722
718
|
// the total spent voice credits will be the sum of the squares of the votes
|
|
723
719
|
this.totalSpentVoiceCredits += v * v;
|
|
724
720
|
}
|
|
@@ -729,19 +725,19 @@ class Poll {
|
|
|
729
725
|
ballots.push(emptyBallot);
|
|
730
726
|
}
|
|
731
727
|
// generate the new salts
|
|
732
|
-
const newResultsRootSalt = (0, crypto_1.
|
|
733
|
-
const
|
|
734
|
-
const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.
|
|
728
|
+
const newResultsRootSalt = (0, crypto_1.generateRandomSalt)();
|
|
729
|
+
const newPerVoteOptionSpentVoiceCreditsRootSalt = (0, crypto_1.generateRandomSalt)();
|
|
730
|
+
const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.generateRandomSalt)();
|
|
735
731
|
// and save them to be used in the next batch
|
|
736
732
|
this.resultRootSalts[batchStartIndex] = newResultsRootSalt;
|
|
737
|
-
this.preVOSpentVoiceCreditsRootSalts[batchStartIndex] =
|
|
733
|
+
this.preVOSpentVoiceCreditsRootSalts[batchStartIndex] = newPerVoteOptionSpentVoiceCreditsRootSalt;
|
|
738
734
|
this.spentVoiceCreditSubtotalSalts[batchStartIndex] = newSpentVoiceCreditSubtotalSalt;
|
|
739
735
|
// generate the new results commitment with the new salts and data
|
|
740
|
-
const newResultsCommitment = (0, crypto_1.
|
|
736
|
+
const newResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, newResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
|
|
741
737
|
// generate the new spent voice credits commitment with the new salts and data
|
|
742
738
|
const newSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(newSpentVoiceCreditSubtotalSalt, batchStartIndex + batchSize, true);
|
|
743
|
-
// generate the new per
|
|
744
|
-
const newPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(
|
|
739
|
+
// generate the new per vote option spent voice credits commitment with the new salts and data
|
|
740
|
+
const newPerVOSpentVoiceCreditsCommitment = this.genPerVOSpentVoiceCreditsCommitment(newPerVoteOptionSpentVoiceCreditsRootSalt, batchStartIndex + batchSize, true);
|
|
745
741
|
// generate the new tally commitment
|
|
746
742
|
const newTallyCommitment = (0, crypto_1.hash3)([
|
|
747
743
|
newResultsCommitment,
|
|
@@ -760,7 +756,7 @@ class Poll {
|
|
|
760
756
|
ballotRoot,
|
|
761
757
|
sbSalt,
|
|
762
758
|
index: BigInt(batchStartIndex),
|
|
763
|
-
|
|
759
|
+
totalSignups: BigInt(this.totalSignups),
|
|
764
760
|
sbCommitment,
|
|
765
761
|
currentTallyCommitment,
|
|
766
762
|
newTallyCommitment,
|
|
@@ -771,10 +767,10 @@ class Poll {
|
|
|
771
767
|
currentResultsRootSalt,
|
|
772
768
|
currentSpentVoiceCreditSubtotal,
|
|
773
769
|
currentSpentVoiceCreditSubtotalSalt,
|
|
774
|
-
|
|
775
|
-
|
|
770
|
+
currentPerVoteOptionSpentVoiceCredits,
|
|
771
|
+
currentPerVoteOptionSpentVoiceCreditsRootSalt,
|
|
776
772
|
newResultsRootSalt,
|
|
777
|
-
|
|
773
|
+
newPerVoteOptionSpentVoiceCreditsRootSalt,
|
|
778
774
|
newSpentVoiceCreditSubtotalSalt,
|
|
779
775
|
});
|
|
780
776
|
this.numBatchesTallied += 1;
|
|
@@ -793,7 +789,7 @@ class Poll {
|
|
|
793
789
|
const currentResultsRootSalt = batchStartIndex === 0 ? 0n : this.resultRootSalts[batchStartIndex - batchSize];
|
|
794
790
|
const currentSpentVoiceCreditSubtotalSalt = batchStartIndex === 0 ? 0n : this.spentVoiceCreditSubtotalSalts[batchStartIndex - batchSize];
|
|
795
791
|
// generate a commitment to the current results
|
|
796
|
-
const currentResultsCommitment = (0, crypto_1.
|
|
792
|
+
const currentResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, currentResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
|
|
797
793
|
// generate a commitment to the current spent voice credits
|
|
798
794
|
const currentSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(currentSpentVoiceCreditSubtotalSalt, batchStartIndex, false);
|
|
799
795
|
// the current commitment for the first batch will be 0
|
|
@@ -828,13 +824,13 @@ class Poll {
|
|
|
828
824
|
ballots.push(emptyBallot);
|
|
829
825
|
}
|
|
830
826
|
// generate the new salts
|
|
831
|
-
const newResultsRootSalt = (0, crypto_1.
|
|
832
|
-
const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.
|
|
827
|
+
const newResultsRootSalt = (0, crypto_1.generateRandomSalt)();
|
|
828
|
+
const newSpentVoiceCreditSubtotalSalt = (0, crypto_1.generateRandomSalt)();
|
|
833
829
|
// and save them to be used in the next batch
|
|
834
830
|
this.resultRootSalts[batchStartIndex] = newResultsRootSalt;
|
|
835
831
|
this.spentVoiceCreditSubtotalSalts[batchStartIndex] = newSpentVoiceCreditSubtotalSalt;
|
|
836
832
|
// generate the new results commitment with the new salts and data
|
|
837
|
-
const newResultsCommitment = (0, crypto_1.
|
|
833
|
+
const newResultsCommitment = (0, crypto_1.generateTreeCommitment)(this.tallyResult, newResultsRootSalt, this.treeDepths.voteOptionTreeDepth);
|
|
838
834
|
// generate the new spent voice credits commitment with the new salts and data
|
|
839
835
|
const newSpentVoiceCreditsCommitment = this.genSpentVoiceCreditSubtotalCommitment(newSpentVoiceCreditSubtotalSalt, batchStartIndex + batchSize, false);
|
|
840
836
|
// generate the new tally commitment
|
|
@@ -851,7 +847,7 @@ class Poll {
|
|
|
851
847
|
ballotRoot,
|
|
852
848
|
sbSalt,
|
|
853
849
|
index: BigInt(batchStartIndex),
|
|
854
|
-
|
|
850
|
+
totalSignups: BigInt(this.totalSignups),
|
|
855
851
|
sbCommitment,
|
|
856
852
|
currentTallyCommitment,
|
|
857
853
|
newTallyCommitment,
|
|
@@ -911,7 +907,7 @@ class Poll {
|
|
|
911
907
|
leaves[j] += useQuadraticVoting ? v * v : v;
|
|
912
908
|
}
|
|
913
909
|
}
|
|
914
|
-
return (0, crypto_1.
|
|
910
|
+
return (0, crypto_1.generateTreeCommitment)(leaves, salt, this.treeDepths.voteOptionTreeDepth);
|
|
915
911
|
};
|
|
916
912
|
/**
|
|
917
913
|
* Create a deep copy of the Poll object.
|
|
@@ -921,23 +917,24 @@ class Poll {
|
|
|
921
917
|
const copied = new Poll(BigInt(this.pollEndTimestamp.toString()), this.coordinatorKeypair.copy(), {
|
|
922
918
|
intStateTreeDepth: Number(this.treeDepths.intStateTreeDepth),
|
|
923
919
|
voteOptionTreeDepth: Number(this.treeDepths.voteOptionTreeDepth),
|
|
920
|
+
stateTreeDepth: Number(this.treeDepths.stateTreeDepth),
|
|
924
921
|
}, {
|
|
925
922
|
tallyBatchSize: Number(this.batchSizes.tallyBatchSize.toString()),
|
|
926
923
|
messageBatchSize: Number(this.batchSizes.messageBatchSize.toString()),
|
|
927
924
|
}, this.maciStateRef, this.voteOptions);
|
|
928
|
-
copied.
|
|
925
|
+
copied.publicKeys = this.publicKeys.map((x) => x.copy());
|
|
929
926
|
copied.pollStateLeaves = this.pollStateLeaves.map((x) => x.copy());
|
|
930
927
|
copied.messages = this.messages.map((x) => x.copy());
|
|
931
928
|
copied.commands = this.commands.map((x) => x.copy());
|
|
932
929
|
copied.ballots = this.ballots.map((x) => x.copy());
|
|
933
|
-
copied.
|
|
930
|
+
copied.encryptionPublicKeys = this.encryptionPublicKeys.map((x) => x.copy());
|
|
934
931
|
if (this.ballotTree) {
|
|
935
932
|
copied.ballotTree = this.ballotTree.copy();
|
|
936
933
|
}
|
|
937
934
|
copied.currentMessageBatchIndex = this.currentMessageBatchIndex;
|
|
938
935
|
copied.maciStateRef = this.maciStateRef;
|
|
939
936
|
copied.tallyResult = this.tallyResult.map((x) => BigInt(x.toString()));
|
|
940
|
-
copied.
|
|
937
|
+
copied.perVoteOptionSpentVoiceCredits = this.perVoteOptionSpentVoiceCredits.map((x) => BigInt(x.toString()));
|
|
941
938
|
copied.numBatchesProcessed = Number(this.numBatchesProcessed.toString());
|
|
942
939
|
copied.numBatchesTallied = Number(this.numBatchesTallied.toString());
|
|
943
940
|
copied.pollId = this.pollId;
|
|
@@ -959,34 +956,34 @@ class Poll {
|
|
|
959
956
|
copied.spentVoiceCreditSubtotalSalts[k] = BigInt(this.spentVoiceCreditSubtotalSalts[k].toString());
|
|
960
957
|
});
|
|
961
958
|
// update the number of signups
|
|
962
|
-
copied.
|
|
959
|
+
copied.setTotalSignups(this.totalSignups);
|
|
963
960
|
return copied;
|
|
964
961
|
};
|
|
965
962
|
/**
|
|
966
963
|
* Check if the Poll object is equal to another Poll object.
|
|
967
|
-
* @param
|
|
964
|
+
* @param poll - The Poll object to compare.
|
|
968
965
|
* @returns True if the two Poll objects are equal, false otherwise.
|
|
969
966
|
*/
|
|
970
|
-
this.equals = (
|
|
971
|
-
const result = this.coordinatorKeypair.equals(
|
|
972
|
-
this.treeDepths.intStateTreeDepth ===
|
|
973
|
-
this.treeDepths.voteOptionTreeDepth ===
|
|
974
|
-
this.batchSizes.tallyBatchSize ===
|
|
975
|
-
this.batchSizes.messageBatchSize ===
|
|
976
|
-
this.maxVoteOptions ===
|
|
977
|
-
this.messages.length ===
|
|
978
|
-
this.
|
|
979
|
-
this.
|
|
967
|
+
this.equals = (poll) => {
|
|
968
|
+
const result = this.coordinatorKeypair.equals(poll.coordinatorKeypair) &&
|
|
969
|
+
this.treeDepths.intStateTreeDepth === poll.treeDepths.intStateTreeDepth &&
|
|
970
|
+
this.treeDepths.voteOptionTreeDepth === poll.treeDepths.voteOptionTreeDepth &&
|
|
971
|
+
this.batchSizes.tallyBatchSize === poll.batchSizes.tallyBatchSize &&
|
|
972
|
+
this.batchSizes.messageBatchSize === poll.batchSizes.messageBatchSize &&
|
|
973
|
+
this.maxVoteOptions === poll.maxVoteOptions &&
|
|
974
|
+
this.messages.length === poll.messages.length &&
|
|
975
|
+
this.encryptionPublicKeys.length === poll.encryptionPublicKeys.length &&
|
|
976
|
+
this.totalSignups === poll.totalSignups;
|
|
980
977
|
if (!result) {
|
|
981
978
|
return false;
|
|
982
979
|
}
|
|
983
980
|
for (let i = 0; i < this.messages.length; i += 1) {
|
|
984
|
-
if (!this.messages[i].equals(
|
|
981
|
+
if (!this.messages[i].equals(poll.messages[i])) {
|
|
985
982
|
return false;
|
|
986
983
|
}
|
|
987
984
|
}
|
|
988
|
-
for (let i = 0; i < this.
|
|
989
|
-
if (!this.
|
|
985
|
+
for (let i = 0; i < this.encryptionPublicKeys.length; i += 1) {
|
|
986
|
+
if (!this.encryptionPublicKeys[i].equals(poll.encryptionPublicKeys[i])) {
|
|
990
987
|
return false;
|
|
991
988
|
}
|
|
992
989
|
}
|
|
@@ -997,20 +994,20 @@ class Poll {
|
|
|
997
994
|
* @param serializedPrivateKey - the serialized private key
|
|
998
995
|
*/
|
|
999
996
|
this.setCoordinatorKeypair = (serializedPrivateKey) => {
|
|
1000
|
-
this.coordinatorKeypair = new domainobjs_1.Keypair(domainobjs_1.
|
|
997
|
+
this.coordinatorKeypair = new domainobjs_1.Keypair(domainobjs_1.PrivateKey.deserialize(serializedPrivateKey));
|
|
1001
998
|
};
|
|
1002
999
|
/**
|
|
1003
1000
|
* Set the number of signups to match the ones from the contract
|
|
1004
|
-
* @param
|
|
1001
|
+
* @param totalSignups - the number of signups
|
|
1005
1002
|
*/
|
|
1006
|
-
this.
|
|
1007
|
-
this.
|
|
1003
|
+
this.setTotalSignups = (totalSignups) => {
|
|
1004
|
+
this.totalSignups = totalSignups;
|
|
1008
1005
|
};
|
|
1009
1006
|
/**
|
|
1010
1007
|
* Get the number of signups
|
|
1011
1008
|
* @returns The number of signups
|
|
1012
1009
|
*/
|
|
1013
|
-
this.
|
|
1010
|
+
this.gettotalSignups = () => this.totalSignups;
|
|
1014
1011
|
this.pollEndTimestamp = pollEndTimestamp;
|
|
1015
1012
|
this.coordinatorKeypair = coordinatorKeypair;
|
|
1016
1013
|
this.treeDepths = treeDepths;
|
|
@@ -1022,12 +1019,11 @@ class Poll {
|
|
|
1022
1019
|
this.maxVoteOptions = constants_1.VOTE_OPTION_TREE_ARITY ** treeDepths.voteOptionTreeDepth;
|
|
1023
1020
|
this.maciStateRef = maciStateRef;
|
|
1024
1021
|
this.pollId = BigInt(maciStateRef.polls.size);
|
|
1025
|
-
this.
|
|
1026
|
-
this.actualStateTreeDepth = maciStateRef.stateTreeDepth;
|
|
1022
|
+
this.actualStateTreeDepth = treeDepths.stateTreeDepth;
|
|
1027
1023
|
this.currentMessageBatchIndex = 0;
|
|
1028
1024
|
this.pollNullifiers = new Map();
|
|
1029
1025
|
this.tallyResult = new Array(this.maxVoteOptions).fill(0n);
|
|
1030
|
-
this.
|
|
1026
|
+
this.perVoteOptionSpentVoiceCredits = new Array(this.maxVoteOptions).fill(0n);
|
|
1031
1027
|
// we put a blank state leaf to prevent a DoS attack
|
|
1032
1028
|
this.emptyBallot = domainobjs_1.Ballot.genBlankBallot(this.maxVoteOptions, treeDepths.voteOptionTreeDepth);
|
|
1033
1029
|
this.ballots.push(this.emptyBallot);
|
|
@@ -1038,6 +1034,7 @@ class Poll {
|
|
|
1038
1034
|
*/
|
|
1039
1035
|
toJSON() {
|
|
1040
1036
|
return {
|
|
1037
|
+
stateTreeDepth: Number(this.treeDepths.stateTreeDepth),
|
|
1041
1038
|
pollEndTimestamp: this.pollEndTimestamp.toString(),
|
|
1042
1039
|
treeDepths: this.treeDepths,
|
|
1043
1040
|
batchSizes: this.batchSizes,
|
|
@@ -1046,13 +1043,13 @@ class Poll {
|
|
|
1046
1043
|
messages: this.messages.map((message) => message.toJSON()),
|
|
1047
1044
|
commands: this.commands.map((command) => command.toJSON()),
|
|
1048
1045
|
ballots: this.ballots.map((ballot) => ballot.toJSON()),
|
|
1049
|
-
|
|
1046
|
+
encryptionPublicKeys: this.encryptionPublicKeys.map((encryptionPublicKey) => encryptionPublicKey.serialize()),
|
|
1050
1047
|
currentMessageBatchIndex: this.currentMessageBatchIndex,
|
|
1051
|
-
|
|
1048
|
+
publicKeys: this.publicKeys.map((leaf) => leaf.toJSON()),
|
|
1052
1049
|
pollStateLeaves: this.pollStateLeaves.map((leaf) => leaf.toJSON()),
|
|
1053
1050
|
results: this.tallyResult.map((result) => result.toString()),
|
|
1054
1051
|
numBatchesProcessed: this.numBatchesProcessed,
|
|
1055
|
-
|
|
1052
|
+
totalSignups: this.totalSignups.toString(),
|
|
1056
1053
|
chainHash: this.chainHash.toString(),
|
|
1057
1054
|
pollNullifiers: [...this.pollNullifiers.keys()].map((nullifier) => nullifier.toString()),
|
|
1058
1055
|
batchHashes: this.batchHashes.map((batchHash) => batchHash.toString()),
|
|
@@ -1069,9 +1066,9 @@ class Poll {
|
|
|
1069
1066
|
// set all properties
|
|
1070
1067
|
poll.pollStateLeaves = json.pollStateLeaves.map((leaf) => domainobjs_1.StateLeaf.fromJSON(leaf));
|
|
1071
1068
|
poll.ballots = json.ballots.map((ballot) => domainobjs_1.Ballot.fromJSON(ballot));
|
|
1072
|
-
poll.
|
|
1069
|
+
poll.encryptionPublicKeys = json.encryptionPublicKeys.map((key) => domainobjs_1.PublicKey.deserialize(key));
|
|
1073
1070
|
poll.messages = json.messages.map((message) => domainobjs_1.Message.fromJSON(message));
|
|
1074
|
-
poll.commands = json.commands.map((command) => domainobjs_1.
|
|
1071
|
+
poll.commands = json.commands.map((command) => domainobjs_1.VoteCommand.fromJSON(command));
|
|
1075
1072
|
poll.tallyResult = json.results.map((result) => BigInt(result));
|
|
1076
1073
|
poll.currentMessageBatchIndex = json.currentMessageBatchIndex;
|
|
1077
1074
|
poll.numBatchesProcessed = json.numBatchesProcessed;
|
|
@@ -1079,7 +1076,7 @@ class Poll {
|
|
|
1079
1076
|
poll.batchHashes = json.batchHashes.map((batchHash) => BigInt(batchHash));
|
|
1080
1077
|
poll.pollNullifiers = new Map(json.pollNullifiers.map((nullifier) => [BigInt(nullifier), true]));
|
|
1081
1078
|
// copy maci state
|
|
1082
|
-
poll.updatePoll(BigInt(json.
|
|
1079
|
+
poll.updatePoll(BigInt(json.totalSignups));
|
|
1083
1080
|
return poll;
|
|
1084
1081
|
}
|
|
1085
1082
|
}
|