@crisp-e3/contracts 0.2.2-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 = 16;
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(16),
15
+ circuitSize: uint256(262144),
16
+ logCircuitSize: uint256(18),
17
+ publicInputsSize: uint256(2066),
17
18
  ql: Honk.G1Point({
18
- x: uint256(0x13ab223ff59cd43e0728277b3e37bce97e3d2faac23f2b3311d8a30a44e25963),
19
- y: uint256(0x16f019597ce96b3e75f6ba1c88a2ca4d229090e158eb668690748f9dbe53d557)
19
+ x: uint256(0x19234e8b486fc9d552cc3ff76f2c34bfbf6e26b2e9eb02fb15f8fe85990cb187),
20
+ y: uint256(0x1c444396f3a0984b7f94fcee1df7f5e4e44cfe53399e648f0bcebe02000a087e)
20
21
  }),
21
22
  qr: Honk.G1Point({
22
- x: uint256(0x0efc1c7316fb670707e58edc7b3b27311d1885a1c991a07b33867c684a9a863c),
23
- y: uint256(0x174f93332ed828e0bef2437d6db802d5126ebab2c3702e8974c6a4ae0646c0c2)
23
+ x: uint256(0x12ff83ae9eb2624de078e8611c08730ab34efcf794202d911d57e7dd8630fa38),
24
+ y: uint256(0x029719af50ddaa8504413a7393b1416a46f70bcdfe3d9d954da57ebbd3c30b38)
24
25
  }),
25
26
  qo: Honk.G1Point({
26
- x: uint256(0x208152ab37453ed055b7108a1424e41ac9e878722aa8ef880c6c012d21eef3d5),
27
- y: uint256(0x1f7dcf9351580536e0fff33cb7b13fb3b0609f0f38c309935a6324959ef64338)
27
+ x: uint256(0x23b949c0019499d2f7456111da69b3b058df2a7ae07482c378b4decf61b6dcd9),
28
+ y: uint256(0x13782bc42aeb4b804e0965f606f11edcb28229238ddbb171eb96b300c881e227)
28
29
  }),
29
30
  q4: Honk.G1Point({
30
- x: uint256(0x0963ddfd632aedb1ebae9f7f3ae7ef217ff9bdf5d5dee30d1f0425d7e5d598b1),
31
- y: uint256(0x220a29354f7f15a3a56faea2719c51fd96b0bc9bb5be5278cc18e4a70b73daec)
31
+ x: uint256(0x2bef4c83fcfe7adf69fbce3ef3379a4c66a7368b3b79920234d588b485c48fe8),
32
+ y: uint256(0x1490ebd0bee5ec6101b0c16dfbf19b22be7ed060dfcd1aec96e9cd767ae36bdc)
32
33
  }),
33
34
  qm: Honk.G1Point({
34
- x: uint256(0x13c6f463efbfdbb1f61e4d88750781b6739363c7892f9833226d65c0ccd9033e),
35
- y: uint256(0x1a46391907c3fb9562fa563bab195d093cc843ede63f936b25344901919d90db)
35
+ x: uint256(0x0c82cc6a2a2cef657c3bd1bedd66c4b4f38289783e19989fc7649a4109474509),
36
+ y: uint256(0x0587d5ba891a52b1285ae0a203288c53f85abee00d0a16de2fcadd3d512146a4)
36
37
  }),
37
38
  qc: Honk.G1Point({
38
- x: uint256(0x1bb538b0a6019118e246dce49852f4bdbcd60fb4150833dafc064b1a8a73e8e5),
39
- y: uint256(0x2969a444b671dd94a764dbd631698886cc3b2e64750c2c4143c6736fa7c56845)
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(0x1928e8e9fee021507d02bcd30412ce506a543e67a85bee951d8af25432cf1e2d),
43
- y: uint256(0x258bf8ef04faf434cc77fe4edaffcc94e6013df01f85ca64260d5d7099280381)
47
+ x: uint256(0x2d41b85dcf0f1defc732bc240d3d709df3475b27fdd10349446282c88c7b93c6),
48
+ y: uint256(0x2de3a73eef194dc3eac369c70160d7fea3941a89ee90d40474f4c0cc5fdbea48)
44
49
  }),
45
50
  qDeltaRange: Honk.G1Point({
46
- x: uint256(0x01dbbbd0cd1b7aa0b578c58d34b271245b64061ef676ef15e092b3089a54cb24),
47
- y: uint256(0x1f1bfae9f9c59de7326795e9f089c7bbbdb1925f439b29206c58b90f624ff057)
51
+ x: uint256(0x0b8cdcf81182771897cdd149f27f9c48e645e17e27898dd978458066a71f65ba),
52
+ y: uint256(0x0a2039dc6d85835f05ea90414529d4965581f28ecc322af2846eb08cc97f3b55)
48
53
  }),
49
54
  qElliptic: Honk.G1Point({
50
- x: uint256(0x0daade853bee6788e93755b59e0da87732527349b02c44a04c71c0facc512df0),
51
- y: uint256(0x08d2431b4246dde4c512fef36fd2057f756fa86df9437b82499788521accab1e)
55
+ x: uint256(0x2e68245b183738e5639624c9d9214055ab2245566faa714c8618fcfc294dde76),
56
+ y: uint256(0x1c0de69c49bf59a98400d7b9ea8677d66a562ace631377b3f2ed21672a8b4174)
52
57
  }),
53
- qAux: Honk.G1Point({
54
- x: uint256(0x091d75c333a546baa162025fc5413bd6a15b73b744bff710a75299a9b1cbb11e),
55
- y: uint256(0x160cd0464b1e360218bb120bf522b2f4c51564750d5acce626d87dadd594ca5e)
58
+ qMemory: Honk.G1Point({
59
+ x: uint256(0x25a52f5a8f82e49523f6ac03d7bffbae8d7bf778d2da64388e08db5685642188),
60
+ y: uint256(0x1ab62a935611f307a8d45f4a61e18efaa432cb441f2d37da9a2d3439f5773e70)
56
61
  }),
57
- qLookup: Honk.G1Point({
58
- x: uint256(0x0d8127977a1a35c9a0d79cb984e7c146cf55d0dcfffed4fe47ba792d80630a57),
59
- y: uint256(0x29a459a12da1ff349a61bc22f74ccf21003c6023d6c2eacfff820f034ca4c4d0)
62
+ qNnf: Honk.G1Point({
63
+ x: uint256(0x2b47e338c9cc9f6c8dfd806f4ddc14bb8a915c6ca26797edd1ce653354efe0ca),
64
+ y: uint256(0x0b0ab523e1297dba7d2b3082e52e970643c65cde7435c743a299e22bb425dc85)
60
65
  }),
61
66
  qPoseidon2External: Honk.G1Point({
62
- x: uint256(0x2e7849b38119f1afb8aefdac89a181e566c5be05150575534bb783802819ae88),
63
- y: uint256(0x039cda5b4478a254bcd6b192d1c67b3ac2143bac86b241b08dc50e0a8d23ceca)
67
+ x: uint256(0x15b800e958d51996ac94950c9edaca0e78119205cdd47fbf3c649e52ac65f14a),
68
+ y: uint256(0x1156eb0be91bc47c7bc23018abd75c52dd036bfdd9fcd52a67132c541ca6e1ca)
64
69
  }),
65
70
  qPoseidon2Internal: Honk.G1Point({
66
- x: uint256(0x11bca67681de3ea476550a63f2b35b177d7c0fc83eeaf5534832e05e67d1477f),
67
- y: uint256(0x258998c74d0c585178ed727548943a4497be15d53bb82603a365a8fa859cbb2c)
71
+ x: uint256(0x186115ffb59ed7ca6d2dc7db68b92788824c6eb44f6741be0791e44812c3c16c),
72
+ y: uint256(0x0b595b8659174ce4759801569ef9ee7acead4fa8de75c4bdf4c5d0db00b98258)
68
73
  }),
69
74
  s1: Honk.G1Point({
70
- x: uint256(0x183047a917ca53516ae710d178cdb35c17b58d4cf6bebe73ab84edc260969dac),
71
- y: uint256(0x16fa136788614a8d2a8bbb8a40742a2ec88200a7557899dc22eebb9917f39e79)
75
+ x: uint256(0x14dd269b9e3c3567adda508de65295995c9a7d0f983ce31fb680f43cade82460),
76
+ y: uint256(0x1f9ddc09be536a402af0ad294cce79bae970a35e68fd1dce90c8dc6a59592fbc)
72
77
  }),
73
78
  s2: Honk.G1Point({
74
- x: uint256(0x2337ae7661f0d0a9cc43523f73e3ccca7f2e98e6de8eff0caef5a2e38bac8050),
75
- y: uint256(0x2dbdd39e65dccf475c00f58e0eb06a9be49797a86404bc850eb56fc27a4ca8eb)
79
+ x: uint256(0x20e437b79e848e9eab0cd5e29b001e6975428ef03b1d1eaf3dfd7364c212ef00),
80
+ y: uint256(0x272039cad2b791d53addc1016b377443fca208ab510a04e3379fd32724242980)
76
81
  }),
77
82
  s3: Honk.G1Point({
78
- x: uint256(0x15569d9f85dc5d0f5d1e8f18ae7eea3b909c7e68626c609b33e7959bb9918648),
79
- y: uint256(0x2d6729e1c9a15ba58ba3cbe46e8c97880014e3f126b17a1b300715cd449be8b1)
83
+ x: uint256(0x00cfcc45e38f6dfe9147cee1aed3554bbc43def92142e6b2973e8da8ca43e494),
84
+ y: uint256(0x04830aca514c7478869b6679d074f80e14096c645bc57faa7061224e22abead2)
80
85
  }),
81
86
  s4: Honk.G1Point({
82
- x: uint256(0x062d199e2a3abdc6bd9c51c9e304859f1c52c29a07449cb515a36ad7ec377240),
83
- y: uint256(0x28000e3b5fe7da7621520bab4c69e5141c6d6d4dc542a8333748d76a07df71b2)
87
+ x: uint256(0x1f16f65c5b2f8202aa15fad48ffb33fb112e5c6e59d7677710f21785a073abe9),
88
+ y: uint256(0x0496adc461ec7de90ea1196b3a727549d7767ec2a58857f7f91fd65d94eccea0)
84
89
  }),
85
90
  t1: Honk.G1Point({
86
- x: uint256(0x0d64abbea744f03212f1bf39e9d9c693424fa71ab2235b3f501ac3bc615e8577),
87
- y: uint256(0x03abf1a9c83fe43033856e016b6940b2cde1a7438d4150d5f6343e54e692544d)
91
+ x: uint256(0x08a5ba822823e5f21f5585f7d90f070aaad388561d817362c819850cccf82580),
92
+ y: uint256(0x2d296fb3ec6c283d6f822a7e7f9edbe350516a4f9cba53be9dc8ac6240d0559c)
88
93
  }),
89
94
  t2: Honk.G1Point({
90
- x: uint256(0x112dfebe6cfb2e00aeee241e82c6091f7706a596da1ed976801260f85fced62b),
91
- y: uint256(0x0cf123627a5260072ece8c03020a378094ef14d4ecd6fa7787cb92b0ff41e16f)
95
+ x: uint256(0x201b4ffc4068dd22cc3a99a1ef5bc10e2be7841ed934ad5ea5247f992687c29b),
96
+ y: uint256(0x28351d4eacb149a545035052b1b2081b7e8c3ffa751c5bc31483b653f95cb6ca)
92
97
  }),
93
98
  t3: Honk.G1Point({
94
- x: uint256(0x0a7a39e50057960052581f511cb596259f1e1588666bc96a9795c0194676c2a3),
95
- y: uint256(0x18d60133c86a16d9192eaffc8a6ac18ccaf3a7ef9f7a2c2a8c0e04df810193a2)
99
+ x: uint256(0x0d1a271b6b84d9a2d8953885c3b2d13d10aa96a483eeb4c7a41d65c19d69d638),
100
+ y: uint256(0x2a40aaa4bc03f75cbc60cc97a07b3e8885d4c99101b026f18219c82ee71443c4)
96
101
  }),
97
102
  t4: Honk.G1Point({
98
- x: uint256(0x2ced4be26f6936520870ea5f91a46f746098f71fbd39136e72e816fd1ccf3fcb),
99
- y: uint256(0x05e4f50caa7b245e81355a0f8966474c9669792cf09f6b4d807a6604ef93cfba)
103
+ x: uint256(0x18216d5e69c40817c81feefd02de1aa548f7bf9d9ce4d671e96b22f368709ed5),
104
+ y: uint256(0x1e5e5f5acbdcd05a0ebffacea7a5426da9ec26a79cbb95692c9e9a499ff0155a)
100
105
  }),
101
106
  id1: Honk.G1Point({
102
- x: uint256(0x1b4b9477e130161cd3a4dab7b5a107cf6eff7794a4dadef3bc0cdf65ec6aa7e5),
103
- y: uint256(0x1abd71747ef723da70730a348cc041dc13da45be7318091d98b6b9d74c79f399)
107
+ x: uint256(0x247ab7f8180ee4378a3735de2d878287808586b925f8bd965ecce15ef6ff300a),
108
+ y: uint256(0x0dd9fe53e476eb4a851b28f0f73cbd72c5871c0201dad4cbfd1cf78deedff2aa)
104
109
  }),
105
110
  id2: Honk.G1Point({
106
- x: uint256(0x12fab07a701a5614890650c7bb37dade42de520bc6933812670c802fcd5c1a69),
107
- y: uint256(0x29a07f1b4b391180ec8bf71f361f2b1ce53959dbbfdada7bd2578ed270e20b82)
111
+ x: uint256(0x0150fd5a4606ac3ee8dd19c29e1902f8e9770afb38c3c18fce68cb5fea0c2626),
112
+ y: uint256(0x04709d671d3ae053977fe93b3eaeae8d2ff5c11c6e0cea3870cffe08167097a6)
108
113
  }),
109
114
  id3: Honk.G1Point({
110
- x: uint256(0x125c6b504f1acc65b0fb6e30eced8baff778514e407bf588dd108153fbeda5af),
111
- y: uint256(0x15f46d027b762ec2aa4a7d59511d5e17e1e13d4df10eb2a5e9748599045d131b)
115
+ x: uint256(0x009cfbd08c0f2f320b312de7921f17bef30ab4ceeec5eca94c0098abf17b800a),
116
+ y: uint256(0x067b007230035477d184136e9e82536f036afd3cf87243b4a5a99bd7ad703d9f)
112
117
  }),
113
118
  id4: Honk.G1Point({
114
- x: uint256(0x0bbc2d69742f95edbeffe3f80527c6e11e9644918540121093c5244ac6d67737),
115
- y: uint256(0x05780b6e9938c0ff75721918d5a4039840c7b9e2827a02e74845a0b51049794f)
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(0x2616fcd041a9cf147f53b259e2110fc80de4cf4382c39a7f6b75109300489dbd),
123
- y: uint256(0x1329a5245299bcd004a3ba9f7b72bcd050d16cbb6c437cb690343e131697fed8)
127
+ x: uint256(0x2e0e9d25627d4fcd339bece11e5b1a39cec75ceed35718d2c24ed14655390c1e),
128
+ y: uint256(0x0c36d39925655a8f2ce6433139283c38d124e49945ac60294bebde700799cb7c)
124
129
  })
125
130
  });
126
131
  return vk;
@@ -129,157 +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;
275
301
  uint256 constant PAIRING_POINTS_SIZE = 16;
276
302
 
277
- // Alphas are used as relation separators so there should be NUMBER_OF_SUBRELATIONS - 1
278
- uint256 constant NUMBER_OF_ALPHAS = 25;
303
+ uint256 constant FIELD_ELEMENT_SIZE = 0x20;
304
+ uint256 constant GROUP_ELEMENT_SIZE = 0x40;
279
305
 
280
- // Prime field order
281
- uint256 constant Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // EC group order. F_q
282
- 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;
283
308
 
284
309
  // ENUM FOR WIRES
285
310
  enum WIRE {
@@ -293,7 +318,8 @@ enum WIRE {
293
318
  Q_ARITH,
294
319
  Q_RANGE,
295
320
  Q_ELLIPTIC,
296
- Q_AUX,
321
+ Q_MEMORY,
322
+ Q_NNF,
297
323
  Q_POSEIDON2_EXTERNAL,
298
324
  Q_POSEIDON2_INTERNAL,
299
325
  SIGMA_1,
@@ -331,13 +357,6 @@ library Honk {
331
357
  uint256 y;
332
358
  }
333
359
 
334
- struct G1ProofPoint {
335
- uint256 x_0;
336
- uint256 x_1;
337
- uint256 y_0;
338
- uint256 y_1;
339
- }
340
-
341
360
  struct VerificationKey {
342
361
  // Misc Params
343
362
  uint256 circuitSize;
@@ -353,7 +372,8 @@ library Honk {
353
372
  G1Point qLookup; // Lookup
354
373
  G1Point qArith; // Arithmetic widget
355
374
  G1Point qDeltaRange; // Delta Range sort
356
- G1Point qAux; // Auxillary
375
+ G1Point qMemory; // Memory
376
+ G1Point qNnf; // Non-native Field
357
377
  G1Point qElliptic; // Auxillary
358
378
  G1Point qPoseidon2External;
359
379
  G1Point qPoseidon2Internal;
@@ -388,72 +408,105 @@ library Honk {
388
408
  Fr publicInputsDelta;
389
409
  }
390
410
 
391
-
392
411
  struct Proof {
393
412
  // Pairing point object
394
413
  Fr[PAIRING_POINTS_SIZE] pairingPointObject;
395
414
  // Free wires
396
- Honk.G1ProofPoint w1;
397
- Honk.G1ProofPoint w2;
398
- Honk.G1ProofPoint w3;
399
- Honk.G1ProofPoint w4;
415
+ G1Point w1;
416
+ G1Point w2;
417
+ G1Point w3;
418
+ G1Point w4;
400
419
  // Lookup helpers - Permutations
401
- Honk.G1ProofPoint zPerm;
420
+ G1Point zPerm;
402
421
  // Lookup helpers - logup
403
- Honk.G1ProofPoint lookupReadCounts;
404
- Honk.G1ProofPoint lookupReadTags;
405
- Honk.G1ProofPoint lookupInverses;
422
+ G1Point lookupReadCounts;
423
+ G1Point lookupReadTags;
424
+ G1Point lookupInverses;
406
425
  // Sumcheck
407
426
  Fr[BATCHED_RELATION_PARTIAL_LENGTH][CONST_PROOF_SIZE_LOG_N] sumcheckUnivariates;
408
427
  Fr[NUMBER_OF_ENTITIES] sumcheckEvaluations;
409
428
  // Shplemini
410
- Honk.G1ProofPoint[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms;
429
+ G1Point[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms;
411
430
  Fr[CONST_PROOF_SIZE_LOG_N] geminiAEvaluations;
412
- Honk.G1ProofPoint shplonkQ;
413
- Honk.G1ProofPoint kzgQuotient;
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;
460
+ Fr[CONST_PROOF_SIZE_LOG_N] geminiAEvaluations;
461
+ Fr[4] libraPolyEvals;
462
+ G1Point shplonkQ;
463
+ G1Point kzgQuotient;
414
464
  }
415
465
  }
416
466
 
417
- // Transcript library to generate fiat shamir challenges
418
- struct Transcript {
467
+ // ZKTranscript library to generate fiat shamir challenges, the ZK transcript only differest
468
+ struct ZKTranscript {
419
469
  // Oink
420
470
  Honk.RelationParameters relationParameters;
421
471
  Fr[NUMBER_OF_ALPHAS] alphas;
422
472
  Fr[CONST_PROOF_SIZE_LOG_N] gateChallenges;
423
473
  // Sumcheck
474
+ Fr libraChallenge;
424
475
  Fr[CONST_PROOF_SIZE_LOG_N] sumCheckUChallenges;
425
- // Gemini
476
+ // Shplemini
426
477
  Fr rho;
427
478
  Fr geminiR;
428
- // Shplonk
429
479
  Fr shplonkNu;
430
480
  Fr shplonkZ;
481
+ // Derived
482
+ Fr publicInputsDelta;
431
483
  }
432
484
 
433
- library TranscriptLib {
434
- function generateTranscript(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 circuitSize, uint256 publicInputsSize, uint256 pubInputsOffset)
435
- internal
436
- pure
437
- returns (Transcript memory t)
438
- {
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) {
439
493
  Fr previousChallenge;
440
494
  (t.relationParameters, previousChallenge) =
441
- generateRelationParametersChallenges(proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset, previousChallenge);
495
+ generateRelationParametersChallenges(proof, publicInputs, vkHash, publicInputsSize, previousChallenge);
442
496
 
443
497
  (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof);
444
498
 
445
- (t.gateChallenges, previousChallenge) = generateGateChallenges(previousChallenge);
446
-
447
- (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);
448
502
 
449
503
  (t.rho, previousChallenge) = generateRhoChallenge(proof, previousChallenge);
450
504
 
451
- (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge);
505
+ (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge, logN);
452
506
 
453
- (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge);
507
+ (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge, logN);
454
508
 
455
509
  (t.shplonkZ, previousChallenge) = generateShplonkZChallenge(proof, previousChallenge);
456
-
457
510
  return t;
458
511
  }
459
512
 
@@ -466,339 +519,317 @@ library TranscriptLib {
466
519
  }
467
520
 
468
521
  function generateRelationParametersChallenges(
469
- Honk.Proof memory proof,
522
+ Honk.ZKProof memory proof,
470
523
  bytes32[] calldata publicInputs,
471
- uint256 circuitSize,
524
+ uint256 vkHash,
472
525
  uint256 publicInputsSize,
473
- uint256 pubInputsOffset,
474
526
  Fr previousChallenge
475
527
  ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) {
476
528
  (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) =
477
- generateEtaChallenge(proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset);
529
+ generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize);
478
530
 
479
531
  (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof);
480
-
481
532
  }
482
533
 
483
- function generateEtaChallenge(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 circuitSize, uint256 publicInputsSize, uint256 pubInputsOffset)
484
- internal
485
- pure
486
- returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge)
487
- {
488
- bytes32[] memory round0 = new bytes32[](3 + publicInputsSize + 12);
489
- round0[0] = bytes32(circuitSize);
490
- round0[1] = bytes32(publicInputsSize);
491
- round0[2] = bytes32(pubInputsOffset);
492
- // TODO(https://github.com/AztecProtocol/barretenberg/issues/1331): Consider making publicInputsSize not include pairing point object.
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
+
493
543
  for (uint256 i = 0; i < publicInputsSize - PAIRING_POINTS_SIZE; i++) {
494
- round0[3 + i] = bytes32(publicInputs[i]);
544
+ round0[1 + i] = bytes32(publicInputs[i]);
495
545
  }
496
546
  for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) {
497
- round0[3 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]);
547
+ round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]);
498
548
  }
499
549
 
500
550
  // Create the first challenge
501
551
  // Note: w4 is added to the challenge later on
502
- round0[3 + publicInputsSize] = bytes32(proof.w1.x_0);
503
- round0[3 + publicInputsSize + 1] = bytes32(proof.w1.x_1);
504
- round0[3 + publicInputsSize + 2] = bytes32(proof.w1.y_0);
505
- round0[3 + publicInputsSize + 3] = bytes32(proof.w1.y_1);
506
- round0[3 + publicInputsSize + 4] = bytes32(proof.w2.x_0);
507
- round0[3 + publicInputsSize + 5] = bytes32(proof.w2.x_1);
508
- round0[3 + publicInputsSize + 6] = bytes32(proof.w2.y_0);
509
- round0[3 + publicInputsSize + 7] = bytes32(proof.w2.y_1);
510
- round0[3 + publicInputsSize + 8] = bytes32(proof.w3.x_0);
511
- round0[3 + publicInputsSize + 9] = bytes32(proof.w3.x_1);
512
- round0[3 + publicInputsSize + 10] = bytes32(proof.w3.y_0);
513
- 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);
514
558
 
515
559
  previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0)));
516
560
  (eta, etaTwo) = splitChallenge(previousChallenge);
517
561
  previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))));
518
- Fr unused;
519
- (etaThree, unused) = splitChallenge(previousChallenge);
562
+
563
+ (etaThree,) = splitChallenge(previousChallenge);
520
564
  }
521
565
 
522
- function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.Proof memory proof)
566
+ function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.ZKProof memory proof)
523
567
  internal
524
568
  pure
525
569
  returns (Fr beta, Fr gamma, Fr nextPreviousChallenge)
526
570
  {
527
- bytes32[13] memory round1;
571
+ bytes32[7] memory round1;
528
572
  round1[0] = FrLib.toBytes32(previousChallenge);
529
- round1[1] = bytes32(proof.lookupReadCounts.x_0);
530
- round1[2] = bytes32(proof.lookupReadCounts.x_1);
531
- round1[3] = bytes32(proof.lookupReadCounts.y_0);
532
- round1[4] = bytes32(proof.lookupReadCounts.y_1);
533
- round1[5] = bytes32(proof.lookupReadTags.x_0);
534
- round1[6] = bytes32(proof.lookupReadTags.x_1);
535
- round1[7] = bytes32(proof.lookupReadTags.y_0);
536
- round1[8] = bytes32(proof.lookupReadTags.y_1);
537
- round1[9] = bytes32(proof.w4.x_0);
538
- round1[10] = bytes32(proof.w4.x_1);
539
- round1[11] = bytes32(proof.w4.y_0);
540
- 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);
541
579
 
542
580
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round1)));
543
581
  (beta, gamma) = splitChallenge(nextPreviousChallenge);
544
582
  }
545
583
 
546
584
  // Alpha challenges non-linearise the gate contributions
547
- function generateAlphaChallenges(Fr previousChallenge, Honk.Proof memory proof)
585
+ function generateAlphaChallenges(Fr previousChallenge, Honk.ZKProof memory proof)
548
586
  internal
549
587
  pure
550
588
  returns (Fr[NUMBER_OF_ALPHAS] memory alphas, Fr nextPreviousChallenge)
551
589
  {
552
590
  // Generate the original sumcheck alpha 0 by hashing zPerm and zLookup
553
- uint256[9] memory alpha0;
591
+ uint256[5] memory alpha0;
554
592
  alpha0[0] = Fr.unwrap(previousChallenge);
555
- alpha0[1] = proof.lookupInverses.x_0;
556
- alpha0[2] = proof.lookupInverses.x_1;
557
- alpha0[3] = proof.lookupInverses.y_0;
558
- alpha0[4] = proof.lookupInverses.y_1;
559
- alpha0[5] = proof.zPerm.x_0;
560
- alpha0[6] = proof.zPerm.x_1;
561
- alpha0[7] = proof.zPerm.y_0;
562
- 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;
563
597
 
564
598
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(alpha0)));
565
- (alphas[0], alphas[1]) = splitChallenge(nextPreviousChallenge);
599
+ Fr alpha;
600
+ (alpha,) = splitChallenge(nextPreviousChallenge);
566
601
 
567
- for (uint256 i = 1; i < NUMBER_OF_ALPHAS / 2; i++) {
568
- nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(nextPreviousChallenge))));
569
- (alphas[2 * i], alphas[2 * i + 1]) = splitChallenge(nextPreviousChallenge);
570
- }
571
- if (((NUMBER_OF_ALPHAS & 1) == 1) && (NUMBER_OF_ALPHAS > 2)) {
572
- nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(nextPreviousChallenge))));
573
- Fr unused;
574
- (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;
575
606
  }
576
607
  }
577
608
 
578
- function generateGateChallenges(Fr previousChallenge)
609
+ function generateGateChallenges(Fr previousChallenge, uint256 logN)
579
610
  internal
