Unverified Commit 9e5bb84c authored by Gautam Botrel's avatar Gautam Botrel Committed by GitHub

tests/fuzzers: crypto/bn256 and crypto/bls12381 tests against gnark-crypto (#22755)

Add more cross-fuzzers to fuzz bls with gnark versus geth's own bls12-381 library
parent 256c5d68
...@@ -3,7 +3,10 @@ module github.com/ethereum/go-ethereum ...@@ -3,7 +3,10 @@ module github.com/ethereum/go-ethereum
go 1.15 go 1.15
require ( require (
github.com/Azure/azure-pipeline-go v0.2.2 // indirect
github.com/Azure/azure-storage-blob-go v0.7.0 github.com/Azure/azure-storage-blob-go v0.7.0
github.com/Azure/go-autorest/autorest/adal v0.8.0 // indirect
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
github.com/VictoriaMetrics/fastcache v1.5.7 github.com/VictoriaMetrics/fastcache v1.5.7
github.com/aws/aws-sdk-go-v2 v1.2.0 github.com/aws/aws-sdk-go-v2 v1.2.0
github.com/aws/aws-sdk-go-v2/config v1.1.1 github.com/aws/aws-sdk-go-v2/config v1.1.1
...@@ -12,15 +15,18 @@ require ( ...@@ -12,15 +15,18 @@ require (
github.com/btcsuite/btcd v0.20.1-beta github.com/btcsuite/btcd v0.20.1-beta
github.com/cespare/cp v0.1.0 github.com/cespare/cp v0.1.0
github.com/cloudflare/cloudflare-go v0.14.0 github.com/cloudflare/cloudflare-go v0.14.0
github.com/consensys/gurvy v0.3.8 github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea
github.com/dlclark/regexp2 v1.2.0 // indirect
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498
github.com/edsrzf/mmap-go v1.0.0 github.com/edsrzf/mmap-go v1.0.0
github.com/fatih/color v1.7.0 github.com/fatih/color v1.7.0
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
github.com/go-ole/go-ole v1.2.1 // indirect
github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect
github.com/go-stack/stack v1.8.0 github.com/go-stack/stack v1.8.0
github.com/golang/protobuf v1.4.3 github.com/golang/protobuf v1.4.3
github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3
...@@ -37,8 +43,10 @@ require ( ...@@ -37,8 +43,10 @@ require (
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
github.com/julienschmidt/httprouter v1.2.0 github.com/julienschmidt/httprouter v1.2.0
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.0 github.com/mattn/go-colorable v0.1.0
github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035 github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035
github.com/naoina/go-stringutil v0.1.0 // indirect
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
...@@ -51,11 +59,12 @@ require ( ...@@ -51,11 +59,12 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954
github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988
golang.org/x/text v0.3.4 golang.org/x/text v0.3.4
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
gopkg.in/urfave/cli.v1 v1.20.0 gopkg.in/urfave/cli.v1 v1.20.0
gotest.tools v2.2.0+incompatible // indirect
) )
This diff is collapsed.
...@@ -114,5 +114,10 @@ compile_fuzzer tests/fuzzers/bls12381 FuzzPairing fuzz_pairing ...@@ -114,5 +114,10 @@ compile_fuzzer tests/fuzzers/bls12381 FuzzPairing fuzz_pairing
compile_fuzzer tests/fuzzers/bls12381 FuzzMapG1 fuzz_map_g1 compile_fuzzer tests/fuzzers/bls12381 FuzzMapG1 fuzz_map_g1
compile_fuzzer tests/fuzzers/bls12381 FuzzMapG2 fuzz_map_g2 compile_fuzzer tests/fuzzers/bls12381 FuzzMapG2 fuzz_map_g2
compile_fuzzer tests/fuzzers/bls12381 FuzzCrossG1Add fuzz_cross_g1_add
compile_fuzzer tests/fuzzers/bls12381 FuzzCrossG1MultiExp fuzz_cross_g1_multiexp
compile_fuzzer tests/fuzzers/bls12381 FuzzCrossG2Add fuzz_cross_g2_add
compile_fuzzer tests/fuzzers/bls12381 FuzzCrossPairing fuzz_cross_pairing
#TODO: move this to tests/fuzzers, if possible #TODO: move this to tests/fuzzers, if possible
compile_fuzzer crypto/blake2b Fuzz fuzzBlake2b compile_fuzzer crypto/blake2b Fuzz fuzzBlake2b
// Copyright 2021 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 <http://www.gnu.org/licenses/>.
// +build gofuzz
package bls
import (
"bytes"
"crypto/rand"
"fmt"
"io"
"math/big"
gnark "github.com/consensys/gnark-crypto/ecc/bls12-381"
"github.com/consensys/gnark-crypto/ecc/bls12-381/fp"
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
"github.com/ethereum/go-ethereum/crypto/bls12381"
)
func FuzzCrossPairing(data []byte) int {
input := bytes.NewReader(data)
// get random G1 points
kpG1, cpG1, err := getG1Points(input)
if err != nil {
return 0
}
// get random G2 points
kpG2, cpG2, err := getG2Points(input)
if err != nil {
return 0
}
// compute pairing using geth
engine := bls12381.NewPairingEngine()
engine.AddPair(kpG1, kpG2)
kResult := engine.Result()
// compute pairing using gnark
cResult, err := gnark.Pair([]gnark.G1Affine{*cpG1}, []gnark.G2Affine{*cpG2})
if err != nil {
panic(fmt.Sprintf("gnark/bls12381 encountered error: %v", err))
}
// compare result
if !(bytes.Equal(cResult.Marshal(), bls12381.NewGT().ToBytes(kResult))) {
panic("pairing mismatch gnark / geth ")
}
return 1
}
func FuzzCrossG1Add(data []byte) int {
input := bytes.NewReader(data)
// get random G1 points
kp1, cp1, err := getG1Points(input)
if err != nil {
return 0
}
// get random G1 points
kp2, cp2, err := getG1Points(input)
if err != nil {
return 0
}
// compute kp = kp1 + kp2
g1 := bls12381.NewG1()
kp := bls12381.PointG1{}
g1.Add(&kp, kp1, kp2)
// compute cp = cp1 + cp2
_cp1 := new(gnark.G1Jac).FromAffine(cp1)
_cp2 := new(gnark.G1Jac).FromAffine(cp2)
cp := new(gnark.G1Affine).FromJacobian(_cp1.AddAssign(_cp2))
// compare result
if !(bytes.Equal(cp.Marshal(), g1.ToBytes(&kp))) {
panic("G1 point addition mismatch gnark / geth ")
}
return 1
}
func FuzzCrossG2Add(data []byte) int {
input := bytes.NewReader(data)
// get random G2 points
kp1, cp1, err := getG2Points(input)
if err != nil {
return 0
}
// get random G2 points
kp2, cp2, err := getG2Points(input)
if err != nil {
return 0
}
// compute kp = kp1 + kp2
g2 := bls12381.NewG2()
kp := bls12381.PointG2{}
g2.Add(&kp, kp1, kp2)
// compute cp = cp1 + cp2
_cp1 := new(gnark.G2Jac).FromAffine(cp1)
_cp2 := new(gnark.G2Jac).FromAffine(cp2)
cp := new(gnark.G2Affine).FromJacobian(_cp1.AddAssign(_cp2))
// compare result
if !(bytes.Equal(cp.Marshal(), g2.ToBytes(&kp))) {
panic("G2 point addition mismatch gnark / geth ")
}
return 1
}
func FuzzCrossG1MultiExp(data []byte) int {
var (
input = bytes.NewReader(data)
gethScalars []*big.Int
gnarkScalars []fr.Element
gethPoints []*bls12381.PointG1
gnarkPoints []gnark.G1Affine
)
// n random scalars (max 17)
for i := 0; i < 17; i++ {
// note that geth/crypto/bls12381 works only with scalars <= 32bytes
s, err := randomScalar(input, fr.Modulus())
if err != nil {
break
}
// get a random G1 point as basis
kp1, cp1, err := getG1Points(input)
if err != nil {
break
}
gethScalars = append(gethScalars, s)
var gnarkScalar = &fr.Element{}
gnarkScalar = gnarkScalar.SetBigInt(s).FromMont()
gnarkScalars = append(gnarkScalars, *gnarkScalar)
gethPoints = append(gethPoints, new(bls12381.PointG1).Set(kp1))
gnarkPoints = append(gnarkPoints, *cp1)
}
if len(gethScalars) == 0{
return 0
}
// compute multi exponentiation
g1 := bls12381.NewG1()
kp := bls12381.PointG1{}
if _, err := g1.MultiExp(&kp, gethPoints, gethScalars); err != nil {
panic(fmt.Sprintf("G1 multi exponentiation errored (geth): %v", err))
}
// note that geth/crypto/bls12381.MultiExp mutates the scalars slice (and sets all the scalars to zero)
// gnark multi exp
cp := new(gnark.G1Affine)
cp.MultiExp(gnarkPoints, gnarkScalars)
// compare result
if !(bytes.Equal(cp.Marshal(), g1.ToBytes(&kp))) {
panic("G1 multi exponentiation mismatch gnark / geth ")
}
return 1
}
func getG1Points(input io.Reader) (*bls12381.PointG1, *gnark.G1Affine, error) {
// sample a random scalar
s, err := randomScalar(input, fp.Modulus())
if err != nil {
return nil, nil, err
}
// compute a random point
cp := new(gnark.G1Affine)
_, _, g1Gen, _ := gnark.Generators()
cp.ScalarMultiplication(&g1Gen, s)
cpBytes := cp.Marshal()
// marshal gnark point -> geth point
g1 := bls12381.NewG1()
kp, err := g1.FromBytes(cpBytes)
if err != nil {
panic(fmt.Sprintf("Could not marshal gnark.G1 -> geth.G1: %v", err))
}
if !bytes.Equal(g1.ToBytes(kp), cpBytes) {
panic("bytes(gnark.G1) != bytes(geth.G1)")
}
return kp, cp, nil
}
func getG2Points(input io.Reader) (*bls12381.PointG2, *gnark.G2Affine, error) {
// sample a random scalar
s, err := randomScalar(input, fp.Modulus())
if err != nil {
return nil, nil, err
}
// compute a random point
cp := new(gnark.G2Affine)
_, _, _, g2Gen := gnark.Generators()
cp.ScalarMultiplication(&g2Gen, s)
cpBytes := cp.Marshal()
// marshal gnark point -> geth point
g2 := bls12381.NewG2()
kp, err := g2.FromBytes(cpBytes)
if err != nil {
panic(fmt.Sprintf("Could not marshal gnark.G2 -> geth.G2: %v", err))
}
if !bytes.Equal(g2.ToBytes(kp), cpBytes) {
panic("bytes(gnark.G2) != bytes(geth.G2)")
}
return kp, cp, nil
}
func randomScalar(r io.Reader, max *big.Int) (k *big.Int, err error) {
for {
k, err = rand.Int(r, max)
if err != nil || k.Sign() > 0 {
return
}
}
}
...@@ -12,12 +12,12 @@ import ( ...@@ -12,12 +12,12 @@ import (
"io" "io"
"math/big" "math/big"
gurvy "github.com/consensys/gurvy/bn256" "github.com/consensys/gnark-crypto/ecc/bn254"
cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
google "github.com/ethereum/go-ethereum/crypto/bn256/google" google "github.com/ethereum/go-ethereum/crypto/bn256/google"
) )
func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *gurvy.G1Affine) { func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *bn254.G1Affine) {
_, xc, err := cloudflare.RandomG1(input) _, xc, err := cloudflare.RandomG1(input)
if err != nil { if err != nil {
// insufficient input // insufficient input
...@@ -25,16 +25,16 @@ func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *gurvy.G1Affine) ...@@ -25,16 +25,16 @@ func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *gurvy.G1Affine)
} }
xg := new(google.G1) xg := new(google.G1)
if _, err := xg.Unmarshal(xc.Marshal()); err != nil { if _, err := xg.Unmarshal(xc.Marshal()); err != nil {
panic(fmt.Sprintf("Could not marshal cloudflare -> google:", err)) panic(fmt.Sprintf("Could not marshal cloudflare -> google: %v", err))
} }
xs := new(gurvy.G1Affine) xs := new(bn254.G1Affine)
if err := xs.Unmarshal(xc.Marshal()); err != nil { if err := xs.Unmarshal(xc.Marshal()); err != nil {
panic(fmt.Sprintf("Could not marshal cloudflare -> consensys:", err)) panic(fmt.Sprintf("Could not marshal cloudflare -> gnark: %v", err))
} }
return xc, xg, xs return xc, xg, xs
} }
func getG2Points(input io.Reader) (*cloudflare.G2, *google.G2, *gurvy.G2Affine) { func getG2Points(input io.Reader) (*cloudflare.G2, *google.G2, *bn254.G2Affine) {
_, xc, err := cloudflare.RandomG2(input) _, xc, err := cloudflare.RandomG2(input)
if err != nil { if err != nil {
// insufficient input // insufficient input
...@@ -42,11 +42,11 @@ func getG2Points(input io.Reader) (*cloudflare.G2, *google.G2, *gurvy.G2Affine) ...@@ -42,11 +42,11 @@ func getG2Points(input io.Reader) (*cloudflare.G2, *google.G2, *gurvy.G2Affine)
} }
xg := new(google.G2) xg := new(google.G2)
if _, err := xg.Unmarshal(xc.Marshal()); err != nil { if _, err := xg.Unmarshal(xc.Marshal()); err != nil {
panic(fmt.Sprintf("Could not marshal cloudflare -> google:", err)) panic(fmt.Sprintf("Could not marshal cloudflare -> google: %v", err))
} }
xs := new(gurvy.G2Affine) xs := new(bn254.G2Affine)
if err := xs.Unmarshal(xc.Marshal()); err != nil { if err := xs.Unmarshal(xc.Marshal()); err != nil {
panic(fmt.Sprintf("Could not marshal cloudflare -> consensys:", err)) panic(fmt.Sprintf("Could not marshal cloudflare -> gnark: %v", err))
} }
return xc, xg, xs return xc, xg, xs
} }
...@@ -70,16 +70,16 @@ func FuzzAdd(data []byte) int { ...@@ -70,16 +70,16 @@ func FuzzAdd(data []byte) int {
rg := new(google.G1) rg := new(google.G1)
rg.Add(xg, yg) rg.Add(xg, yg)
tmpX := new(gurvy.G1Jac).FromAffine(xs) tmpX := new(bn254.G1Jac).FromAffine(xs)
tmpY := new(gurvy.G1Jac).FromAffine(ys) tmpY := new(bn254.G1Jac).FromAffine(ys)
rs := new(gurvy.G1Affine).FromJacobian(tmpX.AddAssign(tmpY)) rs := new(bn254.G1Affine).FromJacobian(tmpX.AddAssign(tmpY))
if !bytes.Equal(rc.Marshal(), rg.Marshal()) { if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
panic("add mismatch: cloudflare/google") panic("add mismatch: cloudflare/google")
} }
if !bytes.Equal(rc.Marshal(), rs.Marshal()) { if !bytes.Equal(rc.Marshal(), rs.Marshal()) {
panic("add mismatch: cloudflare/consensys") panic("add mismatch: cloudflare/gnark")
} }
return 1 return 1
} }
...@@ -112,16 +112,16 @@ func FuzzMul(data []byte) int { ...@@ -112,16 +112,16 @@ func FuzzMul(data []byte) int {
rg := new(google.G1) rg := new(google.G1)
rg.ScalarMult(pg, new(big.Int).SetBytes(buf)) rg.ScalarMult(pg, new(big.Int).SetBytes(buf))
rs := new(gurvy.G1Jac) rs := new(bn254.G1Jac)
psJac := new(gurvy.G1Jac).FromAffine(ps) psJac := new(bn254.G1Jac).FromAffine(ps)
rs.ScalarMultiplication(psJac, new(big.Int).SetBytes(buf)) rs.ScalarMultiplication(psJac, new(big.Int).SetBytes(buf))
rsAffine := new(gurvy.G1Affine).FromJacobian(rs) rsAffine := new(bn254.G1Affine).FromJacobian(rs)
if !bytes.Equal(rc.Marshal(), rg.Marshal()) { if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
panic("scalar mul mismatch: cloudflare/google") panic("scalar mul mismatch: cloudflare/google")
} }
if !bytes.Equal(rc.Marshal(), rsAffine.Marshal()) { if !bytes.Equal(rc.Marshal(), rsAffine.Marshal()) {
panic("scalar mul mismatch: cloudflare/consensys") panic("scalar mul mismatch: cloudflare/gnark")
} }
return 1 return 1
} }
...@@ -136,18 +136,20 @@ func FuzzPair(data []byte) int { ...@@ -136,18 +136,20 @@ func FuzzPair(data []byte) int {
if tc == nil { if tc == nil {
return 0 return 0
} }
// Pair the two points and ensure they result in the same output // Pair the two points and ensure they result in the same output
clPair := cloudflare.PairingCheck([]*cloudflare.G1{pc}, []*cloudflare.G2{tc}) clPair := cloudflare.Pair(pc, tc).Marshal()
if clPair != google.PairingCheck([]*google.G1{pg}, []*google.G2{tg}) { gPair := google.Pair(pg, tg).Marshal()
if !bytes.Equal(clPair, gPair) {
panic("pairing mismatch: cloudflare/google") panic("pairing mismatch: cloudflare/google")
} }
coPair, err := gurvy.PairingCheck([]gurvy.G1Affine{*ps}, []gurvy.G2Affine{*ts}) cPair, err := bn254.Pair([]bn254.G1Affine{*ps}, []bn254.G2Affine{*ts})
if err != nil { if err != nil {
panic(fmt.Sprintf("gurvy encountered error: %v", err)) panic(fmt.Sprintf("gnark/bn254 encountered error: %v", err))
} }
if clPair != coPair { if !bytes.Equal(clPair, cPair.Marshal()) {
panic("pairing mismatch: cloudflare/consensys") panic("pairing mismatch: cloudflare/gnark")
} }
return 1 return 1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment