"Topic :: Security :: Cryptography",
],
python_requires='>=3.7',
- install_requires=['numpy'],
+ install_requires=[],
include_package_data=True,
setup_requires=['pytest-runner', 'numpy'],
tests_require=['pytest'],
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 cat(chain(*transposed))
+ enciphered_chunks = []
+ for message_chunk in chunks(message, len(transpositions) * 25,
+ fillvalue=fillvalue):
+ rows = chunks(message_chunk, len(transpositions), 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)
+ transposed = [transpose(r, transpositions) for r in rotated_rows]
+ enciphered_chunks.append(cat(chain(*transposed)))
+ return cat(enciphered_chunks)
def cadenus_decipher(message, keyword, keycolumn, fillvalue='a'):
"""
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 cat(chain(*rotated_rows))
+ deciphered_chunks = []
+ for message_chunk in chunks(message, len(transpositions) * 25,
+ fillvalue=fillvalue):
+ rows = chunks(message_chunk, len(transpositions), fillvalue=fillvalue)
+ 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)
+ deciphered_chunks.append(cat(chain(*rotated_rows)))
+ return cat(deciphered_chunks)
+
-def cadenus_break(message, words=keywords,
+def cadenus_break(message, wordlist=keywords,
doubled_letters='vw', fitness=Pbigrams):
- c = make_cadenus_keycolumn(reverse=True)
- valid_words = [w for w in words
- if len(transpositions_of(w)) == len(message) // 25]
+ # c = make_cadenus_keycolumn(reverse=True)
+ # valid_words = [w for w in wordlist
+ # if len(transpositions_of(w)) == len(message) // 25]
with multiprocessing.Pool() as pool:
results = pool.starmap(cadenus_break_worker,
[(message, w,
make_cadenus_keycolumn(doubled_letters=doubled_letters,
start=s, reverse=r),
fitness)
- for w in words
+ for w in wordlist
for s in string.ascii_lowercase
for r in [True, False]
# if max(transpositions_of(w)) <= len(
+++ /dev/null
-import multiprocessing
-import numpy as np
-from numpy import matrix
-from numpy import linalg
-from szyfrow.support.utilities import *
-from szyfrow.support.language_models import *
-from szyfrow.affine import modular_division_table
-
-
-def hill_encipher(matrix, message_letters, fillvalue='a'):
- """Hill cipher
-
- >>> hill_encipher(np.matrix([[7,8], [11,11]]), 'hellothere')
- 'drjiqzdrvx'
- >>> hill_encipher(np.matrix([[6, 24, 1], [13, 16, 10], [20, 17, 15]]), \
- 'hello there')
- 'tfjflpznvyac'
- """
- n = len(matrix)
- sanitised_message = sanitise(message_letters)
- if len(sanitised_message) % n != 0:
- padding = fillvalue[0] * (n - len(sanitised_message) % n)
- else:
- padding = ''
- message = [pos(c) for c in sanitised_message + padding]
- message_chunks = [message[i:i+n] for i in range(0, len(message), n)]
- # message_chunks = chunks(message, len(matrix), fillvalue=None)
- enciphered_chunks = [((matrix * np.matrix(c).T).T).tolist()[0]
- for c in message_chunks]
- return cat([unpos(round(l))
- for l in sum(enciphered_chunks, [])])
-
-def hill_decipher(matrix, message, fillvalue='a'):
- """Hill cipher
-
- >>> hill_decipher(np.matrix([[7,8], [11,11]]), 'drjiqzdrvx')
- 'hellothere'
- >>> hill_decipher(np.matrix([[6, 24, 1], [13, 16, 10], [20, 17, 15]]), \
- 'tfjflpznvyac')
- 'hellothereaa'
- """
- adjoint = linalg.det(matrix)*linalg.inv(matrix)
- inverse_determinant = modular_division_table[int(round(linalg.det(matrix))) % 26, 1]
- inverse_matrix = (inverse_determinant * adjoint) % 26
- return hill_encipher(inverse_matrix, message, fillvalue)
-
-def hill_break(message, matrix_size=2, fitness=Pletters,
- number_of_solutions=1, chunksize=500):
-
- all_matrices = [np.matrix(list(m))
- for m in itertools.product([list(r)
- for r in itertools.product(range(26), repeat=matrix_size)],
- repeat=matrix_size)]
- valid_matrices = [m for m, d in
- zip(all_matrices, (int(round(linalg.det(m))) for m in all_matrices))
- if d != 0
- if d % 2 != 0
- if d % 13 != 0 ]
- with multiprocessing.Pool() as pool:
- helper_args = [(message, matrix, fitness)
- for matrix in valid_matrices]
- # Gotcha: the helper function here needs to be defined at the top level
- # (limitation of Pool.starmap)
- breaks = pool.starmap(hill_break_worker, helper_args, chunksize)
- if number_of_solutions == 1:
- return max(breaks, key=lambda k: k[1])
- else:
- return sorted(breaks, key=lambda k: k[1], reverse=True)[:number_of_solutions]
-
-def hill_break_worker(message, matrix, fitness):
- plaintext = hill_decipher(matrix, message)
- fit = fitness(plaintext)
- return matrix, fit
-
-if __name__ == "__main__":
- import doctest
\ No newline at end of file
grid = polybius_grid(keyword, column_order, row_order,
letters_to_merge=letters_to_merge,
wrap_alphabet=wrap_alphabet)
- message_bigrams = playfair_bigrams(sanitise(message), padding_letter=padding_letter,
- padding_replaces_repeat=padding_replaces_repeat)
+ message_bigrams = playfair_bigrams(
+ sanitise(message), padding_letter=padding_letter,
+ padding_replaces_repeat=padding_replaces_repeat)
ciphertext_bigrams = [playfair_encipher_bigram(b, grid, padding_letter=padding_letter) for b in message_bigrams]
return cat(ciphertext_bigrams)
grid = polybius_grid(keyword, column_order, row_order,
letters_to_merge=letters_to_merge,
wrap_alphabet=wrap_alphabet)
- message_bigrams = playfair_bigrams(sanitise(message), padding_letter=padding_letter,
- padding_replaces_repeat=padding_replaces_repeat)
+ message_bigrams = playfair_bigrams(
+ sanitise(message), padding_letter=padding_letter,
+ padding_replaces_repeat=padding_replaces_repeat)
plaintext_bigrams = [playfair_decipher_bigram(b, grid, padding_letter=padding_letter) for b in message_bigrams]
return cat(plaintext_bigrams)
-def playfair_break_mp(message,
+def playfair_break(message,
letters_to_merge=None, padding_letter='x',
wordlist=keywords, fitness=Pletters,
number_of_solutions=1, chunksize=500):
def polybius_flatten(pair, column_first):
- """Convert a series of pairs into a single list of characters"""
+ """Convert a pair of characters into a single string."""
if column_first:
return str(pair[1]) + str(pair[0])
else:
column_index_type = type(column_order[0])
row_index_type = type(row_order[0])
if column_first:
- pairs = [(column_index_type(p[1]), row_index_type(p[0])) for p in chunks(message, 2)]
+ pairs = [(column_index_type(p[1]), row_index_type(p[0]))
+ for p in chunks(message, 2)]
else:
- pairs = [(row_index_type(p[0]), column_index_type(p[1])) for p in chunks(message, 2)]
+ pairs = [(row_index_type(p[0]), column_index_type(p[1]))
+ for p in chunks(message, 2)]
return cat(grid[p] for p in pairs if p in grid)
-def polybius_break_mp(message, column_labels, row_labels,
+def polybius_break(message, column_labels, row_labels,
letters_to_merge=None,
wordlist=keywords, fitness=Pletters,
number_of_solutions=1, chunksize=500):
def test_cadenus_break():
- plaintext = sanitise('''It is a truth universally acknowledged, that a single man in
- possession of a good fortune, must be in want of a wife. However
- little known the feelings or views of such a man may be on his
- first entering a neighbourhood, this truth is so well fixed in
- the minds of the surrounding families, that he is considered the
- rightful property of some one or other of their daughters.''')
+ plaintext = sanitise('''You will rejoice to hear that no disaster has accompanied the
+commencement of an enterprise which you have regarded with such evil
+forebodings. I arrived here yesterday, and my first task is to assure
+my dear sister of my welfare and increasing confidence in the success
+of my undertaking.
+
+I am already far north of London, and as I walk in the streets of
+Petersburgh, I feel a cold northern breeze play upon my cheeks, which
+braces my nerves and fills me with delight. Do you understand this
+feeling? This breeze, which has travelled from the regions towards
+which I am advancing, gives me a foretaste of those icy climes.
+Inspirited by this wind of promise, my daydreams become more fervent
+and vivid.
+
+I try in vain to be persuaded that the pole is the seat of
+frost and desolation; it ever presents itself to my imagination as the
+region of beauty and delight. There, Margaret, the sun is for ever
+visible, its broad disk just skirting the horizon and diffusing a
+perpetual splendour. There—for with your leave, my sister, I will put
+some trust in preceding navigators—there snow and frost are banished;
+and, sailing over a calm sea, we may be wafted to a land surpassing in
+wonders and in beauty every region hitherto discovered on the habitable
+globe.
+
+Its productions and features may be without example, as the
+phenomena of the heavenly bodies undoubtedly are in those undiscovered
+solitudes. What may not be expected in a country of eternal light? I
+may there discover the wondrous power which attracts the needle and may
+regulate a thousand celestial observations that require only this
+voyage to render their seeming eccentricities consistent for ever. I
+shall satiate my ardent curiosity with the sight of a part of the world
+never before visited, and may tread a land never before imprinted by
+the foot of man. These are my enticements, and they are sufficient to
+conquer all fear of danger or death and to induce me to commence this
+laborious voyage with the joy a child feels when he embarks in a little
+boat, with his holiday mates, on an expedition of discovery up his
+native river. '''
+)
expected_key = 'swashbuckling'
- expected_score = Ptrigrams(plaintext)
+ chunk_len = len(transpositions_of(expected_key)) * 25
+ target = plaintext + pad(len(plaintext), chunk_len, 'a')
+ expected_score = Ptrigrams(target)
expected_keycol = make_cadenus_keycolumn(doubled_letters='vw', start='a',
reverse=True)
ciphertext = cadenus_encipher(plaintext, expected_key, expected_keycol)
- # dictionary = ['clearinghouse', 'computerising', 'counterclaims',
- # 'housewarmings', 'intravenously', 'liquefactions', 'somersaulting',
- # 'sportsmanlike', 'swashbuckling']
+ dictionary = ['clearinghouse', 'computerising', 'counterclaims',
+ 'housewarmings', 'intravenously', 'liquefactions', 'somersaulting',
+ 'sportsmanlike', 'swashbuckling']
- dictionary = ['swashbuckling']
+ # dictionary = ['swashbuckling']
- (key, keycol), score = cadenus_break(ciphertext, words=dictionary,
+ (key, keycol), score = cadenus_break(ciphertext, wordlist=dictionary,
fitness=Ptrigrams)
assert key == expected_key
--- /dev/null
+import pytest
+import string
+
+from szyfrow.playfair import *
+from szyfrow.support.utilities import *
+
+def test_wrap():
+ assert playfair_wrap(3, 0, 4) == 3
+ assert playfair_wrap(0, 0, 4) == 0
+ assert playfair_wrap(4, 0, 4) == 4
+ assert playfair_wrap(7, 0, 4) == 2
+ assert playfair_wrap(-1, 0, 4) == 4
+
+def test_encipher_bigram():
+ grid = polybius_grid('playfairexample', list(range(5)), list(range(5)))
+
+ plain_pairs = 'hi de th eg ol di nt he tr ex es tu mp'.split()
+ cipher_pairs = 'bm od zb xd na be ku dm ui xm mo uv if'.split()
+
+ for p, c in zip(plain_pairs, cipher_pairs):
+ assert playfair_encipher_bigram(p, grid) == c
+
+def test_decipher_bigram():
+ grid = polybius_grid('playfairexample', list(range(5)), list(range(5)))
+
+ plain_pairs = 'hi de th eg ol di nt he tr ex es tu mp'.split()
+ cipher_pairs = 'bm od zb xd na be ku dm ui xm mo uv if'.split()
+
+ for p, c in zip(plain_pairs, cipher_pairs):
+ assert playfair_decipher_bigram(c, grid) == p
+
+def test_playfair_bigrams():
+ txt = sanitise('hide the gold in the tree stumps')
+ f_bigrams = 'hi de th eg ol di nt he tr ex es tu mp sx'.split()
+ t_bigrams = 'hi de th eg ol di nt he tr ex st um ps'.split()
+ assert playfair_bigrams(txt, padding_replaces_repeat=True) == t_bigrams
+ assert playfair_bigrams(txt, padding_replaces_repeat=False) == f_bigrams
+
+
+
+def test_encipher_message():
+ ct = playfair_encipher('hide the gold in the tree stump',
+ 'playfairexample', wrap_alphabet=KeywordWrapAlphabet.from_a)
+ assert ct == 'bmodzbxdnabekudmuixmmouvif'
+
+ ct = playfair_encipher('this is a test message for the ' \
+ 'playfair decipherment', 'elephant')
+ assert ct == 'clkrkrldhodghouhflovqbalhphzmerxnabkhapofatb'
+
+ ct = playfair_encipher('this is a test message for the ' \
+ 'playfair decipherment', 'elephant',
+ wrap_alphabet=KeywordWrapAlphabet.from_last)
+ assert ct == 'vlkrkrlwamnoamawdpolovalhplcklrhmnbkhahmentu'
+
+ ct = playfair_encipher('''Whoever has made a voyage up the Hudson must
+ remember the Kaatskill mountains. They are a dismembered branch of
+ the great''', 'hudson')
+ assert ct == 'vuelznmscupnobnwszgpaoqmonudsohephortctnqnctmoclbwepcrkffthdembgchmoczcpnbbqhrntcntcbipcaeuhlmonkpnbqz'
+
+
+def test_decipher_message():
+ plaintext = sanitise('''Whoever has made a voyage up the Hudson must
+ remember the Kaatskill mountains. They are a dismembered branch of
+ the great''')
+
+ trans_table = ''.maketrans('j', 'i')
+
+ for key in ['wink', 'elephant', 'swashbuckling']:
+ for prp in [True, False]:
+ expected = cat(playfair_bigrams(plaintext.translate(trans_table),
+ padding_replaces_repeat=prp))
+ for wrap in KeywordWrapAlphabet:
+ enciphered = playfair_encipher(plaintext, key,
+ padding_replaces_repeat=prp, wrap_alphabet=wrap)
+ deciphered = playfair_decipher(enciphered, key,
+ padding_replaces_repeat=prp, wrap_alphabet=wrap)
+ assert deciphered == expected
+
+
+def test_playfair_break():
+ plaintext = sanitise('''You will rejoice to hear that no disaster has accompanied the
+ commencement of an enterprise which you have regarded with such evil
+ forebodings. I arrived here yesterday, and my first task is to assure
+ my dear sister of my welfare and increasing confidence in the success
+ of my undertaking.''')
+ expected_key = 'swashbuckling'
+ expected_wrap = KeywordWrapAlphabet.from_last
+ expected_letters_to_merge = {'j': 'i'}
+ expected_padding_letter = 'x'
+ expected_padding_replaces_repeat = False
+ ciphertext = playfair_encipher(plaintext, expected_key,
+ padding_letter=expected_padding_letter,
+ padding_replaces_repeat=expected_padding_replaces_repeat,
+ letters_to_merge=expected_letters_to_merge,
+ wrap_alphabet=expected_wrap)
+
+
+ exptected_text = playfair_decipher(ciphertext, expected_key,
+ padding_letter=expected_padding_letter,
+ padding_replaces_repeat=expected_padding_replaces_repeat,
+ letters_to_merge=expected_letters_to_merge,
+ wrap_alphabet=expected_wrap)
+
+ expected_score = Ptrigrams(exptected_text)
+
+ dictionary = ['clearinghouse', 'computerising', 'counterclaims',
+ 'housewarmings', 'intravenously', 'liquefactions', 'somersaulting',
+ 'sportsmanlike', 'swashbuckling']
+
+ # dictionary = ['swashbuckling']
+
+ (key, wrap, letters_to_merge, padding_letter, padding_replaces_repeat), score = playfair_break(
+ ciphertext,
+ letters_to_merge=expected_letters_to_merge,
+ padding_letter=expected_padding_letter,
+ wordlist=dictionary, fitness=Ptrigrams)
+
+ assert key == expected_key
+ assert wrap == expected_wrap
+ assert letters_to_merge == expected_letters_to_merge
+ assert padding_letter == expected_padding_letter
+ assert padding_replaces_repeat == expected_padding_replaces_repeat
+ assert score == pytest.approx(expected_score)
--- /dev/null
+import pytest
+import string
+
+from szyfrow.pocket_enigma import *
+from szyfrow.support.utilities import *
+
+@pytest.fixture
+def pe():
+ return PocketEnigma(1, 'a')
+
+def test_init(pe):
+ assert pe.wheel_map == [25, 4, 23, 10, 1, 7, 9, 5, 12, 6, 3, 17, 8, 14, 13, 21, 19, 11, 20, 16, 18, 15, 24, 2, 22, 0]
+ assert pe.position == 0
+
+def test_wheel_map(pe):
+ assert pe.make_wheel_map(pe.wheel2) == [2, 3, 0, 1, 22, 8, 15, 12, 5, 10, 9, 13, 7, 11, 16, 6, 14, 25, 20, 21, 18, 19, 4, 24, 23, 17]
+
+def test_validate_wheel_map(pe):
+ pe.validate_wheel_spec(pe.wheel2) == True
+
+ with pytest.raises(ValueError):
+ pe.validate_wheel_spec([])
+ with pytest.raises(ValueError):
+ pe.validate_wheel_spec([('a', 'b', 'c')]*13)
+ with pytest.raises(ValueError):
+ pe.validate_wheel_spec([('a', 'b')]*13)
+
+def test_encipher_letter(pe):
+ pe.set_position('f')
+ assert pe.encipher_letter('k') == 'h'
+ assert pe.position == 6
+
+def test_lookup(pe):
+ pe.set_position('f')
+ assert cat([pe.lookup(l) for l in string.ascii_lowercase]) == 'udhbfejcpgmokrliwntsayqzvx'
+ assert pe.lookup('A') == ''
+
+def test_advance(pe):
+ pe.set_position('f')
+ assert pe.position == 5
+ pe.advance()
+ assert pe.position == 6
+
+ pe.set_position('y')
+ assert pe.position == 24
+ pe.advance()
+ assert pe.position == 25
+ pe.advance()
+ assert pe.position == 0
+
+def test_encipher(pe):
+ pe.set_position('f')
+ assert pe.encipher('helloworld') == 'kjsglcjoqc'
+
+ pe.set_position('f')
+ assert pe.encipher('kjsglcjoqc') == 'helloworld'
+
+ assert pe.encipher('helloworld', starting_position = 'x') == 'egrekthnnf'
+
+def test_set_position(pe):
+ assert pe.set_position('a') == 0
+ assert pe.set_position('m') == 12
+ assert pe.set_position('z') == 25
+
+def test_break():
+ assert pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'h', 0) == ['a', 'f', 'q']
+ assert pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'he', 0) == ['a']
+ assert pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'll', 2) == ['a']
+ assert pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'l', 2) == ['a']
+ assert pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'l', 3) == ['a', 'j', 'n']
+ assert pocket_enigma_break_by_crib('aaaaa', 1, 'l', 3) == []
+
\ No newline at end of file
--- /dev/null
+import pytest
+import string
+
+from szyfrow.polybius import *
+from szyfrow.support.utilities import *
+
+def test_grid():
+ grid = polybius_grid('a', 'abcde', 'abcde')
+ assert grid['x'] == ('e', 'c')
+ grid = polybius_grid('elephant', 'abcde', 'abcde')
+ assert grid['e'] == ('a', 'a')
+ assert grid['b'] == ('b', 'c')
+
+def test_reverse_grid():
+ grid = polybius_reverse_grid('a', 'abcde', 'abcde')
+ assert grid['e', 'c'] == 'x'
+ grid = polybius_reverse_grid('elephant', 'abcde', 'abcde')
+ assert grid['a', 'a'] == 'e'
+ assert grid['b', 'c'] == 'b'
+
+def test_grid_round_trip():
+ ltm = {'j': 'i'}
+ fgrid = polybius_grid('elephant', 'abcde', 'abcde',
+ letters_to_merge=ltm)
+ rgrid = polybius_reverse_grid('elephant', 'abcde', 'abcde',
+ letters_to_merge=ltm)
+ for l in fgrid:
+ if l in ltm:
+ assert ltm[l] == rgrid[fgrid[l]]
+ else:
+ assert l == rgrid[fgrid[l]]
+ for p in rgrid:
+ assert p == fgrid[rgrid[p]]
+
+
+def test_polybius_flatten():
+ assert polybius_flatten(('a', 'b'), column_first=True) == 'ba'
+ assert polybius_flatten(('a', 'b'), column_first=False) == 'ab'
+
+
+def test_encipher_message():
+ ct = polybius_encipher('this is a test message for the ' \
+ 'polybius decipherment', 'elephant', \
+ [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], \
+ wrap_alphabet=KeywordWrapAlphabet.from_last)
+ assert ct == '2214445544551522115522511155551543114252542214111352123234442355411135441314115451112122'
+
+ ct = polybius_encipher('this is a test message for the ' \
+ 'polybius decipherment', 'elephant', 'abcde', 'abcde', \
+ column_first=False)
+ assert ct == 'bbadccddccddaebbaaddbbceaaddddaecbaacadadcbbadaaacdaabedbcccdeddbeaabdccacadaadcceaababb'
+
+ ct = polybius_encipher('this is a test message for the ' \
+ 'polybius decipherment', 'elephant', 'abcde', 'abcde', \
+ column_first=True)
+ assert ct == 'bbdaccddccddeabbaaddbbecaaddddeabcaaacadcdbbdaaacaadbadecbccedddebaadbcccadaaacdecaaabbb'
+
+
+def test_decipher_message():
+ plaintext = sanitise('''Whoever has made a voyage up the Hudson must
+ remember the Kaatskill mountains. They are a dismembered branch of
+ the great''')
+ for key in ['wink', 'elephant', 'swashbuckling']:
+ enciphered = polybius_encipher(plaintext, key, 'abcde', 'abcde')
+ deciphered = polybius_decipher(enciphered, key, 'abcde', 'abcde')
+ assert deciphered == plaintext
+
+
+def test_cadenus_break():
+ plaintext = sanitise('''You will rejoice to hear that no disaster has accompanied the
+ commencement of an enterprise which you have regarded with such evil
+ forebodings. I arrived here yesterday, and my first task is to assure
+ my dear sister of my welfare and increasing confidence in the success
+ of my undertaking.''')
+ expected_key = 'swashbuckling'
+ expected_wrap = KeywordWrapAlphabet.from_last
+ expected_row_order = 'abcde'
+ expected_col_order = 'abcde'
+ expected_col_first = True
+ ciphertext = polybius_encipher(plaintext, expected_key,
+ expected_col_order, expected_row_order,
+ column_first=expected_col_first, wrap_alphabet=expected_wrap)
+
+ trans_table = ''.maketrans('j', 'i')
+ expected_score = Ptrigrams(plaintext.translate(trans_table))
+
+ dictionary = ['clearinghouse', 'computerising', 'counterclaims',
+ 'housewarmings', 'intravenously', 'liquefactions', 'somersaulting',
+ 'sportsmanlike', 'swashbuckling']
+
+ # dictionary = ['swashbuckling']
+
+ (key, wrap, col_order, row_order, col_first), score = polybius_break(ciphertext,
+ expected_col_order, expected_row_order,
+ wordlist=dictionary, fitness=Ptrigrams)
+
+ assert key == expected_key
+ assert wrap == expected_wrap
+ assert col_first == expected_col_first
+ assert score == pytest.approx(expected_score)