Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go fuzz differential parsing test #124

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ jobs:
working-directory: tests/go-tests
- name: Run tests
run: go test -v ./rvgo/... -coverprofile=coverage.out -coverpkg=./rvgo/...
- name: Fuzz
- name: Fuzz syscall
run: make fuzz
- name: Fuzz parsing
run: make fuzz-parsing
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
Expand Down
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ fuzz-mac:
fuzz \
fuzz-mac

quick = '10s'
hour = '1h'
daily = '24h'
weekend = '2 days'
fuzztime = $(quick)
fuzz-parsing: build
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeI ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeS ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeB ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeU ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeJ ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseOpcode ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseRd ./rvgo/test
.PHONY: fuzz-parsing

OP_PROGRAM_PATH ?= $(MONOREPO_ROOT)/op-program/bin-riscv/op-program-client-riscv.elf

prestate: build-rvgo op-program-riscv
Expand Down
22 changes: 22 additions & 0 deletions rvgo/diff/DifferentialParsingFuzzTests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Running

```bash
make fuzz-parsing
```

or

```bash
fuzz-parsing: build
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeI ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeS ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeB ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeU ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseTypeJ ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseOpcode ./rvgo/test
go test -run NOTAREALTEST -v -fuzztime $(fuzztime) -fuzz=FuzzParseRd ./rvgo/test
```

## How it works

This test is relatively simple in comparison to others – it implements each Parse function, and calls slow and fast to ensure that the output from both are identical. This pattern is meant to show the recommended way to test these functions when they are publicly accessible, such that you can compare to ensure that fast and slow behave exactly as expected. The EVM implementation of these differential fuzzing tests do not use go fuzz, and use foundry ffi to call out to a `slow` executable instead.
44 changes: 44 additions & 0 deletions rvgo/fast/fast-parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package fast

func ParseImmTypeI(instr U64) U64 {
return parseImmTypeI(instr)
}

func ParseImmTypeS(instr U64) U64 {
return parseImmTypeS(instr)
}

func ParseImmTypeB(instr U64) U64 {
return parseImmTypeB(instr)
}

func ParseImmTypeU(instr U64) U64 {
return parseImmTypeU(instr)
}

func ParseImmTypeJ(instr U64) U64 {
return parseImmTypeJ(instr)
}

func ParseOpcode(instr U64) U64 {
return parseOpcode(instr)
}

func ParseRd(instr U64) U64 {
return parseRd(instr)
}

func ParseFunct3(instr U64) U64 {
return parseFunct3(instr)
}

func ParseRs1(instr U64) U64 {
return parseRs1(instr)
}

func ParseRs2(instr U64) U64 {
return parseRs2(instr)
}
func ParseFunct7(instr U64) U64 {
return parseFunct7(instr)
}
49 changes: 49 additions & 0 deletions rvgo/slow/slow-parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package slow

func ParseImmTypeI(instr U64) U64 {
return parseImmTypeI(instr)
}

func ParseImmTypeS(instr U64) U64 {
return parseImmTypeS(instr)
}

func ParseImmTypeB(instr U64) U64 {
return parseImmTypeB(instr)
}

func ParseImmTypeU(instr U64) U64 {
return parseImmTypeU(instr)
}

func ParseImmTypeJ(instr U64) U64 {
return parseImmTypeJ(instr)
}

func ParseOpcode(instr U64) U64 {
return parseOpcode(instr)
}

func ParseRd(instr U64) U64 {
return parseRd(instr)
}

func ParseFunct3(instr U64) U64 {
return parseFunct3(instr)
}

func ParseRs1(instr U64) U64 {
return parseRs1(instr)
}

func ParseRs2(instr U64) U64 {
return parseRs2(instr)
}

func ParseFunct7(instr U64) U64 {
return parseFunct7(instr)
}

func Val(v U64) uint64 {
return v.val()
}
67 changes: 67 additions & 0 deletions rvgo/test/diff_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package test

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/ethereum-optimism/asterisc/rvgo/fast"
"github.com/ethereum-optimism/asterisc/rvgo/slow"
)

func FuzzParseTypeI(f *testing.F) {
f.Fuzz(func(t *testing.T, instr uint64) {
var slowOutput = slow.ParseImmTypeI(slow.U64{instr})
var fastOutput = fast.ParseImmTypeI(fast.U64(instr))

require.Equal(t, slow.Val(slowOutput), fastOutput)
})
}
func FuzzParseTypeS(f *testing.F) {
f.Fuzz(func(t *testing.T, instr uint64) {
var slowOutput = slow.ParseImmTypeS(slow.U64{instr})
var fastOutput = fast.ParseImmTypeS(fast.U64(instr))

require.Equal(t, slow.Val(slowOutput), fastOutput)
})
}
func FuzzParseTypeB(f *testing.F) {
f.Fuzz(func(t *testing.T, instr uint64) {
var slowOutput = slow.ParseImmTypeB(slow.U64{instr})
var fastOutput = fast.ParseImmTypeB(fast.U64(instr))

require.Equal(t, slow.Val(slowOutput), fastOutput)
})
}
func FuzzParseTypeU(f *testing.F) {
f.Fuzz(func(t *testing.T, instr uint64) {
var slowOutput = slow.ParseImmTypeU(slow.U64{instr})
var fastOutput = fast.ParseImmTypeU(fast.U64(instr))

require.Equal(t, slow.Val(slowOutput), fastOutput)
})
}
func FuzzParseTypeJ(f *testing.F) {
f.Fuzz(func(t *testing.T, instr uint64) {
var slowOutput = slow.ParseImmTypeJ(slow.U64{instr})
var fastOutput = fast.ParseImmTypeJ(fast.U64(instr))

require.Equal(t, slow.Val(slowOutput), fastOutput)
})
}
func FuzzParseOpcode(f *testing.F) {
f.Fuzz(func(t *testing.T, instr uint64) {
var slowOutput = slow.ParseOpcode(slow.U64{instr})
var fastOutput = fast.ParseOpcode(fast.U64(instr))

require.Equal(t, slow.Val(slowOutput), fastOutput)
})
}
func FuzzParseRd(f *testing.F) {
f.Fuzz(func(t *testing.T, instr uint64) {
var slowOutput = slow.ParseRd(slow.U64{instr})
var fastOutput = fast.ParseRd(fast.U64(instr))

require.Equal(t, slow.Val(slowOutput), fastOutput)
})
}
Loading