forked from kodecocodes/swift-algorithm-club
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Simon C. Krüger
committed
Oct 26, 2018
1 parent
a31bd41
commit 56e0547
Showing
7 changed files
with
221 additions
and
225 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 0 additions & 111 deletions
111
Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift
This file was deleted.
Oops, something went wrong.
100 changes: 100 additions & 0 deletions
100
Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// | ||
// MRPrimality.swift | ||
// | ||
// | ||
// Created by Sahn Cha on 2016. 10. 18.. | ||
// | ||
// | ||
|
||
import Foundation | ||
|
||
enum MillerRabinError: Error { | ||
case primeLowAccuracy | ||
case primeLowerBorder | ||
case uIntOverflow | ||
} | ||
|
||
/* | ||
The Miller–Rabin test relies on an equality or set of equalities that | ||
hold true for prime values, then checks whether or not they hold for | ||
a number that we want to test for primality. | ||
|
||
- Parameter n: an odd integer to be tested for primality; | ||
- Parameter k: a parameter that determines the accuracy of the test | ||
- throws: Can throw an error of type `MillerRabinError`. | ||
- Returns: composite if n is composite, otherwise probably prime | ||
*/ | ||
public func checkWithMillerRabin(_ n: UInt, accuracy k: UInt = 1) throws -> Bool { | ||
guard k > 0 else { throw MillerRabinError.primeLowAccuracy } | ||
guard n > 0 else { throw MillerRabinError.primeLowerBorder } | ||
guard n > 3 else { return true } | ||
|
||
// return false for all even numbers bigger than 2 | ||
if n % 2 == 0 { | ||
return false | ||
} | ||
|
||
let s: UInt = UInt((n - 1).trailingZeroBitCount) | ||
let d: UInt = (n - 1) >> s | ||
|
||
guard UInt(pow(2.0, Double(s))) * d == n - 1 else { throw MillerRabinError.primeLowerBorder } | ||
|
||
/// Inspect whether a given witness will reveal the true identity of n. | ||
func tryComposite(_ a: UInt, d: UInt, n: UInt) throws -> Bool? { | ||
var x = try calculateModularExponentiation(base: a, exponent: d, modulus: n) | ||
if x == 1 || x == (n - 1) { | ||
return nil | ||
} | ||
for _ in 1..<s { | ||
x = try calculateModularExponentiation(base: x, exponent: 2, modulus: n) | ||
if x == 1 { | ||
return false | ||
} else if x == (n - 1) { | ||
return nil | ||
} | ||
} | ||
return false | ||
} | ||
|
||
for _ in 0..<k { | ||
let a = UInt.random(in: 2..<n-2) | ||
if let composite = try tryComposite(a, d: d, n: n) { | ||
return composite | ||
} | ||
} | ||
|
||
return true | ||
} | ||
|
||
/* | ||
Calculates the modular exponentiation based on `Applied Cryptography by Bruce Schneier.` | ||
in `Schneier, Bruce (1996). Applied Cryptography: Protocols, Algorithms, | ||
and Source Code in C, Second Edition (2nd ed.). Wiley. ISBN 978-0-471-11709-4.` | ||
|
||
- Parameter base: The natural base b. | ||
- Parameter base: The natural exponent e. | ||
- Parameter base: The natural modulus m. | ||
- Throws: Can throw a `uIntOverflow` if the modulus' square exceeds the memory | ||
limitations of UInt on the current system. | ||
- Returns: The modular exponentiation c. | ||
*/ | ||
private func calculateModularExponentiation(base: UInt, exponent: UInt, modulus: UInt) throws -> UInt { | ||
guard modulus > 1 else { return 0 } | ||
guard !(modulus-1).multipliedReportingOverflow(by: (modulus-1)).overflow else { | ||
throw MillerRabinError.uIntOverflow | ||
} | ||
|
||
var result: UInt = 1 | ||
var exponentCopy = exponent | ||
var baseCopy = base % modulus | ||
|
||
while exponentCopy > 0 { | ||
if exponentCopy % 2 == 1 { | ||
result = (result * baseCopy) % modulus | ||
} | ||
exponentCopy = exponentCopy >> 1 | ||
baseCopy = (baseCopy * baseCopy) % modulus | ||
} | ||
|
||
return result | ||
} |
7 changes: 7 additions & 0 deletions
7
...bin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
8 changes: 8 additions & 0 deletions
8
... Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>IDEDidComputeMac32BitWarning</key> | ||
<true/> | ||
</dict> | ||
</plist> |
Oops, something went wrong.