diff --git a/rvgo/fast/evm.go b/rvgo/fast/evm.go index 11503588..5db91e96 100644 --- a/rvgo/fast/evm.go +++ b/rvgo/fast/evm.go @@ -7,4 +7,5 @@ var ( CheatBytes4 = crypto.Keccak256([]byte("cheat(uint256,bytes32,bytes32,uint256)"))[:4] CheatLocalKeyBytes4 = crypto.Keccak256([]byte("cheatLocalKey(uint256,bytes32,bytes32,uint256,bytes32)"))[:4] LoadKeccak256PreimagePartBytes4 = crypto.Keccak256([]byte("loadKeccak256PreimagePart(uint256,bytes)"))[:4] + LoadLocalDataBytes4 = crypto.Keccak256([]byte("loadLocalData(uint256,bytes32,bytes32,uint256,uint256)"))[:4] ) diff --git a/rvgo/fast/witness.go b/rvgo/fast/witness.go index 6f47c28c..295af378 100644 --- a/rvgo/fast/witness.go +++ b/rvgo/fast/witness.go @@ -63,19 +63,20 @@ func (wit *StepWitness) EncodePreimageOracleInput(localContext LocalContext) ([] switch preimage.KeyType(wit.PreimageKey[0]) { case preimage.LocalKeyType: - // We have no on-chain form of preparing the bootstrap pre-images onchain yet. - // So instead we cheat them in. - // In production usage there should be an on-chain contract that exposes this, - // rather than going through the global keccak256 oracle. + if len(wit.PreimageValue) > 32+8 { + return nil, fmt.Errorf("local pre-image exceeds maximum size of 32 bytes with key 0x%x", wit.PreimageKey) + } var input []byte - input = append(input, CheatLocalKeyBytes4...) - input = append(input, uint64ToBytes32(wit.PreimageOffset)...) + input = append(input, LoadLocalDataBytes4...) input = append(input, wit.PreimageKey[:]...) + input = append(input, common.Hash(localContext).Bytes()...) + + preimagePart := wit.PreimageValue[8:] var tmp [32]byte - copy(tmp[:], wit.PreimageValue[wit.PreimageOffset:]) + copy(tmp[:], preimagePart) input = append(input, tmp[:]...) - input = append(input, uint64ToBytes32(uint64(len(wit.PreimageValue))-8)...) - input = append(input, common.Hash(localContext).Bytes()...) + input = append(input, uint64ToBytes32(uint64(len(wit.PreimageValue)-8))...) + input = append(input, uint64ToBytes32(wit.PreimageOffset)...) // Note: we can pad calldata to 32 byte multiple, but don't strictly have to return input, nil case preimage.Keccak256KeyType: diff --git a/rvsol/src/PreimageOracle.sol b/rvsol/src/PreimageOracle.sol index 9246f9be..c3605da5 100644 --- a/rvsol/src/PreimageOracle.sol +++ b/rvsol/src/PreimageOracle.sol @@ -52,7 +52,40 @@ contract PreimageOracle is IPreimageOracle { uint256 _size, uint256 _partOffset ) external returns (bytes32 key_) { + // Compute the localized key from the given local identifier. + key_ = PreimageKeyLib.localizeIdent(_ident, _localContext); + // Revert if the given part offset is not within bounds. + if (_partOffset > _size + 8 || _size > 32) { + // Revert with "PartOffsetOOB()" + assembly { + // Store "PartOffsetOOB()" + mstore(0, 0xfe254987) + // Revert with "PartOffsetOOB()" + revert(0x1c, 4) + } + // TODO: remove with revert PartOffsetOOB(); + } + + // Prepare the local data part at the given offset + bytes32 part; + assembly { + // Clean the memory in [0x20, 0x40) + mstore(0x20, 0x00) + + // Store the full local data in scratch space. + mstore(0x00, shl(192, _size)) + mstore(0x08, _word) + + // Prepare the local data part at the requested offset. + part := mload(_partOffset) + } + + // Store the first part with `_partOffset`. + preimagePartOk[key_][_partOffset] = true; + preimageParts[key_][_partOffset] = part; + // Assign the length of the preimage at the localized key. + preimageLengths[key_] = _size; } // loadKeccak256PreimagePart prepares the pre-image to be read by keccak256 key,