Add an example fuzzing test
This commit is contained in:
parent
4c80f523c2
commit
b435f1a729
35
README.md
35
README.md
|
@ -61,6 +61,41 @@ To keep track of upstream AMCL:
|
|||
- Test
|
||||
- Commit
|
||||
|
||||
### Executing the test suite
|
||||
|
||||
We recomment working within the nimbus build environment described here:
|
||||
https://github.com/status-im/nim-beacon-chain/
|
||||
|
||||
To execute the test suite, just navigate to the root of this repo and execute:
|
||||
|
||||
```
|
||||
nimble test
|
||||
```
|
||||
|
||||
> Please note that within the nimbus build environment, the repository will
|
||||
be located in `nim-beacon-chain/vendor/nim-blscurve`.
|
||||
|
||||
### Executing the fuzzing tests
|
||||
|
||||
Before you start, please make sure that the regular test suite executes
|
||||
successfully (see the instructions above). To start a particular fuzzing
|
||||
test, navigate to the root of this repo and execute:
|
||||
|
||||
```
|
||||
nim tests/fuzzing/run_fuzzing_test.nims <test-name>
|
||||
```
|
||||
|
||||
You can specify the fuzzing engine being used by passing an additional
|
||||
`--fuzzer` parameter. The currently supported engines are `libFuzzer`
|
||||
(used by default) and `afl`.
|
||||
|
||||
All fuzzing tests are located in `tests/fuzzing` and use the following
|
||||
naming convention:
|
||||
|
||||
```
|
||||
fuzz_<test-name>.nim
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed and distributed under either of
|
||||
|
|
|
@ -12,28 +12,19 @@
|
|||
|
||||
import
|
||||
# Standard library
|
||||
json, strutils, os, streams, unittest,
|
||||
# Third party
|
||||
yaml,
|
||||
json, strutils, os, unittest,
|
||||
# Status libraries
|
||||
stew/byteutils,
|
||||
# Public API
|
||||
../blscurve
|
||||
../blscurve,
|
||||
# Test helpers
|
||||
./test_locator
|
||||
|
||||
const ETH2_DIR = currentSourcePath.rsplit(DirSep, 1)[0] / "eth2.0_v0.10.1_vectors"
|
||||
type InOut = enum
|
||||
Input
|
||||
Output
|
||||
|
||||
proc parseTest(file: string): JsonNode =
|
||||
var yamlStream = openFileStream(file)
|
||||
defer: yamlStream.close()
|
||||
result = yamlStream.loadToJson()[0]
|
||||
|
||||
const SkippedTests = [
|
||||
"small"/"fast_aggregate_verify_e6922a0d196d9869"/"data.yaml", # Buggy upstream vector: https://github.com/ethereum/eth2.0-specs/issues/1618
|
||||
"small"/"fast_aggregate_verify_62bca7cd61880e26"/"data.yaml",
|
||||
"small"/"fast_aggregate_verify_3b2b0141e95125f0"/"data.yaml",
|
||||
]
|
||||
|
||||
template testGen(name, testJson, body: untyped): untyped =
|
||||
template testGen*(name, testJson, body: untyped): untyped =
|
||||
## Generates a test proc
|
||||
## with identifier "test_name"
|
||||
## The test file is availaible as JsonNode under the
|
||||
|
@ -41,14 +32,9 @@ template testGen(name, testJson, body: untyped): untyped =
|
|||
proc `test _ name`() =
|
||||
var count = 0 # Need to fail if walkDir doesn't return anything
|
||||
var skipped = 0
|
||||
const testDir = ETH2_DIR / astToStr(name)
|
||||
for file in walkDirRec(testDir, relative = true):
|
||||
if file in SkippedTests:
|
||||
echo "[WARNING] Skipping - ", file
|
||||
inc skipped
|
||||
continue
|
||||
for dir, file in walkTests(astToStr(name), skipped):
|
||||
echo " ", astToStr(name), " test: ", file
|
||||
let testJson = parseTest(testDir / file)
|
||||
let testJson = parseTest(dir / file)
|
||||
|
||||
body
|
||||
|
||||
|
@ -58,10 +44,6 @@ template testGen(name, testJson, body: untyped): untyped =
|
|||
if skipped > 0:
|
||||
echo "[Warning]: ", skipped, " tests skipped."
|
||||
|
||||
type InOut = enum
|
||||
Input
|
||||
Output
|
||||
|
||||
proc getFrom(T: typedesc, test: JsonNode, inout: static InOut): T =
|
||||
when inout == Output:
|
||||
when T is bool:
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import
|
||||
stew/byteutils,
|
||||
../test_locator,
|
||||
fuzzing_assumptions
|
||||
|
||||
var skipped = 0
|
||||
|
||||
let corpusDir = getAppDir() / "corpus"
|
||||
|
||||
removeDir corpusDir
|
||||
|
||||
template getInputBytes(test: JsonNode, fieldName: string): seq[byte] =
|
||||
test["input"][fieldName].getStr.hexToSeqByte
|
||||
|
||||
var inputIdx = 0
|
||||
template nextInput: string =
|
||||
inc inputIdx
|
||||
"input" & $inputIdx
|
||||
|
||||
let verifyCorpusDir = corpusDir / "verify"
|
||||
createDir verifyCorpusDir
|
||||
|
||||
for dir, test in walkTests("verify", skipped):
|
||||
let t = parseTest(dir / test)
|
||||
let
|
||||
message = t.getInputBytes "message"
|
||||
pubKey = t.getInputBytes "pubkey"
|
||||
signature = t.getInputBytes "signature"
|
||||
|
||||
doAssert pubKey.len == fuzzing_assumptions.pubkeyLen and
|
||||
signature.len == fuzzing_assumptions.signatureLen
|
||||
|
||||
writeFile(verifyCorpusDir / nextInput(), message & pubkey & signature)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import
|
||||
testutils/fuzzing, stew/byteutils,
|
||||
../../blscurve, fuzzing_assumptions
|
||||
|
||||
test:
|
||||
block:
|
||||
if payload.len < pubkeyLen + signatureLen:
|
||||
break
|
||||
|
||||
let
|
||||
signatureStart = payload.len - signatureLen
|
||||
pubkeyStart = signatureStart - pubkeyLen
|
||||
|
||||
var sig: Signature
|
||||
if not sig.fromBytes(payload[signatureStart ..< (signatureStart + signatureLen)]):
|
||||
break
|
||||
|
||||
var pubKey: PublicKey
|
||||
if not pubKey.fromBytes(payload[pubkeyStart ..< (pubkeyStart + pubkeyLen)]):
|
||||
break
|
||||
|
||||
discard pubKey.verify(payload[0 ..< pubkeyStart], sig)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
const
|
||||
pubkeyLen* = 48
|
||||
signatureLen* = 96
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import strformat
|
||||
import os except paramCount, paramStr, fileExists # these are also defined in the system module
|
||||
import confutils, testutils/fuzzing_engines
|
||||
|
||||
cli do (testName {.argument.}: string,
|
||||
fuzzer = libFuzzer):
|
||||
let
|
||||
fuzzingDir = thisDir()
|
||||
fuzzingFile = fuzzingDir / "fuzz_" & addFileExt(testName, "nim")
|
||||
corpusDir = fuzzingDir / "corpus" / testName
|
||||
|
||||
if not fileExists(fuzzingFile):
|
||||
echo testName, " is not a recognized fuzzing test"
|
||||
quit 1
|
||||
|
||||
let
|
||||
collectCorpusNim = fuzzingDir / "collect_corpus.nim"
|
||||
fuzzNims = fuzzingDir / ".." / ".." / ".." / "nim-testutils" / "testutils" / "fuzzing" / "fuzz.nims"
|
||||
|
||||
exec &"""nim c -r "{collectCorpusNim}""""
|
||||
exec &"""nim "{fuzzNims}" {fuzzer} "{fuzzingFile}" "{corpusDir}" """
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import
|
||||
# Standard library
|
||||
json, strutils, os, streams,
|
||||
# Third party
|
||||
yaml
|
||||
|
||||
export
|
||||
os, json
|
||||
|
||||
const ETH2_DIR = currentSourcePath.rsplit(DirSep, 1)[0] / "eth2.0_v0.10.1_vectors"
|
||||
|
||||
proc parseTest*(file: string): JsonNode =
|
||||
var yamlStream = openFileStream(file)
|
||||
defer: yamlStream.close()
|
||||
result = yamlStream.loadToJson()[0]
|
||||
|
||||
const SkippedTests = [
|
||||
"small"/"fast_aggregate_verify_e6922a0d196d9869"/"data.yaml", # Buggy upstream vector: https://github.com/ethereum/eth2.0-specs/issues/1618
|
||||
"small"/"fast_aggregate_verify_62bca7cd61880e26"/"data.yaml",
|
||||
"small"/"fast_aggregate_verify_3b2b0141e95125f0"/"data.yaml",
|
||||
]
|
||||
|
||||
iterator walkTests*(category: string, skipped: var int): (string, string) =
|
||||
let testDir = ETH2_DIR / category
|
||||
|
||||
for file in walkDirRec(testDir, relative = true):
|
||||
if file in SkippedTests:
|
||||
echo "[WARNING] Skipping - ", file
|
||||
inc skipped
|
||||
continue
|
||||
|
||||
yield (testDir, file)
|
||||
|
Loading…
Reference in New Issue