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 }