PolyCrypt Encryption

© Francisco Ruiz, 2023

This document expands on the Human encryption mode built into PassLok Privacy and URSA, which is designed to be performed by hand if necessary. PassLok Privacy is available from https://passlok.com/app, URSA from https://passlok.com/ursa. In addition to performing field encryption and decryption, PolyCrypt is designed as a sandbox so users can experiment with different techniques that have ben used in human-computable ciphers over the centuries: substitutions, transpositions, and key additions or subtractions. Statistical analyses are performed on the result. PolyCrypt takes as many as five alphabetic keys: the first three are for substitutions, the fourth as a seed for a keystream, or as a seed mask for a random seed that is attached to the ciphertext, the fifth for a columnar transposition applied to the ciphertext.

The process begins by concentrating the entropy in the first three keys by means of serpentine operations on a Tabula Recta. Then a pseudo-random keystream is produced starting from the seed by means of a lagged Fibonacci generator that uses the Tabula Recta whose headers perform the substitutions automatically. Finally the processed plaintext (the method uses a trick to preserve spaces, and there is an optional random cut with reversal of the two parts) is combined with the keystream to produce the ciphertext. To decrypt, the first three keys are compressed and the random seed, if any, is extracted from the ciphertext, which allows us to reproduce the same pseudo-random keystream. This is then combined with the ciphertext to recreate the plaintext (and then the trick is reversed to get the spaces back, and the cut is also reversed).

The steps to encrypt or decrypt in more detail:

First take keys 1, 2, and 3 with spaces, puctuation, and diacritics removed, and write each of them, one letter per cell, in a table containing 25 colums. When the first row is filled, continue filling the second, and so on until all letters have been written. Then do the following for each resulting column: look the first letter on the top of a straight Tabula Recta (alphabets on the edges are not mixed), then down that column until you find the second letter(if there is one), then left or right until you find the third letter (if there is one), and so on until the last letter is found, and then again perpendicularly to read of the result at top, bottom, or one of the sides. Write down the result for each column, and then you get the compressed key.

Then we generate a scrambled alphabet for each compressed key. The process is simple: 1, take the compressed key and write down new letters in the order they appear; if a letter in the text key has already been written, write instead the first letter before it in the alphabet that is still available (wrap around to the end if needed); 2, then write the rest of the alphabet in reverse order. Place alphabet 1 at the top of the Tabula Recta, alphabet 2 on the left side, alphabet 3 on the right side and at the bottom. From now on, we will look up letters on these rather than of the original headers.

If we are decrypting and there is a transposition, it should be reversed before doing anything else. The process is detailed below. After the plaintext is optionally processed during encryption —cut at a random location, followed by reversal of the parts; all letters converted to capitals; accented letters replaced by their non-accented versions; numbers in plaintext converted to letters as in 0=A,1=B,...9=J, but not converted back, Q's turned into K's, and then spaces and punctuation (except commas, quotes, and suchlike) turned into Q's— we do the main encrypt/decrypt process, which goes like this:

  1. If encrypting, write a string of random letters as long as key 4, which will become the random seed, and then the processed plaintext immediately to its right. When decrypting, just write the ciphertext.
  2. Take key 4, remove all spaces, punctuation, and diacritics, and write it at the start of the line below the plaintext or ciphertext.
  3. If decrypting, extract the random seed from the ciphertext by following the process in step 5 just for those few letters, bearing in mind that you look up the top row letters on the left or right of the Tabula Recta, and write into the bottom row the letter found at top or bottom of the table. Skip this step if encrypting.
  4. Extend the seed (start of the first row if encrypting, of the third row if decrypting) into a keystream so all spaces in the second row are filled, this way: Look up the first keystream letter still available at the top of the Tabula Recta, then down until you find the letter that follows it in the keystream, then sideways to find the next, then up or down again to find the letter that follows that one, and so forth until you have visited all the letters that are going to be combined to make the new keystream letter. Read that letter at the right or bottom alphabet perpendicularly to the last movement, and then write it in the next available position on the second row. Mark the first keystream letter you looked up, so next time you start with the next letter. Notice that when encrypting you start taking letters from the top row, but when you run out of random seed you continue taking them from the second row, never from the plaintext itself.
  5. Now when encrypting do the following for each pair of letters consisting of a top row letter and the letter right below it: Look up the plaintext letter at the top or bottom of the Tabula Recta, then go down or up until you find the letter below, then sideways to read a letter on the right or left alphabet, which you will write below the pair of letters you involved in this operation, forming the ciphertext. When decrypting you do the same but with the alphabets reversed, that is, you look up the top row letter on the left or right, and read off the result at top or bottom.

