classical-ciphers
v1.0.0
Published
Tiny dependency-free TypeScript implementations of the classic ciphers: Caesar/ROT13/ROT47, Vigenère/Autokey/Beaufort, and Atbash. Case-preserving, total over arbitrary text.
Maintainers
Readme
classical-ciphers
Tiny, dependency-free TypeScript implementations of the classic pen-and-paper ciphers — Caesar / ROT13 / ROT47, Vigenère / Autokey / Beaufort, and Atbash.
Every transform preserves letter case and passes non-letters (digits, spaces, punctuation, other scripts) through untouched, so each function is a total function over arbitrary text — safe to run over a whole document without mangling its shape.
🔐 Prefer an interactive version? Each cipher here has a free in-browser tool at textmachine.org — paste text, tweak the key, and copy the result. No sign-up, nothing leaves your device: Caesar / ROT · Vigenère · Atbash
🔎 Not sure which cipher you're looking at? Paste it into the Cipher Identifier — it analyses the text (letter frequency, Index of Coincidence, χ² shift tests) and ranks the likely ciphers, each with a one-click link to its decoder.
Install
npm install classical-ciphersUsage
import {
caesarShift, caesarEncode, caesarDecode, rot47, rotateDigits,
applyVigenere,
atbash,
} from "classical-ciphers";
// Caesar — shift within each case, punctuation untouched
caesarEncode("Hello, World!", 3); // "Khoor, Zruog!"
caesarDecode("Khoor, Zruog!", 3); // "Hello, World!"
// ROT13 is just a shift of 13 — and its own inverse
caesarShift("Attack at dawn", 13); // "Nggnpx ng qnja"
// ROT47 over printable ASCII (also self-inverse)
rot47("Hello"); // "w6==@"
// ROT5 over the digits 0–9
rotateDigits("Order 2026", 5); // "Order 7571"
// Vigenère — a repeating keyword supplies a different shift per letter
applyVigenere("ATTACKATDAWN", "LEMON", "vigenere", "encode"); // "LXFOPVEFRNHR"
applyVigenere("LXFOPVEFRNHR", "LEMON", "vigenere", "decode"); // "ATTACKATDAWN"
// Autokey (key never repeats) and Beaufort (reciprocal — decode === encode)
applyVigenere("ATTACKATDAWN", "LEMON", "autokey", "encode"); // "LXFOPKTMDCGN"
applyVigenere("ATTACKATDAWN", "LEMON", "beaufort", "encode"); // run again to decode
// Atbash — A↔Z mirror, self-inverse
atbash("Hello, World!"); // "Svool, Dliow!"API
| Function | Signature | Notes |
| --- | --- | --- |
| caesarShift | (text, shift) => string | Rotate letters by shift (mod 26; negative/large normalised). |
| caesarEncode / caesarDecode | (text, shift) => string | Convenience wrappers (decode = shift by -shift). |
| rotateDigits | (text, shift) => string | ROT-N over the digits 0–9 only. |
| rot47 | (text) => string | Rotate printable ASCII (33–126) by 47; self-inverse. |
| applyCipher | (text, cipher, direction) => string | Dispatch {kind:"caesar",shift} | {kind:"rot5"} | {kind:"rot47"}. |
| normalizeKey | (key) => number[] | Reduce a keyword to its A–Z letters as 0–25. |
| applyVigenere | (text, key, variant, direction) => string | variant: "vigenere" | "autokey" | "beaufort". Empty/letterless key = identity. |
| atbash | (text) => string | A↔Z mirror; self-inverse. |
Types Cipher, Direction ("encode" | "decode") and Variant are exported.
Design notes
- No dependencies, no side effects — pure string→string functions.
- Case-preserving and total — non-A–Z characters are emitted unchanged and, for Vigenère, do not advance the keystream, so message structure survives.
- Self-inverse ciphers (ROT13, ROT47, Atbash, Beaufort) use the same call to encode and decode.
- These ciphers are of historical / educational interest and are not secure — don't use them to protect real secrets.
License
MIT © 2026 Text Machine — built alongside the free text tools at textmachine.org.
