@crisp-e3/contracts 0.5.12 → 0.6.0
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/contracts/CRISPProgram.sol +17 -11
- package/contracts/CRISPVerifier.sol +130 -112
- package/package.json +4 -4
|
@@ -41,6 +41,8 @@ contract CRISPProgram is IE3Program, Ownable {
|
|
|
41
41
|
uint8 public constant TREE_DEPTH = 20;
|
|
42
42
|
/// @notice Maximum number of bits allocated for vote counts in the plaintext output per option.
|
|
43
43
|
uint256 constant MAX_VOTE_BITS = 50;
|
|
44
|
+
/// @notice The zero-knowledge verification key hash for the CRISP program.
|
|
45
|
+
bytes32 public constant ZK_VK_HASH = 0xfbb1352f018828a2e0989e3010af055b6217b60462066ae0ce06209e22ffa8c2;
|
|
44
46
|
|
|
45
47
|
// State variables
|
|
46
48
|
IEnclave public enclave;
|
|
@@ -171,22 +173,26 @@ contract CRISPProgram is IE3Program, Ownable {
|
|
|
171
173
|
|
|
172
174
|
if (data.length == 0) revert EmptyInputData();
|
|
173
175
|
|
|
174
|
-
(bytes memory noirProof, address slotAddress, bytes32 encryptedVoteCommitment, bytes memory encryptedVote) = abi
|
|
175
|
-
data,
|
|
176
|
-
|
|
177
|
-
);
|
|
176
|
+
(bytes memory noirProof, address slotAddress, bytes32 encryptedVoteCommitment, bytes32 zkKeyHash, bytes memory encryptedVote) = abi
|
|
177
|
+
.decode(data, (bytes, address, bytes32, bytes32, bytes));
|
|
178
|
+
|
|
179
|
+
if (zkKeyHash != ZK_VK_HASH) revert InvalidNoirProof();
|
|
178
180
|
|
|
179
181
|
(uint40 voteIndex, bytes32 previousEncryptedVoteCommitment) = _processVote(e3Id, slotAddress, encryptedVoteCommitment);
|
|
180
182
|
|
|
181
183
|
// Set the public inputs for the proof. Order must match Noir circuit.
|
|
182
|
-
bytes32[] memory noirPublicInputs = new bytes32[](
|
|
184
|
+
bytes32[] memory noirPublicInputs = new bytes32[](39);
|
|
183
185
|
noirPublicInputs[0] = previousEncryptedVoteCommitment;
|
|
184
|
-
noirPublicInputs[1] =
|
|
185
|
-
noirPublicInputs[2] = bytes32(
|
|
186
|
-
noirPublicInputs[3] = bytes32(uint256(
|
|
187
|
-
noirPublicInputs[4] = bytes32(
|
|
188
|
-
noirPublicInputs[5] =
|
|
189
|
-
noirPublicInputs[6] =
|
|
186
|
+
noirPublicInputs[1] = bytes32(e3Data[e3Id].merkleRoot);
|
|
187
|
+
noirPublicInputs[2] = bytes32(uint256(uint160(slotAddress)));
|
|
188
|
+
noirPublicInputs[3] = bytes32(uint256(previousEncryptedVoteCommitment == bytes32(0) ? 1 : 0));
|
|
189
|
+
noirPublicInputs[4] = bytes32(e3Data[e3Id].numOptions);
|
|
190
|
+
noirPublicInputs[5] = encryptedVoteCommitment;
|
|
191
|
+
noirPublicInputs[6] = e3.committeePublicKey;
|
|
192
|
+
// Insert ZK_VK_HASH as 32 separate bytes (each as bytes32), matching proof format
|
|
193
|
+
for (uint256 i = 0; i < 32; i++) {
|
|
194
|
+
noirPublicInputs[7 + i] = bytes32(uint256(uint8(zkKeyHash[i])));
|
|
195
|
+
}
|
|
190
196
|
|
|
191
197
|
// Check if the ciphertext was encrypted correctly
|
|
192
198
|
if (!honkVerifier.verify(noirProof, noirPublicInputs)) {
|
|
@@ -5,127 +5,127 @@
|
|
|
5
5
|
// or FITNESS FOR A PARTICULAR PURPOSE.
|
|
6
6
|
pragma solidity >=0.8.21;
|
|
7
7
|
|
|
8
|
-
uint256 constant N =
|
|
9
|
-
uint256 constant LOG_N =
|
|
10
|
-
uint256 constant NUMBER_OF_PUBLIC_INPUTS =
|
|
11
|
-
uint256 constant VK_HASH =
|
|
8
|
+
uint256 constant N = 2097152;
|
|
9
|
+
uint256 constant LOG_N = 21;
|
|
10
|
+
uint256 constant NUMBER_OF_PUBLIC_INPUTS = 55;
|
|
11
|
+
uint256 constant VK_HASH = 0x0ea01fb8e0ba32adb2d0ab6391f3bccb82eaf1ea55adcf5b033ea180190f11bc;
|
|
12
12
|
library HonkVerificationKey {
|
|
13
13
|
function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) {
|
|
14
14
|
Honk.VerificationKey memory vk = Honk.VerificationKey({
|
|
15
|
-
circuitSize: uint256(
|
|
16
|
-
logCircuitSize: uint256(
|
|
17
|
-
publicInputsSize: uint256(
|
|
15
|
+
circuitSize: uint256(2097152),
|
|
16
|
+
logCircuitSize: uint256(21),
|
|
17
|
+
publicInputsSize: uint256(55),
|
|
18
18
|
ql: Honk.G1Point({
|
|
19
|
-
x: uint256(
|
|
20
|
-
y: uint256(
|
|
19
|
+
x: uint256(0x0b49cca46309009bcfb42f7e72925f6b8b5f102e6b6ab8825dae8a96fe3cba34),
|
|
20
|
+
y: uint256(0x1e4d119e1991788b257fd6c8b9d701c6b4fb80dc24e6bb34489e2aa679e4369b)
|
|
21
21
|
}),
|
|
22
22
|
qr: Honk.G1Point({
|
|
23
|
-
x: uint256(
|
|
24
|
-
y: uint256(
|
|
23
|
+
x: uint256(0x23fcf389d77e9fb6e9f257b2a577311a62703d7746e077b8c4efe6a40bcadc1a),
|
|
24
|
+
y: uint256(0x257e7923fabec927d96159f14fcede129348203152597db67c4ec0fe392d3038)
|
|
25
25
|
}),
|
|
26
26
|
qo: Honk.G1Point({
|
|
27
|
-
x: uint256(
|
|
28
|
-
y: uint256(
|
|
27
|
+
x: uint256(0x125a3d99a31fa1f16585dfa287e82903828bb535c4b67895869f26d30b34a19b),
|
|
28
|
+
y: uint256(0x1a76e12e46934a8183e4d3983c40a12aa645054d272c5492aa48f933b216c957)
|
|
29
29
|
}),
|
|
30
30
|
q4: Honk.G1Point({
|
|
31
|
-
x: uint256(
|
|
32
|
-
y: uint256(
|
|
31
|
+
x: uint256(0x02717f10da28d42bd2096b5501b44c5e29a9d88ee76ad6b0e48b6d2b68dacf7d),
|
|
32
|
+
y: uint256(0x16e4f684dddc45d91078cef3af321dc5db6ba7ea9fc527a800a0e20e5ffbd9f3)
|
|
33
33
|
}),
|
|
34
34
|
qm: Honk.G1Point({
|
|
35
|
-
x: uint256(
|
|
36
|
-
y: uint256(
|
|
35
|
+
x: uint256(0x0fdda6f7325628ba94b4ae2e823a1d5a1dfe18fbd1c875850ff4d7e6e2bb738a),
|
|
36
|
+
y: uint256(0x1fcedd6727ab1f287d0a2c2e68ef08319e00352719055e9fb40a4292282e167f)
|
|
37
37
|
}),
|
|
38
38
|
qc: Honk.G1Point({
|
|
39
|
-
x: uint256(
|
|
40
|
-
y: uint256(
|
|
39
|
+
x: uint256(0x06422053a8c6503244e00acc1e275c3b86a2bd7139ae666d909453b766797de2),
|
|
40
|
+
y: uint256(0x000033f450d6a78d5841b7027366c1f40bf240dc5fbaf3a01e14aa5f047bb36c)
|
|
41
41
|
}),
|
|
42
42
|
qLookup: Honk.G1Point({
|
|
43
|
-
x: uint256(
|
|
44
|
-
y: uint256(
|
|
43
|
+
x: uint256(0x285cd2008c8e9d282963405be4ac4f7733be06e27d5706a518a5902d712cae6c),
|
|
44
|
+
y: uint256(0x2efd1ebb7f3ed30e0c96ae4d42b15d9e6cd18d906f198a67fb3cbb64c62b3cb5)
|
|
45
45
|
}),
|
|
46
46
|
qArith: Honk.G1Point({
|
|
47
|
-
x: uint256(
|
|
48
|
-
y: uint256(
|
|
47
|
+
x: uint256(0x0afc885f2b56f40755a8f66743425b589f8ac283920e112dc4725a503ed69e14),
|
|
48
|
+
y: uint256(0x0fc111111f23cb77fb579532a4c393fafc412a223f76743c98567d08a2ce8450)
|
|
49
49
|
}),
|
|
50
50
|
qDeltaRange: Honk.G1Point({
|
|
51
|
-
x: uint256(
|
|
52
|
-
y: uint256(
|
|
51
|
+
x: uint256(0x1968df000ac48429eb10b056a0a6dd3d1da8332b5de3724ab87547c3371ffc42),
|
|
52
|
+
y: uint256(0x18e9cb336ca060c58b7f6051d792fc40c0b488fd9672807e10cf10eab7cacb7a)
|
|
53
53
|
}),
|
|
54
54
|
qElliptic: Honk.G1Point({
|
|
55
|
-
x: uint256(
|
|
56
|
-
y: uint256(
|
|
55
|
+
x: uint256(0x177d1a59fab0f5281dfd02b19aa00eb945c77f91c5bd6112b8e857db9dc6b798),
|
|
56
|
+
y: uint256(0x11b2038670e6e114f87b1d472a31cea6390f5de495febdf47237a806969fae04)
|
|
57
57
|
}),
|
|
58
58
|
qMemory: Honk.G1Point({
|
|
59
|
-
x: uint256(
|
|
60
|
-
y: uint256(
|
|
59
|
+
x: uint256(0x02b0cec1f1b948b9e689b5b172eb85c8cd7b901c142e07df3fde5b9d74ca7414),
|
|
60
|
+
y: uint256(0x2d84255bc631bcb170192dd095b8785369495061366530ba5c843e7a97240be9)
|
|
61
61
|
}),
|
|
62
62
|
qNnf: Honk.G1Point({
|
|
63
|
-
x: uint256(
|
|
64
|
-
y: uint256(
|
|
63
|
+
x: uint256(0x053c8110bdde783ecb8ec60d71f1bd85a3bc8b43e1fe443c321a44d5692cdfc8),
|
|
64
|
+
y: uint256(0x177969870de5b24725a64587e0cf2258988960674a6ccc722133edb3fb6768aa)
|
|
65
65
|
}),
|
|
66
66
|
qPoseidon2External: Honk.G1Point({
|
|
67
|
-
x: uint256(
|
|
68
|
-
y: uint256(
|
|
67
|
+
x: uint256(0x087716c4e6b28e30afa0a4b0cf49a1ee4643709464ef89e708481e9fbcb3acf4),
|
|
68
|
+
y: uint256(0x081caf798962ce0724f2880fccebc8c2ee75ee6d0ea87d308fa91a97e4587afb)
|
|
69
69
|
}),
|
|
70
70
|
qPoseidon2Internal: Honk.G1Point({
|
|
71
|
-
x: uint256(
|
|
72
|
-
y: uint256(
|
|
71
|
+
x: uint256(0x1f7ab7d4ad925b2c31233ea29ba4debac639158de845f734d3d4340f84d72937),
|
|
72
|
+
y: uint256(0x2d228dbe4b4eb9baf6d62068cb766b7fb3b44a1a3cbde58a5c40c69ff6e176d8)
|
|
73
73
|
}),
|
|
74
74
|
s1: Honk.G1Point({
|
|
75
|
-
x: uint256(
|
|
76
|
-
y: uint256(
|
|
75
|
+
x: uint256(0x2bd432c0b486d1b9a75870a420e02622eeec72f59615c9532a22c2d946f8dc03),
|
|
76
|
+
y: uint256(0x1037cf6462b36a560256ea2c03306634ed4d87e76ea81052083700fbb1a5f8d4)
|
|
77
77
|
}),
|
|
78
78
|
s2: Honk.G1Point({
|
|
79
|
-
x: uint256(
|
|
80
|
-
y: uint256(
|
|
79
|
+
x: uint256(0x1359c3633ccf1c39969812967b170b2592f88dbec76079f0779c4ae17f79c432),
|
|
80
|
+
y: uint256(0x0e696f759fc6cd345418c89c3737d237bd2685d59b1843a884b2436f2a67fb97)
|
|
81
81
|
}),
|
|
82
82
|
s3: Honk.G1Point({
|
|
83
|
-
x: uint256(
|
|
84
|
-
y: uint256(
|
|
83
|
+
x: uint256(0x2201b7d5413f027286a8ecebfb33c3fdac7974d241e428f2ab549bcb6b1ec379),
|
|
84
|
+
y: uint256(0x1327e17ebdcc90f8233b838e4836974e68812dde890018ce5e59ba0bed8d4eb1)
|
|
85
85
|
}),
|
|
86
86
|
s4: Honk.G1Point({
|
|
87
|
-
x: uint256(
|
|
88
|
-
y: uint256(
|
|
87
|
+
x: uint256(0x2983325004b0f8ebfda26f1425a3fa7c780c9619a0a57b6026cebc3241233bb3),
|
|
88
|
+
y: uint256(0x21e0b11f18c587feb26a1b0984af1b928df573b57f6e1e7430892d02eebdaf56)
|
|
89
89
|
}),
|
|
90
90
|
t1: Honk.G1Point({
|
|
91
|
-
x: uint256(
|
|
92
|
-
y: uint256(
|
|
91
|
+
x: uint256(0x0bed9c3687f3524dbbb6410842f20eb0d87d1915348d97dd74ce9df8681fb03c),
|
|
92
|
+
y: uint256(0x061cf87194c9b570a8d060c9dfed139083f2aedc80da0d97d390d72f5cc75579)
|
|
93
93
|
}),
|
|
94
94
|
t2: Honk.G1Point({
|
|
95
|
-
x: uint256(
|
|
96
|
-
y: uint256(
|
|
95
|
+
x: uint256(0x0441aaeda5bb8ccbef2c72be215aacd45db72650f5a9855820447b241f57c887),
|
|
96
|
+
y: uint256(0x27e4f80d4673c2dc9bc21386edf443e8f74d4cff7b89fb2c34c0bcca5008d9d8)
|
|
97
97
|
}),
|
|
98
98
|
t3: Honk.G1Point({
|
|
99
|
-
x: uint256(
|
|
100
|
-
y: uint256(
|
|
99
|
+
x: uint256(0x17161957b5bea1c4b6cd7dd7a0b530aae4907cffac5801fff85ba8e4c3fa3f2f),
|
|
100
|
+
y: uint256(0x14669badaf49b0e6aaa983ac2a20378e7c5ac3b4141284ca01124c3dd33589f7)
|
|
101
101
|
}),
|
|
102
102
|
t4: Honk.G1Point({
|
|
103
|
-
x: uint256(
|
|
104
|
-
y: uint256(
|
|
103
|
+
x: uint256(0x1e10d6c8482b99a03f78a2028bb33719c19bc62fa08e1d548059b139388532e6),
|
|
104
|
+
y: uint256(0x0139852d1968d8a0c11ba44db1553094224570b77f987b01a73781e265365cea)
|
|
105
105
|
}),
|
|
106
106
|
id1: Honk.G1Point({
|
|
107
|
-
x: uint256(
|
|
108
|
-
y: uint256(
|
|
107
|
+
x: uint256(0x298881ca881438995e404581a83530c3d88dfa93485a6f29a882cdd2670e9593),
|
|
108
|
+
y: uint256(0x2cfd5e44e0a6979145879de24261c18defe4c22e7a7a23b20b002030e675c643)
|
|
109
109
|
}),
|
|
110
110
|
id2: Honk.G1Point({
|
|
111
|
-
x: uint256(
|
|
112
|
-
y: uint256(
|
|
111
|
+
x: uint256(0x02c16723d917f17d181a59379615e683306841760032f394cdb0b4f2903c0af7),
|
|
112
|
+
y: uint256(0x08d4e6f0f5f23b5431a424bd364a33e83009d3dce3214c92c22e033adb02f09c)
|
|
113
113
|
}),
|
|
114
114
|
id3: Honk.G1Point({
|
|
115
|
-
x: uint256(
|
|
116
|
-
y: uint256(
|
|
115
|
+
x: uint256(0x21dc5e14e79ab4bf1244065498cc521f001630dee5a631a0ace7cc03c12afc0c),
|
|
116
|
+
y: uint256(0x1fc77a1fc605ba6548e353b93411784ef9f79b966b676273acf37519b88a451f)
|
|
117
117
|
}),
|
|
118
118
|
id4: Honk.G1Point({
|
|
119
|
-
x: uint256(
|
|
120
|
-
y: uint256(
|
|
119
|
+
x: uint256(0x246bd4706d80d364c95e550e7e12816e13cf5736985becd309eab4503a6a5dec),
|
|
120
|
+
y: uint256(0x1453ed9448d07a67232a466d416620e9cb8438cc6c54225cb12acbde33d0a2a9)
|
|
121
121
|
}),
|
|
122
122
|
lagrangeFirst: Honk.G1Point({
|
|
123
123
|
x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001),
|
|
124
124
|
y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002)
|
|
125
125
|
}),
|
|
126
126
|
lagrangeLast: Honk.G1Point({
|
|
127
|
-
x: uint256(
|
|
128
|
-
y: uint256(
|
|
127
|
+
x: uint256(0x12541b65d3fa0ed265d6fa8823d60b50e7e245797410c733a497fe858346b8fd),
|
|
128
|
+
y: uint256(0x237bf222dbadaeb345852f0bf7e93c87f7bbf30b85cacbd349d95c0f76c4e318)
|
|
129
129
|
})
|
|
130
130
|
});
|
|
131
131
|
return vk;
|
|
@@ -296,14 +296,18 @@ uint256 constant NUMBER_OF_SUBRELATIONS = 28;
|
|
|
296
296
|
uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8;
|
|
297
297
|
uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9;
|
|
298
298
|
uint256 constant NUMBER_OF_ENTITIES = 41;
|
|
299
|
+
// The number of entities added for ZK (gemini_masking_poly)
|
|
300
|
+
uint256 constant NUM_MASKING_POLYNOMIALS = 1;
|
|
301
|
+
uint256 constant NUMBER_OF_ENTITIES_ZK = NUMBER_OF_ENTITIES + NUM_MASKING_POLYNOMIALS;
|
|
299
302
|
uint256 constant NUMBER_UNSHIFTED = 36;
|
|
303
|
+
uint256 constant NUMBER_UNSHIFTED_ZK = NUMBER_UNSHIFTED + NUM_MASKING_POLYNOMIALS;
|
|
300
304
|
uint256 constant NUMBER_TO_BE_SHIFTED = 5;
|
|
301
305
|
uint256 constant PAIRING_POINTS_SIZE = 16;
|
|
302
306
|
|
|
303
307
|
uint256 constant FIELD_ELEMENT_SIZE = 0x20;
|
|
304
308
|
uint256 constant GROUP_ELEMENT_SIZE = 0x40;
|
|
305
309
|
|
|
306
|
-
//
|
|
310
|
+
// Powers of alpha used to batch subrelations (alpha, alpha^2, ..., alpha^(NUM_SUBRELATIONS-1))
|
|
307
311
|
uint256 constant NUMBER_OF_ALPHAS = NUMBER_OF_SUBRELATIONS - 1;
|
|
308
312
|
|
|
309
313
|
// ENUM FOR WIRES
|
|
@@ -377,7 +381,7 @@ library Honk {
|
|
|
377
381
|
G1Point qElliptic; // Auxillary
|
|
378
382
|
G1Point qPoseidon2External;
|
|
379
383
|
G1Point qPoseidon2Internal;
|
|
380
|
-
// Copy
|
|
384
|
+
// Copy constraints
|
|
381
385
|
G1Point s1;
|
|
382
386
|
G1Point s2;
|
|
383
387
|
G1Point s3;
|
|
@@ -432,9 +436,12 @@ library Honk {
|
|
|
432
436
|
G1Point kzgQuotient;
|
|
433
437
|
}
|
|
434
438
|
|
|
439
|
+
/// forge-lint: disable-next-item(pascal-case-struct)
|
|
435
440
|
struct ZKProof {
|
|
436
441
|
// Pairing point object
|
|
437
442
|
Fr[PAIRING_POINTS_SIZE] pairingPointObject;
|
|
443
|
+
// ZK: Gemini masking polynomial commitment (sent first, right after public inputs)
|
|
444
|
+
G1Point geminiMaskingPoly;
|
|
438
445
|
// Commitments to wire polynomials
|
|
439
446
|
G1Point w1;
|
|
440
447
|
G1Point w2;
|
|
@@ -450,11 +457,8 @@ library Honk {
|
|
|
450
457
|
// Sumcheck
|
|
451
458
|
Fr libraSum;
|
|
452
459
|
Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH][CONST_PROOF_SIZE_LOG_N] sumcheckUnivariates;
|
|
453
|
-
Fr[NUMBER_OF_ENTITIES] sumcheckEvaluations;
|
|
454
460
|
Fr libraEvaluation;
|
|
455
|
-
//
|
|
456
|
-
G1Point geminiMaskingPoly;
|
|
457
|
-
Fr geminiMaskingEval;
|
|
461
|
+
Fr[NUMBER_OF_ENTITIES_ZK] sumcheckEvaluations; // Includes gemini_masking_poly eval at index 0 (first position)
|
|
458
462
|
// Shplemini
|
|
459
463
|
G1Point[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms;
|
|
460
464
|
Fr[CONST_PROOF_SIZE_LOG_N] geminiAEvaluations;
|
|
@@ -465,10 +469,11 @@ library Honk {
|
|
|
465
469
|
}
|
|
466
470
|
|
|
467
471
|
// ZKTranscript library to generate fiat shamir challenges, the ZK transcript only differest
|
|
472
|
+
/// forge-lint: disable-next-item(pascal-case-struct)
|
|
468
473
|
struct ZKTranscript {
|
|
469
474
|
// Oink
|
|
470
475
|
Honk.RelationParameters relationParameters;
|
|
471
|
-
Fr[NUMBER_OF_ALPHAS] alphas;
|
|
476
|
+
Fr[NUMBER_OF_ALPHAS] alphas; // Powers of alpha: [alpha, alpha^2, ..., alpha^(NUM_SUBRELATIONS-1)]
|
|
472
477
|
Fr[CONST_PROOF_SIZE_LOG_N] gateChallenges;
|
|
473
478
|
// Sumcheck
|
|
474
479
|
Fr libraChallenge;
|
|
@@ -517,8 +522,9 @@ library ZKTranscriptLib {
|
|
|
517
522
|
|
|
518
523
|
function splitChallenge(Fr challenge) internal pure returns (Fr first, Fr second) {
|
|
519
524
|
uint256 challengeU256 = uint256(Fr.unwrap(challenge));
|
|
520
|
-
|
|
521
|
-
uint256
|
|
525
|
+
// Split into two equal 127-bit chunks (254/2)
|
|
526
|
+
uint256 lo = challengeU256 & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // 127 bits
|
|
527
|
+
uint256 hi = challengeU256 >> 127;
|
|
522
528
|
first = FrLib.fromBytes32(bytes32(lo));
|
|
523
529
|
second = FrLib.fromBytes32(bytes32(hi));
|
|
524
530
|
}
|
|
@@ -541,7 +547,8 @@ library ZKTranscriptLib {
|
|
|
541
547
|
uint256 vkHash,
|
|
542
548
|
uint256 publicInputsSize
|
|
543
549
|
) internal pure returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) {
|
|
544
|
-
|
|
550
|
+
// Size: 1 (vkHash) + publicInputsSize + 8 (geminiMask(2) + 3 wires(6))
|
|
551
|
+
bytes32[] memory round0 = new bytes32[](1 + publicInputsSize + 8);
|
|
545
552
|
round0[0] = bytes32(vkHash);
|
|
546
553
|
|
|
547
554
|
for (uint256 i = 0; i < publicInputsSize - PAIRING_POINTS_SIZE; i++) {
|
|
@@ -551,14 +558,18 @@ library ZKTranscriptLib {
|
|
|
551
558
|
round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]);
|
|
552
559
|
}
|
|
553
560
|
|
|
561
|
+
// For ZK flavors: hash the gemini masking poly commitment (sent right after public inputs)
|
|
562
|
+
round0[1 + publicInputsSize] = bytes32(proof.geminiMaskingPoly.x);
|
|
563
|
+
round0[1 + publicInputsSize + 1] = bytes32(proof.geminiMaskingPoly.y);
|
|
564
|
+
|
|
554
565
|
// Create the first challenge
|
|
555
566
|
// Note: w4 is added to the challenge later on
|
|
556
|
-
round0[1 + publicInputsSize] = bytes32(proof.w1.x);
|
|
557
|
-
round0[1 + publicInputsSize +
|
|
558
|
-
round0[1 + publicInputsSize +
|
|
559
|
-
round0[1 + publicInputsSize +
|
|
560
|
-
round0[1 + publicInputsSize +
|
|
561
|
-
round0[1 + publicInputsSize +
|
|
567
|
+
round0[1 + publicInputsSize + 2] = bytes32(proof.w1.x);
|
|
568
|
+
round0[1 + publicInputsSize + 3] = bytes32(proof.w1.y);
|
|
569
|
+
round0[1 + publicInputsSize + 4] = bytes32(proof.w2.x);
|
|
570
|
+
round0[1 + publicInputsSize + 5] = bytes32(proof.w2.y);
|
|
571
|
+
round0[1 + publicInputsSize + 6] = bytes32(proof.w3.x);
|
|
572
|
+
round0[1 + publicInputsSize + 7] = bytes32(proof.w3.y);
|
|
562
573
|
|
|
563
574
|
previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0)));
|
|
564
575
|
(eta, etaTwo) = splitChallenge(previousChallenge);
|
|
@@ -653,28 +664,21 @@ library ZKTranscriptLib {
|
|
|
653
664
|
nextPreviousChallenge = prevChallenge;
|
|
654
665
|
}
|
|
655
666
|
|
|
656
|
-
// We add Libra claimed eval +
|
|
667
|
+
// We add Libra claimed eval + 2 libra commitments (grand_sum, quotient)
|
|
657
668
|
function generateRhoChallenge(Honk.ZKProof memory proof, Fr prevChallenge) internal pure returns (Fr rho, Fr nextPreviousChallenge) {
|
|
658
|
-
uint256[
|
|
669
|
+
uint256[NUMBER_OF_ENTITIES_ZK + 6] memory rhoChallengeElements;
|
|
659
670
|
rhoChallengeElements[0] = Fr.unwrap(prevChallenge);
|
|
660
671
|
uint256 i;
|
|
661
|
-
for (i = 1; i <=
|
|
672
|
+
for (i = 1; i <= NUMBER_OF_ENTITIES_ZK; i++) {
|
|
662
673
|
rhoChallengeElements[i] = Fr.unwrap(proof.sumcheckEvaluations[i - 1]);
|
|
663
674
|
}
|
|
664
675
|
rhoChallengeElements[i] = Fr.unwrap(proof.libraEvaluation);
|
|
665
|
-
|
|
666
676
|
i += 1;
|
|
667
677
|
rhoChallengeElements[i] = proof.libraCommitments[1].x;
|
|
668
678
|
rhoChallengeElements[i + 1] = proof.libraCommitments[1].y;
|
|
669
679
|
i += 2;
|
|
670
680
|
rhoChallengeElements[i] = proof.libraCommitments[2].x;
|
|
671
681
|
rhoChallengeElements[i + 1] = proof.libraCommitments[2].y;
|
|
672
|
-
i += 2;
|
|
673
|
-
rhoChallengeElements[i] = proof.geminiMaskingPoly.x;
|
|
674
|
-
rhoChallengeElements[i + 1] = proof.geminiMaskingPoly.y;
|
|
675
|
-
|
|
676
|
-
i += 2;
|
|
677
|
-
rhoChallengeElements[i] = Fr.unwrap(proof.geminiMaskingEval);
|
|
678
682
|
|
|
679
683
|
nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(rhoChallengeElements)));
|
|
680
684
|
(rho, ) = splitChallenge(nextPreviousChallenge);
|
|
@@ -742,6 +746,11 @@ library ZKTranscriptLib {
|
|
|
742
746
|
p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
|
|
743
747
|
boundary += FIELD_ELEMENT_SIZE;
|
|
744
748
|
}
|
|
749
|
+
|
|
750
|
+
// Gemini masking polynomial commitment (sent first in ZK flavors, right after pairing points)
|
|
751
|
+
p.geminiMaskingPoly = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
|
|
752
|
+
boundary += GROUP_ELEMENT_SIZE;
|
|
753
|
+
|
|
745
754
|
// Commitments
|
|
746
755
|
p.w1 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
|
|
747
756
|
boundary += GROUP_ELEMENT_SIZE;
|
|
@@ -774,8 +783,8 @@ library ZKTranscriptLib {
|
|
|
774
783
|
}
|
|
775
784
|
}
|
|
776
785
|
|
|
777
|
-
// Sumcheck evaluations
|
|
778
|
-
for (uint256 i = 0; i <
|
|
786
|
+
// Sumcheck evaluations (includes gemini_masking_poly eval at index 0 for ZK flavors)
|
|
787
|
+
for (uint256 i = 0; i < NUMBER_OF_ENTITIES_ZK; i++) {
|
|
779
788
|
p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
|
|
780
789
|
boundary += FIELD_ELEMENT_SIZE;
|
|
781
790
|
}
|
|
@@ -787,10 +796,6 @@ library ZKTranscriptLib {
|
|
|
787
796
|
boundary += GROUP_ELEMENT_SIZE;
|
|
788
797
|
p.libraCommitments[2] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
|
|
789
798
|
boundary += GROUP_ELEMENT_SIZE;
|
|
790
|
-
p.geminiMaskingPoly = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
|
|
791
|
-
boundary += GROUP_ELEMENT_SIZE;
|
|
792
|
-
p.geminiMaskingEval = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
|
|
793
|
-
boundary += FIELD_ELEMENT_SIZE;
|
|
794
799
|
|
|
795
800
|
// Gemini
|
|
796
801
|
// Read gemini fold univariates
|
|
@@ -826,7 +831,7 @@ library RelationsLib {
|
|
|
826
831
|
function accumulateRelationEvaluations(
|
|
827
832
|
Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations,
|
|
828
833
|
Honk.RelationParameters memory rp,
|
|
829
|
-
Fr[NUMBER_OF_ALPHAS] memory
|
|
834
|
+
Fr[NUMBER_OF_ALPHAS] memory subrelationChallenges,
|
|
830
835
|
Fr powPartialEval
|
|
831
836
|
) internal pure returns (Fr accumulator) {
|
|
832
837
|
Fr[NUMBER_OF_SUBRELATIONS] memory evaluations;
|
|
@@ -842,8 +847,8 @@ library RelationsLib {
|
|
|
842
847
|
accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval);
|
|
843
848
|
accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval);
|
|
844
849
|
|
|
845
|
-
// batch the subrelations with the alpha
|
|
846
|
-
accumulator = scaleAndBatchSubrelations(evaluations,
|
|
850
|
+
// batch the subrelations with the precomputed alpha powers to obtain the full honk relation
|
|
851
|
+
accumulator = scaleAndBatchSubrelations(evaluations, subrelationChallenges);
|
|
847
852
|
}
|
|
848
853
|
|
|
849
854
|
/**
|
|
@@ -1520,6 +1525,8 @@ library RelationsLib {
|
|
|
1520
1525
|
evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT));
|
|
1521
1526
|
}
|
|
1522
1527
|
|
|
1528
|
+
// Batch subrelation evaluations using precomputed powers of alpha
|
|
1529
|
+
// First subrelation is implicitly scaled by 1, subsequent ones use powers from the subrelationChallenges array
|
|
1523
1530
|
function scaleAndBatchSubrelations(
|
|
1524
1531
|
Fr[NUMBER_OF_SUBRELATIONS] memory evaluations,
|
|
1525
1532
|
Fr[NUMBER_OF_ALPHAS] memory subrelationChallenges
|
|
@@ -1868,12 +1875,14 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
1868
1875
|
uint256 immutable $LOG_N;
|
|
1869
1876
|
uint256 immutable $VK_HASH;
|
|
1870
1877
|
uint256 immutable $NUM_PUBLIC_INPUTS;
|
|
1878
|
+
uint256 immutable $MSMSize;
|
|
1871
1879
|
|
|
1872
1880
|
constructor(uint256 _N, uint256 _logN, uint256 _vkHash, uint256 _numPublicInputs) {
|
|
1873
1881
|
$N = _N;
|
|
1874
1882
|
$LOG_N = _logN;
|
|
1875
1883
|
$VK_HASH = _vkHash;
|
|
1876
1884
|
$NUM_PUBLIC_INPUTS = _numPublicInputs;
|
|
1885
|
+
$MSMSize = NUMBER_UNSHIFTED_ZK + _logN + LIBRA_COMMITMENTS + 2;
|
|
1877
1886
|
}
|
|
1878
1887
|
|
|
1879
1888
|
// Errors
|
|
@@ -1886,7 +1895,7 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
1886
1895
|
error ConsistencyCheckFailed();
|
|
1887
1896
|
|
|
1888
1897
|
// Constants for proof length calculation (matching UltraKeccakZKFlavor)
|
|
1889
|
-
uint256 constant NUM_WITNESS_ENTITIES = 8;
|
|
1898
|
+
uint256 constant NUM_WITNESS_ENTITIES = 8 + NUM_MASKING_POLYNOMIALS;
|
|
1890
1899
|
uint256 constant NUM_ELEMENTS_COMM = 2; // uint256 elements for curve points
|
|
1891
1900
|
uint256 constant NUM_ELEMENTS_FR = 1; // uint256 elements for field elements
|
|
1892
1901
|
uint256 constant NUM_LIBRA_EVALUATIONS = 4; // libra evaluations
|
|
@@ -1895,14 +1904,14 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
1895
1904
|
function calculateProofSize(uint256 logN) internal pure returns (uint256) {
|
|
1896
1905
|
// Witness and Libra commitments
|
|
1897
1906
|
uint256 proofLength = NUM_WITNESS_ENTITIES * NUM_ELEMENTS_COMM; // witness commitments
|
|
1898
|
-
proofLength += NUM_ELEMENTS_COMM *
|
|
1907
|
+
proofLength += NUM_ELEMENTS_COMM * 3; // Libra concat, grand sum, quotient comms + Gemini masking
|
|
1899
1908
|
|
|
1900
1909
|
// Sumcheck
|
|
1901
1910
|
proofLength += logN * ZK_BATCHED_RELATION_PARTIAL_LENGTH * NUM_ELEMENTS_FR; // sumcheck univariates
|
|
1902
|
-
proofLength +=
|
|
1911
|
+
proofLength += NUMBER_OF_ENTITIES_ZK * NUM_ELEMENTS_FR; // sumcheck evaluations
|
|
1903
1912
|
|
|
1904
1913
|
// Libra and Gemini
|
|
1905
|
-
proofLength += NUM_ELEMENTS_FR *
|
|
1914
|
+
proofLength += NUM_ELEMENTS_FR * 2; // Libra sum, claimed eval
|
|
1906
1915
|
proofLength += logN * NUM_ELEMENTS_FR; // Gemini a evaluations
|
|
1907
1916
|
proofLength += NUM_LIBRA_EVALUATIONS * NUM_ELEMENTS_FR; // libra evaluations
|
|
1908
1917
|
|
|
@@ -2015,8 +2024,14 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2015
2024
|
}
|
|
2016
2025
|
|
|
2017
2026
|
// Last round
|
|
2027
|
+
// For ZK flavors: sumcheckEvaluations has 42 elements
|
|
2028
|
+
// Index 0 is gemini_masking_poly, indices 1-41 are the regular entities used in relations
|
|
2029
|
+
Fr[NUMBER_OF_ENTITIES] memory relationsEvaluations;
|
|
2030
|
+
for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) {
|
|
2031
|
+
relationsEvaluations[i] = proof.sumcheckEvaluations[i + NUM_MASKING_POLYNOMIALS]; // Skip gemini_masking_poly at index 0
|
|
2032
|
+
}
|
|
2018
2033
|
Fr grandHonkRelationSum = RelationsLib.accumulateRelationEvaluations(
|
|
2019
|
-
|
|
2034
|
+
relationsEvaluations,
|
|
2020
2035
|
tp.relationParameters,
|
|
2021
2036
|
tp.alphas,
|
|
2022
2037
|
powPartialEvaluation
|
|
@@ -2089,8 +2104,8 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2089
2104
|
// - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size
|
|
2090
2105
|
Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR, $LOG_N);
|
|
2091
2106
|
// Arrays hold values that will be linearly combined for the gemini and shplonk batch openings
|
|
2092
|
-
Fr[] memory scalars = new Fr[](
|
|
2093
|
-
Honk.G1Point[] memory commitments = new Honk.G1Point[](
|
|
2107
|
+
Fr[] memory scalars = new Fr[]($MSMSize);
|
|
2108
|
+
Honk.G1Point[] memory commitments = new Honk.G1Point[]($MSMSize);
|
|
2094
2109
|
|
|
2095
2110
|
mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert();
|
|
2096
2111
|
mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert();
|
|
@@ -2128,15 +2143,18 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2128
2143
|
* This approach minimizes the number of iterations over the commitments to multilinear polynomials
|
|
2129
2144
|
* and eliminates the need to store the powers of \f$ \rho \f$.
|
|
2130
2145
|
*/
|
|
2131
|
-
|
|
2132
|
-
|
|
2146
|
+
// For ZK flavors: evaluations array is [gemini_masking_poly, qm, qc, ql, qr, ...]
|
|
2147
|
+
// Start batching challenge at 1, not rho, to match non-ZK pattern
|
|
2148
|
+
mem.batchingChallenge = Fr.wrap(1);
|
|
2149
|
+
mem.batchedEvaluation = Fr.wrap(0);
|
|
2150
|
+
|
|
2133
2151
|
mem.unshiftedScalarNeg = mem.unshiftedScalar.neg();
|
|
2134
2152
|
mem.shiftedScalarNeg = mem.shiftedScalar.neg();
|
|
2135
2153
|
|
|
2136
|
-
|
|
2137
|
-
for (uint256 i =
|
|
2138
|
-
scalars[i
|
|
2139
|
-
mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i] * mem.batchingChallenge);
|
|
2154
|
+
// Process all NUMBER_UNSHIFTED_ZK evaluations (includes gemini_masking_poly at index 0)
|
|
2155
|
+
for (uint256 i = 1; i <= NUMBER_UNSHIFTED_ZK; ++i) {
|
|
2156
|
+
scalars[i] = mem.unshiftedScalarNeg * mem.batchingChallenge;
|
|
2157
|
+
mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i - NUM_MASKING_POLYNOMIALS] * mem.batchingChallenge);
|
|
2140
2158
|
mem.batchingChallenge = mem.batchingChallenge * tp.rho;
|
|
2141
2159
|
}
|
|
2142
2160
|
// g commitments are accumulated at r
|
|
@@ -2147,7 +2165,7 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2147
2165
|
// Applied to w1, w2, w3, w4 and zPerm
|
|
2148
2166
|
for (uint256 i = 0; i < NUMBER_TO_BE_SHIFTED; ++i) {
|
|
2149
2167
|
uint256 scalarOff = i + SHIFTED_COMMITMENTS_START;
|
|
2150
|
-
uint256 evaluationOff = i +
|
|
2168
|
+
uint256 evaluationOff = i + NUMBER_UNSHIFTED_ZK;
|
|
2151
2169
|
|
|
2152
2170
|
scalars[scalarOff] = scalars[scalarOff] + (mem.shiftedScalarNeg * mem.batchingChallenge);
|
|
2153
2171
|
mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[evaluationOff] * mem.batchingChallenge);
|
|
@@ -2232,7 +2250,7 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2232
2250
|
mem.constantTermAccumulator = mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator);
|
|
2233
2251
|
|
|
2234
2252
|
mem.batchingChallenge = tp.shplonkNu.sqr();
|
|
2235
|
-
uint256 boundary =
|
|
2253
|
+
uint256 boundary = NUMBER_UNSHIFTED_ZK + 1;
|
|
2236
2254
|
|
|
2237
2255
|
// Compute Shplonk constant term contributions from Aₗ(± r^{2ˡ}) for l = 1, ..., m-1;
|
|
2238
2256
|
// Compute scalar multipliers for each fold commitment
|
|
@@ -2374,7 +2392,7 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2374
2392
|
|
|
2375
2393
|
// This implementation is the same as above with different constants
|
|
2376
2394
|
function batchMul(Honk.G1Point[] memory base, Fr[] memory scalars) internal view returns (Honk.G1Point memory result) {
|
|
2377
|
-
uint256 limit =
|
|
2395
|
+
uint256 limit = $MSMSize;
|
|
2378
2396
|
|
|
2379
2397
|
// Validate all points are on the curve
|
|
2380
2398
|
for (uint256 i = 0; i < limit; ++i) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crisp-e3/contracts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"contracts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@zk-kit/lazy-imt.sol": "2.0.0-beta.12",
|
|
32
32
|
"poseidon-solidity": "^0.0.5",
|
|
33
33
|
"solady": "^0.1.13",
|
|
34
|
-
"@enclave-e3/contracts": "0.1.
|
|
34
|
+
"@enclave-e3/contracts": "0.1.15"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@nomicfoundation/hardhat-ethers": "4",
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"typechain": "^8.3.0",
|
|
60
60
|
"typescript": "5.8.3",
|
|
61
61
|
"viem": "2.30.6",
|
|
62
|
-
"@crisp-e3/
|
|
63
|
-
"@crisp-e3/
|
|
62
|
+
"@crisp-e3/sdk": "^0.6.0",
|
|
63
|
+
"@crisp-e3/zk-inputs": "^0.6.0"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
66
|
"compile": "hardhat compile",
|