I've considered doing a Wolfram implementation of this before. Here is the logic that does the encoding:
It's much simpler to convert letters to numbers before the encoding and convert back after.
lettersToNumbers = Thread[CharacterRange["A", "Z"] -> Range@26];
numbersToLetters = Reverse /@ lettersToNumbers;
The linked applet uses rotors I-V from the Enigma I and M3 Army models and reflector B. Copy the permutations and notch settings for those and others from
here.
rotors = Characters /@ {"EKMFLGDQVZNTOWYHXUSPAIBRCJ",
"AJDKSIRUXBLHWTMCQGZNPYFVOE", "BDFHJLCPRTXVZNYEIWGAKMUSQO",
"ESOVPZJAYQUIRHXLNFTGKDCMWB", "VZBRGITYUPSDNHLXAWMJQOFECK"} /.
lettersToNumbers;
notches = ({"Q", "E", "V", "J", "Z"} /. lettersToNumbers) - 1;
reflector =
Characters@"YRUHQSLDPXNGOKMIEBFZCWVJAT" /. lettersToNumbers;
The state of the machine consists of an ordered set of 3 rotors and their current rotation. The first rotor rotates every letter. The others two periodically rotate based on the notches for each rotor. The configuration below is the one used in the animation above.
configuration = {{3, 2, 1}, ({"X", "D", "H"} /. lettersToNumbers) -
1};
step[] :=
configuration[[2]] =
Mod[configuration[[2]] +
Switch[{configuration[[2, 1]] == notches[[configuration[[1, 1]]]],
configuration[[2, 2]] ==
notches[[configuration[[1, 2]]]]}, {True, True}, {1, 1,
1}, {True, False}, {1, 1, 0}, _, {1, 0, 0}], 26]
Encoding consists of a sequence of permutations where the input prior to each step is offset by that rotor's rotation and the output is then reverse-offset before sending to the next rotor. The reflector rotor does not rotate and has the added constraint that its permutation is its own inverse. After reflecting the input is passed back through the rotors in reverse order.
encode[letter_] := (step[];
Fold[Mod[PermutationReplace[
Mod[# + #2[[2]], 26, 1], #2[[1]]] - #2[[2]], 26, 1] &,
letter /. lettersToNumbers,
Join @@ {#, {{reflector, 0}}, {InversePermutation@#, #2} & @@@
Reverse@#} &@
Thread[{rotors[[configuration[[1]]]], configuration[[2]]}]] /.
numbersToLetters)
Here's the result with the same input from the animation:
encode /@ Characters@"WOLFRAMMATHEMATICA"
{"I", "X", "Z", "K", "H", "E", "U", "W", "T", "J", "Q", "C", "J", \
"P", "Z", "E", "T", "C"}