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  }