@maci-protocol/circuits 0.0.0-ci.d0dddbc → 0.0.0-ci.d231815
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/types.d.ts +2 -2
- package/build/ts/types.d.ts.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/circom/coordinator/full/MessageProcessor.circom +5 -13
- package/circom/coordinator/full/SingleMessageProcessor.circom +3 -4
- package/circom/coordinator/non-qv/MessageProcessor.circom +5 -13
- package/circom/coordinator/non-qv/SingleMessageProcessor.circom +10 -13
- package/circom/coordinator/non-qv/VoteTally.circom +1 -2
- package/circom/coordinator/qv/MessageProcessor.circom +5 -13
- package/circom/coordinator/qv/SingleMessageProcessor.circom +10 -14
- package/circom/coordinator/qv/VoteTally.circom +1 -2
- package/circom/coordinator/qv/VoteTallyWithIndividualCounts.circom +226 -0
- package/circom/utils/EdDSAPoseidonVerifier.circom +8 -3
- package/circom/utils/IsOnCurve.circom +40 -0
- package/circom/utils/full/StateLeafAndBallotTransformer.circom +5 -0
- package/circom/utils/non-qv/StateLeafAndBallotTransformer.circom +5 -0
- package/circom/utils/qv/StateLeafAndBallotTransformer.circom +5 -0
- package/circom/utils/trees/BinaryMerkleRoot.circom +5 -2
- package/circom/voter/PollJoined.circom +3 -3
- package/circom/voter/PollJoining.circom +3 -3
- package/package.json +16 -15
- package/circom/utils/trees/MerklePathIndicesGenerator.circom +0 -44
|
@@ -33,14 +33,6 @@ include "./SingleMessageProcessor.circom";
|
|
|
33
33
|
var PACKED_COMMAND_LENGTH = 4;
|
|
34
34
|
var STATE_LEAF_LENGTH = 3;
|
|
35
35
|
var BALLOT_LENGTH = 2;
|
|
36
|
-
var BALLOT_NONCE_INDEX = 0;
|
|
37
|
-
var BALLOT_VOTE_OPTION_ROOT_INDEX = 1;
|
|
38
|
-
var STATE_LEAF_PUBLIC_X_INDEX = 0;
|
|
39
|
-
var STATE_LEAF_PUBLIC_Y_INDEX = 1;
|
|
40
|
-
var STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX = 2;
|
|
41
|
-
var MESSAGE_TREE_ZERO_VALUE = 8370432830353022751713833565135785980866757267633941821328460903436894336785;
|
|
42
|
-
// Number of options for this poll.
|
|
43
|
-
var maxVoteOptions = VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth;
|
|
44
36
|
|
|
45
37
|
// Number of users that have completed the sign up.
|
|
46
38
|
signal input totalSignups;
|
|
@@ -57,7 +49,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
57
49
|
// The current state root (before the processing).
|
|
58
50
|
signal input currentStateRoot;
|
|
59
51
|
// The actual tree depth (might be <= stateTreeDepth).
|
|
60
|
-
// @note it is a public input to ensure fair processing from
|
|
52
|
+
// @note it is a public input to ensure fair processing from
|
|
61
53
|
// the coordinator (no censoring)
|
|
62
54
|
signal input actualStateTreeDepth;
|
|
63
55
|
// The coordinator public key hash
|
|
@@ -97,7 +89,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
97
89
|
|
|
98
90
|
// The index of the first message in the batch, inclusive.
|
|
99
91
|
signal input index;
|
|
100
|
-
|
|
92
|
+
|
|
101
93
|
// The index of the last message in the batch to process, exclusive.
|
|
102
94
|
// This value may be less than index + batchSize if this batch is
|
|
103
95
|
// the last batch and the total number of messages is not a multiple of the batch size.
|
|
@@ -112,7 +104,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
112
104
|
var computedCurrentSbCommitment = PoseidonHasher(3)([currentStateRoot, currentBallotRoot, currentSbSalt]);
|
|
113
105
|
computedCurrentSbCommitment === currentSbCommitment;
|
|
114
106
|
|
|
115
|
-
// -----------------------------------------------------------------------
|
|
107
|
+
// -----------------------------------------------------------------------
|
|
116
108
|
// 0. Ensure that the maximum vote options signal is valid and if
|
|
117
109
|
// the maximum users signal is valid
|
|
118
110
|
var voteOptionsValid = LessEqThan(32)([voteOptions, VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth]);
|
|
@@ -162,7 +154,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
162
154
|
|
|
163
155
|
// Decrypt each Message into a Command.
|
|
164
156
|
// The command i-th is composed by the following fields.
|
|
165
|
-
// e.g., command 0 is made of commandsStateIndex[0],
|
|
157
|
+
// e.g., command 0 is made of commandsStateIndex[0],
|
|
166
158
|
// commandsNewPublicKey[0], ..., commandsPackedCommandOut[0]
|
|
167
159
|
var computedCommandsStateIndex[batchSize];
|
|
168
160
|
var computedCommandsNewPublicKey[batchSize][2];
|
|
@@ -205,7 +197,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
205
197
|
var computedCurrentStateLeavesPathElements[stateTreeDepth][STATE_TREE_ARITY - 1];
|
|
206
198
|
var computedCurrentBallotPathElements[stateTreeDepth][STATE_TREE_ARITY - 1];
|
|
207
199
|
var computedCurrentVoteWeightsPathElements[voteOptionTreeDepth][VOTE_OPTION_TREE_ARITY - 1];
|
|
208
|
-
|
|
200
|
+
|
|
209
201
|
for (var j = 0; j < stateTreeDepth; j++) {
|
|
210
202
|
for (var k = 0; k < STATE_TREE_ARITY - 1; k++) {
|
|
211
203
|
computedCurrentStateLeavesPathElements[j][k] = currentStateLeavesPathElements[i][j][k];
|
|
@@ -5,7 +5,6 @@ include "./mux1.circom";
|
|
|
5
5
|
// local imports
|
|
6
6
|
include "../../utils/PoseidonHasher.circom";
|
|
7
7
|
include "../../utils/trees/MerkleTreeInclusionProof.circom";
|
|
8
|
-
include "../../utils/trees/MerklePathIndicesGenerator.circom";
|
|
9
8
|
include "../../utils/trees/BinaryMerkleRoot.circom";
|
|
10
9
|
include "../../utils/trees/QuinaryTreeInclusionProof.circom";
|
|
11
10
|
include "../../utils/trees/QuinaryGeneratePathIndices.circom";
|
|
@@ -112,14 +111,13 @@ template SingleMessageProcessorFull(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
112
111
|
// 2. If computedIsStateLeafIndexValid is equal to zero, generate indices for leaf zero.
|
|
113
112
|
// Otherwise, generate indices for command.stateIndex.
|
|
114
113
|
var stateIndexMux = Mux1()([0, commandStateIndex], computedIsStateLeafIndexValid);
|
|
115
|
-
var computedStateLeafPathIndices[stateTreeDepth] = MerklePathIndicesGenerator(stateTreeDepth)(stateIndexMux);
|
|
116
114
|
|
|
117
115
|
// 3. Verify that the original state leaf exists in the given state root.
|
|
118
116
|
var stateLeafHash = PoseidonHasher(3)(stateLeaf);
|
|
119
117
|
var computedStateRoot = BinaryMerkleRoot(stateTreeDepth)(
|
|
120
118
|
stateLeafHash,
|
|
121
119
|
actualStateTreeDepth,
|
|
122
|
-
|
|
120
|
+
stateIndexMux,
|
|
123
121
|
stateLeafPathElements
|
|
124
122
|
);
|
|
125
123
|
|
|
@@ -130,6 +128,7 @@ template SingleMessageProcessorFull(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
130
128
|
ballot[BALLOT_NONCE_INDEX],
|
|
131
129
|
ballot[BALLOT_VOTE_OPTION_ROOT_INDEX]
|
|
132
130
|
]);
|
|
131
|
+
var computedStateLeafPathIndices[stateTreeDepth] = Num2Bits(stateTreeDepth)(stateIndexMux);
|
|
133
132
|
|
|
134
133
|
var computedBallotRoot = MerkleTreeInclusionProof(stateTreeDepth)(
|
|
135
134
|
computedBallot,
|
|
@@ -186,7 +185,7 @@ template SingleMessageProcessorFull(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
186
185
|
var computedNewStateRoot = BinaryMerkleRoot(stateTreeDepth)(
|
|
187
186
|
computedNewStateLeafhash,
|
|
188
187
|
actualStateTreeDepth,
|
|
189
|
-
|
|
188
|
+
stateIndexMux,
|
|
190
189
|
stateLeafPathElements
|
|
191
190
|
);
|
|
192
191
|
|
|
@@ -33,14 +33,6 @@ include "./SingleMessageProcessor.circom";
|
|
|
33
33
|
var PACKED_COMMAND_LENGTH = 4;
|
|
34
34
|
var STATE_LEAF_LENGTH = 3;
|
|
35
35
|
var BALLOT_LENGTH = 2;
|
|
36
|
-
var BALLOT_NONCE_INDEX = 0;
|
|
37
|
-
var BALLOT_VOTE_OPTION_ROOT_INDEX = 1;
|
|
38
|
-
var STATE_LEAF_PUBLIC_X_INDEX = 0;
|
|
39
|
-
var STATE_LEAF_PUBLIC_Y_INDEX = 1;
|
|
40
|
-
var STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX = 2;
|
|
41
|
-
var MESSAGE_TREE_ZERO_VALUE = 8370432830353022751713833565135785980866757267633941821328460903436894336785;
|
|
42
|
-
// Number of options for this poll.
|
|
43
|
-
var maxVoteOptions = VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth;
|
|
44
36
|
|
|
45
37
|
// Number of users that have completed the sign up.
|
|
46
38
|
signal input totalSignups;
|
|
@@ -57,7 +49,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
57
49
|
// The current state root (before the processing).
|
|
58
50
|
signal input currentStateRoot;
|
|
59
51
|
// The actual tree depth (might be <= stateTreeDepth).
|
|
60
|
-
// @note it is a public input to ensure fair processing from
|
|
52
|
+
// @note it is a public input to ensure fair processing from
|
|
61
53
|
// the coordinator (no censoring)
|
|
62
54
|
signal input actualStateTreeDepth;
|
|
63
55
|
// The coordinator public key hash
|
|
@@ -97,7 +89,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
97
89
|
|
|
98
90
|
// The index of the first message in the batch, inclusive.
|
|
99
91
|
signal input index;
|
|
100
|
-
|
|
92
|
+
|
|
101
93
|
// The index of the last message in the batch to process, exclusive.
|
|
102
94
|
// This value may be less than index + batchSize if this batch is
|
|
103
95
|
// the last batch and the total number of messages is not a multiple of the batch size.
|
|
@@ -112,7 +104,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
112
104
|
var computedCurrentSbCommitment = PoseidonHasher(3)([currentStateRoot, currentBallotRoot, currentSbSalt]);
|
|
113
105
|
computedCurrentSbCommitment === currentSbCommitment;
|
|
114
106
|
|
|
115
|
-
// -----------------------------------------------------------------------
|
|
107
|
+
// -----------------------------------------------------------------------
|
|
116
108
|
// 0. Ensure that the maximum vote options signal is valid and if
|
|
117
109
|
// the maximum users signal is valid
|
|
118
110
|
var voteOptionsValid = LessEqThan(32)([voteOptions, VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth]);
|
|
@@ -162,7 +154,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
162
154
|
|
|
163
155
|
// Decrypt each Message into a Command.
|
|
164
156
|
// The command i-th is composed by the following fields.
|
|
165
|
-
// e.g., command 0 is made of commandsStateIndex[0],
|
|
157
|
+
// e.g., command 0 is made of commandsStateIndex[0],
|
|
166
158
|
// commandsNewPublicKey[0], ..., commandsPackedCommandOut[0]
|
|
167
159
|
var computedCommandsStateIndex[batchSize];
|
|
168
160
|
var computedCommandsNewPublicKey[batchSize][2];
|
|
@@ -205,7 +197,7 @@ include "./SingleMessageProcessor.circom";
|
|
|
205
197
|
var computedCurrentStateLeavesPathElements[stateTreeDepth][STATE_TREE_ARITY - 1];
|
|
206
198
|
var computedCurrentBallotPathElements[stateTreeDepth][STATE_TREE_ARITY - 1];
|
|
207
199
|
var computedCurrentVoteWeightsPathElements[voteOptionTreeDepth][VOTE_OPTION_TREE_ARITY - 1];
|
|
208
|
-
|
|
200
|
+
|
|
209
201
|
for (var j = 0; j < stateTreeDepth; j++) {
|
|
210
202
|
for (var k = 0; k < STATE_TREE_ARITY - 1; k++) {
|
|
211
203
|
computedCurrentStateLeavesPathElements[j][k] = currentStateLeavesPathElements[i][j][k];
|
|
@@ -5,7 +5,6 @@ include "./mux1.circom";
|
|
|
5
5
|
// local imports
|
|
6
6
|
include "../../utils/PoseidonHasher.circom";
|
|
7
7
|
include "../../utils/trees/MerkleTreeInclusionProof.circom";
|
|
8
|
-
include "../../utils/trees/MerklePathIndicesGenerator.circom";
|
|
9
8
|
include "../../utils/trees/BinaryMerkleRoot.circom";
|
|
10
9
|
include "../../utils/trees/QuinaryTreeInclusionProof.circom";
|
|
11
10
|
include "../../utils/trees/QuinaryGeneratePathIndices.circom";
|
|
@@ -13,10 +12,10 @@ include "../../utils/non-qv/StateLeafAndBallotTransformer.circom";
|
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
|
-
* Processes one message and updates the state accordingly.
|
|
17
|
-
* This template involves complex interactions, including transformations based on message type,
|
|
18
|
-
* validations against current states like voice credit balances or vote weights,
|
|
19
|
-
* and updates to Merkle trees representing state and ballot information.
|
|
15
|
+
* Processes one message and updates the state accordingly.
|
|
16
|
+
* This template involves complex interactions, including transformations based on message type,
|
|
17
|
+
* validations against current states like voice credit balances or vote weights,
|
|
18
|
+
* and updates to Merkle trees representing state and ballot information.
|
|
20
19
|
* This is a critical building block for ensuring the integrity and correctness of MACI state.
|
|
21
20
|
* This template does not support Quadratic Voting (QV).
|
|
22
21
|
*/
|
|
@@ -24,7 +23,6 @@ template SingleMessageProcessorNonQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
24
23
|
// Constants defining the structure and size of state and ballots.
|
|
25
24
|
var STATE_LEAF_LENGTH = 3;
|
|
26
25
|
var BALLOT_LENGTH = 2;
|
|
27
|
-
var MESSAGE_LENGTH = 10;
|
|
28
26
|
var PACKED_COMMAND_LENGTH = 4;
|
|
29
27
|
var VOTE_OPTION_TREE_ARITY = 5;
|
|
30
28
|
var STATE_TREE_ARITY = 2;
|
|
@@ -38,7 +36,6 @@ template SingleMessageProcessorNonQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
38
36
|
var STATE_LEAF_PUBLIC_Y_INDEX = 1;
|
|
39
37
|
// Voice Credit balance.
|
|
40
38
|
var STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX = 2;
|
|
41
|
-
var NUMBER_BITS = 252;
|
|
42
39
|
|
|
43
40
|
// Number of users that have completed the sign up.
|
|
44
41
|
signal input totalSignups;
|
|
@@ -108,14 +105,13 @@ template SingleMessageProcessorNonQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
108
105
|
// 2. If computedIsStateLeafIndexValid is equal to zero, generate indices for leaf zero.
|
|
109
106
|
// Otherwise, generate indices for command.stateIndex.
|
|
110
107
|
var stateIndexMux = Mux1()([0, commandStateIndex], computedIsStateLeafIndexValid);
|
|
111
|
-
var computedStateLeafPathIndices[stateTreeDepth] = MerklePathIndicesGenerator(stateTreeDepth)(stateIndexMux);
|
|
112
108
|
|
|
113
109
|
// 3. Verify that the original state leaf exists in the given state root.
|
|
114
110
|
var stateLeafHash = PoseidonHasher(3)(stateLeaf);
|
|
115
111
|
var stateLeafQip = BinaryMerkleRoot(stateTreeDepth)(
|
|
116
112
|
stateLeafHash,
|
|
117
113
|
actualStateTreeDepth,
|
|
118
|
-
|
|
114
|
+
stateIndexMux,
|
|
119
115
|
stateLeafPathElements
|
|
120
116
|
);
|
|
121
117
|
|
|
@@ -123,9 +119,10 @@ template SingleMessageProcessorNonQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
123
119
|
|
|
124
120
|
// 4. Verify that the original ballot exists in the given ballot root.
|
|
125
121
|
var computedBallot = PoseidonHasher(2)([
|
|
126
|
-
ballot[BALLOT_NONCE_INDEX],
|
|
122
|
+
ballot[BALLOT_NONCE_INDEX],
|
|
127
123
|
ballot[BALLOT_VOTE_OPTION_ROOT_INDEX]
|
|
128
124
|
]);
|
|
125
|
+
var computedStateLeafPathIndices[stateTreeDepth] = Num2Bits(stateTreeDepth)(stateIndexMux);
|
|
129
126
|
|
|
130
127
|
var computedBallotQip = MerkleTreeInclusionProof(stateTreeDepth)(
|
|
131
128
|
computedBallot,
|
|
@@ -182,13 +179,13 @@ template SingleMessageProcessorNonQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
182
179
|
var computedNewStateLeafQip = BinaryMerkleRoot(stateTreeDepth)(
|
|
183
180
|
computedNewStateLeafHash,
|
|
184
181
|
actualStateTreeDepth,
|
|
185
|
-
|
|
182
|
+
stateIndexMux,
|
|
186
183
|
stateLeafPathElements
|
|
187
184
|
);
|
|
188
185
|
|
|
189
186
|
newStateRoot <== computedNewStateLeafQip;
|
|
190
|
-
|
|
191
|
-
// 7. Generate a new ballot root.
|
|
187
|
+
|
|
188
|
+
// 7. Generate a new ballot root.
|
|
192
189
|
var computedNewBallot = PoseidonHasher(2)([computedNewBallotNonce, newBallotVoteOptionRoot]);
|
|
193
190
|
var computedNewBallotQip = MerkleTreeInclusionProof(stateTreeDepth)(
|
|
194
191
|
computedNewBallot,
|
|
@@ -7,7 +7,6 @@ include "./unpack-element.circom";
|
|
|
7
7
|
// local imports
|
|
8
8
|
include "../../utils/non-qv/ResultCommitmentVerifier.circom";
|
|
9
9
|
include "../../utils/trees/CheckRoot.circom";
|
|
10
|
-
include "../../utils/trees/MerklePathIndicesGenerator.circom";
|
|
11
10
|
include "../../utils/trees/LeafExists.circom";
|
|
12
11
|
include "../../utils/trees/QuinaryCheckRoot.circom";
|
|
13
12
|
include "../../utils/CalculateTotal.circom";
|
|
@@ -97,7 +96,7 @@ template VoteTallyNonQv(
|
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
var computedBallotSubroot = CheckRoot(tallyProcessingStateTreeDepth)(computedBallotHashers);
|
|
100
|
-
var computedBallotPathIndices[STATE_TREE_DEPTH_DIFFERENCE] =
|
|
99
|
+
var computedBallotPathIndices[STATE_TREE_DEPTH_DIFFERENCE] = Num2Bits(STATE_TREE_DEPTH_DIFFERENCE)(index / batchSize);
|
|
101
100
|
|
|
102
101
|
// Verifies each ballot's existence within the ballot tree.
|
|
103
102
|
LeafExists(STATE_TREE_DEPTH_DIFFERENCE)(
|
|
@@ -34,14 +34,6 @@ template MessageProcessorQv(
|
|
|
34
34
|
var PACKED_COMMAND_LENGTH = 4;
|
|
35
35
|
var STATE_LEAF_LENGTH = 3;
|
|
36
36
|
var BALLOT_LENGTH = 2;
|
|
37
|
-
var BALLOT_NONCE_INDEX = 0;
|
|
38
|
-
var BALLOT_VOTE_OPTION_ROOT_INDEX = 1;
|
|
39
|
-
var STATE_LEAF_PUBLIC_X_INDEX = 0;
|
|
40
|
-
var STATE_LEAF_PUBLIC_Y_INDEX = 1;
|
|
41
|
-
var STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX = 2;
|
|
42
|
-
var MESSAGE_TREE_ZERO_VALUE = 8370432830353022751713833565135785980866757267633941821328460903436894336785;
|
|
43
|
-
// Number of options for this poll.
|
|
44
|
-
var maxVoteOptions = VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth;
|
|
45
37
|
|
|
46
38
|
// Number of users that have completed the sign up.
|
|
47
39
|
signal input totalSignups;
|
|
@@ -58,7 +50,7 @@ template MessageProcessorQv(
|
|
|
58
50
|
// The current state root (before the processing).
|
|
59
51
|
signal input currentStateRoot;
|
|
60
52
|
// The actual tree depth (might be <= stateTreeDepth).
|
|
61
|
-
// @note it is a public input to ensure fair processing from
|
|
53
|
+
// @note it is a public input to ensure fair processing from
|
|
62
54
|
// the coordinator (no censoring)
|
|
63
55
|
signal input actualStateTreeDepth;
|
|
64
56
|
// The coordinator public key hash
|
|
@@ -98,7 +90,7 @@ template MessageProcessorQv(
|
|
|
98
90
|
|
|
99
91
|
// The index of the first message in the batch, inclusive.
|
|
100
92
|
signal input index;
|
|
101
|
-
|
|
93
|
+
|
|
102
94
|
// The index of the last message in the batch to process, exclusive.
|
|
103
95
|
// This value may be less than batchSize if this batch is
|
|
104
96
|
// the last batch and the total number of messages is not a multiple of the batch size.
|
|
@@ -160,7 +152,7 @@ template MessageProcessorQv(
|
|
|
160
152
|
|
|
161
153
|
// Decrypt each Message into a Command.
|
|
162
154
|
// The command i-th is composed by the following fields.
|
|
163
|
-
// e.g., command 0 is made of commandsStateIndex[0],
|
|
155
|
+
// e.g., command 0 is made of commandsStateIndex[0],
|
|
164
156
|
// commandsNewPublicKey[0], ..., commandsPackedCommandOut[0]
|
|
165
157
|
var computedCommandsStateIndex[batchSize];
|
|
166
158
|
var computedCommandsNewPublicKey[batchSize][2];
|
|
@@ -203,7 +195,7 @@ template MessageProcessorQv(
|
|
|
203
195
|
var computedCurrentStateLeavesPathElements[stateTreeDepth][STATE_TREE_ARITY - 1];
|
|
204
196
|
var computedCurrentBallotPathElements[stateTreeDepth][STATE_TREE_ARITY - 1];
|
|
205
197
|
var computedCurrentVoteWeightsPathElements[voteOptionTreeDepth][VOTE_OPTION_TREE_ARITY - 1];
|
|
206
|
-
|
|
198
|
+
|
|
207
199
|
for (var j = 0; j < stateTreeDepth; j++) {
|
|
208
200
|
for (var k = 0; k < STATE_TREE_ARITY - 1; k++) {
|
|
209
201
|
computedCurrentStateLeavesPathElements[j][k] = currentStateLeavesPathElements[i][j][k];
|
|
@@ -216,7 +208,7 @@ template MessageProcessorQv(
|
|
|
216
208
|
computedCurrentVoteWeightsPathElements[j][k] = currentVoteWeightsPathElements[i][j][k];
|
|
217
209
|
}
|
|
218
210
|
}
|
|
219
|
-
|
|
211
|
+
|
|
220
212
|
(computedNewVoteStateRoot[i], computedNewVoteBallotRoot[i]) = SingleMessageProcessorQv(stateTreeDepth, voteOptionTreeDepth)(
|
|
221
213
|
totalSignups,
|
|
222
214
|
stateRoots[i + 1],
|
|
@@ -5,17 +5,16 @@ include "./mux1.circom";
|
|
|
5
5
|
// local imports
|
|
6
6
|
include "../../utils/PoseidonHasher.circom";
|
|
7
7
|
include "../../utils/trees/MerkleTreeInclusionProof.circom";
|
|
8
|
-
include "../../utils/trees/MerklePathIndicesGenerator.circom";
|
|
9
8
|
include "../../utils/trees/BinaryMerkleRoot.circom";
|
|
10
9
|
include "../../utils/trees/QuinaryTreeInclusionProof.circom";
|
|
11
10
|
include "../../utils/trees/QuinaryGeneratePathIndices.circom";
|
|
12
11
|
include "../../utils/qv/StateLeafAndBallotTransformer.circom";
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
|
-
* Processes one message and updates the state accordingly.
|
|
16
|
-
* This template involves complex interactions, including transformations based on message type,
|
|
17
|
-
* validations against current states like voice credit balances or vote weights,
|
|
18
|
-
* and updates to Merkle trees representing state and ballot information.
|
|
14
|
+
* Processes one message and updates the state accordingly.
|
|
15
|
+
* This template involves complex interactions, including transformations based on message type,
|
|
16
|
+
* validations against current states like voice credit balances or vote weights,
|
|
17
|
+
* and updates to Merkle trees representing state and ballot information.
|
|
19
18
|
* This is a critical building block for ensuring the integrity and correctness of MACI state.
|
|
20
19
|
* This template supports the Quadratic Voting (QV).
|
|
21
20
|
*/
|
|
@@ -23,7 +22,6 @@ template SingleMessageProcessorQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
23
22
|
// Constants defining the structure and size of state and ballots.
|
|
24
23
|
var STATE_LEAF_LENGTH = 3;
|
|
25
24
|
var BALLOT_LENGTH = 2;
|
|
26
|
-
var MESSAGE_LENGTH = 10;
|
|
27
25
|
var PACKED_COMMAND_LENGTH = 4;
|
|
28
26
|
var VOTE_OPTION_TREE_ARITY = 5;
|
|
29
27
|
var STATE_TREE_ARITY = 2;
|
|
@@ -37,7 +35,6 @@ template SingleMessageProcessorQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
37
35
|
var STATE_LEAF_PUBLIC_Y_INDEX = 1;
|
|
38
36
|
// Voice Credit balance.
|
|
39
37
|
var STATE_LEAF_VOICE_CREDIT_BALANCE_INDEX = 2;
|
|
40
|
-
var NUMBER_BITS = 252;
|
|
41
38
|
|
|
42
39
|
// Number of users that have completed the sign up.
|
|
43
40
|
signal input totalSignups;
|
|
@@ -112,14 +109,13 @@ template SingleMessageProcessorQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
112
109
|
// 2. If computedIsStateLeafIndexValid is equal to zero, generate indices for leaf zero.
|
|
113
110
|
// Otherwise, generate indices for command.stateIndex.
|
|
114
111
|
var stateIndexMux = Mux1()([0, commandStateIndex], computedIsStateLeafIndexValid);
|
|
115
|
-
var computedStateLeafPathIndices[stateTreeDepth] = MerklePathIndicesGenerator(stateTreeDepth)(stateIndexMux);
|
|
116
112
|
|
|
117
113
|
// 3. Verify that the original state leaf exists in the given state root.
|
|
118
114
|
var stateLeafHash = PoseidonHasher(3)(stateLeaf);
|
|
119
115
|
var stateLeafQip = BinaryMerkleRoot(stateTreeDepth)(
|
|
120
116
|
stateLeafHash,
|
|
121
117
|
actualStateTreeDepth,
|
|
122
|
-
|
|
118
|
+
stateIndexMux,
|
|
123
119
|
stateLeafPathElements
|
|
124
120
|
);
|
|
125
121
|
|
|
@@ -127,9 +123,10 @@ template SingleMessageProcessorQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
127
123
|
|
|
128
124
|
// 4. Verify that the original ballot exists in the given ballot root.
|
|
129
125
|
var computedBallot = PoseidonHasher(2)([
|
|
130
|
-
ballot[BALLOT_NONCE_INDEX],
|
|
126
|
+
ballot[BALLOT_NONCE_INDEX],
|
|
131
127
|
ballot[BALLOT_VOTE_OPTION_ROOT_INDEX]
|
|
132
128
|
]);
|
|
129
|
+
var computedStateLeafPathIndices[stateTreeDepth] = Num2Bits(stateTreeDepth)(stateIndexMux);
|
|
133
130
|
|
|
134
131
|
var computedBallotQip = MerkleTreeInclusionProof(stateTreeDepth)(
|
|
135
132
|
computedBallot,
|
|
@@ -189,13 +186,13 @@ template SingleMessageProcessorQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
189
186
|
var computedNewStateLeafQip = BinaryMerkleRoot(stateTreeDepth)(
|
|
190
187
|
computedNewStateLeafHash,
|
|
191
188
|
actualStateTreeDepth,
|
|
192
|
-
|
|
189
|
+
stateIndexMux,
|
|
193
190
|
stateLeafPathElements
|
|
194
191
|
);
|
|
195
192
|
|
|
196
193
|
newStateRoot <== computedNewStateLeafQip;
|
|
197
|
-
|
|
198
|
-
// 7. Generate a new ballot root.
|
|
194
|
+
|
|
195
|
+
// 7. Generate a new ballot root.
|
|
199
196
|
var computedNewBallot = PoseidonHasher(2)([computedNewBallotNonce, newBallotVoteOptionRoot]);
|
|
200
197
|
var computedNewBallotQip = MerkleTreeInclusionProof(stateTreeDepth)(
|
|
201
198
|
computedNewBallot,
|
|
@@ -205,4 +202,3 @@ template SingleMessageProcessorQv(stateTreeDepth, voteOptionTreeDepth) {
|
|
|
205
202
|
|
|
206
203
|
newBallotRoot <== computedNewBallotQip;
|
|
207
204
|
}
|
|
208
|
-
|
|
@@ -6,7 +6,6 @@ include "./comparators.circom";
|
|
|
6
6
|
include "./unpack-element.circom";
|
|
7
7
|
// local imports
|
|
8
8
|
include "../../utils/trees/CheckRoot.circom";
|
|
9
|
-
include "../../utils/trees/MerklePathIndicesGenerator.circom";
|
|
10
9
|
include "../../utils/trees/LeafExists.circom";
|
|
11
10
|
include "../../utils/trees/QuinaryCheckRoot.circom";
|
|
12
11
|
include "../../utils/qv/ResultCommitmentVerifier.circom";
|
|
@@ -102,7 +101,7 @@ template VoteTallyQv(
|
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
var computedBallotSubroot = CheckRoot(tallyProcessingStateTreeDepth)(computedBallotHashers);
|
|
105
|
-
var computedBallotPathIndices[STATE_TREE_DEPTH_DIFFERENCE] =
|
|
104
|
+
var computedBallotPathIndices[STATE_TREE_DEPTH_DIFFERENCE] = Num2Bits(STATE_TREE_DEPTH_DIFFERENCE)(index / batchSize);
|
|
106
105
|
|
|
107
106
|
// Verifies each ballot's existence within the ballot tree.
|
|
108
107
|
LeafExists(STATE_TREE_DEPTH_DIFFERENCE)(
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
pragma circom 2.0.0;
|
|
2
|
+
|
|
3
|
+
// circomlib import
|
|
4
|
+
include "./comparators.circom";
|
|
5
|
+
// zk-kit import
|
|
6
|
+
include "./unpack-element.circom";
|
|
7
|
+
// local imports
|
|
8
|
+
include "../../utils/trees/CheckRoot.circom";
|
|
9
|
+
include "../../utils/trees/LeafExists.circom";
|
|
10
|
+
include "../../utils/trees/QuinaryCheckRoot.circom";
|
|
11
|
+
include "../../utils/qv/ResultCommitmentVerifier.circom";
|
|
12
|
+
include "../../utils/CalculateTotal.circom";
|
|
13
|
+
include "../../utils/PoseidonHasher.circom";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Processes batches of votes and verifies their validity in a Merkle tree structure.
|
|
17
|
+
* This template supports Quadratic Voting (QV) with individual vote counting.
|
|
18
|
+
* Note: this circuit is not using right now, this is a part of individual vote counts functionality.
|
|
19
|
+
* Not finished yet, don't use it in production. It is kept here for future use.
|
|
20
|
+
*/
|
|
21
|
+
template VoteTallyWithIndividualCountsQv(
|
|
22
|
+
stateTreeDepth,
|
|
23
|
+
tallyProcessingStateTreeDepth,
|
|
24
|
+
voteOptionTreeDepth
|
|
25
|
+
) {
|
|
26
|
+
// Ensure there's at least one level in the vote option tree.
|
|
27
|
+
assert(voteOptionTreeDepth > 0);
|
|
28
|
+
// Ensure the intermediate state tree has at least one level.
|
|
29
|
+
assert(tallyProcessingStateTreeDepth > 0);
|
|
30
|
+
// The intermediate state tree must be smaller than the full state tree.
|
|
31
|
+
assert(tallyProcessingStateTreeDepth < stateTreeDepth);
|
|
32
|
+
|
|
33
|
+
// Number of children per node in the tree, defining the tree's branching factor.
|
|
34
|
+
var TREE_ARITY = 5;
|
|
35
|
+
var BALLOT_TREE_ARITY = 2;
|
|
36
|
+
var VOTE_COUNTS_TREE_ARITY = 2;
|
|
37
|
+
|
|
38
|
+
// The number of ballots processed at once, determined by the depth of the intermediate state tree.
|
|
39
|
+
var ballotBatchSize = BALLOT_TREE_ARITY ** tallyProcessingStateTreeDepth;
|
|
40
|
+
var voteCountsBatchSize = VOTE_COUNTS_TREE_ARITY ** tallyProcessingStateTreeDepth;
|
|
41
|
+
// Number of voting options available, determined by the depth of the vote option tree.
|
|
42
|
+
var totalVoteOptions = TREE_ARITY ** voteOptionTreeDepth;
|
|
43
|
+
|
|
44
|
+
// Number of elements in each ballot.
|
|
45
|
+
var BALLOT_LENGTH = 2;
|
|
46
|
+
// Index for the nonce in the ballot array.
|
|
47
|
+
var BALLOT_NONCE_INDEX = 0;
|
|
48
|
+
// Index for the voting option root in the ballot array.
|
|
49
|
+
var BALLOT_VOTE_OPTION_ROOT_INDEX = 1;
|
|
50
|
+
// Difference in tree depths, used in path calculations.
|
|
51
|
+
var STATE_TREE_DEPTH_DIFFERENCE = stateTreeDepth - tallyProcessingStateTreeDepth;
|
|
52
|
+
// Number of elements in each vote count leaf.
|
|
53
|
+
var VOTE_COUNTS_LENGTH = 2;
|
|
54
|
+
// Index for the voting option index.
|
|
55
|
+
var VOTE_COUNTS_NONCE_INDEX = 0;
|
|
56
|
+
// Index for root of the vote count per option.
|
|
57
|
+
var VOTE_COUNTS_ROOT_INDEX = 1;
|
|
58
|
+
|
|
59
|
+
// Root of the state Merkle tree, representing the overall state before voting.
|
|
60
|
+
signal input stateRoot;
|
|
61
|
+
// Root of the ballot Merkle tree, representing the submitted ballots.
|
|
62
|
+
signal input ballotRoot;
|
|
63
|
+
// Root of the vote counts Merkle tree, representing the counts of votes for each option.
|
|
64
|
+
signal input voteCountsRoot;
|
|
65
|
+
// Salt used in commitment to secure the ballot data.
|
|
66
|
+
signal input sbSalt;
|
|
67
|
+
// Commitment to the state and ballots.
|
|
68
|
+
signal input sbCommitment;
|
|
69
|
+
// Commitment to the current tally before this batch.
|
|
70
|
+
signal input currentTallyCommitment;
|
|
71
|
+
// Commitment to the new tally after processing this batch.
|
|
72
|
+
signal input newTallyCommitment;
|
|
73
|
+
// Start index of given batch
|
|
74
|
+
signal input index;
|
|
75
|
+
// Number of users that signup
|
|
76
|
+
signal input totalSignups;
|
|
77
|
+
// Ballots and their corresponding path elements for verification in the tree.
|
|
78
|
+
signal input ballots[ballotBatchSize][BALLOT_LENGTH];
|
|
79
|
+
signal input ballotPathElements[STATE_TREE_DEPTH_DIFFERENCE][BALLOT_TREE_ARITY - 1];
|
|
80
|
+
signal input votes[ballotBatchSize][totalVoteOptions];
|
|
81
|
+
// Individual vote count tree and their corresponding path elements for verification in the tree.
|
|
82
|
+
signal input voteCounts[voteCountsBatchSize][VOTE_COUNTS_LENGTH];
|
|
83
|
+
signal input voteCountsPathElements[STATE_TREE_DEPTH_DIFFERENCE][VOTE_COUNTS_TREE_ARITY - 1];
|
|
84
|
+
signal input voteCountsData[voteCountsBatchSize][totalVoteOptions];
|
|
85
|
+
// Current results for each vote option.
|
|
86
|
+
signal input currentResults[totalVoteOptions];
|
|
87
|
+
// Salt for the root of the current results.
|
|
88
|
+
signal input currentResultsRootSalt;
|
|
89
|
+
// Total voice credits spent so far.
|
|
90
|
+
signal input currentSpentVoiceCreditSubtotal;
|
|
91
|
+
// Salt for the total spent voice credits.
|
|
92
|
+
signal input currentSpentVoiceCreditSubtotalSalt;
|
|
93
|
+
// Spent voice credits per vote option.
|
|
94
|
+
signal input currentPerVoteOptionSpentVoiceCredits[totalVoteOptions];
|
|
95
|
+
// Salt for the root of spent credits per option.
|
|
96
|
+
signal input currentPerVoteOptionSpentVoiceCreditsRootSalt;
|
|
97
|
+
// Salt for the root of the new results.
|
|
98
|
+
signal input newResultsRootSalt;
|
|
99
|
+
// Salt for the new spent credits per vote option root.
|
|
100
|
+
signal input newPerVoteOptionSpentVoiceCreditsRootSalt;
|
|
101
|
+
// Salt for the new total spent voice credits root.
|
|
102
|
+
signal input newSpentVoiceCreditSubtotalSalt;
|
|
103
|
+
|
|
104
|
+
// Verify sbCommitment.
|
|
105
|
+
var computedSbCommitment = PoseidonHasher(3)([stateRoot, ballotRoot, sbSalt]);
|
|
106
|
+
computedSbCommitment === sbCommitment;
|
|
107
|
+
|
|
108
|
+
// Validates that the index is within the valid range of sign-ups.
|
|
109
|
+
var totalSignupsValid = LessEqThan(50)([index, totalSignups]);
|
|
110
|
+
totalSignupsValid === 1;
|
|
111
|
+
|
|
112
|
+
// Hashes each ballot for subroot generation, and checks the existence of the leaf in the Merkle tree.
|
|
113
|
+
var computedBallotHashers[ballotBatchSize];
|
|
114
|
+
var computedVoteCountsHashers[voteCountsBatchSize];
|
|
115
|
+
|
|
116
|
+
for (var i = 0; i < ballotBatchSize; i++) {
|
|
117
|
+
computedBallotHashers[i] = PoseidonHasher(2)([
|
|
118
|
+
ballots[i][BALLOT_NONCE_INDEX],
|
|
119
|
+
ballots[i][BALLOT_VOTE_OPTION_ROOT_INDEX]
|
|
120
|
+
]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for (var i = 0; i < voteCountsBatchSize; i++) {
|
|
124
|
+
computedVoteCountsHashers[i] = PoseidonHasher(2)([
|
|
125
|
+
voteCounts[i][VOTE_COUNTS_NONCE_INDEX],
|
|
126
|
+
voteCounts[i][VOTE_COUNTS_ROOT_INDEX]
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
var computedBallotSubroot = CheckRoot(tallyProcessingStateTreeDepth)(computedBallotHashers);
|
|
131
|
+
var computedBallotPathIndices[STATE_TREE_DEPTH_DIFFERENCE] = Num2Bits(STATE_TREE_DEPTH_DIFFERENCE)(index / ballotBatchSize);
|
|
132
|
+
|
|
133
|
+
var computedVoteCountsSubroot = CheckRoot(tallyProcessingStateTreeDepth)(computedVoteCountsHashers);
|
|
134
|
+
var computedVoteCountsPathIndices[STATE_TREE_DEPTH_DIFFERENCE] = Num2Bits(STATE_TREE_DEPTH_DIFFERENCE)(index / voteCountsBatchSize);
|
|
135
|
+
|
|
136
|
+
// Verifies each ballot's existence within the ballot tree.
|
|
137
|
+
LeafExists(STATE_TREE_DEPTH_DIFFERENCE)(
|
|
138
|
+
computedBallotSubroot,
|
|
139
|
+
ballotPathElements,
|
|
140
|
+
computedBallotPathIndices,
|
|
141
|
+
ballotRoot
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// Verifies each vote count's existence within the vote count tree.
|
|
145
|
+
LeafExists(STATE_TREE_DEPTH_DIFFERENCE)(
|
|
146
|
+
computedVoteCountsSubroot,
|
|
147
|
+
voteCountsPathElements,
|
|
148
|
+
computedVoteCountsPathIndices,
|
|
149
|
+
voteCountsRoot
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Processes vote options, verifying each against its declared root.
|
|
153
|
+
var computedVoteTree[ballotBatchSize];
|
|
154
|
+
|
|
155
|
+
for (var i = 0; i < ballotBatchSize; i++) {
|
|
156
|
+
computedVoteTree[i] = QuinaryCheckRoot(voteOptionTreeDepth)(votes[i]);
|
|
157
|
+
computedVoteTree[i] === ballots[i][BALLOT_VOTE_OPTION_ROOT_INDEX];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Processes vote counts, verifying each against its declared root.
|
|
161
|
+
var computedVoteCountsTree[voteCountsBatchSize];
|
|
162
|
+
|
|
163
|
+
for (var i = 0; i < voteCountsBatchSize; i++) {
|
|
164
|
+
computedVoteCountsTree[i] = QuinaryCheckRoot(voteOptionTreeDepth)(voteCountsData[i]);
|
|
165
|
+
computedVoteCountsTree[i] === voteCounts[i][VOTE_COUNTS_ROOT_INDEX];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Calculates new results and spent voice credits based on the current and incoming votes.
|
|
169
|
+
var computedIsFirstBatch = IsZero()(index);
|
|
170
|
+
var computedIsZero = IsZero()(computedIsFirstBatch);
|
|
171
|
+
|
|
172
|
+
// Tally the new results.
|
|
173
|
+
var computedCalculateTotalResult[totalVoteOptions];
|
|
174
|
+
for (var i = 0; i < totalVoteOptions; i++) {
|
|
175
|
+
var numsRC[ballotBatchSize + 1];
|
|
176
|
+
numsRC[ballotBatchSize] = currentResults[i] * computedIsZero;
|
|
177
|
+
for (var j = 0; j < ballotBatchSize; j++) {
|
|
178
|
+
numsRC[j] = votes[j][i];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
computedCalculateTotalResult[i] = CalculateTotal(ballotBatchSize + 1)(numsRC);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Tally the new spent voice credit total.
|
|
185
|
+
var numsSVC[ballotBatchSize * totalVoteOptions + 1];
|
|
186
|
+
numsSVC[ballotBatchSize * totalVoteOptions] = currentSpentVoiceCreditSubtotal * computedIsZero;
|
|
187
|
+
for (var i = 0; i < ballotBatchSize; i++) {
|
|
188
|
+
for (var j = 0; j < totalVoteOptions; j++) {
|
|
189
|
+
numsSVC[i * totalVoteOptions + j] = votes[i][j] * votes[i][j];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
var computedNewSpentVoiceCreditSubtotal = CalculateTotal(ballotBatchSize * totalVoteOptions + 1)(numsSVC);
|
|
194
|
+
|
|
195
|
+
// Tally the spent voice credits per vote option.
|
|
196
|
+
var computedNewPerVOSpentVoiceCredits[totalVoteOptions];
|
|
197
|
+
|
|
198
|
+
for (var i = 0; i < totalVoteOptions; i++) {
|
|
199
|
+
var computedTotalVoiceCreditSpent[ballotBatchSize + 1];
|
|
200
|
+
computedTotalVoiceCreditSpent[ballotBatchSize] = currentPerVoteOptionSpentVoiceCredits[i] * computedIsZero;
|
|
201
|
+
for (var j = 0; j < ballotBatchSize; j++) {
|
|
202
|
+
computedTotalVoiceCreditSpent[j] = votes[j][i] * votes[j][i];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
computedNewPerVOSpentVoiceCredits[i] = CalculateTotal(ballotBatchSize + 1)(computedTotalVoiceCreditSpent);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Verifies the updated results and spent credits, ensuring consistency and correctness of tally updates.
|
|
209
|
+
ResultCommitmentVerifierQv(voteOptionTreeDepth)(
|
|
210
|
+
computedIsFirstBatch,
|
|
211
|
+
currentTallyCommitment,
|
|
212
|
+
newTallyCommitment,
|
|
213
|
+
currentResults,
|
|
214
|
+
currentResultsRootSalt,
|
|
215
|
+
computedCalculateTotalResult,
|
|
216
|
+
newResultsRootSalt,
|
|
217
|
+
currentSpentVoiceCreditSubtotal,
|
|
218
|
+
currentSpentVoiceCreditSubtotalSalt,
|
|
219
|
+
computedNewSpentVoiceCreditSubtotal,
|
|
220
|
+
newSpentVoiceCreditSubtotalSalt,
|
|
221
|
+
currentPerVoteOptionSpentVoiceCredits,
|
|
222
|
+
currentPerVoteOptionSpentVoiceCreditsRootSalt,
|
|
223
|
+
computedNewPerVOSpentVoiceCredits,
|
|
224
|
+
newPerVoteOptionSpentVoiceCreditsRootSalt
|
|
225
|
+
);
|
|
226
|
+
}
|