11import string
22
33import numpy as np
4- from maths .greatest_common_divisor import greatest_common_divisor
54
5+ from maths .greatest_common_divisor import greatest_common_divisor
66
77class HillCipher :
88 key_string = string .ascii_uppercase + string .digits # 36 chars
@@ -27,15 +27,15 @@ def check_determinant(self) -> None:
2727 det = round (np .linalg .det (self .encrypt_key ))
2828 if det < 0 :
2929 det %= len (self .key_string )
30-
30+
3131 error_msg = f"Det { det } not coprime with 36. Try another key."
3232 if greatest_common_divisor (det , len (self .key_string )) != 1 :
3333 raise ValueError (error_msg )
3434
3535 def process_text (self , text : str ) -> str :
3636 """Uppercase, filter, pad text"""
3737 chars = [c for c in text .upper () if c in self .key_string ]
38- last = chars [- 1 ] if chars else "A"
38+ last = chars [- 1 ] if chars else 'A'
3939 while len (chars ) % self .break_key != 0 :
4040 chars .append (last )
4141 return "" .join (chars )
@@ -45,7 +45,7 @@ def encrypt(self, text: str) -> str:
4545 text = self .process_text (text .upper ())
4646 encrypted = ""
4747 for i in range (0 , len (text ), self .break_key ):
48- batch = text [i : i + self .break_key ]
48+ batch = text [i : i + self .break_key ]
4949 vec = [self .replace_letters (c ) for c in batch ]
5050 batch_vec = np .array ([vec ]).T
5151 product = self .encrypt_key .dot (batch_vec )
@@ -62,13 +62,15 @@ def make_decrypt_key(self) -> np.ndarray:
6262 det = round (np .linalg .det (self .encrypt_key ))
6363 if det < 0 :
6464 det %= len (self .key_string )
65-
65+
6666 # Find det modular inverse
6767 det_inv = next (i for i in range (36 ) if (det * i ) % 36 == 1 )
68-
68+
6969 # Compute inverse key
7070 inv_key = (
71- det_inv * np .linalg .det (self .encrypt_key ) * np .linalg .inv (self .encrypt_key )
71+ det_inv *
72+ np .linalg .det (self .encrypt_key ) *
73+ np .linalg .inv (self .encrypt_key )
7274 )
7375 return self .to_int (self .modulus (inv_key ))
7476
@@ -78,7 +80,7 @@ def decrypt(self, text: str) -> str:
7880 text = self .process_text (text .upper ())
7981 decrypted = ""
8082 for i in range (0 , len (text ), self .break_key ):
81- batch = text [i : i + self .break_key ]
83+ batch = text [i : i + self .break_key ]
8284 vec = [self .replace_letters (c ) for c in batch ]
8385 batch_vec = np .array ([vec ]).T
8486 product = decrypt_key .dot (batch_vec )
@@ -90,26 +92,23 @@ def decrypt(self, text: str) -> str:
9092 decrypted += decrypted_batch
9193 return decrypted
9294
93-
9495def main () -> None :
9596 """Hill Cipher CLI"""
9697 n = int (input ("Enter key order: " ))
9798 print (f"Enter { n } rows of space-separated integers:" )
9899 matrix = [list (map (int , input ().split ())) for _ in range (n )]
99-
100+
100101 hc = HillCipher (np .array (matrix ))
101-
102+
102103 option = input ("1. Encrypt\n 2. Decrypt\n Choose: " )
103104 text = input ("Enter text: " )
104-
105+
105106 if option == "1" :
106107 print ("Encrypted:" , hc .encrypt (text ))
107108 elif option == "2" :
108109 print ("Decrypted:" , hc .decrypt (text ))
109110
110-
111111if __name__ == "__main__" :
112112 import doctest
113-
114113 doctest .testmod ()
115114 main ()
0 commit comments