Here's a very basic (although structured, functional, and extensible) implementation. I didn't include any error checking of user input. So the user needs to make sure that there's the right number (25 by default) of characters in the key, split doubletons in the plain text, make sure only alphabet characters are in the plaintext or ciphertext, and make sure that texts have an even number of characters. However, I did generalize it so that you are not restricted to (the traditional) 5x5 alphabet: You can use any rectangle (just change** R** and **C** in the **module locals**).

(*

A basic implementation of the Playfair cipher (see "Playfair cipher" in Wikipedia).

There is no error checking of user input, and the user has to split doubletons on

their own.

*)

Playfair:= module()

option `Written 19-Apr-2013 by Carl Love.`;

local

R:= 5, C:= 5, #For a 5x5=25 alphabet

#Convert number in 1..25 into row-column coordinates

to_row_col:= proc(n) local r,c; r:= iquo(n-1, C, 'c'); (r+1, c+1) end proc,

#Convert row-column coordinates to number in 1..25

from_row_col:= (r,c)-> C*(r-1)+c,

rotf:= k-> k mod C + 1, #mod C, shifted by 1 (rotate forward)

rotd:= k-> k mod R + 1, #mod R, shifted by 1 (rotate down)

#For a pair in 1..R*C, return the corresponding Playfair pair. Note that if

#we just consider the indices in the array, then the mapping from index-pair

#to index-pair is a constant, independent of the cipher key.

Playfair_pair:= proc(a,b)

option remember;

local r1, r2, c1, c2;

if a=b then error "expected unequal arguments" end if;

(r1,c1):= to_row_col(a);

(r2,c2):= to_row_col(b);

if r1=r2 then (from_row_col(r1,rotf(c1)), from_row_col(r2,rotf(c2)))

elif c1=c2 then (from_row_col(rotd(r1),c1), from_row_col(rotd(r2),c2))

else (from_row_col(r1,c2), from_row_col(r2,c1))

end if

end proc,

EnDig:= table(), #Encrypt: Digraph to Digraph

DeDig:= table() #Decrypt: Digraph to Digraph

;

export

SetKey:= proc(Key::string)

local i, j, i2, j2, DigPlain, DigCrypt;

#Encrypt and decrypt every possible digraph.

for i to R*C do for j to R*C do

if i=j then next end if;

(i2,j2):= Playfair_pair(i,j);

DigPlain:= cat(Key[i],Key[j]);

DigCrypt:= cat(Key[i2],Key[j2]);

EnDig[DigPlain]:= DigCrypt;

DeDig[DigCrypt]:= DigPlain

end do end do;

[][]

end proc,

Encrypt:= proc(plaintext::string)

local k;

cat(seq(EnDig[plaintext[2*k-1..2*k]], k= 1..iquo(length(plaintext),2)))

end proc,

Decrypt:= proc(ciphertext::string)

local k;

cat(seq(DeDig[ciphertext[2*k-1..2*k]], k= 1..iquo(length(ciphertext),2)))

end proc

;

end module;

Download Playfair.mw