580
611
  pure
581
612
  returns (Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, Fr nextPreviousChallenge)
582
613
  {
583
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
584
- previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))));
585
- Fr unused;
586
- (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];
587
618
  }
588
619
  nextPreviousChallenge = previousChallenge;
589
620
  }
590
621
 
591
- 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)
592
638
  internal
593
639
  pure
594
640
  returns (Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, Fr nextPreviousChallenge)
595
641
  {
596
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
597
- 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;
598
644
  univariateChal[0] = prevChallenge;
599
645
 
600
- for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) {
646
+ for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) {
601
647
  univariateChal[j + 1] = proof.sumcheckUnivariates[i][j];
602
648
  }
603
649
  prevChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(univariateChal)));
604
- Fr unused;
605
- (sumcheckChallenges[i], unused) = splitChallenge(prevChallenge);
650
+
651
+ (sumcheckChallenges[i],) = splitChallenge(prevChallenge);
606
652
  }
607
653
  nextPreviousChallenge = prevChallenge;
608
654
  }
609
655
 
610
- 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)
611
658
  internal
612
659
  pure
613
660
  returns (Fr rho, Fr nextPreviousChallenge)
614
661
  {
615
- Fr[NUMBER_OF_ENTITIES + 1] memory rhoChallengeElements;
616
- rhoChallengeElements[0] = prevChallenge;
617
-
618
- for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) {
619
- 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]);
620
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);
621
682
 
622
683
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(rhoChallengeElements)));
623
- Fr unused;
624
- (rho, unused) = splitChallenge(nextPreviousChallenge);
684
+ (rho,) = splitChallenge(nextPreviousChallenge);
625
685
  }
626
686
 
627
- function generateGeminiRChallenge(Honk.Proof memory proof, Fr prevChallenge)
687
+ function generateGeminiRChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN)
628
688
  internal
629
689
  pure
630
690
  returns (Fr geminiR, Fr nextPreviousChallenge)
631
691
  {
632
- uint256[(CONST_PROOF_SIZE_LOG_N - 1) * 4 + 1] memory gR;
692
+ uint256[] memory gR = new uint256[]((logN - 1) * 2 + 1);
633
693
  gR[0] = Fr.unwrap(prevChallenge);
634
694
 
635
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) {
636
- gR[1 + i * 4] = proof.geminiFoldComms[i].x_0;
637
- gR[2 + i * 4] = proof.geminiFoldComms[i].x_1;
638
- gR[3 + i * 4] = proof.geminiFoldComms[i].y_0;
639
- 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;
640
698
  }
641
699
 
642
700
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(gR)));
643
- Fr unused;
644
- (geminiR, unused) = splitChallenge(nextPreviousChallenge);
701
+
702
+ (geminiR,) = splitChallenge(nextPreviousChallenge);
645
703
  }
646
704
 
647
- function generateShplonkNuChallenge(Honk.Proof memory proof, Fr prevChallenge)
705
+ function generateShplonkNuChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN)
648
706
  internal
649
707
  pure
650
708
  returns (Fr shplonkNu, Fr nextPreviousChallenge)
651
709
  {
652
- uint256[(CONST_PROOF_SIZE_LOG_N) + 1] memory shplonkNuChallengeElements;
710
+ uint256[] memory shplonkNuChallengeElements = new uint256[](logN + 1 + 4);
653
711
  shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge);
654
712
 
655
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
656
- 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++;
657
721
  }
658
722
 
659
723
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkNuChallengeElements)));
660
- Fr unused;
661
- (shplonkNu, unused) = splitChallenge(nextPreviousChallenge);
724
+ (shplonkNu,) = splitChallenge(nextPreviousChallenge);
662
725
  }
663
726
 
664
- function generateShplonkZChallenge(Honk.Proof memory proof, Fr prevChallenge)
727
+ function generateShplonkZChallenge(Honk.ZKProof memory proof, Fr prevChallenge)
665
728
  internal
666
729
  pure
667
730
  returns (Fr shplonkZ, Fr nextPreviousChallenge)
668
731
  {
669
- uint256[5] memory shplonkZChallengeElements;
732
+ uint256[3] memory shplonkZChallengeElements;
670
733
  shplonkZChallengeElements[0] = Fr.unwrap(prevChallenge);
671
734
 
672
- shplonkZChallengeElements[1] = proof.shplonkQ.x_0;
673
- shplonkZChallengeElements[2] = proof.shplonkQ.x_1;
674
- shplonkZChallengeElements[3] = proof.shplonkQ.y_0;
675
- shplonkZChallengeElements[4] = proof.shplonkQ.y_1;
735
+ shplonkZChallengeElements[1] = proof.shplonkQ.x;
736
+ shplonkZChallengeElements[2] = proof.shplonkQ.y;
676
737
 
677
738
  nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkZChallengeElements)));
678
- Fr unused;
679
- (shplonkZ, unused) = splitChallenge(nextPreviousChallenge);
739
+ (shplonkZ,) = splitChallenge(nextPreviousChallenge);
680
740
  }
681
741
 
682
- function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory p) {
683
- // TODO(https://github.com/AztecProtocol/barretenberg/issues/1332): Optimize this away when we finalize.
742
+ function loadProof(bytes calldata proof, uint256 logN) internal pure returns (Honk.ZKProof memory p) {
684
743
  uint256 boundary = 0x0;
685
744
 
686
745
  // Pairing point object
687
746
  for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) {
688
- p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + 0x20]);
689
- boundary += 0x20;
747
+ p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
748
+ boundary += FIELD_ELEMENT_SIZE;
690
749
  }
691
750
  // Commitments
692
- p.w1 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
693
- boundary += 0x80;
694
- p.w2 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
695
- boundary += 0x80;
696
- p.w3 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
697
- boundary += 0x80;
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;
698
757
 
699
758
  // Lookup / Permutation Helper Commitments
700
- p.lookupReadCounts = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
701
- boundary += 0x80;
702
- p.lookupReadTags = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
703
- boundary += 0x80;
704
- p.w4 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
705
- boundary += 0x80;
706
- p.lookupInverses = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
707
- boundary += 0x80;
708
- p.zPerm = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
709
- boundary += 0x80;
710
-
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;
711
774
  // Sumcheck univariates
712
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
713
- for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) {
714
- p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + 0x20]);
715
- 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;
716
779
  }
717
780
  }
781
+
718
782
  // Sumcheck evaluations
719
783
  for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) {
720
- p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]);
721
- boundary += 0x20;
784
+ p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]);
785
+ boundary += FIELD_ELEMENT_SIZE;
722
786
  }
723
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
+
724
800
  // Gemini
725
801
  // Read gemini fold univariates
726
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) {
727
- p.geminiFoldComms[i] = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
728
- 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;
729
805
  }
730
806
 
731
807
  // Read gemini a evaluations
732
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) {
733
- p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]);
734
- 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;
735
816
  }
736
817
 
737
818
  // Shplonk
738
- p.shplonkQ = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
739
- boundary += 0x80;
819
+ p.shplonkQ = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
820
+ boundary += GROUP_ELEMENT_SIZE;
740
821
  // KZG
741
- p.kzgQuotient = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]);
822
+ p.kzgQuotient = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]);
742
823
  }
743
824
  }
744
825
 
745
-
746
- // Fr utility
747
-
748
- function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) {
749
- require(proofSection.length == 0x20, "invalid bytes scalar");
750
- scalar = FrLib.fromBytes32(bytes32(proofSection));
751
- }
752
-
753
- // EC Point utilities
754
- function convertProofPoint(Honk.G1ProofPoint memory input) pure returns (Honk.G1Point memory) {
755
- return Honk.G1Point({x: input.x_0 | (input.x_1 << 136), y: input.y_0 | (input.y_1 << 136)});
756
- }
757
-
758
- function bytesToG1ProofPoint(bytes calldata proofSection) pure returns (Honk.G1ProofPoint memory point) {
759
- require(proofSection.length == 0x80, "invalid bytes point");
760
- point = Honk.G1ProofPoint({
761
- x_0: uint256(bytes32(proofSection[0x00:0x20])),
762
- x_1: uint256(bytes32(proofSection[0x20:0x40])),
763
- y_0: uint256(bytes32(proofSection[0x40:0x60])),
764
- y_1: uint256(bytes32(proofSection[0x60:0x80]))
765
- });
766
- }
767
-
768
- function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) {
769
- point.y = (Q - point.y) % Q;
770
- return point;
771
- }
772
-
773
- function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool) {
774
- bytes memory input = abi.encodePacked(
775
- rhs.x,
776
- rhs.y,
777
- // Fixed G1 point
778
- uint256(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2),
779
- uint256(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed),
780
- uint256(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b),
781
- uint256(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa),
782
- lhs.x,
783
- lhs.y,
784
- // G1 point from VK
785
- uint256(0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1),
786
- uint256(0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0),
787
- uint256(0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4),
788
- uint256(0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55)
789
- );
790
-
791
- (bool success, bytes memory result) = address(0x08).staticcall(input);
792
- bool decodedResult = abi.decode(result, (bool));
793
- return success && decodedResult;
794
- }
795
-
826
+ // Field arithmetic libraries
796
827
 
