Beale’s Cipher

December 2, 2016

The book cipher is unusual because different data structures are appropriate for enciphering and deciphering operations. We begin with enciphering:

(define (encipher key txt)
  (define (clean txt)
    (filter (lambda (c) (not (char-whitespace? c)))
            (map char-downcase (string->list txt))))
  (let ((alpha (make-vector 26 (list))))
    (do ((key (map (lambda (s) (string-ref s 0))
                   (string-split #\space key)) (cdr key))
         (i 1 (+ i 1)))
        ((null? key))
      (let ((x (- (char->integer (car key)) 97)))
        (vector-set! alpha x (cons i (vector-ref alpha x)))))
    (map (lambda (c)
           (let ((xs (vector-ref alpha (- (char->integer c) 97))))
             (if (null? xs) 0 (fortune xs))))
         (clean txt))))

Here, alpha as a 26-slot vector, one slot per letter of the alphabet, with each slot containing a list of the indices of the words that begin with that letter. For instance, the key “now is the time” is stored as a vector #(() () () () () () () () (2) () () () () (1) () () () () () (3 4) () () () () () ()). Note that the index numbers of the key words start at 1, not 0. At each letter of plain text, one of the key word indices corresponding to that letter is chosen at random (by the fortune function); plain text letters that do not appear in the key text are encoded as 0.

For deciphering, the initial letters of the words in the key text are stored in a vector, one letter per vector slot, and index numbers are looked up in the vector, applying an offset of 1; an underscore is written if a 0 appears in the cipher text:

(define (decipher key xs)
  (let ((alpha (list->vector
                 (map (lambda (s) (string-ref s 0))
                      (string-split #\space key)))))
    (list->string (map (lambda (x)
                         (if (zero? x) #\_ (vector-ref alpha (- x 1))))

Here are some examples:

> (encipher "now is the time" "tin")
(4 2 1)
> (decipher "now is the time" '(4 2 1))

Unfortunately, Beale misnumbered the words in the Declaration of Independence, and made several other clerical errors during his encipherment, so the resulting message is garbled:

> (decipher declaration text2)

And here is the proper decipherment:

I have deposited in the county of Bedford, about four miles from Buford’s, in an excavation or vault, six feet below the surface of the ground, the following articles, belonging jointly to the parties whose names are given in number “3,” herewith:

The first deposit consisted of one thousand and fourteen pounds of gold, and three thousand eight hundred and twelve pounds of silver, deposited November, 1819. The second was made December, 1821, and consisted of nineteen hundred and seven pounds of gold, and twelve hundred and eighty-eight pounds of silver; also jewels, obtained in St. Louis in exchange for silver to save transportation, and valued at $13,000.

The above is securely packed in iron pots, with iron covers. The vault is roughly lined with stone, and the vessels rest on solid stone, and are covered with others. Paper number “1” describes the exact locality of the vault so that no difficulty will be had in finding it.

The Declaration of Independence and the cipher text of the second document appear on the next page. You can run the program at


Pages: 1 2 3

4 Responses to “Beale’s Cipher”

  1. KCR said

    This was my 2nd ever programming course assignment, and the one I enjoyed programming the most. Thanks for posting this.

  2. Paul said

    In Python. The Beale cipher is apparently so complicated to use, that Beale (probably) messed up the encoding. It is, of course, a daunting task to set up the encoding with a document of 1322 words without a computer. It is also not really known which version of the Declaration of Independence he used.

    def read_decl(list_of_words):
        """create encode and decode dictionaries
        the input is a sequence of lowercase words
        E, D = defaultdict(list), {}
        for n, word in enumerate(list_of_words, 1):
            D[n] = word[0]
        return E, D
    def decode(code, D):
        'input is list of ints - output is string'
        return "".join(D.get(n, "?") for n in code)
    def encode(txt, E):
        'input is string - output is list of ints'
        txt = txt.lower()
        return [choice(E.get(c, [0])) for c in txt]
    E, D = read_decl(open(DECLARATION).read().lower().split())
    print(decode((int(n) for n in open(LETTER).read().split(", ")), D))
  3. matthew said

    Sounds like a good excuse to play around with Unicode and ES6 a little more. ES6 has a number of features that make proper Unicode handling rather easier than in previous versions of Javascript. Notably, strings now support the new iterator protocol that allows us to easily convert strings to arrays of single Unicode characters rather than having to deal with surrogate pairs. For testing this, we will use texts in the Gothic script which uses the astral Unicode codepoints U+10330 to U+1034A, and seems to be reasonably well supported by fonts and browsers. Extant Gothic scripts are mainly religious, but there is one poem in Gothic, “Bagme Bloma”, written by J. R. R. Tolkein. Here we encrypt that poem, using as key text the Gothic version of the Lord’s Prayer. I couldn’t find the texts already in the Gothic script, so we start by converting from latin transliterations.

    "use strict"
    // The Lord's Prayer in Gothic, transliterated.
    const text1 = [
        "atta unsar þu in himinam",
        "weihnai namo þein",
        "qimai þiudinassus þeins",
        "wairþai wilja þeins",
        "swe in himina jah ana airþai",
        "hlaif unsarana þana sinteinan gif uns himma daga",
        "jah aflet uns þatei skulans sijaima",
        "swaswe jah weis afletam þaim skulam unsaraim",
        "jah ni briggais uns in fraistubnjai",
        "ak lausei uns af þamma ubilin",
        "unte þeina ist þiudangardi jah mahts",
        "jah wulþus in aiwins"
    // Tolkein's Bagme Bloma poem
    const text2 = [
        "brunaim bairiþ bairka bogum",
        "laubans liubans liudandei",
        "gilwagroni glitmunjandei",
        "bagme bloma blauandei",
        "fagrafahsa liþulinþi",
        "fraujinondei fairguni",
        "wopjand windos wagjand lindos",
        "lutiþ limam laikandei",
        "slaihta raihta hweitarinda",
        "razda rodeiþ reirandei",
        "bandwa bairhta runa goda",
        "þiuda meina þiuþjandei",
        "andanahti milhmam neipiþ",
        "liuhteiþ liuhmam lauhmuni",
        "laubos liubai fliugand lausai",
        "tulgus triggwa standandei",
        "bairka baza beidiþ blaika",
        "fraujinondei fairguni"
    // Gothic alphabet and the standard latin transliteration
    const gothic = "𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷𐌸𐌹𐌺𐌻𐌼𐌽𐌾𐌿𐍀𐍁𐍂𐍃𐍄𐍅𐍆𐍇𐍈𐍉𐍊";
    const latin = "abgdeqzhþiklmnjup*rstwfxƕo^";
    const gchars = [...gothic] // iterator respects codepoints
    const lchars = [...latin]
    const charmap = new Map(,i)=>[c,gchars[i]])) // zip
    const convert = s => [...s].map(c=>charmap.get(c)||c).join("")
    const keytext =
    // Now construct the encoding tables
    const encoder = new Map()
    const decoder = new Map([[0,"."]]) // Unknown character
    const allwords = [].concat(>s.split(" ")))
    allwords.forEach((w,i) => {
        const index = i+1
        const c = String.fromCodePoint(w.codePointAt(0))
        if (!encoder.has(c)) encoder.set(c,[])
    const encodeone = c => {
        const a = encoder.get(c)
        if (a == undefined) return 0
        else return a[Math.floor(Math.random() * a.length)]
    const encode = s => [...s].map(encodeone,s)
    const decode = s => => decoder.get(n)).join("")
    const plaintext =
    const ciphertext =
    const plaintext2 =

    Here’s the output with the key text, the plain text and the decrypted cipher text, we can see one of the disadvantages of Beale’s scheme – some of the letters do not occur as first letter in the key text so cannot be enciphered:

    𐌰𐍄𐍄𐌰 𐌿𐌽𐍃𐌰𐍂 𐌸𐌿 𐌹𐌽 𐌷𐌹𐌼𐌹𐌽𐌰𐌼
    𐍅𐌴𐌹𐌷𐌽𐌰𐌹 𐌽𐌰𐌼𐍉 𐌸𐌴𐌹𐌽
    𐌵𐌹𐌼𐌰𐌹 𐌸𐌹𐌿𐌳𐌹𐌽𐌰𐍃𐍃𐌿𐍃 𐌸𐌴𐌹𐌽𐍃
    𐍅𐌰𐌹𐍂𐌸𐌰𐌹 𐍅𐌹𐌻𐌾𐌰 𐌸𐌴𐌹𐌽𐍃
    𐍃𐍅𐌴 𐌹𐌽 𐌷𐌹𐌼𐌹𐌽𐌰 𐌾𐌰𐌷 𐌰𐌽𐌰 𐌰𐌹𐍂𐌸𐌰𐌹
    𐌷𐌻𐌰𐌹𐍆 𐌿𐌽𐍃𐌰𐍂𐌰𐌽𐌰 𐌸𐌰𐌽𐌰 𐍃𐌹𐌽𐍄𐌴𐌹𐌽𐌰𐌽 𐌲𐌹𐍆 𐌿𐌽𐍃 𐌷𐌹𐌼𐌼𐌰 𐌳𐌰𐌲𐌰
    𐌾𐌰𐌷 𐌰𐍆𐌻𐌴𐍄 𐌿𐌽𐍃 𐌸𐌰𐍄𐌴𐌹 𐍃𐌺𐌿𐌻𐌰𐌽𐍃 𐍃𐌹𐌾𐌰𐌹𐌼𐌰
    𐍃𐍅𐌰𐍃𐍅𐌴 𐌾𐌰𐌷 𐍅𐌴𐌹𐍃 𐌰𐍆𐌻𐌴𐍄𐌰𐌼 𐌸𐌰𐌹𐌼 𐍃𐌺𐌿𐌻𐌰𐌼 𐌿𐌽𐍃𐌰𐍂𐌰𐌹𐌼
    𐌾𐌰𐌷 𐌽𐌹 𐌱𐍂𐌹𐌲𐌲𐌰𐌹𐍃 𐌿𐌽𐍃 𐌹𐌽 𐍆𐍂𐌰𐌹𐍃𐍄𐌿𐌱𐌽𐌾𐌰𐌹
    𐌰𐌺 𐌻𐌰𐌿𐍃𐌴𐌹 𐌿𐌽𐍃 𐌰𐍆 𐌸𐌰𐌼𐌼𐌰 𐌿𐌱𐌹𐌻𐌹𐌽
    𐌿𐌽𐍄𐌴 𐌸𐌴𐌹𐌽𐌰 𐌹𐍃𐍄 𐌸𐌹𐌿𐌳𐌰𐌽𐌲𐌰𐍂𐌳𐌹 𐌾𐌰𐌷 𐌼𐌰𐌷𐍄𐍃
    𐌾𐌰𐌷 𐍅𐌿𐌻𐌸𐌿𐍃 𐌹𐌽 𐌰𐌹𐍅𐌹𐌽𐍃
    𐌱𐍂𐌿𐌽𐌰𐌹𐌼 𐌱𐌰𐌹𐍂𐌹𐌸 𐌱𐌰𐌹𐍂𐌺𐌰 𐌱𐍉𐌲𐌿𐌼
    𐌻𐌰𐌿𐌱𐌰𐌽𐍃 𐌻𐌹𐌿𐌱𐌰𐌽𐍃 𐌻𐌹𐌿𐌳𐌰𐌽𐌳𐌴𐌹
    𐌲𐌹𐌻𐍅𐌰𐌲𐍂𐍉𐌽𐌹 𐌲𐌻𐌹𐍄𐌼𐌿𐌽𐌾𐌰𐌽𐌳𐌴𐌹
    𐌱𐌰𐌲𐌼𐌴 𐌱𐌻𐍉𐌼𐌰 𐌱𐌻𐌰𐌿𐌰𐌽𐌳𐌴𐌹
    𐍆𐌰𐌲𐍂𐌰𐍆𐌰𐌷𐍃𐌰 𐌻𐌹𐌸𐌿𐌻𐌹𐌽𐌸𐌹
    𐍆𐍂𐌰𐌿𐌾𐌹𐌽𐍉𐌽𐌳𐌴𐌹 𐍆𐌰𐌹𐍂𐌲𐌿𐌽𐌹
    𐍅𐍉𐍀𐌾𐌰𐌽𐌳 𐍅𐌹𐌽𐌳𐍉𐍃 𐍅𐌰𐌲𐌾𐌰𐌽𐌳 𐌻𐌹𐌽𐌳𐍉𐍃
    𐌻𐌿𐍄𐌹𐌸 𐌻𐌹𐌼𐌰𐌼 𐌻𐌰𐌹𐌺𐌰𐌽𐌳𐌴𐌹
    𐍃𐌻𐌰𐌹𐌷𐍄𐌰 𐍂𐌰𐌹𐌷𐍄𐌰 𐌷𐍅𐌴𐌹𐍄𐌰𐍂𐌹𐌽𐌳𐌰
    𐍂𐌰𐌶𐌳𐌰 𐍂𐍉𐌳𐌴𐌹𐌸 𐍂𐌴𐌹𐍂𐌰𐌽𐌳𐌴𐌹
    𐌱𐌰𐌽𐌳𐍅𐌰 𐌱𐌰𐌹𐍂𐌷𐍄𐌰 𐍂𐌿𐌽𐌰 𐌲𐍉𐌳𐌰
    𐌸𐌹𐌿𐌳𐌰 𐌼𐌴𐌹𐌽𐌰 𐌸𐌹𐌿𐌸𐌾𐌰𐌽𐌳𐌴𐌹
    𐌰𐌽𐌳𐌰𐌽𐌰𐌷𐍄𐌹 𐌼𐌹𐌻𐌷𐌼𐌰𐌼 𐌽𐌴𐌹𐍀𐌹𐌸
    𐌻𐌹𐌿𐌷𐍄𐌴𐌹𐌸 𐌻𐌹𐌿𐌷𐌼𐌰𐌼 𐌻𐌰𐌿𐌷𐌼𐌿𐌽𐌹
    𐌻𐌰𐌿𐌱𐍉𐍃 𐌻𐌹𐌿𐌱𐌰𐌹 𐍆𐌻𐌹𐌿𐌲𐌰𐌽𐌳 𐌻𐌰𐌿𐍃𐌰𐌹
    𐍄𐌿𐌻𐌲𐌿𐍃 𐍄𐍂𐌹𐌲𐌲𐍅𐌰 𐍃𐍄𐌰𐌽𐌳𐌰𐌽𐌳𐌴𐌹
    𐌱𐌰𐌹𐍂𐌺𐌰 𐌱𐌰𐌶𐌰 𐌱𐌴𐌹𐌳𐌹𐌸 𐌱𐌻𐌰𐌹𐌺𐌰
    𐍆𐍂𐌰𐌿𐌾𐌹𐌽𐍉𐌽𐌳𐌴𐌹 𐍆𐌰𐌹𐍂𐌲𐌿𐌽𐌹
  4. V said

    In Ruby

    def encipher(key, text)
      words = key.scan(/\w+/)
      text.scan(/\w+/).flat_map do |word| do |char, i|
            .select { |word, _| word.chars.first == char }
            .last + 1
    def decipher(key, cipher)
      char_map = Hash[
          .map { |w, i| [i + 1, w[0]] }
  { |char| char_map[char] }.join
    encipher("now is the time" , "tin")
     => [4, 2, 1]
    decipher("now is the time",  [4, 2, 1])
      => "Tin"
    key = "lorem ipsum dolor sit amet, consectetur adipisicing elit"
    decipher(key, encipher(key, "lisa is ace"))
      => "lisaisace"

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: