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