@crisp-e3/contracts 0.2.3-test → 0.3.0-test

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.
@@ -5,122 +5,127 @@
5
5
  // or FITNESS FOR A PARTICULAR PURPOSE.
6
6
  pragma solidity >=0.8.21;
7
7
 
8
- uint256 constant N = 524288;
9
- uint256 constant LOG_N = 19;
10
- uint256 constant NUMBER_OF_PUBLIC_INPUTS = 0;
8
+ uint256 constant N = 262144;
9
+ uint256 constant LOG_N = 18;
10
+ uint256 constant NUMBER_OF_PUBLIC_INPUTS = 2066;
11
+ uint256 constant VK_HASH = 0x05bd14a0e3103d0d0db90e0f838257986fc1bbc62b88f2f71c653ee51bd72303;
11
12
  library HonkVerificationKey {
12
13
  function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) {
13
14
  Honk.VerificationKey memory vk = Honk.VerificationKey({
14
- circuitSize: uint256(524288),
15
- logCircuitSize: uint256(19),
16
- publicInputsSize: uint256(0),
15
+ circuitSize: uint256(262144),
16
+ logCircuitSize: uint256(18),
17
+ publicInputsSize: uint256(2066),
17
18
  ql: Honk.G1Point({
18
- x: uint256(0x2c3d4ff818b2bd107b25afcec82f8b489d4f474ae163602869b5a8a6c75be6e5),
19
- y: uint256(0x28aa3d140258eea62b3be3a080a7d393b807e00545db188385eb242f441bc85c)
19
+ x: uint256(0x19234e8b486fc9d552cc3ff76f2c34bfbf6e26b2e9eb02fb15f8fe85990cb187),
20
+ y: uint256(0x1c444396f3a0984b7f94fcee1df7f5e4e44cfe53399e648f0bcebe02000a087e)
20
21
  }),
21
22
  qr: Honk.G1Point({
22
- x: uint256(0x08285c76834e6840d1db5a6cfcfa2b94a9ec2e80f8df2cd2d1b18ffc7fe40028),
23
- y: uint256(0x03398be294abb06d5be9215c3a07f41754cdffe71b68c9452f18bde7dbfebbf6)
23
+ x: uint256(0x12ff83ae9eb2624de078e8611c08730ab34efcf794202d911d57e7dd8630fa38),
24
+ y: uint256(0x029719af50ddaa8504413a7393b1416a46f70bcdfe3d9d954da57ebbd3c30b38)
24
25
  }),
25
26
  qo: Honk.G1Point({
26
- x: uint256(0x21c476dfe2f9a4d67870bd34757144ee6fb45cb24b7e0690282da0fd639a3353),
27
- y: uint256(0x1e73766089a804e8a07b8eb1bc05de03735ff1b7f612703016d8d3b4b0cfe7cc)
27
+ x: uint256(0x23b949c0019499d2f7456111da69b3b058df2a7ae07482c378b4decf61b6dcd9),
28
+ y: uint256(0x13782bc42aeb4b804e0965f606f11edcb28229238ddbb171eb96b300c881e227)
28
29
  }),
29
30
  q4: Honk.G1Point({
30
- x: uint256(0x2c86d05c5ba85d0253e26efa5546f4c3fb8ac4ee70f81439ebb7379195e1bca7),
31
- y: uint256(0x019000463d3006c44b2f219477873d0c28ebdc2d89641c78004a0a0954b08319)
31
+ x: uint256(0x2bef4c83fcfe7adf69fbce3ef3379a4c66a7368b3b79920234d588b485c48fe8),
32
+ y: uint256(0x1490ebd0bee5ec6101b0c16dfbf19b22be7ed060dfcd1aec96e9cd767ae36bdc)
32
33
  }),
33
34
  qm: Honk.G1Point({
34
- x: uint256(0x2bdcef4b06d52299573cef34e1c4d76e9c3f2e0fddcb7724f574038b59454723),
35
- y: uint256(0x1b83babf5f2a43a8f49ec5a6559062d1746cde944e2f7b127997d072cb34b773)
35
+ x: uint256(0x0c82cc6a2a2cef657c3bd1bedd66c4b4f38289783e19989fc7649a4109474509),
36
+ y: uint256(0x0587d5ba891a52b1285ae0a203288c53f85abee00d0a16de2fcadd3d512146a4)
36
37
  }),
37
38
  qc: Honk.G1Point({
38
- x: uint256(0x26cad107a18c777ebc50038a599554620c674f90edb5d711ba8a278d6cdd90c1),
39
- y: uint256(0x20f83ee863e42a6500fdd389c885847eefa658a22e1a7ae344efe97128cbfdfb)
39
+ x: uint256(0x24e2900ed26ac3239ddba212a5caac56156eaebe1faa80f88f405f60368794b5),
40
+ y: uint256(0x160a37be35842022504a64c436738ff1657939b63e8ee62fe74fb22aa9302045)
41
+ }),
42
+ qLookup: Honk.G1Point({
43
+ x: uint256(0x205057a47479c3744023a35ca3d08d79c3499d9af48e264ecb31823713bbbca8),
44
+ y: uint256(0x19b2541dcaae69df644bec1bb8ce13455719c73fcadac3763d81a6b1c70560f3)
40
45
  }),
41
46
  qArith: Honk.G1Point({
42
- x: uint256(0x0b43af826bf6b48e6f09cec083808d1287512599954832f1190916c40b1671fa),
43
- y: uint256(0x22f871141d9876b55696ca69a669a55d65c7d37ae850a96ac6e3d2d22ff6514a)
47
+ x: uint256(0x2d41b85dcf0f1defc732bc240d3d709df3475b27fdd10349446282c88c7b93c6),
48
+ y: uint256(0x2de3a73eef194dc3eac369c70160d7fea3941a89ee90d40474f4c0cc5fdbea48)
44
49
  }),
45
50
  qDeltaRange: Honk.G1Point({
46
- x: uint256(0x0d70a4b74f6fe3e56fb046749637c33eda3deb8872ce35f3df9a9096ece42291),
47
- y: uint256(0x0475f69ca23e9a23e8a869233b5feabce8362642f1f4e9aeb1522d259b77e04f)
51
+ x: uint256(0x0b8cdcf81182771897cdd149f27f9c48e645e17e27898dd978458066a71f65ba),
52
+ y: uint256(0x0a2039dc6d85835f05ea90414529d4965581f28ecc322af2846eb08cc97f3b55)
48
53
  }),
49
54
  qElliptic: Honk.G1Point({
50
- x: uint256(0x2bc2c2351835a2dd570566bcc75c3b9a6a1ba3523f0e4e2b0ba2c4f88550150d),
51
- y: uint256(0x0f08565b5963e41a2c40930a416b4e780b181131c05df87d030e2797eb486708)
55
+ x: uint256(0x2e68245b183738e5639624c9d9214055ab2245566faa714c8618fcfc294dde76),
56
+ y: uint256(0x1c0de69c49bf59a98400d7b9ea8677d66a562ace631377b3f2ed21672a8b4174)
52
57
  }),
53
- qAux: Honk.G1Point({
54
- x: uint256(0x1db45523d96ad9e6b6599c69b623e4a0977c518bf40c9b65d440880a11d60300),
55
- y: uint256(0x03e2a52f673e0ab7c9a6f8d9d4478e31fdd5b8e6c17d46e246faee867bf51eb4)
58
+ qMemory: Honk.G1Point({
59
+ x: uint256(0x25a52f5a8f82e49523f6ac03d7bffbae8d7bf778d2da64388e08db5685642188),
60
+ y: uint256(0x1ab62a935611f307a8d45f4a61e18efaa432cb441f2d37da9a2d3439f5773e70)
56
61
  }),
57
- qLookup: Honk.G1Point({
58
- x: uint256(0x2f937da7da3cdb00e22a7bdbfb630ac9d512f349a1d8e9c11fab9be0fa66457e),
59
- y: uint256(0x0a5e66af6292b45fb74c5d93d5cf9b6ef649e35d6dcc1ffc781d2038a301f9d7)
62
+ qNnf: Honk.G1Point({
63
+ x: uint256(0x2b47e338c9cc9f6c8dfd806f4ddc14bb8a915c6ca26797edd1ce653354efe0ca),
64
+ y: uint256(0x0b0ab523e1297dba7d2b3082e52e970643c65cde7435c743a299e22bb425dc85)
60
65
  }),
61
66
  qPoseidon2External: Honk.G1Point({
62
- x: uint256(0x2b0a956add08b0a436c494b0df6f0f8c46c3384cac4b12382ced4c68df586db0),
63
- y: uint256(0x163d269cc1d7cd8d56eab21eb4a4f488623d66fbe11576ba746924e512bae194)
67
+ x: uint256(0x15b800e958d51996ac94950c9edaca0e78119205cdd47fbf3c649e52ac65f14a),
68
+ y: uint256(0x1156eb0be91bc47c7bc23018abd75c52dd036bfdd9fcd52a67132c541ca6e1ca)
64
69
  }),
65
70
  qPoseidon2Internal: Honk.G1Point({
66
- x: uint256(0x1da6676cc9b080ecd66a5f0d7b45b6cbda1f81f2c351b25c9e251e0b5c64e5ab),
67
- y: uint256(0x183a1995a089488ea19245d06bd0db968f862e67e92e0f94d375bbf8c1f7499d)
71
+ x: uint256(0x186115ffb59ed7ca6d2dc7db68b92788824c6eb44f6741be0791e44812c3c16c),
72
+ y: uint256(0x0b595b8659174ce4759801569ef9ee7acead4fa8de75c4bdf4c5d0db00b98258)
68
73
  }),
69
74
  s1: Honk.G1Point({
70
- x: uint256(0x262b5b85bfc63ed2c654dace13dd4174f12d7c742f0718e9d5a1e98994c32083),
71
- y: uint256(0x21fe8ee6c561fcab51f58a368471a5ce2317a7b75476886c1b536e76aeee6b2a)
75
+ x: uint256(0x14dd269b9e3c3567adda508de65295995c9a7d0f983ce31fb680f43cade82460),
76
+ y: uint256(0x1f9ddc09be536a402af0ad294cce79bae970a35e68fd1dce90c8dc6a59592fbc)
72
77
  }),
73
78
  s2: Honk.G1Point({
74
- x: uint256(0x00af332d7114f45137a5543d5afbbde445b1423800e4fc74d21e3a6fb609fd94),
75
- y: uint256(0x1954104be52a1ead2ec9197481607a7d3ca77ea30aea48f69d3278ee8fde3bb5)
79
+ x: uint256(0x20e437b79e848e9eab0cd5e29b001e6975428ef03b1d1eaf3dfd7364c212ef00),
80
+ y: uint256(0x272039cad2b791d53addc1016b377443fca208ab510a04e3379fd32724242980)
76
81
  }),
77
82
  s3: Honk.G1Point({
78
- x: uint256(0x0b6ef97fac2880a778ef04ac752a7c29bade69fede791130cf137350d7b55bf2),
79
- y: uint256(0x29352e633fdd5f90c535ff3fa1a328c4fb10e829260c89a7400ad4c68c4320c0)
83
+ x: uint256(0x00cfcc45e38f6dfe9147cee1aed3554bbc43def92142e6b2973e8da8ca43e494),
84
+ y: uint256(0x04830aca514c7478869b6679d074f80e14096c645bc57faa7061224e22abead2)
80
85
  }),
81
86
  s4: Honk.G1Point({
82
- x: uint256(0x2b6d511d05a187438ba738e2a267129c7eab60a40d2b7626162a7e62aa49decf),
83
- y: uint256(0x2e85f7538945d8929e37bd7bd58b410143dd10f3988f55ba3cdd8ca5a9ead0ca)
87
+ x: uint256(0x1f16f65c5b2f8202aa15fad48ffb33fb112e5c6e59d7677710f21785a073abe9),
88
+ y: uint256(0x0496adc461ec7de90ea1196b3a727549d7767ec2a58857f7f91fd65d94eccea0)
84
89
  }),
85
90
  t1: Honk.G1Point({
86
- x: uint256(0x2026dc48b1355cab6cc65f62e57c2a8b939208914da13061dece58a7d107d72f),
87
- y: uint256(0x24befe3cce085c85100629c8aff5b47e2b283b96796aabd7c6a8b8199a40be2e)
91
+ x: uint256(0x08a5ba822823e5f21f5585f7d90f070aaad388561d817362c819850cccf82580),
92
+ y: uint256(0x2d296fb3ec6c283d6f822a7e7f9edbe350516a4f9cba53be9dc8ac6240d0559c)
88
93
  }),
89
94
  t2: Honk.G1Point({
90
- x: uint256(0x2baaa5f1b8119ca614edaf29dbdee4507d6560b7c1a909bc7e3f1f84b49258ea),
91
- y: uint256(0x12be10f98e563e199b1c3c94a34874986934673a787367455e03ccf4a3ef0cdd)
95
+ x: uint256(0x201b4ffc4068dd22cc3a99a1ef5bc10e2be7841ed934ad5ea5247f992687c29b),
96
+ y: uint256(0x28351d4eacb149a545035052b1b2081b7e8c3ffa751c5bc31483b653f95cb6ca)
92
97
  }),
93
98
  t3: Honk.G1Point({
94
- x: uint256(0x160f6a41dabe93896d38ef5a3fa159df028044d93f4ce90f5473c533a792a824),
95
- y: uint256(0x1038a846deed12d6e5215a4f408c3d9c66baf984ec4c1905c67d4f3c2d80aa24)
99
+ x: uint256(0x0d1a271b6b84d9a2d8953885c3b2d13d10aa96a483eeb4c7a41d65c19d69d638),
100
+ y: uint256(0x2a40aaa4bc03f75cbc60cc97a07b3e8885d4c99101b026f18219c82ee71443c4)
96
101
  }),
97
102
  t4: Honk.G1Point({
98
- x: uint256(0x2c2de7017bed19f1dbac860651ec57db3c7f7d206fd6b68243459b1e109c6b59),
99
- y: uint256(0x01622ed4ea3dcb382f63b793d3ee003d7c33d1aea42683fc5424070f5ad069b9)
103
+ x: uint256(0x18216d5e69c40817c81feefd02de1aa548f7bf9d9ce4d671e96b22f368709ed5),
104
+ y: uint256(0x1e5e5f5acbdcd05a0ebffacea7a5426da9ec26a79cbb95692c9e9a499ff0155a)
100
105
  }),
101
106
  id1: Honk.G1Point({
102
- x: uint256(0x08b931d23212132a225290da0401c47bc60beaf11bbaee3ff1a676b2a8a8cbd2),
103
- y: uint256(0x2b704805f8988ac4fe51638fa6eb80371668913b5253aeee9dd102477995a8a1)
107
+ x: uint256(0x247ab7f8180ee4378a3735de2d878287808586b925f8bd965ecce15ef6ff300a),
108
+ y: uint256(0x0dd9fe53e476eb4a851b28f0f73cbd72c5871c0201dad4cbfd1cf78deedff2aa)
104
109
  }),
105
110
  id2: Honk.G1Point({
106
- x: uint256(0x12e0275781e96737e5eb0adb50d093fa7885172e69e9cc51baaf4b05ad1a8830),
107
- y: uint256(0x03b5d3da82c564191e17426e1e34b59fef2c9de9d6ed16f043333267e544abe3)
111
+ x: uint256(0x0150fd5a4606ac3ee8dd19c29e1902f8e9770afb38c3c18fce68cb5fea0c2626),
112
+ y: uint256(0x04709d671d3ae053977fe93b3eaeae8d2ff5c11c6e0cea3870cffe08167097a6)
108
113
  }),
109
114
  id3: Honk.G1Point({
110
- x: uint256(0x25d731f633791fcedf1b64d76d4a0860352689ab141450737f2349083bcabe8f),
111
- y: uint256(0x2ffda063edd9ac30be6ae4454ad0bcf77e2be627e73cf22e3aa45eb7715f4c08)
115
+ x: uint256(0x009cfbd08c0f2f320b312de7921f17bef30ab4ceeec5eca94c0098abf17b800a),
116
+ y: uint256(0x067b007230035477d184136e9e82536f036afd3cf87243b4a5a99bd7ad703d9f)
112
117
  }),
113
118
  id4: Honk.G1Point({
114
- x: uint256(0x05607184d3e42dfe8ef18ab55f653af79d0030a5fbc6b4be2421cdcf684b32a2),
115
- y: uint256(0x05be236673cb6b322f9b720f2806643762463a1c39aa83570ae7c17421b1ccdc)
119
+ x: uint256(0x079a5be6c98f93960daf8acb02136162a39c71d4b8e60d82aaf16dc68ade9999),
120
+ y: uint256(0x2f48fd8991a0d731c9529a0c6cb5daf714e2aff9c3222a8e960ff89d9f934a94)
116
121
  }),
117
122
  lagrangeFirst: Honk.G1Point({
118
123
  x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001),
119
124
  y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002)
120
125
  }),
121
126
  lagrangeLast: Honk.G1Point({
122
- x: uint256(0x29e6fb99b7ab5bbaae22112941f9e1dfb35d1b9fb78a0ec9e380859a84f48332),
123
- y: uint256(0x07eeab05aa34fc5038de782d1ff4619a8cdf44dc3f4071e3feffc6f947821699)
127
+ x: uint256(0x2e0e9d25627d4fcd339bece11e5b1a39cec75ceed35718d2c24ed14655390c1e),
128
+ y: uint256(0x0c36d39925655a8f2ce6433139283c38d124e49945ac60294bebde700799cb7c)
124
129
  })
125
130
  });
126
131
  return vk;
@@ -129,156 +134,177 @@ library HonkVerificationKey {
129
134
 
130
135
  pragma solidity ^0.8.27;
131
136
 
137
+ interface IVerifier {
138
+ function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external returns (bool);
139
+ }
140
+
132
141
  type Fr is uint256;
133
142
 
134
- using { add as + } for Fr global;
135
- using { sub as - } for Fr global;
136
- using { mul as * } for Fr global;
137
- using { exp as ^ } for Fr global;
138
- using { notEqual as != } for Fr global;
139
- using { equal as == } for Fr global;
143
+ using {add as +} for Fr global;
144
+ using {sub as -} for Fr global;
145
+ using {mul as *} for Fr global;
140
146
 
141
- uint256 constant MODULUS =
142
- 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order
147
+ using {exp as ^} for Fr global;
148
+ using {notEqual as !=} for Fr global;
149
+ using {equal as ==} for Fr global;
143
150
 
151
+ uint256 constant SUBGROUP_SIZE = 256;
152
+ uint256 constant MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order
153
+ uint256 constant P = MODULUS;
154
+ Fr constant SUBGROUP_GENERATOR = Fr.wrap(0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76);
155
+ Fr constant SUBGROUP_GENERATOR_INVERSE = Fr.wrap(0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6);
144
156
  Fr constant MINUS_ONE = Fr.wrap(MODULUS - 1);
145
-
157
+ Fr constant ONE = Fr.wrap(1);
158
+ Fr constant ZERO = Fr.wrap(0);
146
159
  // Instantiation
147
- library FrLib
148
- {
149
- function from(uint256 value) internal pure returns(Fr)
150
- {
151
- return Fr.wrap(value % MODULUS);
160
+
161
+ library FrLib {
162
+ function from(uint256 value) internal pure returns (Fr) {
163
+ unchecked {
164
+ return Fr.wrap(value % MODULUS);
165
+ }
152
166
  }
153
167
 
154
- function fromBytes32(bytes32 value) internal pure returns(Fr)
155
- {
156
- return Fr.wrap(uint256(value) % MODULUS);
168
+ function fromBytes32(bytes32 value) internal pure returns (Fr) {
169
+ unchecked {
170
+ return Fr.wrap(uint256(value) % MODULUS);
171
+ }
157
172
  }
158
173
 
159
- function toBytes32(Fr value) internal pure returns(bytes32)
160
- {
161
- return bytes32(Fr.unwrap(value));
174
+ function toBytes32(Fr value) internal pure returns (bytes32) {
175
+ unchecked {
176
+ return bytes32(Fr.unwrap(value));
177
+ }
162
178
  }
163
179
 
164
- function invert(Fr value) internal view returns(Fr)
165
- {
180
+ function invert(Fr value) internal view returns (Fr) {
166
181
  uint256 v = Fr.unwrap(value);
167
182
  uint256 result;
168
183
 
169
184
  // Call the modexp precompile to invert in the field
170
- assembly
171
- {
185
+ assembly {
172
186
  let free := mload(0x40)
173
187
  mstore(free, 0x20)
174
188
  mstore(add(free, 0x20), 0x20)
175
189
  mstore(add(free, 0x40), 0x20)
176
190
  mstore(add(free, 0x60), v)
177
- mstore(add(free, 0x80), sub(MODULUS, 2))
191
+ mstore(add(free, 0x80), sub(MODULUS, 2))
178
192
  mstore(add(free, 0xa0), MODULUS)
179
193
  let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20)
180
194
  if iszero(success) {
181
195
  revert(0, 0)
182
196
  }
183
197
  result := mload(0x00)
198
+ mstore(0x40, add(free, 0x80))
184
199
  }
185
200
 
186
201
  return Fr.wrap(result);
187
202
  }
188
203
 
189
- function pow(Fr base, uint256 v) internal view returns(Fr)
190
- {
204
+ function pow(Fr base, uint256 v) internal view returns (Fr) {
191
205
  uint256 b = Fr.unwrap(base);
192
206
  uint256 result;
193
207
 
194
208
  // Call the modexp precompile to invert in the field
195
- assembly
196
- {
209
+ assembly {
197
210
  let free := mload(0x40)
198
211
  mstore(free, 0x20)
199
212
  mstore(add(free, 0x20), 0x20)
200
213
  mstore(add(free, 0x40), 0x20)
201
214
  mstore(add(free, 0x60), b)
202
- mstore(add(free, 0x80), v)
215
+ mstore(add(free, 0x80), v)
203
216
  mstore(add(free, 0xa0), MODULUS)
204
217
  let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20)
205
218
  if iszero(success) {
206
219
  revert(0, 0)
207
220
  }
208
221
  result := mload(0x00)
222
+ mstore(0x40, add(free, 0x80))
209
223
  }
210
224
 
211
225
  return Fr.wrap(result);
212
226
  }
213
227
 
214
- function div(Fr numerator, Fr denominator) internal view returns(Fr)
215
- {
216
- return numerator * invert(denominator);
228
+ function div(Fr numerator, Fr denominator) internal view returns (Fr) {
229
+ unchecked {
230
+ return numerator * invert(denominator);
231
+ }
217
232
  }
218
233
 
219
234
  function sqr(Fr value) internal pure returns (Fr) {
220
- return value * value;
235
+ unchecked {
236
+ return value * value;
237
+ }
221
238
  }
222
239
 
223
240
  function unwrap(Fr value) internal pure returns (uint256) {
224
- return Fr.unwrap(value);
241
+ unchecked {
242
+ return Fr.unwrap(value);
243
+ }
225
244
  }
226
245
 
227
246
  function neg(Fr value) internal pure returns (Fr) {
228
- return Fr.wrap(MODULUS - Fr.unwrap(value));
247
+ unchecked {
248
+ return Fr.wrap(MODULUS - Fr.unwrap(value));
249
+ }
229
250
  }
230
251
  }
231
252
 
232
253
  // Free functions
233
- function add(Fr a, Fr b) pure returns(Fr)
234
- {
235
- return Fr.wrap(addmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS));
254
+ function add(Fr a, Fr b) pure returns (Fr) {
255
+ unchecked {
256
+ return Fr.wrap(addmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS));
257
+ }
236
258
  }
237
259
 
238
- function mul(Fr a, Fr b) pure returns(Fr)
239
- {
240
- return Fr.wrap(mulmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS));
260
+ function mul(Fr a, Fr b) pure returns (Fr) {
261
+ unchecked {
262
+ return Fr.wrap(mulmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS));
263
+ }
241
264
  }
242
265
 
243
- function sub(Fr a, Fr b) pure returns(Fr)
244
- {
245
- return Fr.wrap(addmod(Fr.unwrap(a), MODULUS - Fr.unwrap(b), MODULUS));
266
+ function sub(Fr a, Fr b) pure returns (Fr) {
267
+ unchecked {
268
+ return Fr.wrap(addmod(Fr.unwrap(a), MODULUS - Fr.unwrap(b), MODULUS));
269
+ }
246
270
  }
247
271
 
248
- function exp(Fr base, Fr exponent) pure returns(Fr)
249
- {
272
+ function exp(Fr base, Fr exponent) pure returns (Fr) {
250
273
  if (Fr.unwrap(exponent) == 0) return Fr.wrap(1);
251
-
274
+ // Implement exponent with a loop as we will overflow otherwise
252
275
  for (uint256 i = 1; i < Fr.unwrap(exponent); i += i) {
253
276
  base = base * base;
254
277
  }
255
278
  return base;
256
279
  }
257
280
 
258
- function notEqual(Fr a, Fr b) pure returns(bool)
259
- {
260
- return Fr.unwrap(a) != Fr.unwrap(b);
281
+ function notEqual(Fr a, Fr b) pure returns (bool) {
282
+ unchecked {
283
+ return Fr.unwrap(a) != Fr.unwrap(b);
284
+ }
261
285
  }
262
286
 
263
- function equal(Fr a, Fr b) pure returns(bool)
264
- {
265
- return Fr.unwrap(a) == Fr.unwrap(b);
287
+ function equal(Fr a, Fr b) pure returns (bool) {
288
+ unchecked {
289
+ return Fr.unwrap(a) == Fr.unwrap(b);
290
+ }
266
291
  }
267
292
 
268
293
  uint256 constant CONST_PROOF_SIZE_LOG_N = 28;
269
294
 
270
- uint256 constant NUMBER_OF_SUBRELATIONS = 26;
295
+ uint256 constant NUMBER_OF_SUBRELATIONS = 28;
271
296
  uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8;
272
- uint256 constant NUMBER_OF_ENTITIES = 40;
273
- uint256 constant NUMBER_UNSHIFTED = 35;
297
+ uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9;
298
+ uint256 constant NUMBER_OF_ENTITIES = 41;
299
+ uint256 constant NUMBER_UNSHIFTED = 36;
274
300
  uint256 constant NUMBER_TO_BE_SHIFTED = 5;
301
+ uint256 constant PAIRING_POINTS_SIZE = 16;
275
302
 
276
- // Alphas are used as relation separators so there should be NUMBER_OF_SUBRELATIONS - 1
277
- uint256 constant NUMBER_OF_ALPHAS = 25;
303
+ uint256 constant FIELD_ELEMENT_SIZE = 0x20;
304
+ uint256 constant GROUP_ELEMENT_SIZE = 0x40;
278
305
 
279
- // Prime field order
280
- uint256 constant Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // EC group order. F_q
281
- uint256 constant P = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order, F_r
306
+ // Alphas are used as relation separators so there should be NUMBER_OF_SUBRELATIONS - 1
307
+ uint256 constant NUMBER_OF_ALPHAS = NUMBER_OF_SUBRELATIONS - 1;
282
308
 
283
309
  // ENUM FOR WIRES
284
310
  enum WIRE {
@@ -292,7 +318,8 @@ enum WIRE {
292
318
  Q_ARITH,
293
319
  Q_RANGE,
294
320
  Q_ELLIPTIC,
295
- Q_AUX,
321
+ Q_MEMORY,
322
+ Q_NNF,
296
323
  Q_POSEIDON2_EXTERNAL,
297
324
  Q_POSEIDON2_INTERNAL,
298
325
  SIGMA_1,
@@ -330,13 +357,6 @@ library Honk {
330
357
  uint256 y;
331
358
  }
332
359
 
333
- struct G1ProofPoint {
334
- uint256 x_0;
335
- uint256 x_1;
336
- uint256 y_0;
337
- uint256 y_1;
338
- }
339
-
340
360
  struct VerificationKey {
341
361
  // Misc Params
342
362
  uint256 circuitSize;
@@ -352,7 +372,8 @@ library Honk {
352
372
  G1Point qLookup; // Lookup
353
373
  G1Point qArith; // Arithmetic widget
354
374
  G1Point qDeltaRange; // Delta Range sort
355
- G1Point qAux; // Auxillary
375
+ G1Point qMemory; // Memory
376
+ G1Point qNnf; // Non-native Field
356
377
  G1Point qElliptic; // Auxillary
357
378
  G1Point qPoseidon2External;
358
379
  G1Point qPoseidon2Internal;
@@ -387,70 +408,105 @@ library Honk {
387
408
  Fr publicInputsDelta;
388
409
  }
389
410
 
390
-
391
411
  struct Proof {
412
+ // Pairing point object
413
+ Fr[PAIRING_POINTS_SIZE] pairingPointObject;
392
414
  // Free wires
393
- Honk.G1ProofPoint w1;
394
- Honk.G1ProofPoint w2;
395
- Honk.G1ProofPoint w3;
396
- Honk.G1ProofPoint w4;
415
+ G1Point w1;
416
+ G1Point w2;
417
+ G1Point w3;
418
+ G1Point w4;
397
419
  // Lookup helpers - Permutations
398
- Honk.G1ProofPoint zPerm;
420
+ G1Point zPerm;
399
421
  // Lookup helpers - logup
400
- Honk.G1ProofPoint lookupReadCounts;
401
- Honk.G1ProofPoint lookupReadTags;
402
- Honk.G1ProofPoint lookupInverses;
422
+ G1Point lookupReadCounts;
423
+ G1Point lookupReadTags;
424
+ G1Point lookupInverses;
403
425
  // Sumcheck
404
426
  Fr[BATCHED_RELATION_PARTIAL_LENGTH][CONST_PROOF_SIZE_LOG_N] sumcheckUnivariates;
405
427
  Fr[NUMBER_OF_ENTITIES] sumcheckEvaluations;
406
428
  // Shplemini
407
- Honk.G1ProofPoint[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms;
429
+ G1Point[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms;
430
+ Fr[CONST_PROOF_SIZE_LOG_N] geminiAEvaluations;
431
+ G1Point shplonkQ;
432
+ G1Point kzgQuotient;
433
+ }
434
+
435
+ struct ZKProof {
436
+ // Pairing point object
437
+ Fr[PAIRING_POINTS_SIZE] pairingPointObject;
438
+ // Commitments to wire polynomials
439
+ G1Point w1;
440
+ G1Point w2;
441
+ G1Point w3;
442
+ G1Point w4;
443
+ // Commitments to logup witness polynomials
444
+ G1Point lookupReadCounts;
445
+ G1Point lookupReadTags;
446
+ G1Point lookupInverses;
447
+ // Commitment to grand permutation polynomial
448
+ G1Point zPerm;
449
+ G1Point[3] libraCommitments;
450
+ // Sumcheck
451
+ Fr libraSum;
452
+ Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH][CONST_PROOF_SIZE_LOG_N] sumcheckUnivariates;
453
+ Fr[NUMBER_OF_ENTITIES] sumcheckEvaluations;
454
+ Fr libraEvaluation;
455
+ // ZK
456
+ G1Point geminiMaskingPoly;
457
+ Fr geminiMaskingEval;
458
+ // Shplemini
459
+ G1Point[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms;
408
460
  Fr[CONST_PROOF_SIZE_LOG_N] geminiAEvaluations;
409
- Honk.G1ProofPoint shplonkQ;
410
- Honk.G1ProofPoint kzgQuotient;
461
+ Fr[4] libraPolyEvals;
462
+ G1Point shplonkQ;
463
+ G1Point kzgQuotient;
411
464
  }
412
465
  }
413
466
 
414
- // Transcript library to generate fiat shamir challenges
415
- struct Transcript {
467
+ // ZKTranscript library to generate fiat shamir challenges, the ZK transcript only differest
468
+ struct ZKTranscript {
416
469
  // Oink
417
470
  Honk.RelationParameters relationParameters;
418
471
  Fr[NUMBER_OF_ALPHAS] alphas;
419
472
  Fr[CONST_PROOF_SIZE_LOG_N] gateChallenges;
420
473
  // Sumcheck
474
+ Fr libraChallenge;
421
475
  Fr[CONST_PROOF_SIZE_LOG_N] sumCheckUChallenges;
422
- // Gemini
476
+ // Shplemini
423
477
  Fr rho;
424
478
  Fr geminiR;
425
- // Shplonk
426
479
  Fr shplonkNu;
427
480
  Fr shplonkZ;
481
+ // Derived
482
+ Fr publicInputsDelta;
428
483
  }
429
484
 
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
- {
485
+ library ZKTranscriptLib {
486
+ function generateTranscript(
487
+ Honk.ZKProof memory proof,
488
+ bytes32[] calldata publicInputs,
489
+ uint256 vkHash,
490
+ uint256 publicInputsSize,
491
+ uint256 logN
492
+ ) external pure returns (ZKTranscript memory t) {
436
493
  Fr previousChallenge;
437
494
  (t.relationParameters, previousChallenge) =
438
- generateRelationParametersChallenges(proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset, previousChallenge);
495
+ generateRelationParametersChallenges(proof, publicInputs, vkHash, publicInputsSize, previousChallenge);
439
496
 
440
497
  (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof);
441
498
 
442
- (t.gateChallenges, previousChallenge) = generateGateChallenges(previousChallenge);
443
-
444
- (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges(proof, previousChallenge);
499
+ (t.gateChallenges, previousChallenge) = generateGateChallenges(previousChallenge, logN);
500
+ (t.libraChallenge, previousChallenge) = generateLibraChallenge(previousChallenge, proof);
501
+ (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges(proof, previousChallenge, logN);
445
502
 
446
503
  (t.rho, previousChallenge) = generateRhoChallenge(proof, previousChallenge);
447
504
 
448
- (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge);
505
+ (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge, logN);
449
506
 
450
- (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge);
507
+ (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge, logN);
451
508
 
452
509
  (t.shplonkZ, previousChallenge) = generateShplonkZChallenge(proof, previousChallenge);
453
-
454
510
  return t;
455
511
  }
456
512
 
@@ -463,321 +519,317 @@ library TranscriptLib {
463
519
  }
464
520
 
465
521
  function generateRelationParametersChallenges(
466
- Honk.Proof memory proof,
522
+ Honk.ZKProof memory proof,
467
523
  bytes32[] calldata publicInputs,
468
- uint256 circuitSize,
524
+ uint256 vkHash,
469
525
  uint256 publicInputsSize,
470
- uint256 pubInputsOffset,
471
526
  Fr previousChallenge
472
527
  ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) {
473
528
  (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) =
474
- generateEtaChallenge(proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset);
529
+ generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize);
475
530
 
476
531
  (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof);
477
-
478
532
  }
479
533
 
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
- for (uint256 i = 0; i < publicInputsSize; i++) {
490
- round0[3 + i] = bytes32(publicInputs[i]);
534
+ function generateEtaChallenge(
535
+ Honk.ZKProof memory proof,
536
+ bytes32[] calldata publicInputs,
537
+ uint256 vkHash,
538
+ uint256 publicInputsSize
539
+ ) internal pure returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) {
540
+ bytes32[] memory round0 = new bytes32[](1 + publicInputsSize + 6);
541
+ round0[0] = bytes32(vkHash);
542
+
543
+ for (uint256 i = 0; i < publicInputsSize - PAIRING_POINTS_SIZE; i++) {
544
+ round0[1 + i] = bytes32(publicInputs[i]);
545
+ }
546
+ for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) {
547
+ round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]);
491
548
  }
492
549
 
493
550
  // Create the first challenge
494
551
  // Note: w4 is added to the challenge later on
495
- round0[3 + publicInputsSize] = bytes32(proof.w1.x_0);
496
- round0[3 + publicInputsSize + 1] = bytes32(proof.w1.x_1);
497
- round0[3 + publicInputsSize + 2] = bytes32(proof.w1.y_0);
498
- round0[3 + publicInputsSize + 3] = bytes32(proof.w1.y_1);
499
- round0[3 + publicInputsSize + 4] = bytes32(proof.w2.x_0);
500
- round0[3 + publicInputsSize + 5] = bytes32(proof.w2.x_1);
501
- round0[3 + publicInputsSize + 6] = bytes32(proof.w2.y_0);
502
- round0[3 + publicInputsSize + 7] = bytes32(proof.w2.y_1);
503
- round0[3 + publicInputsSize + 8] = bytes32(proof.w3.x_0);
504
- round0[3 + publicInputsSize + 9] = bytes32(proof.w3.x_1);
505
- round0[3 + publicInputsSize + 10] = bytes32(proof.w3.y_0);
506
- round0[3 + publicInputsSize + 11] = bytes32(proof.w3.y_1);
552
+ round0[1 + publicInputsSize] = bytes32(proof.w1.x);
553
+ round0[1 + publicInputsSize + 1] = bytes32(proof.w1.y);
554
+ round0[1 + publicInputsSize + 2] = bytes32(proof.w2.x);
555
+ round0[1 + publicInputsSize + 3] = bytes32(proof.w2.y);
556
+ round0[1 + publicInputsSize + 4] = bytes32(proof.w3.x);
557
+ round0[1 + publicInputsSize + 5] = bytes32(proof.w3.y);
507
558
 
508
559
  previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0)));
509
560
  (eta, etaTwo) = splitChallenge(previousChallenge);
510
561
  previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))));
511
- Fr unused;
512
- (etaThree, unused) = splitChallenge(previousChallenge);
562
+
563
+ (etaThree,) = splitChallenge(previousChallenge);
513
564
  }
514
565
 
515
- function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.Proof memory proof)
566
+ function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.ZKProof memory proof)
516
567
  internal
517
568
  pure
518
569
  returns (Fr beta, Fr gamma, Fr nextPreviousChallenge)
519
570
  {
520
- bytes32[13] memory round1;
571
+ bytes32[7] memory round1;
521
572
  round1[0] = FrLib.toBytes32(previousChallenge);
522
- round1[1] = bytes32(proof.lookupReadCounts.x_0);
523
- round1[2] = bytes32(proof.lookupReadCounts.x_1);
524
- round1[3] = bytes32(proof.lookupReadCounts.y_0);
525
- round1[4] = bytes32(proof.lookupReadCounts.y_1);
526
- round1[5] = bytes32(proof.lookupReadTags.x_0);
527
- round1[6] = bytes32(proof.lookupReadTags.x_1);
528
- round1[7] = bytes32(proof.lookupReadTags.y_0);
529
- round1[8] = bytes32(proof.lookupReadTags.y_1);
530
- round1[9] = bytes32(proof.w4.x_0);
531
- round1[10] = bytes32(proof.w4.x_1);
532
- round1[11] = bytes32(proof.w4.y_0);
533
- round1[12] = bytes32(proof.w4.y_1);
573
+ round1[1] = bytes32(proof.lookupReadCounts.x);
574
+ round1[2] = bytes32(proof.lookupReadCounts.y);
575
+ round1[3] = bytes32(proof.lookupReadTags.x);
576
+ round1[4] = bytes32(proof.lookupReadTags.y);
577
+ round1[5] = bytes32(proof.w4.x);
578
+ round1[6] = bytes32(proof.w4.y);
534
579
 
535
580
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round1)));
536
581
  (beta, gamma) = splitChallenge(nextPreviousChallenge);
537
582
  }
538
583
 
539
584
  // Alpha challenges non-linearise the gate contributions
540
- function generateAlphaChallenges(Fr previousChallenge, Honk.Proof memory proof)
585
+ function generateAlphaChallenges(Fr previousChallenge, Honk.ZKProof memory proof)
541
586
  internal
542
587
  pure
543
588
  returns (Fr[NUMBER_OF_ALPHAS] memory alphas, Fr nextPreviousChallenge)
544
589
  {
545
590
  // Generate the original sumcheck alpha 0 by hashing zPerm and zLookup
546
- uint256[9] memory alpha0;
591
+ uint256[5] memory alpha0;
547
592
  alpha0[0] = Fr.unwrap(previousChallenge);
548
- alpha0[1] = proof.lookupInverses.x_0;
549
- alpha0[2] = proof.lookupInverses.x_1;
550
- alpha0[3] = proof.lookupInverses.y_0;
551
- alpha0[4] = proof.lookupInverses.y_1;
552
- alpha0[5] = proof.zPerm.x_0;
553
- alpha0[6] = proof.zPerm.x_1;
554
- alpha0[7] = proof.zPerm.y_0;
555
- alpha0[8] = proof.zPerm.y_1;
593
+ alpha0[1] = proof.lookupInverses.x;
594
+ alpha0[2] = proof.lookupInverses.y;
595
+ alpha0[3] = proof.zPerm.x;
596
+ alpha0[4] = proof.zPerm.y;
556
597
 
557
598
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(alpha0)));
558
- (alphas[0], alphas[1]) = splitChallenge(nextPreviousChallenge);
599
+ Fr alpha;
600
+ (alpha,) = splitChallenge(nextPreviousChallenge);
559
601
 
560
- for (uint256 i = 1; i < NUMBER_OF_ALPHAS / 2; i++) {
561
- nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(nextPreviousChallenge))));
562
- (alphas[2 * i], alphas[2 * i + 1]) = splitChallenge(nextPreviousChallenge);
563
- }
564
- if (((NUMBER_OF_ALPHAS & 1) == 1) && (NUMBER_OF_ALPHAS > 2)) {
565
- nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(nextPreviousChallenge))));
566
- Fr unused;
567
- (alphas[NUMBER_OF_ALPHAS - 1], unused) = splitChallenge(nextPreviousChallenge);
602
+ // Compute powers of alpha for batching subrelations
603
+ alphas[0] = alpha;
604
+ for (uint256 i = 1; i < NUMBER_OF_ALPHAS; i++) {
605
+ alphas[i] = alphas[i - 1] * alpha;
568
606
  }
569
607
  }
