23
23
import numpy as np
24
24
from maths .greatest_common_divisor import greatest_common_divisor
25
25
26
+
26
27
class HillCipher :
27
28
"""
28
29
Implementation of the Hill Cipher algorithm using matrix operations.
@@ -145,7 +146,7 @@ def check_determinant(self) -> None:
145
146
"""
146
147
# 修复冗余的整数转换
147
148
det = int (round (np .linalg .det (self .encrypt_key )))
148
-
149
+
149
150
if det < 0 :
150
151
det = det % len (self .key_string )
151
152
@@ -183,15 +184,15 @@ def process_text(self, text: str) -> str:
183
184
'ABCC'
184
185
"""
185
186
chars = [char for char in text .upper () if char in self .key_string ]
186
-
187
+
187
188
# Handle empty input case
188
189
if not chars :
189
190
return ""
190
-
191
+
191
192
last = chars [- 1 ]
192
193
while len (chars ) % self .break_key != 0 :
193
194
chars .append (last )
194
-
195
+
195
196
return "" .join (chars )
196
197
197
198
def encrypt (self , text : str ) -> str :
@@ -221,21 +222,21 @@ def encrypt(self, text: str) -> str:
221
222
text = self .process_text (text .upper ())
222
223
if not text :
223
224
return ""
224
-
225
+
225
226
encrypted = ""
226
227
227
228
for i in range (0 , len (text ) - self .break_key + 1 , self .break_key ):
228
229
# Extract batch of characters
229
230
batch = text [i : i + self .break_key ]
230
-
231
+
231
232
# Convert to numerical vector
232
233
vec = [self .replace_letters (char ) for char in batch ]
233
234
batch_vec = np .array ([vec ]).T
234
-
235
+
235
236
# Matrix multiplication and mod 36
236
237
product = self .encrypt_key .dot (batch_vec )
237
238
batch_encrypted = self .modulus (product ).T .tolist ()[0 ]
238
-
239
+
239
240
# Convert back to characters
240
241
encrypted_batch = "" .join (
241
242
self .replace_digits (num ) for num in batch_encrypted
@@ -260,7 +261,7 @@ def make_decrypt_key(self) -> np.ndarray:
260
261
>>> cipher.make_decrypt_key()
261
262
array([[ 6, 25],
262
263
[ 5, 26]])
263
-
264
+
264
265
>>> key3x3 = np.array([[1,2,3],[4,5,6],[7,8,9]])
265
266
>>> cipher3 = HillCipher(key3x3)
266
267
>>> cipher3.make_decrypt_key() # Determinant 0 should be invalid
@@ -271,10 +272,10 @@ def make_decrypt_key(self) -> np.ndarray:
271
272
"""
272
273
# 修复冗余的整数转换
273
274
det = int (round (np .linalg .det (self .encrypt_key )))
274
-
275
+
275
276
if det < 0 :
276
277
det = det % len (self .key_string )
277
-
278
+
278
279
det_inv : int | None = None
279
280
for i in range (len (self .key_string )):
280
281
if (det * i ) % len (self .key_string ) == 1 :
@@ -317,22 +318,22 @@ def decrypt(self, text: str) -> str:
317
318
text = self .process_text (text .upper ())
318
319
if not text :
319
320
return ""
320
-
321
+
321
322
decrypt_key = self .make_decrypt_key ()
322
323
decrypted = ""
323
324
324
325
for i in range (0 , len (text ) - self .break_key + 1 , self .break_key ):
325
326
# Extract batch of characters
326
327
batch = text [i : i + self .break_key ]
327
-
328
+
328
329
# Convert to numerical vector
329
330
vec = [self .replace_letters (char ) for char in batch ]
330
331
batch_vec = np .array ([vec ]).T
331
-
332
+
332
333
# Matrix multiplication and mod 36
333
334
product = decrypt_key .dot (batch_vec )
334
335
batch_decrypted = self .modulus (product ).T .tolist ()[0 ]
335
-
336
+
336
337
# Convert back to characters
337
338
decrypted_batch = "" .join (
338
339
self .replace_digits (num ) for num in batch_decrypted
@@ -345,7 +346,7 @@ def decrypt(self, text: str) -> str:
345
346
def main () -> None :
346
347
"""
347
348
Command-line interface for Hill Cipher operations.
348
-
349
+
349
350
Steps:
350
351
1. User inputs encryption key size
351
352
2. User inputs encryption key matrix rows
@@ -358,14 +359,14 @@ def main() -> None:
358
359
359
360
print ("Enter each row of the encryption key with space separated integers" )
360
361
for i in range (n ):
361
- 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 ()]
362
363
hill_matrix .append (row )
363
364
364
365
hc = HillCipher (np .array (hill_matrix ))
365
366
366
367
print ("\n Would you like to encrypt or decrypt some text?" )
367
368
option = input ("1. Encrypt\n 2. Decrypt\n Enter choice (1/2): " )
368
-
369
+
369
370
if option == "1" :
370
371
text = input ("\n Enter text to encrypt: " )
371
372
print ("\n Encrypted text:" )
@@ -380,20 +381,21 @@ def main() -> None:
380
381
381
382
if __name__ == "__main__" :
382
383
import doctest
384
+
383
385
doctest .testmod ()
384
-
386
+
385
387
print ("\n Running sample tests..." )
386
388
key = np .array ([[2 , 5 ], [1 , 6 ]])
387
389
cipher = HillCipher (key )
388
-
390
+
389
391
# Test encryption/decryption round trip
390
392
plaintext = "HELLO123"
391
393
encrypted = cipher .encrypt (plaintext )
392
394
decrypted = cipher .decrypt (encrypted )
393
-
395
+
394
396
print (f"\n Original text: { plaintext } " )
395
397
print (f"Encrypted text: { encrypted } " )
396
398
print (f"Decrypted text: { decrypted } " )
397
-
399
+
398
400
# Run CLI interface
399
401
main ()
0 commit comments