797
828
  library RelationsLib {
798
829
  Fr internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = Fr.wrap(17); // -(-17)
799
830
 
800
831
  function accumulateRelationEvaluations(
801
- Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations,
832
+ Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations,
802
833
  Honk.RelationParameters memory rp,
803
834
  Fr[NUMBER_OF_ALPHAS] memory alphas,
804
835
  Fr powPartialEval
@@ -811,9 +842,11 @@ library RelationsLib {
811
842
  accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval);
812
843
  accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval);
813
844
  accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval);
814
- accumulateAuxillaryRelation(purportedEvaluations, rp, evaluations, powPartialEval);
845
+ accumulateMemoryRelation(purportedEvaluations, rp, evaluations, powPartialEval);
846
+ accumulateNnfRelation(purportedEvaluations, evaluations, powPartialEval);
815
847
  accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval);
816
848
  accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval);
849
+
817
850
  // batch the subrelations with the alpha challenges to obtain the full honk relation
818
851
  accumulator = scaleAndBatchSubrelations(evaluations, alphas);
819
852
  }
@@ -832,6 +865,7 @@ library RelationsLib {
832
865
  * Ultra Arithmetic Relation
833
866
  *
834
867
  */
868
+
835
869
  function accumulateArithmeticRelation(
836
870
  Fr[NUMBER_OF_ENTITIES] memory p,
837
871
  Fr[NUMBER_OF_SUBRELATIONS] memory evals,
@@ -845,7 +879,7 @@ library RelationsLib {
845
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;
846
880
  accum = accum + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R))
847
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);
848
- 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);
849
883
  accum = accum * q_arith;
850
884
  accum = accum * domainSep;
851
885
  evals[0] = accum;
@@ -855,7 +889,7 @@ library RelationsLib {
855
889
  {
856
890
  Fr accum = wire(p, WIRE.W_L) + wire(p, WIRE.W_4) - wire(p, WIRE.W_L_SHIFT) + wire(p, WIRE.Q_M);
857
891
  accum = accum * (q_arith - Fr.wrap(2));
858
- accum = accum * (q_arith - Fr.wrap(1));
892
+ accum = accum * (q_arith - ONE);
859
893
  accum = accum * q_arith;
860
894
  accum = accum * domainSep;
861
895
  evals[1] = accum;
@@ -946,8 +980,13 @@ library RelationsLib {
946
980
  // Inverse
947
981
  Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * read_inverse - wire(p, WIRE.LOOKUP_READ_COUNTS) * write_inverse;
948
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
+
949
987
  evals[4] = accumulatorNone;
950
988
  evals[5] = accumulatorOne;
989
+ evals[6] = read_tag_boolean_relation * domainSep;
951
990
  }
952
991
 
953
992
  function accumulateDeltaRangeRelation(
@@ -955,9 +994,9 @@ library RelationsLib {
955
994
  Fr[NUMBER_OF_SUBRELATIONS] memory evals,
956
995
  Fr domainSep
957
996
  ) internal pure {
958
- Fr minus_one = Fr.wrap(0) - Fr.wrap(1);
959
- Fr minus_two = Fr.wrap(0) - Fr.wrap(2);
960
- 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);
961
1000
 
962
1001
  // Compute wire differences
963
1002
  Fr delta_1 = wire(p, WIRE.W_R) - wire(p, WIRE.W_L);
@@ -973,7 +1012,7 @@ library RelationsLib {
973
1012
  acc = acc * (delta_1 + minus_three);
974
1013
  acc = acc * wire(p, WIRE.Q_RANGE);
975
1014
  acc = acc * domainSep;
976
- evals[6] = acc;
1015
+ evals[7] = acc;
977
1016
  }
978
1017
 
979
1018
  // Contribution 7
@@ -984,7 +1023,7 @@ library RelationsLib {
984
1023
  acc = acc * (delta_2 + minus_three);
985
1024
  acc = acc * wire(p, WIRE.Q_RANGE);
986
1025
  acc = acc * domainSep;
987
- evals[7] = acc;
1026
+ evals[8] = acc;
988
1027
  }
989
1028
 
990
1029
  // Contribution 8
@@ -995,7 +1034,7 @@ library RelationsLib {
995
1034
  acc = acc * (delta_3 + minus_three);
996
1035
  acc = acc * wire(p, WIRE.Q_RANGE);
997
1036
  acc = acc * domainSep;
998
- evals[8] = acc;
1037
+ evals[9] = acc;
999
1038
  }
1000
1039
 
1001
1040
  // Contribution 9
@@ -1006,7 +1045,7 @@ library RelationsLib {
1006
1045
  acc = acc * (delta_4 + minus_three);
1007
1046
  acc = acc * wire(p, WIRE.Q_RANGE);
1008
1047
  acc = acc * domainSep;
1009
- evals[9] = acc;
1048
+ evals[10] = acc;
1010
1049
  }
1011
1050
  }
1012
1051
 
@@ -1053,7 +1092,7 @@ library RelationsLib {
1053
1092
  x_add_identity = x_add_identity * x_diff * x_diff;
1054
1093
  x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2;
1055
1094
 
1056
- 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);
1057
1096
  }
1058
1097
 
1059
1098
  // Contribution 11 point addition, x-coordinate check
@@ -1062,7 +1101,7 @@ library RelationsLib {
1062
1101
  Fr y1_plus_y3 = ep.y_1 + ep.y_3;
1063
1102
  Fr y_diff = ep.y_2 * q_sign - ep.y_1;
1064
1103
  Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff;
1065
- 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);
1066
1105
  }
1067
1106
 
1068
1107
  // Contribution 10 point doubling, x-coordinate check
@@ -1078,7 +1117,7 @@ library RelationsLib {
1078
1117
  ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9;
1079
1118
 
1080
1119
  Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double;
1081
- evals[10] = evals[10] + acc;
1120
+ evals[11] = evals[11] + acc;
1082
1121
  }
1083
1122
 
1084
1123
  // Contribution 11 point doubling, y-coordinate check
@@ -1086,23 +1125,13 @@ library RelationsLib {
1086
1125
  {
1087
1126
  Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1;
1088
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);
1089
- 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;
1090
1129
  }
1091
1130
  }
1092
1131
 
1093
- // Constants for the auxiliary relation
1094
- Fr constant LIMB_SIZE = Fr.wrap(uint256(1) << 68);
1095
- Fr constant SUBLIMB_SHIFT = Fr.wrap(uint256(1) << 14);
1096
-
1097
- // Parameters used within the Auxiliary Relation
1132
+ // Parameters used within the Memory Relation
1098
1133
  // A struct is used to work around stack too deep. This relation has alot of variables
1099
- struct AuxParams {
1100
- Fr limb_subproduct;
1101
- Fr non_native_field_gate_1;
1102
- Fr non_native_field_gate_2;
1103
- Fr non_native_field_gate_3;
1104
- Fr limb_accumulator_1;
1105
- Fr limb_accumulator_2;
1134
+ struct MemParams {
1106
1135
  Fr memory_record_check;
1107
1136
  Fr partial_record_check;
1108
1137
  Fr next_gate_access_type;
@@ -1118,80 +1147,15 @@ library RelationsLib {
1118
1147
  Fr RAM_timestamp_check_identity;
1119
1148
  Fr memory_identity;
1120
1149
  Fr index_is_monotonically_increasing;
1121
- Fr auxiliary_identity;
1122
1150
  }
1123
1151
 
1124
- function accumulateAuxillaryRelation(
1152
+ function accumulateMemoryRelation(
1125
1153
  Fr[NUMBER_OF_ENTITIES] memory p,
1126
1154
  Honk.RelationParameters memory rp,
1127
1155
  Fr[NUMBER_OF_SUBRELATIONS] memory evals,
1128
1156
  Fr domainSep
1129
1157
  ) internal pure {
1130
- AuxParams memory ap;
1131
-
1132
- /**
1133
- * Contribution 12
1134
- * Non native field arithmetic gate 2
1135
- * deg 4
1136
- *
1137
- * _ _
1138
- * / _ _ _ 14 \
1139
- * 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 |
1140
- * \_ _/
1141
- *
1142
- *
1143
- */
1144
- 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);
1145
- ap.non_native_field_gate_2 =
1146
- (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));
1147
- ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * LIMB_SIZE;
1148
- ap.non_native_field_gate_2 = ap.non_native_field_gate_2 - wire(p, WIRE.W_4_SHIFT);
1149
- ap.non_native_field_gate_2 = ap.non_native_field_gate_2 + ap.limb_subproduct;
1150
- ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * wire(p, WIRE.Q_4);
1151
-
1152
- ap.limb_subproduct = ap.limb_subproduct * LIMB_SIZE;
1153
- ap.limb_subproduct = ap.limb_subproduct + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT));
1154
- ap.non_native_field_gate_1 = ap.limb_subproduct;
1155
- ap.non_native_field_gate_1 = ap.non_native_field_gate_1 - (wire(p, WIRE.W_O) + wire(p, WIRE.W_4));
1156
- ap.non_native_field_gate_1 = ap.non_native_field_gate_1 * wire(p, WIRE.Q_O);
1157
-
1158
- ap.non_native_field_gate_3 = ap.limb_subproduct;
1159
- ap.non_native_field_gate_3 = ap.non_native_field_gate_3 + wire(p, WIRE.W_4);
1160
- ap.non_native_field_gate_3 = ap.non_native_field_gate_3 - (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT));
1161
- ap.non_native_field_gate_3 = ap.non_native_field_gate_3 * wire(p, WIRE.Q_M);
1162
-
1163
- Fr non_native_field_identity =
1164
- ap.non_native_field_gate_1 + ap.non_native_field_gate_2 + ap.non_native_field_gate_3;
1165
- non_native_field_identity = non_native_field_identity * wire(p, WIRE.Q_R);
1166
-
1167
- // ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm
1168
- // deg 2
1169
- ap.limb_accumulator_1 = wire(p, WIRE.W_R_SHIFT) * SUBLIMB_SHIFT;
1170
- ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L_SHIFT);
1171
- ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1172
- ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_O);
1173
- ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1174
- ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_R);
1175
- ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT;
1176
- ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L);
1177
- ap.limb_accumulator_1 = ap.limb_accumulator_1 - wire(p, WIRE.W_4);
1178
- ap.limb_accumulator_1 = ap.limb_accumulator_1 * wire(p, WIRE.Q_4);
1179
-
1180
- // ((((w3' * 2^14 + w2') * 2^14 + w1') * 2^14 + w4) * 2^14 + w3 - w4') * qm
1181
- // deg 2
1182
- ap.limb_accumulator_2 = wire(p, WIRE.W_O_SHIFT) * SUBLIMB_SHIFT;
1183
- ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_R_SHIFT);
1184
- ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1185
- ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_L_SHIFT);
1186
- ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1187
- ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_4);
1188
- ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT;
1189
- ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_O);
1190
- ap.limb_accumulator_2 = ap.limb_accumulator_2 - wire(p, WIRE.W_4_SHIFT);
1191
- ap.limb_accumulator_2 = ap.limb_accumulator_2 * wire(p, WIRE.Q_M);
1192
-
1193
- Fr limb_accumulator_identity = ap.limb_accumulator_1 + ap.limb_accumulator_2;
1194
- limb_accumulator_identity = limb_accumulator_identity * wire(p, WIRE.Q_O); // deg 3
1158
+ MemParams memory ap;
1195
1159
 