570
608
 
571
- function generateGateChallenges(Fr previousChallenge)
609
+ function generateGateChallenges(Fr previousChallenge, uint256 logN)
572
610
  internal
573
611
  pure
574
612
  returns (Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, Fr nextPreviousChallenge)
575
613
  {
576
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
577
- previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))));
578
- Fr unused;
579
- (gateChallenges[i], unused) = splitChallenge(previousChallenge);
614
+ previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))));
615
+ (gateChallenges[0],) = splitChallenge(previousChallenge);
616
+ for (uint256 i = 1; i < logN; i++) {
617
+ gateChallenges[i] = gateChallenges[i - 1] * gateChallenges[i - 1];
580
618
  }
581
619
  nextPreviousChallenge = previousChallenge;
582
620
  }
583
621
 
584
- function generateSumcheckChallenges(Honk.Proof memory proof, Fr prevChallenge)
622
+ function generateLibraChallenge(Fr previousChallenge, Honk.ZKProof memory proof)
623
+ internal
624
+ pure
625
+ returns (Fr libraChallenge, Fr nextPreviousChallenge)
626
+ {
627
+ // 2 comm, 1 sum, 1 challenge
628
+ uint256[4] memory challengeData;
629
+ challengeData[0] = Fr.unwrap(previousChallenge);
630
+ challengeData[1] = proof.libraCommitments[0].x;
631
+ challengeData[2] = proof.libraCommitments[0].y;
632
+ challengeData[3] = Fr.unwrap(proof.libraSum);
633
+ nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(challengeData)));
634
+ (libraChallenge,) = splitChallenge(nextPreviousChallenge);
635
+ }
636
+
637
+ function generateSumcheckChallenges(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN)
585
638
  internal
586
639
  pure
587
640
  returns (Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, Fr nextPreviousChallenge)
588
641
  {
589
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
590
- Fr[BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal;
642
+ for (uint256 i = 0; i < logN; i++) {
643
+ Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal;
591
644
  univariateChal[0] = prevChallenge;
592
645
 
593
- for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) {
646
+ for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) {
594
647
  univariateChal[j + 1] = proof.sumcheckUnivariates[i][j];
595
648
  }
596
649
  prevChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(univariateChal)));
597
- Fr unused;
598
- (sumcheckChallenges[i], unused) = splitChallenge(prevChallenge);
650
+
651
+ (sumcheckChallenges[i],) = splitChallenge(prevChallenge);
599
652
  }
600
653
  nextPreviousChallenge = prevChallenge;
601
654
  }
602
655
 
603
- function generateRhoChallenge(Honk.Proof memory proof, Fr prevChallenge)
656
+ // We add Libra claimed eval + 3 comm + 1 more eval
657
+ function generateRhoChallenge(Honk.ZKProof memory proof, Fr prevChallenge)
604
658
  internal
605
659
  pure
606
660
  returns (Fr rho, Fr nextPreviousChallenge)
607
661
  {
608
- Fr[NUMBER_OF_ENTITIES + 1] memory rhoChallengeElements;
609
- rhoChallengeElements[0] = prevChallenge;
610
-
611
- for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) {
612
- rhoChallengeElements[i + 1] = proof.sumcheckEvaluations[i];
662
+ uint256[NUMBER_OF_ENTITIES + 9] memory rhoChallengeElements;
663
+ rhoChallengeElements[0] = Fr.unwrap(prevChallenge);
664
+ uint256 i;
665
+ for (i = 1; i <= NUMBER_OF_ENTITIES; i++) {
666
+ rhoChallengeElements[i] = Fr.unwrap(proof.sumcheckEvaluations[i - 1]);
613
667
  }
668
+ rhoChallengeElements[i] = Fr.unwrap(proof.libraEvaluation);
669
+
670
+ i += 1;
671
+ rhoChallengeElements[i] = proof.libraCommitments[1].x;
672
+ rhoChallengeElements[i + 1] = proof.libraCommitments[1].y;
673
+ i += 2;
674
+ rhoChallengeElements[i] = proof.libraCommitments[2].x;
675
+ rhoChallengeElements[i + 1] = proof.libraCommitments[2].y;
676
+ i += 2;
677
+ rhoChallengeElements[i] = proof.geminiMaskingPoly.x;
678
+ rhoChallengeElements[i + 1] = proof.geminiMaskingPoly.y;
679
+
680
+ i += 2;
681
+ rhoChallengeElements[i] = Fr.unwrap(proof.geminiMaskingEval);
614
682
 
615
683
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(rhoChallengeElements)));
616
- Fr unused;
617
- (rho, unused) = splitChallenge(nextPreviousChallenge);
684
+ (rho,) = splitChallenge(nextPreviousChallenge);
618
685
  }
619
686
 
620
- function generateGeminiRChallenge(Honk.Proof memory proof, Fr prevChallenge)
687
+ function generateGeminiRChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN)
621
688
  internal
622
689
  pure
623
690
  returns (Fr geminiR, Fr nextPreviousChallenge)
624
691
  {
625
- uint256[(CONST_PROOF_SIZE_LOG_N - 1) * 4 + 1] memory gR;
692
+ uint256[] memory gR = new uint256[]((logN - 1) * 2 + 1);
626
693
  gR[0] = Fr.unwrap(prevChallenge);
627
694
 
628
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) {
629
- gR[1 + i * 4] = proof.geminiFoldComms[i].x_0;
630
- gR[2 + i * 4] = proof.geminiFoldComms[i].x_1;
631
- gR[3 + i * 4] = proof.geminiFoldComms[i].y_0;
632
- gR[4 + i * 4] = proof.geminiFoldComms[i].y_1;
695
+ for (uint256 i = 0; i < logN - 1; i++) {
696
+ gR[1 + i * 2] = proof.geminiFoldComms[i].x;
697
+ gR[2 + i * 2] = proof.geminiFoldComms[i].y;
633
698
  }
634
699
 
635
700
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(gR)));
636
- Fr unused;
637
- (geminiR, unused) = splitChallenge(nextPreviousChallenge);
701
+
702
+ (geminiR,) = splitChallenge(nextPreviousChallenge);
638
703
  }
639
704
 
640
- function generateShplonkNuChallenge(Honk.Proof memory proof, Fr prevChallenge)
705
+ function generateShplonkNuChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN)
641
706
  internal
642
707
  pure
643
708
  returns (Fr shplonkNu, Fr nextPreviousChallenge)
644
709
  {
645
- uint256[(CONST_PROOF_SIZE_LOG_N) + 1] memory shplonkNuChallengeElements;
710
+ uint256[] memory shplonkNuChallengeElements = new uint256[](logN + 1 + 4);
646
711
  shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge);
647
712
 
648
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
649
- shplonkNuChallengeElements[i + 1] = Fr.unwrap(proof.geminiAEvaluations[i]);
713
+ for (uint256 i = 1; i <= logN; i++) {
714
+ shplonkNuChallengeElements[i] = Fr.unwrap(proof.geminiAEvaluations[i - 1]);
715
+ }
716
+
717
+ uint256 libraIdx = 0;
718
+ for (uint256 i = logN + 1; i <= logN + 4; i++) {
719
+ shplonkNuChallengeElements[i] = Fr.unwrap(proof.libraPolyEvals[libraIdx]);
720
+ libraIdx++;
650
721
  }
651
722
 
652
723
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkNuChallengeElements)));
653
- Fr unused;
654
- (shplonkNu, unused) = splitChallenge(nextPreviousChallenge);
724
+ (shplonkNu,) = splitChallenge(nextPreviousChallenge);
655
725
  }
656
726
 
657
- function generateShplonkZChallenge(Honk.Proof memory proof, Fr prevChallenge)
727
+ function generateShplonkZChallenge(Honk.ZKProof memory proof, Fr prevChallenge)
658
728
  internal
659
729
  pure
660
730
  returns (Fr shplonkZ, Fr nextPreviousChallenge)
661
731
  {
662
- uint256[5] memory shplonkZChallengeElements;
732
+ uint256[3] memory shplonkZChallengeElements;
663
733
  shplonkZChallengeElements[0] = Fr.unwrap(prevChallenge);
664
734
 
665
- shplonkZChallengeElements[1] = proof.shplonkQ.x_0;
666
- shplonkZChallengeElements[2] = proof.shplonkQ.x_1;
667
- shplonkZChallengeElements[3] = proof.shplonkQ.y_0;
668
- shplonkZChallengeElements[4] = proof.shplonkQ.y_1;
735
+ shplonkZChallengeElements[1] = proof.shplonkQ.x;
736
+ shplonkZChallengeElements[2] = proof.shplonkQ.y;
669
737
 
670
738
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkZChallengeElements)));
671
- Fr unused;
672
- (shplonkZ, unused) = splitChallenge(nextPreviousChallenge);
739
+ (shplonkZ,) = splitChallenge(nextPreviousChallenge);
673
740
  }
674
741
 
