# Chaocipher

Chaocipher is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Description

The Chaocipher was invented by J.F.Byrne in 1918 and, although simple by modern cryptographic standards, does not appear to have been broken until the algorithm was finally disclosed by his family in 2010.

The algorithm is described in this paper by M.Rubin in 2010 and there is a C# implementation here.

The task is to code the algorithm in your language and to test that it works with the plaintext 'WELLDONEISBETTERTHANWELLSAID' used in the paper itself.

## C

Translation of: Kotlin
`#include <stdio.h>#include <string.h>#include <stdlib.h> #define TRUE 1#define FALSE 0 typedef int bool;typedef enum { ENCRYPT, DECRYPT } cmode; const char *l_alphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ";const char *r_alphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC"; void chao(const char *in, char *out, cmode mode, bool show_steps) {    int i, j, index;    char store;    size_t len = strlen(in);    char left[27], right[27], temp[27];    strcpy(left, l_alphabet);    strcpy(right, r_alphabet);    temp[26] = '\0';     for (i = 0; i < len; ++i ) {        if (show_steps) printf("%s  %s\n", left, right);        if (mode == ENCRYPT) {            index = strchr(right, in[i]) - right;            out[i] = left[index];        }        else {            index = strchr(left, in[i]) - left;            out[i] = right[index];        }        if (i == len - 1) break;         /* permute left */         for (j = index; j < 26; ++j) temp[j - index] = left[j];        for (j = 0; j < index; ++j) temp[26 - index + j] = left[j];        store = temp[1];        for (j = 2; j < 14; ++j) temp[j - 1] = temp[j];        temp[13] = store;        strcpy(left, temp);         /* permute right */         for (j = index; j < 26; ++j) temp[j - index] = right[j];        for (j = 0; j < index; ++j) temp[26 - index + j] = right[j];        store = temp[0];        for (j = 1; j < 26; ++j) temp[j - 1] = temp[j];        temp[25] = store;        store = temp[2];        for (j = 3; j < 14; ++j) temp[j - 1] = temp[j];        temp[13] = store;        strcpy(right, temp);    }} int main() {    const char *plain_text = "WELLDONEISBETTERTHANWELLSAID";    char *cipher_text = malloc(strlen(plain_text) + 1);    char *plain_text2 = malloc(strlen(plain_text) + 1);    printf("The original plaintext is : %s\n", plain_text);    printf("\nThe left and right alphabets after each permutation"           " during encryption are :\n\n");    chao(plain_text, cipher_text, ENCRYPT, TRUE);    printf("\nThe ciphertext is : %s\n", cipher_text);    chao(cipher_text, plain_text2, DECRYPT, FALSE);    printf("\nThe recovered plaintext is : %s\n", plain_text2);    free(cipher_text);    free(plain_text2);    return 0;}`
Output:
```The original plaintext is : WELLDONEISBETTERTHANWELLSAID

The left and right alphabets after each permutation during encryption are :

HXUCZVAMDSLKPEFJRIGTWOBNYQ  PTLNBQDEOYSFAVZKGJRIHWXUMC
ONYQHXUCZVAMDBSLKPEFJRIGTW  XUCPTLNBQDEOYMSFAVZKGJRIHW
ZILGMTONQXCVARDBSKWPEYHUFJ  LNBIMSAVKGQDJOERYHFWZXUCPT
JILGMTONQXCVAZRDBSKWPEYHUF  LNIMSAVKGQDJOBERYHFWZXUCPT
RBSKWPEYHUFJIDLGMTONQXCVAZ  RYFWZXUCPTLNIHMSAVKGQDJOBE
RSKWPEYHUFJIDBLGMTONQXCVAZ  YFZXUCPTLNIHMWSAVKGQDJOBER
HFJIDBLGMTONQUXCVAZRSKWPEY  LNHMWSAVKGQDJIOBERYFZXUCPT
JDBLGMTONQUXCIVAZRSKWPEYHF  MWAVKGQDJIOBESRYFZXUCPTLNH
BGMTONQUXCIVALZRSKWPEYHFJD  VKQDJIOBESRYFGZXUCPTLNHMWA
YFJDBGMTONQUXHCIVALZRSKWPE  HMAVKQDJIOBESWRYFGZXUCPTLN
HIVALZRSKWPEYCFJDBGMTONQUX  RYGZXUCPTLNHMFAVKQDJIOBESW
QXHIVALZRSKWPUEYCFJDBGMTON  SWYGZXUCPTLNHRMFAVKQDJIOBE
KPUEYCFJDBGMTWONQXHIVALZRS  NHMFAVKQDJIOBRESWYGZXUCPTL
SPUEYCFJDBGMTKWONQXHIVALZR  NHFAVKQDJIOBRMESWYGZXUCPTL
OQXHIVALZRSPUNEYCFJDBGMTKW  WYZXUCPTLNHFAGVKQDJIOBRMES
UEYCFJDBGMTKWNOQXHIVALZRSP  GVQDJIOBRMESWKYZXUCPTLNHFA
JBGMTKWNOQXHIDVALZRSPUEYCF  OBMESWKYZXUCPRTLNHFAGVQDJI

The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY

The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
```

