First commit
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: Cryptotools
|
||||
Version: 1.0
|
||||
Summary: Cryptography library
|
||||
Author: Geoffrey Bucchino
|
||||
Author-email: contact@bucchino.org
|
||||
@@ -0,0 +1,13 @@
|
||||
README.md
|
||||
setup.py
|
||||
Cryptotools/Cryptotools.egg-info/PKG-INFO
|
||||
Cryptotools/Cryptotools.egg-info/SOURCES.txt
|
||||
Cryptotools/Cryptotools.egg-info/dependency_links.txt
|
||||
Cryptotools/Cryptotools.egg-info/top_level.txt
|
||||
Cryptotools/Numbers/__init__.py
|
||||
Cryptotools/Numbers/carmi.py
|
||||
Cryptotools/Numbers/numbers.py
|
||||
Cryptotools/Numbers/primeNumber.py
|
||||
tests/test_carmi.py
|
||||
tests/test_numbers.py
|
||||
tests/test_phi.py
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Numbers
|
||||
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from Cryptotools.Numbers.coprime import phi
|
||||
from Cryptotools.Numbers.carmi import carmichael_lambda
|
||||
from Cryptotools.Utils.utils import gcd
|
||||
from Cryptotools.Numbers.primeNumber import getPrimeNumber
|
||||
from sys import getsizeof
|
||||
|
||||
class RSAKey:
|
||||
"""
|
||||
This class store the RSA key with the modulus associated
|
||||
The key is a tuple of the key and the modulus n
|
||||
|
||||
Attributes:
|
||||
key: It's the exponent key, can be public or private
|
||||
modulus: It's the public modulus
|
||||
length: It's the key length
|
||||
"""
|
||||
def __init__(self, key, modulus, length):
|
||||
"""
|
||||
Contain the RSA Key. An object of RSAKey can be a public key or a private key
|
||||
|
||||
Args:
|
||||
key (Integer): it's the exponent of the key
|
||||
modulus (Integer): it's the public modulus of the key
|
||||
length (Integer): length of the key
|
||||
"""
|
||||
|
||||
self._key = key
|
||||
self._modulus = modulus
|
||||
self._length = length
|
||||
|
||||
@property
|
||||
def key(self):
|
||||
return self._key
|
||||
|
||||
@property
|
||||
def modulus(self):
|
||||
return self._modulus
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
return self.length
|
||||
|
||||
class RSA:
|
||||
"""
|
||||
This class generate public key based on RSA algorithm
|
||||
|
||||
Attributes:
|
||||
p: it's the prime number for generating the modulus
|
||||
q: it's the second prime number for the modulus
|
||||
public: Object of the RSAKey which is the public key
|
||||
private: Object of the RSAKey for the private key
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Build a RSA Key
|
||||
"""
|
||||
self._p = None
|
||||
self._q = None
|
||||
self._public = None
|
||||
self._private = None
|
||||
|
||||
def generateKeys(self, size=512):
|
||||
"""
|
||||
This function generate both public and private keys
|
||||
Args:
|
||||
size: It's the size of the key and must be multiple of 64
|
||||
"""
|
||||
# p and q must be coprime
|
||||
self._p = getPrimeNumber(size)
|
||||
self._q = getPrimeNumber(size)
|
||||
|
||||
# compute n = pq
|
||||
n = self._p * self._q
|
||||
|
||||
phin = (self._p - 1) * (self._q - 1)
|
||||
|
||||
# e must be coprime with phi(n)
|
||||
# According to the FIPS 186-5, the public key exponent must be odd
|
||||
# and the minimum size is 65536 (Cf. Section 5.4 PKCS #1)
|
||||
# https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
|
||||
e = 65535 # Works
|
||||
for i in range(2, phin - 1):
|
||||
if gcd(phin, e) == 1:
|
||||
break
|
||||
e += 1
|
||||
# print(gcd(phin, e))
|
||||
self._public = RSAKey(e, n, getsizeof(e))
|
||||
|
||||
# d is the reverse modulo of phi(n)
|
||||
# d = self._inverseModular(e, phin)
|
||||
d = pow(e, -1, phin) # Works in python 3.8
|
||||
self._private = RSAKey(d, n, getsizeof(d))
|
||||
|
||||
@property
|
||||
def e(self):
|
||||
return self._public.key
|
||||
|
||||
@property
|
||||
def d(self):
|
||||
return self._private.key
|
||||
|
||||
@property
|
||||
def n(self):
|
||||
return self._public.modulus
|
||||
|
||||
@property
|
||||
def p(self):
|
||||
return self._p
|
||||
|
||||
@property
|
||||
def q(self):
|
||||
return self._q
|
||||
|
||||
def encrypt(self, data) -> list:
|
||||
"""
|
||||
This function return a list of data encrypted with the public key
|
||||
|
||||
Args:
|
||||
data (str): it's the plaintext which need to be encrypted
|
||||
|
||||
Returns:
|
||||
return a list of the data encrypted, each entries contains the value encoded
|
||||
"""
|
||||
dataEncoded = self._str2bin(data)
|
||||
return list(
|
||||
pow(int(x), self._public.key, self._public.modulus)
|
||||
for x in dataEncoded
|
||||
)
|
||||
|
||||
def decrypt(self, data) -> list:
|
||||
"""
|
||||
This function return a list decrypted with the private key
|
||||
|
||||
Args:
|
||||
data (str): It's the encrypted data which need to be decrypted
|
||||
|
||||
Returns:
|
||||
Return the list of data uncrypted into plaintext
|
||||
"""
|
||||
decrypted = list()
|
||||
for x in data:
|
||||
d = pow(x, self._private.key, self._private.modulus)
|
||||
decrypted.append(chr(d))
|
||||
return ''.join(decrypted)
|
||||
|
||||
def _str2bin(self, data) -> list:
|
||||
"""
|
||||
This function convert a string into the unicode value
|
||||
|
||||
Args:
|
||||
data: the string which need to be converted
|
||||
|
||||
Returns:
|
||||
Return a list of unicode values of data
|
||||
"""
|
||||
return list(ord(x) for x in data)
|
||||
|
||||
def _inverseModular(self, a, n):
|
||||
"""
|
||||
This function compute the modular inverse for finding d, the decryption key
|
||||
|
||||
Args:
|
||||
a (Integer): the base of the exponent
|
||||
n (Integer): the modulus
|
||||
"""
|
||||
for b in range(1, n):
|
||||
#if pow(a, b, n) == 1:
|
||||
if (a * b) % n == 1:
|
||||
inv = b
|
||||
break
|
||||
return inv
|
||||
@@ -0,0 +1 @@
|
||||
#!/usr/bin/env python3
|
||||
@@ -0,0 +1 @@
|
||||
#!/usr/bin/env python3
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from Cryptotools.Groups.group import Group
|
||||
|
||||
|
||||
class Cyclic(Group):
|
||||
"""
|
||||
This object contain a list of the Group for a cyclic group. This class find all generator of the group.
|
||||
This class is inherited from Group object
|
||||
|
||||
Attributes:
|
||||
G (list): list of all elements in the group
|
||||
n (Integer): it's the value where the group has been generated
|
||||
operation (Function): it's the operation generating the group
|
||||
generators (list): contain all generators of the group
|
||||
generatorChecked (boolean): Check if generators has been found
|
||||
"""
|
||||
def __init__(self, G:list, n, ope):
|
||||
super().__init__(n, G, ope) # Call the Group's constructor
|
||||
self._G = G
|
||||
self._n = n
|
||||
self._operation = ope
|
||||
self._generators = list()
|
||||
self._generatorChecked = False
|
||||
|
||||
def generator(self):
|
||||
"""
|
||||
This function find all generators in the group G
|
||||
"""
|
||||
|
||||
index = 1
|
||||
G = sorted(self._g)
|
||||
for g in range(2, self._n):
|
||||
z = list()
|
||||
for entry in range(1, self._n):
|
||||
res = self._operation(g, index, self._n)
|
||||
if res not in z:
|
||||
z.append(res)
|
||||
index = index + 1
|
||||
|
||||
# We check if that match with G
|
||||
# If yes, we find a generator
|
||||
if sorted(z) == G:
|
||||
self._generators.append(g)
|
||||
self._generatorChecked = True
|
||||
|
||||
def getPrimitiveRoot(self):
|
||||
"""
|
||||
This function return the primitive root modulo of n
|
||||
|
||||
Returns:
|
||||
Return the primitive root of the group. None if no primitive has been found
|
||||
"""
|
||||
|
||||
index = 1
|
||||
G = sorted(self._g)
|
||||
for g in range(2, self._n):
|
||||
z = list()
|
||||
for entry in range(1, self._n):
|
||||
res = self._operation(g, index, self._n)
|
||||
if res not in z:
|
||||
z.append(res)
|
||||
index += 1
|
||||
|
||||
# If the group is the same has G, we found a generator
|
||||
if sorted(z) == G:
|
||||
return g
|
||||
return None
|
||||
|
||||
def getGenerators(self) -> list:
|
||||
"""
|
||||
This function return all generators of that group
|
||||
|
||||
Returns:
|
||||
Return the list of generators found. The function generators() must be called before to call this function
|
||||
"""
|
||||
if not self._generatorChecked:
|
||||
self.generator()
|
||||
self._generatorChecked = True
|
||||
return self._generators
|
||||
|
||||
def isCyclic(self) -> bool:
|
||||
"""
|
||||
Check if the group is a cyclic group, means we have at least one generator
|
||||
|
||||
Returns:
|
||||
REturn a boolean, False if the group is not Cyclic otherwise return True
|
||||
"""
|
||||
if len(self.getGenerators()) == 0:
|
||||
return False
|
||||
return True
|
||||
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from Cryptotools.Groups.group import Group
|
||||
|
||||
|
||||
class Galois:
|
||||
"""
|
||||
This class contain the Galois Field (Finite Field)
|
||||
|
||||
|
||||
|
||||
Attributes:
|
||||
q (Integer): it's the number of the GF
|
||||
operation (Function): Function for generating the group
|
||||
identityAdd (Integer): it's the identity element in the GF(n) for the addition operation
|
||||
identityMul (Integer): it's the identity element in the GF(n) for the multiplicative operation
|
||||
"""
|
||||
def __init__(self, q, operation):
|
||||
self._q = q
|
||||
self._operation = operation
|
||||
self._identityAdd = 0
|
||||
self._identityMul = 1
|
||||
self._F = [x for x in range(q)]
|
||||
self._add = [[0 for x in range(q)] for y in range(q)]
|
||||
|
||||
# TODO: May do we do a deep copy between all groups ?
|
||||
self._div = [[0 for x in range(q)] for y in range(q)]
|
||||
self._mul = [[0 for x in range(q)] for y in range(q)]
|
||||
self._sub = [[0 for x in range(q)] for y in range(q)]
|
||||
self._primitiveRoot = list()
|
||||
|
||||
def primitiveRoot(self):
|
||||
"""
|
||||
In this function, we going to find the primitive root modulo n of the galois field
|
||||
|
||||
Returns:
|
||||
Return the list of primitive root of the GF(q)
|
||||
"""
|
||||
for x in range(2, self._q):
|
||||
z = list()
|
||||
for entry in range(1, self._q):
|
||||
res = self._operation(x, entry, self._q)
|
||||
if res not in z:
|
||||
z.append(res)
|
||||
|
||||
if self.isPrimitiveRoot(z, self._q - 1):
|
||||
if x not in self._primitiveRoot: # It's dirty, need to find why we have duplicate entry
|
||||
self._primitiveRoot.append(x)
|
||||
return z
|
||||
|
||||
def getPrimitiveRoot(self):
|
||||
"""
|
||||
Return the list of primitives root
|
||||
|
||||
Returns:
|
||||
Return the primitive root
|
||||
"""
|
||||
return self._primitiveRoot
|
||||
|
||||
def isPrimitiveRoot(self, z, length):
|
||||
"""
|
||||
Check if z is a primitive root
|
||||
|
||||
Args:
|
||||
z (list): check if z is a primitive root
|
||||
length (Integer): Length of the GF(q)
|
||||
"""
|
||||
if len(z) == length:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add(self):
|
||||
"""
|
||||
This function do the operation + on the Galois Field
|
||||
|
||||
Returns:
|
||||
Return a list of the group with the addition operation
|
||||
"""
|
||||
for x in range(0, self._q):
|
||||
for y in range(0, self._q):
|
||||
self._add[x][y] = (x + y) % self._q
|
||||
return self._add
|
||||
|
||||
def _inverseModular(self, a, n):
|
||||
"""
|
||||
This function find the reverse modular of a by n
|
||||
|
||||
Returns:
|
||||
Return the reverse modular
|
||||
"""
|
||||
for b in range(1, n):
|
||||
if (a * b) % n == 1:
|
||||
inv = b
|
||||
break
|
||||
return inv
|
||||
|
||||
def div(self):
|
||||
"""
|
||||
This function do the operation / on the Galois Field
|
||||
|
||||
Returns:
|
||||
Return a list of the group with the division operation
|
||||
"""
|
||||
for x in range(1, self._q):
|
||||
for y in range(1, self._q):
|
||||
inv = self._inverseModular(y, self._q)
|
||||
|
||||
self._div[x][y] = (x * inv) % self._q
|
||||
return self._div
|
||||
|
||||
def mul(self):
|
||||
"""
|
||||
This function do the operation * on the Galois Field
|
||||
|
||||
Returns:
|
||||
Return a list of the group with the multiplication operation
|
||||
"""
|
||||
for x in range(0, self._q):
|
||||
for y in range(0, self._q):
|
||||
self._mul[x][y] = (x * y) % self._q
|
||||
return self._mul
|
||||
|
||||
def sub(self):
|
||||
"""
|
||||
This function do the operation - on the Galois Field
|
||||
|
||||
Returns:
|
||||
Return a list of the group with the subtraction operation
|
||||
"""
|
||||
for x in range(0, self._q):
|
||||
for y in range(0, self._q):
|
||||
self._sub[x][y] = (x - y) % self._q
|
||||
return self._sub
|
||||
|
||||
def check_closure_law(self, arithmetic):
|
||||
"""
|
||||
This function check the closure law.
|
||||
By definition, every element in the GF is an abelian group, which respect the closure law: for a and b belongs to G, a + b belongs to G, the operation is a binary operation
|
||||
|
||||
Args:
|
||||
Arithmetics (str): contain the operation to be made, must be '+', '*', '/' or /-'
|
||||
"""
|
||||
if arithmetic not in ['+', '*', '/', '-']:
|
||||
raise Exception("The arithmetic need to be '+', '*', '/' or '-'")
|
||||
|
||||
if arithmetic == '+':
|
||||
G = self._add
|
||||
elif arithmetic == '*':
|
||||
G = self._mul
|
||||
elif arithmetic == '/':
|
||||
G = self._div
|
||||
else:
|
||||
G = self._sub
|
||||
|
||||
start = 0
|
||||
"""
|
||||
In case of multiplicative, we bypass the first line, because all elements are zero, otherwise the test fail
|
||||
"""
|
||||
if arithmetic == '*' or arithmetic == '/':
|
||||
start = 1
|
||||
|
||||
isClosure = True
|
||||
for x in range(start, self._q):
|
||||
gr = Group(self._q, G[x], self._operation)
|
||||
if not gr.closure():
|
||||
isClosure = False
|
||||
del gr
|
||||
|
||||
if isClosure:
|
||||
print(f"The group {arithmetic} respect closure law")
|
||||
else:
|
||||
print(f"The group {arithmetic} does not respect closure law")
|
||||
|
||||
def check_identity_add(self):
|
||||
"""
|
||||
This function check the identity element and must satisfy this condition: $a + 0 = a$ for each element in the GF(n)
|
||||
In Group Theory, an identity element is an element in the group which do not change the value every element in the group
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
for x in self._F:
|
||||
if not self._identityAdd + x == x:
|
||||
raise Exception(
|
||||
f"The identity element {self._identityAdd} "\
|
||||
"do not satisfy $a + element = a$"
|
||||
)
|
||||
|
||||
def check_identity_mul(self):
|
||||
"""
|
||||
This function check the identity element and must satisfy this condition: $a * 1 = a$ for each element in the GF(n)
|
||||
In Group Theory, an identity element is an element in the group which do not change the value every element in the group
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
for x in self._F:
|
||||
if not self._identityMul * x == x:
|
||||
raise Exception(
|
||||
f"The identity element {self._identityAdd} "\
|
||||
"do not satisfy $a * element = a$"
|
||||
)
|
||||
|
||||
def printMatrice(self, m):
|
||||
"""
|
||||
This function print the GF(m)
|
||||
|
||||
Args:
|
||||
m (list): Matrix of the GF
|
||||
"""
|
||||
header = str()
|
||||
header = " "
|
||||
for x in range(0, self._q):
|
||||
header += f"{x} "
|
||||
|
||||
header += "\n--|" + "-" * (len(header)- 3) +"\n"
|
||||
|
||||
s = str()
|
||||
|
||||
for x in range(0, self._q):
|
||||
s += f"{x} | "
|
||||
for y in range(0, self._q):
|
||||
s += f"{m[x][y]} "
|
||||
s += "\n"
|
||||
|
||||
s = header + s
|
||||
print(s)
|
||||
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
class Group:
|
||||
"""
|
||||
This class generate a group self._g based on the operation (here denoted +)
|
||||
with the function ope: (a ** b) % n
|
||||
|
||||
In group theory, any group has an identity element (e), which with the binary operation, do not change the value and must satisfy the condition: $a + e = 0$
|
||||
|
||||
Attributes:
|
||||
n (Integer): It's the G_n elements in the Group
|
||||
g (List): The set of the Group
|
||||
operation (Function): Function for generating the Group
|
||||
identity (Integer): The identity of the group.
|
||||
reverse (Dict): For each elements of the Group of n, we have the reverse value
|
||||
"""
|
||||
def __init__(self, n, g, ope):
|
||||
self._n = n
|
||||
self._g = g
|
||||
self._operation = ope
|
||||
self._identity = 0
|
||||
self._reverse = dict()
|
||||
|
||||
def getG(self) -> list():
|
||||
"""
|
||||
This function return the Group
|
||||
|
||||
Returns:
|
||||
List of all elements in the Group
|
||||
"""
|
||||
return self._g
|
||||
|
||||
def closure(self) -> bool:
|
||||
"""
|
||||
Check the closure law
|
||||
In a group, each element a, b belongs to G, such as a + b belongs to G
|
||||
|
||||
Returns:
|
||||
Return a Boolean if the closure law is respected. True if yes otherwise it's False
|
||||
"""
|
||||
for e1 in self._g:
|
||||
for e2 in self._g:
|
||||
res = self._operation(e1, e2, self._n)
|
||||
if not res in self._g:
|
||||
# raise Exception(f"{res} not in g. g is not a group")
|
||||
return False
|
||||
return True
|
||||
|
||||
def associative(self) -> bool:
|
||||
"""
|
||||
Check the associative law.
|
||||
In a group, for any a, b and c belongs to G,
|
||||
they must respect this condition: (a + b) + c = a + (a + b)
|
||||
|
||||
Returns:
|
||||
Return a boolean if the Associative law is respected. True if yes otherwise it's False
|
||||
"""
|
||||
a = self._g[0]
|
||||
b = self._g[1]
|
||||
c = self._g[2]
|
||||
|
||||
res_ope = self._operation(a, b, self._n)
|
||||
res1 = self._operation(res_ope, c, self._n)
|
||||
|
||||
res_ope = self._operation(b, c, self._n)
|
||||
res2 = self._operation(a, res_ope, self._n)
|
||||
if res1 != res2:
|
||||
# raise Exception(f"{res1} is different from {res2}. g is not a group")
|
||||
return False
|
||||
return True
|
||||
|
||||
def identity(self) -> bool:
|
||||
"""
|
||||
Check the identity law.
|
||||
In a group, an identity element exist and must be uniq
|
||||
|
||||
Returns:
|
||||
Return a Boolean if the identity elements has been found. True if found otherwise it's False
|
||||
"""
|
||||
for a in self._g:
|
||||
for b in self._g:
|
||||
if not self._operation(a, b, self._n) == b:
|
||||
break
|
||||
|
||||
self._identity = a
|
||||
return True
|
||||
return False
|
||||
|
||||
def getIdentity(self) -> int:
|
||||
"""
|
||||
Return the identity element. The function identitu() must be called before.
|
||||
|
||||
Returns:
|
||||
Return the identity element if it has been found
|
||||
"""
|
||||
return self._identity
|
||||
|
||||
def reverse(self) -> bool:
|
||||
"""
|
||||
Check the inverse law
|
||||
In a group, for each element belongs to G
|
||||
they must have an inverse a ^ (-1) = e (identity)
|
||||
|
||||
Returns:
|
||||
Return a Boolean if the all elements ha a reverse element. True if yes otherwise it's False
|
||||
"""
|
||||
reverse = False
|
||||
for a in self._g:
|
||||
for b in self._g:
|
||||
if self._operation(a, b, self._n) == self._identity:
|
||||
self._reverse[a] = b
|
||||
reverse = True
|
||||
break
|
||||
return reverse
|
||||
|
||||
def getReverses(self) -> dict:
|
||||
"""
|
||||
This function return the dictionary of all reverses elements. The key is the element in G and the value is the reverse element
|
||||
|
||||
Returns:
|
||||
Return the reverse dictionary
|
||||
|
||||
"""
|
||||
return self._reverse
|
||||
@@ -0,0 +1 @@
|
||||
#!/usr/bin/env python3
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from Cryptotools.Numbers.primeNumber import gcd, isPrimeNumber
|
||||
from Cryptotools.lcm import lcm
|
||||
from Cryptotools.Numbers.coprime import phi
|
||||
from Cryptotools.Utils.utils import gcd
|
||||
from sympy import factorint
|
||||
from functools import reduce
|
||||
|
||||
|
||||
def carmichael_lambda(n: int) -> int:
|
||||
"""
|
||||
This function is a carmichael lambda for identifying the smallest integer m
|
||||
and saisfy this condition: a ** m congrue 1 modulo n
|
||||
This function is relatively closed with the euler's totient (phi of n)
|
||||
|
||||
Args:
|
||||
n (Integer): found the smallest integer of n
|
||||
|
||||
Returns:
|
||||
REturn the smallest integer of n
|
||||
"""
|
||||
|
||||
# First, factorizing n number
|
||||
# factorint return a list of prime factors of n
|
||||
# Base on that theorem:
|
||||
# https://en.wikipedia.org/wiki/Fundamental_theorem_of_arithmetic
|
||||
factorsN = factorint(n)
|
||||
|
||||
"""
|
||||
The result of the factorint, we have the following:
|
||||
n = p ** e1, p ** e2, ..., p ** ek
|
||||
"""
|
||||
|
||||
factors = list()
|
||||
|
||||
for p, e in factorsN.items():
|
||||
# Base on the theorem of arithmetic, p is always prime
|
||||
if isPrimeNumber(p):
|
||||
if p == 2 and e >= 3:
|
||||
factors.append(phi(pow(p, e)) // 2)
|
||||
elif p >= 2 and e > 0:
|
||||
factors.append(phi(pow(p, e)))
|
||||
elif p > 2:
|
||||
factors.append(phi(pow(p, e)))
|
||||
|
||||
# Now, we can compute lcm
|
||||
result = reduce(lcm, factors)
|
||||
|
||||
return result
|
||||
|
||||
def carmichael_lambda2(n):
|
||||
"""
|
||||
Deprecated function
|
||||
"""
|
||||
# Get all coprimes with n
|
||||
coprimes = list()
|
||||
for a in range(1, n):
|
||||
if gcd(a, n) == 1:
|
||||
coprimes.append(a)
|
||||
|
||||
# Need to find the smallest value
|
||||
"""
|
||||
Need to find the smallest value m. Must to satisfy this condition:
|
||||
a ** m congrus 1 mod n
|
||||
"""
|
||||
for m in range(1, n):
|
||||
print(f"{m} {a ** m % n}")
|
||||
|
||||
print(coprimes)
|
||||
|
||||
def carmi_numbers(n):
|
||||
"""
|
||||
This function get all GCD of the number if these number are prime or not
|
||||
|
||||
Args:
|
||||
n (Integer): Iterate to n elements
|
||||
|
||||
Returns:
|
||||
Return a list of prime numbers
|
||||
"""
|
||||
# https://kconrad.math.uconn.edu/blurbs/ugradnumthy/carmichaelkorselt.pdf
|
||||
primes = list()
|
||||
for i in range(2, n - 1):
|
||||
if gcd(n, i) == i:
|
||||
if isPrimeNumber(i):
|
||||
primes.append(i)
|
||||
|
||||
return primes
|
||||
|
||||
def is_carmichael(n, primes):
|
||||
"""
|
||||
This function check if the n number is a carmichael number. The arguments primes at least 3 prime numbers
|
||||
As it's said in the Carmichael theorem, a carmichael number has three factors and they are all primes: https://en.wikipedia.org/wiki/Carmichael_number
|
||||
With the Korselt's criterion, to check if the number is a carmichael number p - 1 / n - 1.
|
||||
|
||||
Args:
|
||||
n (Integer): the carmichael number
|
||||
primes (list): list of prime numbers
|
||||
|
||||
Returns:
|
||||
Boolean of the carmichael's number result
|
||||
"""
|
||||
r = True
|
||||
n = n - 1
|
||||
|
||||
if len(primes) < 3:
|
||||
return False
|
||||
|
||||
# Korselt's criterion
|
||||
for p in primes:
|
||||
p = p - 1
|
||||
if n % p != 0:
|
||||
r = False
|
||||
break
|
||||
return r
|
||||
|
||||
def is_carmi_number(n) -> bool:
|
||||
"""
|
||||
This function check if the number n is a carmichael number (pseudoprime)
|
||||
|
||||
Args:
|
||||
n (Integer): Iterate to n elements
|
||||
|
||||
Returns:
|
||||
Return a Boolean if n is a carmichael number or not. True if yes
|
||||
"""
|
||||
j = 0
|
||||
for i in range(n):
|
||||
if i ** n % n == i:
|
||||
j += 1
|
||||
if j == n:
|
||||
return True
|
||||
return False
|
||||
|
||||
def generate_carmi_numbers(nbr) -> list:
|
||||
"""
|
||||
This function generate carmichael numbers, they are called pseudoprimes
|
||||
For instance: a = 545, n = 561
|
||||
gcd(a, n) = 1
|
||||
pow(a, n - 1) % n = 1
|
||||
|
||||
Args:
|
||||
nbr (Integer): Find all pseudoprimes until nbr is achieves
|
||||
|
||||
Returns:
|
||||
Return the list of pseudoprimes
|
||||
"""
|
||||
carmi = list()
|
||||
|
||||
count = 0
|
||||
n = 2
|
||||
while count < nbr:
|
||||
# First, we need to find a, coprime with n
|
||||
for a in range(1, n):
|
||||
# We check if n is coprime with a
|
||||
# All integers must be coprime with n, a belong to n
|
||||
if gcd(a, n) == 1:
|
||||
# Check if is a carmichael number
|
||||
# Fermat's little theorem, a ** (n - 1) % n, must be congruent to 1
|
||||
if pow(a, (n - 1)) % n == 1:
|
||||
#if (a ** (n - 1)) % n == 1:
|
||||
#print(f"{gcd(a, n)} {a} {n}")
|
||||
if n not in carmi:
|
||||
count += 1
|
||||
carmi.append(n)
|
||||
else:
|
||||
print(f"{gcd(a, n)} {a} {n}")
|
||||
|
||||
break
|
||||
n += 1
|
||||
print(carmi)
|
||||
#for cop in range(2, n):
|
||||
# if gcd(cop, n) == 1:
|
||||
# coprimes.append(cop)
|
||||
|
||||
return carmi
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from Cryptotools.Utils.utils import gcd
|
||||
|
||||
|
||||
# https://oeis.org/A000010
|
||||
def phi(n):
|
||||
"""
|
||||
This function count all phi(n)
|
||||
|
||||
Args:
|
||||
n (integer): it's the phi(n) value
|
||||
|
||||
Returns:
|
||||
Return the phi(n)
|
||||
"""
|
||||
y = 1
|
||||
for i in range(2, n):
|
||||
if gcd(n, i) == 1:
|
||||
y += 1
|
||||
return y
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from random import randint
|
||||
from Cryptotools.Numbers.primeNumber import _millerRabinTest, isPrimeNumber
|
||||
from Cryptotools.Utils.utils import gcd
|
||||
from Cryptotools.lcm import lcm
|
||||
from math import floor, log
|
||||
|
||||
|
||||
def pollard_p_minus_1(n, B=None) -> int:
|
||||
"""
|
||||
This function factorize the number n into factor based on the Pollard's p - 1 algorithm
|
||||
|
||||
The first is to choose B, which is a positive integer and B < n
|
||||
In the second step, we need to define $M=\prod _{primes~q\leq B}q^{\lfloor \log_{q}{B}\rfloor }$
|
||||
|
||||
Args:
|
||||
n (Integer): The number n to factorize
|
||||
|
||||
Returns:
|
||||
Return the factorize of the number n or None
|
||||
"""
|
||||
|
||||
if B is None:
|
||||
B = randint(1, n - 1)
|
||||
# B = randint(1, n - 1)
|
||||
|
||||
#### We define M
|
||||
# Select all prime numbers 1 < B
|
||||
q = list()
|
||||
for x in range(2, B):
|
||||
# with the _millerRabinTest, the program crash, because the randint() is empty
|
||||
# because, both min value and max value are 2
|
||||
# if _millerRabinTest(x):
|
||||
if isPrimeNumber(x):
|
||||
q.append(x)
|
||||
|
||||
M = 1
|
||||
for prime in q:
|
||||
e = floor(log(B, prime))
|
||||
# print(prime, e)
|
||||
M *= pow(prime, e)
|
||||
|
||||
# We choose a and coprime with n
|
||||
a = 2
|
||||
while True:
|
||||
if gcd(a, n) == 1:
|
||||
break
|
||||
a += 1
|
||||
|
||||
# We can compute g = gcd((a ** M) - 1, n)
|
||||
g = gcd(pow(a, M, n) - 1, n)
|
||||
if g > 1:
|
||||
return g
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
def fibonacci(n) -> list:
|
||||
"""
|
||||
This function generate the list of Fibonacci
|
||||
|
||||
Args:
|
||||
n (integer): it's maximum value of Fibonacci sequence
|
||||
|
||||
Returns:
|
||||
Return a list of n element in the Fibonacci sequence
|
||||
"""
|
||||
fibo = [0, 1]
|
||||
fibo.append(fibo[0] + fibo[1])
|
||||
for i in range(2, n):
|
||||
fibo.append(fibo[i - 1] + fibo[i])
|
||||
return fibo
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
#!/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
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#!/usr/bin/env python3
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
COMPOSITE = 0
|
||||
PRIME = 1
|
||||
|
||||
class Number:
|
||||
def __init__(self):
|
||||
self._int = int()
|
||||
self._kind = COMPOSITE
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
def gcd(a, b):
|
||||
"""
|
||||
This function calculate the GCD (Greatest Common Divisor of the number a of b
|
||||
Args:
|
||||
a (Integer): the number a
|
||||
b (integer): the number b
|
||||
|
||||
Return:
|
||||
the GCD
|
||||
"""
|
||||
|
||||
if b == 0:
|
||||
return a
|
||||
return gcd(b, a%b)
|
||||
|
||||
def egcd(a, b):
|
||||
"""
|
||||
This function compute the Extended Euclidean algorithm
|
||||
https://user.eng.umd.edu/~danadach/Cryptography_20/ExtEuclAlg.pdf
|
||||
https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
|
||||
|
||||
Args:
|
||||
a (Integer): the number a
|
||||
b (Integer): the number b
|
||||
"""
|
||||
if a == 0:
|
||||
return b, 0, 1
|
||||
gcd, x1, y1 = egcd(b % a, a)
|
||||
x = y1 - (b // a) * x1
|
||||
y = x1
|
||||
return gcd, x, y
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
__all__ = ["Numbers", "Groups"]
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from Cryptotools.Numbers.primeNumber import gcd
|
||||
|
||||
def compute_multiple(a):
|
||||
"""
|
||||
This function compute the 20 first multiples of the number a
|
||||
|
||||
Args:
|
||||
a (Integer): the number
|
||||
|
||||
Return:
|
||||
list of multiple of a
|
||||
"""
|
||||
|
||||
r = list()
|
||||
for i in range(1, 20):
|
||||
r.append(a * i)
|
||||
return r
|
||||
|
||||
def lcm(a, b):
|
||||
"""
|
||||
This function get the LCM (Least Common Multiple) a of b
|
||||
|
||||
Args:
|
||||
a (Integer): the number
|
||||
b (Integer): the number
|
||||
|
||||
Return:
|
||||
the LCM
|
||||
"""
|
||||
return (b // gcd(a, b)) * a
|
||||
|
||||
Reference in New Issue
Block a user