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 }