Skip to content

Commit 5b090a3

Browse files
authored
Update hill_cipher.py
1 parent 9ed3bbe commit 5b090a3

File tree

1 file changed

+50
-58
lines changed

1 file changed

+50
-58
lines changed

ciphers/hill_cipher.py

Lines changed: 50 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,11 @@
1818
https://www.youtube.com/watch?v=4RhLNDqcjpA
1919
"""
2020

21-
# Standard library imports
2221
import string
2322

24-
# Third-party imports
2523
import numpy as np
26-
27-
# Local application imports
2824
from maths.greatest_common_divisor import greatest_common_divisor
2925

30-
3126
class HillCipher:
3227
"""
3328
Implementation of the Hill Cipher algorithm using matrix operations.
@@ -148,19 +143,19 @@ def check_determinant(self) -> None:
148143
ValueError: determinant modular 36 of encryption key(0) is not co prime
149144
w.r.t 36. Try another key.
150145
"""
151-
det_value = np.linalg.det(self.encrypt_key)
152-
det = int(round(det_value))
153-
154-
if det < 0:
155-
det = det % len(self.key_string)
156-
157-
req_l = len(self.key_string)
158-
if greatest_common_divisor(det, req_l) != 1:
159-
msg = (
160-
f"determinant modular {req_l} of encryption key({det}) is not co prime "
161-
f"w.r.t {req_l}.\nTry another key."
162-
)
163-
raise ValueError(msg)
146+
# 修复冗余的整数转换
147+
det = int(round(np.linalg.det(self.encrypt_key)))
148+
149+
if det < 0:
150+
det = det % len(self.key_string)
151+
152+
req_l = len(self.key_string)
153+
if greatest_common_divisor(det, req_l) != 1:
154+
msg = (
155+
f"determinant modular {req_l} of encryption key({det}) is not co prime "
156+
f"w.r.t {req_l}.\nTry another key."
157+
)
158+
raise ValueError(msg)
164159

165160
def process_text(self, text: str) -> str:
166161
"""
@@ -188,15 +183,15 @@ def process_text(self, text: str) -> str:
188183
'ABCC'
189184
"""
190185
chars = [char for char in text.upper() if char in self.key_string]
191-
186+
192187
# Handle empty input case
193188
if not chars:
194189
return ""
195-
190+
196191
last = chars[-1]
197192
while len(chars) % self.break_key != 0:
198193
chars.append(last)
199-
194+
200195
return "".join(chars)
201196

202197
def encrypt(self, text: str) -> str:
@@ -226,21 +221,21 @@ def encrypt(self, text: str) -> str:
226221
text = self.process_text(text.upper())
227222
if not text:
228223
return ""
229-
224+
230225
encrypted = ""
231226

232227
for i in range(0, len(text) - self.break_key + 1, self.break_key):
233228
# Extract batch of characters
234229
batch = text[i : i + self.break_key]
235-
230+
236231
# Convert to numerical vector
237232
vec = [self.replace_letters(char) for char in batch]
238233
batch_vec = np.array([vec]).T
239-
234+
240235
# Matrix multiplication and mod 36
241236
product = self.encrypt_key.dot(batch_vec)
242237
batch_encrypted = self.modulus(product).T.tolist()[0]
243-
238+
244239
# Convert back to characters
245240
encrypted_batch = "".join(
246241
self.replace_digits(num) for num in batch_encrypted
@@ -265,7 +260,7 @@ def make_decrypt_key(self) -> np.ndarray:
265260
>>> cipher.make_decrypt_key()
266261
array([[ 6, 25],
267262
[ 5, 26]])
268-
263+
269264
>>> key3x3 = np.array([[1,2,3],[4,5,6],[7,8,9]])
270265
>>> cipher3 = HillCipher(key3x3)
271266
>>> cipher3.make_decrypt_key() # Determinant 0 should be invalid
@@ -274,26 +269,24 @@ def make_decrypt_key(self) -> np.ndarray:
274269
ValueError: determinant modular 36 of encryption key(0) is not co prime
275270
w.r.t 36. Try another key.
276271
"""
277-
det_value = np.linalg.det(self.encrypt_key)
278-
279-
# 直接取整并转换为整数
280-
det = int(round(det_value))
281-
282-
if det < 0:
283-
det = det % len(self.key_string)
284-
285-
det_inv: int | None = None
286-
for i in range(len(self.key_string)):
287-
if (det * i) % len(self.key_string) == 1:
288-
det_inv = i
289-
break
290-
291-
if det_inv is None:
292-
raise ValueError("Modular inverse does not exist for decryption key")
293-
294-
det_float = np.linalg.det(self.encrypt_key)
295-
inv_key = det_inv * det_float * np.linalg.inv(self.encrypt_key)
296-
return self.to_int(self.modulus(inv_key))
272+
# 修复冗余的整数转换
273+
det = int(round(np.linalg.det(self.encrypt_key)))
274+
275+
if det < 0:
276+
det = det % len(self.key_string)
277+
278+
det_inv: int | None = None
279+
for i in range(len(self.key_string)):
280+
if (det * i) % len(self.key_string) == 1:
281+
det_inv = i
282+
break
283+
284+
if det_inv is None:
285+
raise ValueError("Modular inverse does not exist for decryption key")
286+
287+
det_float = np.linalg.det(self.encrypt_key)
288+
inv_key = det_inv * det_float * np.linalg.inv(self.encrypt_key)
289+
return self.to_int(self.modulus(inv_key))
297290

