@@ -146,7 +146,7 @@ def check_determinant(self) -> None:
146146 # Optimized determinant calculation to avoid redundant rounding
147147 det_value = np .linalg .det (self .encrypt_key )
148148 det = int (round (det_value )) if not det_value .is_integer () else int (det_value )
149-
149+
150150 if det < 0 :
151151 det = det % len (self .key_string )
152152
@@ -157,6 +157,7 @@ def check_determinant(self) -> None:
157157 f"w.r.t { req_l } .\n Try another key."
158158 )
159159 raise ValueError (msg )
160+
160161 def process_text (self , text : str ) -> str :
161162 """
162163 Prepare text for encryption/decryption by:
@@ -183,16 +184,17 @@ def process_text(self, text: str) -> str:
183184 'ABCC'
184185 """
185186 chars = [char for char in text .upper () if char in self .key_string ]
186-
187+
187188 # Handle empty input case
188189 if not chars :
189190 return ""
190-
191+
191192 last = chars [- 1 ]
192193 while len (chars ) % self .break_key != 0 :
193194 chars .append (last )
194-
195+
195196 return "" .join (chars )
197+
196198 def encrypt (self , text : str ) -> str :
197199 """
198200 Encrypt plaintext using Hill Cipher.
@@ -220,21 +222,21 @@ def encrypt(self, text: str) -> str:
220222 text = self .process_text (text .upper ())
221223 if not text :
222224 return ""
223-
225+
224226 encrypted = ""
225227
226228 for i in range (0 , len (text ) - self .break_key + 1 , self .break_key ):
227229 # Extract batch of characters
228230 batch = text [i : i + self .break_key ]
229-
231+
230232 # Convert to numerical vector
231233 vec = [self .replace_letters (char ) for char in batch ]
232234 batch_vec = np .array ([vec ]).T
233-
235+
234236 # Matrix multiplication and mod 36
235237 product = self .encrypt_key .dot (batch_vec )
236238 batch_encrypted = self .modulus (product ).T .tolist ()[0 ]
237-
239+
238240 # Convert back to characters
239241 encrypted_batch = "" .join (
240242 self .replace_digits (num ) for num in batch_encrypted
@@ -259,7 +261,7 @@ def make_decrypt_key(self) -> np.ndarray:
259261 >>> cipher.make_decrypt_key()
260262 array([[ 6, 25],
261263 [ 5, 26]])
262-
264+
263265 >>> key3x3 = np.array([[1,2,3],[4,5,6],[7,8,9]])
264266 >>> cipher3 = HillCipher(key3x3)
265267 >>> cipher3.make_decrypt_key() # Determinant 0 should be invalid
@@ -271,10 +273,10 @@ def make_decrypt_key(self) -> np.ndarray:
271273 # Optimized determinant calculation to avoid redundant rounding
272274 det_value = np .linalg .det (self .encrypt_key )
273275 det = int (round (det_value )) if not det_value .is_integer () else int (det_value )
274-
276+
275277 if det < 0 :
276278 det = det % len (self .key_string )
277-
279+
278280 det_inv : int | None = None
279281 for i in range (len (self .key_string )):
280282 if (det * i ) % len (self .key_string ) == 1 :
@@ -317,22 +319,22 @@ def decrypt(self, text: str) -> str:
317319 text = self .process_text (text .upper ())
318320 if not text :
319321 return ""
320-
322+
321323 decrypt_key = self .make_decrypt_key ()
322324 decrypted = ""
323325
324326 for i in range (0 , len (text ) - self .break_key + 1 , self .break_key ):
325327 # Extract batch of characters
326328 batch = text [i : i + self .break_key ]
327-
329+
328330 # Convert to numerical vector
329331 vec = [self .replace_letters (char ) for char in batch ]
330332 batch_vec = np .array ([vec ]).T
331-
333+
332334 # Matrix multiplication and mod 36
333335 product = decrypt_key .dot (batch_vec )
334336 batch_decrypted = self .modulus (product ).T .tolist ()[0 ]
335-
337+
336338 # Convert back to characters
337339 decrypted_batch = "" .join (
338340 self .replace_digits (num ) for num in batch_decrypted
@@ -342,11 +344,10 @@ def decrypt(self, text: str) -> str:
342344 return decrypted
343345
344346
345-
346347def main () -> None :
347348 """
348349 Command-line interface for Hill Cipher operations.
349-
350+
350351 Steps:
351352 1. User inputs encryption key size
352353 2. User inputs encryption key matrix rows
@@ -359,14 +360,14 @@ def main() -> None:
359360
360361 print ("Enter each row of the encryption key with space separated integers" )
361362 for i in range (n ):
362- row = [int (x ) for x in input (f"Row { i + 1 } : " ).split ()]
363+ row = [int (x ) for x in input (f"Row { i + 1 } : " ).split ()]
363364 hill_matrix .append (row )
364365
365366 hc = HillCipher (np .array (hill_matrix ))
366367
367368 print ("\n Would you like to encrypt or decrypt some text?" )
368369 option = input ("1. Encrypt\n 2. Decrypt\n Enter choice (1/2): " )
369-
370+
370371 if option == "1" :
371372 text = input ("\n Enter text to encrypt: " )
372373 print ("\n Encrypted text:" )
@@ -378,22 +379,24 @@ def main() -> None:
378379 else :
379380 print ("Invalid option selected" )
380381
382+
381383if __name__ == "__main__" :
382384 import doctest
385+
383386 doctest .testmod ()
384-
387+
385388 print ("\n Running sample tests..." )
386389 key = np .array ([[2 , 5 ], [1 , 6 ]])
387390 cipher = HillCipher (key )
388-
391+
389392 # Test encryption/decryption round trip
390393 plaintext = "HELLO123"
391394 encrypted = cipher .encrypt (plaintext )
392395 decrypted = cipher .decrypt (encrypted )
393-
396+
394397 print (f"\n Original text: { plaintext } " )
395398 print (f"Encrypted text: { encrypted } " )
396399 print (f"Decrypted text: { decrypted } " )
397-
400+
398401 # Run CLI interface
399402 main ()
0 commit comments