Numeracci encryption

© Francisco Ruiz, 2015

This page implements the paper-and-pencil "Numeracci" cipher by F. Ruiz for those who wish to use a computer as a convenience. All steps can be performed by hand without excessive effort. The process is described in detail in this article, which also presents a letter-based variation called "Letteracci."

Numeracci uses normal text taken from a book or similar source to generate a one-time pad of sorts, which is then used to encrypt a message. A straddling checkerboard is used for encoding text into decimal digits. The cipher takes a piece of encoded key text that is one digit longer than the encoded plaintext, then feeds it into a lagged Fibonacci generator (LFG) in order to generate a pseudorandom keystream. This does not come close to a one-time pad, as BookPad does, because the entropy of the key text is only slightly larger than one-third of the entropy of a true random string of the same length, but it is still a respectable entropy, roughly equivalent to 1.58 bits per character. Numeracci involves the same number of sums and subtractions as BookPad but requires half as much text encoding, which might be an advantage. In order to provide more resistance against brute force and approach the perfect undecipherability of a one-time pad, a pseudo-Shannon compression can be applied to the key text before it is used to make a keystream; this compression has the effect of using three times as many words from the key text, resulting in a higher entropy.

The process is nearly identical for encryption and decryption. The difference is that ciphertext might have an extra digit that would not be there if it was encoded plaintext; this extra digit is decoded back as ! or ?. Numbers in plaintext are converted to letters and then encoded.


Step 1. Encoding set-up

To cover the case where the encoding pattern depends on the key text taken from a book or similar source, let us enter the key text ahead of everything else, in the box below, which is shaded blue like all the other boxes where you can enter something. This key text will be used to encrypt the plaintext (or decrypt the ciphertext) below, and then it will never be used again.

Key Text

We will encode this into decimal digits later on. For the time being, we need to decide whether the default "Arsenio" checkerboard encoding is to be used, or a similar one derived from the key text. This is the Arsenio checkerboard:

    1 2 3 4 5 6 7 8 9 0
  | A R S E N I O +
9 | B C D F G H J K L M
0 | P Q T U V W X Y Z =

where "+" designates a space and "=" a period or other important punctuation. To use the checkerboard, simply replace each letter, space or strong punctuation with a single-digit (top) or two-digit code (first left, then top digit), as shown on the checkerboard. Examples: s = 3, h = 96, p = 01.

A key-derived checkerboard would be made this way: count the number of letters in the first two words of the key text (mod 10); these become N1 and N2; if there is only one word or all the words have equal length, take N2=N1+1 mod 10. Then order the letters in "arsenio" plus the space, as they appear in the first sentence of the key text (before the first period) and assign to them the single numerals 1-9,0, skipping N1 and N2. Do the same for the rest of the letters in the English alphabet, placing them in the two rows headed by N1 and N2, then follow with the '=' character, and then the letters that are not in the key text, in reverse alphabetical order (if they are part of "arsenio", they go on the top row, in reverse "arsenio" order). The encoding pattern is displayed below (+ represents a space, = a generic punctuation mark).

Encoding Pattern


Let us now tell the program what we want to do by checking one of the two buttons below. The difference is the conversion between text and digits, which considers spaces and periods as part of the text when encrypting, but ignores them when decrypting.

     Encrypt     Decrypt

We must decide whether the key text will be used as-is, or a pseudo-Shannon compression will be applied first. This consists of taking only the first letter from each word, for words containing four or fewer letters, or the first and last, for longer words, ignoring spaces and punctuation:

     No compression     Apply compression

And let us also decide whether or not we are basing the encoding on the key text. Warning: encrypted messages using default encoding can be altered by an adversary, plus the key text can be recovered if the plaintext is known.

     Key text-derived encoding     Default encoding


Step 2. Plaintext encoding / Ciphertext preparation

Now we write the plaintext that we wish to encrypt, which will be converted to lowercase. Punctuation marks other than periods, colons, exclamations and interrogations are ignored. Spaces are encoded as high-frequency letters. Diacritical marks (accents) are ignored. If there are any numbers, they are first converted to letters as in a = 1, ... i = 9, j = 0. Plaintext numbers are not decoded back upon decryption, but hopefully the user can spot them easily.

Plaintext / Ciphertext as letters

And this is the same text, encoded as decimal digits. If now you type into the Encoded Plaintext box, its contents are automatically decoded and the result placed in the Plaintext box. When decrypting a ciphertext already encoded as digits, we start with the next box.

Encoded Plaintext / Ciphertext as digits

If a key shift and/or MAC are embedded in ciphertext, they are now extracted and placed in the shift box below and the embeded MAC box at the bottom of the page. This is not done for encoded plaintext.


Step 3. Keystream generation

The next step is to generate the keystream. In this version, we can enter a variable number of LFG rows in the box below. Typically, 4 rows are enough.

LFG rows

Allowed values are 1 to 9

We begin by taking a piece of the encoded key text that is one digit longer than the encoded plaintext, which will become the seed for the LFG. If the key text is not long enough, it will be repeated and a warning will appear below this line.

This is where the warning will appear


Now the seed is used to initialize a lagged Fibonacci generator, where each digit after the seed is the carryless sum of the previous digit and the one located a number of spaces equal to the encoded plaintext length before the current digit. This is best done by rows, adding the numbers immediately to the left of the one we are filling and the one above it. We stop when the set number of rows are completed. The process is initialized by putting the seed in row one, except for the last digit, which becomes the first in row two.

And take the last row as the keystream.


Information about keystream quality will appear here


Step 4. Encrypted Ciphertext / Decrypted Plaintext

Finally, we subtract, again without carries, the encoded plaintext (encoded ciphertext, when decrypting) from the keystream, resulting in the raw ciphertext below (plaintext, when decrypting), which is ready to be sent out. The next step only serves to convert back to letters. Because this is output, the cells are shaded green.

Raw Ciphertext / Encoded Plaintext

And finally, we decode the result back to letters using the encoding pattern. When encrypting, it is possible to find a single N1 or N2 digit at the end. In this case, we convert N1='!' and N2='?'

Text-based Ciphertext / Final Plaintext