Chaocipher: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
Line 201: Line 201:
The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
</pre>
</pre>

=={{header|D}}==
{{trans|Kotlin}}
<lang d>import std.stdio;
import std.string;

immutable L_ALPHABET = "HXUCZVAMDSLKPEFJRIGTWOBNYQ";
immutable R_ALPHABET = "PTLNBQDEOYSFAVZKGJRIHWXUMC";

enum Mode {
ENCRYPT,
DECRYPT,
}

string exec(string text, Mode mode, bool showSteps = false) {
char[] left = L_ALPHABET.dup;
char[] right = R_ALPHABET.dup;
char[] eText;
eText.length = text.length;
char[26] temp;

foreach (i; 0..text.length) {
if (showSteps) writeln(left, ' ', right);
int index;
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

foreach (j; index..26) temp[j - index] = left[j];
foreach (j; 0..index) temp[26 - index + j] = left[j];
auto store = temp[1];
foreach (j; 2..14) temp[j - 1] = temp[j];
temp[13] = store;
left = temp.dup;

// permute right

foreach (j; index..26) temp[j - index] = right[j];
foreach (j; 0..index) temp[26 - index + j] = right[j];
store = temp[0];
foreach (j; 1..26) temp[j - 1] = temp[j];
temp[25] = store;
store = temp[2];
foreach (j; 3..14) temp[j - 1] = temp[j];
temp[13] = store;
right = temp.dup;
}

return eText.idup;
}

void main() {
auto plainText = "WELLDONEISBETTERTHANWELLSAID";
writeln("The original plaintext is : ", plainText);
writeln("\nThe left and right alphabets after each permutation during encryption are :\n");
auto cipherText = exec(plainText, Mode.ENCRYPT, true);
writeln("\nThe ciphertext is : ", cipherText);
auto plainText2 = exec(cipherText, Mode.DECRYPT);
writeln("\nThe recovered plaintext is : ", plainText2);
}</lang>
{{out}}
<pre>The original plaintext is : WELLDONEISBETTERTHANWELLSAID

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

HXUCZVAMDSLKPEFJRIGTWOBNYQ PTLNBQDEOYSFAVZKGJRIHWXUMC
ONYQHXUCZVAMDBSLKPEFJRIGTW XUCPTLNBQDEOYMSFAVZKGJRIHW
ADBSLKPEFJRIGMTWONYQHXUCZV OYSFAVZKGJRIHMWXUCPTLNBQDE
HUCZVADBSLKPEXFJRIGMTWONYQ NBDEOYSFAVZKGQJRIHMWXUCPTL
QUCZVADBSLKPEHXFJRIGMTWONY NBEOYSFAVZKGQDJRIHMWXUCPTL
HFJRIGMTWONYQXUCZVADBSLKPE JRHMWXUCPTLNBIEOYSFAVZKGQD
CVADBSLKPEHFJZRIGMTWONYQXU YSAVZKGQDJRHMFWXUCPTLNBIEO
NQXUCVADBSLKPYEHFJZRIGMTWO BIOYSAVZKGQDJERHMFWXUCPTLN
YHFJZRIGMTWONEQXUCVADBSLKP RHFWXUCPTLNBIMOYSAVZKGQDJE
NQXUCVADBSLKPEYHFJZRIGMTWO MOSAVZKGQDJERYHFWXUCPTLNBI
XCVADBSLKPEYHUFJZRIGMTWONQ AVKGQDJERYHFWZXUCPTLNBIMOS
TONQXCVADBSLKWPEYHUFJZRIGM IMSAVKGQDJERYOHFWZXUCPTLNB
SKWPEYHUFJZRILGMTONQXCVADB RYHFWZXUCPTLNOBIMSAVKGQDJE
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</pre>


=={{header|Factor}}==
=={{header|Factor}}==

Revision as of 23:45, 10 July 2019

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.


Task

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.

Arc

<lang arc>(= lshift '((0 1) (2 14) (1 2) (14 26))) (= rshift '((1 3) (4 15) (3 4) (15 26) (0 1)))

