Skip to content

fix(mypy): Fix annotations for 13 cipher algorithms #4278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 22, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
8 changes: 4 additions & 4 deletions ciphers/a1z26.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@
"""


def encode(plain: str) -> list:
def encode(plain: str) -> list[int]:
"""
>>> encode("myname")
[13, 25, 14, 1, 13, 5]
"""
return [ord(elem) - 96 for elem in plain]


def decode(encoded: list) -> str:
def decode(encoded: list[int]) -> str:
"""
>>> decode([13, 25, 14, 1, 13, 5])
'myname'
"""
return "".join(chr(elem + 96) for elem in encoded)


def main():
encoded = encode(input("->").strip().lower())
def main() -> None:
encoded = encode(input("-> ").strip().lower())
print("Encoded: ", encoded)
print("Decoded:", decode(encoded))

Expand Down
44 changes: 22 additions & 22 deletions ciphers/affine_cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,12 @@

from . import cryptomath_module as cryptomath

SYMBOLS = (
SYMBOLS: str = (
r""" !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`"""
r"""abcdefghijklmnopqrstuvwxyz{|}~"""
)


def main():
"""
>>> key = get_random_key()
>>> msg = "This is a test!"
>>> decrypt_message(key, encrypt_message(key, msg)) == msg
True
"""
message = input("Enter message: ").strip()
key = int(input("Enter key [2000 - 9000]: ").strip())
mode = input("Encrypt/Decrypt [E/D]: ").strip().lower()

if mode.startswith("e"):
mode = "encrypt"
translated = encrypt_message(key, message)
elif mode.startswith("d"):
mode = "decrypt"
translated = decrypt_message(key, message)
print(f"\n{mode.title()}ed text: \n{translated}")


def check_keys(keyA: int, keyB: int, mode: str) -> None:
if mode == "encrypt":
if keyA == 1:
Expand Down Expand Up @@ -80,7 +60,7 @@ def decrypt_message(key: int, message: str) -> str:
keyA, keyB = divmod(key, len(SYMBOLS))
check_keys(keyA, keyB, "decrypt")
plainText = ""
modInverseOfkeyA = cryptomath.findModInverse(keyA, len(SYMBOLS))
modInverseOfkeyA = cryptomath.find_mod_inverse(keyA, len(SYMBOLS))
for symbol in message:
if symbol in SYMBOLS:
symIndex = SYMBOLS.find(symbol)
Expand All @@ -98,6 +78,26 @@ def get_random_key() -> int:
return keyA * len(SYMBOLS) + keyB


def main() -> None:
"""
>>> key = get_random_key()
>>> msg = "This is a test!"
>>> decrypt_message(key, encrypt_message(key, msg)) == msg
True
"""
message = input("Enter message: ").strip()
key = int(input("Enter key [2000 - 9000]: ").strip())
mode = input("Encrypt/Decrypt [E/D]: ").strip().lower()

if mode.startswith("e"):
mode = "encrypt"
translated = encrypt_message(key, message)
elif mode.startswith("d"):
mode = "decrypt"
translated = decrypt_message(key, message)
print(f"\n{mode.title()}ed text: \n{translated}")


if __name__ == "__main__":
import doctest

Expand Down
4 changes: 2 additions & 2 deletions ciphers/atbash.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ def benchmark() -> None:


if __name__ == "__main__":
for sequence in ("ABCDEFGH", "123GGjj", "testStringtest", "with space"):
print(f"{sequence} encrypted in atbash: {atbash(sequence)}")
for example in ("ABCDEFGH", "123GGjj", "testStringtest", "with space"):
print(f"{example} encrypted in atbash: {atbash(example)}")
benchmark()
2 changes: 1 addition & 1 deletion ciphers/base32.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import base64


def main():
def main() -> None:
inp = input("->")
encoded = inp.encode("utf-8") # encoded the input (we need a bytes like object)
b32encoded = base64.b32encode(encoded) # b32encoded the encoded string
Expand Down
2 changes: 1 addition & 1 deletion ciphers/base85.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import base64


def main():
def main() -> None:
inp = input("->")
encoded = inp.encode("utf-8") # encoded the input (we need a bytes like object)
a85encoded = base64.a85encode(encoded) # a85encoded the encoded string
Expand Down
2 changes: 1 addition & 1 deletion ciphers/beaufort_cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def original_text(cipher_text: str, key_new: str) -> str:
return or_txt


def main():
def main() -> None:
message = "THE GERMAN ATTACK"
key = "SECRET"
key_new = generate_key(message, key)
Expand Down
2 changes: 1 addition & 1 deletion ciphers/brute_force_caesar_cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def decrypt(message: str) -> None:
print(f"Decryption using Key #{key}: {translated}")


def main():
def main() -> None:
message = input("Encrypted message: ")
message = message.upper()
decrypt(message)
Expand Down
4 changes: 2 additions & 2 deletions ciphers/cryptomath_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ def gcd(a: int, b: int) -> int:
return b


def findModInverse(a: int, m: int) -> int:
def find_mod_inverse(a: int, m: int) -> int:
if gcd(a, m) != 1:
return None
raise ValueError(f"mod inverse of {a!r} and {m!r} does not exist")
u1, u2, u3 = 1, 0, a
v1, v2, v3 = 0, 1, m
while v3 != 0:
Expand Down
30 changes: 15 additions & 15 deletions ciphers/decrypt_caesar_with_chi_squared.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/usr/bin/env python3

from typing import Tuple
from typing import Optional


def decrypt_caesar_with_chi_squared(
ciphertext: str,
cipher_alphabet: str = None,
frequencies_dict: str = None,
cipher_alphabet: Optional[list[str]] = None,
frequencies_dict: Optional[dict[str, float]] = None,
case_sensetive: bool = False,
) -> Tuple[int, float, str]:
) -> tuple[int, float, str]:
"""
Basic Usage
===========
Expand Down Expand Up @@ -123,9 +123,9 @@ def decrypt_caesar_with_chi_squared(
AttributeError: 'int' object has no attribute 'lower'
"""
alphabet_letters = cipher_alphabet or [chr(i) for i in range(97, 123)]
frequencies_dict = frequencies_dict or {}

if frequencies_dict == {}:
# If the argument is None or the user provided an empty dictionary
if frequencies_dict is None or not frequencies_dict:
# Frequencies of letters in the english language (how much they show up)
frequencies = {
"a": 0.08497,
Expand Down Expand Up @@ -163,7 +163,7 @@ def decrypt_caesar_with_chi_squared(
ciphertext = ciphertext.lower()

# Chi squared statistic values
chi_squared_statistic_values = {}
chi_squared_statistic_values: dict[int, tuple[float, str]] = {}

# cycle through all of the shifts
for shift in range(len(alphabet_letters)):
Expand Down Expand Up @@ -215,22 +215,22 @@ def decrypt_caesar_with_chi_squared(
chi_squared_statistic += chi_letter_value

# Add the data to the chi_squared_statistic_values dictionary
chi_squared_statistic_values[shift] = [
chi_squared_statistic_values[shift] = (
chi_squared_statistic,
decrypted_with_shift,
]
)

# Get the most likely cipher by finding the cipher with the smallest chi squared
# statistic
most_likely_cipher = min(
most_likely_cipher: int = min(
chi_squared_statistic_values, key=chi_squared_statistic_values.get
)
) # type: ignore # First argument to `min` is not optional

# Get all the data from the most likely cipher (key, decoded message)
most_likely_cipher_chi_squared_value = chi_squared_statistic_values[
most_likely_cipher
][0]
decoded_most_likely_cipher = chi_squared_statistic_values[most_likely_cipher][1]
(
most_likely_cipher_chi_squared_value,
decoded_most_likely_cipher,
) = chi_squared_statistic_values[most_likely_cipher]

# Return the data on the most likely shift
return (
Expand Down
25 changes: 16 additions & 9 deletions ciphers/diffie.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
def find_primitive(n: int) -> int:
from typing import Optional


def find_primitive(n: int) -> Optional[int]:
for r in range(1, n):
li = []
for x in range(n - 1):
Expand All @@ -8,18 +11,22 @@ def find_primitive(n: int) -> int:
li.append(val)
else:
return r
return None


if __name__ == "__main__":
q = int(input("Enter a prime number q: "))
a = find_primitive(q)
a_private = int(input("Enter private key of A: "))
a_public = pow(a, a_private, q)
b_private = int(input("Enter private key of B: "))
b_public = pow(a, b_private, q)
if a is None:
print(f"Cannot find the primitive for the value: {a!r}")
else:
a_private = int(input("Enter private key of A: "))
a_public = pow(a, a_private, q)
b_private = int(input("Enter private key of B: "))
b_public = pow(a, b_private, q)

a_secret = pow(b_public, a_private, q)
b_secret = pow(a_public, b_private, q)
a_secret = pow(b_public, a_private, q)
b_secret = pow(a_public, b_private, q)

print("The key value generated by A is: ", a_secret)
print("The key value generated by B is: ", b_secret)
print("The key value generated by A is: ", a_secret)
print("The key value generated by B is: ", b_secret)
36 changes: 18 additions & 18 deletions ciphers/elgamal_key_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,18 @@
import random
import sys

from . import cryptomath_module as cryptoMath
from . import rabin_miller as rabinMiller
from . import cryptomath_module as cryptomath
from . import rabin_miller

min_primitive_root = 3


def main():
print("Making key files...")
makeKeyFiles("elgamal", 2048)
print("Key files generation successful")


# I have written my code naively same as definition of primitive root
# however every time I run this program, memory exceeded...
# so I used 4.80 Algorithm in
# Handbook of Applied Cryptography(CRC Press, ISBN : 0-8493-8523-7, October 1996)
# and it seems to run nicely!
def primitiveRoot(p_val: int) -> int:
def primitive_root(p_val: int) -> int:
print("Generating primitive root of p")
while True:
g = random.randrange(3, p_val)
Expand All @@ -30,20 +24,20 @@ def primitiveRoot(p_val: int) -> int:
return g


def generateKey(keySize: int) -> ((int, int, int, int), (int, int)):
def generate_key(key_size: int) -> tuple[tuple[int, int, int, int], tuple[int, int]]:
print("Generating prime p...")
p = rabinMiller.generateLargePrime(keySize) # select large prime number.
e_1 = primitiveRoot(p) # one primitive root on modulo p.
p = rabin_miller.generateLargePrime(key_size) # select large prime number.
e_1 = primitive_root(p) # one primitive root on modulo p.
d = random.randrange(3, p) # private_key -> have to be greater than 2 for safety.
e_2 = cryptoMath.findModInverse(pow(e_1, d, p), p)
e_2 = cryptomath.find_mod_inverse(pow(e_1, d, p), p)

publicKey = (keySize, e_1, e_2, p)
privateKey = (keySize, d)
public_key = (key_size, e_1, e_2, p)
private_key = (key_size, d)

return publicKey, privateKey
return public_key, private_key


def makeKeyFiles(name: str, keySize: int):
def make_key_files(name: str, keySize: int) -> None:
if os.path.exists("%s_pubkey.txt" % name) or os.path.exists(
"%s_privkey.txt" % name
):
Expand All @@ -55,7 +49,7 @@ def makeKeyFiles(name: str, keySize: int):
)
sys.exit()

publicKey, privateKey = generateKey(keySize)
publicKey, privateKey = generate_key(keySize)
print("\nWriting public key to file %s_pubkey.txt..." % name)
with open("%s_pubkey.txt" % name, "w") as fo:
fo.write(
Expand All @@ -67,5 +61,11 @@ def makeKeyFiles(name: str, keySize: int):
fo.write("%d,%d" % (privateKey[0], privateKey[1]))


def main() -> None:
print("Making key files...")
make_key_files("elgamal", 2048)
print("Key files generation successful")


if __name__ == "__main__":
main()
Loading