Skip to content

Commit 6e99319

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent 8979274 commit 6e99319

1 file changed

Lines changed: 26 additions & 13 deletions

File tree

ciphers/hill_cipher.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@
3333
https://www.youtube.com/watch?v=kfmNeskzs2o
3434
https://www.youtube.com/watch?v=4RhLNDqcjpA
3535
"""
36+
3637
import string
3738
import numpy as np
3839
from maths.greatest_common_divisor import greatest_common_divisor
3940

41+
4042
class HillCipher:
4143
key_string = string.ascii_uppercase + string.digits # 36 alphanumeric chars
4244
modulus = np.vectorize(lambda x: x % 36) # Mod 36 operation
@@ -60,14 +62,14 @@ def check_determinant(self) -> None:
6062
det = round(np.linalg.det(self.encrypt_key))
6163
if det < 0:
6264
det %= len(self.key_string)
63-
65+
6466
if greatest_common_divisor(det, len(self.key_string)) != 1:
6567
raise ValueError(f"Det {det} not coprime with 36. Try another key.")
6668

6769
def process_text(self, text: str) -> str:
6870
"""Convert to uppercase, remove invalid chars, pad to multiple of break_key"""
6971
chars = [c for c in text.upper() if c in self.key_string]
70-
last = chars[-1] if chars else 'A'
72+
last = chars[-1] if chars else "A"
7173
while len(chars) % self.break_key != 0:
7274
chars.append(last)
7375
return "".join(chars)
@@ -77,24 +79,30 @@ def encrypt(self, text: str) -> str:
7779
text = self.process_text(text.upper())
7880
encrypted = ""
7981
for i in range(0, len(text), self.break_key):
80-
batch = text[i:i+self.break_key]
82+
batch = text[i : i + self.break_key]
8183
vec = [self.replace_letters(c) for c in batch]
8284
batch_vec = np.array([vec]).T
83-
batch_encrypted = self.modulus(self.encrypt_key.dot(batch_vec)).T.tolist()[0]
84-
encrypted += "".join(self.replace_digits(int(round(n))) for n in batch_encrypted)
85+
batch_encrypted = self.modulus(self.encrypt_key.dot(batch_vec)).T.tolist()[
86+
0
87+
]
88+
encrypted += "".join(
89+
self.replace_digits(int(round(n))) for n in batch_encrypted
90+
)
8591
return encrypted
8692

8793
def make_decrypt_key(self) -> np.ndarray:
8894
"""Calculate decryption key matrix"""
8995
det = round(np.linalg.det(self.encrypt_key))
9096
if det < 0:
9197
det %= len(self.key_string)
92-
98+
9399
# Find modular inverse of det
94100
det_inv = next(i for i in range(36) if (det * i) % 36 == 1)
95-
101+
96102
# Calculate inverse key
97-
inv_key = det_inv * np.linalg.det(self.encrypt_key) * np.linalg.inv(self.encrypt_key)
103+
inv_key = (
104+
det_inv * np.linalg.det(self.encrypt_key) * np.linalg.inv(self.encrypt_key)
105+
)
98106
return self.to_int(self.modulus(inv_key))
99107

100108
def decrypt(self, text: str) -> str:
@@ -103,30 +111,35 @@ def decrypt(self, text: str) -> str:
103111
text = self.process_text(text.upper())
104112
decrypted = ""
105113
for i in range(0, len(text), self.break_key):
106-
batch = text[i:i+self.break_key]
114+
batch = text[i : i + self.break_key]
107115
vec = [self.replace_letters(c) for c in batch]
108116
batch_vec = np.array([vec]).T
109117
batch_decrypted = self.modulus(decrypt_key.dot(batch_vec)).T.tolist()[0]
110-
decrypted += "".join(self.replace_digits(int(round(n))) for n in batch_decrypted)
118+
decrypted += "".join(
119+
self.replace_digits(int(round(n))) for n in batch_decrypted
120+
)
111121
return decrypted
112122

123+
113124
def main() -> None:
114125
"""CLI for Hill Cipher"""
115126
n = int(input("Enter key order: "))
116127
print(f"Enter {n} rows of space-separated integers:")
117128
matrix = [list(map(int, input().split())) for _ in range(n)]
118-
129+
119130
hc = HillCipher(np.array(matrix))
120-
131+
121132
option = input("1. Encrypt\n2. Decrypt\nChoose: ")
122133
text = input("Enter text: ")
123-
134+
124135
if option == "1":
125136
print("Encrypted:", hc.encrypt(text))
126137
elif option == "2":
127138
print("Decrypted:", hc.decrypt(text))
128139

140+
129141
if __name__ == "__main__":
130142
import doctest
143+
131144
doctest.testmod()
132145
main()

0 commit comments

Comments
 (0)