Skip to content

Commit 798934b

Browse files
committed
Merge remote-tracking branch 'origin/develop' into 4844-only
2 parents 0e733fc + b2b52d9 commit 798934b

File tree

1 file changed

+75
-2
lines changed

1 file changed

+75
-2
lines changed

src/osp/OneStepProverHostIo.sol

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,35 @@ contract OneStepProverHostIo is IOneStepProver {
101101
state.u64Vals[idx] = val;
102102
}
103103

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+
104123
function executeReadPreImage(
105124
ExecutionContext calldata,
106125
Machine memory mach,
107126
Module memory mod,
108127
Instruction calldata inst,
109128
bytes calldata proof
110-
) internal pure {
129+
) internal view {
111130
uint256 preimageOffset = mach.valueStack.pop().assumeI32();
112131
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) {
114133
mach.status = MachineStatus.ERRORED;
115134
return;
116135
}
@@ -158,6 +177,60 @@ contract OneStepProverHostIo is IOneStepProver {
158177
preimageEnd = preimage.length;
159178
}
160179
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+
}
161234
} else {
162235
revert("UNKNOWN_PREIMAGE_TYPE");
163236
}

0 commit comments

Comments
 (0)