X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=hill.py;fp=hill.py;h=0000000000000000000000000000000000000000;hb=311b300d197536622980f7a837294d8245e326b4;hp=75048f9a52ddd3840ef19d614455de848f314153;hpb=d7224fba67d9f99c01bd78ef669c96189686e4c2;p=cipher-tools.git diff --git a/hill.py b/hill.py deleted file mode 100644 index 75048f9..0000000 --- a/hill.py +++ /dev/null @@ -1,80 +0,0 @@ -from utilities import * -from language_models import * -import multiprocessing -import numpy as np -from numpy import matrix -from numpy import linalg - -from logger import logger - - -def hill_encipher(matrix, message_letters, fillvalue='a'): - """Hill cipher - - >>> hill_encipher(np.matrix([[7,8], [11,11]]), 'hellothere') - 'drjiqzdrvx' - >>> hill_encipher(np.matrix([[6, 24, 1], [13, 16, 10], [20, 17, 15]]), \ - 'hello there') - 'tfjflpznvyac' - """ - n = len(matrix) - sanitised_message = sanitise(message_letters) - if len(sanitised_message) % n != 0: - padding = fillvalue[0] * (n - len(sanitised_message) % n) - else: - padding = '' - message = [pos(c) for c in sanitised_message + padding] - message_chunks = [message[i:i+n] for i in range(0, len(message), n)] - # message_chunks = chunks(message, len(matrix), fillvalue=None) - enciphered_chunks = [((matrix * np.matrix(c).T).T).tolist()[0] - for c in message_chunks] - return cat([unpos(round(l)) - for l in sum(enciphered_chunks, [])]) - -def hill_decipher(matrix, message, fillvalue='a'): - """Hill cipher - - >>> hill_decipher(np.matrix([[7,8], [11,11]]), 'drjiqzdrvx') - 'hellothere' - >>> hill_decipher(np.matrix([[6, 24, 1], [13, 16, 10], [20, 17, 15]]), \ - 'tfjflpznvyac') - 'hellothereaa' - """ - adjoint = linalg.det(matrix)*linalg.inv(matrix) - inverse_determinant = modular_division_table[int(round(linalg.det(matrix))) % 26][1] - inverse_matrix = (inverse_determinant * adjoint) % 26 - return hill_encipher(inverse_matrix, message, fillvalue) - -def hill_break(message, matrix_size=2, fitness=Pletters, - number_of_solutions=1, chunksize=500): - - all_matrices = [np.matrix(list(m)) - for m in itertools.product([list(r) - for r in itertools.product(range(26), repeat=matrix_size)], - repeat=matrix_size)] - valid_matrices = [m for m, d in - zip(all_matrices, (int(round(linalg.det(m))) for m in all_matrices)) - if d != 0 - if d % 2 != 0 - if d % 13 != 0 ] - with multiprocessing.Pool() as pool: - helper_args = [(message, matrix, fitness) - for matrix in valid_matrices] - # Gotcha: the helper function here needs to be defined at the top level - # (limitation of Pool.starmap) - breaks = pool.starmap(hill_break_worker, helper_args, chunksize) - if number_of_solutions == 1: - return max(breaks, key=lambda k: k[1]) - else: - return sorted(breaks, key=lambda k: k[1], reverse=True)[:number_of_solutions] - -def hill_break_worker(message, matrix, fitness): - plaintext = hill_decipher(matrix, message) - fit = fitness(plaintext) - logger.debug('Hill cipher break attempt using key {0} gives fit of ' - '{1} and decrypt starting: {2}'.format(matrix, - fit, sanitise(plaintext)[:50])) - return matrix, fit - -if __name__ == "__main__": - import doctest \ No newline at end of file