github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/src/math/big/prime.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package big
     6  
     7  import "math/rand"
     8  
     9  // ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
    10  // If x is prime, it returns true.
    11  // If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
    12  //
    13  // It is not suitable for judging primes that an adversary may have crafted
    14  // to fool this test.
    15  func (x *Int) ProbablyPrime(n int) bool {
    16  	if n <= 0 {
    17  		panic("non-positive n for ProbablyPrime")
    18  	}
    19  	return !x.neg && x.abs.probablyPrime(n)
    20  }
    21  
    22  // probablyPrime performs n Miller-Rabin tests to check whether x is prime.
    23  // If x is prime, it returns true.
    24  // If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
    25  //
    26  // It is not suitable for judging primes that an adversary may have crafted
    27  // to fool this test.
    28  func (n nat) probablyPrime(reps int) bool {
    29  	if len(n) == 0 {
    30  		return false
    31  	}
    32  
    33  	if len(n) == 1 {
    34  		if n[0] < 2 {
    35  			return false
    36  		}
    37  
    38  		if n[0]%2 == 0 {
    39  			return n[0] == 2
    40  		}
    41  
    42  		// We have to exclude these cases because we reject all
    43  		// multiples of these numbers below.
    44  		switch n[0] {
    45  		case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
    46  			return true
    47  		}
    48  	}
    49  
    50  	if n[0]&1 == 0 {
    51  		return false // n is even
    52  	}
    53  
    54  	const primesProduct32 = 0xC0CFD797         // Π {p ∈ primes, 2 < p <= 29}
    55  	const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
    56  
    57  	var r Word
    58  	switch _W {
    59  	case 32:
    60  		r = n.modW(primesProduct32)
    61  	case 64:
    62  		r = n.modW(primesProduct64 & _M)
    63  	default:
    64  		panic("Unknown word size")
    65  	}
    66  
    67  	if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
    68  		r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
    69  		return false
    70  	}
    71  
    72  	if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
    73  		r%43 == 0 || r%47 == 0 || r%53 == 0) {
    74  		return false
    75  	}
    76  
    77  	nm1 := nat(nil).sub(n, natOne)
    78  	// determine q, k such that nm1 = q << k
    79  	k := nm1.trailingZeroBits()
    80  	q := nat(nil).shr(nm1, k)
    81  
    82  	nm3 := nat(nil).sub(nm1, natTwo)
    83  	rand := rand.New(rand.NewSource(int64(n[0])))
    84  
    85  	var x, y, quotient nat
    86  	nm3Len := nm3.bitLen()
    87  
    88  NextRandom:
    89  	for i := 0; i < reps; i++ {
    90  		x = x.random(rand, nm3, nm3Len)
    91  		x = x.add(x, natTwo)
    92  		y = y.expNN(x, q, n)
    93  		if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
    94  			continue
    95  		}
    96  		for j := uint(1); j < k; j++ {
    97  			y = y.mul(y, y)
    98  			quotient, y = quotient.div(y, y, n)
    99  			if y.cmp(nm1) == 0 {
   100  				continue NextRandom
   101  			}
   102  			if y.cmp(natOne) == 0 {
   103  				return false
   104  			}
   105  		}
   106  		return false
   107  	}
   108  
   109  	return true
   110  }