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