github.com/consensys/gnark-crypto@v0.14.0/ecc/bn254/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 17522657719365597833, 209 13107472804851548667, 210 5164255478447964150, 211 493319470278259999, 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 17522657719365597833, 223 13107472804851548667, 224 5164255478447964150, 225 493319470278259999, 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 TestElementFixedExp(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 var ( 1672 _bLegendreExponentElement *big.Int 1673 _bSqrtExponentElement *big.Int 1674 ) 1675 1676 _bLegendreExponentElement, _ = new(big.Int).SetString("183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3", 16) 1677 const sqrtExponentElement = "c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52" 1678 _bSqrtExponentElement, _ = new(big.Int).SetString(sqrtExponentElement, 16) 1679 1680 genA := gen() 1681 1682 properties.Property(fmt.Sprintf("expBySqrtExp must match Exp(%s)", sqrtExponentElement), prop.ForAll( 1683 func(a testPairElement) bool { 1684 c := a.element 1685 d := a.element 1686 c.expBySqrtExp(c) 1687 d.Exp(d, _bSqrtExponentElement) 1688 return c.Equal(&d) 1689 }, 1690 genA, 1691 )) 1692 1693 properties.Property("expByLegendreExp must match Exp(183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3)", prop.ForAll( 1694 func(a testPairElement) bool { 1695 c := a.element 1696 d := a.element 1697 c.expByLegendreExp(c) 1698 d.Exp(d, _bLegendreExponentElement) 1699 return c.Equal(&d) 1700 }, 1701 genA, 1702 )) 1703 1704 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1705 } 1706 1707 func TestElementHalve(t *testing.T) { 1708 1709 t.Parallel() 1710 parameters := gopter.DefaultTestParameters() 1711 if testing.Short() { 1712 parameters.MinSuccessfulTests = nbFuzzShort 1713 } else { 1714 parameters.MinSuccessfulTests = nbFuzz 1715 } 1716 1717 properties := gopter.NewProperties(parameters) 1718 1719 genA := gen() 1720 var twoInv Element 1721 twoInv.SetUint64(2) 1722 twoInv.Inverse(&twoInv) 1723 1724 properties.Property("z.Halve must match z / 2", prop.ForAll( 1725 func(a testPairElement) bool { 1726 c := a.element 1727 d := a.element 1728 c.Halve() 1729 d.Mul(&d, &twoInv) 1730 return c.Equal(&d) 1731 }, 1732 genA, 1733 )) 1734 1735 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1736 } 1737 1738 func combineSelectionArguments(c int64, z int8) int { 1739 if z%3 == 0 { 1740 return 0 1741 } 1742 return int(c) 1743 } 1744 1745 func TestElementSelect(t *testing.T) { 1746 t.Parallel() 1747 parameters := gopter.DefaultTestParameters() 1748 if testing.Short() { 1749 parameters.MinSuccessfulTests = nbFuzzShort 1750 } else { 1751 parameters.MinSuccessfulTests = nbFuzz 1752 } 1753 1754 properties := gopter.NewProperties(parameters) 1755 1756 genA := genFull() 1757 genB := genFull() 1758 genC := ggen.Int64() //the condition 1759 genZ := ggen.Int8() //to make zeros artificially more likely 1760 1761 properties.Property("Select: must select correctly", prop.ForAll( 1762 func(a, b Element, cond int64, z int8) bool { 1763 condC := combineSelectionArguments(cond, z) 1764 1765 var c Element 1766 c.Select(condC, &a, &b) 1767 1768 if condC == 0 { 1769 return c.Equal(&a) 1770 } 1771 return c.Equal(&b) 1772 }, 1773 genA, 1774 genB, 1775 genC, 1776 genZ, 1777 )) 1778 1779 properties.Property("Select: having the receiver as operand should output the same result", prop.ForAll( 1780 func(a, b Element, cond int64, z int8) bool { 1781 condC := combineSelectionArguments(cond, z) 1782 1783 var c, d Element 1784 d.Set(&a) 1785 c.Select(condC, &a, &b) 1786 a.Select(condC, &a, &b) 1787 b.Select(condC, &d, &b) 1788 return a.Equal(&b) && a.Equal(&c) && b.Equal(&c) 1789 }, 1790 genA, 1791 genB, 1792 genC, 1793 genZ, 1794 )) 1795 1796 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1797 } 1798 1799 func TestElementSetInt64(t *testing.T) { 1800 1801 t.Parallel() 1802 parameters := gopter.DefaultTestParameters() 1803 if testing.Short() { 1804 parameters.MinSuccessfulTests = nbFuzzShort 1805 } else { 1806 parameters.MinSuccessfulTests = nbFuzz 1807 } 1808 1809 properties := gopter.NewProperties(parameters) 1810 1811 genA := gen() 1812 1813 properties.Property("z.SetInt64 must match z.SetString", prop.ForAll( 1814 func(a testPairElement, v int64) bool { 1815 c := a.element 1816 d := a.element 1817 1818 c.SetInt64(v) 1819 d.SetString(fmt.Sprintf("%v", v)) 1820 1821 return c.Equal(&d) 1822 }, 1823 genA, ggen.Int64(), 1824 )) 1825 1826 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1827 } 1828 1829 func TestElementSetInterface(t *testing.T) { 1830 1831 t.Parallel() 1832 parameters := gopter.DefaultTestParameters() 1833 if testing.Short() { 1834 parameters.MinSuccessfulTests = nbFuzzShort 1835 } else { 1836 parameters.MinSuccessfulTests = nbFuzz 1837 } 1838 1839 properties := gopter.NewProperties(parameters) 1840 1841 genA := gen() 1842 genInt := ggen.Int 1843 genInt8 := ggen.Int8 1844 genInt16 := ggen.Int16 1845 genInt32 := ggen.Int32 1846 genInt64 := ggen.Int64 1847 1848 genUint := ggen.UInt 1849 genUint8 := ggen.UInt8 1850 genUint16 := ggen.UInt16 1851 genUint32 := ggen.UInt32 1852 genUint64 := ggen.UInt64 1853 1854 properties.Property("z.SetInterface must match z.SetString with int8", prop.ForAll( 1855 func(a testPairElement, v int8) bool { 1856 c := a.element 1857 d := a.element 1858 1859 c.SetInterface(v) 1860 d.SetString(fmt.Sprintf("%v", v)) 1861 1862 return c.Equal(&d) 1863 }, 1864 genA, genInt8(), 1865 )) 1866 1867 properties.Property("z.SetInterface must match z.SetString with int16", prop.ForAll( 1868 func(a testPairElement, v int16) bool { 1869 c := a.element 1870 d := a.element 1871 1872 c.SetInterface(v) 1873 d.SetString(fmt.Sprintf("%v", v)) 1874 1875 return c.Equal(&d) 1876 }, 1877 genA, genInt16(), 1878 )) 1879 1880 properties.Property("z.SetInterface must match z.SetString with int32", prop.ForAll( 1881 func(a testPairElement, v int32) bool { 1882 c := a.element 1883 d := a.element 1884 1885 c.SetInterface(v) 1886 d.SetString(fmt.Sprintf("%v", v)) 1887 1888 return c.Equal(&d) 1889 }, 1890 genA, genInt32(), 1891 )) 1892 1893 properties.Property("z.SetInterface must match z.SetString with int64", prop.ForAll( 1894 func(a testPairElement, v int64) bool { 1895 c := a.element 1896 d := a.element 1897 1898 c.SetInterface(v) 1899 d.SetString(fmt.Sprintf("%v", v)) 1900 1901 return c.Equal(&d) 1902 }, 1903 genA, genInt64(), 1904 )) 1905 1906 properties.Property("z.SetInterface must match z.SetString with int", prop.ForAll( 1907 func(a testPairElement, v int) bool { 1908 c := a.element 1909 d := a.element 1910 1911 c.SetInterface(v) 1912 d.SetString(fmt.Sprintf("%v", v)) 1913 1914 return c.Equal(&d) 1915 }, 1916 genA, genInt(), 1917 )) 1918 1919 properties.Property("z.SetInterface must match z.SetString with uint8", prop.ForAll( 1920 func(a testPairElement, v uint8) bool { 1921 c := a.element 1922 d := a.element 1923 1924 c.SetInterface(v) 1925 d.SetString(fmt.Sprintf("%v", v)) 1926 1927 return c.Equal(&d) 1928 }, 1929 genA, genUint8(), 1930 )) 1931 1932 properties.Property("z.SetInterface must match z.SetString with uint16", prop.ForAll( 1933 func(a testPairElement, v uint16) bool { 1934 c := a.element 1935 d := a.element 1936 1937 c.SetInterface(v) 1938 d.SetString(fmt.Sprintf("%v", v)) 1939 1940 return c.Equal(&d) 1941 }, 1942 genA, genUint16(), 1943 )) 1944 1945 properties.Property("z.SetInterface must match z.SetString with uint32", prop.ForAll( 1946 func(a testPairElement, v uint32) bool { 1947 c := a.element 1948 d := a.element 1949 1950 c.SetInterface(v) 1951 d.SetString(fmt.Sprintf("%v", v)) 1952 1953 return c.Equal(&d) 1954 }, 1955 genA, genUint32(), 1956 )) 1957 1958 properties.Property("z.SetInterface must match z.SetString with uint64", prop.ForAll( 1959 func(a testPairElement, v uint64) bool { 1960 c := a.element 1961 d := a.element 1962 1963 c.SetInterface(v) 1964 d.SetString(fmt.Sprintf("%v", v)) 1965 1966 return c.Equal(&d) 1967 }, 1968 genA, genUint64(), 1969 )) 1970 1971 properties.Property("z.SetInterface must match z.SetString with uint", prop.ForAll( 1972 func(a testPairElement, v uint) bool { 1973 c := a.element 1974 d := a.element 1975 1976 c.SetInterface(v) 1977 d.SetString(fmt.Sprintf("%v", v)) 1978 1979 return c.Equal(&d) 1980 }, 1981 genA, genUint(), 1982 )) 1983 1984 properties.TestingRun(t, gopter.ConsoleReporter(false)) 1985 1986 { 1987 assert := require.New(t) 1988 var e Element 1989 r, err := e.SetInterface(nil) 1990 assert.Nil(r) 1991 assert.Error(err) 1992 1993 var ptE *Element 1994 var ptB *big.Int 1995 1996 r, err = e.SetInterface(ptE) 1997 assert.Nil(r) 1998 assert.Error(err) 1999 ptE = new(Element).SetOne() 2000 r, err = e.SetInterface(ptE) 2001 assert.NoError(err) 2002 assert.True(r.IsOne()) 2003 2004 r, err = e.SetInterface(ptB) 2005 assert.Nil(r) 2006 assert.Error(err) 2007 2008 } 2009 } 2010 2011 func TestElementNegativeExp(t *testing.T) { 2012 t.Parallel() 2013 2014 parameters := gopter.DefaultTestParameters() 2015 if testing.Short() { 2016 parameters.MinSuccessfulTests = nbFuzzShort 2017 } else { 2018 parameters.MinSuccessfulTests = nbFuzz 2019 } 2020 2021 properties := gopter.NewProperties(parameters) 2022 2023 genA := gen() 2024 2025 properties.Property("x⁻ᵏ == 1/xᵏ", prop.ForAll( 2026 func(a, b testPairElement) bool { 2027 2028 var nb, d, e big.Int 2029 nb.Neg(&b.bigint) 2030 2031 var c Element 2032 c.Exp(a.element, &nb) 2033 2034 d.Exp(&a.bigint, &nb, Modulus()) 2035 2036 return c.BigInt(&e).Cmp(&d) == 0 2037 }, 2038 genA, genA, 2039 )) 2040 2041 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2042 } 2043 2044 func TestElementNewElement(t *testing.T) { 2045 assert := require.New(t) 2046 2047 t.Parallel() 2048 2049 e := NewElement(1) 2050 assert.True(e.IsOne()) 2051 2052 e = NewElement(0) 2053 assert.True(e.IsZero()) 2054 } 2055 2056 func TestElementBatchInvert(t *testing.T) { 2057 assert := require.New(t) 2058 2059 t.Parallel() 2060 2061 // ensure batchInvert([x]) == invert(x) 2062 for i := int64(-1); i <= 2; i++ { 2063 var e, eInv Element 2064 e.SetInt64(i) 2065 eInv.Inverse(&e) 2066 2067 a := []Element{e} 2068 aInv := BatchInvert(a) 2069 2070 assert.True(aInv[0].Equal(&eInv), "batchInvert != invert") 2071 2072 } 2073 2074 // test x * x⁻¹ == 1 2075 tData := [][]int64{ 2076 {-1, 1, 2, 3}, 2077 {0, -1, 1, 2, 3, 0}, 2078 {0, -1, 1, 0, 2, 3, 0}, 2079 {-1, 1, 0, 2, 3}, 2080 {0, 0, 1}, 2081 {1, 0, 0}, 2082 {0, 0, 0}, 2083 } 2084 2085 for _, t := range tData { 2086 a := make([]Element, len(t)) 2087 for i := 0; i < len(a); i++ { 2088 a[i].SetInt64(t[i]) 2089 } 2090 2091 aInv := BatchInvert(a) 2092 2093 assert.True(len(aInv) == len(a)) 2094 2095 for i := 0; i < len(a); i++ { 2096 if a[i].IsZero() { 2097 assert.True(aInv[i].IsZero(), "0⁻¹ != 0") 2098 } else { 2099 assert.True(a[i].Mul(&a[i], &aInv[i]).IsOne(), "x * x⁻¹ != 1") 2100 } 2101 } 2102 } 2103 2104 parameters := gopter.DefaultTestParameters() 2105 if testing.Short() { 2106 parameters.MinSuccessfulTests = nbFuzzShort 2107 } else { 2108 parameters.MinSuccessfulTests = nbFuzz 2109 } 2110 2111 properties := gopter.NewProperties(parameters) 2112 2113 genA := gen() 2114 2115 properties.Property("batchInvert --> x * x⁻¹ == 1", prop.ForAll( 2116 func(tp testPairElement, r uint8) bool { 2117 2118 a := make([]Element, r) 2119 if r != 0 { 2120 a[0] = tp.element 2121 2122 } 2123 one := One() 2124 for i := 1; i < len(a); i++ { 2125 a[i].Add(&a[i-1], &one) 2126 } 2127 2128 aInv := BatchInvert(a) 2129 2130 assert.True(len(aInv) == len(a)) 2131 2132 for i := 0; i < len(a); i++ { 2133 if a[i].IsZero() { 2134 if !aInv[i].IsZero() { 2135 return false 2136 } 2137 } else { 2138 if !a[i].Mul(&a[i], &aInv[i]).IsOne() { 2139 return false 2140 } 2141 } 2142 } 2143 return true 2144 }, 2145 genA, ggen.UInt8(), 2146 )) 2147 2148 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2149 } 2150 2151 func TestElementFromMont(t *testing.T) { 2152 2153 t.Parallel() 2154 parameters := gopter.DefaultTestParameters() 2155 if testing.Short() { 2156 parameters.MinSuccessfulTests = nbFuzzShort 2157 } else { 2158 parameters.MinSuccessfulTests = nbFuzz 2159 } 2160 2161 properties := gopter.NewProperties(parameters) 2162 2163 genA := gen() 2164 2165 properties.Property("Assembly implementation must be consistent with generic one", prop.ForAll( 2166 func(a testPairElement) bool { 2167 c := a.element 2168 d := a.element 2169 c.fromMont() 2170 _fromMontGeneric(&d) 2171 return c.Equal(&d) 2172 }, 2173 genA, 2174 )) 2175 2176 properties.Property("x.fromMont().toMont() == x", prop.ForAll( 2177 func(a testPairElement) bool { 2178 c := a.element 2179 c.fromMont().toMont() 2180 return c.Equal(&a.element) 2181 }, 2182 genA, 2183 )) 2184 2185 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2186 } 2187 2188 func TestElementJSON(t *testing.T) { 2189 assert := require.New(t) 2190 2191 type S struct { 2192 A Element 2193 B [3]Element 2194 C *Element 2195 D *Element 2196 } 2197 2198 // encode to JSON 2199 var s S 2200 s.A.SetString("-1") 2201 s.B[2].SetUint64(42) 2202 s.D = new(Element).SetUint64(8000) 2203 2204 encoded, err := json.Marshal(&s) 2205 assert.NoError(err) 2206 // we may need to adjust "42" and "8000" values for some moduli; see Text() method for more details. 2207 formatValue := func(v int64) string { 2208 var a big.Int 2209 a.SetInt64(v) 2210 a.Mod(&a, Modulus()) 2211 const maxUint16 = 65535 2212 var aNeg big.Int 2213 aNeg.Neg(&a).Mod(&aNeg, Modulus()) 2214 if aNeg.Uint64() != 0 && aNeg.Uint64() <= maxUint16 { 2215 return "-" + aNeg.Text(10) 2216 } 2217 return a.Text(10) 2218 } 2219 expected := fmt.Sprintf("{\"A\":%s,\"B\":[0,0,%s],\"C\":null,\"D\":%s}", formatValue(-1), formatValue(42), formatValue(8000)) 2220 assert.Equal(expected, string(encoded)) 2221 2222 // decode valid 2223 var decoded S 2224 err = json.Unmarshal([]byte(expected), &decoded) 2225 assert.NoError(err) 2226 2227 assert.Equal(s, decoded, "element -> json -> element round trip failed") 2228 2229 // decode hex and string values 2230 withHexValues := "{\"A\":\"-1\",\"B\":[0,\"0x00000\",\"0x2A\"],\"C\":null,\"D\":\"8000\"}" 2231 2232 var decodedS S 2233 err = json.Unmarshal([]byte(withHexValues), &decodedS) 2234 assert.NoError(err) 2235 2236 assert.Equal(s, decodedS, " json with strings -> element failed") 2237 2238 } 2239 2240 type testPairElement struct { 2241 element Element 2242 bigint big.Int 2243 } 2244 2245 func gen() gopter.Gen { 2246 return func(genParams *gopter.GenParameters) *gopter.GenResult { 2247 var g testPairElement 2248 2249 g.element = Element{ 2250 genParams.NextUint64(), 2251 genParams.NextUint64(), 2252 genParams.NextUint64(), 2253 genParams.NextUint64(), 2254 } 2255 if qElement[3] != ^uint64(0) { 2256 g.element[3] %= (qElement[3] + 1) 2257 } 2258 2259 for !g.element.smallerThanModulus() { 2260 g.element = Element{ 2261 genParams.NextUint64(), 2262 genParams.NextUint64(), 2263 genParams.NextUint64(), 2264 genParams.NextUint64(), 2265 } 2266 if qElement[3] != ^uint64(0) { 2267 g.element[3] %= (qElement[3] + 1) 2268 } 2269 } 2270 2271 g.element.BigInt(&g.bigint) 2272 genResult := gopter.NewGenResult(g, gopter.NoShrinker) 2273 return genResult 2274 } 2275 } 2276 2277 func genFull() gopter.Gen { 2278 return func(genParams *gopter.GenParameters) *gopter.GenResult { 2279 2280 genRandomFq := func() Element { 2281 var g Element 2282 2283 g = Element{ 2284 genParams.NextUint64(), 2285 genParams.NextUint64(), 2286 genParams.NextUint64(), 2287 genParams.NextUint64(), 2288 } 2289 2290 if qElement[3] != ^uint64(0) { 2291 g[3] %= (qElement[3] + 1) 2292 } 2293 2294 for !g.smallerThanModulus() { 2295 g = Element{ 2296 genParams.NextUint64(), 2297 genParams.NextUint64(), 2298 genParams.NextUint64(), 2299 genParams.NextUint64(), 2300 } 2301 if qElement[3] != ^uint64(0) { 2302 g[3] %= (qElement[3] + 1) 2303 } 2304 } 2305 2306 return g 2307 } 2308 a := genRandomFq() 2309 2310 var carry uint64 2311 a[0], carry = bits.Add64(a[0], qElement[0], carry) 2312 a[1], carry = bits.Add64(a[1], qElement[1], carry) 2313 a[2], carry = bits.Add64(a[2], qElement[2], carry) 2314 a[3], _ = bits.Add64(a[3], qElement[3], carry) 2315 2316 genResult := gopter.NewGenResult(a, gopter.NoShrinker) 2317 return genResult 2318 } 2319 } 2320 2321 func (z *Element) matchVeryBigInt(aHi uint64, aInt *big.Int) error { 2322 var modulus big.Int 2323 var aIntMod big.Int 2324 modulus.SetInt64(1) 2325 modulus.Lsh(&modulus, (Limbs+1)*64) 2326 aIntMod.Mod(aInt, &modulus) 2327 2328 slice := append(z[:], aHi) 2329 2330 return bigIntMatchUint64Slice(&aIntMod, slice) 2331 } 2332 2333 // TODO: Phase out in favor of property based testing 2334 func (z *Element) assertMatchVeryBigInt(t *testing.T, aHi uint64, aInt *big.Int) { 2335 2336 if err := z.matchVeryBigInt(aHi, aInt); err != nil { 2337 t.Error(err) 2338 } 2339 } 2340 2341 // bigIntMatchUint64Slice is a test helper to match big.Int words against a uint64 slice 2342 func bigIntMatchUint64Slice(aInt *big.Int, a []uint64) error { 2343 2344 words := aInt.Bits() 2345 2346 const steps = 64 / bits.UintSize 2347 const filter uint64 = 0xFFFFFFFFFFFFFFFF >> (64 - bits.UintSize) 2348 for i := 0; i < len(a)*steps; i++ { 2349 2350 var wI big.Word 2351 2352 if i < len(words) { 2353 wI = words[i] 2354 } 2355 2356 aI := a[i/steps] >> ((i * bits.UintSize) % 64) 2357 aI &= filter 2358 2359 if uint64(wI) != aI { 2360 return fmt.Errorf("bignum mismatch: disagreement on word %d: %x ≠ %x; %d ≠ %d", i, uint64(wI), aI, uint64(wI), aI) 2361 } 2362 } 2363 2364 return nil 2365 } 2366 2367 func TestElementInversionApproximation(t *testing.T) { 2368 var x Element 2369 for i := 0; i < 1000; i++ { 2370 x.SetRandom() 2371 2372 // Normally small elements are unlikely. Here we give them a higher chance 2373 xZeros := mrand.Int() % Limbs //#nosec G404 weak rng is fine here 2374 for j := 1; j < xZeros; j++ { 2375 x[Limbs-j] = 0 2376 } 2377 2378 a := approximate(&x, x.BitLen()) 2379 aRef := approximateRef(&x) 2380 2381 if a != aRef { 2382 t.Error("Approximation mismatch") 2383 } 2384 } 2385 } 2386 2387 func TestElementInversionCorrectionFactorFormula(t *testing.T) { 2388 const kLimbs = k * Limbs 2389 const power = kLimbs*6 + invIterationsN*(kLimbs-k+1) 2390 factorInt := big.NewInt(1) 2391 factorInt.Lsh(factorInt, power) 2392 factorInt.Mod(factorInt, Modulus()) 2393 2394 var refFactorInt big.Int 2395 inversionCorrectionFactor := Element{ 2396 inversionCorrectionFactorWord0, 2397 inversionCorrectionFactorWord1, 2398 inversionCorrectionFactorWord2, 2399 inversionCorrectionFactorWord3, 2400 } 2401 inversionCorrectionFactor.toBigInt(&refFactorInt) 2402 2403 if refFactorInt.Cmp(factorInt) != 0 { 2404 t.Error("mismatch") 2405 } 2406 } 2407 2408 func TestElementLinearComb(t *testing.T) { 2409 var x Element 2410 var y Element 2411 2412 for i := 0; i < 1000; i++ { 2413 x.SetRandom() 2414 y.SetRandom() 2415 testLinearComb(t, &x, mrand.Int63(), &y, mrand.Int63()) //#nosec G404 weak rng is fine here 2416 } 2417 } 2418 2419 // Probably unnecessary post-dev. In case the output of inv is wrong, this checks whether it's only off by a constant factor. 2420 func TestElementInversionCorrectionFactor(t *testing.T) { 2421 2422 // (1/x)/inv(x) = (1/1)/inv(1) ⇔ inv(1) = x inv(x) 2423 2424 var one Element 2425 var oneInv Element 2426 one.SetOne() 2427 oneInv.Inverse(&one) 2428 2429 for i := 0; i < 100; i++ { 2430 var x Element 2431 var xInv Element 2432 x.SetRandom() 2433 xInv.Inverse(&x) 2434 2435 x.Mul(&x, &xInv) 2436 if !x.Equal(&oneInv) { 2437 t.Error("Correction factor is inconsistent") 2438 } 2439 } 2440 2441 if !oneInv.Equal(&one) { 2442 var i big.Int 2443 oneInv.BigInt(&i) // no montgomery 2444 i.ModInverse(&i, Modulus()) 2445 var fac Element 2446 fac.setBigInt(&i) // back to montgomery 2447 2448 var facTimesFac Element 2449 facTimesFac.Mul(&fac, &Element{ 2450 inversionCorrectionFactorWord0, 2451 inversionCorrectionFactorWord1, 2452 inversionCorrectionFactorWord2, 2453 inversionCorrectionFactorWord3, 2454 }) 2455 2456 t.Error("Correction factor is consistently off by", fac, "Should be", facTimesFac) 2457 } 2458 } 2459 2460 func TestElementBigNumNeg(t *testing.T) { 2461 var a Element 2462 aHi := negL(&a, 0) 2463 if !a.IsZero() || aHi != 0 { 2464 t.Error("-0 != 0") 2465 } 2466 } 2467 2468 func TestElementBigNumWMul(t *testing.T) { 2469 var x Element 2470 2471 for i := 0; i < 1000; i++ { 2472 x.SetRandom() 2473 w := mrand.Int63() //#nosec G404 weak rng is fine here 2474 testBigNumWMul(t, &x, w) 2475 } 2476 } 2477 2478 func TestElementVeryBigIntConversion(t *testing.T) { 2479 xHi := mrand.Uint64() //#nosec G404 weak rng is fine here 2480 var x Element 2481 x.SetRandom() 2482 var xInt big.Int 2483 x.toVeryBigIntSigned(&xInt, xHi) 2484 x.assertMatchVeryBigInt(t, xHi, &xInt) 2485 } 2486 2487 type veryBigInt struct { 2488 asInt big.Int 2489 low Element 2490 hi uint64 2491 } 2492 2493 // genVeryBigIntSigned if sign == 0, no sign is forced 2494 func genVeryBigIntSigned(sign int) gopter.Gen { 2495 return func(genParams *gopter.GenParameters) *gopter.GenResult { 2496 var g veryBigInt 2497 2498 g.low = Element{ 2499 genParams.NextUint64(), 2500 genParams.NextUint64(), 2501 genParams.NextUint64(), 2502 genParams.NextUint64(), 2503 } 2504 2505 g.hi = genParams.NextUint64() 2506 2507 if sign < 0 { 2508 g.hi |= signBitSelector 2509 } else if sign > 0 { 2510 g.hi &= ^signBitSelector 2511 } 2512 2513 g.low.toVeryBigIntSigned(&g.asInt, g.hi) 2514 2515 genResult := gopter.NewGenResult(g, gopter.NoShrinker) 2516 return genResult 2517 } 2518 } 2519 2520 func TestElementMontReduce(t *testing.T) { 2521 2522 parameters := gopter.DefaultTestParameters() 2523 if testing.Short() { 2524 parameters.MinSuccessfulTests = nbFuzzShort 2525 } else { 2526 parameters.MinSuccessfulTests = nbFuzz 2527 } 2528 2529 properties := gopter.NewProperties(parameters) 2530 2531 gen := genVeryBigIntSigned(0) 2532 2533 properties.Property("Montgomery reduction is correct", prop.ForAll( 2534 func(g veryBigInt) bool { 2535 var res Element 2536 var resInt big.Int 2537 2538 montReduce(&resInt, &g.asInt) 2539 res.montReduceSigned(&g.low, g.hi) 2540 2541 return res.matchVeryBigInt(0, &resInt) == nil 2542 }, 2543 gen, 2544 )) 2545 2546 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2547 } 2548 2549 func TestElementMontReduceMultipleOfR(t *testing.T) { 2550 2551 parameters := gopter.DefaultTestParameters() 2552 if testing.Short() { 2553 parameters.MinSuccessfulTests = nbFuzzShort 2554 } else { 2555 parameters.MinSuccessfulTests = nbFuzz 2556 } 2557 2558 properties := gopter.NewProperties(parameters) 2559 2560 gen := ggen.UInt64() 2561 2562 properties.Property("Montgomery reduction is correct", prop.ForAll( 2563 func(hi uint64) bool { 2564 var zero, res Element 2565 var asInt, resInt big.Int 2566 2567 zero.toVeryBigIntSigned(&asInt, hi) 2568 2569 montReduce(&resInt, &asInt) 2570 res.montReduceSigned(&zero, hi) 2571 2572 return res.matchVeryBigInt(0, &resInt) == nil 2573 }, 2574 gen, 2575 )) 2576 2577 properties.TestingRun(t, gopter.ConsoleReporter(false)) 2578 } 2579 2580 func TestElement0Inverse(t *testing.T) { 2581 var x Element 2582 x.Inverse(&x) 2583 if !x.IsZero() { 2584 t.Fail() 2585 } 2586 } 2587 2588 // TODO: Tests like this (update factor related) are common to all fields. Move them to somewhere non-autogen 2589 func TestUpdateFactorSubtraction(t *testing.T) { 2590 for i := 0; i < 1000; i++ { 2591 2592 f0, g0 := randomizeUpdateFactors() 2593 f1, g1 := randomizeUpdateFactors() 2594 2595 for f0-f1 > 1<<31 || f0-f1 <= -1<<31 { 2596 f1 /= 2 2597 } 2598 2599 for g0-g1 > 1<<31 || g0-g1 <= -1<<31 { 2600 g1 /= 2 2601 } 2602 2603 c0 := updateFactorsCompose(f0, g0) 2604 c1 := updateFactorsCompose(f1, g1) 2605 2606 cRes := c0 - c1 2607 fRes, gRes := updateFactorsDecompose(cRes) 2608 2609 if fRes != f0-f1 || gRes != g0-g1 { 2610 t.Error(i) 2611 } 2612 } 2613 } 2614 2615 func TestUpdateFactorsDouble(t *testing.T) { 2616 for i := 0; i < 1000; i++ { 2617 f, g := randomizeUpdateFactors() 2618 2619 if f > 1<<30 || f < (-1<<31+1)/2 { 2620 f /= 2 2621 if g <= 1<<29 && g >= (-1<<31+1)/4 { 2622 g *= 2 //g was kept small on f's account. Now that we're halving f, we can double g 2623 } 2624 } 2625 2626 if g > 1<<30 || g < (-1<<31+1)/2 { 2627 g /= 2 2628 2629 if f <= 1<<29 && f >= (-1<<31+1)/4 { 2630 f *= 2 //f was kept small on g's account. Now that we're halving g, we can double f 2631 } 2632 } 2633 2634 c := updateFactorsCompose(f, g) 2635 cD := c * 2 2636 fD, gD := updateFactorsDecompose(cD) 2637 2638 if fD != 2*f || gD != 2*g { 2639 t.Error(i) 2640 } 2641 } 2642 } 2643 2644 func TestUpdateFactorsNeg(t *testing.T) { 2645 var fMistake bool 2646 for i := 0; i < 1000; i++ { 2647 f, g := randomizeUpdateFactors() 2648 2649 if f == 0x80000000 || g == 0x80000000 { 2650 // Update factors this large can only have been obtained after 31 iterations and will therefore never be negated 2651 // We don't have capacity to store -2³¹ 2652 // Repeat this iteration 2653 i-- 2654 continue 2655 } 2656 2657 c := updateFactorsCompose(f, g) 2658 nc := -c 2659 nf, ng := updateFactorsDecompose(nc) 2660 fMistake = fMistake || nf != -f 2661 if nf != -f || ng != -g { 2662 t.Errorf("Mismatch iteration #%d:\n%d, %d ->\n %d -> %d ->\n %d, %d\n Inputs in hex: %X, %X", 2663 i, f, g, c, nc, nf, ng, f, g) 2664 } 2665 } 2666 if fMistake { 2667 t.Error("Mistake with f detected") 2668 } else { 2669 t.Log("All good with f") 2670 } 2671 } 2672 2673 func TestUpdateFactorsNeg0(t *testing.T) { 2674 c := updateFactorsCompose(0, 0) 2675 t.Logf("c(0,0) = %X", c) 2676 cn := -c 2677 2678 if c != cn { 2679 t.Error("Negation of zero update factors should yield the same result.") 2680 } 2681 } 2682 2683 func TestUpdateFactorDecomposition(t *testing.T) { 2684 var negSeen bool 2685 2686 for i := 0; i < 1000; i++ { 2687 2688 f, g := randomizeUpdateFactors() 2689 2690 if f <= -(1<<31) || f > 1<<31 { 2691 t.Fatal("f out of range") 2692 } 2693 2694 negSeen = negSeen || f < 0 2695 2696 c := updateFactorsCompose(f, g) 2697 2698 fBack, gBack := updateFactorsDecompose(c) 2699 2700 if f != fBack || g != gBack { 2701 t.Errorf("(%d, %d) -> %d -> (%d, %d)\n", f, g, c, fBack, gBack) 2702 } 2703 } 2704 2705 if !negSeen { 2706 t.Fatal("No negative f factors") 2707 } 2708 } 2709 2710 func TestUpdateFactorInitialValues(t *testing.T) { 2711 2712 f0, g0 := updateFactorsDecompose(updateFactorIdentityMatrixRow0) 2713 f1, g1 := updateFactorsDecompose(updateFactorIdentityMatrixRow1) 2714 2715 if f0 != 1 || g0 != 0 || f1 != 0 || g1 != 1 { 2716 t.Error("Update factor initial value constants are incorrect") 2717 } 2718 } 2719 2720 func TestUpdateFactorsRandomization(t *testing.T) { 2721 var maxLen int 2722 2723 //t.Log("|f| + |g| is not to exceed", 1 << 31) 2724 for i := 0; i < 1000; i++ { 2725 f, g := randomizeUpdateFactors() 2726 lf, lg := abs64T32(f), abs64T32(g) 2727 absSum := lf + lg 2728 if absSum >= 1<<31 { 2729 2730 if absSum == 1<<31 { 2731 maxLen++ 2732 } else { 2733 t.Error(i, "Sum of absolute values too large, f =", f, ",g =", g, ",|f| + |g| =", absSum) 2734 } 2735 } 2736 } 2737 2738 if maxLen == 0 { 2739 t.Error("max len not observed") 2740 } else { 2741 t.Log(maxLen, "maxLens observed") 2742 } 2743 } 2744 2745 func randomizeUpdateFactor(absLimit uint32) int64 { 2746 const maxSizeLikelihood = 10 2747 maxSize := mrand.Intn(maxSizeLikelihood) //#nosec G404 weak rng is fine here 2748 2749 absLimit64 := int64(absLimit) 2750 var f int64 2751 switch maxSize { 2752 case 0: 2753 f = absLimit64 2754 case 1: 2755 f = -absLimit64 2756 default: 2757 f = int64(mrand.Uint64()%(2*uint64(absLimit64)+1)) - absLimit64 //#nosec G404 weak rng is fine here 2758 } 2759 2760 if f > 1<<31 { 2761 return 1 << 31 2762 } else if f < -1<<31+1 { 2763 return -1<<31 + 1 2764 } 2765 2766 return f 2767 } 2768 2769 func abs64T32(f int64) uint32 { 2770 if f >= 1<<32 || f < -1<<32 { 2771 panic("f out of range") 2772 } 2773 2774 if f < 0 { 2775 return uint32(-f) 2776 } 2777 return uint32(f) 2778 } 2779 2780 func randomizeUpdateFactors() (int64, int64) { 2781 var f [2]int64 2782 b := mrand.Int() % 2 //#nosec G404 weak rng is fine here 2783 2784 f[b] = randomizeUpdateFactor(1 << 31) 2785 2786 //As per the paper, |f| + |g| \le 2³¹. 2787 f[1-b] = randomizeUpdateFactor(1<<31 - abs64T32(f[b])) 2788 2789 //Patching another edge case 2790 if f[0]+f[1] == -1<<31 { 2791 b = mrand.Int() % 2 //#nosec G404 weak rng is fine here 2792 f[b]++ 2793 } 2794 2795 return f[0], f[1] 2796 } 2797 2798 func testLinearComb(t *testing.T, x *Element, xC int64, y *Element, yC int64) { 2799 2800 var p1 big.Int 2801 x.toBigInt(&p1) 2802 p1.Mul(&p1, big.NewInt(xC)) 2803 2804 var p2 big.Int 2805 y.toBigInt(&p2) 2806 p2.Mul(&p2, big.NewInt(yC)) 2807 2808 p1.Add(&p1, &p2) 2809 p1.Mod(&p1, Modulus()) 2810 montReduce(&p1, &p1) 2811 2812 var z Element 2813 z.linearComb(x, xC, y, yC) 2814 z.assertMatchVeryBigInt(t, 0, &p1) 2815 } 2816 2817 func testBigNumWMul(t *testing.T, a *Element, c int64) { 2818 var aHi uint64 2819 var aTimes Element 2820 aHi = aTimes.mulWNonModular(a, c) 2821 2822 assertMulProduct(t, a, c, &aTimes, aHi) 2823 } 2824 2825 func updateFactorsCompose(f int64, g int64) int64 { 2826 return f + g<<32 2827 } 2828 2829 var rInv big.Int 2830 2831 func montReduce(res *big.Int, x *big.Int) { 2832 if rInv.BitLen() == 0 { // initialization 2833 rInv.SetUint64(1) 2834 rInv.Lsh(&rInv, Limbs*64) 2835 rInv.ModInverse(&rInv, Modulus()) 2836 } 2837 res.Mul(x, &rInv) 2838 res.Mod(res, Modulus()) 2839 } 2840 2841 func (z *Element) toVeryBigIntUnsigned(i *big.Int, xHi uint64) { 2842 z.toBigInt(i) 2843 var upperWord big.Int 2844 upperWord.SetUint64(xHi) 2845 upperWord.Lsh(&upperWord, Limbs*64) 2846 i.Add(&upperWord, i) 2847 } 2848 2849 func (z *Element) toVeryBigIntSigned(i *big.Int, xHi uint64) { 2850 z.toVeryBigIntUnsigned(i, xHi) 2851 if signBitSelector&xHi != 0 { 2852 twosCompModulus := big.NewInt(1) 2853 twosCompModulus.Lsh(twosCompModulus, (Limbs+1)*64) 2854 i.Sub(i, twosCompModulus) 2855 } 2856 } 2857 2858 func assertMulProduct(t *testing.T, x *Element, c int64, result *Element, resultHi uint64) big.Int { 2859 var xInt big.Int 2860 x.toBigInt(&xInt) 2861 2862 xInt.Mul(&xInt, big.NewInt(c)) 2863 2864 result.assertMatchVeryBigInt(t, resultHi, &xInt) 2865 return xInt 2866 } 2867 2868 func approximateRef(x *Element) uint64 { 2869 2870 var asInt big.Int 2871 x.toBigInt(&asInt) 2872 n := x.BitLen() 2873 2874 if n <= 64 { 2875 return asInt.Uint64() 2876 } 2877 2878 modulus := big.NewInt(1 << 31) 2879 var lo big.Int 2880 lo.Mod(&asInt, modulus) 2881 2882 modulus.Lsh(modulus, uint(n-64)) 2883 var hi big.Int 2884 hi.Div(&asInt, modulus) 2885 hi.Lsh(&hi, 31) 2886 2887 hi.Add(&hi, &lo) 2888 return hi.Uint64() 2889 }