@crisp-e3/contracts 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -7,125 +7,125 @@ pragma solidity >=0.8.21;
|
|
|
7
7
|
|
|
8
8
|
uint256 constant N = 2097152;
|
|
9
9
|
uint256 constant LOG_N = 21;
|
|
10
|
-
uint256 constant NUMBER_OF_PUBLIC_INPUTS =
|
|
11
|
-
uint256 constant VK_HASH =
|
|
10
|
+
uint256 constant NUMBER_OF_PUBLIC_INPUTS = 15;
|
|
11
|
+
uint256 constant VK_HASH = 0x0a7642f3693429035e756c034137ba93ed0bc3e7d3f370e24143d7e52a7aabc4;
|
|
12
12
|
library HonkVerificationKey {
|
|
13
13
|
function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) {
|
|
14
14
|
Honk.VerificationKey memory vk = Honk.VerificationKey({
|
|
15
15
|
circuitSize: uint256(2097152),
|
|
16
16
|
logCircuitSize: uint256(21),
|
|
17
|
-
publicInputsSize: uint256(
|
|
17
|
+
publicInputsSize: uint256(15),
|
|
18
18
|
ql: Honk.G1Point({
|
|
19
|
-
x: uint256(
|
|
20
|
-
y: uint256(
|
|
19
|
+
x: uint256(0x14493dc1077b2f351879feecaa600ca60f7ce233869e11f274bb6fc7d31427dd),
|
|
20
|
+
y: uint256(0x03269bd3e0e7fcd095c3a6eaddf8e30e33ca383497034c7e028ddc372df027da)
|
|
21
21
|
}),
|
|
22
22
|
qr: Honk.G1Point({
|
|
23
|
-
x: uint256(
|
|
24
|
-
y: uint256(
|
|
23
|
+
x: uint256(0x1fa18580baf7ded1c161e13ca6a20c5670ef984a3396979faf7e0a656387e527),
|
|
24
|
+
y: uint256(0x2e94ddf45aecdaee626a6eeded33d0feda0b05fe0681f3ee3d6340a4a8c10896)
|
|
25
25
|
}),
|
|
26
26
|
qo: Honk.G1Point({
|
|
27
|
-
x: uint256(
|
|
28
|
-
y: uint256(
|
|
27
|
+
x: uint256(0x092b0d4c826cbe5e07c1e19020272e116ff633dc953763c357f5fd841722123e),
|
|
28
|
+
y: uint256(0x2c32eb8ab851dfe95645d6e6c15d5074c4e3d179d58aa0ed636f7dfafabecede)
|
|
29
29
|
}),
|
|
30
30
|
q4: Honk.G1Point({
|
|
31
|
-
x: uint256(
|
|
32
|
-
y: uint256(
|
|
31
|
+
x: uint256(0x25306c50d5acbe8b63f31114c2a33abd494ee69eaf0d83dfd5a2a77c6c7694dc),
|
|
32
|
+
y: uint256(0x1a86fb908a0a332216ad4e0651be7f73f720d402f00ce3e8b32e94b89f25087f)
|
|
33
33
|
}),
|
|
34
34
|
qm: Honk.G1Point({
|
|
35
|
-
x: uint256(
|
|
36
|
-
y: uint256(
|
|
35
|
+
x: uint256(0x26516743e498c0fd06b97618fb55478fd29807b4d6305ca3bb2d7b506264fd6f),
|
|
36
|
+
y: uint256(0x10bb22b28f6420cea07563e6114b960dd9bdbf203ad39a4bed6b42d014fff8f9)
|
|
37
37
|
}),
|
|
38
38
|
qc: Honk.G1Point({
|
|
39
|
-
x: uint256(
|
|
40
|
-
y: uint256(
|
|
39
|
+
x: uint256(0x14e3747585344848708d74e5cac292bd806b04496ce2a1f19b832be2b06a46a0),
|
|
40
|
+
y: uint256(0x24e01d1273374ee4f50c390758c45738b0dee956af2038acbd53b58d4b74779a)
|
|
41
41
|
}),
|
|
42
42
|
qLookup: Honk.G1Point({
|
|
43
|
-
x: uint256(
|
|
44
|
-
y: uint256(
|
|
43
|
+
x: uint256(0x0000000000000000000000000000000000000000000000000000000000000000),
|
|
44
|
+
y: uint256(0x0000000000000000000000000000000000000000000000000000000000000000)
|
|
45
45
|
}),
|
|
46
46
|
qArith: Honk.G1Point({
|
|
47
|
-
x: uint256(
|
|
48
|
-
y: uint256(
|
|
47
|
+
x: uint256(0x176c5cf9eb8c27900484c632289e86dfbfab9d4bbc5d927e2fe3a79b36479290),
|
|
48
|
+
y: uint256(0x2fc22055c186e3bcd7b55e48688c899b5a5c804e3d7403f520776666dbb3f23e)
|
|
49
49
|
}),
|
|
50
50
|
qDeltaRange: Honk.G1Point({
|
|
51
|
-
x: uint256(
|
|
52
|
-
y: uint256(
|
|
51
|
+
x: uint256(0x2d0e8c12eebb1f0a1604752470e237658a92f612da2abc65a791cc777a35a341),
|
|
52
|
+
y: uint256(0x23ebdb221e2fc512e6bce94cc3701880ee87e340c16e2fcce619ee8e97949e56)
|
|
53
53
|
}),
|
|
54
54
|
qElliptic: Honk.G1Point({
|
|
55
|
-
x: uint256(
|
|
56
|
-
y: uint256(
|
|
55
|
+
x: uint256(0x0000000000000000000000000000000000000000000000000000000000000000),
|
|
56
|
+
y: uint256(0x0000000000000000000000000000000000000000000000000000000000000000)
|
|
57
57
|
}),
|
|
58
58
|
qMemory: Honk.G1Point({
|
|
59
|
-
x: uint256(
|
|
60
|
-
y: uint256(
|
|
59
|
+
x: uint256(0x0f8820a8b43ed7f9a6e0aa355bf3ef04dc47c88a221a6c41a4f253e50783fab4),
|
|
60
|
+
y: uint256(0x2de4b7c386bedbf5694b899eb29dd3c1be6e7691ecc10d4074966cfe8efb0421)
|
|
61
61
|
}),
|
|
62
62
|
qNnf: Honk.G1Point({
|
|
63
|
-
x: uint256(
|
|
64
|
-
y: uint256(
|
|
63
|
+
x: uint256(0x19a8398c7b609f27c334c656127ebdc34db4982bb1f1bbec186873c113d2f0b1),
|
|
64
|
+
y: uint256(0x29c36f8a702f73fec6a32d581fdc17e59c4999625d7c9147e7eac48df66b1740)
|
|
65
65
|
}),
|
|
66
66
|
qPoseidon2External: Honk.G1Point({
|
|
67
|
-
x: uint256(
|
|
68
|
-
y: uint256(
|
|
67
|
+
x: uint256(0x00fd3df42aead1d3fe2aedac899b5a5a1d33072137bbf9cd98933a7f939ca4af),
|
|
68
|
+
y: uint256(0x0daa73db37e213845ad80630816c01724f21e0151759b18358a51651bbc5ef49)
|
|
69
69
|
}),
|
|
70
70
|
qPoseidon2Internal: Honk.G1Point({
|
|
71
|
-
x: uint256(
|
|
72
|
-
y: uint256(
|
|
71
|
+
x: uint256(0x0d04ebec0a4f4c5343b72c528f4de039629eab96223847720e5fb619b1a8f10d),
|
|
72
|
+
y: uint256(0x128f4178942625efadd7fe3adbaeb337fd961488236802d50ece4a7552e96370)
|
|
73
73
|
}),
|
|
74
74
|
s1: Honk.G1Point({
|
|
75
|
-
x: uint256(
|
|
76
|
-
y: uint256(
|
|
75
|
+
x: uint256(0x0774647b2dca67d5649beb99b794a2eb00df29cf5f41a651f1dbd4ef6e9efbf7),
|
|
76
|
+
y: uint256(0x2f0f9a00cfdd4915a84eeecae14991cf8aed2f0efc17685988b2c5513a868150)
|
|
77
77
|
}),
|
|
78
78
|
s2: Honk.G1Point({
|
|
79
|
-
x: uint256(
|
|
80
|
-
y: uint256(
|
|
79
|
+
x: uint256(0x07fb7e3aefe3a10bf887114d2d23a0e6e625695d1edc4507aaa362cf13cbe95b),
|
|
80
|
+
y: uint256(0x27c70c4226f232a5649e44053b2b71db25553c54f57ade536e7a60a7e4321836)
|
|
81
81
|
}),
|
|
82
82
|
s3: Honk.G1Point({
|
|
83
|
-
x: uint256(
|
|
84
|
-
y: uint256(
|
|
83
|
+
x: uint256(0x28cd82d09235cab51c5909d625fd077e6b1c19e3f9d74963ebd6be11d165c8fa),
|
|
84
|
+
y: uint256(0x1f13e6a87683c7105f1ad021f09f02db97654f78c52d549b8b927794f5fdde58)
|
|
85
85
|
}),
|
|
86
86
|
s4: Honk.G1Point({
|
|
87
|
-
x: uint256(
|
|
88
|
-
y: uint256(
|
|
87
|
+
x: uint256(0x2706b7dbb9755b086936581aa3d9c43e6e24f1dc44e8d6268d1ae9e80b52015e),
|
|
88
|
+
y: uint256(0x237ab989a520291d485957047de8e083cfd74afb501593c9429c9d40b5b8a070)
|
|
89
89
|
}),
|
|
90
90
|
t1: Honk.G1Point({
|
|
91
|
-
x: uint256(
|
|
92
|
-
y: uint256(
|
|
91
|
+
x: uint256(0x0000000000000000000000000000000000000000000000000000000000000000),
|
|
92
|
+
y: uint256(0x0000000000000000000000000000000000000000000000000000000000000000)
|
|
93
93
|
}),
|
|
94
94
|
t2: Honk.G1Point({
|
|
95
|
-
x: uint256(
|
|
96
|
-
y: uint256(
|
|
95
|
+
x: uint256(0x0000000000000000000000000000000000000000000000000000000000000000),
|
|
96
|
+
y: uint256(0x0000000000000000000000000000000000000000000000000000000000000000)
|
|
97
97
|
}),
|
|
98
98
|
t3: Honk.G1Point({
|
|
99
|
-
x: uint256(
|
|
100
|
-
y: uint256(
|
|
99
|
+
x: uint256(0x0000000000000000000000000000000000000000000000000000000000000000),
|
|
100
|
+
y: uint256(0x0000000000000000000000000000000000000000000000000000000000000000)
|
|
101
101
|
}),
|
|
102
102
|
t4: Honk.G1Point({
|
|
103
|
-
x: uint256(
|
|
104
|
-
y: uint256(
|
|
103
|
+
x: uint256(0x0000000000000000000000000000000000000000000000000000000000000000),
|
|
104
|
+
y: uint256(0x0000000000000000000000000000000000000000000000000000000000000000)
|
|
105
105
|
}),
|
|
106
106
|
id1: Honk.G1Point({
|
|
107
|
-
x: uint256(
|
|
108
|
-
y: uint256(
|
|
107
|
+
x: uint256(0x117f92d3a69b1401f1b3eb19da6bf4dacd4a0c7b0fbc2767112674ae33356634),
|
|
108
|
+
y: uint256(0x18d8c2c0d2dab140e273b4607eda1ebb4560dbb0c8299e21e702a20d2252b91a)
|
|
109
109
|
}),
|
|
110
110
|
id2: Honk.G1Point({
|
|
111
|
-
x: uint256(
|
|
112
|
-
y: uint256(
|
|
111
|
+
x: uint256(0x2cffdc37befb4d7147f9b1e40dc54b529684766c4f6ed722a08af2080129fa8c),
|
|
112
|
+
y: uint256(0x0f9ea00342ceb61caea3d52750c757d17b6d4d63fc7d855d4b3fdbad8566cab9)
|
|
113
113
|
}),
|
|
114
114
|
id3: Honk.G1Point({
|
|
115
|
-
x: uint256(
|
|
116
|
-
y: uint256(
|
|
115
|
+
x: uint256(0x04b9f40f2cd4123d03663d63758856d3f947c857cdb16e4c45587df95a5239c1),
|
|
116
|
+
y: uint256(0x149255bba819e1a349307d4a334143f77028d663bee3a4761177dd5f5610df21)
|
|
117
117
|
}),
|
|
118
118
|
id4: Honk.G1Point({
|
|
119
|
-
x: uint256(
|
|
120
|
-
y: uint256(
|
|
119
|
+
x: uint256(0x2b8aba03c2291ad20411a8f5c9eafa2177e093539e88f085c376496455ce16ab),
|
|
120
|
+
y: uint256(0x2b2cda526df47bdb8ff2257b7c3b8eadfcd5c195ad0d619ddcc3a960ece05656)
|
|
121
121
|
}),
|
|
122
122
|
lagrangeFirst: Honk.G1Point({
|
|
123
|
-
x: uint256(
|
|
124
|
-
y: uint256(
|
|
123
|
+
x: uint256(0x2a56ce41f6b0be13b9c26747621b821eee81b23a887f299049b14c11e98460d6),
|
|
124
|
+
y: uint256(0x1aa98f2de3ddda547d8f6de4e725ded5827d6338c78656c0d12ca1aea6ef2c7c)
|
|
125
125
|
}),
|
|
126
126
|
lagrangeLast: Honk.G1Point({
|
|
127
|
-
x: uint256(
|
|
128
|
-
y: uint256(
|
|
127
|
+
x: uint256(0x100c5101d69d23da354afa62b1d0354277b5f12dc6dbd26b1b33eae7973aca5a),
|
|
128
|
+
y: uint256(0x2ae821e69f12831c7dd899a431ff8eb56f8637b07fbd23ca8abcaae6ea299326)
|
|
129
129
|
})
|
|
130
130
|
});
|
|
131
131
|
return vk;
|
|
@@ -135,7 +135,33 @@ library HonkVerificationKey {
|
|
|
135
135
|
pragma solidity ^0.8.27;
|
|
136
136
|
|
|
137
137
|
interface IVerifier {
|
|
138
|
-
function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external returns (bool);
|
|
138
|
+
function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @notice Library of error codes
|
|
143
|
+
* @dev You can run `forge inspect Errors errors` to get the selectors for the optimised verifier
|
|
144
|
+
*/
|
|
145
|
+
library Errors {
|
|
146
|
+
error ValueGeLimbMax();
|
|
147
|
+
error ValueGeGroupOrder();
|
|
148
|
+
error ValueGeFieldOrder();
|
|
149
|
+
|
|
150
|
+
error InvertOfZero();
|
|
151
|
+
error NotPowerOfTwo();
|
|
152
|
+
error ModExpFailed();
|
|
153
|
+
|
|
154
|
+
error ProofLengthWrong();
|
|
155
|
+
error ProofLengthWrongWithLogN(uint256 logN, uint256 actualLength, uint256 expectedLength);
|
|
156
|
+
error PublicInputsLengthWrong();
|
|
157
|
+
error SumcheckFailed();
|
|
158
|
+
error ShpleminiFailed();
|
|
159
|
+
|
|
160
|
+
error PointAtInfinity();
|
|
161
|
+
|
|
162
|
+
error ConsistencyCheckFailed();
|
|
163
|
+
error VerificationKeyConfigurationMismatch();
|
|
164
|
+
error GeminiChallengeInSubgroup();
|
|
139
165
|
}
|
|
140
166
|
|
|
141
167
|
type Fr is uint256;
|
|
@@ -144,7 +170,6 @@ using { add as + } for Fr global;
|
|
|
144
170
|
using { sub as - } for Fr global;
|
|
145
171
|
using { mul as * } for Fr global;
|
|
146
172
|
|
|
147
|
-
using { exp as ^ } for Fr global;
|
|
148
173
|
using { notEqual as != } for Fr global;
|
|
149
174
|
using { equal as == } for Fr global;
|
|
150
175
|
|
|
@@ -156,29 +181,21 @@ Fr constant SUBGROUP_GENERATOR_INVERSE = Fr.wrap(0x204bd3277422fad364751ad938e2b
|
|
|
156
181
|
Fr constant MINUS_ONE = Fr.wrap(MODULUS - 1);
|
|
157
182
|
Fr constant ONE = Fr.wrap(1);
|
|
158
183
|
Fr constant ZERO = Fr.wrap(0);
|
|
184
|
+
|
|
185
|
+
// SmallSubgroupIPA opening-claim layout — mirrors SMALL_IPA_CLAIMS in
|
|
186
|
+
// barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa_utils.hpp.
|
|
187
|
+
uint256 constant NUM_SMALL_IPA_OPENING_CLAIMS = 5;
|
|
188
|
+
uint256 constant SMALL_IPA_BOUNDARY_OPENING_IDX = 3;
|
|
189
|
+
uint256 constant NUM_SMALL_IPA_TRANSCRIPT_EVALS = 4;
|
|
159
190
|
// Instantiation
|
|
160
191
|
|
|
161
192
|
library FrLib {
|
|
162
|
-
|
|
163
|
-
unchecked {
|
|
164
|
-
return Fr.wrap(value % MODULUS);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function fromBytes32(bytes32 value) internal pure returns (Fr) {
|
|
169
|
-
unchecked {
|
|
170
|
-
return Fr.wrap(uint256(value) % MODULUS);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function toBytes32(Fr value) internal pure returns (bytes32) {
|
|
175
|
-
unchecked {
|
|
176
|
-
return bytes32(Fr.unwrap(value));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
193
|
+
bytes4 internal constant FRLIB_MODEXP_FAILED_SELECTOR = 0x1f7ec5f0;
|
|
179
194
|
|
|
180
195
|
function invert(Fr value) internal view returns (Fr) {
|
|
181
196
|
uint256 v = Fr.unwrap(value);
|
|
197
|
+
require(v != 0, Errors.InvertOfZero());
|
|
198
|
+
|
|
182
199
|
uint256 result;
|
|
183
200
|
|
|
184
201
|
// Call the modexp precompile to invert in the field
|
|
@@ -192,10 +209,11 @@ library FrLib {
|
|
|
192
209
|
mstore(add(free, 0xa0), MODULUS)
|
|
193
210
|
let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20)
|
|
194
211
|
if iszero(success) {
|
|
195
|
-
|
|
212
|
+
mstore(0x00, FRLIB_MODEXP_FAILED_SELECTOR)
|
|
213
|
+
revert(0, 0x04)
|
|
196
214
|
}
|
|
197
215
|
result := mload(0x00)
|
|
198
|
-
mstore(0x40, add(free,
|
|
216
|
+
mstore(0x40, add(free, 0xc0))
|
|
199
217
|
}
|
|
200
218
|
|
|
201
219
|
return Fr.wrap(result);
|
|
@@ -203,6 +221,8 @@ library FrLib {
|
|
|
203
221
|
|
|
204
222
|
function pow(Fr base, uint256 v) internal view returns (Fr) {
|
|
205
223
|
uint256 b = Fr.unwrap(base);
|
|
224
|
+
// Only works for power of 2
|
|
225
|
+
require(v > 0 && (v & (v - 1)) == 0, Errors.NotPowerOfTwo());
|
|
206
226
|
uint256 result;
|
|
207
227
|
|
|
208
228
|
// Call the modexp precompile to invert in the field
|
|
@@ -216,10 +236,11 @@ library FrLib {
|
|
|
216
236
|
mstore(add(free, 0xa0), MODULUS)
|
|
217
237
|
let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20)
|
|
218
238
|
if iszero(success) {
|
|
219
|
-
|
|
239
|
+
mstore(0x00, FRLIB_MODEXP_FAILED_SELECTOR)
|
|
240
|
+
revert(0, 0x04)
|
|
220
241
|
}
|
|
221
242
|
result := mload(0x00)
|
|
222
|
-
mstore(0x40, add(free,
|
|
243
|
+
mstore(0x40, add(free, 0xc0))
|
|
223
244
|
}
|
|
224
245
|
|
|
225
246
|
return Fr.wrap(result);
|
|
@@ -248,6 +269,27 @@ library FrLib {
|
|
|
248
269
|
return Fr.wrap(MODULUS - Fr.unwrap(value));
|
|
249
270
|
}
|
|
250
271
|
}
|
|
272
|
+
|
|
273
|
+
function from(uint256 value) internal pure returns (Fr) {
|
|
274
|
+
unchecked {
|
|
275
|
+
require(value < MODULUS, Errors.ValueGeFieldOrder());
|
|
276
|
+
return Fr.wrap(value);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function fromBytes32(bytes32 value) internal pure returns (Fr) {
|
|
281
|
+
unchecked {
|
|
282
|
+
uint256 v = uint256(value);
|
|
283
|
+
require(v < MODULUS, Errors.ValueGeFieldOrder());
|
|
284
|
+
return Fr.wrap(v);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function toBytes32(Fr value) internal pure returns (bytes32) {
|
|
289
|
+
unchecked {
|
|
290
|
+
return bytes32(Fr.unwrap(value));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
251
293
|
}
|
|
252
294
|
|
|
253
295
|
// Free functions
|
|
@@ -269,15 +311,6 @@ function sub(Fr a, Fr b) pure returns (Fr) {
|
|
|
269
311
|
}
|
|
270
312
|
}
|
|
271
313
|
|
|
272
|
-
function exp(Fr base, Fr exponent) pure returns (Fr) {
|
|
273
|
-
if (Fr.unwrap(exponent) == 0) return Fr.wrap(1);
|
|
274
|
-
// Implement exponent with a loop as we will overflow otherwise
|
|
275
|
-
for (uint256 i = 1; i < Fr.unwrap(exponent); i += i) {
|
|
276
|
-
base = base * base;
|
|
277
|
-
}
|
|
278
|
-
return base;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
314
|
function notEqual(Fr a, Fr b) pure returns (bool) {
|
|
282
315
|
unchecked {
|
|
283
316
|
return Fr.unwrap(a) != Fr.unwrap(b);
|
|
@@ -290,9 +323,9 @@ function equal(Fr a, Fr b) pure returns (bool) {
|
|
|
290
323
|
}
|
|
291
324
|
}
|
|
292
325
|
|
|
293
|
-
uint256 constant CONST_PROOF_SIZE_LOG_N =
|
|
326
|
+
uint256 constant CONST_PROOF_SIZE_LOG_N = 25;
|
|
294
327
|
|
|
295
|
-
uint256 constant NUMBER_OF_SUBRELATIONS =
|
|
328
|
+
uint256 constant NUMBER_OF_SUBRELATIONS = 29;
|
|
296
329
|
uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8;
|
|
297
330
|
uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9;
|
|
298
331
|
uint256 constant NUMBER_OF_ENTITIES = 41;
|
|
@@ -302,7 +335,7 @@ uint256 constant NUMBER_OF_ENTITIES_ZK = NUMBER_OF_ENTITIES + NUM_MASKING_POLYNO
|
|
|
302
335
|
uint256 constant NUMBER_UNSHIFTED = 36;
|
|
303
336
|
uint256 constant NUMBER_UNSHIFTED_ZK = NUMBER_UNSHIFTED + NUM_MASKING_POLYNOMIALS;
|
|
304
337
|
uint256 constant NUMBER_TO_BE_SHIFTED = 5;
|
|
305
|
-
uint256 constant PAIRING_POINTS_SIZE =
|
|
338
|
+
uint256 constant PAIRING_POINTS_SIZE = 8;
|
|
306
339
|
|
|
307
340
|
uint256 constant FIELD_ELEMENT_SIZE = 0x20;
|
|
308
341
|
uint256 constant GROUP_ELEMENT_SIZE = 0x40;
|
|
@@ -310,22 +343,8 @@ uint256 constant GROUP_ELEMENT_SIZE = 0x40;
|
|
|
310
343
|
// Powers of alpha used to batch subrelations (alpha, alpha^2, ..., alpha^(NUM_SUBRELATIONS-1))
|
|
311
344
|
uint256 constant NUMBER_OF_ALPHAS = NUMBER_OF_SUBRELATIONS - 1;
|
|
312
345
|
|
|
313
|
-
//
|
|
346
|
+
// Must match UltraFlavor_Generated::EntityId order.
|
|
314
347
|
enum WIRE {
|
|
315
|
-
Q_M,
|
|
316
|
-
Q_C,
|
|
317
|
-
Q_L,
|
|
318
|
-
Q_R,
|
|
319
|
-
Q_O,
|
|
320
|
-
Q_4,
|
|
321
|
-
Q_LOOKUP,
|
|
322
|
-
Q_ARITH,
|
|
323
|
-
Q_RANGE,
|
|
324
|
-
Q_ELLIPTIC,
|
|
325
|
-
Q_MEMORY,
|
|
326
|
-
Q_NNF,
|
|
327
|
-
Q_POSEIDON2_EXTERNAL,
|
|
328
|
-
Q_POSEIDON2_INTERNAL,
|
|
329
348
|
SIGMA_1,
|
|
330
349
|
SIGMA_2,
|
|
331
350
|
SIGMA_3,
|
|
@@ -334,12 +353,26 @@ enum WIRE {
|
|
|
334
353
|
ID_2,
|
|
335
354
|
ID_3,
|
|
336
355
|
ID_4,
|
|
356
|
+
LAGRANGE_FIRST,
|
|
357
|
+
LAGRANGE_LAST,
|
|
358
|
+
Q_LOOKUP,
|
|
337
359
|
TABLE_1,
|
|
338
360
|
TABLE_2,
|
|
339
361
|
TABLE_3,
|
|
340
362
|
TABLE_4,
|
|
341
|
-
|
|
342
|
-
|
|
363
|
+
Q_M,
|
|
364
|
+
Q_R,
|
|
365
|
+
Q_O,
|
|
366
|
+
Q_C,
|
|
367
|
+
Q_L,
|
|
368
|
+
Q_4,
|
|
369
|
+
Q_ARITH,
|
|
370
|
+
Q_RANGE,
|
|
371
|
+
Q_ELLIPTIC,
|
|
372
|
+
Q_MEMORY,
|
|
373
|
+
Q_NNF,
|
|
374
|
+
Q_POSEIDON2_EXTERNAL,
|
|
375
|
+
Q_POSEIDON2_INTERNAL,
|
|
343
376
|
W_L,
|
|
344
377
|
W_R,
|
|
345
378
|
W_O,
|
|
@@ -404,8 +437,6 @@ library Honk {
|
|
|
404
437
|
struct RelationParameters {
|
|
405
438
|
// challenges
|
|
406
439
|
Fr eta;
|
|
407
|
-
Fr etaTwo;
|
|
408
|
-
Fr etaThree;
|
|
409
440
|
Fr beta;
|
|
410
441
|
Fr gamma;
|
|
411
442
|
// derived
|
|
@@ -525,8 +556,8 @@ library ZKTranscriptLib {
|
|
|
525
556
|
// Split into two equal 127-bit chunks (254/2)
|
|
526
557
|
uint256 lo = challengeU256 & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // 127 bits
|
|
527
558
|
uint256 hi = challengeU256 >> 127;
|
|
528
|
-
first = FrLib.
|
|
529
|
-
second = FrLib.
|
|
559
|
+
first = FrLib.from(lo);
|
|
560
|
+
second = FrLib.from(hi);
|
|
530
561
|
}
|
|
531
562
|
|
|
532
563
|
function generateRelationParametersChallenges(
|
|
@@ -536,9 +567,9 @@ library ZKTranscriptLib {
|
|
|
536
567
|
uint256 publicInputsSize,
|
|
537
568
|
Fr previousChallenge
|
|
538
569
|
) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) {
|
|
539
|
-
(rp.eta,
|
|
570
|
+
(rp.eta, previousChallenge) = generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize);
|
|
540
571
|
|
|
541
|
-
(rp.beta, rp.gamma, nextPreviousChallenge) =
|
|
572
|
+
(rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaGammaChallenges(previousChallenge, proof);
|
|
542
573
|
}
|
|
543
574
|
|
|
544
575
|
function generateEtaChallenge(
|
|
@@ -546,13 +577,14 @@ library ZKTranscriptLib {
|
|
|
546
577
|
bytes32[] calldata publicInputs,
|
|
547
578
|
uint256 vkHash,
|
|
548
579
|
uint256 publicInputsSize
|
|
549
|
-
) internal pure returns (Fr eta, Fr
|
|
580
|
+
) internal pure returns (Fr eta, Fr previousChallenge) {
|
|
550
581
|
// Size: 1 (vkHash) + publicInputsSize + 8 (geminiMask(2) + 3 wires(6))
|
|
551
582
|
bytes32[] memory round0 = new bytes32[](1 + publicInputsSize + 8);
|
|
552
583
|
round0[0] = bytes32(vkHash);
|
|
553
584
|
|
|
554
585
|
for (uint256 i = 0; i < publicInputsSize - PAIRING_POINTS_SIZE; i++) {
|
|
555
|
-
|
|
586
|
+
require(uint256(publicInputs[i]) < P, Errors.ValueGeFieldOrder());
|
|
587
|
+
round0[1 + i] = publicInputs[i];
|
|
556
588
|
}
|
|
557
589
|
for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) {
|
|
558
590
|
round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]);
|
|
@@ -571,14 +603,11 @@ library ZKTranscriptLib {
|
|
|
571
603
|
round0[1 + publicInputsSize + 6] = bytes32(proof.w3.x);
|
|
572
604
|
round0[1 + publicInputsSize + 7] = bytes32(proof.w3.y);
|
|
573
605
|
|
|
574
|
-
previousChallenge = FrLib.
|
|
575
|
-
(eta,
|
|
576
|
-
previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))));
|
|
577
|
-
|
|
578
|
-
(etaThree, ) = splitChallenge(previousChallenge);
|
|
606
|
+
previousChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(round0))) % P);
|
|
607
|
+
(eta, ) = splitChallenge(previousChallenge);
|
|
579
608
|
}
|
|
580
609
|
|
|
581
|
-
function
|
|
610
|
+
function generateBetaGammaChallenges(
|
|
582
611
|
Fr previousChallenge,
|
|
583
612
|
Honk.ZKProof memory proof
|
|
584
613
|
) internal pure returns (Fr beta, Fr gamma, Fr nextPreviousChallenge) {
|
|
@@ -591,7 +620,7 @@ library ZKTranscriptLib {
|
|
|
591
620
|
round1[5] = bytes32(proof.w4.x);
|
|
592
621
|
round1[6] = bytes32(proof.w4.y);
|
|
593
622
|
|
|
594
|
-
nextPreviousChallenge = FrLib.
|
|
623
|
+
nextPreviousChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(round1))) % P);
|
|
595
624
|
(beta, gamma) = splitChallenge(nextPreviousChallenge);
|
|
596
625
|
}
|
|
597
626
|
|
|
@@ -608,7 +637,7 @@ library ZKTranscriptLib {
|
|
|
608
637
|
alpha0[3] = proof.zPerm.x;
|
|
609
638
|
alpha0[4] = proof.zPerm.y;
|
|
610
639
|
|
|
611
|
-
nextPreviousChallenge = FrLib.
|
|
640
|
+
nextPreviousChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(alpha0))) % P);
|
|
612
641
|
Fr alpha;
|
|
613
642
|
(alpha, ) = splitChallenge(nextPreviousChallenge);
|
|
614
643
|
|
|
@@ -623,7 +652,7 @@ library ZKTranscriptLib {
|
|
|
623
652
|
Fr previousChallenge,
|
|
624
653
|
uint256 logN
|
|
625
654
|
) internal pure returns (Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, Fr nextPreviousChallenge) {
|
|
626
|
-
previousChallenge = FrLib.
|
|
655
|
+
previousChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))) % P);
|
|
627
656
|
(gateChallenges[0], ) = splitChallenge(previousChallenge);
|
|
628
657
|
for (uint256 i = 1; i < logN; i++) {
|
|
629
658
|
gateChallenges[i] = gateChallenges[i - 1] * gateChallenges[i - 1];
|
|
@@ -641,7 +670,7 @@ library ZKTranscriptLib {
|
|
|
641
670
|
challengeData[1] = proof.libraCommitments[0].x;
|
|
642
671
|
challengeData[2] = proof.libraCommitments[0].y;
|
|
643
672
|
challengeData[3] = Fr.unwrap(proof.libraSum);
|
|
644
|
-
nextPreviousChallenge = FrLib.
|
|
673
|
+
nextPreviousChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(challengeData))) % P);
|
|
645
674
|
(libraChallenge, ) = splitChallenge(nextPreviousChallenge);
|
|
646
675
|
}
|
|
647
676
|
|
|
@@ -657,7 +686,7 @@ library ZKTranscriptLib {
|
|
|
657
686
|
for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) {
|
|
658
687
|
univariateChal[j + 1] = proof.sumcheckUnivariates[i][j];
|
|
659
688
|
}
|
|
660
|
-
prevChallenge = FrLib.
|
|
689
|
+
prevChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(univariateChal))) % P);
|
|
661
690
|
|
|
662
691
|
(sumcheckChallenges[i], ) = splitChallenge(prevChallenge);
|
|
663
692
|
}
|
|
@@ -680,7 +709,7 @@ library ZKTranscriptLib {
|
|
|
680
709
|
rhoChallengeElements[i] = proof.libraCommitments[2].x;
|
|
681
710
|
rhoChallengeElements[i + 1] = proof.libraCommitments[2].y;
|
|
682
711
|
|
|
683
|
-
nextPreviousChallenge = FrLib.
|
|
712
|
+
nextPreviousChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(rhoChallengeElements))) % P);
|
|
684
713
|
(rho, ) = splitChallenge(nextPreviousChallenge);
|
|
685
714
|
}
|
|
686
715
|
|
|
@@ -697,7 +726,7 @@ library ZKTranscriptLib {
|
|
|
697
726
|
gR[2 + i * 2] = proof.geminiFoldComms[i].y;
|
|
698
727
|
}
|
|
699
728
|
|
|
700
|
-
nextPreviousChallenge = FrLib.
|
|
729
|
+
nextPreviousChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(gR))) % P);
|
|
701
730
|
|
|
702
731
|
(geminiR, ) = splitChallenge(nextPreviousChallenge);
|
|
703
732
|
}
|
|
@@ -720,7 +749,7 @@ library ZKTranscriptLib {
|
|
|
720
749
|
libraIdx++;
|
|
721
750
|
}
|
|
722
751
|
|
|
723
|
-
nextPreviousChallenge = FrLib.
|
|
752
|
+
nextPreviousChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(shplonkNuChallengeElements))) % P);
|
|
724
753
|
(shplonkNu, ) = splitChallenge(nextPreviousChallenge);
|
|
725
754
|
}
|
|
726
755
|
|
|
@@ -734,7 +763,7 @@ library ZKTranscriptLib {
|
|
|
734
763
|
shplonkZChallengeElements[1] = proof.shplonkQ.x;
|
|
735
764
|
shplonkZChallengeElements[2] = proof.shplonkQ.y;
|
|
736
765
|
|
|
737
|
-
nextPreviousChallenge = FrLib.
|
|
766
|
+
nextPreviousChallenge = FrLib.from(uint256(keccak256(abi.encodePacked(shplonkZChallengeElements))) % P);
|
|
738
767
|
(shplonkZ, ) = splitChallenge(nextPreviousChallenge);
|
|
739
768
|
}
|
|
740
769
|
|
|
@@ -743,7 +772,10 @@ library ZKTranscriptLib {
|
|
|
743
772
|
|
|
744
773
|
// Pairing point object
|
|
745
774
|
for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) {
|
|
746
|
-
|
|
775
|
+
uint256 limb = uint256(bytes32(proof[boundary:boundary + FIELD_ELEMENT_SIZE]));
|
|
776
|
+
// lo limbs (even index) < 2^136, hi limbs (odd index) < 2^120
|
|
777
|
+
require(limb < 2 ** (i % 2 == 0 ? 136 : 120), Errors.ValueGeLimbMax());
|
|
778
|
+
p.pairingPointObject[i] = FrLib.from(limb);
|
|
747
779
|
boundary += FIELD_ELEMENT_SIZE;
|
|
748
780
|
}
|
|
749
781
|
|
|
@@ -823,17 +855,98 @@ library ZKTranscriptLib {
|
|
|
823
855
|
}
|
|
824
856
|
}
|
|
825
857
|
|
|
826
|
-
// Field arithmetic libraries
|
|
827
|
-
|
|
828
858
|
library RelationsLib {
|
|
859
|
+
struct EllipticParams {
|
|
860
|
+
// Points
|
|
861
|
+
Fr x_1;
|
|
862
|
+
Fr y_1;
|
|
863
|
+
Fr x_2;
|
|
864
|
+
Fr y_2;
|
|
865
|
+
Fr y_3;
|
|
866
|
+
Fr x_3;
|
|
867
|
+
// push accumulators into memory
|
|
868
|
+
Fr x_double_identity;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// Parameters used within the Memory Relation
|
|
872
|
+
// A struct is used to work around stack too deep. This relation has alot of variables
|
|
873
|
+
struct MemParams {
|
|
874
|
+
Fr memory_record_check;
|
|
875
|
+
Fr partial_record_check;
|
|
876
|
+
Fr next_gate_access_type;
|
|
877
|
+
Fr record_delta;
|
|
878
|
+
Fr index_delta;
|
|
879
|
+
Fr adjacent_values_match_if_adjacent_indices_match;
|
|
880
|
+
Fr adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation;
|
|
881
|
+
Fr access_check;
|
|
882
|
+
Fr next_gate_access_type_is_boolean;
|
|
883
|
+
Fr ROM_consistency_check_identity;
|
|
884
|
+
Fr RAM_consistency_check_identity;
|
|
885
|
+
Fr timestamp_delta;
|
|
886
|
+
Fr RAM_timestamp_check_identity;
|
|
887
|
+
Fr memory_identity;
|
|
888
|
+
Fr index_is_monotonically_increasing;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// Parameters used within the Non-Native Field Relation
|
|
892
|
+
// A struct is used to work around stack too deep. This relation has alot of variables
|
|
893
|
+
struct NnfParams {
|
|
894
|
+
Fr limb_subproduct;
|
|
895
|
+
Fr non_native_field_gate_1;
|
|
896
|
+
Fr non_native_field_gate_2;
|
|
897
|
+
Fr non_native_field_gate_3;
|
|
898
|
+
Fr limb_accumulator_1;
|
|
899
|
+
Fr limb_accumulator_2;
|
|
900
|
+
Fr nnf_identity;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
struct PoseidonExternalParams {
|
|
904
|
+
Fr s1;
|
|
905
|
+
Fr s2;
|
|
906
|
+
Fr s3;
|
|
907
|
+
Fr s4;
|
|
908
|
+
Fr u1;
|
|
909
|
+
Fr u2;
|
|
910
|
+
Fr u3;
|
|
911
|
+
Fr u4;
|
|
912
|
+
Fr t0;
|
|
913
|
+
Fr t1;
|
|
914
|
+
Fr t2;
|
|
915
|
+
Fr t3;
|
|
916
|
+
Fr v1;
|
|
917
|
+
Fr v2;
|
|
918
|
+
Fr v3;
|
|
919
|
+
Fr v4;
|
|
920
|
+
Fr q_pos_by_scaling;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
struct PoseidonInternalParams {
|
|
924
|
+
Fr u1;
|
|
925
|
+
Fr u2;
|
|
926
|
+
Fr u3;
|
|
927
|
+
Fr u4;
|
|
928
|
+
Fr u_sum;
|
|
929
|
+
Fr v1;
|
|
930
|
+
Fr v2;
|
|
931
|
+
Fr v3;
|
|
932
|
+
Fr v4;
|
|
933
|
+
Fr s1;
|
|
934
|
+
Fr q_pos_by_scaling;
|
|
935
|
+
}
|
|
936
|
+
|
|
829
937
|
Fr internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = Fr.wrap(17); // -(-17)
|
|
938
|
+
uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;
|
|
939
|
+
|
|
940
|
+
// Constants for the Non-native Field relation
|
|
941
|
+
Fr internal constant LIMB_SIZE = Fr.wrap(uint256(1) << 68);
|
|
942
|
+
Fr internal constant SUBLIMB_SHIFT = Fr.wrap(uint256(1) << 14);
|
|
830
943
|
|
|
831
944
|
function accumulateRelationEvaluations(
|
|
832
945
|
Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations,
|
|
833
946
|
Honk.RelationParameters memory rp,
|
|
834
947
|
Fr[NUMBER_OF_ALPHAS] memory subrelationChallenges,
|
|
835
948
|
Fr powPartialEval
|
|
836
|
-
)
|
|
949
|
+
) external pure returns (Fr accumulator) {
|
|
837
950
|
Fr[NUMBER_OF_SUBRELATIONS] memory evaluations;
|
|
838
951
|
|
|
839
952
|
// Accumulate all relations in Ultra Honk - each with varying number of subrelations
|
|
@@ -860,12 +973,10 @@ library RelationsLib {
|
|
|
860
973
|
return p[uint256(_wire)];
|
|
861
974
|
}
|
|
862
975
|
|
|
863
|
-
uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;
|
|
864
976
|
/**
|
|
865
977
|
* Ultra Arithmetic Relation
|
|
866
978
|
*
|
|
867
979
|
*/
|
|
868
|
-
|
|
869
980
|
function accumulateArithmeticRelation(
|
|
870
981
|
Fr[NUMBER_OF_ENTITIES] memory p,
|
|
871
982
|
Fr[NUMBER_OF_SUBRELATIONS] memory evals,
|
|
@@ -887,7 +998,7 @@ library RelationsLib {
|
|
|
887
998
|
accum = accum + (q_arith - ONE) * wire(p, WIRE.W_4_SHIFT);
|
|
888
999
|
accum = accum * q_arith;
|
|
889
1000
|
accum = accum * domainSep;
|
|
890
|
-
evals[
|
|
1001
|
+
evals[6] = accum;
|
|
891
1002
|
}
|
|
892
1003
|
|
|
893
1004
|
// Relation 1
|
|
@@ -897,7 +1008,7 @@ library RelationsLib {
|
|
|
897
1008
|
accum = accum * (q_arith - ONE);
|
|
898
1009
|
accum = accum * q_arith;
|
|
899
1010
|
accum = accum * domainSep;
|
|
900
|
-
evals[
|
|
1011
|
+
evals[7] = accum;
|
|
901
1012
|
}
|
|
902
1013
|
}
|
|
903
1014
|
|
|
@@ -933,13 +1044,19 @@ library RelationsLib {
|
|
|
933
1044
|
|
|
934
1045
|
acc = acc - ((wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) * grand_product_denominator);
|
|
935
1046
|
acc = acc * domainSep;
|
|
936
|
-
evals[
|
|
1047
|
+
evals[0] = acc;
|
|
937
1048
|
}
|
|
938
1049
|
|
|
939
1050
|
// Contribution 3
|
|
940
1051
|
{
|
|
941
1052
|
Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep;
|
|
942
|
-
evals[
|
|
1053
|
+
evals[1] = acc;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// Contribution 4: z_perm initialization check (lagrange_first * z_perm = 0)
|
|
1057
|
+
{
|
|
1058
|
+
Fr acc = (wire(p, WIRE.LAGRANGE_FIRST) * wire(p, WIRE.Z_PERM)) * domainSep;
|
|
1059
|
+
evals[2] = acc;
|
|
943
1060
|
}
|
|
944
1061
|
}
|
|
945
1062
|
|
|
@@ -949,49 +1066,53 @@ library RelationsLib {
|
|
|
949
1066
|
Fr[NUMBER_OF_SUBRELATIONS] memory evals,
|
|
950
1067
|
Fr domainSep
|
|
951
1068
|
) internal pure {
|
|
952
|
-
Fr
|
|
953
|
-
Fr
|
|
1069
|
+
Fr table_term;
|
|
1070
|
+
Fr lookup_term;
|
|
954
1071
|
|
|
955
1072
|
// Calculate the write term (the table accumulation)
|
|
1073
|
+
// table_term = table_1 + γ + table_2 * β + table_3 * β² + table_4 * β³
|
|
956
1074
|
{
|
|
957
|
-
|
|
1075
|
+
Fr beta_sqr = rp.beta * rp.beta;
|
|
1076
|
+
table_term =
|
|
958
1077
|
wire(p, WIRE.TABLE_1) +
|
|
959
1078
|
rp.gamma +
|
|
960
|
-
(wire(p, WIRE.TABLE_2) * rp.
|
|
961
|
-
(wire(p, WIRE.TABLE_3) *
|
|
962
|
-
(wire(p, WIRE.TABLE_4) * rp.
|
|
1079
|
+
(wire(p, WIRE.TABLE_2) * rp.beta) +
|
|
1080
|
+
(wire(p, WIRE.TABLE_3) * beta_sqr) +
|
|
1081
|
+
(wire(p, WIRE.TABLE_4) * beta_sqr * rp.beta);
|
|
963
1082
|
}
|
|
964
1083
|
|
|
965
|
-
// Calculate the
|
|
1084
|
+
// Calculate the read term
|
|
1085
|
+
// lookup_term = derived_entry_1 + γ + derived_entry_2 * β + derived_entry_3 * β² + q_index * β³
|
|
966
1086
|
{
|
|
1087
|
+
Fr beta_sqr = rp.beta * rp.beta;
|
|
967
1088
|
Fr derived_entry_1 = wire(p, WIRE.W_L) + rp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT));
|
|
968
1089
|
Fr derived_entry_2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_M) * wire(p, WIRE.W_R_SHIFT);
|
|
969
1090
|
Fr derived_entry_3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_C) * wire(p, WIRE.W_O_SHIFT);
|
|
970
1091
|
|
|
971
|
-
|
|
1092
|
+
lookup_term = derived_entry_1 + (derived_entry_2 * rp.beta) + (derived_entry_3 * beta_sqr) + (wire(p, WIRE.Q_O) * beta_sqr * rp.beta);
|
|
972
1093
|
}
|
|
973
1094
|
|
|
974
|
-
Fr
|
|
975
|
-
Fr
|
|
1095
|
+
Fr lookup_inverse = wire(p, WIRE.LOOKUP_INVERSES) * table_term;
|
|
1096
|
+
Fr table_inverse = wire(p, WIRE.LOOKUP_INVERSES) * lookup_term;
|
|
976
1097
|
|
|
977
1098
|
Fr inverse_exists_xor = wire(p, WIRE.LOOKUP_READ_TAGS) +
|
|
978
1099
|
wire(p, WIRE.Q_LOOKUP) -
|
|
979
1100
|
(wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP));
|
|
980
1101
|
|
|
981
1102
|
// Inverse calculated correctly relation
|
|
982
|
-
Fr accumulatorNone =
|
|
1103
|
+
Fr accumulatorNone = lookup_term * table_term * wire(p, WIRE.LOOKUP_INVERSES) - inverse_exists_xor;
|
|
983
1104
|
accumulatorNone = accumulatorNone * domainSep;
|
|
984
1105
|
|
|
985
1106
|
// Inverse
|
|
986
|
-
Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) *
|
|
1107
|
+
Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * lookup_inverse - wire(p, WIRE.LOOKUP_READ_COUNTS) * table_inverse;
|
|
987
1108
|
|
|
988
1109
|
Fr read_tag = wire(p, WIRE.LOOKUP_READ_TAGS);
|
|
989
1110
|
|
|
990
1111
|
Fr read_tag_boolean_relation = read_tag * read_tag - read_tag;
|
|
991
1112
|
|
|
992
|
-
evals[
|
|
993
|
-
evals[
|
|
994
|
-
evals[
|
|
1113
|
+
evals[3] = accumulatorNone;
|
|
1114
|
+
evals[4] = accumulatorOne;
|
|
1115
|
+
evals[5] = read_tag_boolean_relation * domainSep;
|
|
995
1116
|
}
|
|
996
1117
|
|
|
997
1118
|
function accumulateDeltaRangeRelation(
|
|
@@ -1017,7 +1138,7 @@ library RelationsLib {
|
|
|
1017
1138
|
acc = acc * (delta_1 + minus_three);
|
|
1018
1139
|
acc = acc * wire(p, WIRE.Q_RANGE);
|
|
1019
1140
|
acc = acc * domainSep;
|
|
1020
|
-
evals[
|
|
1141
|
+
evals[8] = acc;
|
|
1021
1142
|
}
|
|
1022
1143
|
|
|
1023
1144
|
// Contribution 7
|
|
@@ -1028,7 +1149,7 @@ library RelationsLib {
|
|
|
1028
1149
|
acc = acc * (delta_2 + minus_three);
|
|
1029
1150
|
acc = acc * wire(p, WIRE.Q_RANGE);
|
|
1030
1151
|
acc = acc * domainSep;
|
|
1031
|
-
evals[
|
|
1152
|
+
evals[9] = acc;
|
|
1032
1153
|
}
|
|
1033
1154
|
|
|
1034
1155
|
// Contribution 8
|
|
@@ -1039,7 +1160,7 @@ library RelationsLib {
|
|
|
1039
1160
|
acc = acc * (delta_3 + minus_three);
|
|
1040
1161
|
acc = acc * wire(p, WIRE.Q_RANGE);
|
|
1041
1162
|
acc = acc * domainSep;
|
|
1042
|
-
evals[
|
|
1163
|
+
evals[10] = acc;
|
|
1043
1164
|
}
|
|
1044
1165
|
|
|
1045
1166
|
// Contribution 9
|
|
@@ -1050,22 +1171,10 @@ library RelationsLib {
|
|
|
1050
1171
|
acc = acc * (delta_4 + minus_three);
|
|
1051
1172
|
acc = acc * wire(p, WIRE.Q_RANGE);
|
|
1052
1173
|
acc = acc * domainSep;
|
|
1053
|
-
evals[
|
|
1174
|
+
evals[11] = acc;
|
|
1054
1175
|
}
|
|
1055
1176
|
}
|
|
1056
1177
|
|
|
1057
|
-
struct EllipticParams {
|
|
1058
|
-
// Points
|
|
1059
|
-
Fr x_1;
|
|
1060
|
-
Fr y_1;
|
|
1061
|
-
Fr x_2;
|
|
1062
|
-
Fr y_2;
|
|
1063
|
-
Fr y_3;
|
|
1064
|
-
Fr x_3;
|
|
1065
|
-
// push accumulators into memory
|
|
1066
|
-
Fr x_double_identity;
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
1178
|
function accumulateEllipticRelation(
|
|
1070
1179
|
Fr[NUMBER_OF_ENTITIES] memory p,
|
|
1071
1180
|
Fr[NUMBER_OF_SUBRELATIONS] memory evals,
|
|
@@ -1097,7 +1206,7 @@ library RelationsLib {
|
|
|
1097
1206
|
x_add_identity = x_add_identity * x_diff * x_diff;
|
|
1098
1207
|
x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2;
|
|
1099
1208
|
|
|
1100
|
-
evals[
|
|
1209
|
+
evals[12] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double);
|
|
1101
1210
|
}
|
|
1102
1211
|
|
|
1103
1212
|
// Contribution 11 point addition, x-coordinate check
|
|
@@ -1106,7 +1215,7 @@ library RelationsLib {
|
|
|
1106
1215
|
Fr y1_plus_y3 = ep.y_1 + ep.y_3;
|
|
1107
1216
|
Fr y_diff = ep.y_2 * q_sign - ep.y_1;
|
|
1108
1217
|
Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff;
|
|
1109
|
-
evals[
|
|
1218
|
+
evals[13] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double);
|
|
1110
1219
|
}
|
|
1111
1220
|
|
|
1112
1221
|
// Contribution 10 point doubling, x-coordinate check
|
|
@@ -1122,7 +1231,7 @@ library RelationsLib {
|
|
|
1122
1231
|
ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9;
|
|
1123
1232
|
|
|
1124
1233
|
Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double;
|
|
1125
|
-
evals[
|
|
1234
|
+
evals[12] = evals[12] + acc;
|
|
1126
1235
|
}
|
|
1127
1236
|
|
|
1128
1237
|
// Contribution 11 point doubling, y-coordinate check
|
|
@@ -1130,30 +1239,10 @@ library RelationsLib {
|
|
|
1130
1239
|
{
|
|
1131
1240
|
Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1;
|
|
1132
1241
|
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);
|
|
1133
|
-
evals[
|
|
1242
|
+
evals[13] = evals[13] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double;
|
|
1134
1243
|
}
|
|
1135
1244
|
}
|
|
1136
1245
|
|
|
1137
|
-
// Parameters used within the Memory Relation
|
|
1138
|
-
// A struct is used to work around stack too deep. This relation has alot of variables
|
|
1139
|
-
struct MemParams {
|
|
1140
|
-
Fr memory_record_check;
|
|
1141
|
-
Fr partial_record_check;
|
|
1142
|
-
Fr next_gate_access_type;
|
|
1143
|
-
Fr record_delta;
|
|
1144
|
-
Fr index_delta;
|
|
1145
|
-
Fr adjacent_values_match_if_adjacent_indices_match;
|
|
1146
|
-
Fr adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation;
|
|
1147
|
-
Fr access_check;
|
|
1148
|
-
Fr next_gate_access_type_is_boolean;
|
|
1149
|
-
Fr ROM_consistency_check_identity;
|
|
1150
|
-
Fr RAM_consistency_check_identity;
|
|
1151
|
-
Fr timestamp_delta;
|
|
1152
|
-
Fr RAM_timestamp_check_identity;
|
|
1153
|
-
Fr memory_identity;
|
|
1154
|
-
Fr index_is_monotonically_increasing;
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
1246
|
function accumulateMemoryRelation(
|
|
1158
1247
|
Fr[NUMBER_OF_ENTITIES] memory p,
|
|
1159
1248
|
Honk.RelationParameters memory rp,
|
|
@@ -1162,6 +1251,10 @@ library RelationsLib {
|
|
|
1162
1251
|
) internal pure {
|
|
1163
1252
|
MemParams memory ap;
|
|
1164
1253
|
|
|
1254
|
+
// Compute eta powers locally
|
|
1255
|
+
Fr eta_two = rp.eta * rp.eta;
|
|
1256
|
+
Fr eta_three = eta_two * rp.eta;
|
|
1257
|
+
|
|
1165
1258
|
/**
|
|
1166
1259
|
* MEMORY
|
|
1167
1260
|
*
|
|
@@ -1203,8 +1296,8 @@ library RelationsLib {
|
|
|
1203
1296
|
*
|
|
1204
1297
|
* For ROM gates, qc = 0
|
|
1205
1298
|
*/
|
|
1206
|
-
ap.memory_record_check = wire(p, WIRE.W_O) *
|
|
1207
|
-
ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) *
|
|
1299
|
+
ap.memory_record_check = wire(p, WIRE.W_O) * eta_three;
|
|
1300
|
+
ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * eta_two);
|
|
1208
1301
|
ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * rp.eta);
|
|
1209
1302
|
ap.memory_record_check = ap.memory_record_check + wire(p, WIRE.Q_C);
|
|
1210
1303
|
ap.partial_record_check = ap.memory_record_check; // used in RAM consistency check; deg 1 or 4
|
|
@@ -1233,11 +1326,11 @@ library RelationsLib {
|
|
|
1233
1326
|
|
|
1234
1327
|
ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + ONE) * ap.record_delta; // deg 2
|
|
1235
1328
|
|
|
1236
|
-
evals[
|
|
1329
|
+
evals[15] =
|
|
1237
1330
|
ap.adjacent_values_match_if_adjacent_indices_match *
|
|
1238
1331
|
(wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) *
|
|
1239
1332
|
(wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5
|
|
1240
|
-
evals[
|
|
1333
|
+
evals[16] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5
|
|
1241
1334
|
|
|
1242
1335
|
ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7
|
|
1243
1336
|
|
|
@@ -1265,8 +1358,8 @@ library RelationsLib {
|
|
|
1265
1358
|
|
|
1266
1359
|
// reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta
|
|
1267
1360
|
// deg 1 or 4
|
|
1268
|
-
ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) *
|
|
1269
|
-
ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) *
|
|
1361
|
+
ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * eta_three;
|
|
1362
|
+
ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * eta_two);
|
|
1270
1363
|
ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta);
|
|
1271
1364
|
ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type;
|
|
1272
1365
|
|
|
@@ -1284,12 +1377,12 @@ library RelationsLib {
|
|
|
1284
1377
|
ap.next_gate_access_type_is_boolean = ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type;
|
|
1285
1378
|
|
|
1286
1379
|
// Putting it all together...
|
|
1287
|
-
evals[
|
|
1380
|
+
evals[17] =
|
|
1288
1381
|
ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation *
|
|
1289
1382
|
(wire(p, WIRE.Q_O)) *
|
|
1290
1383
|
(wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8
|
|
1291
|
-
evals[
|
|
1292
|
-
evals[
|
|
1384
|
+
evals[18] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4
|
|
1385
|
+
evals[19] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6
|
|
1293
1386
|
|
|
1294
1387
|
ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9
|
|
1295
1388
|
|
|
@@ -1319,23 +1412,7 @@ library RelationsLib {
|
|
|
1319
1412
|
|
|
1320
1413
|
// (deg 3 or 9) + (deg 4) + (deg 3)
|
|
1321
1414
|
ap.memory_identity = ap.memory_identity * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10
|
|
1322
|
-
evals[
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
// Constants for the Non-native Field relation
|
|
1326
|
-
Fr constant LIMB_SIZE = Fr.wrap(uint256(1) << 68);
|
|
1327
|
-
Fr constant SUBLIMB_SHIFT = Fr.wrap(uint256(1) << 14);
|
|
1328
|
-
|
|
1329
|
-
// Parameters used within the Non-Native Field Relation
|
|
1330
|
-
// A struct is used to work around stack too deep. This relation has alot of variables
|
|
1331
|
-
struct NnfParams {
|
|
1332
|
-
Fr limb_subproduct;
|
|
1333
|
-
Fr non_native_field_gate_1;
|
|
1334
|
-
Fr non_native_field_gate_2;
|
|
1335
|
-
Fr non_native_field_gate_3;
|
|
1336
|
-
Fr limb_accumulator_1;
|
|
1337
|
-
Fr limb_accumulator_2;
|
|
1338
|
-
Fr nnf_identity;
|
|
1415
|
+
evals[14] = ap.memory_identity;
|
|
1339
1416
|
}
|
|
1340
1417
|
|
|
1341
1418
|
function accumulateNnfRelation(Fr[NUMBER_OF_ENTITIES] memory p, Fr[NUMBER_OF_SUBRELATIONS] memory evals, Fr domainSep) internal pure {
|
|
@@ -1405,27 +1482,7 @@ library RelationsLib {
|
|
|
1405
1482
|
|
|
1406
1483
|
ap.nnf_identity = non_native_field_identity + limb_accumulator_identity;
|
|
1407
1484
|
ap.nnf_identity = ap.nnf_identity * (wire(p, WIRE.Q_NNF) * domainSep);
|
|
1408
|
-
evals[
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
struct PoseidonExternalParams {
|
|
1412
|
-
Fr s1;
|
|
1413
|
-
Fr s2;
|
|
1414
|
-
Fr s3;
|
|
1415
|
-
Fr s4;
|
|
1416
|
-
Fr u1;
|
|
1417
|
-
Fr u2;
|
|
1418
|
-
Fr u3;
|
|
1419
|
-
Fr u4;
|
|
1420
|
-
Fr t0;
|
|
1421
|
-
Fr t1;
|
|
1422
|
-
Fr t2;
|
|
1423
|
-
Fr t3;
|
|
1424
|
-
Fr v1;
|
|
1425
|
-
Fr v2;
|
|
1426
|
-
Fr v3;
|
|
1427
|
-
Fr v4;
|
|
1428
|
-
Fr q_pos_by_scaling;
|
|
1485
|
+
evals[20] = ap.nnf_identity;
|
|
1429
1486
|
}
|
|
1430
1487
|
|
|
1431
1488
|
function accumulatePoseidonExternalRelation(
|
|
@@ -1461,27 +1518,13 @@ library RelationsLib {
|
|
|
1461
1518
|
ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4
|
|
1462
1519
|
|
|
1463
1520
|
ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep;
|
|
1464
|
-
evals[
|
|
1465
|
-
|
|
1466
|
-
evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT));
|
|
1521
|
+
evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT));
|
|
1467
1522
|
|
|
1468
|
-
evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.
|
|
1523
|
+
evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT));
|
|
1469
1524
|
|
|
1470
|
-
evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.
|
|
1471
|
-
}
|
|
1525
|
+
evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT));
|
|
1472
1526
|
|
|
1473
|
-
|
|
1474
|
-
Fr u1;
|
|
1475
|
-
Fr u2;
|
|
1476
|
-
Fr u3;
|
|
1477
|
-
Fr u4;
|
|
1478
|
-
Fr u_sum;
|
|
1479
|
-
Fr v1;
|
|
1480
|
-
Fr v2;
|
|
1481
|
-
Fr v3;
|
|
1482
|
-
Fr v4;
|
|
1483
|
-
Fr s1;
|
|
1484
|
-
Fr q_pos_by_scaling;
|
|
1527
|
+
evals[24] = evals[24] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT));
|
|
1485
1528
|
}
|
|
1486
1529
|
|
|
1487
1530
|
function accumulatePoseidonInternalRelation(
|
|
@@ -1513,16 +1556,16 @@ library RelationsLib {
|
|
|
1513
1556
|
ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep;
|
|
1514
1557
|
|
|
1515
1558
|
ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum;
|
|
1516
|
-
evals[
|
|
1559
|
+
evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT));
|
|
1517
1560
|
|
|
1518
1561
|
ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum;
|
|
1519
|
-
evals[
|
|
1562
|
+
evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT));
|
|
1520
1563
|
|
|
1521
1564
|
ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum;
|
|
1522
|
-
evals[
|
|
1565
|
+
evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT));
|
|
1523
1566
|
|
|
1524
1567
|
ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum;
|
|
1525
|
-
evals[
|
|
1568
|
+
evals[28] = evals[28] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT));
|
|
1526
1569
|
}
|
|
1527
1570
|
|
|
1528
1571
|
// Batch subrelation evaluations using precomputed powers of alpha
|
|
@@ -1539,8 +1582,6 @@ library RelationsLib {
|
|
|
1539
1582
|
}
|
|
1540
1583
|
}
|
|
1541
1584
|
|
|
1542
|
-
// Field arithmetic libraries - prevent littering the code with modmul / addmul
|
|
1543
|
-
|
|
1544
1585
|
library CommitmentSchemeLib {
|
|
1545
1586
|
using FrLib for Fr;
|
|
1546
1587
|
|
|
@@ -1556,8 +1597,8 @@ library CommitmentSchemeLib {
|
|
|
1556
1597
|
Fr batchingChallenge;
|
|
1557
1598
|
// Linear combination of multilinear (sumcheck) evaluations and powers of rho
|
|
1558
1599
|
Fr batchedEvaluation;
|
|
1559
|
-
Fr[
|
|
1560
|
-
Fr[
|
|
1600
|
+
Fr[NUM_SMALL_IPA_OPENING_CLAIMS] denominators;
|
|
1601
|
+
Fr[NUM_SMALL_IPA_OPENING_CLAIMS] batchingScalars;
|
|
1561
1602
|
// 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated
|
|
1562
1603
|
Fr posInvertedDenominator;
|
|
1563
1604
|
// 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated
|
|
@@ -1570,16 +1611,7 @@ library CommitmentSchemeLib {
|
|
|
1570
1611
|
Fr[] foldPosEvaluations;
|
|
1571
1612
|
}
|
|
1572
1613
|
|
|
1573
|
-
function computeSquares(Fr r, uint256 logN) internal pure returns (Fr[] memory) {
|
|
1574
|
-
Fr[] memory squares = new Fr[](logN);
|
|
1575
|
-
squares[0] = r;
|
|
1576
|
-
for (uint256 i = 1; i < logN; ++i) {
|
|
1577
|
-
squares[i] = squares[i - 1].sqr();
|
|
1578
|
-
}
|
|
1579
|
-
return squares;
|
|
1580
|
-
}
|
|
1581
1614
|
// Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1
|
|
1582
|
-
|
|
1583
1615
|
function computeFoldPosEvaluations(
|
|
1584
1616
|
Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges,
|
|
1585
1617
|
Fr batchedEvalAccumulator,
|
|
@@ -1603,23 +1635,19 @@ library CommitmentSchemeLib {
|
|
|
1603
1635
|
}
|
|
1604
1636
|
return foldPosEvaluations;
|
|
1605
1637
|
}
|
|
1606
|
-
}
|
|
1607
1638
|
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
str[1] = "x";
|
|
1616
|
-
for (uint256 i = 0; i < 32; i++) {
|
|
1617
|
-
str[2 + i * 2] = alphabet[uint8(value[i] >> 4)];
|
|
1618
|
-
str[3 + i * 2] = alphabet[uint8(value[i] & 0x0f)];
|
|
1639
|
+
function computeSquares(Fr r, uint256 logN) internal pure returns (Fr[] memory) {
|
|
1640
|
+
Fr[] memory squares = new Fr[](logN);
|
|
1641
|
+
squares[0] = r;
|
|
1642
|
+
for (uint256 i = 1; i < logN; ++i) {
|
|
1643
|
+
squares[i] = squares[i - 1].sqr();
|
|
1644
|
+
}
|
|
1645
|
+
return squares;
|
|
1619
1646
|
}
|
|
1620
|
-
result = string(str);
|
|
1621
1647
|
}
|
|
1622
1648
|
|
|
1649
|
+
uint256 constant Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // EC group order. F_q
|
|
1650
|
+
|
|
1623
1651
|
// Fr utility
|
|
1624
1652
|
|
|
1625
1653
|
function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) {
|
|
@@ -1628,51 +1656,63 @@ function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) {
|
|
|
1628
1656
|
|
|
1629
1657
|
// EC Point utilities
|
|
1630
1658
|
function bytesToG1Point(bytes calldata proofSection) pure returns (Honk.G1Point memory point) {
|
|
1631
|
-
|
|
1659
|
+
uint256 x = uint256(bytes32(proofSection[0x00:0x20]));
|
|
1660
|
+
uint256 y = uint256(bytes32(proofSection[0x20:0x40]));
|
|
1661
|
+
require(x < Q && y < Q, Errors.ValueGeGroupOrder());
|
|
1662
|
+
|
|
1663
|
+
// (0,0) is the canonical EIP-196 encoding of the identity. It is accepted here
|
|
1664
|
+
// because polynomial commitments to identically-zero polynomials (e.g. unused
|
|
1665
|
+
// selector or table polys) are legitimately the identity. On-curve validation
|
|
1666
|
+
// (y² = x³ + 3) is handled by the ecAdd/ecMul precompiles per EIP-196.
|
|
1667
|
+
point = Honk.G1Point({ x: x, y: y });
|
|
1632
1668
|
}
|
|
1633
1669
|
|
|
1634
1670
|
function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) {
|
|
1635
|
-
|
|
1671
|
+
// When y == 0 (order-2 point), negation is the same point. Q - 0 = Q which is >= Q.
|
|
1672
|
+
if (point.y != 0) {
|
|
1673
|
+
point.y = Q - point.y;
|
|
1674
|
+
}
|
|
1636
1675
|
return point;
|
|
1637
1676
|
}
|
|
1638
1677
|
|
|
1639
1678
|
/**
|
|
1640
1679
|
* Convert the pairing points to G1 points.
|
|
1641
1680
|
*
|
|
1642
|
-
* The pairing points are serialised as an array of
|
|
1643
|
-
*
|
|
1681
|
+
* The pairing points are serialised as an array of 2 limbs representing two points
|
|
1682
|
+
* (P0 and P1, used for lhs and rhs of pairing operation).
|
|
1644
1683
|
*
|
|
1645
|
-
* There are
|
|
1684
|
+
* There are 2 limbs (lo, hi) for each coordinate, so 4 limbs per point, 8 total.
|
|
1685
|
+
* Layout: [P0.x_lo, P0.x_hi, P0.y_lo, P0.y_hi, P1.x_lo, P1.x_hi, P1.y_lo, P1.y_hi]
|
|
1646
1686
|
*
|
|
1647
1687
|
* @param pairingPoints The pairing points to convert.
|
|
1648
|
-
* @return lhs
|
|
1649
|
-
* @return rhs
|
|
1688
|
+
* @return lhs P0 point
|
|
1689
|
+
* @return rhs P1 point
|
|
1650
1690
|
*/
|
|
1651
1691
|
function convertPairingPointsToG1(
|
|
1652
1692
|
Fr[PAIRING_POINTS_SIZE] memory pairingPoints
|
|
1653
1693
|
) pure returns (Honk.G1Point memory lhs, Honk.G1Point memory rhs) {
|
|
1694
|
+
// P0 (lhs): x = lo | (hi << 136)
|
|
1654
1695
|
uint256 lhsX = Fr.unwrap(pairingPoints[0]);
|
|
1655
|
-
lhsX |= Fr.unwrap(pairingPoints[1]) <<
|
|
1656
|
-
lhsX |= Fr.unwrap(pairingPoints[2]) << 136;
|
|
1657
|
-
lhsX |= Fr.unwrap(pairingPoints[3]) << 204;
|
|
1658
|
-
lhs.x = lhsX;
|
|
1696
|
+
lhsX |= Fr.unwrap(pairingPoints[1]) << 136;
|
|
1659
1697
|
|
|
1660
|
-
uint256 lhsY = Fr.unwrap(pairingPoints[
|
|
1661
|
-
lhsY |= Fr.unwrap(pairingPoints[
|
|
1662
|
-
lhsY |= Fr.unwrap(pairingPoints[6]) << 136;
|
|
1663
|
-
lhsY |= Fr.unwrap(pairingPoints[7]) << 204;
|
|
1664
|
-
lhs.y = lhsY;
|
|
1698
|
+
uint256 lhsY = Fr.unwrap(pairingPoints[2]);
|
|
1699
|
+
lhsY |= Fr.unwrap(pairingPoints[3]) << 136;
|
|
1665
1700
|
|
|
1666
|
-
|
|
1667
|
-
rhsX
|
|
1668
|
-
rhsX |= Fr.unwrap(pairingPoints[
|
|
1669
|
-
|
|
1670
|
-
|
|
1701
|
+
// P1 (rhs): x = lo | (hi << 136)
|
|
1702
|
+
uint256 rhsX = Fr.unwrap(pairingPoints[4]);
|
|
1703
|
+
rhsX |= Fr.unwrap(pairingPoints[5]) << 136;
|
|
1704
|
+
|
|
1705
|
+
uint256 rhsY = Fr.unwrap(pairingPoints[6]);
|
|
1706
|
+
rhsY |= Fr.unwrap(pairingPoints[7]) << 136;
|
|
1671
1707
|
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
rhsY
|
|
1708
|
+
// Reconstructed coordinates must be < Q to prevent malleability.
|
|
1709
|
+
// Without this, two different limb encodings could map to the same curve point
|
|
1710
|
+
// (via mulmod reduction in on-curve checks) but produce different transcript hashes.
|
|
1711
|
+
require(lhsX < Q && lhsY < Q && rhsX < Q && rhsY < Q, Errors.ValueGeGroupOrder());
|
|
1712
|
+
|
|
1713
|
+
lhs.x = lhsX;
|
|
1714
|
+
lhs.y = lhsY;
|
|
1715
|
+
rhs.x = rhsX;
|
|
1676
1716
|
rhs.y = rhsY;
|
|
1677
1717
|
}
|
|
1678
1718
|
|
|
@@ -1710,7 +1750,7 @@ function generateRecursionSeparator(
|
|
|
1710
1750
|
recursionSeparatorElements[6] = accRhs.x;
|
|
1711
1751
|
recursionSeparatorElements[7] = accRhs.y;
|
|
1712
1752
|
|
|
1713
|
-
recursionSeparator = FrLib.
|
|
1753
|
+
recursionSeparator = FrLib.from(uint256(keccak256(abi.encodePacked(recursionSeparatorElements))) % P);
|
|
1714
1754
|
}
|
|
1715
1755
|
|
|
1716
1756
|
/**
|
|
@@ -1831,17 +1871,20 @@ function ecAdd(Honk.G1Point memory lhs, Honk.G1Point memory rhs) view returns (H
|
|
|
1831
1871
|
return result;
|
|
1832
1872
|
}
|
|
1833
1873
|
|
|
1834
|
-
function
|
|
1835
|
-
|
|
1836
|
-
|
|
1874
|
+
function rejectPointAtInfinity(Honk.G1Point memory point) pure {
|
|
1875
|
+
require((point.x | point.y) != 0, Errors.PointAtInfinity());
|
|
1876
|
+
}
|
|
1837
1877
|
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1878
|
+
/**
|
|
1879
|
+
* Check if pairing point limbs are all zero (default/infinity).
|
|
1880
|
+
* Default pairing points indicate no recursive verification occurred.
|
|
1881
|
+
*/
|
|
1882
|
+
function arePairingPointsDefault(Fr[PAIRING_POINTS_SIZE] memory pairingPoints) pure returns (bool) {
|
|
1883
|
+
uint256 acc = 0;
|
|
1884
|
+
for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) {
|
|
1885
|
+
acc |= Fr.unwrap(pairingPoints[i]);
|
|
1842
1886
|
}
|
|
1843
|
-
|
|
1844
|
-
require(success, "point is not on the curve");
|
|
1887
|
+
return acc == 0;
|
|
1845
1888
|
}
|
|
1846
1889
|
|
|
1847
1890
|
function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool decodedResult) {
|
|
@@ -1866,84 +1909,68 @@ function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns
|
|
|
1866
1909
|
decodedResult = success && abi.decode(result, (bool));
|
|
1867
1910
|
}
|
|
1868
1911
|
|
|
1869
|
-
// Field arithmetic libraries - prevent littering the code with modmul / addmul
|
|
1870
|
-
|
|
1871
1912
|
abstract contract BaseZKHonkVerifier is IVerifier {
|
|
1872
1913
|
using FrLib for Fr;
|
|
1873
1914
|
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
uint256 immutable $NUM_PUBLIC_INPUTS;
|
|
1878
|
-
uint256 immutable $MSMSize;
|
|
1879
|
-
|
|
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;
|
|
1885
|
-
$MSMSize = NUMBER_UNSHIFTED_ZK + _logN + LIBRA_COMMITMENTS + 2;
|
|
1915
|
+
struct PairingInputs {
|
|
1916
|
+
Honk.G1Point P_0;
|
|
1917
|
+
Honk.G1Point P_1;
|
|
1886
1918
|
}
|
|
1887
1919
|
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1920
|
+
struct SmallSubgroupIpaIntermediates {
|
|
1921
|
+
Fr[SUBGROUP_SIZE] challengePolyLagrange;
|
|
1922
|
+
Fr challengePolyEval;
|
|
1923
|
+
Fr lagrangeFirst;
|
|
1924
|
+
Fr lagrangeLast;
|
|
1925
|
+
Fr rootPower;
|
|
1926
|
+
Fr[SUBGROUP_SIZE] denominators; // this has to disappear
|
|
1927
|
+
Fr diff;
|
|
1928
|
+
}
|
|
1896
1929
|
|
|
1897
1930
|
// Constants for proof length calculation (matching UltraKeccakZKFlavor)
|
|
1898
|
-
uint256 constant NUM_WITNESS_ENTITIES = 8 + NUM_MASKING_POLYNOMIALS;
|
|
1899
|
-
uint256 constant NUM_ELEMENTS_COMM = 2; // uint256 elements for curve points
|
|
1900
|
-
uint256 constant NUM_ELEMENTS_FR = 1; // uint256 elements for field elements
|
|
1901
|
-
uint256 constant NUM_LIBRA_EVALUATIONS = 4; // libra evaluations
|
|
1931
|
+
uint256 internal constant NUM_WITNESS_ENTITIES = 8 + NUM_MASKING_POLYNOMIALS;
|
|
1932
|
+
uint256 internal constant NUM_ELEMENTS_COMM = 2; // uint256 elements for curve points
|
|
1933
|
+
uint256 internal constant NUM_ELEMENTS_FR = 1; // uint256 elements for field elements
|
|
1934
|
+
uint256 internal constant NUM_LIBRA_EVALUATIONS = 4; // libra evaluations
|
|
1902
1935
|
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
uint256 proofLength = NUM_WITNESS_ENTITIES * NUM_ELEMENTS_COMM; // witness commitments
|
|
1907
|
-
proofLength += NUM_ELEMENTS_COMM * 3; // Libra concat, grand sum, quotient comms + Gemini masking
|
|
1908
|
-
|
|
1909
|
-
// Sumcheck
|
|
1910
|
-
proofLength += logN * ZK_BATCHED_RELATION_PARTIAL_LENGTH * NUM_ELEMENTS_FR; // sumcheck univariates
|
|
1911
|
-
proofLength += NUMBER_OF_ENTITIES_ZK * NUM_ELEMENTS_FR; // sumcheck evaluations
|
|
1912
|
-
|
|
1913
|
-
// Libra and Gemini
|
|
1914
|
-
proofLength += NUM_ELEMENTS_FR * 2; // Libra sum, claimed eval
|
|
1915
|
-
proofLength += logN * NUM_ELEMENTS_FR; // Gemini a evaluations
|
|
1916
|
-
proofLength += NUM_LIBRA_EVALUATIONS * NUM_ELEMENTS_FR; // libra evaluations
|
|
1936
|
+
uint256 internal constant LIBRA_COMMITMENTS = 3;
|
|
1937
|
+
uint256 internal constant LIBRA_EVALUATIONS = 4;
|
|
1938
|
+
uint256 internal constant LIBRA_UNIVARIATES_LENGTH = 9;
|
|
1917
1939
|
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
proofLength += NUM_ELEMENTS_COMM * 2; // Shplonk Q and KZG W commitments
|
|
1940
|
+
uint256 internal constant SHIFTED_COMMITMENTS_START = 30;
|
|
1941
|
+
uint256 internal constant PERMUTATION_ARGUMENT_VALUE_SEPARATOR = 1 << 28;
|
|
1921
1942
|
|
|
1922
|
-
|
|
1923
|
-
|
|
1943
|
+
uint256 internal immutable $N;
|
|
1944
|
+
uint256 internal immutable $LOG_N;
|
|
1945
|
+
uint256 internal immutable $VK_HASH;
|
|
1946
|
+
uint256 internal immutable $NUM_PUBLIC_INPUTS;
|
|
1947
|
+
uint256 internal immutable $MSMSize;
|
|
1924
1948
|
|
|
1925
|
-
|
|
1949
|
+
constructor(uint256 _N, uint256 _logN, uint256 _vkHash, uint256 _numPublicInputs) {
|
|
1950
|
+
$N = _N;
|
|
1951
|
+
$LOG_N = _logN;
|
|
1952
|
+
$VK_HASH = _vkHash;
|
|
1953
|
+
$NUM_PUBLIC_INPUTS = _numPublicInputs;
|
|
1954
|
+
$MSMSize = NUMBER_UNSHIFTED_ZK + _logN + LIBRA_COMMITMENTS + 2;
|
|
1926
1955
|
}
|
|
1927
1956
|
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1957
|
+
function validateVerificationKey(Honk.VerificationKey memory vk) internal view {
|
|
1958
|
+
require($N == vk.circuitSize, Errors.VerificationKeyConfigurationMismatch());
|
|
1959
|
+
require($LOG_N == vk.logCircuitSize, Errors.VerificationKeyConfigurationMismatch());
|
|
1960
|
+
require($NUM_PUBLIC_INPUTS == vk.publicInputsSize, Errors.VerificationKeyConfigurationMismatch());
|
|
1961
|
+
}
|
|
1931
1962
|
|
|
1932
1963
|
function verify(bytes calldata proof, bytes32[] calldata publicInputs) public view override returns (bool verified) {
|
|
1933
1964
|
// Calculate expected proof size based on $LOG_N
|
|
1934
1965
|
uint256 expectedProofSize = calculateProofSize($LOG_N);
|
|
1935
1966
|
|
|
1936
1967
|
// Check the received proof is the expected size where each field element is 32 bytes
|
|
1937
|
-
|
|
1938
|
-
revert ProofLengthWrongWithLogN($LOG_N, proof.length, expectedProofSize * 32);
|
|
1939
|
-
}
|
|
1968
|
+
require(proof.length == expectedProofSize, Errors.ProofLengthWrongWithLogN($LOG_N, proof.length, expectedProofSize));
|
|
1940
1969
|
|
|
1941
1970
|
Honk.VerificationKey memory vk = loadVerificationKey();
|
|
1942
1971
|
Honk.ZKProof memory p = ZKTranscriptLib.loadProof(proof, $LOG_N);
|
|
1943
1972
|
|
|
1944
|
-
|
|
1945
|
-
revert PublicInputsLengthWrong();
|
|
1946
|
-
}
|
|
1973
|
+
require(publicInputs.length == vk.publicInputsSize - PAIRING_POINTS_SIZE, Errors.PublicInputsLengthWrong());
|
|
1947
1974
|
|
|
1948
1975
|
// Generate the fiat shamir challenges for the whole protocol
|
|
1949
1976
|
ZKTranscript memory t = ZKTranscriptLib.generateTranscript(p, publicInputs, $VK_HASH, $NUM_PUBLIC_INPUTS, $LOG_N);
|
|
@@ -1953,20 +1980,17 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
1953
1980
|
publicInputs,
|
|
1954
1981
|
p.pairingPointObject,
|
|
1955
1982
|
t.relationParameters.beta,
|
|
1956
|
-
t.relationParameters.gamma
|
|
1957
|
-
1
|
|
1983
|
+
t.relationParameters.gamma,
|
|
1984
|
+
5 // pubInputsOffset = NUM_DISABLED_ROWS_IN_SUMCHECK + NUM_ZERO_ROWS = 4 + 1
|
|
1958
1985
|
);
|
|
1959
1986
|
|
|
1960
1987
|
// Sumcheck
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
if (!verifyShplemini(p, vk, t)) revert ShpleminiFailed();
|
|
1988
|
+
require(verifySumcheck(p, t), Errors.SumcheckFailed());
|
|
1989
|
+
require(verifyShplemini(p, vk, t), Errors.ShpleminiFailed());
|
|
1964
1990
|
|
|
1965
1991
|
verified = true;
|
|
1966
1992
|
}
|
|
1967
1993
|
|
|
1968
|
-
uint256 constant PERMUTATION_ARGUMENT_VALUE_SEPARATOR = 1 << 28;
|
|
1969
|
-
|
|
1970
1994
|
function computePublicInputDelta(
|
|
1971
1995
|
bytes32[] memory publicInputs,
|
|
1972
1996
|
Fr[PAIRING_POINTS_SIZE] memory pairingPointObject,
|
|
@@ -2014,7 +2038,7 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2014
2038
|
for (uint256 round; round < $LOG_N; ++round) {
|
|
2015
2039
|
Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round];
|
|
2016
2040
|
Fr totalSum = roundUnivariate[0] + roundUnivariate[1];
|
|
2017
|
-
|
|
2041
|
+
require(totalSum == roundTargetSum, Errors.SumcheckFailed());
|
|
2018
2042
|
|
|
2019
2043
|
Fr roundChallenge = tp.sumCheckUChallenges[round];
|
|
2020
2044
|
|
|
@@ -2037,9 +2061,10 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2037
2061
|
powPartialEvaluation
|
|
2038
2062
|
);
|
|
2039
2063
|
|
|
2064
|
+
// Row-disabling polynomial: 1 - ∏_{i≥2}(1 - u_i)
|
|
2040
2065
|
Fr evaluation = Fr.wrap(1);
|
|
2041
2066
|
for (uint256 i = 2; i < $LOG_N; i++) {
|
|
2042
|
-
evaluation = evaluation * tp.sumCheckUChallenges[i];
|
|
2067
|
+
evaluation = evaluation * (Fr.wrap(1) - tp.sumCheckUChallenges[i]);
|
|
2043
2068
|
}
|
|
2044
2069
|
|
|
2045
2070
|
grandHonkRelationSum = grandHonkRelationSum * (Fr.wrap(1) - evaluation) + proof.libraEvaluation * tp.libraChallenge;
|
|
@@ -2085,15 +2110,6 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2085
2110
|
targetSum = targetSum * numeratorValue;
|
|
2086
2111
|
}
|
|
2087
2112
|
|
|
2088
|
-
uint256 constant LIBRA_COMMITMENTS = 3;
|
|
2089
|
-
uint256 constant LIBRA_EVALUATIONS = 4;
|
|
2090
|
-
uint256 constant LIBRA_UNIVARIATES_LENGTH = 9;
|
|
2091
|
-
|
|
2092
|
-
struct PairingInputs {
|
|
2093
|
-
Honk.G1Point P_0;
|
|
2094
|
-
Honk.G1Point P_1;
|
|
2095
|
-
}
|
|
2096
|
-
|
|
2097
2113
|
function verifyShplemini(
|
|
2098
2114
|
Honk.ZKProof memory proof,
|
|
2099
2115
|
Honk.VerificationKey memory vk,
|
|
@@ -2174,34 +2190,34 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2174
2190
|
|
|
2175
2191
|
commitments[1] = proof.geminiMaskingPoly;
|
|
2176
2192
|
|
|
2177
|
-
commitments[2] = vk.
|
|
2178
|
-
commitments[3] = vk.
|
|
2179
|
-
commitments[4] = vk.
|
|
2180
|
-
commitments[5] = vk.
|
|
2181
|
-
commitments[6] = vk.
|
|
2182
|
-
commitments[7] = vk.
|
|
2183
|
-
commitments[8] = vk.
|
|
2184
|
-
commitments[9] = vk.
|
|
2185
|
-
commitments[10] = vk.
|
|
2186
|
-
commitments[11] = vk.
|
|
2187
|
-
commitments[12] = vk.
|
|
2188
|
-
commitments[13] = vk.
|
|
2189
|
-
commitments[14] = vk.
|
|
2190
|
-
commitments[15] = vk.
|
|
2191
|
-
commitments[16] = vk.
|
|
2192
|
-
commitments[17] = vk.
|
|
2193
|
-
commitments[18] = vk.
|
|
2194
|
-
commitments[19] = vk.
|
|
2195
|
-
commitments[20] = vk.
|
|
2196
|
-
commitments[21] = vk.
|
|
2197
|
-
commitments[22] = vk.
|
|
2198
|
-
commitments[23] = vk.
|
|
2199
|
-
commitments[24] = vk.
|
|
2200
|
-
commitments[25] = vk.
|
|
2201
|
-
commitments[26] = vk.
|
|
2202
|
-
commitments[27] = vk.
|
|
2203
|
-
commitments[28] = vk.
|
|
2204
|
-
commitments[29] = vk.
|
|
2193
|
+
commitments[2] = vk.s1;
|
|
2194
|
+
commitments[3] = vk.s2;
|
|
2195
|
+
commitments[4] = vk.s3;
|
|
2196
|
+
commitments[5] = vk.s4;
|
|
2197
|
+
commitments[6] = vk.id1;
|
|
2198
|
+
commitments[7] = vk.id2;
|
|
2199
|
+
commitments[8] = vk.id3;
|
|
2200
|
+
commitments[9] = vk.id4;
|
|
2201
|
+
commitments[10] = vk.lagrangeFirst;
|
|
2202
|
+
commitments[11] = vk.lagrangeLast;
|
|
2203
|
+
commitments[12] = vk.qLookup;
|
|
2204
|
+
commitments[13] = vk.t1;
|
|
2205
|
+
commitments[14] = vk.t2;
|
|
2206
|
+
commitments[15] = vk.t3;
|
|
2207
|
+
commitments[16] = vk.t4;
|
|
2208
|
+
commitments[17] = vk.qm;
|
|
2209
|
+
commitments[18] = vk.qr;
|
|
2210
|
+
commitments[19] = vk.qo;
|
|
2211
|
+
commitments[20] = vk.qc;
|
|
2212
|
+
commitments[21] = vk.ql;
|
|
2213
|
+
commitments[22] = vk.q4;
|
|
2214
|
+
commitments[23] = vk.qArith;
|
|
2215
|
+
commitments[24] = vk.qDeltaRange;
|
|
2216
|
+
commitments[25] = vk.qElliptic;
|
|
2217
|
+
commitments[26] = vk.qMemory;
|
|
2218
|
+
commitments[27] = vk.qNnf;
|
|
2219
|
+
commitments[28] = vk.qPoseidon2External;
|
|
2220
|
+
commitments[29] = vk.qPoseidon2Internal;
|
|
2205
2221
|
|
|
2206
2222
|
// Accumulate proof points
|
|
2207
2223
|
commitments[30] = proof.w1;
|
|
@@ -2281,22 +2297,40 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2281
2297
|
|
|
2282
2298
|
boundary += $LOG_N - 1;
|
|
2283
2299
|
|
|
2284
|
-
//
|
|
2285
|
-
mem.denominators[0] =
|
|
2286
|
-
mem.denominators[1] =
|
|
2300
|
+
// Denominators 1/(z - point_i) for the five opening points {r, g*r, r, 1, r}.
|
|
2301
|
+
mem.denominators[0] = ONE.div(tp.shplonkZ - tp.geminiR);
|
|
2302
|
+
mem.denominators[1] = ONE.div(tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR);
|
|
2287
2303
|
mem.denominators[2] = mem.denominators[0];
|
|
2288
|
-
mem.denominators[
|
|
2304
|
+
mem.denominators[SMALL_IPA_BOUNDARY_OPENING_IDX] = ONE.div(tp.shplonkZ - ONE);
|
|
2305
|
+
mem.denominators[NUM_SMALL_IPA_OPENING_CLAIMS - 1] = mem.denominators[0];
|
|
2289
2306
|
|
|
2290
|
-
|
|
2291
|
-
|
|
2307
|
+
// Iterate the opening claims in three segments — the inner loops can't be merged without an extra induction
|
|
2308
|
+
// variable, which pushes us into stack-too-deep.
|
|
2309
|
+
for (uint256 i = 0; i < SMALL_IPA_BOUNDARY_OPENING_IDX; i++) {
|
|
2292
2310
|
Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge;
|
|
2293
2311
|
mem.batchingScalars[i] = scalingFactor.neg();
|
|
2294
2312
|
mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu;
|
|
2295
2313
|
mem.constantTermAccumulator = mem.constantTermAccumulator + scalingFactor * proof.libraPolyEvals[i];
|
|
2296
2314
|
}
|
|
2315
|
+
|
|
2316
|
+
// Boundary slot: claimed value is hardcoded 0, so no constantTermAccumulator contribution.
|
|
2317
|
+
{
|
|
2318
|
+
Fr scalingFactor = mem.denominators[SMALL_IPA_BOUNDARY_OPENING_IDX] * mem.batchingChallenge;
|
|
2319
|
+
mem.batchingScalars[SMALL_IPA_BOUNDARY_OPENING_IDX] = scalingFactor.neg();
|
|
2320
|
+
mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu;
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
for (uint256 i = SMALL_IPA_BOUNDARY_OPENING_IDX + 1; i < NUM_SMALL_IPA_OPENING_CLAIMS; i++) {
|
|
2324
|
+
Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge;
|
|
2325
|
+
mem.batchingScalars[i] = scalingFactor.neg();
|
|
2326
|
+
mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu;
|
|
2327
|
+
mem.constantTermAccumulator = mem.constantTermAccumulator + scalingFactor * proof.libraPolyEvals[i - 1];
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
// Group per-claim batching scalars by commitment: [G], [A] (three openings), [Q].
|
|
2297
2331
|
scalars[boundary] = mem.batchingScalars[0];
|
|
2298
|
-
scalars[boundary + 1] = mem.batchingScalars[1] + mem.batchingScalars[2];
|
|
2299
|
-
scalars[boundary + 2] = mem.batchingScalars[
|
|
2332
|
+
scalars[boundary + 1] = mem.batchingScalars[1] + mem.batchingScalars[2] + mem.batchingScalars[SMALL_IPA_BOUNDARY_OPENING_IDX];
|
|
2333
|
+
scalars[boundary + 2] = mem.batchingScalars[NUM_SMALL_IPA_OPENING_CLAIMS - 1];
|
|
2300
2334
|
|
|
2301
2335
|
for (uint256 i = 0; i < LIBRA_COMMITMENTS; i++) {
|
|
2302
2336
|
commitments[boundary++] = proof.libraCommitments[i];
|
|
@@ -2305,9 +2339,10 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2305
2339
|
commitments[boundary] = Honk.G1Point({ x: 1, y: 2 });
|
|
2306
2340
|
scalars[boundary++] = mem.constantTermAccumulator;
|
|
2307
2341
|
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2342
|
+
require(
|
|
2343
|
+
checkEvalsConsistency(proof.libraPolyEvals, tp.geminiR, tp.sumCheckUChallenges, proof.libraEvaluation),
|
|
2344
|
+
Errors.ConsistencyCheckFailed()
|
|
2345
|
+
);
|
|
2311
2346
|
|
|
2312
2347
|
Honk.G1Point memory quotient_commitment = proof.kzgQuotient;
|
|
2313
2348
|
|
|
@@ -2318,31 +2353,23 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2318
2353
|
pair.P_0 = batchMul(commitments, scalars);
|
|
2319
2354
|
pair.P_1 = negateInplace(quotient_commitment);
|
|
2320
2355
|
|
|
2321
|
-
// Aggregate pairing points
|
|
2322
|
-
|
|
2323
|
-
|
|
2356
|
+
// Aggregate pairing points (skip if default/infinity — no recursive verification occurred)
|
|
2357
|
+
if (!arePairingPointsDefault(proof.pairingPointObject)) {
|
|
2358
|
+
Fr recursionSeparator = generateRecursionSeparator(proof.pairingPointObject, pair.P_0, pair.P_1);
|
|
2359
|
+
(Honk.G1Point memory P_0_other, Honk.G1Point memory P_1_other) = convertPairingPointsToG1(proof.pairingPointObject);
|
|
2324
2360
|
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2361
|
+
// Validate the points from the proof are on the curve
|
|
2362
|
+
rejectPointAtInfinity(P_0_other);
|
|
2363
|
+
rejectPointAtInfinity(P_1_other);
|
|
2328
2364
|
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2365
|
+
// accumulate with aggregate points in proof
|
|
2366
|
+
pair.P_0 = mulWithSeperator(pair.P_0, P_0_other, recursionSeparator);
|
|
2367
|
+
pair.P_1 = mulWithSeperator(pair.P_1, P_1_other, recursionSeparator);
|
|
2368
|
+
}
|
|
2332
2369
|
|
|
2333
2370
|
return pairing(pair.P_0, pair.P_1);
|
|
2334
2371
|
}
|
|
2335
2372
|
|
|
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
2373
|
function checkEvalsConsistency(
|
|
2347
2374
|
Fr[LIBRA_EVALUATIONS] memory libraPolyEvals,
|
|
2348
2375
|
Fr geminiR,
|
|
@@ -2351,9 +2378,7 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2351
2378
|
) internal view returns (bool check) {
|
|
2352
2379
|
Fr one = Fr.wrap(1);
|
|
2353
2380
|
Fr vanishingPolyEval = geminiR.pow(SUBGROUP_SIZE) - one;
|
|
2354
|
-
|
|
2355
|
-
revert GeminiChallengeInSubgroup();
|
|
2356
|
-
}
|
|
2381
|
+
require(vanishingPolyEval != Fr.wrap(0), Errors.GeminiChallengeInSubgroup());
|
|
2357
2382
|
|
|
2358
2383
|
SmallSubgroupIpaIntermediates memory mem;
|
|
2359
2384
|
mem.challengePolyLagrange[0] = one;
|
|
@@ -2394,10 +2419,10 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2394
2419
|
function batchMul(Honk.G1Point[] memory base, Fr[] memory scalars) internal view returns (Honk.G1Point memory result) {
|
|
2395
2420
|
uint256 limit = $MSMSize;
|
|
2396
2421
|
|
|
2397
|
-
//
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2422
|
+
// Identity bases are accepted: VK selector/table polys may be identically zero,
|
|
2423
|
+
// and the ecAdd/ecMul precompiles treat (0,0) as the additive identity per EIP-196.
|
|
2424
|
+
// Soundness against an attacker substituting (0,0) for a non-zero commitment is
|
|
2425
|
+
// upheld by sumcheck/Shplemini, which would fail on inconsistent evaluations.
|
|
2401
2426
|
|
|
2402
2427
|
bool success = true;
|
|
2403
2428
|
assembly {
|
|
@@ -2426,11 +2451,42 @@ abstract contract BaseZKHonkVerifier is IVerifier {
|
|
|
2426
2451
|
mstore(add(result, 0x20), mload(add(free, 0x20)))
|
|
2427
2452
|
}
|
|
2428
2453
|
|
|
2429
|
-
require(success, ShpleminiFailed());
|
|
2454
|
+
require(success, Errors.ShpleminiFailed());
|
|
2430
2455
|
}
|
|
2456
|
+
|
|
2457
|
+
// Calculate proof size based on log_n (matching UltraKeccakZKFlavor formula)
|
|
2458
|
+
function calculateProofSize(uint256 logN) internal pure returns (uint256) {
|
|
2459
|
+
// Witness and Libra commitments
|
|
2460
|
+
uint256 proofLength = NUM_WITNESS_ENTITIES * NUM_ELEMENTS_COMM; // witness commitments
|
|
2461
|
+
proofLength += NUM_ELEMENTS_COMM * 3; // Libra concat, grand sum, quotient comms
|
|
2462
|
+
|
|
2463
|
+
// Sumcheck
|
|
2464
|
+
proofLength += logN * ZK_BATCHED_RELATION_PARTIAL_LENGTH * NUM_ELEMENTS_FR; // sumcheck univariates
|
|
2465
|
+
proofLength += NUMBER_OF_ENTITIES_ZK * NUM_ELEMENTS_FR; // sumcheck evaluations
|
|
2466
|
+
|
|
2467
|
+
// Libra and Gemini
|
|
2468
|
+
proofLength += NUM_ELEMENTS_FR * 2; // Libra sum, claimed eval
|
|
2469
|
+
proofLength += logN * NUM_ELEMENTS_FR; // Gemini a evaluations
|
|
2470
|
+
proofLength += NUM_LIBRA_EVALUATIONS * NUM_ELEMENTS_FR; // libra evaluations
|
|
2471
|
+
|
|
2472
|
+
// PCS commitments
|
|
2473
|
+
proofLength += (logN - 1) * NUM_ELEMENTS_COMM; // Gemini Fold commitments
|
|
2474
|
+
proofLength += NUM_ELEMENTS_COMM * 2; // Shplonk Q and KZG W commitments
|
|
2475
|
+
|
|
2476
|
+
// Pairing points
|
|
2477
|
+
proofLength += PAIRING_POINTS_SIZE; // pairing inputs carried on public inputs
|
|
2478
|
+
|
|
2479
|
+
return proofLength * 32;
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory);
|
|
2431
2483
|
}
|
|
2432
2484
|
|
|
2433
2485
|
contract HonkVerifier is BaseZKHonkVerifier(N, LOG_N, VK_HASH, NUMBER_OF_PUBLIC_INPUTS) {
|
|
2486
|
+
constructor() {
|
|
2487
|
+
validateVerificationKey(HonkVerificationKey.loadVerificationKey());
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2434
2490
|
function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) {
|
|
2435
2491
|
return HonkVerificationKey.loadVerificationKey();
|
|
2436
2492
|
}
|