1196
1160
  /**
1197
1161
  * MEMORY
@@ -1260,14 +1224,14 @@ library RelationsLib {
1260
1224
  ap.index_delta = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_L);
1261
1225
  ap.record_delta = wire(p, WIRE.W_4_SHIFT) - wire(p, WIRE.W_4);
1262
1226
 
1263
- 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
1264
1228
 
1265
- 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
1266
1230
 
1267
- evals[13] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R))
1268
- * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5
1269
- evals[14] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R))
1270
- * (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
1271
1235
 
1272
1236
  ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7
1273
1237
 
@@ -1291,17 +1255,18 @@ library RelationsLib {
1291
1255
  * with a WRITE operation.
1292
1256
  */
1293
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
1294
- 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
1295
1259
 
1260
+ // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta
1261
+ // deg 1 or 4
1296
1262
  ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree;
1297
1263
  ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo);
1298
1264
  ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta);
1299
1265
  ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type;
1300
1266
 
1301
1267
  Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O);
1302
- ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (
1303
- ap.index_delta * MINUS_ONE + Fr.wrap(1)
1304
- ) * 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
1305
1270
 
1306
1271
  // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the
1307
1272
  // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't
@@ -1312,12 +1277,12 @@ library RelationsLib {
1312
1277
  ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type;
1313
1278
 
1314
1279
  // Putting it all together...
1315
- evals[15] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation
1316
- * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5 or 8
1317
- evals[16] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4
1318
- 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
1319
1284
 
1320
- 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
1321
1286
 
1322
1287
  /**
1323
1288
  * RAM Timestamp Consistency Check
@@ -1331,8 +1296,7 @@ library RelationsLib {
1331
1296
  * Else timestamp_check = 0
1332
1297
  */
1333
1298
  ap.timestamp_delta = wire(p, WIRE.W_R_SHIFT) - wire(p, WIRE.W_R);
1334
- ap.RAM_timestamp_check_identity =
1335
- (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
1336
1300
 
1337
1301
  /**
1338
1302
  * Complete Contribution 12
@@ -1346,9 +1310,100 @@ library RelationsLib {
1346
1310
  ap.memory_identity = ap.memory_identity + ap.RAM_consistency_check_identity; // deg 3 or 9
1347
1311
 
1348
1312
  // (deg 3 or 9) + (deg 4) + (deg 3)
1349
- ap.auxiliary_identity = ap.memory_identity + non_native_field_identity + limb_accumulator_identity;
1350
- ap.auxiliary_identity = ap.auxiliary_identity * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4 or 10
1351
- 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;
1352
1407
  }
1353
1408
 
1354
1409
  struct PoseidonExternalParams {
@@ -1404,13 +1459,13 @@ library RelationsLib {
1404
1459
  ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4
1405
1460
 
1406
1461
  ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep;
1407
- 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));
1408
1463
 
1409
- 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));
1410
1465
 
1411
- 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));
1412
1467
 
1413
- 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));
1414
1469
  }
1415
1470
 
1416
1471
  struct PoseidonInternalParams {
@@ -1456,23 +1511,23 @@ library RelationsLib {
1456
1511
  ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep;
1457
1512
 
1458
1513
  ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum;
1459
- 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));
1460
1515
 
1461
1516
  ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum;
1462
- 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));
1463
1518
 
1464
1519
  ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum;
1465
- 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));
1466
1521
 
1467
1522
  ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum;
1468
- 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));
1469
1524
  }
1470
1525
 
1471
1526
  function scaleAndBatchSubrelations(
1472
1527
  Fr[NUMBER_OF_SUBRELATIONS] memory evaluations,
1473
1528
  Fr[NUMBER_OF_ALPHAS] memory subrelationChallenges
1474
1529
  ) internal pure returns (Fr accumulator) {
1475
- accumulator = accumulator + evaluations[0];
1530
+ accumulator = evaluations[0];
1476
1531
 
1477
1532
  for (uint256 i = 1; i < NUMBER_OF_SUBRELATIONS; ++i) {
1478
1533
  accumulator = accumulator + evaluations[i] * subrelationChallenges[i - 1];
@@ -1480,139 +1535,458 @@ library RelationsLib {
1480
1535
  }
1481
1536
  }
1482
1537
 
1483
- struct ShpleminiIntermediates {
1484
- Fr unshiftedScalar;
1485
- Fr shiftedScalar;
1486
- // Scalar to be multiplied by [1]₁
1487
- Fr constantTermAccumulator;
1488
- // Accumulator for powers of rho
1489
- Fr batchingChallenge;
1490
- // Linear combination of multilinear (sumcheck) evaluations and powers of rho
1491
- Fr batchedEvaluation;
1492
- // 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated
1493
- Fr posInvertedDenominator;
1494
- // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated
1495
- Fr negInvertedDenominator;
1496
- // v^{2i} * 1/(z - r^{2^i})
1497
- Fr scalingFactorPos;
1498
- // v^{2i+1} * 1/(z + r^{2^i})
1499
- Fr scalingFactorNeg;
1500
- // // Fold_i(r^{2^i}) reconstructed by Verifier
1501
- // Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations;
1502
- }
1538
+ // Field arithmetic libraries - prevent littering the code with modmul / addmul
1503
1539
 
1504
1540
  library CommitmentSchemeLib {
1505
1541
  using FrLib for Fr;
1506
1542
 
1507
- 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);
1508
1571
  squares[0] = r;
1509
- for (uint256 i = 1; i < CONST_PROOF_SIZE_LOG_N; ++i) {
1572
+ for (uint256 i = 1; i < logN; ++i) {
1510
1573
  squares[i] = squares[i - 1].sqr();
1511
1574
  }
1575
+ return squares;
1512
1576
  }
1577
+ // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1
1513
1578
 
1514
- // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., m-1
1515
1579
  function computeFoldPosEvaluations(
1516
1580
  Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges,
1517
1581
  Fr batchedEvalAccumulator,
1518
1582
  Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvaluations,
1519
- Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvalChallengePowers,
1583
+ Fr[] memory geminiEvalChallengePowers,
1520
1584
  uint256 logSize
1521
- ) internal view returns (Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations) {
1522
- 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) {
1523
1588
  Fr challengePower = geminiEvalChallengePowers[i - 1];
1524
1589
  Fr u = sumcheckUChallenges[i - 1];
1525
1590
 
1526
1591
  Fr batchedEvalRoundAcc = (
1527
1592
  (challengePower * batchedEvalAccumulator * Fr.wrap(2))
1528
- - geminiEvaluations[i - 1] * (challengePower * (Fr.wrap(1) - u) - u)
1593
+ - geminiEvaluations[i - 1] * (challengePower * (ONE - u) - u)
1529
1594
  );
1530
1595
  // Divide by the denominator
1531
- batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (Fr.wrap(1) - u) + u).invert();
1596
+ batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (ONE - u) + u).invert();
1532
1597
 
1533
- if (i <= logSize) {
1534
- batchedEvalAccumulator = batchedEvalRoundAcc;
1535
- foldPosEvaluations[i - 1] = batchedEvalRoundAcc;
1536
- }
1598
+ batchedEvalAccumulator = batchedEvalRoundAcc;
1599
+ foldPosEvaluations[i - 1] = batchedEvalRoundAcc;
1537
1600
  }
1601
+ return foldPosEvaluations;
1602
+ }
1603
+ }
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";
1538
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)];
1539
1616
  }
1617
+ result = string(str);
1540
1618
  }
1541
1619
 
1542
- interface IVerifier {
1543
- 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)));
1715
+ }
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
+ }
1831
+
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");
1544
1843
  }
1545
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
+
1546
1870
 
1547
- abstract contract BaseHonkVerifier is IVerifier {
1871
+
1872
+ abstract contract BaseZKHonkVerifier is IVerifier {
1548
1873
  using FrLib for Fr;
1549
1874
 
1550
- uint256 immutable n;
1551
- uint256 immutable logN;
1552
- uint256 immutable numPublicInputs;
1875
+ uint256 immutable $N;
1876
+ uint256 immutable $LOG_N;
1877
+ uint256 immutable $VK_HASH;
1878
+ uint256 immutable $NUM_PUBLIC_INPUTS;
1553
1879
 
1554
- constructor(uint256 _n, uint256 _logN, uint256 _numPublicInputs) {
1555
- n = _n;
1556
- logN = _logN;
1557
- 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;
1558
1885
  }
1559
1886
 
1887
+ // Errors
1560
1888
  error ProofLengthWrong();
1889
+ error ProofLengthWrongWithLogN(uint256 logN, uint256 actualLength, uint256 expectedLength);
1561
1890
  error PublicInputsLengthWrong();
1562
1891
  error SumcheckFailed();
1563
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
1901
+
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
1564
1907
 
1565
- // Number of field elements in a ultra honk zero knowledge proof
1566
- uint256 constant PROOF_SIZE = 456;
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;
1567
1928
 
1568
1929
  function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory);
1569
1930
 
1570
- function verify(bytes calldata proof, bytes32[] calldata publicInputs) public view override returns (bool) {
1571
- // Check the received proof is the expected size where each field element is 32 bytes
1572
- if (proof.length != PROOF_SIZE * 32) {
1573
- 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);
1574
1943
  }
1575
1944
 
1576
1945
  Honk.VerificationKey memory vk = loadVerificationKey();
1577
- Honk.Proof memory p = TranscriptLib.loadProof(proof);
1946
+ Honk.ZKProof memory p = ZKTranscriptLib.loadProof(proof, $LOG_N);
1578
1947
 
1579
1948
  if (publicInputs.length != vk.publicInputsSize - PAIRING_POINTS_SIZE) {
1580
1949
  revert PublicInputsLengthWrong();
1581
1950
  }
1582
1951
 
1583
1952
  // Generate the fiat shamir challenges for the whole protocol
1584
- // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely.
1585
- 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);
1586
1955
 
1587
1956
  // Derive public input delta
1588
- // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely.
1589
1957
  t.relationParameters.publicInputsDelta = computePublicInputDelta(
1590
- publicInputs, p.pairingPointObject, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/1
1958
+ publicInputs,
1959
+ p.pairingPointObject,
1960
+ t.relationParameters.beta,
1961
+ t.relationParameters.gamma, /*pubInputsOffset=*/
1962
+ 1
1591
1963
  );
1592
1964
 
1593
1965
  // Sumcheck
1594
- bool sumcheckVerified = verifySumcheck(p, t);
1595
- if (!sumcheckVerified) revert SumcheckFailed();
1966
+ if (!verifySumcheck(p, t)) revert SumcheckFailed();
1596
1967
 
1597
- bool shpleminiVerified = verifyShplemini(p, vk, t);
1598
- if (!shpleminiVerified) revert ShpleminiFailed();
1968
+ if (!verifyShplemini(p, vk, t)) revert ShpleminiFailed();
1599
1969
 
1600
- return sumcheckVerified && shpleminiVerified; // Boolean condition not required - nice for vanity :)
1970
+ verified = true;
1601
1971
  }
1602
1972
 
1603
- function computePublicInputDelta(bytes32[] memory publicInputs, Fr[PAIRING_POINTS_SIZE] memory pairingPointObject, Fr beta, Fr gamma, uint256 offset)
1604
- internal
1605
- view
1606
- returns (Fr publicInputDelta)
1607
- {
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) {
1608
1982
  Fr numerator = Fr.wrap(1);
1609
1983
  Fr denominator = Fr.wrap(1);
1610
1984
 
1611
- Fr numeratorAcc = gamma + (beta * FrLib.from(n + offset));
1985
+ Fr numeratorAcc = gamma + (beta * FrLib.from(PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset));
1612
1986
  Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1));
1613
1987
 
1614
1988
  {
1615
- for (uint256 i = 0; i < numPublicInputs - PAIRING_POINTS_SIZE; i++) {
1989
+ for (uint256 i = 0; i < $NUM_PUBLIC_INPUTS - PAIRING_POINTS_SIZE; i++) {
1616
1990
  Fr pubInput = FrLib.fromBytes32(publicInputs[i]);
1617
1991
 
1618
1992
  numerator = numerator * (numeratorAcc + pubInput);
@@ -1637,54 +2011,55 @@ abstract contract BaseHonkVerifier is IVerifier {
1637
2011
  publicInputDelta = FrLib.div(numerator, denominator);
1638
2012
  }
1639
2013
 
1640
- function verifySumcheck(Honk.Proof memory proof, Transcript memory tp) internal view returns (bool verified) {
1641
- 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
1642
2016
  Fr powPartialEvaluation = Fr.wrap(1);
1643
2017
 
1644
2018
  // We perform sumcheck reductions over log n rounds ( the multivariate degree )
1645
- for (uint256 round; round < logN; ++round) {
1646
- Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round];
1647
- bool valid = checkSum(roundUnivariate, roundTarget);
1648
- 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();
1649
2023
 
1650
2024
  Fr roundChallenge = tp.sumCheckUChallenges[round];
1651
2025
 
1652
2026
  // Update the round target for the next rounf
1653
- roundTarget = computeNextTargetSum(roundUnivariate, roundChallenge);
1654
- 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)));
1655
2030
  }
1656
2031
 
1657
2032
  // Last round
1658
- Fr grandHonkRelationSum =
1659
- RelationsLib.accumulateRelationEvaluations(proof.sumcheckEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation);
1660
- verified = (grandHonkRelationSum == roundTarget);
1661
- }
2033
+ Fr grandHonkRelationSum = RelationsLib.accumulateRelationEvaluations(
2034
+ proof.sumcheckEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation
2035
+ );
1662
2036
 
1663
- function checkSum(Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate, Fr roundTarget)
1664
- internal
1665
- pure
1666
- returns (bool checked)
1667
- {
1668
- Fr totalSum = roundUnivariate[0] + roundUnivariate[1];
1669
- 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);
1670
2045
  }
1671
2046
 
1672
2047
  // Return the new target sum for the next sumcheck round
1673
- function computeNextTargetSum(Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge)
2048
+ function computeNextTargetSum(Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge)
1674
2049
  internal
1675
2050
  view
1676
2051
  returns (Fr targetSum)
1677
2052
  {
1678
- // TODO: inline
1679
- Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [
2053
+ Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [
2054
+ Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80),
1680
2055
  Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51),
1681
- Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000002d0),
1682
- Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff11),
1683
- Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000090),
1684
- Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff71),
1685
- Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000000f0),
2056
+ Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0),
1686
2057
  Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31),
1687
- Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000013b0)
2058
+ Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000240),
2059
+ Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31),
2060
+ Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0),
2061
+ Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51),
2062
+ Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80)
1688
2063
  ];
1689
2064
 
1690
2065
  // To compute the next target sum, we evaluate the given univariate at a point u (challenge).
@@ -1692,52 +2067,44 @@ abstract contract BaseHonkVerifier is IVerifier {
1692
2067
  // Performing Barycentric evaluations
1693
2068
  // Compute B(x)
1694
2069
  Fr numeratorValue = Fr.wrap(1);
1695
- for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
2070
+ for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
1696
2071
  numeratorValue = numeratorValue * (roundChallenge - Fr.wrap(i));
1697
2072
  }
1698
2073
 
1699
- // Calculate domain size N of inverses
1700
- Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory denominatorInverses;
1701
- for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
1702
- Fr inv = BARYCENTRIC_LAGRANGE_DENOMINATORS[i];
1703
- inv = inv * (roundChallenge - Fr.wrap(i));
1704
- inv = FrLib.invert(inv);
1705
- 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)));
1706
2077
  }
1707
2078
 
1708
- for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
1709
- Fr term = roundUnivariates[i];
1710
- term = term * denominatorInverses[i];
1711
- targetSum = targetSum + term;
2079
+ for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) {
2080
+ targetSum = targetSum + roundUnivariates[i] * denominatorInverses[i];
1712
2081
  }
1713
2082
 
1714
2083
  // Scale the sum by the value of B(x)
1715
2084
  targetSum = targetSum * numeratorValue;
1716
2085
  }
1717
2086
 
1718
- // Univariate evaluation of the monomial ((1-X_l) + X_l.B_l) at the challenge point X_l=u_l
1719
- function partiallyEvaluatePOW(Fr gateChallenge, Fr currentEvaluation, Fr roundChallenge)
1720
- internal
1721
- pure
1722
- returns (Fr newEvaluation)
1723
- {
1724
- Fr univariateEval = Fr.wrap(1) + (roundChallenge * (gateChallenge - Fr.wrap(1)));
1725
- 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;
1726
2094
  }
1727
2095
 
1728
- 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)
1729
2097
  internal
1730
2098
  view
1731
2099
  returns (bool verified)
