github.com/ethereum/go-ethereum@v1.16.1/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  	cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
    26  	gnark "github.com/ethereum/go-ethereum/crypto/bn256/gnark"
    27  	google "github.com/ethereum/go-ethereum/crypto/bn256/google"
    28  )
    29  
    30  func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *gnark.G1) {
    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(gnark.G1)
    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, *gnark.G2) {
    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(gnark.G2)
    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 fuzzes bn256 addition between the Google, Cloudflare and Gnark 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 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  	rs := new(gnark.G1)
    84  	rs.Add(xs, ys)
    85  
    86  	if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
    87  		panic("add mismatch: cloudflare/google")
    88  	}
    89  
    90  	if !bytes.Equal(rc.Marshal(), rs.Marshal()) {
    91  		panic("add mismatch: cloudflare/gnark")
    92  	}
    93  	return 1
    94  }
    95  
    96  // fuzzMul fuzzes bn256 scalar multiplication between the Google, Cloudflare
    97  // and Gnark libraries.
    98  func fuzzMul(data []byte) int {
    99  	input := bytes.NewReader(data)
   100  	pc, pg, ps := getG1Points(input)
   101  	if pc == nil {
   102  		return 0
   103  	}
   104  	// Add the two points and ensure they result in the same output
   105  	remaining := input.Len()
   106  	if remaining == 0 {
   107  		return 0
   108  	}
   109  	if remaining > 128 {
   110  		// The evm only ever uses 32 byte integers, we need to cap this otherwise
   111  		// we run into slow exec. A 236Kb byte integer cause oss-fuzz to report it as slow.
   112  		// 128 bytes should be fine though
   113  		return 0
   114  	}
   115  	buf := make([]byte, remaining)
   116  	input.Read(buf)
   117  
   118  	rc := new(cloudflare.G1)
   119  	rc.ScalarMult(pc, new(big.Int).SetBytes(buf))
   120  
   121  	rg := new(google.G1)
   122  	rg.ScalarMult(pg, new(big.Int).SetBytes(buf))
   123  
   124  	rs := new(gnark.G1)
   125  	rs.ScalarMult(ps, new(big.Int).SetBytes(buf))
   126  
   127  	if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
   128  		panic("scalar mul mismatch: cloudflare/google")
   129  	}
   130  	if !bytes.Equal(rc.Marshal(), rs.Marshal()) {
   131  		panic("scalar mul mismatch: cloudflare/gnark")
   132  	}
   133  	return 1
   134  }
   135  
   136  func fuzzPair(data []byte) int {
   137  	input := bytes.NewReader(data)
   138  	pc, pg, ps := getG1Points(input)
   139  	if pc == nil {
   140  		return 0
   141  	}
   142  	tc, tg, ts := getG2Points(input)
   143  	if tc == nil {
   144  		return 0
   145  	}
   146  
   147  	// Pair the two points and ensure they result in the same output
   148  	clPair := cloudflare.Pair(pc, tc).Marshal()
   149  	gPair := google.Pair(pg, tg).Marshal()
   150  	sPair := gnark.Pair(ps, ts).Marshal()
   151  
   152  	if !bytes.Equal(clPair, gPair) {
   153  		panic("pairing mismatch: cloudflare/google")
   154  	}
   155  
   156  	normalizedClPair := normalizeGTToGnark(clPair).Marshal()
   157  	if !bytes.Equal(normalizedClPair, sPair) {
   158  		panic("pairing mismatch: cloudflare/gnark")
   159  	}
   160  
   161  	return 1
   162  }
   163  
   164  func fuzzUnmarshalG1(input []byte) int {
   165  	rc := new(cloudflare.G1)
   166  	_, errC := rc.Unmarshal(input)
   167  
   168  	rg := new(google.G1)
   169  	_, errG := rg.Unmarshal(input)
   170  
   171  	rs := new(gnark.G1)
   172  	_, errS := rs.Unmarshal(input)
   173  
   174  	if errC != nil && errG != nil && errS != nil {
   175  		return 0 // bad input
   176  	}
   177  	if errC == nil && errG == nil && errS == nil {
   178  		//make sure we unmarshalled the same points:
   179  		if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
   180  			panic("marshaling mismatch: cloudflare/google")
   181  		}
   182  		if !bytes.Equal(rc.Marshal(), rs.Marshal()) {
   183  			panic("marshaling mismatch: cloudflare/gnark")
   184  		}
   185  		return 1
   186  	} else {
   187  		panic(fmt.Sprintf("error missmatch: cf: %v g: %v gn: %v", errC, errG, errS))
   188  	}
   189  }
   190  
   191  func fuzzUnmarshalG2(input []byte) int {
   192  	rc := new(cloudflare.G2)
   193  	_, errC := rc.Unmarshal(input)
   194  
   195  	rg := new(google.G2)
   196  	_, errG := rg.Unmarshal(input)
   197  
   198  	rs := new(gnark.G2)
   199  	_, errS := rs.Unmarshal(input)
   200  
   201  	if errC != nil && errG != nil && errS != nil {
   202  		return 0 // bad input
   203  	}
   204  	if errC == nil && errG == nil && errS == nil {
   205  		//make sure we unmarshalled the same points:
   206  		if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
   207  			panic("marshaling mismatch: cloudflare/google")
   208  		}
   209  		if !bytes.Equal(rc.Marshal(), rs.Marshal()) {
   210  			panic("marshaling mismatch: cloudflare/gnark")
   211  		}
   212  		return 1
   213  	} else {
   214  		panic(fmt.Sprintf("error missmatch: cf: %v g: %v gn: %v", errC, errG, errS))
   215  	}
   216  }
   217  
   218  // normalizeGTToGnark scales a Cloudflare/Google GT element by `s`
   219  // so that it can be compared with a gnark GT point.
   220  //
   221  // For the definition of `s` see 3.5 in https://eprint.iacr.org/2015/192.pdf
   222  func normalizeGTToGnark(cloudflareOrGoogleGT []byte) *gnark.GT {
   223  	// Compute s = 2*u(6*u^2 + 3*u + 1)
   224  	u, _ := new(big.Int).SetString("0x44e992b44a6909f1", 0)
   225  	u_exp2 := new(big.Int).Exp(u, big.NewInt(2), nil)   // u^2
   226  	u_6_exp2 := new(big.Int).Mul(big.NewInt(6), u_exp2) // 6*u^2
   227  	u_3 := new(big.Int).Mul(big.NewInt(3), u)           // 3*u
   228  	inner := u_6_exp2.Add(u_6_exp2, u_3)                // 6*u^2 + 3*u
   229  	inner.Add(inner, big.NewInt(1))                     // 6*u^2 + 3*u + 1
   230  	u_2 := new(big.Int).Mul(big.NewInt(2), u)           // 2*u
   231  	s := u_2.Mul(u_2, inner)                            // 2*u(6*u^2 + 3*u + 1)
   232  
   233  	// Scale the Cloudflare/Google GT element by `s`
   234  	gRes := new(gnark.GT)
   235  	if err := gRes.Unmarshal(cloudflareOrGoogleGT); err != nil {
   236  		panic(err)
   237  	}
   238  	gRes = gRes.Exp(*gRes, s)
   239  
   240  	return gRes
   241  }