675
- function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory p) {
676
- // Commitments
677
- p.w1 = bytesToG1ProofPoint(proof[0x0:0x80]);
742
+ function loadProof(bytes calldata proof, uint256 logN) internal pure returns (Honk.ZKProof memory p) {
743
+ uint256 boundary = 0x0;
678
744
 
679
- p.w2 = bytesToG1ProofPoint(proof[0x80:0x100]);
680
- p.w3 = bytesToG1ProofPoint(proof[0x100:0x180]);
745
+ // Pairing point object
746
+ for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) {
747
+ p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
748
+ boundary += FIELD_ELEMENT_SIZE;
749
+ }
750
+ // Commitments
751
+ p.w1 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
752
+ boundary += GROUP_ELEMENT_SIZE;
753
+ p.w2 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
754
+ boundary += GROUP_ELEMENT_SIZE;
755
+ p.w3 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
756
+ boundary += GROUP_ELEMENT_SIZE;
681
757
 
682
758
  // Lookup / Permutation Helper Commitments
683
- p.lookupReadCounts = bytesToG1ProofPoint(proof[0x180:0x200]);
684
- p.lookupReadTags = bytesToG1ProofPoint(proof[0x200:0x280]);
685
- p.w4 = bytesToG1ProofPoint(proof[0x280:0x300]);
686
- p.lookupInverses = bytesToG1ProofPoint(proof[0x300:0x380]);
687
- p.zPerm = bytesToG1ProofPoint(proof[0x380:0x400]);
688
- uint256 boundary = 0x400;
689
-
759
+ p.lookupReadCounts = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
760
+ boundary += GROUP_ELEMENT_SIZE;
761
+ p.lookupReadTags = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
762
+ boundary += GROUP_ELEMENT_SIZE;
763
+ p.w4 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
764
+ boundary += GROUP_ELEMENT_SIZE;
765
+ p.lookupInverses = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
766
+ boundary += GROUP_ELEMENT_SIZE;
767
+ p.zPerm = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
768
+ boundary += GROUP_ELEMENT_SIZE;
769
+ p.libraCommitments[0] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
770
+ boundary += GROUP_ELEMENT_SIZE;
771
+
772
+ p.libraSum = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
773
+ boundary += FIELD_ELEMENT_SIZE;
690
774
  // Sumcheck univariates
691
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
692
- for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) {
693
- p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + 0x20]);
694
- boundary += 0x20;
775
+ for (uint256 i = 0; i < logN; i++) {
776
+ for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) {
777
+ p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
778
+ boundary += FIELD_ELEMENT_SIZE;
695
779
  }
696
780
  }
781
+
697
782
  // Sumcheck evaluations
698
783
  for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) {
699
- p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]);
700
- boundary += 0x20;
784
+ p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
785
+ boundary += FIELD_ELEMENT_SIZE;
701
786
  }
702
787
 
788
+ p.libraEvaluation = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
789
+ boundary += FIELD_ELEMENT_SIZE;
790
+
791
+ p.libraCommitments[1] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
792
+ boundary += GROUP_ELEMENT_SIZE;
793
+ p.libraCommitments[2] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
794
+ boundary += GROUP_ELEMENT_SIZE;
795
+ p.geminiMaskingPoly = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
796
+ boundary += GROUP_ELEMENT_SIZE;
797
+ p.geminiMaskingEval = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
798
+ boundary += FIELD_ELEMENT_SIZE;
799
+
703
800
  // Gemini
704
801
  // Read gemini fold univariates
705
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) {
706
- p.geminiFoldComms[i] = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
707
- boundary += 0x80;
802
+ for (uint256 i = 0; i < logN - 1; i++) {
803
+ p.geminiFoldComms[i] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
804
+ boundary += GROUP_ELEMENT_SIZE;
708
805
  }
709
806
 
710
807
  // Read gemini a evaluations
711
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
712
- p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]);
713
- boundary += 0x20;
808
+ for (uint256 i = 0; i < logN; i++) {
809
+ p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
810
+ boundary += FIELD_ELEMENT_SIZE;
811
+ }
812
+
813
+ for (uint256 i = 0; i < 4; i++) {
814
+ p.libraPolyEvals[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
815
+ boundary += FIELD_ELEMENT_SIZE;
714
816
  }
715
817
 
716
818
  // Shplonk
717
- p.shplonkQ = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
718
- boundary = boundary + 0x80;
819
+ p.shplonkQ = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
820
+ boundary += GROUP_ELEMENT_SIZE;
719
821
  // KZG
720
- p.kzgQuotient = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
822
+ p.kzgQuotient = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
721
823
  }
722
824
  }
723
825
 
724
-
725
- // Fr utility
726
-
727
- function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) {
728
- require(proofSection.length == 0x20, "invalid bytes scalar");
729
- scalar = FrLib.fromBytes32(bytes32(proofSection));
730
- }
731
-
732
- // EC Point utilities
733
- function convertProofPoint(Honk.G1ProofPoint memory input) pure returns (Honk.G1Point memory) {
734
- return Honk.G1Point({x: input.x_0 | (input.x_1 << 136), y: input.y_0 | (input.y_1 << 136)});
735
- }
736
-
737
- function bytesToG1ProofPoint(bytes calldata proofSection) pure returns (Honk.G1ProofPoint memory point) {
738
- require(proofSection.length == 0x80, "invalid bytes point");
739
- point = Honk.G1ProofPoint({
740
- x_0: uint256(bytes32(proofSection[0x00:0x20])),
741
- x_1: uint256(bytes32(proofSection[0x20:0x40])),
742
- y_0: uint256(bytes32(proofSection[0x40:0x60])),
743
- y_1: uint256(bytes32(proofSection[0x60:0x80]))
744
- });
745
- }
746
-
747
- function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) {
748
- point.y = (Q - point.y) % Q;
749
- return point;
750
- }
751
-
752
- function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool) {
753
- bytes memory input = abi.encodePacked(
754
- rhs.x,
755
- rhs.y,
756
- // Fixed G1 point
757
- uint256(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2),
758
- uint256(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed),
759
- uint256(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b),
760
- uint256(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa),
761
- lhs.x,
762
- lhs.y,
763
- // G1 point from VK
764
- uint256(0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1),
765
- uint256(0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0),
766
- uint256(0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4),
767
- uint256(0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55)
768
- );
769
-
770
- (bool success, bytes memory result) = address(0x08).staticcall(input);
771
- bool decodedResult = abi.decode(result, (bool));
772
- return success && decodedResult;
773
- }
774
-
826
+ // Field arithmetic libraries
775
827
 
776
828
  library RelationsLib {
777
829
  Fr internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = Fr.wrap(17); // -(-17)
778
830
 
779
831
  function accumulateRelationEvaluations(
780
- Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations,
832
+ Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations,
781
833
  Honk.RelationParameters memory rp,
782
834
  Fr[NUMBER_OF_ALPHAS] memory alphas,
783
835
  Fr powPartialEval
@@ -790,9 +842,11 @@ library RelationsLib {
790
842
  accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval);
791
843
  accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval);
792
844
  accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval);
793
- accumulateAuxillaryRelation(purportedEvaluations, rp, evaluations, powPartialEval);
845
+ accumulateMemoryRelation(purportedEvaluations, rp, evaluations, powPartialEval);
846
+ accumulateNnfRelation(purportedEvaluations, evaluations, powPartialEval);
794
847
  accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval);
795
848
  accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval);
849
+
796
850
  // batch the subrelations with the alpha challenges to obtain the full honk relation
797
851
  accumulator = scaleAndBatchSubrelations(evaluations, alphas);
798
852
  }
@@ -811,6 +865,7 @@ library RelationsLib {
811
865
  * Ultra Arithmetic Relation
812
866
  *
813
867
  */
868
+
814
869
  function accumulateArithmeticRelation(
815
870
  Fr[NUMBER_OF_ENTITIES] memory p,
816
871
  Fr[NUMBER_OF_SUBRELATIONS] memory evals,
@@ -824,7 +879,7 @@ library RelationsLib {
824
879
  Fr accum = (q_arith - Fr.wrap(3)) * (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * neg_half;
825
880
  accum = accum + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R))
826
881
  + (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);
827
- accum = accum + (q_arith - Fr.wrap(1)) * wire(p, WIRE.W_4_SHIFT);
882
+ accum = accum + (q_arith - ONE) * wire(p, WIRE.W_4_SHIFT);
828
883
  accum = accum * q_arith;
829
884
  accum = accum * domainSep;
830
885
  evals[0] = accum;
@@ -834,7 +889,7 @@ library RelationsLib {
834
889
  {
835
890
  Fr accum = wire(p, WIRE.W_L) + wire(p, WIRE.W_4) - wire(p, WIRE.W_L_SHIFT) + wire(p, WIRE.Q_M);
836
891
  accum = accum * (q_arith - Fr.wrap(2));
837
- accum = accum * (q_arith - Fr.wrap(1));
892
+ accum = accum * (q_arith - ONE);
838
893
  accum = accum * q_arith;
839
894
  accum = accum * domainSep;
840
895
  evals[1] = accum;
@@ -925,8 +980,13 @@ library RelationsLib {
925
980
  // Inverse
926
981
  Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * read_inverse - wire(p, WIRE.LOOKUP_READ_COUNTS) * write_inverse;
927
982
 
983
+ Fr read_tag = wire(p, WIRE.LOOKUP_READ_TAGS);
984
+
985
+ Fr read_tag_boolean_relation = read_tag * read_tag - read_tag;
986
+
928
987
  evals[4] = accumulatorNone;
929
988
  evals[5] = accumulatorOne;
989
+ evals[6] = read_tag_boolean_relation * domainSep;
930
990
  }
931
991
 
932
992
  function accumulateDeltaRangeRelation(
@@ -934,9 +994,9 @@ library RelationsLib {
934
994
  Fr[NUMBER_OF_SUBRELATIONS] memory evals,
935
995
  Fr domainSep
936
996
  ) internal pure {
937
- Fr minus_one = Fr.wrap(0) - Fr.wrap(1);
938
- Fr minus_two = Fr.wrap(0) - Fr.wrap(2);
939
- Fr minus_three = Fr.wrap(0) - Fr.wrap(3);
997
+ Fr minus_one = ZERO - ONE;
998
+ Fr minus_two = ZERO - Fr.wrap(2);
999
+ Fr minus_three = ZERO - Fr.wrap(3);
940
1000
 
941
1001
  // Compute wire differences
942
1002
  Fr delta_1 = wire(p, WIRE.W_R) - wire(p, WIRE.W_L);
@@ -952,7 +1012,7 @@ library RelationsLib {
952
1012
  acc = acc * (delta_1 + minus_three);
953
1013
  acc = acc * wire(p, WIRE.Q_RANGE);
954
1014
  acc = acc * domainSep;
955
- evals[6] = acc;
1015
+ evals[7] = acc;
956
1016
  }
957
1017
 
958
1018
  // Contribution 7
@@ -963,7 +1023,7 @@ library RelationsLib {
963
1023
  acc = acc * (delta_2 + minus_three);
964
1024
  acc = acc * wire(p, WIRE.Q_RANGE);
965
1025
  acc = acc * domainSep;
966
- evals[7] = acc;
1026
+ evals[8] = acc;
967
1027
  }
968
1028
 
969
1029
  // Contribution 8
@@ -974,7 +1034,7 @@ library RelationsLib {
974
1034
  acc = acc * (delta_3 + minus_three);
975
1035
  acc = acc * wire(p, WIRE.Q_RANGE);
976
1036
  acc = acc * domainSep;
977
- evals[8] = acc;
1037
+ evals[9] = acc;
978
1038
  }
979
1039
 
980
1040
  // Contribution 9
@@ -985,7 +1045,7 @@ library RelationsLib {
985
1045
  acc = acc * (delta_4 + minus_three);
986
1046
  acc = acc * wire(p, WIRE.Q_RANGE);
987
1047
  acc = acc * domainSep;
988
- evals[9] = acc;
1048
+ evals[10] = acc;
989
1049
  }
990
1050
  }
991
1051
 
@@ -1032,7 +1092,7 @@ library RelationsLib {
1032
1092
  x_add_identity = x_add_identity * x_diff * x_diff;
1033
1093
  x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2;
1034
1094
 
1035
- evals[10] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (Fr.wrap(1) - q_is_double);
1095
+ evals[11] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double);
1036
1096
  }
1037
1097
 
1038
1098
  // Contribution 11 point addition, x-coordinate check
@@ -1041,7 +1101,7 @@ library RelationsLib {
1041
1101
  Fr y1_plus_y3 = ep.y_1 + ep.y_3;
1042
1102
  Fr y_diff = ep.y_2 * q_sign - ep.y_1;
1043
1103
  Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff;
1044
- evals[11] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (Fr.wrap(1) - q_is_double);
1104
+ evals[12] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double);
1045
1105
  }
1046
1106
 
1047
1107
  // Contribution 10 point doubling, x-coordinate check
@@ -1057,7 +1117,7 @@ library RelationsLib {
1057
1117
  ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9;
1058
1118
 
1059
1119
  Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double;
1060
- evals[10] = evals[10] + acc;
1120
+ evals[11] = evals[11] + acc;
1061
1121
  }
1062
1122
 
1063
1123
  // Contribution 11 point doubling, y-coordinate check
@@ -1065,23 +1125,13 @@ library RelationsLib {
1065
1125
  {
1066
1126
  Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1;
1067
1127
  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);
1068
- evals[11] = evals[11] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double;
1128
+ evals[12] = evals[12] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double;
1069
1129
  }
1070
1130
  }
1071
1131
 
1072
- // Constants for the auxiliary relation
1073
- Fr constant LIMB_SIZE = Fr.wrap(uint256(1) << 68);
1074
- Fr constant SUBLIMB_SHIFT = Fr.wrap(uint256(1) << 14);
1075
-
1076
- // Parameters used within the Auxiliary Relation
1132
+ // Parameters used within the Memory Relation
1077
1133
  // A struct is used to work around stack too deep. This relation has alot of variables
1078
- struct AuxParams {
1079
- Fr limb_subproduct;
1080
- Fr non_native_field_gate_1;
1081
- Fr non_native_field_gate_2;
1082
- Fr non_native_field_gate_3;
1083
- Fr limb_accumulator_1;
1084
- Fr limb_accumulator_2;
1134
+ struct MemParams {
1085
1135
  Fr memory_record_check;
1086
1136
  Fr partial_record_check;
1087
1137
  Fr next_gate_access_type;
@@ -1097,80 +1147,15 @@ library RelationsLib {
1097
1147
  Fr RAM_timestamp_check_identity;
1098
1148
  Fr memory_identity;
1099
1149
  Fr index_is_monotonically_increasing;
1100
- Fr auxiliary_identity;
1101
1150
  }
1102
1151
 
1103
- function accumulateAuxillaryRelation(
1152
+ function accumulateMemoryRelation(
1104
1153
  Fr[NUMBER_OF_ENTITIES] memory p,
1105
1154
  Honk.RelationParameters memory rp,
1106
1155
  Fr[NUMBER_OF_SUBRELATIONS] memory evals,
1107
1156
  Fr domainSep
1108
1157
  ) internal pure {
1109
- AuxParams memory ap;
1110
-
1111
- /**
1112
- * Contribution 12
1113
- * Non native field arithmetic gate 2
1114
- * deg 4
1115
- *
1116
- * _ _
1117
- * / _ _ _ 14 \
1118
- * 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 |
1119
- * \_ _/
1120
- *
1121
- *
1122
- */
1123
- 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);
1124
- ap.non_native_field_gate_2 =
1125
- (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));
1126
- ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * LIMB_SIZE;
1127
- ap.non_native_field_gate_2 = ap.non_native_field_gate_2 - wire(p, WIRE.W_4_SHIFT);
1128
- ap.non_native_field_gate_2 = ap.non_native_field_gate_2 + ap.limb_subproduct;
1129
- ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * wire(p, WIRE.Q_4);
1130
-
1131
- ap.limb_subproduct = ap.limb_subproduct * LIMB_SIZE;
1132
- ap.limb_subproduct = ap.limb_subproduct + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT));
1133
- ap.non_native_field_gate_1 = ap.limb_subproduct;
1134
- ap.non_native_field_gate_1 = ap.non_native_field_gate_1 - (wire(p, WIRE.W_O) + wire(p, WIRE.W_4));
1135
- ap.non_native_field_gate_1 = ap.non_native_field_gate_1 * wire(p, WIRE.Q_O);
1136
-
1137
- ap.non_native_field_gate_3 = ap.limb_subproduct;
1138
- ap.non_native_field_gate_3 = ap.non_native_field_gate_3 + wire(p, WIRE.W_4);
1139
- ap.non_native_field_gate_3 = ap.non_native_field_gate_3 - (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT));
1140
- ap.non_native_field_gate_3 = ap.non_native_field_gate_3 * wire(p, WIRE.Q_M);
1141
-
1142
- Fr non_native_field_identity =
1143
- ap.non_native_field_gate_1 + ap.non_native_field_gate_2 + ap.non_native_field_gate_3;
1144
- non_native_field_identity = non_native_field_identity * wire(p, WIRE.Q_R);
1145
-
1146
- // ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm
1147
- // deg 2
1148
- ap.limb_accumulator_1 = wire(p, WIRE.W_R_SHIFT) * SUBLIMB_SHIFT;
1149
- ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L_SHIFT);
1150
- ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1151
- ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_O);
1152
- ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1153
- ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_R);
1154
- ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1155
- ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L);
1156
- ap.limb_accumulator_1 = ap.limb_accumulator_1 - wire(p, WIRE.W_4);
1157
- ap.limb_accumulator_1 = ap.limb_accumulator_1 * wire(p, WIRE.Q_4);
1158
-
1159
- // ((((w3' * 2^14 + w2') * 2^14 + w1') * 2^14 + w4) * 2^14 + w3 - w4') * qm
1160
- // deg 2
1161
- ap.limb_accumulator_2 = wire(p, WIRE.W_O_SHIFT) * SUBLIMB_SHIFT;
1162
- ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_R_SHIFT);
1163
- ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1164
- ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_L_SHIFT);
1165
- ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1166
- ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_4);
1167
- ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1168
- ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_O);
1169
- ap.limb_accumulator_2 = ap.limb_accumulator_2 - wire(p, WIRE.W_4_SHIFT);
1170
- ap.limb_accumulator_2 = ap.limb_accumulator_2 * wire(p, WIRE.Q_M);
1171
-
1172
- Fr limb_accumulator_identity = ap.limb_accumulator_1 + ap.limb_accumulator_2;
1173
- limb_accumulator_identity = limb_accumulator_identity * wire(p, WIRE.Q_O); // deg 3
1158
+ MemParams memory ap;
1174
1159
 
