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