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