If encrypting and you want to add a transposition, this is the time to do it. Write key 5 and number the characters according to their position in the regular alphabet (1 for the first encountered, then 2, etc.). Start numbering repeated letters from the right. Then write the ciphertext by rows below key 5, and read it by columns starting from the columns labeled 1, then 2, and so forth. If decrypting, you now need to undo the plaintext processing. That is: undo the cut, if any, and if spaces were preserved replace every Q with a space, or a period and a space if there are two Q's in a row; replace every instance of "KU" followed by a vowel with "QU". The result won't be exactly the original plaintext, but it will be quite readable.

Tabula Recta

Key compression is done using this table before the alphabets at the edges are mixed (you can use the first row and column for this purpose, even after those change). The rest of the operations are done using the mixed alphabets deriving from the keys, which are added to this table automatically. Here's a Tabula Recta as a graphic ready to print, on gridded paper: https://passlok.com/human/tabula.png

  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z  
---------------------------------------------------
A | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z | A
B | B C D E F G H I J K L M N O P Q R S T U V W X Y Z A | B
C | C D E F G H I J K L M N O P Q R S T U V W X Y Z A B | C
D | D E F G H I J K L M N O P Q R S T U V W X Y Z A B C | D
E | E F G H I J K L M N O P Q R S T U V W X Y Z A B C D | E
F | F G H I J K L M N O P Q R S T U V W X Y Z A B C D E | F
G | G H I J K L M N O P Q R S T U V W X Y Z A B C D E F | G
H | H I J K L M N O P Q R S T U V W X Y Z A B C D E F G | H
I | I J K L M N O P Q R S T U V W X Y Z A B C D E F G H | I
J | J K L M N O P Q R S T U V W X Y Z A B C D E F G H I | J
K | K L M N O P Q R S T U V W X Y Z A B C D E F G H I J | K
L | L M N O P Q R S T U V W X Y Z A B C D E F G H I J K | L
M | M N O P Q R S T U V W X Y Z A B C D E F G H I J K L | M
N | N O P Q R S T U V W X Y Z A B C D E F G H I J K L M | N
O | O P Q R S T U V W X Y Z A B C D E F G H I J K L M N | O
P | P Q R S T U V W X Y Z A B C D E F G H I J K L M N O | P
Q | Q R S T U V W X Y Z A B C D E F G H I J K L M N O P | Q
R | R S T U V W X Y Z A B C D E F G H I J K L M N O P Q | R
S | S T U V W X Y Z A B C D E F G H I J K L M N O P Q R | S
T | T U V W X Y Z A B C D E F G H I J K L M N O P Q R S | T
U | U V W X Y Z A B C D E F G H I J K L M N O P Q R S T | U
V | V W X Y Z A B C D E F G H I J K L M N O P Q R S T U | V
W | W X Y Z A B C D E F G H I J K L M N O P Q R S T U V | W
X | X Y Z A B C D E F G H I J K L M N O P Q R S T U V W | X
Y | Y Z A B C D E F G H I J K L M N O P Q R S T U V W X | Y
Z | Z A B C D E F G H I J K L M N O P Q R S T U V W X Y | Z
---------------------------------------------------
  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z  

Step 1. Tabula preparation

The straight alphabet is used if a box is left empty for keys 1 through 3.

Key 1 (top substitution)

Key 2 (left substitution)

Key 3 (right and bottom substitution)

If you want to use for key 4 a string different from key 1, write it in this box, otherwise key 1 will be used. This key should be at least as long as the number of letters to be used to generate the keystream. The checkbox tells the program whether to use this key as a mask for a random seed, or as the seed itself.

Key 4 (seed)

 Random Seed

Key 5 (transposition)

The first step is to compress keys 1, 2, and 3 by writing them into rows of 25 letters and performing a serpentine operation, as described above, on each resulting column. The following three boxes show the operations involved in compressing both keys, plus the resulting mixed alphabets:

Compressed Key 1 -> Mixed Alphabet 1