## Factor

`USING: arrays combinators fry io kernel locals math namespacesprettyprint sequences sequences.extras strings ;IN: rosetta-code.chaocipher CONSTANT: zenith 0CONSTANT: nadir  13 SYMBOLS: l-alphabet r-alphabet last-index ; : init-alphabets ( -- )    "HXUCZVAMDSLKPEFJRIGTWOBNYQ" l-alphabet    "PTLNBQDEOYSFAVZKGJRIHWXUMC" r-alphabet [ set ] [email protected] ; : zero-alphabet ( seq -- seq' )    last-index get rotate ; : 3append ( a b c d -- abcd )    append append append ; :: permute-l-alphabet ( -- )    l-alphabet get zero-alphabet dup    zenith 1 + swap nth :> extracted-char    {        [ 1 head ]        [ nadir 1 + head 2 tail ]        [ drop extracted-char 1string ]        [ nadir 1 + tail ]    } cleave    3append l-alphabet set ; :: permute-r-alphabet ( -- )    r-alphabet get zero-alphabet    1 rotate dup    zenith 2 + swap nth :> extracted-char    {        [ 2 head ]        [ nadir 1 + head 3 tail ]        [ drop extracted-char 1string ]        [ nadir 1 + tail ]    } cleave    3append r-alphabet set ; : encipher-char ( char alpha1 alpha2 -- char' )    '[ _ get index dup last-index set _ get nth ] call ; : encipher ( str quot -- str' )    [ permute-l-alphabet permute-r-alphabet ] compose map    init-alphabets ; inline : encrypt ( str -- str' )    [ r-alphabet l-alphabet encipher-char ] encipher ; : decrypt ( str -- str' )    [ l-alphabet r-alphabet encipher-char ] encipher ; : main ( -- )    init-alphabets    "WELLDONEISBETTERTHANWELLSAID" encrypt dup decrypt    [ print ] [email protected] ; MAIN: main`
Output:
```OAHQHCNYNXTSZJRRHJBYHQKSOUJY
WELLDONEISBETTERTHANWELLSAID
```

## Go

Translation of: Kotlin
`package main import(    "fmt"    "strings"    "unicode/utf8") type Mode int const(    Encrypt Mode = iota    Decrypt) const(    lAlphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"    rAlphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC") func Chao(text string, mode Mode, showSteps bool) string {    len := len(text)    if utf8.RuneCountInString(text) != len {        fmt.Println("Text contains non-ASCII characters")        return ""    }    left  := lAlphabet    right := rAlphabet    eText := make([]byte, len)    temp  := make([]byte, 26)     for i := 0; i < len; i++ {        if showSteps {            fmt.Println(left, " ", right)        }        var index int        if mode == Encrypt {            index = strings.IndexByte(right, text[i])            eText[i] = left[index]        } else {            index = strings.IndexByte(left, text[i])            eText[i] = right[index]        }        if i == len - 1 {            break        }         // permute left        for j := index; j < 26; j++ {            temp[j - index] = left[j]        }        for j := 0; j < index; j++ {            temp[26 - index + j] = left[j]        }        store := temp[1]        for j := 2; j < 14; j++ {            temp[j - 1] = temp[j]        }        temp[13] = store        left = string(temp[:])         // permute right         for j := index; j < 26; j++ {            temp[j - index] = right[j]        }        for j := 0; j < index; j++ {            temp[26 - index + j] = right[j]        }        store = temp[0]        for j := 1; j < 26; j++ {            temp[j - 1] = temp[j]        }        temp[25] = store        store = temp[2]        for j := 3; j < 14; j++ {            temp[j - 1] = temp[j]        }        temp[13] = store        right = string(temp[:])    }     return string(eText[:])} func main() {    plainText := "WELLDONEISBETTERTHANWELLSAID"    fmt.Println("The original plaintext is :", plainText)    fmt.Print("\nThe left and right alphabets after each permutation ")    fmt.Println("during encryption are :\n")    cipherText := Chao(plainText, Encrypt, true)    fmt.Println("\nThe ciphertext is :",  cipherText)    plainText2 := Chao(cipherText, Decrypt, false)    fmt.Println("\nThe recovered plaintext is :", plainText2)}`
Output:
```Same as Kotlin entry.
```

## Kotlin

This is based on the C# implementation referred to in the task description, except that the encrypt and decrypt operations are combined into a single method.

`// Version 1.2.40 enum class Mode { ENCRYPT, DECRYPT } object Chao {    private val lAlphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"    private val rAlphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC"     fun exec(text: String, mode: Mode, showSteps: Boolean = false): String {        var left  = lAlphabet        var right = rAlphabet        val eText = CharArray(text.length)        val temp  = CharArray(26)         for (i in 0 until text.length) {            if (showSteps) println("\$left  \$right")            var index: Int            if (mode == Mode.ENCRYPT) {                index = right.indexOf(text[i])                eText[i] = left[index]            }            else {                index = left.indexOf(text[i])                eText[i] = right[index]            }            if (i == text.length - 1) break             // permute left             for (j in index..25) temp[j - index] = left[j]            for (j in 0 until index) temp[26 - index + j] = left[j]            var store = temp[1]            for (j in 2..13) temp[j - 1] = temp[j]            temp[13] = store            left = String(temp)             // permute right             for (j in index..25) temp[j - index] = right[j]            for (j in 0 until index) temp[26 - index + j] = right[j]            store = temp[0]            for (j in 1..25) temp[j - 1] = temp[j]            temp[25] = store            store = temp[2]            for (j in 3..13) temp[j - 1] = temp[j]            temp[13] = store            right = String(temp)        }         return String(eText)    }} fun main(args: Array<String>) {    val plainText = "WELLDONEISBETTERTHANWELLSAID"    println("The original plaintext is : \$plainText")    println("\nThe left and right alphabets after each permutation" +             " during encryption are :\n")    val cipherText = Chao.exec(plainText, Mode.ENCRYPT, true)    println("\nThe ciphertext is : \$cipherText")    val plainText2 = Chao.exec(cipherText, Mode.DECRYPT)    println("\nThe recovered plaintext is : \$plainText2")}`
Output:
```The original plaintext is : WELLDONEISBETTERTHANWELLSAID

The left and right alphabets after each permutation during encryption are :

HXUCZVAMDSLKPEFJRIGTWOBNYQ  PTLNBQDEOYSFAVZKGJRIHWXUMC
ONYQHXUCZVAMDBSLKPEFJRIGTW  XUCPTLNBQDEOYMSFAVZKGJRIHW
ZILGMTONQXCVARDBSKWPEYHUFJ  LNBIMSAVKGQDJOERYHFWZXUCPT
JILGMTONQXCVAZRDBSKWPEYHUF  LNIMSAVKGQDJOBERYHFWZXUCPT
RBSKWPEYHUFJIDLGMTONQXCVAZ  RYFWZXUCPTLNIHMSAVKGQDJOBE
RSKWPEYHUFJIDBLGMTONQXCVAZ  YFZXUCPTLNIHMWSAVKGQDJOBER
HFJIDBLGMTONQUXCVAZRSKWPEY  LNHMWSAVKGQDJIOBERYFZXUCPT
JDBLGMTONQUXCIVAZRSKWPEYHF  MWAVKGQDJIOBESRYFZXUCPTLNH
BGMTONQUXCIVALZRSKWPEYHFJD  VKQDJIOBESRYFGZXUCPTLNHMWA
YFJDBGMTONQUXHCIVALZRSKWPE  HMAVKQDJIOBESWRYFGZXUCPTLN
HIVALZRSKWPEYCFJDBGMTONQUX  RYGZXUCPTLNHMFAVKQDJIOBESW
QXHIVALZRSKWPUEYCFJDBGMTON  SWYGZXUCPTLNHRMFAVKQDJIOBE
KPUEYCFJDBGMTWONQXHIVALZRS  NHMFAVKQDJIOBRESWYGZXUCPTL
SPUEYCFJDBGMTKWONQXHIVALZR  NHFAVKQDJIOBRMESWYGZXUCPTL
OQXHIVALZRSPUNEYCFJDBGMTKW  WYZXUCPTLNHFAGVKQDJIOBRMES
UEYCFJDBGMTKWNOQXHIVALZRSP  GVQDJIOBRMESWKYZXUCPTLNHFA
JBGMTKWNOQXHIDVALZRSPUEYCF  OBMESWKYZXUCPRTLNHFAGVQDJI

The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY

The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
```

