github.com/theQRL/go-zond@v0.1.1/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/consensys/gnark-crypto/ecc" 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 "github.com/theQRL/go-zond/common" 35 "github.com/theQRL/go-zond/crypto/bls12381" 36 ) 37 38 func FuzzCrossPairing(data []byte) int { 39 input := bytes.NewReader(data) 40 41 // get random G1 points 42 kpG1, cpG1, blG1, err := getG1Points(input) 43 if err != nil { 44 return 0 45 } 46 47 // get random G2 points 48 kpG2, cpG2, blG2, err := getG2Points(input) 49 if err != nil { 50 return 0 51 } 52 53 // compute pairing using geth 54 engine := bls12381.NewPairingEngine() 55 engine.AddPair(kpG1, kpG2) 56 kResult := engine.Result() 57 58 // compute pairing using gnark 59 cResult, err := gnark.Pair([]gnark.G1Affine{*cpG1}, []gnark.G2Affine{*cpG2}) 60 if err != nil { 61 panic(fmt.Sprintf("gnark/bls12381 encountered error: %v", err)) 62 } 63 64 // compare result 65 if !(bytes.Equal(cResult.Marshal(), bls12381.NewGT().ToBytes(kResult))) { 66 panic("pairing mismatch gnark / geth ") 67 } 68 69 // compute pairing using blst 70 blstResult := blst.Fp12MillerLoop(blG2, blG1) 71 blstResult.FinalExp() 72 res := massageBLST(blstResult.ToBendian()) 73 if !(bytes.Equal(res, bls12381.NewGT().ToBytes(kResult))) { 74 panic("pairing mismatch blst / geth") 75 } 76 77 return 1 78 } 79 80 func massageBLST(in []byte) []byte { 81 out := make([]byte, len(in)) 82 len := 12 * 48 83 // 1 84 copy(out[0:], in[len-1*48:len]) 85 copy(out[1*48:], in[len-2*48:len-1*48]) 86 // 2 87 copy(out[6*48:], in[len-3*48:len-2*48]) 88 copy(out[7*48:], in[len-4*48:len-3*48]) 89 // 3 90 copy(out[2*48:], in[len-5*48:len-4*48]) 91 copy(out[3*48:], in[len-6*48:len-5*48]) 92 // 4 93 copy(out[8*48:], in[len-7*48:len-6*48]) 94 copy(out[9*48:], in[len-8*48:len-7*48]) 95 // 5 96 copy(out[4*48:], in[len-9*48:len-8*48]) 97 copy(out[5*48:], in[len-10*48:len-9*48]) 98 // 6 99 copy(out[10*48:], in[len-11*48:len-10*48]) 100 copy(out[11*48:], in[len-12*48:len-11*48]) 101 return out 102 } 103 104 func FuzzCrossG1Add(data []byte) int { 105 input := bytes.NewReader(data) 106 107 // get random G1 points 108 kp1, cp1, bl1, err := getG1Points(input) 109 if err != nil { 110 return 0 111 } 112 113 // get random G1 points 114 kp2, cp2, bl2, err := getG1Points(input) 115 if err != nil { 116 return 0 117 } 118 119 // compute kp = kp1 + kp2 120 g1 := bls12381.NewG1() 121 kp := bls12381.PointG1{} 122 g1.Add(&kp, kp1, kp2) 123 124 // compute cp = cp1 + cp2 125 _cp1 := new(gnark.G1Jac).FromAffine(cp1) 126 _cp2 := new(gnark.G1Jac).FromAffine(cp2) 127 cp := new(gnark.G1Affine).FromJacobian(_cp1.AddAssign(_cp2)) 128 129 // compare result 130 if !(bytes.Equal(cp.Marshal(), g1.ToBytes(&kp))) { 131 panic("G1 point addition mismatch gnark / geth ") 132 } 133 134 bl3 := blst.P1AffinesAdd([]*blst.P1Affine{bl1, bl2}) 135 if !(bytes.Equal(cp.Marshal(), bl3.Serialize())) { 136 panic("G1 point addition mismatch blst / geth ") 137 } 138 139 return 1 140 } 141 142 func FuzzCrossG2Add(data []byte) int { 143 input := bytes.NewReader(data) 144 145 // get random G2 points 146 kp1, cp1, bl1, err := getG2Points(input) 147 if err != nil { 148 return 0 149 } 150 151 // get random G2 points 152 kp2, cp2, bl2, err := getG2Points(input) 153 if err != nil { 154 return 0 155 } 156 157 // compute kp = kp1 + kp2 158 g2 := bls12381.NewG2() 159 kp := bls12381.PointG2{} 160 g2.Add(&kp, kp1, kp2) 161 162 // compute cp = cp1 + cp2 163 _cp1 := new(gnark.G2Jac).FromAffine(cp1) 164 _cp2 := new(gnark.G2Jac).FromAffine(cp2) 165 cp := new(gnark.G2Affine).FromJacobian(_cp1.AddAssign(_cp2)) 166 167 // compare result 168 if !(bytes.Equal(cp.Marshal(), g2.ToBytes(&kp))) { 169 panic("G2 point addition mismatch gnark / geth ") 170 } 171 172 bl3 := blst.P2AffinesAdd([]*blst.P2Affine{bl1, bl2}) 173 if !(bytes.Equal(cp.Marshal(), bl3.Serialize())) { 174 panic("G1 point addition mismatch blst / geth ") 175 } 176 177 return 1 178 } 179 180 func FuzzCrossG1MultiExp(data []byte) int { 181 var ( 182 input = bytes.NewReader(data) 183 gethScalars []*big.Int 184 gnarkScalars []fr.Element 185 gethPoints []*bls12381.PointG1 186 gnarkPoints []gnark.G1Affine 187 ) 188 // n random scalars (max 17) 189 for i := 0; i < 17; i++ { 190 // note that geth/crypto/bls12381 works only with scalars <= 32bytes 191 s, err := randomScalar(input, fr.Modulus()) 192 if err != nil { 193 break 194 } 195 // get a random G1 point as basis 196 kp1, cp1, _, err := getG1Points(input) 197 if err != nil { 198 break 199 } 200 gethScalars = append(gethScalars, s) 201 var gnarkScalar = &fr.Element{} 202 gnarkScalar = gnarkScalar.SetBigInt(s) 203 gnarkScalars = append(gnarkScalars, *gnarkScalar) 204 205 gethPoints = append(gethPoints, new(bls12381.PointG1).Set(kp1)) 206 gnarkPoints = append(gnarkPoints, *cp1) 207 } 208 if len(gethScalars) == 0 { 209 return 0 210 } 211 // compute multi exponentiation 212 g1 := bls12381.NewG1() 213 kp := bls12381.PointG1{} 214 if _, err := g1.MultiExp(&kp, gethPoints, gethScalars); err != nil { 215 panic(fmt.Sprintf("G1 multi exponentiation errored (geth): %v", err)) 216 } 217 // note that geth/crypto/bls12381.MultiExp mutates the scalars slice (and sets all the scalars to zero) 218 219 // gnark multi exp 220 cp := new(gnark.G1Affine) 221 cp.MultiExp(gnarkPoints, gnarkScalars, ecc.MultiExpConfig{}) 222 223 // compare result 224 if !(bytes.Equal(cp.Marshal(), g1.ToBytes(&kp))) { 225 panic("G1 multi exponentiation mismatch gnark / geth ") 226 } 227 228 return 1 229 } 230 231 func getG1Points(input io.Reader) (*bls12381.PointG1, *gnark.G1Affine, *blst.P1Affine, error) { 232 // sample a random scalar 233 s, err := randomScalar(input, fp.Modulus()) 234 if err != nil { 235 return nil, nil, nil, err 236 } 237 238 // compute a random point 239 cp := new(gnark.G1Affine) 240 _, _, g1Gen, _ := gnark.Generators() 241 cp.ScalarMultiplication(&g1Gen, s) 242 cpBytes := cp.Marshal() 243 244 // marshal gnark point -> geth point 245 g1 := bls12381.NewG1() 246 kp, err := g1.FromBytes(cpBytes) 247 if err != nil { 248 panic(fmt.Sprintf("Could not marshal gnark.G1 -> geth.G1: %v", err)) 249 } 250 if !bytes.Equal(g1.ToBytes(kp), cpBytes) { 251 panic("bytes(gnark.G1) != bytes(geth.G1)") 252 } 253 254 // marshal gnark point -> blst point 255 scalar := new(blst.Scalar).FromBEndian(common.LeftPadBytes(s.Bytes(), 32)) 256 p1 := new(blst.P1Affine).From(scalar) 257 if !bytes.Equal(p1.Serialize(), cpBytes) { 258 panic("bytes(blst.G1) != bytes(geth.G1)") 259 } 260 261 return kp, cp, p1, nil 262 } 263 264 func getG2Points(input io.Reader) (*bls12381.PointG2, *gnark.G2Affine, *blst.P2Affine, error) { 265 // sample a random scalar 266 s, err := randomScalar(input, fp.Modulus()) 267 if err != nil { 268 return nil, nil, nil, err 269 } 270 271 // compute a random point 272 cp := new(gnark.G2Affine) 273 _, _, _, g2Gen := gnark.Generators() 274 cp.ScalarMultiplication(&g2Gen, s) 275 cpBytes := cp.Marshal() 276 277 // marshal gnark point -> geth point 278 g2 := bls12381.NewG2() 279 kp, err := g2.FromBytes(cpBytes) 280 if err != nil { 281 panic(fmt.Sprintf("Could not marshal gnark.G2 -> geth.G2: %v", err)) 282 } 283 if !bytes.Equal(g2.ToBytes(kp), cpBytes) { 284 panic("bytes(gnark.G2) != bytes(geth.G2)") 285 } 286 287 // marshal gnark point -> blst point 288 // Left pad the scalar to 32 bytes 289 scalar := new(blst.Scalar).FromBEndian(common.LeftPadBytes(s.Bytes(), 32)) 290 p2 := new(blst.P2Affine).From(scalar) 291 if !bytes.Equal(p2.Serialize(), cpBytes) { 292 panic("bytes(blst.G2) != bytes(geth.G2)") 293 } 294 295 return kp, cp, p2, nil 296 } 297 298 func randomScalar(r io.Reader, max *big.Int) (k *big.Int, err error) { 299 for { 300 k, err = rand.Int(r, max) 301 if err != nil || k.Sign() > 0 { 302 return 303 } 304 } 305 }