diff --git a/crypto/bls12381/fp_test.go b/crypto/bls12381/fp_test.go index 14bb4d7d6..97528d9db 100644 --- a/crypto/bls12381/fp_test.go +++ b/crypto/bls12381/fp_test.go @@ -1393,6 +1393,15 @@ func BenchmarkMultiplication(t *testing.B) { } } +func BenchmarkInverse(t *testing.B) { + a, _ := new(fe).rand(rand.Reader) + b, _ := new(fe).rand(rand.Reader) + t.ResetTimer() + for i := 0; i < t.N; i++ { + inverse(a, b) + } +} + func padBytes(in []byte, size int) []byte { out := make([]byte, size) if len(in) > size { diff --git a/oss-fuzz.sh b/oss-fuzz.sh index 23fb4dd41..e0a293a6d 100644 --- a/oss-fuzz.sh +++ b/oss-fuzz.sh @@ -30,13 +30,20 @@ function compile_fuzzer { path=$SRC/go-ethereum/$1 func=$2 fuzzer=$3 - echo "Building $fuzzer" + corpusfile="${path}/testdata/${fuzzer}_seed_corpus.zip" + echo "Building $fuzzer (expecting corpus at $corpusfile)" (cd $path && \ go-fuzz -func $func -o $WORK/$fuzzer.a . && \ echo "First stage built OK" && \ $CXX $CXXFLAGS $LIB_FUZZING_ENGINE $WORK/$fuzzer.a -o $OUT/$fuzzer && \ echo "Second stage built ok" ) + ## Check if there exists a seed corpus file + if [ -f $corpusfile ] + then + cp $corpusfile $OUT/ + echo "Found seed corpus: $corpusfile" + fi } compile_fuzzer common/bitutil Fuzz fuzzBitutilCompress @@ -51,6 +58,16 @@ compile_fuzzer tests/fuzzers/rlp Fuzz fuzzRlp compile_fuzzer tests/fuzzers/trie Fuzz fuzzTrie compile_fuzzer tests/fuzzers/stacktrie Fuzz fuzzStackTrie +compile_fuzzer tests/fuzzers/bls12381 FuzzG1Add fuzz_g1_add +compile_fuzzer tests/fuzzers/bls12381 FuzzG1Mul fuzz_g1_mul +compile_fuzzer tests/fuzzers/bls12381 FuzzG1MultiExp fuzz_g1_multiexp +compile_fuzzer tests/fuzzers/bls12381 FuzzG2Add fuzz_g2_add +compile_fuzzer tests/fuzzers/bls12381 FuzzG2Mul fuzz_g2_mul +compile_fuzzer tests/fuzzers/bls12381 FuzzG2MultiExp fuzz_g2_multiexp +compile_fuzzer tests/fuzzers/bls12381 FuzzPairing fuzz_pairing +compile_fuzzer tests/fuzzers/bls12381 FuzzMapG1 fuzz_map_g1 +compile_fuzzer tests/fuzzers/bls12381 FuzzMapG2 fuzz_map_g2 + # This doesn't work very well @TODO #compile_fuzzertests/fuzzers/abi Fuzz fuzzAbi diff --git a/tests/fuzzers/bls12381/bls_fuzzer.go b/tests/fuzzers/bls12381/bls_fuzzer.go new file mode 100644 index 000000000..7e3f94c2a --- /dev/null +++ b/tests/fuzzers/bls12381/bls_fuzzer.go @@ -0,0 +1,101 @@ +// Copyright 2020 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package bls + +import ( + "bytes" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" +) + +const ( + blsG1Add = byte(10) + blsG1Mul = byte(11) + blsG1MultiExp = byte(12) + blsG2Add = byte(13) + blsG2Mul = byte(14) + blsG2MultiExp = byte(15) + blsPairing = byte(16) + blsMapG1 = byte(17) + blsMapG2 = byte(18) +) + +func FuzzG1Add(data []byte) int { return fuzz(blsG1Add, data) } +func FuzzG1Mul(data []byte) int { return fuzz(blsG1Mul, data) } +func FuzzG1MultiExp(data []byte) int { return fuzz(blsG1MultiExp, data) } +func FuzzG2Add(data []byte) int { return fuzz(blsG2Add, data) } +func FuzzG2Mul(data []byte) int { return fuzz(blsG2Mul, data) } +func FuzzG2MultiExp(data []byte) int { return fuzz(blsG2MultiExp, data) } +func FuzzPairing(data []byte) int { return fuzz(blsPairing, data) } +func FuzzMapG1(data []byte) int { return fuzz(blsMapG1, data) } +func FuzzMapG2(data []byte) int { return fuzz(blsMapG2, data) } + +func checkInput(id byte, inputLen int) bool { + switch id { + case blsG1Add: + return inputLen == 256 + case blsG1Mul: + return inputLen == 160 + case blsG1MultiExp: + return inputLen%160 == 0 + case blsG2Add: + return inputLen == 512 + case blsG2Mul: + return inputLen == 288 + case blsG2MultiExp: + return inputLen%288 == 0 + case blsPairing: + return inputLen%384 == 0 + case blsMapG1: + return inputLen == 64 + case blsMapG2: + return inputLen == 128 + } + panic("programmer error") +} + +// The fuzzer functions must return +// 1 if the fuzzer should increase priority of the +// given input during subsequent fuzzing (for example, the input is lexically +// correct and was parsed successfully); +// -1 if the input must not be added to corpus even if gives new coverage; and +// 0 otherwise +// other values are reserved for future use. +func fuzz(id byte, data []byte) int { + // Even on bad input, it should not crash, so we still test the gas calc + precompile := vm.PrecompiledContractsYoloV2[common.BytesToAddress([]byte{id})] + gas := precompile.RequiredGas(data) + if !checkInput(id, len(data)) { + return 0 + } + // If the gas cost is too large (25M), bail out + if gas > 25*1000*1000 { + return 0 + } + cpy := make([]byte, len(data)) + copy(cpy, data) + _, err := precompile.Run(cpy) + if !bytes.Equal(cpy, data) { + panic(fmt.Sprintf("input data modified, precompile %d: %x %x", id, data, cpy)) + } + if err != nil { + return 0 + } + return 1 +} diff --git a/tests/fuzzers/bls12381/testdata/fuzz_g1_add_seed_corpus.zip b/tests/fuzzers/bls12381/testdata/fuzz_g1_add_seed_corpus.zip new file mode 100644 index 000000000..16498c1cb Binary files /dev/null and b/tests/fuzzers/bls12381/testdata/fuzz_g1_add_seed_corpus.zip differ diff --git a/tests/fuzzers/bls12381/testdata/fuzz_g1_mul_seed_corpus.zip b/tests/fuzzers/bls12381/testdata/fuzz_g1_mul_seed_corpus.zip new file mode 100644 index 000000000..57f9d6696 Binary files /dev/null and b/tests/fuzzers/bls12381/testdata/fuzz_g1_mul_seed_corpus.zip differ diff --git a/tests/fuzzers/bls12381/testdata/fuzz_g1_multiexp_seed_corpus.zip b/tests/fuzzers/bls12381/testdata/fuzz_g1_multiexp_seed_corpus.zip new file mode 100644 index 000000000..7271f040f Binary files /dev/null and b/tests/fuzzers/bls12381/testdata/fuzz_g1_multiexp_seed_corpus.zip differ diff --git a/tests/fuzzers/bls12381/testdata/fuzz_g2_add_seed_corpus.zip b/tests/fuzzers/bls12381/testdata/fuzz_g2_add_seed_corpus.zip new file mode 100644 index 000000000..cd5206ca0 Binary files /dev/null and b/tests/fuzzers/bls12381/testdata/fuzz_g2_add_seed_corpus.zip differ diff --git a/tests/fuzzers/bls12381/testdata/fuzz_g2_mul_seed_corpus.zip b/tests/fuzzers/bls12381/testdata/fuzz_g2_mul_seed_corpus.zip new file mode 100644 index 000000000..f784a5a3d Binary files /dev/null and b/tests/fuzzers/bls12381/testdata/fuzz_g2_mul_seed_corpus.zip differ diff --git a/tests/fuzzers/bls12381/testdata/fuzz_g2_multiexp_seed_corpus.zip b/tests/fuzzers/bls12381/testdata/fuzz_g2_multiexp_seed_corpus.zip new file mode 100644 index 000000000..c205117a4 Binary files /dev/null and b/tests/fuzzers/bls12381/testdata/fuzz_g2_multiexp_seed_corpus.zip differ diff --git a/tests/fuzzers/bls12381/testdata/fuzz_map_g1_seed_corpus.zip b/tests/fuzzers/bls12381/testdata/fuzz_map_g1_seed_corpus.zip new file mode 100644 index 000000000..70382fbe5 Binary files /dev/null and b/tests/fuzzers/bls12381/testdata/fuzz_map_g1_seed_corpus.zip differ diff --git a/tests/fuzzers/bls12381/testdata/fuzz_map_g2_seed_corpus.zip b/tests/fuzzers/bls12381/testdata/fuzz_map_g2_seed_corpus.zip new file mode 100644 index 000000000..67adc5b5e Binary files /dev/null and b/tests/fuzzers/bls12381/testdata/fuzz_map_g2_seed_corpus.zip differ diff --git a/tests/fuzzers/bls12381/testdata/fuzz_pairing_seed_corpus.zip b/tests/fuzzers/bls12381/testdata/fuzz_pairing_seed_corpus.zip new file mode 100644 index 000000000..e24d2b0a5 Binary files /dev/null and b/tests/fuzzers/bls12381/testdata/fuzz_pairing_seed_corpus.zip differ