Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
61d19312
Commit
61d19312
authored
Aug 08, 2023
by
inphi
Committed by
clabby
Aug 10, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(ctb): Cannon contracts VM tests
parent
d6dcb1f4
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1472 additions
and
3 deletions
+1472
-3
differential-testing.go
...rock/scripts/differential-testing/differential-testing.go
+44
-0
CommonTest.t.sol
packages/contracts-bedrock/test/CommonTest.t.sol
+40
-0
MIPS.t.sol
packages/contracts-bedrock/test/MIPS.t.sol
+1388
-3
No files found.
packages/contracts-bedrock/scripts/differential-testing/differential-testing.go
View file @
61d19312
...
...
@@ -5,7 +5,9 @@ import (
"fmt"
"math/big"
"os"
"strconv"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum/go-ethereum/accounts/abi"
...
...
@@ -60,6 +62,15 @@ var (
proveWithdrawalInputsArgs
=
abi
.
Arguments
{
{
Name
:
"inputs"
,
Type
:
proveWithdrawalInputs
},
}
// cannonMemoryProof inputs tuple (bytes32, bytes)
cannonMemoryProof
,
_
=
abi
.
NewType
(
"tuple"
,
"CannonMemoryProof"
,
[]
abi
.
ArgumentMarshaling
{
{
Name
:
"memRoot"
,
Type
:
"bytes32"
},
{
Name
:
"proof"
,
Type
:
"bytes"
},
})
cannonMemoryProofArgs
=
abi
.
Arguments
{
{
Name
:
"encodedCannonMemoryProof"
,
Type
:
cannonMemoryProof
},
}
)
func
main
()
{
...
...
@@ -312,6 +323,39 @@ func main() {
// Print the output
fmt
.
Print
(
hexutil
.
Encode
(
packed
[
32
:
]))
case
"cannonMemoryProof"
:
// <pc, insn, [memAddr, memValue]>
mem
:=
mipsevm
.
NewMemory
()
if
len
(
args
)
!=
3
&&
len
(
args
)
!=
5
{
panic
(
"Error: cannonMemoryProofWithProof requires 2 or 4 arguments"
)
}
pc
,
err
:=
strconv
.
ParseUint
(
args
[
1
],
10
,
32
)
checkErr
(
err
,
"Error decocding addr"
)
insn
,
err
:=
strconv
.
ParseUint
(
args
[
2
],
10
,
32
)
checkErr
(
err
,
"Error decocding insn"
)
mem
.
SetMemory
(
uint32
(
pc
),
uint32
(
insn
))
var
insnProof
,
memProof
[
896
]
byte
if
len
(
args
)
==
5
{
memAddr
,
err
:=
strconv
.
ParseUint
(
args
[
3
],
10
,
32
)
checkErr
(
err
,
"Error decocding memAddr"
)
memValue
,
err
:=
strconv
.
ParseUint
(
args
[
4
],
10
,
32
)
checkErr
(
err
,
"Error decocding memValue"
)
mem
.
SetMemory
(
uint32
(
memAddr
),
uint32
(
memValue
))
memProof
=
mem
.
MerkleProof
(
uint32
(
memAddr
))
}
insnProof
=
mem
.
MerkleProof
(
uint32
(
pc
))
output
:=
struct
{
MemRoot
common
.
Hash
Proof
[]
byte
}{
MemRoot
:
mem
.
MerkleRoot
(),
Proof
:
append
(
insnProof
[
:
],
memProof
[
:
]
...
),
}
packed
,
err
:=
cannonMemoryProofArgs
.
Pack
(
&
output
)
checkErr
(
err
,
"Error encoding output"
)
fmt
.
Print
(
hexutil
.
Encode
(
packed
[
32
:
]))
default
:
panic
(
fmt
.
Errorf
(
"Unknown command: %s"
,
args
[
0
]))
}
...
...
packages/contracts-bedrock/test/CommonTest.t.sol
View file @
61d19312
...
...
@@ -678,6 +678,46 @@ contract FFIInterface is Test {
return abi.decode(vm.ffi(cmds), (bytes32, bytes, bytes, bytes[]));
}
function getCannonMemoryProof(uint32 pc, uint32 insn)
external
returns (
bytes32,
bytes memory
) {
string[] memory cmds = new string[](4);
cmds[0] = "scripts/differential-testing/differential-testing";
cmds[1] = "cannonMemoryProof";
cmds[2] = vm.toString(pc);
cmds[3] = vm.toString(insn);
bytes memory result = vm.ffi(cmds);
(
bytes32 memRoot,
bytes memory proof
) = abi.decode(result, (bytes32, bytes));
return (memRoot, proof);
}
function getCannonMemoryProof(uint32 pc, uint32 insn, uint32 memAddr, uint32 memVal)
external
returns (
bytes32,
bytes memory
) {
string[] memory cmds = new string[](6);
cmds[0] = "scripts/differential-testing/differential-testing";
cmds[1] = "cannonMemoryProof";
cmds[2] = vm.toString(pc);
cmds[3] = vm.toString(insn);
cmds[4] = vm.toString(memAddr);
cmds[5] = vm.toString(memVal);
bytes memory result = vm.ffi(cmds);
(
bytes32 memRoot,
bytes memory proof
) = abi.decode(result, (bytes32, bytes));
return (memRoot, proof);
}
}
// Used for testing a future upgrade beyond the current implementations.
...
...
packages/contracts-bedrock/test/MIPS.t.sol
View file @
61d19312
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import {
Test } from "forge-std/Tes
t.sol";
import {
CommonTest } from "./CommonTest.
t.sol";
import { MIPS } from "src/cannon/MIPS.sol";
import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
import { console2 as console } from "forge-std/console2.sol";
contract MIPS_Test is Test {
contract MIPS_Test is
Common
Test {
MIPS internal mips;
PreimageOracle internal oracle;
function setUp() public {
function setUp() public virtual override {
super.setUp();
oracle = new PreimageOracle();
mips = new MIPS(oracle);
vm.store(address(mips), 0x0, bytes32(abi.encode(address(oracle))));
...
...
@@ -41,6 +43,1364 @@ contract MIPS_Test is Test {
assertTrue(postState != bytes32(0));
}
function test_add_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x20); // add t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 12;
state.registers[18] = 20;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] + state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_addu_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x21); // addu t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 12;
state.registers[18] = 20;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] + state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_addi_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0x8, 17, 8, imm); // addi t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] + imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_addui_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0x9, 17, 8, imm); // addui t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] + imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_sub_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x22); // sub t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 20;
state.registers[18] = 12;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] - state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_subu_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x23); // subu t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 20;
state.registers[18] = 12;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] - state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_and_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x24); // and t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] & state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_andi_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0xc, 17, 8, imm); // andi t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] & imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_or_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x25); // or t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] | state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_ori_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0xd, 17, 8, imm); // ori t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] | imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_xor_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x26); // xor t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] ^ state.registers[18]; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_xori_succeeds() external {
uint16 imm = 40;
uint32 insn = encodeitype(0xe, 17, 8, imm); // xori t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 4; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[17] ^ imm;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_nor_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x27); // nor t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = ~(state.registers[17] | state.registers[18]); // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_lb_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x20, 0x9, 0x8, 0x4); // lb $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_00_00_00);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_lh_succeeds() external {
uint32 t1 = 0x100;
uint32 val = 0x12_23_00_00;
uint32 insn = encodeitype(0x21, 0x9, 0x8, 0x4); // lh $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, val);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12_23; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_lw_succeeds() external {
uint32 t1 = 0x100;
uint32 val = 0x12_23_45_67;
uint32 insn = encodeitype(0x23, 0x9, 0x8, 0x4); // lw $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, val);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = val; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_lbu_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x24, 0x9, 0x8, 0x4); // lbu $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_23_00_00);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_lhu_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x25, 0x9, 0x8, 0x4); // lhu $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_23_00_00);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12_23; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_lwl_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x22, 0x9, 0x8, 0x4); // lwl $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_34_56_78);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x12_34_56_78; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
// test unaligned address
insn = encodeitype(0x22, 0x9, 0x8, 0x5); // lwl $t0, 5($t1)
(state.memRoot, proof) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0x12_34_56_78);
expect.memRoot = state.memRoot;
expect.registers[8] = 0x34_56_78_dd; // t0
postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_lwr_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x26, 0x9, 0x8, 0x4); // lwr $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0x12_34_56_78);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0xaa_bb_cc_12; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
// test unaligned address
insn = encodeitype(0x26, 0x9, 0x8, 0x5); // lwr $t0, 5($t1)
(state.memRoot, proof) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0x12_34_56_78);
expect.memRoot = state.memRoot;
expect.registers[8] = 0xaa_bb_12_34; // t0
postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_sb_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x28, 0x9, 0x8, 0x4); // sb $t0, 4($t1)
// note. cannon memory is zero-initalized. mem[t+4] = 0 is a no-op
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xdd_00_00_00);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_sh_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x29, 0x9, 0x8, 0x4); // sh $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xcc_dd_00_00);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_swl_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x2a, 0x9, 0x8, 0x4); // swl $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xaa_bb_cc_dd);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_sw_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x2b, 0x9, 0x8, 0x4); // sw $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xaa_bb_cc_dd);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_swr_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x2e, 0x9, 0x8, 0x5); // swr $t0, 5($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xcc_dd_00_00);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[8];
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_ll_succeeds() external {
uint32 t1 = 0x100;
uint32 val = 0x12_23_45_67;
uint32 insn = encodeitype(0x30, 0x9, 0x8, 0x4); // ll $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, val);
state.registers[8] = 0; // t0
state.registers[9] = t1;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = val; // t0
expect.registers[9] = t1;
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_sc_succeeds() external {
uint32 t1 = 0x100;
uint32 insn = encodeitype(0x38, 0x9, 0x8, 0x4); // sc $t0, 4($t1)
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, t1 + 4, 0);
state.registers[8] = 0xaa_bb_cc_dd; // t0
state.registers[9] = t1;
MIPS.State memory expect;
(expect.memRoot,) = ffi.getCannonMemoryProof(0, insn, t1 + 4, 0xaa_bb_cc_dd);
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x1;
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_movn_succeeds() external {
// test mips mov instruction
uint32 insn = encodespec(0x9, 0xa, 0x8, 0xb); // movn $t0, $t1, $t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xa; // t0
state.registers[9] = 0xb; // t1
state.registers[10] = 0x1; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9];
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
state.registers[10] = 0x0; // t2
expect.registers[10] = 0x0; // t2
expect.registers[8] = state.registers[8];
postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_movz_succeeds() external {
// test mips mov instruction
uint32 insn = encodespec(0x9, 0xa, 0x8, 0xa); // movz $t0, $t1, $t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xa; // t0
state.registers[9] = 0xb; // t1
state.registers[10] = 0x0; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9];
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
state.registers[10] = 0x1; // t2
expect.registers[10] = 0x1; // t2
expect.registers[8] = state.registers[8];
postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_mflo_succeeds() external {
uint32 insn = encodespec(0x0, 0x0, 0x8, 0x12); // mflo $t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.lo = 0xdeadbeef;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.lo = state.lo;
expect.registers[8] = state.lo;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_mfhi_succeeds() external {
uint32 insn = encodespec(0x0, 0x0, 0x8, 0x10); // mfhi $t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.hi = 0xdeadbeef;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.hi = state.hi;
expect.registers[8] = state.hi;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_mthi_succeeds() external {
uint32 insn = encodespec(0x8, 0x0, 0x0, 0x11); // mthi $t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.hi = state.registers[8];
expect.registers[8] = state.registers[8];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_mtlo_succeeds() external {
uint32 insn = encodespec(0x8, 0x0, 0x0, 0x13); // mtlo $t0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.lo = state.registers[8];
expect.registers[8] = state.registers[8];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_mul_succeeds() external {
uint32 insn = encodespec2(0x9, 0xa, 0x8, 0x2); // mul t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 5; // t1
state.registers[10] = 2; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] * state.registers[10]; // t0
expect.registers[9] = 5;
expect.registers[10] = 2;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_mult_succeeds() external {
uint32 insn = encodespec(0x9, 0xa, 0x0, 0x18); // mult t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x0F_FF_00_00; // t1
state.registers[10] = 100; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
expect.lo = 0x3F_9C_00_00;
expect.hi = 0x6;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_multu_succeeds() external {
uint32 insn = encodespec(0x9, 0xa, 0x0, 0x19); // multu t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x0F_FF_00_00; // t1
state.registers[10] = 100; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
expect.lo = 0x3F_9C_00_00;
expect.hi = 0x6;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_div_succeeds() external {
uint32 insn = encodespec(0x9, 0xa, 0x0, 0x1a); // div t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 5; // t1
state.registers[10] = 2; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
expect.lo = 2;
expect.hi = 1;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_divu_succeeds() external {
uint32 insn = encodespec(0x9, 0xa, 0x0, 0x1b); // divu t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 5; // t1
state.registers[10] = 2; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
expect.lo = 2;
expect.hi = 1;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_beq_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x4, 0x9, 0x8, boff); // beq $t0, $t1, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
state.registers[9] = 0xdeadbeef; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0xdeadbeef;
expect.registers[9] = 0xdeadbeef;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
// branch not taken
state.registers[8] = 0xaa;
expect.registers[8] = 0xaa;
expect.nextPC = state.nextPC + 4;
postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_bne_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x5, 0x9, 0x8, boff); // bne $t0, $t1, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
state.registers[9] = 0xaa; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0xdeadbeef;
expect.registers[9] = 0xaa;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_blez_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x6, 0x8, 0x0, boff); // blez $t0, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_bgtz_succeeds() external {
uint16 boff = 0xa0;
uint32 insn = encodeitype(0x7, 0x8, 0x0, boff); // bgtz $t0, 0xa0
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 1;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_bltz_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x1, 0x8, 0x0, boff); // bltz $t0, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xF0_00_00_00; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0xF0_00_00_00;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_bgez_succeeds() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x1, 0x8, 0x1, boff); // bgez $t0, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0x00_00_00_01; // t0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + (uint32(boff) << 2);
expect.step = state.step + 1;
expect.registers[8] = 0x00_00_00_01;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_jump_succeeds() external {
uint16 label = 0x2;
uint32 insn = uint32(0x08_00_00_00) | label; // j label
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = label << 2;
expect.step = state.step + 1;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_jal_succeeds() external {
uint32 pc = 0x0;
uint16 label = 0x2;
uint32 insn = uint32(0x0c_00_00_00) | label; // jal label
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(pc, insn);
MIPS.State memory state;
state.pc = 0;
state.nextPC = 4;
state.memRoot = memRoot;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = label << 2;
expect.step = state.step + 1;
expect.registers[31] = state.pc + 8;
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_sll_succeeds() external {
uint8 shiftamt = 4;
uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6); // sll t0, t1, 3
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] << shiftamt;
expect.registers[9] = state.registers[9];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_srl_succeeds() external {
uint8 shiftamt = 4;
uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6 | 2); // srl t0, t1, 3
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> shiftamt;
expect.registers[9] = state.registers[9];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_sra_succeeds() external {
uint8 shiftamt = 4;
uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6 | 3); // sra t0, t1, 3
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> shiftamt;
expect.registers[9] = state.registers[9];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_sllv_succeeds() external {
uint32 insn = encodespec(0xa, 0x9, 0x8, 4); // sllv t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1
state.registers[10] = 4; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] << state.registers[10]; // t0
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_srlv_succeeds() external {
uint32 insn = encodespec(0xa, 0x9, 0x8, 6); // srlv t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20_00; // t1
state.registers[10] = 4; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> state.registers[10]; // t0
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_srav_succeeds() external {
uint32 insn = encodespec(0xa, 0x9, 0x8, 7); // srav t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20_00; // t1
state.registers[10] = 4; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> state.registers[10]; // t0
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_lui_succeeds() external {
uint32 insn = encodeitype(0xf, 0x0, 0x8, 0x4); // lui $t0, 0x04
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0x00_04_00_00; // t0
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_clo_succeeds() external {
uint32 insn = encodespec2(0x9, 0x0, 0x8, 0x21); // clo t0, t1
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0xFF_00_00_00; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 8; // t0
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_clz_succeeds() external {
uint32 insn = encodespec2(0x9, 0x0, 0x8, 0x20); // clz t0, t1
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x00_00_F0_00; // t1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 16; // t0
expect.registers[9] = state.registers[9];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_preimage_read_succeeds() external {
uint32 pc = 0x0;
uint32 insn = 0x0000000c; // syscall
uint32 a1 = 0x4;
uint32 a1_val = 0x0000abba;
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(pc, insn, a1, a1_val);
uint32[32] memory registers;
registers[2] = 4003; // read syscall
registers[4] = 5; // fd
registers[5] = a1; // addr
registers[6] = 4; // count
MIPS.State memory state = MIPS.State({
memRoot: memRoot,
preimageKey: bytes32(uint256(1) << 248 | 0x01),
preimageOffset: 8, // start reading past the pre-image length prefix
pc: pc,
nextPC: pc + 4,
lo: 0,
hi: 0,
heap: 0,
exitCode: 0,
exited: false,
step: 1,
registers: registers
});
bytes memory encodedState = encodeState(state);
// prime the pre-image oracle
bytes32 word = bytes32(uint256(0xdeadbeef) << 224);
uint8 size = 4;
uint8 partOffset = 8;
oracle.loadLocalData(uint256(state.preimageKey), word, size, partOffset);
MIPS.State memory expect = state;
expect.preimageOffset += 4;
expect.pc = state.nextPC;
expect.nextPC += 4;
expect.step += 1;
expect.registers[2] = 4; // return
expect.registers[7] = 0; // errno
// recompute merkle root of written pre-image
(expect.memRoot,) = ffi.getCannonMemoryProof(pc, insn, a1, 0xdeadbeef);
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_preimage_write_succeeds() external {
uint32 pc = 0x0;
uint32 insn = 0x0000000c; // syscall
uint32 a1 = 0x4;
uint32 a1_val = 0x0000abba;
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(pc, insn, a1, a1_val);
uint32[32] memory registers;
registers[2] = 4004; // write syscall
registers[4] = 6; // fd
registers[5] = a1; // addr
registers[6] = 4; // count
MIPS.State memory state = MIPS.State({
memRoot: memRoot,
preimageKey: bytes32(0),
preimageOffset: 1,
pc: pc,
nextPC: 4,
lo: 0,
hi: 0,
heap: 0,
exitCode: 0,
exited: false,
step: 1,
registers: registers
});
bytes memory encodedState = encodeState(state);
MIPS.State memory expect = state;
expect.preimageOffset = 0; // preimage write resets offset
expect.pc = state.nextPC;
expect.nextPC += 4;
expect.step += 1;
expect.preimageKey = bytes32(uint256(0xabba));
expect.registers[2] = 4; // return
expect.registers[7] = 0; // errno
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_mmap_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(0, insn);
MIPS.State memory state;
state.memRoot = memRoot;
state.nextPC = 4;
state.registers[2] = 4090; // mmap syscall
state.registers[4] = 0x0; // a0
state.registers[5] = 4095; // a1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
// assert page allocation is aligned to 4k
expect.step = state.step + 1;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.heap = state.heap + 4096;
expect.registers[2] = 0; // return old heap
expect.registers[4] = 0x0; // a0
expect.registers[5] = 4095; // a1
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_brk_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4045; // brk syscall
state.registers[4] = 0xdead;
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.step = state.step + 1;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.registers[2] = 0x40000000;
expect.registers[4] = state.registers[4]; // registers unchanged
bytes32 postState = mips.step(encodedState, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_clone_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4120; // clone syscall
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.step = state.step + 1;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.registers[2] = 1;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_exit_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4246; // exit_group syscall
state.registers[4] = 0x5; // a0
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.pc;
expect.nextPC = state.nextPC;
expect.step = state.step + 1;
expect.registers[2] = state.registers[2]; // unchanged
expect.registers[4] = state.registers[4]; // unchanged
expect.exited = true;
expect.exitCode = uint8(state.registers[4]);
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_fcntl_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4055; // fnctl syscall
state.registers[4] = 0x0; // a0
state.registers[5] = 0x3; // a1
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[2] = 0;
expect.registers[5] = state.registers[5];
bytes32 postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
// assert O_WRONLY
state.registers[4] = 0x1; // a0
expect.registers[4] = state.registers[4];
expect.registers[2] = 1;
postState = mips.step(encodeState(state), proof);
assertTrue(postState == outputState(expect), "unexpected post state");
}
function test_prestate_exited_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.exited = true;
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof);
assertTrue(postState == outputState(state), "unexpected post state");
}
function test_illegal_instruction_fails() external {
uint32 illegal_insn = 0xFF_FF_FF_FF;
// the illegal instruction is partially decoded as containing a memory operand
// so we stuff random data to the expected address
uint32 addr = 0xFF_FF_FF_FC; // 4-byte aligned ff..ff
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(0, illegal_insn, addr, 0);
MIPS.State memory state;
state.memRoot = memRoot;
bytes memory encodedState = encodeState(state);
vm.expectRevert("invalid instruction");
mips.step(encodedState, proof);
}
function test_invalid_root_fails() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[2] = 4246; // exit_group syscall
state.registers[4] = 0x5; // a0
// invalidate proof
for (uint i = 0; i < proof.length; i++) {
proof[i] = 0x0;
}
vm.expectRevert(hex"000000000000000000000000000000000000000000000000000000000badf00d");
mips.step(encodeState(state), proof);
}
function test_jump_inDelaySlot_fails() external {
uint16 label = 0x2;
uint32 insn = uint32(0x08_00_00_00) | label; // j label
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.nextPC = 0xa;
vm.expectRevert("jump in delay slot");
mips.step(encodeState(state), proof);
}
function test_branch_inDelaySlot_fails() external {
uint16 boff = 0x10;
uint32 insn = encodeitype(0x4, 0x9, 0x8, boff); // beq $t0, $t1, 16
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 0xdeadbeef; // t0
state.registers[9] = 0xdeadbeef; // t1
state.nextPC = 0xa;
vm.expectRevert("branch in delay slot");
mips.step(encodeState(state), proof);
}
function encodeState(MIPS.State memory state) internal pure returns (bytes memory) {
bytes memory registers;
for (uint256 i = 0; i < state.registers.length; i++) {
...
...
@@ -61,4 +1421,29 @@ contract MIPS_Test is Test {
registers
);
}
function outputState(MIPS.State memory state) internal pure returns (bytes32 out_) {
bytes memory enc = encodeState(state);
assembly {
out_ := keccak256(add(enc, 0x20), 226)
}
}
function constructMIPSState(uint32 pc, uint32 insn, uint32 addr, uint32 val) internal returns (MIPS.State memory state, bytes memory proof) {
(state.memRoot, proof) = ffi.getCannonMemoryProof(pc, insn, addr, val);
state.pc = pc;
state.nextPC = pc + 4;
}
function encodeitype(uint8 opcode, uint8 rs, uint8 rt, uint16 imm) internal pure returns (uint32 insn) {
insn = uint32(opcode) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | imm;
}
function encodespec(uint8 rs, uint8 rt, uint8 rd, uint16 funct) internal pure returns (uint32 insn) {
insn = uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct);
}
function encodespec2(uint8 rs, uint8 rt, uint8 rd, uint8 funct) internal pure returns (uint32 insn) {
insn = uint32(28) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment