Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contracts/GatewayRequest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ library GatewayOP {
uint8 constant READ_ARRAY = 62;
uint8 constant READ_HASHED_BYTES = 63;
uint8 constant READ_SLOTS = 64;
uint8 constant READ_CODE = 65;

uint8 constant SET_SLOT = 70;
uint8 constant ADD_SLOT = 71;
Expand Down
53 changes: 32 additions & 21 deletions contracts/GatewayVM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
pragma solidity ^0.8.0;

import {GatewayRequest, GatewayOP, EvalFlag} from './GatewayRequest.sol';
import {IVerifierHooks, InvalidProof, NOT_A_CONTRACT} from './IVerifierHooks.sol';
import {Bytes} from '../lib/optimism/packages/contracts-bedrock/src/libraries/Bytes.sol'; // Bytes.slice
import {
IVerifierHooks,
InvalidProof,
NOT_A_CONTRACT
} from './IVerifierHooks.sol';
import {
Bytes
} from '../lib/optimism/packages/contracts-bedrock/src/libraries/Bytes.sol'; // Bytes.slice

import {console} from 'forge-std/console.sol'; // DEBUG

Expand Down Expand Up @@ -57,11 +63,7 @@ library GatewayVM {
let x
ret := 1 // assume zero
// while (p < e)
for {

} lt(p, e) {

} {
for {} lt(p, e) {} {
x := mload(p) // remember last
p := add(p, 32) // step by word
if x {
Expand Down Expand Up @@ -233,15 +235,6 @@ library GatewayVM {
return p.proofs[uint8(p.order[p.index++])];
}

function getStorageRoot(Machine memory vm) internal view returns (bytes32) {
return
vm.proofs.hooks.verifyAccountState(
vm.proofs.stateRoot,
vm.target,
vm.readProof()
);
}

function getStorage(
Machine memory vm,
uint256 slot
Expand Down Expand Up @@ -326,13 +319,13 @@ library GatewayVM {
}

function createMachine() internal pure returns (Machine memory vm) {
vm.pos = 0;
//vm.pos = 0;
vm.stack = new uint256[](MAX_STACK);
vm.stackBits = 0;
vm.stackSize = 0;
//vm.stackBits = 0;
//vm.stackSize = 0;
vm.target = address(0);
vm.storageRoot = NOT_A_CONTRACT;
vm.slot = 0;
//vm.slot = 0;
}

function evalRequest(
Expand All @@ -359,7 +352,11 @@ library GatewayVM {
vm.pushBytes(vm.readBytes(vm.readUint(vm.readByte())));
} else if (op == GatewayOP.SET_TARGET) {
vm.target = address(uint160(vm.popAsUint256()));
vm.storageRoot = vm.getStorageRoot();
vm.storageRoot = vm.proofs.hooks.verifyAccountState(
vm.proofs.stateRoot,
vm.target,
vm.readProof()
);
vm.slot = 0;
} else if (op == GatewayOP.SET_OUTPUT) {
uint256 i = vm.popAsUint256();
Expand All @@ -382,6 +379,20 @@ library GatewayVM {
revert InvalidProof();
}
vm.pushBytes(v);
} else if (op == GatewayOP.READ_CODE) {
bytes memory proof = vm.readProof();
bytes memory code = vm.readProof();
if (
!vm.proofs.hooks.verifyCode(
vm.proofs.stateRoot,
address(uint160(vm.popAsUint256())),
proof,
code
)
) {
revert InvalidProof();
}
vm.pushBytes(code);
} else if (op == GatewayOP.READ_ARRAY) {
vm.pushBytes(vm.proveArray(vm.popAsUint256()));
} else if (op == GatewayOP.SET_SLOT) {
Expand Down
8 changes: 8 additions & 0 deletions contracts/IVerifierHooks.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ interface IVerifierHooks {
address target,
bytes memory proof
) external view returns (bytes32 storageRoot);

function verifyCode(
bytes32 stateRoot,
address target,
bytes memory proof,
bytes memory code
) external view returns (bool);

function verifyStorageValue(
bytes32 storageRoot,
address target,
Expand Down
32 changes: 32 additions & 0 deletions contracts/StandardVerifierHooks.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IVerifierHooks} from "./IVerifierHooks.sol";

abstract contract StandardVerifierHooks is IVerifierHooks {

function verifyAccount(
bytes32 stateRoot,
address target,
bytes memory encodedProof
) public virtual view returns (bytes32 storageRoot, bytes32 codeHash);

function verifyAccountState(
bytes32 stateRoot,
address target,
bytes memory proof
) external view returns (bytes32 storageRoot) {
(storageRoot, ) = verifyAccount(stateRoot, target, proof);
}

function verifyCode(
bytes32 stateRoot,
address target,
bytes memory proof,
bytes memory code
) external view returns (bool) {
(, bytes32 codeHash) = verifyAccount(stateRoot, target, proof);
return keccak256(code) == codeHash;
}

}
20 changes: 10 additions & 10 deletions contracts/eth/EthVerifierHooks.sol
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IVerifierHooks, NOT_A_CONTRACT, NULL_CODE_HASH} from '../IVerifierHooks.sol';
import {StandardVerifierHooks} from '../StandardVerifierHooks.sol';
import {NOT_A_CONTRACT, NULL_CODE_HASH} from '../IVerifierHooks.sol';
import {SecureMerkleTrie} from './SecureMerkleTrie.sol';
import {RLPReader, RLPReaderExt} from '../RLPReaderExt.sol';

bytes32 constant EMPTY_STORAGE_HASH = keccak256(hex'80'); // see: src/eth/types.ts

contract EthVerifierHooks is IVerifierHooks {
function verifyAccountState(
contract EthVerifierHooks is StandardVerifierHooks {
function verifyAccount(
bytes32 stateRoot,
address target,
bytes memory proof
) external pure returns (bytes32 storageRoot) {
) public pure override returns (bytes32 storageRoot, bytes32 codeHash) {
(bool exists, bytes memory value) = SecureMerkleTrie.get(
abi.encodePacked(target),
abi.decode(proof, (bytes[])),
stateRoot
);
if (!exists) return NOT_A_CONTRACT;
if (!exists) return (NOT_A_CONTRACT, NULL_CODE_HASH);
RLPReader.RLPItem[] memory v = RLPReader.readList(value);
// accountState structure:
// standard: [nonce, balance, storageRoot, codeHash]
// blast: [nonce, flags, fixed, shares, remainder, storageRoot, codeHash]
// generalization: index from the end
bytes32 codeHash = RLPReaderExt.strictBytes32FromRLP(v[v.length - 1]);
return
codeHash == NULL_CODE_HASH
? NOT_A_CONTRACT
: RLPReaderExt.strictBytes32FromRLP(v[v.length - 2]);
codeHash = RLPReaderExt.strictBytes32FromRLP(v[v.length - 1]);
storageRoot = codeHash == NULL_CODE_HASH
? NOT_A_CONTRACT
: RLPReaderExt.strictBytes32FromRLP(v[v.length - 2]);
}

function verifyStorageValue(
Expand Down
18 changes: 9 additions & 9 deletions contracts/linea/LineaVerifierHooks.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {IVerifierHooks, InvalidProof, NOT_A_CONTRACT, NULL_CODE_HASH} from '../IVerifierHooks.sol';
import {StandardVerifierHooks} from '../StandardVerifierHooks.sol';
import {InvalidProof, NOT_A_CONTRACT, NULL_CODE_HASH} from '../IVerifierHooks.sol';
import {SparseMerkleProof} from './SparseMerkleProof.sol';

bytes32 constant EMPTY_STORAGE_HASH = 0x07977874126658098c066972282d4c85f230520af3847e297fe7524f976873e5; // see: src/linea/types.ts

contract LineaVerifierHooks is IVerifierHooks {
contract LineaVerifierHooks is StandardVerifierHooks {
uint256 constant LAST_LEAF_INDEX = 41;

struct Proof {
Expand All @@ -15,11 +16,11 @@ contract LineaVerifierHooks is IVerifierHooks {
bytes[] nodes;
}

function verifyAccountState(
function verifyAccount(
bytes32 stateRoot,
address target,
bytes memory encodedProof
) external pure returns (bytes32) {
) public override pure returns (bytes32, bytes32) {
// NOTE: dynamic Proof[] abi.decode() codegen is awful
// instead, right nodes are empty when existence proof
(Proof memory proof, Proof memory right) = abi.decode(
Expand All @@ -36,14 +37,13 @@ contract LineaVerifierHooks is IVerifierHooks {
);
SparseMerkleProof.Account memory account = SparseMerkleProof
.getAccount(proof.value);
return
account.keccakCodeHash == NULL_CODE_HASH
? NOT_A_CONTRACT
: account.storageRoot;
if (account.keccakCodeHash != NULL_CODE_HASH) {
return (account.storageRoot, account.keccakCodeHash);
}
} else {
_requireExclusion(stateRoot, hKey, proof, right);
return NOT_A_CONTRACT;
}
return (NOT_A_CONTRACT, NULL_CODE_HASH);
}

function verifyStorageValue(
Expand Down
28 changes: 19 additions & 9 deletions contracts/scroll/ScrollVerifierHooks.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IVerifierHooks, InvalidProof, NOT_A_CONTRACT, NULL_CODE_HASH} from '../IVerifierHooks.sol';
import {StandardVerifierHooks} from '../StandardVerifierHooks.sol';
import {
InvalidProof,
NOT_A_CONTRACT,
NULL_CODE_HASH
} from '../IVerifierHooks.sol';

interface IPoseidon {
function poseidon(
Expand All @@ -10,7 +15,7 @@ interface IPoseidon {
) external view returns (bytes32);
}

contract ScrollVerifierHooks is IVerifierHooks {
contract ScrollVerifierHooks is StandardVerifierHooks {
IPoseidon immutable _poseidon;

constructor(IPoseidon poseidon) {
Expand Down Expand Up @@ -40,21 +45,20 @@ contract ScrollVerifierHooks is IVerifierHooks {
// https://docs.scroll.io/en/technology/sequencer/zktrie/
uint256 constant MAX_TRIE_DEPTH = 248;

function verifyAccountState(
function verifyAccount(
bytes32 stateRoot,
address account,
bytes memory encodedProof
) external view returns (bytes32 storageRoot) {
) public view override returns (bytes32 storageRoot, bytes32 codeHash) {
(
bytes32 keyHash,
bytes32 leafHash,
bytes memory leaf,
bool exists
) = walkTree(bytes20(account), encodedProof, stateRoot, 230); // flags = 0x05080000
if (leafHash == 0) return NOT_A_CONTRACT;
if (leafHash == 0) return (NOT_A_CONTRACT, NULL_CODE_HASH);
bytes32 temp;
bytes32 amount;
bytes32 codeHash;
assembly {
temp := mload(add(leaf, 69)) // nonce||codesize||0
amount := mload(add(leaf, 101))
Expand All @@ -69,7 +73,10 @@ contract ScrollVerifierHooks is IVerifierHooks {
h = poseidonHash2(h, temp, 1280);
h = poseidonHash2(keyHash, h, 4);
if (leafHash != h) revert InvalidProof(); // InvalidAccountLeafNodeHash
if (codeHash == NULL_CODE_HASH || !exists) storageRoot = NOT_A_CONTRACT;
if (codeHash == NULL_CODE_HASH || !exists) {
codeHash = NULL_CODE_HASH;
storageRoot = NOT_A_CONTRACT;
}
}

function verifyStorageValue(
Expand Down Expand Up @@ -120,8 +127,11 @@ contract ScrollVerifierHooks is IVerifierHooks {
// NOTE: leafSize is >= 33
if (uint8(v[leafSize - 33]) != 32) revert InvalidProof(); // InvalidKeyPreimageLength

// Proof is invalid if there are un-used proof elements after this leaf node and magic bytes
if (keccak256(proof[i + 1]) != keccak256("THIS IS SOME MAGIC BYTES FOR SMT m1rRXgP2xpDI")) revert InvalidProof();
// Proof is invalid if there are un-used proof elements after this leaf node and magic bytes
if (
keccak256(proof[i + 1]) !=
keccak256('THIS IS SOME MAGIC BYTES FOR SMT m1rRXgP2xpDI')
) revert InvalidProof();
if (proof.length - 1 != i + 1) revert InvalidProof();

bytes32 temp;
Expand Down
9 changes: 9 additions & 0 deletions contracts/starknet/StarknetVerifierHooks.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ contract StarknetVerifierHooks is IVerifierHooks {
return 0;
}

function verifyCode(
bytes32 /*stateRoot*/,
address /*target*/,
bytes memory /*encodedProof*/,
bytes memory /*code*/
) external pure returns (bool) {
return false;
}

function verifyStorageValue(
bytes32 /*storageRoot*/,
address,
Expand Down
10 changes: 5 additions & 5 deletions contracts/unchecked/UncheckedVerifierHooks.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {IVerifierHooks} from '../IVerifierHooks.sol';
import {StandardVerifierHooks} from '../StandardVerifierHooks.sol';

contract UncheckedVerifierHooks is IVerifierHooks {
function verifyAccountState(
contract UncheckedVerifierHooks is StandardVerifierHooks {
function verifyAccount(
bytes32 /*stateRoot*/,
address /*target*/,
bytes memory proof
) external pure returns (bytes32 storageRoot) {
return bytes32(proof);
) public pure override returns (bytes32, bytes32) {
return abi.decode(proof, (bytes32, bytes32));
}

function verifyStorageValue(
Expand Down
22 changes: 21 additions & 1 deletion contracts/zksync/ZKSyncVerifierHooks.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IVerifierHooks, InvalidProof, NOT_A_CONTRACT} from '../IVerifierHooks.sol';
import {
IVerifierHooks,
InvalidProof,
NOT_A_CONTRACT,
NULL_CODE_HASH
} from '../IVerifierHooks.sol';
import {IZKSyncSMT, TreeEntry, ACCOUNT_CODE_HASH} from './IZKSyncSMT.sol';

contract ZKSyncVerifierHooks is IVerifierHooks {
Expand All @@ -25,6 +30,21 @@ contract ZKSyncVerifierHooks is IVerifierHooks {
: root;
}

function verifyCode(
bytes32 root,
address target,
bytes memory proof,
bytes memory code
) external view returns (bool) {
if (proof.length > 0) {
return
_verifyProof(root, ACCOUNT_CODE_HASH, uint160(target), proof) ==
keccak256(code);
} else {
return code.length == 0;
}
}

function verifyStorageValue(
bytes32 root,
address target,
Expand Down
Loading
Loading