Skip to content

Commit 66e97f1

Browse files
dhruvmanilacclauss
authored andcommitted
fix(mypy): Fix annotations for 13 cipher algorithms (TheAlgorithms#4278)
* Initial fix for mypy errors in some cipher algorithms * fix(mypy): Update type hints * fix(mypy): Update type hints for enigma_machine2.py * Update as per the suggestion Co-authored-by: Christian Clauss <[email protected]> Co-authored-by: Christian Clauss <[email protected]>
1 parent 1b1ef70 commit 66e97f1

13 files changed

+101
-89
lines changed

Diff for: ciphers/a1z26.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,24 @@
77
"""
88

99

10-
def encode(plain: str) -> list:
10+
def encode(plain: str) -> list[int]:
1111
"""
1212
>>> encode("myname")
1313
[13, 25, 14, 1, 13, 5]
1414
"""
1515
return [ord(elem) - 96 for elem in plain]
1616

1717

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

2525

26-
def main():
27-
encoded = encode(input("->").strip().lower())
26+
def main() -> None:
27+
encoded = encode(input("-> ").strip().lower())
2828
print("Encoded: ", encoded)
2929
print("Decoded:", decode(encoded))
3030

Diff for: ciphers/affine_cipher.py

+21-21
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,6 @@
99
)
1010

1111

12-
def main():
13-
"""
14-
>>> key = get_random_key()
15-
>>> msg = "This is a test!"
16-
>>> decrypt_message(key, encrypt_message(key, msg)) == msg
17-
True
18-
"""
19-
message = input("Enter message: ").strip()
20-
key = int(input("Enter key [2000 - 9000]: ").strip())
21-
mode = input("Encrypt/Decrypt [E/D]: ").strip().lower()
22-
23-
if mode.startswith("e"):
24-
mode = "encrypt"
25-
translated = encrypt_message(key, message)
26-
elif mode.startswith("d"):
27-
mode = "decrypt"
28-
translated = decrypt_message(key, message)
29-
print(f"\n{mode.title()}ed text: \n{translated}")
30-
31-
3212
def check_keys(keyA: int, keyB: int, mode: str) -> None:
3313
if mode == "encrypt":
3414
if keyA == 1:
@@ -80,7 +60,7 @@ def decrypt_message(key: int, message: str) -> str:
8060
keyA, keyB = divmod(key, len(SYMBOLS))
8161
check_keys(keyA, keyB, "decrypt")
8262
plainText = ""
83-
modInverseOfkeyA = cryptomath.findModInverse(keyA, len(SYMBOLS))
63+
modInverseOfkeyA = cryptomath.find_mod_inverse(keyA, len(SYMBOLS))
8464
for symbol in message:
8565
if symbol in SYMBOLS:
8666
symIndex = SYMBOLS.find(symbol)
@@ -98,6 +78,26 @@ def get_random_key() -> int:
9878
return keyA * len(SYMBOLS) + keyB
9979

10080

81+
def main() -> None:
82+
"""
83+
>>> key = get_random_key()
84+
>>> msg = "This is a test!"
85+
>>> decrypt_message(key, encrypt_message(key, msg)) == msg
86+
True
87+
"""
88+
message = input("Enter message: ").strip()
89+
key = int(input("Enter key [2000 - 9000]: ").strip())
90+
mode = input("Encrypt/Decrypt [E/D]: ").strip().lower()
91+
92+
if mode.startswith("e"):
93+
mode = "encrypt"
94+
translated = encrypt_message(key, message)
95+
elif mode.startswith("d"):
96+
mode = "decrypt"
97+
translated = decrypt_message(key, message)
98+
print(f"\n{mode.title()}ed text: \n{translated}")
99+
100+
101101
if __name__ == "__main__":
102102
import doctest
103103

Diff for: ciphers/atbash.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,6 @@ def benchmark() -> None:
6161

6262

6363
if __name__ == "__main__":
64-
for sequence in ("ABCDEFGH", "123GGjj", "testStringtest", "with space"):
65-
print(f"{sequence} encrypted in atbash: {atbash(sequence)}")
64+
for example in ("ABCDEFGH", "123GGjj", "testStringtest", "with space"):
65+
print(f"{example} encrypted in atbash: {atbash(example)}")
6666
benchmark()

Diff for: ciphers/base32.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import base64
22

33

4-
def main():
4+
def main() -> None:
55
inp = input("->")
66
encoded = inp.encode("utf-8") # encoded the input (we need a bytes like object)
77
b32encoded = base64.b32encode(encoded) # b32encoded the encoded string

Diff for: ciphers/base85.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import base64
22

33

4-
def main():
4+
def main() -> None:
55
inp = input("->")
66
encoded = inp.encode("utf-8") # encoded the input (we need a bytes like object)
77
a85encoded = base64.a85encode(encoded) # a85encoded the encoded string

Diff for: ciphers/beaufort_cipher.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def original_text(cipher_text: str, key_new: str) -> str:
6666
return or_txt
6767

6868

69-
def main():
69+
def main() -> None:
7070
message = "THE GERMAN ATTACK"
7171
key = "SECRET"
7272
key_new = generate_key(message, key)

Diff for: ciphers/brute_force_caesar_cipher.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def decrypt(message: str) -> None:
4343
print(f"Decryption using Key #{key}: {translated}")
4444

4545

46-
def main():
46+
def main() -> None:
4747
message = input("Encrypted message: ")
4848
message = message.upper()
4949
decrypt(message)

Diff for: ciphers/cryptomath_module.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ def gcd(a: int, b: int) -> int:
44
return b
55

66

7-
def findModInverse(a: int, m: int) -> int:
7+
def find_mod_inverse(a: int, m: int) -> int:
88
if gcd(a, m) != 1:
9-
return None
9+
raise ValueError(f"mod inverse of {a!r} and {m!r} does not exist")
1010
u1, u2, u3 = 1, 0, a
1111
v1, v2, v3 = 0, 1, m
1212
while v3 != 0:

Diff for: ciphers/decrypt_caesar_with_chi_squared.py

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#!/usr/bin/env python3
22

3-
from typing import Tuple
3+
from typing import Optional
44

55

66
def decrypt_caesar_with_chi_squared(
77
ciphertext: str,
8-
cipher_alphabet: str = None,
9-
frequencies_dict: str = None,
8+
cipher_alphabet: Optional[list[str]] = None,
9+
frequencies_dict: Optional[dict[str, float]] = None,
1010
case_sensetive: bool = False,
11-
) -> Tuple[int, float, str]:
11+
) -> tuple[int, float, str]:
1212
"""
1313
Basic Usage
1414
===========
@@ -123,9 +123,9 @@ def decrypt_caesar_with_chi_squared(
123123
AttributeError: 'int' object has no attribute 'lower'
124124
"""
125125
alphabet_letters = cipher_alphabet or [chr(i) for i in range(97, 123)]
126-
frequencies_dict = frequencies_dict or {}
127126

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

165165
# Chi squared statistic values
166-
chi_squared_statistic_values = {}
166+
chi_squared_statistic_values: dict[int, tuple[float, str]] = {}
167167

168168
# cycle through all of the shifts
169169
for shift in range(len(alphabet_letters)):
@@ -215,22 +215,22 @@ def decrypt_caesar_with_chi_squared(
215215
chi_squared_statistic += chi_letter_value
216216

217217
# Add the data to the chi_squared_statistic_values dictionary
218-
chi_squared_statistic_values[shift] = [
218+
chi_squared_statistic_values[shift] = (
219219
chi_squared_statistic,
220220
decrypted_with_shift,
221-
]
221+
)
222222

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

229229
# Get all the data from the most likely cipher (key, decoded message)
230-
most_likely_cipher_chi_squared_value = chi_squared_statistic_values[
231-
most_likely_cipher
232-
][0]
233-
decoded_most_likely_cipher = chi_squared_statistic_values[most_likely_cipher][1]
230+
(
231+
most_likely_cipher_chi_squared_value,
232+
decoded_most_likely_cipher,
233+
) = chi_squared_statistic_values[most_likely_cipher]
234234

235235
# Return the data on the most likely shift
236236
return (

Diff for: ciphers/diffie.py

+16-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
def find_primitive(n: int) -> int:
1+
from typing import Optional
2+
3+
4+
def find_primitive(n: int) -> Optional[int]:
25
for r in range(1, n):
36
li = []
47
for x in range(n - 1):
@@ -8,18 +11,22 @@ def find_primitive(n: int) -> int:
811
li.append(val)
912
else:
1013
return r
14+
return None
1115

1216

1317
if __name__ == "__main__":
1418
q = int(input("Enter a prime number q: "))
1519
a = find_primitive(q)
16-
a_private = int(input("Enter private key of A: "))
17-
a_public = pow(a, a_private, q)
18-
b_private = int(input("Enter private key of B: "))
19-
b_public = pow(a, b_private, q)
20+
if a is None:
21+
print(f"Cannot find the primitive for the value: {a!r}")
22+
else:
23+
a_private = int(input("Enter private key of A: "))
24+
a_public = pow(a, a_private, q)
25+
b_private = int(input("Enter private key of B: "))
26+
b_public = pow(a, b_private, q)
2027

21-
a_secret = pow(b_public, a_private, q)
22-
b_secret = pow(a_public, b_private, q)
28+
a_secret = pow(b_public, a_private, q)
29+
b_secret = pow(a_public, b_private, q)
2330

24-
print("The key value generated by A is: ", a_secret)
25-
print("The key value generated by B is: ", b_secret)
31+
print("The key value generated by A is: ", a_secret)
32+
print("The key value generated by B is: ", b_secret)

Diff for: ciphers/elgamal_key_generator.py

+18-18
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,18 @@
22
import random
33
import sys
44

5-
from . import cryptomath_module as cryptoMath
6-
from . import rabin_miller as rabinMiller
5+
from . import cryptomath_module as cryptomath
6+
from . import rabin_miller
77

88
min_primitive_root = 3
99

1010

11-
def main():
12-
print("Making key files...")
13-
makeKeyFiles("elgamal", 2048)
14-
print("Key files generation successful")
15-
16-
1711
# I have written my code naively same as definition of primitive root
1812
# however every time I run this program, memory exceeded...
1913
# so I used 4.80 Algorithm in
2014
# Handbook of Applied Cryptography(CRC Press, ISBN : 0-8493-8523-7, October 1996)
2115
# and it seems to run nicely!
22-
def primitiveRoot(p_val: int) -> int:
16+
def primitive_root(p_val: int) -> int:
2317
print("Generating primitive root of p")
2418
while True:
2519
g = random.randrange(3, p_val)
@@ -30,20 +24,20 @@ def primitiveRoot(p_val: int) -> int:
3024
return g
3125

3226

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

40-
publicKey = (keySize, e_1, e_2, p)
41-
privateKey = (keySize, d)
34+
public_key = (key_size, e_1, e_2, p)
35+
private_key = (key_size, d)
4236

43-
return publicKey, privateKey
37+
return public_key, private_key
4438

4539

46-
def makeKeyFiles(name: str, keySize: int):
40+
def make_key_files(name: str, keySize: int) -> None:
4741
if os.path.exists("%s_pubkey.txt" % name) or os.path.exists(
4842
"%s_privkey.txt" % name
4943
):
@@ -55,7 +49,7 @@ def makeKeyFiles(name: str, keySize: int):
5549
)
5650
sys.exit()
5751

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

6963

64+
def main() -> None:
65+
print("Making key files...")
66+
make_key_files("elgamal", 2048)
67+
print("Key files generation successful")
68+
69+
7070
if __name__ == "__main__":
7171
main()

Diff for: ciphers/enigma_machine2.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
Created by TrapinchO
1616
"""
1717

18+
RotorPositionT = tuple[int, int, int]
19+
RotorSelectionT = tuple[str, str, str]
20+
21+
1822
# used alphabet --------------------------
1923
# from string.ascii_uppercase
2024
abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -63,7 +67,9 @@
6367
rotor9 = "KOAEGVDHXPQZMLFTYWJNBRCIUS"
6468

6569

66-
def _validator(rotpos: tuple, rotsel: tuple, pb: str) -> tuple:
70+
def _validator(
71+
rotpos: RotorPositionT, rotsel: RotorSelectionT, pb: str
72+
) -> tuple[RotorPositionT, RotorSelectionT, dict[str, str]]:
6773
"""
6874
Checks if the values can be used for the 'enigma' function
6975
@@ -99,12 +105,12 @@ def _validator(rotpos: tuple, rotsel: tuple, pb: str) -> tuple:
99105
)
100106

101107
# Validates string and returns dict
102-
pb = _plugboard(pb)
108+
pbdict = _plugboard(pb)
103109

104-
return rotpos, rotsel, pb
110+
return rotpos, rotsel, pbdict
105111

106112

107-
def _plugboard(pbstring: str) -> dict:
113+
def _plugboard(pbstring: str) -> dict[str, str]:
108114
"""
109115
https://en.wikipedia.org/wiki/Enigma_machine#Plugboard
110116
@@ -145,17 +151,17 @@ def _plugboard(pbstring: str) -> dict:
145151

146152
# Created the dictionary
147153
pb = {}
148-
for i in range(0, len(pbstring) - 1, 2):
149-
pb[pbstring[i]] = pbstring[i + 1]
150-
pb[pbstring[i + 1]] = pbstring[i]
154+
for j in range(0, len(pbstring) - 1, 2):
155+
pb[pbstring[j]] = pbstring[j + 1]
156+
pb[pbstring[j + 1]] = pbstring[j]
151157

152158
return pb
153159

154160

155161
def enigma(
156162
text: str,
157-
rotor_position: tuple,
158-
rotor_selection: tuple = (rotor1, rotor2, rotor3),
163+
rotor_position: RotorPositionT,
164+
rotor_selection: RotorSelectionT = (rotor1, rotor2, rotor3),
159165
plugb: str = "",
160166
) -> str:
161167
"""

0 commit comments

Comments
 (0)