September 1999 Programmer's Challenge
Playfair Decipher
Mail solutions to:
progchallenge@mactech.com
Due Date: 11:59pm ET, Monday, 6 September 1999
This month the Challenge ventures into the world of codebreaking. Simple codes, perhaps, but codes with a real-world history. Tom Saxton recently wrote to suggest a Challenge based on a simple substitution cipher. The problem we picked is a little more complicated, being based on letter pairs (digraphs) rather than single character substitutions. Invented by Sir Charles Wheatstone in the mid-1800s, the Playfair cipher (named after his friend, Baron Lyon Playfair) was used to encrypt telegraphic traffic and was also used during the Boer War and the First World War.
The Playfair cipher uses a 5x5 encryption matrix, in which each letter of the alphabet appears once. (The letters "i" and "j" map to the same cell.) While we codebreakers don’t know what the keyword is, or what the matrix is for any given cipherText, we are fortunate in that our Intelligence organization has determined that our adversaries create their matrices from a keyword in a known manner.
As an example, let’s use the keyword "cryptogram" to generate the encryption matrix. First, we write the unique characters in the keyword across in one line: Notice that the letter "r" appears only once, even though it occurs twice in the keyword.
CRYPTOGAM
Next, the remaining letters of the alphabet are written below:
CRYPTOGAM
BDEFHIKLN
QSUVWXZ--
To form the 5x5 encryption matrix, the letters are read off by columns:
C B Q R D
S Y E U P
F V T H W
O IJ X G K
Z A L M N
To encode a message, the plainText is split into two-letter groups. If a two-letter group would consist of a double letter, an ‘X’ is inserted between the double letters. An ‘X’ is also added at the end if needed to complete the last group. So, if the plainText is "The scheme really works." the two-letter groups formed as follows:
TH ES CH EM ER EA LX LY WO RK SX
Each letter pair is encoded using the encryption matrix. If the letters are in the same row, the letter to its right in that row (wrapping the row if necessary) replaces each letter. If the letters are in the same column, each letter is replaced by the letter beneath it in that column (again, wrapping the column back to the top if necessary). If the letters are in different rows and columns, each letter is replaced with the letter at the intersection of its row and the other letter’s column. So, in our example, the cipherText becomes:
HW UY RF UL UQ YL QL AE FK DG EO
So, with that explanation, the prototype for the code you should write is:
#if defined(__cplusplus)
extern "C" {
#endif
void InitPlayfair(
const char *words[], /* dictionary words */
long numDictionaryWords /* number of null-terminated words in dictionary */
);
void DecodePlayfair(
const char *cipherText, /* null-terminated text to decode */
char *plainText /* null-terminated decoded text */
);
void TermPlayfair(void);
#if defined(__cplusplus)
}
#endif
All of the words used in the plainText messages, as well as the keyword used to construct the encryption matrix, will be included in the numDictionaryWords words provided to your InitPlayfair routine. The words will contain only uppercase alphabetic characters and will be sorted in alphabetical order. Your InitPlayfair routine may analyze the dictionary and allocate memory to store any analysis results. After InitPlayfair is called, DecodePlayfair will be called multiple (an average of 10-100) times with cipherText messages that are to be decoded into plainText. Finally, TermPlayfair will be called so that you can return any memory allocated by InitPlayfair.
The winner will be the solution that decodes all of the cipherText correctly in the least amount of execution time. A large fixed penalty will be added for each message that is decoded incorrectly.
This will be a native PowerPC Challenge, using the latest CodeWarrior environment. Solutions may be coded in C, C++, or Pascal. Following our tradition for September Challenges, solutions may also be coded in assembly language. In response to numerous requests, solutions in Java will also be accepted this month. Java entries must be accompanied by a test driver that uses the interface provided in the problem statement.
Thanks to Tom Saxton for suggesting this Challenge. Tom wins two Programmer’s Challenge points for the suggestion, as can you if you send in an idea that inspires a Challenge used in the column.
Test code for this Challenge is available.
You can get a head start on the Challenge by reading the
Programmer's Challenge mailing list. It will be posted to the list on
or before the 12th of the preceding month. To join, send an email to
listserv@listmail.xplain.com
with the subject "subscribe challenge-A". You can also join the
discussion list by sending a message with the subject "subscribe
challenge-D".
|