1
0
mirror of https://github.com/golang/go synced 2024-11-05 15:46:11 -07:00

math/big: move ProbablyPrime into its own source file

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>
This commit is contained in:
Russ Cox 2016-10-10 16:03:13 -04:00
parent 9927f25d71
commit 88562dc83e
5 changed files with 210 additions and 193 deletions

View 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

View 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

View 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

110
src/math/big/prime.go Normal file
View File

@ -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
}

100
src/math/big/prime_test.go Normal file
View File

@ -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)
}
})
}
}