]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: move ProbablyPrime into its own source file
authorRuss Cox <rsc@golang.org>
Mon, 10 Oct 2016 20:03:13 +0000 (16:03 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 11 Oct 2016 16:16:17 +0000 (16:16 +0000)
A later CL will be adding more code here.
It will help to keep it separate from the other code.

Change-Id: I971ba53de819cd10991b51fdec665984939a5f9b
Reviewed-on: https://go-review.googlesource.com/30709
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/math/big/int.go
src/math/big/int_test.go
src/math/big/nat.go
src/math/big/prime.go [new file with mode: 0644]
src/math/big/prime_test.go [new file with mode: 0644]

index e8bd13f5b3be0dae3b3e48d32f8e3f7af1aa8f02..51dc6f78ff9a434f26778612fd49a7d0bea1f7bd 100644 (file)
@@ -550,19 +550,6 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
        return z.Lsh(u, k)
 }
 
-// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
-// If x is prime, it returns true.
-// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
-//
-// It is not suitable for judging primes that an adversary may have crafted
-// to fool this test.
-func (x *Int) ProbablyPrime(n int) bool {
-       if n <= 0 {
-               panic("non-positive n for ProbablyPrime")
-       }
-       return !x.neg && x.abs.probablyPrime(n)
-}
-
 // Rand sets z to a pseudo-random number in [0, n) and returns z.
 func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
        z.neg = false
index 2b62ad8120164731ca252851629a7d632c966844..18f5be749dd7966053b8134c6b01fa61a4e3460b 100644 (file)
@@ -760,96 +760,6 @@ func TestGcd(t *testing.T) {
        }
 }
 
-var primes = []string{
-       "2",
-       "3",
-       "5",
-       "7",
-       "11",
-
-       "13756265695458089029",
-       "13496181268022124907",
-       "10953742525620032441",
-       "17908251027575790097",
-
-       // https://golang.org/issue/638
-       "18699199384836356663",
-
-       "98920366548084643601728869055592650835572950932266967461790948584315647051443",
-       "94560208308847015747498523884063394671606671904944666360068158221458669711639",
-
-       // http://primes.utm.edu/lists/small/small3.html
-       "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
-       "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
-       "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
-       "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
-
-       // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
-       "3618502788666131106986593281521497120414687020801267626233049500247285301239",                                                                                  // Curve1174: 2^251-9
-       "57896044618658097711785492504343953926634992332820282019728792003956564819949",                                                                                 // Curve25519: 2^255-19
-       "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599",                                           // E-382: 2^382-105
-       "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367",                                 // Curve41417: 2^414-17
-       "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
-}
-
-var composites = []string{
-       "0",
-       "1",
-       "21284175091214687912771199898307297748211672914763848041968395774954376176754",
-       "6084766654921918907427900243509372380954290099172559290432744450051395395951",
-       "84594350493221918389213352992032324280367711247940675652888030554255915464401",
-       "82793403787388584738507275144194252681",
-}
-
-func TestProbablyPrime(t *testing.T) {
-       nreps := 20
-       if testing.Short() {
-               nreps = 1
-       }
-       for i, s := range primes {
-               p, _ := new(Int).SetString(s, 10)
-               if !p.ProbablyPrime(nreps) {
-                       t.Errorf("#%d prime found to be non-prime (%s)", i, s)
-               }
-       }
-
-       for i, s := range composites {
-               c, _ := new(Int).SetString(s, 10)
-               if c.ProbablyPrime(nreps) {
-                       t.Errorf("#%d composite found to be prime (%s)", i, s)
-               }
-               if testing.Short() {
-                       break
-               }
-       }
-
-       // check that ProbablyPrime panics if n <= 0
-       c := NewInt(11) // a prime
-       for _, n := range []int{-1, 0, 1} {
-               func() {
-                       defer func() {
-                               if n <= 0 && recover() == nil {
-                                       t.Fatalf("expected panic from ProbablyPrime(%d)", n)
-                               }
-                       }()
-                       if !c.ProbablyPrime(n) {
-                               t.Fatalf("%v should be a prime", c)
-                       }
-               }()
-       }
-}
-
-func BenchmarkProbablyPrime(b *testing.B) {
-       p, _ := new(Int).SetString("203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123", 10)
-       for _, rep := range []int{1, 5, 10, 20} {
-               b.Run(fmt.Sprintf("Rep=%d", rep), func(b *testing.B) {
-                       for i := 0; i < b.N; i++ {
-                               p.ProbablyPrime(rep)
-                       }
-               })
-       }
-}
-
 type intShiftTest struct {
        in    string
        shift uint
index ae5f70cf4218e2d0bfc43d16c4571c155a994a14..4a3b7ae33f2be14e8c26f8f3cb7a932a9da03d1d 100644 (file)
@@ -1179,96 +1179,6 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
        return zz.norm()
 }
 