298291
def decrypt(self, text: str) -> str:
299292
"""
@@ -324,22 +317,22 @@ def decrypt(self, text: str) -> str:
324317
text = self.process_text(text.upper())
325318
if not text:
326319
return ""
327-
320+
328321
decrypt_key = self.make_decrypt_key()
329322
decrypted = ""
330323

331324
for i in range(0, len(text) - self.break_key + 1, self.break_key):
332325
# Extract batch of characters
333326
batch = text[i : i + self.break_key]
334-
327+
335328
# Convert to numerical vector
336329
vec = [self.replace_letters(char) for char in batch]
337330
batch_vec = np.array([vec]).T
338-
331+
339332
# Matrix multiplication and mod 36
340333
product = decrypt_key.dot(batch_vec)
341334
batch_decrypted = self.modulus(product).T.tolist()[0]
342-
335+
343336
# Convert back to characters
344337
decrypted_batch = "".join(
345338
self.replace_digits(num) for num in batch_decrypted
@@ -352,7 +345,7 @@ def decrypt(self, text: str) -> str:
352345
def main() -> None:
353346
"""
354347
Command-line interface for Hill Cipher operations.
355-
348+
356349
Steps:
357350
1. User inputs encryption key size
358351
2. User inputs encryption key matrix rows
@@ -365,14 +358,14 @@ def main() -> None:
365358

366359
print("Enter each row of the encryption key with space separated integers")
367360
for i in range(n):
368-
row = [int(x) for x in input(f"Row {i + 1}: ").split()]
361+
row = [int(x) for x in input(f"Row {i+1}: ").split()]
369362
hill_matrix.append(row)
370363

371364
hc = HillCipher(np.array(hill_matrix))
372365

373366
print("\nWould you like to encrypt or decrypt some text?")
374367
option = input("1. Encrypt\n2. Decrypt\nEnter choice (1/2): ")
375-
368+
376369
if option == "1":
377370
text = input("\nEnter text to encrypt: ")
378371
print("\nEncrypted text:")
@@ -387,21 +380,20 @@ def main() -> None:
387380

388381
if __name__ == "__main__":
389382
import doctest
390-
391383
doctest.testmod()
392-
384+
393385
print("\nRunning sample tests...")
394386
key = np.array([[2, 5], [1, 6]])
395387
cipher = HillCipher(key)
396-
388+
397389
# Test encryption/decryption round trip
398390
plaintext = "HELLO123"
399391
encrypted = cipher.encrypt(plaintext)
400392
decrypted = cipher.decrypt(encrypted)
401-
393+
402394
print(f"\nOriginal text: {plaintext}")
403395
print(f"Encrypted text: {encrypted}")
404396
print(f"Decrypted text: {decrypted}")
405-
397+
406398
# Run CLI interface
407399
main()

0 commit comments

Comments
 (0)