0f33ac517070aa6eb892751b2c61bf24ac63f5b9
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 rows
= chunks(message
, len(message
) // 25, fillvalue
=fillvalue
)
67 rotated_columns
= [col
[start
:] + col
[:start
] for start
, col
in zip([keycolumn
[l
] for l
in keyword
], columns
)]
68 rotated_rows
= zip(*rotated_columns
)
69 transpositions
= transpositions_of(keyword
)
70 transposed
= [transpose(r
, transpositions
) for r
in rotated_rows
]
71 return cat(chain(*transposed
))
73 def cadenus_decipher(message
, keyword
, keycolumn
, fillvalue
='a'):
75 >>> cadenus_decipher('antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaa' \
76 'suvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned', \
78 make_cadenus_keycolumn(reverse=True))
79 'whoeverhasmadeavoyageupthehudsonmustrememberthekaatskillmountainstheyareadismemberedbranchofthegreat'
80 >>> cadenus_decipher('systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtof' \
81 'arenuseieeieltarlmentieetogevesitfaisltngeeuvowul', \
83 make_cadenus_keycolumn(reverse=True))
84 'aseverelimitationontheusefulnessofthecadenusisthateverymessagemustbeamultipleoftwentyfiveletterslong'
86 rows
= chunks(message
, len(message
) // 25, fillvalue
=fillvalue
)
87 transpositions
= transpositions_of(keyword
)
88 untransposed_rows
= [untranspose(r
, transpositions
) for r
in rows
]
89 columns
= zip(*untransposed_rows
)
90 rotated_columns
= [col
[-start
:] + col
[:-start
] for start
, col
in zip([keycolumn
[l
] for l
in keyword
], columns
)]
91 rotated_rows
= zip(*rotated_columns
)
92 # return rotated_columns
93 return cat(chain(*rotated_rows
))
96 def cadenus_break(message
, words
=keywords
,
97 doubled_letters
='vw', fitness
=Pbigrams
):
98 c
= make_cadenus_keycolumn(reverse
=True)
99 valid_words
= [w
for w
in words
100 if max(transpositions_of(w
)) <= len(c
)]
101 with multiprocessing
.Pool() as pool
:
102 results
= pool
.starmap(cadenus_break_worker
,
104 make_cadenus_keycolumn(doubled_letters
=doubled_letters
,
108 for s
in string
.ascii_lowercase
109 for r
in [True, False]
110 if max(transpositions_of(w
)) <= len(
111 make_cadenus_keycolumn(
112 doubled_letters
=doubled_letters
, start
=s
, reverse
=r
))
114 # return list(results)
115 return max(results
, key
=lambda k
: k
[1])
117 def cadenus_break_worker(message
, keyword
, keycolumn
, fitness
):
118 message_chunks
= chunks(message
, 175)
119 plaintext
= ''.join(cadenus_decipher(c
, keyword
, keycolumn
) for c
in message_chunks
)
120 fit
= fitness(plaintext
)
121 return (keyword
, keycolumn
), fit
123 if __name__
== "__main__":