First commit

This commit is contained in:
2026-01-11 09:19:22 +01:00
commit 50f7b1159e
108 changed files with 11791 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python3
from Cryptotools.Utils.utils import gcd
def carmi_first_method(n) -> int:
coprimes = list()
for i in range(1, n):
if gcd(i, n) == 1:
coprimes.append(i)
print(coprimes)
smallest = list()
for m in range(1, n):
l = 0
for a in coprimes:
if a ** m % n == 1:
l += 1
if l == len(coprimes):
smallest.append(m)
#print(smallest)
return min(smallest)
print(f"lambda(12) = {carmi_first_method(12)}")
print(f"lambda(19) = {carmi_first_method(19)}")
#print(f"lambda(28) = {carmi_first_method(28)}")
#print(f"lambda(32) = {carmi_first_method(32)}")
#print(f"lambda(33) = {carmi_first_method(33)}")
#print(f"lambda(35) = {carmi_first_method(35)}")
#print(f"lambda(36) = {carmi_first_method(36)}")
#print(f"lambda(135) = {carmi_first_method(135)}")
#print(f"lambda(1200) = {carmi_first_method(1200)}")
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.coprime import phi
from Cryptotools.lcm import lcm
from Cryptotools.Numbers.carmi import carmi_numbers, is_carmichael, carmichael_lambda
print(f"phi(19) = {phi(19)}")
print("Carmichael's number")
l = carmi_numbers(561)
print(is_carmichael(561, l))
# Test Carmichael lambda
print("Carmichael")
print(f"12 {carmichael_lambda(12)}")
print(f"19 {carmichael_lambda(19)}")
print(f"28 {carmichael_lambda(28)}")
print(f"32 {carmichael_lambda(32)}")
print(f"33 {carmichael_lambda(33)}")
print(f"35 {carmichael_lambda(35)}")
print(f"36 {carmichael_lambda(36)}")
print(f"135 {carmichael_lambda(135)}")
print(f"1200 {carmichael_lambda(1200)}")
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import isPrimeNumber
from random import choice
def operation(a, b, n):
return (a ** b) % n
n = 19
g = list()
for i in range(1, n):
g.append(i)
print(f"n = {n}")
print(f"G = {g}")
cyclic = Cyclic(g, n, operation)
order = len(g) # Length of the group
print(f"len: {order}")
print(f"prime: {isPrimeNumber(order)}")
cyclic.generator()
print(f"All generators: {cyclic.getGenerators()}")
print(f"Is cyclic: {cyclic.isCyclic()}")
# Check if the abelian group is respected
print(f"It is an abelian group: {cyclic.closure()}\n")
e = choice(cyclic.getGenerators())
z = list()
for a in range(1, n):
res = operation(e, a, n)
z.append(res)
print(z)
if z == g:
print(f"The group generated with the generator {e} works")
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import getPrimeNumber
from random import randint, choice
from math import log, log10, log2
"""
Here, we will try to understand why we need to have a generator when we encrypt data for Diffie-Hellman
https://crypto.stackexchange.com/questions/25489/why-does-diffie-hellman-need-be-a-cyclic-group
"""
def operation(a, b, n):
return (a ** b) % n
def getGenerator(gr, p):
index = 1
for g in range(2, p):
z = list()
for entry in range(1, p):
res = operation(g, index, p)
#if res not in z:
z.append(res)
index = index + 1
print(f"{g}: {sorted(z)}")
def generateGroupByG(gr, p, g):
index = 1
z = list()
for entry in range(1, p):
res = operation(g, index, p)
#if res not in z:
z.append(res)
index = index + 1
return z
def computePublicKey(key, p, g):
return (g ** key) % p
gr = list()
# Public value
p = 5
g = 0
for i in range(1, p):
gr.append(i)
print(f"p = {p}")
print(f"G = {gr}")
# We try with a generator which is not in list
cyclic = Cyclic(gr, p, operation)
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
# Generate group with g = 2
grWithG = generateGroupByG(gr, p, 2)
print(f"Group generated with g = 2: {grWithG}")
for a in grWithG:
# print(f"log2({a}) = {log(a, 2)}") # Same as below
print(f"log2({a}) = {log2(a)}")
print()
for a in range(1, len(grWithG) + 1):
print(f"log2({a}) = {log2(a)}")
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from random import choice
def operation(a, b, n):
return (a ** b) % n
n = 19
g = list()
for i in range(1, n):
g.append(i)
print(f"n = {n}")
print(f"G = {g}")
cyclic = Cyclic(g, n, operation)
cyclic.generator()
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
e = choice(generators)
z = list()
for a in range(1, n):
res = operation(e, a, n)
z.append(res)
z = sorted(z)
if z == g:
print(f"Working with the generator {e}")
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import getPrimeNumber
from random import randint, choice
from math import log, log10
"""
Here, we will try to understand why we need to have a generator when we encrypt data for Diffie-Hellman
https://crypto.stackexchange.com/questions/25489/why-does-diffie-hellman-need-be-a-cyclic-group
"""
def operation(a, b, n):
return (a ** b) % n
def getGenerator(gr, p):
cyclic = Cyclic(gr, p, operation)
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
cyclic.identity()
print(f"Identity: {cyclic.getIdentity()}")
return generators
gr = list()
# Public value
p = 13
g = 0
for i in range(1, p):
gr.append(i)
print(f"p = {p}")
print(f"G = {gr}")
# We try with a generator which is not in list
generators = getGenerator(gr, p)
g = 3 # In the group
#g = # Not in the group
#print(f"g = {g}")
# Try to compute the cyclic subgroup
for G in range(p + 1):
res = 0
for a in range(G):
r = operation(G, a, p)
res = res + r
if res == p:
print(f"G = {G}; res = {res}")
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Utils.utils import gcd
from Cryptotools.Numbers.primeNumber import isPrimeNumber
from random import choice
def operation(a, b, n):
return (a ** b) % n
def test1(n):
"""
We test with n is not prime but the order of the group is a prime number
"""
g = list()
g2 = list()
for i in range(1, n):
#if gcd(i, n) == 1:
g.append(i)
print(f"n = {n}")
print(f"G = {g}")
Gsorted = sorted(g)
cyclic = Cyclic(g, n, operation)
order = len(g) # https://en.wikipedia.org/wiki/Order_(group_theory)
print(f"len: {order}")
print(f"prime: {isPrimeNumber(order)}")
g2 = list()
for i in range(1, order):
if gcd(i, order) == 1:
g2.append(i)
pass
print(g2)
# Pick a number in the previous list and check if we can generate all number with it
item = choice(g2)
print()
# if the order is prime, the group is cyclic ?
# Check if we have all items
g3 = list()
for i in range(1, n):
res = operation(i, item, n)
if gcd(res, item) == 1:
g3.append(res)
#print(res)
pass
G2sorted = sorted(g2)
G3sorted = sorted(g3)
print()
# print(f"{g} = {cyclic.generator(g)}")
gen = cyclic.generator()
print(f"All generators: {cyclic.getGenerators()}")
print(f"Is cyclic: {cyclic.isCyclic()}")
print()
print(G2sorted)
print(G3sorted)
if G3sorted == Gsorted:
print(f"Matching with item {item}") # Always match with item 1
# Check if the abelian group is respected
print(f"It is an abelian group: {cyclic.closure()}\n")
test1(19)
test1(12)
+74
View File
@@ -0,0 +1,74 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import getPrimeNumber
from random import randint, choice
from math import log, log10
"""
Here, we will try to understand why we need to have a generator when we encrypt data for Diffie-Hellman
https://crypto.stackexchange.com/questions/25489/why-does-diffie-hellman-need-be-a-cyclic-group
"""
def operation(a, b, n):
return (a ** b) % n
def getGenerator(gr, p):
cyclic = Cyclic(gr, p, operation)
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
# Test with a no generator
item = 2
while item in generators: # we loop until we found an item which is not a generators of the group
item = randint(1, p)
return item
def computePublicKey(key, p, g):
return (g ** key) % p
def computeEphemeralKey(public, secret, p):
return (public ** secret) % p
gr = list()
# Public value
#p = getPrimeNumber(n = 8)
#p = 257
p = 19
g = 0
for i in range(1, p):
gr.append(i)
print(f"p = {p}")
print(f"G = {gr}")
# We try with a generator which is not in list
g = getGenerator(gr, p)
#g = [3, 5, 6, 7, 10, 12, 14, 19, 20, 24, 27, 28, 33, 37, 38, 39, 40, 41, 43, 45, 47, 48, 51, 53, 54, 55, 56, 63, 65, 66, 69, 71, 74, 75, 76, 77, 78, 80, 82, 83, 85, 86, 87, 90, 91, 93, 94, 96, 97, 101, 102, 103, 105, 106, 107, 108, 109, 110, 112, 115, 119, 125, 126, 127, 130, 131, 132, 138, 142, 145, 147, 148, 149, 150, 151, 152, 154, 155, 156, 160, 161, 163, 164, 166, 167, 170, 171, 172, 174, 175, 177, 179, 180, 181, 182, 183, 186, 188, 191, 192, 194, 201, 202, 203, 204, 206, 209, 210, 212, 214, 216, 217, 218, 219, 220, 224, 229, 230, 233, 237, 238, 243, 245, 247, 250, 251, 252, 254]
g = 29 # Not in the group
print(f"g = {g}")
# We can compute with the secret key
secretKeyA = 5
secretKeyB = 10
publicKeyA = computePublicKey(secretKeyA, p, g)
publicKeyB = computePublicKey(secretKeyB, p, g)
print(f"Public key A: {publicKeyA}")
print(f"Public key B: {publicKeyB}")
# Eve sniff the traffic and knows p, g and publicKeyA and B
# Generator need to be use, because that avoid to Eve to try to find a secret key of Alice or Bob ???
# Utiliser un generateur qui genere la tout le groupe, va permettre d'éviter à Eve de trouver la secret key de Alice ou Bob ????
# https://eitca.org/cybersecurity/eitc-is-acc-advanced-classical-cryptography/diffie-hellman-cryptosystem/diffie-hellman-key-exchange-and-the-discrete-log-problem/examination-review-diffie-hellman-key-exchange-and-the-discrete-log-problem/what-are-the-roles-of-the-prime-number-p-and-the-generator-alpha-in-the-diffie-hellman-key-exchange-process/
# https://www.perplexity.ai/search/why-generator-in-cyclic-group-QRYR6.rxSI218hs_x5CvnQ#0
# They exchange their public keys
ephemeralKeyA = computeEphemeralKey(publicKeyB, secretKeyA, p)
ephemeralKeyB = computeEphemeralKey(publicKeyA, secretKeyB, p)
print(f"Ephemeral key A: {ephemeralKeyA}")
print(f"Ephemeral key B: {ephemeralKeyB}")
# Test log10
#for i in range(1, 1000):
# r = log10(i)
# if isinstance(r, int):
# print(f"{i} = {r}")
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import getPrimeNumber
from random import randint, choice
from math import log, log10
"""
Here, we will try to understand why we need to have a generator when we encrypt data for Diffie-Hellman
https://crypto.stackexchange.com/questions/25489/why-does-diffie-hellman-need-be-a-cyclic-group
"""
def operation(a, b, n):
return (a ** b) % n
def getGenerator(gr, p):
index = 1
for g in range(2, p):
z = list()
for entry in range(1, p):
res = operation(g, index, p)
#if res not in z:
z.append(res)
index = index + 1
print(f"{g}: {sorted(z)}")
def getGenerator2(gr, p, g):
index = 1
z = list()
for entry in range(1, p):
res = operation(g, index, p)
if res not in z:
z.append(res)
index = index + 1
return z
def computePublicKey(key, p, g):
return (g ** key) % p
def computeEphemeralKey(public, secret, p):
return (public ** secret) % p
gr = list()
# Public value
p = 43
g = 0
for i in range(1, p):
gr.append(i)
print(f"p = {p}")
print(f"G = {gr}")
# We try with a generator which is not in list
cyclic = Cyclic(gr, p, operation)
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
g = 3 # In the group
print(f"g = {g}")
# We can compute with the secret key
secretKeyA = 5
secretKeyB = 10
publicKeyA = computePublicKey(secretKeyA, p, g)
publicKeyB = computePublicKey(secretKeyB, p, g)
print(f"Public key A: {publicKeyA}")
print(f"Public key B: {publicKeyB}\n")
# Here, g is in the generator, we need to compute all values until that match with publicKeyA
for a in range(1, p):
res = operation(g, a, p)
if res == publicKeyA:
print(f"Brute forced secret key of A: {a}")
for a in range(1, p):
res = operation(g, a, p)
if res == publicKeyB:
print(f"Brute forced secret key of B: {a}")
print()
#for a in generators:
# print(a)
#
#print()
# Here, we generate all key withthe same generator
keys = list()
for a in range(1, p):
keys.append(operation(g, a, p))
print((keys))
print(sorted(keys))
print()
print(f"Keys with g = 4: {sorted(getGenerator2(gr, p, 4))}")
# Do the same, but g is not a generator
g = 4 # Not in the generator group
publicKeyA = computePublicKey(secretKeyA, p, g)
publicKeyB = computePublicKey(secretKeyB, p, g)
print(f"Public key A: {publicKeyA}")
print(f"Public key B: {publicKeyB}")
keys = list()
for a in range(1, p):
keys.append(operation(g, a, p))
print(keys)
# Eve sniff the traffic and knows p, g and publicKeyA and B
# Eve, knows p and g, because it's public
# Eve need to guess the secretKey of A.
# For doing that, we iterate all posibility until that match with the publicKeyA
#for a in range(1, 4):
# res = operation(g, a, p)
# print(res)
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env python3
import unittest
from Cryptotools.Numbers.primeNumber import isPrimeNumber, _millerRabinTest, getPrimeNumber
from math import sqrt, isqrt, ceil
from sympy import sqrt as sq
def get_closest_prime(p):
q = p + 1
l = list()
while True:
if _millerRabinTest(q):
l.append(q)
if len(l) == 20:
break
q += 1
return l
def test():
while True:
p = getPrimeNumber(64)
b = sqrt(p)
if b % 2 == 0.0:
break
print(p)
#test()
#exit(1)
p = 7901
q = 7817
#p = getPrimeNumber(64)
#q = get_closest_prime(p)[1]
p = 7943202761666983 # Works
q = 7943202761667119
#p = 314159200000000028138418196395985880850000485810513
#q = 314159200000000028138415196395985880850000485810479
print(f"p = {p}")
print(f"q = {q}")
n = p * q
print(f"n = {n}")
a = ceil(sqrt(n))
#print(a)
#print(sqrt(n))
#print(sqrt(n) < n) # True
#print(a * a)
#print(a * a < n)
#print()
#a = isqrt(n) + 1
iteration = 0
while True:
# b2 = (a ** 2) - n
iteration += 1
b2 = pow(a, 2) - n
#b2 = ceil(a*a) - n
# print(b2)
sqb2 = ceil(sqrt(b2))
# print(b2, isqrt(pow(b2, 2)))
if b2 % 2 == 0.0:
#if isqrt(pow(b2, 2)) == b2:
b = isqrt(b2)
break
a = a + 1
print(f"Iteration: {iteration}")
print(f"a = {a}")
print(f"b2 = {b2}")
print(f"b = {b}")
p = int((a + b))
q = int((a - b))
print(p)
print(q)
#N = (a + b) * (a - b)
N = p * q
print(_millerRabinTest(p))
print(_millerRabinTest(q))
print(f"N = {N}")
print(n == N)
print()
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.numbers import fibonacci
print(fibonacci(40))
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env python3
from Cryptotools.Groups.galois import Galois
import matplotlib.pyplot as plt # pip install numpy==1.26.4
def operation(a, b, n):
return (a ** b) % n
q = 13
g = Galois(q, operation)
add = g.add()
div = g.div()
mul = g.mul()
sub = g.sub()
g.check_closure_law('+')
g.check_closure_law('*')
g.check_closure_law('-')
g.check_closure_law('/')
print("Addition")
g.printMatrice(add)
print("Division")
g.printMatrice(div)
print("Multiplication")
g.printMatrice(mul)
print("Substraction")
g.printMatrice(sub)
print("Primitives root")
print(g.primitiveRoot(), end="\n\n")
#print("Identity elements")
g.check_identity_add()
g.check_identity_mul()
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python3
from Cryptotools.Groups.group import Group
from Cryptotools.Utils.utils import gcd
import matplotlib.pyplot as plt
n = 18
def operation(e1, e2, n) -> int:
return e1 * e2 % n
# Generate the group G
g = list()
for i in range(1, n):
#if gcd(i, n) == 1:
g.append(i)
G = Group(n = n, g = g, ope=operation)
print(f"n = {n}")
print(f"G = {G.getG()}")
if G.closure() is False:
print("The closure law is not respected. It's not an abelian (commutative) group")
else:
print("It is a closure group")
if G.associative() is False:
print("The associative law is not respected. It's not a group")
else:
print("It is an associative group")
if G.identity() is False:
print("The group hasn't an identity element")
else:
print(f"Identity: {G.getIdentity()}")
if G.reverse() is False:
print(f"The group hasn't a reverse")
else:
print(f"Reverses: {G.getReverses()}")
#reverses = G.getReverses()
#plt.rcParams["figure.figsize"] = [7.00, 3.50]
#plt.rcParams["figure.autolayout"] = True
#for key, value in reverses.items():
# x = key
# y = value
# plt.plot(x, y, marker="o", markersize=2, markeredgecolor="blue")
# #plt.Circle((0, n), 0.2, color='r')
#
#plt.xlim(0, n)
#plt.ylim(0, n)
#plt.grid()
#plt.show()
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env python3
from utils.primeNumber import primeNumber
print(primeNumber(19))
print(primeNumber(20))
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import get_n_prime_numbers
import matplotlib.pyplot as plt
#import numpy as np
# Get list of n prime numbers
n = 100
primes = get_n_prime_numbers(n)
print(primes)
# With matplotlib, show into a graphics and try to explain that
plt.rcParams["figure.figsize"] = [7.00, 3.50]
plt.rcParams["figure.autolayout"] = True
for i in range(0, n):
x = primes[i]
y = primes[i]
plt.plot(x, y, marker="o", markersize=2, markeredgecolor="blue")
plt.xlim(0, n)
plt.ylim(0, n)
plt.grid()
plt.show()
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.factorization import pollard_p_minus_1
from Cryptotools.Numbers.primeNumber import _millerRabinTest, getPrimeNumber
from sympy.ntheory.factor_ import pollard_pm1
from sympy import factorint
def pollard(n):
p = pollard_p_minus_1(n, B=10)
if p is not None:
print(p, n / p)
print(pollard_pm1(n, B=10))
print()
return True
return False
def safePrime(p):
nP = 2 * p + 1
return _millerRabinTest(nP)
#pollard(299)
#pollard(257 * 1009)
#pollard(1684) # Doesn't works
# Test for RSA
#p = 281
while True:
while True:
p = getPrimeNumber(64)
if ((p - 1) / 2520) % 2 == 0.0:
#print(p)
break
#p = 322506219347091343
#q = 13953581789873249851
# n = p * q
while True:
q = getPrimeNumber(64)
if int(((q - 1) / 2520) % 2) == 1:
#print(q)
break
#q = 223
n = p * q
##print(n)
#print(pollard(n))
#break
if pollard(n): # We can factorize n
break
print(safePrime(p))
#print(safePrime(q))
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import getPrimeNumber, sophieGermainPrime
p = getPrimeNumber(512)
print(p)
if sophieGermainPrime(p):
print("It's a safe prime")
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import _millerRabinTest, _fermatLittleTheorem
from Cryptotools.Numbers.carmi import carmi_numbers, is_carmi_number, generate_carmi_numbers
print(_fermatLittleTheorem(1729))
print(_fermatLittleTheorem(1105))
print(_fermatLittleTheorem(6601))
print(_millerRabinTest(1729))
print(f"1729: {is_carmi_number(1729)}")
print(f"1105: {is_carmi_number(1105)}")
print(f"110: {is_carmi_number(110)}")
print(f"2465: {is_carmi_number(2465)}")
print(f"6601: {is_carmi_number(6601)}")
#print(carmi_numbers(1729))
print(generate_carmi_numbers(10))
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python3
from Cryptotools.Encryptions.RSA import RSA
rsa = RSA()
rsa.generateKeys(size=512)
e = rsa.e
d = rsa.d
n = rsa.n
s = "I am encrypted with RSA"
print(f"plaintext: {s}")
encrypted = rsa.encrypt(s)
# Encrypt data
# print(f"ciphertext: {encrypted}")
# We decrypt
plaintext = rsa.decrypt(encrypted)
print(f"Plaintext: {plaintext}")
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.coprime import phi
from Cryptotools.Utils.utils import gcd
def generate_keys():
p = 7853
q = 7919
n = p * q
e = 65536 # It's public value, must be coprime with phi n
print(n)
#phin = phi(n)
phin = (p - 1) * (q - 1)
print(phin)
for _ in range(2, phin):
if gcd(phin, e) == 1:
break
e += 1
print(e)
plaintext = 'A'
ciphertext = pow(ord(plaintext), e, n)
print(f"Ciphertext: {ciphertext}")
# Now, we can test
# To resolve that formula: C = x ** e mod n
# Where C is the ciphertext, and C, e and n are known (public values)
# First, we need to find the reverse modular of phi(n) or carmi(n)
# z = e -1 mod phi(n)
# After that, we have our decryption key, we can resolve x
# x = C ** z mod n
# The RSA Problem is to decrypt with the public-key
# We just need to find the decryption key with the public-key and the modulus
# First, we need to find phi(n)
# phin = phi(n) # I computed here, result = 62172136
n = 62187907
phin = 62172136
e = 65537
ciphertext = 38605768
# print(phin)
# Find the reverse modular
d = pow(e, -1, phin)
# print(d)
plaintext = pow(ciphertext, d, n)
print(chr(plaintext))
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import sieveOfEratosthenes
print(sieveOfEratosthenes(100))
print()
+15
View File
@@ -0,0 +1,15 @@
from Cryptotools.Utils.utils import gcd
for i in range(1, 30):
if 30 % i == 0:
print(i)
print()
for i in range(1, 40):
if 40 % i == 0:
print(i)
print(gcd(30, 40))