Chaocipher

July 6, 2010

In 1918, John Byrne invented a two-disk cryptographic machine, which he called a chaocipher; he drew up blueprints, but was unsuccessful in his efforts to sell the machine to the US Signal Corps and Navy. He left several challenge messages in his 1954 autobiography, but no one successfully deciphered the messages. Recently, following the death of Byrne’s son, the son’s widow donated Byrne’s complete archives, including a mock-up of the machine, to the National Cryptologic Museum at Fort Meade, Maryland. Last Friday, Moshe Rubin published the first public description of the chaocipher algorithm.

The algorithm uses two key sequences, one for cipher-text and one for plain-text. Encryption and decryption look up the desired character on one sequence and report the corresponding character on the other sequence, working from plain-text to cipher-text for encryption and from cipher-text to plain-text for decryption.

After each character, both sequences are permuted, each by a different method. Thus, the chaocipher is similar to an autokey cipher, because the key is modified according to the plain-text.

The left disk, which normally represents the cipher-text, is permuted in two steps. First, the entire alphabet is shifted left as far as cipher-text of the current character (so the current cipher-text character becomes the first character in the sequence), with the shifted-off portion of the sequence reattached at the end. Second, the second through fourteenth characters are shifted left one character, and cycled; the third character becomes the second, the fourth character becomes the third, and so on, until the fourteenth character becomes the thirteenth and the second character becomes the fourteenth. For instance, given the sequence HXUCZVAMDSLKPEFJRIGTWOBNYQ and the current character P, the entire sequence is shifted to bring P to the front, giving PEFJRIGTWOBNYQHXUCZVAMDSLK, then the second through fourteenth characters are shifted to move E after Q, giving PFJRIGTWOBNYQEHXUCZVAMDSLK. Byrne invented the terms zenith and nadir to represent the first and fourteenth characters, Rubin refers to zenith and zenith+13, but we’ll just call them by their ordinal positions in the sequence.

The right disk, which normally represents the plain-text, is permuted in three steps. First, the entire alphabet is shifted left as far as the plain-text of the current character (so the current plain-text character becomes the first character in the sequence), with the shifted-off portion of the sequence reattached at the end. Second, the first character is shifted to the end (so the current plain-text character becomes the last character in the sequence). Third, the third through fourteenth characters are shifted left one character, and cycled, similar to the left disk except for the different starting position. For instance, given the sequence PTLNBQDEOYSFAVZKGJRIHWXUMC and the current character A, the final sequence is VZGJRIHWXUMCPKTLNBQDEOYSFA.

Thus, the encryption of WELLDONEISBETTERTHANWELLSAID, given the above cipher-text and plain-text sequences, is OAHQHCNYNXTSZJRRHJBYHQKSOUJY.

Your task is to write functions that perform encryption and decryption according to the algorithm given above. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