(= rot (fn (alpha shift)

 (let shift (mod shift 26)
   (string (cut alpha shift) (cut alpha 0 shift)))))

(= scramble-wheel (fn (alpha moves)

 (= oput '())
 (up i 0 (- (len moves) 1)
     (push (cut alpha ((moves i) 0) ((moves i) 1)) oput))
 (= oput (string (rev oput)))))

(= chaocipher (fn (left right msg (o crypted) (o dec?))

 (unless crypted
   (prn "Encoding " msg " with chaocipher")
   (prn left " " right))
 (when dec? (swap left right))
   (= offset ((positions (msg 0) right) 0))
   (= left (rot left offset))
   (= right (rot right offset))
   (push (cut left 0 1) crypted)
 (when dec? (swap left right))
 (prn (scramble-wheel left lshift)
  " " (scramble-wheel right rshift))
 (if (> (len msg) 1)
     (chaocipher (scramble-wheel left lshift)
            (scramble-wheel right rshift)
                 (cut msg 1) crypted dec?)
     (string (rev crypted)))))

(chaocipher "HXUCZVAMDSLKPEFJRIGTWOBNYQ" "PTLNBQDEOYSFAVZKGJRIHWXUMC"

           "WELLDONEISBETTERTHANWELLSAID")

(chaocipher "HXUCZVAMDSLKPEFJRIGTWOBNYQ" "PTLNBQDEOYSFAVZKGJRIHWXUMC"

           "OAHQHCNYNXTSZJRRHJBYHQKSOUJY" nil 1)

</lang>

Output:

<lang arc> arc> (chaocipher "HXUCZVAMDSLKPEFJRIGTWOBNYQ" "PTLNBQDEOYSFAVZKGJRIHWXUMC"

                "WELLDONEISBETTERTHANWELLSAID")

Encoding WELLDONEISBETTERTHANWELLSAID with chaocipher HXUCZVAMDSLKPEFJRIGTWOBNYQ PTLNBQDEOYSFAVZKGJRIHWXUMC ONYQHXUCZVAMDBSLKPEFJRIGTW XUCPTLNBQDEOYMSFAVZKGJRIHW ADBSLKPEFJRIGMTWONYQHXUCZV OYSFAVZKGJRIHMWXUCPTLNBQDE HUCZVADBSLKPEXFJRIGMTWONYQ NBDEOYSFAVZKGQJRIHMWXUCPTL QUCZVADBSLKPEHXFJRIGMTWONY NBEOYSFAVZKGQDJRIHMWXUCPTL HFJRIGMTWONYQXUCZVADBSLKPE JRHMWXUCPTLNBIEOYSFAVZKGQD CVADBSLKPEHFJZRIGMTWONYQXU YSAVZKGQDJRHMFWXUCPTLNBIEO NQXUCVADBSLKPYEHFJZRIGMTWO BIOYSAVZKGQDJERHMFWXUCPTLN YHFJZRIGMTWONEQXUCVADBSLKP RHFWXUCPTLNBIMOYSAVZKGQDJE NQXUCVADBSLKPEYHFJZRIGMTWO MOSAVZKGQDJERYHFWXUCPTLNBI XCVADBSLKPEYHUFJZRIGMTWONQ AVKGQDJERYHFWZXUCPTLNBIMOS TONQXCVADBSLKWPEYHUFJZRIGM IMSAVKGQDJERYOHFWZXUCPTLNB SKWPEYHUFJZRILGMTONQXCVADB RYHFWZXUCPTLNOBIMSAVKGQDJE 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 YFJBGMTKWNOQXCHIDVALZRSPUE JIBMESWKYZXUCOPRTLNHFAGVQD "OAHQHCNYNXTSZJRRHJBYHQKSOUJY" </lang>

C

Translation of: Kotlin

<lang c>#include <stdio.h>

  1. include <string.h>
  2. include <stdlib.h>
  1. define TRUE 1
  2. 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;

}</lang>

Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID

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

HXUCZVAMDSLKPEFJRIGTWOBNYQ  PTLNBQDEOYSFAVZKGJRIHWXUMC
ONYQHXUCZVAMDBSLKPEFJRIGTW  XUCPTLNBQDEOYMSFAVZKGJRIHW
ADBSLKPEFJRIGMTWONYQHXUCZV  OYSFAVZKGJRIHMWXUCPTLNBQDE
HUCZVADBSLKPEXFJRIGMTWONYQ  NBDEOYSFAVZKGQJRIHMWXUCPTL
QUCZVADBSLKPEHXFJRIGMTWONY  NBEOYSFAVZKGQDJRIHMWXUCPTL
HFJRIGMTWONYQXUCZVADBSLKPE  JRHMWXUCPTLNBIEOYSFAVZKGQD
CVADBSLKPEHFJZRIGMTWONYQXU  YSAVZKGQDJRHMFWXUCPTLNBIEO
NQXUCVADBSLKPYEHFJZRIGMTWO  BIOYSAVZKGQDJERHMFWXUCPTLN
YHFJZRIGMTWONEQXUCVADBSLKP  RHFWXUCPTLNBIMOYSAVZKGQDJE
NQXUCVADBSLKPEYHFJZRIGMTWO  MOSAVZKGQDJERYHFWXUCPTLNBI
XCVADBSLKPEYHUFJZRIGMTWONQ  AVKGQDJERYHFWZXUCPTLNBIMOS
TONQXCVADBSLKWPEYHUFJZRIGM  IMSAVKGQDJERYOHFWZXUCPTLNB
SKWPEYHUFJZRILGMTONQXCVADB  RYHFWZXUCPTLNOBIMSAVKGQDJE
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

D

Translation of: Kotlin

<lang d>import std.stdio; import std.string;

immutable L_ALPHABET = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"; immutable R_ALPHABET = "PTLNBQDEOYSFAVZKGJRIHWXUMC";

enum Mode {

   ENCRYPT,
   DECRYPT,

}

string exec(string text, Mode mode, bool showSteps = false) {

   char[] left = L_ALPHABET.dup;
   char[] right = R_ALPHABET.dup;
   char[] eText;
   eText.length = text.length;
   char[26] temp;
   foreach (i; 0..text.length) {
       if (showSteps) writeln(left, ' ', right);
       int index;
       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
       foreach (j; index..26) temp[j - index] = left[j];
       foreach (j; 0..index) temp[26 - index + j] = left[j];
       auto store = temp[1];
       foreach (j; 2..14) temp[j - 1] = temp[j];
       temp[13] = store;
       left = temp.dup;
       // permute right
       foreach (j; index..26) temp[j - index] = right[j];
       foreach (j; 0..index) temp[26 - index + j] = right[j];
       store = temp[0];
       foreach (j; 1..26) temp[j - 1] = temp[j];
       temp[25] = store;
       store = temp[2];
       foreach (j; 3..14) temp[j - 1] = temp[j];
       temp[13] = store;
       right = temp.dup;
   }
   return eText.idup;

}

void main() {

   auto plainText = "WELLDONEISBETTERTHANWELLSAID";
   writeln("The original plaintext is : ", plainText);
   writeln("\nThe left and right alphabets after each permutation during encryption are :\n");
   auto cipherText = exec(plainText, Mode.ENCRYPT, true);
   writeln("\nThe ciphertext is : ", cipherText);
   auto plainText2 = exec(cipherText, Mode.DECRYPT);
   writeln("\nThe recovered plaintext is : ", plainText2);

}</lang>

Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID

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

