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