---
title: "aadhar.sh/lwe/vigenere"
description: "The Vigenère cipher (and Kryptos) explained at the pace of a 2009 MSN chat: keyed alphabets, autokeys, K1–K3, and how you crank a Kryptos-shaped problem and score the noise. Live workbench and statistics demos."
path: "/lwe/vigenere"
section: "lwe"
kind: "content"
updated: "2026-06-21"
source: "https://aadhar.sh/lwe/vigenere"
---

> Site index: https://aadhar.sh/llms.txt
> Section index: https://aadhar.sh/lwe/llms.txt
> This is the Markdown twin of a page on aadhar.sh. The HTML at the source
> URL below is the original, and is hand-written and unminified on purpose.

**Vigenère**Online, polyalphabetic ciphers & Kryptos

Learning With Errors  
keys & keystreams

**Heads up:** a **first-pass** walkthrough. **K1–K3** are the publicly-solved parts of [Kryptos](https://en.wikipedia.org/wiki/Kryptos) (Jim Sanborn, CIA HQ), so their mechanisms are public. The unsolved, private "Paradigm" work stays **abstract** here: methods only, no solutions. The demos compute **real ciphertext and real statistics** live.

**aadharsh**23:01

every time I bring up **Kryptos**, people go "oh, a Caesar cipher." it's so much more than a shift, right?

**Vigenère**23:01

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:

**Vigenère**23:02

Vigenère shared a demo: keystream workbench

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.

presets:

**aadharsh**23:04

and Kryptos K1–K3 are these?

**Vigenère**23:04

**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 running key is `PALIMPSEST`; K2's is `ABSCISSA`. 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** (not a substitution). 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.

**aadharsh**23:05

plain Vigenère gets broken through the repeating key though, right? what's an **autokey**?

**Vigenère**23:05

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 26 little Caesars you solve separately. An **autokey** kills the period, because instead of repeating the keyword you *extend* 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.

**aadharsh**23:06

ok, the unsolved Kryptos-style stuff. how do you even *start* when you don't know anything?

**sidekick**23:07

AI · general method, not the PK solutions

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 specific Paradigm PK1–PK6 pipelines we've run stay off this page.)

**aadharsh**23:07

let me actually try that, stack a couple of those ops, paste a ciphertext, and crank it by hand.

**Vigenère**23:07

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.

Vigenère shared a demo: the cranking workbench

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 Paradigm PK recipes stay off this page; the tool is general enough to run them once you know the recipe.

presets:

**aadharsh**23:08

"score the output," sure, but every candidate is just a wall of letters. how do you tell signal from noise?

**Vigenère**23:08

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:

**Vigenère**23:08

Vigenère shared a demo: the statistical shape of 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.

presets:

**Index of Coincidence**—English ≈ .067 · random ≈ .038

**letters scored**—χ² vs English: —

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

—

**aadharsh**23:09

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.

**Vigenère**23:10

It can, and the whole attack is four steps. **One:** find the **period**. Slice the ciphertext into every-*k*th 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 you no longer have a Vigenère, you have *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:

**Vigenère**23:10

Vigenère shared a demo: the cracker

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.

you · you know the key

presets:

the cracker · ciphertext only, no key

**1 · period**

**2 · seed each column by &chi;²**

**3 · hill-climb on quadgrams**

**4 · verdict**

**sidekick**23:10

AI · where this one came from

the solver above is a JavaScript port of the periodic-cipher attack in [buttcrack](https://github.com/0xdiid/buttcrack) (MIT, © 2026 diid), a classical-cipher cracker built to be driven by *agents* rather than by a GUI: 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, and the 61-letter K1-shaped case that the full table gets.

**aadharsh**23:11

it nailed mine, then I shortened the message and it fell apart. what's the actual floor?

**Vigenère**23:11

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, and it's why **Kryptos K1 resists this** for two independent reasons at once: 63 letters under a 10-letter key is 6 per column, and 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.

**aadharsh**23:11

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.

**Vigenère**23:09

Right: in K3 no letter ever changes, only its *position*. 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](https://mathweb.ucsd.edu/~crypto/Projects/KarlWang/index2.html). Drag the grid:

**Vigenère**23:09

Vigenère shared a demo: columnar transposition

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.

presets:

**aadharsh**23:10

so cranking Kryptos really means searching the space of (transposition × substitution × key × order), then ranking every candidate by how English-shaped its stats are. thanks, Vigenère.

→ [Kryptos](https://en.wikipedia.org/wiki/Kryptos) · [Vigenère cipher](https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher) · [Index of coincidence](https://en.wikipedia.org/wiki/Index_of_coincidence) · [columnar transposition (Karl Wang, UCSD)](https://mathweb.ucsd.edu/~crypto/Projects/KarlWang/index2.html) · [back to Learning With Errors](https://aadhar.sh/lwe)

end of conversation (first pass)

This is a recorded conversation. Crank the workbench and stats above.

Source: https://aadhar.sh/lwe/vigenere
