@aztec/ivc-integration 0.84.0 → 0.85.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.
Files changed (56) hide show
  1. package/artifacts/app_creator.json +1 -1
  2. package/artifacts/app_reader.json +1 -1
  3. package/artifacts/keys/app_creator.vk.data.json +69 -69
  4. package/artifacts/keys/app_reader.vk.data.json +69 -69
  5. package/artifacts/keys/mock_private_kernel_init.vk.data.json +69 -69
  6. package/artifacts/keys/mock_private_kernel_inner.vk.data.json +69 -69
  7. package/artifacts/keys/mock_private_kernel_reset.vk.data.json +69 -69
  8. package/artifacts/keys/mock_private_kernel_tail.vk.data.json +69 -69
  9. package/artifacts/keys/mock_rollup_base_private.vk.data.json +144 -0
  10. package/artifacts/keys/mock_rollup_base_public.vk.data.d.json.ts +2 -0
  11. package/artifacts/keys/mock_rollup_base_public.vk.data.json +144 -0
  12. package/artifacts/keys/mock_rollup_merge.vk.data.d.json.ts +2 -0
  13. package/artifacts/keys/mock_rollup_merge.vk.data.json +144 -0
  14. package/artifacts/keys/mock_rollup_root.vk.data.d.json.ts +2 -0
  15. package/artifacts/keys/mock_rollup_root.vk.data.json +133 -0
  16. package/artifacts/keys/mock_rollup_root_verifier.sol +1914 -0
  17. package/artifacts/mock_private_kernel_init.json +1 -1
  18. package/artifacts/mock_private_kernel_inner.json +1 -1
  19. package/artifacts/mock_private_kernel_reset.json +1 -1
  20. package/artifacts/mock_private_kernel_tail.json +1 -1
  21. package/artifacts/mock_rollup_base_private.json +1 -0
  22. package/artifacts/mock_rollup_base_public.d.json.ts +3 -0
  23. package/artifacts/mock_rollup_base_public.json +1 -0
  24. package/artifacts/mock_rollup_merge.d.json.ts +3 -0
  25. package/artifacts/mock_rollup_merge.json +1 -0
  26. package/artifacts/mock_rollup_root.d.json.ts +3 -0
  27. package/artifacts/mock_rollup_root.json +1 -0
  28. package/dest/index.d.ts +1 -35
  29. package/dest/index.d.ts.map +1 -1
  30. package/dest/index.js +1 -227
  31. package/dest/prove_native.d.ts +15 -0
  32. package/dest/prove_native.d.ts.map +1 -0
  33. package/dest/prove_native.js +105 -0
  34. package/dest/prove_wasm.d.ts +2 -0
  35. package/dest/prove_wasm.d.ts.map +1 -0
  36. package/dest/prove_wasm.js +17 -0
  37. package/dest/scripts/generate_ts_from_abi.js +4 -1
  38. package/dest/serve.js +2 -1
  39. package/dest/types/index.d.ts +41 -7
  40. package/dest/types/index.d.ts.map +1 -1
  41. package/dest/types/index.js +29 -2
  42. package/dest/witgen.d.ts +60 -0
  43. package/dest/witgen.d.ts.map +1 -0
  44. package/dest/witgen.js +335 -0
  45. package/package.json +15 -17
  46. package/src/index.ts +1 -260
  47. package/src/prove_native.ts +238 -0
  48. package/src/prove_wasm.ts +24 -0
  49. package/src/scripts/generate_ts_from_abi.ts +4 -1
  50. package/src/serve.ts +2 -1
  51. package/src/types/index.ts +72 -10
  52. package/src/witgen.ts +373 -0
  53. package/artifacts/keys/mock_public_base.vk.data.json +0 -133
  54. package/artifacts/mock_public_base.json +0 -1
  55. /package/artifacts/keys/{mock_public_base.vk.data.d.json.ts → mock_rollup_base_private.vk.data.d.json.ts} +0 -0
  56. /package/artifacts/{mock_public_base.d.json.ts → mock_rollup_base_private.d.json.ts} +0 -0
@@ -0,0 +1,1914 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2022 Aztec
3
+ pragma solidity >=0.8.21;
4
+
5
+ uint256 constant N = 33554432;
6
+ uint256 constant LOG_N = 25;
7
+ uint256 constant NUMBER_OF_PUBLIC_INPUTS = 17;
8
+ library HonkVerificationKey {
9
+ function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) {
10
+ Honk.VerificationKey memory vk = Honk.VerificationKey({
11
+ circuitSize: uint256(33554432),
12
+ logCircuitSize: uint256(25),
13
+ publicInputsSize: uint256(17),
14
+ ql: Honk.G1Point({
15
+ x: uint256(0x0269f3d8377e3b3f0788892a3af33607c3bb78480066338d6085969b64be6cae),
16
+ y: uint256(0x2c5337034f380f5435c330625aeaf52d468f0010d2a4b16dea269917d26589e3)
17
+ }),
18
+ qr: Honk.G1Point({
19
+ x: uint256(0x06ee3c6909dca9296960ce33650b92b41ebc41a8eba67aabde961395188c7814),
20
+ y: uint256(0x188cce7377b4a1902913009eb5cede501bb8cc34225485ac577851cdc38bf3d9)
21
+ }),
22
+ qo: Honk.G1Point({
23
+ x: uint256(0x0e486003ca38f33f854585e57a5255fec4694afe38783e4856d8dce69e1d9ee5),
24
+ y: uint256(0x29bd4dbaeca933626d32d9bc0f8d04912678c28a916dd6eee319094c3804de33)
25
+ }),
26
+ q4: Honk.G1Point({
27
+ x: uint256(0x16daffc2f8af138710f0dd47248ee8972a78aa397e02df19d13986c1a22170ef),
28
+ y: uint256(0x2cb5e97100e3265a36edc89a2442d48ef3b86a9f9415fa9b4ed88e364464c436)
29
+ }),
30
+ qm: Honk.G1Point({
31
+ x: uint256(0x029db7cc7f3597cc035e2b5e49b763d2fd9f4b439585e254b5d858c0c915e8ad),
32
+ y: uint256(0x240fd331edbc835ef5dc6105d1ea8e11da4707e73b13a5bdb4aee9d61d4a1444)
33
+ }),
34
+ qc: Honk.G1Point({
35
+ x: uint256(0x09a4a549264b8925346d072f387dc197040b7ac03fc63daa77de2ca1dc17e237),
36
+ y: uint256(0x2abca4d5e7f926c141940eab950e8cab5c4127900f4224a70ca3e6db000668e4)
37
+ }),
38
+ qArith: Honk.G1Point({
39
+ x: uint256(0x0e72d5eec2e833bab12f7551c6150c9296a53423b38e4414fc6808521464fcea),
40
+ y: uint256(0x0aebe9cc92cb62ef997c2fd5029c4abae3fd485a81c9c34e361d361284a8a7de)
41
+ }),
42
+ qDeltaRange: Honk.G1Point({
43
+ x: uint256(0x0a00a44659ceaae1bceeb6c513282f35ae88f28ba9acbc07b6503b8191f07df7),
44
+ y: uint256(0x248e75dd6ab3a11ad5b343512ce5a3526c872d3aba14cffd479890c434c864c7)
45
+ }),
46
+ qElliptic: Honk.G1Point({
47
+ x: uint256(0x048f6cdb40ccad1b73e373558ba8776b9c47159d2901948e467c737c4acb68b3),
48
+ y: uint256(0x26699628127e697beb1f9aad6d6755e97c08de894d1d7dc1d11f91bbb351bd26)
49
+ }),
50
+ qAux: Honk.G1Point({
51
+ x: uint256(0x0c418fe0e21311884418442d126242c4d224652399ec2744477831fdc9436e94),
52
+ y: uint256(0x067d4032cad21cb4b92706c31ac823a8093f5f90b7da9049c468ad3b23556d41)
53
+ }),
54
+ qLookup: Honk.G1Point({
55
+ x: uint256(0x0c4032c3079594eb75a8449d3d5ce8bc3661650d53f9b24d923d8f404cb0bbc9),
56
+ y: uint256(0x1084d709650356d40f0158fd6da81f54eb5fe796a0ca89441369b7c24301f851)
57
+ }),
58
+ qPoseidon2External: Honk.G1Point({
59
+ x: uint256(0x283cd95c5bb1ca3eb1ab5ebb4ed7355f4a1fefcf09cecfbb98fd0a4bd8fefe66),
60
+ y: uint256(0x17ec24d24be5f8dcb5b88a42ebd7e97599125318243f7c632baa261b22243399)
61
+ }),
62
+ qPoseidon2Internal: Honk.G1Point({
63
+ x: uint256(0x013e7fcb5cc49bdffbe4b95578885f68fe6ebacbc7ea3d2d426796e2d0553c9b),
64
+ y: uint256(0x070d1beb01f6fe8e737f7bfc0d137b718040d0af2e729ece2f19c7e091371c71)
65
+ }),
66
+ s1: Honk.G1Point({
67
+ x: uint256(0x0149e47e2bbe5b249cbefc0af18371b05fd8314e7b32b869b6ce1940946a9f15),
68
+ y: uint256(0x1f0f191f65a4c26d6f74df9b934af1253f292bfa31ff73d9e4ed58ea5a27cf4e)
69
+ }),
70
+ s2: Honk.G1Point({
71
+ x: uint256(0x0c37b3b0cef85113593bcb013b877e70b9062c8e1ea5a6bfe833d20ff34e5699),
72
+ y: uint256(0x0399612d65bf805c4914339a055c080e9a84823629b8687815d15de7c6d8f5ae)
73
+ }),
74
+ s3: Honk.G1Point({
75
+ x: uint256(0x0848860efa421e0c899be5839ea60cdea38aa16b4a9b7db4510d6e49b455ab3a),
76
+ y: uint256(0x14f773013d36ccc277efb14c57f68e2cf4ae594d49fa7cd18fb689af15eb55fd)
77
+ }),
78
+ s4: Honk.G1Point({
79
+ x: uint256(0x2189f44e0e855056d61b22bdb0c0e839680627105eefab22dea6732e0c4a0e21),
80
+ y: uint256(0x27bee6e5841576f97bc56b9188c0ca11edf6d5841c7cdf247a05d6e2213d3149)
81
+ }),
82
+ t1: Honk.G1Point({
83
+ x: uint256(0x0450f8716810dff987300c3bc10a892b1c1c2637db3f8fecd9d8bb38442cc468),
84
+ y: uint256(0x10005567f9eb3d3a97098baa0d71c65db2bf83f8a194086a4cca39916b578faf)
85
+ }),
86
+ t2: Honk.G1Point({
87
+ x: uint256(0x103bcf2cf468d53c71d57b5c0ab31231e12e1ce3a444583203ea04c16ec69eb2),
88
+ y: uint256(0x0c5d6e7a8b0b14d4ed8f51217ae8af4207277f4116e0af5a9268b38a5d34910b)
89
+ }),
90
+ t3: Honk.G1Point({
91
+ x: uint256(0x187b9371870f579be414054241d418f5689db2f6cbfabe968378fd68e9b280c0),
92
+ y: uint256(0x0964ab30f99cb72cc59d0f621604926cfebfcff535f724f619bb0e7a4853dbdb)
93
+ }),
94
+ t4: Honk.G1Point({
95
+ x: uint256(0x132b76a71278e567595f3aaf837a72eb0ab515191143e5a3c8bd587526486628),
96
+ y: uint256(0x2c6b2a0de0a3fefdfc4fb4f3b8381d2c37ccc495848c2887f98bfbaca776ca39)
97
+ }),
98
+ id1: Honk.G1Point({
99
+ x: uint256(0x19b1cf50fc0e679d6112b1d88cc29c7c1c6b06ee2bc01faf42adfab251583fdb),
100
+ y: uint256(0x21dce98d8abe9075529130f7b95c43997055ec9c77afc50fa0867916d69ebf67)
101
+ }),
102
+ id2: Honk.G1Point({
103
+ x: uint256(0x0ac0d94bd5f8891dc9744d8591858b4fa1464d6a8c230465ec2cc59e21b79df2),
104
+ y: uint256(0x09a6a6c7d5212c245739f101b3ac8235b5ed34fd3dbaba0496a8c20423eae6de)
105
+ }),
106
+ id3: Honk.G1Point({
107
+ x: uint256(0x1a58bb80697a6941abdfee21932a820036476f9c6563cb937f6726feb25c0ff2),
108
+ y: uint256(0x09066bf9f7fafb9d17eec1ee16f3e37c8a841097b4a5631b0b5483f459f65a32)
109
+ }),
110
+ id4: Honk.G1Point({
111
+ x: uint256(0x14df6ded0851e1650f662dd43ff2f3768cc2961d35424cd8b96d29e9323d26f4),
112
+ y: uint256(0x065964c2e37e892f35a475856a78df3d9560add0bdc4693343d13fd033344f90)
113
+ }),
114
+ lagrangeFirst: Honk.G1Point({
115
+ x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001),
116
+ y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002)
117
+ }),
118
+ lagrangeLast: Honk.G1Point({
119
+ x: uint256(0x04ed1afab66bf9dc50f2622f2552d3a13a2b8b8483c64ad99124f05b7fd7ea4f),
120
+ y: uint256(0x2504f9a227c6872ed94578ac68630bc276ca71ce049d8669a67fe9f80607b7e8)
121
+ })
122
+ });
123
+ return vk;
124
+ }
125
+ }
126
+
127
+ pragma solidity ^0.8.27;
128
+
129
+ type Fr is uint256;
130
+
131
+ using { add as + } for Fr global;
132
+ using { sub as - } for Fr global;
133
+ using { mul as * } for Fr global;
134
+ using { exp as ^ } for Fr global;
135
+ using { notEqual as != } for Fr global;
136
+ using { equal as == } for Fr global;
137
+
138
+ uint256 constant MODULUS =
139
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order
140
+
141
+ Fr constant MINUS_ONE = Fr.wrap(MODULUS - 1);
142
+
143
+ // Instantiation
144
+ library FrLib
145
+ {
146
+ function from(uint256 value) internal pure returns(Fr)
147
+ {
148
+ return Fr.wrap(value % MODULUS);
149
+ }
150
+
151
+ function fromBytes32(bytes32 value) internal pure returns(Fr)
152
+ {
153
+ return Fr.wrap(uint256(value) % MODULUS);
154
+ }
155
+
156
+ function toBytes32(Fr value) internal pure returns(bytes32)
157
+ {
158
+ return bytes32(Fr.unwrap(value));
159
+ }
160
+
161
+ function invert(Fr value) internal view returns(Fr)
162
+ {
163
+ uint256 v = Fr.unwrap(value);
164
+ uint256 result;
165
+
166
+ // Call the modexp precompile to invert in the field
167
+ assembly
168
+ {
169
+ let free := mload(0x40)
170
+ mstore(free, 0x20)
171
+ mstore(add(free, 0x20), 0x20)
172
+ mstore(add(free, 0x40), 0x20)
173
+ mstore(add(free, 0x60), v)
174
+ mstore(add(free, 0x80), sub(MODULUS, 2))
175
+ mstore(add(free, 0xa0), MODULUS)
176
+ let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20)
177
+ if iszero(success) {
178
+ revert(0, 0)
179
+ }
180
+ result := mload(0x00)
181
+ }
182
+
183
+ return Fr.wrap(result);
184
+ }
185
+
186
+ function pow(Fr base, uint256 v) internal view returns(Fr)
187
+ {
188
+ uint256 b = Fr.unwrap(base);
189
+ uint256 result;
190
+
191
+ // Call the modexp precompile to invert in the field
192
+ assembly
193
+ {
194
+ let free := mload(0x40)
195
+ mstore(free, 0x20)
196
+ mstore(add(free, 0x20), 0x20)
197
+ mstore(add(free, 0x40), 0x20)
198
+ mstore(add(free, 0x60), b)
199
+ mstore(add(free, 0x80), v)
200
+ mstore(add(free, 0xa0), MODULUS)
201
+ let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20)
202
+ if iszero(success) {
203
+ revert(0, 0)
204
+ }
205
+ result := mload(0x00)
206
+ }
207
+
208
+ return Fr.wrap(result);
209
+ }
210
+
211
+ function div(Fr numerator, Fr denominator) internal view returns(Fr)
212
+ {
213
+ return numerator * invert(denominator);
214
+ }
215
+
216
+ function sqr(Fr value) internal pure returns (Fr) {
217
+ return value * value;
218
+ }
219
+
220
+ function unwrap(Fr value) internal pure returns (uint256) {
221
+ return Fr.unwrap(value);
222
+ }
223
+
224
+ function neg(Fr value) internal pure returns (Fr) {
225
+ return Fr.wrap(MODULUS - Fr.unwrap(value));
226
+ }
227
+ }
228
+
229
+ // Free functions
230
+ function add(Fr a, Fr b) pure returns(Fr)
231
+ {
232
+ return Fr.wrap(addmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS));
233
+ }
234
+
235
+ function mul(Fr a, Fr b) pure returns(Fr)
236
+ {
237
+ return Fr.wrap(mulmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS));
238
+ }
239
+
240
+ function sub(Fr a, Fr b) pure returns(Fr)
241
+ {
242
+ return Fr.wrap(addmod(Fr.unwrap(a), MODULUS - Fr.unwrap(b), MODULUS));
243
+ }
244
+
245
+ function exp(Fr base, Fr exponent) pure returns(Fr)
246
+ {
247
+ if (Fr.unwrap(exponent) == 0) return Fr.wrap(1);
248
+
249
+ for (uint256 i = 1; i < Fr.unwrap(exponent); i += i) {
250
+ base = base * base;
251
+ }
252
+ return base;
253
+ }
254
+
255
+ function notEqual(Fr a, Fr b) pure returns(bool)
256
+ {
257
+ return Fr.unwrap(a) != Fr.unwrap(b);
258
+ }
259
+
260
+ function equal(Fr a, Fr b) pure returns(bool)
261
+ {
262
+ return Fr.unwrap(a) == Fr.unwrap(b);
263
+ }
264
+
265
+ uint256 constant CONST_PROOF_SIZE_LOG_N = 28;
266
+
267
+ uint256 constant NUMBER_OF_SUBRELATIONS = 26;
268
+ uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8;
269
+ uint256 constant NUMBER_OF_ENTITIES = 40;
270
+ uint256 constant NUMBER_UNSHIFTED = 35;
271
+ uint256 constant NUMBER_TO_BE_SHIFTED = 5;
272
+ uint256 constant PAIRING_POINT_OBJECT_LENGTH = 16;
273
+
274
+ // Alphas are used as relation separators so there should be NUMBER_OF_SUBRELATIONS - 1
275
+ uint256 constant NUMBER_OF_ALPHAS = 25;
276
+
277
+ // Prime field order
278
+ uint256 constant Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // EC group order. F_q
279
+ uint256 constant P = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order, F_r
280
+
281
+ // ENUM FOR WIRES
282
+ enum WIRE {
283
+ Q_M,
284
+ Q_C,
285
+ Q_L,
286
+ Q_R,
287
+ Q_O,
288
+ Q_4,
289
+ Q_LOOKUP,
290
+ Q_ARITH,
291
+ Q_RANGE,
292
+ Q_ELLIPTIC,
293
+ Q_AUX,
294
+ Q_POSEIDON2_EXTERNAL,
295
+ Q_POSEIDON2_INTERNAL,
296
+ SIGMA_1,
297
+ SIGMA_2,
298
+ SIGMA_3,
299
+ SIGMA_4,
300
+ ID_1,
301
+ ID_2,
302
+ ID_3,
303
+ ID_4,
304
+ TABLE_1,
305
+ TABLE_2,
306
+ TABLE_3,
307
+ TABLE_4,
308
+ LAGRANGE_FIRST,
309
+ LAGRANGE_LAST,
310
+ W_L,
311
+ W_R,
312
+ W_O,
313
+ W_4,
314
+ Z_PERM,
315
+ LOOKUP_INVERSES,
316
+ LOOKUP_READ_COUNTS,
317
+ LOOKUP_READ_TAGS,
318
+ W_L_SHIFT,
319
+ W_R_SHIFT,
320
+ W_O_SHIFT,
321
+ W_4_SHIFT,
322
+ Z_PERM_SHIFT
323
+ }
324
+
325
+ library Honk {
326
+ struct G1Point {
327
+ uint256 x;
328
+ uint256 y;
329
+ }
330
+
331
+ struct G1ProofPoint {
332
+ uint256 x_0;
333
+ uint256 x_1;
334
+ uint256 y_0;
335
+ uint256 y_1;
336
+ }
337
+
338
+ struct VerificationKey {
339
+ // Misc Params
340
+ uint256 circuitSize;
341
+ uint256 logCircuitSize;
342
+ uint256 publicInputsSize;
343
+ // Selectors
344
+ G1Point qm;
345
+ G1Point qc;
346
+ G1Point ql;
347
+ G1Point qr;
348
+ G1Point qo;
349
+ G1Point q4;
350
+ G1Point qLookup; // Lookup
351
+ G1Point qArith; // Arithmetic widget
352
+ G1Point qDeltaRange; // Delta Range sort
353
+ G1Point qAux; // Auxillary
354
+ G1Point qElliptic; // Auxillary
355
+ G1Point qPoseidon2External;
356
+ G1Point qPoseidon2Internal;
357
+ // Copy cnstraints
358
+ G1Point s1;
359
+ G1Point s2;
360
+ G1Point s3;
361
+ G1Point s4;
362
+ // Copy identity
363
+ G1Point id1;
364
+ G1Point id2;
365
+ G1Point id3;
366
+ G1Point id4;
367
+ // Precomputed lookup table
368
+ G1Point t1;
369
+ G1Point t2;
370
+ G1Point t3;
371
+ G1Point t4;
372
+ // Fixed first and last
373
+ G1Point lagrangeFirst;
374
+ G1Point lagrangeLast;
375
+ }
376
+
377
+ struct RelationParameters {
378
+ // challenges
379
+ Fr eta;
380
+ Fr etaTwo;
381
+ Fr etaThree;
382
+ Fr beta;
383
+ Fr gamma;
384
+ // derived
385
+ Fr publicInputsDelta;
386
+ }
387
+
388
+
389
+ struct Proof {
390
+ // Pairing point object
391
+ Fr[PAIRING_POINT_OBJECT_LENGTH] pairingPointObject;
392
+ // Free wires
393
+ Honk.G1ProofPoint w1;
394
+ Honk.G1ProofPoint w2;
395
+ Honk.G1ProofPoint w3;
396
+ Honk.G1ProofPoint w4;
397
+ // Lookup helpers - Permutations
398
+ Honk.G1ProofPoint zPerm;
399
+ // Lookup helpers - logup
400
+ Honk.G1ProofPoint lookupReadCounts;
401
+ Honk.G1ProofPoint lookupReadTags;
402
+ Honk.G1ProofPoint lookupInverses;
403
+ // Sumcheck
404
+ Fr[BATCHED_RELATION_PARTIAL_LENGTH][CONST_PROOF_SIZE_LOG_N] sumcheckUnivariates;
405
+ Fr[NUMBER_OF_ENTITIES] sumcheckEvaluations;
406
+ // Shplemini
407
+ Honk.G1ProofPoint[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms;
408
+ Fr[CONST_PROOF_SIZE_LOG_N] geminiAEvaluations;
409
+ Honk.G1ProofPoint shplonkQ;
410
+ Honk.G1ProofPoint kzgQuotient;
411
+ }
412
+ }
413
+
414
+ // Transcript library to generate fiat shamir challenges
415
+ struct Transcript {
416
+ // Oink
417
+ Honk.RelationParameters relationParameters;
418
+ Fr[NUMBER_OF_ALPHAS] alphas;
419
+ Fr[CONST_PROOF_SIZE_LOG_N] gateChallenges;
420
+ // Sumcheck
421
+ Fr[CONST_PROOF_SIZE_LOG_N] sumCheckUChallenges;
422
+ // Gemini
423
+ Fr rho;
424
+ Fr geminiR;
425
+ // Shplonk
426
+ Fr shplonkNu;
427
+ Fr shplonkZ;
428
+ }
429
+
430
+ library TranscriptLib {
431
+ function generateTranscript(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 circuitSize, uint256 publicInputsSize, uint256 pubInputsOffset)
432
+ internal
433
+ pure
434
+ returns (Transcript memory t)
435
+ {
436
+ Fr previousChallenge;
437
+ (t.relationParameters, previousChallenge) =
438
+ generateRelationParametersChallenges(proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset, previousChallenge);
439
+
440
+ (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof);
441
+
442
+ (t.gateChallenges, previousChallenge) = generateGateChallenges(previousChallenge);
443
+
444
+ (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges(proof, previousChallenge);
445
+
446
+ (t.rho, previousChallenge) = generateRhoChallenge(proof, previousChallenge);
447
+
448
+ (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge);
449
+
450
+ (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge);
451
+
452
+ (t.shplonkZ, previousChallenge) = generateShplonkZChallenge(proof, previousChallenge);
453
+
454
+ return t;
455
+ }
456
+
457
+ function splitChallenge(Fr challenge) internal pure returns (Fr first, Fr second) {
458
+ uint256 challengeU256 = uint256(Fr.unwrap(challenge));
459
+ uint256 lo = challengeU256 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
460
+ uint256 hi = challengeU256 >> 128;
461
+ first = FrLib.fromBytes32(bytes32(lo));
462
+ second = FrLib.fromBytes32(bytes32(hi));
463
+ }
464
+
465
+ function generateRelationParametersChallenges(
466
+ Honk.Proof memory proof,
467
+ bytes32[] calldata publicInputs,
468
+ uint256 circuitSize,
469
+ uint256 publicInputsSize,
470
+ uint256 pubInputsOffset,
471
+ Fr previousChallenge
472
+ ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) {
473
+ (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) =
474
+ generateEtaChallenge(proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset);
475
+
476
+ (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof);
477
+
478
+ }
479
+
480
+ function generateEtaChallenge(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 circuitSize, uint256 publicInputsSize, uint256 pubInputsOffset)
481
+ internal
482
+ pure
483
+ returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge)
484
+ {
485
+ bytes32[] memory round0 = new bytes32[](3 + publicInputsSize + 12);
486
+ round0[0] = bytes32(circuitSize);
487
+ round0[1] = bytes32(publicInputsSize);
488
+ round0[2] = bytes32(pubInputsOffset);
489
+ // TODO(https://github.com/AztecProtocol/barretenberg/issues/1331): Consider making publicInputsSize not include pairing point object.
490
+ for (uint256 i = 0; i < publicInputsSize - PAIRING_POINT_OBJECT_LENGTH; i++) {
491
+ round0[3 + i] = bytes32(publicInputs[i]);
492
+ }
493
+ for (uint256 i = 0; i < PAIRING_POINT_OBJECT_LENGTH; i++) {
494
+ round0[3 + publicInputsSize - PAIRING_POINT_OBJECT_LENGTH + i] = FrLib.toBytes32(proof.pairingPointObject[i]);
495
+ }
496
+
497
+ // Create the first challenge
498
+ // Note: w4 is added to the challenge later on
499
+ round0[3 + publicInputsSize] = bytes32(proof.w1.x_0);
500
+ round0[3 + publicInputsSize + 1] = bytes32(proof.w1.x_1);
501
+ round0[3 + publicInputsSize + 2] = bytes32(proof.w1.y_0);
502
+ round0[3 + publicInputsSize + 3] = bytes32(proof.w1.y_1);
503
+ round0[3 + publicInputsSize + 4] = bytes32(proof.w2.x_0);
504
+ round0[3 + publicInputsSize + 5] = bytes32(proof.w2.x_1);
505
+ round0[3 + publicInputsSize + 6] = bytes32(proof.w2.y_0);
506
+ round0[3 + publicInputsSize + 7] = bytes32(proof.w2.y_1);
507
+ round0[3 + publicInputsSize + 8] = bytes32(proof.w3.x_0);
508
+ round0[3 + publicInputsSize + 9] = bytes32(proof.w3.x_1);
509
+ round0[3 + publicInputsSize + 10] = bytes32(proof.w3.y_0);
510
+ round0[3 + publicInputsSize + 11] = bytes32(proof.w3.y_1);
511
+
512
+ previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0)));
513
+ (eta, etaTwo) = splitChallenge(previousChallenge);
514
+ previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))));
515
+ Fr unused;
516
+ (etaThree, unused) = splitChallenge(previousChallenge);
517
+ }
518
+
519
+ function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.Proof memory proof)
520
+ internal
521
+ pure
522
+ returns (Fr beta, Fr gamma, Fr nextPreviousChallenge)
523
+ {
524
+ bytes32[13] memory round1;
525
+ round1[0] = FrLib.toBytes32(previousChallenge);
526
+ round1[1] = bytes32(proof.lookupReadCounts.x_0);
527
+ round1[2] = bytes32(proof.lookupReadCounts.x_1);
528
+ round1[3] = bytes32(proof.lookupReadCounts.y_0);
529
+ round1[4] = bytes32(proof.lookupReadCounts.y_1);
530
+ round1[5] = bytes32(proof.lookupReadTags.x_0);
531
+ round1[6] = bytes32(proof.lookupReadTags.x_1);
532
+ round1[7] = bytes32(proof.lookupReadTags.y_0);
533
+ round1[8] = bytes32(proof.lookupReadTags.y_1);
534
+ round1[9] = bytes32(proof.w4.x_0);
535
+ round1[10] = bytes32(proof.w4.x_1);
536
+ round1[11] = bytes32(proof.w4.y_0);
537
+ round1[12] = bytes32(proof.w4.y_1);
538
+
539
+ nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round1)));
540
+ (beta, gamma) = splitChallenge(nextPreviousChallenge);
541
+ }
542
+
543
+ // Alpha challenges non-linearise the gate contributions
544
+ function generateAlphaChallenges(Fr previousChallenge, Honk.Proof memory proof)
545
+ internal
546
+ pure
547
+ returns (Fr[NUMBER_OF_ALPHAS] memory alphas, Fr nextPreviousChallenge)
548
+ {
549
+ // Generate the original sumcheck alpha 0 by hashing zPerm and zLookup
550
+ uint256[9] memory alpha0;
551
+ alpha0[0] = Fr.unwrap(previousChallenge);
552
+ alpha0[1] = proof.lookupInverses.x_0;
553
+ alpha0[2] = proof.lookupInverses.x_1;
554
+ alpha0[3] = proof.lookupInverses.y_0;
555
+ alpha0[4] = proof.lookupInverses.y_1;
556
+ alpha0[5] = proof.zPerm.x_0;
557
+ alpha0[6] = proof.zPerm.x_1;
558
+ alpha0[7] = proof.zPerm.y_0;
559
+ alpha0[8] = proof.zPerm.y_1;
560
+
561
+ nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(alpha0)));
562
+ (alphas[0], alphas[1]) = splitChallenge(nextPreviousChallenge);
563
+
564
+ for (uint256 i = 1; i < NUMBER_OF_ALPHAS / 2; i++) {
565
+ nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(nextPreviousChallenge))));
566
+ (alphas[2 * i], alphas[2 * i + 1]) = splitChallenge(nextPreviousChallenge);
567
+ }
568
+ if (((NUMBER_OF_ALPHAS & 1) == 1) && (NUMBER_OF_ALPHAS > 2)) {
569
+ nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(nextPreviousChallenge))));
570
+ Fr unused;
571
+ (alphas[NUMBER_OF_ALPHAS - 1], unused) = splitChallenge(nextPreviousChallenge);
572
+ }
573
+ }
574
+
575
+ function generateGateChallenges(Fr previousChallenge)
576
+ internal
577
+ pure
578
+ returns (Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, Fr nextPreviousChallenge)
579
+ {
580
+ for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
581
+ previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))));
582
+ Fr unused;
583
+ (gateChallenges[i], unused) = splitChallenge(previousChallenge);
584
+ }
585
+ nextPreviousChallenge = previousChallenge;
586
+ }
587
+
588
+ function generateSumcheckChallenges(Honk.Proof memory proof, Fr prevChallenge)
589
+ internal
590
+ pure
591
+ returns (Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, Fr nextPreviousChallenge)
592
+ {
593
+ for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
594
+ Fr[BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal;
595
+ univariateChal[0] = prevChallenge;
596
+
597
+ for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) {
598
+ univariateChal[j + 1] = proof.sumcheckUnivariates[i][j];
599
+ }
600
+ prevChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(univariateChal)));
601
+ Fr unused;
602
+ (sumcheckChallenges[i], unused) = splitChallenge(prevChallenge);
603
+ }
604
+ nextPreviousChallenge = prevChallenge;
605
+ }
606
+
607
+ function generateRhoChallenge(Honk.Proof memory proof, Fr prevChallenge)
608
+ internal
609
+ pure
610
+ returns (Fr rho, Fr nextPreviousChallenge)
611
+ {
612
+ Fr[NUMBER_OF_ENTITIES + 1] memory rhoChallengeElements;
613
+ rhoChallengeElements[0] = prevChallenge;
614
+
615
+ for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) {
616
+ rhoChallengeElements[i + 1] = proof.sumcheckEvaluations[i];
617
+ }
618
+
619
+ nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(rhoChallengeElements)));
620
+ Fr unused;
621
+ (rho, unused) = splitChallenge(nextPreviousChallenge);
622
+ }
623
+
624
+ function generateGeminiRChallenge(Honk.Proof memory proof, Fr prevChallenge)
625
+ internal
626
+ pure
627
+ returns (Fr geminiR, Fr nextPreviousChallenge)
628
+ {
629
+ uint256[(CONST_PROOF_SIZE_LOG_N - 1) * 4 + 1] memory gR;
630
+ gR[0] = Fr.unwrap(prevChallenge);
631
+
632
+ for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) {
633
+ gR[1 + i * 4] = proof.geminiFoldComms[i].x_0;
634
+ gR[2 + i * 4] = proof.geminiFoldComms[i].x_1;
635
+ gR[3 + i * 4] = proof.geminiFoldComms[i].y_0;
636
+ gR[4 + i * 4] = proof.geminiFoldComms[i].y_1;
637
+ }
638
+
639
+ nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(gR)));
640
+ Fr unused;
641
+ (geminiR, unused) = splitChallenge(nextPreviousChallenge);
642
+ }
643
+
644
+ function generateShplonkNuChallenge(Honk.Proof memory proof, Fr prevChallenge)
645
+ internal
646
+ pure
647
+ returns (Fr shplonkNu, Fr nextPreviousChallenge)
648
+ {
649
+ uint256[(CONST_PROOF_SIZE_LOG_N) + 1] memory shplonkNuChallengeElements;
650
+ shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge);
651
+
652
+ for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
653
+ shplonkNuChallengeElements[i + 1] = Fr.unwrap(proof.geminiAEvaluations[i]);
654
+ }
655
+
656
+ nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkNuChallengeElements)));
657
+ Fr unused;
658
+ (shplonkNu, unused) = splitChallenge(nextPreviousChallenge);
659
+ }
660
+
661
+ function generateShplonkZChallenge(Honk.Proof memory proof, Fr prevChallenge)
662
+ internal
663
+ pure
664
+ returns (Fr shplonkZ, Fr nextPreviousChallenge)
665
+ {
666
+ uint256[5] memory shplonkZChallengeElements;
667
+ shplonkZChallengeElements[0] = Fr.unwrap(prevChallenge);
668
+
669
+ shplonkZChallengeElements[1] = proof.shplonkQ.x_0;
670
+ shplonkZChallengeElements[2] = proof.shplonkQ.x_1;
671
+ shplonkZChallengeElements[3] = proof.shplonkQ.y_0;
672
+ shplonkZChallengeElements[4] = proof.shplonkQ.y_1;
673
+
674
+ nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkZChallengeElements)));
675
+ Fr unused;
676
+ (shplonkZ, unused) = splitChallenge(nextPreviousChallenge);
677
+ }
678
+
679
+ function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory p) {
680
+ // TODO(https://github.com/AztecProtocol/barretenberg/issues/1332): Optimize this away when we finalize.
681
+ uint256 boundary = 0x0;
682
+
683
+ // Pairing point object
684
+ for (uint256 i = 0; i < PAIRING_POINT_OBJECT_LENGTH; i++) {
685
+ p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + 0x20]);
686
+ boundary += 0x20;
687
+ }
688
+ // Commitments
689
+ p.w1 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
690
+ boundary += 0x80;
691
+ p.w2 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
692
+ boundary += 0x80;
693
+ p.w3 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
694
+ boundary += 0x80;
695
+
696
+ // Lookup / Permutation Helper Commitments
697
+ p.lookupReadCounts = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
698
+ boundary += 0x80;
699
+ p.lookupReadTags = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
700
+ boundary += 0x80;
701
+ p.w4 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
702
+ boundary += 0x80;
703
+ p.lookupInverses = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
704
+ boundary += 0x80;
705
+ p.zPerm = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
706
+ boundary += 0x80;
707
+
708
+ // Sumcheck univariates
709
+ for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
710
+ for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) {
711
+ p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + 0x20]);
712
+ boundary += 0x20;
713
+ }
714
+ }
715
+ // Sumcheck evaluations
716
+ for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) {
717
+ p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]);
718
+ boundary += 0x20;
719
+ }
720
+
721
+ // Gemini
722
+ // Read gemini fold univariates
723
+ for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) {
724
+ p.geminiFoldComms[i] = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
725
+ boundary += 0x80;
726
+ }
727
+
728
+ // Read gemini a evaluations
729
+ for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
730
+ p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]);
731
+ boundary += 0x20;
732
+ }
733
+
734
+ // Shplonk
735
+ p.shplonkQ = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
736
+ boundary += 0x80;
737
+ // KZG
738
+ p.kzgQuotient = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
739
+ }
740
+ }
741
+
742
+
743
+ // Fr utility
744
+
745
+ function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) {
746
+ require(proofSection.length == 0x20, "invalid bytes scalar");
747
+ scalar = FrLib.fromBytes32(bytes32(proofSection));
748
+ }
749
+
750
+ // EC Point utilities
751
+ function convertProofPoint(Honk.G1ProofPoint memory input) pure returns (Honk.G1Point memory) {
752
+ return Honk.G1Point({x: input.x_0 | (input.x_1 << 136), y: input.y_0 | (input.y_1 << 136)});
753
+ }
754
+
755
+ function bytesToG1ProofPoint(bytes calldata proofSection) pure returns (Honk.G1ProofPoint memory point) {
756
+ require(proofSection.length == 0x80, "invalid bytes point");
757
+ point = Honk.G1ProofPoint({
758
+ x_0: uint256(bytes32(proofSection[0x00:0x20])),
759
+ x_1: uint256(bytes32(proofSection[0x20:0x40])),
760
+ y_0: uint256(bytes32(proofSection[0x40:0x60])),
761
+ y_1: uint256(bytes32(proofSection[0x60:0x80]))
762
+ });
763
+ }
764
+
765
+ function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) {
766
+ point.y = (Q - point.y) % Q;
767
+ return point;
768
+ }
769
+
770
+ function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool) {
771
+ bytes memory input = abi.encodePacked(
772
+ rhs.x,
773
+ rhs.y,
774
+ // Fixed G1 point
775
+ uint256(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2),
776
+ uint256(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed),
777
+ uint256(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b),
778
+ uint256(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa),
779
+ lhs.x,
780
+ lhs.y,
781
+ // G1 point from VK
782
+ uint256(0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1),
783
+ uint256(0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0),
784
+ uint256(0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4),
785
+ uint256(0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55)
786
+ );
787
+
788
+ (bool success, bytes memory result) = address(0x08).staticcall(input);
789
+ bool decodedResult = abi.decode(result, (bool));
790
+ return success && decodedResult;
791
+ }
792
+
793
+
794
+ library RelationsLib {
795
+ Fr internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = Fr.wrap(17); // -(-17)
796
+
797
+ function accumulateRelationEvaluations(
798
+ Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations,
799
+ Honk.RelationParameters memory rp,
800
+ Fr[NUMBER_OF_ALPHAS] memory alphas,
801
+ Fr powPartialEval
802
+ ) internal pure returns (Fr accumulator) {
803
+ Fr[NUMBER_OF_SUBRELATIONS] memory evaluations;
804
+
805
+ // Accumulate all relations in Ultra Honk - each with varying number of subrelations
806
+ accumulateArithmeticRelation(purportedEvaluations, evaluations, powPartialEval);
807
+ accumulatePermutationRelation(purportedEvaluations, rp, evaluations, powPartialEval);
808
+ accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval);
809
+ accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval);
810
+ accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval);
811
+ accumulateAuxillaryRelation(purportedEvaluations, rp, evaluations, powPartialEval);
812
+ accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval);
813
+ accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval);
814
+ // batch the subrelations with the alpha challenges to obtain the full honk relation
815
+ accumulator = scaleAndBatchSubrelations(evaluations, alphas);
816
+ }
817
+
818
+ /**
819
+ * Aesthetic helper function that is used to index by enum into proof.sumcheckEvaluations, it avoids
820
+ * the relation checking code being cluttered with uint256 type casting, which is often a different colour in code
821
+ * editors, and thus is noisy.
822
+ */
823
+ function wire(Fr[NUMBER_OF_ENTITIES] memory p, WIRE _wire) internal pure returns (Fr) {
824
+ return p[uint256(_wire)];
825
+ }
826
+
827
+ uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;
828
+ /**
829
+ * Ultra Arithmetic Relation
830
+ *
831
+ */
832
+ function accumulateArithmeticRelation(
833
+ Fr[NUMBER_OF_ENTITIES] memory p,
834
+ Fr[NUMBER_OF_SUBRELATIONS] memory evals,
835
+ Fr domainSep
836
+ ) internal pure {
837
+ // Relation 0
838
+ Fr q_arith = wire(p, WIRE.Q_ARITH);
839
+ {
840
+ Fr neg_half = Fr.wrap(NEG_HALF_MODULO_P);
841
+
842
+ Fr accum = (q_arith - Fr.wrap(3)) * (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * neg_half;
843
+ accum = accum + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R))
844
+ + (wire(p, WIRE.Q_O) * wire(p, WIRE.W_O)) + (wire(p, WIRE.Q_4) * wire(p, WIRE.W_4)) + wire(p, WIRE.Q_C);
845
+ accum = accum + (q_arith - Fr.wrap(1)) * wire(p, WIRE.W_4_SHIFT);
846
+ accum = accum * q_arith;
847
+ accum = accum * domainSep;
848
+ evals[0] = accum;
849
+ }
850
+
851
+ // Relation 1
852
+ {
853
+ Fr accum = wire(p, WIRE.W_L) + wire(p, WIRE.W_4) - wire(p, WIRE.W_L_SHIFT) + wire(p, WIRE.Q_M);
854
+ accum = accum * (q_arith - Fr.wrap(2));
855
+ accum = accum * (q_arith - Fr.wrap(1));
856
+ accum = accum * q_arith;
857
+ accum = accum * domainSep;
858
+ evals[1] = accum;
859
+ }
860
+ }
861
+
862
+ function accumulatePermutationRelation(
863
+ Fr[NUMBER_OF_ENTITIES] memory p,
864
+ Honk.RelationParameters memory rp,
865
+ Fr[NUMBER_OF_SUBRELATIONS] memory evals,
866
+ Fr domainSep
867
+ ) internal pure {
868
+ Fr grand_product_numerator;
869
+ Fr grand_product_denominator;
870
+
871
+ {
872
+ Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * rp.beta + rp.gamma;
873
+ num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma);
874
+ num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma);
875
+ num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma);
876
+
877
+ grand_product_numerator = num;
878
+ }
879
+ {
880
+ Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * rp.beta + rp.gamma;
881
+ den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * rp.beta + rp.gamma);
882
+ den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * rp.beta + rp.gamma);
883
+ den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * rp.beta + rp.gamma);
884
+
885
+ grand_product_denominator = den;
886
+ }
887
+
888
+ // Contribution 2
889
+ {
890
+ Fr acc = (wire(p, WIRE.Z_PERM) + wire(p, WIRE.LAGRANGE_FIRST)) * grand_product_numerator;
891
+
892
+ acc = acc
893
+ - (
894
+ (wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta))
895
+ * grand_product_denominator
896
+ );
897
+ acc = acc * domainSep;
898
+ evals[2] = acc;
899
+ }
900
+
901
+ // Contribution 3
902
+ {
903
+ Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep;
904
+ evals[3] = acc;
905
+ }
906
+ }
907
+
908
+ function accumulateLogDerivativeLookupRelation(
909
+ Fr[NUMBER_OF_ENTITIES] memory p,
910
+ Honk.RelationParameters memory rp,
911
+ Fr[NUMBER_OF_SUBRELATIONS] memory evals,
912
+ Fr domainSep
913
+ ) internal pure {
914
+ Fr write_term;
915
+ Fr read_term;
916
+
917
+ // Calculate the write term (the table accumulation)
918
+ {
919
+ write_term = wire(p, WIRE.TABLE_1) + rp.gamma + (wire(p, WIRE.TABLE_2) * rp.eta)
920
+ + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + (wire(p, WIRE.TABLE_4) * rp.etaThree);
921
+ }
922
+
923
+ // Calculate the write term
924
+ {
925
+ Fr derived_entry_1 = wire(p, WIRE.W_L) + rp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT));
926
+ Fr derived_entry_2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_M) * wire(p, WIRE.W_R_SHIFT);
927
+ Fr derived_entry_3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_C) * wire(p, WIRE.W_O_SHIFT);
928
+
929
+ read_term = derived_entry_1 + (derived_entry_2 * rp.eta) + (derived_entry_3 * rp.etaTwo)
930
+ + (wire(p, WIRE.Q_O) * rp.etaThree);
931
+ }
932
+
933
+ Fr read_inverse = wire(p, WIRE.LOOKUP_INVERSES) * write_term;
934
+ Fr write_inverse = wire(p, WIRE.LOOKUP_INVERSES) * read_term;
935
+
936
+ Fr inverse_exists_xor = wire(p, WIRE.LOOKUP_READ_TAGS) + wire(p, WIRE.Q_LOOKUP)
937
+ - (wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP));
938
+
939
+ // Inverse calculated correctly relation
940
+ Fr accumulatorNone = read_term * write_term * wire(p, WIRE.LOOKUP_INVERSES) - inverse_exists_xor;
941
+ accumulatorNone = accumulatorNone * domainSep;
942
+
943
+ // Inverse
944
+ Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * read_inverse - wire(p, WIRE.LOOKUP_READ_COUNTS) * write_inverse;
945
+
946
+ evals[4] = accumulatorNone;
947
+ evals[5] = accumulatorOne;
948
+ }
949
+
950
+ function accumulateDeltaRangeRelation(
951
+ Fr[NUMBER_OF_ENTITIES] memory p,
952
+ Fr[NUMBER_OF_SUBRELATIONS] memory evals,
953
+ Fr domainSep
954
+ ) internal pure {
955
+ Fr minus_one = Fr.wrap(0) - Fr.wrap(1);
956
+ Fr minus_two = Fr.wrap(0) - Fr.wrap(2);
957
+ Fr minus_three = Fr.wrap(0) - Fr.wrap(3);
958
+
959
+ // Compute wire differences
960
+ Fr delta_1 = wire(p, WIRE.W_R) - wire(p, WIRE.W_L);
961
+ Fr delta_2 = wire(p, WIRE.W_O) - wire(p, WIRE.W_R);
962
+ Fr delta_3 = wire(p, WIRE.W_4) - wire(p, WIRE.W_O);
963
+ Fr delta_4 = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_4);
964
+
965
+ // Contribution 6
966
+ {
967
+ Fr acc = delta_1;
968
+ acc = acc * (delta_1 + minus_one);
969
+ acc = acc * (delta_1 + minus_two);
970
+ acc = acc * (delta_1 + minus_three);
971
+ acc = acc * wire(p, WIRE.Q_RANGE);
972
+ acc = acc * domainSep;
973
+ evals[6] = acc;
974
+ }
975
+
976
+ // Contribution 7
977
+ {
978
+ Fr acc = delta_2;
979
+ acc = acc * (delta_2 + minus_one);
980
+ acc = acc * (delta_2 + minus_two);
981
+ acc = acc * (delta_2 + minus_three);
982
+ acc = acc * wire(p, WIRE.Q_RANGE);
983
+ acc = acc * domainSep;
984
+ evals[7] = acc;
985
+ }
986
+
987
+ // Contribution 8
988
+ {
989
+ Fr acc = delta_3;
990
+ acc = acc * (delta_3 + minus_one);
991
+ acc = acc * (delta_3 + minus_two);
992
+ acc = acc * (delta_3 + minus_three);
993
+ acc = acc * wire(p, WIRE.Q_RANGE);
994
+ acc = acc * domainSep;
995
+ evals[8] = acc;
996
+ }
997
+
998
+ // Contribution 9
999
+ {
1000
+ Fr acc = delta_4;
1001
+ acc = acc * (delta_4 + minus_one);
1002
+ acc = acc * (delta_4 + minus_two);
1003
+ acc = acc * (delta_4 + minus_three);
1004
+ acc = acc * wire(p, WIRE.Q_RANGE);
1005
+ acc = acc * domainSep;
1006
+ evals[9] = acc;
1007
+ }
1008
+ }
1009
+
1010
+ struct EllipticParams {
1011
+ // Points
1012
+ Fr x_1;
1013
+ Fr y_1;
1014
+ Fr x_2;
1015
+ Fr y_2;
1016
+ Fr y_3;
1017
+ Fr x_3;
1018
+ // push accumulators into memory
1019
+ Fr x_double_identity;
1020
+ }
1021
+
1022
+ function accumulateEllipticRelation(
1023
+ Fr[NUMBER_OF_ENTITIES] memory p,
1024
+ Fr[NUMBER_OF_SUBRELATIONS] memory evals,
1025
+ Fr domainSep
1026
+ ) internal pure {
1027
+ EllipticParams memory ep;
1028
+ ep.x_1 = wire(p, WIRE.W_R);
1029
+ ep.y_1 = wire(p, WIRE.W_O);
1030
+
1031
+ ep.x_2 = wire(p, WIRE.W_L_SHIFT);
1032
+ ep.y_2 = wire(p, WIRE.W_4_SHIFT);
1033
+ ep.y_3 = wire(p, WIRE.W_O_SHIFT);
1034
+ ep.x_3 = wire(p, WIRE.W_R_SHIFT);
1035
+
1036
+ Fr q_sign = wire(p, WIRE.Q_L);
1037
+ Fr q_is_double = wire(p, WIRE.Q_M);
1038
+
1039
+ // Contribution 10 point addition, x-coordinate check
1040
+ // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0
1041
+ Fr x_diff = (ep.x_2 - ep.x_1);
1042
+ Fr y1_sqr = (ep.y_1 * ep.y_1);
1043
+ {
1044
+ // Move to top
1045
+ Fr partialEval = domainSep;
1046
+
1047
+ Fr y2_sqr = (ep.y_2 * ep.y_2);
1048
+ Fr y1y2 = ep.y_1 * ep.y_2 * q_sign;
1049
+ Fr x_add_identity = (ep.x_3 + ep.x_2 + ep.x_1);
1050
+ x_add_identity = x_add_identity * x_diff * x_diff;
1051
+ x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2;
1052
+
1053
+ evals[10] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (Fr.wrap(1) - q_is_double);
1054
+ }
1055
+
1056
+ // Contribution 11 point addition, x-coordinate check
1057
+ // q_elliptic * (q_sign * y1 + y3)(x2 - x1) + (x3 - x1)(y2 - q_sign * y1) = 0
1058
+ {
1059
+ Fr y1_plus_y3 = ep.y_1 + ep.y_3;
1060
+ Fr y_diff = ep.y_2 * q_sign - ep.y_1;
1061
+ Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff;
1062
+ evals[11] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (Fr.wrap(1) - q_is_double);
1063
+ }
1064
+
1065
+ // Contribution 10 point doubling, x-coordinate check
1066
+ // (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0
1067
+ // N.B. we're using the equivalence x1*x1*x1 === y1*y1 - curve_b to reduce degree by 1
1068
+ {
1069
+ Fr x_pow_4 = (y1_sqr + GRUMPKIN_CURVE_B_PARAMETER_NEGATED) * ep.x_1;
1070
+ Fr y1_sqr_mul_4 = y1_sqr + y1_sqr;
1071
+ y1_sqr_mul_4 = y1_sqr_mul_4 + y1_sqr_mul_4;
1072
+ Fr x1_pow_4_mul_9 = x_pow_4 * Fr.wrap(9);
1073
+
1074
+ // NOTE: pushed into memory (stack >:'( )
1075
+ ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9;
1076
+
1077
+ Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double;
1078
+ evals[10] = evals[10] + acc;
1079
+ }
1080
+
1081
+ // Contribution 11 point doubling, y-coordinate check
1082
+ // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0
1083
+ {
1084
+ Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1;
1085
+ Fr y_double_identity = x1_sqr_mul_3 * (ep.x_1 - ep.x_3) - (ep.y_1 + ep.y_1) * (ep.y_1 + ep.y_3);
1086
+ evals[11] = evals[11] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double;
1087
+ }
1088
+ }
1089
+
1090
+ // Constants for the auxiliary relation
1091
+ Fr constant LIMB_SIZE = Fr.wrap(uint256(1) << 68);
1092
+ Fr constant SUBLIMB_SHIFT = Fr.wrap(uint256(1) << 14);
1093
+
1094
+ // Parameters used within the Auxiliary Relation
1095
+ // A struct is used to work around stack too deep. This relation has alot of variables
1096
+ struct AuxParams {
1097
+ Fr limb_subproduct;
1098
+ Fr non_native_field_gate_1;
1099
+ Fr non_native_field_gate_2;
1100
+ Fr non_native_field_gate_3;
1101
+ Fr limb_accumulator_1;
1102
+ Fr limb_accumulator_2;
1103
+ Fr memory_record_check;
1104
+ Fr partial_record_check;
1105
+ Fr next_gate_access_type;
1106
+ Fr record_delta;
1107
+ Fr index_delta;
1108
+ Fr adjacent_values_match_if_adjacent_indices_match;
1109
+ Fr adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation;
1110
+ Fr access_check;
1111
+ Fr next_gate_access_type_is_boolean;
1112
+ Fr ROM_consistency_check_identity;
1113
+ Fr RAM_consistency_check_identity;
1114
+ Fr timestamp_delta;
1115
+ Fr RAM_timestamp_check_identity;
1116
+ Fr memory_identity;
1117
+ Fr index_is_monotonically_increasing;
1118
+ Fr auxiliary_identity;
1119
+ }
1120
+
1121
+ function accumulateAuxillaryRelation(
1122
+ Fr[NUMBER_OF_ENTITIES] memory p,
1123
+ Honk.RelationParameters memory rp,
1124
+ Fr[NUMBER_OF_SUBRELATIONS] memory evals,
1125
+ Fr domainSep
1126
+ ) internal pure {
1127
+ AuxParams memory ap;
1128
+
1129
+ /**
1130
+ * Contribution 12
1131
+ * Non native field arithmetic gate 2
1132
+ * deg 4
1133
+ *
1134
+ * _ _
1135
+ * / _ _ _ 14 \
1136
+ * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 |
1137
+ * \_ _/
1138
+ *
1139
+ *
1140
+ */
1141
+ ap.limb_subproduct = wire(p, WIRE.W_L) * wire(p, WIRE.W_R_SHIFT) + wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R);
1142
+ ap.non_native_field_gate_2 =
1143
+ (wire(p, WIRE.W_L) * wire(p, WIRE.W_4) + wire(p, WIRE.W_R) * wire(p, WIRE.W_O) - wire(p, WIRE.W_O_SHIFT));
1144
+ ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * LIMB_SIZE;
1145
+ ap.non_native_field_gate_2 = ap.non_native_field_gate_2 - wire(p, WIRE.W_4_SHIFT);
1146
+ ap.non_native_field_gate_2 = ap.non_native_field_gate_2 + ap.limb_subproduct;
1147
+ ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * wire(p, WIRE.Q_4);
1148
+
1149
+ ap.limb_subproduct = ap.limb_subproduct * LIMB_SIZE;
1150
+ ap.limb_subproduct = ap.limb_subproduct + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT));
1151
+ ap.non_native_field_gate_1 = ap.limb_subproduct;
1152
+ ap.non_native_field_gate_1 = ap.non_native_field_gate_1 - (wire(p, WIRE.W_O) + wire(p, WIRE.W_4));
1153
+ ap.non_native_field_gate_1 = ap.non_native_field_gate_1 * wire(p, WIRE.Q_O);
1154
+
1155
+ ap.non_native_field_gate_3 = ap.limb_subproduct;
1156
+ ap.non_native_field_gate_3 = ap.non_native_field_gate_3 + wire(p, WIRE.W_4);
1157
+ ap.non_native_field_gate_3 = ap.non_native_field_gate_3 - (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT));
1158
+ ap.non_native_field_gate_3 = ap.non_native_field_gate_3 * wire(p, WIRE.Q_M);
1159
+
1160
+ Fr non_native_field_identity =
1161
+ ap.non_native_field_gate_1 + ap.non_native_field_gate_2 + ap.non_native_field_gate_3;
1162
+ non_native_field_identity = non_native_field_identity * wire(p, WIRE.Q_R);
1163
+
1164
+ // ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm
1165
+ // deg 2
1166
+ ap.limb_accumulator_1 = wire(p, WIRE.W_R_SHIFT) * SUBLIMB_SHIFT;
1167
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L_SHIFT);
1168
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1169
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_O);
1170
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1171
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_R);
1172
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1173
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L);
1174
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 - wire(p, WIRE.W_4);
1175
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 * wire(p, WIRE.Q_4);
1176
+
1177
+ // ((((w3' * 2^14 + w2') * 2^14 + w1') * 2^14 + w4) * 2^14 + w3 - w4') * qm
1178
+ // deg 2
1179
+ ap.limb_accumulator_2 = wire(p, WIRE.W_O_SHIFT) * SUBLIMB_SHIFT;
1180
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_R_SHIFT);
1181
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1182
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_L_SHIFT);
1183
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1184
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_4);
1185
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1186
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_O);
1187
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 - wire(p, WIRE.W_4_SHIFT);
1188
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 * wire(p, WIRE.Q_M);
1189
+
1190
+ Fr limb_accumulator_identity = ap.limb_accumulator_1 + ap.limb_accumulator_2;
1191
+ limb_accumulator_identity = limb_accumulator_identity * wire(p, WIRE.Q_O); // deg 3
1192
+
1193
+ /**
1194
+ * MEMORY
1195
+ *
1196
+ * A RAM memory record contains a tuple of the following fields:
1197
+ * * i: `index` of memory cell being accessed
1198
+ * * t: `timestamp` of memory cell being accessed (used for RAM, set to 0 for ROM)
1199
+ * * v: `value` of memory cell being accessed
1200
+ * * a: `access` type of record. read: 0 = read, 1 = write
1201
+ * * r: `record` of memory cell. record = access + index * eta + timestamp * eta_two + value * eta_three
1202
+ *
1203
+ * A ROM memory record contains a tuple of the following fields:
1204
+ * * i: `index` of memory cell being accessed
1205
+ * * v: `value1` of memory cell being accessed (ROM tables can store up to 2 values per index)
1206
+ * * v2:`value2` of memory cell being accessed (ROM tables can store up to 2 values per index)
1207
+ * * r: `record` of memory cell. record = index * eta + value2 * eta_two + value1 * eta_three
1208
+ *
1209
+ * When performing a read/write access, the values of i, t, v, v2, a, r are stored in the following wires +
1210
+ * selectors, depending on whether the gate is a RAM read/write or a ROM read
1211
+ *
1212
+ * | gate type | i | v2/t | v | a | r |
1213
+ * | --------- | -- | ----- | -- | -- | -- |
1214
+ * | ROM | w1 | w2 | w3 | -- | w4 |
1215
+ * | RAM | w1 | w2 | w3 | qc | w4 |
1216
+ *
1217
+ * (for accesses where `index` is a circuit constant, it is assumed the circuit will apply a copy constraint on
1218
+ * `w2` to fix its value)
1219
+ *
1220
+ *
1221
+ */
1222
+
1223
+ /**
1224
+ * Memory Record Check
1225
+ * Partial degree: 1
1226
+ * Total degree: 4
1227
+ *
1228
+ * A ROM/ROM access gate can be evaluated with the identity:
1229
+ *
1230
+ * qc + w1 \eta + w2 \eta_two + w3 \eta_three - w4 = 0
1231
+ *
1232
+ * For ROM gates, qc = 0
1233
+ */
1234
+ ap.memory_record_check = wire(p, WIRE.W_O) * rp.etaThree;
1235
+ ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * rp.etaTwo);
1236
+ ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * rp.eta);
1237
+ ap.memory_record_check = ap.memory_record_check + wire(p, WIRE.Q_C);
1238
+ ap.partial_record_check = ap.memory_record_check; // used in RAM consistency check; deg 1 or 4
1239
+ ap.memory_record_check = ap.memory_record_check - wire(p, WIRE.W_4);
1240
+
1241
+ /**
1242
+ * Contribution 13 & 14
1243
+ * ROM Consistency Check
1244
+ * Partial degree: 1
1245
+ * Total degree: 4
1246
+ *
1247
+ * For every ROM read, a set equivalence check is applied between the record witnesses, and a second set of
1248
+ * records that are sorted.
1249
+ *
1250
+ * We apply the following checks for the sorted records:
1251
+ *
1252
+ * 1. w1, w2, w3 correctly map to 'index', 'v1, 'v2' for a given record value at w4
1253
+ * 2. index values for adjacent records are monotonically increasing
1254
+ * 3. if, at gate i, index_i == index_{i + 1}, then value1_i == value1_{i + 1} and value2_i == value2_{i + 1}
1255
+ *
1256
+ */
1257
+ ap.index_delta = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_L);
1258
+ ap.record_delta = wire(p, WIRE.W_4_SHIFT) - wire(p, WIRE.W_4);
1259
+
1260
+ ap.index_is_monotonically_increasing = ap.index_delta * ap.index_delta - ap.index_delta; // deg 2
1261
+
1262
+ ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + Fr.wrap(1)) * ap.record_delta; // deg 2
1263
+
1264
+ evals[13] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R))
1265
+ * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5
1266
+ evals[14] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R))
1267
+ * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5
1268
+
1269
+ ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7
1270
+
1271
+ /**
1272
+ * Contributions 15,16,17
1273
+ * RAM Consistency Check
1274
+ *
1275
+ * The 'access' type of the record is extracted with the expression `w_4 - ap.partial_record_check`
1276
+ * (i.e. for an honest Prover `w1 * eta + w2 * eta^2 + w3 * eta^3 - w4 = access`.
1277
+ * This is validated by requiring `access` to be boolean
1278
+ *
1279
+ * For two adjacent entries in the sorted list if _both_
1280
+ * A) index values match
1281
+ * B) adjacent access value is 0 (i.e. next gate is a READ)
1282
+ * then
1283
+ * C) both values must match.
1284
+ * The gate boolean check is
1285
+ * (A && B) => C === !(A && B) || C === !A || !B || C
1286
+ *
1287
+ * N.B. it is the responsibility of the circuit writer to ensure that every RAM cell is initialized
1288
+ * with a WRITE operation.
1289
+ */
1290
+ Fr access_type = (wire(p, WIRE.W_4) - ap.partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 4
1291
+ ap.access_check = access_type * access_type - access_type; // check value is 0 or 1; deg 2 or 8
1292
+
1293
+ ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree;
1294
+ ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo);
1295
+ ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta);
1296
+ ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type;
1297
+
1298
+ Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O);
1299
+ ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (
1300
+ ap.index_delta * MINUS_ONE + Fr.wrap(1)
1301
+ ) * value_delta * (ap.next_gate_access_type * MINUS_ONE + Fr.wrap(1)); // deg 3 or 6
1302
+
1303
+ // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the
1304
+ // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't
1305
+ // do with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access
1306
+ // type is correct, to cover this edge case
1307
+ // deg 2 or 4
1308
+ ap.next_gate_access_type_is_boolean =
1309
+ ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type;
1310
+
1311
+ // Putting it all together...
1312
+ evals[15] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation
1313
+ * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5 or 8
1314
+ evals[16] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4
1315
+ evals[17] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4 or 6
1316
+
1317
+ ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_ARITH)); // deg 3 or 9
1318
+
1319
+ /**
1320
+ * RAM Timestamp Consistency Check
1321
+ *
1322
+ * | w1 | w2 | w3 | w4 |
1323
+ * | index | timestamp | timestamp_check | -- |
1324
+ *
1325
+ * Let delta_index = index_{i + 1} - index_{i}
1326
+ *
1327
+ * Iff delta_index == 0, timestamp_check = timestamp_{i + 1} - timestamp_i
1328
+ * Else timestamp_check = 0
1329
+ */
1330
+ ap.timestamp_delta = wire(p, WIRE.W_R_SHIFT) - wire(p, WIRE.W_R);
1331
+ ap.RAM_timestamp_check_identity =
1332
+ (ap.index_delta * MINUS_ONE + Fr.wrap(1)) * ap.timestamp_delta - wire(p, WIRE.W_O); // deg 3
1333
+
1334
+ /**
1335
+ * Complete Contribution 12
1336
+ * The complete RAM/ROM memory identity
1337
+ * Partial degree:
1338
+ */
1339
+ ap.memory_identity = ap.ROM_consistency_check_identity; // deg 3 or 6
1340
+ ap.memory_identity =
1341
+ ap.memory_identity + ap.RAM_timestamp_check_identity * (wire(p, WIRE.Q_4) * wire(p, WIRE.Q_L)); // deg 4
1342
+ ap.memory_identity = ap.memory_identity + ap.memory_record_check * (wire(p, WIRE.Q_M) * wire(p, WIRE.Q_L)); // deg 3 or 6
1343
+ ap.memory_identity = ap.memory_identity + ap.RAM_consistency_check_identity; // deg 3 or 9
1344
+
1345
+ // (deg 3 or 9) + (deg 4) + (deg 3)
1346
+ ap.auxiliary_identity = ap.memory_identity + non_native_field_identity + limb_accumulator_identity;
1347
+ ap.auxiliary_identity = ap.auxiliary_identity * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4 or 10
1348
+ evals[12] = ap.auxiliary_identity;
1349
+ }
1350
+
1351
+ struct PoseidonExternalParams {
1352
+ Fr s1;
1353
+ Fr s2;
1354
+ Fr s3;
1355
+ Fr s4;
1356
+ Fr u1;
1357
+ Fr u2;
1358
+ Fr u3;
1359
+ Fr u4;
1360
+ Fr t0;
1361
+ Fr t1;
1362
+ Fr t2;
1363
+ Fr t3;
1364
+ Fr v1;
1365
+ Fr v2;
1366
+ Fr v3;
1367
+ Fr v4;
1368
+ Fr q_pos_by_scaling;
1369
+ }
1370
+
1371
+ function accumulatePoseidonExternalRelation(
1372
+ Fr[NUMBER_OF_ENTITIES] memory p,
1373
+ Fr[NUMBER_OF_SUBRELATIONS] memory evals,
1374
+ Fr domainSep
1375
+ ) internal pure {
1376
+ PoseidonExternalParams memory ep;
1377
+
1378
+ ep.s1 = wire(p, WIRE.W_L) + wire(p, WIRE.Q_L);
1379
+ ep.s2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_R);
1380
+ ep.s3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_O);
1381
+ ep.s4 = wire(p, WIRE.W_4) + wire(p, WIRE.Q_4);
1382
+
1383
+ ep.u1 = ep.s1 * ep.s1 * ep.s1 * ep.s1 * ep.s1;
1384
+ ep.u2 = ep.s2 * ep.s2 * ep.s2 * ep.s2 * ep.s2;
1385
+ ep.u3 = ep.s3 * ep.s3 * ep.s3 * ep.s3 * ep.s3;
1386
+ ep.u4 = ep.s4 * ep.s4 * ep.s4 * ep.s4 * ep.s4;
1387
+ // matrix mul v = M_E * u with 14 additions
1388
+ ep.t0 = ep.u1 + ep.u2; // u_1 + u_2
1389
+ ep.t1 = ep.u3 + ep.u4; // u_3 + u_4
1390
+ ep.t2 = ep.u2 + ep.u2 + ep.t1; // 2u_2
1391
+ // ep.t2 += ep.t1; // 2u_2 + u_3 + u_4
1392
+ ep.t3 = ep.u4 + ep.u4 + ep.t0; // 2u_4
1393
+ // ep.t3 += ep.t0; // u_1 + u_2 + 2u_4
1394
+ ep.v4 = ep.t1 + ep.t1;
1395
+ ep.v4 = ep.v4 + ep.v4 + ep.t3;
1396
+ // ep.v4 += ep.t3; // u_1 + u_2 + 4u_3 + 6u_4
1397
+ ep.v2 = ep.t0 + ep.t0;
1398
+ ep.v2 = ep.v2 + ep.v2 + ep.t2;
1399
+ // ep.v2 += ep.t2; // 4u_1 + 6u_2 + u_3 + u_4
1400
+ ep.v1 = ep.t3 + ep.v2; // 5u_1 + 7u_2 + u_3 + 3u_4
1401
+ ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4
1402
+
1403
+ ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep;
1404
+ evals[18] = evals[18] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT));
1405
+
1406
+ evals[19] = evals[19] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT));
1407
+
1408
+ evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT));
1409
+
1410
+ evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT));
1411
+ }
1412
+
1413
+ struct PoseidonInternalParams {
1414
+ Fr u1;
1415
+ Fr u2;
1416
+ Fr u3;
1417
+ Fr u4;
1418
+ Fr u_sum;
1419
+ Fr v1;
1420
+ Fr v2;
1421
+ Fr v3;
1422
+ Fr v4;
1423
+ Fr s1;
1424
+ Fr q_pos_by_scaling;
1425
+ }
1426
+
1427
+ function accumulatePoseidonInternalRelation(
1428
+ Fr[NUMBER_OF_ENTITIES] memory p,
1429
+ Fr[NUMBER_OF_SUBRELATIONS] memory evals,
1430
+ Fr domainSep
1431
+ ) internal pure {
1432
+ PoseidonInternalParams memory ip;
1433
+
1434
+ Fr[4] memory INTERNAL_MATRIX_DIAGONAL = [
1435
+ FrLib.from(0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7),
1436
+ FrLib.from(0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b),
1437
+ FrLib.from(0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15),
1438
+ FrLib.from(0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b)
1439
+ ];
1440
+
1441
+ // add round constants
1442
+ ip.s1 = wire(p, WIRE.W_L) + wire(p, WIRE.Q_L);
1443
+
1444
+ // apply s-box round
1445
+ ip.u1 = ip.s1 * ip.s1 * ip.s1 * ip.s1 * ip.s1;
1446
+ ip.u2 = wire(p, WIRE.W_R);
1447
+ ip.u3 = wire(p, WIRE.W_O);
1448
+ ip.u4 = wire(p, WIRE.W_4);
1449
+
1450
+ // matrix mul with v = M_I * u 4 muls and 7 additions
1451
+ ip.u_sum = ip.u1 + ip.u2 + ip.u3 + ip.u4;
1452
+
1453
+ ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep;
1454
+
1455
+ ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum;
1456
+ evals[22] = evals[22] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT));
1457
+
1458
+ ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum;
1459
+ evals[23] = evals[23] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT));
1460
+
1461
+ ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum;
1462
+ evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT));
1463
+
1464
+ ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum;
1465
+ evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT));
1466
+ }
1467
+
1468
+ function scaleAndBatchSubrelations(
1469
+ Fr[NUMBER_OF_SUBRELATIONS] memory evaluations,
1470
+ Fr[NUMBER_OF_ALPHAS] memory subrelationChallenges
1471
+ ) internal pure returns (Fr accumulator) {
1472
+ accumulator = accumulator + evaluations[0];
1473
+
1474
+ for (uint256 i = 1; i < NUMBER_OF_SUBRELATIONS; ++i) {
1475
+ accumulator = accumulator + evaluations[i] * subrelationChallenges[i - 1];
1476
+ }
1477
+ }
1478
+ }
1479
+
1480
+ struct ShpleminiIntermediates {
1481
+ Fr unshiftedScalar;
1482
+ Fr shiftedScalar;
1483
+ // Scalar to be multiplied by [1]₁
1484
+ Fr constantTermAccumulator;
1485
+ // Accumulator for powers of rho
1486
+ Fr batchingChallenge;
1487
+ // Linear combination of multilinear (sumcheck) evaluations and powers of rho
1488
+ Fr batchedEvaluation;
1489
+ // 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated
1490
+ Fr posInvertedDenominator;
1491
+ // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated
1492
+ Fr negInvertedDenominator;
1493
+ // v^{2i} * 1/(z - r^{2^i})
1494
+ Fr scalingFactorPos;
1495
+ // v^{2i+1} * 1/(z + r^{2^i})
1496
+ Fr scalingFactorNeg;
1497
+ // // Fold_i(r^{2^i}) reconstructed by Verifier
1498
+ // Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations;
1499
+ }
1500
+
1501
+ library CommitmentSchemeLib {
1502
+ using FrLib for Fr;
1503
+
1504
+ function computeSquares(Fr r) internal pure returns (Fr[CONST_PROOF_SIZE_LOG_N] memory squares) {
1505
+ squares[0] = r;
1506
+ for (uint256 i = 1; i < CONST_PROOF_SIZE_LOG_N; ++i) {
1507
+ squares[i] = squares[i - 1].sqr();
1508
+ }
1509
+ }
1510
+
1511
+ // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., m-1
1512
+ function computeFoldPosEvaluations(
1513
+ Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges,
1514
+ Fr batchedEvalAccumulator,
1515
+ Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvaluations,
1516
+ Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvalChallengePowers,
1517
+ uint256 logSize
1518
+ ) internal view returns (Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations) {
1519
+ for (uint256 i = CONST_PROOF_SIZE_LOG_N; i > 0; --i) {
1520
+ Fr challengePower = geminiEvalChallengePowers[i - 1];
1521
+ Fr u = sumcheckUChallenges[i - 1];
1522
+
1523
+ Fr batchedEvalRoundAcc = (
1524
+ (challengePower * batchedEvalAccumulator * Fr.wrap(2))
1525
+ - geminiEvaluations[i - 1] * (challengePower * (Fr.wrap(1) - u) - u)
1526
+ );
1527
+ // Divide by the denominator
1528
+ batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (Fr.wrap(1) - u) + u).invert();
1529
+
1530
+ if (i <= logSize) {
1531
+ batchedEvalAccumulator = batchedEvalRoundAcc;
1532
+ foldPosEvaluations[i - 1] = batchedEvalRoundAcc;
1533
+ }
1534
+ }
1535
+
1536
+ }
1537
+ }
1538
+
1539
+ interface IVerifier {
1540
+ function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool);
1541
+ }
1542
+
1543
+
1544
+ abstract contract BaseHonkVerifier is IVerifier {
1545
+ using FrLib for Fr;
1546
+
1547
+ uint256 immutable n;
1548
+ uint256 immutable logN;
1549
+ uint256 immutable numPublicInputs;
1550
+
1551
+ constructor(uint256 _n, uint256 _logN, uint256 _numPublicInputs) {
1552
+ n = _n;
1553
+ logN = _logN;
1554
+ numPublicInputs = _numPublicInputs;
1555
+ }
1556
+
1557
+ error ProofLengthWrong();
1558
+ error PublicInputsLengthWrong();
1559
+ error SumcheckFailed();
1560
+ error ShpleminiFailed();
1561
+
1562
+ // Number of field elements in a ultra honk zero knowledge proof
1563
+ uint256 constant PROOF_SIZE = 456;
1564
+
1565
+ function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory);
1566
+
1567
+ function verify(bytes calldata proof, bytes32[] calldata publicInputs) public view override returns (bool) {
1568
+ // Check the received proof is the expected size where each field element is 32 bytes
1569
+ if (proof.length != PROOF_SIZE * 32) {
1570
+ revert ProofLengthWrong();
1571
+ }
1572
+
1573
+ Honk.VerificationKey memory vk = loadVerificationKey();
1574
+ Honk.Proof memory p = TranscriptLib.loadProof(proof);
1575
+
1576
+ if (publicInputs.length != vk.publicInputsSize - PAIRING_POINT_OBJECT_LENGTH) {
1577
+ revert PublicInputsLengthWrong();
1578
+ }
1579
+
1580
+ // Generate the fiat shamir challenges for the whole protocol
1581
+ // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely.
1582
+ Transcript memory t = TranscriptLib.generateTranscript(p, publicInputs, vk.circuitSize, vk.publicInputsSize, /*pubInputsOffset=*/1);
1583
+
1584
+ // Derive public input delta
1585
+ // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely.
1586
+ t.relationParameters.publicInputsDelta = computePublicInputDelta(
1587
+ publicInputs, p.pairingPointObject, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/1
1588
+ );
1589
+
1590
+ // Sumcheck
1591
+ bool sumcheckVerified = verifySumcheck(p, t);
1592
+ if (!sumcheckVerified) revert SumcheckFailed();
1593
+
1594
+ bool shpleminiVerified = verifyShplemini(p, vk, t);
1595
+ if (!shpleminiVerified) revert ShpleminiFailed();
1596
+
1597
+ return sumcheckVerified && shpleminiVerified; // Boolean condition not required - nice for vanity :)
1598
+ }
1599
+
1600
+ function computePublicInputDelta(bytes32[] memory publicInputs, Fr[PAIRING_POINT_OBJECT_LENGTH] memory pairingPointObject, Fr beta, Fr gamma, uint256 offset)
1601
+ internal
1602
+ view
1603
+ returns (Fr publicInputDelta)
1604
+ {
1605
+ Fr numerator = Fr.wrap(1);
1606
+ Fr denominator = Fr.wrap(1);
1607
+
1608
+ Fr numeratorAcc = gamma + (beta * FrLib.from(n + offset));
1609
+ Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1));
1610
+
1611
+ {
1612
+ for (uint256 i = 0; i < numPublicInputs - PAIRING_POINT_OBJECT_LENGTH; i++) {
1613
+ Fr pubInput = FrLib.fromBytes32(publicInputs[i]);
1614
+
1615
+ numerator = numerator * (numeratorAcc + pubInput);
1616
+ denominator = denominator * (denominatorAcc + pubInput);
1617
+
1618
+ numeratorAcc = numeratorAcc + beta;
1619
+ denominatorAcc = denominatorAcc - beta;
1620
+ }
1621
+
1622
+ for (uint256 i = 0; i < PAIRING_POINT_OBJECT_LENGTH; i++) {
1623
+ Fr pubInput = pairingPointObject[i];
1624
+
1625
+ numerator = numerator * (numeratorAcc + pubInput);
1626
+ denominator = denominator * (denominatorAcc + pubInput);
1627
+
1628
+ numeratorAcc = numeratorAcc + beta;
1629
+ denominatorAcc = denominatorAcc - beta;
1630
+ }
1631
+ }
1632
+
1633
+ // Fr delta = numerator / denominator; // TOOO: batch invert later?
1634
+ publicInputDelta = FrLib.div(numerator, denominator);
1635
+ }
1636
+
1637
+ function verifySumcheck(Honk.Proof memory proof, Transcript memory tp) internal view returns (bool verified) {
1638
+ Fr roundTarget;
1639
+ Fr powPartialEvaluation = Fr.wrap(1);
1640
+
1641
+ // We perform sumcheck reductions over log n rounds ( the multivariate degree )
1642
+ for (uint256 round; round < logN; ++round) {
1643
+ Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round];
1644
+ bool valid = checkSum(roundUnivariate, roundTarget);
1645
+ if (!valid) revert SumcheckFailed();
1646
+
1647
+ Fr roundChallenge = tp.sumCheckUChallenges[round];
1648
+
1649
+ // Update the round target for the next rounf
1650
+ roundTarget = computeNextTargetSum(roundUnivariate, roundChallenge);
1651
+ powPartialEvaluation = partiallyEvaluatePOW(tp.gateChallenges[round], powPartialEvaluation, roundChallenge);
1652
+ }
1653
+
1654
+ // Last round
1655
+ Fr grandHonkRelationSum =
1656
+ RelationsLib.accumulateRelationEvaluations(proof.sumcheckEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation);
1657
+ verified = (grandHonkRelationSum == roundTarget);
1658
+ }
1659
+
1660
+ function checkSum(Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate, Fr roundTarget)
1661
+ internal
1662
+ pure
1663
+ returns (bool checked)
1664
+ {
1665
+ Fr totalSum = roundUnivariate[0] + roundUnivariate[1];
1666
+ checked = totalSum == roundTarget;
1667
+ }
1668
+
1669
+ // Return the new target sum for the next sumcheck round
1670
+ function computeNextTargetSum(Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge)
1671
+ internal
1672
+ view
1673
+ returns (Fr targetSum)
1674
+ {
1675
+ // TODO: inline
1676
+ Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [
1677
+ Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51),
1678
+ Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000002d0),
1679
+ Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff11),
1680
+ Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000090),
1681
+ Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff71),
1682
+ Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000000f0),
1683
+ Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31),
1684
+ Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000013b0)
1685
+ ];
1686
+
1687
+ // To compute the next target sum, we evaluate the given univariate at a point u (challenge).
1688
+
1689
+ // Performing Barycentric evaluations
1690
+ // Compute B(x)
1691
+ Fr numeratorValue = Fr.wrap(1);
1692
+ for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
1693
+ numeratorValue = numeratorValue * (roundChallenge - Fr.wrap(i));
1694
+ }
1695
+
1696
+ // Calculate domain size N of inverses
1697
+ Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory denominatorInverses;
1698
+ for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
1699
+ Fr inv = BARYCENTRIC_LAGRANGE_DENOMINATORS[i];
1700
+ inv = inv * (roundChallenge - Fr.wrap(i));
1701
+ inv = FrLib.invert(inv);
1702
+ denominatorInverses[i] = inv;
1703
+ }
1704
+
1705
+ for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
1706
+ Fr term = roundUnivariates[i];
1707
+ term = term * denominatorInverses[i];
1708
+ targetSum = targetSum + term;
1709
+ }
1710
+
1711
+ // Scale the sum by the value of B(x)
1712
+ targetSum = targetSum * numeratorValue;
1713
+ }
1714
+
1715
+ // Univariate evaluation of the monomial ((1-X_l) + X_l.B_l) at the challenge point X_l=u_l
1716
+ function partiallyEvaluatePOW(Fr gateChallenge, Fr currentEvaluation, Fr roundChallenge)
1717
+ internal
1718
+ pure
1719
+ returns (Fr newEvaluation)
1720
+ {
1721
+ Fr univariateEval = Fr.wrap(1) + (roundChallenge * (gateChallenge - Fr.wrap(1)));
1722
+ newEvaluation = currentEvaluation * univariateEval;
1723
+ }
1724
+
1725
+ function verifyShplemini(Honk.Proof memory proof, Honk.VerificationKey memory vk, Transcript memory tp)
1726
+ internal
1727
+ view
1728
+ returns (bool verified)
1729
+ {
1730
+ ShpleminiIntermediates memory mem; // stack
1731
+
1732
+ // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size
1733
+ Fr[CONST_PROOF_SIZE_LOG_N] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR);
1734
+
1735
+ // Arrays hold values that will be linearly combined for the gemini and shplonk batch openings
1736
+ Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars;
1737
+ Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory commitments;
1738
+
1739
+ mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert();
1740
+ mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert();
1741
+
1742
+ mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator);
1743
+ mem.shiftedScalar =
1744
+ tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator));
1745
+
1746
+ scalars[0] = Fr.wrap(1);
1747
+ commitments[0] = convertProofPoint(proof.shplonkQ);
1748
+
1749
+ mem.batchingChallenge = Fr.wrap(1);
1750
+ mem.batchedEvaluation = Fr.wrap(0);
1751
+
1752
+ for (uint256 i = 1; i <= NUMBER_UNSHIFTED; ++i) {
1753
+ scalars[i] = mem.unshiftedScalar.neg() * mem.batchingChallenge;
1754
+ mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i - 1] * mem.batchingChallenge);
1755
+ mem.batchingChallenge = mem.batchingChallenge * tp.rho;
1756
+ }
1757
+ // g commitments are accumulated at r
1758
+ for (uint256 i = NUMBER_UNSHIFTED + 1; i <= NUMBER_OF_ENTITIES; ++i) {
1759
+ scalars[i] = mem.shiftedScalar.neg() * mem.batchingChallenge;
1760
+ mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i - 1] * mem.batchingChallenge);
1761
+ mem.batchingChallenge = mem.batchingChallenge * tp.rho;
1762
+ }
1763
+
1764
+ commitments[1] = vk.qm;
1765
+ commitments[2] = vk.qc;
1766
+ commitments[3] = vk.ql;
1767
+ commitments[4] = vk.qr;
1768
+ commitments[5] = vk.qo;
1769
+ commitments[6] = vk.q4;
1770
+ commitments[7] = vk.qLookup;
1771
+ commitments[8] = vk.qArith;
1772
+ commitments[9] = vk.qDeltaRange;
1773
+ commitments[10] = vk.qElliptic;
1774
+ commitments[11] = vk.qAux;
1775
+ commitments[12] = vk.qPoseidon2External;
1776
+ commitments[13] = vk.qPoseidon2Internal;
1777
+ commitments[14] = vk.s1;
1778
+ commitments[15] = vk.s2;
1779
+ commitments[16] = vk.s3;
1780
+ commitments[17] = vk.s4;
1781
+ commitments[18] = vk.id1;
1782
+ commitments[19] = vk.id2;
1783
+ commitments[20] = vk.id3;
1784
+ commitments[21] = vk.id4;
1785
+ commitments[22] = vk.t1;
1786
+ commitments[23] = vk.t2;
1787
+ commitments[24] = vk.t3;
1788
+ commitments[25] = vk.t4;
1789
+ commitments[26] = vk.lagrangeFirst;
1790
+ commitments[27] = vk.lagrangeLast;
1791
+
1792
+ // Accumulate proof points
1793
+ commitments[28] = convertProofPoint(proof.w1);
1794
+ commitments[29] = convertProofPoint(proof.w2);
1795
+ commitments[30] = convertProofPoint(proof.w3);
1796
+ commitments[31] = convertProofPoint(proof.w4);
1797
+ commitments[32] = convertProofPoint(proof.zPerm);
1798
+ commitments[33] = convertProofPoint(proof.lookupInverses);
1799
+ commitments[34] = convertProofPoint(proof.lookupReadCounts);
1800
+ commitments[35] = convertProofPoint(proof.lookupReadTags);
1801
+
1802
+ // to be Shifted
1803
+ commitments[36] = convertProofPoint(proof.w1);
1804
+ commitments[37] = convertProofPoint(proof.w2);
1805
+ commitments[38] = convertProofPoint(proof.w3);
1806
+ commitments[39] = convertProofPoint(proof.w4);
1807
+ commitments[40] = convertProofPoint(proof.zPerm);
1808
+
1809
+ // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator:
1810
+ // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., logN - 1
1811
+ Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations(
1812
+ tp.sumCheckUChallenges,
1813
+ mem.batchedEvaluation,
1814
+ proof.geminiAEvaluations,
1815
+ powers_of_evaluation_challenge,
1816
+ logN
1817
+ );
1818
+
1819
+ // Compute the Shplonk constant term contributions from A₀(±r)
1820
+ mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator;
1821
+ mem.constantTermAccumulator =
1822
+ mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator);
1823
+ mem.batchingChallenge = tp.shplonkNu.sqr();
1824
+
1825
+ // Compute Shplonk constant term contributions from Aₗ(±r^{2ˡ}) for l = 1, ..., m-1;
1826
+ // Compute scalar multipliers for each fold commitment
1827
+ for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) {
1828
+ bool dummy_round = i >= (logN - 1);
1829
+
1830
+ if (!dummy_round) {
1831
+ // Update inverted denominators
1832
+ mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert();
1833
+ mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert();
1834
+
1835
+ // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ]
1836
+ mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator;
1837
+ mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator;
1838
+ // [Aₗ] is multiplied by -v^{2l}/(z-r^{2^l}) - v^{2l+1} /(z+ r^{2^l})
1839
+ scalars[NUMBER_OF_ENTITIES + 1 + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg();
1840
+
1841
+ // Accumulate the const term contribution given by
1842
+ // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l})
1843
+ Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1];
1844
+ accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1];
1845
+ mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution;
1846
+ // Update the running power of v
1847
+ mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu;
1848
+ }
1849
+
1850
+ commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]);
1851
+ }
1852
+
1853
+ // Finalise the batch opening claim
1854
+ commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = Honk.G1Point({x: 1, y: 2});
1855
+ scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = mem.constantTermAccumulator;
1856
+
1857
+ Honk.G1Point memory quotient_commitment = convertProofPoint(proof.kzgQuotient);
1858
+
1859
+ commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 1] = quotient_commitment;
1860
+ scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 1] = tp.shplonkZ; // evaluation challenge
1861
+
1862
+ Honk.G1Point memory P_0 = batchMul(commitments, scalars);
1863
+ Honk.G1Point memory P_1 = negateInplace(quotient_commitment);
1864
+
1865
+ return pairing(P_0, P_1);
1866
+ }
1867
+
1868
+ // This implementation is the same as above with different constants
1869
+ function batchMul(
1870
+ Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory base,
1871
+ Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars
1872
+ ) internal view returns (Honk.G1Point memory result) {
1873
+ uint256 limit = NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2;
1874
+ assembly {
1875
+ let success := 0x01
1876
+ let free := mload(0x40)
1877
+
1878
+ // Write the original into the accumulator
1879
+ // Load into memory for ecMUL, leave offset for eccAdd result
1880
+ // base is an array of pointers, so we have to dereference them
1881
+ mstore(add(free, 0x40), mload(mload(base)))
1882
+ mstore(add(free, 0x60), mload(add(0x20, mload(base))))
1883
+ // Add scalar
1884
+ mstore(add(free, 0x80), mload(scalars))
1885
+ success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, free, 0x40))
1886
+
1887
+ let count := 0x01
1888
+ for {} lt(count, limit) { count := add(count, 1) } {
1889
+ // Get loop offsets
1890
+ let base_base := add(base, mul(count, 0x20))
1891
+ let scalar_base := add(scalars, mul(count, 0x20))
1892
+
1893
+ mstore(add(free, 0x40), mload(mload(base_base)))
1894
+ mstore(add(free, 0x60), mload(add(0x20, mload(base_base))))
1895
+ // Add scalar
1896
+ mstore(add(free, 0x80), mload(scalar_base))
1897
+
1898
+ success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, add(free, 0x40), 0x40))
1899
+ // accumulator = accumulator + accumulator_2
1900
+ success := and(success, staticcall(gas(), 6, free, 0x80, free, 0x40))
1901
+ }
1902
+
1903
+ // Return the result - i hate this
1904
+ mstore(result, mload(free))
1905
+ mstore(add(result, 0x20), mload(add(free, 0x20)))
1906
+ }
1907
+ }
1908
+ }
1909
+
1910
+ contract HonkVerifier is BaseHonkVerifier(N, LOG_N, NUMBER_OF_PUBLIC_INPUTS) {
1911
+ function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) {
1912
+ return HonkVerificationKey.loadVerificationKey();
1913
+ }
1914
+ }