HXUCZVAMDSLKPEFJRIGTWOBNYQ PTLNBQDEOYSFAVZKGJRIHWXUMC
ONYQHXUCZVAMDBSLKPEFJRIGTW XUCPTLNBQDEOYMSFAVZKGJRIHW
ADBSLKPEFJRIGMTWONYQHXUCZV OYSFAVZKGJRIHMWXUCPTLNBQDE
HUCZVADBSLKPEXFJRIGMTWONYQ NBDEOYSFAVZKGQJRIHMWXUCPTL
QUCZVADBSLKPEHXFJRIGMTWONY NBEOYSFAVZKGQDJRIHMWXUCPTL
HFJRIGMTWONYQXUCZVADBSLKPE JRHMWXUCPTLNBIEOYSFAVZKGQD
CVADBSLKPEHFJZRIGMTWONYQXU YSAVZKGQDJRHMFWXUCPTLNBIEO
NQXUCVADBSLKPYEHFJZRIGMTWO BIOYSAVZKGQDJERHMFWXUCPTLN
YHFJZRIGMTWONEQXUCVADBSLKP RHFWXUCPTLNBIMOYSAVZKGQDJE
NQXUCVADBSLKPEYHFJZRIGMTWO MOSAVZKGQDJERYHFWXUCPTLNBI
XCVADBSLKPEYHUFJZRIGMTWONQ AVKGQDJERYHFWZXUCPTLNBIMOS
TONQXCVADBSLKWPEYHUFJZRIGM IMSAVKGQDJERYOHFWZXUCPTLNB
SKWPEYHUFJZRILGMTONQXCVADB RYHFWZXUCPTLNOBIMSAVKGQDJE
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

<lang factor>USING: arrays combinators fry io kernel locals math namespaces prettyprint sequences sequences.extras strings ; IN: rosetta-code.chaocipher

CONSTANT: zenith 0 CONSTANT: nadir 13

SYMBOLS: l-alphabet r-alphabet last-index ;

init-alphabets ( -- )
   "HXUCZVAMDSLKPEFJRIGTWOBNYQ" l-alphabet
   "PTLNBQDEOYSFAVZKGJRIHWXUMC" r-alphabet [ set ] 2bi@ ;
   
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 ] bi@ ;
   

MAIN: main</lang>

Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY
WELLDONEISBETTERTHANWELLSAID

Go

Translation of: Kotlin

<lang go>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)

}</lang>

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. <lang scala>// 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")

}</lang>

Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID

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

HXUCZVAMDSLKPEFJRIGTWOBNYQ  PTLNBQDEOYSFAVZKGJRIHWXUMC
ONYQHXUCZVAMDBSLKPEFJRIGTW  XUCPTLNBQDEOYMSFAVZKGJRIHW
ADBSLKPEFJRIGMTWONYQHXUCZV  OYSFAVZKGJRIHMWXUCPTLNBQDE
HUCZVADBSLKPEXFJRIGMTWONYQ  NBDEOYSFAVZKGQJRIHMWXUCPTL
QUCZVADBSLKPEHXFJRIGMTWONY  NBEOYSFAVZKGQDJRIHMWXUCPTL
HFJRIGMTWONYQXUCZVADBSLKPE  JRHMWXUCPTLNBIEOYSFAVZKGQD
CVADBSLKPEHFJZRIGMTWONYQXU  YSAVZKGQDJRHMFWXUCPTLNBIEO
NQXUCVADBSLKPYEHFJZRIGMTWO  BIOYSAVZKGQDJERHMFWXUCPTLN
YHFJZRIGMTWONEQXUCVADBSLKP  RHFWXUCPTLNBIMOYSAVZKGQDJE
NQXUCVADBSLKPEYHFJZRIGMTWO  MOSAVZKGQDJERYHFWXUCPTLNBI
XCVADBSLKPEYHUFJZRIGMTWONQ  AVKGQDJERYHFWZXUCPTLNBIMOS
TONQXCVADBSLKWPEYHUFJZRIGM  IMSAVKGQDJERYOHFWZXUCPTLNB
SKWPEYHUFJZRILGMTONQXCVADB  RYHFWZXUCPTLNOBIMSAVKGQDJE
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. <lang perl>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";</lang>

Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY
WELLDONEISBETTERTHANWELLSAID

Perl 6

Works with: Rakudo version 2018.03

<lang perl6>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;</lang>

Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY
WELLDONEISBETTERTHANWELLSAID

Phix

Originally translated from C, but ended up more of a direct implementation of the algorithm in the pdf. <lang Phix>-- demo\rosetta\Chao_cipher.exw constant l_alphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ",

        r_alphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC"

