github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/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 gnark "github.com/consensys/gnark-crypto/ecc/bls12-381" 30 "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" 31 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" 32 "github.com/ethereum/go-ethereum/crypto/bls12381" 33 ) 34 35 func FuzzCrossPairing(data []byte) int { 36 input := bytes.NewReader(data) 37 38 // get random G1 points 39 kpG1, cpG1, err := getG1Points(input) 40 if err != nil { 41 return 0 42 } 43 44 // get random G2 points 45 kpG2, cpG2, err := getG2Points(input) 46 if err != nil { 47 return 0 48 } 49 50 // compute pairing using geth 51 engine := bls12381.NewPairingEngine() 52 engine.AddPair(kpG1, kpG2) 53 kResult := engine.Result() 54 55 // compute pairing using gnark 56 cResult, err := gnark.Pair([]gnark.G1Affine{*cpG1}, []gnark.G2Affine{*cpG2}) 57 if err != nil { 58 panic(fmt.Sprintf("gnark/bls12381 encountered error: %v", err)) 59 } 60 61 // compare result 62 if !(bytes.Equal(cResult.Marshal(), bls12381.NewGT().ToBytes(kResult))) { 63 panic("pairing mismatch gnark / geth ") 64 } 65 66 return 1 67 } 68 69 func FuzzCrossG1Add(data []byte) int { 70 input := bytes.NewReader(data) 71 72 // get random G1 points 73 kp1, cp1, err := getG1Points(input) 74 if err != nil { 75 return 0 76 } 77 78 // get random G1 points 79 kp2, cp2, err := getG1Points(input) 80 if err != nil { 81 return 0 82 } 83 84 // compute kp = kp1 + kp2 85 g1 := bls12381.NewG1() 86 kp := bls12381.PointG1{} 87 g1.Add(&kp, kp1, kp2) 88 89 // compute cp = cp1 + cp2 90 _cp1 := new(gnark.G1Jac).FromAffine(cp1) 91 _cp2 := new(gnark.G1Jac).FromAffine(cp2) 92 cp := new(gnark.G1Affine).FromJacobian(_cp1.AddAssign(_cp2)) 93 94 // compare result 95 if !(bytes.Equal(cp.Marshal(), g1.ToBytes(&kp))) { 96 panic("G1 point addition mismatch gnark / geth ") 97 } 98 99 return 1 100 } 101 102 func FuzzCrossG2Add(data []byte) int { 103 input := bytes.NewReader(data) 104 105 // get random G2 points 106 kp1, cp1, err := getG2Points(input) 107 if err != nil { 108 return 0 109 } 110 111 // get random G2 points 112 kp2, cp2, err := getG2Points(input) 113 if err != nil { 114 return 0 115 } 116 117 // compute kp = kp1 + kp2 118 g2 := bls12381.NewG2() 119 kp := bls12381.PointG2{} 120 g2.Add(&kp, kp1, kp2) 121 122 // compute cp = cp1 + cp2 123 _cp1 := new(gnark.G2Jac).FromAffine(cp1) 124 _cp2 := new(gnark.G2Jac).FromAffine(cp2) 125 cp := new(gnark.G2Affine).FromJacobian(_cp1.AddAssign(_cp2)) 126 127 // compare result 128 if !(bytes.Equal(cp.Marshal(), g2.ToBytes(&kp))) { 129 panic("G2 point addition mismatch gnark / geth ") 130 } 131 132 return 1 133 } 134 135 func FuzzCrossG1MultiExp(data []byte) int { 136 var ( 137 input = bytes.NewReader(data) 138 gethScalars []*big.Int 139 gnarkScalars []fr.Element 140 gethPoints []*bls12381.PointG1 141 gnarkPoints []gnark.G1Affine 142 ) 143 // n random scalars (max 17) 144 for i := 0; i < 17; i++ { 145 // note that geth/crypto/bls12381 works only with scalars <= 32bytes 146 s, err := randomScalar(input, fr.Modulus()) 147 if err != nil { 148 break 149 } 150 // get a random G1 point as basis 151 kp1, cp1, err := getG1Points(input) 152 if err != nil { 153 break 154 } 155 gethScalars = append(gethScalars, s) 156 var gnarkScalar = &fr.Element{} 157 gnarkScalar = gnarkScalar.SetBigInt(s).FromMont() 158 gnarkScalars = append(gnarkScalars, *gnarkScalar) 159 160 gethPoints = append(gethPoints, new(bls12381.PointG1).Set(kp1)) 161 gnarkPoints = append(gnarkPoints, *cp1) 162 } 163 if len(gethScalars) == 0 { 164 return 0 165 } 166 // compute multi exponentiation 167 g1 := bls12381.NewG1() 168 kp := bls12381.PointG1{} 169 if _, err := g1.MultiExp(&kp, gethPoints, gethScalars); err != nil { 170 panic(fmt.Sprintf("G1 multi exponentiation errored (geth): %v", err)) 171 } 172 // note that geth/crypto/bls12381.MultiExp mutates the scalars slice (and sets all the scalars to zero) 173 174 // gnark multi exp 175 cp := new(gnark.G1Affine) 176 cp.MultiExp(gnarkPoints, gnarkScalars) 177 178 // compare result 179 if !(bytes.Equal(cp.Marshal(), g1.ToBytes(&kp))) { 180 panic("G1 multi exponentiation mismatch gnark / geth ") 181 } 182 183 return 1 184 } 185 186 func getG1Points(input io.Reader) (*bls12381.PointG1, *gnark.G1Affine, error) { 187 // sample a random scalar 188 s, err := randomScalar(input, fp.Modulus()) 189 if err != nil { 190 return nil, nil, err 191 } 192 193 // compute a random point 194 cp := new(gnark.G1Affine) 195 _, _, g1Gen, _ := gnark.Generators() 196 cp.ScalarMultiplication(&g1Gen, s) 197 cpBytes := cp.Marshal() 198 199 // marshal gnark point -> geth point 200 g1 := bls12381.NewG1() 201 kp, err := g1.FromBytes(cpBytes) 202 if err != nil { 203 panic(fmt.Sprintf("Could not marshal gnark.G1 -> geth.G1: %v", err)) 204 } 205 if !bytes.Equal(g1.ToBytes(kp), cpBytes) { 206 panic("bytes(gnark.G1) != bytes(geth.G1)") 207 } 208 209 return kp, cp, nil 210 } 211 212 func getG2Points(input io.Reader) (*bls12381.PointG2, *gnark.G2Affine, error) { 213 // sample a random scalar 214 s, err := randomScalar(input, fp.Modulus()) 215 if err != nil { 216 return nil, nil, err 217 } 218 219 // compute a random point 220 cp := new(gnark.G2Affine) 221 _, _, _, g2Gen := gnark.Generators() 222 cp.ScalarMultiplication(&g2Gen, s) 223 cpBytes := cp.Marshal() 224 225 // marshal gnark point -> geth point 226 g2 := bls12381.NewG2() 227 kp, err := g2.FromBytes(cpBytes) 228 if err != nil { 229 panic(fmt.Sprintf("Could not marshal gnark.G2 -> geth.G2: %v", err)) 230 } 231 if !bytes.Equal(g2.ToBytes(kp), cpBytes) { 232 panic("bytes(gnark.G2) != bytes(geth.G2)") 233 } 234 235 return kp, cp, nil 236 } 237 238 func randomScalar(r io.Reader, max *big.Int) (k *big.Int, err error) { 239 for { 240 k, err = rand.Int(r, max) 241 if err != nil || k.Sign() > 0 { 242 return 243 } 244 } 245 }