5 Responses to “Chaocipher”

  1. […] Praxis – Chaocipher By Remco Niemeijer In today’s Programming Praxis we have another cipher on our hands, called chaocipher. The provided Scheme […]

  2. Remco Niemeijer said

    My Haskell solution (see http://bonsaicode.wordpress.com/2010/07/06/programming-praxis-chaocipher/ for a version with comments):

    import Control.Arrow
    import Data.List
    
    seek :: Int -> [a] -> [a]
    seek to = uncurry (flip (++)) . splitAt to
    
    shift :: Int -> Int -> [a] -> [a]
    shift from to = (\((a,b),c) -> a ++ seek 1 b ++ c) . 
                    first (splitAt from) . splitAt to
    
    cipher :: Eq a => Bool -> [a] -> [a] -> [a] -> [a]
    cipher _ _ _ []     = []
    cipher e l r (x:xs) = to !! i : cipher e (shift 1 14 $ seek i l)
                          (shift 2 14 . shift 0 26 $ seek i r) xs
        where Just i = elemIndex x from
              (from, to) = if e then (r, l) else (l, r)
    
    encipher, decipher :: Eq a => [a] -> [a] -> [a] -> [a]
    encipher = cipher True
    decipher = cipher False
    
  3. razvan said

    My version, in Java:

    package chaocipher;
    
    import java.util.LinkedList;
    
    public class Chaocipher {
    
        private LinkedList<Character> cipher, plain;
        private final int SIZE;
    
        public Chaocipher(String ciphertext, String plaintext) {
            cipher = new LinkedList<Character>();
            plain = new LinkedList<Character>();
            for(int i=0; i<ciphertext.length(); i++) {
                cipher.addLast(ciphertext.charAt(i));
                plain.addLast(plaintext.charAt(i));
            }
            SIZE = cipher.size();
        }
    
        public String encrypt(String text) {
            StringBuilder sb = new StringBuilder();
            for(int i=0; i<text.length(); i++) {
                char plainChar = text.charAt(i);
                char cipherChar = encrypt(plainChar);
                sb.append(cipherChar);
                rotateDisks(cipherChar, plainChar);
            }
            return sb.toString();
        }
    
        public String decrypt(String text) {
            StringBuilder sb = new StringBuilder();
            for(int i=0; i<text.length(); i++) {
                char cipherChar = text.charAt(i);
                char plainChar = decrypt(cipherChar);
                sb.append(plainChar);
                rotateDisks(cipherChar, plainChar);
            }
            return sb.toString();
        }
    
        private char encrypt(char ch) {
            int i = plain.indexOf(ch);
            return cipher.get(i);
        }
    
        private char decrypt(char ch) {
            int i = cipher.indexOf(ch);
            return plain.get(i);
        }
    
        private void rotateDisks(char cipherChar, char plainChar) {
            int ind = cipher.indexOf(cipherChar);
            for(int i=0; i<ind; i++) {
                char ch = cipher.remove(0);
                cipher.addLast(ch);
            }
            char ch = cipher.remove(1);
            cipher.add(13, ch);
    
            ind = plain.indexOf(plainChar);
            for(int i=0; i<ind; i++) {
                ch = plain.remove(0);
                plain.addLast(ch);
            }
            ch = plain.remove(0);
            plain.addLast(ch);
            ch = plain.remove(2);
            plain.add(13, ch);
        }
    }
    

    And the main class is:

    package chaocipher;
    
    public class Main {
    
        public static void main(String[] args) {
            Chaocipher ch = new Chaocipher("HXUCZVAMDSLKPEFJRIGTWOBNYQ",
                    "PTLNBQDEOYSFAVZKGJRIHWXUMC");
            System.out.println(ch.encrypt("WELLDONEISBETTERTHANWELLSAID"));
        }
    
    }
    

    And the output is as expected, i.e. OAHQHCNYNXTSZJRRHJBYHQKSOUJY.

  4. Charles said

    I am a student learning about encryption ciphers, and after attempting to run the java code above, I noticed the decrypt function does not work as expected. I have copied the source code directly from here, so there is no error in typing, and I will post the output of the decrypt function of the encryption of WELLDONEISBETTERTHANWELLSAID.

    WELLDONEISBETTERTHANWELLSAID

    OAHQHCNYNXTSZJRRHJBYHQKSOUJY

    XHTJNNTWNDTWSBFVRGLSLSSCXAZY

    HXUCZVAMDSLKPEFJRIGTWOBNYQ
    PTLNBQDEOYSFAVZKGJRIHWXUMC

    the first line is the line that was to be encrypted. the second line is what is to be expected from the encryption function. the third line is the unexpected result of the decryption function, and the fourth and fifth lines are the ciphertext and plaintext that are the arguments passed in through the Chaocipher object

  5. I know this is old, but to answer Charles (and anyone else who comes along)…

    To use the java solution one needs to create a second Chaocipher object for decryption. Alternatively you could do something weird like reset the cipher and plain texts after each encryption/decryption, but that sort of ruins the complexity of the thing.

Leave a comment