import collections
import norms
import logging
+import math
from itertools import zip_longest
from segment import segment
c = (a * b) % 26
modular_division_table[b][c] = a
-modular_division_table_one_based = [[0]*27 for x in range(27)]
-for a in range(27):
- for b in range(27):
- c = ((a * b)-1) % 26 + 1
- modular_division_table_one_based[b][c] = a
-
-
def sanitise(text):
"""Remove all non-alphabetic characters and convert the text to lowercase
else:
alphabet_start = ord('a')
letter_number = ord(letter) - alphabet_start
- if one_based:
- letter_number += 1
- raw_cipher_number = (letter_number * multiplier + adder)
- cipher_number = 0
- if one_based:
- cipher_number = (raw_cipher_number - 1) % 26
- else:
- cipher_number = raw_cipher_number % 26
- return chr(cipher_number + alphabet_start)
+ if one_based: letter_number += 1
+ cipher_number = (letter_number * multiplier + adder) % 26
+ if one_based: cipher_number -= 1
+ return chr(cipher_number % 26 + alphabet_start)
else:
return letter
else:
alphabet_start = ord('a')
cipher_number = ord(letter) - alphabet_start
- if one_based:
- cipher_number += 1
- plaintext_number = 0
- if one_based:
- plaintext_number = (modular_division_table_one_based[multiplier][(cipher_number - adder + 26) % 26] - 1) % 26
- else:
- #plaintext_number = (modular_division_table[multiplier][cipher_number] - adder) % 26
- plaintext_number = modular_division_table[multiplier][(cipher_number - adder + 26) % 26]
- return chr(plaintext_number + alphabet_start)
+ if one_based: cipher_number += 1
+ plaintext_number = modular_division_table[multiplier][(cipher_number - adder) % 26]
+ if one_based: plaintext_number -= 1
+ return chr(plaintext_number % 26 + alphabet_start)
else:
return letter
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 '
+ """
+ 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='')])
+
+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 '
+ """
+ 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='')])
+
def caesar_break(message, metric=norms.euclidean_distance, target_frequencies=normalised_english_counts, message_frequency_scaling=norms.normalise):
"""Breaks a Caesar cipher using frequency analysis