Chaocipher: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
Line 10: Line 10:
Code the algorithm in your language and to test that it works with the plaintext 'WELLDONEISBETTERTHANWELLSAID' used in the paper itself.
Code the algorithm in your language and to test that it works with the plaintext 'WELLDONEISBETTERTHANWELLSAID' used in the paper itself.
<br><br>
<br><br>

=={{header|Ada}}==
Ada strings are indexed starting at 1. This fact resulted in some adjustments in loop control values compared with the C# reference solution.
<lang Ada>
with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
type iMode is (Encrypt, Decrypt);

L_Alphabet : String := "HXUCZVAMDSLKPEFJRIGTWOBNYQ";
R_Alphabet : String := "PTLNBQDEOYSFAVZKGJRIHWXUMC";
plaintext : String := "WELLDONEISBETTERTHANWELLSAID";
ciphertext : String (1 .. plaintext'length);
plaintext2 : String (1 .. plaintext'length);

function IndexOf (Source : String; Value : Character) return Positive is
Result : Positive;

begin
for I in Source'Range loop
if Source (I) = Value then
Result := I;
exit;
end if;
end loop;
return Result;
end IndexOf;

function Exec
(Text : String; mode : iMode; showsteps : Boolean := False) return String
is
etext : String (Text'First .. Text'Last);
temp : String (1 .. 26);
index : Positive;
store : Character;
left : String := L_Alphabet;
right : String := R_Alphabet;
begin
for I in Text'Range loop
if showsteps then
Put_Line (left & " " & right);
end if;

if mode = Encrypt then
index := IndexOf (Source => right, Value => Text (I));
etext (I) := left (index);
else
index := IndexOf (Source => left, Value => Text (I));
etext (I) := right (index);
end if;

exit when I = Text'Last;

-- permute left

for j in index .. 26 loop
temp (j - index + 1) := left (j);
end loop;
for j in 1 .. index loop
temp (26 - index + j) := left (j);
end loop;
store := temp (2);
for j in 3 .. 14 loop
temp (j - 1) := temp (j);
end loop;
temp (14) := store;
left := temp;

-- permute right

for j in index .. 26 loop
temp (j - index + 1) := right (j);
end loop;
for j in 1 .. index loop
temp (26 - index + j) := right (j);
end loop;
store := temp (1);
for j in 2 .. 26 loop
temp (j - 1) := temp (j);
end loop;
temp (26) := store;
store := temp (3);
for j in 4 .. 14 loop
temp (j - 1) := temp (j);
end loop;
temp (14) := store;
right := temp;
end loop;

return etext;

end Exec;

begin
Put_Line ("The original text is : " & plaintext);
New_Line;
Put_Line
("The left and right alphabets after each permutation during encryption are:");
New_Line;
ciphertext := Exec (plaintext, Encrypt, True);
New_Line;
Put_Line ("The ciphertext is : " & ciphertext);
plaintext2 := Exec (ciphertext, Decrypt);
New_Line;
Put_Line ("The recovered plaintext is : " & plaintext2);
end Main;
</lang>
{{output}}
<lang Ada>
The original text is : WELLDONEISBETTERTHANWELLSAID

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

HXUCZVAMDSLKPEFJRIGTWOBNYQ PTLNBQDEOYSFAVZKGJRIHWXUMC
ONYHXUCZVAMDSBLKPEFJRIGTWO XUPTLNBQDEOYSMFAVZKGJRIHWW
ADSBLKPEFJRIGMTWONYHXUCZVA OYMFAVZKGJRIHSWXUPTLNBQDEE
HUCZVADSBLKPEXFJRIGMTWONYH NBDEOYMFAVZKGQJRIHSWXUPTLL
YUCZVADSBLKPEHXFJRIGMTWONY NBEOYMFAVZKGQDJRIHSWXUPTLL
HFJRIGMTWONYUXCZVADSBLKPEH JRHSWXUPTLNBEIOYMFAVZKGQDD
CVADSBLKPEHFJZRIGMTWONYUXC YMAVZKGQDJRHSFWXUPTLNBEIOO
OYUXCVADSBLKPNEHFJZRIGMTWO BEOYMAVZKGQDJIRHSFWXUPTLNN
YXCVADSBLKPNEUHFJZRIGMTWOY OYAVZKGQDJIRHMSFWXUPTLNBEE
PEUHFJZRIGMTWNOYXCVADSBLKP RHSFWXUPTLNBEMOYAVZKGQDJII
UFJZRIGMTWNOYHXCVADSBLKPEU FWUPTLNBEMOYAXVZKGQDJIRHSS
MWNOYHXCVADSBTLKPEUFJZRIGM EMYAXVZKGQDJIORHSFWUPTLNBB
MNOYHXCVADSBTWLKPEUFJZRIGM MYXVZKGQDJIORAHSFWUPTLNBEE
JRIGMNOYHXCVAZDSBTWLKPEUFJ LNEMYXVZKGQDJBIORAHSFWUPTT
FRIGMNOYHXCVAJZDSBTWLKPEUF LNMYXVZKGQDJBEIORAHSFWUPTT
JDSBTWLKPEUFRZIGMNOYHXCVAJ IOAHSFWUPTLNMRYXVZKGQDJBEE
ZGMNOYHXCVAJDISBTWLKPEUFRZ YXZKGQDJBEIOAVHSFWUPTLNMRR
PUFRZGMNOYHXCEVAJDISBTWLKP LNRYXZKGQDJBEMIOAVHSFWUPTT
IBTWLKPUFRZGMSNOYHXCEVAJDI SFUPTLNRYXZKGWQDJBEMIOAVHH
ADIBTWLKPUFRZJGMSNOYHXCEVA VHFUPTLNRYXZKSGWQDJBEMIOAA
KUFRZJGMSNOYHPXCEVADIBTWLK RYZKSGWQDJBEMXIOAVHFUPTLNN
GSNOYHPXCEVADMIBTWLKUFRZJG QDBEMXIOAVHFUJPTLNRYZKSGWW
OHPXCEVADMIBTYWLKUFRZJGSNO MXOAVHFUJPTLNIRYZKSGWQDBEE
BYWLKUFRZJGSNTOHPXCEVADMIB NIYZKSGWQDBEMRXOAVHFUJPTLL
IYWLKUFRZJGSNBTOHPXCEVADMI NIZKSGWQDBEMRYXOAVHFUJPTLL
KFRZJGSNBTOHPUXCEVADMIYWLK GWDBEMRYXOAVHQFUJPTLNIZKSS
OPUXCEVADMIYWHLKFRZJGSNBTO VHFUJPTLNIZKSQGWDBEMRYXOAA
MYWHLKFRZJGSNIBTOPUXCEVADM ZKQGWDBEMRYXOSAVHFUJPTLNII

The ciphertext is : OAHYHCOYPUMMJFJZPIAKGOBIKOMK

The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
</lang>


=={{header|Arc}}==
=={{header|Arc}}==

Revision as of 00:27, 31 December 2020

Task
Chaocipher
You are encouraged to solve this task according to the task description, using any language you may know.
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

Code the algorithm in your language and to test that it works with the plaintext 'WELLDONEISBETTERTHANWELLSAID' used in the paper itself.

Ada

Ada strings are indexed starting at 1. This fact resulted in some adjustments in loop control values compared with the C# reference solution. <lang Ada> with Ada.Text_IO; use Ada.Text_IO;

procedure Main is

  type iMode is (Encrypt, Decrypt);
  L_Alphabet : String := "HXUCZVAMDSLKPEFJRIGTWOBNYQ";
  R_Alphabet : String := "PTLNBQDEOYSFAVZKGJRIHWXUMC";
  plaintext  : String := "WELLDONEISBETTERTHANWELLSAID";
  ciphertext : String (1 .. plaintext'length);
  plaintext2 : String (1 .. plaintext'length);
  function IndexOf (Source : String; Value : Character) return Positive is
     Result : Positive;
  begin
     for I in Source'Range loop
        if Source (I) = Value then
           Result := I;
           exit;
        end if;
     end loop;
     return Result;
  end IndexOf;
  function Exec
    (Text : String; mode : iMode; showsteps : Boolean := False) return String
  is
     etext : String (Text'First .. Text'Last);
     temp  : String (1 .. 26);
     index : Positive;
     store : Character;
     left  : String := L_Alphabet;
     right : String := R_Alphabet;
  begin
     for I in Text'Range loop
        if showsteps then
           Put_Line (left & "  " & right);
        end if;
        if mode = Encrypt then
           index     := IndexOf (Source => right, Value => Text (I));
           etext (I) := left (index);
        else
           index     := IndexOf (Source => left, Value => Text (I));
           etext (I) := right (index);
        end if;
        exit when I = Text'Last;
        -- permute left
        for j in index .. 26 loop
           temp (j - index + 1) := left (j);
        end loop;
        for j in 1 .. index loop
           temp (26 - index + j) := left (j);
        end loop;
        store := temp (2);
        for j in 3 .. 14 loop
           temp (j - 1) := temp (j);
        end loop;
        temp (14) := store;
        left      := temp;
        -- permute right
        for j in index .. 26 loop
           temp (j - index + 1) := right (j);
        end loop;
        for j in 1 .. index loop
           temp (26 - index + j) := right (j);
        end loop;
        store := temp (1);
        for j in 2 .. 26 loop
           temp (j - 1) := temp (j);
        end loop;
        temp (26) := store;
        store     := temp (3);
        for j in 4 .. 14 loop
           temp (j - 1) := temp (j);
        end loop;
        temp (14) := store;
        right     := temp;
     end loop;
     return etext;
  end Exec;

begin

  Put_Line ("The original text is : " & plaintext);
  New_Line;
  Put_Line
    ("The left and right alphabets after each permutation during encryption are:");
  New_Line;
  ciphertext := Exec (plaintext, Encrypt, True);
  New_Line;
  Put_Line ("The ciphertext is : " & ciphertext);
  plaintext2 := Exec (ciphertext, Decrypt);
  New_Line;
  Put_Line ("The recovered plaintext is : " & plaintext2);

end Main; </lang>

Output:

<lang Ada> The original text is : WELLDONEISBETTERTHANWELLSAID

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

HXUCZVAMDSLKPEFJRIGTWOBNYQ PTLNBQDEOYSFAVZKGJRIHWXUMC ONYHXUCZVAMDSBLKPEFJRIGTWO XUPTLNBQDEOYSMFAVZKGJRIHWW ADSBLKPEFJRIGMTWONYHXUCZVA OYMFAVZKGJRIHSWXUPTLNBQDEE HUCZVADSBLKPEXFJRIGMTWONYH NBDEOYMFAVZKGQJRIHSWXUPTLL YUCZVADSBLKPEHXFJRIGMTWONY NBEOYMFAVZKGQDJRIHSWXUPTLL HFJRIGMTWONYUXCZVADSBLKPEH JRHSWXUPTLNBEIOYMFAVZKGQDD CVADSBLKPEHFJZRIGMTWONYUXC YMAVZKGQDJRHSFWXUPTLNBEIOO OYUXCVADSBLKPNEHFJZRIGMTWO BEOYMAVZKGQDJIRHSFWXUPTLNN YXCVADSBLKPNEUHFJZRIGMTWOY OYAVZKGQDJIRHMSFWXUPTLNBEE PEUHFJZRIGMTWNOYXCVADSBLKP RHSFWXUPTLNBEMOYAVZKGQDJII UFJZRIGMTWNOYHXCVADSBLKPEU FWUPTLNBEMOYAXVZKGQDJIRHSS MWNOYHXCVADSBTLKPEUFJZRIGM EMYAXVZKGQDJIORHSFWUPTLNBB MNOYHXCVADSBTWLKPEUFJZRIGM MYXVZKGQDJIORAHSFWUPTLNBEE JRIGMNOYHXCVAZDSBTWLKPEUFJ LNEMYXVZKGQDJBIORAHSFWUPTT FRIGMNOYHXCVAJZDSBTWLKPEUF LNMYXVZKGQDJBEIORAHSFWUPTT JDSBTWLKPEUFRZIGMNOYHXCVAJ IOAHSFWUPTLNMRYXVZKGQDJBEE ZGMNOYHXCVAJDISBTWLKPEUFRZ YXZKGQDJBEIOAVHSFWUPTLNMRR PUFRZGMNOYHXCEVAJDISBTWLKP LNRYXZKGQDJBEMIOAVHSFWUPTT IBTWLKPUFRZGMSNOYHXCEVAJDI SFUPTLNRYXZKGWQDJBEMIOAVHH ADIBTWLKPUFRZJGMSNOYHXCEVA VHFUPTLNRYXZKSGWQDJBEMIOAA KUFRZJGMSNOYHPXCEVADIBTWLK RYZKSGWQDJBEMXIOAVHFUPTLNN GSNOYHPXCEVADMIBTWLKUFRZJG QDBEMXIOAVHFUJPTLNRYZKSGWW OHPXCEVADMIBTYWLKUFRZJGSNO MXOAVHFUJPTLNIRYZKSGWQDBEE BYWLKUFRZJGSNTOHPXCEVADMIB NIYZKSGWQDBEMRXOAVHFUJPTLL IYWLKUFRZJGSNBTOHPXCEVADMI NIZKSGWQDBEMRYXOAVHFUJPTLL KFRZJGSNBTOHPUXCEVADMIYWLK GWDBEMRYXOAVHQFUJPTLNIZKSS OPUXCEVADMIYWHLKFRZJGSNBTO VHFUJPTLNIZKSQGWDBEMRYXOAA MYWHLKFRZJGSNIBTOPUXCEVADM ZKQGWDBEMRYXOSAVHFUJPTLNII

The ciphertext is : OAHYHCOYPUMMJFJZPIAKGOBIKOMK

The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID </lang>

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

C#

Translation of: D

<lang csharp>using System;

namespace Chaocipher {

   enum Mode {
       ENCRYPT,
       DECRYPT,
   }
   class Program {
       const string L_ALPHABET = "HXUCZVAMDSLKPEFJRIGTWOBNYQ";
       const string R_ALPHABET = "PTLNBQDEOYSFAVZKGJRIHWXUMC";
       static string Exec(string text, Mode mode, bool showSteps = false) {
           char[] left = L_ALPHABET.ToCharArray();
           char[] right = R_ALPHABET.ToCharArray();
           char[] eText = new char[text.Length];
           char[] temp = new char[26];
           for (int i = 0; i < text.Length; ++i) {
               if (showSteps) Console.WriteLine("{0} {1}", string.Join("", left), string.Join("", right));
               int index = 0;
               if (mode == Mode.ENCRYPT) {
                   index = Array.IndexOf(right, text[i]);
                   eText[i] = left[index];
               } else {
                   index = Array.IndexOf(left, text[i]);
                   eText[i] = right[index];
               }
               if (i == text.Length - 1) break;
               // permute left
               for (int j = index; j < 26; ++j) temp[j - index] = left[j];
               for (int j = 0; j < index; ++j) temp[26 - index + j] = left[j];
               var store = temp[1];
               for (int j = 2; j < 14; ++j) temp[j - 1] = temp[j];
               temp[13] = store;
               temp.CopyTo(left, 0);
               // permute right
               for (int j = index; j < 26; ++j) temp[j - index] = right[j];
               for (int j = 0; j < index; ++j) temp[26 - index + j] = right[j];
               store = temp[0];
               for (int j = 1; j < 26; ++j) temp[j - 1] = temp[j];
               temp[25] = store;
               store = temp[2];
               for (int j = 3; j < 14; ++j) temp[j - 1] = temp[j];
               temp[13] = store;
               temp.CopyTo(right, 0);
           }
           return new string(eText);
       }
       static void Main(string[] args) {
           var plainText = "WELLDONEISBETTERTHANWELLSAID";
           Console.WriteLine("The original plaintext is : {0}", plainText);
           Console.WriteLine("\nThe left and right alphabets after each permutation during encryption are :\n");
           var cipherText = Exec(plainText, Mode.ENCRYPT, true);
           Console.WriteLine("\nThe ciphertext is : {0}", cipherText);
           var plainText2 = Exec(cipherText, Mode.DECRYPT);
           Console.WriteLine("\nThe recovered plaintext is : {0}", 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

C++

Translation of: C#

<lang cpp>#include <iostream>

enum class Mode {

   ENCRYPT,
   DECRYPT,

};

const std::string L_ALPHABET = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"; const std::string R_ALPHABET = "PTLNBQDEOYSFAVZKGJRIHWXUMC";

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

   auto left = L_ALPHABET;
   auto right = R_ALPHABET;
   auto eText = new char[text.size() + 1];
   auto temp = new char[27];
   memset(eText, 0, text.size() + 1);
   memset(temp, 0, 27);
   for (size_t i = 0; i < text.size(); i++) {
       if (showSteps) std::cout << left << ' ' << right << '\n';
       size_t index;
       if (mode == Mode::ENCRYPT) {
           index = right.find(text[i]);
           eText[i] = left[index];
       } else {
           index = left.find(text[i]);
           eText[i] = right[index];
       }
       if (i == text.size() - 1) break;
       // permute left
       for (int j = index; j < 26; ++j) temp[j - index] = left[j];
       for (int j = 0; j < index; ++j) temp[26 - index + j] = left[j];
       auto store = temp[1];
       for (int j = 2; j < 14; ++j) temp[j - 1] = temp[j];
       temp[13] = store;
       left = temp;
       // permurte right
       for (int j = index; j < 26; ++j) temp[j - index] = right[j];
       for (int j = 0; j < index; ++j) temp[26 - index + j] = right[j];
       store = temp[0];
       for (int j = 1; j < 26; ++j) temp[j - 1] = temp[j];
       temp[25] = store;
       store = temp[2];
       for (int j = 3; j < 14; ++j) temp[j - 1] = temp[j];
       temp[13] = store;
       right = temp;
   }
   return eText;

}

int main() {

   auto plainText = "WELLDONEISBETTERTHANWELLSAID";
   std::cout << "The original plaintext is : " << plainText << "\n\n";
   std::cout << "The left and right alphabets after each permutation during encryption are :\n";
   auto cipherText = exec(plainText, Mode::ENCRYPT, true);
   std::cout << "\nThe ciphertext is : " << cipherText << '\n';
   auto plainText2 = exec(cipherText, Mode::DECRYPT);
   std::cout << "\nThe recovered plaintext is : " << plainText2 << '\n';
   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

F#

The Functions

<lang fsharp> // Implement Chaocipher. Nigel Galloway: July 13th., 2019 let pL n=function g when g=n->0 |g when g=(n+1)%26->13 |g->let x=(25+g-n)%26 in if x<13 then x else x+1 let pR n=function g when g=n->25 |g when g=(n+3)%26->13 |g when g=(n+1)%26->0 |g when g=(n+2)%26->1 |g->let x=(24+g-n)%26 in if x<13 then x else x+1 let encrypt lW rW txt=Array.scan(fun (lW,rW) t->let n=Array.findIndex(fun n->n=t) rW in ((Array.permute(pL n) lW,(Array.permute(pR n) rW))))(lW,rW) txt

                       |>Array.skip 1|>Array.map(fun(n,_)->n.[0])|>System.String

let decrypt lW rW txt=Array.scan(fun (_,lW,rW) t->let n=Array.findIndex(fun n->n=t) lW in ((Array.item n rW,Array.permute(pL n) lW,(Array.permute(pR n) rW))))('0',lW,rW) txt

                       |>Array.skip 1|>Array.map(fun(n,_,_)->n)|>System.String

</lang>

The Task

<lang fsharp> printfn "%s" (encrypt ("HXUCZVAMDSLKPEFJRIGTWOBNYQ".ToCharArray()) ("PTLNBQDEOYSFAVZKGJRIHWXUMC".ToCharArray()) ("WELLDONEISBETTERTHANWELLSAID".ToCharArray())) printfn "%s" (decrypt ("HXUCZVAMDSLKPEFJRIGTWOBNYQ".ToCharArray()) ("PTLNBQDEOYSFAVZKGJRIHWXUMC".ToCharArray()) ("OAHQHCNYNXTSZJRRHJBYHQKSOUJY".ToCharArray())) </lang>

Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY
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

Fōrmulæ

In this page you can see the solution of this task.

Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text (more info). Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for transportation effects more than visualization and edition.

The option to show Fōrmulæ programs and their results is showing images. Unfortunately images cannot be uploaded in Rosetta Code.

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.

Groovy

Translation of: Java

<lang groovy>class Chaocipher {

   private enum Mode {
       ENCRYPT,
       DECRYPT
   }
   private static final String L_ALPHABET = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"
   private static final String R_ALPHABET = "PTLNBQDEOYSFAVZKGJRIHWXUMC"
   private static int indexOf(char[] a, char c) {
       for (int i = 0; i < a.length; ++i) {
           if (a[i] == c) {
               return i
           }
       }
       return -1
   }
   private static String exec(String text, Mode mode) {
       return exec(text, mode, false)
   }
   private static String exec(String text, Mode mode, Boolean showSteps) {
       char[] left = L_ALPHABET.toCharArray()
       char[] right = R_ALPHABET.toCharArray()
       char[] eText = new char[text.length()]
       char[] temp = new char[26]
       for (int i = 0; i < text.length(); ++i) {
           if (showSteps) {
               println("${new String(left)}  ${new String(right)}")
           }
           int index
           if (mode == Mode.ENCRYPT) {
               index = indexOf(right, text.charAt(i))
               eText[i] = left[index]
           } else {
               index = indexOf(left, text.charAt(i))
               eText[i] = right[index]
           }
           if (i == text.length() - 1) {
               break
           }
           // permute left
           if (26 - index >= 0) System.arraycopy(left, index, temp, 0, 26 - index)
           System.arraycopy(left, 0, temp, 26 - index, index)
           char store = temp[1]
           System.arraycopy(temp, 2, temp, 1, 12)
           temp[13] = store
           left = Arrays.copyOf(temp, temp.length)
           // permute right
           if (26 - index >= 0) System.arraycopy(right, index, temp, 0, 26 - index)
           System.arraycopy(right, 0, temp, 26 - index, index)
           store = temp[0]
           System.arraycopy(temp, 1, temp, 0, 25)
           temp[25] = store
           store = temp[2]
           System.arraycopy(temp, 3, temp, 2, 11)
           temp[13] = store
           right = Arrays.copyOf(temp, temp.length)
       }
       return new String(eText)
   }
   static void main(String[] args) {
       String plainText = "WELLDONEISBETTERTHANWELLSAID"
       println("The original plaintext is : $plainText")
       println("\nThe left and right alphabets after each permutation during encryption are:")
       String cipherText = exec(plainText, Mode.ENCRYPT, true)
       println("\nThe cipher text is : $cipherText")
       String plainText2 = 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 cipher text is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY

The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID

Haskell

<lang haskell>import Data.List (elemIndex)

chao

 :: Eq a
 => [a] -> [a] -> Bool -> [a] -> [a]

chao _ _ _ [] = [] chao l r plain (x:xs) = maybe [] go (elemIndex x src)

 where
   (src, dst)
     | plain = (l, r)
     | otherwise = (r, l)
   go n =
     dst !! n :
     chao
       (shifted 1 14 (rotated n l))
       ((shifted 2 14 . shifted 0 26) (rotated n r))
       plain
       xs

rotated :: Int -> [a] -> [a] rotated n = take . length <*> drop n . cycle

shifted :: Int -> Int -> [a] -> [a] shifted src dst s = concat [x, rotated 1 y, b]

 where
   (a, b) = splitAt dst s
   (x, y) = splitAt src a

encode = False

decode = True

main :: IO () main = do

 let chaoWheels =
       chao "HXUCZVAMDSLKPEFJRIGTWOBNYQ" "PTLNBQDEOYSFAVZKGJRIHWXUMC"
     plainText = "WELLDONEISBETTERTHANWELLSAID"
     cipherText = chaoWheels encode plainText
 print plainText
 print cipherText
 print $ chaoWheels decode cipherText</lang>
Output:
"WELLDONEISBETTERTHANWELLSAID"
"OAHQHCNYNXTSZJRRHJBYHQKSOUJY"
"WELLDONEISBETTERTHANWELLSAID"

Java

Translation of: Kotlin

<lang java>import java.util.Arrays;

public class Chaocipher {

   private enum Mode {
       ENCRYPT,
       DECRYPT
   }
   private static final String L_ALPHABET = "HXUCZVAMDSLKPEFJRIGTWOBNYQ";
   private static final String R_ALPHABET = "PTLNBQDEOYSFAVZKGJRIHWXUMC";
   private static int indexOf(char[] a, char c) {
       for (int i = 0; i < a.length; ++i) {
           if (a[i] == c) {
               return i;
           }
       }
       return -1;
   }
   private static String exec(String text, Mode mode) {
       return exec(text, mode, false);
   }
   private static String exec(String text, Mode mode, Boolean showSteps) {
       char[] left = L_ALPHABET.toCharArray();
       char[] right = R_ALPHABET.toCharArray();
       char[] eText = new char[text.length()];
       char[] temp = new char[26];
       for (int i = 0; i < text.length(); ++i) {
           if (showSteps) {
               System.out.printf("%s  %s\n", new String(left), new String(right));
           }
           int index;
           if (mode == Mode.ENCRYPT) {
               index = indexOf(right, text.charAt(i));
               eText[i] = left[index];
           } else {
               index = indexOf(left, text.charAt(i));
               eText[i] = right[index];
           }
           if (i == text.length() - 1) {
               break;
           }
           // permute left
           if (26 - index >= 0) System.arraycopy(left, index, temp, 0, 26 - index);
           System.arraycopy(left, 0, temp, 26 - index, index);
           char store = temp[1];
           System.arraycopy(temp, 2, temp, 1, 12);
           temp[13] = store;
           left = Arrays.copyOf(temp, temp.length);
           // permute right
           if (26 - index >= 0) System.arraycopy(right, index, temp, 0, 26 - index);
           System.arraycopy(right, 0, temp, 26 - index, index);
           store = temp[0];
           System.arraycopy(temp, 1, temp, 0, 25);
           temp[25] = store;
           store = temp[2];
           System.arraycopy(temp, 3, temp, 2, 11);
           temp[13] = store;
           right = Arrays.copyOf(temp, temp.length);
       }
       return new String(eText);
   }
   public static void main(String[] args) {
       String plainText = "WELLDONEISBETTERTHANWELLSAID";
       System.out.printf("The original plaintext is : %s\n", plainText);
       System.out.println("\nThe left and right alphabets after each permutation during encryption are:");
       String cipherText = exec(plainText, Mode.ENCRYPT, true);
       System.out.printf("\nThe cipher text is : %s\n", cipherText);
       String plainText2 = exec(cipherText, Mode.DECRYPT);
       System.out.printf("\nThe recovered plaintext is : %s\n", 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 cipher text is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY

The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID

JavaScript

Translation of: C

Script source <lang javascript>const L_ALPHABET = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"; const R_ALPHABET = "PTLNBQDEOYSFAVZKGJRIHWXUMC";

const ENCRYPT = 0; const DECRYPT = 1;

function setCharAt(str, index, chr) {

   if (index > str.length - 1) return str;
   return str.substr(0, index) + chr + str.substr(index + 1);

}

function chao(text, mode, show_steps) {

   var left = L_ALPHABET;
   var right = R_ALPHABET;
   var out = text;
   var temp = "01234567890123456789012345";
   var i = 0;
   var index, j, store;
   if (show_steps) {
       console.log("The left and right alphabets after each permutation during encryption are :");
   }
   while (i < text.length) {
       if (show_steps) {
           console.log(left + "  " + right);
       }
       if (mode == ENCRYPT) {
           index = right.indexOf(text[i]);
           out = setCharAt(out, i, left[index]);
       } else {
           index = left.indexOf(text[i]);
           out = setCharAt(out, i, right[index]);
       }
       if (i == text.length - 1) {
           break;
       }
       //permute left
       j = index;
       while (j < 26) {
           temp = setCharAt(temp, j - index, left[j])
           j += 1;
       }
       j = 0;
       while (j < index) {
           temp = setCharAt(temp, 26 - index + j, left[j]);
           j += 1;
       }
       store = temp[1];
       j = 2;
       while (j < 14) {
           temp = setCharAt(temp, j - 1, temp[j]);
           j += 1;
       }
       temp = setCharAt(temp, 13, store);
       left = temp;
       //permute right
       j = index;
       while (j < 26) {
           temp = setCharAt(temp, j - index, right[j]);
           j += 1;
       }
       j = 0;
       while (j < index) {
           temp = setCharAt(temp, 26 - index + j, right[j]);
           j += 1;
       }
       store = temp[0];
       j = 1;
       while (j < 26) {
           temp = setCharAt(temp, j - 1, temp[j]);
           j += 1;
       }
       temp = setCharAt(temp, 25, store);
       store = temp[2];
       j = 3;
       while (j < 14) {
           temp = setCharAt(temp, j - 1, temp[j]);
           j += 1;
       }
       temp = setCharAt(temp, 13, store);
       right = temp;
       i += 1;
   }
   return out;

}

function main() {

   var out = document.getElementById("content");
   const plain_text = "WELLDONEISBETTERTHANWELLSAID";

out.innerHTML = "

The original plaintext is : " + plain_text + "

";

   var cipher_text = chao(plain_text, ENCRYPT, true);

out.innerHTML += "

The ciphertext is : " + cipher_text + "

";

   var decipher_text = chao(cipher_text, DECRYPT, false);

out.innerHTML += "

The recovered plaintext is : " + decipher_text + "

";

}</lang>

Solution page <lang html><!DOCTYPE html> <html>

   <head>
       <title>Chaocipher</title>
       <script src="chaocipher.js"></script>
   </head>
   <body onload="main()">
   </body>

</html></lang>

Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID
The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY
The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID

Julia

Modified from the Kotlin and Raku entries. <lang julia>const leftalphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ" const rightalphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC"

function chacocoding(text, encoding, verbose=false)

   left, right = Vector{Char}(leftalphabet), Vector{Char}(rightalphabet)
   len, coded = length(text), similar(Vector{Char}(text))
   for i in 1:len
       verbose && println(String(left), "   ", String(right))
       n = indexin(text[i], encoding ? right : left)[1]
       coded[i] = encoding ? left[n] : right[n]
       if i < len
           left .= circshift(left, -n + 1)
           left[2:14] .= circshift(left[2:14], -1)
           right .= circshift(right, -n)
           right[3:14] .= circshift(right[3:14], -1)
       end
   end
   String(coded)

end

function testchacocipher(txt)

   println("The original plaintext is: $txt")
   println("\nThe left and right alphabets for each character during encryption are:")
   encoded = chacocoding(txt, true, true)
   println("\nThe encoded ciphertext is: $encoded")
   decoded = chacocoding(encoded, false)
   println("\nDecoded, the recovered plaintext is: $decoded")

end

testchacocipher("WELLDONEISBETTERTHANWELLSAID")

</lang>

Output:
The original plaintext is: WELLDONEISBETTERTHANWELLSAID

The left and right alphabets for each character 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 encoded ciphertext is: OAHQHCNYNXTSZJRRHJBYHQKSOUJY

Decoded, the recovered plaintext is: WELLDONEISBETTERTHANWELLSAID

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


Lua

<lang lua>-- Chaocipher, in Lua, 6/19/2020 db local Chaocipher = {

 ct = "HXUCZVAMDSLKPEFJRIGTWOBNYQ",
 pt = "PTLNBQDEOYSFAVZKGJRIHWXUMC",
 encrypt = function(self, text) return self:_encdec(text, true) end,
 decrypt = function(self, text) return self:_encdec(text, false) end,
 _encdec = function(self, text, encflag)
   local ct, pt, s = self.ct, self.pt, ""
   local cshl = function(s,i) return s:sub(i) .. s:sub(1,i-1) end
   local sshl = function(s,i) return s:sub(1,i-1) .. s:sub(i+1,14) .. s:sub(i,i) .. s:sub(15) end
   for ch in text:gmatch(".") do
     local i = (encflag and pt or ct):find(ch)
     s = s .. (encflag and ct or pt):sub(i,i)
     if encflag then print(ct, pt, ct:sub(i,i), pt:sub(i,i)) end
     ct, pt = sshl(cshl(ct, i), 2), sshl(cshl(pt, i+1), 3)
   end
   return s
 end,

} local plainText = "WELLDONEISBETTERTHANWELLSAID" local encryptText = Chaocipher:encrypt(plainText) local decryptText = Chaocipher:decrypt(encryptText) print() print("The original text was: " .. plainText) print("The encrypted text is: " .. encryptText) print("The decrypted text is: " .. decryptText)</lang>

Output:
HXUCZVAMDSLKPEFJRIGTWOBNYQ      PTLNBQDEOYSFAVZKGJRIHWXUMC      O       W
ONYQHXUCZVAMDBSLKPEFJRIGTW      XUCPTLNBQDEOYMSFAVZKGJRIHW      A       E
ADBSLKPEFJRIGMTWONYQHXUCZV      OYSFAVZKGJRIHMWXUCPTLNBQDE      H       L
HUCZVADBSLKPEXFJRIGMTWONYQ      NBDEOYSFAVZKGQJRIHMWXUCPTL      Q       L
QUCZVADBSLKPEHXFJRIGMTWONY      NBEOYSFAVZKGQDJRIHMWXUCPTL      H       D
HFJRIGMTWONYQXUCZVADBSLKPE      JRHMWXUCPTLNBIEOYSFAVZKGQD      C       O
CVADBSLKPEHFJZRIGMTWONYQXU      YSAVZKGQDJRHMFWXUCPTLNBIEO      N       N
NQXUCVADBSLKPYEHFJZRIGMTWO      BIOYSAVZKGQDJERHMFWXUCPTLN      Y       E
YHFJZRIGMTWONEQXUCVADBSLKP      RHFWXUCPTLNBIMOYSAVZKGQDJE      N       I
NQXUCVADBSLKPEYHFJZRIGMTWO      MOSAVZKGQDJERYHFWXUCPTLNBI      X       S
XCVADBSLKPEYHUFJZRIGMTWONQ      AVKGQDJERYHFWZXUCPTLNBIMOS      T       B
TONQXCVADBSLKWPEYHUFJZRIGM      IMSAVKGQDJERYOHFWZXUCPTLNB      S       E
SKWPEYHUFJZRILGMTONQXCVADB      RYHFWZXUCPTLNOBIMSAVKGQDJE      Z       T
ZILGMTONQXCVARDBSKWPEYHUFJ      LNBIMSAVKGQDJOERYHFWZXUCPT      J       T
JILGMTONQXCVAZRDBSKWPEYHUF      LNIMSAVKGQDJOBERYHFWZXUCPT      R       E
RBSKWPEYHUFJIDLGMTONQXCVAZ      RYFWZXUCPTLNIHMSAVKGQDJOBE      R       R
RSKWPEYHUFJIDBLGMTONQXCVAZ      YFZXUCPTLNIHMWSAVKGQDJOBER      H       T
HFJIDBLGMTONQUXCVAZRSKWPEY      LNHMWSAVKGQDJIOBERYFZXUCPT      J       H
JDBLGMTONQUXCIVAZRSKWPEYHF      MWAVKGQDJIOBESRYFZXUCPTLNH      B       A
BGMTONQUXCIVALZRSKWPEYHFJD      VKQDJIOBESRYFGZXUCPTLNHMWA      Y       N
YFJDBGMTONQUXHCIVALZRSKWPE      HMAVKQDJIOBESWRYFGZXUCPTLN      H       W
HIVALZRSKWPEYCFJDBGMTONQUX      RYGZXUCPTLNHMFAVKQDJIOBESW      Q       E
QXHIVALZRSKWPUEYCFJDBGMTON      SWYGZXUCPTLNHRMFAVKQDJIOBE      K       L
KPUEYCFJDBGMTWONQXHIVALZRS      NHMFAVKQDJIOBRESWYGZXUCPTL      S       L
SPUEYCFJDBGMTKWONQXHIVALZR      NHFAVKQDJIOBRMESWYGZXUCPTL      O       S
OQXHIVALZRSPUNEYCFJDBGMTKW      WYZXUCPTLNHFAGVKQDJIOBRMES      U       A
UEYCFJDBGMTKWNOQXHIVALZRSP      GVQDJIOBRMESWKYZXUCPTLNHFA      J       I
JBGMTKWNOQXHIDVALZRSPUEYCF      OBMESWKYZXUCPRTLNHFAGVQDJI      Y       D

The original text was:  WELLDONEISBETTERTHANWELLSAID
The encrypted text is:  OAHQHCNYNXTSZJRRHJBYHQKSOUJY
The decrypted text is:  WELLDONEISBETTERTHANWELLSAID

Nim

Translation of: Kotlin

<lang nim>import strformat

type

 Mode = enum
   Encrypt
   Decrypt

const lAlphabet: string = "HXUCZVAMDSLKPEFJRIGTWOBNYQ" const rAlphabet: string = "PTLNBQDEOYSFAVZKGJRIHWXUMC"

proc chao(text: string, mode: Mode, verbose: bool = false): string =

 var left = lAlphabet
 var right = rAlphabet
 var eText = newSeq[char](text.len)
 var temp: array[26, char]
 
 for i in 0..<text.len:
   if verbose:
     echo &"{left}  {right}"
   var index: int
   if mode == Encrypt:
     index = right.find(text[i])
     eText[i] = left[index]
   else:
     index = left.find(text[i])
     eText[i] = right[index]
   if (i == text.len - 1):
     break
   
   # permute left
   for j in index..25:
     temp[j - index] = left[j]
   for j in 0..<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 = ""
   for i in temp:
     left &= $i
   
   # permute right
   for j in index..25:
     temp[j - index] = right[j]
   for j in 0..<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 = ""
   for i in temp:
     right &= $i
  
 for i in eText:
   result &= $i

var plainText = "WELLDONEISBETTERTHANWELLSAID" echo &"The original plaintext is: {plainText}" echo "\nThe left and right alphabets after each permutation during encryption are:\n" var cipherText = chao(plainText, Encrypt, true) echo &"\nThe ciphertext is: {cipherText}" var plainText2 = chao(cipherText, Decrypt, false) echo &"\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

Objeck

Translation of: Kotlin

<lang objeck>class Chaocipher {

 L_ALPHABET : static : Char[];
 R_ALPHABET : static : Char[];
 function : Main(args : String[]) ~ Nil {
   L_ALPHABET := "HXUCZVAMDSLKPEFJRIGTWOBNYQ"->ToCharArray();
   R_ALPHABET := "PTLNBQDEOYSFAVZKGJRIHWXUMC"->ToCharArray();
   plainText := "WELLDONEISBETTERTHANWELLSAID"->ToCharArray();
   System.IO.Console->Print("The original plaintext is: ")->PrintLine(plainText);
   "\nThe left and right alphabets after each permutation during encryption are:\n"->PrintLine();
   cipherText := Chao(plainText, Mode->ENCRYPT, true);
   System.IO.Console->Print("\nThe ciphertext is: ")->PrintLine(cipherText);
   plainText2 := Chao(cipherText, Mode->DECRYPT, false);
   System.IO.Console->Print("The recovered plaintext is: ")->PrintLine(plainText2);
 }
 function : Chao(in : Char[], mode : Mode, show_steps : Bool) ~ Char[] {  
   i : Int; j : Int; index : Int;
   store : Char;
   len := in->Size();
   left := Char->New[26];   right := Char->New[26]; temp := Char->New[26];
   eText := Char->New[len];
   Runtime->Copy(left, 0, L_ALPHABET, 0, L_ALPHABET->Size());
   Runtime->Copy(right, 0, R_ALPHABET, 0, R_ALPHABET->Size());
   for(i := 0; i < len; i += 1;) {
     if (show_steps) {
       System.IO.Console->Print(left)->Print(' ')->PrintLine(right);
     };
     if (mode = Mode->ENCRYPT) {
       index := IndexOf(right, in[i]);
       eText[i] := left[index];
     }
     else {
       index := IndexOf(left, in[i]);
       eText[i] := right[index];
     };
     if (i = len - 1) {
       break;
     };
     # left
     for(j := index; j < 26; j += 1;) { temp[j - index] := left[j]; };
     for(j :=0; j < index; j += 1;) { temp[26 - index + j] := left[j]; };
     store := temp[1];
     for(j := 2; j < 14; j += 1;) { temp[j - 1] := temp[j]; };
     temp[13] := store;
     Runtime->Copy(left, 0, temp, 0, temp->Size());
     # right
     for(j := index; j < 26; j += 1;) { temp[j - index] := right[j]; };
     for(j :=0; j < index; j += 1;) { temp[26 - index + j] := right[j]; };
     store := temp[0];
     for(j :=1; j < 26; j += 1;) { temp[j - 1] := temp[j]; };
         temp[25] := store;
         store := temp[2];
         for(j := 3; j < 14; j += 1;) { temp[j - 1] := temp[j]; };
         temp[13] := store;
         Runtime->Copy(right, 0, temp, 0, temp->Size());
   };
       
   return eText;
 }
 function : IndexOf(str : Char[], c : Char) ~ Int {
   for(i := 0; i < str->Size(); i += 1;) {
     if(c = str[i]) {
       return i;
     };
   };
   return -1;
 }
 enum Mode { ENCRYPT, DECRYPT }  

}</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: Raku

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

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

Procedural

<lang python># Python3 implementation of Chaocipher

  1. left wheel = ciphertext wheel
  2. 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

Functional

Translation of: Haskell
Works with: Python version 3.7

<lang python>Chaocipher

from itertools import chain, cycle, islice


  1. chao :: String -> String -> Bool -> String -> String

def chao(l):

   Chaocipher encoding or decoding for the given
      left and right 'wheels'.
      A ciphertext is returned if the boolean flag
      is True, and a plaintext if the flag is False.
   
   def go(l, r, plain, xxs):
       if xxs:
           (src, dst) = (l, r) if plain else (r, l)
           (x, xs) = (xxs[0], xxs[1:])
           def chaoProcess(n):
               return [dst[n]] + go(
                   shifted(1)(14)(rotated(n, l)),
                   compose(shifted(2)(14))(shifted(0)(26))(
                       rotated(n, r)
                   ),
                   plain,
                   xs
               )
           return maybe()(chaoProcess)(
               elemIndex(x)(src)
           )
       else:
           return []
   return lambda r: lambda plain: lambda xxs: concat(go(
       l, r, plain, xxs
   ))


  1. rotated :: Int -> [a] -> [a]

def rotated(z, s):

   Rotation of string s by z characters.
   return take(len(s))(
       drop(z)(
           cycle(s)
       )
   )


  1. shifted :: Int -> Int -> [a] -> [a]

def shifted(src):

   The string s with a set of its characters cyclically
      shifted from a source index to a destination index.
   
   def go(dst, s):
       (a, b) = splitAt(dst)(s)
       (x, y) = splitAt(src)(a)
       return concat([x, rotated(1, y), b])
   return lambda dst: lambda s: go(dst, s)


  1. TEST ----------------------------------------------------
  2. main :: IO ()

def main():

   Print the plain text, followed by
      a corresponding cipher text,
      and a decode of that cipher text.
   
   chaoWheels = chao(
       "HXUCZVAMDSLKPEFJRIGTWOBNYQ"
   )(
       "PTLNBQDEOYSFAVZKGJRIHWXUMC"
   )
   plainText = "WELLDONEISBETTERTHANWELLSAID"
   cipherText = chaoWheels(False)(plainText)
   print(plainText)
   print(cipherText)
   print(
       chaoWheels(True)(cipherText)
   )


  1. GENERIC -------------------------------------------------
  1. Just :: a -> Maybe a

def Just(x):

   Constructor for an inhabited Maybe (option type) value.
      Wrapper containing the result of a computation.
   
   return {'type': 'Maybe', 'Nothing': False, 'Just': x}


  1. Nothing :: Maybe a

def Nothing():

   Constructor for an empty Maybe (option type) value.
      Empty wrapper returned where a computation is not possible.
   
   return {'type': 'Maybe', 'Nothing': True}


  1. compose (<<<) :: (b -> c) -> (a -> b) -> a -> c

def compose(g):

   Right to left function composition.
   return lambda f: lambda x: g(f(x))


  1. concat :: a -> [a]
  2. concat :: [String] -> String

def concat(xs):

   The concatenation of all the elements
      in a list or iterable.
   
   def f(ys):
       zs = list(chain(*ys))
       return .join(zs) if isinstance(ys[0], str) else zs
   return (
       f(xs) if isinstance(xs, list) else (
           chain.from_iterable(xs)
       )
   ) if xs else []


  1. drop :: Int -> [a] -> [a]
  2. drop :: Int -> String -> String

def drop(n):

   The sublist of xs beginning at
      (zero-based) index n.
   
   def go(xs):
       if isinstance(xs, (list, tuple, str)):
           return xs[n:]
       else:
           take(n)(xs)
           return xs
   return lambda xs: go(xs)


  1. elemIndex :: Eq a => a -> [a] -> Maybe Int

def elemIndex(x):

   Just the index of the first element in xs
      which is equal to x,
      or Nothing if there is no such element.
   
   def go(xs):
       try:
           return Just(xs.index(x))
       except ValueError:
           return Nothing()
   return lambda xs: go(xs)


  1. maybe :: b -> (a -> b) -> Maybe a -> b

def maybe(v):

   Either the default value v, if m is Nothing,
      or the application of f to x,
      where m is Just(x).
   
   return lambda f: lambda m: v if None is m or m.get('Nothing') else (
       f(m.get('Just'))
   )


  1. splitAt :: Int -> [a] -> ([a], [a])

def splitAt(n):

   A tuple pairing the prefix of length n
      with the rest of xs.
   
   return lambda xs: (xs[0:n], xs[n:])


  1. take :: Int -> [a] -> [a]
  2. take :: Int -> String -> String

def take(n):

   The prefix of xs of length n,
      or xs itself if n > length xs.
   
   return lambda xs: (
       xs[0:n]
       if isinstance(xs, (list, tuple))
       else list(islice(xs, n))
   )


  1. MAIN ---

if __name__ == '__main__':

   main()</lang>
Output:
WELLDONEISBETTERTHANWELLSAID
OAHQHCNYNXTSZJRRHJBYHQKSOUJY
WELLDONEISBETTERTHANWELLSAID

Raku

(formerly 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

Ruby

<lang ruby>txt = "WELLDONEISBETTERTHANWELLSAID" @left = "HXUCZVAMDSLKPEFJRIGTWOBNYQ".chars @right = "PTLNBQDEOYSFAVZKGJRIHWXUMC".chars

def encrypt(char)

 coded_char = @left[@right.index(char)]
 @left.rotate!(@left.index(coded_char))
 part = @left.slice!(1,13).rotate
 @left.insert(1, *part)
 @right.rotate!(@right.index(char)+1)
 part = @right.slice!(2,12).rotate
 @right.insert(2, *part)
 
 @left[0]

end

puts txt.each_char.map{|c| encrypt(c) }.join </lang>

Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY

Rust

<lang rust>const LEFT_ALPHABET_CT: &str = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"; const RIGHT_ALPHABET_PT: &str = "PTLNBQDEOYSFAVZKGJRIHWXUMC"; const ZENITH: usize = 0; const NADIR: usize = 12; const SEQUENCE: &str = "WELLDONEISBETTERTHANWELLSAID";

fn cipher(letter: &char, left: &String, right: &String) -> (usize, char) {

   let pos = right.find(*letter).unwrap();
   let cipher = left.chars().nth(pos).unwrap();
   (pos, cipher)

}

fn main() {

   let mut left = LEFT_ALPHABET_CT.to_string();
   let mut right = RIGHT_ALPHABET_PT.to_string();
   let ciphertext = SEQUENCE.chars()
       .map(|letter| {
           let (pos, cipher_char) = cipher(&letter, &left, &right);
           left = format!("{}{}", &left[pos..], &left[..pos]);
           left = format!("{}{}{}{}", &left[ZENITH..1], &left[2..NADIR+2], &left[1..2], &left[NADIR+2..]);
           if pos != right.len() - 1 {
               right = format!("{}{}", &right[pos + 1..], &right[..pos + 1]);
           }
           right = format!("{}{}{}{}", &right[ZENITH..2], &right[3..NADIR+2], &right[2..3], &right[NADIR+2..]);
           cipher_char
       })
       .collect::<String>();
   println!("Plaintext: {}", SEQUENCE);
   println!("Ciphertext: {}", ciphertext);

}</lang>

Output:
Plaintext: WELLDONEISBETTERTHANWELLSAID
Ciphertext: OAHQHCNYNXTSZJRRHJBYHQKSOUJY

Tailspin

<lang tailspin> templates chaocipher&{left:,right:,decode:}

 templates permute
   def ctshift: [ $@chaocipher.ct($..last)..., $@chaocipher.ct(1..$-1)...];
   def p1: $ mod 26 + 1;
   def ptshift: [ $@chaocipher.pt($p1..last)..., $@chaocipher.pt(1..$p1-1)...];
   ..|@chaocipher: { ct: [ $ctshift(1), $ctshift(3..14)..., $ctshift(2), $ctshift(15..last)...],
     pt: [ $ptshift(1..2)..., $ptshift(4..14)..., $ptshift(3), $ptshift(15..last)...] };
 end permute
 @: {ct:[ $left... ], pt: [ $right... ], result:[]};
 $... -> #
 '$@.result...;' !
 when <?($decode <=0>)> do
   def plain: $;
   def index: $@.pt -> \[i](<=$plain> $i!\) -> $(1);
   ..|@.result: $@.ct($index);
   $index -> permute -> !VOID
 otherwise
   def cipher: $;
   def index: $@.ct -> \[i](<=$cipher> $i!\) -> $(1);
   ..|@.result: $@.pt($index);
   $index -> permute -> !VOID

end chaocipher

'WELLDONEISBETTERTHANWELLSAID' -> chaocipher&{left:'HXUCZVAMDSLKPEFJRIGTWOBNYQ', right:'PTLNBQDEOYSFAVZKGJRIHWXUMC',decode:0} -> '$; ' -> !OUT::write

'OAHQHCNYNXTSZJRRHJBYHQKSOUJY' -> chaocipher&{left:'HXUCZVAMDSLKPEFJRIGTWOBNYQ', right:'PTLNBQDEOYSFAVZKGJRIHWXUMC',decode:1} -> '$; ' -> !OUT::write </lang>

Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY
WELLDONEISBETTERTHANWELLSAID

Visual Basic .NET

Translation of: C#

<lang vbnet>Module Module1

   ReadOnly L_ALPHABET As String = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"
   ReadOnly R_ALPHABET As String = "PTLNBQDEOYSFAVZKGJRIHWXUMC"
   Enum Mode
       ENCRYPT
       DECRYPT
   End Enum
   Function Exec(text As String, mode As Mode, Optional showSteps As Boolean = False) As String
       Dim left = L_ALPHABET.ToCharArray()
       Dim right = R_ALPHABET.ToCharArray()
       Dim eText(text.Length - 1) As Char
       Dim temp(25) As Char
       For i = 0 To text.Length - 1
           If showSteps Then Console.WriteLine("{0} {1}", String.Join("", left), String.Join("", right))
           Dim index As Integer
           If mode = Mode.ENCRYPT Then
               index = Array.IndexOf(right, text(i))
               eText(i) = left(index)
           Else
               index = Array.IndexOf(left, text(i))
               eText(i) = right(index)
           End If
           If i = text.Length - 1 Then Exit For
           'permute left
           For j = index To 25
               temp(j - index) = left(j)
           Next
           For j = 0 To index - 1
               temp(26 - index + j) = left(j)
           Next
           Dim store = temp(1)
           For j = 2 To 13
               temp(j - 1) = temp(j)
           Next
           temp(13) = store
           temp.CopyTo(left, 0)
           'permute right
           For j = index To 25
               temp(j - index) = right(j)
           Next
           For j = 0 To index - 1
               temp(26 - index + j) = right(j)
           Next
           store = temp(0)
           For j = 1 To 25
               temp(j - 1) = temp(j)
           Next
           temp(25) = store
           store = temp(2)
           For j = 3 To 13
               temp(j - 1) = temp(j)
           Next
           temp(13) = store
           temp.CopyTo(right, 0)
       Next
       Return eText
   End Function
   Sub Main()
       Dim plainText = "WELLDONEISBETTERTHANWELLSAID"
       Console.WriteLine("The original plaintext is : {0}", plainText)
       Console.WriteLine(vbNewLine + "The left and right alphabets after each permutation during encryption are :" + vbNewLine)
       Dim cipherText = Exec(plainText, Mode.ENCRYPT, True)
       Console.WriteLine(vbNewLine + "The ciphertext is : {0}", cipherText)
       Dim plainText2 = Exec(cipherText, Mode.DECRYPT)
       Console.WriteLine(vbNewLine + "The recovered plaintext is : {0}", plainText2)
   End Sub

End Module</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

Wren

Translation of: Kotlin

<lang ecmascript>class Chao {

   static encrypt { 0 }
   static decrypt { 1 }
   static exec(text, mode, showSteps) {
       var len = text.count
       if (len != text.bytes.count) Fiber.abort("Text contains non-ASCII characters.")
       var left  = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"
       var right = "PTLNBQDEOYSFAVZKGJRIHWXUMC"
       var eText = List.filled(len, "")
       var temp  = List.filled(26, "")
       for (i in 0...len) {
           if (showSteps) System.print("%(left)  %(right)")
           var index
           if (mode == Chao.encrypt) {
               index = right.indexOf(text[i])
               eText[i] = left[index]
           } else {
               index = left.indexOf(text[i])
               eText[i] = right[index]
           }
           if (i == len - 1) break
           // permute left
           for (j in index..25) temp[j-index] = left[j]
           for (j in 0...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 = temp.join()
           // permute right
           for (j in index..25) temp[j-index] = right[j]
           for (j in 0...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 = temp.join()
       }
       return eText.join()
   }

}

var plainText = "WELLDONEISBETTERTHANWELLSAID" System.print("The original plaintext is : %(plainText)") System.write("\nThe left and right alphabets after each permutation ") System.print("during encryption are :\n") var cipherText = Chao.exec(plainText, Chao.encrypt, true) System.print("\nThe ciphertext is : %(cipherText)") var plainText2 = Chao.exec(cipherText, Chao.decrypt, false) System.print("\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

zkl

Translation of: Raku

<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