1818 https://www.youtube.com/watch?v=4RhLNDqcjpA
1919"""
2020
21- # Standard library imports
2221import string
2322
24- # Third-party imports
2523import numpy as np
26-
27- # Local application imports
2824from maths .greatest_common_divisor import greatest_common_divisor
2925
30-
3126class 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 } .\n Try 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 } .\n Try 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:
352345def 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 ("\n Would you like to encrypt or decrypt some text?" )
374367 option = input ("1. Encrypt\n 2. Decrypt\n Enter choice (1/2): " )
375-
368+
376369 if option == "1" :
377370 text = input ("\n Enter text to encrypt: " )
378371 print ("\n Encrypted text:" )
@@ -387,21 +380,20 @@ def main() -> None:
387380
388381if __name__ == "__main__" :
389382 import doctest
390-
391383 doctest .testmod ()
392-
384+
393385 print ("\n Running 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"\n Original 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