next up previous
Next: Improved Caesar-like ciphers Up: fsqFsHn sGGousG Previous: Defining functions with proc;

Caesar cipher redux

Now that we know about proc, lets implement the Caesar cipher again, this time with an arbitrary alphabet.

First, we define a global variable Alphabet that lists all the characters we intend to encode. Note that, in this case, the newline character is in our alphabet, as well as a space and a few punctuation characters.

> Alphabet := `ABCDEFGHIJKLMNOPQRSTUVWXYZ
  abcdefghijklmnopqrstuvwxyz., `;


\begin{maplelatex}\begin{eqnarray*}
\lefteqn{\mathit{Alphabet} := \mathit{ABCDEF...
...defghijklmnopqrstuvwxyz.,\ }\mbox{\hspace{71pt}}
\end{eqnarray*}\end{maplelatex}

Now, we can define two procedures, ToNum and FromNum, which convert character strings to and from lists of numbers. The numbers correspond to the position of the character in Alphabet, with (in this case) A=0. As in Scramble of §2.1, we use substring to pick out the i-th character, and SearchText to find its position in Alphabet. Note that Alphabet is declared as a global variable.

 

> ToNum := proc(text)
    local i;
    global Alphabet;
    [seq(SearchText( substring(text,i),Alphabet)-1, i=1..length(text))];
  end:
    
  FromNum := proc(numlist)
    local i;
    global Alphabet;
    cat(seq( substring(Alphabet,numlist[i]+1), i=1..nops(numlist)));
  end:

Now the Caesar cipher is written in terms of these functions. Note that this is a little easier to understand than the previous version.

 

> Caesar2:= proc(plaintext, shift)
    local textnum,codenum,i,p;
    global Alphabet;
    
    p       := length(Alphabet);
    textnum := ToNum(plaintext);
    codenum := [seq( modp(textnum[i]+shift, p),
                     i=1..length(plaintext)) ];
    FromNum(codenum);
  end:

It works as follows.

Let's see how it works.

> Caesar2(`Veni, Vidi, Vici`,3);


\begin{maplelatex}\begin{displaymath}
\mathit{YhqlBCYlglBCYlfl}
\end{displaymath}
\end{maplelatex}

> test:=`I have heard the mermaids singing, each to each
  I do not think that they will sing to me.`;


\begin{maplelatex}\begin{eqnarray*}
\lefteqn{\mathit{test} := \mathit{I\ have\ h...
... they\ will\ sing\ to\ me.}
\mbox{\hspace{45pt}}
\end{eqnarray*}\end{maplelatex}

> encoded:=Caesar2(test,38);


\begin{maplelatex}\begin{eqnarray*}
\lefteqn{\mathit{encoded} := \mathit{tkQJdNk...
...\backslash }
\\
& & \mathit{eRUUkaRWPkbXkVNi}
\end{eqnarray*}\end{maplelatex}

Note that since our alphabet treats an end-of-line as a character, the linebreaks in both the plain and encoded versions are significant, and are different in number. We can use the same function to decode, but giving the negative of the shift as the key.

> Caesar2(encoded,-38);


\begin{maplelatex}\begin{eqnarray*}
\lefteqn{\mathit{I\ have\ heard\ the\ mermai...
... they\ will\ sing\ to\ me.}
\mbox{\hspace{12pt}}
\end{eqnarray*}\end{maplelatex}

Finally, notice what happens if we try to encode characters that do not occur in our alphabet. To better see what happens, we will shorten the alphabet dramatically.

> Alphabet:=`abcdefghijklmop_`;


\begin{maplelatex}\begin{displaymath}
\mathit{Alphabet} := \mathit{abcdefghijklmop\_}
\end{displaymath}
\end{maplelatex}

Now let's re-encode the test message, with a shift of zero. Ordinarily, a shift by 0 would not change the text at all. But with the shortened alphabet, something happens to the characters that aren't mentioned.

> Caesar2(test,0);


\begin{maplelatex}\begin{displaymath}
\mathit{\_\_ha\_e\_hea\_d\_\_he\_me\_maid\...
...i\_k\_\_ha\_\_\_he\_\_\_ill\_i\_g\_\_o\_me\_}
\end{displaymath}
\end{maplelatex}

Can you explain why this happens?


next up previous
Next: Improved Caesar-like ciphers Up: fsqFsHn sGGousG Previous: Defining functions with proc;

Translated from LaTeX by Scott Sutherland
1999-12-08