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