Chaocipher

July 6, 2010

We begin with a function that shifts characters left in a sequence. Shift preserves the beginning and ending portions of the sequence (either of which may be null, depending on the parameters) and cycles the middle portion using an auxiliary function cycle:

(define (shift first past offset str)
  (define (cycle str offset)
    (append (drop offset str) (take offset str)))
  (let ((str (string->list str)))
    (list->string (append
      (take first str)
      (cycle (take (- past first) (drop first str)) offset)
      (drop past str)))))

Then shift-left and shift-right apply the rules stated above:

(define (shift-left n str)
  (shift 1 14 1
    (shift 0 26 n str)))

(define (shift-right n str)
  (shift 2 14 1
    (shift 0 26 1
      (shift 0 26 n str))))

The cipher function loops through the input text, processing each character and shifting the two sequences. The enciphering? flag chooses the appropriate disk:

(define (cipher left right enciphering? str)
  (let loop ((old (string->list str))
             (left left) (right right) (new '()))
    (if (null? old)
        (list->string (reverse new))
        (let ((n (string-index (car old) (if enciphering? right left))))
          (loop (cdr old) (shift-left n left) (shift-right n right)
                (cons (string-ref (if enciphering? left right) n) new))))))

Given cipher, the functions that actually perform enciphering and deciphering are trivial:

(define (encipher left right str) (cipher left right #t str))
(define (decipher left right str) (cipher left right #f str))

Here’s an example:

> (encipher ct pt "WELLDONEISBETTERTHANWELLSAID")
"OAHQHCNYNXTSZJRRHJBYHQKSOUJY"
> (decipher ct pt "OAHQHCNYNXTSZJRRHJBYHQKSOUJY")
"WELLDONEISBETTERTHANWELLSAID"

We used take, drop and string-index from the Standard Prelude. You can run the program at http://programmingpraxis.codepad.org/W6om4hgd.

Advertisement

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 Reply

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

WordPress.com Logo

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

Facebook photo

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

Connecting to %s

%d bloggers like this: