github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-761/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-761/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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] 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-761] compressed cyclotomic square (Karabina) and square should be the same in the cyclotomic subgroup", prop.ForAll(
   302  		func(a *E6) bool {
   303  			var _a, b, c, d, _c, _d E6
   304  			_a.SetOne().Double(&_a)
   305  
   306  			// put a and _a in the cyclotomic subgroup
   307  			// a (g3 != 0 probably)
   308  			b.Conjugate(a)
   309  			a.Inverse(a)
   310  			b.Mul(&b, a)
   311  			a.Frobenius(&b).Mul(a, &b)
   312  			// _a (g3 == 0)
   313  			b.Conjugate(&_a)
   314  			_a.Inverse(&_a)
   315  			b.Mul(&b, &_a)
   316  			_a.Frobenius(&b).Mul(&_a, &b)
   317  
   318  			// case g3 != 0
   319  			c.Square(a)
   320  			d.CyclotomicSquareCompressed(a).DecompressKarabina(&d)
   321  
   322  			// case g3 == 0
   323  			_c.Square(&_a)
   324  			_d.CyclotomicSquareCompressed(&_a).DecompressKarabina(&_d)
   325  
   326  			return c.Equal(&d)
   327  		},
   328  		genA,
   329  	))
   330  
   331  	properties.Property("[BW6-761] Exp and CyclotomicExp results must be the same in the cyclotomic subgroup", prop.ForAll(
   332  		func(a *E6, e fp.Element) bool {
   333  			var b, c, d E6
   334  			// put in the cyclo subgroup
   335  			b.Conjugate(a)
   336  			a.Inverse(a)
   337  			b.Mul(&b, a)
   338  			a.Frobenius(&b).Mul(a, &b)
   339  
   340  			var _e big.Int
   341  			k := new(big.Int).SetUint64(6)
   342  			e.Exp(e, k)
   343  			e.BigInt(&_e)
   344  
   345  			c.Exp(*a, &_e)
   346  			d.CyclotomicExp(*a, &_e)
   347  
   348  			return c.Equal(&d)
   349  		},
   350  		genA,
   351  		genExp,
   352  	))
   353  
   354  	properties.Property("[BW6-761] Frobenius of x in E6 should be equal to x^q", prop.ForAll(
   355  		func(a *E6) bool {
   356  			var b, c E6
   357  			q := fp.Modulus()
   358  			b.Frobenius(a)
   359  			c.Exp(*a, q)
   360  			return c.Equal(&b)
   361  		},
   362  		genA,
   363  	))
   364  
   365  	properties.TestingRun(t, gopter.ConsoleReporter(false))
   366  
   367  }
   368  
   369  // ------------------------------------------------------------
   370  // benches
   371  
   372  func BenchmarkE6Add(b *testing.B) {
   373  	var a, c E6
   374  	a.SetRandom()
   375  	c.SetRandom()
   376  	b.ResetTimer()
   377  	for i := 0; i < b.N; i++ {
   378  		a.Add(&a, &c)
   379  	}
   380  }
   381  
   382  func BenchmarkE6Sub(b *testing.B) {
   383  	var a, c E6
   384  	a.SetRandom()
   385  	c.SetRandom()
   386  	b.ResetTimer()
   387  	for i := 0; i < b.N; i++ {
   388  		a.Sub(&a, &c)
   389  	}
   390  }
   391  
   392  func BenchmarkE6Mul(b *testing.B) {
   393  	var a, c E6
   394  	a.SetRandom()
   395  	c.SetRandom()
   396  	b.ResetTimer()
   397  	for i := 0; i < b.N; i++ {
   398  		a.Mul(&a, &c)
   399  	}
   400  }
   401  
   402  func BenchmarkE6Cyclosquare(b *testing.B) {
   403  	var a E6
   404  	a.SetRandom()
   405  	b.ResetTimer()
   406  	for i := 0; i < b.N; i++ {
   407  		a.CyclotomicSquare(&a)
   408  	}
   409  }
   410  
   411  func BenchmarkE6Square(b *testing.B) {
   412  	var a E6
   413  	a.SetRandom()
   414  	b.ResetTimer()
   415  	for i := 0; i < b.N; i++ {
   416  		a.Square(&a)
   417  	}
   418  }
   419  
   420  func BenchmarkE6Inverse(b *testing.B) {
   421  	var a E6
   422  	a.SetRandom()
   423  	b.ResetTimer()
   424  	for i := 0; i < b.N; i++ {
   425  		a.Inverse(&a)
   426  	}
   427  }
   428  
   429  func BenchmarkE6Conjugate(b *testing.B) {
   430  	var a E6
   431  	a.SetRandom()
   432  	b.ResetTimer()
   433  	for i := 0; i < b.N; i++ {
   434  		a.Conjugate(&a)
   435  	}
   436  }
   437  
   438  func BenchmarkE6Frobenius(b *testing.B) {
   439  	var a E6
   440  	a.SetRandom()
   441  	b.ResetTimer()
   442  	for i := 0; i < b.N; i++ {
   443  		a.Frobenius(&a)
   444  	}
   445  }
   446  
   447  func BenchmarkE6Expt(b *testing.B) {
   448  	var a, c E6
   449  	a.SetRandom()
   450  	b.ResetTimer()
   451  	c.Conjugate(&a)
   452  	a.Inverse(&a)
   453  	c.Mul(&c, &a)
   454  
   455  	a.Frobenius(&c).
   456  		Mul(&a, &c)
   457  
   458  	for i := 0; i < b.N; i++ {
   459  		a.Expt(&a)
   460  	}
   461  }