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