Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ca3f441
[Add] Find order algorithm and its supplemental
D-Sinus Dec 2, 2019
d323b30
[Add] Find primitive root algorithm
D-Sinus Dec 3, 2019
de67fd4
[Edit] Add 'find_' in front of primitive root algorithm file
D-Sinus Dec 3, 2019
ac8a395
[Add/Fix] Supplemental & exception handling for the case n = 1
D-Sinus Dec 3, 2019
5e699ba
[Fix] Exception handling for the case a == n == 1 in findOrder function
D-Sinus Dec 3, 2019
54b2c0b
Merge branch 'master' of https://github.com/keon/algorithms into add_…
D-Sinus Dec 9, 2019
3c05cd2
[Delete] Algorithms in my other branch
D-Sinus Dec 9, 2019
84b175a
[Add] Diffie-Hellman Key Exchange Illustration
D-Sinus Dec 9, 2019
2f77ffc
[Add] Description for Diffie-Hellman Key exchange
D-Sinus Dec 9, 2019
50d257d
Merge branch 'master' of https://github.com/keon/algorithms into add_…
D-Sinus Dec 9, 2019
5f92e1d
[Add] Supplemental for DH Key Exchange
D-Sinus Dec 9, 2019
ad4fc3d
[Add] Test and its operating environment
D-Sinus Dec 9, 2019
3956a2d
[Edit] Add link to README.md file
D-Sinus Dec 9, 2019
37ab3e6
[Edit] Synchonize current branch with remote branch
D-Sinus Dec 12, 2019
e7d6970
[Edit] For not primitive root case, code raise ValueError now
D-Sinus Dec 12, 2019
999fd6a
[Edit] Change test cases according to immediate before commit
D-Sinus Dec 12, 2019
5ad351e
[Edit] For not primitive root case, code return False now, for consis…
D-Sinus Dec 12, 2019
ccdbadd
Change test cases according to immediate before commit
D-Sinus Dec 12, 2019
db01cd2
[Edit] If optional parameter is given, additional explanation would a…
D-Sinus Dec 12, 2019
c96f04c
Merge branch 'master' of https://github.com/keon/algorithms into add_…
D-Sinus Dec 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ If you want to uninstall algorithms, it is as simple as:
- [recursive_binomial_coefficient](algorithms/maths/recursive_binomial_coefficient.py)
- [find_order](algorithms/maths/find_order_simple.py)
- [find_primitive_root](algorithms/maths/find_primitive_root_simple.py)
- [diffie_hellman_key_exchange](algorithms/maths/diffie_hellman_key_exchange.py)
- [matrix](algorithms/matrix)
- [sudoku_validator](algorithms/matrix/sudoku_validator.py)
- [bomb_enemy](algorithms/matrix/bomb_enemy.py)
Expand Down
1 change: 1 addition & 0 deletions algorithms/maths/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
from .cosine_similarity import *
from .find_order_simple import *
from .find_primitive_root_simple import *
from .diffie_hellman_key_exchange import *
190 changes: 190 additions & 0 deletions algorithms/maths/diffie_hellman_key_exchange.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import math
from random import randint

"""
Code from /algorithms/maths/prime_check.py,
written by 'goswami-rahul' and 'Hai Honag Dang'
"""
def prime_check(n):
"""Return True if n is a prime number
Else return False.
"""

if n <= 1:
return False
if n == 2 or n == 3:
return True
if n % 2 == 0 or n % 3 == 0:
return False
j = 5
while j * j <= n:
if n % j == 0 or n % (j + 2) == 0:
return False
j += 6
return True


"""
For positive integer n and given integer a that satisfies gcd(a, n) = 1,
the order of a modulo n is the smallest positive integer k that satisfies
pow (a, k) % n = 1. In other words, (a^k) ≡ 1 (mod n).
Order of certain number may or may not be exist. If so, return -1.
"""
def find_order(a, n):
if ((a == 1) & (n == 1)):
return 1
""" Exception Handeling :
1 is the order of of 1 """
else:
if (math.gcd(a, n) != 1):
print ("a and n should be relative prime!")
return -1
else:
for i in range(1, n):
if (pow(a, i) % n == 1):
return i
return -1

"""
Euler's totient function, also known as phi-function ϕ(n),
counts the number of integers between 1 and n inclusive,
which are coprime to n.
(Two numbers are coprime if their greatest common divisor (GCD) equals 1).
Code from /algorithms/maths/euler_totient.py, written by 'goswami-rahul'
"""
def euler_totient(n):
"""Euler's totient function or Phi function.
Time Complexity: O(sqrt(n))."""
result = n;
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
while n % i == 0:
n //= i
result -= result // i
if n > 1:
result -= result // n;
return result;

