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