18
18
https://www.youtube.com/watch?v=4RhLNDqcjpA
19
19
"""
20
20
21
- # Standard library imports
22
21
import string
23
22
24
- # Third-party imports
25
23
import numpy as np
26
-
27
- # Local application imports
28
24
from maths .greatest_common_divisor import greatest_common_divisor
29
25
30
-
31
26
class HillCipher :
32
27
"""
33
28
Implementation of the Hill Cipher algorithm using matrix operations.
@@ -148,19 +143,19 @@ def check_determinant(self) -> None:
148
143
ValueError: determinant modular 36 of encryption key(0) is not co prime
149
144
w.r.t 36. Try another key.
150
145
"""
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 )
164
159
165
160
def process_text (self , text : str ) -> str :
166
161
"""
@@ -188,15 +183,15 @@ def process_text(self, text: str) -> str:
188
183
'ABCC'
189
184
"""
190
185
chars = [char for char in text .upper () if char in self .key_string ]
191
-
186
+
192
187
# Handle empty input case
193
188
if not chars :
194
189
return ""
195
-
190
+
196
191
last = chars [- 1 ]
197
192
while len (chars ) % self .break_key != 0 :
198
193
chars .append (last )
199
-
194
+
200
195
return "" .join (chars )
201
196
202
197
def encrypt (self , text : str ) -> str :
@@ -226,21 +221,21 @@ def encrypt(self, text: str) -> str:
226
221
text = self .process_text (text .upper ())
227
222
if not text :
228
223
return ""
229
-
224
+
230
225
encrypted = ""
231
226
232
227
for i in range (0 , len (text ) - self .break_key + 1 , self .break_key ):
233
228
# Extract batch of characters
234
229
batch = text [i : i + self .break_key ]
235
-
230
+
236
231
# Convert to numerical vector
237
232
vec = [self .replace_letters (char ) for char in batch ]
238
233
batch_vec = np .array ([vec ]).T
239
-
234
+
240
235
# Matrix multiplication and mod 36
241
236
product = self .encrypt_key .dot (batch_vec )
242
237
batch_encrypted = self .modulus (product ).T .tolist ()[0 ]
243
-
238
+
244
239
# Convert back to characters
245
240
encrypted_batch = "" .join (
246
241
self .replace_digits (num ) for num in batch_encrypted
@@ -265,7 +260,7 @@ def make_decrypt_key(self) -> np.ndarray:
265
260
>>> cipher.make_decrypt_key()
266
261
array([[ 6, 25],
267
262
[ 5, 26]])
268
-
263
+
269
264
>>> key3x3 = np.array([[1,2,3],[4,5,6],[7,8,9]])
270
265
>>> cipher3 = HillCipher(key3x3)
271
266
>>> cipher3.make_decrypt_key() # Determinant 0 should be invalid
@@ -274,26 +269,24 @@ def make_decrypt_key(self) -> np.ndarray:
274
269
ValueError: determinant modular 36 of encryption key(0) is not co prime
275
270
w.r.t 36. Try another key.
276
271
"""
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 ))
297
290
298
291
def decrypt (self , text : str ) -> str :
299
292
"""
@@ -324,22 +317,22 @@ def decrypt(self, text: str) -> str:
324
317
text = self .process_text (text .upper ())
325
318
if not text :
326
319
return ""
327
-
320
+
328
321
decrypt_key = self .make_decrypt_key ()
329
322
decrypted = ""
330
323
331
324
for i in range (0 , len (text ) - self .break_key + 1 , self .break_key ):
332
325
# Extract batch of characters
333
326
batch = text [i : i + self .break_key ]
334
-
327
+
335
328
# Convert to numerical vector
336
329
vec = [self .replace_letters (char ) for char in batch ]
337
330
batch_vec = np .array ([vec ]).T
338
-
331
+
339
332
# Matrix multiplication and mod 36
340
333
product = decrypt_key .dot (batch_vec )
341
334
batch_decrypted = self .modulus (product ).T .tolist ()[0 ]
342
-
335
+
343
336
# Convert back to characters
344
337
decrypted_batch = "" .join (
345
338
self .replace_digits (num ) for num in batch_decrypted
@@ -352,7 +345,7 @@ def decrypt(self, text: str) -> str:
352
345
def main () -> None :
353
346
"""
354
347
Command-line interface for Hill Cipher operations.
355
-
348
+
356
349
Steps:
357
350
1. User inputs encryption key size
358
351
2. User inputs encryption key matrix rows
@@ -365,14 +358,14 @@ def main() -> None:
365
358
366
359
print ("Enter each row of the encryption key with space separated integers" )
367
360
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 ()]
369
362
hill_matrix .append (row )
370
363
371
364
hc = HillCipher (np .array (hill_matrix ))
372
365
373
366
print ("\n Would you like to encrypt or decrypt some text?" )
374
367
option = input ("1. Encrypt\n 2. Decrypt\n Enter choice (1/2): " )
375
-
368
+
376
369
if option == "1" :
377
370
text = input ("\n Enter text to encrypt: " )
378
371
print ("\n Encrypted text:" )
@@ -387,21 +380,20 @@ def main() -> None:
387
380
388
381
if __name__ == "__main__" :
389
382
import doctest
390
-
391
383
doctest .testmod ()
392
-
384
+
393
385
print ("\n Running sample tests..." )
394
386
key = np .array ([[2 , 5 ], [1 , 6 ]])
395
387
cipher = HillCipher (key )
396
-
388
+
397
389
# Test encryption/decryption round trip
398
390
plaintext = "HELLO123"
399
391
encrypted = cipher .encrypt (plaintext )
400
392
decrypted = cipher .decrypt (encrypted )
401
-
393
+
402
394
print (f"\n Original text: { plaintext } " )
403
395
print (f"Encrypted text: { encrypted } " )
404
396
print (f"Decrypted text: { decrypted } " )
405
-
397
+
406
398
# Run CLI interface
407
399
main ()
0 commit comments