Skip to content

Commit 4268f2e

Browse files
authored
Update hill_cipher.py
1 parent 2aa8610 commit 4268f2e

File tree

1 file changed

+36
-35
lines changed

1 file changed

+36
-35
lines changed

ciphers/hill_cipher.py

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@
1919
"""
2020

2121
import string
22-
from typing import Optional
23-
2422
import numpy as np
25-
2623
from maths.greatest_common_divisor import greatest_common_divisor
2724

2825

@@ -136,25 +133,27 @@ def check_determinant(self) -> None:
136133
>>> HillCipher(invalid_key) # Determinant 0
137134
Traceback (most recent call last):
138135
...
139-
ValueError: determinant modular 36 of encryption key(0) is not co prime w.r.t 36.
140-
Try another key.
136+
ValueError: determinant modular 36 of encryption key(0) is not co prime
137+
w.r.t 36. Try another key.
141138
142139
>>> invalid_key2 = np.array([[4, 2], [6, 3]])
143140
>>> HillCipher(invalid_key2) # Determinant 0
144141
Traceback (most recent call last):
145142
...
146-
ValueError: determinant modular 36 of encryption key(0) is not co prime w.r.t 36.
147-
Try another key.
143+
ValueError: determinant modular 36 of encryption key(0) is not co prime
144+
w.r.t 36. Try another key.
148145
"""
149-
det = int(round(np.linalg.det(self.encrypt_key)))
146+
det = round(np.linalg.det(self.encrypt_key))
147+
det = int(det) # Convert to int after rounding float
148+
150149
if det < 0:
151150
det = det % len(self.key_string)
152151

153152
req_l = len(self.key_string)
154153
if greatest_common_divisor(det, req_l) != 1:
155154
msg = (
156-
f"determinant modular {req_l} of encryption key({det}) "
157-
f"is not co prime w.r.t {req_l}.\nTry another key."
155+
f"determinant modular {req_l} of encryption key({det}) is not co prime "
156+
f"w.r.t {req_l}.\nTry another key."
158157
)
159158
raise ValueError(msg)
160159

@@ -184,15 +183,15 @@ def process_text(self, text: str) -> str:
184183
'ABCC'
185184
"""
186185
chars = [char for char in text.upper() if char in self.key_string]
187-
186+
188187
# Handle empty input case
189188
if not chars:
190189
return ""
191-
190+
192191
last = chars[-1]
193192
while len(chars) % self.break_key != 0:
194193
chars.append(last)
195-
194+
196195
return "".join(chars)
197196

198197
def encrypt(self, text: str) -> str:
@@ -222,21 +221,21 @@ def encrypt(self, text: str) -> str:
222221
text = self.process_text(text.upper())
223222
if not text:
224223
return ""
225-
224+
226225
encrypted = ""
227226

228227
for i in range(0, len(text) - self.break_key + 1, self.break_key):
229228
# Extract batch of characters
230229
batch = text[i : i + self.break_key]
231-
230+
232231
# Convert to numerical vector
233232
vec = [self.replace_letters(char) for char in batch]
234233
batch_vec = np.array([vec]).T
235-
234+
236235
# Matrix multiplication and mod 36
237236
product = self.encrypt_key.dot(batch_vec)
238237
batch_encrypted = self.modulus(product).T.tolist()[0]
239-
238+
240239
# Convert back to characters
241240
encrypted_batch = "".join(
242241
self.replace_digits(num) for num in batch_encrypted
@@ -245,6 +244,7 @@ def encrypt(self, text: str) -> str:
245244

246245
return encrypted
247246

247+
248248
def make_decrypt_key(self) -> np.ndarray:
249249
"""
250250
Compute decryption key matrix from encryption key.
@@ -261,20 +261,22 @@ def make_decrypt_key(self) -> np.ndarray:
261261
>>> cipher.make_decrypt_key()
262262
array([[ 6, 25],
263263
[ 5, 26]])
264-
264+
265265
>>> key3x3 = np.array([[1,2,3],[4,5,6],[7,8,9]])
266266
>>> cipher3 = HillCipher(key3x3)
267267
>>> cipher3.make_decrypt_key() # Determinant 0 should be invalid
268268
Traceback (most recent call last):
269269
...
270-
ValueError: determinant modular 36 of encryption key(0) is not co prime w.r.t 36.
271-
Try another key.
270+
ValueError: determinant modular 36 of encryption key(0) is not co prime
271+
w.r.t 36. Try another key.
272272
"""
273-
det = int(round(np.linalg.det(self.encrypt_key)))
273+
det = round(np.linalg.det(self.encrypt_key))
274+
det = int(det) # Convert to int after rounding float
275+
274276
if det < 0:
275277
det = det % len(self.key_string)
276-
277-
det_inv: Optional[int] = None
278+
279+
det_inv: int | None = None
278280
for i in range(len(self.key_string)):
279281
if (det * i) % len(self.key_string) == 1:
280282
det_inv = i
@@ -316,22 +318,22 @@ def decrypt(self, text: str) -> str:
316318
text = self.process_text(text.upper())
317319
if not text:
318320
return ""
319-
321+
320322
decrypt_key = self.make_decrypt_key()
321323
decrypted = ""
322324

323325
for i in range(0, len(text) - self.break_key + 1, self.break_key):
324326
# Extract batch of characters
325327
batch = text[i : i + self.break_key]
326-
328+
327329
# Convert to numerical vector
328330
vec = [self.replace_letters(char) for char in batch]
329331
batch_vec = np.array([vec]).T
330-
332+
331333
# Matrix multiplication and mod 36
332334
product = decrypt_key.dot(batch_vec)
333335
batch_decrypted = self.modulus(product).T.tolist()[0]
334-
336+
335337
# Convert back to characters
336338
decrypted_batch = "".join(
337339
self.replace_digits(num) for num in batch_decrypted
@@ -344,7 +346,7 @@ def decrypt(self, text: str) -> str:
344346
def main() -> None:
345347
"""
346348
Command-line interface for Hill Cipher operations.
347-
349+
348350
Steps:
349351
1. User inputs encryption key size
350352
2. User inputs encryption key matrix rows
@@ -357,14 +359,14 @@ def main() -> None:
357359

358360
print("Enter each row of the encryption key with space separated integers")
359361
for i in range(n):
360-
row = [int(x) for x in input(f"Row {i + 1}: ").split()]
362+
row = [int(x) for x in input(f"Row {i+1}: ").split()]
361363
hill_matrix.append(row)
362364

363365
hc = HillCipher(np.array(hill_matrix))
364366

365367
print("\nWould you like to encrypt or decrypt some text?")
366368
option = input("1. Encrypt\n2. Decrypt\nEnter choice (1/2): ")
367-
369+
368370
if option == "1":
369371
text = input("\nEnter text to encrypt: ")
370372
print("\nEncrypted text:")
@@ -379,21 +381,20 @@ def main() -> None:
379381

380382
if __name__ == "__main__":
381383
import doctest
382-
383384
doctest.testmod()
384-
385+
385386
print("\nRunning sample tests...")
386387
key = np.array([[2, 5], [1, 6]])
387388
cipher = HillCipher(key)
388-
389+
389390
# Test encryption/decryption round trip
390391
plaintext = "HELLO123"
391392
encrypted = cipher.encrypt(plaintext)
392393
decrypted = cipher.decrypt(encrypted)
393-
394+
394395
print(f"\nOriginal text: {plaintext}")
395396
print(f"Encrypted text: {encrypted}")
396397
print(f"Decrypted text: {decrypted}")
397-
398+
398399
# Run CLI interface
399400
main()

0 commit comments

Comments
 (0)