@@ -101,16 +101,35 @@ contract OneStepProverHostIo is IOneStepProver {
101
101
state.u64Vals[idx] = val;
102
102
}
103
103
104
+ uint256 internal constant BLS_MODULUS =
105
+ 52435875175126190479447740508185965837690552500527637822603658699938581184513 ;
106
+ uint256 internal constant PRIMITIVE_ROOT_OF_UNITY =
107
+ 10238227357739495823651030575849232062558860180284477541189508159991286009131 ;
108
+
109
+ // Computes b**e % m
110
+ // Really pure but the Solidity compiler sees the staticcall and requires view
111
+ function modExp256 (
112
+ uint256 b ,
113
+ uint256 e ,
114
+ uint256 m
115
+ ) internal view returns (uint256 ) {
116
+ bytes memory modExpInput = abi.encode (32 , 32 , 32 , b, e, m);
117
+ (bool modexpSuccess , bytes memory modExpOutput ) = address (0x05 ).staticcall (modExpInput);
118
+ require (modexpSuccess, "MODEXP_FAILED " );
119
+ require (modExpOutput.length == 32 , "MODEXP_WRONG_LENGTH " );
120
+ return uint256 (bytes32 (modExpOutput));
121
+ }
122
+
104
123
function executeReadPreImage (
105
124
ExecutionContext calldata ,
106
125
Machine memory mach ,
107
126
Module memory mod ,
108
127
Instruction calldata inst ,
109
128
bytes calldata proof
110
- ) internal pure {
129
+ ) internal view {
111
130
uint256 preimageOffset = mach.valueStack.pop ().assumeI32 ();
112
131
uint256 ptr = mach.valueStack.pop ().assumeI32 ();
113
- if (ptr + 32 > mod.moduleMemory.size || ptr % LEAF_SIZE != 0 ) {
132
+ if (preimageOffset % 32 != 0 || ptr + 32 > mod.moduleMemory.size || ptr % LEAF_SIZE != 0 ) {
114
133
mach.status = MachineStatus.ERRORED;
115
134
return ;
116
135
}
@@ -158,6 +177,60 @@ contract OneStepProverHostIo is IOneStepProver {
158
177
preimageEnd = preimage.length ;
159
178
}
160
179
extracted = preimage[preimageOffset:preimageEnd];
180
+ } else if (inst.argumentData == 2 ) {
181
+ // The machine is asking for an Ethereum versioned hash preimage
182
+
183
+ require (proofType == 0 , "UNKNOWN_PREIMAGE_PROOF " );
184
+
185
+ // kzgProof should be a valid input to the EIP-4844 point evaluation precompile at address 0x0A.
186
+ // It should prove the preimageOffset/32'th word of the machine's requested KZG commitment.
187
+ bytes calldata kzgProof = proof[proofOffset:];
188
+
189
+ require (bytes32 (kzgProof[:32 ]) == leafContents, "KZG_PROOF_WRONG_HASH " );
190
+
191
+ uint256 fieldElementsPerBlob;
192
+ uint256 blsModulus;
193
+ {
194
+ (bool success , bytes memory kzgParams ) = address (0x0A ).staticcall (kzgProof);
195
+ require (success, "INVALID_KZG_PROOF " );
196
+ require (kzgParams.length > 0 , "KZG_PRECOMPILE_MISSING " );
197
+ (fieldElementsPerBlob, blsModulus) = abi.decode (kzgParams, (uint256 , uint256 ));
198
+ }
199
+
200
+ // With a hardcoded PRIMITIVE_ROOT_OF_UNITY, we can only support this BLS modulus.
201
+ // It may be worth in the future supporting arbitrary BLS moduli, but we would likely need to
202
+ // validate a user-supplied root of unity.
203
+ require (blsModulus == BLS_MODULUS, "UNKNOWN_BLS_MODULUS " );
204
+
205
+ // If preimageOffset is greater than or equal to the blob size, leave extracted empty and call it here.
206
+ if (preimageOffset < fieldElementsPerBlob * 32 ) {
207
+ // We need to compute what point the polynomial should be evaluated at to get the right part of the preimage.
208
+ // KZG commitments use a bit reversal permutation to order the roots of unity.
209
+ // To account for that, we reverse the bit order of the index.
210
+ uint256 bitReversedIndex = 0 ;
211
+ // preimageOffset was required to be 32 byte aligned above
212
+ uint256 tmp = preimageOffset / 32 ;
213
+ for (uint256 i = 1 ; i < fieldElementsPerBlob; i <<= 1 ) {
214
+ bitReversedIndex <<= 1 ;
215
+ if (tmp & 1 == 1 ) {
216
+ bitReversedIndex |= 1 ;
217
+ }
218
+ tmp >>= 1 ;
219
+ }
220
+
221
+ // First, we get the root of unity of order 2**fieldElementsPerBlob.
222
+ // We start with a root of unity of order 2**32 and then raise it to
223
+ // the power of (2**32)/fieldElementsPerBlob to get root of unity we need.
224
+ uint256 rootOfUnityPower = (1 << 32 ) / fieldElementsPerBlob;
225
+ // Then, we raise the root of unity to the power of bitReversedIndex,
226
+ // to retrieve this word of the KZG commitment.
227
+ rootOfUnityPower *= bitReversedIndex;
228
+ // z is the point the polynomial is evaluated at to retrieve this word of data
229
+ uint256 z = modExp256 (PRIMITIVE_ROOT_OF_UNITY, rootOfUnityPower, blsModulus);
230
+ require (bytes32 (kzgProof[32 :64 ]) == bytes32 (z), "KZG_PROOF_WRONG_Z " );
231
+
232
+ extracted = kzgProof[64 :96 ];
233
+ }
161
234
} else {
162
235
revert ("UNKNOWN_PREIMAGE_TYPE " );
163
236
}
0 commit comments