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 }