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 }