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