Analysis
Brute force
A Caesar has 25 keys. The attack is all of them, then read:
ciphers brute "KHOOR ZRUOG"
shift= 1 → JGNNQ YQTNF
shift= 2 → IFMMP XPSME
shift= 3 → HELLO WORLD
...
There is no dedicated function for this in the library, and there shouldn't be. It's create("caesar").decode(text, { shift }) in a loop from 1 to 25 - that's what the command, the cipher_brute_caesar tool and the landing panel run. Shift 0 is not on the list. It would be the input, and the library refuses it as a shift anyway.
Frequency
import { analyzeFrequency } from "@agntn/ciphers";
const analysis = analyzeFrequency("DWWDFN DW GDZQ", "en");
analysis?.counts; // [["D", 4], ["W", 3], ["F", 1], ...] sorted by count
analysis?.reference; // "ETAOINSHRDLCUMWFGYPBVKJXQZ"
analysis?.ic; // index of coincidence
analyzeFrequency(text, language) uppercases, drops everything outside A to Z and counts. No letters at all - undefined, not an empty table, so check before you read. The language picks the reference order, en or pl.
| Field | Meaning |
|---|---|
total | Letters counted |
counts | [letter, count] pairs, most frequent first |
reference | Expected order for the language |
ic | Index of coincidence, missing with fewer than two letters |
Reading the index of coincidence
The IC is the chance that two letters picked from the text are the same. English sits near 0.067, uniform random near 0.038. That one number tells you which family you are looking at before you try a single key:
- Monoalphabetic substitution (Caesar, Atbash, Affine) keeps the histogram shape and only relabels the bars. IC stays high, and the tallest ciphertext letter is probably E.
- Polyalphabetic (Vigenère, Alberti) spreads one plaintext letter over several ciphertext letters. IC drops toward 0.038 and the histogram goes flat. Time to look for a period.
- Transposition (rail fence, columnar) moves letters without changing them. The histogram is the plaintext's, only the words are gone.
The Playground draws the histogram for any text, expected order next to actual.
The CLI
ciphers frequency "DWWDFN DW GDZQ"
ciphers frequency "ZAŻÓŁĆ GĘŚLĄ JAŹŃ" --lang pl
One bar per letter, expected and actual order, then the IC with the two reference values next to it so you don't have to remember them.