-// probablyPrime performs n Miller-Rabin tests to check whether x is prime.
-// If x is prime, it returns true.
-// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
-//
-// It is not suitable for judging primes that an adversary may have crafted
-// to fool this test.
-func (n nat) probablyPrime(reps int) bool {
-       if len(n) == 0 {
-               return false
-       }
-
-       if len(n) == 1 {
-               if n[0] < 2 {
-                       return false
-               }
-
-               if n[0]%2 == 0 {
-                       return n[0] == 2
-               }
-
-               // We have to exclude these cases because we reject all
-               // multiples of these numbers below.
-               switch n[0] {
-               case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
-                       return true
-               }
-       }
-
-       if n[0]&1 == 0 {
-               return false // n is even
-       }
-
-       const primesProduct32 = 0xC0CFD797         // Π {p ∈ primes, 2 < p <= 29}
-       const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
-
-       var r Word
-       switch _W {
-       case 32:
-               r = n.modW(primesProduct32)
-       case 64:
-               r = n.modW(primesProduct64 & _M)
-       default:
-               panic("Unknown word size")
-       }
-
-       if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
-               r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
-               return false
-       }
-
-       if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
-               r%43 == 0 || r%47 == 0 || r%53 == 0) {
-               return false
-       }
-
-       nm1 := nat(nil).sub(n, natOne)
-       // determine q, k such that nm1 = q << k
-       k := nm1.trailingZeroBits()
-       q := nat(nil).shr(nm1, k)
-
-       nm3 := nat(nil).sub(nm1, natTwo)
-       rand := rand.New(rand.NewSource(int64(n[0])))
-
-       var x, y, quotient nat
-       nm3Len := nm3.bitLen()
-
-NextRandom:
-       for i := 0; i < reps; i++ {
-               x = x.random(rand, nm3, nm3Len)
-               x = x.add(x, natTwo)
-               y = y.expNN(x, q, n)
-               if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
-                       continue
-               }
-               for j := uint(1); j < k; j++ {
-                       y = y.mul(y, y)
-                       quotient, y = quotient.div(y, y, n)
-                       if y.cmp(nm1) == 0 {
-                               continue NextRandom
-                       }
-                       if y.cmp(natOne) == 0 {
-                               return false
-                       }
-               }
-               return false
-       }
-
-       return true
-}
-
 // bytes writes the value of z into buf using big-endian encoding.
 // len(buf) must be >= len(z)*_S. The value of z is encoded in the
 // slice buf[i:]. The number i of unused bytes at the beginning of
diff --git a/src/math/big/prime.go b/src/math/big/prime.go
new file mode 100644 (file)
index 0000000..c1fcc9d
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import "math/rand"
+
+// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
+// If x is prime, it returns true.
+// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
+//
+// It is not suitable for judging primes that an adversary may have crafted
+// to fool this test.
+func (x *Int) ProbablyPrime(n int) bool {
+       if n <= 0 {
+               panic("non-positive n for ProbablyPrime")
+       }
+       return !x.neg && x.abs.probablyPrime(n)
+}
+
+// probablyPrime performs n Miller-Rabin tests to check whether x is prime.
+// If x is prime, it returns true.
+// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
+//
+// It is not suitable for judging primes that an adversary may have crafted
+// to fool this test.
+func (n nat) probablyPrime(reps int) bool {
+       if len(n) == 0 {
+               return false
+       }
+
+       if len(n) == 1 {
+               if n[0] < 2 {
+                       return false
+               }
+
+               if n[0]%2 == 0 {
+                       return n[0] == 2
+               }
+
+               // We have to exclude these cases because we reject all
+               // multiples of these numbers below.
+               switch n[0] {
+               case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
+                       return true
+               }
+       }
+
+       if n[0]&1 == 0 {
+               return false // n is even
+       }
+
+       const primesProduct32 = 0xC0CFD797         // Π {p ∈ primes, 2 < p <= 29}
+       const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
+
+       var r Word
+       switch _W {
+       case 32:
+               r = n.modW(primesProduct32)
+       case 64:
+               r = n.modW(primesProduct64 & _M)
+       default:
+               panic("Unknown word size")
+       }
+
+       if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
+               r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
+               return false
+       }
+
+       if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
+               r%43 == 0 || r%47 == 0 || r%53 == 0) {
+               return false
+       }
+
+       nm1 := nat(nil).sub(n, natOne)
+       // determine q, k such that nm1 = q << k
+       k := nm1.trailingZeroBits()
+       q := nat(nil).shr(nm1, k)
+
+       nm3 := nat(nil).sub(nm1, natTwo)
+       rand := rand.New(rand.NewSource(int64(n[0])))
+
+       var x, y, quotient nat
+       nm3Len := nm3.bitLen()
+
+NextRandom:
+       for i := 0; i < reps; i++ {
+               x = x.random(rand, nm3, nm3Len)
+               x = x.add(x, natTwo)
+               y = y.expNN(x, q, n)
+               if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
+                       continue
+               }
+               for j := uint(1); j < k; j++ {
+                       y = y.mul(y, y)
+                       quotient, y = quotient.div(y, y, n)
+                       if y.cmp(nm1) == 0 {
+                               continue NextRandom
+                       }
+                       if y.cmp(natOne) == 0 {
+                               return false
+                       }
+               }
+               return false
+       }
+
+       return true
+}
diff --git a/src/math/big/prime_test.go b/src/math/big/prime_test.go
new file mode 100644 (file)
index 0000000..8f6d83b
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+       "fmt"
+       "testing"
+)
+
+var primes = []string{
+       "2",
+       "3",
+       "5",
+       "7",
+       "11",
+
+       "13756265695458089029",
+       "13496181268022124907",
+       "10953742525620032441",
+       "17908251027575790097",
+
+       // https://golang.org/issue/638
+       "18699199384836356663",
+
+       "98920366548084643601728869055592650835572950932266967461790948584315647051443",
+       "94560208308847015747498523884063394671606671904944666360068158221458669711639",
+
+       // http://primes.utm.edu/lists/small/small3.html
+       "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
+       "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
+       "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
+       "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+
+       // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
+       "3618502788666131106986593281521497120414687020801267626233049500247285301239",                                                                                  // Curve1174: 2^251-9
+       "57896044618658097711785492504343953926634992332820282019728792003956564819949",                                                                                 // Curve25519: 2^255-19
+       "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599",                                           // E-382: 2^382-105
+       "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367",                                 // Curve41417: 2^414-17
+       "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
+}
+
+var composites = []string{
+       "0",
+       "1",
+       "21284175091214687912771199898307297748211672914763848041968395774954376176754",
+       "6084766654921918907427900243509372380954290099172559290432744450051395395951",
+       "84594350493221918389213352992032324280367711247940675652888030554255915464401",
+       "82793403787388584738507275144194252681",
+}
+
+func TestProbablyPrime(t *testing.T) {
+       nreps := 20
+       if testing.Short() {
+               nreps = 1
+       }
+       for i, s := range primes {
+               p, _ := new(Int).SetString(s, 10)
+               if !p.ProbablyPrime(nreps) {
+                       t.Errorf("#%d prime found to be non-prime (%s)", i, s)
+               }
+       }
+
+       for i, s := range composites {
+               c, _ := new(Int).SetString(s, 10)
+               if c.ProbablyPrime(nreps) {
+                       t.Errorf("#%d composite found to be prime (%s)", i, s)
+               }
+               if testing.Short() {
+                       break
+               }
+       }
+
+       // check that ProbablyPrime panics if n <= 0
+       c := NewInt(11) // a prime
+       for _, n := range []int{-1, 0, 1} {
+               func() {
+                       defer func() {
+                               if n <= 0 && recover() == nil {
+                                       t.Fatalf("expected panic from ProbablyPrime(%d)", n)
+                               }
+                       }()
+                       if !c.ProbablyPrime(n) {
+                               t.Fatalf("%v should be a prime", c)
+                       }
+               }()
+       }
+}
+
+func BenchmarkProbablyPrime(b *testing.B) {
+       p, _ := new(Int).SetString("203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123", 10)
+       for _, rep := range []int{1, 5, 10, 20} {
+               b.Run(fmt.Sprintf("Rep=%d", rep), func(b *testing.B) {
+                       for i := 0; i < b.N; i++ {
+                               p.ProbablyPrime(rep)
+                       }
+               })
+       }
+}