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  }