Skip to main content
The transposition cipher rearranges the letters of a message using a columnar transposition matrix. Unlike substitution ciphers, it doesn’t change the letters themselves—it only changes their positions.

How it works

The transposition cipher uses a matrix-based approach:
  1. Remove spaces from the message
  2. Arrange the message into a matrix with a fixed number of columns (the key)
  3. Add padding characters (*) if needed to fill the last row
  4. Read the matrix column-by-column to create the ciphertext
This cipher preserves all letter frequencies, making it resistant to frequency analysis but vulnerable to anagramming attacks.

Algorithm explanation

Visual example

For message “HOLA MUNDO” with key = 5:
Original: HOLAMUNDO

Step 1: Arrange in matrix (5 columns)
┌─┬─┬─┬─┬─┐
│H│O│L│A│M│
├─┼─┼─┼─┼─┤
│U│N│D│O│*│  ← Padding added
└─┴─┴─┴─┴─┘

Step 2: Read column by column
Column 1: H, U → HU
Column 2: O, N → ON
Column 3: L, D → LD
Column 4: A, O → AO
Column 5: M, * → M*

Ciphertext: HUONLDAOM*

Decryption process

Ciphertext: HUONLDAOM*
Key: 5 columns, 2 rows

Read sequentially into matrix by columns:
┌─┬─┬─┬─┬─┐
│H│O│L│A│M│
├─┼─┼─┼─┼─┤
│U│N│D│O│*│
└─┴─┴─┴─┴─┘

Read row by row: HOLAMUNDO* → Remove padding → HOLAMUNDO

Implementation details

The implementation is in transposicion.py with two main functions:
def cifrar(mensaje, clave):
    mensaje = mensaje.replace(" ", "")
    filas = len(mensaje) // clave
    if len(mensaje) % clave != 0:
        filas += 1
        mensaje += "*" * (clave - (len(mensaje) % clave))  # Add padding
    cifrado = ""
    for j in range(clave):
        for i in range(filas):
            cifrado += mensaje[i * clave + j]
    return cifrado

Usage example

Basic encryption and decryption

from transposicion import cifrar, descifrar

# Original message
mensaje = "HOLA MUNDO"

# Key (number of columns)
clave = 5

# Encryption
mensaje_cifrado = cifrar(mensaje, clave)
print(f"Original: {mensaje}")
print(f"Encrypted: {mensaje_cifrado}")  # "HUONLDAOM*"

# Decryption
mensaje_descifrado = descifrar(mensaje_cifrado, clave)
print(f"Decrypted: {mensaje_descifrado}")  # "HOLAMUNDO"

Step-by-step example

1

Remove spaces

mensaje = "HOLA MUNDO"
mensaje = mensaje.replace(" ", "")  # "HOLAMUNDO"
2

Calculate matrix dimensions

clave = 5  # columns
filas = len(mensaje) // clave  # 9 // 5 = 1
if len(mensaje) % clave != 0:  # 9 % 5 = 4 (remainder)
    filas += 1  # filas = 2
3

Add padding if needed

padding_needed = clave - (len(mensaje) % clave)  # 5 - 4 = 1
mensaje += "*" * padding_needed  # "HOLAMUNDO*"
4

Read column by column

# Column 0: positions 0, 5 → "HU"
# Column 1: positions 1, 6 → "ON"
# Column 2: positions 2, 7 → "LD"
# Column 3: positions 3, 8 → "AO"
# Column 4: positions 4, 9 → "M*"
cifrado = "HUONLDAOM*"

Parameters

mensaje
string
required
The plaintext message to encrypt. Spaces are automatically removed. All characters are preserved.
clave
int
default:"5"
The number of columns in the transposition matrix. Must be a positive integer. Larger values create wider, shorter matrices.

Key characteristics

Letter frequency

Preserved - Same letters appear in ciphertext

Message length

May increase due to padding with *

Character support

Supports any characters (not limited to alphabet)

Encryption speed

O(n) linear time complexity

Padding behavior

The cipher adds asterisk (*) characters as padding when the message length is not divisible by the key. These are automatically removed during decryption.

Padding calculation

message_length = 9
key = 5
padding_needed = key - (message_length % key)  # 5 - (9 % 5) = 5 - 4 = 1

Example with different keys

mensaje = "HOLA"  # Length: 4
clave = 3

# Matrix (3 columns, 2 rows)
# H O L
# A * *  ← 2 padding characters

cifrado = cifrar(mensaje, 3)  # "HAOL**"

Security notes

The transposition cipher provides minimal security and should only be used for educational purposes.

Vulnerabilities

  1. Frequency preservation: Letter frequencies remain unchanged, revealing language patterns
  2. Anagramming attacks: The ciphertext is just an anagram of the plaintext
  3. Pattern analysis: Common words and patterns can be identified
  4. Small keyspace: Limited number of practical key values
  5. Known-plaintext attack: If part of the message is known, the key can be deduced

Educational value

The transposition cipher teaches important concepts:
  • Difference between substitution and transposition
  • Matrix operations in cryptography
  • Why encryption needs both confusion and diffusion
  • Limitations of single-technique ciphers

Advanced example

# Longer message with special characters
mensaje = "ESTO ES UN MENSAJE SECRETO!"
clave = 7

print(f"Original: {mensaje}")
print(f"Length: {len(mensaje)} characters")

cifrado = cifrar(mensaje, clave)
print(f"Encrypted: {cifrado}")
print(f"Length: {len(cifrado)} characters (with padding)")

descifrado = descifrar(cifrado, clave)
print(f"Decrypted: {descifrado}")

# Output:
# Original: ESTO ES UN MENSAJE SECRETO!
# Length: 28 characters
# Encrypted: EEMTESOSSEUTNJREETCO*!S***
# Length: 28 characters (with padding)
# Decrypted: ESTOESUNENJAJESECRETO!
Notice that spaces are removed during encryption, so the decrypted message won’t have the original spacing.

Matrix visualization

For better understanding, here’s how different key values affect the matrix:
mensaje = "ABCDEFGHIJ"  # 10 characters

# Key = 2 (2 columns, 5 rows)
# A B
# C D
# E F
# G H
# I J
# Ciphertext: ACEGIBDFHJ

# Key = 5 (5 columns, 2 rows)
# A B C D E
# F G H I J
# Ciphertext: AFBGCHDIEJ

# Key = 10 (10 columns, 1 row)
# A B C D E F G H I J
# Ciphertext: ABCDEFGHIJ (no change!)
Using a key equal to the message length produces no encryption at all!

Common use cases

  • Teaching transposition vs substitution
  • Demonstrating matrix operations
  • Understanding cipher weaknesses
  • Cryptanalysis practice
  • Used in ancient military communications
  • Rail fence cipher variant
  • Route cipher techniques
  • Classical cryptography study
  • Can be combined with substitution for stronger encryption
  • Double transposition increases security
  • Historical use in World War communications
  • Teaching defense-in-depth principles

Performance considerations

import time

# Short message
mensaje_corto = "HOLA" * 10
start = time.time()
cifrado = cifrar(mensaje_corto, 5)
end = time.time()
print(f"Short message: {(end - start) * 1000:.3f}ms")

# Long message
mensaje_largo = "HOLA" * 10000
start = time.time()
cifrado = cifrar(mensaje_largo, 5)
end = time.time()
print(f"Long message: {(end - start) * 1000:.3f}ms")
The cipher has O(n) time complexity, making it efficient even for longer messages.

See also

Build docs developers (and LLMs) love