Caesar cipher

From Rosetta Code
Task
Caesar cipher
You are encouraged to solve this task according to the task description, using any language you may know.

Implement a Caesar cipher, both encryption and decryption. The key is an integer from 1 to 25. This cipher rotates the letters of the alphabet (A to Z). The encryption replaces each letter with the 1st to 25th next letter in the alphabet (wrapping Z to A). So key 2 encrypts "HI" to "JK", but key 20 encrypts "HI" to "BC". This simple "monoalphabetic substitution cipher" provides almost no security, because an attacker who has the encrypted message can either use frequency analysis to guess the key, or just try all 25 keys.

Caesar cipher is identical to Vigenère cipher with key of length 1. Also, Rot-13 is identical to Caesar cipher with key 13.

Ada

<lang Ada>with Ada.Text_IO;

procedure Caesar is

  type M26 is mod 26;
  function To_M26(C: Character; Offset: Character) return M26 is
  begin
     return M26(Character'Pos(C)-Character'Pos(Offset));
  end To_M26;
  function To_Character(Value:   in  M26; Offset: Character)
                       return Character is
  begin
     return Character'Val(Integer(Value)+Character'Pos(Offset));
  end To_Character;
  function Encrypt (Plain: String; Key: M26) return String is
     Ciph: String(Plain'Range);
  begin
     for I in Plain'Range loop
        case Plain(I) is
           when 'A' .. 'Z' =>
              Ciph(I) := To_Character(To_M26(Plain(I), 'A')+Key, 'A');
           when 'a' .. 'z' =>
              Ciph(I) := To_Character(To_M26(Plain(I), 'a')+Key, 'a');
           when others =>
              Ciph(I) := Plain(I);
        end case;
     end loop;
     return Ciph;
  end Encrypt;
  Text:  String := Ada.Text_IO.Get_Line;
  Key: M26 := 3; -- Default key from "Commentarii de Bello Gallico"

begin -- Caesar main program

  Ada.Text_IO.Put_Line("Plaintext ------------>" & Text);
  Text := Encrypt(Text, Key);
  Ada.Text_IO.Put_Line("Ciphertext ----------->" & Text);
  Ada.Text_IO.Put_Line("Decrypted Ciphertext ->" & Encrypt(Text, -Key));

end Caesar;</lang> Output

> ./caesar 
The five boxing wizards jump quickly
Plaintext ------------>The five boxing wizards jump quickly
Ciphertext ----------->Wkh ilyh eralqj zlcdugv mxps txlfnob
Decrypted Ciphertext ->The five boxing wizards jump quickly

ALGOL 68

Translation of: Ada

Note: This specimen retains the original Ada coding style.

Works with: ALGOL 68 version Revision 1 - no extensions to language used.
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny.

<lang algol68>#!/usr/local/bin/a68g --script #

program caesar: BEGIN

  MODE MODXXVI = SHORT SHORT INT; # MOD26 #
  PROC to m26 = (CHAR c, offset)MODXXVI:
  BEGIN
     ABS c - ABS offset
  END #to m26#;
  PROC to char = (MODXXVI value, CHAR offset)CHAR:
  BEGIN
     REPR ( ABS offset + value MOD 26 )
  END #to char#;
  PROC encrypt = (STRING plain, MODXXVI key)STRING:
  BEGIN
     [UPB plain]CHAR ciph;
     FOR i TO UPB plain DO
        CHAR c = plain[i];
        ciph[i]:=
          IF "A" <= c AND c <= "Z" THEN
              to char(to m26(c, "A")+key, "A")
          ELIF "a" <= c AND c <= "z" THEN
              to char(to m26(c, "a")+key, "a")
          ELSE
              c
          FI
     OD;
     ciph
  END #encrypt#;
  1. caesar main program #
  STRING text := "The five boxing wizards jump quickly" # OR read string #;
  MODXXVI key := 3; # Default key from "Bello Gallico" #
  printf(($gl$, "Plaintext ------------>" + text));
  text := encrypt(text, key);
  printf(($gl$, "Ciphertext ----------->" + text));
  printf(($gl$, "Decrypted Ciphertext ->" + encrypt(text, -key)))

END #caesar#</lang> Output:

Plaintext ------------>The five boxing wizards jump quickly
Ciphertext ----------->Wkh ilyh eralqj zlcdugv mxps txlfnob
Decrypted Ciphertext ->The five boxing wizards jump quickly

C

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <string.h>
  1. define caesar(x) rot(13, x)
  2. define decaesar(x) rot(13, x)
  3. define decrypt_rot(x, y) rot((26-x), y)

void rot(int c, char *str) { int l = strlen(str); char alpha[2][27] = { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"};

int i; for (i = 0; i < l; i++) { if (!isalpha(str[i]) || (str[i] == ' ')) continue;

str[i] = alpha[isupper(str[i])][((int)(tolower(str[i])-'a')+c)%26]; } }


int main() { char str[100] = "This is a top secret text message!";

printf("Original: %s\n", str); caesar(str); printf("Encrypted: %s\n", str); decaesar(str); printf("Decrypted: %s\n", str);

return 0; }</lang>

D

<lang d>import std.stdio, std.traits, std.ctype, std.conv;

S rot(S)(S s, int key) if (isSomeString!S) {

   dchar[] r = new dchar[s.length];
       
   foreach (i, dchar c; s) {
       if (islower(c)) 
           c = ((c - 'a' + key) % 26 + 'a');
       else if (isupper(c)) 
           c = ((c - 'A' + key) % 26 + 'A');
       r[i] = c;      
   }
   return to!S(r);

}

void main() {

   int key = 3;
   auto txt = "The five boxing wizards jump quickly";
   writeln("Original:  ", txt);
   writeln("Encrypted: ", txt.rot(key));
   writeln("Decrypted: ", txt.rot(key).rot(26-key));

}</lang>

Original:  The five boxing wizards jump quickly
Encrypted: Wkh ilyh eralqj zlcdugv mxps txlfnob
Decrypted: The five boxing wizards jump quickly

Simpler in-place version (same output): <lang d>import std.stdio, std.ctype;

void inplaceRot(char[] txt, in int key) {

   foreach (ref c; txt) {
       if (islower(c))
           c = cast(char)((c - 'a' + key) % 26 + 'a');
       else if (isupper(c))
           c = cast(char)((c - 'A' + key) % 26 + 'A');
   }

}

void main() {

   enum key = 3;
   auto txt = "The five boxing wizards jump quickly".dup;
   writeln("Original:  ", txt);
   txt.inplaceRot(key);
   writeln("Encrypted: ", txt);
   txt.inplaceRot(26 - key);
   writeln("Decrypted: ", txt);

}</lang>

Fortran

<lang fortran>program Caesar_Cipher

 implicit none
 integer, parameter :: key = 3     
 character(43) :: message = "The five boxing wizards jump quickly"
 write(*, "(2a)") "Original message  = ", message
 call encrypt(message)
 write(*, "(2a)") "Encrypted message = ", message
 call decrypt(message)
 write(*, "(2a)") "Decrypted message = ", message
 

contains

subroutine encrypt(text)

 character(*), intent(inout) :: text
 integer :: i
 
 do i = 1, len(text)
   select case(text(i:i))
     case ('A':'Z')
       text(i:i) = achar(modulo(iachar(text(i:i)) - 65 + key, 26) + 65)
     case ('a':'z')
       text(i:i) = achar(modulo(iachar(text(i:i)) - 97 + key, 26) + 97)
   end select
 end do

end subroutine

subroutine decrypt(text)

 character(*), intent(inout) :: text
 integer :: i
 
 do i = 1, len(text)
   select case(text(i:i))
     case ('A':'Z')
       text(i:i) = achar(modulo(iachar(text(i:i)) - 65 - key, 26) + 65)
     case ('a':'z')
       text(i:i) = achar(modulo(iachar(text(i:i)) - 97 - key, 26) + 97)
   end select
 end do

end subroutine

end program Caesar_Cipher</lang> Output

Original message  = The five boxing wizards jump quickly
Encrypted message = Wkh ilyh eralgj zlcdugv mxps txlfnob
Decrypted message = The five boxing wizards jump quickly

GAP

<lang gap>CaesarCipher := function(s, n) local r, c, i, lower, upper; lower := "abcdefghijklmnopqrstuvwxyz"; upper := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; r := ""; for c in s do i := Position(lower, c); if i <> fail then Add(r, lower[RemInt(i + n - 1, 26) + 1]); else i := Position(upper, c); if i <> fail then Add(r, upper[RemInt(i + n - 1, 26) + 1]); else Add(r, c); fi; fi; od; return r; end;

CaesarCipher("IBM", 25);

  1. "HAL"

CaesarCipher("Vgg cphvi wzdibn vmz wjmi amzz viy zlpvg di ydbidot viy mdbcon.", 5);

  1. "All human beings are born free and equal in dignity and rights."</lang>

Go

<lang go>package main

import (

   "fmt"
   "strings"

)

type ckey struct {

   enc, dec func(int) int

}

func newCaesar(k int) (*ckey, bool) {

   if k < 1 || k > 25 {
       return nil, false
   }
   return &ckey{
       enc: func(c int) int {
           if c >= 'a' && c <= 'z'-k || c >= 'A' && c <= 'Z'-k {
               return c + k
           } else if c > 'z'-k && c <= 'z' || c > 'Z'-k && c <= 'Z' {
               return c + k - 26
           }
           return c
       },
       dec: func(c int) int {
           if c >= 'a'+k && c <= 'z' || c >= 'A'+k && c <= 'Z' {
               return c - k
           } else if c >= 'a' && c < 'a'+k || c >= 'A' && c < 'A'+k {
               return c - k + 26
           }
           return c
       },
   }, true

}

func (ck ckey) encipher(pt string) string {

   return strings.Map(ck.enc, pt)

}

func (ck ckey) decipher(ct string) string {

   return strings.Map(ck.dec, ct)

}

func main() {

   pt := "The five boxing wizards jump quickly"
   fmt.Println("Plaintext:", pt)
   for _, key := range []int{0, 1, 7, 25, 26} {
       ck, ok := newCaesar(key)
       if !ok {
           fmt.Println("Key", key, "invalid")
           continue
       }
       ct := ck.encipher(pt)
       fmt.Println("Key", key)
       fmt.Println("  Enciphered:", ct)
       fmt.Println("  Deciphered:", ck.decipher(ct))
   }

}</lang> Output:

Plaintext: The five boxing wizards jump quickly
Key 0 invalid
Key 1
  Enciphered: Uif gjwf cpyjoh xjabset kvnq rvjdlmz
  Deciphered: The five boxing wizards jump quickly
Key 7
  Enciphered: Aol mpcl ivepun dpghykz qbtw xbpjrsf
  Deciphered: The five boxing wizards jump quickly
Key 25
  Enciphered: Sgd ehud anwhmf vhyzqcr itlo pthbjkx
  Deciphered: The five boxing wizards jump quickly
Key 26 invalid

Haskell

<lang haskell> import Data.Char (ord, chr)

caesar :: Int -> String -> String caesar k str = map f str

 where
   f c
     | c `elem` ['a'..'z'] = tr 'a' k c
     | c `elem` ['A'..'Z'] = tr 'A' k c
     | otherwise = c

unCaesar :: Int -> String -> String unCaesar k = caesar (-1 * k)

-- char addition tr :: Char -> Int -> Char -> Char tr base offset char = chr $ ord base + (ord char - ord base + offset) `mod` 26 </lang> And trying it out in GHCi:

*Main> caesar 1 "hal"
"ibm"
*Main> unCaesar 1 "ibm"
"hal"

Icon and Unicon

Strictly speaking a Ceasar Cipher is a shift of 3 (the default in this case). <lang Icon>procedure main() ctext := caesar(ptext := map("The quick brown fox jumped over the lazy dog")) dtext := caesar(ctext,,"decrypt") write("Plain text = ",image(ptext)) write("Encphered text = ",image(ctext)) write("Decphered text = ",image(dtext)) end

procedure caesar(text,k,mode) #: mono-alphabetic shift cipher /k := 3 k := (((k % *&lcase) + *&lcase) % *&lcase) + 1 case mode of {

 &null|"e"|"encrypt": return map(text,&lcase,(&lcase||&lcase)[k+:*&lcase])
 "d"|"decrypt"      : return map(text,(&lcase||&lcase)[k+:*&lcase],&lcase)
 }

end</lang>

Output:

Plain text  = "the quick brown fox jumped over the lazy dog"
Encphered text = "wkh txlfn eurzq ira mxpshg ryhu wkh odcb grj"
Decphered text = "the quick brown fox jumped over the lazy dog"

J

If we assume that the task also requires us to leave non-alphabetic characters alone:

<lang j>cndx=: [: , 65 97 +/ 26 | (i.26)&+ caesar=: (cndx 0)}&a.@u:@cndx@[ {~ a.i.]</lang>

Example use:<lang j> 2 caesar 'This simple "monoalphabetic substitution cipher" provides almost no security, ...' Vjku ukorng "oqpqcnrjcdgvke uwduvkvwvkqp ekrjgt" rtqxkfgu cnoquv pq ugewtkva, ...</lang>

NetRexx

The cipher code in this sample is also used in the Rot-13 – NetRexx task. <lang NetRexx>/* NetRexx */

options replace format comments java crossref savelog symbols nobinary

messages = [ -

 'The five boxing wizards jump quickly', -
 'Attack at dawn!', -
 'HI']

keys = [1, 2, 20, 25, 13]

loop m_ = 0 to messages.length - 1

 in = messages[m_]
 loop k_ = 0 to keys.length - 1
   say 'Caesar cipher, key:' keys[k_].right(3)
   ec = caesar_encipher(in, keys[k_])
   dc = caesar_decipher(ec, keys[k_])
   say in
   say ec
   say dc
   say
   end k_
 say 'Rot-13:'
 ec = rot13(in)
 dc = rot13(ec)
 say in
 say ec
 say dc
 say
 end m_

return

method rot13(input) public static signals IllegalArgumentException

 return caesar(input, 13, isFalse)

method caesar(input = Rexx, idx = int, caps = boolean) public static signals IllegalArgumentException

 if idx < 1 | idx > 25 then signal IllegalArgumentException()
 --      12345678901234567890123456
 itab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 shift = itab.length - idx
 parse itab tl +(shift) tr
 otab = tr || tl
 if caps then input = input.upper
 cipher = input.translate(itab || itab.lower, otab || otab.lower)
 return cipher

method caesar_encipher(input = Rexx, idx = int, caps = boolean) public static signals IllegalArgumentException

 return caesar(input, idx, caps)

method caesar_decipher(input = Rexx, idx = int, caps = boolean) public static signals IllegalArgumentException

 return caesar(input, int(26) - idx, isFalse)

method caesar_encipher(input = Rexx, idx = int) public static signals IllegalArgumentException

 return caesar(input, idx, isFalse)

method caesar_decipher(input = Rexx, idx = int) public static signals IllegalArgumentException

 return caesar(input, int(26) - idx, isFalse)

method caesar_encipher(input = Rexx, idx = int, opt = Rexx) public static signals IllegalArgumentException

 return caesar(input, idx, opt)

method caesar_decipher(input = Rexx, idx = int, opt = Rexx) public static signals IllegalArgumentException

 return caesar(input, int(26) - idx, opt)

method caesar(input = Rexx, idx = int, opt = Rexx) public static signals IllegalArgumentException

 if opt.upper.abbrev('U') >= 1 then caps = isTrue
 else                               caps = isFalse
 return caesar(input, idx, caps)

method caesar(input = Rexx, idx = int) public static signals IllegalArgumentException

 return caesar(input, idx, isFalse)

method isTrue public static returns boolean

 return (1 == 1)

method isFalse public static returns boolean

 return \isTrue

</lang>

Caesar cipher, key:   1
The five boxing wizards jump quickly
Uif gjwf cpyjoh xjabset kvnq rvjdlmz
The five boxing wizards jump quickly

Caesar cipher, key:   2
The five boxing wizards jump quickly
Vjg hkxg dqzkpi ykbctfu lwor swkemna
The five boxing wizards jump quickly

Caesar cipher, key:  20
The five boxing wizards jump quickly
Nby zcpy vircha qctulxm dogj kocwefs
The five boxing wizards jump quickly

Caesar cipher, key:  25
The five boxing wizards jump quickly
Sgd ehud anwhmf vhyzqcr itlo pthbjkx
The five boxing wizards jump quickly

Caesar cipher, key:  13
The five boxing wizards jump quickly
Gur svir obkvat jvmneqf whzc dhvpxyl
The five boxing wizards jump quickly

Rot-13:
The five boxing wizards jump quickly
Gur svir obkvat jvmneqf whzc dhvpxyl
The five boxing wizards jump quickly

Caesar cipher, key:   1
Attack at dawn!
Buubdl bu ebxo!
Attack at dawn!

Caesar cipher, key:   2
Attack at dawn!
Cvvcem cv fcyp!
Attack at dawn!

Caesar cipher, key:  20
Attack at dawn!
Unnuwe un xuqh!
Attack at dawn!

Caesar cipher, key:  25
Attack at dawn!
Zsszbj zs czvm!
Attack at dawn!

Caesar cipher, key:  13
Attack at dawn!
Nggnpx ng qnja!
Attack at dawn!

Rot-13:
Attack at dawn!
Nggnpx ng qnja!
Attack at dawn!

Caesar cipher, key:   1
HI
IJ
HI

Caesar cipher, key:   2
HI
JK
HI

Caesar cipher, key:  20
HI
BC
HI

Caesar cipher, key:  25
HI
GH
HI

Caesar cipher, key:  13
HI
UV
HI

Rot-13:
HI
UV
HI

Perl

It's supposed to be a cipher, so all non-letters are dropped. <lang Perl>sub encipher {

       my ($_, $k, $decode) = @_;
       $k = 26 - $k if $decode;
       join(, map(chr(((ord(uc $_) - 65 + $k) % 26) + 65), /([a-z])/gi));

}

my $msg = 'THE FIVE BOXING WIZARDS JUMP QUICKLY'; my $enc = encipher($msg, 10); my $dec = encipher($enc, 10, 'decode');

print "msg: $msg\nenc: $enc\ndec: $dec\n";</lang>output<lang>msg: THE FIVE BOXING WIZARDS JUMP QUICKLY enc: DROPSFOLYHSXQGSJKBNCTEWZAESMUVI dec: THEFIVEBOXINGWIZARDSJUMPQUICKLY</lang>

Perl 6

<lang perl6>my @alpha = 'A' .. 'Z'; sub encrypt ( $key where 1..25, $plaintext ) {

   $plaintext.trans( @alpha Z=> @alpha.rotate($key) );

} sub decrypt ( $key where 1..25, $cyphertext ) {

   $cyphertext.trans( @alpha.rotate($key) Z=> @alpha );

}

my $original = 'THE FIVE BOXING WIZARDS JUMP QUICKLY'; my $en = encrypt( 13, $original ); my $de = decrypt( 13, $en );

.say for $original, $en, $de;

say 'OK' if $original eq all( map { .&decrypt(.&encrypt($original)) }, 1..25 );</lang>

Output:

THE FIVE BOXING WIZARDS JUMP QUICKLY
GUR SVIR OBKVAT JVMNEQF WHZC DHVPXYL
THE FIVE BOXING WIZARDS JUMP QUICKLY
OK

PicoLisp

<lang PicoLisp>(setq *Letters (apply circ (mapcar char (range 65 90))))

(de caesar (Str Key)

  (pack
     (mapcar '((C) (cadr (nth (member C *Letters) Key)))
        (chop (uppc Str)) ) ) )</lang>

Test:

: (caesar "IBM" 25)
-> "HAL"
: (caesar @ 1)
-> "IBM"

: (caesar "The quick brown fox jumped over the lazy dog's back" 7)
-> "AOLXBPJRIYVDUMVEQBTWLKVCLYAOLSHGFKVNZIHJR"
: (caesar @ (- 26 7))
-> "THEQUICKBROWNFOXJUMPEDOVERTHELAZYDOGSBACK"

Prolog

Works with SWI-Prolog and library clpfd. <lang Prolog>:- use_module(library(clpfd)).

caesar :- L1 = "The five boxing wizards jump quickly", writef("Original : %s\n", [L1]),

% encryption of the sentence encoding(3, L1, L2) , writef("Encoding : %s\n", [L2]),

% deciphering on the encoded sentence encoding(3, L3, L2), writef("Decoding : %s\n", [L3]).

% encoding/decoding of a sentence encoding(Key, L1, L2) :- maplist(caesar_cipher(Key), L1, L2).

caesar_cipher(_, 32, 32) :- !.

caesar_cipher(Key, V1, V2) :- V #= Key + V1,

% we verify that we are in the limits of A-Z and a-z. ((V1 #=< 0'Z #/\ V #> 0'Z) #\/ (V1 #=< 0'z #/\ V #> 0'z) #\/ (V1 #< 0'A #/\ V2 #>= 0'A)#\/ (V1 #< 0'a #/\ V2 #>= 0'a)) #==> A,

% if we are not in these limits A is 1, otherwise 0. V2 #= V - A * 26,

% compute values of V1 and V2 label([A, V1, V2]).

</lang> Output :

 ?- caesar.
Original : The five boxing wizards jump quickly
Encoding : Wkh ilyh eralqj zlcdugv mxps txlfnob
Decoding : The five boxing wizards jump quickly
true .

PureBasic

The case is maintained for alphabetic characters (uppercase/lowercase input = uppercase/lowercase output) while non-alphabetic characters, if present are included and left unchanged in the result. <lang PureBasic>Procedure.s CC_encrypt(plainText.s, key, reverse = 0)

 ;if reverse <> 0 then reverse the encryption (decrypt)
 If reverse: reverse = 26: key = 26 - key: EndIf
 
 Static alphabet$ = "ABCEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
 
 Protected result.s, i, length = Len(plainText), letter.s, legal
 If key < 1 Or key > 25: ProcedureReturn: EndIf  ;keep key in range
  
 For i = 1 To length
   letter = Mid(plainText, i, 1)
   legal = FindString(alphabet$, letter, 1 + reverse)
   If legal
     result + Mid(alphabet$, legal + key, 1)
   Else
     result + letter
   EndIf 
 Next 
 ProcedureReturn result

EndProcedure

Procedure.s CC_decrypt(cypherText.s, key)

 ProcedureReturn CC_encrypt(cypherText, key, 1)

EndProcedure

If OpenConsole()

 Define key, plainText.s, encryptedText.s, decryptedText.s
 
 key = Random(24) + 1 ;get a random key in the range 1 -> 25
 
 plainText = "The quick brown fox jumped over the lazy dogs.": PrintN(RSet("Plain text = ", 17) + #DQUOTE$ + plainText + #DQUOTE$)
 encryptedText = CC_encrypt(plainText, key): PrintN(RSet("Encrypted text = ", 17) + #DQUOTE$ + encryptedText + #DQUOTE$)
 decryptedText = CC_decrypt(encryptedText, key): PrintN(RSet("Decrypted text = ", 17) + #DQUOTE$ + decryptedText + #DQUOTE$)
 
 Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
 CloseConsole()

EndIf</lang> Sample output:

    Plain text = "The quick brown fox jumped over the lazy dogs."
Encrypted text = "Znk waoiq hxuct lud pasvkj ubkx znk rgfe jumy."
Decrypted text = "the quick brown fox jumped over the lazy dogs."

Alternate solution

Here is an alternate and more advanced form of the encrypt procedure. It improves on the simple version in terms of speed, in case Caesar is using the cipher on some very long documents. It is meant to replace the encrypt procedure in the previous code and produces identical results. <lang PureBasic>Procedure.s CC_encrypt(text.s, key, reverse = 0)

 ;if reverse <> 0 then reverse the encryption (decrypt)
 Protected i, *letter.Character, *resultLetter.Character, result.s = Space(Len(text))
 
 If reverse: key = 26 - key: EndIf
 If key < 1 Or key > 25: ProcedureReturn: EndIf  ;exit if key out of range
  
 *letter = @text: *resultLetter = @result
 While *letter\c
   Select *letter\c
     Case 'A' To 'Z'
       *resultLetter\c = ((*letter\c - 65 + key) % 26) + 65
     Case 'a' To 'z'
       *resultLetter\c = ((*letter\c - 97 + key) % 26) + 97
     Default
       *resultLetter\c = *letter\c
   EndSelect
   *letter + SizeOf(Character): *resultLetter + SizeOf(Character)
 Wend
 ProcedureReturn result

EndProcedure</lang>

Python

<lang Python>def caesar(s, k, decode = False): if decode: k = 26 - k return "".join([chr((ord(i) - 65 + k) % 26 + 65) for i in s.upper() if ord(i) >= 65 and ord(i) <= 90 ])

msg = "The quick brown fox jumped over the lazy dogs" print msg enc = caesar(msg, 11) print enc print caesar(enc, 11, decode = True)</lang>Output:<lang>The quick brown fox jumped over the lazy dogs ESPBFTNVMCZHYQZIUFXAPOZGPCESPWLKJOZRD THEQUICKBROWNFOXJUMPEDOVERTHELAZYDOGS</lang>

Ruby

Translation of: Perl 6

<lang ruby>@atoz = Hash.new do |hash, key|

 str = ('A'..'Z').to_a.rotate(key).join("")
 hash[key] = (str << str.downcase)

end

def encrypt(key, plaintext)

 (1..25) === key or raise ArgumentError, "key not in 1..25"
 plaintext.tr(@atoz[0], @atoz[key])

end

def decrypt(key, ciphertext)

 (1..25) === key or raise ArgumentError, "key not in 1..25"
 ciphertext.tr(@atoz[key], @atoz[0])

end

original = "THEYBROKEOURCIPHEREVERYONECANREADTHIS" en = encrypt(3, original) de = decrypt(3, en)

[original, en, de].each {|e| puts e}

puts 'OK' if

 (1..25).all? {|k| original == decrypt(k, encrypt(k, original))}</lang>

The Ruby translation saves the rotations in an @atoz hash. (The Perl 6 code called rotate() during each encrypt or decrypt.) The code block on Hash.new makes the rotation and puts it in the hash.

  • @atoz[0] becomes "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
  • @atoz[3] becomes "DEFGHIJKLMNOPQRSTUVWXYZABCdefghijklmnopqrstuvwxyzabc",
  • and so on.

When the key is 3, encryption uses String#tr(@atoz[0], @atoz[3]) to substitute characters. Decryption uses String#tr(@atoz[3], @atoz[0]).

To make a rotation, Ruby is worse than Perl 6. Ruby needs two extra conversions: the code ('A'..'Z').to_a.rotate(key).join("") uses to_a to convert a Range to an Array, to access the Array#rotate method. Then join("") converts the rotated Array to a String, because String#tr needs a String, not an Array.

Tcl

<lang tcl>package require Tcl 8.6; # Or TclOO package for 8.5

oo::class create Caesar {

   variable encryptMap decryptMap
   constructor shift {

for {set i 0} {$i < 26} {incr i} { # Play fast and loose with string/list duality for shorter code append encryptMap [format "%c %c %c %c " \ [expr {$i+65}] [expr {($i+$shift)%26+65}] \ [expr {$i+97}] [expr {($i+$shift)%26+97}]] append decryptMap [format "%c %c %c %c " \ [expr {$i+65}] [expr {($i-$shift)%26+65}] \ [expr {$i+97}] [expr {($i-$shift)%26+97}]] }

   }
   method encrypt text {

string map $encryptMap $text

   }
   method decrypt text {

string map $decryptMap $text

   }

}</lang> Demonstrating: <lang tcl>set caesar [Caesar new 3] set txt "The five boxing wizards jump quickly." set enc [$caesar encrypt $txt] set dec [$caesar decrypt $enc] puts "Original message = $txt" puts "Encrypted message = $enc" puts "Decrypted message = $dec"</lang> Output:

Original message  = The five boxing wizards jump quickly.
Encrypted message = Wkh ilyh eralqj zlcdugv mxps txlfnob.
Decrypted message = The five boxing wizards jump quickly.

TUSCRIPT

<lang tuscript> $$ MODE TUSCRIPT text="THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG" PRINT "text orginal ",text

abc="ABCDEFGHIJKLMNOPQRSTUVWXYZ",key=3,caesarskey=key+1 secretbeg=EXTRACT (abc,#caesarskey,0) secretend=EXTRACT (abc,0,#caesarskey) secretabc=CONCAT (secretbeg,secretend)

abc=STRINGS (abc,":</:"),secretabc=STRINGS (secretabc,":</:") abc=SPLIT (abc), secretabc=SPLIT (secretabc) abc2secret=JOIN(abc," ",secretabc),secret2abc=JOIN(secretabc," ",abc)

BUILD X_TABLE abc2secret=* DATA {abc2secret}

BUILD X_TABLE secret2abc=* DATA {secret2abc}

ENCODED = EXCHANGE (text,abc2secret) PRINT "text encoded ",encoded

DECODED = EXCHANGE (encoded,secret2abc) PRINT "encoded decoded ",decoded </lang> Output:

text orginal    THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
text encoded    WKH TXLFN EURZQ IRA MXPSV RYHU WKH ODCB GRJ
encoded decoded THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG