github.com/ethereum/go-ethereum@v1.14.3/tests/fuzzers/bn256/bn256_fuzz.go (about)

     1  // Copyright 2018 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  package bn256
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"math/big"
    24  
    25  	"github.com/consensys/gnark-crypto/ecc/bn254"
    26  	cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
    27  	google "github.com/ethereum/go-ethereum/crypto/bn256/google"
    28  )
    29  
    30  func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *bn254.G1Affine) {
    31  	_, xc, err := cloudflare.RandomG1(input)
    32  	if err != nil {
    33  		// insufficient input
    34  		return nil, nil, nil
    35  	}
    36  	xg := new(google.G1)
    37  	if _, err := xg.Unmarshal(xc.Marshal()); err != nil {
    38  		panic(fmt.Sprintf("Could not marshal cloudflare -> google: %v", err))
    39  	}
    40  	xs := new(bn254.G1Affine)
    41  	if err := xs.Unmarshal(xc.Marshal()); err != nil {
    42  		panic(fmt.Sprintf("Could not marshal cloudflare -> gnark: %v", err))
    43  	}
    44  	return xc, xg, xs
    45  }
    46  
    47  func getG2Points(input io.Reader) (*cloudflare.G2, *google.G2, *bn254.G2Affine) {
    48  	_, xc, err := cloudflare.RandomG2(input)
    49  	if err != nil {
    50  		// insufficient input
    51  		return nil, nil, nil
    52  	}
    53  	xg := new(google.G2)
    54  	if _, err := xg.Unmarshal(xc.Marshal()); err != nil {
    55  		panic(fmt.Sprintf("Could not marshal cloudflare -> google: %v", err))
    56  	}
    57  	xs := new(bn254.G2Affine)
    58  	if err := xs.Unmarshal(xc.Marshal()); err != nil {
    59  		panic(fmt.Sprintf("Could not marshal cloudflare -> gnark: %v", err))
    60  	}
    61  	return xc, xg, xs
    62  }
    63  
    64  // fuzzAdd fuzzez bn256 addition between the Google and Cloudflare libraries.
    65  func fuzzAdd(data []byte) int {
    66  	input := bytes.NewReader(data)
    67  	xc, xg, xs := getG1Points(input)
    68  	if xc == nil {
    69  		return 0
    70  	}
    71  	yc, yg, ys := getG1Points(input)
    72  	if yc == nil {
    73  		return 0
    74  	}
    75  	// Ensure both libs can parse the second curve point
    76  	// Add the two points and ensure they result in the same output
    77  	rc := new(cloudflare.G1)
    78  	rc.Add(xc, yc)
    79  
    80  	rg := new(google.G1)
    81  	rg.Add(xg, yg)
    82  
    83  	tmpX := new(bn254.G1Jac).FromAffine(xs)
    84  	tmpY := new(bn254.G1Jac).FromAffine(ys)
    85  	rs := new(bn254.G1Affine).FromJacobian(tmpX.AddAssign(tmpY))
    86  
    87  	if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
    88  		panic("add mismatch: cloudflare/google")
    89  	}
    90  
    91  	if !bytes.Equal(rc.Marshal(), rs.Marshal()) {
    92  		panic("add mismatch: cloudflare/gnark")
    93  	}
    94  	return 1
    95  }
    96  
    97  // fuzzMul fuzzez bn256 scalar multiplication between the Google and Cloudflare
    98  // libraries.
    99  func fuzzMul(data []byte) int {
   100  	input := bytes.NewReader(data)
   101  	pc, pg, ps := getG1Points(input)
   102  	if pc == nil {
   103  		return 0
   104  	}
   105  	// Add the two points and ensure they result in the same output
   106  	remaining := input.Len()
   107  	if remaining == 0 {
   108  		return 0
   109  	}
   110  	if remaining > 128 {
   111  		// The evm only ever uses 32 byte integers, we need to cap this otherwise
   112  		// we run into slow exec. A 236Kb byte integer cause oss-fuzz to report it as slow.
   113  		// 128 bytes should be fine though
   114  		return 0
   115  	}
   116  	buf := make([]byte, remaining)
   117  	input.Read(buf)
   118  
   119  	rc := new(cloudflare.G1)
   120  	rc.ScalarMult(pc, new(big.Int).SetBytes(buf))
   121  
   122  	rg := new(google.G1)
   123  	rg.ScalarMult(pg, new(big.Int).SetBytes(buf))
   124  
   125  	rs := new(bn254.G1Jac)
   126  	psJac := new(bn254.G1Jac).FromAffine(ps)
   127  	rs.ScalarMultiplication(psJac, new(big.Int).SetBytes(buf))
   128  	rsAffine := new(bn254.G1Affine).FromJacobian(rs)
   129  
   130  	if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
   131  		panic("scalar mul mismatch: cloudflare/google")
   132  	}
   133  	if !bytes.Equal(rc.Marshal(), rsAffine.Marshal()) {
   134  		panic("scalar mul mismatch: cloudflare/gnark")
   135  	}
   136  	return 1
   137  }
   138  
   139  func fuzzPair(data []byte) int {
   140  	input := bytes.NewReader(data)
   141  	pc, pg, ps := getG1Points(input)
   142  	if pc == nil {
   143  		return 0
   144  	}
   145  	tc, tg, ts := getG2Points(input)
   146  	if tc == nil {
   147  		return 0
   148  	}
   149  
   150  	// Pair the two points and ensure they result in the same output
   151  	clPair := cloudflare.Pair(pc, tc).Marshal()
   152  	gPair := google.Pair(pg, tg).Marshal()
   153  	if !bytes.Equal(clPair, gPair) {
   154  		panic("pairing mismatch: cloudflare/google")
   155  	}
   156  	cPair, err := bn254.Pair([]bn254.G1Affine{*ps}, []bn254.G2Affine{*ts})
   157  	if err != nil {
   158  		panic(fmt.Sprintf("gnark/bn254 encountered error: %v", err))
   159  	}
   160  
   161  	// gnark uses a different pairing algorithm which might produce
   162  	// different but also correct outputs, we need to scale the output by s
   163  
   164  	u, _ := new(big.Int).SetString("0x44e992b44a6909f1", 0)
   165  	u_exp2 := new(big.Int).Exp(u, big.NewInt(2), nil)   // u^2
   166  	u_6_exp2 := new(big.Int).Mul(big.NewInt(6), u_exp2) // 6*u^2
   167  	u_3 := new(big.Int).Mul(big.NewInt(3), u)           // 3*u
   168  	inner := u_6_exp2.Add(u_6_exp2, u_3)                // 6*u^2 + 3*u
   169  	inner.Add(inner, big.NewInt(1))                     // 6*u^2 + 3*u + 1
   170  	u_2 := new(big.Int).Mul(big.NewInt(2), u)           // 2*u
   171  	s := u_2.Mul(u_2, inner)                            // 2*u(6*u^2 + 3*u + 1)
   172  
   173  	gRes := new(bn254.GT)
   174  	if err := gRes.SetBytes(clPair); err != nil {
   175  		panic(err)
   176  	}
   177  	gRes = gRes.Exp(*gRes, s)
   178  	if !bytes.Equal(cPair.Marshal(), gRes.Marshal()) {
   179  		panic("pairing mismatch: cloudflare/gnark")
   180  	}
   181  
   182  	return 1
   183  }