Skip to content

Commit c8755d6

Browse files
authored
Update hill_cipher.py
1 parent 6e99319 commit c8755d6

1 file changed

Lines changed: 15 additions & 27 deletions

File tree

ciphers/hill_cipher.py

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,10 @@
3333
https://www.youtube.com/watch?v=kfmNeskzs2o
3434
https://www.youtube.com/watch?v=4RhLNDqcjpA
3535
"""
36-
3736
import string
3837
import numpy as np
3938
from maths.greatest_common_divisor import greatest_common_divisor
4039

41-
4240
class HillCipher:
4341
key_string = string.ascii_uppercase + string.digits # 36 alphanumeric chars
4442
modulus = np.vectorize(lambda x: x % 36) # Mod 36 operation
@@ -62,14 +60,15 @@ def check_determinant(self) -> None:
6260
det = round(np.linalg.det(self.encrypt_key))
6361
if det < 0:
6462
det %= len(self.key_string)
65-
63+
64+
error_msg = f"Det {det} not coprime with 36. Try another key."
6665
if greatest_common_divisor(det, len(self.key_string)) != 1:
67-
raise ValueError(f"Det {det} not coprime with 36. Try another key.")
66+
raise ValueError(error_msg)
6867

6968
def process_text(self, text: str) -> str:
7069
"""Convert to uppercase, remove invalid chars, pad to multiple of break_key"""
7170
chars = [c for c in text.upper() if c in self.key_string]
72-
last = chars[-1] if chars else "A"
71+
last = chars[-1] if chars else 'A'
7372
while len(chars) % self.break_key != 0:
7473
chars.append(last)
7574
return "".join(chars)
@@ -79,30 +78,24 @@ def encrypt(self, text: str) -> str:
7978
text = self.process_text(text.upper())
8079
encrypted = ""
8180
for i in range(0, len(text), self.break_key):
82-
batch = text[i : i + self.break_key]
81+
batch = text[i:i+self.break_key]
8382
vec = [self.replace_letters(c) for c in batch]
8483
batch_vec = np.array([vec]).T
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-
)
84+
batch_encrypted = self.modulus(self.encrypt_key.dot(batch_vec)).T.tolist()[0]
85+
encrypted += "".join(self.replace_digits(round(n)) for n in batch_encrypted)
9186
return encrypted
9287

9388
def make_decrypt_key(self) -> np.ndarray:
9489
"""Calculate decryption key matrix"""
9590
det = round(np.linalg.det(self.encrypt_key))
9691
if det < 0:
9792
det %= len(self.key_string)
98-
93+
9994
# Find modular inverse of det
10095
det_inv = next(i for i in range(36) if (det * i) % 36 == 1)
101-
96+
10297
# Calculate inverse key
103-
inv_key = (
104-
det_inv * np.linalg.det(self.encrypt_key) * np.linalg.inv(self.encrypt_key)
105-
)
98+
inv_key = det_inv * np.linalg.det(self.encrypt_key) * np.linalg.inv(self.encrypt_key)
10699
return self.to_int(self.modulus(inv_key))
107100

108101
def decrypt(self, text: str) -> str:
@@ -111,35 +104,30 @@ def decrypt(self, text: str) -> str:
111104
text = self.process_text(text.upper())
112105
decrypted = ""
113106
for i in range(0, len(text), self.break_key):
114-
batch = text[i : i + self.break_key]
107+
batch = text[i:i+self.break_key]
115108
vec = [self.replace_letters(c) for c in batch]
116109
batch_vec = np.array([vec]).T
117110
batch_decrypted = self.modulus(decrypt_key.dot(batch_vec)).T.tolist()[0]
118-
decrypted += "".join(
119-
self.replace_digits(int(round(n))) for n in batch_decrypted
120-
)
111+
decrypted += "".join(self.replace_digits(round(n)) for n in batch_decrypted)
121112
return decrypted
122113

123-
124114
def main() -> None:
125115
"""CLI for Hill Cipher"""
126116
n = int(input("Enter key order: "))
127117
print(f"Enter {n} rows of space-separated integers:")
128118
matrix = [list(map(int, input().split())) for _ in range(n)]
129-
119+
130120
hc = HillCipher(np.array(matrix))
131-
121+
132122
option = input("1. Encrypt\n2. Decrypt\nChoose: ")
133123
text = input("Enter text: ")
134-
124+
135125
if option == "1":
136126
print("Encrypted:", hc.encrypt(text))
137127
elif option == "2":
138128
print("Decrypted:", hc.decrypt(text))
139129

140-
141130
if __name__ == "__main__":
142131
import doctest
143-
144132
doctest.testmod()
145133
main()

0 commit comments

Comments
 (0)