up_rows.reverse()
return ''.join(c for r in zip_longest(*(down_rows + up_rows), fillvalue='') for c in r)
+def make_cadenus_keycolumn(doubled_letters = 'vw', start='a', reverse=False):
+ """Makes the key column for a Cadenus cipher (the column down between the
+ rows of letters)
+
+ >>> make_cadenus_keycolumn()['a']
+ 0
+ >>> make_cadenus_keycolumn()['b']
+ 1
+ >>> make_cadenus_keycolumn()['c']
+ 2
+ >>> make_cadenus_keycolumn()['v']
+ 21
+ >>> make_cadenus_keycolumn()['w']
+ 21
+ >>> make_cadenus_keycolumn()['z']
+ 24
+ >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['a']
+ 1
+ >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['b']
+ 0
+ >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['c']
+ 24
+ >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['i']
+ 18
+ >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['j']
+ 18
+ >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['v']
+ 6
+ >>> make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['z']
+ 2
+ """
+ index_to_remove = string.ascii_lowercase.find(doubled_letters[0])
+ short_alphabet = string.ascii_lowercase[:index_to_remove] + string.ascii_lowercase[index_to_remove+1:]
+ if reverse:
+ short_alphabet = ''.join(reversed(short_alphabet))
+ start_pos = short_alphabet.find(start)
+ rotated_alphabet = short_alphabet[start_pos:] + short_alphabet[:start_pos]
+ keycolumn = {l: i for i, l in enumerate(rotated_alphabet)}
+ keycolumn[doubled_letters[0]] = keycolumn[doubled_letters[1]]
+ return keycolumn
+
+def cadenus_encipher(message, keyword, keycolumn, fillvalue='a'):
+ """Encipher with the Cadenus cipher
+
+ >>> cadenus_encipher(sanitise('Whoever has made a voyage up the Hudson ' \
+ 'must remember the Kaatskill mountains. ' \
+ 'They are a dismembered branch of the great'), \
+ 'wink', \
+ make_cadenus_keycolumn(doubled_letters='vw', start='a', reverse=True))
+ 'antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaasuvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned'
+ >>> cadenus_encipher(sanitise('a severe limitation on the usefulness of ' \
+ 'the cadenus is that every message must be ' \
+ 'a multiple of twenty-five letters long'), \
+ 'easy', \
+ make_cadenus_keycolumn(doubled_letters='vw', start='a', reverse=True))
+ 'systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtofarenuseieeieltarlmentieetogevesitfaisltngeeuvowul'
+ """
+ rows = chunks(message, len(message) // 25, fillvalue=fillvalue)
+ columns = zip(*rows)
+ rotated_columns = [col[start:] + col[:start] for start, col in zip([keycolumn[l] for l in keyword], columns)]
+ rotated_rows = zip(*rotated_columns)
+ transpositions = transpositions_of(keyword)
+ transposed = [transpose(r, transpositions) for r in rotated_rows]
+ return ''.join(chain(*transposed))
+
+def cadenus_decipher(message, keyword, keycolumn, fillvalue='a'):
+ """
+ >>> cadenus_decipher('antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaa' \
+ 'suvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned', \
+ 'wink', \
+ make_cadenus_keycolumn(reverse=True))
+ 'whoeverhasmadeavoyageupthehudsonmustrememberthekaatskillmountainstheyareadismemberedbranchofthegreat'
+ >>> cadenus_decipher('systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtof' \
+ 'arenuseieeieltarlmentieetogevesitfaisltngeeuvowul', \
+ 'easy', \
+ make_cadenus_keycolumn(reverse=True))
+ 'aseverelimitationontheusefulnessofthecadenusisthateverymessagemustbeamultipleoftwentyfiveletterslong'
+ """
+ rows = chunks(message, len(message) // 25, fillvalue=fillvalue)
+ transpositions = transpositions_of(keyword)
+ untransposed_rows = [untranspose(r, transpositions) for r in rows]
+ columns = zip(*untransposed_rows)
+ rotated_columns = [col[-start:] + col[:-start] for start, col in zip([keycolumn[l] for l in keyword], columns)]
+ rotated_rows = zip(*rotated_columns)
+ # return rotated_columns
+ return ''.join(chain(*rotated_rows))
+
def hill_encipher(matrix, message_letters, fillvalue='a'):
"""Hill cipher
# from 'start' to 'end'
AmscoSlice = collections.namedtuple('AmscoSlice', ['index', 'start', 'end'])
+class AmscoFillStyle(Enum):
+ continuous = 1
+ same_each_row = 2
+ reverse_each_row = 3
+
def amsco_transposition_positions(message, keyword,
fillpattern=(1, 2),
+ fillstyle=AmscoFillStyle.continuous,
fillcolumnwise=False,
emptycolumnwise=True):
"""Creates the grid for the AMSCO transposition cipher. Each element in the
current_position = 0
grid = []
+ current_fillpattern = fillpattern
while current_position < message_length:
row = []
+ if fillstyle == AmscoFillStyle.same_each_row:
+ fill_iterator = cycle(fillpattern)
+ if fillstyle == AmscoFillStyle.reverse_each_row:
+ fill_iterator = cycle(current_fillpattern)
for _ in range(len(transpositions)):
index = next(indices)
gap = next(fill_iterator)
row += [AmscoSlice(index, current_position, current_position + gap)]
current_position += gap
grid += [row]
+ if fillstyle == AmscoFillStyle.reverse_each_row:
+ current_fillpattern = list(reversed(current_fillpattern))
return [transpose(r, transpositions) for r in grid]
-def amsco_transposition_encipher(message, keyword, fillpattern=(1,2)):
+def amsco_transposition_encipher(message, keyword,
+ fillpattern=(1,2), fillstyle=AmscoFillStyle.reverse_each_row):
"""AMSCO transposition encipher.
>>> amsco_transposition_encipher('hellothere', 'abc', fillpattern=(1, 2))
'hotelerelh'
>>> amsco_transposition_encipher('hellothere', 'acb', fillpattern=(2, 1))
'hetelorlhe'
+ >>> amsco_transposition_encipher('hereissometexttoencipher', 'encode')
+ 'etecstthhomoerereenisxip'
>>> amsco_transposition_encipher('hereissometexttoencipher', 'cipher', fillpattern=(1, 2))
+ 'hetcsoeisterereipexthomn'
+ >>> amsco_transposition_encipher('hereissometexttoencipher', 'cipher', fillpattern=(1, 2), fillstyle=AmscoFillStyle.continuous)
'hecsoisttererteipexhomen'
>>> amsco_transposition_encipher('hereissometexttoencipher', 'cipher', fillpattern=(2, 1))
- 'heetcisooestrrepeixthemn'
+ 'heecisoosttrrtepeixhemen'
>>> amsco_transposition_encipher('hereissometexttoencipher', 'cipher', fillpattern=(1, 3, 2))
+ 'hxtomephescieretoeisnter'
+ >>> amsco_transposition_encipher('hereissometexttoencipher', 'cipher', fillpattern=(1, 3, 2), fillstyle=AmscoFillStyle.continuous)
'hxomeiphscerettoisenteer'
"""
- grid = amsco_transposition_positions(message, keyword, fillpattern=fillpattern)
+ grid = amsco_transposition_positions(message, keyword,
+ fillpattern=fillpattern, fillstyle=fillstyle)
ct_as_grid = [[message[s.start:s.end] for s in r] for r in grid]
return combine_every_nth(ct_as_grid)
-def amsco_transposition_decipher(message, keyword, fillpattern=(1,2)):
+def amsco_transposition_decipher(message, keyword,
+ fillpattern=(1,2), fillstyle=AmscoFillStyle.reverse_each_row):
"""AMSCO transposition decipher
>>> amsco_transposition_decipher('hoteelhler', 'abc', fillpattern=(1, 2))
'hellothere'
>>> amsco_transposition_decipher('hetelorlhe', 'acb', fillpattern=(2, 1))
'hellothere'
- >>> amsco_transposition_decipher('hecsoisttererteipexhomen', 'cipher', fillpattern=(1, 2))
+ >>> amsco_transposition_decipher('etecstthhomoerereenisxip', 'encode')
+ 'hereissometexttoencipher'
+ >>> amsco_transposition_decipher('hetcsoeisterereipexthomn', 'cipher', fillpattern=(1, 2))
+ 'hereissometexttoencipher'
+ >>> amsco_transposition_decipher('hecsoisttererteipexhomen', 'cipher', fillpattern=(1, 2), fillstyle=AmscoFillStyle.continuous)
+ 'hereissometexttoencipher'
+ >>> amsco_transposition_decipher('heecisoosttrrtepeixhemen', 'cipher', fillpattern=(2, 1))
'hereissometexttoencipher'
- >>> amsco_transposition_decipher('heetcisooestrrepeixthemn', 'cipher', fillpattern=(2, 1))
+ >>> amsco_transposition_decipher('hxtomephescieretoeisnter', 'cipher', fillpattern=(1, 3, 2))
'hereissometexttoencipher'
- >>> amsco_transposition_decipher('hxomeiphscerettoisenteer', 'cipher', fillpattern=(1, 3, 2))
+ >>> amsco_transposition_decipher('hxomeiphscerettoisenteer', 'cipher', fillpattern=(1, 3, 2), fillstyle=AmscoFillStyle.continuous)
'hereissometexttoencipher'
"""
- grid = amsco_transposition_positions(message, keyword, fillpattern=fillpattern)
+ grid = amsco_transposition_positions(message, keyword,
+ fillpattern=fillpattern, fillstyle=fillstyle)
transposed_sections = [s for c in [l for l in zip(*grid)] for s in c]
plaintext_list = [''] * len(transposed_sections)
current_pos = 0