Book cipher
Book Cipher
Every word as its place in a text both sides own.
- Keyspace
- every text both sides have
- Decode
- same options back
- Works on
- letters and digits in any script, as words or one by one with pick letter, the rest dropped
- Family
- 1 in homophonic
Options
Access
- Create
create("book") - CLI
ciphers encode book 'seek and ye shall find' --book 'Ask, and it shall be given you; seek, and ye shall find; knock, and it shall be opened unto you.' - Tryplayground with the sample above
The key is a whole text. A novel, a song, a founding document. Both sides own the same copy, and the ciphertext is just numbers pointing into it. Beale hid a treasure description this way, or so the pamphlet says.
const book = create("book");
const verse =
"Ask, and it shall be given you; seek, and ye shall find; knock, and it shall be opened unto you.";
book.encode("seek and ye shall find", { book: verse }).text; // "8 2 10 4 12"
book.decode("13 3 4 20", { book: verse, pick: "letter" }).text; // "KISY"
That verse is Matthew 7:7, the key a spy uses in The Imitation Game. Good taste in keys.
What's a word?
Letters and digits in a row, in any script, with the marks that sit on them. An apostrophe inside keeps it whole, so Nature's is one word. Anything else splits, so self-evident is two. Beale counted self-evident as two, and the dCode examples only add up with Nature's as one. So that's the rule.
Words or letters
pick: "word" hands back the word itself, spelled as the book spells it. pick: "letter" takes its first letter. That's the Beale trick: word 115 is instituted, so it means I. Words come back with spaces between them. Letters come back uppercase and glued together. ß stays ß, since its capital is two letters.
Encoding looks up each word, or each letter with pick: "letter", and ignores case. STRAẞE finds straße. Everything that isn't a letter or a digit is dropped.
Why not always the first match? Five Es with the same number is the first thing anyone attacking it looks for. So a repeat takes the next word that fits, and after the last one it starts over.
Lines and pages
address sets how many numbers one place takes:
wordis the place in the whole book, like305.line-wordis the line, then the word in it, like12-3.page-line-wordis the page, the line on it and the word, like4-12-3.
A line without a word doesn't count. A page ends at a form feed, which is exactly what pdftotext puts between PDF pages. Got a PDF of the right edition? Run it through pdftotext and hand over the file.
ciphers decode book "4-12-3 4-12-7" --book-file edition.txt --address page-line-word
start: 0 counts every word, line and page from zero. For puzzles written by programmers.
Decoding doesn't care how the numbers are dressed. 12-3-5, 12.3.5 and (12, 3, 5) read the same. Every number counts, in order, and page-line-word takes them three at a time.
Same book, same split?
Not always. One copy has a preface, the other doesn't. One keeps the title, one starts at the first sentence. So every result says how the book split:
book.decode("8", { book: verse }).options;
// { address: "word", pick: "word", start: 1, words: 20, lines: 1, pages: 1 }
Compare those counts before you blame the cipher. The book itself stays out of the result. It can be a whole novel, and nobody needs it echoed back.
Checked against
The dCode book cipher page, over the Declaration of Independence as the National Archives transcribes it, counted from "When". 15 4 12 52 7 with pick: "letter" is DCODE. 221 132 136 305 is by of of King, or BOOK in letters. And the Wikipedia page on the Beale ciphers: word 115 is instituted.
Errors
A number past the end is a CipherError that says what it looked for and how many there are: Word 40 is out of range: the book has 20 words, numbered from 1. Numbers that don't split into whole addresses are a CipherError too. So is a word the book doesn't have. No book is a MissingOptionError. A book without a single word is an InvalidOptionError, and so is an address, pick or start it doesn't know.