enum ENCRYPT, DECRYPT

function chao_cipher(string in, integer mode, bool show_steps)

   integer len = length(in)
   string out = repeat(' ',len)
   string left = l_alphabet,
          right = r_alphabet
   for i=1 to len do
       if show_steps then printf(1,"%s  %s\n", {left, right}) end if
       integer index = find(in[i],iff(mode==ENCRYPT?right:left))
       out[i] = iff(mode==ENCRYPT?left:right)[index]
       if i==len then exit end if

       /* permute left */
       left = left[index..26]&left[1..index-1]
       left[2..14] = left[3..14]&left[2]
       /* permute right */
       right = right[index+1..26]&right[1..index]
       right[3..14] = right[4..14]&right[3]
   end for
   return out

end function

string plain_text = "WELLDONEISBETTERTHANWELLSAID" printf(1,"The original plaintext is : %s\n", {plain_text})

--printf(1,"\nThe left and right alphabets after each permutation"& -- " during encryption are :\n\n") --string cipher_text = chao_cipher(plain_text, ENCRYPT, true) string cipher_text = chao_cipher(plain_text, ENCRYPT, false) printf(1,"\nThe ciphertext is : %s\n", {cipher_text})

string plain_text2 = chao_cipher(cipher_text, DECRYPT, false) printf(1,"\nThe recovered plaintext is : %s\n", {plain_text2})</lang>

Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID

The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY

The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID

Python

<lang Python3>

  1. Python3 implementation of Chaocipher
  2. left wheel = ciphertext wheel
  3. right wheel = plaintext wheel

def main():

   # letters only! makealpha(key) helps generate lalpha/ralpha. 
   lalpha = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"
   ralpha = "PTLNBQDEOYSFAVZKGJRIHWXUMC"
   msg = "WELLDONEISBETTERTHANWELLSAID"
   print("L:", lalpha)
   print("R:", ralpha)
   print("I:", msg)
   print("O:", do_chao(msg, lalpha, ralpha, 1, 0), "\n")
   
   do_chao(msg, lalpha, ralpha, 1, 1)

def do_chao(msg, lalpha, ralpha, en=1, show=0):

   msg = correct_case(msg)
   out = ""    
   if show:
       print("="*54)        
       print(10*" " + "left:" + 21*" " + "right: ")
       print("="*54)        
       print(lalpha, ralpha, "\n")
   for L in msg:
       if en:
           lalpha, ralpha = rotate_wheels(lalpha, ralpha, L)
           out += lalpha[0]
       else:
           ralpha, lalpha = rotate_wheels(ralpha, lalpha, L)
           out += ralpha[0]
       lalpha, ralpha = scramble_wheels(lalpha, ralpha)
       if show:
           print(lalpha, ralpha)            
   return out
   

def makealpha(key=""):

   alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   z = set()
   key = [x.upper() for x in (key + alpha[::-1])
          if not (x.upper() in z or z.add(x.upper()))]
   return "".join(key)

def correct_case(string):

   return "".join([s.upper() for s in string if s.isalpha()])

def permu(alp, num):

   alp = alp[:num], alp[num:]
   return "".join(alp[::-1])

def rotate_wheels(lalph, ralph, key):

   newin = ralph.index(key)
   return permu(lalph, newin), permu(ralph, newin)    

def scramble_wheels(lalph, ralph):

   # LEFT = cipher wheel 
   # Cycle second[1] through nadir[14] forward
   lalph = list(lalph)
   lalph = "".join([*lalph[0],
                   *lalph[2:14],
                   lalph[1],
                   *lalph[14:]])
   
   # RIGHT = plain wheel                    
   # Send the zenith[0] character to the end[25],
   # cycle third[2] through nadir[14] characters forward
   ralph = list(ralph)
   ralph = "".join([*ralph[1:3],
                    *ralph[4:15],
                    ralph[3],
                    *ralph[15:],
                    ralph[0]])
   return lalph, ralph

main()</lang>

