From c1289c1ccb8b5c1ade4e5ec7b8e64d7e536f6596 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 14:41:41 +0900 Subject: [PATCH 01/16] Refactor using interface and lib --- rvsol/src/PreimageKeyLib.sol | 59 ++++++++++++++++++++++++ rvsol/src/PreimageOracle.sol | 35 +++++++------- rvsol/src/interfaces/IPreimageOracle.sol | 56 ++++++++++++++++++++++ 3 files changed, 133 insertions(+), 17 deletions(-) create mode 100644 rvsol/src/PreimageKeyLib.sol create mode 100644 rvsol/src/interfaces/IPreimageOracle.sol diff --git a/rvsol/src/PreimageKeyLib.sol b/rvsol/src/PreimageKeyLib.sol new file mode 100644 index 00000000..c3f36cb8 --- /dev/null +++ b/rvsol/src/PreimageKeyLib.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +/// @title PreimageKeyLib +/// @notice Shared utilities for localizing local keys in the preimage oracle. +library PreimageKeyLib { + /// @notice Generates a context-specific local key for the given local data identifier. + /// @dev See `localize` for a description of the localization operation. + /// @param _ident The identifier of the local data. [0, 32) bytes in size. + /// @param _localContext The local context for the key. + /// @return key_ The context-specific local key. + function localizeIdent(uint256 _ident, bytes32 _localContext) internal view returns (bytes32 key_) { + assembly { + // Set the type byte in the given identifier to `1` (Local). We only care about + // the [1, 32) bytes in this value. + key_ := or(shl(248, 1), and(_ident, not(shl(248, 0xFF)))) + } + // Localize the key with the given local context. + key_ = localize(key_, _localContext); + } + + /// @notice Localizes a given local data key for the caller's context. + /// @dev The localization operation is defined as: + /// localize(k) = H(k .. sender .. local_context) & ~(0xFF << 248) | (0x01 << 248) + /// where H is the Keccak-256 hash function. + /// @param _key The local data key to localize. + /// @param _localContext The local context for the key. + /// @return localizedKey_ The localized local data key. + function localize(bytes32 _key, bytes32 _localContext) internal view returns (bytes32 localizedKey_) { + assembly { + // Grab the current free memory pointer to restore later. + let ptr := mload(0x40) + // Store the local data key and caller next to each other in memory for hashing. + mstore(0, _key) + mstore(0x20, caller()) + mstore(0x40, _localContext) + // Localize the key with the above `localize` operation. + localizedKey_ := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) + // Restore the free memory pointer. + mstore(0x40, ptr) + } + } + + /// @notice Computes and returns the key for a global keccak pre-image. + /// @param _preimage The pre-image. + /// @return key_ The pre-image key. + function keccak256PreimageKey(bytes memory _preimage) internal pure returns (bytes32 key_) { + assembly { + // Grab the size of the `_preimage` + let size := mload(_preimage) + + // Compute the pre-image keccak256 hash (aka the pre-image key) + let h := keccak256(add(_preimage, 0x20), size) + + // Mask out prefix byte, replace with type 2 byte + key_ := or(and(h, not(shl(248, 0xFF))), shl(248, 2)) + } + } +} diff --git a/rvsol/src/PreimageOracle.sol b/rvsol/src/PreimageOracle.sol index 27a4298b..9246f9be 100644 --- a/rvsol/src/PreimageOracle.sol +++ b/rvsol/src/PreimageOracle.sol @@ -1,7 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; +import { IPreimageOracle } from "./interfaces/IPreimageOracle.sol"; +import { PreimageKeyLib } from "./PreimageKeyLib.sol"; -contract PreimageOracle { +contract PreimageOracle is IPreimageOracle { mapping(bytes32 => uint256) public preimageLengths; mapping(bytes32 => mapping(uint256 => bytes32)) public preimageParts; mapping(bytes32 => mapping(uint256 => bool)) public preimagePartOk; @@ -32,32 +34,27 @@ contract PreimageOracle { preimageLengths[key] = size; } - function localize(bytes32 _key, bytes32 _localContext) internal view returns (bytes32 localizedKey_) { - assembly { - // Grab the current free memory pointer to restore later. - let ptr := mload(0x40) - // Store the local data key and caller next to each other in memory for hashing. - mstore(0, _key) - mstore(0x20, caller()) - mstore(0x40, _localContext) - // Localize the key with the above `localize` operation. - localizedKey_ := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) - // Restore the free memory pointer. - mstore(0x40, ptr) - } - } - // temporary method for localizeation function cheatLocalKey(uint256 partOffset, bytes32 key, bytes32 part, uint256 size, bytes32 localContext) external { // sanity check key is local key using prefix require(uint8(key[0]) == 1, "must be used for local key"); - bytes32 localizedKey = localize(key, localContext); + bytes32 localizedKey = PreimageKeyLib.localize(key, localContext); preimagePartOk[localizedKey][partOffset] = true; preimageParts[localizedKey][partOffset] = part; preimageLengths[localizedKey] = size; } + function loadLocalData( + uint256 _ident, + bytes32 _localContext, + bytes32 _word, + uint256 _size, + uint256 _partOffset + ) external returns (bytes32 key_) { + + } + // loadKeccak256PreimagePart prepares the pre-image to be read by keccak256 key, // starting at the given offset, up to 32 bytes (clipped at preimage length, if out of data). function loadKeccak256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external { @@ -94,4 +91,8 @@ contract PreimageOracle { preimageParts[key][_partOffset] = part; preimageLengths[key] = size; } + + function loadSha256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external { + + } } diff --git a/rvsol/src/interfaces/IPreimageOracle.sol b/rvsol/src/interfaces/IPreimageOracle.sol new file mode 100644 index 00000000..f7380eba --- /dev/null +++ b/rvsol/src/interfaces/IPreimageOracle.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +/// @title IPreimageOracle +/// @notice Interface for a preimage oracle. +interface IPreimageOracle { + /// @notice Reads a preimage from the oracle. + /// @param _key The key of the preimage to read. + /// @param _offset The offset of the preimage to read. + /// @return dat_ The preimage data. + /// @return datLen_ The length of the preimage data. + function readPreimage(bytes32 _key, uint256 _offset) external view returns (bytes32 dat_, uint256 datLen_); + + /// @notice Loads of local data part into the preimage oracle. + /// @param _ident The identifier of the local data. + /// @param _localContext The local key context for the preimage oracle. Optionally, can be set as a constant + /// if the caller only requires one set of local keys. + /// @param _word The local data word. + /// @param _size The number of bytes in `_word` to load. + /// @param _partOffset The offset of the local data part to write to the oracle. + /// @dev The local data parts are loaded into the preimage oracle under the context + /// of the caller - no other account can write to the caller's context + /// specific data. + /// + /// There are 5 local data identifiers: + /// ┌────────────┬────────────────────────┐ + /// │ Identifier │ Data │ + /// ├────────────┼────────────────────────┤ + /// │ 1 │ L1 Head Hash (bytes32) │ + /// │ 2 │ Output Root (bytes32) │ + /// │ 3 │ Root Claim (bytes32) │ + /// │ 4 │ L2 Block Number (u64) │ + /// │ 5 │ Chain ID (u64) │ + /// └────────────┴────────────────────────┘ + function loadLocalData( + uint256 _ident, + bytes32 _localContext, + bytes32 _word, + uint256 _size, + uint256 _partOffset + ) + external + returns (bytes32 key_); + + /// @notice Prepares a preimage to be read by keccak256 key, starting at the given offset and up to 32 bytes + /// (clipped at preimage length, if out of data). + /// @param _partOffset The offset of the preimage to read. + /// @param _preimage The preimage data. + function loadKeccak256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external; + + /// @notice Prepares a preimage to be read by sha256 key, starting at the given offset and up to 32 bytes + /// (clipped at preimage length, if out of data). + /// @param _partOffset The offset of the preimage to read. + /// @param _preimage The preimage data. + function loadSha256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external; +} From bf31f2a887d9ee61c1829e9afd20332198c62e85 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 15:02:49 +0900 Subject: [PATCH 02/16] Implement LoadLocalData and Apply --- rvgo/fast/evm.go | 1 + rvgo/fast/witness.go | 19 ++++++++++--------- rvsol/src/PreimageOracle.sol | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) 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, From 5d3073173795cc8d162e35c7f7f3cec23fbcad16 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 15:30:34 +0900 Subject: [PATCH 03/16] Deduplicate localize method --- rvsol/src/Step.sol | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/rvsol/src/Step.sol b/rvsol/src/Step.sol index 5b12cd12..d5ba9ab4 100644 --- a/rvsol/src/Step.sol +++ b/rvsol/src/Step.sol @@ -1,13 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; +import { IPreimageOracle } from "./interfaces/IPreimageOracle.sol"; +import { PreimageKeyLib } from "./PreimageKeyLib.sol"; contract Step { + IPreimageOracle public preimageOracle; + address public preimageKeyLib; - address public preimageOracle; - - constructor(address _preimageOracle) { + constructor(IPreimageOracle _preimageOracle) { preimageOracle = _preimageOracle; + preimageKeyLib = address(PreimageKeyLib); } // Executes a single RISC-V instruction, starting from @@ -21,6 +24,9 @@ contract Step { function preimageOraclePos() -> out { // slot of preimageOraclePos field out := 0 } + function preimageKeyLibPos() -> out { // slot of preimageKeyLib field + out := 1 + } // // Yul64 - functions to do 64 bit math - see yul64.go @@ -774,17 +780,18 @@ contract Step { } function localize(preImageKey, localContext_) -> localizedKey { - // TODO: deduplicate definition of localize using lib - // Grab the current free memory pointer to restore later. - let ptr := mload(0x40) - // Store the local data key and caller next to each other in memory for hashing. - mstore(0, preImageKey) - mstore(0x20, caller()) - mstore(0x40, localContext_) - // Localize the key with the above `localize` operation. - localizedKey := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) - // Restore the free memory pointer. - mstore(0x40, ptr) + let addr := sload(preimageKeyLibPos()) // calling PreimageKeyLib.localize(bytes32,bytes32) + let memPtr := mload(0x40) // get pointer to free memory for preimage interactions + mstore(memPtr, shl(224, 0x1aae47f0)) // (32-4)*8=224: right-pad the function selector, and then store it as prefix + mstore(add(memPtr, 0x04), preImageKey) + mstore(add(memPtr, 0x24), localContext_) + let cgas := 100000 // TODO change call gas + let res := call(cgas, addr, 0, memPtr, 0x44, 0x00, 0x20) // output into scratch space + if res { // 1 on success + localizedKey := mload(0x00) + leave + } + revertWithCode(0xbadf00d0) } function readPreimageValue(addr, count, localContext_) -> out { From 29f530c1aa5aaf670cf3d1d1e27a79c00eefe3d3 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 15:45:37 +0900 Subject: [PATCH 04/16] test --- rvsol/src/Step.sol | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/rvsol/src/Step.sol b/rvsol/src/Step.sol index d5ba9ab4..aeeff4c4 100644 --- a/rvsol/src/Step.sol +++ b/rvsol/src/Step.sol @@ -791,7 +791,19 @@ contract Step { localizedKey := mload(0x00) leave } - revertWithCode(0xbadf00d0) + revertWithCode(addr) + + // // TODO: deduplicate definition of localize using lib + // // Grab the current free memory pointer to restore later. + // let ptr := mload(0x40) + // // Store the local data key and caller next to each other in memory for hashing. + // mstore(0, preImageKey) + // mstore(0x20, caller()) + // mstore(0x40, localContext_) + // // Localize the key with the above `localize` operation. + // localizedKey := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) + // // Restore the free memory pointer. + // mstore(0x40, ptr) } function readPreimageValue(addr, count, localContext_) -> out { From f044772e262404eb7d24349ad5c929fe5cbd8baa Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 16:01:59 +0900 Subject: [PATCH 05/16] test --- rvsol/src/Step.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rvsol/src/Step.sol b/rvsol/src/Step.sol index aeeff4c4..51168c1a 100644 --- a/rvsol/src/Step.sol +++ b/rvsol/src/Step.sol @@ -776,7 +776,7 @@ contract Step { datlen := mload(0x20) leave } - revertWithCode(0xbadf00d0) + revertWithCode(0x4321dead) } function localize(preImageKey, localContext_) -> localizedKey { @@ -791,7 +791,7 @@ contract Step { localizedKey := mload(0x00) leave } - revertWithCode(addr) + revertWithCode(0x1234dead) // // TODO: deduplicate definition of localize using lib // // Grab the current free memory pointer to restore later. From f51ad2dc989e7a529ea0039b77c4592e43ce08cc Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 17:53:02 +0900 Subject: [PATCH 06/16] Test --- rvsol/src/PreimageKeyLib.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rvsol/src/PreimageKeyLib.sol b/rvsol/src/PreimageKeyLib.sol index c3f36cb8..ca54862e 100644 --- a/rvsol/src/PreimageKeyLib.sol +++ b/rvsol/src/PreimageKeyLib.sol @@ -32,7 +32,8 @@ library PreimageKeyLib { let ptr := mload(0x40) // Store the local data key and caller next to each other in memory for hashing. mstore(0, _key) - mstore(0x20, caller()) + // mstore(0x20, caller()) + mstore(0, 0x1234) mstore(0x40, _localContext) // Localize the key with the above `localize` operation. localizedKey_ := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) From e6cbd7d80d2685972b149ae8e5032ad84821fabd Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 18:11:48 +0900 Subject: [PATCH 07/16] test --- rvsol/src/Step.sol | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/rvsol/src/Step.sol b/rvsol/src/Step.sol index 51168c1a..32906160 100644 --- a/rvsol/src/Step.sol +++ b/rvsol/src/Step.sol @@ -770,7 +770,11 @@ contract Step { mstore(add(memPtr, 0x04), key) mstore(add(memPtr, 0x24), offset) let cgas := 100000 // TODO change call gas - let res := call(cgas, addr, 0, memPtr, 0x44, 0x00, 0x40) // output into scratch space + + // CALL: msg.sender: this contract, + // DELEGATECALL: msg.sender: tx.origin + + let res := delegatecall(cgas, addr, memPtr, 0x44, 0x00, 0x40) // output into scratch space if res { // 1 on success dat := mload(0x00) datlen := mload(0x20) @@ -786,7 +790,11 @@ contract Step { mstore(add(memPtr, 0x04), preImageKey) mstore(add(memPtr, 0x24), localContext_) let cgas := 100000 // TODO change call gas - let res := call(cgas, addr, 0, memPtr, 0x44, 0x00, 0x20) // output into scratch space + + // CALL: msg.sender: this contract + // DELEGATECALL: msg.sender: tx.origin + + let res := delegatecall(cgas, addr, memPtr, 0x44, 0x00, 0x20) // output into scratch space if res { // 1 on success localizedKey := mload(0x00) leave From 4fa428bbf8794115363c7273e43e7c2825993f45 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 18:15:36 +0900 Subject: [PATCH 08/16] Test --- rvsol/src/PreimageKeyLib.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rvsol/src/PreimageKeyLib.sol b/rvsol/src/PreimageKeyLib.sol index ca54862e..c3f36cb8 100644 --- a/rvsol/src/PreimageKeyLib.sol +++ b/rvsol/src/PreimageKeyLib.sol @@ -32,8 +32,7 @@ library PreimageKeyLib { let ptr := mload(0x40) // Store the local data key and caller next to each other in memory for hashing. mstore(0, _key) - // mstore(0x20, caller()) - mstore(0, 0x1234) + mstore(0x20, caller()) mstore(0x40, _localContext) // Localize the key with the above `localize` operation. localizedKey_ := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) From 11d2ced8801753ad5ce4f02b9f2f6f80c9e7e497 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 18:23:37 +0900 Subject: [PATCH 09/16] wowowow --- rvsol/src/Step.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rvsol/src/Step.sol b/rvsol/src/Step.sol index 32906160..64da0580 100644 --- a/rvsol/src/Step.sol +++ b/rvsol/src/Step.sol @@ -774,7 +774,7 @@ contract Step { // CALL: msg.sender: this contract, // DELEGATECALL: msg.sender: tx.origin - let res := delegatecall(cgas, addr, memPtr, 0x44, 0x00, 0x40) // output into scratch space + let res := call(cgas, addr, 0, memPtr, 0x44, 0x00, 0x40) // output into scratch space if res { // 1 on success dat := mload(0x00) datlen := mload(0x20) @@ -794,7 +794,7 @@ contract Step { // CALL: msg.sender: this contract // DELEGATECALL: msg.sender: tx.origin - let res := delegatecall(cgas, addr, memPtr, 0x44, 0x00, 0x20) // output into scratch space + let res := call(cgas, addr, 0, memPtr, 0x44, 0x00, 0x20) // output into scratch space if res { // 1 on success localizedKey := mload(0x00) leave From 4c2124b3bf21fefd93192d8e87fbce5259065346 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 18:24:13 +0900 Subject: [PATCH 10/16] twtwt --- rvsol/src/Step.sol | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/rvsol/src/Step.sol b/rvsol/src/Step.sol index 64da0580..f6d408a4 100644 --- a/rvsol/src/Step.sol +++ b/rvsol/src/Step.sol @@ -784,34 +784,34 @@ contract Step { } function localize(preImageKey, localContext_) -> localizedKey { - let addr := sload(preimageKeyLibPos()) // calling PreimageKeyLib.localize(bytes32,bytes32) - let memPtr := mload(0x40) // get pointer to free memory for preimage interactions - mstore(memPtr, shl(224, 0x1aae47f0)) // (32-4)*8=224: right-pad the function selector, and then store it as prefix - mstore(add(memPtr, 0x04), preImageKey) - mstore(add(memPtr, 0x24), localContext_) - let cgas := 100000 // TODO change call gas - - // CALL: msg.sender: this contract - // DELEGATECALL: msg.sender: tx.origin - - let res := call(cgas, addr, 0, memPtr, 0x44, 0x00, 0x20) // output into scratch space - if res { // 1 on success - localizedKey := mload(0x00) - leave - } - revertWithCode(0x1234dead) + // let addr := sload(preimageKeyLibPos()) // calling PreimageKeyLib.localize(bytes32,bytes32) + // let memPtr := mload(0x40) // get pointer to free memory for preimage interactions + // mstore(memPtr, shl(224, 0x1aae47f0)) // (32-4)*8=224: right-pad the function selector, and then store it as prefix + // mstore(add(memPtr, 0x04), preImageKey) + // mstore(add(memPtr, 0x24), localContext_) + // let cgas := 100000 // TODO change call gas + + // // CALL: msg.sender: this contract + // // DELEGATECALL: msg.sender: tx.origin + + // let res := call(cgas, addr, 0, memPtr, 0x44, 0x00, 0x20) // output into scratch space + // if res { // 1 on success + // localizedKey := mload(0x00) + // leave + // } + // revertWithCode(0x1234dead) // // TODO: deduplicate definition of localize using lib // // Grab the current free memory pointer to restore later. - // let ptr := mload(0x40) - // // Store the local data key and caller next to each other in memory for hashing. - // mstore(0, preImageKey) - // mstore(0x20, caller()) - // mstore(0x40, localContext_) - // // Localize the key with the above `localize` operation. - // localizedKey := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) - // // Restore the free memory pointer. - // mstore(0x40, ptr) + let ptr := mload(0x40) + // Store the local data key and caller next to each other in memory for hashing. + mstore(0, preImageKey) + mstore(0x20, caller()) + mstore(0x40, localContext_) + // Localize the key with the above `localize` operation. + localizedKey := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) + // Restore the free memory pointer. + mstore(0x40, ptr) } function readPreimageValue(addr, count, localContext_) -> out { From 08ead1cacee68f03c7a7227c009f3cfb0ab9923a Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 22:56:06 +0900 Subject: [PATCH 11/16] Expose lib methods as public --- rvgo/evm_test.go | 47 +++++++++++++++++++++++++----------- rvsol/foundry.toml | 1 + rvsol/src/PreimageKeyLib.sol | 6 ++--- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/rvgo/evm_test.go b/rvgo/evm_test.go index b9ca12cb..24289e23 100644 --- a/rvgo/evm_test.go +++ b/rvgo/evm_test.go @@ -72,6 +72,15 @@ func loadPreimageOracleContractCode(t *testing.T) *Contract { return &outDat } +func loadPreimageKeyLibCode(t *testing.T) *Contract { + dat, err := os.ReadFile("../rvsol/out/PreimageKeyLib.sol/PreimageKeyLib.json") + require.NoError(t, err) + var outDat Contract + err = json.Unmarshal(dat, &outDat) + require.NoError(t, err) + return &outDat +} + type Contract struct { DeployedBytecode struct { Object hexutil.Bytes `json:"object"` @@ -84,15 +93,17 @@ func (c *Contract) SourceMap(sourcePaths []string) (*srcmap.SourceMap, error) { } type Contracts struct { - RISCV *Contract - Oracle *Contract + RISCV *Contract + Oracle *Contract + PreimageKeyLib *Contract } type Addresses struct { - RISCV common.Address - Oracle common.Address - Sender common.Address - FeeRecipient common.Address + RISCV common.Address + Oracle common.Address + PreimageKeyLib common.Address + Sender common.Address + FeeRecipient common.Address } func newEVMEnv(t *testing.T, contracts *Contracts, addrs *Addresses) *vm.EVM { @@ -109,7 +120,9 @@ func newEVMEnv(t *testing.T, contracts *Contracts, addrs *Addresses) *vm.EVM { env := vm.NewEVM(blockContext, vm.TxContext{}, state, chainCfg, vmCfg) env.StateDB.SetCode(addrs.RISCV, contracts.RISCV.DeployedBytecode.Object) env.StateDB.SetCode(addrs.Oracle, contracts.Oracle.DeployedBytecode.Object) + env.StateDB.SetCode(addrs.PreimageKeyLib, contracts.Oracle.DeployedBytecode.Object) env.StateDB.SetState(addrs.RISCV, common.Hash{}, addrs.Oracle.Hash()) // set storage slot pointing to preimage oracle + env.StateDB.SetState(addrs.RISCV, common.Hash{1}, addrs.PreimageKeyLib.Hash()) // set slot pointing to preimageKeyLib rules := env.ChainConfig().Rules(header.Number, true, header.Time) env.StateDB.Prepare(rules, addrs.Sender, addrs.FeeRecipient, &addrs.RISCV, vm.ActivePrecompiles(rules), nil) @@ -117,16 +130,18 @@ func newEVMEnv(t *testing.T, contracts *Contracts, addrs *Addresses) *vm.EVM { } var testAddrs = &Addresses{ - RISCV: common.HexToAddress("0x1337"), - Oracle: common.HexToAddress("0xf00d"), - Sender: common.HexToAddress("0x7070"), - FeeRecipient: common.HexToAddress("0xbd69"), + RISCV: common.HexToAddress("0x1337"), + Oracle: common.HexToAddress("0xf00d"), + PreimageKeyLib: common.HexToAddress("0x7331"), + Sender: common.HexToAddress("0x7070"), + FeeRecipient: common.HexToAddress("0xbd69"), } func testContracts(t *testing.T) *Contracts { return &Contracts{ - RISCV: loadStepContractCode(t), - Oracle: loadPreimageOracleContractCode(t), + RISCV: loadStepContractCode(t), + Oracle: loadPreimageOracleContractCode(t), + PreimageKeyLib: loadPreimageKeyLibCode(t), } } @@ -137,9 +152,13 @@ func addTracer(t *testing.T, env *vm.EVM, addrs *Addresses, contracts *Contracts require.NoError(t, err) b, err := contracts.Oracle.SourceMap([]string{"../rvsol/src/PreimageOracle.sol"}) require.NoError(t, err) + c, err := contracts.PreimageKeyLib.SourceMap([]string{"../rvsol/src/PreimageKeyLib.sol"}) + require.NoError(t, err) + env.Config.Tracer = srcmap.NewSourceMapTracer(map[common.Address]*srcmap.SourceMap{ - addrs.RISCV: a, - addrs.Oracle: b, + addrs.RISCV: a, + addrs.Oracle: b, + addrs.PreimageKeyLib: c, }, os.Stdout) } diff --git a/rvsol/foundry.toml b/rvsol/foundry.toml index f49d8c9e..28ac7ad4 100644 --- a/rvsol/foundry.toml +++ b/rvsol/foundry.toml @@ -2,6 +2,7 @@ src = 'src' out = 'out' libs = ['lib'] +libraries = ['src/PreimageKeyLib.sol:PreimageKeyLib:0x0000000000000000000000000000000000007331'] optimizer = true optimizer_runs = 999999 diff --git a/rvsol/src/PreimageKeyLib.sol b/rvsol/src/PreimageKeyLib.sol index c3f36cb8..3a8357a2 100644 --- a/rvsol/src/PreimageKeyLib.sol +++ b/rvsol/src/PreimageKeyLib.sol @@ -9,7 +9,7 @@ library PreimageKeyLib { /// @param _ident The identifier of the local data. [0, 32) bytes in size. /// @param _localContext The local context for the key. /// @return key_ The context-specific local key. - function localizeIdent(uint256 _ident, bytes32 _localContext) internal view returns (bytes32 key_) { + function localizeIdent(uint256 _ident, bytes32 _localContext) public view returns (bytes32 key_) { assembly { // Set the type byte in the given identifier to `1` (Local). We only care about // the [1, 32) bytes in this value. @@ -26,7 +26,7 @@ library PreimageKeyLib { /// @param _key The local data key to localize. /// @param _localContext The local context for the key. /// @return localizedKey_ The localized local data key. - function localize(bytes32 _key, bytes32 _localContext) internal view returns (bytes32 localizedKey_) { + function localize(bytes32 _key, bytes32 _localContext) public view returns (bytes32 localizedKey_) { assembly { // Grab the current free memory pointer to restore later. let ptr := mload(0x40) @@ -44,7 +44,7 @@ library PreimageKeyLib { /// @notice Computes and returns the key for a global keccak pre-image. /// @param _preimage The pre-image. /// @return key_ The pre-image key. - function keccak256PreimageKey(bytes memory _preimage) internal pure returns (bytes32 key_) { + function keccak256PreimageKey(bytes memory _preimage) public pure returns (bytes32 key_) { assembly { // Grab the size of the `_preimage` let size := mload(_preimage) From 4aa6b05ddcfc1a5a5e1d97d9b6bff1f3cab67502 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Mon, 5 Feb 2024 23:14:39 +0900 Subject: [PATCH 12/16] Fund user --- rvgo/evm_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rvgo/evm_test.go b/rvgo/evm_test.go index 24289e23..efcbc362 100644 --- a/rvgo/evm_test.go +++ b/rvgo/evm_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" @@ -121,8 +122,9 @@ func newEVMEnv(t *testing.T, contracts *Contracts, addrs *Addresses) *vm.EVM { env.StateDB.SetCode(addrs.RISCV, contracts.RISCV.DeployedBytecode.Object) env.StateDB.SetCode(addrs.Oracle, contracts.Oracle.DeployedBytecode.Object) env.StateDB.SetCode(addrs.PreimageKeyLib, contracts.Oracle.DeployedBytecode.Object) - env.StateDB.SetState(addrs.RISCV, common.Hash{}, addrs.Oracle.Hash()) // set storage slot pointing to preimage oracle + env.StateDB.SetState(addrs.RISCV, common.Hash{}, addrs.Oracle.Hash()) // set storage slot pointing to preimage oracle env.StateDB.SetState(addrs.RISCV, common.Hash{1}, addrs.PreimageKeyLib.Hash()) // set slot pointing to preimageKeyLib + env.StateDB.AddBalance(addrs.Sender, abi.MaxUint256) rules := env.ChainConfig().Rules(header.Number, true, header.Time) env.StateDB.Prepare(rules, addrs.Sender, addrs.FeeRecipient, &addrs.RISCV, vm.ActivePrecompiles(rules), nil) From 25209fa6f3d13d432c07b38eda62f61870152a7f Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Tue, 6 Feb 2024 16:43:34 +0900 Subject: [PATCH 13/16] Fix error --- rvgo/evm_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rvgo/evm_test.go b/rvgo/evm_test.go index efcbc362..3164b3db 100644 --- a/rvgo/evm_test.go +++ b/rvgo/evm_test.go @@ -9,7 +9,6 @@ import ( "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" @@ -121,11 +120,10 @@ func newEVMEnv(t *testing.T, contracts *Contracts, addrs *Addresses) *vm.EVM { env := vm.NewEVM(blockContext, vm.TxContext{}, state, chainCfg, vmCfg) env.StateDB.SetCode(addrs.RISCV, contracts.RISCV.DeployedBytecode.Object) env.StateDB.SetCode(addrs.Oracle, contracts.Oracle.DeployedBytecode.Object) - env.StateDB.SetCode(addrs.PreimageKeyLib, contracts.Oracle.DeployedBytecode.Object) + env.StateDB.SetCode(addrs.PreimageKeyLib, contracts.PreimageKeyLib.DeployedBytecode.Object) env.StateDB.SetState(addrs.RISCV, common.Hash{}, addrs.Oracle.Hash()) // set storage slot pointing to preimage oracle env.StateDB.SetState(addrs.RISCV, common.Hash{1}, addrs.PreimageKeyLib.Hash()) // set slot pointing to preimageKeyLib - env.StateDB.AddBalance(addrs.Sender, abi.MaxUint256) - + rules := env.ChainConfig().Rules(header.Number, true, header.Time) env.StateDB.Prepare(rules, addrs.Sender, addrs.FeeRecipient, &addrs.RISCV, vm.ActivePrecompiles(rules), nil) return env From 418b0f0b5b51ef0d8c9064a603d07f8b64f40e87 Mon Sep 17 00:00:00 2001 From: Tei Im Date: Tue, 6 Feb 2024 19:26:20 +0900 Subject: [PATCH 14/16] fixfix --- rvsol/foundry.toml | 1 - rvsol/src/PreimageKeyLib.sol | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rvsol/foundry.toml b/rvsol/foundry.toml index 28ac7ad4..f49d8c9e 100644 --- a/rvsol/foundry.toml +++ b/rvsol/foundry.toml @@ -2,7 +2,6 @@ src = 'src' out = 'out' libs = ['lib'] -libraries = ['src/PreimageKeyLib.sol:PreimageKeyLib:0x0000000000000000000000000000000000007331'] optimizer = true optimizer_runs = 999999 diff --git a/rvsol/src/PreimageKeyLib.sol b/rvsol/src/PreimageKeyLib.sol index 3a8357a2..c3f36cb8 100644 --- a/rvsol/src/PreimageKeyLib.sol +++ b/rvsol/src/PreimageKeyLib.sol @@ -9,7 +9,7 @@ library PreimageKeyLib { /// @param _ident The identifier of the local data. [0, 32) bytes in size. /// @param _localContext The local context for the key. /// @return key_ The context-specific local key. - function localizeIdent(uint256 _ident, bytes32 _localContext) public view returns (bytes32 key_) { + function localizeIdent(uint256 _ident, bytes32 _localContext) internal view returns (bytes32 key_) { assembly { // Set the type byte in the given identifier to `1` (Local). We only care about // the [1, 32) bytes in this value. @@ -26,7 +26,7 @@ library PreimageKeyLib { /// @param _key The local data key to localize. /// @param _localContext The local context for the key. /// @return localizedKey_ The localized local data key. - function localize(bytes32 _key, bytes32 _localContext) public view returns (bytes32 localizedKey_) { + function localize(bytes32 _key, bytes32 _localContext) internal view returns (bytes32 localizedKey_) { assembly { // Grab the current free memory pointer to restore later. let ptr := mload(0x40) @@ -44,7 +44,7 @@ library PreimageKeyLib { /// @notice Computes and returns the key for a global keccak pre-image. /// @param _preimage The pre-image. /// @return key_ The pre-image key. - function keccak256PreimageKey(bytes memory _preimage) public pure returns (bytes32 key_) { + function keccak256PreimageKey(bytes memory _preimage) internal pure returns (bytes32 key_) { assembly { // Grab the size of the `_preimage` let size := mload(_preimage) From a1048643760777144d48337ace56d8e701769d28 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Tue, 6 Feb 2024 20:17:33 +0900 Subject: [PATCH 15/16] fasdinfasdofasdiofnasodfiasd --- rvsol/src/Step.sol | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/rvsol/src/Step.sol b/rvsol/src/Step.sol index f6d408a4..bd41ab31 100644 --- a/rvsol/src/Step.sol +++ b/rvsol/src/Step.sol @@ -6,11 +6,13 @@ import { PreimageKeyLib } from "./PreimageKeyLib.sol"; contract Step { IPreimageOracle public preimageOracle; - address public preimageKeyLib; constructor(IPreimageOracle _preimageOracle) { preimageOracle = _preimageOracle; - preimageKeyLib = address(PreimageKeyLib); + } + + function localize(bytes32 _key, bytes32 _localContext) public view returns (bytes32 localizedKey_) { + return PreimageKeyLib.localize(_key, _localContext); } // Executes a single RISC-V instruction, starting from @@ -24,10 +26,6 @@ contract Step { function preimageOraclePos() -> out { // slot of preimageOraclePos field out := 0 } - function preimageKeyLibPos() -> out { // slot of preimageKeyLib field - out := 1 - } - // // Yul64 - functions to do 64 bit math - see yul64.go // @@ -784,6 +782,21 @@ contract Step { } function localize(preImageKey, localContext_) -> localizedKey { + // calling address(this).localize(bytes32,bytes32) + // eventually calling PreimageKeyLib.localize(bytes32,bytes32) + let memPtr := mload(0x40) // get pointer to free memory for preimage interactions + mstore(memPtr, shl(224, 0x1aae47f0)) // (32-4)*8=224: right-pad the function selector, and then store it as prefix + mstore(add(memPtr, 0x04), preImageKey) + mstore(add(memPtr, 0x24), localContext_) + let cgas := 100000 // TODO change call gas + + let res := delegatecall(cgas, address(), memPtr, 0x44, 0x00, 0x20) // output into scratch space + if res { // 1 on success + localizedKey := mload(0x00) + leave + } + revertWithCode(0x1234dead) + // let addr := sload(preimageKeyLibPos()) // calling PreimageKeyLib.localize(bytes32,bytes32) // let memPtr := mload(0x40) // get pointer to free memory for preimage interactions // mstore(memPtr, shl(224, 0x1aae47f0)) // (32-4)*8=224: right-pad the function selector, and then store it as prefix @@ -803,15 +816,15 @@ contract Step { // // TODO: deduplicate definition of localize using lib // // Grab the current free memory pointer to restore later. - let ptr := mload(0x40) - // Store the local data key and caller next to each other in memory for hashing. - mstore(0, preImageKey) - mstore(0x20, caller()) - mstore(0x40, localContext_) - // Localize the key with the above `localize` operation. - localizedKey := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) - // Restore the free memory pointer. - mstore(0x40, ptr) + // let ptr := mload(0x40) + // // Store the local data key and caller next to each other in memory for hashing. + // mstore(0, preImageKey) + // mstore(0x20, caller()) + // mstore(0x40, localContext_) + // // Localize the key with the above `localize` operation. + // localizedKey := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1)) + // // Restore the free memory pointer. + // mstore(0x40, ptr) } function readPreimageValue(addr, count, localContext_) -> out { From 540bd79cb9a536a220165faeb101208c2eff5303 Mon Sep 17 00:00:00 2001 From: pcw109550 Date: Tue, 6 Feb 2024 20:18:37 +0900 Subject: [PATCH 16/16] I love solidity --- rvsol/src/Step.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/rvsol/src/Step.sol b/rvsol/src/Step.sol index bd41ab31..1c2583c0 100644 --- a/rvsol/src/Step.sol +++ b/rvsol/src/Step.sol @@ -11,6 +11,7 @@ contract Step { preimageOracle = _preimageOracle; } + // we must use public scope because solidity compiler optimizes out function localize(bytes32 _key, bytes32 _localContext) public view returns (bytes32 localizedKey_) { return PreimageKeyLib.localize(_key, _localContext); }