## Perl

Translation of: Perl 6

Since rotate is not a built-in in Perl, using a custom one, not general-purpose but sufficient for this task.

`sub init {    @left  = split '', 'HXUCZVAMDSLKPEFJRIGTWOBNYQ';    @right = split '', 'PTLNBQDEOYSFAVZKGJRIHWXUMC';} sub encode {    my(\$letter) = @_;    my \$index = index join('', @right), \$letter;    my \$enc   = \$left[\$index];    left_permute(\$index);    right_permute(\$index);    \$enc} sub decode {    my(\$letter) = @_;    my \$index = index join('', @left), \$letter;    my \$dec   = \$right[\$index];    left_permute(\$index);    right_permute(\$index);    \$dec} sub right_permute {    my(\$index) = @_;    rotate(\@right, \$index + 1);    rotate(\@right, 1, 2, 13);} sub left_permute {    my(\$index) = @_;    rotate(\@left, \$index);    rotate(\@left, 1, 1, 13);} sub rotate {    our @list; local *list = shift;    my(\$n,\$s,\$e) = @_;    @list = \$s ? @list[0..\$s-1, \$s+\$n..\$e+\$n-1, \$s..\$s+\$n-1, \$e+1..\$#list]               : @list[\$n..\$#list, 0..\$n-1]} init; \$e_msg .= encode(\$_) for split '', 'WELLDONEISBETTERTHANWELLSAID';init; \$d_msg .= decode(\$_) for split '', \$e_msg; print "\$e_msg\n";print "\$d_msg\n";`
Output:
```OAHQHCNYNXTSZJRRHJBYHQKSOUJY
WELLDONEISBETTERTHANWELLSAID```

## Perl 6

Works with: Rakudo version 2018.03
`my @left;my @right; sub reset {    @left  = <HXUCZVAMDSLKPEFJRIGTWOBNYQ>.comb;    @right = <PTLNBQDEOYSFAVZKGJRIHWXUMC>.comb;} sub encode (\$letter) {    my \$index = @right.first: \$letter.uc, :k;    my \$enc   = @left[\$index];    \$index.&permute;    \$enc} sub decode (\$letter) {    my \$index = @left.first: \$letter.uc, :k;    my \$dec   = @right[\$index];    \$index.&permute;    \$dec} sub permute (\$index) {    @left.=rotate: \$index;    @left[1..13].=rotate;    @right.=rotate: \$index + 1;    @right[2..13].=rotate;} reset;say 'WELLDONEISBETTERTHANWELLSAID'.comb».&encode.join;reset;say 'OAHQHCNYNXTSZJRRHJBYHQKSOUJY'.comb».&decode.join;`
Output:
```OAHQHCNYNXTSZJRRHJBYHQKSOUJY
WELLDONEISBETTERTHANWELLSAID```

