forked from amitfinkel/RSA_project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnumber_theory_functions.py
135 lines (109 loc) · 2.84 KB
/
number_theory_functions.py
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
from random import randrange
from math import floor
from numpy import binary_repr
def extended_gcd(a, b):
"""
Returns the extended gcd of a and b
Parameters
----------
a : Input data.
b : Input data.
Returns
-------
(d, x, y): d = gcd(a,b) = a*x + b*y
"""
# if initially b>a, after one iteration they will switch places
# and the calculation can go on normally.
if a == 0:
return b, 0, 1
d, temp_a, temp_b = extended_gcd(b % a, a)
a = temp_b - floor(b / a) * temp_a
b = temp_a
return d, a, b
def modular_inverse(a, n):
"""
Returns the inverse of a modulo n if one exists
Parameters
----------
a : Input data.
n : Input data.
Returns
-------
x: such that (a*x % n) == 1 and 0 <= x < n if one exists, else None
"""
gcd, x, y = extended_gcd(a, n)
if gcd != 1:
return None
return x % n
def modular_exponent(a, d, n):
"""
Returns a to the power of d modulo n
Parameters
----------
a : The exponential's base.
d : The exponential's exponent.
n : The exponential's modulus.
Returns
-------
b: such that b == (a**d) % n
"""
binary = binary_repr(d)
c = 1
prev = (1, a) # a ** 1 % n = a
for index, i in enumerate(reversed(list(binary))):
if int(i) != 0:
power = 2 ** index
p = int(power / prev[0])
num = prev[1] ** p
num = num % n
prev = (power, num) # a ** power % n = num
c = (c * num) % n
return c
def miller_rabin(n):
"""
Checks the primality of n using the Miller-Rabin test
Parameters
----------
n : The number to check
Returns
-------
b: If n is prime, b is guaranteed to be True.
If n is not a prime, b has a 3/4 chance at least to be False
"""
a = randrange(1, n)
k = 0
d = n - 1
while d % 2 == 0:
k = k + 1
d = d // 2
x = modular_exponent(a, d, n)
if x == 1 or x == n - 1:
return True
for _ in range(k):
x = (x * x) % n
if x == 1:
return False
if x == n - 1:
return True
return False
def is_prime(n):
"""
Checks the primality of n
Parameters
----------
n : The number to check
Returns
-------
b: If n is prime, b is guaranteed to be True.
If n is not a prime, b has a chance of less than 1e-10 to be True
"""
for _ in range(10):
if not miller_rabin(n):
return False
return True
def generate_prime(digits):
for i in range(digits * 20):
n = randrange(10 ** (digits - 1), 10 ** digits)
if is_prime(n):
return n
return None