HILL CIPHER DECRYPTION - PE
import numpy as np
#Modulo 26 inverse helper
def modinv(a, m):
for i in range(1, m):
if (a * i) % m == 1:
return i
raise ValueError(f"No modular inverse for {a} mod {m}")
#Matrix inverse modulo 26
def matrix_modinv(matrix, modulus):
det = int(round(np.linalg.det(matrix))) # Determinant
det_inv = modinv(det % modulus, modulus)
matrix_modinv = (
det_inv * np.round(det * np.linalg.inv(matrix)).astype(int) % modulus
)
return matrix_modinv % modulus
#Convert text to numbers (A=0 to Z=25)
def text_to_numbers(text):
return [ord(char) - ord('A') for char in text]
#Convert numbers to text
def numbers_to_text(numbers):
return ''.join(chr(num % 26 + ord('A')) for num in numbers)
#Decrypt function
def decrypt_hill_cipher(ciphertext, key_matrix):
ciphertext = ciphertext.upper()
nums = text_to_numbers(ciphertext)
inv_key = matrix_modinv(key_matrix, 26)
plaintext_numbers = []
for i in range(0, len(nums), 3):
block = np.array(nums[i:i+3])
decrypted = np.dot(inv_key, block) % 26
plaintext_numbers.extend(decrypted.astype(int))
return numbers_to_text(plaintext_numbers)
#Given key matrix
key_matrix = np.array([
[6, 24, 1],
[13, 16, 10],
[20, 17, 15]
])
ciphertext = "ZWOBYZ"
plaintext = decrypt_hill_cipher(ciphertext, key_matrix)
print(f"Decrypted plaintext: {plaintext}")