Updated engima machine, refactored, added tests
[cipher-tools.git] / railfence-experiment-2.ipynb
1 {
2 "metadata": {
3 "name": "",
4 "signature": "sha256:285f7a82eaf5cc815e9a686ebce8aa2cfbdecb14f2473c9b5dfe0aedafcd727c"
5 },
6 "nbformat": 3,
7 "nbformat_minor": 0,
8 "worksheets": [
9 {
10 "cells": [
11 {
12 "cell_type": "code",
13 "collapsed": false,
14 "input": [
15 "from cipher import *\n",
16 "from cipherbreak import *\n",
17 "import math"
18 ],
19 "language": "python",
20 "metadata": {},
21 "outputs": [],
22 "prompt_number": 79
23 },
24 {
25 "cell_type": "code",
26 "collapsed": false,
27 "input": [
28 "def railfence_encipher(message, height, fillvalue=' '):\n",
29 " \"\"\"Railfence cipher\n",
30 "\n",
31 " >>> railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 2, fillvalue='!')\n",
32 " 'hlohraateerishsslnpeefetotsigaleccpeselteevsmhatetiiaogicotxfretnrifneihr!'\n",
33 " >>> railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 3, fillvalue='!')\n",
34 " 'horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihr!!lhateihsnefttiaece!'\n",
35 " >>> railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 5, fillvalue='!')\n",
36 " 'hresleogcseeemhetaocofrnrner!!lhateihsnefttiaece!!ltvsatiigitxetifih!!oarspeslp!'\n",
37 " >>> railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 10, fillvalue='!')\n",
38 " 'hepisehagitnr!!lernesge!!lmtocerh!!otiletap!!tseaorii!!hassfolc!!evtitffe!!rahsetec!!eixn!'\n",
39 " \"\"\"\n",
40 " sections = chunks(message, (height - 1) * 2, fillvalue=fillvalue)\n",
41 " # Add the top row\n",
42 " rows = [s[0] for s in sections]\n",
43 " # process the middle rows of the grid\n",
44 " for r in range(1, height - 1):\n",
45 " rows += [s[r] + s[-r] for s in sections]\n",
46 " # process the bottom row\n",
47 " rows += [s[height - 1] for s in sections]\n",
48 " return ''.join(rows)"
49 ],
50 "language": "python",
51 "metadata": {},
52 "outputs": [],
53 "prompt_number": 2
54 },
55 {
56 "cell_type": "code",
57 "collapsed": false,
58 "input": [
59 "pt = 'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'\n",
60 "height = 6"
61 ],
62 "language": "python",
63 "metadata": {},
64 "outputs": [],
65 "prompt_number": 195
66 },
67 {
68 "cell_type": "code",
69 "collapsed": false,
70 "input": [
71 "sections = chunks(pt, (height - 1) * 2, fillvalue='!')\n",
72 "n_sections = len(sections)\n",
73 "# Add the top row\n",
74 "rows = [' '.join([s[0] for s in sections])]\n",
75 "# process the middle rows of the grid\n",
76 "for r in range(1, height - 1):\n",
77 " # rows += [''.join([s[r:r+1] + s[n_sections-r:n_sections-r+1] for s in sections])]\n",
78 " rows += [''.join([s[r] + s[-r] for s in sections])]\n",
79 "# process the bottom row\n",
80 "# rows += [' '.join([s[height - 1:height] for s in sections])]\n",
81 "rows += [' '.join([s[height - 1] for s in sections])]\n",
82 "rows"
83 ],
84 "language": "python",
85 "metadata": {},
86 "outputs": [
87 {
88 "metadata": {},
89 "output_type": "pyout",
90 "prompt_number": 196,
91 "text": [
92 "['h a r s e t l e',\n",
93 " 'eevatiacoreifhr!',\n",
94 " 'lraeislefosaeps!',\n",
95 " 'lesheioitftrni!!',\n",
96 " 'ohteshnpetigcc!!',\n",
97 " 't m t g x n e !']"
98 ]
99 }
100 ],
101 "prompt_number": 196
102 },
103 {
104 "cell_type": "code",
105 "collapsed": false,
106 "input": [
107 "sections"
108 ],
109 "language": "python",
110 "metadata": {},
111 "outputs": [
112 {
113 "metadata": {},
114 "output_type": "pyout",
115 "prompt_number": 197,
116 "text": [
117 "['hellothere',\n",
118 " 'avastmehea',\n",
119 " 'rtiesthisi',\n",
120 " 'salongpiec',\n",
121 " 'eoftextfor',\n",
122 " 'testingrai',\n",
123 " 'lfenceciph',\n",
124 " 'ers!!!!!!!']"
125 ]
126 }
127 ],
128 "prompt_number": 197
129 },
130 {
131 "cell_type": "code",
132 "collapsed": false,
133 "input": [
134 "sections = chunks(pt, (height - 1) * 2, fillvalue='')\n",
135 "# Add the top row\n",
136 "rows = [' '.join([s[0] for s in sections])]\n",
137 "# process the middle rows of the grid\n",
138 "for r in range(1, height-1):\n",
139 " print(r, height*2-r-2, ':', sections[0][r:r+1], sections[0][height*2-r-2:height*2-r-1])\n",
140 " rows += [''.join([s[r:r+1] + s[height*2-r-2:height*2-r-1] for s in sections])]\n",
141 " # rows += [''.join([s[r] + s[-r] for s in sections])]\n",
142 "# process the bottom row\n",
143 "rows += [' '.join([s[height - 1:height] for s in sections])]\n",
144 "# rows += [' '.join([s[height - 1] for s in sections])]\n",
145 "rows"
146 ],
147 "language": "python",
148 "metadata": {},
149 "outputs": [
150 {
151 "output_type": "stream",
152 "stream": "stdout",
153 "text": [
154 "1 9 : e e\n",
155 "2 8 : l r\n",
156 "3 7 : l e\n",
157 "4 6 : o h\n"
158 ]
159 },
160 {
161 "metadata": {},
162 "output_type": "pyout",
163 "prompt_number": 198,
164 "text": [
165 "['h a r s e t l e',\n",
166 " 'eevatiacoreifhr',\n",
167 " 'lraeislefosaeps',\n",
168 " 'lesheioitftrni',\n",
169 " 'ohteshnpetigcc',\n",
170 " 't m t g x n e ']"
171 ]
172 }
173 ],
174 "prompt_number": 198
175 },
176 {
177 "cell_type": "code",
178 "collapsed": false,
179 "input": [
180 "sections"
181 ],
182 "language": "python",
183 "metadata": {},
184 "outputs": [
185 {
186 "metadata": {},
187 "output_type": "pyout",
188 "prompt_number": 199,
189 "text": [
190 "['hellothere',\n",
191 " 'avastmehea',\n",
192 " 'rtiesthisi',\n",
193 " 'salongpiec',\n",
194 " 'eoftextfor',\n",
195 " 'testingrai',\n",
196 " 'lfenceciph',\n",
197 " 'ers']"
198 ]
199 }
200 ],
201 "prompt_number": 199
202 },
203 {
204 "cell_type": "code",
205 "collapsed": false,
206 "input": [
207 "ct = ''.join(c for c in ''.join(rows) if c != ' ')\n",
208 "ct"
209 ],
210 "language": "python",
211 "metadata": {},
212 "outputs": [
213 {
214 "metadata": {},
215 "output_type": "pyout",
216 "prompt_number": 200,
217 "text": [
218 "'harsetleeevatiacoreifhrlraeislefosaepslesheioitftrniohteshnpetigcctmtgxne'"
219 ]
220 }
221 ],
222 "prompt_number": 200
223 },
224 {
225 "cell_type": "code",
226 "collapsed": false,
227 "input": [
228 "n_sections = math.ceil(len(pt) / ((height - 1) * 2))\n",
229 "n_sections"
230 ],
231 "language": "python",
232 "metadata": {},
233 "outputs": [
234 {
235 "metadata": {},
236 "output_type": "pyout",
237 "prompt_number": 202,
238 "text": [
239 "8"
240 ]
241 }
242 ],
243 "prompt_number": 202
244 },
245 {
246 "cell_type": "code",
247 "collapsed": false,
248 "input": [
249 "padding_to_add = n_sections * (height - 1) * 2 - len(pt)\n",
250 "padding_to_add"
251 ],
252 "language": "python",
253 "metadata": {},
254 "outputs": [
255 {
256 "metadata": {},
257 "output_type": "pyout",
258 "prompt_number": 203,
259 "text": [
260 "7"
261 ]
262 }
263 ],
264 "prompt_number": 203
265 },
266 {
267 "cell_type": "code",
268 "collapsed": false,
269 "input": [
270 "row_lengths = [n_sections] * (height - 1) * 2\n",
271 "row_lengths"
272 ],
273 "language": "python",
274 "metadata": {},
275 "outputs": [
276 {
277 "metadata": {},
278 "output_type": "pyout",
279 "prompt_number": 204,
280 "text": [
281 "[8, 8, 8, 8, 8, 8, 8, 8, 8, 8]"
282 ]
283 }
284 ],
285 "prompt_number": 204
286 },
287 {
288 "cell_type": "code",
289 "collapsed": false,
290 "input": [
291 "for i in range((height - 1) * 2 - 1, (height - 1) * 2 - (padding_to_add + 1), -1):\n",
292 " row_lengths[i] -= 1\n",
293 "row_lengths"
294 ],
295 "language": "python",
296 "metadata": {},
297 "outputs": [
298 {
299 "metadata": {},
300 "output_type": "pyout",
301 "prompt_number": 205,
302 "text": [
303 "[8, 8, 8, 7, 7, 7, 7, 7, 7, 7]"
304 ]
305 }
306 ],
307 "prompt_number": 205
308 },
309 {
310 "cell_type": "code",
311 "collapsed": false,
312 "input": [
313 "folded_row_lengths = [row_lengths[0]]\n",
314 "for i in range(1, height-1):\n",
315 " folded_row_lengths += [row_lengths[i] + row_lengths[-i]]\n",
316 "folded_row_lengths += [row_lengths[height - 1]]\n",
317 "folded_row_lengths"
318 ],
319 "language": "python",
320 "metadata": {},
321 "outputs": [
322 {
323 "metadata": {},
324 "output_type": "pyout",
325 "prompt_number": 206,
326 "text": [
327 "[8, 15, 15, 14, 14, 7]"
328 ]
329 }
330 ],
331 "prompt_number": 206
332 },
333 {
334 "cell_type": "code",
335 "collapsed": false,
336 "input": [
337 "rows = []\n",
338 "row_start = 0\n",
339 "for i in folded_row_lengths:\n",
340 " rows += [ct[row_start:row_start + i]]\n",
341 " row_start += i\n",
342 "rows"
343 ],
344 "language": "python",
345 "metadata": {},
346 "outputs": [
347 {
348 "metadata": {},
349 "output_type": "pyout",
350 "prompt_number": 207,
351 "text": [
352 "['harsetle',\n",
353 " 'eevatiacoreifhr',\n",
354 " 'lraeislefosaeps',\n",
355 " 'lesheioitftrni',\n",
356 " 'ohteshnpetigcc',\n",
357 " 'tmtgxne']"
358 ]
359 }
360 ],
361 "prompt_number": 207
362 },
363 {
364 "cell_type": "code",
365 "collapsed": false,
366 "input": [
367 "down_rows = [rows[0]]\n",
368 "up_rows = []\n",
369 "for i in range(1, height-1):\n",
370 " down_rows += [''.join([c for n, c in enumerate(rows[i]) if n % 2 == 0])]\n",
371 " up_rows += [''.join([c for n, c in enumerate(rows[i]) if n % 2 == 1])]\n",
372 "down_rows += [rows[-1]]\n",
373 "down_rows, up_rows"
374 ],
375 "language": "python",
376 "metadata": {},
377 "outputs": [
378 {
379 "metadata": {},
380 "output_type": "pyout",
381 "prompt_number": 208,
382 "text": [
383 "(['harsetle', 'evtaoefr', 'lailfses', 'lseottn', 'otsneic', 'tmtgxne'],\n",
384 " ['eaicrih', 'reseoap', 'ehiifri', 'hehptgc'])"
385 ]
386 }
387 ],
388 "prompt_number": 208
389 },
390 {
391 "cell_type": "code",
392 "collapsed": false,
393 "input": [
394 "up_rows.reverse()\n",
395 "down_rows + up_rows"
396 ],
397 "language": "python",
398 "metadata": {},
399 "outputs": [
400 {
401 "metadata": {},
402 "output_type": "pyout",
403 "prompt_number": 164,
404 "text": [
405 "['hresleogcs',\n",
406 " 'eehtoorre',\n",
407 " 'laehnftac',\n",
408 " 'lvaigteii',\n",
409 " 'oarspeslp',\n",
410 " 'tstiixtfh',\n",
411 " 'htisetiee',\n",
412 " 'emeacfnnr']"
413 ]
414 }
415 ],
416 "prompt_number": 164
417 },
418 {
419 "cell_type": "code",
420 "collapsed": false,
421 "input": [
422 "''.join(c for r in zip_longest(*(down_rows + up_rows), fillvalue='') for c in r)"
423 ],
424 "language": "python",
425 "metadata": {},
426 "outputs": [
427 {
428 "metadata": {},
429 "output_type": "pyout",
430 "prompt_number": 165,
431 "text": [
432 "'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'"
433 ]
434 }
435 ],
436 "prompt_number": 165
437 },
438 {
439 "cell_type": "code",
440 "collapsed": false,
441 "input": [
442 "def rfe(message, height, fillvalue=''):\n",
443 " sections = chunks(message, (height - 1) * 2, fillvalue=fillvalue)\n",
444 " n_sections = len(sections)\n",
445 " # Add the top row\n",
446 " rows = [''.join([s[0] for s in sections])]\n",
447 " # process the middle rows of the grid\n",
448 " for r in range(1, height-1):\n",
449 " rows += [''.join([s[r:r+1] + s[height*2-r-2:height*2-r-1] for s in sections])]\n",
450 " # process the bottom row\n",
451 " rows += [''.join([s[height - 1:height] for s in sections])]\n",
452 " # rows += [' '.join([s[height - 1] for s in sections])]\n",
453 " return ''.join(rows)"
454 ],
455 "language": "python",
456 "metadata": {},
457 "outputs": [],
458 "prompt_number": 171
459 },
460 {
461 "cell_type": "code",
462 "collapsed": false,
463 "input": [
464 "rfe(pt, 5)"
465 ],
466 "language": "python",
467 "metadata": {},
468 "outputs": [
469 {
470 "metadata": {},
471 "output_type": "pyout",
472 "prompt_number": 177,
473 "text": [
474 "'hresleogcseeemhetaocofrnrnerlhateihsnefttiaeceltvsatiigitxetifihoarspeslp'"
475 ]
476 }
477 ],
478 "prompt_number": 177
479 },
480 {
481 "cell_type": "code",
482 "collapsed": false,
483 "input": [
484 "rfe(pt, 5) == ct"
485 ],
486 "language": "python",
487 "metadata": {},
488 "outputs": [
489 {
490 "metadata": {},
491 "output_type": "pyout",
492 "prompt_number": 178,
493 "text": [
494 "True"
495 ]
496 }
497 ],
498 "prompt_number": 178
499 },
500 {
501 "cell_type": "code",
502 "collapsed": false,
503 "input": [
504 "def rfd(message, height, fillvalue=''):\n",
505 " n_sections = math.ceil(len(message) / ((height - 1) * 2))\n",
506 " padding_to_add = n_sections * (height - 1) * 2 - len(message)\n",
507 " row_lengths = [n_sections] * (height - 1) * 2\n",
508 " for i in range((height - 1) * 2 - 1, (height - 1) * 2 - (padding_to_add + 1), -1):\n",
509 " row_lengths[i] -= 1\n",
510 " folded_row_lengths = [row_lengths[0]]\n",
511 " for i in range(1, height-1):\n",
512 " folded_row_lengths += [row_lengths[i] + row_lengths[-i]]\n",
513 " folded_row_lengths += [row_lengths[height - 1]]\n",
514 " rows = []\n",
515 " row_start = 0\n",
516 " for i in folded_row_lengths:\n",
517 " rows += [message[row_start:row_start + i]]\n",
518 " row_start += i\n",
519 " down_rows = [rows[0]]\n",
520 " up_rows = []\n",
521 " for i in range(1, height-1):\n",
522 " down_rows += [''.join([c for n, c in enumerate(rows[i]) if n % 2 == 0])]\n",
523 " up_rows += [''.join([c for n, c in enumerate(rows[i]) if n % 2 == 1])]\n",
524 " down_rows += [rows[-1]]\n",
525 " up_rows.reverse()\n",
526 " return ''.join(c for r in zip_longest(*(down_rows + up_rows), fillvalue='') for c in r)"
527 ],
528 "language": "python",
529 "metadata": {},
530 "outputs": [],
531 "prompt_number": 220
532 },
533 {
534 "cell_type": "code",
535 "collapsed": false,
536 "input": [
537 "h = 7\n",
538 "print(rfe(pt, h))\n",
539 "rfd(rfe(pt, h), h)"
540 ],
541 "language": "python",
542 "metadata": {},
543 "outputs": [
544 {
545 "output_type": "stream",
546 "stream": "stdout",
547 "text": [
548 "haspolsevsetgifrifrlatihnettaeelemtiocxernhorersleesgcptehaiaottneihesfic\n"
549 ]
550 },
551 {
552 "metadata": {},
553 "output_type": "pyout",
554 "prompt_number": 221,
555 "text": [
556 "'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'"
557 ]
558 }
559 ],
560 "prompt_number": 221
561 },
562 {
563 "cell_type": "code",
564 "collapsed": false,
565 "input": [
566 "for h in range(2, 51):\n",
567 " assert rfd(rfe(pt, h), h) == pt\n",
568 " print(h, ':', rfd(rfe(pt, h), h) == pt)"
569 ],
570 "language": "python",
571 "metadata": {},
572 "outputs": [
573 {
574 "output_type": "stream",
575 "stream": "stdout",
576 "text": [
577 "2 : True\n",
578 "3 : True\n",
579 "4 : True\n",
580 "5 : True\n",
581 "6 : True\n",
582 "7 : True\n",
583 "8 : True\n",
584 "9 : True\n",
585 "10 : True\n",
586 "11 : True\n",
587 "12 : True\n",
588 "13 : True\n",
589 "14 : True\n",
590 "15 : True\n",
591 "16 : True\n",
592 "17 : True\n",
593 "18 : True\n",
594 "19 : True\n",
595 "20 : True\n",
596 "21 : True\n",
597 "22 : True\n",
598 "23 : True\n",
599 "24 : True\n",
600 "25 : True\n",
601 "26 : True\n",
602 "27 : True\n",
603 "28 : True\n",
604 "29 : True\n",
605 "30 : True\n",
606 "31 : True\n",
607 "32 : True\n",
608 "33 : True\n",
609 "34 : True\n",
610 "35 : True\n",
611 "36 : True\n",
612 "37 : True\n",
613 "38 : True\n",
614 "39 : True\n",
615 "40 : True\n",
616 "41 : True\n",
617 "42 : True\n",
618 "43 : True\n",
619 "44 : True\n",
620 "45 : True\n",
621 "46 : True\n",
622 "47 : True\n",
623 "48 : True\n",
624 "49 : True\n",
625 "50 : True\n"
626 ]
627 }
628 ],
629 "prompt_number": 227
630 },
631 {
632 "cell_type": "code",
633 "collapsed": false,
634 "input": [
635 "h"
636 ],
637 "language": "python",
638 "metadata": {},
639 "outputs": [
640 {
641 "metadata": {},
642 "output_type": "pyout",
643 "prompt_number": 224,
644 "text": [
645 "1"
646 ]
647 }
648 ],
649 "prompt_number": 224
650 },
651 {
652 "cell_type": "code",
653 "collapsed": false,
654 "input": [
655 "rfe('hellotherefriends', 4)"
656 ],
657 "language": "python",
658 "metadata": {},
659 "outputs": [
660 {
661 "metadata": {},
662 "output_type": "pyout",
663 "prompt_number": 228,
664 "text": [
665 "'hhieterelorfnsled'"
666 ]
667 }
668 ],
669 "prompt_number": 228
670 },
671 {
672 "cell_type": "code",
673 "collapsed": false,
674 "input": [
675 "rfd('hhieterelorfnsled', 4)"
676 ],
677 "language": "python",
678 "metadata": {},
679 "outputs": [
680 {
681 "metadata": {},
682 "output_type": "pyout",
683 "prompt_number": 229,
684 "text": [
685 "'hellotherefriends'"
686 ]
687 }
688 ],
689 "prompt_number": 229
690 },
691 {
692 "cell_type": "code",
693 "collapsed": false,
694 "input": [
695 "for h in [3, 5, 7]:\n",
696 " print(rfe(pt, h))"
697 ],
698 "language": "python",
699 "metadata": {},
700 "outputs": [
701 {
702 "output_type": "stream",
703 "stream": "stdout",
704 "text": [
705 "horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihrlhateihsnefttiaece\n",
706 "hresleogcseeemhetaocofrnrnerlhateihsnefttiaeceltvsatiigitxetifihoarspeslp\n",
707 "haspolsevsetgifrifrlatihnettaeelemtiocxernhorersleesgcptehaiaottneihesfic\n"
708 ]
709 }
710 ],
711 "prompt_number": 230
712 },
713 {
714 "cell_type": "code",
715 "collapsed": false,
716 "input": [],
717 "language": "python",
718 "metadata": {},
719 "outputs": []
720 }
721 ],
722 "metadata": {}
723 }
724 ]
725 }