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