"""
For positive integer n and given integer a that satisfies gcd(a, n) = 1,
a is the primitive root of n, if a's order k for n satisfies k = ϕ(n).
Primitive roots of certain number may or may not be exist.
If so, return empty list.
"""

def find_primitive_root(n):
if (n == 1):
return [0]
""" Exception Handeling :
0 is the only primitive root of 1 """
else:
phi = euler_totient(n)
p_root_list = []
""" It will return every primitive roots of n. """
for i in range (1, n):
if (math.gcd(i, n) != 1):
continue
""" To have order, a and n must be
relative prime with each other. """
else:
order = find_order(i, n)
if (order == phi):
p_root_list.append(i)
else:
continue
return p_root_list


"""
Diffie-Hellman key exchange is the method that enables
two entities (in here, Alice and Bob), not knowing each other,
to share common secret key through not-encrypted communication network.
This method use the property of one-way function (discrete logarithm)
For example, given a, b and n, it is easy to calculate x
that satisfies (a^b) ≡ x (mod n).
However, it is very hard to calculate x that satisfies (a^x) ≡ b (mod n).
For using this method, large prime number p and its primitive root a must be given.
"""

def alice_private_key(p):
"""Alice determine her private key
in the range of 1 ~ p-1.
This must be kept in secret"""
return randint(1, p-1)


def alice_public_key(a_pr_k, a, p):
"""Alice calculate her public key
with her private key.
This is open to public"""
return pow(a, a_pr_k) % p


def bob_private_key(p):
"""Bob determine his private key
in the range of 1 ~ p-1.
This must be kept in secret"""
return randint(1, p-1)


def bob_public_key(b_pr_k, a, p):
"""Bob calculate his public key
with his private key.
This is open to public"""
return pow(a, b_pr_k) % p


def alice_shared_key(b_pu_k, a_pr_k, p):
""" Alice calculate secret key shared with Bob,
with her private key and Bob's public key.
This must be kept in secret"""
return pow(b_pu_k, a_pr_k) % p


def bob_shared_key(a_pu_k, b_pr_k, p):
""" Bob calculate secret key shared with Alice,
with his private key and Alice's public key.
This must be kept in secret"""
return pow(a_pu_k, b_pr_k) % p


def diffie_hellman_key_exchange(a, p, option = None):
if (option != None):
option = 1
""" Print explanation of process
when option parameter is given """
if (prime_check(p) == False):
print("%d is not a prime number" % p)
return False
"""p must be large prime number"""
else:
try:
p_root_list = find_primitive_root(p)
p_root_list.index(a)
except ValueError:
print("%d is not a primitive root of %d" % (a, p))
return False
""" a must be primitive root of p """

a_pr_k = alice_private_key(p)
a_pu_k = alice_public_key(a_pr_k, a, p)


b_pr_k = bob_private_key(p)
b_pu_k = bob_public_key(b_pr_k, a, p)

if (option == 1):
print ("Private key of Alice = %d" % a_pr_k)
print ("Public key of Alice = %d" % a_pu_k)
print ("Private key of Bob = %d" % b_pr_k)
print ("Public key of Bob = %d" % b_pu_k)

""" In here, Alice send her public key to Bob,
and Bob also send his public key to Alice."""

a_sh_k = alice_shared_key(b_pu_k, a_pr_k, p)
b_sh_k = bob_shared_key(a_pu_k, b_pr_k, p)
print ("Shared key calculated by Alice = %d" % a_sh_k)
print ("Shared key calculated by Bob = %d" % b_sh_k)

return (a_sh_k == b_sh_k)
16 changes: 16 additions & 0 deletions tests/test_maths.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
cosine_similarity,
find_order,
find_primitive_root,
alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange
)

import unittest
Expand Down Expand Up @@ -326,6 +327,7 @@ def test_cosine_similarity(self):
self.assertAlmostEqual(cosine_similarity(vec_a, vec_b), -1)
self.assertAlmostEqual(cosine_similarity(vec_a, vec_c), 0.4714045208)


class TestFindPrimitiveRoot(unittest.TestCase):
"""[summary]
Test for the file find_primitive_root_simple.py
Expand Down Expand Up @@ -353,6 +355,20 @@ def test_find_order_simple(self):
self.assertEqual(-1, find_order(128, 256))
self.assertEqual(352, find_order(3, 353))


class TestDiffieHellmanKeyExchange(unittest.TestCase):
"""[summary]
Test for the file diffie_hellman_key_exchange.py

Arguments:
unittest {[type]} -- [description]
"""
def test_find_order_simple(self):
self.assertFalse(diffie_hellman_key_exchange(3, 6))
self.assertTrue(diffie_hellman_key_exchange(3, 353))
self.assertFalse(diffie_hellman_key_exchange(5, 211))
self.assertTrue(diffie_hellman_key_exchange(11, 971))

if __name__ == "__main__":
unittest.main()