Chaocipher: Difference between revisions
m (→{{header|Phix}}: added syntax colouring, marked p2js compatible) |
(insert →Pascal) |
||
Line 2,265: | Line 2,265: | ||
The recovered plaintext is: WELLDONEISBETTERTHANWELLSAID |
The recovered plaintext is: WELLDONEISBETTERTHANWELLSAID |
||
</pre> |
</pre> |
||
=={{header|Pascal}}== |
|||
{{works with|Extended Pascal}} |
|||
<lang pascal>program chaocipher(input, output); |
|||
const |
|||
{ This denotes a `set` literal: } |
|||
alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', |
|||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; |
|||
{ The `card` function is an Extended Pascal (ISO 10206) extension. } |
|||
alphabetCardinality = card(alphabet); |
|||
{ 1st character denotes “zenith”. } |
|||
zenith = 1; |
|||
{ In a 26-character alphabet the 14th character denotes “nadir”. } |
|||
nadir = alphabetCardinality div 2 + 1; |
|||
{ For simplicity use compile-time-defined maximum lengths. } |
|||
messageMaximumLength = 80; |
|||
type |
|||
{ This “discriminates” the Extended Pascal schema data type `string` to be } |
|||
{ capable of holding strings up to `alphabetCardinality` `char` values. } |
|||
map = string(alphabetCardinality); |
|||
{ Variables of this data type can only assume integer values within 1..26: } |
|||
mapCharacterIndex = 1..alphabetCardinality; |
|||
{ Later used as a buffer for the input/output. } |
|||
message = string(messageMaximumLength); |
|||
messageCharacterIndex = 1..messageMaximumLength; |
|||
{ Stores a key for the Chaocipher algorithm. } |
|||
key = record |
|||
cipherText: map; |
|||
plainText: map; |
|||
end; |
|||
{ --- auxilliary routines ---------------------------------------------- } |
|||
{ |
|||
\brief verifies that a key is valid for the Chaocipher |
|||
\param sample a potential `key` for a Chaocipher |
|||
\return `true` iff \param sample is an acceptable `key` |
|||
} |
|||
{ `protected` (Extended Pascal extension) denotes an immutable parameter. } |
|||
function isValid(protected sample: key): Boolean; |
|||
{ Determines whether a `map` contains all characters of `alphabet`. } |
|||
{ Nesting this function allows for a neat expression below. } |
|||
function isComplete(text: map): Boolean; |
|||
var |
|||
i: integer; |
|||
{ `value []` will initialize this variable to an empty set value. } |
|||
{ This is an Extended Pascal (ISO 10206) extension. } |
|||
s: set of char value []; |
|||
begin |
|||
{ NB: In Pascal `for`-loop limits are inclusive. } |
|||
for i := 1 to length(text) do |
|||
begin |
|||
{ This adds the set containing one character to the set `s`. } |
|||
s := s + [text[i]] |
|||
end; |
|||
isComplete := card(s) = alphabetCardinality |
|||
end; |
|||
begin |
|||
{ This way `sample.cipherText` can be simply written as `cipherText`. } |
|||
with sample do |
|||
begin |
|||
{ `and_then` is an EP extension indicating “lazy evaluation”. } |
|||
isValid := (alphabetCardinality > 8) and_then |
|||
isComplete(cipherText) and_then isComplete(plainText) |
|||
end |
|||
end; |
|||
{ |
|||
\brief permutes a key for the next encryption/decryption step |
|||
\param shift the index of the characters just substituted |
|||
} |
|||
{ `var` means the parameter value will be modified _at_ the call site. } |
|||
procedure permute(var state: key; protected shift: mapCharacterIndex); |
|||
begin |
|||
with state do |
|||
begin |
|||
{ Indices in `cipherText[1..pred(shift)]` _must_ be non-descending: } |
|||
if shift > 1 then |
|||
begin |
|||
cipherText := subStr(cipherText, shift) + cipherText[1..pred(shift)] |
|||
{ `subStr(str, ini)` is equivalent to `str[ini..length(str)]`. } |
|||
end; |
|||
{ Likewise, `succ(shift)` must be a valid index in `plainText`: } |
|||
if shift < alphabetCardinality then |
|||
begin |
|||
plainText := subStr(plainText, succ(shift)) + plainText[1..shift] |
|||
end; |
|||
{ If it does _not_ _alter_ the _entire_ string’s _length_, you can } |
|||
{ modify parts of a string like this (Extended Pascal extension): } |
|||
cipherText[zenith+1..nadir] := cipherText[zenith+2..nadir] + cipherText[zenith+1]; |
|||
plainText[zenith+2..nadir] := plainText[zenith+3..nadir] + plainText[zenith+2] |
|||
end |
|||
end; |
|||
{ --- the core routine of the algorithm -------------------------------- } |
|||
{ |
|||
\brief performs Chaocipher common steps |
|||
\param line the message to encrypt/decrypt |
|||
\param state the initial key to start encrpytion/decryption with |
|||
\param locate a function determining the 2-tuple index in the key |
|||
\param substitute the procedure substituting the correct characters |
|||
} |
|||
procedure chaocipher( |
|||
var line: message; |
|||
var state: key; |
|||
{ These are “routine parameters”. Essentially the address of a routine } |
|||
{ matching the specified routine signature is passed to `chaocipher`. } |
|||
function locate(protected i: messageCharacterIndex): mapCharacterIndex; |
|||
procedure substitute( |
|||
protected i: messageCharacterIndex; |
|||
protected z: mapCharacterIndex |
|||
) |
|||
); |
|||
var |
|||
{ For demonstration purposes: In this program } |
|||
{ `line.capacity` refers to `messageMaximumLength`. } |
|||
i: 1..line.capacity; |
|||
substitutionPairIndex: mapCharacterIndex; |
|||
begin |
|||
{ Don’t trust user input, even though this is just a RosettaCode example. } |
|||
if not isValid(state) then |
|||
begin |
|||
writeLn('Error: Key is invalid. Got:'); |
|||
writeLn('Cipher text: ', state.cipherText); |
|||
writeLn(' Plain text: ', state.plainText); |
|||
halt |
|||
end; |
|||
for i := 1 to length(line) do |
|||
begin |
|||
{ We’ll better skip characters that aren’t in the `alphabet`. } |
|||
if line[i] in alphabet then |
|||
begin |
|||
{ Here you see the beauty of using routine parameters. } |
|||
{ Depending on whether we’re encrypting or decrypting, } |
|||
{ you need to find a character in the `cipherText` or } |
|||
{ `plainText` key value respectively, yet the basic order |
|||
{ of the steps are still the same. } |
|||
substitutionPairIndex := locate(i); |
|||
substitute(i, substitutionPairIndex); |
|||
permute(state, substitutionPairIndex) |
|||
end |
|||
end |
|||
end; |
|||
{ --- entry routines --------------------------------------------------- } |
|||
{ |
|||
\brief encrypts a message according to Chaocipher |
|||
} |
|||
{ Note: without `var` or `protected` both `encrypt` and `decrypt`get } |
|||
{ and have their own independent copies of the parameter values. } |
|||
function encrypt(line: message; state: key): message; |
|||
function encryptor(protected i: messageCharacterIndex): mapCharacterIndex; |
|||
begin |
|||
encryptor := index(state.plainText, line[i]) |
|||
end; |
|||
procedure substitutor( |
|||
protected i: messageCharacterIndex; |
|||
protected z: mapCharacterIndex |
|||
); |
|||
begin |
|||
line[i] := state.cipherText[z] |
|||
end; |
|||
begin |
|||
chaocipher(line, state, encryptor, substitutor); |
|||
encrypt := line |
|||
end; |
|||
function decrypt(line: message; state: key): message; |
|||
function decryptor(protected i: messageCharacterIndex): mapCharacterIndex; |
|||
begin |
|||
decryptor := index(state.cipherText, line[i]) |
|||
end; |
|||
procedure substitutor( |
|||
protected i: messageCharacterIndex; |
|||
protected z: mapCharacterIndex |
|||
); |
|||
begin |
|||
line[i] := state.plainText[z] |
|||
end; |
|||
begin |
|||
chaocipher(line, state, decryptor, substitutor); |
|||
decrypt := line |
|||
end; |
|||
{ === MAIN ============================================================= } |
|||
var |
|||
exampleKey: key; |
|||
line: message; |
|||
begin |
|||
{ Instead of writing `exampleKey.cipherText := '…', you can } |
|||
{ write in Extended Pascal a `record` literal like this: } |
|||
exampleKey := key[ |
|||
cipherText: 'HXUCZVAMDSLKPEFJRIGTWOBNYQ'; |
|||
plainText: 'PTLNBQDEOYSFAVZKGJRIHWXUMC'; |
|||
]; |
|||
{ `EOF` is shorthand for `EOF(input)`. } |
|||
while not EOF do |
|||
begin |
|||
{ `readLn(line)` is shorthand for `readLn(input, line)`. } |
|||
readLn(line); |
|||
line := encrypt(line, exampleKey); |
|||
writeLn(decrypt(line, exampleKey)); |
|||
{ Likewise, `writeLn(line)` is short for `writeLn(output, line)`. } |
|||
writeLn(line) |
|||
end |
|||
end.</lang> |
|||
{{in}} |
|||
WELLDONEISBETTERTHANWELLSAID |
|||
{{out}} |
|||
WELLDONEISBETTERTHANWELLSAID |
|||
OAHQHCNYNXTSZJRRHJBYHQKSOUJY |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
Revision as of 21:27, 20 May 2022
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.
11l
<lang 11l>F correct_case(string)
R string.filter(s -> s.is_alpha()).map(s -> s.uppercase()).join(‘’)
F permu(String alp; num)
R alp[num..]‘’alp[0 .< num]
F rotate_wheels(lalph, ralph, key)
V newin = ralph.index(key) R (permu(lalph, newin), permu(ralph, newin))
F scramble_wheels(String =lalph, String =ralph)
lalph = lalph[0]‘’lalph[2.<14]‘’lalph[1]‘’lalph[14..] ralph = ralph[1.<3]‘’ralph[4.<15]‘’ralph[3]‘’ralph[15..]‘’ralph[0] R (lalph, ralph)
F do_chao(=msg, =lalpha, =ralpha, en = 1B, show = 0B)
msg = correct_case(msg) V out = ‘’ I show print(‘=’ * 54) print((10 * ‘ ’)‘left:’(21 * ‘ ’)‘right: ’) print(‘=’ * 54) print(lalpha‘ ’ralpha" \n") L(l) msg I en (lalpha, ralpha) = rotate_wheels(lalpha, ralpha, l) out ‘’= lalpha[0] E (ralpha, lalpha) = rotate_wheels(ralpha, lalpha, l) out ‘’= ralpha[0] (lalpha, ralpha) = scramble_wheels(lalpha, ralpha) I show print(lalpha‘ ’ralpha) R out
V lalpha = ‘HXUCZVAMDSLKPEFJRIGTWOBNYQ’ V ralpha = ‘PTLNBQDEOYSFAVZKGJRIHWXUMC’ V msg = ‘WELLDONEISBETTERTHANWELLSAID’
print(‘L: ’lalpha) print(‘R: ’ralpha) print(‘I: ’msg) V o = do_chao(msg, lalpha, ralpha, 1B, 0B) print(‘O: ’o) print(‘D: ’do_chao(o, lalpha, ralpha, 0B, 0B)) print()
do_chao(msg, lalpha, ralpha, 1B, 1B)</lang>
- Output:
L: HXUCZVAMDSLKPEFJRIGTWOBNYQ R: PTLNBQDEOYSFAVZKGJRIHWXUMC I: WELLDONEISBETTERTHANWELLSAID O: OAHQHCNYNXTSZJRRHJBYHQKSOUJY D: WELLDONEISBETTERTHANWELLSAID ====================================================== 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
Ada
This solution uses array slices to permute the left and right strings. Use of slices clarifies the looping logic. Ada strings are indexed with the predefined subtype Positive which begins at 1. <lang Ada> with Ada.Text_IO; use Ada.Text_IO;
procedure chao_slices 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); offset : Natural;
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 -- The array value permutations are performed using array slices -- rather than explicit loops
if index > 1 then offset := 26 - index; temp (1 .. offset + 1) := left (index .. index + offset);
temp (offset + 2 .. 26) := left (1 .. index - 1); store := temp (2);
temp (2 .. 13) := temp (3 .. 14); temp (14) := store; left := temp;
-- permute right -- The array value permutations are performed using array slices -- rather than explicit loops
temp (1 .. offset + 1) := right (index .. index + offset);
temp (offset + 2 .. 26) := right (1 .. index - 1); store := temp (1);
temp (1 .. 25) := temp (2 .. 26); temp (26) := store; store := temp (3);
temp (3 .. 13) := temp (4 .. 14); temp (14) := store; right := temp; end if;
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 chao_slices; </lang>
- Output:
The original text 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 RBSKWPEYHUFJIDLGMTONQXCVAZ RYFWZXUCPTLNIHMSAVKGQDJOBE UJIDLGMTONQXCFVAZRBSKWPEYH LNHMSAVKGQDJOIBERYFWZXUCPT ILGMTONQXCFVADZRBSKWPEYHUJ MSVKGQDJOIBERAYFWZXUCPTLNH DRBSKWPEYHUJIZLGMTONQXCFVA YFZXUCPTLNHMSWVKGQDJOIBERA HJIZLGMTONQXCUFVADRBSKWPEY HMWVKGQDJOIBESRAYFZXUCPTLN ILGMTONQXCUFVZADRBSKWPEYHJ VKQDJOIBESRAYGFZXUCPTLNHMW XUFVZADRBSKWPCEYHJILGMTONQ SRYGFZXUCPTLNAHMWVKQDJOIBE WCEYHJILGMTONPQXUFVZADRBSK NAMWVKQDJOIBEHSRYGFZXUCPTL KCEYHJILGMTONWPQXUFVZADRBS NAWVKQDJOIBEHMSRYGFZXUCPTL PXUFVZADRBSKCQEYHJILGMTONW RYFZXUCPTLNAWGVKQDJOIBEHMS KQEYHJILGMTONCWPXUFVZADRBS WGKQDJOIBEHMSVRYFZXUCPTLNA LMTONCWPXUFVZGADRBSKQEYHJI BEMSVRYFZXUCPHTLNAWGKQDJOI The ciphertext is : OAHQHCNYNXTSZJRRUIDHIXWKPKLY The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
AppleScript
<lang applescript>-- Chaocipher algorithm by J.F.Byrne 1918. on chaocipher(input, |key|, mode)
-- input: text to be enciphered or deciphered. -- |key|: script object or record with leftAlpha and rightAlpha properties, each of whose values is a shuffled alphabet text. -- mode: the text "encipher" or "decipher". script o property inputChars : input's characters property leftAlpha : |key|'s leftAlpha's characters property rightAlpha : |key|'s rightAlpha's characters property inAlpha : leftAlpha property outAlpha : rightAlpha property output : {} end script set alphaLen to (count o's leftAlpha) if ((count o's rightAlpha) ≠ alphaLen) then error if (mode is "encipher") then set {o's inAlpha, o's outAlpha} to {o's rightAlpha, o's leftAlpha} else if (mode is not "decipher") then error end if set zenith to 1 set nadir to alphaLen div 2 + 1 repeat with char in o's inputChars set char to char's contents set found to false repeat with i from 1 to alphaLen if (o's inAlpha's item i = char) then set end of o's output to o's outAlpha's item i set found to true exit repeat end if end repeat if (found) then rotate(o's leftAlpha, zenith, alphaLen, -(i - zenith)) rotate(o's leftAlpha, zenith + 1, nadir, -1) rotate(o's rightAlpha, zenith, alphaLen, -i) rotate(o's rightAlpha, zenith + 2, nadir, -1) end if end repeat return join(o's output, "")
end chaocipher
on rotate(theList, l, r, amount)
set listLength to (count theList) if (listLength < 2) then return if (l < 0) then set l to listLength + l + 1 if (r < 0) then set r to listLength + r + 1 if (l > r) then set {l, r} to {r, l} script o property lst : theList property storage : missing value end script set rangeLength to r - l + 1 set amount to (rangeLength + rangeLength - amount) mod rangeLength if (amount is 0) then return set o's storage to o's lst's items l thru (l + amount - 1) repeat with i from (l + amount) to r set o's lst's item (i - amount) to o's lst's item i end repeat set j to r - amount repeat with i from 1 to amount set o's lst's item (j + i) to o's storage's item i end repeat
end rotate
on join(lst, delim)
set astid to AppleScript's text item delimiters set AppleScript's text item delimiters to delim set txt to lst as text set AppleScript's text item delimiters to astid return txt
end join
-- Return a script object containing a couple of randomised alphabets to use as a choacipher key. on makeKey()
set lAlpha to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"'s characters copy lAlpha to rAlpha script |key| property leftAlpha : join(shuffle(lAlpha, 1, -1), "") property rightAlpha : join(shuffle(rAlpha, 1, -1), "") end script return |key|
end makeKey
-- Fisher-Yates (aka Durstenfeld, aka Knuth) shuffle. on shuffle(theList, l, r)
set listLength to (count theList) if (listLength < 2) then return array if (l < 0) then set l to listLength + l + 1 if (r < 0) then set r to listLength + r + 1 if (l > r) then set {l, r} to {r, l} script o property lst : theList end script repeat with i from l to (r - 1) set j to (random number from i to r) set v to o's lst's item i set o's lst's item i to o's lst's item j set o's lst's item j to v end repeat return theList
end shuffle
-- Demo using the two-alphabet key from the Rubin paper and another generated at random. -- Decription must be with the key that was used for the encription. on demo(originalText)
set key1 to {leftAlpha:"HXUCZVAMDSLKPEFJRIGTWOBNYQ", rightAlpha:"PTLNBQDEOYSFAVZKGJRIHWXUMC"} set key2 to makeKey() set enciphered to chaocipher(originalText, key1, "encipher") set doubleEnciphered to chaocipher(enciphered, key2, "encipher") set deDoubleEnciphered to chaocipher(doubleEnciphered, key2, "decipher") set deciphered to chaocipher(deDoubleEnciphered, key1, "decipher") return join({"Original text = " & originalText, ¬ "Enciphered = " & enciphered, "Double enciphered = " & doubleEnciphered, ¬ "De-double enciphered = " & deDoubleEnciphered, "Deciphered = " & deciphered}, linefeed)
end demo demo("WELLDONEISBETTERTHANWELLSAID")</lang>
- Output:
<lang applescript>"Original text = WELLDONEISBETTERTHANWELLSAID Enciphered = OAHQHCNYNXTSZJRRHJBYHQKSOUJY Double enciphered = ZJVDGIXNNDNRHAXQUUJZGAFTANHW De-double enciphered = OAHQHCNYNXTSZJRRHJBYHQKSOUJY Deciphered = 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>
AutoHotkey
<lang AutoHotkey>LeftW := "HXUCZVAMDSLKPEFJRIGTWOBNYQ" RghtW := "PTLNBQDEOYSFAVZKGJRIHWXUMC"
PlainText := "WELLDONEISBETTERTHANWELLSAID" CipherText := Chao_Cipher(PlainText, LeftW, RghtW) ; "OAHQHCNYNXTSZJRRHJBYHQKSOUJY" DecipherText:= Chao_Decipher(CipherText, LeftW, RghtW) ; "WELLDONEISBETTERTHANWELLSAID"
MsgBox % Result := "Original text:`t" PlainText "`nCipher text:`t" CipherText "`nDecipher text:`t" DecipherText return
- -------------------------------------------
Chao_Cipher(PT, LeftW, RghtW){
oRght:=StrSplit(RghtW), oLeft:=StrSplit(LeftW) for i, p in StrSplit(PT){ result .= (c := Key2Val(oRght, oLeft, p)) oLeft:=Permute(oLeft, c, 1) oRght:=Permute(oRght, p) } return result
}
- -------------------------------------------
Chao_Decipher(CT, LeftW, RghtW){
oRght:=StrSplit(RghtW), oLeft:=StrSplit(LeftW) for i, c in StrSplit(CT){ result .= (p := Key2Val(oLeft, oRght, c)) oLeft:=Permute(oLeft, c, 1) oRght:=Permute(oRght, p) } return result
}
- -------------------------------------------
Key2Val(Key, Val, char){
for i, ch in Key if (ch = char) return Val[i]
}
- -------------------------------------------
Permute(Arr, ch, dt:=0){
for i, c in Arr if (c=ch) break loop % i-dt Arr.Push(Arr.RemoveAt(1)) ; shift left ch := Arr[3-dt] ; save 2nd/3rd chr loop % 11+dt Arr[A_Index+2-dt]:=Arr[A_Index+3-dt] ; shift pos 3/4-14 left Arr[14] := ch ; place 2nd/3rd chr in pos 14 return Arr
}</lang>
- Output:
Original text: WELLDONEISBETTERTHANWELLSAID Cipher text: OAHQHCNYNXTSZJRRHJBYHQKSOUJY Decipher text: WELLDONEISBETTERTHANWELLSAID
C
<lang c>#include <stdio.h>
- include <string.h>
- include <stdlib.h>
- define TRUE 1
- define FALSE 0
typedef int bool; typedef enum { ENCRYPT, DECRYPT } cmode;
const char *l_alphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"; const char *r_alphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC";
void chao(const char *in, char *out, cmode mode, bool show_steps) {
int i, j, index; char store; size_t len = strlen(in); char left[27], right[27], temp[27]; strcpy(left, l_alphabet); strcpy(right, r_alphabet); temp[26] = '\0';
for (i = 0; i < len; ++i ) { if (show_steps) printf("%s %s\n", left, right); if (mode == ENCRYPT) { index = strchr(right, in[i]) - right; out[i] = left[index]; } else { index = strchr(left, in[i]) - left; out[i] = right[index]; } if (i == len - 1) break;
/* permute left */
for (j = index; j < 26; ++j) temp[j - index] = left[j]; for (j = 0; j < index; ++j) temp[26 - index + j] = left[j]; store = temp[1]; for (j = 2; j < 14; ++j) temp[j - 1] = temp[j]; temp[13] = store; strcpy(left, temp);
/* permute right */
for (j = index; j < 26; ++j) temp[j - index] = right[j]; for (j = 0; j < index; ++j) temp[26 - index + j] = right[j]; store = temp[0]; for (j = 1; j < 26; ++j) temp[j - 1] = temp[j]; temp[25] = store; store = temp[2]; for (j = 3; j < 14; ++j) temp[j - 1] = temp[j]; temp[13] = store; strcpy(right, temp); }
}
int main() {
const char *plain_text = "WELLDONEISBETTERTHANWELLSAID"; char *cipher_text = malloc(strlen(plain_text) + 1); char *plain_text2 = malloc(strlen(plain_text) + 1); printf("The original plaintext is : %s\n", plain_text); printf("\nThe left and right alphabets after each permutation" " during encryption are :\n\n"); chao(plain_text, cipher_text, ENCRYPT, TRUE); printf("\nThe ciphertext is : %s\n", cipher_text); chao(cipher_text, plain_text2, DECRYPT, FALSE); printf("\nThe recovered plaintext is : %s\n", plain_text2); free(cipher_text); free(plain_text2); return 0;
}</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#
<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++
<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
<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
Delphi
<lang Delphi> program Chaocipher;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
TMode = (mcEncrypt, mcDecrypt);
const
lAlphabet = 'HXUCZVAMDSLKPEFJRIGTWOBNYQ'; rAlphabet = 'PTLNBQDEOYSFAVZKGJRIHWXUMC';
function Chao(text: AnsiString; Mode: TMode; showSteps: boolean): AnsiString; begin
var len := Length(text);
var left: AnsiString := lAlphabet; var right: AnsiString := rAlphabet;
var eText: AnsiString; SetLength(eText, len); var temp: AnsiString; SetLength(temp, 26);
for var i := 0 to len - 1 do begin if showSteps then writeln(left, ' ', right);
var index := 0;
if Mode = mcEncrypt then begin index := pos(text[i + 1], right) - 1; eText[i + 1] := left[index + 1]; end else begin index := pos(text[i + 1], left) - 1; eText[i + 1] := right[index + 1]; end;
if i = len - 1 then Break;
// premute left for var j := index to 25 do temp[j - index + 1] := left[j + 1];
for var j := 0 to index - 1 do temp[27 - index + j] := left[j + 1]; var store := temp[2];
for var j := 2 to 13 do temp[j] := temp[j + 1];
temp[14] := store;
left := temp;
// permute right for var j := index to 25 do temp[j - index + 1] := right[j + 1];
for var j := 0 to index - 1 do temp[27 - index + j] := right[j + 1];
store := temp[0 + 1];
for var j := 1 to 25 do temp[j] := temp[j + 1];
temp[26] := store; store := temp[3];
for var j := 3 to 13 do temp[j] := temp[j + 1];
temp[14] := store;
right := temp; end; Result := eText;
end;
begin
var plainText := 'WELLDONEISBETTERTHANWELLSAID'; writeln('The original plaintext is :', plainText); write(#10'The left and right alphabets after each permutation '); writeln('during encryption are :'#10); var cipherText := Chao(plainText, mcEncrypt, true); writeln(#10'The ciphertext is :', cipherText); var plainText2 := Chao(cipherText, mcDecrypt, false); writeln(#10'The recovered plaintext is : ', plainText2); readln;
end.</lang>
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æ
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. 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 storage and transfer purposes more than visualization and edition.
Programs in Fōrmulæ are created/edited online in its website, However they run on execution servers. By default remote servers are used, but they are limited in memory and processing power, since they are intended for demonstration and casual use. A local server can be downloaded and installed, it has no limitations (it runs in your own computer). Because of that, example programs can be fully visualized and edited, but some of them will not run if they require a moderate or heavy computation/memory resources, and no local server is being used.
In this page you can see the program(s) related to this task and their results.
Go
<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
<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
<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
J
<lang j>reset =: verb define
LEFT =: 'HXUCZVAMDSLKPEFJRIGTWOBNYQ' RIGHT =: 'PTLNBQDEOYSFAVZKGJRIHWXUMC'
)
enc =: verb define
z =. LEFT {~ i =. RIGHT i. y permute {. i z
)
dec =: verb define
z =. RIGHT {~ i =. LEFT i. y permute {. i z
)
permute =: verb define
LEFT =: LEFT |.~ - y LEFT =: (1 |. 13 {. LEFT) , 13 }. LEFT RIGHT =: RIGHT |.~ - y + 1 RIGHT =: ({. RIGHT) , (1 |. RIGHT {~ 2+i.12) , 13 }. RIGHT
)
chao =: enc :. dec
reset smoutput E =. chao 'WELLDONEISBETTERTHANWELLSAID' reset smoutput D =. chao^:_1 E</lang>
- Output:
OMUUADCMTLZMXXMGXWPCOMUULPTA WELLDONEISBETTERTHANWELLSAID
JavaScript
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
Mathematica/Wolfram Language
<lang Mathematica>ClearAll[ichaoalphabet, iMoveToFront, ChaoCipher] ichaoalphabet = CharacterRange["A", "Z"]; iMoveToFront[l_List, sel_] := Module[{p},
p = FirstPosition[l, sel]; RotateLeft[l, p - 1] ]
ChaoCipher::wrongcipheralpha =
"The cipher alphabet `1` is not a permutation of \
\"A\"\[LongDash]\"Z\"."; ChaoCipher::wrongplainalpha =
"The plain alphabet `1` is not a permutation of \"A\"\[LongDash]\"Z\
\"."; ChaoCipher[str_String, {plainalpha_List, cipheralpha_List}] :=
Module[{pa, ca, plain, new, papermute, capermute, out}, ca = ToUpperCase[cipheralpha]; pa = ToUpperCase[plainalpha]; If[Sort[ca] =!= Sort[ichaoalphabet], Message[ChaoCipher::wrongcipheralpha, ca]; $Failed , If[Sort[pa] =!= Sort[ichaoalphabet], Message[ChaoCipher::wrongplainalpha, pa]; $Failed , capermute = SubsetMap[RotateLeft, Range[26], Range[2, 14]]; papermute = SubsetMap[RotateLeft, RotateLeft[Range[26], 1], Range[3, 14]]; plain = Select[Characters[ToUpperCase[str]], MemberQ[ichaoalphabet, #] &]; out = Table[ new = Association[Thread[pa -> ca]][p]; pa = iMoveToFront[pa, p]; ca = iMoveToFront[ca, new]; pa = papapermute; ca = cacapermute; new , {p, plain} ]; StringJoin[out] ] ] ]
ChaoCipher["WELLDONEISBETTERTHANWELLSAID",{Characters@"PTLNBQDEOYSFAVZKGJRIHWXUMC",Characters@"HXUCZVAMDSLKPEFJRIGTWOBNYQ"}] </lang>
- Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY
Nim
<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
Another implementation
Using functions from the stdlib instead of manual array manipulations: <lang nim>import std/[algorithm, strutils]
type
Mode = enum Encrypt Decrypt
const
lAlphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ" rAlphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC"
proc chao(text: string; mode: Mode; verbose = false): string =
var left = lAlphabet right = rAlphabet eText = newSeq[char](text.len)
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 left.rotateLeft(index) left.rotateLeft(1..13, 1)
# permute right right.rotateLeft(index + 1) right.rotateLeft(2..13, 1)
result = eText.join()
let plainText = "WELLDONEISBETTERTHANWELLSAID" echo "The original plaintext is: ", plainText echo "\nThe left and right alphabets after each permutation during encryption are:\n" let cipherText = chao(plainText, Encrypt, true) echo "\nThe ciphertext is: ", cipherText let plainText2 = chao(cipherText, Decrypt, false) echo "\nThe recovered plaintext is: ", plainText2</lang> Same output as above.
Objeck
<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
Pascal
<lang pascal>program chaocipher(input, output);
const { This denotes a `set` literal: } alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; { The `card` function is an Extended Pascal (ISO 10206) extension. } alphabetCardinality = card(alphabet); { 1st character denotes “zenith”. } zenith = 1; { In a 26-character alphabet the 14th character denotes “nadir”. } nadir = alphabetCardinality div 2 + 1; { For simplicity use compile-time-defined maximum lengths. } messageMaximumLength = 80;
type { This “discriminates” the Extended Pascal schema data type `string` to be } { capable of holding strings up to `alphabetCardinality` `char` values. } map = string(alphabetCardinality); { Variables of this data type can only assume integer values within 1..26: } mapCharacterIndex = 1..alphabetCardinality; { Later used as a buffer for the input/output. } message = string(messageMaximumLength); messageCharacterIndex = 1..messageMaximumLength; { Stores a key for the Chaocipher algorithm. } key = record cipherText: map; plainText: map; end;
{ --- auxilliary routines ---------------------------------------------- }
{ \brief verifies that a key is valid for the Chaocipher \param sample a potential `key` for a Chaocipher \return `true` iff \param sample is an acceptable `key` } { `protected` (Extended Pascal extension) denotes an immutable parameter. } function isValid(protected sample: key): Boolean; { Determines whether a `map` contains all characters of `alphabet`. } { Nesting this function allows for a neat expression below. } function isComplete(text: map): Boolean; var i: integer; { `value []` will initialize this variable to an empty set value. } { This is an Extended Pascal (ISO 10206) extension. } s: set of char value []; begin { NB: In Pascal `for`-loop limits are inclusive. } for i := 1 to length(text) do begin { This adds the set containing one character to the set `s`. } s := s + [text[i]] end; isComplete := card(s) = alphabetCardinality end; begin { This way `sample.cipherText` can be simply written as `cipherText`. } with sample do begin { `and_then` is an EP extension indicating “lazy evaluation”. } isValid := (alphabetCardinality > 8) and_then isComplete(cipherText) and_then isComplete(plainText) end end;
{ \brief permutes a key for the next encryption/decryption step \param shift the index of the characters just substituted } { `var` means the parameter value will be modified _at_ the call site. } procedure permute(var state: key; protected shift: mapCharacterIndex); begin with state do begin { Indices in `cipherText[1..pred(shift)]` _must_ be non-descending: } if shift > 1 then begin cipherText := subStr(cipherText, shift) + cipherText[1..pred(shift)] { `subStr(str, ini)` is equivalent to `str[ini..length(str)]`. } end; { Likewise, `succ(shift)` must be a valid index in `plainText`: } if shift < alphabetCardinality then begin plainText := subStr(plainText, succ(shift)) + plainText[1..shift] end;
{ If it does _not_ _alter_ the _entire_ string’s _length_, you can } { modify parts of a string like this (Extended Pascal extension): } cipherText[zenith+1..nadir] := cipherText[zenith+2..nadir] + cipherText[zenith+1]; plainText[zenith+2..nadir] := plainText[zenith+3..nadir] + plainText[zenith+2] end end;
{ --- the core routine of the algorithm -------------------------------- }
{ \brief performs Chaocipher common steps \param line the message to encrypt/decrypt \param state the initial key to start encrpytion/decryption with \param locate a function determining the 2-tuple index in the key \param substitute the procedure substituting the correct characters } procedure chaocipher( var line: message; var state: key; { These are “routine parameters”. Essentially the address of a routine } { matching the specified routine signature is passed to `chaocipher`. } function locate(protected i: messageCharacterIndex): mapCharacterIndex; procedure substitute( protected i: messageCharacterIndex; protected z: mapCharacterIndex ) ); var { For demonstration purposes: In this program } { `line.capacity` refers to `messageMaximumLength`. } i: 1..line.capacity; substitutionPairIndex: mapCharacterIndex; begin { Don’t trust user input, even though this is just a RosettaCode example. } if not isValid(state) then begin writeLn('Error: Key is invalid. Got:'); writeLn('Cipher text: ', state.cipherText); writeLn(' Plain text: ', state.plainText); halt end;
for i := 1 to length(line) do begin { We’ll better skip characters that aren’t in the `alphabet`. } if line[i] in alphabet then begin { Here you see the beauty of using routine parameters. } { Depending on whether we’re encrypting or decrypting, } { you need to find a character in the `cipherText` or } { `plainText` key value respectively, yet the basic order { of the steps are still the same. } substitutionPairIndex := locate(i); substitute(i, substitutionPairIndex); permute(state, substitutionPairIndex) end end end;
{ --- entry routines --------------------------------------------------- }
{ \brief encrypts a message according to Chaocipher } { Note: without `var` or `protected` both `encrypt` and `decrypt`get } { and have their own independent copies of the parameter values. } function encrypt(line: message; state: key): message; function encryptor(protected i: messageCharacterIndex): mapCharacterIndex; begin encryptor := index(state.plainText, line[i]) end; procedure substitutor( protected i: messageCharacterIndex; protected z: mapCharacterIndex ); begin line[i] := state.cipherText[z] end; begin chaocipher(line, state, encryptor, substitutor); encrypt := line end;
function decrypt(line: message; state: key): message; function decryptor(protected i: messageCharacterIndex): mapCharacterIndex; begin decryptor := index(state.cipherText, line[i]) end; procedure substitutor( protected i: messageCharacterIndex; protected z: mapCharacterIndex ); begin line[i] := state.plainText[z] end; begin chaocipher(line, state, decryptor, substitutor); decrypt := line end;
{ === MAIN ============================================================= } var exampleKey: key; line: message; begin { Instead of writing `exampleKey.cipherText := '…', you can } { write in Extended Pascal a `record` literal like this: } exampleKey := key[ cipherText: 'HXUCZVAMDSLKPEFJRIGTWOBNYQ'; plainText: 'PTLNBQDEOYSFAVZKGJRIHWXUMC'; ];
{ `EOF` is shorthand for `EOF(input)`. } while not EOF do begin { `readLn(line)` is shorthand for `readLn(input, line)`. } readLn(line); line := encrypt(line, exampleKey); writeLn(decrypt(line, exampleKey)); { Likewise, `writeLn(line)` is short for `writeLn(output, line)`. } writeLn(line) end end.</lang>
- Input:
WELLDONEISBETTERTHANWELLSAID
- Output:
WELLDONEISBETTERTHANWELLSAID OAHQHCNYNXTSZJRRHJBYHQKSOUJY
Perl
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.
-- demo\rosetta\Chao_cipher.exw with javascript_semantics constant l_alphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ", r_alphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC" enum ENCRYPT, DECRYPT function chao_cipher(string s, integer mode, bool show_steps) integer len = length(s) string out = repeat(' ',len), 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(s[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})
- Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
Python
Procedural
<lang python># Python3 implementation of Chaocipher
- left wheel = ciphertext wheel
- 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
<lang python>Chaocipher
from itertools import chain, cycle, islice
- 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 ))
- rotated :: Int -> [a] -> [a]
def rotated(z, s):
Rotation of string s by z characters. return take(len(s))( drop(z)( cycle(s) ) )
- 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)
- TEST ----------------------------------------------------
- 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) )
- GENERIC -------------------------------------------------
- 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}
- 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}
- compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
Right to left function composition. return lambda f: lambda x: g(f(x))
- concat :: a -> [a]
- 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 []
- drop :: Int -> [a] -> [a]
- 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)
- 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)
- 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')) )
- 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:])
- take :: Int -> [a] -> [a]
- 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)) )
- MAIN ---
if __name__ == '__main__':
main()</lang>
- Output:
WELLDONEISBETTERTHANWELLSAID OAHQHCNYNXTSZJRRHJBYHQKSOUJY WELLDONEISBETTERTHANWELLSAID
Raku
(formerly Perl 6)
<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
<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
<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
<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