VigenèreOnline, polyalphabetic ciphers & Kryptos
keys & keystreams
Heads up: a first-pass walkthrough. K1–K3 are the publicly-solved parts of Kryptos (Jim Sanborn, CIA HQ), so their mechanisms are public. Paradigm's ten Kryptos-style PK puzzles are all solved too (the last two fell on 2026-10-02), so the back half opens our solver group's private notes: the PK1–PK8 recipes, PK7 as we solved it, and where we went wrong on PK8. The demos compute real ciphertext and real statistics live.
every time I bring up Kryptos, people go "oh, a Caesar cipher." it's so much more than a shift, right?
Right. A Caesar cipher shifts every letter by one fixed amount (A→D, shift 3). That's monoalphabetic: the same plaintext letter always maps to the same ciphertext letter, so a frequency count cracks it in seconds (E stays the most common letter, just relabeled).
A Vigenère cipher uses a repeating key of shifts: position 1 shifts by the 1st key letter, position 2 by the 2nd, and so on. The same plaintext letter lands as different ciphertext depending on its position. That's polyalphabetic, and it flattens the frequency signal.
Here's the unifying trick: a Caesar is just a Vigenère with a one-letter key. Key J repeats into the keystream JJJJJJ…, shifting every letter by the same 9, exactly a Caesar shift of 9. Key JJJ is identical, since it repeats into the same stream. A Caesar is the period-1 case; Vigenère is what you get once the key has more than one letter. Try it:
Type a plaintext, a key, and an alphabet (the cipher uses the alphabet's order, so a keyed alphabet scrambles it). See the keystream and the ciphertext, computed live.
and Kryptos K1–K3 are these?
K1 and K2 are Vigenère on a keyed alphabet: the tableau is built on the keyword KRYPTOS, so the alphabet becomes KRYPTOSABCDEFGHIJLMNQUVWXZ instead of A…Z. K1's key is PALIMPSEST and K2's is ABSCISSA, each repeated end to end. Hit the Kryptos K1 preset above and it reproduces the real sculpture ciphertext EMUFPHZLRFAXYUSDJKZLD…; decrypt that and you get Sanborn's line ending in the deliberate misspelling "…the nuance of iqlusion."
K3 plays a different game: it's a transposition. The letters are all correct, just rearranged by a route or columnar scheme. That split, substitution versus transposition, becomes the whole game once you reach the unsolved parts.
plain Vigenère gets broken through the repeating key though, right? what's an autokey?
Exactly: a repeating key has a period, and that period is its weakness. Kasiski spacing and the Friedman test recover the key length, and then it's one little Caesar per key letter, each solved separately. An autokey kills the period by extending the key with the message itself (the key, then the plaintext). No repeat means no period to find. Switch the demo's mode to autokey and watch the keystream stop repeating.
ok, the Kryptos-style puzzles. how do you even start when you don't know anything?
you treat it as a search over a pipeline, because you don't know the alphabet, the key, or the order of operations. the toolkit, in the abstract:
• transposition: columnar, route, rotation, skip-reads (rearrange the letters)
• substitution: Vigenère and the Quagmire I–IV family, which differ in which of the plaintext, ciphertext, or key alphabets are keyed (QIII is the Kryptos one; QIV keys all three)
• running keys: a long text used as the key, plus autokeys
• order: transpose-then-Vig, Vig-then-transpose, "Vig first" versus "Vig last," stacked stages
you compose a candidate pipeline from those, run the text through it, and score the output. then crank the next combination. (the real PK pipelines, public now, close out this conversation.)
let me actually try that, stack a couple of those ops, paste a ciphertext, and crank it by hand.
Here's the workbench. Each stage is one operation (a transposition, a substitution, a Vigenère, or a plain Caesar shift) set to encrypt or decrypt. The pipeline runs top to bottom, so the order is yours: a Vigenère above a transposition is "Vig first," below it is "Vig last," and the two give different ciphertext. Watch a transposition keep every letter but shuffle the order, and a substitution swap the letters but keep the order.
Stack operations, paste text, and run it. To decode, set every stage to dec and list them in the reverse of how it was encoded. Set the right recipe and a Kryptos-shaped ciphertext falls out as plaintext. The PK presets load real Paradigm ciphertext with its published recipe, already set to decode.
"score the output," sure, but every candidate is just a wall of letters. how do you tell signal from noise?
By the statistical shape of the letters. Random, polyalphabetic text reads flat, every letter roughly equally likely. Real language reads lumpy, with E, T, A spiking. The single number that captures this is the Index of Coincidence: the chance two random letters of the text match. English ≈ 0.067; uniform random ≈ 0.038. A correct (mono-alphabetic) decrypt jumps to ~0.067; a wrong, polyalphabetic one sits near 0.04. Paste candidates in and watch the noise:
Drop in any text. The Index of Coincidence and the frequency shape tell you how language-like it is, exactly the score you'd crank candidate decrypts against.
ok but I'm scoring these by hand. a machine should crank the whole search. can it just break one? give it something of mine, don't tell it the key, and let me watch.
It can, and the whole attack is four steps. One: find the period. Slice the ciphertext into every-kth letter for each candidate key length and measure each slice's Index of Coincidence. At the wrong length the slices are still polyalphabetic and read flat (~.038); at the right one each slice is a single Caesar, so it reads English-lumpy (~.067). The period pops out of the chart. Two: at that length the Vigenère splits into k independent Caesars, so solve each one by picking the shift whose χ² against English letter frequencies is lowest. That gets most of the key. Three: hill-climb the rest, because χ² only sees one column at a time and can't tell that column 3's guess makes THEQ where THER was available. Try all 26 shifts at each position, keep any that improves the quadgram score of the whole plaintext, repeat until nothing improves. Cross-column context is what recovers the last letters. Four: report a verdict, because a solver that always answers is useless. Type your own message and key:
Write a message, pick a key, and the top half encrypts it. The bottom half is handed the ciphertext only and has to find your key from scratch. Watch the four steps run, then compare what it recovered against what you chose.
the solver above is a JavaScript port of the periodic-cipher attack in buttcrack (MIT, © 2026 diid), a classical-cipher cracker built for agents to drive: every command is non-interactive and emits JSON, across 78 cipher types. its whole Vigenère family lives in one ~100-line file, _periodic.py, and the two ideas worth stealing are both in there. seed by χ², then climb on the full text, because per-column analysis alone can't recover a short key. and dedupe candidates by resulting plaintext, keeping the shortest key, so a 5-letter key and its 10-letter repeat collapse into one answer instead of competing.
what the port doesn't carry is the model. the real thing scores against 46,040 quadgrams with counts; this page ships the top 4,000 in rank order only, 16 KB raw, 7.9 KB over the wire, fetched the first time you press the button. measured cost of that cut: nothing above 100 letters, but it misses the 61-letter K1-shaped case that the full table gets.
it nailed mine, then I shortened the message and it fell apart. what's the actual floor?
Letters per column are what run out. A key of length k splits your text into k separate Caesars, and each one is solved from only its own slice, so 200 letters under a 4-letter key is a comfortable 50 per column while the same 200 under a 20-letter key is a starved 10. Measured on this exact solver and this exact table: at 20+ per column it solved every test, at 12 it got 10 of 12, at 8 it got 6 of 12. That's the gauge under your message. It's also why Kryptos K1 resists this for two independent reasons at once. First, 63 letters under a 10-letter key is 6 per column. Second, the alphabet isn't A–Z anyway, so even a correct key decrypts to nothing. Short text starves the statistics; a keyed alphabet moves the target.
back up to the transposition stage for a sec. K3 of Kryptos is pure transposition, no substitution at all, right? show me columnar specifically, and the double version.
Right: in K3 every letter keeps its identity and only its position moves. Columnar is the workhorse. Write the message into a grid row by row under a keyword, then read it back column by column, taking the columns in the alphabetical order of the keyword's letters. KRYPTOS ranks its seven columns 1 4 7 3 6 2 5, so you read the K column first, then O, then P, and so on. Same letters, new order, and a ragged last row is the only bookkeeping. Double columnar just runs that twice, the first ciphertext poured into a fresh grid under a second keyword. The two passes scramble the column structure enough that the hand version resisted cryptanalysis for decades. There's a clean step-by-step walkthrough here. Drag the grid:
In by rows, out by columns. The keyword numbers the columns by alphabetical order and you read them lowest number first. Flip double to pour the first ciphertext into a second grid under a second keyword, the way K3-style ciphers stack stages.
ok, the Paradigm puzzles. all ten are solved now (PK9 and PK10 fell on 2026-10-02), so we can open the notes. what were they actually?
Mostly the toolkit on this page, stacked. The ten puzzles tell one story, a narrator chasing a legendary needle "fine enough to split a hair," and every substitution in the first eight is the same move: a Vigenère on the KRYPTOS alphabet (Quagmire III), each letter worth its index in KRYPTOSABCDEFGHIJLMNQUVWXZ. A test that runs in A–Z never sees it. The recipes, in encryption order:
• PK1: one Vigenère, PROVENANCE
• PK2: one columnar, width 7, MARGINS
• PK3: two Vigenères, ORDINATE + PENTIMENTO
• PK4: columnar UNDERLAY, then OCHRE + VERDIGRIS
• PK5: columnar TWOYEARS, then a running key that is all 224 letters of PK4's plaintext
• PK6: two width-9 columnars, HANDIWORK and SMITHWORK, then PORTAL
• PK7: ANNEAL, then a 3×3 matrix spelled by ALCHEMIST
• PK8: four Vigenères, METE, METER, METIER, MASTERY
PK9 and PK10 fell after our shared notes stop, so their recipes aren't here. Two house rules held. The keys name the scene they hide in: ALCHEMIST encrypts PK7, whose whitesmith shows "his technique for purifying his metal." And every grid divides its text exactly: 350 = 7 × 50, 224 = 8 × 28, 272 = 8 × 34, 315 = 9 × 35, 279 = 3 × 93. No ragged last row anywhere, so the length hands you the admissible widths before you search.
wait, PK3 puts two keys on the same letters. doesn't that just add up to one key?
It does, and that's the trick. Add two repeating keys letter by letter and you get one repeating key whose period is their least common multiple. ORDINATE is 8 and PENTIMENTO is 10, so the sum repeats every 40, and collapsed it reads BFPNBZITCSGKFENPJQHQVMWIQNUBWFAVXOZATKBJ. That buys the setter two things. The period gets long: 280 letters over 40 columns is 7 per column, under the 8 where the cracker above got 6 of 12. And a solver who does recover the stream tends to throw it out, because no dictionary has it.
Our notes split PK3's stream back into its two words, and PK4's period-45 stream into OCHRE + VERDIGRIS (5 × 9). The rule we wrote down: never reject a recovered key for failing to be a word. Press PK3 in the cranking workbench: two stages, real ciphertext in, "SEVENTH MONTH. I WROTE TO FIFTEEN CORRESPONDENTS" out.
so PK8 is the same move with four words?
Four words, and four is where the attack on this page dies. The periods are 4, 5, 6 and 7, their least common multiple is 420, and PK8 is 153 letters long. The summed key never repeats inside the text, so the cracker's step one has no period to find. Four short words built a running key. They're one word family, too: METER, drop a letter for METE, add one for METIER (a trade, a calling; PK8 ends on "the archive is my true calling"), then MASTERY.
The instruction sat in PK7's plaintext the whole time: "He has me repeat the same step four times with slight variations." Our group read that as structure, a period of 28 or four interleaved lanes. The solver who cracked it on 2026-09-06 read it as a recipe: the series' one substitution, four times, with keys that vary slightly. Press PK8 in the workbench and watch "I LEAVE AT MIDNIGHT" fall out of four stages.
how close did we get?
close on the family, wrong on the word bank. word-sum Vigenère was on our list from the day PK3 came apart. we ran every pair from a 4,375-word thematic bank, three-word sums, and every subset of one to five of the keys harvested from PK1–PK7, in both alphabets. all cold, and correctly cold: METER was the only one of the four words in any bank, and nobody had tried four at once.
the instrument that misled us was a real one. we measured a faint period 7 in PK8 (column IC 0.0536, at the 99th percentile of a fixed-period null) and spent weeks on period-7 substitution under a transposition. the post-mortem found the signal at lags 28, 35 and 42, where MASTERY and one shorter word cancel at once, and found lags 7, 14 and 21, where MASTERY cancels alone, dead. every number we measured was right, and the model we built on them was wrong. forward-model the candidate keys before you trust what a period count implies.
and PK7, the one we cracked ourselves?
PK7 is a Vigenère hidden under a Hill cipher. Encrypt with ANNEAL (period 6), cut the result into 3-letter blocks, and multiply each block by the matrix ALCHEMIST spells in KRYPTOS indices, [[7,17,9],[14,11,18],[15,6,4]], mod 26.
Each layer blinds the other's detector. The Hill's input is Vigenère-of-English, so every Hill attack scoring against English frequencies read noise. The Vigenère sits under a three-letter mix, so Kasiski, the IoC period chart and every word-sum test read flat. We validated each single-layer attack on a planted cipher first, and each was correctly cold on PK7. What broke it was arithmetic, from a nudge by another solver in the group: 279 is odd, 279 = 3 × 93, so take the 3 literally. Solved 2026-07-02, and the re-encryption matched the official ciphertext on all 279 letters.
The cleanest lesson came on 2026-07-22. A Hill is linear, so M(p + k) = Mp + Mk, which makes Vigenère-then-Hill the same cipher as Hill-then-a-different-period-6-Vigenère (its key is the matrix applied to ANNEAL). For any linear layer, substitution-inside and substitution-outside are one family, and testing both spends the budget twice.
our general-Hill attack once returned a "plaintext" scoring −5.16 per letter on quadgrams, about what English scores, and it was WOLLASTONITE repeated end to end: the Vigenère key it had guessed. a quadgram model rewards real words, and a key spelled over and over is wall-to-wall real words. two checks before calling anything solved: the decrypt isn't the key repeated, and it re-encrypts to the exact official ciphertext. it's the same reason the cracker above ends on a verdict instead of its best guess.
so cranking Kryptos really means searching the space of (transposition × substitution × key × order), then ranking every candidate by how English-shaped its stats are, and re-encrypting before you believe any of them. thanks, Vigenère.
→ Paradigm's Kryptos CTF · Kryptos ·Vigenère cipher · Index of coincidence · columnar transposition (Karl Wang, UCSD) · back to Learning With Errors