4 <title>Pocket enigma
</title>
5 <meta http-equiv=
"Content-Type" content=
"text/html; charset=UTF-8"/>
6 <style type=
"text/css">
15 h1 { font-size:
3em; }
16 h2 { font-size:
2em; }
17 h3 { font-size:
1.6em; }
19 text-decoration: none;
22 -moz-border-radius:
5px;
23 -web-border-radius:
5px;
31 text-shadow:
0 0 20px #
333;
37 text-shadow:
0 0 20px #
333;
51 <textarea id=
"source">
55 ![centre-aligned Pocket Engima](pocket-enigma-small.jpg)
63 .indexlink[[Index](index.html)]
69 Emulates the Enigma machine from WWII
71 Mechanical cipher machine
74 * Substitution changes with every letter
76 Ciphering method: advance the wheel, then follow the lines to encipher the letter
78 ## Stateful enciphering
80 The cipher depends on the position of the wheel
82 We need to encapsulate that state
88 # The PocketEnigma object
90 What do we want it to do?
92 What data should the object hold?
96 # The PocketEnigma object
98 What do we want it to do?
100 * Initialise with the appropriate wheel (and possible starting position)
101 * Spin the wheel to a given position
102 * Advance the wheel one position
103 * Look up a letter given the wheel position
104 * Encipher a letter (advance the wheel then look up the letter)
105 * Encipher a message (optionally give the key)
106 * Make aliases for deciphering (same as enciphering)
109 * Accept user-defined wheels
110 * ...and validate them
112 What data should it hold?
114 * A description of the wheel being used
115 * The current position of the wheel
121 What's a convenient representation of the wheel
123 1. for the object to use internally
124 2. for a person to use to describe the wheel
126 They may not be the same, and we'll have to translate between them
132 ### Internal use: list of transpositions.
135 [
2,
3,
0,
1,
22,
8,
15,
12,
5, ...
138 so position
0 ('a') swaps with position
2 ('c'), position
3 ('d') swaps with position
1 ('b'), and so on.
140 * This will be a nightmare to enter correctly
142 ### Exernal use: list of pairs
145 [('a', 'c'), ('b', 'd'), ...]
150 * Need to validate the human-entered list, to check it's valid
154 # Validating the wheel description
160 # Validating the wheel specification
166 * ...and
26 letters mentioned overall
168 Raise exceptions if the specification is invalid
172 # Making the PocketEnigma class
175 class PocketEnigma(object):
176 def __init__(self, wheel=
1, position='a'):
177 self.wheel1 = [('a', 'z'), ('b', 'e'), ('c', 'x'), ('d', 'k'),
178 ('f', 'h'), ('g', 'j'), ('i', 'm'), ('l', 'r'), ('n', 'o'),
179 ('p', 'v'), ('q', 't'), ('s', 'u'), ('w', 'y')]
180 self.wheel2 = [('a', 'c'), ('b', 'd'), ('e', 'w'), ('f', 'i'),
181 ('g', 'p'), ('h', 'm'), ('j', 'k'), ('l', 'n'), ('o', 'q'),
182 ('r', 'z'), ('s', 'u'), ('t', 'v'), ('x', 'y')]
183 # Rest of initialisation code here
185 def make_wheel_map(self, wheel_spec):
190 def validate_wheel_spec(self, wheel_spec):
191 if len(wheel_spec) !=
13:
192 raise ValueError(
"Wheel specification has {} pairs, requires 13".
193 format(len(wheel_spec)))
201 Testing's easier if everything returns a meaningful value
203 Saves having to look up different values after performing each operation
205 `__init__` can't return a value (restriction of Python)
208 if __name__ ==
"__main__":
210 doctest.testmod(extraglobs={'pe': PocketEnigma(
1, 'a')})
213 `pe` is now available in all tests.
217 # Looking up the enciphered version of a letter
219 *Not* advancing the wheel before
221 Keep `self.position` to record where the wheel is
223 * `__init__` can be passed a letter, but internally it's a number
225 But the wheel map only works if the wheel arrow is pointing at 'a'
229 1. Rotate the source letter back `position` spaces
231 3. Rotate the destination letter forward `position` spaces
235 i.e. source → subtract position → lookup destination → add position
245 Advance the wheel, then look up the letter
253 for letter in plaintext:
254 ciphertext += encipher_letter(letter)
258 Have to be explicit as the order of the operations is important
260 * Something like `map` might choose an order different from strict left-to-right
262 ## Test it against the physical object
265 <script src=
"http://gnab.github.io/remark/downloads/remark-0.6.0.min.js" type=
"text/javascript">
268 <script type=
"text/javascript"
269 src=
"http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML&delayStartupUntil=configured"></script>
271 <script type=
"text/javascript">
272 var slideshow = remark.create({ ratio:
"16:9" });
277 skipTags: ['script', 'noscript', 'style', 'textarea', 'pre']
280 MathJax.Hub.Queue(function() {
281 $(MathJax.Hub.getAllJax()).map(function(index, elem) {
282 return(elem.SourceElement());
283 }).parent().addClass('has-jax');
285 MathJax.Hub.Configured();