Built enigma machine
[cipher-tools.git] / enigma.ipynb
1 {
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "metadata": {},
6 "source": [
7 "# Enigma machine\n",
8 "Specification from [Codes and Ciphers](http://www.codesandciphers.org.uk/enigma/rotorspec.htm) page.\n",
9 "\n",
10 "Example Enigma machines from [Louise Dale](http://enigma.louisedade.co.uk/enigma.html) (full simulation) and [EnigmaCo](http://enigmaco.de/enigma/enigma.html) (good animation of the wheels, but no ring settings).\n",
11 "\n",
12 "There's also the nice Enigma simulator for Android by [Franklin Heath](https://franklinheath.co.uk/2012/02/04/our-first-app-published-enigma-simulator/), available on the [Google Play store](https://play.google.com/store/apps/details?id=uk.co.franklinheath.enigmasim&hl=en_GB)."
13 ]
14 },
15 {
16 "cell_type": "code",
17 "execution_count": 333,
18 "metadata": {
19 "collapsed": true
20 },
21 "outputs": [],
22 "source": [
23 "import string\n",
24 "\n",
25 "cat = ''.join"
26 ]
27 },
28 {
29 "cell_type": "code",
30 "execution_count": 334,
31 "metadata": {
32 "collapsed": true
33 },
34 "outputs": [],
35 "source": [
36 "wheel_i_spec = 'ekmflgdqvzntowyhxuspaibrcj'\n",
37 "wheel_ii_spec = 'ajdksiruxblhwtmcqgznpyfvoe'\n",
38 "wheel_iii_spec = 'bdfhjlcprtxvznyeiwgakmusqo'\n",
39 "wheel_iv_spec = 'esovpzjayquirhxlnftgkdcmwb'\n",
40 "wheel_v_spec = 'vzbrgityupsdnhlxawmjqofeck'\n",
41 "wheel_vi_spec = 'jpgvoumfyqbenhzrdkasxlictw'\n",
42 "wheel_vii_spec = 'nzjhgrcxmyswboufaivlpekqdt'\n",
43 "wheel_viii_spec = 'fkqhtlxocbjspdzramewniuygv'\n",
44 "beta_wheel_spec = 'leyjvcnixwpbqmdrtakzgfuhos'\n",
45 "gamma_wheel_spec = 'fsokanuerhmbtiycwlqpzxvgjd'\n",
46 "\n",
47 "wheel_i_pegs = ['q']\n",
48 "wheel_ii_pegs = ['e']\n",
49 "wheel_iii_pegs = ['v']\n",
50 "wheel_iv_pegs = ['j']\n",
51 "wheel_v_pegs = ['z']\n",
52 "wheel_vi_pegs = ['z', 'm']\n",
53 "wheel_vii_pegs = ['z', 'm']\n",
54 "wheel_viii_pegs = ['z', 'm']\n",
55 "\n",
56 "reflector_b_spec = '(ay) (br) (cu) (dh) (eq) (fs) (gl) (ip) (jx) (kn) (mo) (tz) (vw)'\n",
57 "reflector_c_spec = '(af) (bv) (cp) (dj) (ei) (go) (hy) (kr) (lz) (mx) (nw) (tq) (su)'"
58 ]
59 },
60 {
61 "cell_type": "code",
62 "execution_count": 335,
63 "metadata": {
64 "collapsed": false
65 },
66 "outputs": [],
67 "source": [
68 "class LetterTransformer(object):\n",
69 " def __init__(self, specification, raw_transform=False):\n",
70 " if raw_transform:\n",
71 " transform = specification\n",
72 " else:\n",
73 " transform = self.parse_specification(specification)\n",
74 " self.validate_transform(transform)\n",
75 " self.make_transform_map(transform)\n",
76 " \n",
77 " def parse_specification(self, specification):\n",
78 " return specification\n",
79 " \n",
80 " def validate_transform(self, transform):\n",
81 " \"\"\"A set of pairs, of from-to\"\"\"\n",
82 " if len(transform) != 26:\n",
83 " raise ValueError(\"Transform specification has {} pairs, requires 26\".\n",
84 " format(len(transform)))\n",
85 " for p in transform:\n",
86 " if len(p) != 2:\n",
87 " raise ValueError(\"Not all mappings in transform \"\n",
88 " \"have two elements\")\n",
89 " if len(set([p[0] for p in transform])) != 26:\n",
90 " raise ValueError(\"Transform specification must list 26 origin letters\") \n",
91 " if len(set([p[1] for p in transform])) != 26:\n",
92 " raise ValueError(\"Transform specification must list 26 destination letters\") \n",
93 "\n",
94 " def make_empty_transform(self):\n",
95 " self.forward_map = [0] * 26\n",
96 " self.backward_map = [0] * 26\n",
97 " \n",
98 " def make_transform_map(self, transform):\n",
99 " self.make_empty_transform()\n",
100 " for p in transform:\n",
101 " self.forward_map[ord(p[0]) - ord('a')] = ord(p[1]) - ord('a')\n",
102 " self.backward_map[ord(p[1]) - ord('a')] = ord(p[0]) - ord('a')\n",
103 " return self.forward_map, self.backward_map\n",
104 " \n",
105 " def forward(self, letter):\n",
106 " if letter in string.ascii_lowercase:\n",
107 " return chr(\n",
108 " (self.forward_map[(ord(letter) - ord('a')) % 26] + ord('a')))\n",
109 " else:\n",
110 " return ''\n",
111 " \n",
112 " def backward(self, letter):\n",
113 " if letter in string.ascii_lowercase:\n",
114 " return chr(\n",
115 " (self.backward_map[(ord(letter) - ord('a')) % 26] + ord('a')))\n",
116 " else:\n",
117 " return ''"
118 ]
119 },
120 {
121 "cell_type": "code",
122 "execution_count": 336,
123 "metadata": {
124 "collapsed": false
125 },
126 "outputs": [
127 {
128 "data": {
129 "text/plain": [
130 "[('z', 'a'),\n",
131 " ('a', 'b'),\n",
132 " ('b', 'c'),\n",
133 " ('c', 'd'),\n",
134 " ('d', 'e'),\n",
135 " ('e', 'f'),\n",
136 " ('f', 'g'),\n",
137 " ('g', 'h'),\n",
138 " ('h', 'i'),\n",
139 " ('i', 'j'),\n",
140 " ('j', 'k'),\n",
141 " ('k', 'l'),\n",
142 " ('l', 'm'),\n",
143 " ('m', 'n'),\n",
144 " ('n', 'o'),\n",
145 " ('o', 'p'),\n",
146 " ('p', 'q'),\n",
147 " ('q', 'r'),\n",
148 " ('r', 's'),\n",
149 " ('s', 't'),\n",
150 " ('t', 'u'),\n",
151 " ('u', 'v'),\n",
152 " ('v', 'w'),\n",
153 " ('w', 'x'),\n",
154 " ('x', 'y'),\n",
155 " ('y', 'z')]"
156 ]
157 },
158 "execution_count": 336,
159 "metadata": {},
160 "output_type": "execute_result"
161 }
162 ],
163 "source": [
164 "tmap = [('z', 'a')] + [(l, string.ascii_lowercase[i+1]) for i, l in enumerate(string.ascii_lowercase[:-1])]\n",
165 "tmap"
166 ]
167 },
168 {
169 "cell_type": "code",
170 "execution_count": 337,
171 "metadata": {
172 "collapsed": false,
173 "scrolled": true
174 },
175 "outputs": [
176 {
177 "data": {
178 "text/plain": [
179 "([1,\n",
180 " 2,\n",
181 " 3,\n",
182 " 4,\n",
183 " 5,\n",
184 " 6,\n",
185 " 7,\n",
186 " 8,\n",
187 " 9,\n",
188 " 10,\n",
189 " 11,\n",
190 " 12,\n",
191 " 13,\n",
192 " 14,\n",
193 " 15,\n",
194 " 16,\n",
195 " 17,\n",
196 " 18,\n",
197 " 19,\n",
198 " 20,\n",
199 " 21,\n",
200 " 22,\n",
201 " 23,\n",
202 " 24,\n",
203 " 25,\n",
204 " 0],\n",
205 " [25,\n",
206 " 0,\n",
207 " 1,\n",
208 " 2,\n",
209 " 3,\n",
210 " 4,\n",
211 " 5,\n",
212 " 6,\n",
213 " 7,\n",
214 " 8,\n",
215 " 9,\n",
216 " 10,\n",
217 " 11,\n",
218 " 12,\n",
219 " 13,\n",
220 " 14,\n",
221 " 15,\n",
222 " 16,\n",
223 " 17,\n",
224 " 18,\n",
225 " 19,\n",
226 " 20,\n",
227 " 21,\n",
228 " 22,\n",
229 " 23,\n",
230 " 24])"
231 ]
232 },
233 "execution_count": 337,
234 "metadata": {},
235 "output_type": "execute_result"
236 }
237 ],
238 "source": [
239 "lt = LetterTransformer(tmap)\n",
240 "lt.forward_map, lt.backward_map"
241 ]
242 },
243 {
244 "cell_type": "code",
245 "execution_count": 338,
246 "metadata": {
247 "collapsed": false
248 },
249 "outputs": [
250 {
251 "data": {
252 "text/plain": [
253 "'bcdefghijklmnopqrstuvwxyza'"
254 ]
255 },
256 "execution_count": 338,
257 "metadata": {},
258 "output_type": "execute_result"
259 }
260 ],
261 "source": [
262 "cat(lt.forward(l) for l in string.ascii_lowercase)"
263 ]
264 },
265 {
266 "cell_type": "code",
267 "execution_count": 339,
268 "metadata": {
269 "collapsed": false
270 },
271 "outputs": [
272 {
273 "data": {
274 "text/plain": [
275 "'zabcdefghijklmnopqrstuvwxy'"
276 ]
277 },
278 "execution_count": 339,
279 "metadata": {},
280 "output_type": "execute_result"
281 }
282 ],
283 "source": [
284 "cat(lt.backward(l) for l in string.ascii_lowercase)"
285 ]
286 },
287 {
288 "cell_type": "code",
289 "execution_count": 340,
290 "metadata": {
291 "collapsed": true
292 },
293 "outputs": [],
294 "source": [
295 "class Plugboard(LetterTransformer):\n",
296 " def parse_specification(self, specification):\n",
297 " return [tuple(p) for p in specification.split()]\n",
298 " \n",
299 " def validate_transform(self, transform):\n",
300 " \"\"\"A set of pairs, of from-to\"\"\"\n",
301 " for p in transform:\n",
302 " if len(p) != 2:\n",
303 " raise ValueError(\"Not all mappings in transform\"\n",
304 " \"have two elements\")\n",
305 " \n",
306 " def make_empty_transform(self):\n",
307 " self.forward_map = list(range(26))\n",
308 " self.backward_map = list(range(26))\n",
309 " \n",
310 " def make_transform_map(self, transform):\n",
311 " expanded_transform = transform + [tuple(reversed(p)) for p in transform]\n",
312 " return super(Plugboard, self).make_transform_map(expanded_transform)"
313 ]
314 },
315 {
316 "cell_type": "code",
317 "execution_count": 341,
318 "metadata": {
319 "collapsed": false
320 },
321 "outputs": [],
322 "source": [
323 "pb = Plugboard([('a', 'z'), ('b', 'y')], raw_transform=True)"
324 ]
325 },
326 {
327 "cell_type": "code",
328 "execution_count": 342,
329 "metadata": {
330 "collapsed": false
331 },
332 "outputs": [
333 {
334 "data": {
335 "text/plain": [
336 "'zycdefghijklmnopqrstuvwxba'"
337 ]
338 },
339 "execution_count": 342,
340 "metadata": {},
341 "output_type": "execute_result"
342 }
343 ],
344 "source": [
345 "cat(pb.forward(l) for l in string.ascii_lowercase)"
346 ]
347 },
348 {
349 "cell_type": "code",
350 "execution_count": 343,
351 "metadata": {
352 "collapsed": false
353 },
354 "outputs": [
355 {
356 "data": {
357 "text/plain": [
358 "'zycdefghijklmnopqrstuvwxba'"
359 ]
360 },
361 "execution_count": 343,
362 "metadata": {},
363 "output_type": "execute_result"
364 }
365 ],
366 "source": [
367 "cat(pb.backward(l) for l in string.ascii_lowercase)"
368 ]
369 },
370 {
371 "cell_type": "code",
372 "execution_count": 344,
373 "metadata": {
374 "collapsed": false
375 },
376 "outputs": [],
377 "source": [
378 "pb = Plugboard('az by')"
379 ]
380 },
381 {
382 "cell_type": "code",
383 "execution_count": 345,
384 "metadata": {
385 "collapsed": false
386 },
387 "outputs": [
388 {
389 "data": {
390 "text/plain": [
391 "('zycdefghijklmnopqrstuvwxba', 'zycdefghijklmnopqrstuvwxba')"
392 ]
393 },
394 "execution_count": 345,
395 "metadata": {},
396 "output_type": "execute_result"
397 }
398 ],
399 "source": [
400 "cat(pb.forward(l) for l in string.ascii_lowercase), cat(pb.backward(l) for l in string.ascii_lowercase)"
401 ]
402 },
403 {
404 "cell_type": "code",
405 "execution_count": 346,
406 "metadata": {
407 "collapsed": true
408 },
409 "outputs": [],
410 "source": [
411 "class Reflector(Plugboard):\n",
412 " def parse_specification(self, specification):\n",
413 " return [tuple(p) for p in specification[1:-1].split(') (')]\n",
414 " \n",
415 " def validate_transform(self, transform):\n",
416 " if len(transform) != 13:\n",
417 " raise ValueError(\"Reflector specification has {} pairs, requires 13\".\n",
418 " format(len(transform)))\n",
419 " if len(set([p[0] for p in transform] + \n",
420 " [p[1] for p in transform])) != 26:\n",
421 " raise ValueError(\"Reflector specification does not contain 26 letters\")\n",
422 " try:\n",
423 " super(Reflector, self).validate_transform(transform)\n",
424 " except ValueError as v:\n",
425 " raise ValueError(\"Not all mappings in reflector have two elements\")"
426 ]
427 },
428 {
429 "cell_type": "code",
430 "execution_count": 347,
431 "metadata": {
432 "collapsed": false
433 },
434 "outputs": [
435 {
436 "data": {
437 "text/plain": [
438 "[('a', 'y'),\n",
439 " ('b', 'r'),\n",
440 " ('c', 'u'),\n",
441 " ('d', 'h'),\n",
442 " ('e', 'q'),\n",
443 " ('f', 's'),\n",
444 " ('g', 'l'),\n",
445 " ('i', 'p'),\n",
446 " ('j', 'x'),\n",
447 " ('k', 'n'),\n",
448 " ('m', 'o'),\n",
449 " ('t', 'z'),\n",
450 " ('v', 'w')]"
451 ]
452 },
453 "execution_count": 347,
454 "metadata": {},
455 "output_type": "execute_result"
456 }
457 ],
458 "source": [
459 "# reflector_b_text = '(AY) (BR) (CU) (DH) (EQ) (FS) (GL) (IP) (JX) (KN) (MO) (TZ) (VW)'\n",
460 "reflector_b_l = [tuple(p) for p in reflector_b_spec.lower()[1:-1].split(') (')]\n",
461 "reflector_b_l"
462 ]
463 },
464 {
465 "cell_type": "code",
466 "execution_count": 348,
467 "metadata": {
468 "collapsed": false
469 },
470 "outputs": [],
471 "source": [
472 "reflector_b = Reflector(reflector_b_spec, raw_transform=False)"
473 ]
474 },
475 {
476 "cell_type": "code",
477 "execution_count": 349,
478 "metadata": {
479 "collapsed": false
480 },
481 "outputs": [
482 {
483 "data": {
484 "text/plain": [
485 "'yruhqsldpxngokmiebfzcwvjat'"
486 ]
487 },
488 "execution_count": 349,
489 "metadata": {},
490 "output_type": "execute_result"
491 }
492 ],
493 "source": [
494 "cat(reflector_b.forward(l) for l in string.ascii_lowercase)"
495 ]
496 },
497 {
498 "cell_type": "code",
499 "execution_count": 350,
500 "metadata": {
501 "collapsed": true
502 },
503 "outputs": [],
504 "source": [
505 "reflector_c = Reflector(reflector_c_spec)"
506 ]
507 },
508 {
509 "cell_type": "code",
510 "execution_count": 351,
511 "metadata": {
512 "collapsed": false
513 },
514 "outputs": [
515 {
516 "data": {
517 "text/plain": [
518 "'fvpjiaoyedrzxwgctkuqsbnmhl'"
519 ]
520 },
521 "execution_count": 351,
522 "metadata": {},
523 "output_type": "execute_result"
524 }
525 ],
526 "source": [
527 "cat(reflector_c.forward(l) for l in string.ascii_lowercase)"
528 ]
529 },
530 {
531 "cell_type": "code",
532 "execution_count": 352,
533 "metadata": {
534 "collapsed": true
535 },
536 "outputs": [],
537 "source": [
538 "class SimpleWheel(LetterTransformer):\n",
539 " def __init__(self, transform, position='a', raw_transform=False):\n",
540 " super(SimpleWheel, self).__init__(transform, raw_transform)\n",
541 " self.set_position(position)\n",
542 " \n",
543 " def parse_specification(self, specification):\n",
544 " return list(zip(string.ascii_lowercase, specification))\n",
545 " \n",
546 " def set_position(self, position):\n",
547 " self.position = ord(position) - ord('a')\n",
548 " self.position_l = position\n",
549 " \n",
550 " def forward(self, letter):\n",
551 " if letter in string.ascii_lowercase:\n",
552 " return chr(\n",
553 " (self.forward_map[(ord(letter) - ord('a') + self.position) % 26] - \n",
554 " self.position) % 26 + \n",
555 " ord('a'))\n",
556 " else:\n",
557 " return ''\n",
558 " \n",
559 " def backward(self, letter):\n",
560 " if letter in string.ascii_lowercase:\n",
561 " return chr(\n",
562 " (self.backward_map[(ord(letter) - ord('a') + self.position) % 26] - \n",
563 " self.position) % 26 + \n",
564 " ord('a'))\n",
565 " else:\n",
566 " return ''\n",
567 " \n",
568 " def advance(self):\n",
569 " self.position = (self.position + 1) % 26\n",
570 " self.position_l = chr(self.position + ord('a'))\n",
571 " return self.position"
572 ]
573 },
574 {
575 "cell_type": "code",
576 "execution_count": 353,
577 "metadata": {
578 "collapsed": false,
579 "scrolled": true
580 },
581 "outputs": [
582 {
583 "data": {
584 "text/plain": [
585 "[('a', 'e'),\n",
586 " ('b', 'k'),\n",
587 " ('c', 'm'),\n",
588 " ('d', 'f'),\n",
589 " ('e', 'l'),\n",
590 " ('f', 'g'),\n",
591 " ('g', 'd'),\n",
592 " ('h', 'q'),\n",
593 " ('i', 'v'),\n",
594 " ('j', 'z'),\n",
595 " ('k', 'n'),\n",
596 " ('l', 't'),\n",
597 " ('m', 'o'),\n",
598 " ('n', 'w'),\n",
599 " ('o', 'y'),\n",
600 " ('p', 'h'),\n",
601 " ('q', 'x'),\n",
602 " ('r', 'u'),\n",
603 " ('s', 's'),\n",
604 " ('t', 'p'),\n",
605 " ('u', 'a'),\n",
606 " ('v', 'i'),\n",
607 " ('w', 'b'),\n",
608 " ('x', 'r'),\n",
609 " ('y', 'c'),\n",
610 " ('z', 'j')]"
611 ]
612 },
613 "execution_count": 353,
614 "metadata": {},
615 "output_type": "execute_result"
616 }
617 ],
618 "source": [
619 "rotor_1_transform = list(zip(string.ascii_lowercase, 'EKMFLGDQVZNTOWYHXUSPAIBRCJ'.lower()))\n",
620 "rotor_1_transform"
621 ]
622 },
623 {
624 "cell_type": "code",
625 "execution_count": 354,
626 "metadata": {
627 "collapsed": false
628 },
629 "outputs": [],
630 "source": [
631 "wheel_1 = SimpleWheel(rotor_1_transform, raw_transform=True)"
632 ]
633 },
634 {
635 "cell_type": "code",
636 "execution_count": 355,
637 "metadata": {
638 "collapsed": false
639 },
640 "outputs": [
641 {
642 "data": {
643 "text/plain": [
644 "('ekmflgdqvzntowyhxuspaibrcj', 'uwygadfpvzbeckmthxslrinqoj')"
645 ]
646 },
647 "execution_count": 355,
648 "metadata": {},
649 "output_type": "execute_result"
650 }
651 ],
652 "source": [
653 "cat(wheel_1.forward(l) for l in string.ascii_lowercase), cat(wheel_1.backward(l) for l in string.ascii_lowercase)"
654 ]
655 },
656 {
657 "cell_type": "code",
658 "execution_count": 356,
659 "metadata": {
660 "collapsed": false
661 },
662 "outputs": [],
663 "source": [
664 "wheel_2 = SimpleWheel(wheel_ii_spec)"
665 ]
666 },
667 {
668 "cell_type": "code",
669 "execution_count": 357,
670 "metadata": {
671 "collapsed": false
672 },
673 "outputs": [
674 {
675 "data": {
676 "text/plain": [
677 "('ajdksiruxblhwtmcqgznpyfvoe', 'ajpczwrlfbdkotyuqgenhxmivs')"
678 ]
679 },
680 "execution_count": 357,
681 "metadata": {},
682 "output_type": "execute_result"
683 }
684 ],
685 "source": [
686 "cat(wheel_2.forward(l) for l in string.ascii_lowercase), cat(wheel_2.backward(l) for l in string.ascii_lowercase)"
687 ]
688 },
689 {
690 "cell_type": "code",
691 "execution_count": 358,
692 "metadata": {
693 "collapsed": false
694 },
695 "outputs": [
696 {
697 "data": {
698 "text/plain": [
699 "'cegikboqswuymxdhvfzjltrpna'"
700 ]
701 },
702 "execution_count": 358,
703 "metadata": {},
704 "output_type": "execute_result"
705 }
706 ],
707 "source": [
708 "wheel_3 = SimpleWheel(wheel_iii_spec)\n",
709 "wheel_3.set_position('a')\n",
710 "wheel_3.advance()\n",
711 "cat(wheel_3.forward(l) for l in string.ascii_lowercase)"
712 ]
713 },
714 {
715 "cell_type": "code",
716 "execution_count": 524,
717 "metadata": {
718 "collapsed": false
719 },
720 "outputs": [],
721 "source": [
722 "class Wheel(SimpleWheel):\n",
723 " def __init__(self, transform, ring_peg_letters, ring_setting=1, position='a', raw_transform=False):\n",
724 " self.ring_peg_letters = ring_peg_letters\n",
725 " self.ring_setting = ring_setting\n",
726 " super(Wheel, self).__init__(transform, position=position, raw_transform=raw_transform)\n",
727 " self.set_position(position)\n",
728 " \n",
729 " def set_position(self, position):\n",
730 " super(Wheel, self).set_position(position)\n",
731 " self.peg_positions = [(ord(p) - ord(position)) % 26 for p in self.ring_peg_letters]\n",
732 " self.position = (self.position - self.ring_setting + 1) % 26\n",
733 " \n",
734 " def advance(self):\n",
735 " super(Wheel, self).advance()\n",
736 " self.peg_positions = [(p - 1) % 26 for p in self.peg_positions]\n",
737 " return self.position"
738 ]
739 },
740 {
741 "cell_type": "code",
742 "execution_count": 525,
743 "metadata": {
744 "collapsed": false
745 },
746 "outputs": [],
747 "source": [
748 "wheel_3 = Wheel(wheel_iii_spec, wheel_iii_pegs, position='b', ring_setting=1)"
749 ]
750 },
751 {
752 "cell_type": "code",
753 "execution_count": 526,
754 "metadata": {
755 "collapsed": false
756 },
757 "outputs": [
758 {
759 "data": {
760 "text/plain": [
761 "(1, [20])"
762 ]
763 },
764 "execution_count": 526,
765 "metadata": {},
766 "output_type": "execute_result"
767 }
768 ],
769 "source": [
770 "wheel_3.position, wheel_3.peg_positions"
771 ]
772 },
773 {
774 "cell_type": "code",
775 "execution_count": 527,
776 "metadata": {
777 "collapsed": false
778 },
779 "outputs": [
780 {
781 "data": {
782 "text/plain": [
783 "(25, [24, 11])"
784 ]
785 },
786 "execution_count": 527,
787 "metadata": {},
788 "output_type": "execute_result"
789 }
790 ],
791 "source": [
792 "wheel_6 = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', ring_setting=3)\n",
793 "wheel_6.position, wheel_6.peg_positions"
794 ]
795 },
796 {
797 "cell_type": "code",
798 "execution_count": 528,
799 "metadata": {
800 "collapsed": false,
801 "scrolled": true
802 },
803 "outputs": [
804 {
805 "name": "stdout",
806 "output_type": "stream",
807 "text": [
808 "0 [23, 10]\n",
809 "1 [22, 9]\n",
810 "2 [21, 8]\n",
811 "3 [20, 7]\n",
812 "4 [19, 6]\n",
813 "5 [18, 5]\n",
814 "6 [17, 4]\n",
815 "7 [16, 3]\n",
816 "8 [15, 2]\n",
817 "9 [14, 1]\n",
818 "10 [13, 0]\n",
819 "11 [12, 25]\n",
820 "12 [11, 24]\n",
821 "13 [10, 23]\n",
822 "14 [9, 22]\n",
823 "15 [8, 21]\n",
824 "16 [7, 20]\n",
825 "17 [6, 19]\n",
826 "18 [5, 18]\n",
827 "19 [4, 17]\n",
828 "20 [3, 16]\n",
829 "21 [2, 15]\n",
830 "22 [1, 14]\n",
831 "23 [0, 13]\n",
832 "24 [25, 12]\n",
833 "25 [24, 11]\n",
834 "0 [23, 10]\n"
835 ]
836 }
837 ],
838 "source": [
839 "for _ in range(27):\n",
840 " wheel_6.advance()\n",
841 " print(wheel_6.position, wheel_6.peg_positions)"
842 ]
843 },
844 {
845 "cell_type": "code",
846 "execution_count": 529,
847 "metadata": {
848 "collapsed": true
849 },
850 "outputs": [],
851 "source": [
852 "class Enigma(object):\n",
853 " def __init__(self, reflector_spec,\n",
854 " left_wheel_spec, left_wheel_pegs,\n",
855 " middle_wheel_spec, middle_wheel_pegs,\n",
856 " right_wheel_spec, right_wheel_pegs,\n",
857 " left_ring_setting, middle_ring_setting, right_ring_setting,\n",
858 " plugboard_setting):\n",
859 " self.reflector = Reflector(reflector_spec)\n",
860 " self.left_wheel = Wheel(left_wheel_spec, left_wheel_pegs, ring_setting=left_ring_setting)\n",
861 " self.middle_wheel = Wheel(middle_wheel_spec, middle_wheel_pegs, ring_setting=middle_ring_setting)\n",
862 " self.right_wheel = Wheel(right_wheel_spec, right_wheel_pegs, ring_setting=right_ring_setting)\n",
863 " self.plugboard = Plugboard(plugboard_setting)\n",
864 " \n",
865 " def set_wheels(self, left_wheel_position, middle_wheel_position, right_wheel_position):\n",
866 " self.left_wheel.set_position(left_wheel_position)\n",
867 " self.middle_wheel.set_position(middle_wheel_position)\n",
868 " self.right_wheel.set_position(right_wheel_position)\n",
869 " \n",
870 " def lookup(self, letter):\n",
871 " a = self.plugboard.forward(letter)\n",
872 " b = self.right_wheel.forward(a)\n",
873 " c = self.middle_wheel.forward(b)\n",
874 " d = self.left_wheel.forward(c)\n",
875 " e = self.reflector.forward(d)\n",
876 " f = self.left_wheel.backward(e)\n",
877 " g = self.middle_wheel.backward(f)\n",
878 " h = self.right_wheel.backward(g)\n",
879 " i = self.plugboard.backward(h)\n",
880 " return i\n",
881 " \n",
882 " def advance(self):\n",
883 " advance_middle = False\n",
884 " advance_left = False\n",
885 " if 0 in self.right_wheel.peg_positions:\n",
886 " advance_middle = True\n",
887 " if 0 in self.middle_wheel.peg_positions:\n",
888 " advance_left = True\n",
889 " if 0 in self.middle_wheel.peg_positions and 25 in self.right_wheel.peg_positions:\n",
890 " advance_middle = True\n",
891 " advance_left = True\n",
892 " self.right_wheel.advance()\n",
893 " if advance_middle: self.middle_wheel.advance()\n",
894 " if advance_left: self.left_wheel.advance()\n",
895 " \n",
896 " def encipher_letter(self, letter):\n",
897 " self.advance()\n",
898 " return self.lookup(letter)\n",
899 " \n",
900 " def encipher(self, message):\n",
901 " enciphered = ''\n",
902 " for letter in message:\n",
903 " enciphered += self.encipher_letter(letter)\n",
904 " return enciphered"
905 ]
906 },
907 {
908 "cell_type": "code",
909 "execution_count": 548,
910 "metadata": {
911 "collapsed": false
912 },
913 "outputs": [],
914 "source": [
915 "enigma = Enigma(reflector_b_spec, \n",
916 " wheel_i_spec, wheel_i_pegs,\n",
917 " wheel_ii_spec, wheel_ii_pegs,\n",
918 " wheel_iii_spec, wheel_iii_pegs,\n",
919 " 1, 1, 1,\n",
920 " '')"
921 ]
922 },
923 {
924 "cell_type": "code",
925 "execution_count": 549,
926 "metadata": {
927 "collapsed": false
928 },
929 "outputs": [
930 {
931 "data": {
932 "text/plain": [
933 "'u'"
934 ]
935 },
936 "execution_count": 549,
937 "metadata": {},
938 "output_type": "execute_result"
939 }
940 ],
941 "source": [
942 "enigma.lookup('a')"
943 ]
944 },
945 {
946 "cell_type": "code",
947 "execution_count": 550,
948 "metadata": {
949 "collapsed": false
950 },
951 "outputs": [
952 {
953 "data": {
954 "text/plain": [
955 "'a'"
956 ]
957 },
958 "execution_count": 550,
959 "metadata": {},
960 "output_type": "execute_result"
961 }
962 ],
963 "source": [
964 "enigma.lookup('u')"
965 ]
966 },
967 {
968 "cell_type": "code",
969 "execution_count": 551,
970 "metadata": {
971 "collapsed": false,
972 "scrolled": true
973 },
974 "outputs": [
975 {
976 "name": "stdout",
977 "output_type": "stream",
978 "text": [
979 "a a a ; [16] [4] [21]\n",
980 "a a b ; [16] [4] [20]\n",
981 "a a c ; [16] [4] [19]\n",
982 "a a d ; [16] [4] [18]\n",
983 "a a e ; [16] [4] [17]\n",
984 "a a f ; [16] [4] [16]\n",
985 "a a g ; [16] [4] [15]\n",
986 "a a h ; [16] [4] [14]\n",
987 "a a i ; [16] [4] [13]\n",
988 "a a j ; [16] [4] [12]\n",
989 "a a k ; [16] [4] [11]\n",
990 "a a l ; [16] [4] [10]\n",
991 "a a m ; [16] [4] [9]\n",
992 "a a n ; [16] [4] [8]\n",
993 "a a o ; [16] [4] [7]\n",
994 "a a p ; [16] [4] [6]\n",
995 "a a q ; [16] [4] [5]\n",
996 "a a r ; [16] [4] [4]\n",
997 "a a s ; [16] [4] [3]\n",
998 "a a t ; [16] [4] [2]\n",
999 "a a u ; [16] [4] [1]\n",
1000 "a a v ; [16] [4] [0]\n",
1001 "a b w ; [16] [3] [25]\n",
1002 "a b x ; [16] [3] [24]\n",
1003 "a b y ; [16] [3] [23]\n",
1004 "a b z ; [16] [3] [22]\n"
1005 ]
1006 }
1007 ],
1008 "source": [
1009 "enigma.set_wheels('a', 'a', 'a')\n",
1010 "for _ in range(26):\n",
1011 " print(enigma.left_wheel.position_l, enigma.middle_wheel.position_l, enigma.right_wheel.position_l, ';',\n",
1012 " enigma.left_wheel.peg_positions, enigma.middle_wheel.peg_positions, enigma.right_wheel.peg_positions)\n",
1013 " enigma.advance()"
1014 ]
1015 },
1016 {
1017 "cell_type": "code",
1018 "execution_count": 552,
1019 "metadata": {
1020 "collapsed": false,
1021 "scrolled": true
1022 },
1023 "outputs": [
1024 {
1025 "name": "stdout",
1026 "output_type": "stream",
1027 "text": [
1028 "a d t ; [16] [1] [2]\n",
1029 "a d u ; [16] [1] [1]\n",
1030 "a d v ; [16] [1] [0]\n",
1031 "a e w ; [16] [0] [25]\n",
1032 "b f x ; [15] [25] [24]\n",
1033 "b f y ; [15] [25] [23]\n",
1034 "b f z ; [15] [25] [22]\n",
1035 "b f a ; [15] [25] [21]\n",
1036 "b f b ; [15] [25] [20]\n",
1037 "b f c ; [15] [25] [19]\n",
1038 "b f d ; [15] [25] [18]\n",
1039 "b f e ; [15] [25] [17]\n",
1040 "b f f ; [15] [25] [16]\n",
1041 "b f g ; [15] [25] [15]\n",
1042 "b f h ; [15] [25] [14]\n",
1043 "b f i ; [15] [25] [13]\n",
1044 "b f j ; [15] [25] [12]\n",
1045 "b f k ; [15] [25] [11]\n",
1046 "b f l ; [15] [25] [10]\n",
1047 "b f m ; [15] [25] [9]\n",
1048 "b f n ; [15] [25] [8]\n",
1049 "b f o ; [15] [25] [7]\n",
1050 "b f p ; [15] [25] [6]\n",
1051 "b f q ; [15] [25] [5]\n",
1052 "b f r ; [15] [25] [4]\n",
1053 "b f s ; [15] [25] [3]\n"
1054 ]
1055 }
1056 ],
1057 "source": [
1058 "enigma.set_wheels('a', 'd', 't')\n",
1059 "for _ in range(26):\n",
1060 " print(enigma.left_wheel.position_l, enigma.middle_wheel.position_l, enigma.right_wheel.position_l, ';',\n",
1061 " enigma.left_wheel.peg_positions, enigma.middle_wheel.peg_positions, enigma.right_wheel.peg_positions)\n",
1062 " enigma.advance()"
1063 ]
1064 },
1065 {
1066 "cell_type": "code",
1067 "execution_count": 553,
1068 "metadata": {
1069 "collapsed": false
1070 },
1071 "outputs": [
1072 {
1073 "data": {
1074 "text/plain": [
1075 "'i'"
1076 ]
1077 },
1078 "execution_count": 553,
1079 "metadata": {},
1080 "output_type": "execute_result"
1081 }
1082 ],
1083 "source": [
1084 "enigma.set_wheels('a', 'a', 'a')\n",
1085 "enigma.advance()\n",
1086 "enigma.lookup('h')"
1087 ]
1088 },
1089 {
1090 "cell_type": "code",
1091 "execution_count": 560,
1092 "metadata": {
1093 "collapsed": false
1094 },
1095 "outputs": [
1096 {
1097 "data": {
1098 "text/plain": [
1099 "'ilbdartydc'"
1100 ]
1101 },
1102 "execution_count": 560,
1103 "metadata": {},
1104 "output_type": "execute_result"
1105 }
1106 ],
1107 "source": [
1108 "enigma.set_wheels('a', 'a', 'a')\n",
1109 "ct = enigma.encipher('hellothere')\n",
1110 "assert(ct == 'ilbdartydc')\n",
1111 "ct"
1112 ]
1113 },
1114 {
1115 "cell_type": "code",
1116 "execution_count": 555,
1117 "metadata": {
1118 "collapsed": false
1119 },
1120 "outputs": [
1121 {
1122 "data": {
1123 "text/plain": [
1124 "'hellothere'"
1125 ]
1126 },
1127 "execution_count": 555,
1128 "metadata": {},
1129 "output_type": "execute_result"
1130 }
1131 ],
1132 "source": [
1133 "enigma.set_wheels('a', 'a', 'a')\n",
1134 "pt = enigma.encipher(ct)\n",
1135 "pt"
1136 ]
1137 },
1138 {
1139 "cell_type": "code",
1140 "execution_count": 556,
1141 "metadata": {
1142 "collapsed": false
1143 },
1144 "outputs": [
1145 {
1146 "data": {
1147 "text/plain": [
1148 "'i'"
1149 ]
1150 },
1151 "execution_count": 556,
1152 "metadata": {},
1153 "output_type": "execute_result"
1154 }
1155 ],
1156 "source": [
1157 "enigma.set_wheels('a', 'a', 'a')\n",
1158 "enigma.advance()\n",
1159 "enigma.lookup('h')"
1160 ]
1161 },
1162 {
1163 "cell_type": "code",
1164 "execution_count": 557,
1165 "metadata": {
1166 "collapsed": false
1167 },
1168 "outputs": [
1169 {
1170 "data": {
1171 "text/plain": [
1172 "('h', 'q', 'q', 'x', 'j', 'z', 's', 'i', 'i')"
1173 ]
1174 },
1175 "execution_count": 557,
1176 "metadata": {},
1177 "output_type": "execute_result"
1178 }
1179 ],
1180 "source": [
1181 "enigma.set_wheels('a', 'a', 'a')\n",
1182 "enigma.advance()\n",
1183 "a = enigma.plugboard.forward('h')\n",
1184 "b = enigma.right_wheel.forward(a)\n",
1185 "c = enigma.middle_wheel.forward(b)\n",
1186 "d = enigma.left_wheel.forward(c)\n",
1187 "e = enigma.reflector.forward(d)\n",
1188 "f = enigma.left_wheel.backward(e)\n",
1189 "g = enigma.middle_wheel.backward(f)\n",
1190 "h = enigma.right_wheel.backward(g)\n",
1191 "i = enigma.plugboard.backward(h)\n",
1192 "a, b, c, d, e, f, g, h, i"
1193 ]
1194 },
1195 {
1196 "cell_type": "code",
1197 "execution_count": 558,
1198 "metadata": {
1199 "collapsed": false
1200 },
1201 "outputs": [
1202 {
1203 "data": {
1204 "text/plain": [
1205 "'h'"
1206 ]
1207 },
1208 "execution_count": 558,
1209 "metadata": {},
1210 "output_type": "execute_result"
1211 }
1212 ],
1213 "source": [
1214 "pb = Plugboard('')\n",
1215 "pb.forward('h')"
1216 ]
1217 },
1218 {
1219 "cell_type": "code",
1220 "execution_count": 561,
1221 "metadata": {
1222 "collapsed": false
1223 },
1224 "outputs": [
1225 {
1226 "data": {
1227 "text/plain": [
1228 "'bahxvfrpdc'"
1229 ]
1230 },
1231 "execution_count": 561,
1232 "metadata": {},
1233 "output_type": "execute_result"
1234 }
1235 ],
1236 "source": [
1237 "enigma.set_wheels('a', 'd', 't')\n",
1238 "ct = enigma.encipher('hellothere')\n",
1239 "assert(ct == 'bahxvfrpdc')\n",
1240 "ct"
1241 ]
1242 },
1243 {
1244 "cell_type": "code",
1245 "execution_count": 562,
1246 "metadata": {
1247 "collapsed": false
1248 },
1249 "outputs": [
1250 {
1251 "data": {
1252 "text/plain": [
1253 "'kvmmwrlqlqsqpeugjrcxzwpfyiyybwloewrouvkpoztceuwtfjzqwpbqldttsr'"
1254 ]
1255 },
1256 "execution_count": 562,
1257 "metadata": {},
1258 "output_type": "execute_result"
1259 }
1260 ],
1261 "source": [
1262 "enigma.set_wheels('b', 'd', 'q')\n",
1263 "ct = enigma.encipher('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')\n",
1264 "assert(ct == 'kvmmwrlqlqsqpeugjrcxzwpfyiyybwloewrouvkpoztceuwtfjzqwpbqldttsr')\n",
1265 "assert(enigma.left_wheel.position_l == 'c')\n",
1266 "assert(enigma.middle_wheel.position_l == 'h')\n",
1267 "assert(enigma.right_wheel.position_l == 'a')\n",
1268 "ct"
1269 ]
1270 },
1271 {
1272 "cell_type": "code",
1273 "execution_count": 563,
1274 "metadata": {
1275 "collapsed": false
1276 },
1277 "outputs": [
1278 {
1279 "data": {
1280 "text/plain": [
1281 "'c'"
1282 ]
1283 },
1284 "execution_count": 563,
1285 "metadata": {},
1286 "output_type": "execute_result"
1287 }
1288 ],
1289 "source": [
1290 "enigma.left_wheel.position_l"
1291 ]
1292 },
1293 {
1294 "cell_type": "code",
1295 "execution_count": 564,
1296 "metadata": {
1297 "collapsed": true
1298 },
1299 "outputs": [],
1300 "source": [
1301 "# Setting sheet line 31 from http://www.codesandciphers.org.uk/enigma/enigma3.htm\n",
1302 "# Enigma simulation settings are \n",
1303 "# http://enigma.louisedade.co.uk/enigma.html?m3;b;b153;AFTX;AJFE;AU-BG-EY-FP-HL-IN-JZ-OS-QR-TX\n",
1304 "w_enigma = Enigma(reflector_b_spec, \n",
1305 " wheel_i_spec, wheel_i_pegs,\n",
1306 " wheel_v_spec, wheel_v_pegs,\n",
1307 " wheel_iii_spec, wheel_iii_pegs,\n",
1308 " 6, 20, 24,\n",
1309 " 'ua pf rq so ni ey bg hl tx zj')"
1310 ]
1311 },
1312 {
1313 "cell_type": "code",
1314 "execution_count": 566,
1315 "metadata": {
1316 "collapsed": false
1317 },
1318 "outputs": [
1319 {
1320 "name": "stdout",
1321 "output_type": "stream",
1322 "text": [
1323 "wzmfiwuntn\n"
1324 ]
1325 },
1326 {
1327 "data": {
1328 "text/plain": [
1329 "'wzmfiwuntn'"
1330 ]
1331 },
1332 "execution_count": 566,
1333 "metadata": {},
1334 "output_type": "execute_result"
1335 }
1336 ],
1337 "source": [
1338 "w_enigma.set_wheels('j', 'e', 'u')\n",
1339 "ct = w_enigma.encipher('hellothere')\n",
1340 "print(ct)\n",
1341 "assert(ct == 'wzmfiwuntn')\n",
1342 "ct"
1343 ]
1344 },
1345 {
1346 "cell_type": "code",
1347 "execution_count": 568,
1348 "metadata": {
1349 "collapsed": false
1350 },
1351 "outputs": [
1352 {
1353 "data": {
1354 "text/plain": [
1355 "'ayraqvsfkhflwsmkqicvfwawswmiwvvlteb'"
1356 ]
1357 },
1358 "execution_count": 568,
1359 "metadata": {},
1360 "output_type": "execute_result"
1361 }
1362 ],
1363 "source": [
1364 "w_enigma.set_wheels('n', 'y', 'q')\n",
1365 "ct = w_enigma.encipher('hellotomweshouldgetbeerorcoffeesoon')\n",
1366 "ct"
1367 ]
1368 },
1369 {
1370 "cell_type": "code",
1371 "execution_count": null,
1372 "metadata": {
1373 "collapsed": true
1374 },
1375 "outputs": [],
1376 "source": []
1377 }
1378 ],
1379 "metadata": {
1380 "kernelspec": {
1381 "display_name": "Python 3",
1382 "language": "python",
1383 "name": "python3"
1384 },
1385 "language_info": {
1386 "codemirror_mode": {
1387 "name": "ipython",
1388 "version": 3
1389 },
1390 "file_extension": ".py",
1391 "mimetype": "text/x-python",
1392 "name": "python",
1393 "nbconvert_exporter": "python",
1394 "pygments_lexer": "ipython3",
1395 "version": "3.5.1+"
1396 }
1397 },
1398 "nbformat": 4,
1399 "nbformat_minor": 0
1400 }