github.com/bearnetworkchain/go-bearnetwork@v1.10.19-0.20220604150648-d63890c2e42b/tests/fuzzers/bls12381/bls12381_fuzz.go (about)

     1  // Copyright 2021 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  //go:build gofuzz
    18  // +build gofuzz
    19  
    20  package bls
    21  
    22  import (
    23  	"bytes"
    24  	"crypto/rand"
    25  	"fmt"
    26  	"io"
    27  	"math/big"
    28  
    29  	"github.com/bearnetworkchain/go-bearnetwork/crypto/bls12381"
    30  	gnark "github.com/consensys/gnark-crypto/ecc/bls12-381"
    31  	"github.com/consensys/gnark-crypto/ecc/bls12-381/fp"
    32  	"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
    33  	blst "github.com/supranational/blst/bindings/go"
    34  )
    35  
    36  func FuzzCrossPairing(data []byte) int {
    37  	input := bytes.NewReader(data)
    38  
    39  	// get random G1 points
    40  	kpG1, cpG1, blG1, err := getG1Points(input)
    41  	if err != nil {
    42  		return 0
    43  	}
    44  
    45  	// get random G2 points
    46  	kpG2, cpG2, blG2, err := getG2Points(input)
    47  	if err != nil {
    48  		return 0
    49  	}
    50  
    51  	// compute pairing using geth
    52  	engine := bls12381.NewPairingEngine()
    53  	engine.AddPair(kpG1, kpG2)
    54  	kResult := engine.Result()
    55  
    56  	// compute pairing using gnark
    57  	cResult, err := gnark.Pair([]gnark.G1Affine{*cpG1}, []gnark.G2Affine{*cpG2})
    58  	if err != nil {
    59  		panic(fmt.Sprintf("gnark/bls12381 encountered error: %v", err))
    60  	}
    61  
    62  	// compare result
    63  	if !(bytes.Equal(cResult.Marshal(), bls12381.NewGT().ToBytes(kResult))) {
    64  		panic("pairing mismatch gnark / geth ")
    65  	}
    66  
    67  	var b []byte
    68  	ctx := blst.PairingCtx(false, b)
    69  	// compute pairing using blst
    70  	blst.PairingRawAggregate(ctx, blG2, blG1)
    71  	blstResult := blst.PairingAsFp12(ctx)
    72  	if !(bytes.Equal(blstResult.ToBendian(), bls12381.NewGT().ToBytes(kResult))) {
    73  		panic("pairing mismatch blst / geth ")
    74  	}
    75  
    76  	return 1
    77  }
    78  
    79  func FuzzCrossG1Add(data []byte) int {
    80  	input := bytes.NewReader(data)
    81  
    82  	// get random G1 points
    83  	kp1, cp1, bl1, err := getG1Points(input)
    84  	if err != nil {
    85  		return 0
    86  	}
    87  
    88  	// get random G1 points
    89  	kp2, cp2, bl2, err := getG1Points(input)
    90  	if err != nil {
    91  		return 0
    92  	}
    93  
    94  	// compute kp = kp1 + kp2
    95  	g1 := bls12381.NewG1()
    96  	kp := bls12381.PointG1{}
    97  	g1.Add(&kp, kp1, kp2)
    98  
    99  	// compute cp = cp1 + cp2
   100  	_cp1 := new(gnark.G1Jac).FromAffine(cp1)
   101  	_cp2 := new(gnark.G1Jac).FromAffine(cp2)
   102  	cp := new(gnark.G1Affine).FromJacobian(_cp1.AddAssign(_cp2))
   103  
   104  	// compare result
   105  	if !(bytes.Equal(cp.Marshal(), g1.ToBytes(&kp))) {
   106  		panic("G1 point addition mismatch gnark / geth ")
   107  	}
   108  
   109  	bl3 := blst.P1AffinesAdd([]*blst.P1Affine{bl1, bl2})
   110  	if !(bytes.Equal(cp.Marshal(), bl3.Serialize())) {
   111  		panic("G1 point addition mismatch blst / geth ")
   112  	}
   113  
   114  	return 1
   115  }
   116  
   117  func FuzzCrossG2Add(data []byte) int {
   118  	input := bytes.NewReader(data)
   119  
   120  	// get random G2 points
   121  	kp1, cp1, bl1, err := getG2Points(input)
   122  	if err != nil {
   123  		return 0
   124  	}
   125  
   126  	// get random G2 points
   127  	kp2, cp2, bl2, err := getG2Points(input)
   128  	if err != nil {
   129  		return 0
   130  	}
   131  
   132  	// compute kp = kp1 + kp2
   133  	g2 := bls12381.NewG2()
   134  	kp := bls12381.PointG2{}
   135  	g2.Add(&kp, kp1, kp2)
   136  
   137  	// compute cp = cp1 + cp2
   138  	_cp1 := new(gnark.G2Jac).FromAffine(cp1)
   139  	_cp2 := new(gnark.G2Jac).FromAffine(cp2)
   140  	cp := new(gnark.G2Affine).FromJacobian(_cp1.AddAssign(_cp2))
   141  
   142  	// compare result
   143  	if !(bytes.Equal(cp.Marshal(), g2.ToBytes(&kp))) {
   144  		panic("G2 point addition mismatch gnark / geth ")
   145  	}
   146  
   147  	bl3 := blst.P2AffinesAdd([]*blst.P2Affine{bl1, bl2})
   148  	if !(bytes.Equal(cp.Marshal(), bl3.Serialize())) {
   149  		panic("G1 point addition mismatch blst / geth ")
   150  	}
   151  
   152  	return 1
   153  }
   154  
   155  func FuzzCrossG1MultiExp(data []byte) int {
   156  	var (
   157  		input        = bytes.NewReader(data)
   158  		gethScalars  []*big.Int
   159  		gnarkScalars []fr.Element
   160  		gethPoints   []*bls12381.PointG1
   161  		gnarkPoints  []gnark.G1Affine
   162  	)
   163  	// n random scalars (max 17)
   164  	for i := 0; i < 17; i++ {
   165  		// note that geth/crypto/bls12381 works only with scalars <= 32bytes
   166  		s, err := randomScalar(input, fr.Modulus())
   167  		if err != nil {
   168  			break
   169  		}
   170  		// get a random G1 point as basis
   171  		kp1, cp1, _, err := getG1Points(input)
   172  		if err != nil {
   173  			break
   174  		}
   175  		gethScalars = append(gethScalars, s)
   176  		var gnarkScalar = &fr.Element{}
   177  		gnarkScalar = gnarkScalar.SetBigInt(s).FromMont()
   178  		gnarkScalars = append(gnarkScalars, *gnarkScalar)
   179  
   180  		gethPoints = append(gethPoints, new(bls12381.PointG1).Set(kp1))
   181  		gnarkPoints = append(gnarkPoints, *cp1)
   182  	}
   183  	if len(gethScalars) == 0 {
   184  		return 0
   185  	}
   186  	// compute multi exponentiation
   187  	g1 := bls12381.NewG1()
   188  	kp := bls12381.PointG1{}
   189  	if _, err := g1.MultiExp(&kp, gethPoints, gethScalars); err != nil {
   190  		panic(fmt.Sprintf("G1 multi exponentiation errored (geth): %v", err))
   191  	}
   192  	// note that geth/crypto/bls12381.MultiExp mutates the scalars slice (and sets all the scalars to zero)
   193  
   194  	// gnark multi exp
   195  	cp := new(gnark.G1Affine)
   196  	cp.MultiExp(gnarkPoints, gnarkScalars)
   197  
   198  	// compare result
   199  	if !(bytes.Equal(cp.Marshal(), g1.ToBytes(&kp))) {
   200  		panic("G1 multi exponentiation mismatch gnark / geth ")
   201  	}
   202  
   203  	return 1
   204  }
   205  
   206  func getG1Points(input io.Reader) (*bls12381.PointG1, *gnark.G1Affine, *blst.P1Affine, error) {
   207  	// sample a random scalar
   208  	s, err := randomScalar(input, fp.Modulus())
   209  	if err != nil {
   210  		return nil, nil, nil, err
   211  	}
   212  
   213  	// compute a random point
   214  	cp := new(gnark.G1Affine)
   215  	_, _, g1Gen, _ := gnark.Generators()
   216  	cp.ScalarMultiplication(&g1Gen, s)
   217  	cpBytes := cp.Marshal()
   218  
   219  	// marshal gnark point -> geth point
   220  	g1 := bls12381.NewG1()
   221  	kp, err := g1.FromBytes(cpBytes)
   222  	if err != nil {
   223  		panic(fmt.Sprintf("Could not marshal gnark.G1 -> geth.G1: %v", err))
   224  	}
   225  	if !bytes.Equal(g1.ToBytes(kp), cpBytes) {
   226  		panic("bytes(gnark.G1) != bytes(geth.G1)")
   227  	}
   228  
   229  	// marshal gnark point -> blst point
   230  	var p1 *blst.P1Affine
   231  	var scalar *blst.Scalar
   232  	scalar.Deserialize(s.Bytes())
   233  	p1.From(scalar)
   234  	if !bytes.Equal(p1.Serialize(), cpBytes) {
   235  		panic("bytes(blst.G1) != bytes(geth.G1)")
   236  	}
   237  
   238  	return kp, cp, p1, nil
   239  }
   240  
   241  func getG2Points(input io.Reader) (*bls12381.PointG2, *gnark.G2Affine, *blst.P2Affine, error) {
   242  	// sample a random scalar
   243  	s, err := randomScalar(input, fp.Modulus())
   244  	if err != nil {
   245  		return nil, nil, nil, err
   246  	}
   247  
   248  	// compute a random point
   249  	cp := new(gnark.G2Affine)
   250  	_, _, _, g2Gen := gnark.Generators()
   251  	cp.ScalarMultiplication(&g2Gen, s)
   252  	cpBytes := cp.Marshal()
   253  
   254  	// marshal gnark point -> geth point
   255  	g2 := bls12381.NewG2()
   256  	kp, err := g2.FromBytes(cpBytes)
   257  	if err != nil {
   258  		panic(fmt.Sprintf("Could not marshal gnark.G2 -> geth.G2: %v", err))
   259  	}
   260  	if !bytes.Equal(g2.ToBytes(kp), cpBytes) {
   261  		panic("bytes(gnark.G2) != bytes(geth.G2)")
   262  	}
   263  
   264  	// marshal gnark point -> blst point
   265  	var p2 *blst.P2Affine
   266  	var scalar *blst.Scalar
   267  	scalar.Deserialize(s.Bytes())
   268  	p2.From(scalar)
   269  	if !bytes.Equal(p2.Serialize(), cpBytes) {
   270  		panic("bytes(blst.G2) != bytes(geth.G2)")
   271  	}
   272  
   273  	return kp, cp, p2, nil
   274  }
   275  
   276  func randomScalar(r io.Reader, max *big.Int) (k *big.Int, err error) {
   277  	for {
   278  		k, err = rand.Int(r, max)
   279  		if err != nil || k.Sign() > 0 {
   280  			return
   281  		}
   282  	}
   283  }