0d3b4156e53d86739cb2648c38834880cab2fb96
[cipher-tools.git] / cipher / cadenus.py
1 from utilities import *
2 from language_models import *
3 from itertools import chain
4
5 from logger import logger
6
7 def make_cadenus_keycolumn(doubled_letters = 'vw', start='a', reverse=False):
8 """Makes the key column for a Cadenus cipher (the column down between the
9 rows of letters)
10
11 >>> make_cadenus_keycolumn()['a']
12 0
13 >>> make_cadenus_keycolumn()['b']
14 1
15 >>> make_cadenus_keycolumn()['c']
16 2
17 >>> make_cadenus_keycolumn()['v']
18 21
19 >>> make_cadenus_keycolumn()['w']
20 21
21 >>> make_cadenus_keycolumn()['z']
22 24
23 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['a']
24 1
25 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['b']
26 0
27 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['c']
28 24
29 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['i']
30 18
31 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['j']
32 18
33 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['v']
34 6
35 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['z']
36 2
37 """
38 index_to_remove = string.ascii_lowercase.find(doubled_letters[0])
39 short_alphabet = string.ascii_lowercase[:index_to_remove] + string.ascii_lowercase[index_to_remove+1:]
40 if reverse:
41 short_alphabet = cat(reversed(short_alphabet))
42 start_pos = short_alphabet.find(start)
43 rotated_alphabet = short_alphabet[start_pos:] + short_alphabet[:start_pos]
44 keycolumn = {l: i for i, l in enumerate(rotated_alphabet)}
45 keycolumn[doubled_letters[0]] = keycolumn[doubled_letters[1]]
46 return keycolumn
47
48 def cadenus_encipher(message, keyword, keycolumn, fillvalue='a'):
49 """Encipher with the Cadenus cipher
50
51 >>> cadenus_encipher(sanitise('Whoever has made a voyage up the Hudson ' \
52 'must remember the Kaatskill mountains. ' \
53 'They are a dismembered branch of the great'), \
54 'wink', \
55 make_cadenus_keycolumn(doubled_letters='vw', start='a', reverse=True))
56 'antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaasuvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned'
57 >>> cadenus_encipher(sanitise('a severe limitation on the usefulness of ' \
58 'the cadenus is that every message must be ' \
59 'a multiple of twenty-five letters long'), \
60 'easy', \
61 make_cadenus_keycolumn(doubled_letters='vw', start='a', reverse=True))
62 'systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtofarenuseieeieltarlmentieetogevesitfaisltngeeuvowul'
63 """
64 rows = chunks(message, len(message) // 25, fillvalue=fillvalue)
65 columns = zip(*rows)
66 rotated_columns = [col[start:] + col[:start] for start, col in zip([keycolumn[l] for l in keyword], columns)]
67 rotated_rows = zip(*rotated_columns)
68 transpositions = transpositions_of(keyword)
69 transposed = [transpose(r, transpositions) for r in rotated_rows]
70 return cat(chain(*transposed))
71
72 def cadenus_decipher(message, keyword, keycolumn, fillvalue='a'):
73 """
74 >>> cadenus_decipher('antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaa' \
75 'suvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned', \
76 'wink', \
77 make_cadenus_keycolumn(reverse=True))
78 'whoeverhasmadeavoyageupthehudsonmustrememberthekaatskillmountainstheyareadismemberedbranchofthegreat'
79 >>> cadenus_decipher('systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtof' \
80 'arenuseieeieltarlmentieetogevesitfaisltngeeuvowul', \
81 'easy', \
82 make_cadenus_keycolumn(reverse=True))
83 'aseverelimitationontheusefulnessofthecadenusisthateverymessagemustbeamultipleoftwentyfiveletterslong'
84 """
85 rows = chunks(message, len(message) // 25, fillvalue=fillvalue)
86 transpositions = transpositions_of(keyword)
87 untransposed_rows = [untranspose(r, transpositions) for r in rows]
88 columns = zip(*untransposed_rows)
89 rotated_columns = [col[-start:] + col[:-start] for start, col in zip([keycolumn[l] for l in keyword], columns)]
90 rotated_rows = zip(*rotated_columns)
91 # return rotated_columns
92 return cat(chain(*rotated_rows))
93
94 if __name__ == "__main__":
95 import doctest