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