## zkl

Translation of: perl6
`class Chao{   var [const private] lAlphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ",		       rAlphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC";   fcn encode(text){ code(text,encodeL); }   fcn decode(text){ code(text,decodeL); }   // reset alphabets each [en|de]code and maintain re-entrancy   fcn code(text,f){ text.apply(f,Data(Void,lAlphabet),Data(Void,rAlphabet)) }   fcn [private] encodeL(letter,left,right){  // encode a letter      index:=right.index(letter);      enc  :=left[index].toChar();      permute(left,right,index);      println(left.text," ",right.text,"  ",index);      enc   }   fcn [private] decodeL(letter,left,right){  // decode a letter      index:=left.index(letter);      dec  :=right[index].toChar();      permute(left,right,index);      dec   }   fcn [private] permute(left,right,index){      left.append(left.pop(0,index));		// rotate index times      left.insert(13,left.pop(1));		// rotate [1..13] once       right.append(right.pop(0,index+1)); # rotate index+1 times, idx==25==noop      right.insert(13,right.pop(2));		// rotate [2..13] once   }}`
`plainText:="WELLDONEISBETTERTHANWELLSAID";println("The original plaintext is : ",plainText);println("\nThe left and right alphabets after each permutation"         " during encryption are:");cipherText:=Chao.encode(plainText);println("\nThe ciphertext is : ",cipherText); plainText2:=Chao.decode(cipherText);println("\nThe recovered plaintext is : ",plainText2);`
Output:
```The original plaintext is : WELLDONEISBETTERTHANWELLSAID

The left and right alphabets after each permutation during encryption are:
ONYQHXUCZVAMDBSLKPEFJRIGTW XUCPTLNBQDEOYMSFAVZKGJRIHW  21
ZILGMTONQXCVARDBSKWPEYHUFJ LNBIMSAVKGQDJOERYHFWZXUCPT  10
JILGMTONQXCVAZRDBSKWPEYHUF LNIMSAVKGQDJOBERYHFWZXUCPT  25
RBSKWPEYHUFJIDLGMTONQXCVAZ RYFWZXUCPTLNIHMSAVKGQDJOBE  14
RSKWPEYHUFJIDBLGMTONQXCVAZ YFZXUCPTLNIHMWSAVKGQDJOBER  0
HFJIDBLGMTONQUXCVAZRSKWPEY LNHMWSAVKGQDJIOBERYFZXUCPT  7
JDBLGMTONQUXCIVAZRSKWPEYHF MWAVKGQDJIOBESRYFZXUCPTLNH  2
BGMTONQUXCIVALZRSKWPEYHFJD VKQDJIOBESRYFGZXUCPTLNHMWA  2
YFJDBGMTONQUXHCIVALZRSKWPE HMAVKQDJIOBESWRYFGZXUCPTLN  21
HIVALZRSKWPEYCFJDBGMTONQUX RYGZXUCPTLNHMFAVKQDJIOBESW  13
QXHIVALZRSKWPUEYCFJDBGMTON SWYGZXUCPTLNHRMFAVKQDJIOBE  23
KPUEYCFJDBGMTWONQXHIVALZRS NHMFAVKQDJIOBRESWYGZXUCPTL  10
SPUEYCFJDBGMTKWONQXHIVALZR NHFAVKQDJIOBRMESWYGZXUCPTL  25
OQXHIVALZRSPUNEYCFJDBGMTKW WYZXUCPTLNHFAGVKQDJIOBRMES  15
UEYCFJDBGMTKWNOQXHIVALZRSP GVQDJIOBRMESWKYZXUCPTLNHFA  12
JBGMTKWNOQXHIDVALZRSPUEYCF OBMESWKYZXUCPRTLNHFAGVQDJI  5
YFJBGMTKWNOQXCHIDVALZRSPUE JIBMESWKYZXUCOPRTLNHFAGVQD  23

The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY

The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
```