github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-633/internal/fptower/e6_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  package fptower
    16  
    17  import (
    18  	"math/big"
    19  	"testing"
    20  
    21  	"github.com/consensys/gnark-crypto/ecc/bw6-633/fp"
    22  	"github.com/leanovate/gopter"
    23  	"github.com/leanovate/gopter/prop"
    24  )
    25  
    26  // ------------------------------------------------------------
    27  // tests
    28  
    29  func TestE6Serialization(t *testing.T) {
    30  
    31  	parameters := gopter.DefaultTestParameters()
    32  	parameters.MinSuccessfulTests = 100
    33  
    34  	properties := gopter.NewProperties(parameters)
    35  
    36  	genA := GenE6()
    37  
    38  	properties.Property("[BW6-633] SetBytes(Bytes()) should stay constant", prop.ForAll(
    39  		func(a *E6) bool {
    40  			var b E6
    41  			buf := a.Bytes()
    42  			if err := b.SetBytes(buf[:]); err != nil {
    43  				return false
    44  			}
    45  			return a.Equal(&b)
    46  		},
    47  		genA,
    48  	))
    49  
    50  	properties.TestingRun(t, gopter.ConsoleReporter(false))
    51  }
    52  
    53  func TestE6ReceiverIsOperand(t *testing.T) {
    54  
    55  	parameters := gopter.DefaultTestParameters()
    56  	parameters.MinSuccessfulTests = 100
    57  
    58  	properties := gopter.NewProperties(parameters)
    59  
    60  	genA := GenE6()
    61  	genB := GenE6()
    62  
    63  	properties.Property("[BW6-633] Having the receiver as operand (addition) should output the same result", prop.ForAll(
    64  		func(a, b *E6) bool {
    65  			var c, d E6
    66  			d.Set(a)
    67  			c.Add(a, b)
    68  			a.Add(a, b)
    69  			b.Add(&d, b)
    70  			return a.Equal(b) && a.Equal(&c) && b.Equal(&c)
    71  		},
    72  		genA,
    73  		genB,
    74  	))
    75  
    76  	properties.Property("[BW6-633] Having the receiver as operand (sub) should output the same result", prop.ForAll(
    77  		func(a, b *E6) bool {
    78  			var c, d E6
    79  			d.Set(a)
    80  			c.Sub(a, b)
    81  			a.Sub(a, b)
    82  			b.Sub(&d, b)
    83  			return a.Equal(b) && a.Equal(&c) && b.Equal(&c)
    84  		},
    85  		genA,
    86  		genB,
    87  	))
    88  
    89  	properties.Property("[BW6-633] Having the receiver as operand (mul) should output the same result", prop.ForAll(
    90  		func(a, b *E6) bool {
    91  			var c, d E6
    92  			d.Set(a)
    93  			c.Mul(a, b)
    94  			a.Mul(a, b)
    95  			b.Mul(&d, b)
    96  			return a.Equal(b) && a.Equal(&c) && b.Equal(&c)
    97  		},
    98  		genA,
    99  		genB,
   100  	))
   101  
   102  	properties.Property("[BW6-633] Having the receiver as operand (square) should output the same result", prop.ForAll(
   103  		func(a *E6) bool {
   104  			var b E6
   105  			b.Square(a)
   106  			a.Square(a)
   107  			return a.Equal(&b)
   108  		},
   109  		genA,
   110  	))
   111  
   112  	properties.Property("[BW6-633] Having the receiver as operand (double) should output the same result", prop.ForAll(
   113  		func(a *E6) bool {
   114  			var b E6
   115  			b.Double(a)
   116  			a.Double(a)
   117  			return a.Equal(&b)
   118  		},
   119  		genA,
   120  	))
   121  
   122  	properties.Property("[BW6-633] Having the receiver as operand (Inverse) should output the same result", prop.ForAll(
   123  		func(a *E6) bool {
   124  			var b E6
   125  			b.Inverse(a)
   126  			a.Inverse(a)
   127  			return a.Equal(&b)
   128  		},
   129  		genA,
   130  	))
   131  
   132  	properties.Property("[BW6-633] Having the receiver as operand (Cyclotomic square) should output the same result", prop.ForAll(
   133  		func(a *E6) bool {
   134  			var b E6
   135  			b.CyclotomicSquare(a)
   136  			a.CyclotomicSquare(a)
   137  			return a.Equal(&b)
   138  		},
   139  		genA,
   140  	))
   141  
   142  	properties.Property("[BW6-633] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll(
   143  		func(a *E6) bool {
   144  			var b E6
   145  			b.Conjugate(a)
   146  			a.Conjugate(a)
   147  			return a.Equal(&b)
   148  		},
   149  		genA,
   150  	))
   151  
   152  	properties.Property("[BW6-633] Having the receiver as operand (Frobenius) should output the same result", prop.ForAll(
   153  		func(a *E6) bool {
   154  			var b E6
   155  			b.Frobenius(a)
   156  			a.Frobenius(a)
   157  			return a.Equal(&b)
   158  		},
   159  		genA,
   160  	))
   161  
   162  	properties.TestingRun(t, gopter.ConsoleReporter(false))
   163  }
   164  
   165  func TestE6Ops(t *testing.T) {
   166  
   167  	parameters := gopter.DefaultTestParameters()
   168  	parameters.MinSuccessfulTests = 100
   169  
   170  	properties := gopter.NewProperties(parameters)
   171  
   172  	genA := GenE6()
   173  	genB := GenE6()
   174  	genExp := GenFp()
   175  
   176  	properties.Property("[BW6-633] sub & add should leave an element invariant", prop.ForAll(
   177  		func(a, b *E6) bool {
   178  			var c E6
   179  			c.Set(a)
   180  			c.Add(&c, b).Sub(&c, b)
   181  			return c.Equal(a)
   182  		},
   183  		genA,
   184  		genB,
   185  	))
   186  
   187  	properties.Property("[BW6-633] mul & inverse should leave an element invariant", prop.ForAll(
   188  		func(a, b *E6) bool {
   189  			var c, d E6
   190  			d.Inverse(b)
   191  			c.Set(a)
   192  			c.Mul(&c, b).Mul(&c, &d)
   193  			return c.Equal(a)
   194  		},
   195  		genA,
   196  		genB,
   197  	))
   198  
   199  	properties.Property("[BW6-633] inverse twice should leave an element invariant", prop.ForAll(
   200  		func(a *E6) bool {
   201  			var b E6
   202  			b.Inverse(a).Inverse(&b)
   203  			return a.Equal(&b)
   204  		},
   205  		genA,
   206  	))
   207  
   208  	properties.Property("[BW6-633] square and mul should output the same result", prop.ForAll(
   209  		func(a *E6) bool {
   210  			var b, c E6
   211  			b.Mul(a, a)
   212  			c.Square(a)
   213  			return b.Equal(&c)
   214  		},
   215  		genA,
   216  	))
   217  
   218  	properties.Property("[BW6-633] a + pi(a), a-pi(a) should be real", prop.ForAll(
   219  		func(a *E6) bool {
   220  			var b, c, d E6
   221  			var e, f, g E3
   222  			b.Conjugate(a)
   223  			c.Add(a, &b)
   224  			d.Sub(a, &b)
   225  			e.Double(&a.B0)
   226  			f.Double(&a.B1)
   227  			return c.B1.Equal(&g) && d.B0.Equal(&g) && e.Equal(&c.B0) && f.Equal(&d.B1)
   228  		},
   229  		genA,
   230  	))
   231  
   232  	properties.Property("[BW6-633] Torus-based Compress/decompress E6 elements in the cyclotomic subgroup", prop.ForAll(
   233  		func(a *E6) bool {
   234  			var b E6
   235  			b.Conjugate(a)
   236  			a.Inverse(a)
   237  			b.Mul(&b, a)
   238  			a.Frobenius(&b).Mul(a, &b)
   239  
   240  			c, _ := a.CompressTorus()
   241  			d := c.DecompressTorus()
   242  			return a.Equal(&d)
   243  		},
   244  		genA,
   245  	))
   246  
   247  	properties.Property("[BW6-633] Torus-based batch Compress/decompress E6 elements in the cyclotomic subgroup", prop.ForAll(
   248  		func(a, e, f *E6) bool {
   249  			var b E6
   250  			b.Conjugate(a)
   251  			a.Inverse(a)
   252  			b.Mul(&b, a)
   253  			a.Frobenius(&b).Mul(a, &b)
   254  
   255  			e.CyclotomicSquare(a)
   256  			f.CyclotomicSquare(e)
   257  
   258  			c, _ := BatchCompressTorus([]E6{*a, *e, *f})
   259  			d, _ := BatchDecompressTorus(c)
   260  			return a.Equal(&d[0]) && e.Equal(&d[1]) && f.Equal(&d[2])
   261  		},
   262  		genA,
   263  		genA,
   264  		genA,
   265  	))
   266  
   267  	properties.Property("[BW6-633] pi**12=id", prop.ForAll(
   268  		func(a *E6) bool {
   269  			var b E6
   270  			b.Frobenius(a).
   271  				Frobenius(&b).
   272  				Frobenius(&b).
   273  				Frobenius(&b).
   274  				Frobenius(&b).
   275  				Frobenius(&b).
   276  				Frobenius(&b).
   277  				Frobenius(&b).
   278  				Frobenius(&b).
   279  				Frobenius(&b).
   280  				Frobenius(&b).
   281  				Frobenius(&b)
   282  			return b.Equal(a)
   283  		},
   284  		genA,
   285  	))
   286  
   287  	properties.Property("[BW6-633] cyclotomic square (Granger-Scott) and square should be the same in the cyclotomic subgroup", prop.ForAll(
   288  		func(a *E6) bool {
   289  			var b, c, d E6
   290  			b.Conjugate(a)
   291  			a.Inverse(a)
   292  			b.Mul(&b, a)
   293  			a.Frobenius(&b).Mul(a, &b)
   294  			c.Square(a)
   295  			d.CyclotomicSquare(a)
   296  			return c.Equal(&d)
   297  		},
   298  		genA,
   299  	))
   300  
   301  	properties.Property("[BW6-633] compressed cyclotomic square (Karabina) and square should be the same in the cyclotomic subgroup", prop.ForAll(
   302  		func(a *E6) bool {
   303  			var b, c, d E6
   304  			b.Conjugate(a)
   305  			a.Inverse(a)
   306  			b.Mul(&b, a)
   307  			a.Frobenius(&b).Mul(a, &b)
   308  			c.Square(a)
   309  			d.CyclotomicSquareCompressed(a).DecompressKarabina(&d)
   310  			return c.Equal(&d)
   311  		},
   312  		genA,
   313  	))
   314  
   315  	properties.Property("[BW6-633] batch decompress and individual decompress (Karabina) should be the same", prop.ForAll(
   316  		func(a *E6) bool {
   317  			var _a, b E6
   318  			_a.SetOne().Double(&_a)
   319  
   320  			// put a and _a in the cyclotomic subgroup
   321  			// a (g3 !=0 probably)
   322  			b.Conjugate(a)
   323  			a.Inverse(a)
   324  			b.Mul(&b, a)
   325  			a.Frobenius(&b).Mul(a, &b)
   326  			// _a (g3 == 0)
   327  			b.Conjugate(&_a)
   328  			_a.Inverse(&_a)
   329  			b.Mul(&b, &_a)
   330  			_a.Frobenius(&b).Mul(&_a, &b)
   331  
   332  			var a2, a4, a17 E6
   333  			a2.Set(&_a)
   334  			a4.Set(a)
   335  			a17.Set(a)
   336  			a2.nSquareCompressed(2) // case g3 == 0
   337  			a4.nSquareCompressed(4)
   338  			a17.nSquareCompressed(17)
   339  			batch := BatchDecompressKarabina([]E6{a2, a4, a17})
   340  			a2.DecompressKarabina(&a2)
   341  			a4.DecompressKarabina(&a4)
   342  			a17.DecompressKarabina(&a17)
   343  
   344  			return a2.Equal(&batch[0]) && a4.Equal(&batch[1]) && a17.Equal(&batch[2])
   345  		},
   346  		genA,
   347  	))
   348  
   349  	properties.Property("[BW6-633] Exp and CyclotomicExp results must be the same in the cyclotomic subgroup", prop.ForAll(
   350  		func(a *E6, e fp.Element) bool {
   351  			var b, c, d E6
   352  			// put in the cyclo subgroup
   353  			b.Conjugate(a)
   354  			a.Inverse(a)
   355  			b.Mul(&b, a)
   356  			a.Frobenius(&b).Mul(a, &b)
   357  
   358  			var _e big.Int
   359  			k := new(big.Int).SetUint64(6)
   360  			e.Exp(e, k)
   361  			e.BigInt(&_e)
   362  
   363  			c.Exp(*a, &_e)
   364  			d.CyclotomicExp(*a, &_e)
   365  
   366  			return c.Equal(&d)
   367  		},
   368  		genA,
   369  		genExp,
   370  	))
   371  
   372  	properties.Property("[BW6-633] Frobenius of x in E6 should be equal to x^q", prop.ForAll(
   373  		func(a *E6) bool {
   374  			var b, c E6
   375  			q := fp.Modulus()
   376  			b.Frobenius(a)
   377  			c.Exp(*a, q)
   378  			return c.Equal(&b)
   379  		},
   380  		genA,
   381  	))
   382  
   383  	properties.TestingRun(t, gopter.ConsoleReporter(false))
   384  
   385  }
   386  
   387  // ------------------------------------------------------------
   388  // benches
   389  
   390  func BenchmarkE6Add(b *testing.B) {
   391  	var a, c E6
   392  	a.SetRandom()
   393  	c.SetRandom()
   394  	b.ResetTimer()
   395  	for i := 0; i < b.N; i++ {
   396  		a.Add(&a, &c)
   397  	}
   398  }
   399  
   400  func BenchmarkE6Sub(b *testing.B) {
   401  	var a, c E6
   402  	a.SetRandom()
   403  	c.SetRandom()
   404  	b.ResetTimer()
   405  	for i := 0; i < b.N; i++ {
   406  		a.Sub(&a, &c)
   407  	}
   408  }
   409  
   410  func BenchmarkE6Mul(b *testing.B) {
   411  	var a, c E6
   412  	a.SetRandom()
   413  	c.SetRandom()
   414  	b.ResetTimer()
   415  	for i := 0; i < b.N; i++ {
   416  		a.Mul(&a, &c)
   417  	}
   418  }
   419  
   420  func BenchmarkE6Cyclosquare(b *testing.B) {
   421  	var a E6
   422  	a.SetRandom()
   423  	b.ResetTimer()
   424  	for i := 0; i < b.N; i++ {
   425  		a.CyclotomicSquare(&a)
   426  	}
   427  }
   428  
   429  func BenchmarkE6Square(b *testing.B) {
   430  	var a E6
   431  	a.SetRandom()
   432  	b.ResetTimer()
   433  	for i := 0; i < b.N; i++ {
   434  		a.Square(&a)
   435  	}
   436  }
   437  
   438  func BenchmarkE6Inverse(b *testing.B) {
   439  	var a E6
   440  	a.SetRandom()
   441  	b.ResetTimer()
   442  	for i := 0; i < b.N; i++ {
   443  		a.Inverse(&a)
   444  	}
   445  }
   446  
   447  func BenchmarkE6Conjugate(b *testing.B) {
   448  	var a E6
   449  	a.SetRandom()
   450  	b.ResetTimer()
   451  	for i := 0; i < b.N; i++ {
   452  		a.Conjugate(&a)
   453  	}
   454  }
   455  
   456  func BenchmarkE6Frobenius(b *testing.B) {
   457  	var a E6
   458  	a.SetRandom()
   459  	b.ResetTimer()
   460  	for i := 0; i < b.N; i++ {
   461  		a.Frobenius(&a)
   462  	}
   463  }
   464  
   465  func BenchmarkE6Expt(b *testing.B) {
   466  	var a, c E6
   467  	a.SetRandom()
   468  	b.ResetTimer()
   469  	c.Conjugate(&a)
   470  	a.Inverse(&a)
   471  	c.Mul(&c, &a)
   472  
   473  	a.Frobenius(&c).
   474  		Mul(&a, &c)
   475  
   476  	for i := 0; i < b.N; i++ {
   477  		a.Expt(&a)
   478  	}
   479  }