← Back to Blog

ADFGVX Project — Round 1/5

We start with substitution. As we discussed in the concept article, the cipher begins with a 6×6 grid — rows and columns labeled with the six letters: A, D, F, G, V, X. Every character in the message gets replaced with its row-column pair.

In its standard form, the grid looks like this — characters placed in alphabetical order:

   A  D  F  G  V  X
A  A  B  C  D  E  F
D  G  H  I  J  K  L
F  M  N  O  P  Q  R
G  S  T  U  V  W  X
V  Y  Z  0  1  2  3
X  4  5  6  7  8  9

In this grid, A is at row A, column A → AA. T is at row G, column D → GD. 9 is at row X, column X → XX.

But a fixed grid is a weak grid. The whole point of the cipher is variation — personalization. In practice, characters are rearranged based on a keyword. Let's use WASHINGTON.

The keyword goes first — unique characters only, in order. WASHINGTON becomes WASHINGT0 — we drop the second N. Then we continue with the remaining characters from the full alphabet and digits, in order, skipping anything already used. The result: WASHINGTOBCDEFJKLMPQRUVWXYZ0123456789.

Placed in the grid:

   A  D  F  G  V  X
A  W  A  S  H  I  N
D  G  T  O  B  C  D
F  E  F  J  K  L  M
G  P  Q  R  U  V  X
V  Y  Z  0  1  2  3
X  4  5  6  7  8  9

Now A is at row A, column D → AD. T is at row D, column D → DD. The same message produces completely different ciphertext. That's the point.

Let's build it. We need the full character set first.

import string

print(string.ascii_uppercase)
# ABCDEFGHIJKLMNOPQRSTUVWXYZ
print(string.digits)
# 0123456789

all_chars = string.ascii_uppercase + string.digits
# ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

Now the key. We start simple — fixed value, no input yet:

key = "WASHINGTON"

sorted_chars = ""
reference = key.upper() + all_chars

for letter in reference:
    if letter not in sorted_chars:
        sorted_chars += letter

print(sorted_chars)
# WASHINGTOBCDEFJKLMPQRUVWXYZ0123456789

We concatenate the key and the full character set. Then we iterate — if the character isn't already in sorted_chars, we add it. Duplicates are ignored. The result is the personalized character order for our grid.

But a fixed key defeats the purpose. We want input. And we want that input to meet some quality standards — not empty, not full of characters that don't belong to all_chars, and with enough unique valid characters to make the reordering meaningful.

We build the validation in three layers.

Layer 1 — not empty. Simple while not key catches an empty string. But a key like "@@@" passes this check — it's not empty, but it contains no valid characters.

Layer 2 — contains valid characters. We clean the key — keep only characters that exist in all_chars. If nothing survives the cleaning, the key is useless.

Layer 3 — minimum 6 unique valid characters. A key like "MAMAMAMA" has 8 characters, but after removing duplicates we're left with just MA — two characters. That's a minimal reordering, easy to guess. We require at least 6 unique valid characters after cleaning.

All three layers, combined:

final_key = ""
while len(final_key) < 6:
    key = input("Please enter key: ")
    clean_key = ""
    for letter in key.upper():
        if letter in all_chars:
            clean_key += letter
    final_key = ""
    for letter in clean_key:
        if letter not in final_key:
            final_key += letter
    if len(final_key) < 6:
        print("Invalid key. Please try again.")

From here we only use final_key. Not key, not clean_key. They served their purpose — final_key is what matters.

The full block, clean:

import string

all_chars = string.ascii_uppercase + string.digits

final_key = ""
while len(final_key) < 6:
    key = input("Please enter key: ")
    clean_key = ""
    for letter in key.upper():
        if letter in all_chars:
            clean_key += letter
    final_key = ""
    for letter in clean_key:
        if letter not in final_key:
            final_key += letter
    if len(final_key) < 6:
        print("Invalid key. Please try again.")

sorted_chars = ""
reference = final_key + all_chars

for letter in reference:
    if letter not in sorted_chars:
        sorted_chars += letter

A simulation. The user enters MANHATTAN:

Please enter key: MANHATTAN

clean_keyMANHATTAN — all characters valid. final_keyMANHTA — 6 unique characters. Passes.

sorted_chars result:

MANHTABCDEFGIJKLOPQRSUVWXYZ0123456789

Placed in the grid:

   A  D  F  G  V  X
A  M  A  N  H  T  A  ← wait

Wait — A appears twice in MANHTA? No. MANHATTAN → unique characters in order → M, A, N, H, T — the second A is dropped, the second N is dropped. final_key is MANHT — only 5 unique characters. The validation rejects it.

Please enter key: MANHATTAN
Invalid key. Please try again.
Please enter key: WASHINGTON

final_keyWASHINGT — 8 unique characters. Passes.

sorted_chars:

WASHINGTOBCDEFJKLMPQRUVWXYZ0123456789
   A  D  F  G  V  X
A  W  A  S  H  I  N
D  G  T  O  B  C  D
F  E  F  J  K  L  M
G  P  Q  R  U  V  X
V  Y  Z  0  1  2  3
X  4  5  6  7  8  9

The grid is ready. Next — we map every character to its ADFGVX pair. That's the substitution dictionary. Round 2.

[ login to bookmark ] // copied! 29 views · 4 min
← prev ADFGVX Cipher — The Concept next → ADFGVX Project — Round 2/5
// 0 comments
// No comments yet. Be the first.
// leave a comment

// Your comment will appear after approval.