@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.
@@ -9,6 +9,7 @@ include "./escalarmulany.circom";
9
9
  include "./escalarmulfix.circom";
10
10
  // local imports
11
11
  include "./PoseidonHasher.circom";
12
+ include "./IsOnCurve.circom";
12
13
 
13
14
  /**
14
15
  * Variant of the EdDSAPoseidonVerifier template from circomlib
@@ -37,9 +38,13 @@ template EdDSAPoseidonVerifier() {
37
38
  // Output signal for the validity of the signature.
38
39
  signal output isValid;
39
40
 
41
+ // Verify the public key and signature point are on the BabyJubJub curve.
42
+ var computedIsPkOnCurve = IsOnCurve()(publicKeyX, publicKeyY);
43
+ var computedIsSpOnCurve = IsOnCurve()(signaturePointX, signaturePointY);
44
+
40
45
  // Ensure signatureScalar<Subgroup Order.
41
46
  // convert the signature scalar signatureScalar into its binary representation.
42
- var computedNum2Bits[254] = Num2Bits(254)(signatureScalar);
47
+ var computedNum2Bits[254] = Num2Bits_strict()(signatureScalar);
43
48
 
44
49
  var computedCompConstantIn[254] = computedNum2Bits;
45
50
  computedCompConstantIn[253] = 0;
@@ -82,10 +87,10 @@ template EdDSAPoseidonVerifier() {
82
87
  // Components to handle edge cases and ensure that all conditions
83
88
  // for a valid signature are met, including the
84
89
  // public key not being zero and other integrity checks.
85
- var computedIsAxZero = IsZero()(publicKeyX);
90
+ var computedIsAxZero = IsZero()(computedDouble3XOut);
86
91
  var computedIsAxEqual = IsEqual()([computedIsAxZero, 0]);
87
92
  var computedIsCcZero = IsZero()(computedCompConstant);
88
- var computedIsValid = IsEqual()([computedIsLeftRightValid + computedIsAxEqual + computedIsCcZero, 3]);
93
+ var computedIsValid = IsEqual()([computedIsLeftRightValid + computedIsAxEqual + computedIsCcZero + computedIsPkOnCurve + computedIsSpOnCurve, 5]);
89
94
 
90
95
  isValid <== computedIsValid;
91
96
  }
@@ -0,0 +1,40 @@
1
+ pragma circom 2.0.0;
2
+
3
+ // zk-kit imports
4
+ include "./comparators.circom";
5
+
6
+ /**
7
+ * Returns 0 or 1 depending on if the point is on the BabyJubJub curve or not. The point is on the
8
+ * BabyJubJub curve if the following equation is true: a*x^2 + y^2 == 1 + d*x^2*y^2
9
+ * This template is identical to the BabyCheck template from circomlib, but it returns 0 or 1
10
+ * instead of having a hard constraint.
11
+ * Based on: https://github.com/iden3/circomlib/blob/master/circuits/babyjub.circom
12
+ */
13
+ template IsOnCurve() {
14
+ // x coordinate of the point on the BabyJubJub curve.
15
+ signal input x;
16
+ // y coordinate of the point on the BabyJubJub curve.
17
+ signal input y;
18
+ // True when the point (x, y) satisfies the BabyJubJub curve equation.
19
+ signal output isValid;
20
+
21
+ // x^2 and y^2 intermediate values.
22
+ signal x2;
23
+ signal y2;
24
+ // x^2 * y^2 intermediate value.
25
+ signal x2y2;
26
+
27
+ // BabyJubJub curve parameters.
28
+ var a = 168700;
29
+ var d = 168696;
30
+
31
+ // Compute x^2 and y^2.
32
+ x2 <== x * x;
33
+ y2 <== y * y;
34
+
35
+ // Compute x^2 * y^2.
36
+ x2y2 <== x2 * y2;
37
+
38
+ // Check if a*x^2 + y^2 == 1 + d*x^2*y^2.
39
+ isValid <== IsEqual()([a * x2 + y2, 1 + d * x2y2]);
40
+ }
@@ -119,4 +119,9 @@ template StateLeafAndBallotTransformerFull() {
119
119
  isValid <== computedIsValid;
120
120
  isStateLeafIndexValid <== computedIsStateLeafIndexValid;
121
121
  isVoteOptionIndexValid <== computedIsVoteOptionIndexValid;
122
+
123
+ // Constrain commandPollId and commandSalt using dummy squares.
124
+ // This binds the proof to a specific poll and salt.
125
+ signal commandPollIdSquare <== commandPollId * commandPollId;
126
+ signal commandSaltSquared <== commandSalt * commandSalt;
122
127
  }
