Module szyfrow.hill
++Expand source code +
+import multiprocessing
+import numpy as np
+from numpy import matrix
+from numpy import linalg
+from szyfrow.support.utilities import *
+from szyfrow.support.language_models import *
+from szyfrow.affine import modular_division_table
+
+
+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)
+ return matrix, fit
+
+if __name__ == "__main__":
+ import doctest
+Functions
+-
+
+def cat(iterable, /) +
+-
++
Concatenate any number of strings.
+The string whose method is called is inserted in between each given string. +The result is returned as a new string.
+Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'
+ +def hill_break(message, matrix_size=2, fitness=<function Pletters>, number_of_solutions=1, chunksize=500) +
+-
+
+++
+Expand source code +
+
+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) +
+-
+
+++
+Expand source code +
+
+def hill_break_worker(message, matrix, fitness): + plaintext = hill_decipher(matrix, message) + fit = fitness(plaintext) + return matrix, fit
+ +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' +
+++Expand source code +
+
+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_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' +
+++Expand source code +
+
+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 lcat(iterable, /) +
+-
++
Concatenate any number of strings.
+The string whose method is called is inserted in between each given string. +The result is returned as a new string.
+Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'
+ +def wcat(iterable, /) +
+-
++
Concatenate any number of strings.
+The string whose method is called is inserted in between each given string. +The result is returned as a new string.
+Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'
+