Skip to content

Commit 56e0547

Browse files
author
Simon C. Krüger
committed
Extended Miller-Rabin Primality test [code]
* Adds a more readable documentation and clear naming for variables to the Miller-Rabin Primality Test example * Miller-Rabin can fail under certain situations. These have to throw an error. * Updates the relevant playground files * Add name to documentation
1 parent a31bd41 commit 56e0547

File tree

7 files changed

+221
-225
lines changed

7 files changed

+221
-225
lines changed

Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift

+24-22
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,27 @@
55
print("Hello, Swift 4!")
66
#endif
77

8-
// Real primes
9-
mrPrimalityTest(5)
10-
mrPrimalityTest(439)
11-
mrPrimalityTest(1201)
12-
mrPrimalityTest(143477)
13-
mrPrimalityTest(1299869)
14-
mrPrimalityTest(15487361)
15-
mrPrimalityTest(179426363)
16-
mrPrimalityTest(32416187747)
17-
18-
// Fake primes
19-
mrPrimalityTest(15)
20-
mrPrimalityTest(435)
21-
mrPrimalityTest(1207)
22-
mrPrimalityTest(143473)
23-
mrPrimalityTest(1291869)
24-
mrPrimalityTest(15487161)
25-
mrPrimalityTest(178426363)
26-
mrPrimalityTest(32415187747)
27-
28-
// With iteration
29-
mrPrimalityTest(32416190071, iteration: 10)
8+
do {
9+
// Real primes
10+
try checkWithMillerRabin(5)
11+
try checkWithMillerRabin(439)
12+
try checkWithMillerRabin(1201)
13+
try checkWithMillerRabin(143477)
14+
try checkWithMillerRabin(1299869)
15+
try checkWithMillerRabin(15487361)
16+
try checkWithMillerRabin(179426363)
17+
18+
// Fake primes
19+
try checkWithMillerRabin(15)
20+
try checkWithMillerRabin(435)
21+
try checkWithMillerRabin(1207)
22+
try checkWithMillerRabin(143473)
23+
try checkWithMillerRabin(1291869)
24+
try checkWithMillerRabin(15487161)
25+
try checkWithMillerRabin(178426363)
26+
27+
// Specifying accuracy
28+
try checkWithMillerRabin(179426363, accuracy: 10)
29+
} catch {
30+
dump(error)
31+
}

Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift

-111
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//
2+
// MRPrimality.swift
3+
//
4+
//
5+
// Created by Sahn Cha on 2016. 10. 18..
6+
//
7+
//
8+
9+
import Foundation
10+
11+
enum MillerRabinError: Error {
12+
case primeLowAccuracy
13+
case primeLowerBorder
14+
case uIntOverflow
15+
}
16+
17+
/*
18+
The Miller–Rabin test relies on an equality or set of equalities that
19+
hold true for prime values, then checks whether or not they hold for
20+
a number that we want to test for primality.
21+
22+
- Parameter n: an odd integer to be tested for primality;
23+
- Parameter k: a parameter that determines the accuracy of the test
24+
- throws: Can throw an error of type `MillerRabinError`.
25+
- Returns: composite if n is composite, otherwise probably prime
26+
*/
27+
public func checkWithMillerRabin(_ n: UInt, accuracy k: UInt = 1) throws -> Bool {
28+
guard k > 0 else { throw MillerRabinError.primeLowAccuracy }
29+
guard n > 0 else { throw MillerRabinError.primeLowerBorder }
30+
guard n > 3 else { return true }
31+
32+
// return false for all even numbers bigger than 2
33+
if n % 2 == 0 {
34+
return false
35+
}
36+
37+
let s: UInt = UInt((n - 1).trailingZeroBitCount)
38+
let d: UInt = (n - 1) >> s
39+
40+
guard UInt(pow(2.0, Double(s))) * d == n - 1 else { throw MillerRabinError.primeLowerBorder }
41+
42+
/// Inspect whether a given witness will reveal the true identity of n.
43+
func tryComposite(_ a: UInt, d: UInt, n: UInt) throws -> Bool? {
44+
var x = try calculateModularExponentiation(base: a, exponent: d, modulus: n)
45+
if x == 1 || x == (n - 1) {
46+
return nil
47+
}
48+
for _ in 1..<s {
49+
x = try calculateModularExponentiation(base: x, exponent: 2, modulus: n)
50+
if x == 1 {
51+
return false
52+
} else if x == (n - 1) {
53+
return nil
54+
}
55+
}
56+
return false
57+
}
58+
59+
for _ in 0..<k {
60+
let a = UInt.random(in: 2..<n-2)
61+
if let composite = try tryComposite(a, d: d, n: n) {
62+
return composite
63+
}
64+
}
65+
66+
return true
67+
}
68+
69+
/*
70+
Calculates the modular exponentiation based on `Applied Cryptography by Bruce Schneier.`
71+
in `Schneier, Bruce (1996). Applied Cryptography: Protocols, Algorithms,
72+
and Source Code in C, Second Edition (2nd ed.). Wiley. ISBN 978-0-471-11709-4.`
73+
74+
- Parameter base: The natural base b.
75+
- Parameter base: The natural exponent e.
76+
- Parameter base: The natural modulus m.
77+
- Throws: Can throw a `uIntOverflow` if the modulus' square exceeds the memory
78+
limitations of UInt on the current system.
79+
- Returns: The modular exponentiation c.
80+
*/
81+
private func calculateModularExponentiation(base: UInt, exponent: UInt, modulus: UInt) throws -> UInt {
82+
guard modulus > 1 else { return 0 }
83+
guard !(modulus-1).multipliedReportingOverflow(by: (modulus-1)).overflow else {
84+
throw MillerRabinError.uIntOverflow
85+
}
86+
87+
var result: UInt = 1
88+
var exponentCopy = exponent
89+
var baseCopy = base % modulus
90+
91+
while exponentCopy > 0 {
92+
if exponentCopy % 2 == 1 {
93+
result = (result * baseCopy) % modulus
94+
}
95+
exponentCopy = exponentCopy >> 1
96+
baseCopy = (baseCopy * baseCopy) % modulus
97+
}
98+
99+
return result
100+
}

Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>

0 commit comments

Comments
 (0)