We are now in the era of Artificial Intelligence, and I’m using it to improve many things—including my cryptographic codes. I asked Gemini AI to analyze the PolyCrypt algorithm, which is designed to be human-computable, and it discovered several vulnerabilities. These issues are now resolved in PolyCrypt 2. Read on to see how these improvements were achieved.
If you think having a friend critique your fiction is tough, try getting feedback on a homemade encryption scheme—especially one that must be usable by hand, while resisting an attacker with enormous computational resources. (For clarity, I’ll refer to “the enemy” as an AI adversary, using ‘its’ pronouns).
AIs are not only patient reviewers (within their limits), but—when prompted as cryptography experts—are surprisingly effective at analyzing ciphers. Here’s a summary of their key insights and the resulting improvements:
1. Substitution Key Optimization:
PolyCrypt uses multiple substitution alphabets, but not all increase security. Substitution applied to plaintext, for example, doesn’t effectively conceal letter patterns, so one strong key can suffice in certain steps. Three distinct keys remain essential for the other substitutions.
2. Improved Keystream Seeding:
Previous versions combined the random seed with a key and published it with the ciphertext, risking exposure if the key was weak. PolyCrypt 2 uses a nonce transmitted with the ciphertext and combines it with a private seed key, which is never revealed—greatly reducing information leakage.
3. Strengthened Keystream Generator:
A simple two-tap Lagged Fibonacci Generator (LFG) can be reverse-engineered too easily. Using a multi-tap LFG with widely spaced taps (mechanically chosen via “snake” operations on the Tabula Recta) adds substantial resistance to cryptanalysis.
4. Revised Transposition Techniques:
Keyed transposition enhances security when applied to ciphertext—less so to plaintext. PolyCrypt 2 performs columnar transpositions post-substitution, supporting rows of variable length or padded columns for evenness.
5. Efficient Preprocessing:
Quick cut-and-reverse operations protect against predictable text structures before encryption—no extra key needed.
So here’s the revised workflow for the new version of PolyCrypt, which you can also see in this app.
The PolyCrypt 2 Workflow
Overview:
PolyCrypt 2 builds on <a href=”https://arxiv.org/abs/1404.0024″>human-computable ciphers</a> (PassLok, URSA, KyberLock), combining substitution, transposition, and keystream mixing using up to six readable keys:
- Keys 1–4: Substitution alphabets (compressed using Tabula Recta “snake” logic)
- Key 5: Keystream seed (comes from a nonce + private secret)
- Key 6: Columnar transposition key (optional)
Encryption and decryption mirror one another, with custom handling for spaces and punctuation.
1. Key Compression
– Strip key phrases of spaces and accents.
– Write each key in 25-letter blocks.
– Using the Tabula Recta, compress keys by alternating down/right moves within each block to distill one letter per column.
2. Scrambled Alphabets
– Each compressed key generates a scrambled alphabet: take each letter in order (skipping repeats with unused backward-fill), then append unused letters in reverse.
3. Preprocess Plaintext (Encryption Only)
– Optionally cut and swap halves.
– Uppercase and remove accents/numbers.
– Q replaces all spaces/most punctuation; numbers become A-J.
4. Setup Table (for Seed/Nonce Handling)
– Row 1: Ciphertext (when decrypting) or blank (when encrypting, to match Key 5 length)
– Row 2: Key 5
– Row 3: Random nonce; paired with Key 5 to seed keystream on the Tabula Recta.
5. Keystream Expansion (Lagged Fibonacci)
– Determine lag d by dividing seed length by number of LFG taps—4 taps is a practical choice.
– Generate keystream using Tabula Recta “snake” logic, alternating directions, appending output after each round.
– Fill Row 2 with the full expanded keystream.
6. Main Encryption/Decryption
– For each plaintext (Row 1) and keystream (Row 2) letter pair:
– Encrypt:
– Find Row 1 (top), move vertically to Row 2, then horizontally to read the cipher letter (Row 3).
– Decrypt:
– Start at the left (Row 1), move horizontally to Row 2, then up to find the original letter (Row 3).
7. Columnar Transposition (Optional, Key 6)
– Number Key 6’s letters by their alphabetical order (ties right-to-left).
– Fill ciphertext under Key 6 as columns and read out in numeric order.
– Reverse for decryption before step 4.
8. Postprocessing (Decryption Only)
– Undo any cuts or reversals.
– Restore spaces (“Q” to space, “QQ” to period-and-space).
– Reconstruct special digraphs (e.g., “KU” + vowel → “QU”).
Ergonomics & Tips
The most cumbersome part is expanding the keystream, especially with multitap LFG. To simplify, copy the keystream into offset rows equal to the lag—this way, you read across columns instead of counting positions.
Take PolyCrypt 2 for a test drive and let me know how it could be improved! Below is an example.
Example of Encryption
Plaintext:
MEET AT NINE
Keys:
(Key lengths and values are illustrative for demo clarity.)
Key 1: SECRETKEYA
Key 2: ALPHABETLO
Key 3: QWERTYUIOP
Key 4: ZXCVMNBASD
Key 5: FLUFFYPET
Key 6: none (no transposition)
Step 1: Preprocess Plaintext
Remove spaces and punctuation; convert to uppercase.
Substitute Q for space.
MEET AT NINE → MEETQATQNINE
Step 2: Generate Scrambled Alphabets
(Short demo):
For Key 1, order: S E C R T K E Y A
Fill in remaining in reverse order (Z to A, skipping existing):
S E C R D T K B Y A Z X W V U Q P O N M L J I H G F
Similar for Keys 2–4.
Step 4: Setup the Table
Row 1 (plaintext): MEETQATQNINE
Row 2 (seed/key5): FLUFFYPET
Row 3 (nonce): ECXMNEPTW (random for this example)
Step 5: Keystream Seed (Tabula Recta Nonce-Seeding Mini-Step)
For each nonce/key5 pair, go down “top” (Key 1 scrambled) from Row 3 (E, C, X…) to Row 2 (F, L, U…).
Demo output (varies by table):
Seed letters (Row 1): ZOOWVFCCT
Step 6: Keystream Expansion (Lagged Fibonacci)
Use seed (e.g., ZOO…) and calculate lag for 4 taps, d = floor((seedLength-1)/(taps-1)) = floor(8/3) = 2.
Pick the initial taps with separation 2, so positions 1, 3, 5, and 7 in the seed row.
Example outputs:
1st keystream letter: Use seed1 (Z) at top-top > seed3 (O) > seed5 (V) > seed7 (C), apply Tabula Recta “snake” logic, result: W at right
2nd keystream letter: shift +1 (O>W>F>C), result: W
3rd: M, and so on.
Final Keystream Row: W W M F K G N G K R M L
Step 7: Main Encryption Step
For each position, use:
Plaintext (from Step 4 Row 1): M E E T Q A T Q N I N E
Keystream (repeat as needed): W W M F K G N G K R M L
Now, for each (Plain, Key):
Use Tabula Recta (Key 1 as top, Key 2 as left):
Ciphertext = Tabula Recta[Plain, Key]
Example:
M > W = H
E > W = I
E > M = X
T > F = A
Q > K = I
A > G = F
(Continue…)
Resulting Row (Ciphertext): H I X A I F K Q N I J Y
Step 8: Columnar Transposition (skipped)
Step 9: Output
Final ciphertext: H I X A I F K Q N I J Y
Prepend the nonce. Final result to be transmitted: ECXMNEPTWHIXAIFKQNIJY