Skip to content

Instantly share code, notes, and snippets.

@avi-arora
Last active December 2, 2021 09:34
Show Gist options
  • Save avi-arora/4e91e6625a300f7f0a2ad488a5049edd to your computer and use it in GitHub Desktop.
Save avi-arora/4e91e6625a300f7f0a2ad488a5049edd to your computer and use it in GitHub Desktop.
Hill Cipher
import numpy as np
from sympy import Matrix
CHAR_TABLE = {chr(i+97): i for i in range(0,26)}
CHAR_TABLE_REV = dict(zip(CHAR_TABLE.values(), CHAR_TABLE.keys()))
def program():
#take user input
#plain_text = sanitize(input("Enter Plain Text: "))
print("Reading Plain Text From File ....")
print("\n\n\n")
file = open("plaintext.txt", "r+")
plain_text = sanitize(file.readline())
print("Plain Text: ")
print(plain_text)
print("\n\n\n")
file.close()
print("Reading Key From File ...")
print("\n\n\n")
file = open("key.txt", "r+")
key = sanitize(file.readline())
file.close()
#key = sanitize(input("Enter Key: "))
print("Key: ")
print(key)
cipher_text = encrypt(plain_text, key)
print("\n\n\n")
print("Cipher Text: ")
print(cipher_text)
print("\n\n\n")
print("cipher text Saved in file encrypted.txt")
#print output on file
file = open("encrypted.txt", "w")
file.write(cipher_text)
file.close()
try:
decrypted_text = decrypt(cipher_text, key)
print("Decrypted Text: ")
print(decrypted_text)
except:
print("Inverse of Matrix Does Not Exist.")
def encrypt(plain_text, key):
"""
Hill Cipher Encryption
C = P*K MOD 26
where
C = cipher text
P = plain text
K = key (matrix)
"""
matrix_size = findMatrixSize(len(key))
#padding added from a and convert alpha to numeric valud
padded_key = getPaddedKey(key, matrix_size)
encoded_matrix = np.fromstring(padded_key,dtype=int, sep=' ').reshape(matrix_size,matrix_size)
#if plaintext size is not compatible with matrix size in such
#case matrix multiplication is not possible
#that why we are adding padding to plaintext
padded_pt = getPaddedPlainText(plain_text, matrix_size)
text_matrix = np.fromstring(padded_pt, dtype=int,sep=' ').reshape(-1, matrix_size)
cipher_text = ''
for column in text_matrix:
x = (encoded_matrix @ column) % 26
#using reverse table we are assigning alphabets to numbers
for elem in x:
cipher_text += CHAR_TABLE_REV[elem]
return cipher_text
def decrypt(cipher_text, key):
"""
Hill Cipher Decryption
p = C*K(Inv) MOD 26
where
P = plain text
C = cipher text
K = Key
K(INV) = Inverse of K
"""
matrix_size = findMatrixSize(len(key))
padded_key = getPaddedKey(key, matrix_size)
key_matrix = np.fromstring(padded_key,dtype=int, sep=' ').reshape(matrix_size,matrix_size)
#change cipher text into matrix
encoded_ct_string = encode(cipher_text)
cipher_text_matrix = np.fromstring(encoded_ct_string, dtype=int, sep=' ').reshape(-1, matrix_size)
#inverted_key_matrix = np.linalg.inv(key_matrix)
matrix = Matrix(key_matrix)
inverted_key_matrix = np.array(matrix.inv_mod(26)).astype(np.int32)
plain_text = ''
for column in cipher_text_matrix:
x = (inverted_key_matrix @ column) % 26
for elem in x:
plain_text += CHAR_TABLE_REV[elem]
return plain_text
def sanitize(text):
return ''.join(c for c in text if c.isalpha()).lower()
def findMatrixSize(length):
start, size = 1, 2
while True:
if length in range(start, (size*size)+1):
return size
start = (size*size)+1
size = size+1
def encode(string):
"""
Returns space seperated encoded string
encoded string: string of numbers based of char table
"""
return ' '.join([str(CHAR_TABLE[c]) for c in string])
def decode(matrix):
"""
Returns string decoded from encoded matrix
"""
text = ''
for row, col in np.ndindex(matrix.shape):
text += CHAR_TABLE_REV[matrix[row, col]]
return text
def getPaddedKey(string, k):
for i in range(0, (k*k) - len(string)):
string = string + list(CHAR_TABLE.keys())[i]
return encode(string)
def getPaddedPlainText(string, k):
if len(string) % k != 0:
if len(string) < k*k:
#closest multiple of k
for i in range(0,len(string) // k):
string = string + list(CHAR_TABLE.keys())[i]
elif len(string) > k*k:
#compute expected size
i = len(string)
while i % k != 0:
i+=1
for i in range(0, i - len(string)):
string = string + list(CHAR_TABLE.keys())[i]
return encode(string)
#entry point of program
# int main / public static void main
#scripting
if __name__ == "__main__":
program()
@avi-arora
Copy link
Author

updated the code for encryption and decryption.

@avi-arora
Copy link
Author

Added exception handling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment