Skip to content

Commit 479bfd0

Browse files
authored
Merge pull request kodecocodes#819 from kayoslab/miller-rabin-primality-test-code-improvement
Extended Miller-Rabin Primality test [code]
2 parents 264a5d1 + e540929 commit 479bfd0

File tree

6 files changed

+209
-225
lines changed

6 files changed

+209
-225
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
//: Playground - noun: a place where people can play
22

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

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

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)