-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
millerrabintest.go
162 lines (145 loc) · 4.5 KB
/
millerrabintest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// This file implements two versions of the Miller-Rabin primality test.
// One of the implementations is deterministic and the other is probabilistic.
// The Miller-Rabin test is one of the simplest and fastest known primality
// tests and is widely used.
// time complexity: O(k * log(n)^3)
// space complexity: O(1)
// Authors:
// [Taj](https://github.com/tjgurwara99)
// [Rak](https://github.com/raklaptudirm)
package prime
import (
"math/rand"
"github.com/TheAlgorithms/Go/math/modular"
)
// formatNum accepts a number and returns the
// odd number d such that num = 2^s * d + 1
func formatNum(num int64) (d int64, s int64) {
d = num - 1
for num%2 == 0 {
d /= 2
s++
}
return
}
// isTrivial checks if num's primality is easy to determine.
// If it is, it returns true and num's primality. Otherwise
// it returns false and false.
func isTrivial(num int64) (prime bool, trivial bool) {
if num <= 4 {
// 2 and 3 are primes
prime = num == 2 || num == 3
trivial = true
} else {
prime = false
// number is trivial prime if
// it is divisible by 2
trivial = num%2 == 0
}
return
}
// MillerTest tests whether num is a strong probable prime to a witness.
// Formally: a^d ≡ 1 (mod n) or a^(2^r * d) ≡ -1 (mod n), 0 <= r <= s
func MillerTest(num, witness int64) (bool, error) {
d, _ := formatNum(num)
res, err := modular.Exponentiation(witness, d, num)
if err != nil {
return false, err
}
// miller conditions checks
if res == 1 || res == num-1 {
return true, nil
}
for d != num-1 {
res = (res * res) % num
d *= 2
if res == 1 {
return false, nil
}
if res == num-1 {
return true, nil
}
}
return false, nil
}
// MillerRandomTest This is the intermediate step that repeats within the
// miller rabin primality test for better probabilitic chances of
// receiving the correct result with random witnesses.
func MillerRandomTest(num int64) (bool, error) {
random := rand.Int63n(num-2) + 2
return MillerTest(num, random)
}
// MillerTestMultiple is like MillerTest but runs the test for multiple
// witnesses.
func MillerTestMultiple(num int64, witnesses ...int64) (bool, error) {
for _, witness := range witnesses {
prime, err := MillerTest(num, witness)
if err != nil {
return false, err
}
if !prime {
return false, nil
}
}
return true, nil
}
// MillerRabinProbabilistic is a probabilistic test for primality
// of an integer based of the algorithm devised by Miller and Rabin.
func MillerRabinProbabilistic(num, rounds int64) (bool, error) {
if prime, trivial := isTrivial(num); trivial {
// num is a trivial number
return prime, nil
}
for i := int64(0); i < rounds; i++ {
val, err := MillerRandomTest(num)
if err != nil {
return false, err
}
if !val {
return false, nil
}
}
return true, nil
}
// MillerRabinDeterministic is a Deterministic version of the Miller-Rabin
// test, which returns correct results for all valid int64 numbers.
func MillerRabinDeterministic(num int64) (bool, error) {
if prime, trivial := isTrivial(num); trivial {
// num is a trivial number
return prime, nil
}
switch {
case num < 2047:
// witness 2 can determine the primality of any number less than 2047
return MillerTest(num, 2)
case num < 1_373_653:
// witnesses 2 and 3 can determine the primality
// of any number less than 1,373,653
return MillerTestMultiple(num, 2, 3)
case num < 9_080_191:
// witnesses 31 and 73 can determine the primality
// of any number less than 9,080,191
return MillerTestMultiple(num, 31, 73)
case num < 25_326_001:
// witnesses 2, 3, and 5 can determine the
// primality of any number less than 25,326,001
return MillerTestMultiple(num, 2, 3, 5)
case num < 1_122_004_669_633:
// witnesses 2, 13, 23, and 1,662,803 can determine the
// primality of any number less than 1,122,004,669,633
return MillerTestMultiple(num, 2, 13, 23, 1_662_803)
case num < 2_152_302_898_747:
// witnesses 2, 3, 5, 7, and 11 can determine the primality
// of any number less than 2,152,302,898,747
return MillerTestMultiple(num, 2, 3, 5, 7, 11)
case num < 341_550_071_728_321:
// witnesses 2, 3, 5, 7, 11, 13, and 17 can determine the
// primality of any number less than 341,550,071,728,321
return MillerTestMultiple(num, 2, 3, 5, 7, 11, 13, 17)
default:
// witnesses 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, and 37 can determine
// the primality of any number less than 318,665,857,834,031,151,167,461
// which is well above the max int64 9,223,372,036,854,775,807
return MillerTestMultiple(num, 2, 3, 5, 7, 11, 13, 17, 19, 23, 31, 37)
}
}