github.com/consensys/gnark-crypto@v0.14.0/ecc/bn254/pairing_test.go (about) 1 // Copyright 2020 Consensys Software Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Code generated by consensys/gnark-crypto DO NOT EDIT 16 17 package bn254 18 19 import ( 20 "fmt" 21 "math/big" 22 "testing" 23 24 "github.com/consensys/gnark-crypto/ecc/bn254/fp" 25 "github.com/consensys/gnark-crypto/ecc/bn254/fr" 26 "github.com/leanovate/gopter" 27 "github.com/leanovate/gopter/prop" 28 ) 29 30 // ------------------------------------------------------------ 31 // tests 32 33 func TestPairing(t *testing.T) { 34 35 t.Parallel() 36 parameters := gopter.DefaultTestParameters() 37 if testing.Short() { 38 parameters.MinSuccessfulTests = nbFuzzShort 39 } else { 40 parameters.MinSuccessfulTests = nbFuzz 41 } 42 43 properties := gopter.NewProperties(parameters) 44 45 genA := GenE12() 46 genR1 := GenFr() 47 genR2 := GenFr() 48 49 properties.Property("[BN254] Having the receiver as operand (final expo) should output the same result", prop.ForAll( 50 func(a GT) bool { 51 b := FinalExponentiation(&a) 52 a = FinalExponentiation(&a) 53 return a.Equal(&b) 54 }, 55 genA, 56 )) 57 58 properties.Property("[BN254] Exponentiating FinalExpo(a) to r should output 1", prop.ForAll( 59 func(a GT) bool { 60 b := FinalExponentiation(&a) 61 return !a.IsInSubGroup() && b.IsInSubGroup() 62 }, 63 genA, 64 )) 65 66 properties.Property("[BN254] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( 67 func(a GT, e fr.Element) bool { 68 69 var res bool 70 71 // exponent > r 72 { 73 a = FinalExponentiation(&a) 74 var _e big.Int 75 _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) 76 var b, c, d GT 77 b.Exp(a, &_e) 78 c.ExpGLV(a, &_e) 79 d.CyclotomicExp(a, &_e) 80 res = b.Equal(&c) && c.Equal(&d) 81 } 82 83 // exponent < r 84 { 85 a = FinalExponentiation(&a) 86 var _e big.Int 87 e.BigInt(&_e) 88 var b, c, d GT 89 b.Exp(a, &_e) 90 c.ExpGLV(a, &_e) 91 d.CyclotomicExp(a, &_e) 92 res = res && b.Equal(&c) && c.Equal(&d) 93 } 94 95 return res 96 }, 97 genA, 98 genR1, 99 )) 100 101 properties.Property("[BN254] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( 102 func(a GT) bool { 103 var b, c, d GT 104 b.Conjugate(&a) 105 a.Inverse(&a) 106 b.Mul(&b, &a) 107 108 a.FrobeniusSquare(&b). 109 Mul(&a, &b) 110 111 c.Expt(&a).Expt(&c) 112 d.Exp(a, &xGen).Exp(d, &xGen) 113 return c.Equal(&d) 114 }, 115 genA, 116 )) 117 118 properties.Property("[BN254] bilinearity", prop.ForAll( 119 func(a, b fr.Element) bool { 120 121 var res, resa, resb, resab, zero GT 122 123 var ag1 G1Affine 124 var bg2 G2Affine 125 126 var abigint, bbigint, ab big.Int 127 128 a.BigInt(&abigint) 129 b.BigInt(&bbigint) 130 ab.Mul(&abigint, &bbigint) 131 132 ag1.ScalarMultiplication(&g1GenAff, &abigint) 133 bg2.ScalarMultiplication(&g2GenAff, &bbigint) 134 135 res, _ = Pair([]G1Affine{g1GenAff}, []G2Affine{g2GenAff}) 136 resa, _ = Pair([]G1Affine{ag1}, []G2Affine{g2GenAff}) 137 resb, _ = Pair([]G1Affine{g1GenAff}, []G2Affine{bg2}) 138 139 resab.Exp(res, &ab) 140 resa.Exp(resa, &bbigint) 141 resb.Exp(resb, &abigint) 142 143 return resab.Equal(&resa) && resab.Equal(&resb) && !res.Equal(&zero) 144 145 }, 146 genR1, 147 genR2, 148 )) 149 150 properties.Property("[BN254] PairingCheck", prop.ForAll( 151 func(a, b fr.Element) bool { 152 153 var g1GenAffNeg G1Affine 154 g1GenAffNeg.Neg(&g1GenAff) 155 tabP := []G1Affine{g1GenAff, g1GenAffNeg} 156 tabQ := []G2Affine{g2GenAff, g2GenAff} 157 158 res, _ := PairingCheck(tabP, tabQ) 159 160 return res 161 }, 162 genR1, 163 genR2, 164 )) 165 166 properties.Property("[BN254] Pair should output the same result with MillerLoop or MillerLoopFixedQ", prop.ForAll( 167 func(a, b fr.Element) bool { 168 169 var ag1 G1Affine 170 var bg2 G2Affine 171 172 var abigint, bbigint big.Int 173 174 a.BigInt(&abigint) 175 b.BigInt(&bbigint) 176 177 ag1.ScalarMultiplication(&g1GenAff, &abigint) 178 bg2.ScalarMultiplication(&g2GenAff, &bbigint) 179 180 P := []G1Affine{g1GenAff, ag1} 181 Q := []G2Affine{g2GenAff, bg2} 182 183 ml1, _ := MillerLoop(P, Q) 184 ml2, _ := MillerLoopFixedQ( 185 P, 186 [][2][len(LoopCounter)]LineEvaluationAff{ 187 PrecomputeLines(Q[0]), 188 PrecomputeLines(Q[1]), 189 }) 190 191 res1 := FinalExponentiation(&ml1) 192 res2 := FinalExponentiation(&ml2) 193 194 return res1.Equal(&res2) 195 }, 196 genR1, 197 genR2, 198 )) 199 200 properties.TestingRun(t, gopter.ConsoleReporter(false)) 201 } 202 203 func TestMillerLoop(t *testing.T) { 204 205 t.Parallel() 206 parameters := gopter.DefaultTestParameters() 207 if testing.Short() { 208 parameters.MinSuccessfulTests = nbFuzzShort 209 } else { 210 parameters.MinSuccessfulTests = nbFuzz 211 } 212 213 properties := gopter.NewProperties(parameters) 214 215 genR1 := GenFr() 216 genR2 := GenFr() 217 218 properties.Property("[BN254] MillerLoop of pairs should be equal to the product of MillerLoops", prop.ForAll( 219 func(a, b fr.Element) bool { 220 221 var simpleProd, factorizedProd GT 222 223 var ag1 G1Affine 224 var bg2 G2Affine 225 226 var abigint, bbigint big.Int 227 228 a.BigInt(&abigint) 229 b.BigInt(&bbigint) 230 231 ag1.ScalarMultiplication(&g1GenAff, &abigint) 232 bg2.ScalarMultiplication(&g2GenAff, &bbigint) 233 234 P0 := []G1Affine{g1GenAff} 235 P1 := []G1Affine{ag1} 236 Q0 := []G2Affine{g2GenAff} 237 Q1 := []G2Affine{bg2} 238 239 // FE( ML(a,b) * ML(c,d) * ML(e,f) * ML(g,h) ) 240 M1, _ := MillerLoop(P0, Q0) 241 M2, _ := MillerLoop(P1, Q0) 242 M3, _ := MillerLoop(P0, Q1) 243 M4, _ := MillerLoop(P1, Q1) 244 simpleProd.Mul(&M1, &M2).Mul(&simpleProd, &M3).Mul(&simpleProd, &M4) 245 simpleProd = FinalExponentiation(&simpleProd) 246 247 tabP := []G1Affine{g1GenAff, ag1, g1GenAff, ag1} 248 tabQ := []G2Affine{g2GenAff, g2GenAff, bg2, bg2} 249 250 // FE( ML([a,c,e,g] ; [b,d,f,h]) ) -> saves 3 squares in Fqk 251 factorizedProd, _ = Pair(tabP, tabQ) 252 253 return simpleProd.Equal(&factorizedProd) 254 }, 255 genR1, 256 genR2, 257 )) 258 259 properties.Property("[BN254] MillerLoop and MillerLoopFixedQ should skip pairs with a point at infinity", prop.ForAll( 260 func(a, b fr.Element) bool { 261 262 var one GT 263 264 var ag1, g1Inf G1Affine 265 var bg2, g2Inf G2Affine 266 267 var abigint, bbigint big.Int 268 269 one.SetOne() 270 271 a.BigInt(&abigint) 272 b.BigInt(&bbigint) 273 274 ag1.ScalarMultiplication(&g1GenAff, &abigint) 275 bg2.ScalarMultiplication(&g2GenAff, &bbigint) 276 277 g1Inf.FromJacobian(&g1Infinity) 278 g2Inf.FromJacobian(&g2Infinity) 279 280 // e([0,c] ; [b,d]) 281 // -> should be equal to e(c,d) 282 tabP := []G1Affine{g1Inf, ag1} 283 tabQ := []G2Affine{g2GenAff, bg2} 284 res1, _ := Pair(tabP, tabQ) 285 286 // e([a,c] ; [0,d]) 287 // -> should be equal to e(c,d) 288 tabP = []G1Affine{g1GenAff, ag1} 289 tabQ = []G2Affine{g2Inf, bg2} 290 res2, _ := Pair(tabP, tabQ) 291 292 // e([0,c] ; [b,d]) with fixed points b and d 293 // -> should be equal to e(c,d) 294 tabP = []G1Affine{g1Inf, ag1} 295 linesQ := [][2][len(LoopCounter)]LineEvaluationAff{ 296 PrecomputeLines(g2GenAff), 297 PrecomputeLines(bg2), 298 } 299 res3, _ := PairFixedQ(tabP, linesQ) 300 301 // e([a,c] ; [0,d]) with fixed points 0 and d 302 // -> should be equal to e(c,d) 303 tabP = []G1Affine{g1GenAff, ag1} 304 linesQ = [][2][len(LoopCounter)]LineEvaluationAff{ 305 PrecomputeLines(g2Inf), 306 PrecomputeLines(bg2), 307 } 308 res4, _ := PairFixedQ(tabP, linesQ) 309 310 // e([0,c] ; [d,0]) 311 // -> should be equal to 1 312 tabP = []G1Affine{g1Inf, ag1} 313 tabQ = []G2Affine{bg2, g2Inf} 314 res5, _ := Pair(tabP, tabQ) 315 316 // e([0,c] ; [d,0]) with fixed points d and 0 317 // -> should be equal to 1 318 tabP = []G1Affine{g1Inf, ag1} 319 linesQ = [][2][len(LoopCounter)]LineEvaluationAff{ 320 PrecomputeLines(bg2), 321 PrecomputeLines(g2Inf), 322 } 323 res6, _ := PairFixedQ(tabP, linesQ) 324 325 // e([0,0]) 326 // -> should be equal to 1 327 tabP = []G1Affine{g1Inf} 328 tabQ = []G2Affine{g2Inf} 329 res7, _ := Pair(tabP, tabQ) 330 331 // e([0,0]) with fixed point 0 332 // -> should be equal to 1 333 tabP = []G1Affine{g1Inf} 334 linesQ = [][2][len(LoopCounter)]LineEvaluationAff{ 335 PrecomputeLines(g2Inf), 336 } 337 res8, _ := PairFixedQ(tabP, linesQ) 338 339 return res1.Equal(&res2) && res2.Equal(&res3) && res3.Equal(&res4) && 340 res5.Equal(&one) && res6.Equal(&one) && res7.Equal(&one) && res8.Equal(&one) 341 }, 342 genR1, 343 genR2, 344 )) 345 346 properties.Property("[BN254] compressed pairing", prop.ForAll( 347 func(a, b fr.Element) bool { 348 349 var ag1 G1Affine 350 var bg2 G2Affine 351 352 var abigint, bbigint big.Int 353 354 a.BigInt(&abigint) 355 b.BigInt(&bbigint) 356 357 ag1.ScalarMultiplication(&g1GenAff, &abigint) 358 bg2.ScalarMultiplication(&g2GenAff, &bbigint) 359 360 res, _ := Pair([]G1Affine{ag1}, []G2Affine{bg2}) 361 362 compressed, _ := res.CompressTorus() 363 decompressed := compressed.DecompressTorus() 364 365 return decompressed.Equal(&res) 366 367 }, 368 genR1, 369 genR2, 370 )) 371 372 properties.TestingRun(t, gopter.ConsoleReporter(false)) 373 } 374 375 // ------------------------------------------------------------ 376 // benches 377 378 func BenchmarkPairing(b *testing.B) { 379 380 var g1GenAff G1Affine 381 var g2GenAff G2Affine 382 383 g1GenAff.FromJacobian(&g1Gen) 384 g2GenAff.FromJacobian(&g2Gen) 385 386 b.ResetTimer() 387 for i := 0; i < b.N; i++ { 388 Pair([]G1Affine{g1GenAff}, []G2Affine{g2GenAff}) 389 } 390 } 391 392 func BenchmarkMillerLoop(b *testing.B) { 393 394 var g1GenAff G1Affine 395 var g2GenAff G2Affine 396 397 g1GenAff.FromJacobian(&g1Gen) 398 g2GenAff.FromJacobian(&g2Gen) 399 400 b.ResetTimer() 401 for i := 0; i < b.N; i++ { 402 MillerLoop([]G1Affine{g1GenAff}, []G2Affine{g2GenAff}) 403 } 404 } 405 406 func BenchmarkFinalExponentiation(b *testing.B) { 407 408 var a GT 409 a.SetRandom() 410 411 b.ResetTimer() 412 for i := 0; i < b.N; i++ { 413 FinalExponentiation(&a) 414 } 415 416 } 417 418 func BenchmarkMultiMiller(b *testing.B) { 419 420 var g1GenAff G1Affine 421 var g2GenAff G2Affine 422 423 g1GenAff.FromJacobian(&g1Gen) 424 g2GenAff.FromJacobian(&g2Gen) 425 426 n := 10 427 P := make([]G1Affine, n) 428 Q := make([]G2Affine, n) 429 430 for i := 2; i <= n; i++ { 431 for j := 0; j < i; j++ { 432 P[j].Set(&g1GenAff) 433 Q[j].Set(&g2GenAff) 434 } 435 b.Run(fmt.Sprintf("%d pairs", i), func(b *testing.B) { 436 b.ResetTimer() 437 for i := 0; i < b.N; i++ { 438 MillerLoop(P, Q) 439 } 440 }) 441 } 442 } 443 444 func BenchmarkMultiPair(b *testing.B) { 445 446 var g1GenAff G1Affine 447 var g2GenAff G2Affine 448 449 g1GenAff.FromJacobian(&g1Gen) 450 g2GenAff.FromJacobian(&g2Gen) 451 452 n := 10 453 P := make([]G1Affine, n) 454 Q := make([]G2Affine, n) 455 456 for i := 2; i <= n; i++ { 457 for j := 0; j < i; j++ { 458 P[j].Set(&g1GenAff) 459 Q[j].Set(&g2GenAff) 460 } 461 b.Run(fmt.Sprintf("%d pairs", i), func(b *testing.B) { 462 b.ResetTimer() 463 for i := 0; i < b.N; i++ { 464 Pair(P, Q) 465 } 466 }) 467 } 468 } 469 470 func BenchmarkExpGT(b *testing.B) { 471 472 var a GT 473 a.SetRandom() 474 a = FinalExponentiation(&a) 475 476 var e fp.Element 477 e.SetRandom() 478 479 k := new(big.Int).SetUint64(12) 480 e.Exp(e, k) 481 var _e big.Int 482 e.BigInt(&_e) 483 484 b.Run("Naive windowed Exp", func(b *testing.B) { 485 b.ResetTimer() 486 for i := 0; i < b.N; i++ { 487 a.Exp(a, &_e) 488 } 489 }) 490 491 b.Run("2-NAF cyclotomic Exp", func(b *testing.B) { 492 b.ResetTimer() 493 for i := 0; i < b.N; i++ { 494 a.CyclotomicExp(a, &_e) 495 } 496 }) 497 498 b.Run("windowed 2-dim GLV Exp", func(b *testing.B) { 499 b.ResetTimer() 500 for i := 0; i < b.N; i++ { 501 a.ExpGLV(a, &_e) 502 } 503 }) 504 }