289 lines
7.3 KiB
Python
289 lines
7.3 KiB
Python
#!/usr/bin/env python3
|
|
|
|
from random import randint, seed, getrandbits
|
|
from math import log2
|
|
from Cryptotools.Utils.utils import gcd
|
|
|
|
|
|
def isPrimeNumber(p):
|
|
"""
|
|
Check if the number p is a prime number or not. The function iterate until p is achieve.
|
|
|
|
This function is not the efficient way to determine if p is prime or a composite.
|
|
|
|
To identify if p is prime or not, the function check the result of the Euclidean Division has a remainder. If yes, it's means it's not a prime number
|
|
|
|
Args:
|
|
p (Integer): number if possible prime or not
|
|
|
|
Returns:
|
|
Return a boolean if the number p is a prime number or not. True if yes
|
|
"""
|
|
for i in range(2, p):
|
|
if p % i == 0:
|
|
return False
|
|
return True
|
|
|
|
# https://people.csail.mit.edu/rivest/Rsapaper.pdf
|
|
# https://arxiv.org/pdf/1912.11546
|
|
# https://link.springer.com/content/pdf/10.1007/3-540-44499-8_27.pdf
|
|
# https://link.springer.com/article/10.1007/BF00202269
|
|
# https://www.geeksforgeeks.org/dsa/how-to-generate-large-prime-numbers-for-rsa-algorithm/
|
|
# https://crypto.stackexchange.com/questions/20548/generation-of-strong-primes
|
|
# https://crypto.stackexchange.com/questions/71/how-can-i-generate-large-prime-numbers-for-rsa
|
|
|
|
def getPrimeNumber(n, safe=True):
|
|
"""
|
|
This function generate a large prime number
|
|
based on "A method for Obtaining Digital Signatures
|
|
and Public-Key Cryptosystems"
|
|
Section B. How to Find Large Prime Numbers
|
|
https://dl.acm.org/doi/pdf/10.1145/359340.359342
|
|
|
|
Args:
|
|
n (Integer): The size of the prime number. Must be a multiple of 64
|
|
safe (Boolean): When generating the prime number, the function must find a safe prime number, based on the Germain primes (2p + 1 is also a prime number)
|
|
|
|
Returns:
|
|
Return the prime number
|
|
"""
|
|
if n % 64 != 0:
|
|
print("Must be multiple of 64")
|
|
return
|
|
# from sys import getsizeof
|
|
upper = getrandbits(n)
|
|
lower = upper >> 7
|
|
r = randint(lower, upper)
|
|
|
|
while r % 2 == 0:
|
|
r += 1
|
|
|
|
# Now, we are going to compute r as prime number
|
|
i = 100
|
|
while 1:
|
|
# Check if it's a prime number
|
|
if _millerRabinTest(r):
|
|
break
|
|
|
|
# TODO: it's dirty, need to change that
|
|
# i = int(log2(r))
|
|
# i *= randint(2, 50)
|
|
|
|
r += i
|
|
# print(f"{i} {r}")
|
|
i += 1
|
|
|
|
|
|
# print(_fermatLittleTheorem(r))
|
|
# print(getsizeof(r))
|
|
return r
|
|
|
|
def getSmallPrimeNumber(n) -> int:
|
|
"""
|
|
This function is deprecated
|
|
|
|
Args:
|
|
n (Integer): Get the small prime number until n
|
|
|
|
Returns:
|
|
Return the first prime number found
|
|
"""
|
|
is_prime = True
|
|
|
|
while True:
|
|
for i in range(2, n):
|
|
# If n is divisible by i, it's not a prime, we break the loop
|
|
if n % i == 0:
|
|
is_prime = False
|
|
break
|
|
|
|
if is_prime:
|
|
break
|
|
is_prime = True
|
|
n = n + 1
|
|
|
|
p = n
|
|
return p
|
|
|
|
def get_prime_numbers(n) -> list:
|
|
"""
|
|
This function get all prime number of the n
|
|
|
|
Args:
|
|
n (Integer): find all prime number until n is achieves
|
|
|
|
Returns:
|
|
Return a list of prime numbers
|
|
"""
|
|
l = list()
|
|
for i in range(2, n):
|
|
if n % i == 0:
|
|
l.append(i)
|
|
return l
|
|
|
|
def get_n_prime_numbers(n) -> list:
|
|
"""
|
|
This function return a list of n prime numbers
|
|
|
|
Args:
|
|
n (Integer): the range, must be an integer
|
|
|
|
Returns:
|
|
Return a list of n prime numbers
|
|
"""
|
|
l = list()
|
|
|
|
count = 2
|
|
index = 0
|
|
while index < n:
|
|
is_prime = True
|
|
for x in range(2, count):
|
|
if count % x == 0:
|
|
is_prime = False
|
|
break
|
|
|
|
if is_prime:
|
|
l.append(count)
|
|
index += 1
|
|
|
|
count += 1
|
|
|
|
return l
|
|
|
|
def are_coprime(p1, p2):
|
|
"""
|
|
This function check if p1 and p2 are coprime
|
|
|
|
Args:
|
|
p1 (list): list of prime numbers of the first number
|
|
p2 (list): list of prime number of the second number
|
|
|
|
Returns:
|
|
Return a boolean result
|
|
"""
|
|
r = True
|
|
for entry in p1:
|
|
if entry in p2:
|
|
r = False
|
|
break
|
|
return r
|
|
|
|
def sieveOfEratosthenes(n) -> list:
|
|
"""
|
|
This function build a list of prime number based on the Sieve of Erastosthenes
|
|
|
|
Args:
|
|
n (Integer): Interate until n is achives
|
|
|
|
Returns:
|
|
Return a list of all prime numbers to n
|
|
"""
|
|
if n < 1:
|
|
return list()
|
|
|
|
eratost = dict()
|
|
for i in range(2, n):
|
|
eratost[i] = True
|
|
|
|
for i in range(2, n):
|
|
if eratost[i]:
|
|
for j in range(i*i, n, i):
|
|
eratost[j] = False
|
|
|
|
sieve = list()
|
|
for i in range(2, n):
|
|
if eratost[i]:
|
|
sieve.append(i)
|
|
|
|
return sieve
|
|
|
|
def _fermatLittleTheorem(n) -> bool:
|
|
"""
|
|
The Fermat's little theorem. if n is a prime number, any number from 0 to n- 1 is a multiple of n
|
|
|
|
Args:
|
|
n (Integer): Check if n is prime or not
|
|
|
|
Returns:
|
|
Return True if the number a is a multiple of n, otherwise it's False
|
|
"""
|
|
a = randint(1, n - 1)
|
|
# We compute a ** (n - 1) % n
|
|
if pow(a, n - 1, n) == 1:
|
|
return True
|
|
return False
|
|
|
|
def _millerRabinTest(n) -> bool:
|
|
"""
|
|
This function execute a Miller Rabin test
|
|
For the algorithm, it's based on the pseudo-algo provided by this document:
|
|
* https://www.cs.cornell.edu/courses/cs4820/2010sp/handouts/MillerRabin.pdf
|
|
The Mille-Rabin test is an efficient way to determine if n is prime or not
|
|
|
|
Args:
|
|
n (Integer): Check if n is a prime number
|
|
Returns:
|
|
Return a boolean. True for a prime otherwise, it's a composite number
|
|
|
|
"""
|
|
if n < 2 or (n > 2 and n % 2 == 0): # If n is even, it's a composite
|
|
return False
|
|
|
|
k = 0
|
|
q = n - 1
|
|
#while (q & 1) == 0:
|
|
# k += 1
|
|
# q >>= 1
|
|
while q % 2 == 0:
|
|
k += 1
|
|
q //= 2
|
|
|
|
# We choose a: a < n - 1
|
|
for _ in range(40):
|
|
a = randint(2, n - 1)
|
|
# We compute a ** q % n
|
|
x = pow(a, q, n)
|
|
|
|
# If it's a composite number
|
|
if x == 1 or x == n - 1:
|
|
continue
|
|
|
|
for _ in range(k):
|
|
z = pow(x, 2, n)
|
|
if z == 1 or z == n - 1:
|
|
return False
|
|
else:
|
|
return False
|
|
return True
|
|
|
|
def sophieGermainPrime(p) -> bool:
|
|
"""
|
|
Check if the number p is a safe prime number: 2p + 1 is also a prime
|
|
|
|
Args:
|
|
p (Integer): Possible prime number
|
|
|
|
Returns:
|
|
Return True if p is a safe prime number, otherwise it's False
|
|
"""
|
|
pp = 2 * p + 1
|
|
return _millerRabinTest(pp)
|
|
|
|
def isSafePrime(n) -> bool:
|
|
"""
|
|
This function has not been implemented yet, but check if the number n is a safe prime number. This function will test different properties of the possible prime number n
|
|
|
|
Args:
|
|
n (Integer): the prime number to check
|
|
|
|
Returns:
|
|
Return a Boolean if the prime number n is safe or not. True if yes, otherwise it's False
|
|
"""
|
|
if n.bit_length() >= 256:
|
|
return True
|
|
|
|
# Do Sophie Germain's test
|
|
|
|
return False
|
|
|