X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=cipher.py;h=c5d542bb915b4cfd0775d5c100e8dce46a271d88;hb=afd131a6e6bc7468bbd15d962468b675754b18b2;hp=d2619029de591af1d07e5f85160e187629332751;hpb=c03fdcbe5891f43ce328f33121105a71c01eef86;p=cipher-tools.git diff --git a/cipher.py b/cipher.py index d261902..c5d542b 100644 --- a/cipher.py +++ b/cipher.py @@ -1,6 +1,7 @@ import string import collections import logging +import math from itertools import zip_longest, cycle, chain from language_models import * @@ -18,18 +19,6 @@ for a in range(26): modular_division_table[b][c] = a -def ngrams(text, n): - """Returns all n-grams of a text - - >>> ngrams(sanitise('the quick brown fox'), 2) # doctest: +NORMALIZE_WHITESPACE - ['th', 'he', 'eq', 'qu', 'ui', 'ic', 'ck', 'kb', 'br', 'ro', 'ow', 'wn', - 'nf', 'fo', 'ox'] - >>> ngrams(sanitise('the quick brown fox'), 4) # doctest: +NORMALIZE_WHITESPACE - ['theq', 'hequ', 'equi', 'quic', 'uick', 'ickb', 'ckbr', 'kbro', 'brow', - 'rown', 'ownf', 'wnfo', 'nfox'] - """ - return [text[i:i+n] for i in range(len(text)-n+1)] - def every_nth(text, n, fillvalue=''): """Returns n strings, each of which consists of every nth character, starting with the 0th, 1st, 2nd, ... (n-1)th character @@ -324,46 +313,29 @@ def keyword_decipher(message, keyword, wrap_alphabet=0): cipher_translation = ''.maketrans(cipher_alphabet, string.ascii_lowercase) return message.lower().translate(cipher_translation) -def scytale_encipher(message, rows): - """Enciphers using the scytale transposition cipher. - Message is padded with spaces to allow all rows to be the same length. - >>> scytale_encipher('thequickbrownfox', 3) - 'tcnhkfeboqrxuo iw ' - >>> scytale_encipher('thequickbrownfox', 4) - 'tubnhirfecooqkwx' - >>> scytale_encipher('thequickbrownfox', 5) - 'tubn hirf ecoo qkwx ' - >>> scytale_encipher('thequickbrownfox', 6) - 'tqcrnxhukof eibwo ' - >>> scytale_encipher('thequickbrownfox', 7) - 'tqcrnx hukof eibwo ' +def vigenere_encipher(message, keyword): + """Vigenere encipher + + >>> vigenere_encipher('hello', 'abc') + 'hfnlp' """ - if len(message) % rows != 0: - message += ' '*(rows - len(message) % rows) - row_length = round(len(message) / rows) - slices = [message[i:i+row_length] - for i in range(0, len(message), row_length)] - return ''.join([''.join(r) for r in zip_longest(*slices, fillvalue='')]) + shifts = [ord(l) - ord('a') for l in sanitise(keyword)] + pairs = zip(message, cycle(shifts)) + return ''.join([caesar_encipher_letter(l, k) for l, k in pairs]) -def scytale_decipher(message, rows): - """Deciphers using the scytale transposition cipher. - Assumes the message is padded so that all rows are the same length. - - >>> scytale_decipher('tcnhkfeboqrxuo iw ', 3) - 'thequickbrownfox ' - >>> scytale_decipher('tubnhirfecooqkwx', 4) - 'thequickbrownfox' - >>> scytale_decipher('tubn hirf ecoo qkwx ', 5) - 'thequickbrownfox ' - >>> scytale_decipher('tqcrnxhukof eibwo ', 6) - 'thequickbrownfox ' - >>> scytale_decipher('tqcrnx hukof eibwo ', 7) - 'thequickbrownfox ' +def vigenere_decipher(message, keyword): + """Vigenere decipher + + >>> vigenere_decipher('hfnlp', 'abc') + 'hello' """ - cols = round(len(message) / rows) - columns = [message[i:i+rows] for i in range(0, cols * rows, rows)] - return ''.join([''.join(c) for c in zip_longest(*columns, fillvalue='')]) + shifts = [ord(l) - ord('a') for l in sanitise(keyword)] + pairs = zip(message, cycle(shifts)) + return ''.join([caesar_decipher_letter(l, k) for l, k in pairs]) + +beaufort_encipher=vigenere_decipher +beaufort_decipher=vigenere_encipher def transpositions_of(keyword): @@ -471,13 +443,6 @@ def column_transposition_decipher(message, keyword, fillvalue=' ', >>> column_transposition_decipher('hleolteher', 'clever', fillcolumnwise=False, emptycolumnwise=False) 'hellothere' """ - # >>> column_transposition_decipher('hleolteher', 'clever') - # 'hellothere' - # >>> column_transposition_decipher('hleolthre!e!', 'cleverly', fillvalue='?') - # 'hellothere!!' - # >>> column_transposition_decipher('htleehoelr', 'clever', columnwise=True) - # 'hellothere' - # """ transpositions = transpositions_of(keyword) message += pad(len(message), len(transpositions), '*') if emptycolumnwise: @@ -490,29 +455,43 @@ def column_transposition_decipher(message, keyword, fillvalue=' ', else: return ''.join(chain(*untransposed)) +def scytale_encipher(message, rows, fillvalue=' '): + """Enciphers using the scytale transposition cipher. + Message is padded with spaces to allow all rows to be the same length. -def vigenere_encipher(message, keyword): - """Vigenere encipher - - >>> vigenere_encipher('hello', 'abc') - 'hfnlp' + >>> scytale_encipher('thequickbrownfox', 3) + 'tcnhkfeboqrxuo iw ' + >>> scytale_encipher('thequickbrownfox', 4) + 'tubnhirfecooqkwx' + >>> scytale_encipher('thequickbrownfox', 5) + 'tubnhirfecooqkwx' + >>> scytale_encipher('thequickbrownfox', 6) + 'tqcrnxhukof eibwo ' + >>> scytale_encipher('thequickbrownfox', 7) + 'tqcrnxhukof eibwo ' """ - shifts = [ord(l) - ord('a') for l in sanitise(keyword)] - pairs = zip(message, cycle(shifts)) - return ''.join([caesar_encipher_letter(l, k) for l, k in pairs]) - -def vigenere_decipher(message, keyword): - """Vigenere decipher + transpositions = [i for i in range(math.ceil(len(message) / rows))] + return column_transposition_encipher(message, transpositions, + fillcolumnwise=False, emptycolumnwise=True) - >>> vigenere_decipher('hfnlp', 'abc') - 'hello' +def scytale_decipher(message, rows): + """Deciphers using the scytale transposition cipher. + Assumes the message is padded so that all rows are the same length. + + >>> scytale_decipher('tcnhkfeboqrxuo iw ', 3) + 'thequickbrownfox ' + >>> scytale_decipher('tubnhirfecooqkwx', 4) + 'thequickbrownfox' + >>> scytale_decipher('tubnhirfecooqkwx', 5) + 'thequickbrownfox' + >>> scytale_decipher('tqcrnxhukof eibwo ', 6) + 'thequickbrownfox ' + >>> scytale_decipher('tqcrnxhukof eibwo ', 7) + 'thequickbrownfox ' """ - shifts = [ord(l) - ord('a') for l in sanitise(keyword)] - pairs = zip(message, cycle(shifts)) - return ''.join([caesar_decipher_letter(l, k) for l, k in pairs]) - -beaufort_encipher=vigenere_decipher -beaufort_decipher=vigenere_encipher + transpositions = [i for i in range(math.ceil(len(message) / rows))] + return column_transposition_decipher(message, transpositions, + fillcolumnwise=False, emptycolumnwise=True) if __name__ == "__main__":