1732
2100
  {
1733
- ShpleminiIntermediates memory mem; // stack
2101
+ CommitmentSchemeLib.ShpleminiIntermediates memory mem; // stack
1734
2102
 
1735
2103
  // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size
1736
- Fr[CONST_PROOF_SIZE_LOG_N] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR);
1737
-
2104
+ Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR, $LOG_N);
1738
2105
  // Arrays hold values that will be linearly combined for the gemini and shplonk batch openings
1739
- Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars;
1740
- 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);
1741
2108
 
1742
2109
  mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert();
1743
2110
  mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert();
@@ -1747,88 +2114,147 @@ abstract contract BaseHonkVerifier is IVerifier {
1747
2114
  tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator));
1748
2115
 
1749
2116
  scalars[0] = Fr.wrap(1);
1750
- commitments[0] = convertProofPoint(proof.shplonkQ);
1751
-
1752
- mem.batchingChallenge = Fr.wrap(1);
1753
- mem.batchedEvaluation = Fr.wrap(0);
1754
-
1755
- for (uint256 i = 1; i <= NUMBER_UNSHIFTED; ++i) {
1756
- scalars[i] = mem.unshiftedScalar.neg() * mem.batchingChallenge;
1757
- 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);
1758
2155
  mem.batchingChallenge = mem.batchingChallenge * tp.rho;
1759
2156
  }
1760
2157
  // g commitments are accumulated at r
1761
- for (uint256 i = NUMBER_UNSHIFTED + 1; i <= NUMBER_OF_ENTITIES; ++i) {
1762
- scalars[i] = mem.shiftedScalar.neg() * mem.batchingChallenge;
1763
- 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);
1764
2170
  mem.batchingChallenge = mem.batchingChallenge * tp.rho;
1765
2171
  }
1766
2172
 
1767
- commitments[1] = vk.qm;
1768
- commitments[2] = vk.qc;
1769
- commitments[3] = vk.ql;
1770
- commitments[4] = vk.qr;
1771
- commitments[5] = vk.qo;
1772
- commitments[6] = vk.q4;
1773
- commitments[7] = vk.qLookup;
1774
- commitments[8] = vk.qArith;
1775
- commitments[9] = vk.qDeltaRange;
1776
- commitments[10] = vk.qElliptic;
1777
- commitments[11] = vk.qAux;
1778
- commitments[12] = vk.qPoseidon2External;
1779
- commitments[13] = vk.qPoseidon2Internal;
1780
- commitments[14] = vk.s1;
1781
- commitments[15] = vk.s2;
1782
- commitments[16] = vk.s3;
1783
- commitments[17] = vk.s4;
1784
- commitments[18] = vk.id1;
1785
- commitments[19] = vk.id2;
1786
- commitments[20] = vk.id3;
1787
- commitments[21] = vk.id4;
1788
- commitments[22] = vk.t1;
1789
- commitments[23] = vk.t2;
1790
- commitments[24] = vk.t3;
1791
- commitments[25] = vk.t4;
1792
- commitments[26] = vk.lagrangeFirst;
1793
- 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;
1794
2203
 
1795
2204
  // Accumulate proof points
1796
- commitments[28] = convertProofPoint(proof.w1);
1797
- commitments[29] = convertProofPoint(proof.w2);
1798
- commitments[30] = convertProofPoint(proof.w3);
1799
- commitments[31] = convertProofPoint(proof.w4);
1800
- commitments[32] = convertProofPoint(proof.zPerm);
1801
- commitments[33] = convertProofPoint(proof.lookupInverses);
1802
- commitments[34] = convertProofPoint(proof.lookupReadCounts);
1803
- commitments[35] = convertProofPoint(proof.lookupReadTags);
1804
-
1805
- // to be Shifted
1806
- commitments[36] = convertProofPoint(proof.w1);
1807
- commitments[37] = convertProofPoint(proof.w2);
1808
- commitments[38] = convertProofPoint(proof.w3);
1809
- commitments[39] = convertProofPoint(proof.w4);
1810
- 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
+ */
1811
2236
 
1812
2237
  // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator:
1813
- // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., logN - 1
1814
- 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(
1815
2240
  tp.sumCheckUChallenges,
1816
2241
  mem.batchedEvaluation,
1817
2242
  proof.geminiAEvaluations,
1818
2243
  powers_of_evaluation_challenge,
1819
- logN
2244
+ $LOG_N
1820
2245
  );
1821
2246
 
1822
- // Compute the Shplonk constant term contributions from A₀(±r)
1823
2247
  mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator;
1824
2248
  mem.constantTermAccumulator =
1825
2249
  mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator);
2250
+
1826
2251
  mem.batchingChallenge = tp.shplonkNu.sqr();
2252
+ uint256 boundary = NUMBER_UNSHIFTED + 2;
1827
2253
 
1828
- // 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;
1829
2255
  // Compute scalar multipliers for each fold commitment
1830
- for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) {
1831
- bool dummy_round = i >= (logN - 1);
2256
+ for (uint256 i = 0; i < $LOG_N - 1; ++i) {
2257
+ bool dummy_round = i >= ($LOG_N - 1);
1832
2258
 
1833
2259
  if (!dummy_round) {
1834
2260
  // Update inverted denominators
@@ -1838,57 +2264,150 @@ abstract contract BaseHonkVerifier is IVerifier {
1838
2264
  // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ]
1839
2265
  mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator;
1840
2266
  mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator;
1841
- // [Aₗ] is multiplied by -v^{2l}/(z-r^{2^l}) - v^{2l+1} /(z+ r^{2^l})
1842
- scalars[NUMBER_OF_ENTITIES + 1 + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg();
2267
+ scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg();
1843
2268
 
1844
2269
  // Accumulate the const term contribution given by
1845
2270
  // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l})
1846
2271
  Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1];
1847
2272
  accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1];
1848
2273
  mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution;
1849
- // Update the running power of v
1850
- mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu;
1851
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
+ }
2303
+
2304
+ commitments[boundary] = Honk.G1Point({x: 1, y: 2});
2305
+ scalars[boundary++] = mem.constantTermAccumulator;
1852
2306
 
1853
- commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]);
2307
+ if (!checkEvalsConsistency(proof.libraPolyEvals, tp.geminiR, tp.sumCheckUChallenges, proof.libraEvaluation)) {
2308
+ revert ConsistencyCheckFailed();
1854
2309
  }
1855
2310
 
1856
- // Finalise the batch opening claim
1857
- commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = Honk.G1Point({x: 1, y: 2});
1858
- scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = mem.constantTermAccumulator;
2311
+ Honk.G1Point memory quotient_commitment = proof.kzgQuotient;
1859
2312
 
1860
- Honk.G1Point memory quotient_commitment = convertProofPoint(proof.kzgQuotient);
2313
+ commitments[boundary] = quotient_commitment;
2314
+ scalars[boundary] = tp.shplonkZ; // evaluation challenge
1861
2315
 
1862
- commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 1] = quotient_commitment;
1863
- scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 1] = tp.shplonkZ; // evaluation challenge
2316
+ PairingInputs memory pair;
2317
+ pair.P_0 = batchMul(commitments, scalars);
2318
+ pair.P_1 = negateInplace(quotient_commitment);
1864
2319
 
1865
- Honk.G1Point memory P_0 = batchMul(commitments, scalars);
1866
- Honk.G1Point memory P_1 = negateInplace(quotient_commitment);
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);
1867
2324
 
1868
- return pairing(P_0, P_1);
2325
+ // Validate the points from the proof are on the curve
2326
+ validateOnCurve(P_0_other);
2327
+ validateOnCurve(P_1_other);
2328
+
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);
1869
2390
  }
1870
2391
 
1871
2392
  // This implementation is the same as above with different constants
1872
- function batchMul(
1873
- Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory base,
1874
- Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars
1875
- ) internal view returns (Honk.G1Point memory result) {
1876
- 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;
1877
2406
  assembly {
1878
- let success := 0x01
1879
2407
  let free := mload(0x40)
1880
2408
 
1881
- // Write the original into the accumulator
1882
- // Load into memory for ecMUL, leave offset for eccAdd result
1883
- // base is an array of pointers, so we have to dereference them
1884
- mstore(add(free, 0x40), mload(mload(base)))
1885
- mstore(add(free, 0x60), mload(add(0x20, mload(base))))
1886
- // Add scalar
1887
- mstore(add(free, 0x80), mload(scalars))
1888
- success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, free, 0x40))
1889
-
1890
2409
  let count := 0x01
1891
- for {} lt(count, limit) { count := add(count, 1) } {
2410
+ for {} lt(count, add(limit, 1)) { count := add(count, 1) } {
1892
2411
  // Get loop offsets
1893
2412
  let base_base := add(base, mul(count, 0x20))
1894
2413
  let scalar_base := add(scalars, mul(count, 0x20))
@@ -1903,14 +2422,16 @@ abstract contract BaseHonkVerifier is IVerifier {
1903
2422
  success := and(success, staticcall(gas(), 6, free, 0x80, free, 0x40))
1904
2423
  }
1905
2424
 
1906
- // Return the result - i hate this
2425
+ // Return the result
1907
2426
  mstore(result, mload(free))
1908
2427
  mstore(add(result, 0x20), mload(add(free, 0x20)))
1909
2428
  }
2429
+
2430
+ require(success, ShpleminiFailed());
1910
2431
  }
1911
2432
  }
1912
2433
 
1913
- 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) {
1914
2435
  function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) {
1915
2436
  return HonkVerificationKey.loadVerificationKey();
1916
2437
  }