diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4a69d198..868904b3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,8 +22,8 @@ jobs: working-directory: tests/go-tests - name: Run tests run: go test -v ./rvgo/... -coverprofile=coverage.out -coverpkg=./rvgo/... - - name: Fuzz - run: make fuzz + - name: Fuzz syscalls + run: make fuzz-syscalls - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: diff --git a/.gitignore b/.gitignore index d5be4f6b..47095509 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ bin rvgo/bin rvgo/scripts/go-ffi/go-ffi -rvgo/test/testdata rvsol/cache rvsol/out diff --git a/Makefile b/Makefile index 81e739c8..f7d81d8a 100644 --- a/Makefile +++ b/Makefile @@ -27,43 +27,9 @@ test: build make fuzz .PHONY: test -fuzz: build - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallExit ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallBrk ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallMmap ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallFcntl ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallOpenat ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallClockGettime ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallClone ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallGetrlimit ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallNoop ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateRead ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateHintRead ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStatePreimageRead ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateWrite ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateHintWrite ./rvgo/test - go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStatePreimageWrite ./rvgo/test - -fuzz-mac: - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallExit ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallBrk ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallMmap ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallFcntl ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallOpenat ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallClockGettime ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallClone ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallGetrlimit ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallNoop ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateRead ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateHintRead ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStatePreimageRead ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateWrite ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateHintWrite ./rvgo/test - go test -ldflags=-extldflags=-Wl,-ld_classic -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStatePreimageWrite ./rvgo/test - -.PHONY: \ - fuzz \ - fuzz-mac +fuzz-syscalls: build + go test -run NOTAREALTEST -v -fuzztime 200s -fuzz=FuzzEverything ./rvgo/test --parallel 15 +.PHONY: fuzz-syscalls OP_PROGRAM_PATH ?= $(MONOREPO_ROOT)/op-program/bin-riscv/op-program-client-riscv.elf diff --git a/rvgo/test/syscall_test.go b/rvgo/test/syscall_test.go index 7d8ef073..6f977d42 100644 --- a/rvgo/test/syscall_test.go +++ b/rvgo/test/syscall_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "fmt" + "math" "math/rand" "os" "testing" @@ -46,6 +47,7 @@ func (t *hintTrackingOracle) GetPreimage(k [32]byte) []byte { } func runEVM(t *testing.T, contracts *Contracts, addrs *Addresses, stepWitness *fast.StepWitness, fastPost fast.StateWitness, revertCode []byte) { + // TODO for fuzzing: avoid creating a new evm environment each time env := newEVMEnv(t, contracts, addrs) evmPost, _, _ := stepEVM(t, env, stepWitness, addrs, 0, revertCode) require.Equal(t, hexutil.Bytes(fastPost).String(), hexutil.Bytes(evmPost).String(), @@ -278,872 +280,960 @@ func TestEVMSysWriteHint(t *testing.T) { } } -func FuzzStateSyscallExit(f *testing.F) { - contracts := testContracts(f) - addrs := testAddrs - - syscalls := []int{riscv.SysExit, riscv.SysExitGroup} - - testExit := func(t *testing.T, syscall int, exitCode uint8, pc uint64, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: uint64(syscall), 10: uint64(exitCode)}, - Step: step, +// The following provides a single entrypoint to fuzz all syscalls. +// go test -run NOTAREALTEST -v -fuzztime 8m -fuzz=FuzzEverything ./rvgo/test --parallel 15 +func FuzzEverything(f *testing.F) { + f.Fuzz(func(t *testing.T, randomFunc uint64, addrSeed uint64, resSeed uint64, seed uint64, fdSeed uint64, heap uint64, exitCode uint8, pcSeed uint64, stepSeed uint64, randSeed int64) { + + // it seems that inputs can be even more random from golang rand vs fuzzing inputs + reservation := randomUint64FromUint(resSeed) + addr := randomUint64FromUint(addrSeed) + fd := randomUint64FromUint(fdSeed) % (math.MaxUint8) + pc := randomUint64FromUint(pcSeed) + step := randomUint64FromUint(stepSeed) + + switch randomFunc { + case riscv.SysExit: + { + StateSyscallExit(t, riscv.SysExit, exitCode, heap, reservation, pc, step) + } + case riscv.SysExitGroup: + { + StateSyscallExit(t, riscv.SysExitGroup, exitCode, heap, reservation, pc, step) + } + case riscv.SysBrk: + { + StateSyscallBrk(t, riscv.SysBrk, heap, reservation, pc, step, exitCode) + } + case riscv.SysMmap: + { + StateSyscallMmap(t, addr, seed, heap, fd, uint64(randSeed), pc, step, reservation, exitCode) + } + case riscv.SysFcntl: + { + outputErrorCode := uint64(0xFFFF_FFFF_FFFF_FFFF) + cmd := seed + switch cmd { + case 1: + { + if fd <= 6 { + // for any cmd=1 where fd <= 6, expect out = 0 and err = 0 + StateSyscallFcntl(t, fd, cmd, pc, heap, reservation, step, 0, 0) + } else { + // for any cmd=1, fd >= 7, expect 0xFF..FF and err = 0x4d + StateSyscallFcntl(t, fd, cmd, pc, heap, reservation, step, outputErrorCode, 0x4d) + } + } + case 3: + { + switch fd { + case riscv.FdStdin, riscv.FdHintRead, riscv.FdPreimageRead: + { + StateSyscallFcntl(t, fd, cmd, pc, heap, reservation, step, 0, 0) + } + case riscv.FdStdout, riscv.FdStderr, riscv.FdHintWrite, riscv.FdPreimageWrite: + { + StateSyscallFcntl(t, fd, cmd, pc, heap, reservation, step, 1, 0) + } + default: + { + StateSyscallFcntl(t, fd, cmd, pc, heap, reservation, step, outputErrorCode, 0x4d) + } + } + } + default: + { // any other input should produce an error with respective error code (including cmd=2) + StateSyscallFcntl(t, fd, cmd, pc, heap, reservation, step, outputErrorCode, 0x16) + } + } + } + case riscv.SysOpenat: + { + StateSyscallOpenat(t, pc, step, heap, reservation) + } + case riscv.SysClockGettime: + { + StateSyscallClockGettime(t, addr, pc, step, heap, reservation) + } + case riscv.SysClone: + { + StateSyscallClone(t, pc, step, heap, reservation) + } + case riscv.SysGetrlimit: + { + rlimit := seed + if rlimit == 7 { + StateSyscallGetrlimit(t, addr, pc, step) + } else { + StatesyscallgetrlimitError(t, rlimit, addr, pc, step) + } + } + case riscv.SysRead: + { + count := reservation + + randBytes, err := randomBytes(randSeed, fd) + require.NoError(t, err) + + switch fd { + case riscv.FdStdin: + { + StateSyscallRead(t, riscv.FdStdin, addr, count, pc, step, 0, 0) + } + case riscv.FdHintRead: + { + StateHintRead(t, addr, count, seed, pc, step, randBytes) + } + case riscv.FdPreimageRead: + { + StatePreimageRead(t, addr, count, seed, randBytes, pc, step) + } + default: + { + StateSyscallRead(t, fd, addr, count, pc, step, 0xFFFF_FFFF_FFFF_FFFF, 0x4d) + } + + } + } + case riscv.SysWrite: + { + opcode := seed + + randBytes, err := randomBytes(randSeed, fd) + require.NoError(t, err) + + switch opcode { + case riscv.FdStdout, riscv.FdStderr: + { + count := heap + StateSyscallWrite(t, opcode, addr, count, pc, step, count, 0) + } + case riscv.FdHintWrite: + { + StateHintWrite(t, addr, seed, heap, randBytes, pc, step, randSeed) + } + case riscv.FdPreimageWrite: + { + preimageOffset := reservation + + StatePreimageWrite(t, addr, heap, preimageOffset, randBytes, pc, step) + } + default: + { + count := heap + StateSyscallWrite(t, opcode, addr, count, pc, step, 0xFFFF_FFFF_FFFF_FFFF, 0x4d) + } + } + } + case riscv.SysPrlimit64, riscv.SysFutex, riscv.SysNanosleep: + { + // Tests unsupported syscalls + unsupportedSyscalls := []int{ + riscv.SysPrlimit64, + riscv.SysFutex, + riscv.SysNanosleep, + } + // index should be between [0, len(unsupportedSyscalls), exclusive of end + index := int(randomUint64FromUint(resSeed)) % len(unsupportedSyscalls) + if index < 0 { + index = -index + } + StateSyscallUnsupported(t, unsupportedSyscalls[index], heap, reservation) + } + default: + { + // if not encompassed in cases above, the syscall should results in a noop + StateSyscallNoop(t, randomFunc, seed, pc, step) + } } - state.Memory.SetUnaligned(pc, syscallInsn) - preStateRoot := state.Memory.MerkleRoot() - preStateRegisters := state.Registers - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) + }) +} - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, exitCode, state.ExitCode) // ExitCode must be set - require.Equal(t, true, state.Exited) // Must be exited - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, preStateRegisters, state.Registers) +func StateSyscallExit(t *testing.T, syscall int, exitCode uint8, heap uint64, reservation uint64, pc uint64, step uint64) { + contracts := testContracts(t) + addrs := testAddrs - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: heap, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: reservation, + Registers: [32]uint64{17: uint64(syscall), 10: uint64(exitCode)}, + Step: step, } + state.Memory.SetUnaligned(pc, syscallInsn) + preStateRoot := state.Memory.MerkleRoot() + preStateRegisters := state.Registers + preStateProof := state.Memory.MerkleProof(pc) - f.Fuzz(func(t *testing.T, exitCode uint8, pc uint64, step uint64) { - for _, syscall := range syscalls { - testExit(t, syscall, exitCode, pc, step) - } - }) + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, heap, state.Heap) + require.Equal(t, reservation, state.LoadReservation) + require.Equal(t, exitCode, state.ExitCode) + require.Equal(t, true, state.Exited) + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, preStateProof, state.Memory.MerkleProof(pc)) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, preStateRegisters, state.Registers) + + fastPost := state.EncodeWitness() + // TODO: The impact of these two checks is intermediary results are not checked – only the final result + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) } -func FuzzStateSyscallBrk(f *testing.F) { - contracts := testContracts(f) +func StateSyscallBrk(t *testing.T, syscall int, heap uint64, reservation uint64, pc uint64, step uint64, exitCode uint8) { + contracts := testContracts(t) addrs := testAddrs - f.Fuzz(func(t *testing.T, pc, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysBrk}, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[10] = 1 << 30 - expectedRegisters[11] = 0 - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) - - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set - require.Equal(t, false, state.Exited) // Must not be exited - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, expectedRegisters, state.Registers) - - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) - }) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: heap, + ExitCode: exitCode, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: reservation, + Registers: [32]uint64{17: uint64(syscall)}, + Step: step, + } + state.Memory.SetUnaligned(pc, syscallInsn) + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + expectedRegisters[10] = 1 << 30 + expectedRegisters[11] = 0 + preStateProof := state.Memory.MerkleProof(pc) + + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, heap, state.Heap) + require.Equal(t, reservation, state.LoadReservation) + require.Equal(t, exitCode, state.ExitCode) + require.Equal(t, false, state.Exited) // Must not be exited + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, preStateProof, state.Memory.MerkleProof(pc)) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, expectedRegisters, state.Registers) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) } -func FuzzStateSyscallMmap(f *testing.F) { - contracts := testContracts(f) +func StateSyscallMmap(t *testing.T, addr uint64, length uint64, heap uint64, flag uint64, fd uint64, pc uint64, step uint64, reservation uint64, exitCode uint8) { + contracts := testContracts(t) addrs := testAddrs - f.Fuzz(func(t *testing.T, isZeroAddr bool, addr uint64, length uint64, heap uint64, pc uint64, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - if isZeroAddr { - addr = 0 - } - state := &fast.VMState{ - PC: pc, - Heap: heap, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{ - 17: riscv.SysMmap, - 10: addr, - 11: length, - 13: 32, // MAP_ANONYMOUS flag - 14: 0xFFFF_FFFF_FFFF_FFFF, // fd == -1 (u64 mask) - }, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[11] = 0 - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: heap, + ExitCode: exitCode, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: reservation, + Registers: [32]uint64{ + 17: riscv.SysMmap, + 10: addr, + 11: length, + 13: flag, // MAP_ANONYMOUS flag + 14: fd, + }, + Step: step, + } + state.Memory.SetUnaligned(pc, syscallInsn) + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + + // true if flag&0x20 == 0 or fd != mask + shouldSkipZero := false + + u64Mask := uint64(0xFFFF_FFFF_FFFF_FFFF) + if (flag&0x20 == 0) || fd != u64Mask { + expectedRegisters[10] = u64Mask + expectedRegisters[11] = 0x4d + shouldSkipZero = true + } else { + expectedRegisters[10] = addr // although this should be unchanged from before + expectedRegisters[11] = 0 // error code is set to zero + } - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set - require.Equal(t, false, state.Exited) // Must not be exited - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - - newHeap := heap - if addr == 0 { - expectedRegisters[10] = heap - align := length & fast.PageAddrMask - if align != 0 { - length = length + fast.PageSize - align - } - newHeap = heap + length + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, reservation, state.LoadReservation) + require.Equal(t, exitCode, state.ExitCode) // ExitCode must be set + require.Equal(t, false, state.Exited) // Must not be exited + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + + newHeap := heap + + // these checks should be skipped if conditions on L#560 are met + if !shouldSkipZero && addr == 0 { + expectedRegisters[10] = heap + align := length & fast.PageAddrMask + if align != 0 { + length = length + fast.PageSize - align } - require.Equal(t, expectedRegisters, state.Registers) - require.Equal(t, newHeap, state.Heap) + newHeap = heap + length + } + require.Equal(t, expectedRegisters, state.Registers) + require.Equal(t, newHeap, state.Heap) - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) - }) + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) } -func FuzzStateSyscallFcntl(f *testing.F) { - contracts := testContracts(f) +func StateSyscallFcntl(t *testing.T, fd, cmd, pc, heap, reservation, step, out, errCode uint64) { + contracts := testContracts(t) addrs := testAddrs - testFcntl := func(t *testing.T, fd, cmd, pc, step, out, errCode uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysFcntl, 10: fd, 11: cmd}, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[10] = out - expectedRegisters[11] = errCode - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: heap, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: riscv.SysFcntl, 10: fd, 11: cmd}, + Step: step, + } + state.Memory.SetUnaligned(pc, syscallInsn) + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + expectedRegisters[10] = out + expectedRegisters[11] = errCode + + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, heap, state.Heap) + require.Equal(t, uint64(0), state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) + require.Equal(t, false, state.Exited) + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, expectedRegisters, state.Registers) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) +} - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set - require.Equal(t, false, state.Exited) // Must not be exited - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, expectedRegisters, state.Registers) +func StateSyscallOpenat(t *testing.T, pc, step, heap, reservation uint64) { + contracts := testContracts(t) + addrs := testAddrs - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: heap, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: reservation, + Registers: [32]uint64{17: riscv.SysOpenat}, + Step: step, } + state.Memory.SetUnaligned(pc, syscallInsn) + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + expectedRegisters[10] = 0xFFFF_FFFF_FFFF_FFFF + expectedRegisters[11] = 0xd + + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) - f.Fuzz(func(t *testing.T, fd uint64, cmd uint64, pc uint64, step uint64) { - // Test F_GETFL for O_RDONLY fds - for _, fd := range []uint64{0, 3, 5} { - testFcntl(t, fd, 3, pc, step, 0, 0) - } - // Test F_GETFL for O_WRONLY fds - for _, fd := range []uint64{1, 2, 4, 6} { - testFcntl(t, fd, 3, pc, step, 1, 0) - } - // Test F_GETFL for unsupported fds - // Add 7 to fd to ensure fd > 6 - testFcntl(t, fd+7, 3, pc, step, 0xFFFF_FFFF_FFFF_FFFF, 0x4d) - - // Test F_GETFD - for _, fd := range []uint64{0, 1, 2, 3, 4, 5, 6} { - testFcntl(t, fd, 1, pc, step, 0, 0) - } + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, heap, state.Heap) + require.Equal(t, reservation, state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set + require.Equal(t, false, state.Exited) // Must not be exited + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, expectedRegisters, state.Registers) - // Test F_GETFD for unsupported fds - // Add 7 to fd to ensure fd > 6 - testFcntl(t, fd+7, 1, pc, step, 0xFFFF_FFFF_FFFF_FFFF, 0x4d) + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) - // Test other commands - if cmd == 3 || cmd == 1 { - // Set arbitrary commands if cmd is F_GETFL - cmd = 4 - } - testFcntl(t, fd, cmd, pc, step, 0xFFFF_FFFF_FFFF_FFFF, 0x16) - }) } -func FuzzStateSyscallOpenat(f *testing.F) { - contracts := testContracts(f) +func StateSyscallClockGettime(t *testing.T, addr, pc, step, heap, reservation uint64) { + contracts := testContracts(t) addrs := testAddrs - f.Fuzz(func(t *testing.T, pc, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysOpenat}, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[10] = 0xFFFF_FFFF_FFFF_FFFF - expectedRegisters[11] = 0xd - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) - - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set - require.Equal(t, false, state.Exited) // Must not be exited - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, expectedRegisters, state.Registers) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: heap, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: reservation, + Registers: [32]uint64{17: riscv.SysClockGettime, 11: addr}, + Step: step, + } + state.Memory.SetUnaligned(pc, syscallInsn) + expectedRegisters := state.Registers + expectedRegisters[10] = 0 + expectedRegisters[11] = 0 - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) - }) + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + postMemory := fast.NewMemory() + postMemory.SetUnaligned(pc, syscallInsn) + var bytes [8]byte + binary.LittleEndian.PutUint64(bytes[:], 1337) + + postMemory.SetUnaligned(addr, bytes[:]) + postMemory.SetUnaligned(addr+8, []byte{42, 0, 0, 0, 0, 0, 0, 0}) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, heap, state.Heap) + require.Equal(t, reservation, state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set + require.Equal(t, false, state.Exited) // Must not be exited + require.Equal(t, state.Memory.MerkleRoot(), postMemory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, expectedRegisters, state.Registers) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) } -func FuzzStateSyscallClockGettime(f *testing.F) { - contracts := testContracts(f) +func StateSyscallClone(t *testing.T, pc, step, heap, reservation uint64) { + contracts := testContracts(t) addrs := testAddrs - f.Fuzz(func(t *testing.T, addr, pc, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysClockGettime, 11: addr}, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - expectedRegisters := state.Registers - expectedRegisters[11] = 0 - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) - - postMemory := fast.NewMemory() - postMemory.SetUnaligned(pc, syscallInsn) - var bytes [8]byte - binary.LittleEndian.PutUint64(bytes[:], 1337) - postMemory.SetUnaligned(addr, bytes[:]) - postMemory.SetUnaligned(addr+8, []byte{42, 0, 0, 0, 0, 0, 0, 0}) - - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set - require.Equal(t, false, state.Exited) // Must not be exited - require.Equal(t, state.Memory.MerkleRoot(), postMemory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, expectedRegisters, state.Registers) - - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) - }) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: heap, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: reservation, + Registers: [32]uint64{17: riscv.SysClone}, + Step: step, + } + state.Memory.SetUnaligned(pc, syscallInsn) + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + expectedRegisters[10] = 1 + expectedRegisters[11] = 0 + + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, heap, state.Heap) + require.Equal(t, reservation, state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set + require.Equal(t, false, state.Exited) // Must not be exited + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, expectedRegisters, state.Registers) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) } -func FuzzStateSyscallClone(f *testing.F) { - contracts := testContracts(f) +func StateSyscallGetrlimit(t *testing.T, addr, pc, step uint64) { + contracts := testContracts(t) addrs := testAddrs - f.Fuzz(func(t *testing.T, pc, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysClone}, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[10] = 1 - expectedRegisters[11] = 0 - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) - - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set - require.Equal(t, false, state.Exited) // Must not be exited - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, expectedRegisters, state.Registers) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: 0, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: riscv.SysGetrlimit, 10: 7, 11: addr}, + Step: step, + } + state.Memory.SetUnaligned(pc, syscallInsn) + expectedRegisters := state.Registers + expectedRegisters[10] = 0 + expectedRegisters[11] = 0 - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) - }) + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + postMemory := fast.NewMemory() + postMemory.SetUnaligned(pc, syscallInsn) + var bytes [8]byte + binary.LittleEndian.PutUint64(bytes[:], 1024) + postMemory.SetUnaligned(addr, bytes[:]) + postMemory.SetUnaligned(addr+8, bytes[:]) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, uint64(0), state.Heap) + require.Equal(t, uint64(0), state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set + require.Equal(t, false, state.Exited) // Must not be exited + require.Equal(t, state.Memory.MerkleRoot(), postMemory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, expectedRegisters, state.Registers) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) } -func FuzzStateSyscallGetrlimit(f *testing.F) { - contracts := testContracts(f) +func StatesyscallgetrlimitError(t *testing.T, res, addr, pc, step uint64) { + contracts := testContracts(t) addrs := testAddrs - testGetrlimit := func(t *testing.T, addr, pc, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysGetrlimit, 10: 7, 11: addr}, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - expectedRegisters := state.Registers - expectedRegisters[10] = 0 - expectedRegisters[11] = 0 - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) - - postMemory := fast.NewMemory() - postMemory.SetUnaligned(pc, syscallInsn) - var bytes [8]byte - binary.LittleEndian.PutUint64(bytes[:], 1024) - postMemory.SetUnaligned(addr, bytes[:]) - postMemory.SetUnaligned(addr+8, bytes[:]) - - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set - require.Equal(t, false, state.Exited) // Must not be exited - require.Equal(t, state.Memory.MerkleRoot(), postMemory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, expectedRegisters, state.Registers) - - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + addr = addr &^ 31 + state := &fast.VMState{ + PC: pc, + Heap: 0, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: riscv.SysGetrlimit, 10: res, 11: addr}, + Step: 0, } + state.Memory.SetUnaligned(pc, syscallInsn) - testGetrlimitErr := func(t *testing.T, res, addr, pc, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - addr = addr &^ 31 - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysGetrlimit, 10: res, 11: addr}, - Step: 0, - } - state.Memory.SetUnaligned(pc, syscallInsn) - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - var fastSyscallErr *fast.UnrecognizedResourceErr - require.ErrorAs(t, err, &fastSyscallErr) + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + var fastSyscallErr *fast.UnrecognizedResourceErr + require.ErrorAs(t, err, &fastSyscallErr) - runEVM(t, contracts, addrs, stepWitness, nil, errCodeToByte32(riscv.ErrUnrecognizedResource)) + runEVM(t, contracts, addrs, stepWitness, nil, errCodeToByte32(riscv.ErrUnrecognizedResource)) - var slowSyscallErr *slow.UnrecognizedResourceErr - runSlow(t, stepWitness, nil, nil, &slowSyscallErr) - } - - f.Fuzz(func(t *testing.T, res, addr, pc, step uint64) { - // Test RLIMIT_NOFILE - testGetrlimit(t, addr, pc, step) - - // Test other resources - if res == 7 { - // Set arbitrary resource if res is RLIMIT_NOFILE - res = 8 - } - testGetrlimitErr(t, res, addr, pc, step) - }) + var slowSyscallErr *slow.UnrecognizedResourceErr + runSlow(t, stepWitness, nil, nil, &slowSyscallErr) } -func FuzzStateSyscallNoop(f *testing.F) { - contracts := testContracts(f) +func StateSyscallNoop(t *testing.T, syscall uint64, arg uint64, pc uint64, step uint64) { + contracts := testContracts(t) addrs := testAddrs - syscalls := []int{ - riscv.SysSchedGetaffinity, - riscv.SysSchedYield, - riscv.SysRtSigprocmask, - riscv.SysSigaltstack, - riscv.SysGettid, - riscv.SysRtSigaction, - riscv.SysMadvise, - riscv.SysEpollCreate1, - riscv.SysEpollCtl, - riscv.SysPipe2, - riscv.SysReadlinnkat, - riscv.SysNewfstatat, - riscv.SysNewuname, - riscv.SysMunmap, - riscv.SysGetRandom, + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: 0, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: syscall, 10: arg}, + Step: step, } + state.Memory.SetUnaligned(pc, syscallInsn) + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + expectedRegisters[10] = 0 + expectedRegisters[11] = 0 + + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) - testNoop := func(t *testing.T, syscall int, arg uint64, pc uint64, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: uint64(syscall), 10: arg}, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[10] = 0 - expectedRegisters[11] = 0 - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) - - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) - require.Equal(t, false, state.Exited) - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, expectedRegisters, state.Registers) + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, uint64(0), state.Heap) + require.Equal(t, uint64(0), state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) + require.Equal(t, false, state.Exited) + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, expectedRegisters, state.Registers) - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) - } + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) - f.Fuzz(func(t *testing.T, arg uint64, pc uint64, step uint64) { - for _, syscall := range syscalls { - testNoop(t, syscall, arg, pc, step) - } - }) } -func FuzzStateSyscallRead(f *testing.F) { - contracts := testContracts(f) +func StateSyscallRead(t *testing.T, fd, addr, count, pc, step, ret, errCode uint64) { + contracts := testContracts(t) addrs := testAddrs - testRead := func(t *testing.T, fd, addr, count, pc, step, ret, errCode uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysRead, 10: fd, 11: addr, 12: count}, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[10] = ret - expectedRegisters[11] = errCode - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: 0, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: riscv.SysRead, 10: fd, 11: addr, 12: count}, + Step: step, + } + state.Memory.SetUnaligned(pc, syscallInsn) + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + expectedRegisters[10] = ret + expectedRegisters[11] = errCode + + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, uint64(0), state.Heap) + require.Equal(t, uint64(0), state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set + require.Equal(t, false, state.Exited) // Must not be exited + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, expectedRegisters, state.Registers) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) +} - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set - require.Equal(t, false, state.Exited) // Must not be exited - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, expectedRegisters, state.Registers) +func StateHintRead(t *testing.T, addr uint64, count uint64, preimageOffset uint64, pc uint64, step uint64, preimageData []byte) { + contracts := testContracts(t) + addrs := testAddrs - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + if preimageOffset >= uint64(len(preimageData)) { + t.SkipNow() } + state := &fast.VMState{ + PC: pc, + Heap: 0, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: riscv.SysRead, 10: riscv.FdHintRead, 11: addr, 12: count}, + Step: step, + PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(), + PreimageOffset: preimageOffset, + } + state.Memory.SetUnaligned(pc, syscallInsn) + preStatePreimageKey := state.PreimageKey + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + expectedRegisters[10] = count + expectedRegisters[11] = 0 - f.Fuzz(func(t *testing.T, fd, addr, count, pc, step uint64) { - // Test stdin - testRead(t, riscv.FdStdin, addr, count, pc, step, 0, 0) + oracle := staticOracle(t, preimageData) - // Test EBADF err - if fd == riscv.FdStdin || fd == riscv.FdHintRead || fd == riscv.FdPreimageRead { - // Ensure unsupported fd - fd += 1 - } - testRead(t, fd, addr, count, pc, step, 0xFFFF_FFFF_FFFF_FFFF, 0x4d) - }) + fastState := fast.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, uint64(0), state.Heap) + require.Equal(t, uint64(0), state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) + require.Equal(t, false, state.Exited) + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, preStatePreimageKey, state.PreimageKey) + require.Equal(t, expectedRegisters, state.Registers) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, oracle, nil) } -func FuzzStateHintRead(f *testing.F) { - contracts := testContracts(f) +func StatePreimageRead(t *testing.T, addr uint64, count uint64, preimageOffset uint64, preimageData []byte, pc uint64, step uint64) { + contracts := testContracts(t) addrs := testAddrs - f.Fuzz(func(t *testing.T, addr uint64, count uint64, preimageOffset uint64, pc uint64, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - preimageData := []byte("hello world") - if preimageOffset >= uint64(len(preimageData)) { - t.SkipNow() - } - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysRead, 10: riscv.FdHintRead, 11: addr, 12: count}, - Step: step, - PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(), - PreimageOffset: preimageOffset, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStatePreimageKey := state.PreimageKey - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[10] = count - expectedRegisters[11] = 0 - - oracle := staticOracle(t, preimageData) - - fastState := fast.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + if preimageOffset >= uint64(len(preimageData)) { + t.SkipNow() + } + state := &fast.VMState{ + PC: pc, + Heap: 0, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: riscv.SysRead, 10: riscv.FdPreimageRead, 11: addr, 12: count}, + Step: step, + PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(), + PreimageOffset: preimageOffset, + } + state.Memory.SetUnaligned(pc, syscallInsn) + preStatePreimageKey := state.PreimageKey + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + writeLen := count + maxData := 32 - addr&31 + if writeLen > maxData { + writeLen = maxData + } + leftPreimageLen := uint64(8+len(preimageData)) - preimageOffset + if writeLen > leftPreimageLen { + writeLen = leftPreimageLen + } + expectedRegisters[10] = writeLen + expectedRegisters[11] = 0 - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) - require.Equal(t, false, state.Exited) + oracle := staticOracle(t, preimageData) + fastState := fast.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.True(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, uint64(0), state.Heap) + require.Equal(t, uint64(0), state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) + require.Equal(t, false, state.Exited) + if writeLen > 0 { + // TODO: add more nuanced check here such that if first 7 bytes are zeroed, only check NotEqual + // Memory may be unchanged if we're writing the first zero-valued 7 bytes of the pre-image. + //require.NotEqual(t, preStateRoot, state.Memory.MerkleRoot()) + require.Greater(t, state.PreimageOffset, preimageOffset) + } else { require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, preStatePreimageKey, state.PreimageKey) - require.Equal(t, expectedRegisters, state.Registers) + require.Equal(t, state.PreimageOffset, preimageOffset) + } + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, preStatePreimageKey, state.PreimageKey) + require.Equal(t, expectedRegisters, state.Registers) - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, oracle, nil) - }) + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, oracle, nil) } -func FuzzStatePreimageRead(f *testing.F) { - contracts := testContracts(f) +func StateSyscallWrite(t *testing.T, fd, addr, count, pc, step, ret, errCode uint64) { + contracts := testContracts(t) addrs := testAddrs - f.Fuzz(func(t *testing.T, addr uint64, count uint64, preimageOffset uint64, pc uint64, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - preimageData := []byte("hello world") - if preimageOffset >= uint64(len(preimageData)) { - t.SkipNow() - } - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysRead, 10: riscv.FdPreimageRead, 11: addr, 12: count}, - Step: step, - PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(), - PreimageOffset: preimageOffset, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStatePreimageKey := state.PreimageKey - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - writeLen := count - maxData := 32 - addr&31 - if writeLen > maxData { - writeLen = maxData - } - leftPreimageLen := uint64(8+len(preimageData)) - preimageOffset - if writeLen > leftPreimageLen { - writeLen = leftPreimageLen - } - expectedRegisters[10] = writeLen - expectedRegisters[11] = 0 + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + state := &fast.VMState{ + PC: pc, + Heap: 0, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: riscv.SysWrite, 10: fd, 11: addr, 12: count}, + Step: step, + } + state.Memory.SetUnaligned(pc, syscallInsn) + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + expectedRegisters[10] = ret + expectedRegisters[11] = errCode + + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) - oracle := staticOracle(t, preimageData) - fastState := fast.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.True(t, stepWitness.HasPreimage()) - - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) - require.Equal(t, false, state.Exited) - if writeLen > 0 { - // Memory may be unchanged if we're writing the first zero-valued 7 bytes of the pre-image. - //require.NotEqual(t, preStateRoot, state.Memory.MerkleRoot()) - require.Greater(t, state.PreimageOffset, preimageOffset) - } else { - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, state.PreimageOffset, preimageOffset) - } - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, preStatePreimageKey, state.PreimageKey) - require.Equal(t, expectedRegisters, state.Registers) + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, uint64(0), state.Heap) + require.Equal(t, uint64(0), state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set + require.Equal(t, false, state.Exited) // Must not be exited + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, expectedRegisters, state.Registers) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, nil, nil) - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, oracle, nil) - }) } -func FuzzStateSyscallWrite(f *testing.F) { - contracts := testContracts(f) +func StateHintWrite(t *testing.T, addr uint64, count uint64, preimageOffset uint64, preimageData []byte, pc uint64, step uint64, randSeed int64) { + contracts := testContracts(t) addrs := testAddrs - testWrite := func(t *testing.T, fd, addr, count, pc, step, ret, errCode uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysWrite, 10: fd, 11: addr, 12: count}, - Step: step, - } - state.Memory.SetUnaligned(pc, syscallInsn) - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[10] = ret - expectedRegisters[11] = errCode - - fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) - - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) // ExitCode must be set - require.Equal(t, false, state.Exited) // Must not be exited - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, expectedRegisters, state.Registers) - - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, nil, nil) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + if preimageOffset >= uint64(len(preimageData)) { + t.SkipNow() } + state := &fast.VMState{ + PC: pc, + Heap: 0, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: riscv.SysWrite, 10: riscv.FdHintWrite, 12: count}, + Step: step, + PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(), + PreimageOffset: preimageOffset, + + LastHint: nil, + } + // Set random data at the target memory range + randBytes, err := randomBytes(randSeed, count) + require.NoError(t, err) + err = state.Memory.SetMemoryRange(addr, bytes.NewReader(randBytes)) + require.NoError(t, err) - f.Fuzz(func(t *testing.T, fd, addr, count, pc, step uint64) { - // Test stdout - testWrite(t, riscv.FdStdout, addr, count, pc, step, count, 0) + // Set syscall instruction + state.Memory.SetUnaligned(pc, syscallInsn) + preStatePreimageKey := state.PreimageKey + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers + expectedRegisters[10] = count + expectedRegisters[11] = 0 - // Test stderr - testWrite(t, riscv.FdStderr, addr, count, pc, step, count, 0) + oracle := staticOracle(t, preimageData) - // Test EBADF err - if fd == riscv.FdStdout || fd == riscv.FdStderr || fd == riscv.FdHintWrite || fd == riscv.FdPreimageWrite { - // Ensure unsupported fd - fd += 6 - } - testWrite(t, fd, addr, count, pc, step, 0xFFFF_FFFF_FFFF_FFFF, 0x4d) - }) + fastState := fast.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, uint64(0), state.Heap) + require.Equal(t, uint64(0), state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) + require.Equal(t, false, state.Exited) + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, preStatePreimageKey, state.PreimageKey) + require.Equal(t, expectedRegisters, state.Registers) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, oracle, nil) } -func FuzzStateHintWrite(f *testing.F) { - contracts := testContracts(f) +func StatePreimageWrite(t *testing.T, addr uint64, heap uint64, preimageOffset uint64, preimageData []byte, pc uint64, step uint64) { + contracts := testContracts(t) addrs := testAddrs - f.Fuzz(func(t *testing.T, addr uint64, count uint64, preimageOffset uint64, pc uint64, step uint64, randSeed int64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - preimageData := []byte("hello world") - if preimageOffset >= uint64(len(preimageData)) { - t.SkipNow() - } - state := &fast.VMState{ - PC: pc, - Heap: 0, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysWrite, 10: riscv.FdHintWrite, 11: addr, 12: count}, - Step: step, - PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(), - PreimageOffset: preimageOffset, - - LastHint: nil, - } - // Set random data at the target memory range - randBytes, err := randomBytes(randSeed, count) - require.NoError(t, err) - err = state.Memory.SetMemoryRange(addr, bytes.NewReader(randBytes)) - require.NoError(t, err) + pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC + if preimageOffset >= uint64(len(preimageData)) { + t.SkipNow() + } + if addr < heap { + // to avoid override code space + addr = heap + addr%(0xff_ff_ff_ff_ff_ff_ff_ff-heap) + } - // Set syscall instruction - state.Memory.SetUnaligned(pc, syscallInsn) - preStatePreimageKey := state.PreimageKey - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers - expectedRegisters[10] = count - expectedRegisters[11] = 0 + count := uint64(32) // preimage key is 32 bytes + state := &fast.VMState{ + PC: pc, + Heap: heap, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: 0, + Registers: [32]uint64{17: riscv.SysWrite, 10: riscv.FdPreimageWrite, 11: addr, 12: count}, + Step: step, + PreimageOffset: preimageOffset, + } + state.Memory.SetUnaligned(pc, syscallInsn) - oracle := staticOracle(t, preimageData) + // Set preimage key to addr + preimageKey := preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey() + state.Memory.SetUnaligned(addr, preimageKey[:]) + preStateRoot := state.Memory.MerkleRoot() + expectedRegisters := state.Registers - fastState := fast.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) + maxData := 32 - (addr & 31) + if maxData < count { + count = maxData + } + expectedRegisters[10] = count + expectedRegisters[11] = 0 - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, uint64(0), state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) - require.Equal(t, false, state.Exited) - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, preStatePreimageKey, state.PreimageKey) - require.Equal(t, expectedRegisters, state.Registers) + var expectedKey common.Hash + // slice preimage key by count + for i := uint64(0); i < count; i++ { + expectedKey[i+32-count] = preimageKey[i] + } - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, oracle, nil) - }) + oracle := staticOracle(t, preimageData) + + fastState := fast.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + require.NoError(t, err) + require.False(t, stepWitness.HasPreimage()) + + require.Equal(t, pc+4, state.PC) // PC must advance + require.Equal(t, heap, state.Heap) + require.Equal(t, uint64(0), state.LoadReservation) + require.Equal(t, uint8(0), state.ExitCode) + require.Equal(t, false, state.Exited) + require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) + require.Equal(t, step+1, state.Step) // Step must advance + require.Equal(t, uint64(0), state.PreimageOffset) + require.Equal(t, expectedRegisters, state.Registers) + require.Equal(t, expectedKey, state.PreimageKey) + + fastPost := state.EncodeWitness() + runEVM(t, contracts, addrs, stepWitness, fastPost, nil) + runSlow(t, stepWitness, fastPost, oracle, nil) } -func FuzzStatePreimageWrite(f *testing.F) { - contracts := testContracts(f) +func StateSyscallUnsupported(t *testing.T, syscall int, heap uint64, reservation uint64) { + contracts := testContracts(t) addrs := testAddrs - f.Fuzz(func(t *testing.T, addr uint64, preimageOffset uint64, pc uint64, step uint64) { - pc = pc & 0xFF_FF_FF_FF_FF_FF_FF_FC // align PC - preimageData := []byte("hello world") - if preimageOffset >= uint64(len(preimageData)) { - t.SkipNow() - } - heap := uint64(0x7f_00_00_00_00_00) - if addr < heap { - // to avoid override code space - addr = heap + addr%(0xff_ff_ff_ff_ff_ff_ff_ff-heap) - } - count := uint64(32) // preimage key is 32 bytes - state := &fast.VMState{ - PC: pc, - Heap: heap, - ExitCode: 0, - Exited: false, - Memory: fast.NewMemory(), - LoadReservation: 0, - Registers: [32]uint64{17: riscv.SysWrite, 10: riscv.FdPreimageWrite, 11: addr, 12: count}, - Step: step, - PreimageOffset: preimageOffset, - } - state.Memory.SetUnaligned(pc, syscallInsn) - - // Set preimage key to addr - preimageKey := preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey() - state.Memory.SetUnaligned(addr, preimageKey[:]) - preStateRoot := state.Memory.MerkleRoot() - expectedRegisters := state.Registers + pc := uint64(0) + state := &fast.VMState{ + PC: pc, + Heap: heap, + ExitCode: 0, + Exited: false, + Memory: fast.NewMemory(), + LoadReservation: reservation, + Registers: [32]uint64{17: uint64(syscall)}, + Step: 0, + } + state.Memory.SetUnaligned(pc, syscallInsn) - maxData := 32 - (addr & 31) - if maxData < count { - count = maxData - } - expectedRegisters[10] = count - expectedRegisters[11] = 0 + fastState := fast.NewInstrumentedState(state, nil, os.Stdout, os.Stderr) + stepWitness, err := fastState.Step(true) + var fastSyscallErr *fast.UnsupportedSyscallErr + require.ErrorAs(t, err, &fastSyscallErr) - var expectedKey common.Hash - // slice preimage key by count - for i := uint64(0); i < count; i++ { - expectedKey[i+32-count] = preimageKey[i] - } + runEVM(t, contracts, addrs, stepWitness, nil, errCodeToByte32(riscv.ErrInvalidSyscall)) - oracle := staticOracle(t, preimageData) + var slowSyscallErr *slow.UnsupportedSyscallErr + runSlow(t, stepWitness, nil, nil, &slowSyscallErr) - fastState := fast.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr) - stepWitness, err := fastState.Step(true) - require.NoError(t, err) - require.False(t, stepWitness.HasPreimage()) - - require.Equal(t, pc+4, state.PC) // PC must advance - require.Equal(t, heap, state.Heap) - require.Equal(t, uint64(0), state.LoadReservation) - require.Equal(t, uint8(0), state.ExitCode) - require.Equal(t, false, state.Exited) - require.Equal(t, preStateRoot, state.Memory.MerkleRoot()) - require.Equal(t, step+1, state.Step) // Step must advance - require.Equal(t, uint64(0), state.PreimageOffset) - require.Equal(t, expectedRegisters, state.Registers) - require.Equal(t, expectedKey, state.PreimageKey) - - fastPost := state.EncodeWitness() - runEVM(t, contracts, addrs, stepWitness, fastPost, nil) - runSlow(t, stepWitness, fastPost, oracle, nil) - }) } func randomBytes(seed int64, length uint64) ([]byte, error) { @@ -1154,3 +1244,7 @@ func randomBytes(seed int64, length uint64) ([]byte, error) { } return randBytes, nil } +func randomUint64FromUint(seed uint64) uint64 { + r := rand.New(rand.NewSource(int64(seed))) + return r.Uint64() +} diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/01ac7490901fc0a6 b/rvgo/test/testdata/fuzz/FuzzEverything/01ac7490901fc0a6 new file mode 100644 index 00000000..d9bf7cd3 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/01ac7490901fc0a6 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(238) +uint64(212) +uint64(85) +uint64(11) +uint64(2) +uint64(7) +byte('d') +uint64(36) +uint64(44) +int64(-263) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/01ff2c851e14560b b/rvgo/test/testdata/fuzz/FuzzEverything/01ff2c851e14560b new file mode 100644 index 00000000..c79ffc2b --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/01ff2c851e14560b @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(87) +uint64(127) +uint64(50) +uint64(6) +uint64(65) +uint64(52) +byte('\x12') +uint64(100) +uint64(24) +int64(-53) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/0d6e6dd76735fef5 b/rvgo/test/testdata/fuzz/FuzzEverything/0d6e6dd76735fef5 new file mode 100644 index 00000000..f55f69b1 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/0d6e6dd76735fef5 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(4) +uint64(63) +uint64(28) +uint64(5) +uint64(31) +uint64(12) +byte('\x12') +uint64(186) +uint64(18) +int64(-22) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/13a390c8da5566a1 b/rvgo/test/testdata/fuzz/FuzzEverything/13a390c8da5566a1 new file mode 100644 index 00000000..7d73faac --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/13a390c8da5566a1 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(56) +uint64(23) +uint64(44) +uint64(6) +uint64(0) +uint64(0) +byte('\x12') +uint64(0) +uint64(49) +int64(-111) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/256e2320af3c55cf b/rvgo/test/testdata/fuzz/FuzzEverything/256e2320af3c55cf new file mode 100644 index 00000000..61c1a506 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/256e2320af3c55cf @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(222) +uint64(62) +uint64(44) +uint64(80) +uint64(31) +uint64(67) +byte('\x18') +uint64(106) +uint64(101) +int64(-65) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/2a5350c37e582f14 b/rvgo/test/testdata/fuzz/FuzzEverything/2a5350c37e582f14 new file mode 100644 index 00000000..cd6b50ca --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/2a5350c37e582f14 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(107) +uint64(62) +uint64(44) +uint64(6) +uint64(31) +uint64(67) +byte('f') +uint64(97) +uint64(49) +int64(-65) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/2c07920ecf27ace9 b/rvgo/test/testdata/fuzz/FuzzEverything/2c07920ecf27ace9 new file mode 100644 index 00000000..c4659c86 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/2c07920ecf27ace9 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(87) +uint64(47) +uint64(0) +uint64(98) +uint64(131) +uint64(0) +byte('\u0084') +uint64(0) +uint64(0) +int64(0) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/3897694e2f758309 b/rvgo/test/testdata/fuzz/FuzzEverything/3897694e2f758309 new file mode 100644 index 00000000..c3afcf53 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/3897694e2f758309 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(51) +uint64(150) +uint64(0) +uint64(79) +uint64(16) +uint64(0) +byte('4') +uint64(114) +uint64(0) +int64(79) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/530cc03fe97614f3 b/rvgo/test/testdata/fuzz/FuzzEverything/530cc03fe97614f3 new file mode 100644 index 00000000..eb96d1b0 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/530cc03fe97614f3 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(75) +uint64(63) +uint64(28) +uint64(5) +uint64(31) +uint64(0) +byte('\x12') +uint64(84) +uint64(18) +int64(-81) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/5420d03a2c18ad34 b/rvgo/test/testdata/fuzz/FuzzEverything/5420d03a2c18ad34 new file mode 100644 index 00000000..98d90541 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/5420d03a2c18ad34 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(23) +uint64(0) +uint64(0) +uint64(0) +uint64(83) +uint64(0) +byte('2') +uint64(0) +uint64(0) +int64(-78) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/563f120374bb6ada b/rvgo/test/testdata/fuzz/FuzzEverything/563f120374bb6ada new file mode 100644 index 00000000..dc4963d1 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/563f120374bb6ada @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(28) +uint64(18) +uint64(2) +uint64(0) +uint64(83) +uint64(47) +byte('d') +uint64(0) +uint64(0) +int64(-77) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/5c3b82c9521bcefc b/rvgo/test/testdata/fuzz/FuzzEverything/5c3b82c9521bcefc new file mode 100644 index 00000000..20bef55a --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/5c3b82c9521bcefc @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(101) +uint64(18) +uint64(2) +uint64(0) +uint64(83) +uint64(47) +byte('d') +uint64(0) +uint64(0) +int64(-77) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/604d2779fb53eb15 b/rvgo/test/testdata/fuzz/FuzzEverything/604d2779fb53eb15 new file mode 100644 index 00000000..52af6646 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/604d2779fb53eb15 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(29) +uint64(0) +uint64(44) +uint64(6) +uint64(1) +uint64(0) +byte('\x12') +uint64(0) +uint64(49) +int64(-105) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/699711399dd645b6 b/rvgo/test/testdata/fuzz/FuzzEverything/699711399dd645b6 new file mode 100644 index 00000000..fc4e9988 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/699711399dd645b6 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(13) +uint64(23) +uint64(100) +uint64(149) +uint64(1) +uint64(0) +byte('\x12') +uint64(0) +uint64(14) +int64(35) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/6e88f10a75e50db8 b/rvgo/test/testdata/fuzz/FuzzEverything/6e88f10a75e50db8 new file mode 100644 index 00000000..abb6f958 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/6e88f10a75e50db8 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(75) +uint64(134) +uint64(63) +uint64(39) +uint64(1) +uint64(84) +byte('\x01') +uint64(95) +uint64(49) +int64(-130) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/95601569bcd72077 b/rvgo/test/testdata/fuzz/FuzzEverything/95601569bcd72077 new file mode 100644 index 00000000..d100288f --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/95601569bcd72077 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(75) +uint64(62) +uint64(44) +uint64(6) +uint64(1) +uint64(0) +byte('\x12') +uint64(0) +uint64(49) +int64(-111) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/bf9a34188da1317f b/rvgo/test/testdata/fuzz/FuzzEverything/bf9a34188da1317f new file mode 100644 index 00000000..7c237542 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/bf9a34188da1317f @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(144) +uint64(72) +uint64(2) +uint64(0) +uint64(83) +uint64(47) +byte('d') +uint64(0) +uint64(0) +int64(-77) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/c65c08cb37d4bdfe b/rvgo/test/testdata/fuzz/FuzzEverything/c65c08cb37d4bdfe new file mode 100644 index 00000000..73e725d5 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/c65c08cb37d4bdfe @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(92) +uint64(7) +uint64(2) +uint64(7) +uint64(416) +uint64(0) +byte('\u0088') +uint64(13) +uint64(20) +int64(-121) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/d0412d3b625fdd24 b/rvgo/test/testdata/fuzz/FuzzEverything/d0412d3b625fdd24 new file mode 100644 index 00000000..eedb4888 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/d0412d3b625fdd24 @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(6) +uint64(7) +uint64(0) +uint64(53) +uint64(62) +uint64(54) +byte('\x00') +uint64(152) +uint64(81) +int64(-29) diff --git a/rvgo/test/testdata/fuzz/FuzzEverything/f845b152d0f13adf b/rvgo/test/testdata/fuzz/FuzzEverything/f845b152d0f13adf new file mode 100644 index 00000000..95440bc8 --- /dev/null +++ b/rvgo/test/testdata/fuzz/FuzzEverything/f845b152d0f13adf @@ -0,0 +1,11 @@ +go test fuzz v1 +uint64(75) +uint64(106) +uint64(41) +uint64(31) +uint64(1) +uint64(0) +byte('>') +uint64(16) +uint64(49) +int64(-157)