github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-756/fp/element_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 fp 18 19 import ( 20 "crypto/rand" 21 "encoding/json" 22 "fmt" 23 "math/big" 24 "math/bits" 25 26 mrand "math/rand" 27 28 "testing" 29 30 "github.com/leanovate/gopter" 31 ggen "github.com/leanovate/gopter/gen" 32 "github.com/leanovate/gopter/prop" 33 34 "github.com/stretchr/testify/require" 35 ) 36 37 // ------------------------------------------------------------------------------------------------- 38 // benchmarks 39 // most benchmarks are rudimentary and should sample a large number of random inputs 40 // or be run multiple times to ensure it didn't measure the fastest path of the function 41 42 var benchResElement Element 43 44 func BenchmarkElementSelect(b *testing.B) { 45 var x, y Element 46 x.SetRandom() 47 y.SetRandom() 48 49 b.ResetTimer() 50 for i := 0; i < b.N; i++ { 51 benchResElement.Select(i%3, &x, &y) 52 } 53 } 54 55 func BenchmarkElementSetRandom(b *testing.B) { 56 var x Element 57 x.SetRandom() 58 59 b.ResetTimer() 60 for i := 0; i < b.N; i++ { 61 _, _ = x.SetRandom() 62 } 63 } 64 65 func BenchmarkElementSetBytes(b *testing.B) { 66 var x Element 67 x.SetRandom() 68 bb := x.Bytes() 69 b.ResetTimer() 70 71 for i := 0; i < b.N; i++ { 72 benchResElement.SetBytes(bb[:]) 73 } 74 75 } 76 77 func BenchmarkElementMulByConstants(b *testing.B) { 78 b.Run("mulBy3", func(b *testing.B) { 79 benchResElement.SetRandom() 80 b.ResetTimer() 81 for i := 0; i < b.N; i++ { 82 MulBy3(&benchResElement) 83 } 84 }) 85 b.Run("mulBy5", func(b *testing.B) { 86 benchResElement.SetRandom() 87 b.ResetTimer() 88 for i := 0; i < b.N; i++ { 89 MulBy5(&benchResElement) 90 } 91 }) 92 b.Run("mulBy13", func(b *testing.B) { 93 benchResElement.SetRandom() 94 b.ResetTimer() 95 for i := 0; i < b.N; i++ { 96 MulBy13(&benchResElement) 97 } 98 }) 99 } 100 101 func BenchmarkElementInverse(b *testing.B) { 102 var x Element 103 x.SetRandom() 104 benchResElement.SetRandom() 105 b.ResetTimer() 106 107 for i := 0; i < b.N; i++ { 108 benchResElement.Inverse(&x) 109 } 110 111 } 112 113 func BenchmarkElementButterfly(b *testing.B) { 114 var x Element 115 x.SetRandom() 116 benchResElement.SetRandom() 117 b.ResetTimer() 118 for i := 0; i < b.N; i++ { 119 Butterfly(&x, &benchResElement) 120 } 121 } 122 123 func BenchmarkElementExp(b *testing.B) { 124 var x Element 125 x.SetRandom() 126 benchResElement.SetRandom() 127 b1, _ := rand.Int(rand.Reader, Modulus()) 128 b.ResetTimer() 129 for i := 0; i < b.N; i++ { 130 benchResElement.Exp(x, b1) 131 } 132 } 133 134 func BenchmarkElementDouble(b *testing.B) { 135 benchResElement.SetRandom() 136 b.ResetTimer() 137 for i := 0; i < b.N; i++ { 138 benchResElement.Double(&benchResElement) 139 } 140 } 141 142 func BenchmarkElementAdd(b *testing.B) { 143 var x Element 144 x.SetRandom() 145 benchResElement.SetRandom() 146 b.ResetTimer() 147 for i := 0; i < b.N; i++ { 148 benchResElement.Add(&x, &benchResElement) 149 } 150 } 151 152 func BenchmarkElementSub(b *testing.B) { 153 var x Element 154 x.SetRandom() 155 benchResElement.SetRandom() 156 b.ResetTimer() 157 for i := 0; i < b.N; i++ { 158 benchResElement.Sub(&x, &benchResElement) 159 } 160 } 161 162 func BenchmarkElementNeg(b *testing.B) { 163 benchResElement.SetRandom() 164 b.ResetTimer() 165 for i := 0; i < b.N; i++ { 166 benchResElement.Neg(&benchResElement) 167 } 168 } 169 170 func BenchmarkElementDiv(b *testing.B) { 171 var x Element 172 x.SetRandom() 173 benchResElement.SetRandom() 174 b.ResetTimer() 175 for i := 0; i < b.N; i++ { 176 benchResElement.Div(&x, &benchResElement) 177 } 178 } 179 180 func BenchmarkElementFromMont(b *testing.B) { 181 benchResElement.SetRandom() 182 b.ResetTimer() 183 for i := 0; i < b.N; i++ { 184 benchResElement.fromMont() 185 } 186 } 187 188 func BenchmarkElementSquare(b *testing.B) { 189 benchResElement.SetRandom() 190 b.ResetTimer() 191 for i := 0; i < b.N; i++ { 192 benchResElement.Square(&benchResElement) 193 } 194 } 195 196 func BenchmarkElementSqrt(b *testing.B) { 197 var a Element 198 a.SetUint64(4) 199 a.Neg(&a) 200 b.ResetTimer() 201 for i := 0; i < b.N; i++ { 202 benchResElement.Sqrt(&a) 203 } 204 } 205 206 func BenchmarkElementMul(b *testing.B) { 207 x := Element{ 208 11214533042317621956, 209 4418601975293183768, 210 2233550636059863627, 211 13772400071271951950, 212 13010224617750716256, 213 15582310590478290871, 214 6301429202206019695, 215 15624904615961126890, 216 14411832617204527559, 217 10495912060283172777, 218 8432856701560321958, 219 4166778949326216, 220 } 221 benchResElement.SetOne() 222 b.ResetTimer() 223 for i := 0; i < b.N; i++ { 224 benchResElement.Mul(&benchResElement, &x) 225 } 226 } 227 228 func BenchmarkElementCmp(b *testing.B) { 229 x := Element{ 230 11214533042317621956, 231 4418601975293183768, 232 2233550636059863627, 233 13772400071271951950, 234 13010224617750716256, 235 15582310590478290871, 236 6301429202206019695, 237 15624904615961126890, 238 14411832617204527559, 239 10495912060283172777, 240 8432856701560321958, 241 4166778949326216, 242 } 243 benchResElement = x 244 benchResElement[0] = 0 245 b.ResetTimer() 246 for i := 0; i < b.N; i++ { 247 benchResElement.Cmp(&x) 248 } 249 } 250 251 func TestElementCmp(t *testing.T) { 252 var x, y Element 253 254 if x.Cmp(&y) != 0 { 255 t.Fatal("x == y") 256 } 257 258 one := One() 259 y.Sub(&y, &one) 260 261 if x.Cmp(&y) != -1 { 262 t.Fatal("x < y") 263 } 264 if y.Cmp(&x) != 1 { 265 t.Fatal("x < y") 266 } 267 268 x = y 269 if x.Cmp(&y) != 0 { 270 t.Fatal("x == y") 271 } 272 273 x.Sub(&x, &one) 274 if x.Cmp(&y) != -1 { 275 t.Fatal("x < y") 276 } 277 if y.Cmp(&x) != 1 { 278 t.Fatal("x < y") 279 } 280 } 281 func TestElementIsRandom(t *testing.T) { 282 for i := 0; i < 50; i++ { 283 var x, y Element 284 x.SetRandom() 285 y.SetRandom() 286 if x.Equal(&y) { 287 t.Fatal("2 random numbers are unlikely to be equal") 288 } 289 } 290 } 291 292 func TestElementIsUint64(t *testing.T) { 293 t.Parallel() 294 parameters := gopter.DefaultTestParameters() 295 if testing.Short() { 296 parameters.MinSuccessfulTests = nbFuzzShort 297 } else { 298 parameters.MinSuccessfulTests = nbFuzz 299 } 300 301 properties := gopter.NewProperties(parameters) 302 303 properties.Property("reduce should output a result smaller than modulus", prop.ForAll( 304 func(v uint64) bool { 305 var e Element 306 e.SetUint64(v) 307 308 if !e.IsUint64() { 309 return false 310 } 311 312 return e.Uint64() == v 313 }, 314 ggen.UInt64(), 315 )) 316 317 properties.TestingRun(t, gopter.ConsoleReporter(false)) 318 } 319 320 func TestElementNegZero(t *testing.T) { 321 var a, b Element 322 b.SetZero() 323 for a.IsZero() { 324 a.SetRandom() 325 } 326 a.Neg(&b) 327 if !a.IsZero() { 328 t.Fatal("neg(0) != 0") 329 } 330 } 331 332 // ------------------------------------------------------------------------------------------------- 333 // Gopter tests 334 // most of them are generated with a template 335 336 const ( 337 nbFuzzShort = 20 338 nbFuzz = 100 339 ) 340 341 // special values to be used in tests 342 var staticTestValues []Element 343 344 func init() { 345 staticTestValues = append(staticTestValues, Element{}) // zero 346 staticTestValues = append(staticTestValues, One()) // one 347 staticTestValues = append(staticTestValues, rSquare) // r² 348 var e, one Element 349 one.SetOne() 350 e.Sub(&qElement, &one) 351 staticTestValues = append(staticTestValues, e) // q - 1 352 e.Double(&one) 353 staticTestValues = append(staticTestValues, e) // 2 354 355 { 356 a := qElement 357 a[0]-- 358 staticTestValues = append(staticTestValues, a) 359 } 360 staticTestValues = append(staticTestValues, Element{0}) 361 staticTestValues = append(staticTestValues, Element{0, 0}) 362 staticTestValues = append(staticTestValues, Element{1}) 363 staticTestValues = append(staticTestValues, Element{0, 1}) 364 staticTestValues = append(staticTestValues, Element{2}) 365 staticTestValues = append(staticTestValues, Element{0, 2}) 366 367 { 368 a := qElement 369 a[11]-- 370 staticTestValues = append(staticTestValues, a) 371 } 372 { 373 a := qElement 374 a[11]-- 375 a[0]++ 376 staticTestValues = append(staticTestValues, a) 377 } 378 379 { 380 a := qElement 381 a[11] = 0 382 staticTestValues = append(staticTestValues, a) 383 } 384 385 } 386 387 func TestElementReduce(t *testing.T) { 388 testValues := make([]Element, len(staticTestValues)) 389 copy(testValues, staticTestValues) 390 391 for i := range testValues { 392 s := testValues[i] 393 expected := s 394 reduce(&s) 395 _reduceGeneric(&expected) 396 if !s.Equal(&expected) { 397 t.Fatal("reduce failed: asm and generic impl don't match") 398 } 399 } 400 401 t.Parallel() 402 parameters := gopter.DefaultTestParameters() 403 if testing.Short() { 404 parameters.MinSuccessfulTests = nbFuzzShort 405 } else { 406 parameters.MinSuccessfulTests = nbFuzz 407 } 408 409 properties := gopter.NewProperties(parameters) 410 411 genA := genFull() 412 413 properties.Property("reduce should output a result smaller than modulus", prop.ForAll( 414 func(a Element) bool { 415 b := a 416 reduce(&a) 417 _reduceGeneric(&b) 418 return a.smallerThanModulus() && a.Equal(&b) 419 }, 420 genA, 421 )) 422 423 properties.TestingRun(t, gopter.ConsoleReporter(false)) 424 425 } 426 427 func TestElementEqual(t *testing.T) { 428 t.Parallel() 429 parameters := gopter.DefaultTestParameters() 430 if testing.Short() { 431 parameters.MinSuccessfulTests = nbFuzzShort 432 } else { 433 parameters.MinSuccessfulTests = nbFuzz 434 } 435 436 properties := gopter.NewProperties(parameters) 437 438 genA := gen() 439 genB := gen() 440 441 properties.Property("x.Equal(&y) iff x == y; likely false for random pairs", prop.ForAll( 442 func(a testPairElement, b testPairElement) bool { 443 return a.element.Equal(&b.element) == (a.element == b.element) 444 }, 445 genA, 446 genB, 447 )) 448 449 properties.Property("x.Equal(&y) if x == y", prop.ForAll( 450 func(a testPairElement) bool { 451 b := a.element 452 return a.element.Equal(&b) 453 }, 454 genA, 455 )) 456 457 properties.TestingRun(t, gopter.ConsoleReporter(false)) 458 } 459 460 func TestElementBytes(t *testing.T) { 461 t.Parallel() 462 parameters := gopter.DefaultTestParameters() 463 if testing.Short() { 464 parameters.MinSuccessfulTests = nbFuzzShort 465 } else { 466 parameters.MinSuccessfulTests = nbFuzz 467 } 468 469 properties := gopter.NewProperties(parameters) 470 471 genA := gen() 472 473 properties.Property("SetBytes(Bytes()) should stay constant", prop.ForAll( 474 func(a testPairElement) bool { 475 var b Element 476 bytes := a.element.Bytes() 477 b.SetBytes(bytes[:]) 478 return a.element.Equal(&b) 479 }, 480 genA, 481 )) 482 483 properties.TestingRun(t, gopter.ConsoleReporter(false)) 484 } 485 486 func TestElementInverseExp(t *testing.T) { 487 // inverse must be equal to exp^-2 488 exp := Modulus() 489 exp.Sub(exp, new(big.Int).SetUint64(2)) 490 491 invMatchExp := func(a testPairElement) bool { 492 var b Element 493 b.Set(&a.element) 494 a.element.Inverse(&a.element) 495 b.Exp(b, exp) 496 497 return a.element.Equal(&b) 498 } 499 500 t.Parallel() 501 parameters := gopter.DefaultTestParameters() 502 if testing.Short() { 503 parameters.MinSuccessfulTests = nbFuzzShort 504 } else { 505 parameters.MinSuccessfulTests = nbFuzz 506 } 507 properties := gopter.NewProperties(parameters) 508 genA := gen() 509 properties.Property("inv == exp^-2", prop.ForAll(invMatchExp, genA)) 510 properties.TestingRun(t, gopter.ConsoleReporter(false)) 511 512 parameters.MinSuccessfulTests = 1 513 properties = gopter.NewProperties(parameters) 514 properties.Property("inv(0) == 0", prop.ForAll(invMatchExp, ggen.OneConstOf(testPairElement{}))) 515 properties.TestingRun(t, gopter.ConsoleReporter(false)) 516 517 } 518 519 func mulByConstant(z *Element, c uint8) { 520 var y Element 521 y.SetUint64(uint64(c)) 522 z.Mul(z, &y) 523 } 524 525 func TestElementMulByConstants(t *testing.T) { 526 527 t.Parallel() 528 parameters := gopter.DefaultTestParameters() 529 if testing.Short() { 530 parameters.MinSuccessfulTests = nbFuzzShort 531 } else { 532 parameters.MinSuccessfulTests = nbFuzz 533 } 534 535 properties := gopter.NewProperties(parameters) 536 537 genA := gen() 538 539 implemented := []uint8{0, 1, 2, 3, 5, 13} 540 properties.Property("mulByConstant", prop.ForAll( 541 func(a testPairElement) bool { 542 for _, c := range implemented { 543 var constant Element 544 constant.SetUint64(uint64(c)) 545 546 b := a.element 547 b.Mul(&b, &constant) 548 549 aa := a.element 550 mulByConstant(&aa, c) 551 552 if !aa.Equal(&b) { 553 return false 554 } 555 } 556 557 return true 558 }, 559 genA, 560 )) 561 562 properties.Property("MulBy3(x) == Mul(x, 3)", prop.ForAll( 563 func(a testPairElement) bool { 564 var constant Element 565 constant.SetUint64(3) 566 567 b := a.element 568 b.Mul(&b, &constant) 569 570 MulBy3(&a.element) 571 572 return a.element.Equal(&b) 573 }, 574 genA, 575 )) 576 577 properties.Property("MulBy5(x) == Mul(x, 5)", prop.ForAll( 578 func(a testPairElement) bool { 579 var constant Element 580 constant.SetUint64(5) 581 582 b := a.element 583 b.Mul(&b, &constant) 584 585 MulBy5(&a.element) 586 587 return a.element.Equal(&b) 588 }, 589 genA, 590 )) 591 592 properties.Property("MulBy13(x) == Mul(x, 13)", prop.ForAll( 593 func(a testPairElement) bool { 594 var constant Element 595 constant.SetUint64(13) 596 597 b := a.element 598 b.Mul(&b, &constant) 599 600 MulBy13(&a.element) 601 602 return a.element.Equal(&b) 603 }, 604 genA, 605 )) 606 607 properties.TestingRun(t, gopter.ConsoleReporter(false)) 608 609 } 610 611 func TestElementLegendre(t *testing.T) { 612 t.Parallel() 613 parameters := gopter.DefaultTestParameters() 614 if testing.Short() { 615 parameters.MinSuccessfulTests = nbFuzzShort 616 } else { 617 parameters.MinSuccessfulTests = nbFuzz 618 } 619 620 properties := gopter.NewProperties(parameters) 621 622 genA := gen() 623 624 properties.Property("legendre should output same result than big.Int.Jacobi", prop.ForAll( 625 func(a testPairElement) bool { 626 return a.element.Legendre() == big.Jacobi(&a.bigint, Modulus()) 627 }, 628 genA, 629 )) 630 631 properties.TestingRun(t, gopter.ConsoleReporter(false)) 632 633 } 634 635 func TestElementBitLen(t *testing.T) { 636 t.Parallel() 637 parameters := gopter.DefaultTestParameters() 638 if testing.Short() { 639 parameters.MinSuccessfulTests = nbFuzzShort 640 } else { 641 parameters.MinSuccessfulTests = nbFuzz 642 } 643 644 properties := gopter.NewProperties(parameters) 645 646 genA := gen() 647 648 properties.Property("BitLen should output same result than big.Int.BitLen", prop.ForAll( 649 func(a testPairElement) bool { 650 return a.element.fromMont().BitLen() == a.bigint.BitLen() 651 }, 652 genA, 653 )) 654 655 properties.TestingRun(t, gopter.ConsoleReporter(false)) 656 657 } 658 659 func TestElementButterflies(t *testing.T) { 660 661 t.Parallel() 662 parameters := gopter.DefaultTestParameters() 663 if testing.Short() { 664 parameters.MinSuccessfulTests = nbFuzzShort 665 } else { 666 parameters.MinSuccessfulTests = nbFuzz 667 } 668 669 properties := gopter.NewProperties(parameters) 670 671 genA := gen() 672 673 properties.Property("butterfly0 == a -b; a +b", prop.ForAll( 674 func(a, b testPairElement) bool { 675 a0, b0 := a.element, b.element 676 677 _butterflyGeneric(&a.element, &b.element) 678 Butterfly(&a0, &b0) 679 680 return a.element.Equal(&a0) && b.element.Equal(&b0) 681 }, 682 genA, 683 genA, 684 )) 685 686 properties.TestingRun(t, gopter.ConsoleReporter(false)) 687 688 } 689 690 func TestElementLexicographicallyLargest(t *testing.T) { 691 t.Parallel() 692 parameters := gopter.DefaultTestParameters() 693 if testing.Short() { 694 parameters.MinSuccessfulTests = nbFuzzShort 695 } else { 696 parameters.MinSuccessfulTests = nbFuzz 697 } 698 699 properties := gopter.NewProperties(parameters) 700 701 genA := gen() 702 703 properties.Property("element.Cmp should match LexicographicallyLargest output", prop.ForAll( 704 func(a testPairElement) bool { 705 var negA Element 706 negA.Neg(&a.element) 707 708 cmpResult := a.element.Cmp(&negA) 709 lResult := a.element.LexicographicallyLargest() 710 711 if lResult && cmpResult == 1 { 712 return true 713 } 714 if !lResult && cmpResult != 1 { 715 return true 716 } 717 return false 718 }, 719 genA, 720 )) 721 722 properties.TestingRun(t, gopter.ConsoleReporter(false)) 723 724 } 725 726 func TestElementAdd(t *testing.T) { 727 t.Parallel() 728 parameters := gopter.DefaultTestParameters() 729 if testing.Short() { 730 parameters.MinSuccessfulTests = nbFuzzShort 731 } else { 732 parameters.MinSuccessfulTests = nbFuzz 733 } 734 735 properties := gopter.NewProperties(parameters) 736 737 genA := gen() 738 genB := gen() 739 740 properties.Property("Add: having the receiver as operand should output the same result", prop.ForAll( 741 func(a, b testPairElement) bool { 742 var c, d Element 743 d.Set(&a.element) 744 745 c.Add(&a.element, &b.element) 746 a.element.Add(&a.element, &b.element) 747 b.element.Add(&d, &b.element) 748 749 return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c) 750 }, 751 genA, 752 genB, 753 )) 754 755 properties.Property("Add: operation result must match big.Int result", prop.ForAll( 756 func(a, b testPairElement) bool { 757 { 758 var c Element 759 760 c.Add(&a.element, &b.element) 761 762 var d, e big.Int 763 d.Add(&a.bigint, &b.bigint).Mod(&d, Modulus()) 764 765 if c.BigInt(&e).Cmp(&d) != 0 { 766 return false 767 } 768 } 769 770 // fixed elements 771 // a is random 772 // r takes special values 773 testValues := make([]Element, len(staticTestValues)) 774 copy(testValues, staticTestValues) 775 776 for i := range testValues { 777 r := testValues[i] 778 var d, e, rb big.Int 779 r.BigInt(&rb) 780 781 var c Element 782 c.Add(&a.element, &r) 783 d.Add(&a.bigint, &rb).Mod(&d, Modulus()) 784 785 if c.BigInt(&e).Cmp(&d) != 0 { 786 return false 787 } 788 } 789 return true 790 }, 791 genA, 792 genB, 793 )) 794 795 properties.Property("Add: operation result must be smaller than modulus", prop.ForAll( 796 func(a, b testPairElement) bool { 797 var c Element 798 799 c.Add(&a.element, &b.element) 800 801 return c.smallerThanModulus() 802 }, 803 genA, 804 genB, 805 )) 806 807 specialValueTest := func() { 808 // test special values against special values 809 testValues := make([]Element, len(staticTestValues)) 810 copy(testValues, staticTestValues) 811 812 for i := range testValues { 813 a := testValues[i] 814 var aBig big.Int 815 a.BigInt(&aBig) 816 for j := range testValues { 817 b := testValues[j] 818 var bBig, d, e big.Int 819 b.BigInt(&bBig) 820 821 var c Element 822 c.Add(&a, &b) 823 d.Add(&aBig, &bBig).Mod(&d, Modulus()) 824 825 if c.BigInt(&e).Cmp(&d) != 0 { 826 t.Fatal("Add failed special test values") 827 } 828 } 829 } 830 } 831 832 properties.TestingRun(t, gopter.ConsoleReporter(false)) 833 specialValueTest() 834 835 } 836 837 func TestElementSub(t *testing.T) { 838 t.Parallel() 839 parameters := gopter.DefaultTestParameters() 840 if testing.Short() { 841 parameters.MinSuccessfulTests = nbFuzzShort 842 } else { 843 parameters.MinSuccessfulTests = nbFuzz 844 } 845 846 properties := gopter.NewProperties(parameters) 847 848 genA := gen() 849 genB := gen() 850 851 properties.Property("Sub: having the receiver as operand should output the same result", prop.ForAll( 852 func(a, b testPairElement) bool { 853 var c, d Element 854 d.Set(&a.element) 855 856 c.Sub(&a.element, &b.element) 857 a.element.Sub(&a.element, &b.element) 858 b.element.Sub(&d, &b.element) 859 860 return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c) 861 }, 862 genA, 863 genB, 864 )) 865 866 properties.Property("Sub: operation result must match big.Int result", prop.ForAll( 867 func(a, b testPairElement) bool { 868 { 869 var c Element 870 871 c.Sub(&a.element, &b.element) 872 873 var d, e big.Int 874 d.Sub(&a.bigint, &b.bigint).Mod(&d, Modulus()) 875 876 if c.BigInt(&e).Cmp(&d) != 0 { 877 return false 878 } 879 } 880 881 // fixed elements 882 // a is random 883 // r takes special values 884 testValues := make([]Element, len(staticTestValues)) 885 copy(testValues, staticTestValues) 886 887 for i := range testValues { 888 r := testValues[i] 889 var d, e, rb big.Int 890 r.BigInt(&rb) 891 892 var c Element 893 c.Sub(&a.element, &r) 894 d.Sub(&a.bigint, &rb).Mod(&d, Modulus()) 895 896 if c.BigInt(&e).Cmp(&d) != 0 { 897 return false 898 } 899 } 900 return true 901 }, 902 genA, 903 genB, 904 )) 905 906 properties.Property("Sub: operation result must be smaller than modulus", prop.ForAll( 907 func(a, b testPairElement) bool { 908 var c Element 909 910 c.Sub(&a.element, &b.element) 911 912 return c.smallerThanModulus() 913 }, 914 genA, 915 genB, 916 )) 917 918 specialValueTest := func() { 919 // test special values against special values 920 testValues := make([]Element, len(staticTestValues)) 921 copy(testValues, staticTestValues) 922 923 for i := range testValues { 924 a := testValues[i] 925 var aBig big.Int 926 a.BigInt(&aBig) 927 for j := range testValues { 928 b := testValues[j] 929 var bBig, d, e big.Int 930 b.BigInt(&bBig) 931 932 var c Element 933 c.Sub(&a, &b) 934 d.Sub(&aBig, &bBig).Mod(&d, Modulus()) 935 936 if c.BigInt(&e).Cmp(&d) != 0 { 937 t.Fatal("Sub failed special test values") 938 } 939 } 940 } 941 } 942 943 properties.TestingRun(t, gopter.ConsoleReporter(false)) 944 specialValueTest() 945 946 } 947 948 func TestElementMul(t *testing.T) { 949 t.Parallel() 950 parameters := gopter.DefaultTestParameters() 951 if testing.Short() { 952 parameters.MinSuccessfulTests = nbFuzzShort 953 } else { 954 parameters.MinSuccessfulTests = nbFuzz 955 } 956 957 properties := gopter.NewProperties(parameters) 958 959 genA := gen() 960 genB := gen() 961 962 properties.Property("Mul: having the receiver as operand should output the same result", prop.ForAll( 963 func(a, b testPairElement) bool { 964 var c, d Element 965 d.Set(&a.element) 966 967 c.Mul(&a.element, &b.element) 968 a.element.Mul(&a.element, &b.element) 969 b.element.Mul(&d, &b.element) 970 971 return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c) 972 }, 973 genA, 974 genB, 975 )) 976 977 properties.Property("Mul: operation result must match big.Int result", prop.ForAll( 978 func(a, b testPairElement) bool { 979 { 980 var c Element 981 982 c.Mul(&a.element, &b.element) 983 984 var d, e big.Int 985 d.Mul(&a.bigint, &b.bigint).Mod(&d, Modulus()) 986 987 if c.BigInt(&e).Cmp(&d) != 0 { 988 return false 989 } 990 } 991 992 // fixed elements 993 // a is random 994 // r takes special values 995 testValues := make([]Element, len(staticTestValues)) 996 copy(testValues, staticTestValues) 997 998 for i := range testValues { 999 r := testValues[i] 1000 var d, e, rb big.Int 1001 r.BigInt(&rb) 1002 1003 var c Element 1004 c.Mul(&a.element, &r) 1005 d.Mul(&a.bigint, &rb).Mod(&d, Modulus()) 1006 1007 // checking generic impl against asm path 1008 var cGeneric Element 1009 _mulGeneric(&cGeneric, &a.element, &r) 1010 if !cGeneric.Equal(&c) { 1011 // need to give context to failing error. 1012 return false 1013 } 1014 1015 if c.BigInt(&e).Cmp(&d) != 0 { 1016 return false 1017 } 1018 } 1019 return true 1020 }, 1021 genA, 1022 genB, 1023 )) 1024 1025 properties.Property("Mul: operation result must be smaller than modulus", prop.ForAll( 1026 func(a, b testPairElement) bool { 1027 var c Element 1028 1029 c.Mul(&a.element, &b.element) 1030 1031 return c.smallerThanModulus() 1032 }, 1033 genA, 1034 genB, 1035 )) 1036 1037 properties.Property("Mul: assembly implementation must be consistent with generic one", prop.ForAll( 1038 func(a, b testPairElement) bool { 1039 var c, d Element 1040 c.Mul(&a.element, &b.element) 1041 _mulGeneric(&d, &a.element, &b.element) 1042 return c.Equal(&d) 1043 }, 1044 genA, 1045 genB, 1046 )) 1047 1048 specialValueTest := func() { 1049 // test special values against special values 1050 testValues := make([]Element, len(staticTestValues)) 1051 copy(testValues, staticTestValues) 1052 1053 for i := range testValues { 1054 a := testValues[i] 1055 var aBig big.Int 1056 a.BigInt(&aBig) 1057 for j := range testValues { 1058 b := testValues[j] 1059 var bBig, d, e big.Int 1060 b.BigInt(&bBig) 1061 1062 var c Element 1063 c.Mul(&a, &b) 1064 d.Mul(&aBig, &bBig).Mod(&d, Modulus()) 1065 1066 // checking asm against generic impl 1067 var cGeneric Element 1068 _mulGeneric(&cGeneric, &a, &b) 1069 if !cGeneric.Equal(&c) { 1070 t.Fatal("Mul failed special test values: asm and generic impl don't match") 1071 } 1072 1073 if c.BigInt(&e).Cmp(&d) != 0 { 1074 t.Fatal("Mul failed special test values") 1075 } 1076 } 1077 } 1078 } 1079 1080 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1081 specialValueTest() 1082 1083 } 1084 1085 func TestElementDiv(t *testing.T) { 1086 t.Parallel() 1087 parameters := gopter.DefaultTestParameters() 1088 if testing.Short() { 1089 parameters.MinSuccessfulTests = nbFuzzShort 1090 } else { 1091 parameters.MinSuccessfulTests = nbFuzz 1092 } 1093 1094 properties := gopter.NewProperties(parameters) 1095 1096 genA := gen() 1097 genB := gen() 1098 1099 properties.Property("Div: having the receiver as operand should output the same result", prop.ForAll( 1100 func(a, b testPairElement) bool { 1101 var c, d Element 1102 d.Set(&a.element) 1103 1104 c.Div(&a.element, &b.element) 1105 a.element.Div(&a.element, &b.element) 1106 b.element.Div(&d, &b.element) 1107 1108 return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c) 1109 }, 1110 genA, 1111 genB, 1112 )) 1113 1114 properties.Property("Div: operation result must match big.Int result", prop.ForAll( 1115 func(a, b testPairElement) bool { 1116 { 1117 var c Element 1118 1119 c.Div(&a.element, &b.element) 1120 1121 var d, e big.Int 1122 d.ModInverse(&b.bigint, Modulus()) 1123 d.Mul(&d, &a.bigint).Mod(&d, Modulus()) 1124 1125 if c.BigInt(&e).Cmp(&d) != 0 { 1126 return false 1127 } 1128 } 1129 1130 // fixed elements 1131 // a is random 1132 // r takes special values 1133 testValues := make([]Element, len(staticTestValues)) 1134 copy(testValues, staticTestValues) 1135 1136 for i := range testValues { 1137 r := testValues[i] 1138 var d, e, rb big.Int 1139 r.BigInt(&rb) 1140 1141 var c Element 1142 c.Div(&a.element, &r) 1143 d.ModInverse(&rb, Modulus()) 1144 d.Mul(&d, &a.bigint).Mod(&d, Modulus()) 1145 1146 if c.BigInt(&e).Cmp(&d) != 0 { 1147 return false 1148 } 1149 } 1150 return true 1151 }, 1152 genA, 1153 genB, 1154 )) 1155 1156 properties.Property("Div: operation result must be smaller than modulus", prop.ForAll( 1157 func(a, b testPairElement) bool { 1158 var c Element 1159 1160 c.Div(&a.element, &b.element) 1161 1162 return c.smallerThanModulus() 1163 }, 1164 genA, 1165 genB, 1166 )) 1167 1168 specialValueTest := func() { 1169 // test special values against special values 1170 testValues := make([]Element, len(staticTestValues)) 1171 copy(testValues, staticTestValues) 1172 1173 for i := range testValues { 1174 a := testValues[i] 1175 var aBig big.Int 1176 a.BigInt(&aBig) 1177 for j := range testValues { 1178 b := testValues[j] 1179 var bBig, d, e big.Int 1180 b.BigInt(&bBig) 1181 1182 var c Element 1183 c.Div(&a, &b) 1184 d.ModInverse(&bBig, Modulus()) 1185 d.Mul(&d, &aBig).Mod(&d, Modulus()) 1186 1187 if c.BigInt(&e).Cmp(&d) != 0 { 1188 t.Fatal("Div failed special test values") 1189 } 1190 } 1191 } 1192 } 1193 1194 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1195 specialValueTest() 1196 1197 } 1198 1199 func TestElementExp(t *testing.T) { 1200 t.Parallel() 1201 parameters := gopter.DefaultTestParameters() 1202 if testing.Short() { 1203 parameters.MinSuccessfulTests = nbFuzzShort 1204 } else { 1205 parameters.MinSuccessfulTests = nbFuzz 1206 } 1207 1208 properties := gopter.NewProperties(parameters) 1209 1210 genA := gen() 1211 genB := gen() 1212 1213 properties.Property("Exp: having the receiver as operand should output the same result", prop.ForAll( 1214 func(a, b testPairElement) bool { 1215 var c, d Element 1216 d.Set(&a.element) 1217 1218 c.Exp(a.element, &b.bigint) 1219 a.element.Exp(a.element, &b.bigint) 1220 b.element.Exp(d, &b.bigint) 1221 1222 return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c) 1223 }, 1224 genA, 1225 genB, 1226 )) 1227 1228 properties.Property("Exp: operation result must match big.Int result", prop.ForAll( 1229 func(a, b testPairElement) bool { 1230 { 1231 var c Element 1232 1233 c.Exp(a.element, &b.bigint) 1234 1235 var d, e big.Int 1236 d.Exp(&a.bigint, &b.bigint, Modulus()) 1237 1238 if c.BigInt(&e).Cmp(&d) != 0 { 1239 return false 1240 } 1241 } 1242 1243 // fixed elements 1244 // a is random 1245 // r takes special values 1246 testValues := make([]Element, len(staticTestValues)) 1247 copy(testValues, staticTestValues) 1248 1249 for i := range testValues { 1250 r := testValues[i] 1251 var d, e, rb big.Int 1252 r.BigInt(&rb) 1253 1254 var c Element 1255 c.Exp(a.element, &rb) 1256 d.Exp(&a.bigint, &rb, Modulus()) 1257 1258 if c.BigInt(&e).Cmp(&d) != 0 { 1259 return false 1260 } 1261 } 1262 return true 1263 }, 1264 genA, 1265 genB, 1266 )) 1267 1268 properties.Property("Exp: operation result must be smaller than modulus", prop.ForAll( 1269 func(a, b testPairElement) bool { 1270 var c Element 1271 1272 c.Exp(a.element, &b.bigint) 1273 1274 return c.smallerThanModulus() 1275 }, 1276 genA, 1277 genB, 1278 )) 1279 1280 specialValueTest := func() { 1281 // test special values against special values 1282 testValues := make([]Element, len(staticTestValues)) 1283 copy(testValues, staticTestValues) 1284 1285 for i := range testValues { 1286 a := testValues[i] 1287 var aBig big.Int 1288 a.BigInt(&aBig) 1289 for j := range testValues { 1290 b := testValues[j] 1291 var bBig, d, e big.Int 1292 b.BigInt(&bBig) 1293 1294 var c Element 1295 c.Exp(a, &bBig) 1296 d.Exp(&aBig, &bBig, Modulus()) 1297 1298 if c.BigInt(&e).Cmp(&d) != 0 { 1299 t.Fatal("Exp failed special test values") 1300 } 1301 } 1302 } 1303 } 1304 1305 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1306 specialValueTest() 1307 1308 } 1309 1310 func TestElementSquare(t *testing.T) { 1311 t.Parallel() 1312 parameters := gopter.DefaultTestParameters() 1313 if testing.Short() { 1314 parameters.MinSuccessfulTests = nbFuzzShort 1315 } else { 1316 parameters.MinSuccessfulTests = nbFuzz 1317 } 1318 1319 properties := gopter.NewProperties(parameters) 1320 1321 genA := gen() 1322 1323 properties.Property("Square: having the receiver as operand should output the same result", prop.ForAll( 1324 func(a testPairElement) bool { 1325 1326 var b Element 1327 1328 b.Square(&a.element) 1329 a.element.Square(&a.element) 1330 return a.element.Equal(&b) 1331 }, 1332 genA, 1333 )) 1334 1335 properties.Property("Square: operation result must match big.Int result", prop.ForAll( 1336 func(a testPairElement) bool { 1337 var c Element 1338 c.Square(&a.element) 1339 1340 var d, e big.Int 1341 d.Mul(&a.bigint, &a.bigint).Mod(&d, Modulus()) 1342 1343 return c.BigInt(&e).Cmp(&d) == 0 1344 }, 1345 genA, 1346 )) 1347 1348 properties.Property("Square: operation result must be smaller than modulus", prop.ForAll( 1349 func(a testPairElement) bool { 1350 var c Element 1351 c.Square(&a.element) 1352 return c.smallerThanModulus() 1353 }, 1354 genA, 1355 )) 1356 1357 specialValueTest := func() { 1358 // test special values 1359 testValues := make([]Element, len(staticTestValues)) 1360 copy(testValues, staticTestValues) 1361 1362 for i := range testValues { 1363 a := testValues[i] 1364 var aBig big.Int 1365 a.BigInt(&aBig) 1366 var c Element 1367 c.Square(&a) 1368 1369 var d, e big.Int 1370 d.Mul(&aBig, &aBig).Mod(&d, Modulus()) 1371 1372 if c.BigInt(&e).Cmp(&d) != 0 { 1373 t.Fatal("Square failed special test values") 1374 } 1375 } 1376 } 1377 1378 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1379 specialValueTest() 1380 1381 } 1382 1383 func TestElementInverse(t *testing.T) { 1384 t.Parallel() 1385 parameters := gopter.DefaultTestParameters() 1386 if testing.Short() { 1387 parameters.MinSuccessfulTests = nbFuzzShort 1388 } else { 1389 parameters.MinSuccessfulTests = nbFuzz 1390 } 1391 1392 properties := gopter.NewProperties(parameters) 1393 1394 genA := gen() 1395 1396 properties.Property("Inverse: having the receiver as operand should output the same result", prop.ForAll( 1397 func(a testPairElement) bool { 1398 1399 var b Element 1400 1401 b.Inverse(&a.element) 1402 a.element.Inverse(&a.element) 1403 return a.element.Equal(&b) 1404 }, 1405 genA, 1406 )) 1407 1408 properties.Property("Inverse: operation result must match big.Int result", prop.ForAll( 1409 func(a testPairElement) bool { 1410 var c Element 1411 c.Inverse(&a.element) 1412 1413 var d, e big.Int 1414 d.ModInverse(&a.bigint, Modulus()) 1415 1416 return c.BigInt(&e).Cmp(&d) == 0 1417 }, 1418 genA, 1419 )) 1420 1421 properties.Property("Inverse: operation result must be smaller than modulus", prop.ForAll( 1422 func(a testPairElement) bool { 1423 var c Element 1424 c.Inverse(&a.element) 1425 return c.smallerThanModulus() 1426 }, 1427 genA, 1428 )) 1429 1430 specialValueTest := func() { 1431 // test special values 1432 testValues := make([]Element, len(staticTestValues)) 1433 copy(testValues, staticTestValues) 1434 1435 for i := range testValues { 1436 a := testValues[i] 1437 var aBig big.Int 1438 a.BigInt(&aBig) 1439 var c Element 1440 c.Inverse(&a) 1441 1442 var d, e big.Int 1443 d.ModInverse(&aBig, Modulus()) 1444 1445 if c.BigInt(&e).Cmp(&d) != 0 { 1446 t.Fatal("Inverse failed special test values") 1447 } 1448 } 1449 } 1450 1451 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1452 specialValueTest() 1453 1454 } 1455 1456 func TestElementSqrt(t *testing.T) { 1457 t.Parallel() 1458 parameters := gopter.DefaultTestParameters() 1459 if testing.Short() { 1460 parameters.MinSuccessfulTests = nbFuzzShort 1461 } else { 1462 parameters.MinSuccessfulTests = nbFuzz 1463 } 1464 1465 properties := gopter.NewProperties(parameters) 1466 1467 genA := gen() 1468 1469 properties.Property("Sqrt: having the receiver as operand should output the same result", prop.ForAll( 1470 func(a testPairElement) bool { 1471 1472 b := a.element 1473 1474 b.Sqrt(&a.element) 1475 a.element.Sqrt(&a.element) 1476 return a.element.Equal(&b) 1477 }, 1478 genA, 1479 )) 1480 1481 properties.Property("Sqrt: operation result must match big.Int result", prop.ForAll( 1482 func(a testPairElement) bool { 1483 var c Element 1484 c.Sqrt(&a.element) 1485 1486 var d, e big.Int 1487 d.ModSqrt(&a.bigint, Modulus()) 1488 1489 return c.BigInt(&e).Cmp(&d) == 0 1490 }, 1491 genA, 1492 )) 1493 1494 properties.Property("Sqrt: operation result must be smaller than modulus", prop.ForAll( 1495 func(a testPairElement) bool { 1496 var c Element 1497 c.Sqrt(&a.element) 1498 return c.smallerThanModulus() 1499 }, 1500 genA, 1501 )) 1502 1503 specialValueTest := func() { 1504 // test special values 1505 testValues := make([]Element, len(staticTestValues)) 1506 copy(testValues, staticTestValues) 1507 1508 for i := range testValues { 1509 a := testValues[i] 1510 var aBig big.Int 1511 a.BigInt(&aBig) 1512 var c Element 1513 c.Sqrt(&a) 1514 1515 var d, e big.Int 1516 d.ModSqrt(&aBig, Modulus()) 1517 1518 if c.BigInt(&e).Cmp(&d) != 0 { 1519 t.Fatal("Sqrt failed special test values") 1520 } 1521 } 1522 } 1523 1524 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1525 specialValueTest() 1526 1527 } 1528 1529 func TestElementDouble(t *testing.T) { 1530 t.Parallel() 1531 parameters := gopter.DefaultTestParameters() 1532 if testing.Short() { 1533 parameters.MinSuccessfulTests = nbFuzzShort 1534 } else { 1535 parameters.MinSuccessfulTests = nbFuzz 1536 } 1537 1538 properties := gopter.NewProperties(parameters) 1539 1540 genA := gen() 1541 1542 properties.Property("Double: having the receiver as operand should output the same result", prop.ForAll( 1543 func(a testPairElement) bool { 1544 1545 var b Element 1546 1547 b.Double(&a.element) 1548 a.element.Double(&a.element) 1549 return a.element.Equal(&b) 1550 }, 1551 genA, 1552 )) 1553 1554 properties.Property("Double: operation result must match big.Int result", prop.ForAll( 1555 func(a testPairElement) bool { 1556 var c Element 1557 c.Double(&a.element) 1558 1559 var d, e big.Int 1560 d.Lsh(&a.bigint, 1).Mod(&d, Modulus()) 1561 1562 return c.BigInt(&e).Cmp(&d) == 0 1563 }, 1564 genA, 1565 )) 1566 1567 properties.Property("Double: operation result must be smaller than modulus", prop.ForAll( 1568 func(a testPairElement) bool { 1569 var c Element 1570 c.Double(&a.element) 1571 return c.smallerThanModulus() 1572 }, 1573 genA, 1574 )) 1575 1576 specialValueTest := func() { 1577 // test special values 1578 testValues := make([]Element, len(staticTestValues)) 1579 copy(testValues, staticTestValues) 1580 1581 for i := range testValues { 1582 a := testValues[i] 1583 var aBig big.Int 1584 a.BigInt(&aBig) 1585 var c Element 1586 c.Double(&a) 1587 1588 var d, e big.Int 1589 d.Lsh(&aBig, 1).Mod(&d, Modulus()) 1590 1591 if c.BigInt(&e).Cmp(&d) != 0 { 1592 t.Fatal("Double failed special test values") 1593 } 1594 } 1595 } 1596 1597 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1598 specialValueTest() 1599 1600 } 1601 1602 func TestElementNeg(t *testing.T) { 1603 t.Parallel() 1604 parameters := gopter.DefaultTestParameters() 1605 if testing.Short() { 1606 parameters.MinSuccessfulTests = nbFuzzShort 1607 } else { 1608 parameters.MinSuccessfulTests = nbFuzz 1609 } 1610 1611 properties := gopter.NewProperties(parameters) 1612 1613 genA := gen() 1614 1615 properties.Property("Neg: having the receiver as operand should output the same result", prop.ForAll( 1616 func(a testPairElement) bool { 1617 1618 var b Element 1619 1620 b.Neg(&a.element) 1621 a.element.Neg(&a.element) 1622 return a.element.Equal(&b) 1623 }, 1624 genA, 1625 )) 1626 1627 properties.Property("Neg: operation result must match big.Int result", prop.ForAll( 1628 func(a testPairElement) bool { 1629 var c Element 1630 c.Neg(&a.element) 1631 1632 var d, e big.Int 1633 d.Neg(&a.bigint).Mod(&d, Modulus()) 1634 1635 return c.BigInt(&e).Cmp(&d) == 0 1636 }, 1637 genA, 1638 )) 1639 1640 properties.Property("Neg: operation result must be smaller than modulus", prop.ForAll( 1641 func(a testPairElement) bool { 1642 var c Element 1643 c.Neg(&a.element) 1644 return c.smallerThanModulus() 1645 }, 1646 genA, 1647 )) 1648 1649 specialValueTest := func() { 1650 // test special values 1651 testValues := make([]Element, len(staticTestValues)) 1652 copy(testValues, staticTestValues) 1653 1654 for i := range testValues { 1655 a := testValues[i] 1656 var aBig big.Int 1657 a.BigInt(&aBig) 1658 var c Element 1659 c.Neg(&a) 1660 1661 var d, e big.Int 1662 d.Neg(&aBig).Mod(&d, Modulus()) 1663 1664 if c.BigInt(&e).Cmp(&d) != 0 { 1665 t.Fatal("Neg failed special test values") 1666 } 1667 } 1668 } 1669 1670 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1671 specialValueTest() 1672 1673 } 1674 1675 func TestElementFixedExp(t *testing.T) { 1676 1677 t.Parallel() 1678 parameters := gopter.DefaultTestParameters() 1679 if testing.Short() { 1680 parameters.MinSuccessfulTests = nbFuzzShort 1681 } else { 1682 parameters.MinSuccessfulTests = nbFuzz 1683 } 1684 1685 properties := gopter.NewProperties(parameters) 1686 1687 var ( 1688 _bLegendreExponentElement *big.Int 1689 _bSqrtExponentElement *big.Int 1690 ) 1691 1692 _bLegendreExponentElement, _ = new(big.Int).SetString("7bb56ddaddcc57156093f0f1ab467ae4bc6697d616744fdf91910a2a8b1d366635739e215236cf581640975027d55053f58e59e8373237149668af6db2352a181551e12c6f3ef685b42f43429276019e3f31fc34200000000000000000000", 16) 1693 const sqrtExponentElement = "1eed5b76b77315c55824fc3c6ad19eb92f19a5f5859d13f7e464428aa2c74d998d5ce788548db3d6059025d409f55414fd63967a0dcc8dc5259a2bdb6c8d4a860554784b1bcfbda16d0bd0d0a49d80678fcc7f0d0" 1694 _bSqrtExponentElement, _ = new(big.Int).SetString(sqrtExponentElement, 16) 1695 1696 genA := gen() 1697 1698 properties.Property(fmt.Sprintf("expBySqrtExp must match Exp(%s)", sqrtExponentElement), prop.ForAll( 1699 func(a testPairElement) bool { 1700 c := a.element 1701 d := a.element 1702 c.expBySqrtExp(c) 1703 d.Exp(d, _bSqrtExponentElement) 1704 return c.Equal(&d) 1705 }, 1706 genA, 1707 )) 1708 1709 properties.Property("expByLegendreExp must match Exp(7bb56ddaddcc57156093f0f1ab467ae4bc6697d616744fdf91910a2a8b1d366635739e215236cf581640975027d55053f58e59e8373237149668af6db2352a181551e12c6f3ef685b42f43429276019e3f31fc34200000000000000000000)", prop.ForAll( 1710 func(a testPairElement) bool { 1711 c := a.element 1712 d := a.element 1713 c.expByLegendreExp(c) 1714 d.Exp(d, _bLegendreExponentElement) 1715 return c.Equal(&d) 1716 }, 1717 genA, 1718 )) 1719 1720 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1721 } 1722 1723 func TestElementHalve(t *testing.T) { 1724 1725 t.Parallel() 1726 parameters := gopter.DefaultTestParameters() 1727 if testing.Short() { 1728 parameters.MinSuccessfulTests = nbFuzzShort 1729 } else { 1730 parameters.MinSuccessfulTests = nbFuzz 1731 } 1732 1733 properties := gopter.NewProperties(parameters) 1734 1735 genA := gen() 1736 var twoInv Element 1737 twoInv.SetUint64(2) 1738 twoInv.Inverse(&twoInv) 1739 1740 properties.Property("z.Halve must match z / 2", prop.ForAll( 1741 func(a testPairElement) bool { 1742 c := a.element 1743 d := a.element 1744 c.Halve() 1745 d.Mul(&d, &twoInv) 1746 return c.Equal(&d) 1747 }, 1748 genA, 1749 )) 1750 1751 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1752 } 1753 1754 func combineSelectionArguments(c int64, z int8) int { 1755 if z%3 == 0 { 1756 return 0 1757 } 1758 return int(c) 1759 } 1760 1761 func TestElementSelect(t *testing.T) { 1762 t.Parallel() 1763 parameters := gopter.DefaultTestParameters() 1764 if testing.Short() { 1765 parameters.MinSuccessfulTests = nbFuzzShort 1766 } else { 1767 parameters.MinSuccessfulTests = nbFuzz 1768 } 1769 1770 properties := gopter.NewProperties(parameters) 1771 1772 genA := genFull() 1773 genB := genFull() 1774 genC := ggen.Int64() //the condition 1775 genZ := ggen.Int8() //to make zeros artificially more likely 1776 1777 properties.Property("Select: must select correctly", prop.ForAll( 1778 func(a, b Element, cond int64, z int8) bool { 1779 condC := combineSelectionArguments(cond, z) 1780 1781 var c Element 1782 c.Select(condC, &a, &b) 1783 1784 if condC == 0 { 1785 return c.Equal(&a) 1786 } 1787 return c.Equal(&b) 1788 }, 1789 genA, 1790 genB, 1791 genC, 1792 genZ, 1793 )) 1794 1795 properties.Property("Select: having the receiver as operand should output the same result", prop.ForAll( 1796 func(a, b Element, cond int64, z int8) bool { 1797 condC := combineSelectionArguments(cond, z) 1798 1799 var c, d Element 1800 d.Set(&a) 1801 c.Select(condC, &a, &b) 1802 a.Select(condC, &a, &b) 1803 b.Select(condC, &d, &b) 1804 return a.Equal(&b) && a.Equal(&c) && b.Equal(&c) 1805 }, 1806 genA, 1807 genB, 1808 genC, 1809 genZ, 1810 )) 1811 1812 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1813 } 1814 1815 func TestElementSetInt64(t *testing.T) { 1816 1817 t.Parallel() 1818 parameters := gopter.DefaultTestParameters() 1819 if testing.Short() { 1820 parameters.MinSuccessfulTests = nbFuzzShort 1821 } else { 1822 parameters.MinSuccessfulTests = nbFuzz 1823 } 1824 1825 properties := gopter.NewProperties(parameters) 1826 1827 genA := gen() 1828 1829 properties.Property("z.SetInt64 must match z.SetString", prop.ForAll( 1830 func(a testPairElement, v int64) bool { 1831 c := a.element 1832 d := a.element 1833 1834 c.SetInt64(v) 1835 d.SetString(fmt.Sprintf("%v", v)) 1836 1837 return c.Equal(&d) 1838 }, 1839 genA, ggen.Int64(), 1840 )) 1841 1842 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1843 } 1844 1845 func TestElementSetInterface(t *testing.T) { 1846 1847 t.Parallel() 1848 parameters := gopter.DefaultTestParameters() 1849 if testing.Short() { 1850 parameters.MinSuccessfulTests = nbFuzzShort 1851 } else { 1852 parameters.MinSuccessfulTests = nbFuzz 1853 } 1854 1855 properties := gopter.NewProperties(parameters) 1856 1857 genA := gen() 1858 genInt := ggen.Int 1859 genInt8 := ggen.Int8 1860 genInt16 := ggen.Int16 1861 genInt32 := ggen.Int32 1862 genInt64 := ggen.Int64 1863 1864 genUint := ggen.UInt 1865 genUint8 := ggen.UInt8 1866 genUint16 := ggen.UInt16 1867 genUint32 := ggen.UInt32 1868 genUint64 := ggen.UInt64 1869 1870 properties.Property("z.SetInterface must match z.SetString with int8", prop.ForAll( 1871 func(a testPairElement, v int8) bool { 1872 c := a.element 1873 d := a.element 1874 1875 c.SetInterface(v) 1876 d.SetString(fmt.Sprintf("%v", v)) 1877 1878 return c.Equal(&d) 1879 }, 1880 genA, genInt8(), 1881 )) 1882 1883 properties.Property("z.SetInterface must match z.SetString with int16", prop.ForAll( 1884 func(a testPairElement, v int16) bool { 1885 c := a.element 1886 d := a.element 1887 1888 c.SetInterface(v) 1889 d.SetString(fmt.Sprintf("%v", v)) 1890 1891 return c.Equal(&d) 1892 }, 1893 genA, genInt16(), 1894 )) 1895 1896 properties.Property("z.SetInterface must match z.SetString with int32", prop.ForAll( 1897 func(a testPairElement, v int32) bool { 1898 c := a.element 1899 d := a.element 1900 1901 c.SetInterface(v) 1902 d.SetString(fmt.Sprintf("%v", v)) 1903 1904 return c.Equal(&d) 1905 }, 1906 genA, genInt32(), 1907 )) 1908 1909 properties.Property("z.SetInterface must match z.SetString with int64", prop.ForAll( 1910 func(a testPairElement, v int64) bool { 1911 c := a.element 1912 d := a.element 1913 1914 c.SetInterface(v) 1915 d.SetString(fmt.Sprintf("%v", v)) 1916 1917 return c.Equal(&d) 1918 }, 1919 genA, genInt64(), 1920 )) 1921 1922 properties.Property("z.SetInterface must match z.SetString with int", prop.ForAll( 1923 func(a testPairElement, v int) bool { 1924 c := a.element 1925 d := a.element 1926 1927 c.SetInterface(v) 1928 d.SetString(fmt.Sprintf("%v", v)) 1929 1930 return c.Equal(&d) 1931 }, 1932 genA, genInt(), 1933 )) 1934 1935 properties.Property("z.SetInterface must match z.SetString with uint8", prop.ForAll( 1936 func(a testPairElement, v uint8) bool { 1937 c := a.element 1938 d := a.element 1939 1940 c.SetInterface(v) 1941 d.SetString(fmt.Sprintf("%v", v)) 1942 1943 return c.Equal(&d) 1944 }, 1945 genA, genUint8(), 1946 )) 1947 1948 properties.Property("z.SetInterface must match z.SetString with uint16", prop.ForAll( 1949 func(a testPairElement, v uint16) bool { 1950 c := a.element 1951 d := a.element 1952 1953 c.SetInterface(v) 1954 d.SetString(fmt.Sprintf("%v", v)) 1955 1956 return c.Equal(&d) 1957 }, 1958 genA, genUint16(), 1959 )) 1960 1961 properties.Property("z.SetInterface must match z.SetString with uint32", prop.ForAll( 1962 func(a testPairElement, v uint32) bool { 1963 c := a.element 1964 d := a.element 1965 1966 c.SetInterface(v) 1967 d.SetString(fmt.Sprintf("%v", v)) 1968 1969 return c.Equal(&d) 1970 }, 1971 genA, genUint32(), 1972 )) 1973 1974 properties.Property("z.SetInterface must match z.SetString with uint64", prop.ForAll( 1975 func(a testPairElement, v uint64) bool { 1976 c := a.element 1977 d := a.element 1978 1979 c.SetInterface(v) 1980 d.SetString(fmt.Sprintf("%v", v)) 1981 1982 return c.Equal(&d) 1983 }, 1984 genA, genUint64(), 1985 )) 1986 1987 properties.Property("z.SetInterface must match z.SetString with uint", prop.ForAll( 1988 func(a testPairElement, v uint) bool { 1989 c := a.element 1990 d := a.element 1991 1992 c.SetInterface(v) 1993 d.SetString(fmt.Sprintf("%v", v)) 1994 1995 return c.Equal(&d) 1996 }, 1997 genA, genUint(), 1998 )) 1999 2000 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2001 2002 { 2003 assert := require.New(t) 2004 var e Element 2005 r, err := e.SetInterface(nil) 2006 assert.Nil(r) 2007 assert.Error(err) 2008 2009 var ptE *Element 2010 var ptB *big.Int 2011 2012 r, err = e.SetInterface(ptE) 2013 assert.Nil(r) 2014 assert.Error(err) 2015 ptE = new(Element).SetOne() 2016 r, err = e.SetInterface(ptE) 2017 assert.NoError(err) 2018 assert.True(r.IsOne()) 2019 2020 r, err = e.SetInterface(ptB) 2021 assert.Nil(r) 2022 assert.Error(err) 2023 2024 } 2025 } 2026 2027 func TestElementNegativeExp(t *testing.T) { 2028 t.Parallel() 2029 2030 parameters := gopter.DefaultTestParameters() 2031 if testing.Short() { 2032 parameters.MinSuccessfulTests = nbFuzzShort 2033 } else { 2034 parameters.MinSuccessfulTests = nbFuzz 2035 } 2036 2037 properties := gopter.NewProperties(parameters) 2038 2039 genA := gen() 2040 2041 properties.Property("x⁻ᵏ == 1/xᵏ", prop.ForAll( 2042 func(a, b testPairElement) bool { 2043 2044 var nb, d, e big.Int 2045 nb.Neg(&b.bigint) 2046 2047 var c Element 2048 c.Exp(a.element, &nb) 2049 2050 d.Exp(&a.bigint, &nb, Modulus()) 2051 2052 return c.BigInt(&e).Cmp(&d) == 0 2053 }, 2054 genA, genA, 2055 )) 2056 2057 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2058 } 2059 2060 func TestElementNewElement(t *testing.T) { 2061 assert := require.New(t) 2062 2063 t.Parallel() 2064 2065 e := NewElement(1) 2066 assert.True(e.IsOne()) 2067 2068 e = NewElement(0) 2069 assert.True(e.IsZero()) 2070 } 2071 2072 func TestElementBatchInvert(t *testing.T) { 2073 assert := require.New(t) 2074 2075 t.Parallel() 2076 2077 // ensure batchInvert([x]) == invert(x) 2078 for i := int64(-1); i <= 2; i++ { 2079 var e, eInv Element 2080 e.SetInt64(i) 2081 eInv.Inverse(&e) 2082 2083 a := []Element{e} 2084 aInv := BatchInvert(a) 2085 2086 assert.True(aInv[0].Equal(&eInv), "batchInvert != invert") 2087 2088 } 2089 2090 // test x * x⁻¹ == 1 2091 tData := [][]int64{ 2092 {-1, 1, 2, 3}, 2093 {0, -1, 1, 2, 3, 0}, 2094 {0, -1, 1, 0, 2, 3, 0}, 2095 {-1, 1, 0, 2, 3}, 2096 {0, 0, 1}, 2097 {1, 0, 0}, 2098 {0, 0, 0}, 2099 } 2100 2101 for _, t := range tData { 2102 a := make([]Element, len(t)) 2103 for i := 0; i < len(a); i++ { 2104 a[i].SetInt64(t[i]) 2105 } 2106 2107 aInv := BatchInvert(a) 2108 2109 assert.True(len(aInv) == len(a)) 2110 2111 for i := 0; i < len(a); i++ { 2112 if a[i].IsZero() { 2113 assert.True(aInv[i].IsZero(), "0⁻¹ != 0") 2114 } else { 2115 assert.True(a[i].Mul(&a[i], &aInv[i]).IsOne(), "x * x⁻¹ != 1") 2116 } 2117 } 2118 } 2119 2120 parameters := gopter.DefaultTestParameters() 2121 if testing.Short() { 2122 parameters.MinSuccessfulTests = nbFuzzShort 2123 } else { 2124 parameters.MinSuccessfulTests = nbFuzz 2125 } 2126 2127 properties := gopter.NewProperties(parameters) 2128 2129 genA := gen() 2130 2131 properties.Property("batchInvert --> x * x⁻¹ == 1", prop.ForAll( 2132 func(tp testPairElement, r uint8) bool { 2133 2134 a := make([]Element, r) 2135 if r != 0 { 2136 a[0] = tp.element 2137 2138 } 2139 one := One() 2140 for i := 1; i < len(a); i++ { 2141 a[i].Add(&a[i-1], &one) 2142 } 2143 2144 aInv := BatchInvert(a) 2145 2146 assert.True(len(aInv) == len(a)) 2147 2148 for i := 0; i < len(a); i++ { 2149 if a[i].IsZero() { 2150 if !aInv[i].IsZero() { 2151 return false 2152 } 2153 } else { 2154 if !a[i].Mul(&a[i], &aInv[i]).IsOne() { 2155 return false 2156 } 2157 } 2158 } 2159 return true 2160 }, 2161 genA, ggen.UInt8(), 2162 )) 2163 2164 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2165 } 2166 2167 func TestElementFromMont(t *testing.T) { 2168 2169 t.Parallel() 2170 parameters := gopter.DefaultTestParameters() 2171 if testing.Short() { 2172 parameters.MinSuccessfulTests = nbFuzzShort 2173 } else { 2174 parameters.MinSuccessfulTests = nbFuzz 2175 } 2176 2177 properties := gopter.NewProperties(parameters) 2178 2179 genA := gen() 2180 2181 properties.Property("Assembly implementation must be consistent with generic one", prop.ForAll( 2182 func(a testPairElement) bool { 2183 c := a.element 2184 d := a.element 2185 c.fromMont() 2186 _fromMontGeneric(&d) 2187 return c.Equal(&d) 2188 }, 2189 genA, 2190 )) 2191 2192 properties.Property("x.fromMont().toMont() == x", prop.ForAll( 2193 func(a testPairElement) bool { 2194 c := a.element 2195 c.fromMont().toMont() 2196 return c.Equal(&a.element) 2197 }, 2198 genA, 2199 )) 2200 2201 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2202 } 2203 2204 func TestElementJSON(t *testing.T) { 2205 assert := require.New(t) 2206 2207 type S struct { 2208 A Element 2209 B [3]Element 2210 C *Element 2211 D *Element 2212 } 2213 2214 // encode to JSON 2215 var s S 2216 s.A.SetString("-1") 2217 s.B[2].SetUint64(42) 2218 s.D = new(Element).SetUint64(8000) 2219 2220 encoded, err := json.Marshal(&s) 2221 assert.NoError(err) 2222 // we may need to adjust "42" and "8000" values for some moduli; see Text() method for more details. 2223 formatValue := func(v int64) string { 2224 var a big.Int 2225 a.SetInt64(v) 2226 a.Mod(&a, Modulus()) 2227 const maxUint16 = 65535 2228 var aNeg big.Int 2229 aNeg.Neg(&a).Mod(&aNeg, Modulus()) 2230 if aNeg.Uint64() != 0 && aNeg.Uint64() <= maxUint16 { 2231 return "-" + aNeg.Text(10) 2232 } 2233 return a.Text(10) 2234 } 2235 expected := fmt.Sprintf("{\"A\":%s,\"B\":[0,0,%s],\"C\":null,\"D\":%s}", formatValue(-1), formatValue(42), formatValue(8000)) 2236 assert.Equal(expected, string(encoded)) 2237 2238 // decode valid 2239 var decoded S 2240 err = json.Unmarshal([]byte(expected), &decoded) 2241 assert.NoError(err) 2242 2243 assert.Equal(s, decoded, "element -> json -> element round trip failed") 2244 2245 // decode hex and string values 2246 withHexValues := "{\"A\":\"-1\",\"B\":[0,\"0x00000\",\"0x2A\"],\"C\":null,\"D\":\"8000\"}" 2247 2248 var decodedS S 2249 err = json.Unmarshal([]byte(withHexValues), &decodedS) 2250 assert.NoError(err) 2251 2252 assert.Equal(s, decodedS, " json with strings -> element failed") 2253 2254 } 2255 2256 type testPairElement struct { 2257 element Element 2258 bigint big.Int 2259 } 2260 2261 func gen() gopter.Gen { 2262 return func(genParams *gopter.GenParameters) *gopter.GenResult { 2263 var g testPairElement 2264 2265 g.element = Element{ 2266 genParams.NextUint64(), 2267 genParams.NextUint64(), 2268 genParams.NextUint64(), 2269 genParams.NextUint64(), 2270 genParams.NextUint64(), 2271 genParams.NextUint64(), 2272 genParams.NextUint64(), 2273 genParams.NextUint64(), 2274 genParams.NextUint64(), 2275 genParams.NextUint64(), 2276 genParams.NextUint64(), 2277 genParams.NextUint64(), 2278 } 2279 if qElement[11] != ^uint64(0) { 2280 g.element[11] %= (qElement[11] + 1) 2281 } 2282 2283 for !g.element.smallerThanModulus() { 2284 g.element = Element{ 2285 genParams.NextUint64(), 2286 genParams.NextUint64(), 2287 genParams.NextUint64(), 2288 genParams.NextUint64(), 2289 genParams.NextUint64(), 2290 genParams.NextUint64(), 2291 genParams.NextUint64(), 2292 genParams.NextUint64(), 2293 genParams.NextUint64(), 2294 genParams.NextUint64(), 2295 genParams.NextUint64(), 2296 genParams.NextUint64(), 2297 } 2298 if qElement[11] != ^uint64(0) { 2299 g.element[11] %= (qElement[11] + 1) 2300 } 2301 } 2302 2303 g.element.BigInt(&g.bigint) 2304 genResult := gopter.NewGenResult(g, gopter.NoShrinker) 2305 return genResult 2306 } 2307 } 2308 2309 func genFull() gopter.Gen { 2310 return func(genParams *gopter.GenParameters) *gopter.GenResult { 2311 2312 genRandomFq := func() Element { 2313 var g Element 2314 2315 g = Element{ 2316 genParams.NextUint64(), 2317 genParams.NextUint64(), 2318 genParams.NextUint64(), 2319 genParams.NextUint64(), 2320 genParams.NextUint64(), 2321 genParams.NextUint64(), 2322 genParams.NextUint64(), 2323 genParams.NextUint64(), 2324 genParams.NextUint64(), 2325 genParams.NextUint64(), 2326 genParams.NextUint64(), 2327 genParams.NextUint64(), 2328 } 2329 2330 if qElement[11] != ^uint64(0) { 2331 g[11] %= (qElement[11] + 1) 2332 } 2333 2334 for !g.smallerThanModulus() { 2335 g = Element{ 2336 genParams.NextUint64(), 2337 genParams.NextUint64(), 2338 genParams.NextUint64(), 2339 genParams.NextUint64(), 2340 genParams.NextUint64(), 2341 genParams.NextUint64(), 2342 genParams.NextUint64(), 2343 genParams.NextUint64(), 2344 genParams.NextUint64(), 2345 genParams.NextUint64(), 2346 genParams.NextUint64(), 2347 genParams.NextUint64(), 2348 } 2349 if qElement[11] != ^uint64(0) { 2350 g[11] %= (qElement[11] + 1) 2351 } 2352 } 2353 2354 return g 2355 } 2356 a := genRandomFq() 2357 2358 var carry uint64 2359 a[0], carry = bits.Add64(a[0], qElement[0], carry) 2360 a[1], carry = bits.Add64(a[1], qElement[1], carry) 2361 a[2], carry = bits.Add64(a[2], qElement[2], carry) 2362 a[3], carry = bits.Add64(a[3], qElement[3], carry) 2363 a[4], carry = bits.Add64(a[4], qElement[4], carry) 2364 a[5], carry = bits.Add64(a[5], qElement[5], carry) 2365 a[6], carry = bits.Add64(a[6], qElement[6], carry) 2366 a[7], carry = bits.Add64(a[7], qElement[7], carry) 2367 a[8], carry = bits.Add64(a[8], qElement[8], carry) 2368 a[9], carry = bits.Add64(a[9], qElement[9], carry) 2369 a[10], carry = bits.Add64(a[10], qElement[10], carry) 2370 a[11], _ = bits.Add64(a[11], qElement[11], carry) 2371 2372 genResult := gopter.NewGenResult(a, gopter.NoShrinker) 2373 return genResult 2374 } 2375 } 2376 2377 func (z *Element) matchVeryBigInt(aHi uint64, aInt *big.Int) error { 2378 var modulus big.Int 2379 var aIntMod big.Int 2380 modulus.SetInt64(1) 2381 modulus.Lsh(&modulus, (Limbs+1)*64) 2382 aIntMod.Mod(aInt, &modulus) 2383 2384 slice := append(z[:], aHi) 2385 2386 return bigIntMatchUint64Slice(&aIntMod, slice) 2387 } 2388 2389 // TODO: Phase out in favor of property based testing 2390 func (z *Element) assertMatchVeryBigInt(t *testing.T, aHi uint64, aInt *big.Int) { 2391 2392 if err := z.matchVeryBigInt(aHi, aInt); err != nil { 2393 t.Error(err) 2394 } 2395 } 2396 2397 // bigIntMatchUint64Slice is a test helper to match big.Int words against a uint64 slice 2398 func bigIntMatchUint64Slice(aInt *big.Int, a []uint64) error { 2399 2400 words := aInt.Bits() 2401 2402 const steps = 64 / bits.UintSize 2403 const filter uint64 = 0xFFFFFFFFFFFFFFFF >> (64 - bits.UintSize) 2404 for i := 0; i < len(a)*steps; i++ { 2405 2406 var wI big.Word 2407 2408 if i < len(words) { 2409 wI = words[i] 2410 } 2411 2412 aI := a[i/steps] >> ((i * bits.UintSize) % 64) 2413 aI &= filter 2414 2415 if uint64(wI) != aI { 2416 return fmt.Errorf("bignum mismatch: disagreement on word %d: %x ≠ %x; %d ≠ %d", i, uint64(wI), aI, uint64(wI), aI) 2417 } 2418 } 2419 2420 return nil 2421 } 2422 2423 func TestElementInversionApproximation(t *testing.T) { 2424 var x Element 2425 for i := 0; i < 1000; i++ { 2426 x.SetRandom() 2427 2428 // Normally small elements are unlikely. Here we give them a higher chance 2429 xZeros := mrand.Int() % Limbs //#nosec G404 weak rng is fine here 2430 for j := 1; j < xZeros; j++ { 2431 x[Limbs-j] = 0 2432 } 2433 2434 a := approximate(&x, x.BitLen()) 2435 aRef := approximateRef(&x) 2436 2437 if a != aRef { 2438 t.Error("Approximation mismatch") 2439 } 2440 } 2441 } 2442 2443 func TestElementInversionCorrectionFactorFormula(t *testing.T) { 2444 const kLimbs = k * Limbs 2445 const power = kLimbs*6 + invIterationsN*(kLimbs-k+1) 2446 factorInt := big.NewInt(1) 2447 factorInt.Lsh(factorInt, power) 2448 factorInt.Mod(factorInt, Modulus()) 2449 2450 var refFactorInt big.Int 2451 inversionCorrectionFactor := Element{ 2452 inversionCorrectionFactorWord0, 2453 inversionCorrectionFactorWord1, 2454 inversionCorrectionFactorWord2, 2455 inversionCorrectionFactorWord3, 2456 inversionCorrectionFactorWord4, 2457 inversionCorrectionFactorWord5, 2458 inversionCorrectionFactorWord6, 2459 inversionCorrectionFactorWord7, 2460 inversionCorrectionFactorWord8, 2461 inversionCorrectionFactorWord9, 2462 inversionCorrectionFactorWord10, 2463 inversionCorrectionFactorWord11, 2464 } 2465 inversionCorrectionFactor.toBigInt(&refFactorInt) 2466 2467 if refFactorInt.Cmp(factorInt) != 0 { 2468 t.Error("mismatch") 2469 } 2470 } 2471 2472 func TestElementLinearComb(t *testing.T) { 2473 var x Element 2474 var y Element 2475 2476 for i := 0; i < 1000; i++ { 2477 x.SetRandom() 2478 y.SetRandom() 2479 testLinearComb(t, &x, mrand.Int63(), &y, mrand.Int63()) //#nosec G404 weak rng is fine here 2480 } 2481 } 2482 2483 // Probably unnecessary post-dev. In case the output of inv is wrong, this checks whether it's only off by a constant factor. 2484 func TestElementInversionCorrectionFactor(t *testing.T) { 2485 2486 // (1/x)/inv(x) = (1/1)/inv(1) ⇔ inv(1) = x inv(x) 2487 2488 var one Element 2489 var oneInv Element 2490 one.SetOne() 2491 oneInv.Inverse(&one) 2492 2493 for i := 0; i < 100; i++ { 2494 var x Element 2495 var xInv Element 2496 x.SetRandom() 2497 xInv.Inverse(&x) 2498 2499 x.Mul(&x, &xInv) 2500 if !x.Equal(&oneInv) { 2501 t.Error("Correction factor is inconsistent") 2502 } 2503 } 2504 2505 if !oneInv.Equal(&one) { 2506 var i big.Int 2507 oneInv.BigInt(&i) // no montgomery 2508 i.ModInverse(&i, Modulus()) 2509 var fac Element 2510 fac.setBigInt(&i) // back to montgomery 2511 2512 var facTimesFac Element 2513 facTimesFac.Mul(&fac, &Element{ 2514 inversionCorrectionFactorWord0, 2515 inversionCorrectionFactorWord1, 2516 inversionCorrectionFactorWord2, 2517 inversionCorrectionFactorWord3, 2518 inversionCorrectionFactorWord4, 2519 inversionCorrectionFactorWord5, 2520 inversionCorrectionFactorWord6, 2521 inversionCorrectionFactorWord7, 2522 inversionCorrectionFactorWord8, 2523 inversionCorrectionFactorWord9, 2524 inversionCorrectionFactorWord10, 2525 inversionCorrectionFactorWord11, 2526 }) 2527 2528 t.Error("Correction factor is consistently off by", fac, "Should be", facTimesFac) 2529 } 2530 } 2531 2532 func TestElementBigNumNeg(t *testing.T) { 2533 var a Element 2534 aHi := negL(&a, 0) 2535 if !a.IsZero() || aHi != 0 { 2536 t.Error("-0 != 0") 2537 } 2538 } 2539 2540 func TestElementBigNumWMul(t *testing.T) { 2541 var x Element 2542 2543 for i := 0; i < 1000; i++ { 2544 x.SetRandom() 2545 w := mrand.Int63() //#nosec G404 weak rng is fine here 2546 testBigNumWMul(t, &x, w) 2547 } 2548 } 2549 2550 func TestElementVeryBigIntConversion(t *testing.T) { 2551 xHi := mrand.Uint64() //#nosec G404 weak rng is fine here 2552 var x Element 2553 x.SetRandom() 2554 var xInt big.Int 2555 x.toVeryBigIntSigned(&xInt, xHi) 2556 x.assertMatchVeryBigInt(t, xHi, &xInt) 2557 } 2558 2559 type veryBigInt struct { 2560 asInt big.Int 2561 low Element 2562 hi uint64 2563 } 2564 2565 // genVeryBigIntSigned if sign == 0, no sign is forced 2566 func genVeryBigIntSigned(sign int) gopter.Gen { 2567 return func(genParams *gopter.GenParameters) *gopter.GenResult { 2568 var g veryBigInt 2569 2570 g.low = Element{ 2571 genParams.NextUint64(), 2572 genParams.NextUint64(), 2573 genParams.NextUint64(), 2574 genParams.NextUint64(), 2575 genParams.NextUint64(), 2576 genParams.NextUint64(), 2577 genParams.NextUint64(), 2578 genParams.NextUint64(), 2579 genParams.NextUint64(), 2580 genParams.NextUint64(), 2581 genParams.NextUint64(), 2582 genParams.NextUint64(), 2583 } 2584 2585 g.hi = genParams.NextUint64() 2586 2587 if sign < 0 { 2588 g.hi |= signBitSelector 2589 } else if sign > 0 { 2590 g.hi &= ^signBitSelector 2591 } 2592 2593 g.low.toVeryBigIntSigned(&g.asInt, g.hi) 2594 2595 genResult := gopter.NewGenResult(g, gopter.NoShrinker) 2596 return genResult 2597 } 2598 } 2599 2600 func TestElementMontReduce(t *testing.T) { 2601 2602 parameters := gopter.DefaultTestParameters() 2603 if testing.Short() { 2604 parameters.MinSuccessfulTests = nbFuzzShort 2605 } else { 2606 parameters.MinSuccessfulTests = nbFuzz 2607 } 2608 2609 properties := gopter.NewProperties(parameters) 2610 2611 gen := genVeryBigIntSigned(0) 2612 2613 properties.Property("Montgomery reduction is correct", prop.ForAll( 2614 func(g veryBigInt) bool { 2615 var res Element 2616 var resInt big.Int 2617 2618 montReduce(&resInt, &g.asInt) 2619 res.montReduceSigned(&g.low, g.hi) 2620 2621 return res.matchVeryBigInt(0, &resInt) == nil 2622 }, 2623 gen, 2624 )) 2625 2626 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2627 } 2628 2629 func TestElementMontReduceMultipleOfR(t *testing.T) { 2630 2631 parameters := gopter.DefaultTestParameters() 2632 if testing.Short() { 2633 parameters.MinSuccessfulTests = nbFuzzShort 2634 } else { 2635 parameters.MinSuccessfulTests = nbFuzz 2636 } 2637 2638 properties := gopter.NewProperties(parameters) 2639 2640 gen := ggen.UInt64() 2641 2642 properties.Property("Montgomery reduction is correct", prop.ForAll( 2643 func(hi uint64) bool { 2644 var zero, res Element 2645 var asInt, resInt big.Int 2646 2647 zero.toVeryBigIntSigned(&asInt, hi) 2648 2649 montReduce(&resInt, &asInt) 2650 res.montReduceSigned(&zero, hi) 2651 2652 return res.matchVeryBigInt(0, &resInt) == nil 2653 }, 2654 gen, 2655 )) 2656 2657 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2658 } 2659 2660 func TestElement0Inverse(t *testing.T) { 2661 var x Element 2662 x.Inverse(&x) 2663 if !x.IsZero() { 2664 t.Fail() 2665 } 2666 } 2667 2668 // TODO: Tests like this (update factor related) are common to all fields. Move them to somewhere non-autogen 2669 func TestUpdateFactorSubtraction(t *testing.T) { 2670 for i := 0; i < 1000; i++ { 2671 2672 f0, g0 := randomizeUpdateFactors() 2673 f1, g1 := randomizeUpdateFactors() 2674 2675 for f0-f1 > 1<<31 || f0-f1 <= -1<<31 { 2676 f1 /= 2 2677 } 2678 2679 for g0-g1 > 1<<31 || g0-g1 <= -1<<31 { 2680 g1 /= 2 2681 } 2682 2683 c0 := updateFactorsCompose(f0, g0) 2684 c1 := updateFactorsCompose(f1, g1) 2685 2686 cRes := c0 - c1 2687 fRes, gRes := updateFactorsDecompose(cRes) 2688 2689 if fRes != f0-f1 || gRes != g0-g1 { 2690 t.Error(i) 2691 } 2692 } 2693 } 2694 2695 func TestUpdateFactorsDouble(t *testing.T) { 2696 for i := 0; i < 1000; i++ { 2697 f, g := randomizeUpdateFactors() 2698 2699 if f > 1<<30 || f < (-1<<31+1)/2 { 2700 f /= 2 2701 if g <= 1<<29 && g >= (-1<<31+1)/4 { 2702 g *= 2 //g was kept small on f's account. Now that we're halving f, we can double g 2703 } 2704 } 2705 2706 if g > 1<<30 || g < (-1<<31+1)/2 { 2707 g /= 2 2708 2709 if f <= 1<<29 && f >= (-1<<31+1)/4 { 2710 f *= 2 //f was kept small on g's account. Now that we're halving g, we can double f 2711 } 2712 } 2713 2714 c := updateFactorsCompose(f, g) 2715 cD := c * 2 2716 fD, gD := updateFactorsDecompose(cD) 2717 2718 if fD != 2*f || gD != 2*g { 2719 t.Error(i) 2720 } 2721 } 2722 } 2723 2724 func TestUpdateFactorsNeg(t *testing.T) { 2725 var fMistake bool 2726 for i := 0; i < 1000; i++ { 2727 f, g := randomizeUpdateFactors() 2728 2729 if f == 0x80000000 || g == 0x80000000 { 2730 // Update factors this large can only have been obtained after 31 iterations and will therefore never be negated 2731 // We don't have capacity to store -2³¹ 2732 // Repeat this iteration 2733 i-- 2734 continue 2735 } 2736 2737 c := updateFactorsCompose(f, g) 2738 nc := -c 2739 nf, ng := updateFactorsDecompose(nc) 2740 fMistake = fMistake || nf != -f 2741 if nf != -f || ng != -g { 2742 t.Errorf("Mismatch iteration #%d:\n%d, %d ->\n %d -> %d ->\n %d, %d\n Inputs in hex: %X, %X", 2743 i, f, g, c, nc, nf, ng, f, g) 2744 } 2745 } 2746 if fMistake { 2747 t.Error("Mistake with f detected") 2748 } else { 2749 t.Log("All good with f") 2750 } 2751 } 2752 2753 func TestUpdateFactorsNeg0(t *testing.T) { 2754 c := updateFactorsCompose(0, 0) 2755 t.Logf("c(0,0) = %X", c) 2756 cn := -c 2757 2758 if c != cn { 2759 t.Error("Negation of zero update factors should yield the same result.") 2760 } 2761 } 2762 2763 func TestUpdateFactorDecomposition(t *testing.T) { 2764 var negSeen bool 2765 2766 for i := 0; i < 1000; i++ { 2767 2768 f, g := randomizeUpdateFactors() 2769 2770 if f <= -(1<<31) || f > 1<<31 { 2771 t.Fatal("f out of range") 2772 } 2773 2774 negSeen = negSeen || f < 0 2775 2776 c := updateFactorsCompose(f, g) 2777 2778 fBack, gBack := updateFactorsDecompose(c) 2779 2780 if f != fBack || g != gBack { 2781 t.Errorf("(%d, %d) -> %d -> (%d, %d)\n", f, g, c, fBack, gBack) 2782 } 2783 } 2784 2785 if !negSeen { 2786 t.Fatal("No negative f factors") 2787 } 2788 } 2789 2790 func TestUpdateFactorInitialValues(t *testing.T) { 2791 2792 f0, g0 := updateFactorsDecompose(updateFactorIdentityMatrixRow0) 2793 f1, g1 := updateFactorsDecompose(updateFactorIdentityMatrixRow1) 2794 2795 if f0 != 1 || g0 != 0 || f1 != 0 || g1 != 1 { 2796 t.Error("Update factor initial value constants are incorrect") 2797 } 2798 } 2799 2800 func TestUpdateFactorsRandomization(t *testing.T) { 2801 var maxLen int 2802 2803 //t.Log("|f| + |g| is not to exceed", 1 << 31) 2804 for i := 0; i < 1000; i++ { 2805 f, g := randomizeUpdateFactors() 2806 lf, lg := abs64T32(f), abs64T32(g) 2807 absSum := lf + lg 2808 if absSum >= 1<<31 { 2809 2810 if absSum == 1<<31 { 2811 maxLen++ 2812 } else { 2813 t.Error(i, "Sum of absolute values too large, f =", f, ",g =", g, ",|f| + |g| =", absSum) 2814 } 2815 } 2816 } 2817 2818 if maxLen == 0 { 2819 t.Error("max len not observed") 2820 } else { 2821 t.Log(maxLen, "maxLens observed") 2822 } 2823 } 2824 2825 func randomizeUpdateFactor(absLimit uint32) int64 { 2826 const maxSizeLikelihood = 10 2827 maxSize := mrand.Intn(maxSizeLikelihood) //#nosec G404 weak rng is fine here 2828 2829 absLimit64 := int64(absLimit) 2830 var f int64 2831 switch maxSize { 2832 case 0: 2833 f = absLimit64 2834 case 1: 2835 f = -absLimit64 2836 default: 2837 f = int64(mrand.Uint64()%(2*uint64(absLimit64)+1)) - absLimit64 //#nosec G404 weak rng is fine here 2838 } 2839 2840 if f > 1<<31 { 2841 return 1 << 31 2842 } else if f < -1<<31+1 { 2843 return -1<<31 + 1 2844 } 2845 2846 return f 2847 } 2848 2849 func abs64T32(f int64) uint32 { 2850 if f >= 1<<32 || f < -1<<32 { 2851 panic("f out of range") 2852 } 2853 2854 if f < 0 { 2855 return uint32(-f) 2856 } 2857 return uint32(f) 2858 } 2859 2860 func randomizeUpdateFactors() (int64, int64) { 2861 var f [2]int64 2862 b := mrand.Int() % 2 //#nosec G404 weak rng is fine here 2863 2864 f[b] = randomizeUpdateFactor(1 << 31) 2865 2866 //As per the paper, |f| + |g| \le 2³¹. 2867 f[1-b] = randomizeUpdateFactor(1<<31 - abs64T32(f[b])) 2868 2869 //Patching another edge case 2870 if f[0]+f[1] == -1<<31 { 2871 b = mrand.Int() % 2 //#nosec G404 weak rng is fine here 2872 f[b]++ 2873 } 2874 2875 return f[0], f[1] 2876 } 2877 2878 func testLinearComb(t *testing.T, x *Element, xC int64, y *Element, yC int64) { 2879 2880 var p1 big.Int 2881 x.toBigInt(&p1) 2882 p1.Mul(&p1, big.NewInt(xC)) 2883 2884 var p2 big.Int 2885 y.toBigInt(&p2) 2886 p2.Mul(&p2, big.NewInt(yC)) 2887 2888 p1.Add(&p1, &p2) 2889 p1.Mod(&p1, Modulus()) 2890 montReduce(&p1, &p1) 2891 2892 var z Element 2893 z.linearComb(x, xC, y, yC) 2894 z.assertMatchVeryBigInt(t, 0, &p1) 2895 } 2896 2897 func testBigNumWMul(t *testing.T, a *Element, c int64) { 2898 var aHi uint64 2899 var aTimes Element 2900 aHi = aTimes.mulWNonModular(a, c) 2901 2902 assertMulProduct(t, a, c, &aTimes, aHi) 2903 } 2904 2905 func updateFactorsCompose(f int64, g int64) int64 { 2906 return f + g<<32 2907 } 2908 2909 var rInv big.Int 2910 2911 func montReduce(res *big.Int, x *big.Int) { 2912 if rInv.BitLen() == 0 { // initialization 2913 rInv.SetUint64(1) 2914 rInv.Lsh(&rInv, Limbs*64) 2915 rInv.ModInverse(&rInv, Modulus()) 2916 } 2917 res.Mul(x, &rInv) 2918 res.Mod(res, Modulus()) 2919 } 2920 2921 func (z *Element) toVeryBigIntUnsigned(i *big.Int, xHi uint64) { 2922 z.toBigInt(i) 2923 var upperWord big.Int 2924 upperWord.SetUint64(xHi) 2925 upperWord.Lsh(&upperWord, Limbs*64) 2926 i.Add(&upperWord, i) 2927 } 2928 2929 func (z *Element) toVeryBigIntSigned(i *big.Int, xHi uint64) { 2930 z.toVeryBigIntUnsigned(i, xHi) 2931 if signBitSelector&xHi != 0 { 2932 twosCompModulus := big.NewInt(1) 2933 twosCompModulus.Lsh(twosCompModulus, (Limbs+1)*64) 2934 i.Sub(i, twosCompModulus) 2935 } 2936 } 2937 2938 func assertMulProduct(t *testing.T, x *Element, c int64, result *Element, resultHi uint64) big.Int { 2939 var xInt big.Int 2940 x.toBigInt(&xInt) 2941 2942 xInt.Mul(&xInt, big.NewInt(c)) 2943 2944 result.assertMatchVeryBigInt(t, resultHi, &xInt) 2945 return xInt 2946 } 2947 2948 func approximateRef(x *Element) uint64 { 2949 2950 var asInt big.Int 2951 x.toBigInt(&asInt) 2952 n := x.BitLen() 2953 2954 if n <= 64 { 2955 return asInt.Uint64() 2956 } 2957 2958 modulus := big.NewInt(1 << 31) 2959 var lo big.Int 2960 lo.Mod(&asInt, modulus) 2961 2962 modulus.Lsh(modulus, uint(n-64)) 2963 var hi big.Int 2964 hi.Div(&asInt, modulus) 2965 hi.Lsh(&hi, 31) 2966 2967 hi.Add(&hi, &lo) 2968 return hi.Uint64() 2969 }