initial
This commit is contained in:
commit
535a49bad9
182
main.py
Normal file
182
main.py
Normal file
|
@ -0,0 +1,182 @@
|
|||
#!/usr/bin/env python3
|
||||
import math
|
||||
import random
|
||||
from itertools import combinations
|
||||
|
||||
|
||||
def euclid(a, b):
|
||||
"""returns the Greatest Common Divisor of a and b"""
|
||||
a = abs(a)
|
||||
b = abs(b)
|
||||
if a < b:
|
||||
a, b = b, a
|
||||
while b != 0:
|
||||
a, b = b, a % b
|
||||
return a
|
||||
|
||||
|
||||
def coPrime(l):
|
||||
"""returns 'True' if the values in the list L are all co-prime
|
||||
otherwise, it returns 'False'. """
|
||||
for i, j in combinations(l, 2):
|
||||
if euclid(i, j) != 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def extendedEuclid(a, b):
|
||||
"""return a tuple of three values: x, y and z, such that x is
|
||||
the GCD of a and b, and x = y * a + z * b"""
|
||||
if a == 0:
|
||||
return b, 0, 1
|
||||
else:
|
||||
g, y, x = extendedEuclid(b % a, a)
|
||||
return g, x - (b // a) * y, y
|
||||
|
||||
|
||||
def modInv(a, m):
|
||||
"""returns the multiplicative inverse of a in modulo m as a
|
||||
positive value between zero and m-1"""
|
||||
# notice that a and m need to co-prime to each other.
|
||||
if coPrime([a, m]):
|
||||
linearCombination = extendedEuclid(a, m)
|
||||
return linearCombination[1] % m
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def extractTwos(m):
|
||||
"""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
|
||||
|
||||
|
||||
def int2baseTwo(x):
|
||||
"""x is a positive integer. Convert it to base two as a list of integers
|
||||
in reverse order as a list."""
|
||||
# repeating x >>= 1 and x & 1 will do the trick
|
||||
assert x >= 0
|
||||
bitInverse = []
|
||||
while x != 0:
|
||||
bitInverse.append(x & 1)
|
||||
x >>= 1
|
||||
return bitInverse
|
||||
|
||||
|
||||
def millerRabin(n, k):
|
||||
"""
|
||||
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:
|
||||
return True
|
||||
# make sure to return True if n == 2
|
||||
|
||||
if n % 2 == 0:
|
||||
return False
|
||||
# immediately return False for all the even numbers bigger than 2
|
||||
|
||||
extract2 = extractTwos(n - 1)
|
||||
s = extract2[0]
|
||||
d = extract2[1]
|
||||
assert 2 ** s * d == n - 1
|
||||
|
||||
def tryComposite(a):
|
||||
"""Inner function which will inspect whether a given witness
|
||||
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:
|
||||
return None
|
||||
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
|
||||
|
||||
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):
|
||||
"""Return a pseudo prime number roughly between a and b,
|
||||
(could be larger than b). Raise ValueError if cannot find a
|
||||
pseudo prime after 10 * ln(x) + 3 tries. """
|
||||
x = random.randint(a, b)
|
||||
for i in range(0, int(10 * math.log(x) + 3)):
|
||||
if millerRabin(x, k):
|
||||
return x
|
||||
else:
|
||||
x += 1
|
||||
raise ValueError
|
||||
|
||||
|
||||
def newKey(a, b, k):
|
||||
""" Try to find two large pseudo primes roughly between a and b.
|
||||
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)
|
||||
|
||||
while True:
|
||||
e = random.randint(1, m)
|
||||
if coPrime([e, m]):
|
||||
break
|
||||
|
||||
d = modInv(e, m)
|
||||
return (n, e, d)
|
||||
|
||||
|
||||
def encrypt(message, modN, e, blockSize):
|
||||
"""given a string message, public keys and blockSize, encrypt using
|
||||
RSA algorithms."""
|
||||
return pow(message, e, modN)
|
||||
|
||||
|
||||
def decrypt(secret, modN, d, blockSize):
|
||||
"""reverse function of encrypt"""
|
||||
return pow(secret, d, modN)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
n, e, d = newKey(10 ** 100, 10 ** 101, 50)
|
||||
message = 35274764
|
||||
|
||||
print("original message is {}".format(message))
|
||||
print("-"*80)
|
||||
cipher = encrypt(message, n, e, 15)
|
||||
print("cipher text is {}".format(cipher))
|
||||
print("-"*80)
|
||||
deciphered = decrypt(cipher, n, d, 15)
|
||||
print("decrypted message is {}".format(deciphered))
|
||||
|
Loading…
Reference in New Issue
Block a user