1175
1160
  /**
1176
1161
  * MEMORY
@@ -1239,14 +1224,14 @@ library RelationsLib {
1239
1224
  ap.index_delta = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_L);
1240
1225
  ap.record_delta = wire(p, WIRE.W_4_SHIFT) - wire(p, WIRE.W_4);
1241
1226
 
1242
- ap.index_is_monotonically_increasing = ap.index_delta * ap.index_delta - ap.index_delta; // deg 2
1227
+ ap.index_is_monotonically_increasing = ap.index_delta * (ap.index_delta - Fr.wrap(1)); // deg 2
1243
1228
 
1244
- ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + Fr.wrap(1)) * ap.record_delta; // deg 2
1229
+ ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + ONE) * ap.record_delta; // deg 2
1245
1230
 
1246
- evals[13] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R))
1247
- * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5
1248
- evals[14] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R))
1249
- * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5
1231
+ evals[14] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R))
1232
+ * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5
1233
+ evals[15] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R))
1234
+ * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5
1250
1235
 
1251
1236
  ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7
1252
1237
 
@@ -1270,17 +1255,18 @@ library RelationsLib {
1270
1255
  * with a WRITE operation.
1271
1256
  */
1272
1257
  Fr access_type = (wire(p, WIRE.W_4) - ap.partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 4
1273
- ap.access_check = access_type * access_type - access_type; // check value is 0 or 1; deg 2 or 8
1258
+ ap.access_check = access_type * (access_type - Fr.wrap(1)); // check value is 0 or 1; deg 2 or 8
1274
1259
 
1260
+ // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta
1261
+ // deg 1 or 4
1275
1262
  ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree;
1276
1263
  ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo);
1277
1264
  ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta);
1278
1265
  ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type;
1279
1266
 
1280
1267
  Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O);
1281
- ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (
1282
- ap.index_delta * MINUS_ONE + Fr.wrap(1)
1283
- ) * value_delta * (ap.next_gate_access_type * MINUS_ONE + Fr.wrap(1)); // deg 3 or 6
1268
+ ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation =
1269
+ (ap.index_delta * MINUS_ONE + ONE) * value_delta * (ap.next_gate_access_type * MINUS_ONE + ONE); // deg 3 or 6
1284
1270
 
1285
1271
  // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the
1286
1272
  // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't
@@ -1291,12 +1277,12 @@ library RelationsLib {
1291
1277
  ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type;
1292
1278
 
1293
1279
  // Putting it all together...
1294
- evals[15] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation
1295
- * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5 or 8
1296
- evals[16] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4
1297
- evals[17] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4 or 6
1280
+ evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation
1281
+ * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8
1282
+ evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4
1283
+ evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6
1298
1284
 
1299
- ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_ARITH)); // deg 3 or 9
1285
+ ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9
1300
1286
 
1301
1287
  /**
1302
1288
  * RAM Timestamp Consistency Check
@@ -1310,8 +1296,7 @@ library RelationsLib {
1310
1296
  * Else timestamp_check = 0
1311
1297
  */
1312
1298
  ap.timestamp_delta = wire(p, WIRE.W_R_SHIFT) - wire(p, WIRE.W_R);
1313
- ap.RAM_timestamp_check_identity =
1314
- (ap.index_delta * MINUS_ONE + Fr.wrap(1)) * ap.timestamp_delta - wire(p, WIRE.W_O); // deg 3
1299
+ ap.RAM_timestamp_check_identity = (ap.index_delta * MINUS_ONE + ONE) * ap.timestamp_delta - wire(p, WIRE.W_O); // deg 3
1315
1300
 
1316
1301
  /**
1317
1302
  * Complete Contribution 12
@@ -1325,9 +1310,100 @@ library RelationsLib {
1325
1310
  ap.memory_identity = ap.memory_identity + ap.RAM_consistency_check_identity; // deg 3 or 9
1326
1311
 
1327
1312
  // (deg 3 or 9) + (deg 4) + (deg 3)
1328
- ap.auxiliary_identity = ap.memory_identity + non_native_field_identity + limb_accumulator_identity;
1329
- ap.auxiliary_identity = ap.auxiliary_identity * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4 or 10
1330
- evals[12] = ap.auxiliary_identity;
1313
+ ap.memory_identity = ap.memory_identity * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10
1314
+ evals[13] = ap.memory_identity;
1315
+ }
1316
+
1317
+ // Constants for the Non-native Field relation
1318
+ Fr constant LIMB_SIZE = Fr.wrap(uint256(1) << 68);
1319
+ Fr constant SUBLIMB_SHIFT = Fr.wrap(uint256(1) << 14);
1320
+
1321
+ // Parameters used within the Non-Native Field Relation
1322
+ // A struct is used to work around stack too deep. This relation has alot of variables
1323
+ struct NnfParams {
1324
+ Fr limb_subproduct;
1325
+ Fr non_native_field_gate_1;
1326
+ Fr non_native_field_gate_2;
1327
+ Fr non_native_field_gate_3;
1328
+ Fr limb_accumulator_1;
1329
+ Fr limb_accumulator_2;
1330
+ Fr nnf_identity;
1331
+ }
1332
+
1333
+ function accumulateNnfRelation(
1334
+ Fr[NUMBER_OF_ENTITIES] memory p,
1335
+ Fr[NUMBER_OF_SUBRELATIONS] memory evals,
1336
+ Fr domainSep
1337
+ ) internal pure {
1338
+ NnfParams memory ap;
1339
+
1340
+ /**
1341
+ * Contribution 12
1342
+ * Non native field arithmetic gate 2
1343
+ * deg 4
1344
+ *
1345
+ * _ _
1346
+ * / _ _ _ 14 \
1347
+ * 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 |
1348
+ * \_ _/
1349
+ *
1350
+ *
1351
+ */
1352
+ 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);
1353
+ ap.non_native_field_gate_2 =
1354
+ (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));
1355
+ ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * LIMB_SIZE;
1356
+ ap.non_native_field_gate_2 = ap.non_native_field_gate_2 - wire(p, WIRE.W_4_SHIFT);
1357
+ ap.non_native_field_gate_2 = ap.non_native_field_gate_2 + ap.limb_subproduct;
1358
+ ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * wire(p, WIRE.Q_4);
1359
+
1360
+ ap.limb_subproduct = ap.limb_subproduct * LIMB_SIZE;
1361
+ ap.limb_subproduct = ap.limb_subproduct + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT));
1362
+ ap.non_native_field_gate_1 = ap.limb_subproduct;
1363
+ ap.non_native_field_gate_1 = ap.non_native_field_gate_1 - (wire(p, WIRE.W_O) + wire(p, WIRE.W_4));
1364
+ ap.non_native_field_gate_1 = ap.non_native_field_gate_1 * wire(p, WIRE.Q_O);
1365
+
1366
+ ap.non_native_field_gate_3 = ap.limb_subproduct;
1367
+ ap.non_native_field_gate_3 = ap.non_native_field_gate_3 + wire(p, WIRE.W_4);
1368
+ ap.non_native_field_gate_3 = ap.non_native_field_gate_3 - (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT));
1369
+ ap.non_native_field_gate_3 = ap.non_native_field_gate_3 * wire(p, WIRE.Q_M);
1370
+
1371
+ Fr non_native_field_identity =
1372
+ ap.non_native_field_gate_1 + ap.non_native_field_gate_2 + ap.non_native_field_gate_3;
1373
+ non_native_field_identity = non_native_field_identity * wire(p, WIRE.Q_R);
1374
+
1375
+ // ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm
1376
+ // deg 2
1377
+ ap.limb_accumulator_1 = wire(p, WIRE.W_R_SHIFT) * SUBLIMB_SHIFT;
1378
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L_SHIFT);
1379
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1380
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_O);
1381
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1382
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_R);
1383
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1384
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L);
1385
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 - wire(p, WIRE.W_4);
1386
+ ap.limb_accumulator_1 = ap.limb_accumulator_1 * wire(p, WIRE.Q_4);
1387
+
1388
+ // ((((w3' * 2^14 + w2') * 2^14 + w1') * 2^14 + w4) * 2^14 + w3 - w4') * qm
1389
+ // deg 2
1390
+ ap.limb_accumulator_2 = wire(p, WIRE.W_O_SHIFT) * SUBLIMB_SHIFT;
1391
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_R_SHIFT);
1392
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1393
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_L_SHIFT);
1394
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1395
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_4);
1396
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1397
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_O);
1398
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 - wire(p, WIRE.W_4_SHIFT);
1399
+ ap.limb_accumulator_2 = ap.limb_accumulator_2 * wire(p, WIRE.Q_M);
1400
+
1401
+ Fr limb_accumulator_identity = ap.limb_accumulator_1 + ap.limb_accumulator_2;
1402
+ limb_accumulator_identity = limb_accumulator_identity * wire(p, WIRE.Q_O); // deg 3
1403
+
1404
+ ap.nnf_identity = non_native_field_identity + limb_accumulator_identity;
1405
+ ap.nnf_identity = ap.nnf_identity * (wire(p, WIRE.Q_NNF) * domainSep);
1406
+ evals[19] = ap.nnf_identity;
1331
1407
  }
1332
1408
 
1333
1409
  struct PoseidonExternalParams {
@@ -1383,13 +1459,13 @@ library RelationsLib {
1383
1459
  ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4
1384
1460
 
1385
1461
  ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep;
1386
- evals[18] = evals[18] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT));
1462
+ evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT));
1387
1463
 
1388
- evals[19] = evals[19] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT));
1464
+ evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT));
1389
1465
 
1390
- evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT));
1466
+ evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT));
1391
1467
 
1392
- evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT));
1468
+ evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT));
1393
1469
  }
1394
1470
 
1395
1471
  struct PoseidonInternalParams {
@@ -1435,23 +1511,23 @@ library RelationsLib {
1435
1511
  ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep;
1436
1512
 
1437
1513
  ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum;
1438
- evals[22] = evals[22] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT));
1514
+ evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT));
1439
1515
 
1440
1516
  ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum;
1441
- evals[23] = evals[23] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT));
1517
+ evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT));
1442
1518
 
1443
1519
  ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum;
1444
- evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT));
1520
+ evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT));
1445
1521
 
1446
1522
  ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum;
1447
- evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT));
1523
+ evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT));
1448
1524
  }
1449
1525
 
1450
1526
  function scaleAndBatchSubrelations(
1451
1527
  Fr[NUMBER_OF_SUBRELATIONS] memory evaluations,
1452
1528
  Fr[NUMBER_OF_ALPHAS] memory subrelationChallenges
1453
1529
  ) internal pure returns (Fr accumulator) {
1454
- accumulator = accumulator + evaluations[0];
1530
+ accumulator = evaluations[0];
1455
1531
 
1456
1532
  for (uint256 i = 1; i < NUMBER_OF_SUBRELATIONS; ++i) {
1457
1533
  accumulator = accumulator + evaluations[i] * subrelationChallenges[i - 1];
@@ -1459,139 +1535,458 @@ library RelationsLib {
1459
1535
  }
1460
1536
  }
1461
1537
 
1462
- struct ShpleminiIntermediates {
1463
- Fr unshiftedScalar;
1464
- Fr shiftedScalar;
1465
- // Scalar to be multiplied by [1]₁
1466
- Fr constantTermAccumulator;
1467
- // Accumulator for powers of rho
1468
- Fr batchingChallenge;
1469
- // Linear combination of multilinear (sumcheck) evaluations and powers of rho
1470
- Fr batchedEvaluation;
1471
- // 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated
1472
- Fr posInvertedDenominator;
1473
- // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated
1474
- Fr negInvertedDenominator;
1475
- // v^{2i} * 1/(z - r^{2^i})
1476
- Fr scalingFactorPos;
1477
- // v^{2i+1} * 1/(z + r^{2^i})
1478
- Fr scalingFactorNeg;
1479
- // // Fold_i(r^{2^i}) reconstructed by Verifier
1480
- // Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations;
1481
- }
1538
+ // Field arithmetic libraries - prevent littering the code with modmul / addmul
1482
1539
 
1483
1540
  library CommitmentSchemeLib {
1484
1541
  using FrLib for Fr;
1485
1542
 
1486
- function computeSquares(Fr r) internal pure returns (Fr[CONST_PROOF_SIZE_LOG_N] memory squares) {
1543
+ // Avoid stack too deep
1544
+ struct ShpleminiIntermediates {
1545
+ Fr unshiftedScalar;
1546
+ Fr shiftedScalar;
1547
+ Fr unshiftedScalarNeg;
1548
+ Fr shiftedScalarNeg;
1549
+ // Scalar to be multiplied by [1]₁
1550
+ Fr constantTermAccumulator;
1551
+ // Accumulator for powers of rho
1552
+ Fr batchingChallenge;
1553
+ // Linear combination of multilinear (sumcheck) evaluations and powers of rho
1554
+ Fr batchedEvaluation;
1555
+ Fr[4] denominators;
1556
+ Fr[4] batchingScalars;
1557
+ // 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated
1558
+ Fr posInvertedDenominator;
1559
+ // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated
1560
+ Fr negInvertedDenominator;
1561
+ // ν^{2i} * 1/(z - r^{2^i})
1562
+ Fr scalingFactorPos;
1563
+ // ν^{2i+1} * 1/(z + r^{2^i})
1564
+ Fr scalingFactorNeg;
1565
+ // Fold_i(r^{2^i}) reconstructed by Verifier
1566
+ Fr[] foldPosEvaluations;
1567
+ }
1568
+
1569
+ function computeSquares(Fr r, uint256 logN) internal pure returns (Fr[] memory) {
1570
+ Fr[] memory squares = new Fr[](logN);
1487
1571
  squares[0] = r;
1488
- for (uint256 i = 1; i < CONST_PROOF_SIZE_LOG_N; ++i) {
1572
+ for (uint256 i = 1; i < logN; ++i) {
1489
1573
  squares[i] = squares[i - 1].sqr();
1490
1574
  }
1575
+ return squares;
1491
1576
  }
1577
+ // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1
1492
1578
 
1493
- // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., m-1
1494
1579
  function computeFoldPosEvaluations(
1495
1580
  Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges,
1496
1581
  Fr batchedEvalAccumulator,
1497
1582
  Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvaluations,
1498
- Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvalChallengePowers,
1583
+ Fr[] memory geminiEvalChallengePowers,
1499
1584
  uint256 logSize
1500
- ) internal view returns (Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations) {
1501
- for (uint256 i = CONST_PROOF_SIZE_LOG_N; i > 0; --i) {
1585
+ ) internal view returns (Fr[] memory) {
1586
+ Fr[] memory foldPosEvaluations = new Fr[](logSize);
1587
+ for (uint256 i = logSize; i > 0; --i) {
1502
1588
  Fr challengePower = geminiEvalChallengePowers[i - 1];
1503
1589
  Fr u = sumcheckUChallenges[i - 1];
1504
1590
 
1505
1591
  Fr batchedEvalRoundAcc = (
1506
1592
  (challengePower * batchedEvalAccumulator * Fr.wrap(2))
1507
- - geminiEvaluations[i - 1] * (challengePower * (Fr.wrap(1) - u) - u)
1593
+ - geminiEvaluations[i - 1] * (challengePower * (ONE - u) - u)
1508
1594
  );
1509
1595
  // Divide by the denominator
1510
- batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (Fr.wrap(1) - u) + u).invert();
1596
+ batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (ONE - u) + u).invert();
1511
1597
 
1512
- if (i <= logSize) {
1513
- batchedEvalAccumulator = batchedEvalRoundAcc;
1514
- foldPosEvaluations[i - 1] = batchedEvalRoundAcc;
1515
- }
1598
+ batchedEvalAccumulator = batchedEvalRoundAcc;
1599
+ foldPosEvaluations[i - 1] = batchedEvalRoundAcc;
1516
1600
  }
1601
+ return foldPosEvaluations;
1602
+ }
1603
+ }
1517
1604
 
1605
+ uint256 constant Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // EC group order. F_q
1606
+
1607
+ function bytes32ToString(bytes32 value) pure returns (string memory result) {
1608
+ bytes memory alphabet = "0123456789abcdef";
1609
+
1610
+ bytes memory str = new bytes(66);
1611
+ str[0] = "0";
1612
+ str[1] = "x";
1613
+ for (uint256 i = 0; i < 32; i++) {
1614
+ str[2 + i * 2] = alphabet[uint8(value[i] >> 4)];
1615
+ str[3 + i * 2] = alphabet[uint8(value[i] & 0x0f)];
1518
1616
  }
1617
+ result = string(str);
1519
1618
  }
1520
1619
 
1521
- interface IVerifier {
1522
- function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool);
1620
+ // Fr utility
1621
+
1622
+ function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) {
1623
+ scalar = FrLib.fromBytes32(bytes32(proofSection));
1624
+ }
1625
+
1626
+ // EC Point utilities
1627
+ function bytesToG1Point(bytes calldata proofSection) pure returns (Honk.G1Point memory point) {
1628
+ point = Honk.G1Point({
1629
+ x: uint256(bytes32(proofSection[0x00:0x20])) % Q,
1630
+ y: uint256(bytes32(proofSection[0x20:0x40])) % Q
1631
+ });
1632
+ }
1633
+
1634
+ function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) {
1635
+ point.y = (Q - point.y) % Q;
1636
+ return point;
1637
+ }
1638
+
1639
+ /**
1640
+ * Convert the pairing points to G1 points.
1641
+ *
1642
+ * The pairing points are serialised as an array of 68 bit limbs representing two points
1643
+ * The lhs of a pairing operation and the rhs of a pairing operation
1644
+ *
1645
+ * There are 4 fields for each group element, leaving 8 fields for each side of the pairing.
1646
+ *
1647
+ * @param pairingPoints The pairing points to convert.
1648
+ * @return lhs
1649
+ * @return rhs
1650
+ */
1651
+ function convertPairingPointsToG1(Fr[PAIRING_POINTS_SIZE] memory pairingPoints)
1652
+ pure
1653
+ returns (Honk.G1Point memory lhs, Honk.G1Point memory rhs)
1654
+ {
1655
+ uint256 lhsX = Fr.unwrap(pairingPoints[0]);
1656
+ lhsX |= Fr.unwrap(pairingPoints[1]) << 68;
1657
+ lhsX |= Fr.unwrap(pairingPoints[2]) << 136;
1658
+ lhsX |= Fr.unwrap(pairingPoints[3]) << 204;
1659
+ lhs.x = lhsX;
1660
+
1661
+ uint256 lhsY = Fr.unwrap(pairingPoints[4]);
1662
+ lhsY |= Fr.unwrap(pairingPoints[5]) << 68;
1663
+ lhsY |= Fr.unwrap(pairingPoints[6]) << 136;
1664
+ lhsY |= Fr.unwrap(pairingPoints[7]) << 204;
1665
+ lhs.y = lhsY;
1666
+
1667
+ uint256 rhsX = Fr.unwrap(pairingPoints[8]);
1668
+ rhsX |= Fr.unwrap(pairingPoints[9]) << 68;
1669
+ rhsX |= Fr.unwrap(pairingPoints[10]) << 136;
1670
+ rhsX |= Fr.unwrap(pairingPoints[11]) << 204;
1671
+ rhs.x = rhsX;
1672
+
1673
+ uint256 rhsY = Fr.unwrap(pairingPoints[12]);
1674
+ rhsY |= Fr.unwrap(pairingPoints[13]) << 68;
1675
+ rhsY |= Fr.unwrap(pairingPoints[14]) << 136;
1676
+ rhsY |= Fr.unwrap(pairingPoints[15]) << 204;
1677
+ rhs.y = rhsY;
1678
+ }
1679
+
1680
+ /**
1681
+ * Hash the pairing inputs from the present verification context with those extracted from the public inputs.
1682
+ *
1683
+ * @param proofPairingPoints Pairing points from the proof - (public inputs).
1684
+ * @param accLhs Accumulator point for the left side - result of shplemini.
1685
+ * @param accRhs Accumulator point for the right side - result of shplemini.
1686
+ * @return recursionSeparator The recursion separator - generated from hashing the above.
1687
+ */
1688
+ function generateRecursionSeparator(
1689
+ Fr[PAIRING_POINTS_SIZE] memory proofPairingPoints,
1690
+ Honk.G1Point memory accLhs,
1691
+ Honk.G1Point memory accRhs
1692
+ ) pure returns (Fr recursionSeparator) {
1693
+ // hash the proof aggregated X
1694
+ // hash the proof aggregated Y
1695
+ // hash the accum X
1696
+ // hash the accum Y
1697
+
1698
+ (Honk.G1Point memory proofLhs, Honk.G1Point memory proofRhs) = convertPairingPointsToG1(proofPairingPoints);
1699
+
1700
+ uint256[8] memory recursionSeparatorElements;
1701
+
1702
+ // Proof points
1703
+ recursionSeparatorElements[0] = proofLhs.x;
1704
+ recursionSeparatorElements[1] = proofLhs.y;
1705
+ recursionSeparatorElements[2] = proofRhs.x;
1706
+ recursionSeparatorElements[3] = proofRhs.y;
1707
+
1708
+ // Accumulator points
1709
+ recursionSeparatorElements[4] = accLhs.x;
1710
+ recursionSeparatorElements[5] = accLhs.y;
1711
+ recursionSeparatorElements[6] = accRhs.x;
1712
+ recursionSeparatorElements[7] = accRhs.y;
1713
+
1714
+ recursionSeparator = FrLib.fromBytes32(keccak256(abi.encodePacked(recursionSeparatorElements)));
1523
1715
  }
1524
1716
 
1717
+ /**
1718
+ * G1 Mul with Separator
1719
+ * Using the ecAdd and ecMul precompiles
1720
+ *
1721
+ * @param basePoint The point to multiply.
1722
+ * @param other The other point to add.
1723
+ * @param recursionSeperator The separator to use for the multiplication.
1724
+ * @return `(recursionSeperator * basePoint) + other`.
1725
+ */
1726
+ function mulWithSeperator(Honk.G1Point memory basePoint, Honk.G1Point memory other, Fr recursionSeperator)
1727
+ view
1728
+ returns (Honk.G1Point memory)
1729
+ {
1730
+ Honk.G1Point memory result;
1731
+
1732
+ result = ecMul(recursionSeperator, basePoint);
1733
+ result = ecAdd(result, other);
1734
+
1735
+ return result;
1736
+ }
1737
+
1738
+ /**
1739
+ * G1 Mul
1740
+ * Takes a Fr value and a G1 point and uses the ecMul precompile to return the result.
1741
+ *
1742
+ * @param value The value to multiply the point by.
1743
+ * @param point The point to multiply.
1744
+ * @return result The result of the multiplication.
1745
+ */
1746
+ function ecMul(Fr value, Honk.G1Point memory point) view returns (Honk.G1Point memory) {
1747
+ Honk.G1Point memory result;
1748
+
1749
+ assembly {
1750
+ let free := mload(0x40)
1751
+ // Write the point into memory (two 32 byte words)
1752
+ // Memory layout:
1753
+ // Address | value
1754
+ // free | point.x
1755
+ // free + 0x20| point.y
1756
+ mstore(free, mload(point))
1757
+ mstore(add(free, 0x20), mload(add(point, 0x20)))
1758
+ // Write the scalar into memory (one 32 byte word)
1759
+ // Memory layout:
1760
+ // Address | value
1761
+ // free + 0x40| value
1762
+ mstore(add(free, 0x40), value)
1763
+
1764
+ // Call the ecMul precompile, it takes in the following
1765
+ // [point.x, point.y, scalar], and returns the result back into the free memory location.
1766
+ let success := staticcall(gas(), 0x07, free, 0x60, free, 0x40)
1767
+ if iszero(success) {
1768
+ revert(0, 0)
1769
+ }
1770
+ // Copy the result of the multiplication back into the result memory location.
1771
+ // Memory layout:
1772
+ // Address | value
1773
+ // result | result.x
1774
+ // result + 0x20| result.y
1775
+ mstore(result, mload(free))
1776
+ mstore(add(result, 0x20), mload(add(free, 0x20)))
1777
+
1778
+ mstore(0x40, add(free, 0x60))
1779
+ }
1780
+
1781
+ return result;
1782
+ }
1783
+
1784
+ /**
1785
+ * G1 Add
1786
+ * Takes two G1 points and uses the ecAdd precompile to return the result.
1787
+ *
1788
+ * @param lhs The left hand side of the addition.
1789
+ * @param rhs The right hand side of the addition.
1790
+ * @return result The result of the addition.
1791
+ */
1792
+ function ecAdd(Honk.G1Point memory lhs, Honk.G1Point memory rhs) view returns (Honk.G1Point memory) {
1793
+ Honk.G1Point memory result;
1794
+
1795
+ assembly {
1796
+ let free := mload(0x40)
1797
+ // Write lhs into memory (two 32 byte words)
1798
+ // Memory layout:
1799
+ // Address | value
1800
+ // free | lhs.x
1801
+ // free + 0x20| lhs.y
1802
+ mstore(free, mload(lhs))
1803
+ mstore(add(free, 0x20), mload(add(lhs, 0x20)))
1804
+
1805
+ // Write rhs into memory (two 32 byte words)
1806
+ // Memory layout:
1807
+ // Address | value
1808
+ // free + 0x40| rhs.x
1809
+ // free + 0x60| rhs.y
1810
+ mstore(add(free, 0x40), mload(rhs))
1811
+ mstore(add(free, 0x60), mload(add(rhs, 0x20)))
1812
+
1813
+ // Call the ecAdd precompile, it takes in the following
1814
+ // [lhs.x, lhs.y, rhs.x, rhs.y], and returns their addition back into the free memory location.
1815
+ let success := staticcall(gas(), 0x06, free, 0x80, free, 0x40)
1816
+ if iszero(success) { revert(0, 0) }
1817
+
1818
+ // Copy the result of the addition back into the result memory location.
1819
+ // Memory layout:
1820
+ // Address | value
1821
+ // result | result.x
1822
+ // result + 0x20| result.y
1823
+ mstore(result, mload(free))
1824
+ mstore(add(result, 0x20), mload(add(free, 0x20)))
1825
+
1826
+ mstore(0x40, add(free, 0x80))
1827
+ }
1828
+
1829
+ return result;
1830
+ }
1525
1831
 
