Skip to content

Commit

Permalink
Extended Miller-Rabin Primality test [code]
Browse files Browse the repository at this point in the history
* 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
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 225 deletions.
46 changes: 24 additions & 22 deletions Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,27 @@
print("Hello, Swift 4!")
#endif

// Real primes
mrPrimalityTest(5)
mrPrimalityTest(439)
mrPrimalityTest(1201)
mrPrimalityTest(143477)
mrPrimalityTest(1299869)
mrPrimalityTest(15487361)
mrPrimalityTest(179426363)
mrPrimalityTest(32416187747)

// Fake primes
mrPrimalityTest(15)
mrPrimalityTest(435)
mrPrimalityTest(1207)
mrPrimalityTest(143473)
mrPrimalityTest(1291869)
mrPrimalityTest(15487161)
mrPrimalityTest(178426363)
mrPrimalityTest(32415187747)

// With iteration
mrPrimalityTest(32416190071, iteration: 10)
do {
// Real primes
try checkWithMillerRabin(5)
try checkWithMillerRabin(439)
try checkWithMillerRabin(1201)
try checkWithMillerRabin(143477)
try checkWithMillerRabin(1299869)
try checkWithMillerRabin(15487361)
try checkWithMillerRabin(179426363)

// Fake primes
try checkWithMillerRabin(15)
try checkWithMillerRabin(435)
try checkWithMillerRabin(1207)
try checkWithMillerRabin(143473)
try checkWithMillerRabin(1291869)
try checkWithMillerRabin(15487161)
try checkWithMillerRabin(178426363)

// Specifying accuracy
try checkWithMillerRabin(179426363, accuracy: 10)
} catch {
dump(error)
}

This file was deleted.

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
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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>
Loading

0 comments on commit 56e0547

Please sign in to comment.