Altered algorithms, added comments
This commit is contained in:
parent
310e3b3b2a
commit
02489adde9
163
main.py
163
main.py
|
@ -5,7 +5,8 @@ from itertools import combinations
|
||||||
|
|
||||||
|
|
||||||
def euclid(a, b):
|
def euclid(a, b):
|
||||||
"""returns the Greatest Common Divisor of a and b"""
|
"""returns the Greatest Common Divisor of a and b.
|
||||||
|
Inspired by https://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations"""
|
||||||
a = abs(a)
|
a = abs(a)
|
||||||
b = abs(b)
|
b = abs(b)
|
||||||
if a < b:
|
if a < b:
|
||||||
|
@ -15,156 +16,136 @@ def euclid(a, b):
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
|
||||||
def coPrime(l):
|
def coPrime(x, y):
|
||||||
"""returns 'True' if the values in the list L are all co-prime
|
"""returns 'True' if the values in the list L are all co-prime
|
||||||
otherwise, it returns 'False'. """
|
otherwise, it returns 'False'. """
|
||||||
for i, j in combinations(l, 2):
|
if euclid(x, y) != 1:
|
||||||
if euclid(i, j) != 1:
|
return False
|
||||||
return False
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def extendedEuclid(a, b):
|
def iterative_extended_euclid(a, b):
|
||||||
"""return a tuple of three values: x, y and z, such that x is
|
""" returns the GCD (in old_r) of a and b as well as the "Bezout's Identity" such that
|
||||||
the GCD of a and b, and x = y * a + z * b"""
|
a*old_s + b*old_t = GCD(a,b).
|
||||||
if a == 0:
|
Algorithm is adopted from https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Pseudocode
|
||||||
return b, 0, 1
|
"""
|
||||||
else:
|
old_r, r = a, b
|
||||||
g, y, x = extendedEuclid(b % a, a)
|
old_s, s = 1, 0
|
||||||
return g, x - (b // a) * y, y
|
old_t, t = 0, 1
|
||||||
|
|
||||||
|
while r != 0:
|
||||||
|
quotient = old_r // r
|
||||||
|
old_r, r = r, old_r - (quotient * r)
|
||||||
|
old_s, s = s, old_s - (quotient * s)
|
||||||
|
old_t, t = t, old_t - (quotient * t)
|
||||||
|
|
||||||
|
print(old_r, old_s, old_t)
|
||||||
|
return old_r, old_s, old_t
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def modInv(a, m):
|
def modInv(a, m):
|
||||||
"""returns the multiplicative inverse of a in modulo m as a
|
"""returns the multiplicative inverse of a in modulo m as a
|
||||||
positive value between zero and m-1"""
|
positive value between zero and m-1
|
||||||
# notice that a and m need to be co-prime to each other.
|
Adopted from https://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Extended_Euclidean_algorithm
|
||||||
if coPrime([a, m]):
|
"""
|
||||||
linearCombination = extendedEuclid(a, m)
|
if coPrime(a, m):
|
||||||
return linearCombination[1] % m
|
linear_combination = iterative_extended_euclid(a, m)
|
||||||
|
print(linear_combination[1] % m)
|
||||||
|
return linear_combination[1] % m
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def extractTwos(m):
|
def miller_rabin(n, k):
|
||||||
"""m is a positive integer. A tuple (s, d) of integers is returned
|
|
||||||
such that m = (2 ** s) * d."""
|
|
||||||
# the problem can be reduced to counting how many '0's there are in
|
|
||||||
# the end of bin(m). This can be done this way: m & a stretch of '1's
|
|
||||||
# which can be represent as (2 ** n) - 1.
|
|
||||||
assert m >= 0
|
|
||||||
i = 0
|
|
||||||
while m & (2 ** i) == 0:
|
|
||||||
i += 1
|
|
||||||
return i, m >> i
|
|
||||||
|
|
||||||
|
# Implementation uses the Miller-Rabin Primality Test
|
||||||
|
# The optimal number of rounds for this test is 40
|
||||||
|
# See http://stackoverflow.com/questions/6325576/how-many-iterations-of-rabin-miller-should-i-use-for-cryptographic-safe-primes
|
||||||
|
# for justification
|
||||||
|
|
||||||
def millerRabin(n, k):
|
# If number is even, it's a composite number
|
||||||
"""
|
|
||||||
Miller Rabin pseudo-prime test
|
|
||||||
return True means likely a prime, (how sure about that, depending on k)
|
|
||||||
return False means definitely a composite.
|
|
||||||
Raise assertion error when n, k are not positive integers
|
|
||||||
and n is not 1
|
|
||||||
"""
|
|
||||||
assert n >= 1
|
|
||||||
# ensure n is bigger than 1
|
|
||||||
assert k > 0
|
|
||||||
# ensure k is a positive integer so everything down here makes sense
|
|
||||||
|
|
||||||
if n == 2:
|
if n == 2:
|
||||||
return True
|
return True
|
||||||
# make sure to return True if n == 2
|
|
||||||
|
|
||||||
if n % 2 == 0:
|
if n % 2 == 0:
|
||||||
return False
|
return False
|
||||||
# immediately return False for all the even numbers bigger than 2
|
|
||||||
|
|
||||||
extract2 = extractTwos(n - 1)
|
r, s = 0, n - 1
|
||||||
s = extract2[0]
|
while s % 2 == 0:
|
||||||
d = extract2[1]
|
r += 1
|
||||||
assert 2 ** s * d == n - 1
|
s //= 2
|
||||||
|
for _ in range(k):
|
||||||
def tryComposite(a):
|
a = random.randrange(2, n - 1)
|
||||||
"""Inner function which will inspect whether a given witness
|
x = pow(a, s, n)
|
||||||
will reveal the true identity of n. Will only be called within
|
|
||||||
millerRabin"""
|
|
||||||
x = pow(a,d,n)
|
|
||||||
if x == 1 or x == n - 1:
|
if x == 1 or x == n - 1:
|
||||||
return None
|
continue
|
||||||
|
for _ in range(r - 1):
|
||||||
|
x = pow(x, 2, n)
|
||||||
|
if x == n - 1:
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
for j in range(1, s):
|
|
||||||
x = pow(x,2,n)
|
|
||||||
if x == 1:
|
|
||||||
return False
|
|
||||||
elif x == n - 1:
|
|
||||||
return None
|
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
for i in range(0, k):
|
|
||||||
a = random.randint(2, n - 2)
|
|
||||||
if tryComposite(a) == False:
|
|
||||||
return False
|
|
||||||
return True # actually, we should return probably true.
|
|
||||||
|
|
||||||
|
|
||||||
def findAPrime(a, b, k):
|
def findAPrime(a, b, k):
|
||||||
"""Return a pseudo prime number roughly between a and b,
|
"""Return a pseudo prime number roughly between a and b,
|
||||||
(could be larger than b). Raise ValueError if cannot find a
|
(could be larger than b). """
|
||||||
pseudo prime after 10 * ln(x) + 3 tries. """
|
|
||||||
x = random.randint(a, b)
|
x = random.randint(a, b)
|
||||||
for i in range(0, int(10 * math.log(x) + 3)):
|
while True:
|
||||||
if millerRabin(x, k):
|
if miller_rabin(x, k):
|
||||||
return x
|
return x
|
||||||
else:
|
else:
|
||||||
x += 1
|
x += 1
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
|
|
||||||
def newKey(a, b, k):
|
def newKey(a, b, k):
|
||||||
""" Try to find two large pseudo primes roughly between a and b.
|
""" Try to find two large pseudo primes roughly between a and b.
|
||||||
Generate public and private keys for RSA encryption.
|
Generate public and private keys for RSA encryption."""
|
||||||
Raises ValueError if it fails to find one"""
|
|
||||||
try:
|
|
||||||
p = findAPrime(a, b, k)
|
|
||||||
while True:
|
|
||||||
q = findAPrime(a, b, k)
|
|
||||||
if q != p:
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
n = p * q
|
|
||||||
m = (p - 1) * (q - 1)
|
|
||||||
|
|
||||||
|
p = findAPrime(a, b, k)
|
||||||
while True:
|
while True:
|
||||||
e = random.randint(1, m)
|
q = findAPrime(a, b, k)
|
||||||
if coPrime([e, m]):
|
if q != p:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
n = p * q
|
||||||
|
m = (p - 1) * (q - 1) # Compute phi(n) for n=pq where p and q are prime
|
||||||
|
|
||||||
|
# Find and e that is coprime to phi(n) to be used in the public key
|
||||||
|
while True:
|
||||||
|
e = random.randint(1, m)
|
||||||
|
if coPrime(e, m):
|
||||||
|
break
|
||||||
|
|
||||||
|
# Let d be the modular inverse to e, to be used as private key
|
||||||
d = modInv(e, m)
|
d = modInv(e, m)
|
||||||
return (n, e, d)
|
return (n, e, d)
|
||||||
|
|
||||||
|
|
||||||
def encrypt(message, modN, e, blockSize):
|
def encrypt(message, modN, e):
|
||||||
"""given a string message, public keys and blockSize, encrypt using
|
"""given a string message, public keys and blockSize, encrypt using
|
||||||
RSA algorithms."""
|
RSA algorithms."""
|
||||||
return pow(message, e, modN)
|
return pow(message, e, modN)
|
||||||
|
|
||||||
|
|
||||||
def decrypt(secret, modN, d, blockSize):
|
def decrypt(secret, modN, d):
|
||||||
"""reverse function of encrypt"""
|
"""reverse function of encrypt"""
|
||||||
return pow(secret, d, modN)
|
return pow(secret, d, modN)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
n, e, d = newKey(2**40, 2 ** 41, 20)
|
n, e, d = newKey(2**40, 2 ** 41, 20)
|
||||||
message = 35274764
|
message = 35274764
|
||||||
|
|
||||||
print("original message is {}".format(message))
|
print("original message is {}".format(message))
|
||||||
print("-"*80)
|
print("-"*80)
|
||||||
cipher = encrypt(message, n, e, 15)
|
cipher = encrypt(message, n, e)
|
||||||
print("cipher text is {}".format(cipher))
|
print("cipher text is {}".format(cipher))
|
||||||
print("-"*80)
|
print("-"*80)
|
||||||
deciphered = decrypt(cipher, n, d, 15)
|
deciphered = decrypt(cipher, n, d)
|
||||||
print("decrypted message is {}".format(deciphered))
|
print("decrypted message is {}".format(deciphered))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user