1526
- abstract contract BaseHonkVerifier is IVerifier {
1832
+ function validateOnCurve(Honk.G1Point memory point) pure {
1833
+ uint256 x = point.x;
1834
+ uint256 y = point.y;
1835
+
1836
+ bool success = false;
1837
+ assembly {
1838
+ let xx := mulmod(x, x, Q)
1839
+ success := eq(mulmod(y, y, Q), addmod(mulmod(x, xx, Q), 3, Q))
1840
+ }
1841
+
1842
+ require(success, "point is not on the curve");
1843
+ }
1844
+
1845
+ function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool decodedResult) {
1846
+ bytes memory input = abi.encodePacked(
1847
+ rhs.x,
1848
+ rhs.y,
1849
+ // Fixed G2 point
1850
+ uint256(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2),
1851
+ uint256(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed),
1852
+ uint256(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b),
1853
+ uint256(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa),
1854
+ lhs.x,
1855
+ lhs.y,
1856
+ // G2 point from VK
1857
+ uint256(0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1),
1858
+ uint256(0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0),
1859
+ uint256(0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4),
1860
+ uint256(0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55)
1861
+ );
1862
+
1863
+ (bool success, bytes memory result) = address(0x08).staticcall(input);
1864
+ decodedResult = success && abi.decode(result, (bool));
1865
+ }
1866
+
1867
+ // Field arithmetic libraries - prevent littering the code with modmul / addmul
1868
+
1869
+
1870
+
1871
+
1872
+ abstract contract BaseZKHonkVerifier is IVerifier {
1527
1873
  using FrLib for Fr;
1528
1874
 
1529
- uint256 immutable n;
1530
- uint256 immutable logN;
1531
- uint256 immutable numPublicInputs;
1875
+ uint256 immutable $N;
1876
+ uint256 immutable $LOG_N;
1877
+ uint256 immutable $VK_HASH;
1878
+ uint256 immutable $NUM_PUBLIC_INPUTS;
1532
1879
 
1533
- constructor(uint256 _n, uint256 _logN, uint256 _numPublicInputs) {
1534
- n = _n;
1535
- logN = _logN;
1536
- numPublicInputs = _numPublicInputs;
1880
+ constructor(uint256 _N, uint256 _logN, uint256 _vkHash, uint256 _numPublicInputs) {
1881
+ $N = _N;
1882
+ $LOG_N = _logN;
1883
+ $VK_HASH = _vkHash;
1884
+ $NUM_PUBLIC_INPUTS = _numPublicInputs;
1537
1885
  }
1538
1886
 
1887
+ // Errors
1539
1888
  error ProofLengthWrong();
1889
+ error ProofLengthWrongWithLogN(uint256 logN, uint256 actualLength, uint256 expectedLength);
1540
1890
  error PublicInputsLengthWrong();
1541
1891
  error SumcheckFailed();
1542
1892
  error ShpleminiFailed();
1893
+ error GeminiChallengeInSubgroup();
1894
+ error ConsistencyCheckFailed();
1895
+
1896
+ // Constants for proof length calculation (matching UltraKeccakZKFlavor)
1897
+ uint256 constant NUM_WITNESS_ENTITIES = 8;
1898
+ uint256 constant NUM_ELEMENTS_COMM = 2; // uint256 elements for curve points
1899
+ uint256 constant NUM_ELEMENTS_FR = 1; // uint256 elements for field elements
1900
+ uint256 constant NUM_LIBRA_EVALUATIONS = 4; // libra evaluations
1543
1901
 
1544
- // Number of field elements in a ultra honk zero knowledge proof
1545
- uint256 constant PROOF_SIZE = 440;
1902
+ // Calculate proof size based on log_n (matching UltraKeccakZKFlavor formula)
1903
+ function calculateProofSize(uint256 logN) internal pure returns (uint256) {
1904
+ // Witness and Libra commitments
1905
+ uint256 proofLength = NUM_WITNESS_ENTITIES * NUM_ELEMENTS_COMM; // witness commitments
1906
+ proofLength += NUM_ELEMENTS_COMM * 4; // Libra concat, grand sum, quotient comms + Gemini masking
1907
+
1908
+ // Sumcheck
1909
+ proofLength += logN * ZK_BATCHED_RELATION_PARTIAL_LENGTH * NUM_ELEMENTS_FR; // sumcheck univariates
1910
+ proofLength += NUMBER_OF_ENTITIES * NUM_ELEMENTS_FR; // sumcheck evaluations
1911
+
1912
+ // Libra and Gemini
1913
+ proofLength += NUM_ELEMENTS_FR * 3; // Libra sum, claimed eval, Gemini masking eval
1914
+ proofLength += logN * NUM_ELEMENTS_FR; // Gemini a evaluations
1915
+ proofLength += NUM_LIBRA_EVALUATIONS * NUM_ELEMENTS_FR; // libra evaluations
1916
+
1917
+ // PCS commitments
1918
+ proofLength += (logN - 1) * NUM_ELEMENTS_COMM; // Gemini Fold commitments
1919
+ proofLength += NUM_ELEMENTS_COMM * 2; // Shplonk Q and KZG W commitments
1920
+
1921
+ // Pairing points
1922
+ proofLength += PAIRING_POINTS_SIZE; // pairing inputs carried on public inputs
1923
+
1924
+ return proofLength;
1925
+ }
1926
+
1927
+ uint256 constant SHIFTED_COMMITMENTS_START = 30;
1546
1928
 
1547
1929
  function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory);
1548
1930
 
1549
- function verify(bytes calldata proof, bytes32[] calldata publicInputs) public view override returns (bool) {
1550
- // Check the received proof is the expected size where each field element is 32 bytes
1551
- if (proof.length != PROOF_SIZE * 32) {
1552
- revert ProofLengthWrong();
1931
+ function verify(bytes calldata proof, bytes32[] calldata publicInputs)
1932
+ public
1933
+ view
1934
+ override
1935
+ returns (bool verified)
1936
+ {
1937
+ // Calculate expected proof size based on $LOG_N
1938
+ uint256 expectedProofSize = calculateProofSize($LOG_N);
1939
+
1940
+ // Check the received proof is the expected size where each field element is 32 bytes
1941
+ if (proof.length != expectedProofSize * 32) {
1942
+ revert ProofLengthWrongWithLogN($LOG_N, proof.length, expectedProofSize * 32);
1553
1943
  }
1554
1944
 
1555
1945
  Honk.VerificationKey memory vk = loadVerificationKey();
1556
- Honk.Proof memory p = TranscriptLib.loadProof(proof);
1946
+ Honk.ZKProof memory p = ZKTranscriptLib.loadProof(proof, $LOG_N);
1557
1947
 
1558
- if (publicInputs.length != vk.publicInputsSize) {
1948
+ if (publicInputs.length != vk.publicInputsSize - PAIRING_POINTS_SIZE) {
1559
1949
  revert PublicInputsLengthWrong();
1560
1950
  }
1561
1951
 
1562
1952
  // Generate the fiat shamir challenges for the whole protocol
1563
- // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely.
1564
- Transcript memory t = TranscriptLib.generateTranscript(p, publicInputs, vk.circuitSize, vk.publicInputsSize, /*pubInputsOffset=*/1);
1953
+ ZKTranscript memory t =
1954
+ ZKTranscriptLib.generateTranscript(p, publicInputs, $VK_HASH, $NUM_PUBLIC_INPUTS, $LOG_N);
1565
1955
 
1566
1956
  // Derive public input delta
1567
- // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely.
1568
1957
  t.relationParameters.publicInputsDelta = computePublicInputDelta(
1569
- publicInputs, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/1
1958
+ publicInputs,
1959
+ p.pairingPointObject,
1960
+ t.relationParameters.beta,
1961
+ t.relationParameters.gamma, /*pubInputsOffset=*/
1962
+ 1
1570
1963
  );
1571
1964
 
1572
1965
  // Sumcheck
1573
- bool sumcheckVerified = verifySumcheck(p, t);
1574
- if (!sumcheckVerified) revert SumcheckFailed();
1966
+ if (!verifySumcheck(p, t)) revert SumcheckFailed();
1575
1967
 
1576
- bool shpleminiVerified = verifyShplemini(p, vk, t);
1577
- if (!shpleminiVerified) revert ShpleminiFailed();
1968
+ if (!verifyShplemini(p, vk, t)) revert ShpleminiFailed();
1578
1969
 
1579
- return sumcheckVerified && shpleminiVerified; // Boolean condition not required - nice for vanity :)
1970
+ verified = true;
1580
1971
  }
1581
1972
 
1582
- function computePublicInputDelta(bytes32[] memory publicInputs, Fr beta, Fr gamma, uint256 offset)
1583
- internal
1584
- view
1585
- returns (Fr publicInputDelta)
1586
- {
1973
+ uint256 constant PERMUTATION_ARGUMENT_VALUE_SEPARATOR = 1 << 28;
1974
+
1975
+ function computePublicInputDelta(
1976
+ bytes32[] memory publicInputs,
1977
+ Fr[PAIRING_POINTS_SIZE] memory pairingPointObject,
1978
+ Fr beta,
1979
+ Fr gamma,
1980
+ uint256 offset
1981
+ ) internal view returns (Fr publicInputDelta) {
1587
1982
  Fr numerator = Fr.wrap(1);
1588
1983
  Fr denominator = Fr.wrap(1);
1589
1984
 
1590
- Fr numeratorAcc = gamma + (beta * FrLib.from(n + offset));
1985
+ Fr numeratorAcc = gamma + (beta * FrLib.from(PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset));
1591
1986
  Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1));
1592
1987
 
1593
1988
  {
1594
- for (uint256 i = 0; i < numPublicInputs; i++) {
1989
+ for (uint256 i = 0; i < $NUM_PUBLIC_INPUTS - PAIRING_POINTS_SIZE; i++) {
1595
1990
  Fr pubInput = FrLib.fromBytes32(publicInputs[i]);
1596
1991
 
1597
1992
  numerator = numerator * (numeratorAcc + pubInput);
@@ -1600,60 +1995,71 @@ abstract contract BaseHonkVerifier is IVerifier {
1600
1995
  numeratorAcc = numeratorAcc + beta;
1601
1996
  denominatorAcc = denominatorAcc - beta;
1602
1997
  }
1998
+
1999
+ for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) {
2000
+ Fr pubInput = pairingPointObject[i];
2001
+
2002
+ numerator = numerator * (numeratorAcc + pubInput);
2003
+ denominator = denominator * (denominatorAcc + pubInput);
2004
+
2005
+ numeratorAcc = numeratorAcc + beta;
2006
+ denominatorAcc = denominatorAcc - beta;
2007
+ }
1603
2008
  }
1604
2009
 
1605
2010
  // Fr delta = numerator / denominator; // TOOO: batch invert later?
1606
2011
  publicInputDelta = FrLib.div(numerator, denominator);
1607
2012
  }
1608
2013
 
1609
- function verifySumcheck(Honk.Proof memory proof, Transcript memory tp) internal view returns (bool verified) {
1610
- Fr roundTarget;
2014
+ function verifySumcheck(Honk.ZKProof memory proof, ZKTranscript memory tp) internal view returns (bool verified) {
2015
+ Fr roundTargetSum = tp.libraChallenge * proof.libraSum; // default 0
1611
2016
  Fr powPartialEvaluation = Fr.wrap(1);
1612
2017
 
1613
2018
  // We perform sumcheck reductions over log n rounds ( the multivariate degree )
1614
- for (uint256 round; round < logN; ++round) {
1615
- Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round];
1616
- bool valid = checkSum(roundUnivariate, roundTarget);
1617
- if (!valid) revert SumcheckFailed();
2019
+ for (uint256 round; round < $LOG_N; ++round) {
2020
+ Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round];
2021
+ Fr totalSum = roundUnivariate[0] + roundUnivariate[1];
2022
+ if (totalSum != roundTargetSum) revert SumcheckFailed();
1618
2023
 
1619
2024
  Fr roundChallenge = tp.sumCheckUChallenges[round];
1620
2025
 
1621
2026
  // Update the round target for the next rounf
1622
- roundTarget = computeNextTargetSum(roundUnivariate, roundChallenge);
1623
- powPartialEvaluation = partiallyEvaluatePOW(tp.gateChallenges[round], powPartialEvaluation, roundChallenge);
2027
+ roundTargetSum = computeNextTargetSum(roundUnivariate, roundChallenge);
2028
+ powPartialEvaluation =
2029
+ powPartialEvaluation * (Fr.wrap(1) + roundChallenge * (tp.gateChallenges[round] - Fr.wrap(1)));
1624
2030
  }
1625
2031
 
1626
2032
  // Last round
1627
- Fr grandHonkRelationSum =
1628
- RelationsLib.accumulateRelationEvaluations(proof.sumcheckEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation);
1629
- verified = (grandHonkRelationSum == roundTarget);
1630
- }
2033
+ Fr grandHonkRelationSum = RelationsLib.accumulateRelationEvaluations(
2034
+ proof.sumcheckEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation
2035
+ );
1631
2036
 
1632
- function checkSum(Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate, Fr roundTarget)
1633
- internal
1634
- pure
1635
- returns (bool checked)
1636
- {
1637
- Fr totalSum = roundUnivariate[0] + roundUnivariate[1];
1638
- checked = totalSum == roundTarget;
2037
+ Fr evaluation = Fr.wrap(1);
2038
+ for (uint256 i = 2; i < $LOG_N; i++) {
2039
+ evaluation = evaluation * tp.sumCheckUChallenges[i];
2040
+ }
2041
+
2042
+ grandHonkRelationSum =
2043
+ grandHonkRelationSum * (Fr.wrap(1) - evaluation) + proof.libraEvaluation * tp.libraChallenge;
2044
+ verified = (grandHonkRelationSum == roundTargetSum);
1639
2045
  }
1640
2046
 
1641
2047
  // Return the new target sum for the next sumcheck round
1642
- function computeNextTargetSum(Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge)
2048
+ function computeNextTargetSum(Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge)
1643
2049
  internal
1644
2050
  view
1645
2051
  returns (Fr targetSum)
1646
2052
  {
1647
- // TODO: inline
1648
- Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [
2053
+ Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [
2054
+ Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80),
1649
2055
  Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51),
1650
- Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000002d0),
1651
- Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff11),
1652
- Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000090),
1653
- Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff71),
1654
- Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000000f0),
2056
+ Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0),
2057
+ Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31),
2058
+ Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000240),
1655
2059
  Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31),
1656
- Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000013b0)
2060
+ Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0),
2061
+ Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51),
2062
+ Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80)
1657
2063
  ];
1658
2064
 
1659
2065
  // To compute the next target sum, we evaluate the given univariate at a point u (challenge).
@@ -1661,52 +2067,44 @@ abstract contract BaseHonkVerifier is IVerifier {
1661
2067
  // Performing Barycentric evaluations
1662
2068
  // Compute B(x)
1663
2069
  Fr numeratorValue = Fr.wrap(1);
1664
- for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
2070
+ for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
1665
2071
  numeratorValue = numeratorValue * (roundChallenge - Fr.wrap(i));
1666
2072
  }
1667
2073
 
1668
- // Calculate domain size N of inverses
1669
- Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory denominatorInverses;
1670
- for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
1671
- Fr inv = BARYCENTRIC_LAGRANGE_DENOMINATORS[i];
1672
- inv = inv * (roundChallenge - Fr.wrap(i));
1673
- inv = FrLib.invert(inv);
1674
- denominatorInverses[i] = inv;
2074
+ Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory denominatorInverses;
2075
+ for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
2076
+ denominatorInverses[i] = FrLib.invert(BARYCENTRIC_LAGRANGE_DENOMINATORS[i] * (roundChallenge - Fr.wrap(i)));
1675
2077
  }
1676
2078
 
1677
- for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
1678
- Fr term = roundUnivariates[i];
1679
- term = term * denominatorInverses[i];
1680
- targetSum = targetSum + term;
2079
+ for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
2080
+ targetSum = targetSum + roundUnivariates[i] * denominatorInverses[i];
1681
2081
  }
1682
2082
 
1683
2083
  // Scale the sum by the value of B(x)
1684
2084
  targetSum = targetSum * numeratorValue;
1685
2085
  }
1686
2086
 
1687
- // Univariate evaluation of the monomial ((1-X_l) + X_l.B_l) at the challenge point X_l=u_l
1688
- function partiallyEvaluatePOW(Fr gateChallenge, Fr currentEvaluation, Fr roundChallenge)
1689
- internal
1690
- pure
1691
- returns (Fr newEvaluation)
1692
- {
1693
- Fr univariateEval = Fr.wrap(1) + (roundChallenge * (gateChallenge - Fr.wrap(1)));
1694
- newEvaluation = currentEvaluation * univariateEval;
2087
+ uint256 constant LIBRA_COMMITMENTS = 3;
2088
+ uint256 constant LIBRA_EVALUATIONS = 4;
2089
+ uint256 constant LIBRA_UNIVARIATES_LENGTH = 9;
2090
+
2091
+ struct PairingInputs {
2092
+ Honk.G1Point P_0;
2093
+ Honk.G1Point P_1;
1695
2094
  }
1696
2095
 
1697
- function verifyShplemini(Honk.Proof memory proof, Honk.VerificationKey memory vk, Transcript memory tp)
2096
+ function verifyShplemini(Honk.ZKProof memory proof, Honk.VerificationKey memory vk, ZKTranscript memory tp)
1698
2097
  internal
1699
2098
  view
1700
2099
  returns (bool verified)
1701
2100
  {
1702
- ShpleminiIntermediates memory mem; // stack
2101
+ CommitmentSchemeLib.ShpleminiIntermediates memory mem; // stack
1703
2102
 
1704
2103
  // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size
1705
- Fr[CONST_PROOF_SIZE_LOG_N] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR);
1706
-
2104
+ Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR, $LOG_N);
1707
2105
  // Arrays hold values that will be linearly combined for the gemini and shplonk batch openings
1708
- Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars;
1709
- Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory commitments;
2106
+ Fr[] memory scalars = new Fr[](NUMBER_UNSHIFTED + $LOG_N + LIBRA_COMMITMENTS + 3);
2107
+ Honk.G1Point[] memory commitments = new Honk.G1Point[](NUMBER_UNSHIFTED + $LOG_N + LIBRA_COMMITMENTS + 3);
1710
2108
 
1711
2109
  mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert();
1712
2110
  mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert();
@@ -1716,88 +2114,147 @@ abstract contract BaseHonkVerifier is IVerifier {
1716
2114
  tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator));
1717
2115
 
1718
2116
  scalars[0] = Fr.wrap(1);
1719
- commitments[0] = convertProofPoint(proof.shplonkQ);
1720
-
1721
- mem.batchingChallenge = Fr.wrap(1);
1722
- mem.batchedEvaluation = Fr.wrap(0);
1723
-
1724
- for (uint256 i = 1; i <= NUMBER_UNSHIFTED; ++i) {
1725
- scalars[i] = mem.unshiftedScalar.neg() * mem.batchingChallenge;
1726
- mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i - 1] * mem.batchingChallenge);
2117
+ commitments[0] = proof.shplonkQ;
2118
+
2119
+ /* Batch multivariate opening claims, shifted and unshifted
2120
+ * The vector of scalars is populated as follows:
2121
+ * \f[
2122
+ * \left(
2123
+ * - \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right),
2124
+ * \ldots,
2125
+ * - \rho^{i+k-1} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right),
2126
+ * - \rho^{i+k} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right),
2127
+ * \ldots,
2128
+ * - \rho^{k+m-1} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right)
2129
+ * \right)
2130
+ * \f]
2131
+ *
2132
+ * The following vector is concatenated to the vector of commitments:
2133
+ * \f[
2134
+ * f_0, \ldots, f_{m-1}, f_{\text{shift}, 0}, \ldots, f_{\text{shift}, k-1}
2135
+ * \f]
2136
+ *
2137
+ * Simultaneously, the evaluation of the multilinear polynomial
2138
+ * \f[
2139
+ * \sum \rho^i \cdot f_i + \sum \rho^{i+k} \cdot f_{\text{shift}, i}
2140
+ * \f]
2141
+ * at the challenge point \f$ (u_0,\ldots, u_{n-1}) \f$ is computed.
2142
+ *
2143
+ * This approach minimizes the number of iterations over the commitments to multilinear polynomials
2144
+ * and eliminates the need to store the powers of \f$ \rho \f$.
2145
+ */
2146
+ mem.batchedEvaluation = proof.geminiMaskingEval;
2147
+ mem.batchingChallenge = tp.rho;
2148
+ mem.unshiftedScalarNeg = mem.unshiftedScalar.neg();
2149
+ mem.shiftedScalarNeg = mem.shiftedScalar.neg();
2150
+
2151
+ scalars[1] = mem.unshiftedScalarNeg;
2152
+ for (uint256 i = 0; i < NUMBER_UNSHIFTED; ++i) {
2153
+ scalars[i + 2] = mem.unshiftedScalarNeg * mem.batchingChallenge;
2154
+ mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i] * mem.batchingChallenge);
1727
2155
  mem.batchingChallenge = mem.batchingChallenge * tp.rho;
1728
2156
  }
1729
2157
  // g commitments are accumulated at r
1730
- for (uint256 i = NUMBER_UNSHIFTED + 1; i <= NUMBER_OF_ENTITIES; ++i) {
1731
- scalars[i] = mem.shiftedScalar.neg() * mem.batchingChallenge;
1732
- mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i - 1] * mem.batchingChallenge);
2158
+ // For each of the to be shifted commitments perform the shift in place by
2159
+ // adding to the unshifted value.
2160
+ // We do so, as the values are to be used in batchMul later, and as
2161
+ // `a * c + b * c = (a + b) * c` this will allow us to reduce memory and compute.
2162
+ // Applied to w1, w2, w3, w4 and zPerm
2163
+ for (uint256 i = 0; i < NUMBER_TO_BE_SHIFTED; ++i) {
2164
+ uint256 scalarOff = i + SHIFTED_COMMITMENTS_START;
2165
+ uint256 evaluationOff = i + NUMBER_UNSHIFTED;
2166
+
2167
+ scalars[scalarOff] = scalars[scalarOff] + (mem.shiftedScalarNeg * mem.batchingChallenge);
2168
+ mem.batchedEvaluation =
2169
+ mem.batchedEvaluation + (proof.sumcheckEvaluations[evaluationOff] * mem.batchingChallenge);
1733
2170
  mem.batchingChallenge = mem.batchingChallenge * tp.rho;
1734
2171
  }
1735
2172
 
