-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathRA2.swift
158 lines (138 loc) · 5.12 KB
/
RA2.swift
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
//
// RA2.swift
// AlgorithmsSwift
//
// Created by Michael Ho on 12/12/20.
//
import Foundation
class RA2 {
/**
Euler Totient Function, count all number under n and is a co-prime number of n.
For example, phi(5) = 4 since 1, 2, 3, 4 are the 4 numbers that are co-prime of 5 and are under 5.
- Parameter n: The number to find the count of co-primes.
- Returns: The count of co-primes.
*/
func phi(_ n: Int) -> Int {
var result = 1
for i in 2..<n {
if RA1.GreatestCommonDivisor.euclidAlgorithm(i, n) == 1 {
result += 1
}
}
return result
}
/**
Determine if the number is a prime number.
- Parameter number: The number to be determined.
- Returns: A boolean indicate whether the number is a prime number.
*/
func isPrime(_ number: Int) -> Bool {
// Corner case
if number <= 1 {
return false
}
let sqrtAtInt = Int(sqrt(Double(number)))
for i in 2...sqrtAtInt {
if number % i == 0 {
return false
}
}
return true
}
/**
Determine if the number is a prime number using Fermat's method.
Reference: https://www.geeksforgeeks.org/primality-test-set-2-fermet-method/
- Parameter number: The number to be determined.
- Parameter k: Try k times.
- Returns: A boolean indicate whether the number is a prime number.
*/
func isPrimeByFermat(_ number: Int, _ k: Int) -> Bool {
// Handle edge cases where n = 1, 2, 3, 4
if number <= 1 || number == 4 {
return true
} else if number <= 3 {
return true
}
var k = k
// Try k times.
while k > 0 {
// Pick a random number in [2..n-2]
let x = 2 + Int.random(in: 0...number) % (number - 4)
// Fermat's little theorem
if RA1.modularExp(x, number - 1, number) != 1 {
return false
}
k -= 1
}
return true
}
/**
This class consists of algorithms required to perform RSA, which are generating public key pair,
private key pair, encryption, and decryption.
Steps for receiver setup:
1. Pick 2 n-bit random primes p and q.
2. Choose e relatively prime to (p - 1)(q - 1), e.g., e = 3, 5, 7, 11...
3. Publish a public key (N, e)
4. Computes private key: d = (e^-1)mod(p - 1)(q - 1)
Steps for sender:
1. Look up public key (N, e)
2. Send a message m, encrypt it to y, where y = (m^e)mod(N)
3. Send y.
Steps for receiver receiving:
1. Receive y.
2. Use d from private key to descrypt.
3. Decrypt by computing (y^d)mod(N) = m, where m is the original messsage.
*/
class RSA {
/**
Generate public key pair. The current recommendation for n = pq is n to be at least 2048 bits.
- Parameter p: First selected prime number.
- Parameter q: Second selected prime number.
- Returns: A tuple represents the public key pair.
*/
func getPublicKeyPair(_ p: Int, _ q: Int) -> (N: Int, e: Int) {
var e = 2
// In practice, it's recommended to pick e as one of a set of known prime values.
let phi = (p - 1)*(q - 1)
while e < phi {
if RA1.GreatestCommonDivisor.euclidAlgorithm(e, phi) == 1 {
break
} else {
e += 1
}
}
let N = p*q
return (N, e)
}
/**
Generate private key.
- Parameter p: The p chosen in public key.
- Parameter q: The q chosen in public key.
- Parameter e: The e computed when public key genereated.
- Returns: A tuple represents the public key pair.
*/
func getPrivateKey(_ p: Int, _ q: Int, _ e: Int) -> Int {
return RA1.multiplicativeInverse(e, (p - 1)*(q - 1))
}
/**
The implementation of RSA encryption, which requires public key.
Encryption c = (msg ^ e) % n
- Parameter message: The message to be encrypted.
- Parameter publicKeyPair: The public key pair which must have N (=p*q) and e.
- Returns: The encrypted message.
*/
func encrypt(_ message: Int, _ publicKeyPair: (N: Int, e: Int)) -> Int {
return RA1.modularExp(message, publicKeyPair.e, publicKeyPair.N)
}
/**
The implementation of RSA decryption, which requires private key.
- Parameter encryptedMessage: The encrypted message to be decrypted.
- Parameter N: The number where N = p*q.
- Parameter privateKey: The private key (d).
- Returns: The decrypted message.
*/
func decrypt(_ encryptedMessage: Int, _ N: Int, _ privateKey: Int) -> Int {
return RA1.modularExp(encryptedMessage, privateKey, N)
}
}
}