Skip to content

Commit a3756da

Browse files
authored
Update hill_cipher.py
1 parent 39711d8 commit a3756da

1 file changed

Lines changed: 25 additions & 14 deletions

File tree

ciphers/hill_cipher.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"""
2-
32
Hill Cipher:
43
The 'HillCipher' class below implements the Hill Cipher algorithm which uses
54
modern linear algebra techniques to encode and decode text using an encryption
@@ -33,13 +32,9 @@
3332
https://apprendre-en-ligne.net/crypto/hill/Hillciph.pdf
3433
https://www.youtube.com/watch?v=kfmNeskzs2o
3534
https://www.youtube.com/watch?v=4RhLNDqcjpA
36-
3735
"""
38-
3936
import string
40-
4137
import numpy as np
42-
4338
from maths.greatest_common_divisor import greatest_common_divisor
4439

4540

@@ -79,7 +74,8 @@ def replace_digits(self, num: int) -> str:
7974
>>> hill_cipher.replace_digits(26)
8075
'0'
8176
"""
82-
return self.key_string[round(num)]
77+
# Directly use integer index without rounding
78+
return self.key_string[num]
8379

8480
def check_determinant(self) -> None:
8581
"""
@@ -107,8 +103,10 @@ def process_text(self, text: str) -> str:
107103
>>> hill_cipher.process_text('hello')
108104
'HELLOO'
109105
"""
106+
# Filter valid characters and convert to uppercase
110107
chars = [char for char in text.upper() if char in self.key_string]
111108

109+
# Pad with last character to make length multiple of break_key
112110
last = chars[-1]
113111
while len(chars) % self.break_key != 0:
114112
chars.append(last)
@@ -123,40 +121,49 @@ def encrypt(self, text: str) -> str:
123121
>>> hill_cipher.encrypt('hello')
124122
'85FF00'
125123
"""
124+
# Preprocess text and initialize encrypted string
126125
text = self.process_text(text.upper())
127126
encrypted = ""
128127

128+
# Process text in batches of size break_key
129129
for i in range(0, len(text) - self.break_key + 1, self.break_key):
130130
batch = text[i : i + self.break_key]
131+
# Convert characters to numerical values
131132
vec = [self.replace_letters(char) for char in batch]
132133
batch_vec = np.array([vec]).T
134+
135+
# Matrix multiplication with encryption key
133136
batch_encrypted = self.modulus(self.encrypt_key.dot(batch_vec)).T.tolist()[
134137
0
135138
]
139+
# Convert numerical results back to characters
136140
encrypted_batch = "".join(
137-
self.replace_digits(num) for num in batch_encrypted
141+
self.replace_digits(int(round(num))) for num in batch_encrypted
138142
)
139143
encrypted += encrypted_batch
140144

141145
return encrypted
142-
143-
def make_decrypt_key(self) -> np.ndarray:
146+
def make_decrypt_key(self) -> np.ndarray:
144147
"""
145148
>>> hill_cipher = HillCipher(np.array([[2, 5], [1, 6]]))
146149
>>> hill_cipher.make_decrypt_key()
147150
array([[ 6, 25],
148151
[ 5, 26]])
149152
"""
153+
# Calculate determinant of encryption key
150154
det = round(np.linalg.det(self.encrypt_key))
151155

152156
if det < 0:
153157
det = det % len(self.key_string)
154158
det_inv = None
159+
160+
# Find modular inverse of determinant
155161
for i in range(len(self.key_string)):
156162
if (det * i) % len(self.key_string) == 1:
157163
det_inv = i
158164
break
159165

166+
# Calculate inverse key matrix
160167
inv_key = (
161168
det_inv * np.linalg.det(self.encrypt_key) * np.linalg.inv(self.encrypt_key)
162169
)
@@ -171,24 +178,29 @@ def decrypt(self, text: str) -> str:
171178
>>> hill_cipher.decrypt('85FF00')
172179
'HELLOO'
173180
"""
181+
# Get decryption key and preprocess text
174182
decrypt_key = self.make_decrypt_key()
175183
text = self.process_text(text.upper())
176184
decrypted = ""
177185

186+
# Process text in batches of size break_key
178187
for i in range(0, len(text) - self.break_key + 1, self.break_key):
179188
batch = text[i : i + self.break_key]
189+
# Convert characters to numerical values
180190
vec = [self.replace_letters(char) for char in batch]
181191
batch_vec = np.array([vec]).T
192+
193+
# Matrix multiplication with decryption key
182194
batch_decrypted = self.modulus(decrypt_key.dot(batch_vec)).T.tolist()[0]
195+
# Convert numerical results back to characters
183196
decrypted_batch = "".join(
184-
self.replace_digits(num) for num in batch_decrypted
197+
self.replace_digits(int(round(num))) for num in batch_decrypted
185198
)
186199
decrypted += decrypted_batch
187200

188201
return decrypted
189-
190-
191-
def main() -> None:
202+
def main() -> None:
203+
"""Command-line interface for Hill Cipher"""
192204
n = int(input("Enter the order of the encryption key: "))
193205
hill_matrix = []
194206

@@ -215,5 +227,4 @@ def main() -> None:
215227
import doctest
216228

217229
doctest.testmod()
218-
219230
main()

0 commit comments

Comments
 (0)