1736
- commitments[1] = vk.qm;
1737
- commitments[2] = vk.qc;
1738
- commitments[3] = vk.ql;
1739
- commitments[4] = vk.qr;
1740
- commitments[5] = vk.qo;
1741
- commitments[6] = vk.q4;
1742
- commitments[7] = vk.qLookup;
1743
- commitments[8] = vk.qArith;
1744
- commitments[9] = vk.qDeltaRange;
1745
- commitments[10] = vk.qElliptic;
1746
- commitments[11] = vk.qAux;
1747
- commitments[12] = vk.qPoseidon2External;
1748
- commitments[13] = vk.qPoseidon2Internal;
1749
- commitments[14] = vk.s1;
1750
- commitments[15] = vk.s2;
1751
- commitments[16] = vk.s3;
1752
- commitments[17] = vk.s4;
1753
- commitments[18] = vk.id1;
1754
- commitments[19] = vk.id2;
1755
- commitments[20] = vk.id3;
1756
- commitments[21] = vk.id4;
1757
- commitments[22] = vk.t1;
1758
- commitments[23] = vk.t2;
1759
- commitments[24] = vk.t3;
1760
- commitments[25] = vk.t4;
1761
- commitments[26] = vk.lagrangeFirst;
1762
- commitments[27] = vk.lagrangeLast;
2173
+ commitments[1] = proof.geminiMaskingPoly;
2174
+
2175
+ commitments[2] = vk.qm;
2176
+ commitments[3] = vk.qc;
2177
+ commitments[4] = vk.ql;
2178
+ commitments[5] = vk.qr;
2179
+ commitments[6] = vk.qo;
2180
+ commitments[7] = vk.q4;
2181
+ commitments[8] = vk.qLookup;
2182
+ commitments[9] = vk.qArith;
2183
+ commitments[10] = vk.qDeltaRange;
2184
+ commitments[11] = vk.qElliptic;
2185
+ commitments[12] = vk.qMemory;
2186
+ commitments[13] = vk.qNnf;
2187
+ commitments[14] = vk.qPoseidon2External;
2188
+ commitments[15] = vk.qPoseidon2Internal;
2189
+ commitments[16] = vk.s1;
2190
+ commitments[17] = vk.s2;
2191
+ commitments[18] = vk.s3;
2192
+ commitments[19] = vk.s4;
2193
+ commitments[20] = vk.id1;
2194
+ commitments[21] = vk.id2;
2195
+ commitments[22] = vk.id3;
2196
+ commitments[23] = vk.id4;
2197
+ commitments[24] = vk.t1;
2198
+ commitments[25] = vk.t2;
2199
+ commitments[26] = vk.t3;
2200
+ commitments[27] = vk.t4;
2201
+ commitments[28] = vk.lagrangeFirst;
2202
+ commitments[29] = vk.lagrangeLast;
1763
2203
 
1764
2204
  // Accumulate proof points
1765
- commitments[28] = convertProofPoint(proof.w1);
1766
- commitments[29] = convertProofPoint(proof.w2);
1767
- commitments[30] = convertProofPoint(proof.w3);
1768
- commitments[31] = convertProofPoint(proof.w4);
1769
- commitments[32] = convertProofPoint(proof.zPerm);
1770
- commitments[33] = convertProofPoint(proof.lookupInverses);
1771
- commitments[34] = convertProofPoint(proof.lookupReadCounts);
1772
- commitments[35] = convertProofPoint(proof.lookupReadTags);
1773
-
1774
- // to be Shifted
1775
- commitments[36] = convertProofPoint(proof.w1);
1776
- commitments[37] = convertProofPoint(proof.w2);
1777
- commitments[38] = convertProofPoint(proof.w3);
1778
- commitments[39] = convertProofPoint(proof.w4);
1779
- commitments[40] = convertProofPoint(proof.zPerm);
2205
+ commitments[30] = proof.w1;
2206
+ commitments[31] = proof.w2;
2207
+ commitments[32] = proof.w3;
2208
+ commitments[33] = proof.w4;
2209
+ commitments[34] = proof.zPerm;
2210
+ commitments[35] = proof.lookupInverses;
2211
+ commitments[36] = proof.lookupReadCounts;
2212
+ commitments[37] = proof.lookupReadTags;
2213
+
2214
+ /* Batch gemini claims from the prover
2215
+ * place the commitments to gemini aᵢ to the vector of commitments, compute the contributions from
2216
+ * aᵢ(−r²ⁱ) for i=1, … , n−1 to the constant term accumulator, add corresponding scalars
2217
+ *
2218
+ * 1. Moves the vector
2219
+ * \f[
2220
+ * \left( \text{com}(A_1), \text{com}(A_2), \ldots, \text{com}(A_{n-1}) \right)
2221
+ * \f]
2222
+ * to the 'commitments' vector.
2223
+ *
2224
+ * 2. Computes the scalars:
2225
+ * \f[
2226
+ * \frac{\nu^{2}}{z + r^2}, \frac{\nu^3}{z + r^4}, \ldots, \frac{\nu^{n-1}}{z + r^{2^{n-1}}}
2227
+ * \f]
2228
+ * and places them into the 'scalars' vector.
2229
+ *
2230
+ * 3. Accumulates the summands of the constant term:
2231
+ * \f[
2232
+ * \sum_{i=2}^{n-1} \frac{\nu^{i} \cdot A_i(-r^{2^i})}{z + r^{2^i}}
2233
+ * \f]
2234
+ * and adds them to the 'constant_term_accumulator'.
2235
+ */
1780
2236
 
1781
2237
  // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator:
1782
- // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., logN - 1
1783
- Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations(
2238
+ // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., $LOG_N - 1
2239
+ Fr[] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations(
1784
2240
  tp.sumCheckUChallenges,
1785
2241
  mem.batchedEvaluation,
1786
2242
  proof.geminiAEvaluations,
1787
2243
  powers_of_evaluation_challenge,
1788
- logN
2244
+ $LOG_N
1789
2245
  );
1790
2246
 
1791
- // Compute the Shplonk constant term contributions from A₀(±r)
1792
2247
  mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator;
1793
2248
  mem.constantTermAccumulator =
1794
2249
  mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator);
2250
+
1795
2251
  mem.batchingChallenge = tp.shplonkNu.sqr();
2252
+ uint256 boundary = NUMBER_UNSHIFTED + 2;
1796
2253
 
1797
- // Compute Shplonk constant term contributions from Aₗ(±r^{2ˡ}) for l = 1, ..., m-1;
2254
+ // Compute Shplonk constant term contributions from Aₗ(± r^{2ˡ}) for l = 1, ..., m-1;
1798
2255
  // Compute scalar multipliers for each fold commitment
1799
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) {
1800
- bool dummy_round = i >= (logN - 1);
2256
+ for (uint256 i = 0; i < $LOG_N - 1; ++i) {
2257
+ bool dummy_round = i >= ($LOG_N - 1);
1801
2258
 
1802
2259
  if (!dummy_round) {
1803
2260
  // Update inverted denominators
@@ -1807,57 +2264,150 @@ abstract contract BaseHonkVerifier is IVerifier {
1807
2264
  // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ]
1808
2265
  mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator;
1809
2266
  mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator;
1810
- // [Aₗ] is multiplied by -v^{2l}/(z-r^{2^l}) - v^{2l+1} /(z+ r^{2^l})
1811
- scalars[NUMBER_OF_ENTITIES + 1 + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg();
2267
+ scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg();
1812
2268
 
1813
2269
  // Accumulate the const term contribution given by
1814
2270
  // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l})
1815
2271
  Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1];
1816
2272
  accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1];
1817
2273
  mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution;
1818
- // Update the running power of v
1819
- mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu;
1820
2274
  }
2275
+ // Update the running power of v
2276
+ mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu;
2277
+
2278
+ commitments[boundary + i] = proof.geminiFoldComms[i];
2279
+ }
2280
+
2281
+ boundary += $LOG_N - 1;
2282
+
2283
+ // Finalize the batch opening claim
2284
+ mem.denominators[0] = Fr.wrap(1).div(tp.shplonkZ - tp.geminiR);
2285
+ mem.denominators[1] = Fr.wrap(1).div(tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR);
2286
+ mem.denominators[2] = mem.denominators[0];
2287
+ mem.denominators[3] = mem.denominators[0];
2288
+
2289
+ mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu;
2290
+ for (uint256 i = 0; i < LIBRA_EVALUATIONS; i++) {
2291
+ Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge;
2292
+ mem.batchingScalars[i] = scalingFactor.neg();
2293
+ mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu;
2294
+ mem.constantTermAccumulator = mem.constantTermAccumulator + scalingFactor * proof.libraPolyEvals[i];
2295
+ }
2296
+ scalars[boundary] = mem.batchingScalars[0];
2297
+ scalars[boundary + 1] = mem.batchingScalars[1] + mem.batchingScalars[2];
2298
+ scalars[boundary + 2] = mem.batchingScalars[3];
2299
+
2300
+ for (uint256 i = 0; i < LIBRA_COMMITMENTS; i++) {
2301
+ commitments[boundary++] = proof.libraCommitments[i];
2302
+ }
1821
2303
 
1822
- commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]);
2304
+ commitments[boundary] = Honk.G1Point({x: 1, y: 2});
2305
+ scalars[boundary++] = mem.constantTermAccumulator;
2306
+
2307
+ if (!checkEvalsConsistency(proof.libraPolyEvals, tp.geminiR, tp.sumCheckUChallenges, proof.libraEvaluation)) {
2308
+ revert ConsistencyCheckFailed();
1823
2309
  }
1824
2310
 
1825
- // Finalise the batch opening claim
1826
- commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = Honk.G1Point({x: 1, y: 2});
1827
- scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = mem.constantTermAccumulator;
2311
+ Honk.G1Point memory quotient_commitment = proof.kzgQuotient;
2312
+
2313
+ commitments[boundary] = quotient_commitment;
2314
+ scalars[boundary] = tp.shplonkZ; // evaluation challenge
1828
2315
 
1829
- Honk.G1Point memory quotient_commitment = convertProofPoint(proof.kzgQuotient);
2316
+ PairingInputs memory pair;
2317
+ pair.P_0 = batchMul(commitments, scalars);
2318
+ pair.P_1 = negateInplace(quotient_commitment);
1830
2319
 
1831
- commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 1] = quotient_commitment;
1832
- scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 1] = tp.shplonkZ; // evaluation challenge
2320
+ // Aggregate pairing points
2321
+ Fr recursionSeparator = generateRecursionSeparator(proof.pairingPointObject, pair.P_0, pair.P_1);
2322
+ (Honk.G1Point memory P_0_other, Honk.G1Point memory P_1_other) =
2323
+ convertPairingPointsToG1(proof.pairingPointObject);
1833
2324
 
1834
- Honk.G1Point memory P_0 = batchMul(commitments, scalars);
1835
- Honk.G1Point memory P_1 = negateInplace(quotient_commitment);
2325
+ // Validate the points from the proof are on the curve
2326
+ validateOnCurve(P_0_other);
2327
+ validateOnCurve(P_1_other);
1836
2328
 
1837
- return pairing(P_0, P_1);
2329
+ // accumulate with aggregate points in proof
2330
+ pair.P_0 = mulWithSeperator(pair.P_0, P_0_other, recursionSeparator);
2331
+ pair.P_1 = mulWithSeperator(pair.P_1, P_1_other, recursionSeparator);
2332
+
2333
+ return pairing(pair.P_0, pair.P_1);
2334
+ }
2335
+
2336
+ struct SmallSubgroupIpaIntermediates {
2337
+ Fr[SUBGROUP_SIZE] challengePolyLagrange;
2338
+ Fr challengePolyEval;
2339
+ Fr lagrangeFirst;
2340
+ Fr lagrangeLast;
2341
+ Fr rootPower;
2342
+ Fr[SUBGROUP_SIZE] denominators; // this has to disappear
2343
+ Fr diff;
2344
+ }
2345
+
2346
+ function checkEvalsConsistency(
2347
+ Fr[LIBRA_EVALUATIONS] memory libraPolyEvals,
2348
+ Fr geminiR,
2349
+ Fr[CONST_PROOF_SIZE_LOG_N] memory uChallenges,
2350
+ Fr libraEval
2351
+ ) internal view returns (bool check) {
2352
+ Fr one = Fr.wrap(1);
2353
+ Fr vanishingPolyEval = geminiR.pow(SUBGROUP_SIZE) - one;
2354
+ if (vanishingPolyEval == Fr.wrap(0)) {
2355
+ revert GeminiChallengeInSubgroup();
2356
+ }
2357
+
2358
+ SmallSubgroupIpaIntermediates memory mem;
2359
+ mem.challengePolyLagrange[0] = one;
2360
+ for (uint256 round = 0; round < $LOG_N; round++) {
2361
+ uint256 currIdx = 1 + LIBRA_UNIVARIATES_LENGTH * round;
2362
+ mem.challengePolyLagrange[currIdx] = one;
2363
+ for (uint256 idx = currIdx + 1; idx < currIdx + LIBRA_UNIVARIATES_LENGTH; idx++) {
2364
+ mem.challengePolyLagrange[idx] = mem.challengePolyLagrange[idx - 1] * uChallenges[round];
2365
+ }
2366
+ }
2367
+
2368
+ mem.rootPower = one;
2369
+ mem.challengePolyEval = Fr.wrap(0);
2370
+ for (uint256 idx = 0; idx < SUBGROUP_SIZE; idx++) {
2371
+ mem.denominators[idx] = mem.rootPower * geminiR - one;
2372
+ mem.denominators[idx] = mem.denominators[idx].invert();
2373
+ mem.challengePolyEval = mem.challengePolyEval + mem.challengePolyLagrange[idx] * mem.denominators[idx];
2374
+ mem.rootPower = mem.rootPower * SUBGROUP_GENERATOR_INVERSE;
2375
+ }
2376
+
2377
+ Fr numerator = vanishingPolyEval * Fr.wrap(SUBGROUP_SIZE).invert();
2378
+ mem.challengePolyEval = mem.challengePolyEval * numerator;
2379
+ mem.lagrangeFirst = mem.denominators[0] * numerator;
2380
+ mem.lagrangeLast = mem.denominators[SUBGROUP_SIZE - 1] * numerator;
2381
+
2382
+ mem.diff = mem.lagrangeFirst * libraPolyEvals[2];
2383
+
2384
+ mem.diff = mem.diff
2385
+ + (geminiR - SUBGROUP_GENERATOR_INVERSE)
2386
+ * (libraPolyEvals[1] - libraPolyEvals[2] - libraPolyEvals[0] * mem.challengePolyEval);
2387
+ mem.diff = mem.diff + mem.lagrangeLast * (libraPolyEvals[2] - libraEval) - vanishingPolyEval * libraPolyEvals[3];
2388
+
2389
+ check = mem.diff == Fr.wrap(0);
1838
2390
  }
1839
2391
 
1840
2392
  // This implementation is the same as above with different constants
1841
- function batchMul(
1842
- Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory base,
1843
- Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars
1844
- ) internal view returns (Honk.G1Point memory result) {
1845
- uint256 limit = NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2;
2393
+ function batchMul(Honk.G1Point[] memory base, Fr[] memory scalars)
2394
+ internal
2395
+ view
2396
+ returns (Honk.G1Point memory result)
2397
+ {
2398
+ uint256 limit = NUMBER_UNSHIFTED + $LOG_N + LIBRA_COMMITMENTS + 3;
2399
+
2400
+ // Validate all points are on the curve
2401
+ for (uint256 i = 0; i < limit; ++i) {
2402
+ validateOnCurve(base[i]);
2403
+ }
2404
+
2405
+ bool success = true;
1846
2406
  assembly {
1847
- let success := 0x01
1848
2407
  let free := mload(0x40)
1849
2408
 
1850
- // Write the original into the accumulator
1851
- // Load into memory for ecMUL, leave offset for eccAdd result
1852
- // base is an array of pointers, so we have to dereference them
1853
- mstore(add(free, 0x40), mload(mload(base)))
1854
- mstore(add(free, 0x60), mload(add(0x20, mload(base))))
1855
- // Add scalar
1856
- mstore(add(free, 0x80), mload(scalars))
1857
- success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, free, 0x40))
1858
-
1859
2409
  let count := 0x01
1860
- for {} lt(count, limit) { count := add(count, 1) } {
2410
+ for {} lt(count, add(limit, 1)) { count := add(count, 1) } {
1861
2411
  // Get loop offsets
1862
2412
  let base_base := add(base, mul(count, 0x20))
1863
2413
  let scalar_base := add(scalars, mul(count, 0x20))
@@ -1872,14 +2422,16 @@ abstract contract BaseHonkVerifier is IVerifier {
1872
2422
  success := and(success, staticcall(gas(), 6, free, 0x80, free, 0x40))
1873
2423
  }
1874
2424
 
1875
- // Return the result - i hate this
2425
+ // Return the result
1876
2426
  mstore(result, mload(free))
1877
2427
  mstore(add(result, 0x20), mload(add(free, 0x20)))
1878
2428
  }
2429
+
2430
+ require(success, ShpleminiFailed());
1879
2431
  }
1880
2432
  }
1881
2433
 
1882
- contract HonkVerifier is BaseHonkVerifier(N, LOG_N, NUMBER_OF_PUBLIC_INPUTS) {
2434
+ contract HonkVerifier is BaseZKHonkVerifier(N, LOG_N, VK_HASH, NUMBER_OF_PUBLIC_INPUTS) {
1883
2435
  function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) {
1884
2436
  return HonkVerificationKey.loadVerificationKey();
1885
2437
  }