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}")