@@ -102,4 +102,9 @@ template StateLeafAndBallotTransformerNonQv() {
102
102
  isValid <== computedIsValid;
103
103
  isStateLeafIndexValid <== computedIsStateLeafIndexValid;
104
104
  isVoteOptionIndexValid <== computedIsVoteOptionIndexValid;
105
+
106
+ // Constrain commandPollId and commandSalt using dummy squares.
107
+ // This binds the proof to a specific poll and salt.
108
+ signal commandPollIdSquare <== commandPollId * commandPollId;
109
+ signal commandSaltSquared <== commandSalt * commandSalt;
105
110
  }
@@ -102,4 +102,9 @@ template StateLeafAndBallotTransformer() {
102
102
  isValid <== computedIsValid;
103
103
  isStateLeafIndexValid <== computedIsStateLeafIndexValid;
104
104
  isVoteOptionIndexValid <== computedIsVoteOptionIndexValid;
105
+
106
+ // Constrain commandPollId and commandSalt using dummy squares.
107
+ // This binds the proof to a specific poll and salt.
108
+ signal commandPollIdSquare <== commandPollId * commandPollId;
109
+ signal commandSaltSquared <== commandSalt * commandSalt;
105
110
  }
@@ -25,14 +25,17 @@ template BinaryMerkleRoot(MAX_DEPTH) {
25
25
  signal input leaf;
26
26
  // The depth of the Merkle tree.
27
27
  signal input depth;
28
- // The indices of the leaf node in the Merkle tree.
29
- signal input indices[MAX_DEPTH];
28
+ // The index of the leaf node in the Merkle tree.
29
+ signal input index;
30
30
  // The sibling nodes of the leaf node in the Merkle tree.
31
31
  signal input siblings[MAX_DEPTH][1];
32
32
 
33
33
  // The output of the Merkle tree root.
34
34
  signal output out;
35
35
 
36
+ // The indices of the leaf node in the Merkle tree.
37
+ signal indices[MAX_DEPTH] <== Num2Bits(MAX_DEPTH)(index);
38
+
36
39
  signal nodes[MAX_DEPTH + 1];
37
40
  nodes[0] <== leaf;
38
41
 
@@ -19,8 +19,8 @@ template PollJoined(stateTreeDepth) {
19
19
  signal input voiceCreditsBalance;
20
20
  // Path elements
21
21
  signal input pathElements[stateTreeDepth][STATE_TREE_ARITY - 1];
22
- // Path indices
23
- signal input pathIndices[stateTreeDepth];
22
+ // Index
23
+ signal input index;
24
24
  // Poll State tree root which proves the user is joined
25
25
  signal input stateRoot;
26
26
  // The actual tree depth (might be <= stateTreeDepth) Used in BinaryMerkleRoot
@@ -35,7 +35,7 @@ template PollJoined(stateTreeDepth) {
35
35
  var calculatedRoot = BinaryMerkleRoot(stateTreeDepth)(
36
36
  stateLeaf,
37
37
  actualStateTreeDepth,
38
- pathIndices,
38
+ index,
39
39
  pathElements
40
40
  );
41
41
 
@@ -18,8 +18,8 @@ template PollJoining(stateTreeDepth) {
18
18
  signal input pollPublicKey[2];
19
19
  // Siblings
20
20
  signal input siblings[stateTreeDepth][STATE_TREE_ARITY - 1];
21
- // Indices
22
- signal input indices[stateTreeDepth];
21
+ // Index
22
+ signal input index;
23
23
  // User's hashed private key
24
24
  signal input nullifier;
25
25
  // MACI State tree root which proves the user is signed up
@@ -46,7 +46,7 @@ template PollJoining(stateTreeDepth) {
46
46
  var calculatedRoot = BinaryMerkleRoot(stateTreeDepth)(
47
47
  publicKeyHash,
48
48
  actualStateTreeDepth,
49
- indices,
49
+ index,
50
50
  siblings
51
51
  );
52
52
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maci-protocol/circuits",
3
- "version": "0.0.0-ci.d0dddbc",
3
+ "version": "0.0.0-ci.d231815",
4
4
  "private": false,
5
5
  "description": "zk-SNARK circuits for MACI",
6
6
  "main": "build/ts/index.js",
@@ -38,7 +38,8 @@
38
38
  "test:verifySignature": "pnpm run mocha-test ts/__tests__/VerifySignature.test.ts",
39
39
  "test:privateToPublicKey": "pnpm run mocha-test ts/__tests__/PrivateToPublicKey.test.ts",
40
40
  "test:calculateTotal": "pnpm run mocha-test ts/__tests__/CalculateTotal.test.ts",
41
- "test:messageProcessor": "pnpm run mocha-test ts/__tests__/MessageProcessor.test.ts",
41
+ "test:messageProcessorFull": "pnpm run mocha-test ts/__tests__/MessageProcessorFull.test.ts",
42
+ "test:isOnCurve": "pnpm run mocha-test ts/__tests__/IsOnCurve.test.ts",
42
43
  "test:voteTally": "pnpm run mocha-test ts/__tests__/VoteTally.test.ts",
43
44
  "test:ceremonyParams": "pnpm run mocha-test ts/__tests__/CeremonyParams.test.ts",
44
45
  "test:incrementalQuinaryTree": "pnpm run mocha-test ts/__tests__/IncrementalQuinaryTree.test.ts",
@@ -46,29 +47,29 @@
46
47
  "test:pollJoined": "pnpm run mocha-test ts/__tests__/PollJoined.test.ts"
47
48
  },
48
49
  "dependencies": {
49
- "@maci-protocol/core": "0.0.0-ci.d0dddbc",
50
- "@maci-protocol/crypto": "0.0.0-ci.d0dddbc",
51
- "@maci-protocol/domainobjs": "0.0.0-ci.d0dddbc",
52
- "@maci-protocol/sdk": "0.0.0-ci.d0dddbc",
50
+ "@maci-protocol/core": "0.0.0-ci.d231815",
51
+ "@maci-protocol/crypto": "0.0.0-ci.d231815",
52
+ "@maci-protocol/domainobjs": "0.0.0-ci.d231815",
53
+ "@maci-protocol/sdk": "0.0.0-ci.d231815",
53
54
  "@zk-kit/circuits": "^0.4.0",
54
- "circomkit": "^0.3.3",
55
+ "circomkit": "^0.3.4",
55
56
  "circomlib": "^2.0.5"
56
57
  },
57
58
  "devDependencies": {
58
59
  "@types/chai": "^4.3.11",
59
- "@types/chai-as-promised": "^7.1.8",
60
+ "@types/chai-as-promised": "^8.0.2",
60
61
  "@types/mocha": "^10.0.10",
61
- "@types/node": "^24.0.1",
62
+ "@types/node": "^24.11.0",
62
63
  "@types/snarkjs": "^0.7.9",
63
64
  "@zk-kit/baby-jubjub": "^1.0.3",
64
65
  "chai": "^4.3.10",
65
- "chai-as-promised": "^7.1.2",
66
- "fast-check": "^4.1.1",
67
- "glob": "^11.0.3",
68
- "mocha": "^11.6.0",
66
+ "chai-as-promised": "^8.0.1",
67
+ "fast-check": "^4.2.0",
68
+ "glob": "^12.0.0",
69
+ "mocha": "^11.7.2",
69
70
  "ts-mocha": "^11.1.0",
70
71
  "ts-node": "^10.9.1",
71
- "typescript": "^5.8.3"
72
+ "typescript": "^5.9.2"
72
73
  },
73
- "gitHead": "f41939d7f430a8b5c9b3729d6d12ca15d94cf181"
74
+ "gitHead": "271bc779ccbd8510ae0fcbc43063aacffe39d4d9"
74
75
  }
@@ -1,44 +0,0 @@
1
- pragma circom 2.0.0;
2
-
3
- // zk-kit imports
4
- include "./safe-comparators.circom";
5
- // local import
6
- include "../CalculateTotal.circom";
7
-
8
- /**
9
- * Calculates the path indices required for Merkle proof verifications.
10
- * Given a node index within an IMT and the total tree levels, it outputs the path indices leading to that node.
11
- * The template handles the modulo and division operations to break down the tree index into its constituent path indices.
12
- */
13
- template MerklePathIndicesGenerator(levels) {
14
- // The base used for the modulo and division operations, set to 2 for binary trees.
15
- var BASE = 2;
16
-
17
- // The total sum of the path indices.
18
- signal input indices;
19
-
20
- // The generated path indices.
21
- signal output out[levels];
22
-
23
- var computedIndices = indices;
24
- var computedResults[levels];
25
-
26
- for (var i = 0; i < levels; i++) {
27
- // circom's best practices suggests to avoid using <-- unless you
28
- // are aware of what's going on. This is the only way to do modulo operation.
29
- out[i] <-- computedIndices % BASE;
30
- computedIndices = computedIndices \ BASE;
31
-
32
- // Check that each output element is less than the base.
33
- var computedIsOutputElementLessThanBase = SafeLessThan(3)([out[i], BASE]);
34
- computedIsOutputElementLessThanBase === 1;
35
-
36
- // Re-compute the total sum.
37
- computedResults[i] = out[i] * (BASE ** i);
38
- }
39
-
40
- // Check that the total sum matches the index.
41
- var computedCalculateTotal = CalculateTotal(levels)(computedResults);
42
-
43
- computedCalculateTotal === indices;
44
- }