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:
parent
9927f25d71
commit
88562dc83e
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
110
src/math/big/prime.go
Normal 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
100
src/math/big/prime_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user