L: HXUCZVAMDSLKPEFJRIGTWOBNYQ
R: PTLNBQDEOYSFAVZKGJRIHWXUMC
I: WELLDONEISBETTERTHANWELLSAID
O: OAHQHCNYNXTSZJRRHJBYHQKSOUJY 

======================================================
          left:                     right: 
======================================================
HXUCZVAMDSLKPEFJRIGTWOBNYQ PTLNBQDEOYSFAVZKGJRIHWXUMC 

ONYQHXUCZVAMDBSLKPEFJRIGTW XUCPTLNBQDEOYMSFAVZKGJRIHW
ADBSLKPEFJRIGMTWONYQHXUCZV OYSFAVZKGJRIHMWXUCPTLNBQDE
HUCZVADBSLKPEXFJRIGMTWONYQ NBDEOYSFAVZKGQJRIHMWXUCPTL
QUCZVADBSLKPEHXFJRIGMTWONY NBEOYSFAVZKGQDJRIHMWXUCPTL
HFJRIGMTWONYQXUCZVADBSLKPE JRHMWXUCPTLNBIEOYSFAVZKGQD
CVADBSLKPEHFJZRIGMTWONYQXU YSAVZKGQDJRHMFWXUCPTLNBIEO
NQXUCVADBSLKPYEHFJZRIGMTWO BIOYSAVZKGQDJERHMFWXUCPTLN
YHFJZRIGMTWONEQXUCVADBSLKP RHFWXUCPTLNBIMOYSAVZKGQDJE
NQXUCVADBSLKPEYHFJZRIGMTWO MOSAVZKGQDJERYHFWXUCPTLNBI
XCVADBSLKPEYHUFJZRIGMTWONQ AVKGQDJERYHFWZXUCPTLNBIMOS
TONQXCVADBSLKWPEYHUFJZRIGM IMSAVKGQDJERYOHFWZXUCPTLNB
SKWPEYHUFJZRILGMTONQXCVADB RYHFWZXUCPTLNOBIMSAVKGQDJE
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
YFJBGMTKWNOQXCHIDVALZRSPUE JIBMESWKYZXUCOPRTLNHFAGVQD

OAHQHCNYNXTSZJRRHJBYHQKSOUJY
WELLDONEISBETTERTHANWELLSAID

zkl

Translation of: perl6

<lang zkl>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
  }

}</lang> <lang zkl>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);</lang>

Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID

The left and right alphabets after each permutation during encryption are:
ONYQHXUCZVAMDBSLKPEFJRIGTW XUCPTLNBQDEOYMSFAVZKGJRIHW  21
ADBSLKPEFJRIGMTWONYQHXUCZV OYSFAVZKGJRIHMWXUCPTLNBQDE  10
HUCZVADBSLKPEXFJRIGMTWONYQ NBDEOYSFAVZKGQJRIHMWXUCPTL  20
QUCZVADBSLKPEHXFJRIGMTWONY NBEOYSFAVZKGQDJRIHMWXUCPTL  25
HFJRIGMTWONYQXUCZVADBSLKPE JRHMWXUCPTLNBIEOYSFAVZKGQD  13
CVADBSLKPEHFJZRIGMTWONYQXU YSAVZKGQDJRHMFWXUCPTLNBIEO  15
NQXUCVADBSLKPYEHFJZRIGMTWO BIOYSAVZKGQDJERHMFWXUCPTLN  21
YHFJZRIGMTWONEQXUCVADBSLKP RHFWXUCPTLNBIMOYSAVZKGQDJE  13
NQXUCVADBSLKPEYHFJZRIGMTWO MOSAVZKGQDJERYHFWXUCPTLNBI  12
XCVADBSLKPEYHUFJZRIGMTWONQ AVKGQDJERYHFWZXUCPTLNBIMOS  2
TONQXCVADBSLKWPEYHUFJZRIGM IMSAVKGQDJERYOHFWZXUCPTLNB  21
SKWPEYHUFJZRILGMTONQXCVADB RYHFWZXUCPTLNOBIMSAVKGQDJE  10
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