📚 Math in Society
⇩ Download ▾

16.3 Transposition Ciphers

Another approach to cryptography is transposition cipher.

A scytale: a wooden rod with a long narrow strip of pale parchment wound around it in a close spiral so that successive wraps sit edge to edge. A message written along the rod is scrambled once the strip is unwound and reads correctly again only when it is wrapped on a rod of the same diameter.An early version of a transposition cipher was a Scytale[1], in which paper was wrapped around a stick and the message was written. Once unwrapped, the message would be unreadable until the message was wrapped around a same-sized stick again.

One modern transposition cipher is done by writing the message in rows, then forming the encrypted message from the text in the columns.

MESSAGE = "Buy some milk and eggs"      # EDIT
KEYWORD = "MONEY"                       # EDIT: its length sets the row length
PAD = "PK"                              # filler letters, cycled, to finish the last row

def column_order(word):
    # Read the column whose keyword letter comes first in the alphabet, then the next...
    return [i for _, i in sorted((c, i) for i, c in enumerate(word.upper()))]

def to_grid(msg, k, pad):
    letters = [c for c in msg.upper() if c.isalnum()]
    j = 0
    while len(letters) % k:
        letters.append(pad[j % len(pad)])
        j += 1
    return [letters[i:i + k] for i in range(0, len(letters), k)]

def encrypt(msg, word, pad):
    grid = to_grid(msg, len(word), pad)
    order = column_order(word)
    return grid, " ".join("".join(row[c] for row in grid) for c in order)

def decrypt(cipher, word):
    letters = [c for c in cipher if c.isalnum()]
    k = len(word)
    grid = [[""] * k for _ in range(len(letters) // k)]
    it = iter(letters)
    for c in column_order(word):
        for row in grid:
            row[c] = next(it)
    return "".join("".join(row) for row in grid)

order = column_order(KEYWORD)
grid, secret = encrypt(MESSAGE, KEYWORD, PAD)
print(f"keyword {KEYWORD}: rows are {len(KEYWORD)} characters long")
print(f"   read the columns in the order {[i + 1 for i in order]} "
      f"(alphabetical order of {', '.join(KEYWORD.upper())})\n")
print("   " + "  ".join(KEYWORD.upper()))
for row in grid:
    print("   " + "  ".join(row))
print(f"\nencrypted   {secret}")
print(f"decrypted   {decrypt(secret, KEYWORD)}")
print(f"round trip? {decrypt(secret, KEYWORD).startswith('BUYSOMEMILKANDEGGS')}")

print("\nthe book's harder one, going backwards:")
got = decrypt("RHA VTN USR EDE AIE RIK ATS OQR", "PRIZED")
print(f"   RHA VTN USR EDE AIE RIK ATS OQR  with keyword PRIZED  ->  {got}")

print("\nnotice what transposition does NOT do:")
from collections import Counter
plain = "".join(c for c in MESSAGE.upper() if c.isalnum())
print(f"   letter counts before: {sorted(Counter(plain).items())[:6]} ...")
print(f"   letter counts after:  {sorted(Counter(''.join(secret.split())).items())[:6]} ...")
print("   the letters are only shuffled, so frequency analysis still works on them")

More complex versions of this rows-and-column based transposition cipher can be created by specifying an order in which the columns should be recorded. For example, the method could specify that after writing the message out in rows that you should record the third column, then the fourth, then the first, then the fifth, then the second. This adds additional complexity that would make it harder to make a brute-force attack.

To make the encryption key easier to remember, a word could be used. For example, if the key word was “MONEY”, it would specify that rows should have 5 characters each. The order of the letters in the alphabet would dictate which order to read the columns in. Since E, the 4th letter in the word, is the earliest letter in the alphabet from the word MONEY, the 4th column would be used first, followed by the 1st column (M), the 3rd column (N), the 2nd column (O), and the 5th column (Y).

To decrypt a keyword-based transposition cipher, we’d reverse the process. In the example above, the keyword MONEY tells us to begin with the 4th column, so we’d start by writing SIDP down the 4th column, then continue to the 1st column, 3rd column, etc.

Unfortunately, since the transposition cipher does not change the frequency of individual letters, it is still susceptible to frequency analysis, though the transposition does eliminate information from letter pairs.

[1] en.Wikipedia.org/wiki/File:Skytala%26EmptyStrip-Shaded.png

Adapted from Math in Society by David Lippman, hosted on LibreTexts (math.libretexts.org) and licensed under CC BY-SA 3.0. Changes were made. License: CC-BY-SA-3.0.

These eBooks are a prerelease and are not yet certified conformant with WCAG 2.1 AA or ADA Title II. Every page is built against an automated accessibility gate, and the published editions will meet ADA Title II requirements when they release in late September 2026. If something is unusable, please tell us.