b0a013858034bd784de5f3487525e5eef1b93db8
1 from itertools
import chain
3 from szyfrow
.support
.utilities
import *
4 from szyfrow
.support
.language_models
import *
5 from szyfrow
.column_transposition
import transpositions_of
8 def make_cadenus_keycolumn(doubled_letters
= 'vw', start
='a', reverse
=False):
9 """Makes the key column for a Cadenus cipher (the column down between the
12 >>> make_cadenus_keycolumn()['a']
14 >>> make_cadenus_keycolumn()['b']
16 >>> make_cadenus_keycolumn()['c']
18 >>> make_cadenus_keycolumn()['v']
20 >>> make_cadenus_keycolumn()['w']
22 >>> make_cadenus_keycolumn()['z']
24 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['a']
26 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['b']
28 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['c']
30 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['i']
32 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['j']
34 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['v']
36 >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['z']
39 index_to_remove
= string
.ascii_lowercase
.find(doubled_letters
[0])
40 short_alphabet
= string
.ascii_lowercase
[:index_to_remove
] + string
.ascii_lowercase
[index_to_remove
+1:]
42 short_alphabet
= cat(reversed(short_alphabet
))
43 start_pos
= short_alphabet
.find(start
)
44 rotated_alphabet
= short_alphabet
[start_pos
:] + short_alphabet
[:start_pos
]
45 keycolumn
= {l
: i
for i
, l
in enumerate(rotated_alphabet
)}
46 keycolumn
[doubled_letters
[0]] = keycolumn
[doubled_letters
[1]]
49 def cadenus_encipher(message
, keyword
, keycolumn
, fillvalue
='a'):
50 """Encipher with the Cadenus cipher
52 >>> cadenus_encipher(sanitise('Whoever has made a voyage up the Hudson ' \
53 'must remember the Kaatskill mountains. ' \
54 'They are a dismembered branch of the great'), \
56 make_cadenus_keycolumn(doubled_letters='vw', start='a', reverse=True))
57 'antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaasuvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned'
58 >>> cadenus_encipher(sanitise('a severe limitation on the usefulness of ' \
59 'the cadenus is that every message must be ' \
60 'a multiple of twenty-five letters long'), \
62 make_cadenus_keycolumn(doubled_letters='vw', start='a', reverse=True))
63 'systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtofarenuseieeieltarlmentieetogevesitfaisltngeeuvowul'
65 transpositions
= transpositions_of(keyword
)
66 enciphered_chunks
= []
67 for message_chunk
in chunks(message
, len(transpositions
) * 25,
69 rows
= chunks(message_chunk
, len(transpositions
), fillvalue
=fillvalue
)
71 rotated_columns
= [col
[start
:] + col
[:start
] for start
, col
in zip([keycolumn
[l
] for l
in keyword
], columns
)]
72 rotated_rows
= zip(*rotated_columns
)
73 transposed
= [transpose(r
, transpositions
) for r
in rotated_rows
]
74 enciphered_chunks
.append(cat(chain(*transposed
)))
75 return cat(enciphered_chunks
)
77 def cadenus_decipher(message
, keyword
, keycolumn
, fillvalue
='a'):
79 >>> cadenus_decipher('antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaa' \
80 'suvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned', \
82 make_cadenus_keycolumn(reverse=True))
83 'whoeverhasmadeavoyageupthehudsonmustrememberthekaatskillmountainstheyareadismemberedbranchofthegreat'
84 >>> cadenus_decipher('systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtof' \
85 'arenuseieeieltarlmentieetogevesitfaisltngeeuvowul', \
87 make_cadenus_keycolumn(reverse=True))
88 'aseverelimitationontheusefulnessofthecadenusisthateverymessagemustbeamultipleoftwentyfiveletterslong'
90 transpositions
= transpositions_of(keyword
)
91 deciphered_chunks
= []
92 for message_chunk
in chunks(message
, len(transpositions
) * 25,
94 rows
= chunks(message_chunk
, len(transpositions
), fillvalue
=fillvalue
)
95 untransposed_rows
= [untranspose(r
, transpositions
) for r
in rows
]
96 columns
= zip(*untransposed_rows
)
97 rotated_columns
= [col
[-start
:] + col
[:-start
] for start
, col
in zip([keycolumn
[l
] for l
in keyword
], columns
)]
98 rotated_rows
= zip(*rotated_columns
)
99 deciphered_chunks
.append(cat(chain(*rotated_rows
)))
100 return cat(deciphered_chunks
)
104 def cadenus_break(message
, wordlist
=keywords
,
105 doubled_letters
='vw', fitness
=Pbigrams
):
106 # c = make_cadenus_keycolumn(reverse=True)
107 # valid_words = [w for w in wordlist
108 # if len(transpositions_of(w)) == len(message) // 25]
109 with multiprocessing
.Pool() as pool
:
110 results
= pool
.starmap(cadenus_break_worker
,
112 make_cadenus_keycolumn(doubled_letters
=doubled_letters
,
116 for s
in string
.ascii_lowercase
117 for r
in [True, False]
118 # if max(transpositions_of(w)) <= len(
119 # make_cadenus_keycolumn(
120 # doubled_letters=doubled_letters, start=s, reverse=r))
122 # return list(results)
123 return max(results
, key
=lambda k
: k
[1])
125 def cadenus_break_worker(message
, keyword
, keycolumn
, fitness
):
126 # message_chunks = chunks(message, 175)
127 # plaintext = ''.join(cadenus_decipher(c, keyword, keycolumn) for c in message_chunks)
128 plaintext
= cadenus_decipher(message
, keyword
, keycolumn
)
129 fit
= fitness(plaintext
)
130 return (keyword
, keycolumn
), fit
132 if __name__
== "__main__":