Tweaked slide layout
[cipher-training.git] / slides / pocket-enigma-encipher.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>Pocket enigma</title>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
6 <style type="text/css">
7 /* Slideshow styles */
8 body {
9 font-size: 20px;
10 }
11 h1, h2, h3 {
12 font-weight: 400;
13 margin-bottom: 0;
14 }
15 h1 { font-size: 3em; }
16 h2 { font-size: 2em; }
17 h3 { font-size: 1.6em; }
18 a, a > code {
19 text-decoration: none;
20 }
21 code {
22 -moz-border-radius: 5px;
23 -web-border-radius: 5px;
24 background: #e7e8e2;
25 border-radius: 5px;
26 font-size: 16px;
27 }
28 .plaintext {
29 background: #272822;
30 color: #80ff80;
31 text-shadow: 0 0 20px #333;
32 padding: 2px 5px;
33 }
34 .ciphertext {
35 background: #272822;
36 color: #ff6666;
37 text-shadow: 0 0 20px #333;
38 padding: 2px 5px;
39 }
40 .indexlink {
41 position: absolute;
42 bottom: 1em;
43 left: 1em;
44 }
45 .float-right {
46 float: right;
47 }
48 </style>
49 </head>
50 <body>
51 <textarea id="source">
52
53 # Pocket Enigma
54
55 ![centre-aligned Pocket Engima](pocket-enigma-small.jpg)
56
57 Stateful cipher
58
59 ---
60
61 layout: true
62
63 .indexlink[[Index](index.html)]
64
65 ---
66
67 # Pocket Enigma
68
69 Emulates the Enigma machine from WWII
70
71 Mechanical cipher machine
72
73 * Substitution cipher
74 * Substitution changes with every letter
75
76 Ciphering method: advance the wheel, then follow the lines to encipher the letter
77
78 ## Stateful enciphering
79
80 The cipher depends on the position of the wheel
81
82 We need to encapsulate that state
83
84 Objects have state
85
86 ---
87
88 # The PocketEnigma object
89
90 What do we want it to do?
91
92 What data should the object hold?
93
94 ---
95
96 # The PocketEnigma object
97
98 What do we want it to do?
99
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)
107
108
109 * Accept user-defined wheels
110 * ...and validate them
111
112 What data should it hold?
113
114 * A description of the wheel being used
115 * The current position of the wheel
116
117 ---
118
119 # Data structures
120
121 What's a convenient representation of the wheel
122
123 1. for the object to use internally
124 2. for a person to use to describe the wheel
125
126 They may not be the same, and we'll have to translate between them
127
128 ---
129
130 # Data structures
131
132 ### Internal use: list of transpositions.
133
134 ```python
135 [2, 3, 0, 1, 22, 8, 15, 12, 5, ...
136 ```
137
138 so position 0 ('a') swaps with position 2 ('c'), position 3 ('d') swaps with position 1 ('b'), and so on.
139
140 * This will be a nightmare to enter correctly
141
142 ### Exernal use: list of pairs
143
144 ```python
145 [('a', 'c'), ('b', 'd'), ...]
146 ```
147
148 Easier to enter
149
150 * Need to validate the human-entered list, to check it's valid
151
152 ---
153
154 # Validating the wheel description
155
156 What tests?
157
158 ---
159
160 # Validating the wheel specification
161
162 What tests?
163
164 * 13 elements...
165 * ...each a pair...
166 * ...and 26 letters mentioned overall
167
168 Raise exceptions if the specification is invalid
169
170 ---
171
172 # Making the PocketEnigma class
173
174 ```python
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
184
185 def make_wheel_map(self, wheel_spec):
186 ...
187 self.wheel_map = ...
188 ...
189
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)))
194 ...
195 ```
196
197 ---
198
199 # A note on testing
200
201 Testing's easier if everything returns a meaningful value
202
203 Saves having to look up different values after performing each operation
204
205 `__init__` can't return a value (restriction of Python)
206
207 ```python
208 if __name__ == "__main__":
209 import doctest
210 doctest.testmod(extraglobs={'pe': PocketEnigma(1, 'a')})
211 ```
212
213 `pe` is now available in all tests.
214
215 ---
216
217 # Looking up the enciphered version of a letter
218
219 *Not* advancing the wheel before
220
221 Keep `self.position` to record where the wheel is
222
223 * `__init__` can be passed a letter, but internally it's a number
224
225 But the wheel map only works if the wheel arrow is pointing at 'a'
226
227 Idea:
228
229 1. Rotate the source letter back `position` spaces
230 2. Do the lookup
231 3. Rotate the destination letter forward `position` spaces
232
233 (all mod 26)
234
235 i.e. source → subtract position → lookup destination → add position
236
237 ---
238
239 # Advance the wheel
240
241 Trivial...
242
243 # Encipher a letter
244
245 Advance the wheel, then look up the letter
246
247 ---
248
249 # Encipher a message
250
251 ```python
252 ciphertext = ''
253 for letter in plaintext:
254 ciphertext += encipher_letter(letter)
255 return ciphertext
256 ```
257
258 Have to be explicit as the order of the operations is important
259
260 * Something like `map` might choose an order different from strict left-to-right
261
262 ## Test it against the physical object
263
264 </textarea>
265 <script src="http://gnab.github.io/remark/downloads/remark-0.6.0.min.js" type="text/javascript">
266 </script>
267
268 <script type="text/javascript"
269 src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML&delayStartupUntil=configured"></script>
270
271 <script type="text/javascript">
272 var slideshow = remark.create({ ratio: "16:9" });
273
274 // Setup MathJax
275 MathJax.Hub.Config({
276 tex2jax: {
277 skipTags: ['script', 'noscript', 'style', 'textarea', 'pre']
278 }
279 });
280 MathJax.Hub.Queue(function() {
281 $(MathJax.Hub.getAllJax()).map(function(index, elem) {
282 return(elem.SourceElement());
283 }).parent().addClass('has-jax');
284 });
285 MathJax.Hub.Configured();
286 </script>
287 </body>
288 </html>