Compressed Key 2 -> Mixed Alphabet 2

Compressed Key 3 -> Mixed Alphabet 3

We make scrambled alphabets out of keys 1, 2, and 3 which are then placed at the top (1), left (2), right (3), and bottom (3) sides of the Tabula Recta, by doing the following with each compressed key: take each key and write the different letters of the alphabet in the order they appear in the compressed key, if a letter has been used already, write instead the immediately preceding letter in the normal alphabet not yet chosen; if there are letters that did not appear in the key, write them now in reverse alphabetical order. The resulting alphabets are displayed on the bottom rows of the preceding work tables, and directly on the Tabula Recta.

Since the process is somewhat different for encryption and decryption, we have to tell the program what we want to do. This is also a good spot to tell it how many previous keystream letters to involve in making a new keystream letter (positive integer smaller or equal to key 4 length).

     Encrypt     Decrypt

Letters used to make keystream:  

 

Step 2. Plaintext preparation

Plaintext / Ciphertext

 Do cut    Preserve spaces

Encryption: by checking the first box above, we perform an optional "cut" at a random location, and write the two parts in reverse order, with the word "polycrypt" between them so the cut location can be found upon decryption. The plaintext then is converted to the following after everything is turned into uppercase, diacritics are removed and, optionally when encrypting (second checkbox), Q's are replaced by K's and spaces and selected punctuation are replaced by Q's.

Decryption: the transposition of the ciphertext is reversed first of all, using key 5 to determine the order in which columns were read on encryption. Details on this are given below. If key 5 is empty this step is skipped.

Processed Plaintext / Ciphertext

 

Step 3. Encryption / Decryption

In order to obtain the ciphertext we generate the table below, following the instructions at the top of this page. The top row is the input, the middle row the keystream, the bottom row the output.

Work table

Information about output randomness will appear here

 

Step 4. Encrypted Ciphertext / Decrypted Plaintext

When encrypting, a transposition is done if key 5 is not empty. First we must generate a permutation order from key 5 this way: Write key 5 and find the letter on it that appears first in the alphabet, and write a 1 above it, then write a 2 above the letter that appears next, and so on. If a letter is repeated, write the number over the rightmost letter, then the one on its left, and so on. Write the ciphertext below this by rows of the same length as key 5. To complete the transposition, read the ciphertext letters by consecutively numbered columns, starting from column 1. If key 5 contains a number instead of letters, simply write the ciphertext by rows of that length, and read by columns from left to right. Finish off by splitting the result into five-letter codegroups.

When decrypting, we now undo the plaintext cut, if any, by searching for the word "polycrypt" and switching the order of the texts on either side of it. Then if spaces are to be recovered (checkbox by plaintext input) replace every "QQ" with a period plus a space, every single "Q" with a single space, and every instance of "KU" followed by a vowel with "QU" resulting in the plaintext in the bottom box.

Raw Ciphertext / Plaintext

Formatted Output

 

Bonus: error correction

It is rather easy to make a mistake when encrypting a text by hand, which will cause problems for decryption. There isn't much that can be done if the error is made when making the scrambled alphabets for the Tabula Recta, encrypting the random seed, or during the transposition because this would be equivalent to using a different set of keys from what the recipients have, and this algorithm doesn't give much of a clue when the keys are close to the correct ones but not quite. On the other hand, it is very easy to spot the mistake and fix it on decryption if the error was made in the operation where the keystream and the plaintext are combined, because then an error in one letter affects only one letter in the ciphertext, and the rest can be decrypted normally. The interesting case is when a mistake is made while processing the keystream. Then almost all the keystream after the error will be affected, resulting in gibberish in the decrypted plaintext.

The buttons below help with this case by intentionally adding errors into the keystream during decryption, while watching the effect on the decrypted plaintext. Usage: 1. Mark the spot in the Formatted Output box where the error is to be introduced by selecting the first wrong character or simply clicking in front of it. 2. Press the Next button repeatedly until the decrypted text after that spot makes sense (each press increments the error added to that character by one). 3. If there appears to be more errors after that, click the Save button to save progress and repeat for the next error, starting from step 1. 4. If the plaintext after the marked spot is not fixed after all possible error values have been tried with the Next button (26 times), chances are the spot chosen for the previous fix was not correct; click the Back button and try doing it again. The box at the bottom displays the errors being introduced.