From: Neil Smith Date: Tue, 12 Sep 2017 15:18:57 +0000 (+0100) Subject: Worked on Enigma, mainly changing how the notch positions are handled X-Git-Url: https://git.njae.me.uk/?a=commitdiff_plain;h=refs%2Fheads%2Fdevelopment;p=cipher-training.git Worked on Enigma, mainly changing how the notch positions are handled --- diff --git a/bombe.ipynb b/bombe.ipynb index 93e0ccb..e28af9a 100644 --- a/bombe.ipynb +++ b/bombe.ipynb @@ -75,9 +75,9 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 4, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -164,7 +164,10 @@ " self.pending += [Signal(current.wire, current.bank)]\n", " for c in self.connections:\n", " if current.bank in c.banks:\n", - " other_bank = [b for b in c.banks if b != current.bank][0]\n", + " if len(set(c.banks)) == 1:\n", + " other_bank = c.banks[0]\n", + " else:\n", + " other_bank = [b for b in c.banks if b != current.bank][0]\n", " other_wire = c.scrambler.lookup(current.wire)\n", " # print(\" adding\", other_bank, other_wire, \"because\", c.banks)\n", " self.pending += [Signal(other_bank, other_wire)]\n", @@ -200,9 +203,9 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 5, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -212,7 +215,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 6, "metadata": { "collapsed": true }, @@ -228,10 +231,8 @@ }, { "cell_type": "code", - "execution_count": 34, - "metadata": { - "collapsed": false - }, + "execution_count": 7, + "metadata": {}, "outputs": [ { "data": { @@ -239,7 +240,7 @@ "'opgndxcrwomnlnecjz'" ] }, - "execution_count": 34, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -253,10 +254,8 @@ }, { "cell_type": "code", - "execution_count": 35, - "metadata": { - "collapsed": false - }, + "execution_count": 8, + "metadata": {}, "outputs": [ { "data": { @@ -264,7 +263,7 @@ "'aas'" ] }, - "execution_count": 35, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -275,10 +274,8 @@ }, { "cell_type": "code", - "execution_count": 36, - "metadata": { - "collapsed": false - }, + "execution_count": 9, + "metadata": {}, "outputs": [ { "data": { @@ -303,7 +300,7 @@ " MenuIem(before='e', after='z', number=18)]" ] }, - "execution_count": 36, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -315,7 +312,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 10, "metadata": { "collapsed": true }, @@ -328,10 +325,8 @@ }, { "cell_type": "code", - "execution_count": 38, - "metadata": { - "collapsed": false - }, + "execution_count": 11, + "metadata": {}, "outputs": [ { "data": { @@ -356,7 +351,7 @@ " MenuIem(before='e', after='z', number=18)]" ] }, - "execution_count": 38, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -367,10 +362,8 @@ }, { "cell_type": "code", - "execution_count": 39, - "metadata": { - "collapsed": false - }, + "execution_count": 12, + "metadata": {}, "outputs": [ { "data": { @@ -378,7 +371,7 @@ "'s'" ] }, - "execution_count": 39, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -389,9 +382,9 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 13, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -400,10 +393,8 @@ }, { "cell_type": "code", - "execution_count": 43, - "metadata": { - "collapsed": false - }, + "execution_count": 14, + "metadata": {}, "outputs": [ { "data": { @@ -411,7 +402,7 @@ "18" ] }, - "execution_count": 43, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -422,33 +413,13 @@ }, { "cell_type": "code", - "execution_count": 27, - "metadata": { - "collapsed": false - }, + "execution_count": 15, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "['t', 'o'] aaa\n", - "['h', 'p'] aab\n", - "['i', 'g'] aac\n", - "['s', 'n'] aad\n", - "['i', 'd'] aae\n", - "['s', 'x'] aaf\n", - "['a', 'c'] aag\n", - "['t', 'r'] aah\n", - "['e', 'w'] aai\n", - "['s', 'o'] aaj\n", - "['t', 'm'] aak\n", - "['m', 'n'] aal\n", - "['e', 'l'] aam\n", - "['s', 'n'] aan\n", - "['s', 'e'] aao\n", - "['a', 'c'] aap\n", - "['g', 'j'] aaq\n", - "['e', 'z'] aar\n", "['t', 'o'] aaa\n", "['h', 'p'] aab\n", "['i', 'g'] aac\n", @@ -477,10 +448,8 @@ }, { "cell_type": "code", - "execution_count": 44, - "metadata": { - "collapsed": false - }, + "execution_count": 16, + "metadata": {}, "outputs": [ { "data": { @@ -488,7 +457,7 @@ "'ot:hp:gi:ns:di:sx:ac:rt:ew:os:mt:mn:el:ns:es:ac:gj:ez'" ] }, - "execution_count": 44, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -499,10 +468,8 @@ }, { "cell_type": "code", - "execution_count": 45, - "metadata": { - "collapsed": false - }, + "execution_count": 17, + "metadata": {}, "outputs": [ { "data": { @@ -510,7 +477,7 @@ "'aaa:aab:aac:aad:aae:aaf:aag:aah:aai:aaj:aak:aal:aam:aan:aao:aap:aaq:aar'" ] }, - "execution_count": 45, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -521,18 +488,16 @@ }, { "cell_type": "code", - "execution_count": 56, - "metadata": { - "collapsed": false - }, + "execution_count": 18, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "True" + "False" ] }, - "execution_count": 56, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -543,43 +508,41 @@ }, { "cell_type": "code", - "execution_count": 57, - "metadata": { - "collapsed": false - }, + "execution_count": 19, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'a': False,\n", - " 'b': False,\n", - " 'c': False,\n", - " 'd': False,\n", - " 'e': False,\n", - " 'f': False,\n", - " 'g': False,\n", - " 'h': False,\n", - " 'i': False,\n", - " 'j': False,\n", - " 'k': False,\n", - " 'l': False,\n", - " 'm': False,\n", - " 'n': False,\n", - " 'o': False,\n", - " 'p': False,\n", - " 'q': False,\n", - " 'r': False,\n", - " 's': False,\n", + "{'a': True,\n", + " 'b': True,\n", + " 'c': True,\n", + " 'd': True,\n", + " 'e': True,\n", + " 'f': True,\n", + " 'g': True,\n", + " 'h': True,\n", + " 'i': True,\n", + " 'j': True,\n", + " 'k': True,\n", + " 'l': True,\n", + " 'm': True,\n", + " 'n': True,\n", + " 'o': True,\n", + " 'p': True,\n", + " 'q': True,\n", + " 'r': True,\n", + " 's': True,\n", " 't': True,\n", - " 'u': False,\n", - " 'v': False,\n", - " 'w': False,\n", - " 'x': False,\n", - " 'y': False,\n", - " 'z': False}" + " 'u': True,\n", + " 'v': True,\n", + " 'w': True,\n", + " 'x': True,\n", + " 'y': True,\n", + " 'z': True}" ] }, - "execution_count": 57, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -590,10 +553,8 @@ }, { "cell_type": "code", - "execution_count": 48, - "metadata": { - "collapsed": false - }, + "execution_count": 20, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -641,10 +602,8 @@ }, { "cell_type": "code", - "execution_count": 49, - "metadata": { - "collapsed": false - }, + "execution_count": 21, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -692,10 +651,8 @@ }, { "cell_type": "code", - "execution_count": 50, - "metadata": { - "collapsed": false - }, + "execution_count": 22, + "metadata": {}, "outputs": [ { "data": { @@ -703,7 +660,7 @@ "('a', 'a', 'a')" ] }, - "execution_count": 50, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -714,10 +671,8 @@ }, { "cell_type": "code", - "execution_count": 51, - "metadata": { - "collapsed": false - }, + "execution_count": 23, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -752,9 +707,9 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 24, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -764,10 +719,8 @@ }, { "cell_type": "code", - "execution_count": 53, - "metadata": { - "collapsed": false - }, + "execution_count": 25, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -818,10 +771,8 @@ }, { "cell_type": "code", - "execution_count": 54, - "metadata": { - "collapsed": false - }, + "execution_count": 26, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -872,10 +823,8 @@ }, { "cell_type": "code", - "execution_count": 55, - "metadata": { - "collapsed": false - }, + "execution_count": 27, + "metadata": {}, "outputs": [ { "data": { @@ -883,7 +832,7 @@ "1" ] }, - "execution_count": 55, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -894,9 +843,9 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 28, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -907,9 +856,9 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 29, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -920,10 +869,8 @@ }, { "cell_type": "code", - "execution_count": 27, - "metadata": { - "collapsed": false - }, + "execution_count": 30, + "metadata": {}, "outputs": [ { "data": { @@ -931,7 +878,7 @@ "('a', 'a', 'b')" ] }, - "execution_count": 27, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -942,10 +889,8 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": { - "collapsed": false - }, + "execution_count": 31, + "metadata": {}, "outputs": [ { "data": { @@ -953,7 +898,7 @@ "False" ] }, - "execution_count": 28, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -964,10 +909,8 @@ }, { "cell_type": "code", - "execution_count": 29, - "metadata": { - "collapsed": false - }, + "execution_count": 32, + "metadata": {}, "outputs": [ { "data": { @@ -975,7 +918,7 @@ "('p', 'p', 'p')" ] }, - "execution_count": 29, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -986,10 +929,8 @@ }, { "cell_type": "code", - "execution_count": 30, - "metadata": { - "collapsed": false - }, + "execution_count": 33, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1037,10 +978,8 @@ }, { "cell_type": "code", - "execution_count": 31, - "metadata": { - "collapsed": false - }, + "execution_count": 34, + "metadata": {}, "outputs": [ { "data": { @@ -1048,7 +987,7 @@ "17576" ] }, - "execution_count": 31, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -1060,10 +999,8 @@ }, { "cell_type": "code", - "execution_count": 32, - "metadata": { - "collapsed": false - }, + "execution_count": 35, + "metadata": {}, "outputs": [ { "data": { @@ -1071,7 +1008,7 @@ "(('a', 'a', 'b'), True)" ] }, - "execution_count": 32, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } @@ -1083,9 +1020,9 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 36, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -1094,10 +1031,8 @@ }, { "cell_type": "code", - "execution_count": 34, - "metadata": { - "collapsed": false - }, + "execution_count": 37, + "metadata": {}, "outputs": [ { "data": { @@ -1105,7 +1040,7 @@ "[('a', 'a', 'b')]" ] }, - "execution_count": 34, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } @@ -1121,7 +1056,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 38, "metadata": { "collapsed": true }, @@ -1143,10 +1078,8 @@ }, { "cell_type": "code", - "execution_count": 36, - "metadata": { - "collapsed": false - }, + "execution_count": 39, + "metadata": {}, "outputs": [ { "data": { @@ -1154,7 +1087,7 @@ "[('a', 'a', 'b')]" ] }, - "execution_count": 36, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -1165,9 +1098,9 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 40, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -1184,10 +1117,8 @@ }, { "cell_type": "code", - "execution_count": 59, - "metadata": { - "collapsed": false - }, + "execution_count": 41, + "metadata": {}, "outputs": [ { "data": { @@ -1195,7 +1126,7 @@ "('e', 'l', 'e')" ] }, - "execution_count": 59, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } @@ -1207,10 +1138,8 @@ }, { "cell_type": "code", - "execution_count": 39, - "metadata": { - "collapsed": false - }, + "execution_count": 42, + "metadata": {}, "outputs": [ { "data": { @@ -1218,7 +1147,7 @@ "'dhnpforeeimgg'" ] }, - "execution_count": 39, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } @@ -1232,10 +1161,8 @@ }, { "cell_type": "code", - "execution_count": 40, - "metadata": { - "collapsed": false - }, + "execution_count": 43, + "metadata": {}, "outputs": [ { "data": { @@ -1243,7 +1170,7 @@ "('j', 'e', 'o')" ] }, - "execution_count": 40, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } @@ -1254,10 +1181,8 @@ }, { "cell_type": "code", - "execution_count": 41, - "metadata": { - "collapsed": false - }, + "execution_count": 44, + "metadata": {}, "outputs": [ { "data": { @@ -1277,7 +1202,7 @@ " MenuIem(before='t', after='g', number=13)]" ] }, - "execution_count": 41, + "execution_count": 44, "metadata": {}, "output_type": "execute_result" } @@ -1289,9 +1214,8 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 45, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -1362,7 +1286,7 @@ " ('z', 'z', 'k')]" ] }, - "execution_count": 42, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } @@ -1379,10 +1303,8 @@ }, { "cell_type": "code", - "execution_count": 43, - "metadata": { - "collapsed": false - }, + "execution_count": 46, + "metadata": {}, "outputs": [ { "data": { @@ -1390,7 +1312,7 @@ "62" ] }, - "execution_count": 43, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } @@ -1401,9 +1323,8 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 47, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -1425,7 +1346,7 @@ " ('y', 'n', 'c')]" ] }, - "execution_count": 44, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -1442,10 +1363,8 @@ }, { "cell_type": "code", - "execution_count": 45, - "metadata": { - "collapsed": false - }, + "execution_count": 48, + "metadata": {}, "outputs": [ { "data": { @@ -1465,7 +1384,7 @@ " ('y', 'n', 'c')]" ] }, - "execution_count": 45, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" } @@ -1476,9 +1395,9 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 49, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -1493,10 +1412,8 @@ }, { "cell_type": "code", - "execution_count": 47, - "metadata": { - "collapsed": false - }, + "execution_count": 50, + "metadata": {}, "outputs": [ { "data": { @@ -1504,7 +1421,7 @@ "13" ] }, - "execution_count": 47, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" } @@ -1515,9 +1432,9 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 51, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -1527,10 +1444,8 @@ }, { "cell_type": "code", - "execution_count": 49, - "metadata": { - "collapsed": false - }, + "execution_count": 52, + "metadata": {}, "outputs": [ { "data": { @@ -1538,7 +1453,7 @@ "Signal(bank='e', wire='e')" ] }, - "execution_count": 49, + "execution_count": 52, "metadata": {}, "output_type": "execute_result" } @@ -1549,10 +1464,8 @@ }, { "cell_type": "code", - "execution_count": 50, - "metadata": { - "collapsed": false - }, + "execution_count": 53, + "metadata": {}, "outputs": [ { "data": { @@ -1560,7 +1473,7 @@ "True" ] }, - "execution_count": 50, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" } @@ -1571,10 +1484,8 @@ }, { "cell_type": "code", - "execution_count": 51, - "metadata": { - "collapsed": false - }, + "execution_count": 54, + "metadata": {}, "outputs": [ { "data": { @@ -1582,7 +1493,7 @@ "True" ] }, - "execution_count": 51, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } @@ -1593,10 +1504,8 @@ }, { "cell_type": "code", - "execution_count": 52, - "metadata": { - "collapsed": false - }, + "execution_count": 55, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1647,10 +1556,8 @@ }, { "cell_type": "code", - "execution_count": 53, - "metadata": { - "collapsed": false - }, + "execution_count": 56, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1701,23 +1608,21 @@ }, { "cell_type": "code", - "execution_count": 54, - "metadata": { - "collapsed": false - }, + "execution_count": 57, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{frozenset({'m'}),\n", + "{frozenset({'t', 'x'}),\n", " frozenset({'i', 'n'}),\n", - " frozenset({'f', 'p'}),\n", - " frozenset({'t', 'x'}),\n", + " frozenset({'m'}),\n", " frozenset({'e', 'y'}),\n", + " frozenset({'f', 'p'}),\n", " frozenset({'b', 'g'})}" ] }, - "execution_count": 54, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } @@ -1729,10 +1634,8 @@ }, { "cell_type": "code", - "execution_count": 55, - "metadata": { - "collapsed": false - }, + "execution_count": 58, + "metadata": {}, "outputs": [ { "data": { @@ -1740,7 +1643,7 @@ "True" ] }, - "execution_count": 55, + "execution_count": 58, "metadata": {}, "output_type": "execute_result" } @@ -1751,21 +1654,19 @@ }, { "cell_type": "code", - "execution_count": 56, - "metadata": { - "collapsed": false - }, + "execution_count": 59, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "({frozenset({1, 2}), frozenset({3, 4}), frozenset({2, 3})},\n", + "({frozenset({1, 2}), frozenset({2, 3}), frozenset({3, 4})},\n", " frozenset({1, 2}),\n", " frozenset({3, 4}),\n", " frozenset({2, 3}))" ] }, - "execution_count": 56, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } @@ -1784,10 +1685,8 @@ }, { "cell_type": "code", - "execution_count": 57, - "metadata": { - "collapsed": false - }, + "execution_count": 60, + "metadata": {}, "outputs": [ { "data": { @@ -1795,7 +1694,7 @@ "False" ] }, - "execution_count": 57, + "execution_count": 60, "metadata": {}, "output_type": "execute_result" } @@ -1806,10 +1705,8 @@ }, { "cell_type": "code", - "execution_count": 58, - "metadata": { - "collapsed": false - }, + "execution_count": 61, + "metadata": {}, "outputs": [ { "data": { @@ -1817,7 +1714,7 @@ "False" ] }, - "execution_count": 58, + "execution_count": 61, "metadata": {}, "output_type": "execute_result" } @@ -1826,6 +1723,223 @@ "{1, 2}.isdisjoint({1, 6})" ] }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Tsest" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'slgncszxltkzebghstgywdmpr'" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_ct = ''.join(c.lower() for c in 'SLGNC SZXLT KZEBG HSTGY WDMPR' if c in string.ascii_letters)\n", + "target_ct" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'theyweredetectedbybritishshipsinclud'" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_pt = ''.join(c.lower() for c in 'Theyw erede tecte d byBri tishs hipsi nclud' if c in string.ascii_letters)\n", + "target_pt" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[MenuIem(before='w', after='c', number=1),\n", + " MenuIem(before='e', after='s', number=2),\n", + " MenuIem(before='r', after='z', number=3),\n", + " MenuIem(before='e', after='x', number=4),\n", + " MenuIem(before='d', after='l', number=5),\n", + " MenuIem(before='e', after='t', number=6),\n", + " MenuIem(before='t', after='k', number=7),\n", + " MenuIem(before='e', after='z', number=8),\n", + " MenuIem(before='c', after='e', number=9),\n", + " MenuIem(before='t', after='b', number=10),\n", + " MenuIem(before='e', after='g', number=11),\n", + " MenuIem(before='d', after='h', number=12),\n", + " MenuIem(before='b', after='s', number=13),\n", + " MenuIem(before='y', after='t', number=14),\n", + " MenuIem(before='b', after='g', number=15),\n", + " MenuIem(before='r', after='y', number=16),\n", + " MenuIem(before='i', after='w', number=17),\n", + " MenuIem(before='t', after='d', number=18),\n", + " MenuIem(before='i', after='m', number=19),\n", + " MenuIem(before='s', after='p', number=20)]" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_menu = [MenuItem(p, c, i+1) for i, (p, c) in enumerate(zip(target_pt[4:24], target_ct[4:24]))]\n", + "tbt_menu" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "tbt_bombe = Bombe(wheel_iii_spec, wheel_i_spec, wheel_ii_spec, reflector_b_spec, \n", + " menu=tbt_menu)" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('k', 'r', 'n')]" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_wheel_posns = run_multi_bombe(wheel_iii_spec, wheel_i_spec, wheel_ii_spec, reflector_b_spec, tbt_menu)\n", + "tbt_wheel_posns" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Signal(bank='e', wire='e')" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_bombe.test_start" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "a : abcdefghi..lmnop.rst.v.x.z\n", + "b : a...ef.hi..lmnop.r.t...x..\n", + "c : a..defg.i..lmn.p.rst...x..\n", + "d : a.c.efghi.klmnopqrstu.wxyz\n", + "e : abcdefghijklmnopqrstuvwx.z\n", + "f : abcdefghijklmno.qrstuvwxyz\n", + "g : a.cdefghijklmnopqrstuvwxyz\n", + "h : ab.defghi...mnopqrstuvwxyz\n", + "i : abcdefghijklm.opqrstuvwxyz\n", + "j : ....efg.i..lmnop...t...x..\n", + "k : ...defg.i..lmn.p..st...x..\n", + "l : abcdefg.ijklmnopqrstuv.x..\n", + "m : abcdefghijkl.nopqrstuvwxyz\n", + "n : abcdefgh.jklmnopqrstuvwxyz\n", + "o : ab.defghij.lmnop.r.tuvwxyz\n", + "p : abcde.ghijklmnopqrstuvwxyz\n", + "q : ...defghi..lmn.p..st...x..\n", + "r : abcdefghi..lmnop.rst.v.x.z\n", + "s : a.cdefghi.klmn.pqr.tuvwxyz\n", + "t : abcdefghijklmnopqrstuvw.yz\n", + "u : ...defghi..lmnop..st...x..\n", + "v : a...efghi..lmnop.rst...x..\n", + "w : ...defghi...mnop..st...x..\n", + "x : abcdefghijklmnopqrs.uvwxyz\n", + "y : ...d.fghi...mnop..st...x..\n", + "z : a..defghi...mnop.rst...x..\n" + ] + } + ], + "source": [ + "r = tbt_bombe.test(start_positions=('l', 's', 'd'))\n", + "print(r)\n", + "for b in sorted(w_bombe.banks):\n", + " print(b, ': ', end='')\n", + " for w in sorted(w_bombe.banks[b]):\n", + " if w_bombe.banks[b][w]:\n", + " print(w, end='')\n", + " else:\n", + " print('.', end='')\n", + " print('')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "set()" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ps = tbt_bombe.possible_plugboards()\n", + "ps" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1852,9 +1966,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.1+" + "version": "3.5.3" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/dtu_notch_big.jpg b/dtu_notch_big.jpg new file mode 100644 index 0000000..dbdbbf1 Binary files /dev/null and b/dtu_notch_big.jpg differ diff --git a/enigma-notch.jpg b/enigma-notch.jpg new file mode 100644 index 0000000..31781e6 Binary files /dev/null and b/enigma-notch.jpg differ diff --git a/enigma-old.ipynb b/enigma-old.ipynb new file mode 100644 index 0000000..a9e832d --- /dev/null +++ b/enigma-old.ipynb @@ -0,0 +1,2639 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Enigma machine\n", + "Specification from [Codes and Ciphers](http://www.codesandciphers.org.uk/enigma/rotorspec.htm) page.\n", + "\n", + "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", + "\n", + "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)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import string\n", + "import collections\n", + "\n", + "cat = ''.join\n", + "\n", + "def clean(text): return cat(l.lower() for l in text if l in string.ascii_letters)\n", + "\n", + "def pos(letter): \n", + " if letter in string.ascii_lowercase:\n", + " return ord(letter) - ord('a')\n", + " elif letter in string.ascii_uppercase:\n", + " return ord(letter) - ord('A')\n", + " else:\n", + " return ''\n", + " \n", + "def unpos(number): return chr(number % 26 + ord('a'))" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "wheel_i_spec = 'ekmflgdqvzntowyhxuspaibrcj'\n", + "wheel_ii_spec = 'ajdksiruxblhwtmcqgznpyfvoe'\n", + "wheel_iii_spec = 'bdfhjlcprtxvznyeiwgakmusqo'\n", + "wheel_iv_spec = 'esovpzjayquirhxlnftgkdcmwb'\n", + "wheel_v_spec = 'vzbrgityupsdnhlxawmjqofeck'\n", + "wheel_vi_spec = 'jpgvoumfyqbenhzrdkasxlictw'\n", + "wheel_vii_spec = 'nzjhgrcxmyswboufaivlpekqdt'\n", + "wheel_viii_spec = 'fkqhtlxocbjspdzramewniuygv'\n", + "beta_wheel_spec = 'leyjvcnixwpbqmdrtakzgfuhos'\n", + "gamma_wheel_spec = 'fsokanuerhmbtiycwlqpzxvgjd'\n", + "\n", + "wheel_i_pegs = ['q']\n", + "wheel_ii_pegs = ['e']\n", + "wheel_iii_pegs = ['v']\n", + "wheel_iv_pegs = ['j']\n", + "wheel_v_pegs = ['z']\n", + "wheel_vi_pegs = ['z', 'm']\n", + "wheel_vii_pegs = ['z', 'm']\n", + "wheel_viii_pegs = ['z', 'm']\n", + "\n", + "reflector_b_spec = 'ay br cu dh eq fs gl ip jx kn mo tz vw'\n", + "reflector_c_spec = 'af bv cp dj ei go hy kr lz mx nw tq su'" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class LetterTransformer(object):\n", + " def __init__(self, specification, raw_transform=False):\n", + " if raw_transform:\n", + " transform = specification\n", + " else:\n", + " transform = self.parse_specification(specification)\n", + " self.validate_transform(transform)\n", + " self.make_transform_map(transform)\n", + " \n", + " def parse_specification(self, specification):\n", + " return list(zip(string.ascii_lowercase, clean(specification)))\n", + " # return specification\n", + " \n", + " def validate_transform(self, transform):\n", + " \"\"\"A set of pairs, of from-to\"\"\"\n", + " if len(transform) != 26:\n", + " raise ValueError(\"Transform specification has {} pairs, requires 26\".\n", + " format(len(transform)))\n", + " for p in transform:\n", + " if len(p) != 2:\n", + " raise ValueError(\"Not all mappings in transform \"\n", + " \"have two elements\")\n", + " if len(set([p[0] for p in transform])) != 26:\n", + " raise ValueError(\"Transform specification must list 26 origin letters\") \n", + " if len(set([p[1] for p in transform])) != 26:\n", + " raise ValueError(\"Transform specification must list 26 destination letters\") \n", + "\n", + " def make_empty_transform(self):\n", + " self.forward_map = [0] * 26\n", + " self.backward_map = [0] * 26\n", + " \n", + " def make_transform_map(self, transform):\n", + " self.make_empty_transform()\n", + " for p in transform:\n", + " self.forward_map[pos(p[0])] = pos(p[1])\n", + " self.backward_map[pos(p[1])] = pos(p[0])\n", + " return self.forward_map, self.backward_map\n", + " \n", + " def forward(self, letter):\n", + " if letter in string.ascii_lowercase:\n", + " return unpos(self.forward_map[pos(letter)])\n", + " else:\n", + " return ''\n", + " \n", + " def backward(self, letter):\n", + " if letter in string.ascii_lowercase:\n", + " return unpos(self.backward_map[pos(letter)])\n", + " else:\n", + " return ''" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('z', 'a'),\n", + " ('a', 'b'),\n", + " ('b', 'c'),\n", + " ('c', 'd'),\n", + " ('d', 'e'),\n", + " ('e', 'f'),\n", + " ('f', 'g'),\n", + " ('g', 'h'),\n", + " ('h', 'i'),\n", + " ('i', 'j'),\n", + " ('j', 'k'),\n", + " ('k', 'l'),\n", + " ('l', 'm'),\n", + " ('m', 'n'),\n", + " ('n', 'o'),\n", + " ('o', 'p'),\n", + " ('p', 'q'),\n", + " ('q', 'r'),\n", + " ('r', 's'),\n", + " ('s', 't'),\n", + " ('t', 'u'),\n", + " ('u', 'v'),\n", + " ('v', 'w'),\n", + " ('w', 'x'),\n", + " ('x', 'y'),\n", + " ('y', 'z')]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tmap = [('z', 'a')] + [(l, string.ascii_lowercase[i+1]) for i, l in enumerate(string.ascii_lowercase[:-1])]\n", + "tmap" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'zyxwcabdefghijklmnopqrstuv'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(collections.OrderedDict.fromkeys('zyxwc' + string.ascii_lowercase))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true, + "scrolled": true + }, + "outputs": [], + "source": [ + "tmap2 = list(zip(string.ascii_lowercase, cat(collections.OrderedDict.fromkeys('zyxwc' + string.ascii_lowercase))))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "([1,\n", + " 2,\n", + " 3,\n", + " 4,\n", + " 5,\n", + " 6,\n", + " 7,\n", + " 8,\n", + " 9,\n", + " 10,\n", + " 11,\n", + " 12,\n", + " 13,\n", + " 14,\n", + " 15,\n", + " 16,\n", + " 17,\n", + " 18,\n", + " 19,\n", + " 20,\n", + " 21,\n", + " 22,\n", + " 23,\n", + " 24,\n", + " 25,\n", + " 0],\n", + " [25,\n", + " 0,\n", + " 1,\n", + " 2,\n", + " 3,\n", + " 4,\n", + " 5,\n", + " 6,\n", + " 7,\n", + " 8,\n", + " 9,\n", + " 10,\n", + " 11,\n", + " 12,\n", + " 13,\n", + " 14,\n", + " 15,\n", + " 16,\n", + " 17,\n", + " 18,\n", + " 19,\n", + " 20,\n", + " 21,\n", + " 22,\n", + " 23,\n", + " 24])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lt = LetterTransformer(tmap, raw_transform = True)\n", + "assert(lt.forward_map == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0])\n", + "assert(lt.backward_map == [25, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24])\n", + "lt.forward_map, lt.backward_map" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "([25,\n", + " 24,\n", + " 23,\n", + " 22,\n", + " 2,\n", + " 0,\n", + " 1,\n", + " 3,\n", + " 4,\n", + " 5,\n", + " 6,\n", + " 7,\n", + " 8,\n", + " 9,\n", + " 10,\n", + " 11,\n", + " 12,\n", + " 13,\n", + " 14,\n", + " 15,\n", + " 16,\n", + " 17,\n", + " 18,\n", + " 19,\n", + " 20,\n", + " 21],\n", + " [5,\n", + " 6,\n", + " 4,\n", + " 7,\n", + " 8,\n", + " 9,\n", + " 10,\n", + " 11,\n", + " 12,\n", + " 13,\n", + " 14,\n", + " 15,\n", + " 16,\n", + " 17,\n", + " 18,\n", + " 19,\n", + " 20,\n", + " 21,\n", + " 22,\n", + " 23,\n", + " 24,\n", + " 25,\n", + " 3,\n", + " 2,\n", + " 1,\n", + " 0])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lt = LetterTransformer(cat(collections.OrderedDict.fromkeys('zyxwc' + string.ascii_lowercase)))\n", + "assert(lt.forward_map == [25, 24, 23, 22, 2, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21])\n", + "assert(lt.backward_map == [5, 6, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 3, 2, 1, 0])\n", + "assert(cat(lt.forward(l) for l in string.ascii_lowercase) == 'zyxwcabdefghijklmnopqrstuv')\n", + "assert(cat(lt.backward(l) for l in string.ascii_lowercase) == 'fgehijklmnopqrstuvwxyzdcba')\n", + "lt.forward_map, lt.backward_map" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'zyxwcabdefghijklmnopqrstuv'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(lt.forward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'fgehijklmnopqrstuvwxyzdcba'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(lt.backward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Plugboard(LetterTransformer):\n", + " def parse_specification(self, specification):\n", + " return [tuple(clean(p)) for p in specification.split()]\n", + " \n", + " def validate_transform(self, transform):\n", + " \"\"\"A set of pairs, of from-to\"\"\"\n", + " for p in transform:\n", + " if len(p) != 2:\n", + " raise ValueError(\"Not all mappings in transform\"\n", + " \"have two elements\")\n", + " \n", + " def make_empty_transform(self):\n", + " self.forward_map = list(range(26))\n", + " self.backward_map = list(range(26))\n", + " \n", + " def make_transform_map(self, transform):\n", + " expanded_transform = transform + [tuple(reversed(p)) for p in transform]\n", + " return super(Plugboard, self).make_transform_map(expanded_transform)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "pb = Plugboard([('a', 'z'), ('b', 'y')], raw_transform=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'zycdefghijklmnopqrstuvwxba'" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(pb.forward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'zycdefghijklmnopqrstuvwxba'" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(pb.backward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "pb = Plugboard('az by')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('zycdefghijklmnopqrstuvwxba', 'zycdefghijklmnopqrstuvwxba')" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(pb.forward(l) for l in string.ascii_lowercase), cat(pb.backward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('ugcdypblnzkhmisfrqoxavwtej', 'ugcdypblnzkhmisfrqoxavwtej')" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pb = Plugboard('ua pf rq so ni ey bg hl tx zj'.upper())\n", + "assert(pb.forward_map == pb.backward_map)\n", + "assert(pb.forward_map == [20, 6, 2, 3, 24, 15, 1, 11, 13, 25, 10, 7, 12, 8, 18, 5, 17, 16, 14, 23, 0, 21, 22, 19, 4, 9])\n", + "assert(cat(pb.forward(l) for l in string.ascii_lowercase) == 'ugcdypblnzkhmisfrqoxavwtej')\n", + "assert(cat(pb.backward(l) for l in string.ascii_lowercase) == 'ugcdypblnzkhmisfrqoxavwtej')\n", + "cat(pb.forward(l) for l in string.ascii_lowercase), cat(pb.backward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Reflector(Plugboard):\n", + " def validate_transform(self, transform):\n", + " if len(transform) != 13:\n", + " raise ValueError(\"Reflector specification has {} pairs, requires 13\".\n", + " format(len(transform)))\n", + " if len(set([p[0] for p in transform] + \n", + " [p[1] for p in transform])) != 26:\n", + " raise ValueError(\"Reflector specification does not contain 26 letters\")\n", + " try:\n", + " super(Reflector, self).validate_transform(transform)\n", + " except ValueError as v:\n", + " raise ValueError(\"Not all mappings in reflector have two elements\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('a', 'y'),\n", + " ('b', 'r'),\n", + " ('c', 'u'),\n", + " ('d', 'h'),\n", + " ('e', 'q'),\n", + " ('f', 's'),\n", + " ('g', 'l'),\n", + " ('i', 'p'),\n", + " ('j', 'x'),\n", + " ('k', 'n'),\n", + " ('m', 'o'),\n", + " ('t', 'z'),\n", + " ('v', 'w')]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# reflector_b_text = '(AY) (BR) (CU) (DH) (EQ) (FS) (GL) (IP) (JX) (KN) (MO) (TZ) (VW)'\n", + "reflector_b_l = [tuple(clean(p)) for p in reflector_b_spec.split()]\n", + "reflector_b_l" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "reflector_b = Reflector(reflector_b_spec)\n", + "assert(reflector_b.forward_map == reflector_b.backward_map)\n", + "assert(reflector_b.forward_map == [24, 17, 20, 7, 16, 18, 11, 3, 15, 23, 13, 6, 14, 10, 12, 8, 4, 1, 5, 25, 2, 22, 21, 9, 0, 19])\n", + "assert(cat(reflector_b.forward(l) for l in string.ascii_lowercase) == 'yruhqsldpxngokmiebfzcwvjat')\n", + "assert(cat(reflector_b.backward(l) for l in string.ascii_lowercase) == 'yruhqsldpxngokmiebfzcwvjat')" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'yruhqsldpxngokmiebfzcwvjat'" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(reflector_b.forward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "reflector_c = Reflector(reflector_c_spec)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'fvpjiaoyedrzxwgctkuqsbnmhl'" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(reflector_c.forward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class SimpleWheel(LetterTransformer):\n", + " def __init__(self, transform, position='a', raw_transform=False):\n", + " super(SimpleWheel, self).__init__(transform, raw_transform)\n", + " self.set_position(position)\n", + " \n", + " def __getattribute__(self,name):\n", + " if name=='position_l':\n", + " return unpos(self.position)\n", + " else:\n", + " return object.__getattribute__(self, name)\n", + " \n", + " def set_position(self, position):\n", + " self.position = ord(position) - ord('a')\n", + " \n", + " def forward(self, letter):\n", + " if letter in string.ascii_lowercase:\n", + " return unpos((self.forward_map[(pos(letter) + self.position) % 26] - self.position))\n", + " else:\n", + " return ''\n", + " \n", + " def backward(self, letter):\n", + " if letter in string.ascii_lowercase:\n", + " return unpos((self.backward_map[(pos(letter) + self.position) % 26] - self.position))\n", + " else:\n", + " return ''\n", + " \n", + " def advance(self):\n", + " self.position = (self.position + 1) % 26\n", + " return self.position" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[('a', 'e'),\n", + " ('b', 'k'),\n", + " ('c', 'm'),\n", + " ('d', 'f'),\n", + " ('e', 'l'),\n", + " ('f', 'g'),\n", + " ('g', 'd'),\n", + " ('h', 'q'),\n", + " ('i', 'v'),\n", + " ('j', 'z'),\n", + " ('k', 'n'),\n", + " ('l', 't'),\n", + " ('m', 'o'),\n", + " ('n', 'w'),\n", + " ('o', 'y'),\n", + " ('p', 'h'),\n", + " ('q', 'x'),\n", + " ('r', 'u'),\n", + " ('s', 's'),\n", + " ('t', 'p'),\n", + " ('u', 'a'),\n", + " ('v', 'i'),\n", + " ('w', 'b'),\n", + " ('x', 'r'),\n", + " ('y', 'c'),\n", + " ('z', 'j')]" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rotor_1_transform = list(zip(string.ascii_lowercase, 'EKMFLGDQVZNTOWYHXUSPAIBRCJ'.lower()))\n", + "rotor_1_transform" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "rotor_1_transform = list(zip(string.ascii_lowercase, 'EKMFLGDQVZNTOWYHXUSPAIBRCJ'.lower()))\n", + "wheel_1 = SimpleWheel(rotor_1_transform, raw_transform=True)\n", + "assert(cat(wheel_1.forward(l) for l in string.ascii_lowercase) == 'ekmflgdqvzntowyhxuspaibrcj')\n", + "assert(cat(wheel_1.backward(l) for l in string.ascii_lowercase) == 'uwygadfpvzbeckmthxslrinqoj')" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('ekmflgdqvzntowyhxuspaibrcj', 'uwygadfpvzbeckmthxslrinqoj')" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(wheel_1.forward(l) for l in string.ascii_lowercase), cat(wheel_1.backward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'a'" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel_1.position_l" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "wheel_2 = SimpleWheel(wheel_ii_spec)\n", + "assert(cat(wheel_2.forward(l) for l in string.ascii_lowercase) == 'ajdksiruxblhwtmcqgznpyfvoe')\n", + "assert(cat(wheel_2.backward(l) for l in string.ascii_lowercase) == 'ajpczwrlfbdkotyuqgenhxmivs')" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('ajdksiruxblhwtmcqgznpyfvoe', 'ajpczwrlfbdkotyuqgenhxmivs')" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(wheel_2.forward(l) for l in string.ascii_lowercase), cat(wheel_2.backward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('bdfhjlcprtxvznyeiwgakmusqo', 'tagbpcsdqeufvnzhyixjwlrkom')" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel_3 = SimpleWheel(wheel_iii_spec)\n", + "wheel_3.set_position('a')\n", + "wheel_3.advance()\n", + "assert(cat(wheel_3.forward(l) for l in string.ascii_lowercase) == 'cegikboqswuymxdhvfzjltrpna')\n", + "assert(cat(wheel_3.backward(l) for l in string.ascii_lowercase) == 'zfaobrcpdteumygxhwivkqjnls')\n", + "assert(wheel_3.position == 1)\n", + "assert(wheel_3.position_l == 'b')\n", + "\n", + "for _ in range(24): wheel_3.advance()\n", + "assert(wheel_3.position == 25)\n", + "assert(wheel_3.position_l == 'z')\n", + "assert(cat(wheel_3.forward(l) for l in string.ascii_lowercase) == 'pcegikmdqsuywaozfjxhblnvtr')\n", + "assert(cat(wheel_3.backward(l) for l in string.ascii_lowercase) == 'nubhcqdterfvgwoaizjykxmslp')\n", + "\n", + "wheel_3.advance()\n", + "assert(wheel_3.position == 0)\n", + "assert(wheel_3.position_l == 'a')\n", + "assert(cat(wheel_3.forward(l) for l in string.ascii_lowercase) == 'bdfhjlcprtxvznyeiwgakmusqo')\n", + "assert(cat(wheel_3.backward(l) for l in string.ascii_lowercase) == 'tagbpcsdqeufvnzhyixjwlrkom')\n", + "\n", + "cat(wheel_3.forward(l) for l in string.ascii_lowercase), cat(wheel_3.backward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Wheel(SimpleWheel):\n", + " def __init__(self, transform, ring_peg_letters, ring_setting=1, position='a', raw_transform=False):\n", + " self.ring_peg_letters = ring_peg_letters\n", + " self.ring_setting = ring_setting\n", + " super(Wheel, self).__init__(transform, position=position, raw_transform=raw_transform)\n", + " self.set_position(position)\n", + " \n", + " def __getattribute__(self,name):\n", + " if name=='position_l':\n", + " return unpos(self.position + self.ring_setting - 1)\n", + " else:\n", + " return object.__getattribute__(self, name)\n", + "\n", + " def set_position(self, position):\n", + " self.position = (pos(position) - self.ring_setting + 1) % 26\n", + " # self.position_l = position\n", + " self.peg_positions = [(pos(p) - pos(position)) % 26 for p in self.ring_peg_letters]\n", + " \n", + " def advance(self):\n", + " super(Wheel, self).advance()\n", + " self.peg_positions = [(p - 1) % 26 for p in self.peg_positions]\n", + " # self.position_l = unpos(self.position + self.ring_setting - 1)\n", + " return self.position" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "wheel_3 = Wheel(wheel_iii_spec, wheel_iii_pegs, position='b', ring_setting=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1, [20])" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel_3.position, wheel_3.peg_positions" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(25, [24, 11])" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel_6 = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', ring_setting=3)\n", + "wheel_6.position, wheel_6.peg_positions" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 [23, 10]\n", + "1 [22, 9]\n", + "2 [21, 8]\n", + "3 [20, 7]\n", + "4 [19, 6]\n", + "5 [18, 5]\n", + "6 [17, 4]\n", + "7 [16, 3]\n", + "8 [15, 2]\n", + "9 [14, 1]\n", + "10 [13, 0]\n", + "11 [12, 25]\n", + "12 [11, 24]\n", + "13 [10, 23]\n", + "14 [9, 22]\n", + "15 [8, 21]\n", + "16 [7, 20]\n", + "17 [6, 19]\n", + "18 [5, 18]\n", + "19 [4, 17]\n", + "20 [3, 16]\n", + "21 [2, 15]\n", + "22 [1, 14]\n", + "23 [0, 13]\n", + "24 [25, 12]\n", + "25 [24, 11]\n", + "0 [23, 10]\n" + ] + } + ], + "source": [ + "for _ in range(27):\n", + " wheel_6.advance()\n", + " print(wheel_6.position, wheel_6.peg_positions)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "wheel_3 = Wheel(wheel_iii_spec, wheel_iii_pegs, position='b', ring_setting=1)\n", + "assert(wheel_3.position == 1)\n", + "assert(wheel_3.peg_positions == [20])\n", + "assert(wheel_3.position_l == 'b')\n", + "wheel_3.advance()\n", + "assert(wheel_3.position == 2)\n", + "assert(wheel_3.peg_positions == [19])\n", + "assert(wheel_3.position_l == 'c')" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "wheel_6 = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', ring_setting=3)\n", + "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'xkqhwpvngzrcfoiaselbtymjdu')\n", + "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'ptlyrmidoxbswhnfckquzgeavj')\n", + "assert(wheel_6.position == 25)\n", + "assert(11 in wheel_6.peg_positions)\n", + "assert(24 in wheel_6.peg_positions)\n", + "assert(wheel_6.position_l == 'b')\n", + "\n", + "wheel_6.advance()\n", + "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'jpgvoumfyqbenhzrdkasxlictw')\n", + "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'skxqlhcnwarvgmebjptyfdzuio')\n", + "assert(wheel_6.position == 0)\n", + "assert(10 in wheel_6.peg_positions)\n", + "assert(23 in wheel_6.peg_positions)\n", + "assert(wheel_6.position_l == 'c')\n", + "\n", + "for _ in range(22): wheel_6.advance()\n", + "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'mgxantkzsyqjcufirldvhoewbp')\n", + "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'dymswobuplgraevzkqifntxcjh')\n", + "assert(wheel_6.position == 22)\n", + "assert(1 in wheel_6.peg_positions)\n", + "assert(14 in wheel_6.peg_positions)\n", + "assert(wheel_6.position_l == 'y')\n", + "\n", + "wheel_6.advance()\n", + "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'fwzmsjyrxpibtehqkcugndvaol')\n", + "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'xlrvnatokfqzduyjphemswbigc')\n", + "assert(wheel_6.position == 23)\n", + "assert(0 in wheel_6.peg_positions)\n", + "assert(13 in wheel_6.peg_positions)\n", + "assert(wheel_6.position_l == 'z')\n", + "\n", + "wheel_6.advance()\n", + "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'vylrixqwohasdgpjbtfmcuznke')\n", + "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'kqumzsnjepyctxiogdlrvahfbw')\n", + "assert(wheel_6.position == 24)\n", + "assert(25 in wheel_6.peg_positions)\n", + "assert(12 in wheel_6.peg_positions)\n", + "assert(wheel_6.position_l == 'a')\n", + "\n", + "wheel_6.advance()\n", + "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'xkqhwpvngzrcfoiaselbtymjdu')\n", + "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'ptlyrmidoxbswhnfckquzgeavj')\n", + "assert(wheel_6.position == 25)\n", + "assert(24 in wheel_6.peg_positions)\n", + "assert(11 in wheel_6.peg_positions)\n", + "assert(wheel_6.position_l == 'b')\n", + "\n", + "wheel_6.advance()\n", + "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'jpgvoumfyqbenhzrdkasxlictw')\n", + "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'skxqlhcnwarvgmebjptyfdzuio')\n", + "assert(wheel_6.position == 0)\n", + "assert(23 in wheel_6.peg_positions)\n", + "assert(10 in wheel_6.peg_positions)\n", + "assert(wheel_6.position_l == 'c')" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0, 'c', [23, 10])" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel_6.position, wheel_6.position_l, wheel_6.peg_positions" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Enigma(object):\n", + " def __init__(self, reflector_spec,\n", + " left_wheel_spec, left_wheel_pegs,\n", + " middle_wheel_spec, middle_wheel_pegs,\n", + " right_wheel_spec, right_wheel_pegs,\n", + " left_ring_setting, middle_ring_setting, right_ring_setting,\n", + " plugboard_setting):\n", + " self.reflector = Reflector(reflector_spec)\n", + " self.left_wheel = Wheel(left_wheel_spec, left_wheel_pegs, ring_setting=left_ring_setting)\n", + " self.middle_wheel = Wheel(middle_wheel_spec, middle_wheel_pegs, ring_setting=middle_ring_setting)\n", + " self.right_wheel = Wheel(right_wheel_spec, right_wheel_pegs, ring_setting=right_ring_setting)\n", + " self.plugboard = Plugboard(plugboard_setting)\n", + " \n", + " def __getattribute__(self,name):\n", + " if name=='wheel_positions':\n", + " return self.left_wheel.position, self.middle_wheel.position, self.right_wheel.position \n", + " elif name=='wheel_positions_l':\n", + " return self.left_wheel.position_l, self.middle_wheel.position_l, self.right_wheel.position_l \n", + " elif name=='peg_positions':\n", + " return self.left_wheel.peg_positions, self.middle_wheel.peg_positions, self.right_wheel.peg_positions\n", + " else:\n", + " return object.__getattribute__(self, name)\n", + "\n", + " \n", + " def set_wheels(self, left_wheel_position, middle_wheel_position, right_wheel_position):\n", + " self.left_wheel.set_position(left_wheel_position)\n", + " self.middle_wheel.set_position(middle_wheel_position)\n", + " self.right_wheel.set_position(right_wheel_position)\n", + " \n", + " def lookup(self, letter):\n", + " a = self.plugboard.forward(letter)\n", + " b = self.right_wheel.forward(a)\n", + " c = self.middle_wheel.forward(b)\n", + " d = self.left_wheel.forward(c)\n", + " e = self.reflector.forward(d)\n", + " f = self.left_wheel.backward(e)\n", + " g = self.middle_wheel.backward(f)\n", + " h = self.right_wheel.backward(g)\n", + " i = self.plugboard.backward(h)\n", + " return i\n", + " \n", + " def advance(self):\n", + " advance_middle = False\n", + " advance_left = False\n", + " if 0 in self.right_wheel.peg_positions:\n", + " advance_middle = True\n", + " if 0 in self.middle_wheel.peg_positions:\n", + " advance_left = True\n", + " advance_middle = True\n", + " self.right_wheel.advance()\n", + " if advance_middle: self.middle_wheel.advance()\n", + " if advance_left: self.left_wheel.advance()\n", + " \n", + " def encipher_letter(self, letter):\n", + " self.advance()\n", + " return self.lookup(letter)\n", + " \n", + " def encipher(self, message, debug=False):\n", + " enciphered = ''\n", + " for letter in clean(message):\n", + " enciphered += self.encipher_letter(letter)\n", + " if debug:\n", + " print('Wheels now', list(self.wheel_positions_l), 'enciphering {} -> {}'.format(letter, self.lookup(letter)))\n", + " return enciphered" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"('a', 'b', 'c')\"" + ] + }, + "execution_count": 82, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sfsdf = ('a', 'b', 'c')\n", + "str(sfsdf)" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "enigma = Enigma(reflector_b_spec, \n", + " wheel_i_spec, wheel_i_pegs,\n", + " wheel_ii_spec, wheel_ii_pegs,\n", + " wheel_iii_spec, wheel_iii_pegs,\n", + " 1, 1, 1,\n", + " '')" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'u'" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enigma.lookup('a')" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'a'" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enigma.lookup('u')" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'uejobtpzwcnsrkdgvmlfaqiyxh'" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(enigma.lookup(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 :: a a a ; [16] [4] [21] uejobtpzwcnsrkdgvmlfaqiyxh\n", + "1 :: a a b ; [16] [4] [20] baqmfexihswpdytlcvjozrkgnu\n", + "2 :: a a c ; [16] [4] [19] djralkwpobfeyqihncxzvugsmt\n", + "3 :: a a d ; [16] [4] [18] zlejcuitgdmbkonsvxphfqyrwa\n", + "4 :: a a e ; [16] [4] [17] gcblwtakqzhdosmxiunfryepvj\n", + "5 :: a a f ; [16] [4] [16] osnirgfmdpvuhcajwebxlkqtzy\n", + "6 :: a a g ; [16] [4] [15] wymvnqzjlhoicekuftxrpdasbg\n", + "7 :: a a h ; [16] [4] [14] cjafkdztpbeuormiwnvhlsqyxg\n", + "8 :: a a i ; [16] [4] [13] xijuyslvbczgnmqwotfrdhpaek\n", + "9 :: a a j ; [16] [4] [12] lfzrwbytjisaovmuxdkhpneqgc\n", + "10 :: a a k ; [16] [4] [11] tkezcqynuwbpvhslfxoaimjrgd\n", + "11 :: a a l ; [16] [4] [10] kiwfnduxbsaotelqpvjmgrchzy\n", + "12 :: a a m ; [16] [4] [9] sfkutbpoxycrnmhgwlaedzqijv\n", + "13 :: a a n ; [16] [4] [8] baqwlkhgrsfextpocijnvudmzy\n", + "14 :: a a o ; [16] [4] [7] teofbdzxqkjyrscvimnawpuhlg\n", + "15 :: a a p ; [16] [4] [6] mhypswrbzxqvaondkgeutlfjci\n", + "16 :: a a q ; [16] [4] [5] cpasnrhgkuixzevbyfdwjotlqm\n", + "17 :: a a r ; [16] [4] [4] dlfatcjwygvbnmzrxpueskhqio\n", + "18 :: a a s ; [16] [4] [3] lxymzjuqtfpadsrkhonigwvbce\n", + "19 :: a a t ; [16] [4] [2] puvioztjdhxmlyeawsrgbcqknf\n", + "20 :: a a u ; [16] [4] [1] baigpldqcowfyzjehvtsxrkumn\n", + "21 :: a a v ; [16] [4] [0] mnvfydiwgzsoablrxpkutchqej\n", + "22 :: a b w ; [16] [3] [25] ulfopcykswhbzvderqixanjtgm\n", + "23 :: a b x ; [16] [3] [24] qmwftdyovursbzhxaklejicpgn\n", + "24 :: a b y ; [16] [3] [23] oljmzxrvucybdqasngpwihtfke\n", + "25 :: a b z ; [16] [3] [22] fwevcalzxutgysrqponkjdbimh\n" + ] + } + ], + "source": [ + "enigma.set_wheels('a', 'a', 'a')\n", + "for i in range(26):\n", + " print(i, '::', \n", + " enigma.left_wheel.position_l, enigma.middle_wheel.position_l, enigma.right_wheel.position_l, ';',\n", + " enigma.left_wheel.peg_positions, enigma.middle_wheel.peg_positions, enigma.right_wheel.peg_positions, \n", + " cat(enigma.lookup(l) for l in string.ascii_lowercase))\n", + " enigma.advance()" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": true, + "scrolled": true + }, + "outputs": [], + "source": [ + "enigma.set_wheels('a', 'a', 't')\n", + "assert(enigma.wheel_positions == (0, 0, 19))\n", + "assert(cat(enigma.wheel_positions_l) == 'aat')\n", + "assert(enigma.peg_positions == ([16], [4], [2]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'puvioztjdhxmlyeawsrgbcqknf')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 0, 20))\n", + "assert(cat(enigma.wheel_positions_l) == 'aau')\n", + "assert(enigma.peg_positions == ([16], [4], [1]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'baigpldqcowfyzjehvtsxrkumn')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 0, 21))\n", + "assert(cat(enigma.wheel_positions_l) == 'aav')\n", + "assert(enigma.peg_positions == ([16], [4], [0]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mnvfydiwgzsoablrxpkutchqej')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 1, 22))\n", + "assert(cat(enigma.wheel_positions_l) == 'abw')\n", + "assert(enigma.peg_positions == ([16], [3], [25]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ulfopcykswhbzvderqixanjtgm')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 1, 23))\n", + "assert(cat(enigma.wheel_positions_l) == 'abx')\n", + "assert(enigma.peg_positions == ([16], [3], [24]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qmwftdyovursbzhxaklejicpgn')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 1, 24))\n", + "assert(cat(enigma.wheel_positions_l) == 'aby')\n", + "assert(enigma.peg_positions == ([16], [3], [23]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'oljmzxrvucybdqasngpwihtfke')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 5, 24) ('b', 'f', 'y') ([15], [25], [23]) baknstqzrmcxjdvygiefwoulph\n" + ] + } + ], + "source": [ + "enigma.set_wheels('a', 'd', 't')\n", + "assert(enigma.wheel_positions == (0, 3, 19))\n", + "assert(cat(enigma.wheel_positions_l) == 'adt')\n", + "assert(enigma.peg_positions == ([16], [1], [2]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'zcbpqxwsjiuonmldethrkygfva')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 3, 20))\n", + "assert(cat(enigma.wheel_positions_l) == 'adu')\n", + "assert(enigma.peg_positions == ([16], [1], [1]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ehprawjbngotxikcsdqlzyfmvu')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 3, 21))\n", + "assert(cat(enigma.wheel_positions_l) == 'adv')\n", + "assert(enigma.peg_positions == ([16], [1], [0]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'eqzxarpihmnvjkwgbfuyslodtc')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 4, 22))\n", + "assert(cat(enigma.wheel_positions_l) == 'aew')\n", + "assert(enigma.peg_positions == ([16], [0], [25]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qedcbtpluzmhkongavwfirsyxj')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 23))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfx')\n", + "assert(enigma.peg_positions == ([15], [25], [24]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'iwuedhsfazqxytvrkpgncoblmj')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 24))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfy')\n", + "assert(enigma.peg_positions == ([15], [25], [23]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'baknstqzrmcxjdvygiefwoulph')\n", + "\n", + "print(enigma.wheel_positions, enigma.wheel_positions_l, enigma.peg_positions, \n", + " cat(enigma.lookup(l) for l in string.ascii_lowercase))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'olpfhnvflyn'" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enigma.set_wheels('a', 'a', 'a')\n", + "ct = enigma.encipher('testmessage')\n", + "assert(ct == 'olpfhnvflyn')\n", + "ct" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'lawnjgpwjik'" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enigma.set_wheels('a', 'd', 't')\n", + "ct = enigma.encipher('testmessage')\n", + "assert(ct == 'lawnjgpwjik')\n", + "ct" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 5))\n", + "assert(cat(enigma.wheel_positions_l) == 'bff')\n", + "assert(enigma.peg_positions == ([15], [25], [16]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'zpqiogfsdlmjkyebcvhxwrutna')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 6))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfg')\n", + "assert(enigma.peg_positions == ([15], [25], [15]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'fjmnwayslbxicdpouthrqzekgv')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 7))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfh')\n", + "assert(enigma.peg_positions == ([15], [25], [14]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'csafzdyloxuhnmitwvbpkrqjge')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 8))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfi')\n", + "assert(enigma.peg_positions == ([15], [25], [13]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'kihyvulcbtagwrqzonxjfemsdp')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 9))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfj')\n", + "assert(enigma.peg_positions == ([15], [25], [12]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pgzrytbksqhwxvuajdifonlmec')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 10))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfk')\n", + "assert(enigma.peg_positions == ([15], [25], [11]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'fkirsazncwbvyhpoudexqljtmg')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 11))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfl')\n", + "assert(enigma.peg_positions == ([15], [25], [10]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mhkronubsvctafeqpdilgjxwzy')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 12))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfm')\n", + "assert(enigma.peg_positions == ([15], [25], [9]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'gnkuoxarzycmlbetvhwpdqsfji')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 13))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfn')\n", + "assert(enigma.peg_positions == ([15], [25], [8]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'bainslqkcxhfudpogtermwvjzy')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 14))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfo')\n", + "assert(enigma.peg_positions == ([15], [25], [7]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xemfbdnwjitycgzusvqkprhalo')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 15))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfp')\n", + "assert(enigma.peg_positions == ([15], [25], [6]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qixksmhgbtdvfonrapejwluczy')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 16))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfq')\n", + "assert(enigma.peg_positions == ([15], [25], [5]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cgaulmbskwiefrtzynhodxjvqp')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 17))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfr')\n", + "assert(enigma.peg_positions == ([15], [25], [4]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'iwqfldszaxvenmyrcpgutkbjoh')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 18))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfs')\n", + "assert(enigma.peg_positions == ([15], [25], [3]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'vxykrjilgfdhqtusmepnoazbcw')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 19))\n", + "assert(cat(enigma.wheel_positions_l) == 'bft')\n", + "assert(enigma.peg_positions == ([15], [25], [2]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ieysbvkjahgmlpxnwtdrzfqocu')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 20))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfu')\n", + "assert(enigma.peg_positions == ([15], [25], [1]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'baihkjvdcfepywsltxoqzgnrmu')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 21))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfv')\n", + "assert(enigma.peg_positions == ([15], [25], [0]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'bayjtrilgdshvzuwxfkeompqcn')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 6, 22))\n", + "assert(cat(enigma.wheel_positions_l) == 'bgw')\n", + "assert(enigma.peg_positions == ([15], [24], [25]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'rszqohpfxyutvwegdablkmnijc')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 6, 23))\n", + "assert(cat(enigma.wheel_positions_l) == 'bgx')\n", + "assert(enigma.peg_positions == ([15], [24], [24]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nfoxhbzeyrwqpacmljtsvukdig')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 6, 24))\n", + "assert(cat(enigma.wheel_positions_l) == 'bgy')\n", + "assert(enigma.peg_positions == ([15], [24], [23]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'czaogmeihtuqfsdxlwnjkyrpvb')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 6, 25))\n", + "assert(cat(enigma.wheel_positions_l) == 'bgz')\n", + "assert(enigma.peg_positions == ([15], [24], [22]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'omwgysdjkhizbxarupfvqtcnel')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 6, 0))\n", + "assert(cat(enigma.wheel_positions_l) == 'bga')\n", + "assert(enigma.peg_positions == ([15], [24], [21]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cxafmdrzoqutepinjgvlksybwh')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 6, 1))\n", + "assert(cat(enigma.wheel_positions_l) == 'bgb')\n", + "assert(enigma.peg_positions == ([15], [24], [20]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'jymvnrxkoahwceiuzftspdlgbq')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 6, 2))\n", + "assert(cat(enigma.wheel_positions_l) == 'bgc')\n", + "assert(enigma.peg_positions == ([15], [24], [19]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'uzlyiqwrestcnmxvfhjkapgodb')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 6, 3))\n", + "assert(cat(enigma.wheel_positions_l) == 'bgd')\n", + "assert(enigma.peg_positions == ([15], [24], [18]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'veosbuhgpzqynmcikwdxfartlj')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 6, 4))\n", + "assert(cat(enigma.wheel_positions_l) == 'bge')\n", + "assert(enigma.peg_positions == ([15], [24], [17]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ydhbmtrclxsiezpougkfqwvjan')\n", + "\n" + ] + } + ], + "source": [ + "\n", + "for i in range(26):\n", + " enigma.advance()\n", + " print('enigma.advance()')\n", + " print(\"assert(enigma.wheel_positions == {})\".format(enigma.wheel_positions))\n", + " print(\"assert(cat(enigma.wheel_positions_l) == '{}')\".format(cat(enigma.wheel_positions_l)))\n", + " print(\"assert(enigma.peg_positions == {})\".format(enigma.peg_positions))\n", + " print(\"assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == '{}')\".format(cat(enigma.lookup(l) for l in string.ascii_lowercase)))\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'bahxvfrpdc'" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enigma.set_wheels('a', 'd', 't')\n", + "ct = enigma.encipher('hellothere')\n", + "assert(ct == 'bahxvfrpdc')\n", + "ct" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'kvmmwrlqlqsqpeugjrcxzwpfyiyybwloewrouvkpoztceuwtfjzqwpbqldttsr'" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enigma.set_wheels('b', 'd', 'q')\n", + "ct = enigma.encipher('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')\n", + "assert(ct == 'kvmmwrlqlqsqpeugjrcxzwpfyiyybwloewrouvkpoztceuwtfjzqwpbqldttsr')\n", + "assert(enigma.left_wheel.position_l == 'c')\n", + "assert(enigma.middle_wheel.position_l == 'h')\n", + "assert(enigma.right_wheel.position_l == 'a')\n", + "ct" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'c'" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enigma.left_wheel.position_l" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting sheet line 31 from http://www.codesandciphers.org.uk/enigma/enigma3.htm\n", + "# Enigma simulation settings are \n", + "# http://enigma.louisedade.co.uk/enigma.html?m3;b;b153;AFTX;AJFE;AU-BG-EY-FP-HL-IN-JZ-OS-QR-TX\n", + "w_enigma = Enigma(reflector_b_spec, \n", + " wheel_i_spec, wheel_i_pegs,\n", + " wheel_v_spec, wheel_v_pegs,\n", + " wheel_iii_spec, wheel_iii_pegs,\n", + " 6, 20, 24,\n", + " 'ua pf rq so ni ey bg hl tx zj')" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting sheet line 31 from http://www.codesandciphers.org.uk/enigma/enigma3.htm\n", + "# Enigma simulation settings are \n", + "# http://enigma.louisedade.co.uk/enigma.html?m3;b;b153;AFTX;AJFE;AU-BG-EY-FP-HL-IN-JZ-OS-QR-TX\n", + "enigma = Enigma(reflector_b_spec, \n", + " wheel_i_spec, wheel_i_pegs,\n", + " wheel_v_spec, wheel_v_pegs,\n", + " wheel_iii_spec, wheel_iii_pegs,\n", + " 6, 20, 24,\n", + " 'ua pf rq so ni ey bg hl tx zj')" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "enigma.set_wheels('j', 'e', 'u')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (4, 11, 24))\n", + "assert(cat(enigma.wheel_positions_l) == 'jev')\n", + "assert(enigma.peg_positions == ([7], [21], [0]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mvqjlyowkdieasgzcunxrbhtfp')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (4, 12, 25))\n", + "assert(cat(enigma.wheel_positions_l) == 'jfw')\n", + "assert(enigma.peg_positions == ([7], [20], [25]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'sjolzuyvrbwdpxcmtiaqfhknge')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (4, 12, 0))\n", + "assert(cat(enigma.wheel_positions_l) == 'jfx')\n", + "assert(enigma.peg_positions == ([7], [20], [24]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qrxedkoywufmlvgsabpzjnicht')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (4, 12, 1))\n", + "assert(cat(enigma.wheel_positions_l) == 'jfy')\n", + "assert(enigma.peg_positions == ([7], [20], [23]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hpsukliagqefwvtbjxcodnmrzy')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (4, 12, 2))\n", + "assert(cat(enigma.wheel_positions_l) == 'jfz')\n", + "assert(enigma.peg_positions == ([7], [20], [22]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'zevnbpyqowrtxdifhkulscjmga')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "enigma.set_wheels('i', 'd', 'z')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 3))\n", + "assert(cat(enigma.wheel_positions_l) == 'ida')\n", + "assert(enigma.peg_positions == ([8], [22], [21]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ikhpqrvcambzjondefwyxgsutl')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 4))\n", + "assert(cat(enigma.wheel_positions_l) == 'idb')\n", + "assert(enigma.peg_positions == ([8], [22], [20]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cdabskhgzwfmlqvunyexpojtri')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 5))\n", + "assert(cat(enigma.wheel_positions_l) == 'idc')\n", + "assert(enigma.peg_positions == ([8], [22], [19]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pcbwiqhgemyvjsuaftnroldzkx')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 6))\n", + "assert(cat(enigma.wheel_positions_l) == 'idd')\n", + "assert(enigma.peg_positions == ([8], [22], [18]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xcbfvdnouptmlghjzwykierasq')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 7))\n", + "assert(cat(enigma.wheel_positions_l) == 'ide')\n", + "assert(enigma.peg_positions == ([8], [22], [17]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xfvglbdynuseriwqpmkzjcoaht')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 8))\n", + "assert(cat(enigma.wheel_positions_l) == 'idf')\n", + "assert(enigma.peg_positions == ([8], [22], [16]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'tfpqlbouynsewjgcdxkahzmriv')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 9))\n", + "assert(cat(enigma.wheel_positions_l) == 'idg')\n", + "assert(enigma.peg_positions == ([8], [22], [15]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cjaunvlwtbygzexrspqidfhokm')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 10))\n", + "assert(cat(enigma.wheel_positions_l) == 'idh')\n", + "assert(enigma.peg_positions == ([8], [22], [14]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'yltxkrqvowebzpingfucshjdam')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 11))\n", + "assert(cat(enigma.wheel_positions_l) == 'idi')\n", + "assert(enigma.peg_positions == ([8], [22], [13]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'myktluzrnxceaiqsohpdfwvjbg')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 12))\n", + "assert(cat(enigma.wheel_positions_l) == 'idj')\n", + "assert(enigma.peg_positions == ([8], [22], [12]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pynjrmiugdqxfcvakewzhoslbt')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 13))\n", + "assert(cat(enigma.wheel_positions_l) == 'idk')\n", + "assert(enigma.peg_positions == ([8], [22], [11]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mwvedyplnoxhaijgrqtszcbkfu')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 14))\n", + "assert(cat(enigma.wheel_positions_l) == 'idl')\n", + "assert(enigma.peg_positions == ([8], [22], [10]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qcbrfeutvoxpnmjladzhgiykws')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 15))\n", + "assert(cat(enigma.wheel_positions_l) == 'idm')\n", + "assert(enigma.peg_positions == ([8], [22], [9]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'dnoahryetsmukbcvwfjilpqzgx')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 16))\n", + "assert(cat(enigma.wheel_positions_l) == 'idn')\n", + "assert(enigma.peg_positions == ([8], [22], [8]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nidcfehgbqsovalyjzkxwmutpr')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 17))\n", + "assert(cat(enigma.wheel_positions_l) == 'ido')\n", + "assert(enigma.peg_positions == ([8], [22], [7]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'joifxdulcarhzpbntkwqgysevm')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 18))\n", + "assert(cat(enigma.wheel_positions_l) == 'idp')\n", + "assert(enigma.peg_positions == ([8], [22], [6]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ptnlsxvozmwdjchayuebrgkfqi')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 19))\n", + "assert(cat(enigma.wheel_positions_l) == 'idq')\n", + "assert(enigma.peg_positions == ([8], [22], [5]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'slwopzqnmxybihdeguavrtcjkf')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 20))\n", + "assert(cat(enigma.wheel_positions_l) == 'idr')\n", + "assert(enigma.peg_positions == ([8], [22], [4]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hcbedwlamzogixkytsrqvufnpj')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 21))\n", + "assert(cat(enigma.wheel_positions_l) == 'ids')\n", + "assert(enigma.peg_positions == ([8], [22], [3]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'odxbjwzrmelkisavuhnyqpfctg')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 22))\n", + "assert(cat(enigma.wheel_positions_l) == 'idt')\n", + "assert(enigma.peg_positions == ([8], [22], [2]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'udgbfeclrwnhxksvtioqapjmzy')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 23))\n", + "assert(cat(enigma.wheel_positions_l) == 'idu')\n", + "assert(enigma.peg_positions == ([8], [22], [1]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nrdczqxmowvshaiufblypkjgte')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 24))\n", + "assert(cat(enigma.wheel_positions_l) == 'idv')\n", + "assert(enigma.peg_positions == ([8], [22], [0]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hkifjdoacebqtzgulyvmpsxwrn')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 11, 25))\n", + "assert(cat(enigma.wheel_positions_l) == 'iew')\n", + "assert(enigma.peg_positions == ([8], [21], [25]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'yptzuhofqvnmlkgbixwcejsrad')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 11, 0))\n", + "assert(cat(enigma.wheel_positions_l) == 'iex')\n", + "assert(enigma.peg_positions == ([8], [21], [24]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'vkdcwhqfjibzsptngumoraeyxl')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 11, 1))\n", + "assert(cat(enigma.wheel_positions_l) == 'iey')\n", + "assert(enigma.peg_positions == ([8], [21], [23]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'wenpbqrouxlkychdfgzvitajms')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('verylongtestmessagewithanextrabitofmessageforgoodmeasure',\n", + " (3, 12, 6),\n", + " ('i', 'f', 'd'),\n", + " ([8], [20], [18]),\n", + " 'urygzpdmxtwshqvfnbljaokice')" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enigma.set_wheels('i', 'd', 'z')\n", + "ct = enigma.encipher('verylongtestmessagewithanextrabitofmessageforgoodmeasure')\n", + "assert(ct == 'gstsegeqdrthkfwesljjomfvcqwcfspxpfqqmewvddybarzwubxtpejz')\n", + "assert(enigma.wheel_positions == (3, 12, 6))\n", + "assert(cat(enigma.wheel_positions_l) == 'ifd')\n", + "assert(enigma.peg_positions == ([8], [20], [18]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'urygzpdmxtwshqvfnbljaokice')\n", + "\n", + "enigma.set_wheels('i', 'd', 'z')\n", + "pt = enigma.encipher('gstsegeqdrthkfwesljjomfvcqwcfspxpfqqmewvddybarzwubxtpejz')\n", + "assert(pt == 'verylongtestmessagewithanextrabitofmessageforgoodmeasure')\n", + "\n", + "pt, enigma.wheel_positions, enigma.wheel_positions_l, enigma.peg_positions, cat(enigma.lookup(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 3))\n", + "assert(cat(enigma.wheel_positions_l) == 'ida')\n", + "assert(enigma.peg_positions == ([8], [22], [21]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ikhpqrvcambzjondefwyxgsutl')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 4))\n", + "assert(cat(enigma.wheel_positions_l) == 'idb')\n", + "assert(enigma.peg_positions == ([8], [22], [20]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cdabskhgzwfmlqvunyexpojtri')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 5))\n", + "assert(cat(enigma.wheel_positions_l) == 'idc')\n", + "assert(enigma.peg_positions == ([8], [22], [19]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pcbwiqhgemyvjsuaftnroldzkx')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 6))\n", + "assert(cat(enigma.wheel_positions_l) == 'idd')\n", + "assert(enigma.peg_positions == ([8], [22], [18]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xcbfvdnouptmlghjzwykierasq')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 7))\n", + "assert(cat(enigma.wheel_positions_l) == 'ide')\n", + "assert(enigma.peg_positions == ([8], [22], [17]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xfvglbdynuseriwqpmkzjcoaht')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 8))\n", + "assert(cat(enigma.wheel_positions_l) == 'idf')\n", + "assert(enigma.peg_positions == ([8], [22], [16]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'tfpqlbouynsewjgcdxkahzmriv')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 9))\n", + "assert(cat(enigma.wheel_positions_l) == 'idg')\n", + "assert(enigma.peg_positions == ([8], [22], [15]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cjaunvlwtbygzexrspqidfhokm')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 10))\n", + "assert(cat(enigma.wheel_positions_l) == 'idh')\n", + "assert(enigma.peg_positions == ([8], [22], [14]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'yltxkrqvowebzpingfucshjdam')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 11))\n", + "assert(cat(enigma.wheel_positions_l) == 'idi')\n", + "assert(enigma.peg_positions == ([8], [22], [13]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'myktluzrnxceaiqsohpdfwvjbg')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 12))\n", + "assert(cat(enigma.wheel_positions_l) == 'idj')\n", + "assert(enigma.peg_positions == ([8], [22], [12]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pynjrmiugdqxfcvakewzhoslbt')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 13))\n", + "assert(cat(enigma.wheel_positions_l) == 'idk')\n", + "assert(enigma.peg_positions == ([8], [22], [11]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mwvedyplnoxhaijgrqtszcbkfu')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 14))\n", + "assert(cat(enigma.wheel_positions_l) == 'idl')\n", + "assert(enigma.peg_positions == ([8], [22], [10]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qcbrfeutvoxpnmjladzhgiykws')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 15))\n", + "assert(cat(enigma.wheel_positions_l) == 'idm')\n", + "assert(enigma.peg_positions == ([8], [22], [9]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'dnoahryetsmukbcvwfjilpqzgx')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 16))\n", + "assert(cat(enigma.wheel_positions_l) == 'idn')\n", + "assert(enigma.peg_positions == ([8], [22], [8]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nidcfehgbqsovalyjzkxwmutpr')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 17))\n", + "assert(cat(enigma.wheel_positions_l) == 'ido')\n", + "assert(enigma.peg_positions == ([8], [22], [7]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'joifxdulcarhzpbntkwqgysevm')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 18))\n", + "assert(cat(enigma.wheel_positions_l) == 'idp')\n", + "assert(enigma.peg_positions == ([8], [22], [6]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ptnlsxvozmwdjchayuebrgkfqi')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 19))\n", + "assert(cat(enigma.wheel_positions_l) == 'idq')\n", + "assert(enigma.peg_positions == ([8], [22], [5]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'slwopzqnmxybihdeguavrtcjkf')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 20))\n", + "assert(cat(enigma.wheel_positions_l) == 'idr')\n", + "assert(enigma.peg_positions == ([8], [22], [4]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hcbedwlamzogixkytsrqvufnpj')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 21))\n", + "assert(cat(enigma.wheel_positions_l) == 'ids')\n", + "assert(enigma.peg_positions == ([8], [22], [3]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'odxbjwzrmelkisavuhnyqpfctg')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 22))\n", + "assert(cat(enigma.wheel_positions_l) == 'idt')\n", + "assert(enigma.peg_positions == ([8], [22], [2]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'udgbfeclrwnhxksvtioqapjmzy')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 23))\n", + "assert(cat(enigma.wheel_positions_l) == 'idu')\n", + "assert(enigma.peg_positions == ([8], [22], [1]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nrdczqxmowvshaiufblypkjgte')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 10, 24))\n", + "assert(cat(enigma.wheel_positions_l) == 'idv')\n", + "assert(enigma.peg_positions == ([8], [22], [0]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hkifjdoacebqtzgulyvmpsxwrn')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 11, 25))\n", + "assert(cat(enigma.wheel_positions_l) == 'iew')\n", + "assert(enigma.peg_positions == ([8], [21], [25]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'yptzuhofqvnmlkgbixwcejsrad')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 11, 0))\n", + "assert(cat(enigma.wheel_positions_l) == 'iex')\n", + "assert(enigma.peg_positions == ([8], [21], [24]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'vkdcwhqfjibzsptngumoraeyxl')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 11, 1))\n", + "assert(cat(enigma.wheel_positions_l) == 'iey')\n", + "assert(enigma.peg_positions == ([8], [21], [23]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'wenpbqrouxlkychdfgzvitajms')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (3, 11, 2))\n", + "assert(cat(enigma.wheel_positions_l) == 'iez')\n", + "assert(enigma.peg_positions == ([8], [21], [22]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'szgyqvclkoihurjwenaxmfptdb')\n", + "\n" + ] + } + ], + "source": [ + "enigma.set_wheels('i', 'd', 'z')\n", + "\n", + "for i in range(26):\n", + " enigma.advance()\n", + " print('enigma.advance()')\n", + " print(\"assert(enigma.wheel_positions == {})\".format(enigma.wheel_positions))\n", + " print(\"assert(cat(enigma.wheel_positions_l) == '{}')\".format(cat(enigma.wheel_positions_l)))\n", + " print(\"assert(enigma.peg_positions == {})\".format(enigma.peg_positions))\n", + " print(\"assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == '{}')\".format(cat(enigma.lookup(l) for l in string.ascii_lowercase)))\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Reflector B\n", + "# Rotors III, I, II with rings 17, 11, 19\n", + "# Plugboard pairs GU FZ BD LK TC PS HV WN JE AM\n", + "\n", + "tbt_enigma = Enigma(reflector_b_spec, \n", + " wheel_iii_spec, wheel_iii_pegs,\n", + " wheel_i_spec, wheel_i_pegs,\n", + " wheel_ii_spec, wheel_ii_pegs,\n", + " 17, 11, 19,\n", + " 'GU FZ BD LK TC PS HV WN JE AM'.lower())" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'jbvbwwzfslhxnhzzccsngebmrnswgjonwbjnzcfgadeuoyameylmpvny'" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'q', 'v')\n", + "ct = tbt_enigma.encipher('verylongtestmessagewithanextrabitofmessageforgoodmeasure')\n", + "ct" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'slgncszxltkzebghstgywdmpr'" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_ct = ''.join(c.lower() for c in 'SLGNC SZXLT KZEBG HSTGY WDMPR' if c in string.ascii_letters)\n", + "target_ct" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'theyweredetectebybritishshipsinclud'" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_pt = ''.join(c.lower() for c in 'Theyw erede tecte byBri tishs hipsi nclud' if c in string.ascii_letters)\n", + "target_pt" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'theyweredetectedbybritishshipsinclud'" + ] + }, + "execution_count": 91, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_pt = ''.join(c.lower() for c in 'Theyw erede tecte d byBri tishs hipsi nclud' if c in string.ascii_letters)\n", + "target_pt" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(25, 35)" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(target_ct), len(target_pt)" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "slgncszxltkzebghstgywdmpr\n", + "theyweredetectebybritishshipsinclud\n" + ] + } + ], + "source": [ + "print('{}\\n{}'.format(target_ct, target_pt))" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "theyweredetectedbybritishshipsinclud\n", + "slgncszxltkzebghstgywdmpr\n", + "slgncszxltkzebghstgywdmprucuzqdqzpve\n", + "theyweredetectedbybritish\n" + ] + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "this_pt = tbt_enigma.encipher(target_ct)\n", + "\n", + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "this_ct = tbt_enigma.encipher(target_pt)\n", + "\n", + "\n", + "print('{}\\n{}\\n{}\\n{}'.format(target_pt, target_ct, this_ct, this_pt))" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import itertools" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def str_ham(s1, s2):\n", + " \"\"\"Hamming distance for strings\"\"\"\n", + " return sum(1 for c1, c2 in zip(s1, s2) if c1 == c2)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "str_ham('hello', 'hello')" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "best ('a', 'a', 'a') 25\n", + "best ('a', 'a', 'a') 25\n", + "best ('a', 'a', 'a') 25\n", + "best ('a', 'a', 'a') 25\n", + "1 loop, best of 3: 17.6 s per loop\n" + ] + } + ], + "source": [ + "%%timeit\n", + "best = ('a', 'a', 'a')\n", + "best_hd = 0\n", + "for w1, w2, w3 in itertools.product(string.ascii_lowercase, repeat=3):\n", + " tbt_enigma.set_wheels(w1, w2, w3)\n", + " this_ct = tbt_enigma.encipher(target_pt)\n", + " if this_ct == target_ct:\n", + " print(w1, w2, w3)\n", + " if str_ham(this_ct, target_ct) > best_hd:\n", + " best = (w1, w2, w3)\n", + " best_hd = str_ham(this_ct, target_ct)\n", + "print('best', best, best_hd)" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wheels now ['a', 'a', 'b'] enciphering t -> s\n", + "Wheels now ['a', 'a', 'c'] enciphering h -> l\n", + "Wheels now ['a', 'a', 'd'] enciphering e -> g\n", + "Wheels now ['a', 'a', 'e'] enciphering y -> n\n", + "Wheels now ['a', 'b', 'f'] enciphering w -> c\n", + "Wheels now ['a', 'b', 'g'] enciphering e -> s\n", + "Wheels now ['a', 'b', 'h'] enciphering r -> z\n", + "Wheels now ['a', 'b', 'i'] enciphering e -> x\n", + "Wheels now ['a', 'b', 'j'] enciphering d -> l\n", + "Wheels now ['a', 'b', 'k'] enciphering e -> t\n", + "Wheels now ['a', 'b', 'l'] enciphering t -> k\n", + "Wheels now ['a', 'b', 'm'] enciphering e -> z\n", + "Wheels now ['a', 'b', 'n'] enciphering c -> e\n", + "Wheels now ['a', 'b', 'o'] enciphering t -> b\n", + "Wheels now ['a', 'b', 'p'] enciphering e -> g\n", + "Wheels now ['a', 'b', 'q'] enciphering d -> h\n", + "Wheels now ['a', 'b', 'r'] enciphering b -> s\n", + "Wheels now ['a', 'b', 's'] enciphering y -> t\n", + "Wheels now ['a', 'b', 't'] enciphering b -> g\n", + "Wheels now ['a', 'b', 'u'] enciphering r -> y\n", + "Wheels now ['a', 'b', 'v'] enciphering i -> w\n", + "Wheels now ['a', 'b', 'w'] enciphering t -> d\n", + "Wheels now ['a', 'b', 'x'] enciphering i -> m\n", + "Wheels now ['a', 'b', 'y'] enciphering s -> p\n", + "Wheels now ['a', 'b', 'z'] enciphering h -> r\n", + "Wheels now ['a', 'b', 'a'] enciphering s -> u\n", + "Wheels now ['a', 'b', 'b'] enciphering h -> c\n", + "Wheels now ['a', 'b', 'c'] enciphering i -> u\n", + "Wheels now ['a', 'b', 'd'] enciphering p -> z\n", + "Wheels now ['a', 'b', 'e'] enciphering s -> q\n", + "Wheels now ['a', 'c', 'f'] enciphering i -> d\n", + "Wheels now ['a', 'c', 'g'] enciphering n -> q\n", + "Wheels now ['a', 'c', 'h'] enciphering c -> z\n", + "Wheels now ['a', 'c', 'i'] enciphering l -> p\n", + "Wheels now ['a', 'c', 'j'] enciphering u -> v\n", + "Wheels now ['a', 'c', 'k'] enciphering d -> e\n" + ] + }, + { + "data": { + "text/plain": [ + "('slgncszxltkzebghstgywdmprucuzqdqzpve', 'slgncszxltkzebghstgywdmpr')" + ] + }, + "execution_count": 94, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "tbt_enigma.encipher(target_pt, debug=True), target_ct" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wheels now ['a', 'a', 'b'] enciphering s -> t\n", + "Wheels now ['a', 'a', 'c'] enciphering l -> h\n", + "Wheels now ['a', 'a', 'd'] enciphering g -> e\n", + "Wheels now ['a', 'a', 'e'] enciphering n -> y\n", + "Wheels now ['a', 'b', 'f'] enciphering c -> w\n", + "Wheels now ['a', 'b', 'g'] enciphering s -> e\n", + "Wheels now ['a', 'b', 'h'] enciphering z -> r\n", + "Wheels now ['a', 'b', 'i'] enciphering x -> e\n", + "Wheels now ['a', 'b', 'j'] enciphering l -> d\n", + "Wheels now ['a', 'b', 'k'] enciphering t -> e\n", + "Wheels now ['a', 'b', 'l'] enciphering k -> t\n", + "Wheels now ['a', 'b', 'm'] enciphering z -> e\n", + "Wheels now ['a', 'b', 'n'] enciphering e -> c\n", + "Wheels now ['a', 'b', 'o'] enciphering b -> t\n", + "Wheels now ['a', 'b', 'p'] enciphering g -> e\n", + "Wheels now ['a', 'b', 'q'] enciphering h -> d\n", + "Wheels now ['a', 'b', 'r'] enciphering s -> b\n", + "Wheels now ['a', 'b', 's'] enciphering t -> y\n", + "Wheels now ['a', 'b', 't'] enciphering g -> b\n", + "Wheels now ['a', 'b', 'u'] enciphering y -> r\n", + "Wheels now ['a', 'b', 'v'] enciphering w -> i\n", + "Wheels now ['a', 'b', 'w'] enciphering d -> t\n", + "Wheels now ['a', 'b', 'x'] enciphering m -> i\n", + "Wheels now ['a', 'b', 'y'] enciphering p -> s\n", + "Wheels now ['a', 'b', 'z'] enciphering r -> h\n" + ] + }, + { + "data": { + "text/plain": [ + "('theyweredetectedbybritish', 'theyweredetectedbybritishshipsinclud')" + ] + }, + "execution_count": 95, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "tbt_enigma.encipher(target_ct, debug=True), target_pt" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('theyweredetectedbybritish', 'theyweredetectedbybritishshipsinclud')" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "tbt_enigma.encipher(target_ct), target_pt" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'mdtbjzuvielkawosqrpcghnxyf'" + ] + }, + "execution_count": 97, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(tbt_enigma.plugboard.forward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 99, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "tbt_enigma.left_wheel.position" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/enigma.ipynb b/enigma.ipynb index 06f684a..50d708f 100644 --- a/enigma.ipynb +++ b/enigma.ipynb @@ -4,17 +4,71 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\n", "# Enigma machine\n", - "Specification from [Codes and Ciphers](http://www.codesandciphers.org.uk/enigma/rotorspec.htm) page.\n", "\n", - "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", + "This is an implementation of an Enigma machine in Python. See below for links that describe the Enigma machine and how it was used.\n", "\n", - "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)." + "The Enigma machine has a bunch of components which can be swapped or modified to change its behaviour. The components are:\n", + "\n", + "* The plugboard\n", + "* The wheels (three chosen from a set of five)\n", + "* The reflector (two available, though generally not swapped)\n", + "\n", + "The plugboard and wheel selection were changed every day. The wheel orientation was changed every message.\n", + "\n", + "## Design sketch\n", + "Each of the components can be thought of as a \"letter transformer\", which take a letter and input and give a different letter as output. From a given setup (plugboard setting or wheel orientation), these transformations are deterministic: if nothing moves, the same letter input will give the same letter output. Depending on the component, forward and backward transformations can be different. For instance, the wheel I converts `a` to `e` forward, and `a` to `u` backward.\n", + "\n", + "This means we can take an object oriented approach to building the Enigma machine. The machine itself is a collection (aggregation) of components. Each component keeps track of its current state. \n", + "\n", + "The components have an inheritance hierarchy.\n", + "\n", + "* [LetterTransformer](#lettertransformer)\n", + " * [Plugobard](#plugboard)\n", + " * [Reflector](#reflector)\n", + " * [SimpleWheel](#simplewheel)\n", + " * [Wheel](#wheel)\n", + "\n", + "The `LetterTransformer` is the base class and defines the basic operations all the transformers apply. \n", + "\n", + "A `Plugboard` is a type of `LetterTransformer` that swaps only some letters, and acts the same both forward and backward. The `Reflector` acts like a `Plugboard` but with 13 pairs of swaps.\n", + "\n", + "A `SimpleWheel` has different forward and backward transforms, and also rotates. A `Wheel` is the same, but the indicator \"ring\" around the outside can be rotated around the core. This ring of a `Wheel` has a notch that can control when other `SimpleWheel`s and `Wheel`s are rotated in the Enigma.\n", + "\n", + "Note that all the logic of when the wheels rotate is controlled by the Enigma machine.\n", + "\n", + "* [Engima](#enigma)\n", + "* [Testing Enigma](#testingenigma)\n", + "\n", + "### Implmentation note\n", + "The normal way to define a class in Python is to define all the methods, class variables, and instance variables at the same time. However, that makes it difficult to place the discussion of the various methods and what they do near the definitions. \n", + "\n", + "This notebook takes a variant approach of defining the base class, then defining methods in separate cells and adding them to the class with the `setattr()` procedure.\n", + "\n", + "\n", + "## See also\n", + "* Specification from [Codes and Ciphers](http://www.codesandciphers.org.uk/enigma/rotorspec.htm) page.\n", + "\n", + "* 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", + "\n", + "* 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).\n", + "\n", + "* Enigma wiring from the [Crypto Museum](http://www.cryptomuseum.com/crypto/enigma/wiring.htm)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, some general-purpose and utility imports. \n", + "\n", + "`pos` and `unpos` convert between letters and numbers (in range 0-25 inclusive)." ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 108, "metadata": { "collapsed": true }, @@ -38,9 +92,16 @@ "def unpos(number): return chr(number % 26 + ord('a'))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The wheel specifications show what positions `a` to `z` (ignoring the ring) go to. For instance, Wheel 1 converts `a` to `e` forward, and `a` to `u` backward. The notch positions show where the wheel advance notches are on the wheel rings. The reflector specifications show the reflected pairs." + ] + }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 109, "metadata": { "collapsed": true }, @@ -57,14 +118,14 @@ "beta_wheel_spec = 'leyjvcnixwpbqmdrtakzgfuhos'\n", "gamma_wheel_spec = 'fsokanuerhmbtiycwlqpzxvgjd'\n", "\n", - "wheel_i_pegs = ['q']\n", - "wheel_ii_pegs = ['e']\n", - "wheel_iii_pegs = ['v']\n", - "wheel_iv_pegs = ['j']\n", - "wheel_v_pegs = ['z']\n", - "wheel_vi_pegs = ['z', 'm']\n", - "wheel_vii_pegs = ['z', 'm']\n", - "wheel_viii_pegs = ['z', 'm']\n", + "wheel_i_notches = ['q']\n", + "wheel_ii_notches = ['e']\n", + "wheel_iii_notches = ['v']\n", + "wheel_iv_notches = ['j']\n", + "wheel_v_notches = ['z']\n", + "wheel_vi_notches = ['z', 'm']\n", + "wheel_vii_notches = ['z', 'm']\n", + "wheel_viii_notches = ['z', 'm']\n", "\n", "reflector_b_spec = 'ay br cu dh eq fs gl ip jx kn mo tz vw'\n", "reflector_c_spec = 'af bv cp dj ei go hy kr lz mx nw tq su'" @@ -72,9 +133,85 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 110, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# class LetterTransformer(object):\n", + "# def __init__(self, specification, raw_transform=False):\n", + "# if raw_transform:\n", + "# transform = specification\n", + "# else:\n", + "# transform = self.parse_specification(specification)\n", + "# self.validate_transform(transform)\n", + "# self.make_transform_map(transform)\n", + " \n", + "# def parse_specification(self, specification):\n", + "# return list(zip(string.ascii_lowercase, clean(specification)))\n", + "# # return specification\n", + " \n", + "# def validate_transform(self, transform):\n", + "# \"\"\"A set of pairs, of from-to\"\"\"\n", + "# if len(transform) != 26:\n", + "# raise ValueError(\"Transform specification has {} pairs, requires 26\".\n", + "# format(len(transform)))\n", + "# for p in transform:\n", + "# if len(p) != 2:\n", + "# raise ValueError(\"Not all mappings in transform \"\n", + "# \"have two elements\")\n", + "# if len(set([p[0] for p in transform])) != 26:\n", + "# raise ValueError(\"Transform specification must list 26 origin letters\") \n", + "# if len(set([p[1] for p in transform])) != 26:\n", + "# raise ValueError(\"Transform specification must list 26 destination letters\") \n", + "\n", + "# def make_empty_transform(self):\n", + "# self.forward_map = [0] * 26\n", + "# self.backward_map = [0] * 26\n", + " \n", + "# def make_transform_map(self, transform):\n", + "# self.make_empty_transform()\n", + "# for p in transform:\n", + "# self.forward_map[pos(p[0])] = pos(p[1])\n", + "# self.backward_map[pos(p[1])] = pos(p[0])\n", + "# return self.forward_map, self.backward_map\n", + " \n", + "# def forward(self, letter):\n", + "# if letter in string.ascii_lowercase:\n", + "# return unpos(self.forward_map[pos(letter)])\n", + "# else:\n", + "# return ''\n", + " \n", + "# def backward(self, letter):\n", + "# if letter in string.ascii_lowercase:\n", + "# return unpos(self.backward_map[pos(letter)])\n", + "# else:\n", + "# return ''" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# Letter transformer\n", + "[Top](#top)\n", + "\n", + "A generic transformer of letters. All components in the Enigma are based on this. \n", + "\n", + "The transformer has two directions, `forward` and `backward`. In each direction, a given letter is transformed into a different letter. Both transformations are general permutations of the alphabet (i.e. each letter goes to one and only one new letter). There is no general requirement for the `forward` and `backward` transformations to have any particular relationship to each other (even though most do in the Enigma machine).\n", + "\n", + "When created, it must be given the transformation which should be applied. A raw transform is a sequence of letter pairs, such that `p[0]` is transformed to `p[1]` forwards, and `p[1]` goes to `p[0]` backwards.\n", + "\n", + "If the transform is not raw, it's assumed that the specification is a sequence of the `p[1]`s, and the standard alphabet gives the `p[0]`s." + ] + }, + { + "cell_type": "code", + "execution_count": 111, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -85,56 +222,200 @@ " else:\n", " transform = self.parse_specification(specification)\n", " self.validate_transform(transform)\n", - " self.make_transform_map(transform)\n", - " \n", - " def parse_specification(self, specification):\n", - " return list(zip(string.ascii_lowercase, clean(specification)))\n", - " # return specification\n", - " \n", - " def validate_transform(self, transform):\n", - " \"\"\"A set of pairs, of from-to\"\"\"\n", - " if len(transform) != 26:\n", - " raise ValueError(\"Transform specification has {} pairs, requires 26\".\n", - " format(len(transform)))\n", - " for p in transform:\n", - " if len(p) != 2:\n", - " raise ValueError(\"Not all mappings in transform \"\n", - " \"have two elements\")\n", - " if len(set([p[0] for p in transform])) != 26:\n", - " raise ValueError(\"Transform specification must list 26 origin letters\") \n", - " if len(set([p[1] for p in transform])) != 26:\n", - " raise ValueError(\"Transform specification must list 26 destination letters\") \n", - "\n", - " def make_empty_transform(self):\n", - " self.forward_map = [0] * 26\n", - " self.backward_map = [0] * 26\n", - " \n", - " def make_transform_map(self, transform):\n", - " self.make_empty_transform()\n", - " for p in transform:\n", - " self.forward_map[pos(p[0])] = pos(p[1])\n", - " self.backward_map[pos(p[1])] = pos(p[0])\n", - " return self.forward_map, self.backward_map\n", - " \n", - " def forward(self, letter):\n", - " if letter in string.ascii_lowercase:\n", - " return unpos(self.forward_map[pos(letter)])\n", - " else:\n", - " return ''\n", - " \n", - " def backward(self, letter):\n", - " if letter in string.ascii_lowercase:\n", - " return unpos(self.backward_map[pos(letter)])\n", - " else:\n", - " return ''" + " self.make_transform_map(transform)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Parse a specification: convert a string of destination letters into a list of pairs. " + ] + }, + { + "cell_type": "code", + "execution_count": 112, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def parse_specification(self, specification):\n", + " return list(zip(string.ascii_lowercase, clean(specification)))\n", + " # return specification\n", + "\n", + "setattr(LetterTransformer, \"parse_specification\", parse_specification)" + ] + }, + { + "cell_type": "code", + "execution_count": 113, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('a', 'e'),\n", + " ('b', 'k'),\n", + " ('c', 'm'),\n", + " ('d', 'f'),\n", + " ('e', 'l'),\n", + " ('f', 'g'),\n", + " ('g', 'd'),\n", + " ('h', 'q'),\n", + " ('i', 'v'),\n", + " ('j', 'z'),\n", + " ('k', 'n'),\n", + " ('l', 't'),\n", + " ('m', 'o'),\n", + " ('n', 'w'),\n", + " ('o', 'y'),\n", + " ('p', 'h'),\n", + " ('q', 'x'),\n", + " ('r', 'u'),\n", + " ('s', 's'),\n", + " ('t', 'p'),\n", + " ('u', 'a'),\n", + " ('v', 'i'),\n", + " ('w', 'b'),\n", + " ('x', 'r'),\n", + " ('y', 'c'),\n", + " ('z', 'j')]" + ] + }, + "execution_count": 113, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "parse_specification(None, wheel_i_spec)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Checks that a transform is valid." + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def validate_transform(self, transform):\n", + " \"\"\"A set of pairs, of from-to\"\"\"\n", + " if len(transform) != 26:\n", + " raise ValueError(\"Transform specification has {} pairs, requires 26\".\n", + " format(len(transform)))\n", + " for p in transform:\n", + " if len(p) != 2:\n", + " raise ValueError(\"Not all mappings in transform \"\n", + " \"have two elements\")\n", + " if len(set([p[0] for p in transform])) != 26:\n", + " raise ValueError(\"Transform specification must list 26 origin letters\") \n", + " if len(set([p[1] for p in transform])) != 26:\n", + " raise ValueError(\"Transform specification must list 26 destination letters\") \n", + "\n", + "setattr(LetterTransformer, \"validate_transform\", validate_transform) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The empty transform maps each letter to itself, forward and backward. A useful starting point for creating the maps needed.\n", + "\n", + "The forward and backward maps are `list`s of numbers (rather than `dict`s of letters to letters) to make the calculations easier when it comes to the wheels, and wheels with turnable indicator rings." + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# def make_empty_transform(self):\n", + "# self.forward_map = [0] * 26\n", + "# self.backward_map = [0] * 26\n", + "\n", + "# setattr(LetterTransformer, \"make_empty_transform\", make_empty_transform) " + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def make_empty_transform(self):\n", + " self.forward_map = list(range(26))\n", + " self.backward_map = list(range(26))\n", + "\n", + "setattr(LetterTransformer, \"make_empty_transform\", make_empty_transform) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Make the transform. Starting from an empty transform, mutate it to include the swaps. Note that the forward and backward swaps are stored separately. " + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def make_transform_map(self, transform):\n", + " self.make_empty_transform()\n", + " for p in transform:\n", + " self.forward_map[pos(p[0])] = pos(p[1])\n", + " self.backward_map[pos(p[1])] = pos(p[0])\n", + " return self.forward_map, self.backward_map\n", + "\n", + "setattr(LetterTransformer, \"make_transform_map\", make_transform_map)" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 118, "metadata": { - "collapsed": false + "collapsed": true }, + "outputs": [], + "source": [ + "def forward(self, letter):\n", + " if letter in string.ascii_lowercase:\n", + " return unpos(self.forward_map[pos(letter)])\n", + " else:\n", + " return ''\n", + "\n", + "def backward(self, letter):\n", + " if letter in string.ascii_lowercase:\n", + " return unpos(self.backward_map[pos(letter)])\n", + " else:\n", + " return ''\n", + "\n", + "setattr(LetterTransformer, \"forward\", forward)\n", + "setattr(LetterTransformer, \"backward\", backward) " + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, "outputs": [ { "data": { @@ -167,7 +448,7 @@ " ('y', 'z')]" ] }, - "execution_count": 4, + "execution_count": 119, "metadata": {}, "output_type": "execute_result" } @@ -179,10 +460,8 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, + "execution_count": 120, + "metadata": {}, "outputs": [ { "data": { @@ -190,7 +469,7 @@ "'zyxwcabdefghijklmnopqrstuv'" ] }, - "execution_count": 5, + "execution_count": 120, "metadata": {}, "output_type": "execute_result" } @@ -201,9 +480,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 121, "metadata": { - "collapsed": false, + "collapsed": true, "scrolled": true }, "outputs": [], @@ -213,9 +492,8 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 122, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -276,7 +554,7 @@ " 24])" ] }, - "execution_count": 7, + "execution_count": 122, "metadata": {}, "output_type": "execute_result" } @@ -290,9 +568,8 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 123, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -353,7 +630,7 @@ " 0])" ] }, - "execution_count": 8, + "execution_count": 123, "metadata": {}, "output_type": "execute_result" } @@ -369,10 +646,8 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, + "execution_count": 124, + "metadata": {}, "outputs": [ { "data": { @@ -380,7 +655,7 @@ "'zyxwcabdefghijklmnopqrstuv'" ] }, - "execution_count": 9, + "execution_count": 124, "metadata": {}, "output_type": "execute_result" } @@ -391,10 +666,8 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, + "execution_count": 125, + "metadata": {}, "outputs": [ { "data": { @@ -402,7 +675,7 @@ "'fgehijklmnopqrstuvwxyzdcba'" ] }, - "execution_count": 10, + "execution_count": 125, "metadata": {}, "output_type": "execute_result" } @@ -411,9 +684,20 @@ "cat(lt.backward(l) for l in string.ascii_lowercase)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Plugboard\n", + "[Top](#top)\n", + "\n", + "A `Plugboard` is a `LetterTransformer` that swaps some pairs of letters, and does the same swaps forward and backward." + ] + }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 126, "metadata": { "collapsed": true }, @@ -430,9 +714,9 @@ " raise ValueError(\"Not all mappings in transform\"\n", " \"have two elements\")\n", " \n", - " def make_empty_transform(self):\n", - " self.forward_map = list(range(26))\n", - " self.backward_map = list(range(26))\n", + "# def make_empty_transform(self):\n", + "# self.forward_map = list(range(26))\n", + "# self.backward_map = list(range(26))\n", " \n", " def make_transform_map(self, transform):\n", " expanded_transform = transform + [tuple(reversed(p)) for p in transform]\n", @@ -441,9 +725,9 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 127, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -452,10 +736,8 @@ }, { "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, + "execution_count": 128, + "metadata": {}, "outputs": [ { "data": { @@ -463,7 +745,7 @@ "'zycdefghijklmnopqrstuvwxba'" ] }, - "execution_count": 13, + "execution_count": 128, "metadata": {}, "output_type": "execute_result" } @@ -474,10 +756,8 @@ }, { "cell_type": "code", - "execution_count": 14, - "metadata": { - "collapsed": false - }, + "execution_count": 129, + "metadata": {}, "outputs": [ { "data": { @@ -485,7 +765,7 @@ "'zycdefghijklmnopqrstuvwxba'" ] }, - "execution_count": 14, + "execution_count": 129, "metadata": {}, "output_type": "execute_result" } @@ -496,9 +776,9 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 130, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -507,10 +787,8 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, + "execution_count": 131, + "metadata": {}, "outputs": [ { "data": { @@ -518,7 +796,7 @@ "('zycdefghijklmnopqrstuvwxba', 'zycdefghijklmnopqrstuvwxba')" ] }, - "execution_count": 16, + "execution_count": 131, "metadata": {}, "output_type": "execute_result" } @@ -529,10 +807,8 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, + "execution_count": 132, + "metadata": {}, "outputs": [ { "data": { @@ -540,7 +816,7 @@ "('ugcdypblnzkhmisfrqoxavwtej', 'ugcdypblnzkhmisfrqoxavwtej')" ] }, - "execution_count": 17, + "execution_count": 132, "metadata": {}, "output_type": "execute_result" } @@ -554,9 +830,20 @@ "cat(pb.forward(l) for l in string.ascii_lowercase), cat(pb.backward(l) for l in string.ascii_lowercase)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Reflector\n", + "[Top](#top)\n", + "\n", + "A `Reflector` is a `Plugboard` that takes exactly 13 pairs of letters to swap." + ] + }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 133, "metadata": { "collapsed": true }, @@ -578,10 +865,8 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, + "execution_count": 134, + "metadata": {}, "outputs": [ { "data": { @@ -601,7 +886,7 @@ " ('v', 'w')]" ] }, - "execution_count": 19, + "execution_count": 134, "metadata": {}, "output_type": "execute_result" } @@ -614,9 +899,9 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 135, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -629,10 +914,8 @@ }, { "cell_type": "code", - "execution_count": 21, - "metadata": { - "collapsed": false - }, + "execution_count": 136, + "metadata": {}, "outputs": [ { "data": { @@ -640,7 +923,7 @@ "'yruhqsldpxngokmiebfzcwvjat'" ] }, - "execution_count": 21, + "execution_count": 136, "metadata": {}, "output_type": "execute_result" } @@ -651,9 +934,9 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 137, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -662,10 +945,8 @@ }, { "cell_type": "code", - "execution_count": 23, - "metadata": { - "collapsed": false - }, + "execution_count": 138, + "metadata": {}, "outputs": [ { "data": { @@ -673,7 +954,7 @@ "'fvpjiaoyedrzxwgctkuqsbnmhl'" ] }, - "execution_count": 23, + "execution_count": 138, "metadata": {}, "output_type": "execute_result" } @@ -683,49 +964,122 @@ ] }, { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "collapsed": true - }, - "outputs": [], + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## SimpleWheel\n", + "[Top](#top)\n", + "\n", + "A `SimpleWheel` has different forward and backward maps, and also a position. The position is set with the `set_position` method (and initially in the creator), and the wheel can advance using the `advance` method. \n", + "\n", + "How the position is used is best explained with an example. The Enigma wheel 1, in the neutral position, transforms `a` to `e` (+4 letters) and `b` to `k` (+10 letters). When the wheel is in position `b` and an `a` in enciphered, it's the _second_ element of the map that's used, so `a` would be advanced 10 letters, to give `j`.\n", + "\n", + "This means that when using the letter transformation maps, you use the element in the map that's offset by the position of the wheel. When enciphering a `c`, you'd normally use transformation at position 2 in the map; if the wheel is in position 7, you'd instead use the transform at position 2 + 7 = 9 in the map.\n", + "\n", + "There are various modulus operators to keep the numbers in the requried range, meaning you can wrap around the map and around the wheel.\n", + "\n", + "Note the use of `__getattribute__` to give a more human-friendly version of the position without making it a method call. That allows you to write `wheel.position` and `wheel.position_l` and get the appropriate answers." + ] + }, + { + "cell_type": "code", + "execution_count": 139, + "metadata": { + "collapsed": true + }, + "outputs": [], "source": [ "class SimpleWheel(LetterTransformer):\n", " def __init__(self, transform, position='a', raw_transform=False):\n", " super(SimpleWheel, self).__init__(transform, raw_transform)\n", " self.set_position(position)\n", " \n", - " def __getattribute__(self,name):\n", + " def __getattribute__(self, name):\n", " if name=='position_l':\n", " return unpos(self.position)\n", " else:\n", - " return object.__getattribute__(self, name)\n", - " \n", - " def set_position(self, position):\n", - " self.position = ord(position) - ord('a')\n", - " \n", - " def forward(self, letter):\n", - " if letter in string.ascii_lowercase:\n", - " return unpos((self.forward_map[(pos(letter) + self.position) % 26] - self.position))\n", - " else:\n", - " return ''\n", - " \n", - " def backward(self, letter):\n", - " if letter in string.ascii_lowercase:\n", - " return unpos((self.backward_map[(pos(letter) + self.position) % 26] - self.position))\n", - " else:\n", - " return ''\n", + " return object.__getattribute__(self, name) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the wheel to a new position. Note that it expects a letter, not a number." + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def set_position(self, position):\n", + " self.position = ord(position) - ord('a')\n", + " \n", + "setattr(SimpleWheel, 'set_position', set_position) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Advance the wheel one step. Note that advancing beyond position 25 moves back to 0." + ] + }, + { + "cell_type": "code", + "execution_count": 141, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def advance(self):\n", + " self.position = (self.position + 1) % 26\n", + " return self.position\n", + "\n", + "setattr(SimpleWheel, 'advance', advance) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Do the encipherment forward and backward. Note how the map element to use is affected by the wheel position, and how the modulus wraps that map element around the wheel if needed." + ] + }, + { + "cell_type": "code", + "execution_count": 142, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def forward(self, letter):\n", + " if letter in string.ascii_lowercase:\n", + " return unpos((self.forward_map[(pos(letter) + self.position) % 26] - self.position))\n", + " else:\n", + " return ''\n", + "\n", + "def backward(self, letter):\n", + " if letter in string.ascii_lowercase:\n", + " return unpos((self.backward_map[(pos(letter) + self.position) % 26] - self.position))\n", + " else:\n", + " return ''\n", " \n", - " def advance(self):\n", - " self.position = (self.position + 1) % 26\n", - " return self.position" + "setattr(SimpleWheel, 'forward', forward) \n", + "setattr(SimpleWheel, 'backward', backward) " ] }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 143, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -760,7 +1114,7 @@ " ('z', 'j')]" ] }, - "execution_count": 25, + "execution_count": 143, "metadata": {}, "output_type": "execute_result" } @@ -772,9 +1126,9 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 144, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -786,18 +1140,84 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 145, "metadata": { - "collapsed": false + "scrolled": true }, "outputs": [ { "data": { "text/plain": [ - "('ekmflgdqvzntowyhxuspaibrcj', 'uwygadfpvzbeckmthxslrinqoj')" + "[4,\n", + " 10,\n", + " 12,\n", + " 5,\n", + " 11,\n", + " 6,\n", + " 3,\n", + " 16,\n", + " 21,\n", + " 25,\n", + " 13,\n", + " 19,\n", + " 14,\n", + " 22,\n", + " 24,\n", + " 7,\n", + " 23,\n", + " 20,\n", + " 18,\n", + " 15,\n", + " 0,\n", + " 8,\n", + " 1,\n", + " 17,\n", + " 2,\n", + " 9]" + ] + }, + "execution_count": 145, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel_1.forward_map" + ] + }, + { + "cell_type": "code", + "execution_count": 146, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'j'" + ] + }, + "execution_count": 146, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel_1.advance()\n", + "wheel_1.forward('a')" + ] + }, + { + "cell_type": "code", + "execution_count": 147, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('jlekfcpuymsnvxgwtrozhaqbid', 'vxfzceouyadbjlsgwrkqhmpnit')" ] }, - "execution_count": 27, + "execution_count": 147, "metadata": {}, "output_type": "execute_result" } @@ -808,18 +1228,16 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": { - "collapsed": false - }, + "execution_count": 148, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'a'" + "'b'" ] }, - "execution_count": 28, + "execution_count": 148, "metadata": {}, "output_type": "execute_result" } @@ -830,9 +1248,9 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 149, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -843,10 +1261,8 @@ }, { "cell_type": "code", - "execution_count": 30, - "metadata": { - "collapsed": false - }, + "execution_count": 150, + "metadata": {}, "outputs": [ { "data": { @@ -854,7 +1270,7 @@ "('ajdksiruxblhwtmcqgznpyfvoe', 'ajpczwrlfbdkotyuqgenhxmivs')" ] }, - "execution_count": 30, + "execution_count": 150, "metadata": {}, "output_type": "execute_result" } @@ -865,10 +1281,8 @@ }, { "cell_type": "code", - "execution_count": 31, - "metadata": { - "collapsed": false - }, + "execution_count": 151, + "metadata": {}, "outputs": [ { "data": { @@ -876,7 +1290,7 @@ "('bdfhjlcprtxvznyeiwgakmusqo', 'tagbpcsdqeufvnzhyixjwlrkom')" ] }, - "execution_count": 31, + "execution_count": 151, "metadata": {}, "output_type": "execute_result" } @@ -905,100 +1319,158 @@ "cat(wheel_3.forward(l) for l in string.ascii_lowercase), cat(wheel_3.backward(l) for l in string.ascii_lowercase)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Wheel\n", + "[Top](#top)\n", + "\n", + "This is the same as a `SimpleWheel`, but with the addition of a ring.\n", + "\n", + "The ring is moveable around the core of the wheel (with the wiring). This means that moving the ring changes the orientation of the core and wiring for the same setting.\n", + "\n", + "| Wheel with notch | Notch showing peg to hold it in place |\n", + "| ---------------- | ------------------------------------- |\n", + "| \"Enigma | \"Enigma |\n", + "| (From [Crypto museum](http://www.cryptomuseum.com/crypto/enigma/img/300879/035/full.jpg)) | From [Matematik Sider](http://www.matematiksider.dk/enigma/dtu_notch_big.jpg) |\n", + "\n", + "Though it's not very visible in the right hand image, the extra metal below the ring shows a spring-loaded peg on the wheel core which drops into the ring, with one hole per letter. The ring setting is where the peg drops into the ring.\n", + "\n", + "The notch setting is used in the full Enigma to control when the wheels step forward.\n", + "\n", + "Note that the constructor calls the superclass's constructor, then sets the positions properly with a call to `set_position`." + ] + }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 152, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ "class Wheel(SimpleWheel):\n", - " def __init__(self, transform, ring_peg_letters, ring_setting=1, position='a', raw_transform=False):\n", - " self.ring_peg_letters = ring_peg_letters\n", + " def __init__(self, transform, ring_notch_letters, ring_setting=1, position='a', raw_transform=False):\n", + " self.ring_notch_letters = ring_notch_letters\n", " self.ring_setting = ring_setting\n", " super(Wheel, self).__init__(transform, position=position, raw_transform=raw_transform)\n", - " self.set_position(position)\n", - " \n", - " def __getattribute__(self,name):\n", - " if name=='position_l':\n", - " return unpos(self.position + self.ring_setting - 1)\n", - " else:\n", - " return object.__getattribute__(self, name)\n", + " self.set_position(position)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `position` of the wheel is the orientation of the core. It's the same as the ring if the ring setting is 1. The `position_l` attribute is used to report the position of the ring letter, which is what the Enigma operator would see. " + ] + }, + { + "cell_type": "code", + "execution_count": 153, + "metadata": {}, + "outputs": [], + "source": [ + "def __getattribute__(self,name):\n", + " if name=='position_l':\n", + " return unpos(self.position + self.ring_setting - 1)\n", + " else:\n", + " return object.__getattribute__(self, name)\n", "\n", - " def set_position(self, position):\n", + "def set_position(self, position):\n", + "# self.position = (pos(position) - self.ring_setting + 1) % 26\n", + " if isinstance(position, str):\n", " self.position = (pos(position) - self.ring_setting + 1) % 26\n", - " # self.position_l = position\n", - " self.peg_positions = [(pos(p) - pos(position)) % 26 for p in self.ring_peg_letters]\n", + " else:\n", + " self.position = (position - self.ring_setting) % 26\n", + "# self.notch_positions = [(pos(position) - pos(p)) % 26 for p in self.ring_notch_letters]\n", + " self.notch_positions = [(self.position + self.ring_setting - 1 - pos(p)) % 26 for p in self.ring_notch_letters]\n", " \n", - " def advance(self):\n", - " super(Wheel, self).advance()\n", - " self.peg_positions = [(p - 1) % 26 for p in self.peg_positions]\n", - " # self.position_l = unpos(self.position + self.ring_setting - 1)\n", - " return self.position" + "setattr(Wheel, '__getattribute__', __getattribute__) \n", + "setattr(Wheel, 'set_position', set_position) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Advance the wheel. Again, note the superclass call, followed by the update of the notch positions." ] }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 154, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ - "wheel_3 = Wheel(wheel_iii_spec, wheel_iii_pegs, position='b', ring_setting=1)" + "def advance(self):\n", + " super(Wheel, self).advance()\n", + " self.notch_positions = [(p + 1) % 26 for p in self.notch_positions]\n", + " # self.position_l = unpos(self.position + self.ring_setting - 1)\n", + " return self.position\n", + " \n", + "setattr(Wheel, 'advance', advance) " ] }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 155, "metadata": { - "collapsed": false + "collapsed": true }, + "outputs": [], + "source": [ + "wheel_3 = Wheel(wheel_iii_spec, wheel_iii_notches, position='b', ring_setting=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 156, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "(1, [20])" + "(1, [6])" ] }, - "execution_count": 34, + "execution_count": 156, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "wheel_3.position, wheel_3.peg_positions" + "wheel_3.position, wheel_3.notch_positions" ] }, { "cell_type": "code", - "execution_count": 35, - "metadata": { - "collapsed": false - }, + "execution_count": 157, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "(25, [24, 11])" + "(25, [2, 15])" ] }, - "execution_count": 35, + "execution_count": 157, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "wheel_6 = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', ring_setting=3)\n", - "wheel_6.position, wheel_6.peg_positions" + "wheel_6 = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3)\n", + "wheel_6.position, wheel_6.notch_positions" ] }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 158, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -1006,166 +1478,252 @@ "name": "stdout", "output_type": "stream", "text": [ - "0 [23, 10]\n", - "1 [22, 9]\n", - "2 [21, 8]\n", - "3 [20, 7]\n", - "4 [19, 6]\n", - "5 [18, 5]\n", - "6 [17, 4]\n", - "7 [16, 3]\n", - "8 [15, 2]\n", - "9 [14, 1]\n", + "0 [3, 16]\n", + "1 [4, 17]\n", + "2 [5, 18]\n", + "3 [6, 19]\n", + "4 [7, 20]\n", + "5 [8, 21]\n", + "6 [9, 22]\n", + "7 [10, 23]\n", + "8 [11, 24]\n", + "9 [12, 25]\n", "10 [13, 0]\n", - "11 [12, 25]\n", - "12 [11, 24]\n", - "13 [10, 23]\n", - "14 [9, 22]\n", - "15 [8, 21]\n", - "16 [7, 20]\n", - "17 [6, 19]\n", - "18 [5, 18]\n", - "19 [4, 17]\n", - "20 [3, 16]\n", - "21 [2, 15]\n", - "22 [1, 14]\n", + "11 [14, 1]\n", + "12 [15, 2]\n", + "13 [16, 3]\n", + "14 [17, 4]\n", + "15 [18, 5]\n", + "16 [19, 6]\n", + "17 [20, 7]\n", + "18 [21, 8]\n", + "19 [22, 9]\n", + "20 [23, 10]\n", + "21 [24, 11]\n", + "22 [25, 12]\n", "23 [0, 13]\n", - "24 [25, 12]\n", - "25 [24, 11]\n", - "0 [23, 10]\n" + "24 [1, 14]\n", + "25 [2, 15]\n", + "0 [3, 16]\n" ] } ], "source": [ "for _ in range(27):\n", " wheel_6.advance()\n", - " print(wheel_6.position, wheel_6.peg_positions)" + " print(wheel_6.position, wheel_6.notch_positions)" + ] + }, + { + "cell_type": "code", + "execution_count": 159, + "metadata": {}, + "outputs": [], + "source": [ + "wheel = Wheel(wheel_iii_spec, wheel_iii_notches, position='b', \n", + " ring_setting=3)\n", + "wheel.set_position(12)\n", + "assert(wheel.position == 9)\n", + "assert(16 in wheel.notch_positions)\n", + "assert(wheel.position_l =='l')" + ] + }, + { + "cell_type": "code", + "execution_count": 160, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[16]" + ] + }, + "execution_count": 160, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel.notch_positions" + ] + }, + { + "cell_type": "code", + "execution_count": 161, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'l'" + ] + }, + "execution_count": 161, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel.position_l" ] }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 162, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ - "wheel_3 = Wheel(wheel_iii_spec, wheel_iii_pegs, position='b', ring_setting=1)\n", + "wheel_3 = Wheel(wheel_iii_spec, wheel_iii_notches, position='b', ring_setting=1)\n", "assert(wheel_3.position == 1)\n", - "assert(wheel_3.peg_positions == [20])\n", + "assert(wheel_3.notch_positions == [6])\n", "assert(wheel_3.position_l == 'b')\n", "wheel_3.advance()\n", "assert(wheel_3.position == 2)\n", - "assert(wheel_3.peg_positions == [19])\n", + "assert(wheel_3.notch_positions == [7])\n", "assert(wheel_3.position_l == 'c')" ] }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 163, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 15]" + ] + }, + "execution_count": 163, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wheel_6 = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3)\n", + "wheel_6.notch_positions" + ] + }, + { + "cell_type": "code", + "execution_count": 164, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ - "wheel_6 = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', ring_setting=3)\n", + "wheel_6 = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3)\n", "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'xkqhwpvngzrcfoiaselbtymjdu')\n", "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'ptlyrmidoxbswhnfckquzgeavj')\n", "assert(wheel_6.position == 25)\n", - "assert(11 in wheel_6.peg_positions)\n", - "assert(24 in wheel_6.peg_positions)\n", + "assert(2 in wheel_6.notch_positions)\n", + "assert(15 in wheel_6.notch_positions)\n", "assert(wheel_6.position_l == 'b')\n", "\n", "wheel_6.advance()\n", "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'jpgvoumfyqbenhzrdkasxlictw')\n", "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'skxqlhcnwarvgmebjptyfdzuio')\n", "assert(wheel_6.position == 0)\n", - "assert(10 in wheel_6.peg_positions)\n", - "assert(23 in wheel_6.peg_positions)\n", + "assert(3 in wheel_6.notch_positions)\n", + "assert(16 in wheel_6.notch_positions)\n", "assert(wheel_6.position_l == 'c')\n", "\n", "for _ in range(22): wheel_6.advance()\n", "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'mgxantkzsyqjcufirldvhoewbp')\n", "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'dymswobuplgraevzkqifntxcjh')\n", "assert(wheel_6.position == 22)\n", - "assert(1 in wheel_6.peg_positions)\n", - "assert(14 in wheel_6.peg_positions)\n", + "assert(25 in wheel_6.notch_positions)\n", + "assert(12 in wheel_6.notch_positions)\n", "assert(wheel_6.position_l == 'y')\n", "\n", "wheel_6.advance()\n", "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'fwzmsjyrxpibtehqkcugndvaol')\n", "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'xlrvnatokfqzduyjphemswbigc')\n", "assert(wheel_6.position == 23)\n", - "assert(0 in wheel_6.peg_positions)\n", - "assert(13 in wheel_6.peg_positions)\n", + "assert(0 in wheel_6.notch_positions)\n", + "assert(13 in wheel_6.notch_positions)\n", "assert(wheel_6.position_l == 'z')\n", "\n", "wheel_6.advance()\n", "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'vylrixqwohasdgpjbtfmcuznke')\n", "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'kqumzsnjepyctxiogdlrvahfbw')\n", "assert(wheel_6.position == 24)\n", - "assert(25 in wheel_6.peg_positions)\n", - "assert(12 in wheel_6.peg_positions)\n", + "assert(1 in wheel_6.notch_positions)\n", + "assert(14 in wheel_6.notch_positions)\n", "assert(wheel_6.position_l == 'a')\n", "\n", "wheel_6.advance()\n", "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'xkqhwpvngzrcfoiaselbtymjdu')\n", "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'ptlyrmidoxbswhnfckquzgeavj')\n", "assert(wheel_6.position == 25)\n", - "assert(24 in wheel_6.peg_positions)\n", - "assert(11 in wheel_6.peg_positions)\n", + "assert(2 in wheel_6.notch_positions)\n", + "assert(15 in wheel_6.notch_positions)\n", "assert(wheel_6.position_l == 'b')\n", "\n", "wheel_6.advance()\n", "assert(cat(wheel_6.forward(l) for l in string.ascii_lowercase) == 'jpgvoumfyqbenhzrdkasxlictw')\n", "assert(cat(wheel_6.backward(l) for l in string.ascii_lowercase) == 'skxqlhcnwarvgmebjptyfdzuio')\n", "assert(wheel_6.position == 0)\n", - "assert(23 in wheel_6.peg_positions)\n", - "assert(10 in wheel_6.peg_positions)\n", + "assert(3 in wheel_6.notch_positions)\n", + "assert(16 in wheel_6.notch_positions)\n", "assert(wheel_6.position_l == 'c')" ] }, { "cell_type": "code", - "execution_count": 39, - "metadata": { - "collapsed": false - }, + "execution_count": 165, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "(0, 'c', [23, 10])" + "(0, 'c', [3, 16])" ] }, - "execution_count": 39, + "execution_count": 165, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "wheel_6.position, wheel_6.position_l, wheel_6.peg_positions" + "wheel_6.position, wheel_6.position_l, wheel_6.notch_positions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Enigma\n", + "[Top](#top)\n", + "\n", + "This is the full Enigma machine.\n", + "\n", + "It's a collection of the various components defined above. There are three wheels (left, middle, and right), a plugboard, and a reflector.\n", + "\n", + "The `__getattribute__` method returns the state of the machine in friendly form, generally by asking the components to return the relevant attributes." ] }, { "cell_type": "code", - "execution_count": 40, - "metadata": { - "collapsed": true - }, + "execution_count": 167, + "metadata": {}, "outputs": [], "source": [ "class Enigma(object):\n", " def __init__(self, reflector_spec,\n", - " left_wheel_spec, left_wheel_pegs,\n", - " middle_wheel_spec, middle_wheel_pegs,\n", - " right_wheel_spec, right_wheel_pegs,\n", + " left_wheel_spec, left_wheel_notches,\n", + " middle_wheel_spec, middle_wheel_notches,\n", + " right_wheel_spec, right_wheel_notches,\n", " left_ring_setting, middle_ring_setting, right_ring_setting,\n", " plugboard_setting):\n", " self.reflector = Reflector(reflector_spec)\n", - " self.left_wheel = Wheel(left_wheel_spec, left_wheel_pegs, ring_setting=left_ring_setting)\n", - " self.middle_wheel = Wheel(middle_wheel_spec, middle_wheel_pegs, ring_setting=middle_ring_setting)\n", - " self.right_wheel = Wheel(right_wheel_spec, right_wheel_pegs, ring_setting=right_ring_setting)\n", + " self.left_wheel = Wheel(left_wheel_spec, left_wheel_notches, ring_setting=left_ring_setting)\n", + " self.middle_wheel = Wheel(middle_wheel_spec, middle_wheel_notches, ring_setting=middle_ring_setting)\n", + " self.right_wheel = Wheel(right_wheel_spec, right_wheel_notches, ring_setting=right_ring_setting)\n", " self.plugboard = Plugboard(plugboard_setting)\n", " \n", " def __getattribute__(self,name):\n", @@ -1173,74 +1731,166 @@ " return self.left_wheel.position, self.middle_wheel.position, self.right_wheel.position \n", " elif name=='wheel_positions_l':\n", " return self.left_wheel.position_l, self.middle_wheel.position_l, self.right_wheel.position_l \n", - " elif name=='peg_positions':\n", - " return self.left_wheel.peg_positions, self.middle_wheel.peg_positions, self.right_wheel.peg_positions\n", + " elif name=='notch_positions':\n", + " return (self.left_wheel.notch_positions, \n", + " self.middle_wheel.notch_positions, \n", + " self.right_wheel.notch_positions)\n", " else:\n", - " return object.__getattribute__(self, name)\n", - "\n", - " \n", - " def set_wheels(self, left_wheel_position, middle_wheel_position, right_wheel_position):\n", - " self.left_wheel.set_position(left_wheel_position)\n", - " self.middle_wheel.set_position(middle_wheel_position)\n", - " self.right_wheel.set_position(right_wheel_position)\n", - " \n", - " def lookup(self, letter):\n", - " a = self.plugboard.forward(letter)\n", - " b = self.right_wheel.forward(a)\n", - " c = self.middle_wheel.forward(b)\n", - " d = self.left_wheel.forward(c)\n", - " e = self.reflector.forward(d)\n", - " f = self.left_wheel.backward(e)\n", - " g = self.middle_wheel.backward(f)\n", - " h = self.right_wheel.backward(g)\n", - " i = self.plugboard.backward(h)\n", - " return i\n", - " \n", - " def advance(self):\n", - " advance_middle = False\n", - " advance_left = False\n", - " if 0 in self.right_wheel.peg_positions:\n", - " advance_middle = True\n", - " if 0 in self.middle_wheel.peg_positions:\n", - " advance_left = True\n", - " advance_middle = True\n", - " self.right_wheel.advance()\n", - " if advance_middle: self.middle_wheel.advance()\n", - " if advance_left: self.left_wheel.advance()\n", - " \n", - " def encipher_letter(self, letter):\n", - " self.advance()\n", - " return self.lookup(letter)\n", - " \n", - " def encipher(self, message):\n", - " enciphered = ''\n", - " for letter in clean(message):\n", - " enciphered += self.encipher_letter(letter)\n", - " return enciphered" + " return object.__getattribute__(self, name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the wheels to the initial positions. " + ] + }, + { + "cell_type": "code", + "execution_count": 168, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def set_wheels(self, left_wheel_position, middle_wheel_position, right_wheel_position):\n", + " self.left_wheel.set_position(left_wheel_position)\n", + " self.middle_wheel.set_position(middle_wheel_position)\n", + " self.right_wheel.set_position(right_wheel_position)\n", + "\n", + "setattr(Enigma, 'set_wheels', set_wheels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`lookup` just follows a path through the machine without changing the positions of any parts. It just follows a signal from the input, thorough all the components, to the reflector, back through all the components, to the output." + ] + }, + { + "cell_type": "code", + "execution_count": 169, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def lookup(self, letter):\n", + " a = self.plugboard.forward(letter)\n", + " b = self.right_wheel.forward(a)\n", + " c = self.middle_wheel.forward(b)\n", + " d = self.left_wheel.forward(c)\n", + " e = self.reflector.forward(d)\n", + " f = self.left_wheel.backward(e)\n", + " g = self.middle_wheel.backward(f)\n", + " h = self.right_wheel.backward(g)\n", + " i = self.plugboard.backward(h)\n", + " return i\n", + "\n", + "setattr(Enigma, 'lookup', lookup)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`advance` moves the wheels on one step. The right wheel always advances. If the notch is in the zero position, the wheel also advances the wheel to the left. \n", + "\n", + "It follows the 'double stepping' behaviour of the engima machines." + ] + }, + { + "cell_type": "code", + "execution_count": 170, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def advance(self):\n", + " advance_middle = False\n", + " advance_left = False\n", + " if 0 in self.right_wheel.notch_positions:\n", + " advance_middle = True\n", + " if 0 in self.middle_wheel.notch_positions:\n", + " advance_left = True\n", + " advance_middle = True\n", + " self.right_wheel.advance()\n", + " if advance_middle: self.middle_wheel.advance()\n", + " if advance_left: self.left_wheel.advance()\n", + "\n", + "setattr(Enigma, 'advance', advance) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, encipher letters and messages. \n", + "\n", + "Note that the wheels advance _before_ the letter signal is sent through the machine: in the physical machine, the advancing is done by pressing the key on the keyboard. \n", + "\n", + "Also note that the messages are cleaned before use, so letters are converted to lower case and non-letters are removed." + ] + }, + { + "cell_type": "code", + "execution_count": 220, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def encipher_letter(self, letter):\n", + " self.advance()\n", + " return self.lookup(letter)\n", + "\n", + "def encipher(self, message, debug=False):\n", + " enciphered = ''\n", + " for letter in clean(message):\n", + " enciphered += self.encipher_letter(letter)\n", + " if debug:\n", + " print('Wheels now', list(self.wheel_positions_l), 'enciphering {} -> {}'.format(letter, self.lookup(letter)))\n", + " return enciphered\n", + "\n", + "setattr(Enigma, 'encipher_letter', encipher_letter)\n", + "setattr(Enigma, 'encipher', encipher)\n", + "setattr(Enigma, 'decipher', encipher)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Testing Enigma\n", + "[Top](#top)\n", + "\n", + "Some tests of the Enigma machine." ] }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 172, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ "enigma = Enigma(reflector_b_spec, \n", - " wheel_i_spec, wheel_i_pegs,\n", - " wheel_ii_spec, wheel_ii_pegs,\n", - " wheel_iii_spec, wheel_iii_pegs,\n", + " wheel_i_spec, wheel_i_notches,\n", + " wheel_ii_spec, wheel_ii_notches,\n", + " wheel_iii_spec, wheel_iii_notches,\n", " 1, 1, 1,\n", " '')" ] }, { "cell_type": "code", - "execution_count": 42, - "metadata": { - "collapsed": false - }, + "execution_count": 173, + "metadata": {}, "outputs": [ { "data": { @@ -1248,7 +1898,7 @@ "'u'" ] }, - "execution_count": 42, + "execution_count": 173, "metadata": {}, "output_type": "execute_result" } @@ -1259,10 +1909,8 @@ }, { "cell_type": "code", - "execution_count": 43, - "metadata": { - "collapsed": false - }, + "execution_count": 174, + "metadata": {}, "outputs": [ { "data": { @@ -1270,7 +1918,7 @@ "'a'" ] }, - "execution_count": 43, + "execution_count": 174, "metadata": {}, "output_type": "execute_result" } @@ -1281,10 +1929,8 @@ }, { "cell_type": "code", - "execution_count": 44, - "metadata": { - "collapsed": false - }, + "execution_count": 175, + "metadata": {}, "outputs": [ { "data": { @@ -1292,7 +1938,7 @@ "'uejobtpzwcnsrkdgvmlfaqiyxh'" ] }, - "execution_count": 44, + "execution_count": 175, "metadata": {}, "output_type": "execute_result" } @@ -1303,9 +1949,39 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 176, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'abcdefghijklmnopqrstuvwxyz'" + ] + }, + "execution_count": 176, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(enigma.lookup(enigma.lookup(l)) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 177, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "assert(cat(enigma.lookup(enigma.lookup(l)) for l in string.ascii_lowercase) == string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 178, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -1313,50 +1989,58 @@ "name": "stdout", "output_type": "stream", "text": [ - "0 :: a a a ; [16] [4] [21] uejobtpzwcnsrkdgvmlfaqiyxh\n", - "1 :: a a b ; [16] [4] [20] baqmfexihswpdytlcvjozrkgnu\n", - "2 :: a a c ; [16] [4] [19] djralkwpobfeyqihncxzvugsmt\n", - "3 :: a a d ; [16] [4] [18] zlejcuitgdmbkonsvxphfqyrwa\n", - "4 :: a a e ; [16] [4] [17] gcblwtakqzhdosmxiunfryepvj\n", - "5 :: a a f ; [16] [4] [16] osnirgfmdpvuhcajwebxlkqtzy\n", - "6 :: a a g ; [16] [4] [15] wymvnqzjlhoicekuftxrpdasbg\n", - "7 :: a a h ; [16] [4] [14] cjafkdztpbeuormiwnvhlsqyxg\n", - "8 :: a a i ; [16] [4] [13] xijuyslvbczgnmqwotfrdhpaek\n", - "9 :: a a j ; [16] [4] [12] lfzrwbytjisaovmuxdkhpneqgc\n", - "10 :: a a k ; [16] [4] [11] tkezcqynuwbpvhslfxoaimjrgd\n", - "11 :: a a l ; [16] [4] [10] kiwfnduxbsaotelqpvjmgrchzy\n", - "12 :: a a m ; [16] [4] [9] sfkutbpoxycrnmhgwlaedzqijv\n", - "13 :: a a n ; [16] [4] [8] baqwlkhgrsfextpocijnvudmzy\n", - "14 :: a a o ; [16] [4] [7] teofbdzxqkjyrscvimnawpuhlg\n", - "15 :: a a p ; [16] [4] [6] mhypswrbzxqvaondkgeutlfjci\n", - "16 :: a a q ; [16] [4] [5] cpasnrhgkuixzevbyfdwjotlqm\n", - "17 :: a a r ; [16] [4] [4] dlfatcjwygvbnmzrxpueskhqio\n", - "18 :: a a s ; [16] [4] [3] lxymzjuqtfpadsrkhonigwvbce\n", - "19 :: a a t ; [16] [4] [2] puvioztjdhxmlyeawsrgbcqknf\n", - "20 :: a a u ; [16] [4] [1] baigpldqcowfyzjehvtsxrkumn\n", - "21 :: a a v ; [16] [4] [0] mnvfydiwgzsoablrxpkutchqej\n", - "22 :: a b w ; [16] [3] [25] ulfopcykswhbzvderqixanjtgm\n", - "23 :: a b x ; [16] [3] [24] qmwftdyovursbzhxaklejicpgn\n", - "24 :: a b y ; [16] [3] [23] oljmzxrvucybdqasngpwihtfke\n", - "25 :: a b z ; [16] [3] [22] fwevcalzxutgysrqponkjdbimh\n" + "0 :: a a a ; [10] [22] [5] uejobtpzwcnsrkdgvmlfaqiyxh\n", + "1 :: a a b ; [10] [22] [6] baqmfexihswpdytlcvjozrkgnu\n", + "2 :: a a c ; [10] [22] [7] djralkwpobfeyqihncxzvugsmt\n", + "3 :: a a d ; [10] [22] [8] zlejcuitgdmbkonsvxphfqyrwa\n", + "4 :: a a e ; [10] [22] [9] gcblwtakqzhdosmxiunfryepvj\n", + "5 :: a a f ; [10] [22] [10] osnirgfmdpvuhcajwebxlkqtzy\n", + "6 :: a a g ; [10] [22] [11] wymvnqzjlhoicekuftxrpdasbg\n", + "7 :: a a h ; [10] [22] [12] cjafkdztpbeuormiwnvhlsqyxg\n", + "8 :: a a i ; [10] [22] [13] xijuyslvbczgnmqwotfrdhpaek\n", + "9 :: a a j ; [10] [22] [14] lfzrwbytjisaovmuxdkhpneqgc\n", + "10 :: a a k ; [10] [22] [15] tkezcqynuwbpvhslfxoaimjrgd\n", + "11 :: a a l ; [10] [22] [16] kiwfnduxbsaotelqpvjmgrchzy\n", + "12 :: a a m ; [10] [22] [17] sfkutbpoxycrnmhgwlaedzqijv\n", + "13 :: a a n ; [10] [22] [18] baqwlkhgrsfextpocijnvudmzy\n", + "14 :: a a o ; [10] [22] [19] teofbdzxqkjyrscvimnawpuhlg\n", + "15 :: a a p ; [10] [22] [20] mhypswrbzxqvaondkgeutlfjci\n", + "16 :: a a q ; [10] [22] [21] cpasnrhgkuixzevbyfdwjotlqm\n", + "17 :: a a r ; [10] [22] [22] dlfatcjwygvbnmzrxpueskhqio\n", + "18 :: a a s ; [10] [22] [23] lxymzjuqtfpadsrkhonigwvbce\n", + "19 :: a a t ; [10] [22] [24] puvioztjdhxmlyeawsrgbcqknf\n", + "20 :: a a u ; [10] [22] [25] baigpldqcowfyzjehvtsxrkumn\n", + "21 :: a a v ; [10] [22] [0] mnvfydiwgzsoablrxpkutchqej\n", + "22 :: a b w ; [10] [23] [1] ulfopcykswhbzvderqixanjtgm\n", + "23 :: a b x ; [10] [23] [2] qmwftdyovursbzhxaklejicpgn\n", + "24 :: a b y ; [10] [23] [3] oljmzxrvucybdqasngpwihtfke\n", + "25 :: a b z ; [10] [23] [4] fwevcalzxutgysrqponkjdbimh\n" ] } ], "source": [ + "# check the middle wheel turns over\n", "enigma.set_wheels('a', 'a', 'a')\n", "for i in range(26):\n", " print(i, '::', \n", " enigma.left_wheel.position_l, enigma.middle_wheel.position_l, enigma.right_wheel.position_l, ';',\n", - " enigma.left_wheel.peg_positions, enigma.middle_wheel.peg_positions, enigma.right_wheel.peg_positions, \n", + " enigma.left_wheel.notch_positions, enigma.middle_wheel.notch_positions, enigma.right_wheel.notch_positions, \n", " cat(enigma.lookup(l) for l in string.ascii_lowercase))\n", " enigma.advance()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Formal test of middle wheel turnover" + ] + }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 179, "metadata": { - "collapsed": false, + "collapsed": true, "scrolled": true }, "outputs": [], @@ -1364,45 +2048,51 @@ "enigma.set_wheels('a', 'a', 't')\n", "assert(enigma.wheel_positions == (0, 0, 19))\n", "assert(cat(enigma.wheel_positions_l) == 'aat')\n", - "assert(enigma.peg_positions == ([16], [4], [2]))\n", + "assert(enigma.notch_positions == ([10], [22], [24]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'puvioztjdhxmlyeawsrgbcqknf')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (0, 0, 20))\n", "assert(cat(enigma.wheel_positions_l) == 'aau')\n", - "assert(enigma.peg_positions == ([16], [4], [1]))\n", + "assert(enigma.notch_positions == ([10], [22], [25]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'baigpldqcowfyzjehvtsxrkumn')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (0, 0, 21))\n", "assert(cat(enigma.wheel_positions_l) == 'aav')\n", - "assert(enigma.peg_positions == ([16], [4], [0]))\n", + "assert(enigma.notch_positions == ([10], [22], [0]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mnvfydiwgzsoablrxpkutchqej')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (0, 1, 22))\n", "assert(cat(enigma.wheel_positions_l) == 'abw')\n", - "assert(enigma.peg_positions == ([16], [3], [25]))\n", + "assert(enigma.notch_positions == ([10], [23], [1]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ulfopcykswhbzvderqixanjtgm')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (0, 1, 23))\n", "assert(cat(enigma.wheel_positions_l) == 'abx')\n", - "assert(enigma.peg_positions == ([16], [3], [24]))\n", + "assert(enigma.notch_positions == ([10], [23], [2]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qmwftdyovursbzhxaklejicpgn')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (0, 1, 24))\n", "assert(cat(enigma.wheel_positions_l) == 'aby')\n", - "assert(enigma.peg_positions == ([16], [3], [23]))\n", + "assert(enigma.notch_positions == ([10], [23 ], [3]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'oljmzxrvucybdqasngpwihtfke')\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Test of middle wheel advancing the left wheel, exhibiting the \"double step\" behaviour." + ] + }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 180, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -1410,7 +2100,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "(1, 5, 24) ('b', 'f', 'y') ([15], [25], [23]) baknstqzrmcxjdvygiefwoulph\n" + "(1, 5, 24) ('b', 'f', 'y') ([11], [1], [3]) baknstqzrmcxjdvygiefwoulph\n" ] } ], @@ -1418,49 +2108,47 @@ "enigma.set_wheels('a', 'd', 't')\n", "assert(enigma.wheel_positions == (0, 3, 19))\n", "assert(cat(enigma.wheel_positions_l) == 'adt')\n", - "assert(enigma.peg_positions == ([16], [1], [2]))\n", + "assert(enigma.notch_positions == ([10], [25], [24]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'zcbpqxwsjiuonmldethrkygfva')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (0, 3, 20))\n", "assert(cat(enigma.wheel_positions_l) == 'adu')\n", - "assert(enigma.peg_positions == ([16], [1], [1]))\n", + "assert(enigma.notch_positions == ([10], [25], [25]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ehprawjbngotxikcsdqlzyfmvu')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (0, 3, 21))\n", "assert(cat(enigma.wheel_positions_l) == 'adv')\n", - "assert(enigma.peg_positions == ([16], [1], [0]))\n", + "assert(enigma.notch_positions == ([10], [25], [0]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'eqzxarpihmnvjkwgbfuyslodtc')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (0, 4, 22))\n", "assert(cat(enigma.wheel_positions_l) == 'aew')\n", - "assert(enigma.peg_positions == ([16], [0], [25]))\n", + "assert(enigma.notch_positions == ([10], [0], [1]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qedcbtpluzmhkongavwfirsyxj')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 23))\n", "assert(cat(enigma.wheel_positions_l) == 'bfx')\n", - "assert(enigma.peg_positions == ([15], [25], [24]))\n", + "assert(enigma.notch_positions == ([11], [1], [2]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'iwuedhsfazqxytvrkpgncoblmj')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 24))\n", "assert(cat(enigma.wheel_positions_l) == 'bfy')\n", - "assert(enigma.peg_positions == ([15], [25], [23]))\n", + "assert(enigma.notch_positions == ([11], [1], [3]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'baknstqzrmcxjdvygiefwoulph')\n", "\n", - "print(enigma.wheel_positions, enigma.wheel_positions_l, enigma.peg_positions, \n", + "print(enigma.wheel_positions, enigma.wheel_positions_l, enigma.notch_positions, \n", " cat(enigma.lookup(l) for l in string.ascii_lowercase))\n" ] }, { "cell_type": "code", - "execution_count": 48, - "metadata": { - "collapsed": false - }, + "execution_count": 181, + "metadata": {}, "outputs": [ { "data": { @@ -1468,7 +2156,7 @@ "'olpfhnvflyn'" ] }, - "execution_count": 48, + "execution_count": 181, "metadata": {}, "output_type": "execute_result" } @@ -1482,10 +2170,8 @@ }, { "cell_type": "code", - "execution_count": 49, - "metadata": { - "collapsed": false - }, + "execution_count": 182, + "metadata": {}, "outputs": [ { "data": { @@ -1493,7 +2179,7 @@ "'lawnjgpwjik'" ] }, - "execution_count": 49, + "execution_count": 182, "metadata": {}, "output_type": "execute_result" } @@ -1507,192 +2193,188 @@ }, { "cell_type": "code", - "execution_count": 50, - "metadata": { - "collapsed": false - }, + "execution_count": 183, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 3, 20))\n", + "assert(cat(enigma.wheel_positions_l) == 'adu')\n", + "assert(enigma.notch_positions == ([10], [25], [25]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ehprawjbngotxikcsdqlzyfmvu')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 3, 21))\n", + "assert(cat(enigma.wheel_positions_l) == 'adv')\n", + "assert(enigma.notch_positions == ([10], [25], [0]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'eqzxarpihmnvjkwgbfuyslodtc')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (0, 4, 22))\n", + "assert(cat(enigma.wheel_positions_l) == 'aew')\n", + "assert(enigma.notch_positions == ([10], [0], [1]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qedcbtpluzmhkongavwfirsyxj')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 23))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfx')\n", + "assert(enigma.notch_positions == ([11], [1], [2]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'iwuedhsfazqxytvrkpgncoblmj')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 24))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfy')\n", + "assert(enigma.notch_positions == ([11], [1], [3]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'baknstqzrmcxjdvygiefwoulph')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 25))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfz')\n", + "assert(enigma.notch_positions == ([11], [1], [4]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mudcgteyjiwravxzslqfbnkohp')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 0))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfa')\n", + "assert(enigma.notch_positions == ([11], [1], [5]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'gjkuotarmbcziwesvhpfdqnyxl')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 1))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfb')\n", + "assert(enigma.notch_positions == ([11], [1], [6]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'fcbmpaqihxytdrvegnwlzosjku')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 2))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfc')\n", + "assert(enigma.notch_positions == ([11], [1], [7]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'jktrlpmywabegzqfodxcvuishn')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 3))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfd')\n", + "assert(enigma.notch_positions == ([11], [1], [8]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'baetclivgurfzqponkxdjhyswm')\n", + "\n", + "enigma.advance()\n", + "assert(enigma.wheel_positions == (1, 5, 4))\n", + "assert(cat(enigma.wheel_positions_l) == 'bfe')\n", + "assert(enigma.notch_positions == ([11], [1], [9]))\n", + "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'wvjlkpzxtcedqsyfmunirbahog')\n", + "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 5))\n", "assert(cat(enigma.wheel_positions_l) == 'bff')\n", - "assert(enigma.peg_positions == ([15], [25], [16]))\n", + "assert(enigma.notch_positions == ([11], [1], [10]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'zpqiogfsdlmjkyebcvhxwrutna')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 6))\n", "assert(cat(enigma.wheel_positions_l) == 'bfg')\n", - "assert(enigma.peg_positions == ([15], [25], [15]))\n", + "assert(enigma.notch_positions == ([11], [1], [11]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'fjmnwayslbxicdpouthrqzekgv')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 7))\n", "assert(cat(enigma.wheel_positions_l) == 'bfh')\n", - "assert(enigma.peg_positions == ([15], [25], [14]))\n", + "assert(enigma.notch_positions == ([11], [1], [12]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'csafzdyloxuhnmitwvbpkrqjge')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 8))\n", "assert(cat(enigma.wheel_positions_l) == 'bfi')\n", - "assert(enigma.peg_positions == ([15], [25], [13]))\n", + "assert(enigma.notch_positions == ([11], [1], [13]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'kihyvulcbtagwrqzonxjfemsdp')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 9))\n", "assert(cat(enigma.wheel_positions_l) == 'bfj')\n", - "assert(enigma.peg_positions == ([15], [25], [12]))\n", + "assert(enigma.notch_positions == ([11], [1], [14]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pgzrytbksqhwxvuajdifonlmec')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 10))\n", "assert(cat(enigma.wheel_positions_l) == 'bfk')\n", - "assert(enigma.peg_positions == ([15], [25], [11]))\n", + "assert(enigma.notch_positions == ([11], [1], [15]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'fkirsazncwbvyhpoudexqljtmg')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 11))\n", "assert(cat(enigma.wheel_positions_l) == 'bfl')\n", - "assert(enigma.peg_positions == ([15], [25], [10]))\n", + "assert(enigma.notch_positions == ([11], [1], [16]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mhkronubsvctafeqpdilgjxwzy')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 12))\n", "assert(cat(enigma.wheel_positions_l) == 'bfm')\n", - "assert(enigma.peg_positions == ([15], [25], [9]))\n", + "assert(enigma.notch_positions == ([11], [1], [17]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'gnkuoxarzycmlbetvhwpdqsfji')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 13))\n", "assert(cat(enigma.wheel_positions_l) == 'bfn')\n", - "assert(enigma.peg_positions == ([15], [25], [8]))\n", + "assert(enigma.notch_positions == ([11], [1], [18]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'bainslqkcxhfudpogtermwvjzy')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 14))\n", "assert(cat(enigma.wheel_positions_l) == 'bfo')\n", - "assert(enigma.peg_positions == ([15], [25], [7]))\n", + "assert(enigma.notch_positions == ([11], [1], [19]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xemfbdnwjitycgzusvqkprhalo')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 15))\n", "assert(cat(enigma.wheel_positions_l) == 'bfp')\n", - "assert(enigma.peg_positions == ([15], [25], [6]))\n", + "assert(enigma.notch_positions == ([11], [1], [20]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qixksmhgbtdvfonrapejwluczy')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 16))\n", "assert(cat(enigma.wheel_positions_l) == 'bfq')\n", - "assert(enigma.peg_positions == ([15], [25], [5]))\n", + "assert(enigma.notch_positions == ([11], [1], [21]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cgaulmbskwiefrtzynhodxjvqp')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 17))\n", "assert(cat(enigma.wheel_positions_l) == 'bfr')\n", - "assert(enigma.peg_positions == ([15], [25], [4]))\n", + "assert(enigma.notch_positions == ([11], [1], [22]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'iwqfldszaxvenmyrcpgutkbjoh')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 18))\n", "assert(cat(enigma.wheel_positions_l) == 'bfs')\n", - "assert(enigma.peg_positions == ([15], [25], [3]))\n", + "assert(enigma.notch_positions == ([11], [1], [23]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'vxykrjilgfdhqtusmepnoazbcw')\n", "\n", "enigma.advance()\n", "assert(enigma.wheel_positions == (1, 5, 19))\n", "assert(cat(enigma.wheel_positions_l) == 'bft')\n", - "assert(enigma.peg_positions == ([15], [25], [2]))\n", + "assert(enigma.notch_positions == ([11], [1], [24]))\n", "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ieysbvkjahgmlpxnwtdrzfqocu')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 5, 20))\n", - "assert(cat(enigma.wheel_positions_l) == 'bfu')\n", - "assert(enigma.peg_positions == ([15], [25], [1]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'baihkjvdcfepywsltxoqzgnrmu')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 5, 21))\n", - "assert(cat(enigma.wheel_positions_l) == 'bfv')\n", - "assert(enigma.peg_positions == ([15], [25], [0]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'bayjtrilgdshvzuwxfkeompqcn')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 6, 22))\n", - "assert(cat(enigma.wheel_positions_l) == 'bgw')\n", - "assert(enigma.peg_positions == ([15], [24], [25]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'rszqohpfxyutvwegdablkmnijc')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 6, 23))\n", - "assert(cat(enigma.wheel_positions_l) == 'bgx')\n", - "assert(enigma.peg_positions == ([15], [24], [24]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nfoxhbzeyrwqpacmljtsvukdig')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 6, 24))\n", - "assert(cat(enigma.wheel_positions_l) == 'bgy')\n", - "assert(enigma.peg_positions == ([15], [24], [23]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'czaogmeihtuqfsdxlwnjkyrpvb')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 6, 25))\n", - "assert(cat(enigma.wheel_positions_l) == 'bgz')\n", - "assert(enigma.peg_positions == ([15], [24], [22]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'omwgysdjkhizbxarupfvqtcnel')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 6, 0))\n", - "assert(cat(enigma.wheel_positions_l) == 'bga')\n", - "assert(enigma.peg_positions == ([15], [24], [21]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cxafmdrzoqutepinjgvlksybwh')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 6, 1))\n", - "assert(cat(enigma.wheel_positions_l) == 'bgb')\n", - "assert(enigma.peg_positions == ([15], [24], [20]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'jymvnrxkoahwceiuzftspdlgbq')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 6, 2))\n", - "assert(cat(enigma.wheel_positions_l) == 'bgc')\n", - "assert(enigma.peg_positions == ([15], [24], [19]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'uzlyiqwrestcnmxvfhjkapgodb')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 6, 3))\n", - "assert(cat(enigma.wheel_positions_l) == 'bgd')\n", - "assert(enigma.peg_positions == ([15], [24], [18]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'veosbuhgpzqynmcikwdxfartlj')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (1, 6, 4))\n", - "assert(cat(enigma.wheel_positions_l) == 'bge')\n", - "assert(enigma.peg_positions == ([15], [24], [17]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ydhbmtrclxsiezpougkfqwvjan')\n", "\n" ] } ], "source": [ - "\n", + "enigma.set_wheels('a', 'd', 't')\n", "for i in range(26):\n", " enigma.advance()\n", " print('enigma.advance()')\n", " print(\"assert(enigma.wheel_positions == {})\".format(enigma.wheel_positions))\n", " print(\"assert(cat(enigma.wheel_positions_l) == '{}')\".format(cat(enigma.wheel_positions_l)))\n", - " print(\"assert(enigma.peg_positions == {})\".format(enigma.peg_positions))\n", + " print(\"assert(enigma.notch_positions == {})\".format(enigma.notch_positions))\n", " print(\"assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == '{}')\".format(cat(enigma.lookup(l) for l in string.ascii_lowercase)))\n", " print()" ] }, { "cell_type": "code", - "execution_count": 51, - "metadata": { - "collapsed": false - }, + "execution_count": 184, + "metadata": {}, "outputs": [ { "data": { @@ -1700,7 +2382,7 @@ "'bahxvfrpdc'" ] }, - "execution_count": 51, + "execution_count": 184, "metadata": {}, "output_type": "execute_result" } @@ -1714,10 +2396,8 @@ }, { "cell_type": "code", - "execution_count": 52, - "metadata": { - "collapsed": false - }, + "execution_count": 185, + "metadata": {}, "outputs": [ { "data": { @@ -1725,7 +2405,7 @@ "'kvmmwrlqlqsqpeugjrcxzwpfyiyybwloewrouvkpoztceuwtfjzqwpbqldttsr'" ] }, - "execution_count": 52, + "execution_count": 185, "metadata": {}, "output_type": "execute_result" } @@ -1742,10 +2422,8 @@ }, { "cell_type": "code", - "execution_count": 53, - "metadata": { - "collapsed": false - }, + "execution_count": 186, + "metadata": {}, "outputs": [ { "data": { @@ -1753,7 +2431,7 @@ "'c'" ] }, - "execution_count": 53, + "execution_count": 186, "metadata": {}, "output_type": "execute_result" } @@ -1764,7 +2442,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 187, "metadata": { "collapsed": true }, @@ -1774,455 +2452,1051 @@ "# Enigma simulation settings are \n", "# http://enigma.louisedade.co.uk/enigma.html?m3;b;b153;AFTX;AJFE;AU-BG-EY-FP-HL-IN-JZ-OS-QR-TX\n", "w_enigma = Enigma(reflector_b_spec, \n", - " wheel_i_spec, wheel_i_pegs,\n", - " wheel_v_spec, wheel_v_pegs,\n", - " wheel_iii_spec, wheel_iii_pegs,\n", + " wheel_i_spec, wheel_i_notches,\n", + " wheel_v_spec, wheel_v_notches,\n", + " wheel_iii_spec, wheel_iii_notches,\n", " 6, 20, 24,\n", " 'ua pf rq so ni ey bg hl tx zj')" ] }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 188, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "# Setting sheet line 31 from http://www.codesandciphers.org.uk/enigma/enigma3.htm\n", - "# Enigma simulation settings are \n", - "# http://enigma.louisedade.co.uk/enigma.html?m3;b;b153;AFTX;AJFE;AU-BG-EY-FP-HL-IN-JZ-OS-QR-TX\n", - "enigma = Enigma(reflector_b_spec, \n", - " wheel_i_spec, wheel_i_pegs,\n", - " wheel_v_spec, wheel_v_pegs,\n", - " wheel_iii_spec, wheel_iii_pegs,\n", - " 6, 20, 24,\n", - " 'ua pf rq so ni ey bg hl tx zj')" + "# # Setting sheet line 31 from http://www.codesandciphers.org.uk/enigma/enigma3.htm\n", + "# # Enigma simulation settings are \n", + "# # http://enigma.louisedade.co.uk/enigma.html?m3;b;b153;AFTX;AJFE;AU-BG-EY-FP-HL-IN-JZ-OS-QR-TX\n", + "# enigma = Enigma(reflector_b_spec, \n", + "# wheel_i_spec, wheel_i_notches,\n", + "# wheel_v_spec, wheel_v_notches,\n", + "# wheel_iii_spec, wheel_iii_notches,\n", + "# 6, 20, 24,\n", + "# 'ua pf rq so ni ey bg hl tx zj')" ] }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 189, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "enigma.set_wheels('j', 'e', 'u')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (4, 11, 24))\n", - "assert(cat(enigma.wheel_positions_l) == 'jev')\n", - "assert(enigma.peg_positions == ([7], [21], [0]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mvqjlyowkdieasgzcunxrbhtfp')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (4, 12, 25))\n", - "assert(cat(enigma.wheel_positions_l) == 'jfw')\n", - "assert(enigma.peg_positions == ([7], [20], [25]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'sjolzuyvrbwdpxcmtiaqfhknge')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (4, 12, 0))\n", - "assert(cat(enigma.wheel_positions_l) == 'jfx')\n", - "assert(enigma.peg_positions == ([7], [20], [24]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qrxedkoywufmlvgsabpzjnicht')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (4, 12, 1))\n", - "assert(cat(enigma.wheel_positions_l) == 'jfy')\n", - "assert(enigma.peg_positions == ([7], [20], [23]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hpsukliagqefwvtbjxcodnmrzy')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (4, 12, 2))\n", - "assert(cat(enigma.wheel_positions_l) == 'jfz')\n", - "assert(enigma.peg_positions == ([7], [20], [22]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'zevnbpyqowrtxdifhkulscjmga')\n" + "w_enigma.set_wheels('j', 'e', 'u')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (4, 11, 24))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'jev')\n", + "assert(w_enigma.notch_positions == ([19], [5], [0]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'mvqjlyowkdieasgzcunxrbhtfp')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (4, 12, 25))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'jfw')\n", + "assert(w_enigma.notch_positions == ([19], [6], [1]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'sjolzuyvrbwdpxcmtiaqfhknge')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (4, 12, 0))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'jfx')\n", + "assert(w_enigma.notch_positions == ([19], [6], [2]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'qrxedkoywufmlvgsabpzjnicht')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (4, 12, 1))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'jfy')\n", + "assert(w_enigma.notch_positions == ([19], [6], [3]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'hpsukliagqefwvtbjxcodnmrzy')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (4, 12, 2))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'jfz')\n", + "assert(w_enigma.notch_positions == ([19], [6], [4]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'zevnbpyqowrtxdifhkulscjmga')\n" ] }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 190, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "enigma.set_wheels('i', 'd', 'z')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 3))\n", - "assert(cat(enigma.wheel_positions_l) == 'ida')\n", - "assert(enigma.peg_positions == ([8], [22], [21]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ikhpqrvcambzjondefwyxgsutl')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 4))\n", - "assert(cat(enigma.wheel_positions_l) == 'idb')\n", - "assert(enigma.peg_positions == ([8], [22], [20]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cdabskhgzwfmlqvunyexpojtri')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 5))\n", - "assert(cat(enigma.wheel_positions_l) == 'idc')\n", - "assert(enigma.peg_positions == ([8], [22], [19]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pcbwiqhgemyvjsuaftnroldzkx')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 6))\n", - "assert(cat(enigma.wheel_positions_l) == 'idd')\n", - "assert(enigma.peg_positions == ([8], [22], [18]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xcbfvdnouptmlghjzwykierasq')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 7))\n", - "assert(cat(enigma.wheel_positions_l) == 'ide')\n", - "assert(enigma.peg_positions == ([8], [22], [17]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xfvglbdynuseriwqpmkzjcoaht')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 8))\n", - "assert(cat(enigma.wheel_positions_l) == 'idf')\n", - "assert(enigma.peg_positions == ([8], [22], [16]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'tfpqlbouynsewjgcdxkahzmriv')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 9))\n", - "assert(cat(enigma.wheel_positions_l) == 'idg')\n", - "assert(enigma.peg_positions == ([8], [22], [15]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cjaunvlwtbygzexrspqidfhokm')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 10))\n", - "assert(cat(enigma.wheel_positions_l) == 'idh')\n", - "assert(enigma.peg_positions == ([8], [22], [14]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'yltxkrqvowebzpingfucshjdam')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 11))\n", - "assert(cat(enigma.wheel_positions_l) == 'idi')\n", - "assert(enigma.peg_positions == ([8], [22], [13]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'myktluzrnxceaiqsohpdfwvjbg')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 12))\n", - "assert(cat(enigma.wheel_positions_l) == 'idj')\n", - "assert(enigma.peg_positions == ([8], [22], [12]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pynjrmiugdqxfcvakewzhoslbt')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 13))\n", - "assert(cat(enigma.wheel_positions_l) == 'idk')\n", - "assert(enigma.peg_positions == ([8], [22], [11]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mwvedyplnoxhaijgrqtszcbkfu')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 14))\n", - "assert(cat(enigma.wheel_positions_l) == 'idl')\n", - "assert(enigma.peg_positions == ([8], [22], [10]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qcbrfeutvoxpnmjladzhgiykws')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 15))\n", - "assert(cat(enigma.wheel_positions_l) == 'idm')\n", - "assert(enigma.peg_positions == ([8], [22], [9]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'dnoahryetsmukbcvwfjilpqzgx')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 16))\n", - "assert(cat(enigma.wheel_positions_l) == 'idn')\n", - "assert(enigma.peg_positions == ([8], [22], [8]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nidcfehgbqsovalyjzkxwmutpr')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 17))\n", - "assert(cat(enigma.wheel_positions_l) == 'ido')\n", - "assert(enigma.peg_positions == ([8], [22], [7]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'joifxdulcarhzpbntkwqgysevm')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 18))\n", - "assert(cat(enigma.wheel_positions_l) == 'idp')\n", - "assert(enigma.peg_positions == ([8], [22], [6]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ptnlsxvozmwdjchayuebrgkfqi')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 19))\n", - "assert(cat(enigma.wheel_positions_l) == 'idq')\n", - "assert(enigma.peg_positions == ([8], [22], [5]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'slwopzqnmxybihdeguavrtcjkf')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 20))\n", - "assert(cat(enigma.wheel_positions_l) == 'idr')\n", - "assert(enigma.peg_positions == ([8], [22], [4]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hcbedwlamzogixkytsrqvufnpj')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 21))\n", - "assert(cat(enigma.wheel_positions_l) == 'ids')\n", - "assert(enigma.peg_positions == ([8], [22], [3]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'odxbjwzrmelkisavuhnyqpfctg')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 22))\n", - "assert(cat(enigma.wheel_positions_l) == 'idt')\n", - "assert(enigma.peg_positions == ([8], [22], [2]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'udgbfeclrwnhxksvtioqapjmzy')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 23))\n", - "assert(cat(enigma.wheel_positions_l) == 'idu')\n", - "assert(enigma.peg_positions == ([8], [22], [1]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nrdczqxmowvshaiufblypkjgte')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 24))\n", - "assert(cat(enigma.wheel_positions_l) == 'idv')\n", - "assert(enigma.peg_positions == ([8], [22], [0]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hkifjdoacebqtzgulyvmpsxwrn')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 11, 25))\n", - "assert(cat(enigma.wheel_positions_l) == 'iew')\n", - "assert(enigma.peg_positions == ([8], [21], [25]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'yptzuhofqvnmlkgbixwcejsrad')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 11, 0))\n", - "assert(cat(enigma.wheel_positions_l) == 'iex')\n", - "assert(enigma.peg_positions == ([8], [21], [24]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'vkdcwhqfjibzsptngumoraeyxl')\n", - "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 11, 1))\n", - "assert(cat(enigma.wheel_positions_l) == 'iey')\n", - "assert(enigma.peg_positions == ([8], [21], [23]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'wenpbqrouxlkychdfgzvitajms')\n" + "w_enigma.set_wheels('i', 'd', 'z')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 3))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'ida')\n", + "assert(w_enigma.notch_positions == ([18], [4], [5]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'ikhpqrvcambzjondefwyxgsutl')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 4))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idb')\n", + "assert(w_enigma.notch_positions == ([18], [4], [6]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'cdabskhgzwfmlqvunyexpojtri')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 5))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idc')\n", + "assert(w_enigma.notch_positions == ([18], [4], [7]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'pcbwiqhgemyvjsuaftnroldzkx')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 6))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idd')\n", + "assert(w_enigma.notch_positions == ([18], [4], [8]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'xcbfvdnouptmlghjzwykierasq')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 7))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'ide')\n", + "assert(w_enigma.notch_positions == ([18], [4], [9]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'xfvglbdynuseriwqpmkzjcoaht')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 8))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idf')\n", + "assert(w_enigma.notch_positions == ([18], [4], [10]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'tfpqlbouynsewjgcdxkahzmriv')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 9))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idg')\n", + "assert(w_enigma.notch_positions == ([18], [4], [11]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'cjaunvlwtbygzexrspqidfhokm')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 10))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idh')\n", + "assert(w_enigma.notch_positions == ([18], [4], [12]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'yltxkrqvowebzpingfucshjdam')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 11))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idi')\n", + "assert(w_enigma.notch_positions == ([18], [4], [13]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'myktluzrnxceaiqsohpdfwvjbg')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 12))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idj')\n", + "assert(w_enigma.notch_positions == ([18], [4], [14]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'pynjrmiugdqxfcvakewzhoslbt')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 13))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idk')\n", + "assert(w_enigma.notch_positions == ([18], [4], [15]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'mwvedyplnoxhaijgrqtszcbkfu')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 14))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idl')\n", + "assert(w_enigma.notch_positions == ([18], [4], [16]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'qcbrfeutvoxpnmjladzhgiykws')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 15))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idm')\n", + "assert(w_enigma.notch_positions == ([18], [4], [17]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'dnoahryetsmukbcvwfjilpqzgx')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 16))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idn')\n", + "assert(w_enigma.notch_positions == ([18], [4], [18]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'nidcfehgbqsovalyjzkxwmutpr')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 17))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'ido')\n", + "assert(w_enigma.notch_positions == ([18], [4], [19]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'joifxdulcarhzpbntkwqgysevm')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 18))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idp')\n", + "assert(w_enigma.notch_positions == ([18], [4], [20]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'ptnlsxvozmwdjchayuebrgkfqi')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 19))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idq')\n", + "assert(w_enigma.notch_positions == ([18], [4], [21]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'slwopzqnmxybihdeguavrtcjkf')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 20))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idr')\n", + "assert(w_enigma.notch_positions == ([18], [4], [22]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'hcbedwlamzogixkytsrqvufnpj')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 21))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'ids')\n", + "assert(w_enigma.notch_positions == ([18], [4], [23]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'odxbjwzrmelkisavuhnyqpfctg')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 22))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idt')\n", + "assert(w_enigma.notch_positions == ([18], [4], [24]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'udgbfeclrwnhxksvtioqapjmzy')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 23))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idu')\n", + "assert(w_enigma.notch_positions == ([18], [4], [25]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'nrdczqxmowvshaiufblypkjgte')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 24))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idv')\n", + "assert(w_enigma.notch_positions == ([18], [4], [0]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'hkifjdoacebqtzgulyvmpsxwrn')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 11, 25))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'iew')\n", + "assert(w_enigma.notch_positions == ([18], [5], [1]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'yptzuhofqvnmlkgbixwcejsrad')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 11, 0))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'iex')\n", + "assert(w_enigma.notch_positions == ([18], [5], [2]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'vkdcwhqfjibzsptngumoraeyxl')\n", + "\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 11, 1))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'iey')\n", + "assert(w_enigma.notch_positions == ([18], [5], [3]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'wenpbqrouxlkychdfgzvitajms')\n" ] }, { "cell_type": "code", - "execution_count": 58, - "metadata": { - "collapsed": false - }, + "execution_count": 191, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "('verylongtestmessagewithanextrabitofmessageforgoodmeasure',\n", - " (3, 12, 6),\n", - " ('i', 'f', 'd'),\n", - " ([8], [20], [18]),\n", - " 'urygzpdmxtwshqvfnbljaokice')" + "([18], [5], [3])" ] }, - "execution_count": 58, + "execution_count": 191, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "enigma.set_wheels('i', 'd', 'z')\n", - "ct = enigma.encipher('verylongtestmessagewithanextrabitofmessageforgoodmeasure')\n", - "assert(ct == 'gstsegeqdrthkfwesljjomfvcqwcfspxpfqqmewvddybarzwubxtpejz')\n", - "assert(enigma.wheel_positions == (3, 12, 6))\n", - "assert(cat(enigma.wheel_positions_l) == 'ifd')\n", - "assert(enigma.peg_positions == ([8], [20], [18]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'urygzpdmxtwshqvfnbljaokice')\n", + "w_enigma.notch_positions" + ] + }, + { + "cell_type": "code", + "execution_count": 192, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('verylongtestmessagewithanextrabitofmessageforgoodmeasure',\n", + " (3, 12, 6),\n", + " ('i', 'f', 'd'),\n", + " ([18], [6], [8]),\n", + " 'urygzpdmxtwshqvfnbljaokice')" + ] + }, + "execution_count": 192, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "w_enigma.set_wheels('i', 'd', 'z')\n", + "ct = w_enigma.encipher('verylongtestmessagewithanextrabitofmessageforgoodmeasure')\n", + "assert(ct == 'gstsegeqdrthkfwesljjomfvcqwcfspxpfqqmewvddybarzwubxtpejz')\n", + "assert(w_enigma.wheel_positions == (3, 12, 6))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'ifd')\n", + "assert(w_enigma.notch_positions == ([18], [6], [8]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'urygzpdmxtwshqvfnbljaokice')\n", "\n", - "enigma.set_wheels('i', 'd', 'z')\n", - "pt = enigma.encipher('gstsegeqdrthkfwesljjomfvcqwcfspxpfqqmewvddybarzwubxtpejz')\n", + "w_enigma.set_wheels('i', 'd', 'z')\n", + "pt = w_enigma.encipher('gstsegeqdrthkfwesljjomfvcqwcfspxpfqqmewvddybarzwubxtpejz')\n", "assert(pt == 'verylongtestmessagewithanextrabitofmessageforgoodmeasure')\n", "\n", - "pt, enigma.wheel_positions, enigma.wheel_positions_l, enigma.peg_positions, cat(enigma.lookup(l) for l in string.ascii_lowercase)" + "pt, w_enigma.wheel_positions, w_enigma.wheel_positions_l, w_enigma.notch_positions, cat(w_enigma.lookup(l) for l in string.ascii_lowercase)" ] }, { "cell_type": "code", - "execution_count": 59, - "metadata": { - "collapsed": false - }, + "execution_count": 193, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 3))\n", - "assert(cat(enigma.wheel_positions_l) == 'ida')\n", - "assert(enigma.peg_positions == ([8], [22], [21]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ikhpqrvcambzjondefwyxgsutl')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 3))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'ida')\n", + "assert(w_enigma.notch_positions == ([18], [4], [5]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'ikhpqrvcambzjondefwyxgsutl')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 4))\n", - "assert(cat(enigma.wheel_positions_l) == 'idb')\n", - "assert(enigma.peg_positions == ([8], [22], [20]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cdabskhgzwfmlqvunyexpojtri')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 4))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idb')\n", + "assert(w_enigma.notch_positions == ([18], [4], [6]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'cdabskhgzwfmlqvunyexpojtri')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 5))\n", - "assert(cat(enigma.wheel_positions_l) == 'idc')\n", - "assert(enigma.peg_positions == ([8], [22], [19]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pcbwiqhgemyvjsuaftnroldzkx')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 5))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idc')\n", + "assert(w_enigma.notch_positions == ([18], [4], [7]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'pcbwiqhgemyvjsuaftnroldzkx')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 6))\n", - "assert(cat(enigma.wheel_positions_l) == 'idd')\n", - "assert(enigma.peg_positions == ([8], [22], [18]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xcbfvdnouptmlghjzwykierasq')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 6))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idd')\n", + "assert(w_enigma.notch_positions == ([18], [4], [8]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'xcbfvdnouptmlghjzwykierasq')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 7))\n", - "assert(cat(enigma.wheel_positions_l) == 'ide')\n", - "assert(enigma.peg_positions == ([8], [22], [17]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'xfvglbdynuseriwqpmkzjcoaht')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 7))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'ide')\n", + "assert(w_enigma.notch_positions == ([18], [4], [9]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'xfvglbdynuseriwqpmkzjcoaht')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 8))\n", - "assert(cat(enigma.wheel_positions_l) == 'idf')\n", - "assert(enigma.peg_positions == ([8], [22], [16]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'tfpqlbouynsewjgcdxkahzmriv')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 8))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idf')\n", + "assert(w_enigma.notch_positions == ([18], [4], [10]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'tfpqlbouynsewjgcdxkahzmriv')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 9))\n", - "assert(cat(enigma.wheel_positions_l) == 'idg')\n", - "assert(enigma.peg_positions == ([8], [22], [15]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'cjaunvlwtbygzexrspqidfhokm')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 9))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idg')\n", + "assert(w_enigma.notch_positions == ([18], [4], [11]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'cjaunvlwtbygzexrspqidfhokm')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 10))\n", - "assert(cat(enigma.wheel_positions_l) == 'idh')\n", - "assert(enigma.peg_positions == ([8], [22], [14]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'yltxkrqvowebzpingfucshjdam')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 10))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idh')\n", + "assert(w_enigma.notch_positions == ([18], [4], [12]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'yltxkrqvowebzpingfucshjdam')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 11))\n", - "assert(cat(enigma.wheel_positions_l) == 'idi')\n", - "assert(enigma.peg_positions == ([8], [22], [13]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'myktluzrnxceaiqsohpdfwvjbg')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 11))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idi')\n", + "assert(w_enigma.notch_positions == ([18], [4], [13]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'myktluzrnxceaiqsohpdfwvjbg')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 12))\n", - "assert(cat(enigma.wheel_positions_l) == 'idj')\n", - "assert(enigma.peg_positions == ([8], [22], [12]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'pynjrmiugdqxfcvakewzhoslbt')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 12))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idj')\n", + "assert(w_enigma.notch_positions == ([18], [4], [14]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'pynjrmiugdqxfcvakewzhoslbt')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 13))\n", - "assert(cat(enigma.wheel_positions_l) == 'idk')\n", - "assert(enigma.peg_positions == ([8], [22], [11]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'mwvedyplnoxhaijgrqtszcbkfu')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 13))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idk')\n", + "assert(w_enigma.notch_positions == ([18], [4], [15]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'mwvedyplnoxhaijgrqtszcbkfu')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 14))\n", - "assert(cat(enigma.wheel_positions_l) == 'idl')\n", - "assert(enigma.peg_positions == ([8], [22], [10]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'qcbrfeutvoxpnmjladzhgiykws')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 14))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idl')\n", + "assert(w_enigma.notch_positions == ([18], [4], [16]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'qcbrfeutvoxpnmjladzhgiykws')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 15))\n", - "assert(cat(enigma.wheel_positions_l) == 'idm')\n", - "assert(enigma.peg_positions == ([8], [22], [9]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'dnoahryetsmukbcvwfjilpqzgx')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 15))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idm')\n", + "assert(w_enigma.notch_positions == ([18], [4], [17]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'dnoahryetsmukbcvwfjilpqzgx')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 16))\n", - "assert(cat(enigma.wheel_positions_l) == 'idn')\n", - "assert(enigma.peg_positions == ([8], [22], [8]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nidcfehgbqsovalyjzkxwmutpr')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 16))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idn')\n", + "assert(w_enigma.notch_positions == ([18], [4], [18]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'nidcfehgbqsovalyjzkxwmutpr')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 17))\n", - "assert(cat(enigma.wheel_positions_l) == 'ido')\n", - "assert(enigma.peg_positions == ([8], [22], [7]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'joifxdulcarhzpbntkwqgysevm')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 17))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'ido')\n", + "assert(w_enigma.notch_positions == ([18], [4], [19]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'joifxdulcarhzpbntkwqgysevm')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 18))\n", - "assert(cat(enigma.wheel_positions_l) == 'idp')\n", - "assert(enigma.peg_positions == ([8], [22], [6]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'ptnlsxvozmwdjchayuebrgkfqi')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 18))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idp')\n", + "assert(w_enigma.notch_positions == ([18], [4], [20]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'ptnlsxvozmwdjchayuebrgkfqi')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 19))\n", - "assert(cat(enigma.wheel_positions_l) == 'idq')\n", - "assert(enigma.peg_positions == ([8], [22], [5]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'slwopzqnmxybihdeguavrtcjkf')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 19))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idq')\n", + "assert(w_enigma.notch_positions == ([18], [4], [21]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'slwopzqnmxybihdeguavrtcjkf')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 20))\n", - "assert(cat(enigma.wheel_positions_l) == 'idr')\n", - "assert(enigma.peg_positions == ([8], [22], [4]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hcbedwlamzogixkytsrqvufnpj')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 20))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idr')\n", + "assert(w_enigma.notch_positions == ([18], [4], [22]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'hcbedwlamzogixkytsrqvufnpj')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 21))\n", - "assert(cat(enigma.wheel_positions_l) == 'ids')\n", - "assert(enigma.peg_positions == ([8], [22], [3]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'odxbjwzrmelkisavuhnyqpfctg')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 21))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'ids')\n", + "assert(w_enigma.notch_positions == ([18], [4], [23]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'odxbjwzrmelkisavuhnyqpfctg')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 22))\n", - "assert(cat(enigma.wheel_positions_l) == 'idt')\n", - "assert(enigma.peg_positions == ([8], [22], [2]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'udgbfeclrwnhxksvtioqapjmzy')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 22))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idt')\n", + "assert(w_enigma.notch_positions == ([18], [4], [24]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'udgbfeclrwnhxksvtioqapjmzy')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 23))\n", - "assert(cat(enigma.wheel_positions_l) == 'idu')\n", - "assert(enigma.peg_positions == ([8], [22], [1]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'nrdczqxmowvshaiufblypkjgte')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 23))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idu')\n", + "assert(w_enigma.notch_positions == ([18], [4], [25]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'nrdczqxmowvshaiufblypkjgte')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 10, 24))\n", - "assert(cat(enigma.wheel_positions_l) == 'idv')\n", - "assert(enigma.peg_positions == ([8], [22], [0]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'hkifjdoacebqtzgulyvmpsxwrn')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 10, 24))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'idv')\n", + "assert(w_enigma.notch_positions == ([18], [4], [0]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'hkifjdoacebqtzgulyvmpsxwrn')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 11, 25))\n", - "assert(cat(enigma.wheel_positions_l) == 'iew')\n", - "assert(enigma.peg_positions == ([8], [21], [25]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'yptzuhofqvnmlkgbixwcejsrad')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 11, 25))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'iew')\n", + "assert(w_enigma.notch_positions == ([18], [5], [1]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'yptzuhofqvnmlkgbixwcejsrad')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 11, 0))\n", - "assert(cat(enigma.wheel_positions_l) == 'iex')\n", - "assert(enigma.peg_positions == ([8], [21], [24]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'vkdcwhqfjibzsptngumoraeyxl')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 11, 0))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'iex')\n", + "assert(w_enigma.notch_positions == ([18], [5], [2]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'vkdcwhqfjibzsptngumoraeyxl')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 11, 1))\n", - "assert(cat(enigma.wheel_positions_l) == 'iey')\n", - "assert(enigma.peg_positions == ([8], [21], [23]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'wenpbqrouxlkychdfgzvitajms')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 11, 1))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'iey')\n", + "assert(w_enigma.notch_positions == ([18], [5], [3]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'wenpbqrouxlkychdfgzvitajms')\n", "\n", - "enigma.advance()\n", - "assert(enigma.wheel_positions == (3, 11, 2))\n", - "assert(cat(enigma.wheel_positions_l) == 'iez')\n", - "assert(enigma.peg_positions == ([8], [21], [22]))\n", - "assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == 'szgyqvclkoihurjwenaxmfptdb')\n", + "w_enigma.advance()\n", + "assert(w_enigma.wheel_positions == (3, 11, 2))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'iez')\n", + "assert(w_enigma.notch_positions == ([18], [5], [4]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'szgyqvclkoihurjwenaxmfptdb')\n", "\n" ] } ], "source": [ - "enigma.set_wheels('i', 'd', 'z')\n", + "w_enigma.set_wheels('i', 'd', 'z')\n", "\n", "for i in range(26):\n", - " enigma.advance()\n", - " print('enigma.advance()')\n", - " print(\"assert(enigma.wheel_positions == {})\".format(enigma.wheel_positions))\n", - " print(\"assert(cat(enigma.wheel_positions_l) == '{}')\".format(cat(enigma.wheel_positions_l)))\n", - " print(\"assert(enigma.peg_positions == {})\".format(enigma.peg_positions))\n", - " print(\"assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == '{}')\".format(cat(enigma.lookup(l) for l in string.ascii_lowercase)))\n", + " w_enigma.advance()\n", + " print('w_enigma.advance()')\n", + " print(\"assert(w_enigma.wheel_positions == {})\".format(w_enigma.wheel_positions))\n", + " print(\"assert(cat(w_enigma.wheel_positions_l) == '{}')\".format(cat(w_enigma.wheel_positions_l)))\n", + " print(\"assert(w_enigma.notch_positions == {})\".format(w_enigma.notch_positions))\n", + " print(\"assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == '{}')\".format(cat(w_enigma.lookup(l) for l in string.ascii_lowercase)))\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": 215, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "self.assertEqual(self.enigma31.wheel_positions, (21, 5, 22))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ayt')\n", + "self.assertEqual(self.enigma31.notch_positions, ([10], [25], [24]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'izhrgtecaslkywvqpdjfxonumb')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (21, 5, 23))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ayu')\n", + "self.assertEqual(self.enigma31.notch_positions, ([10], [25], [25]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'dtoavihgflwjnmcsrqpbzekyxu')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (21, 5, 24))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ayv')\n", + "self.assertEqual(self.enigma31.notch_positions, ([10], [25], [0]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'xquhtpsdwkjonmlfbvgecriazy')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (21, 6, 25))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'azw')\n", + "self.assertEqual(self.enigma31.notch_positions, ([10], [0], [1]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'dofapcluvmngjkbezyxwhitsrq')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (22, 7, 0))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bax')\n", + "self.assertEqual(self.enigma31.notch_positions, ([11], [1], [2]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'jdlbmswztapcexrkuofiqygnvh')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (22, 7, 1))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bay')\n", + "self.assertEqual(self.enigma31.notch_positions, ([11], [1], [3]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'iydcnuhgawsoxelztvkqfrjmbp')\n", + "\n" + ] + } + ], + "source": [ + "w_enigma.set_wheels('a', 'y', 't')\n", + "\n", + "print(\"self.assertEqual(self.enigma31.wheel_positions, {})\".format(w_enigma.wheel_positions))\n", + "print(\"self.assertEqual(cat(self.enigma31.wheel_positions_l), '{}')\".format(cat(w_enigma.wheel_positions_l)))\n", + "print(\"self.assertEqual(self.enigma31.notch_positions, {})\".format(w_enigma.notch_positions))\n", + "print(\"assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == '{}')\".format(cat(w_enigma.lookup(l) for l in string.ascii_lowercase)))\n", + "print()\n", + "\n", + "for i in range(5):\n", + " w_enigma.advance()\n", + " print('self.enigma31.advance()')\n", + " print(\"self.assertEqual(self.enigma31.wheel_positions, {})\".format(w_enigma.wheel_positions))\n", + " print(\"self.assertEqual(cat(self.enigma31.wheel_positions_l), '{}')\".format(cat(w_enigma.wheel_positions_l)))\n", + " print(\"self.assertEqual(self.enigma31.notch_positions, {})\".format(w_enigma.notch_positions))\n", + " print(\"assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == '{}')\".format(cat(w_enigma.lookup(l) for l in string.ascii_lowercase)))\n", " print()" ] }, + { + "cell_type": "code", + "execution_count": 216, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "self.assertEqual(self.enigma31.wheel_positions, (21, 6, 22))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'azt')\n", + "self.assertEqual(self.enigma31.notch_positions, ([10], [0], [24]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'idjbptqwacsvnmregokfzlhyxu')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (22, 7, 23))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bau')\n", + "self.assertEqual(self.enigma31.notch_positions, ([11], [1], [25]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'rniszouwcxtvqbfymadkglhjpe')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (22, 7, 24))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bav')\n", + "self.assertEqual(self.enigma31.notch_positions, ([11], [1], [0]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'qijfsdmkbchugxtwazeolypnvr')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (22, 8, 25))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bbw')\n", + "self.assertEqual(self.enigma31.notch_positions, ([11], [2], [1]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'xprtlozyskjewqfbncidvumahg')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (22, 8, 0))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bbx')\n", + "self.assertEqual(self.enigma31.notch_positions, ([11], [2], [2]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'vtfuyczoqxmpkwhlisrbdanjeg')\n", + "\n", + "self.enigma31.advance()\n", + "self.assertEqual(self.enigma31.wheel_positions, (22, 8, 1))\n", + "self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bby')\n", + "self.assertEqual(self.enigma31.notch_positions, ([11], [2], [3]))\n", + "assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'tjrhzpqdobwxyuifgcvansklme')\n", + "\n" + ] + } + ], + "source": [ + "w_enigma.set_wheels('a', 'z', 't')\n", + "\n", + "print(\"self.assertEqual(self.enigma31.wheel_positions, {})\".format(w_enigma.wheel_positions))\n", + "print(\"self.assertEqual(cat(self.enigma31.wheel_positions_l), '{}')\".format(cat(w_enigma.wheel_positions_l)))\n", + "print(\"self.assertEqual(self.enigma31.notch_positions, {})\".format(w_enigma.notch_positions))\n", + "print(\"assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == '{}')\".format(cat(w_enigma.lookup(l) for l in string.ascii_lowercase)))\n", + "print()\n", + "\n", + "for i in range(5):\n", + " w_enigma.advance()\n", + " print('self.enigma31.advance()')\n", + " print(\"self.assertEqual(self.enigma31.wheel_positions, {})\".format(w_enigma.wheel_positions))\n", + " print(\"self.assertEqual(cat(self.enigma31.wheel_positions_l), '{}')\".format(cat(w_enigma.wheel_positions_l)))\n", + " print(\"self.assertEqual(self.enigma31.notch_positions, {})\".format(w_enigma.notch_positions))\n", + " print(\"assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == '{}')\".format(cat(w_enigma.lookup(l) for l in string.ascii_lowercase)))\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": 221, + "metadata": {}, + "outputs": [], + "source": [ + "w_enigma.set_wheels('i', 'z', 'd')\n", + "ct = w_enigma.encipher('verylongtestmessagewithanextrabitofmessageforgoodmeasure')\n", + "assert(ct == 'apocwtjuikurcfivlozvhffkoacxufcekthcvodfqpxdjqyckdozlqki')\n", + "assert(w_enigma.wheel_positions == (4, 9, 10))\n", + "assert(cat(w_enigma.wheel_positions_l) == 'jch')\n", + "assert(w_enigma.notch_positions == ([19], [3], [12]))\n", + "assert(cat(w_enigma.lookup(l) for l in string.ascii_lowercase) == 'mopnigfuesqwadbcktjrhylzvx')\n", + "\n", + "w_enigma.set_wheels('i', 'z', 'd')\n", + "pt = w_enigma.decipher('apocwtjuikurcfivlozvhffkoacxufcekthcvodfqpxdjqyckdozlqki')\n", + "assert(pt == 'verylongtestmessagewithanextrabitofmessageforgoodmeasure')" + ] + }, + { + "cell_type": "code", + "execution_count": 218, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "([19], [3], [12])" + ] + }, + "execution_count": 218, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "w_enigma.notch_positions" + ] + }, + { + "cell_type": "code", + "execution_count": 194, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Reflector B\n", + "# Rotors III, I, II with rings 17, 11, 19\n", + "# Plugboard pairs GU FZ BD LK TC PS HV WN JE AM\n", + "\n", + "tbt_enigma = Enigma(reflector_b_spec, \n", + " wheel_iii_spec, wheel_iii_notches,\n", + " wheel_i_spec, wheel_i_notches,\n", + " wheel_ii_spec, wheel_ii_notches,\n", + " 17, 11, 19,\n", + " 'GU FZ BD LK TC PS HV WN JE AM'.lower())" + ] + }, + { + "cell_type": "code", + "execution_count": 195, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'jbvbwwzfslhxnhzzccsngebmrnswgjonwbjnzcfgadeuoyameylmpvny'" + ] + }, + "execution_count": 195, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'q', 'v')\n", + "ct = tbt_enigma.encipher('very long test message with an extra bit of message for good measure')\n", + "ct" + ] + }, + { + "cell_type": "code", + "execution_count": 196, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'SLGNC SZXLT KZEBG HSTGY WDMPR'" + ] + }, + "execution_count": 196, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_ct = 'SLGNC SZXLT KZEBG HSTGY WDMPR'\n", + "target_ct" + ] + }, + { + "cell_type": "code", + "execution_count": 197, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Theyw erede tecte d byBri tishs hipsi nclud'" + ] + }, + "execution_count": 197, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_pt = 'Theyw erede tecte d byBri tishs hipsi nclud'\n", + "target_pt" + ] + }, + { + "cell_type": "code", + "execution_count": 198, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(29, 43)" + ] + }, + "execution_count": 198, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(target_ct), len(target_pt)" + ] + }, + { + "cell_type": "code", + "execution_count": 199, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SLGNC SZXLT KZEBG HSTGY WDMPR\n", + "Theyw erede tecte d byBri tishs hipsi nclud\n" + ] + } + ], + "source": [ + "print('{}\\n{}'.format(target_ct, target_pt))" + ] + }, + { + "cell_type": "code", + "execution_count": 200, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Theyw erede tecte d byBri tishs hipsi nclud\n", + "SLGNC SZXLT KZEBG HSTGY WDMPR\n", + "slgncszxltkzebghstgywdmprucuzqdqzpve\n", + "theyweredetectedbybritish\n" + ] + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "this_pt = tbt_enigma.encipher(target_ct)\n", + "\n", + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "this_ct = tbt_enigma.encipher(target_pt)\n", + "\n", + "\n", + "print('{}\\n{}\\n{}\\n{}'.format(target_pt, target_ct, this_ct, this_pt))" + ] + }, + { + "cell_type": "code", + "execution_count": 201, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import itertools" + ] + }, + { + "cell_type": "code", + "execution_count": 202, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def str_ham(s1, s2):\n", + " \"\"\"Hamming distance for strings\"\"\"\n", + " return sum(1 for c1, c2 in zip(s1, s2) if c1 != c2)" + ] + }, + { + "cell_type": "code", + "execution_count": 203, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 203, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "str_ham('hello', 'hello')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A brute-force check of all message settings, looking for the one that generates the target text." + ] + }, + { + "cell_type": "code", + "execution_count": 204, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "best ('a', 'a', 'a') 29\n", + "best ('a', 'a', 'a') 29\n", + "best ('a', 'a', 'a') 29\n", + "best ('a', 'a', 'a') 29\n", + "1 loop, best of 3: 20.6 s per loop\n" + ] + } + ], + "source": [ + "%%timeit\n", + "best = ('a', 'a', 'a')\n", + "best_hd = 10000\n", + "for w1, w2, w3 in itertools.product(string.ascii_lowercase, repeat=3):\n", + " tbt_enigma.set_wheels(w1, w2, w3)\n", + " this_ct = tbt_enigma.encipher(target_pt)\n", + " if this_ct == target_ct:\n", + " print(w1, w2, w3)\n", + " if str_ham(this_ct, target_ct) < best_hd:\n", + " best = (w1, w2, w3)\n", + " best_hd = str_ham(this_ct, target_ct)\n", + "print('best', best, best_hd)" + ] + }, + { + "cell_type": "code", + "execution_count": 205, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wheels now ['a', 'a', 'b'] enciphering t -> s\n", + "Wheels now ['a', 'a', 'c'] enciphering h -> l\n", + "Wheels now ['a', 'a', 'd'] enciphering e -> g\n", + "Wheels now ['a', 'a', 'e'] enciphering y -> n\n", + "Wheels now ['a', 'b', 'f'] enciphering w -> c\n", + "Wheels now ['a', 'b', 'g'] enciphering e -> s\n", + "Wheels now ['a', 'b', 'h'] enciphering r -> z\n", + "Wheels now ['a', 'b', 'i'] enciphering e -> x\n", + "Wheels now ['a', 'b', 'j'] enciphering d -> l\n", + "Wheels now ['a', 'b', 'k'] enciphering e -> t\n", + "Wheels now ['a', 'b', 'l'] enciphering t -> k\n", + "Wheels now ['a', 'b', 'm'] enciphering e -> z\n", + "Wheels now ['a', 'b', 'n'] enciphering c -> e\n", + "Wheels now ['a', 'b', 'o'] enciphering t -> b\n", + "Wheels now ['a', 'b', 'p'] enciphering e -> g\n", + "Wheels now ['a', 'b', 'q'] enciphering d -> h\n", + "Wheels now ['a', 'b', 'r'] enciphering b -> s\n", + "Wheels now ['a', 'b', 's'] enciphering y -> t\n", + "Wheels now ['a', 'b', 't'] enciphering b -> g\n", + "Wheels now ['a', 'b', 'u'] enciphering r -> y\n", + "Wheels now ['a', 'b', 'v'] enciphering i -> w\n", + "Wheels now ['a', 'b', 'w'] enciphering t -> d\n", + "Wheels now ['a', 'b', 'x'] enciphering i -> m\n", + "Wheels now ['a', 'b', 'y'] enciphering s -> p\n", + "Wheels now ['a', 'b', 'z'] enciphering h -> r\n", + "Wheels now ['a', 'b', 'a'] enciphering s -> u\n", + "Wheels now ['a', 'b', 'b'] enciphering h -> c\n", + "Wheels now ['a', 'b', 'c'] enciphering i -> u\n", + "Wheels now ['a', 'b', 'd'] enciphering p -> z\n", + "Wheels now ['a', 'b', 'e'] enciphering s -> q\n", + "Wheels now ['a', 'c', 'f'] enciphering i -> d\n", + "Wheels now ['a', 'c', 'g'] enciphering n -> q\n", + "Wheels now ['a', 'c', 'h'] enciphering c -> z\n", + "Wheels now ['a', 'c', 'i'] enciphering l -> p\n", + "Wheels now ['a', 'c', 'j'] enciphering u -> v\n", + "Wheels now ['a', 'c', 'k'] enciphering d -> e\n" + ] + }, + { + "data": { + "text/plain": [ + "('slgncszxltkzebghstgywdmprucuzqdqzpve', 'SLGNC SZXLT KZEBG HSTGY WDMPR')" + ] + }, + "execution_count": 205, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "tbt_enigma.encipher(target_pt, debug=True), target_ct" + ] + }, + { + "cell_type": "code", + "execution_count": 206, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wheels now ['a', 'a', 'b'] enciphering s -> t\n", + "Wheels now ['a', 'a', 'c'] enciphering l -> h\n", + "Wheels now ['a', 'a', 'd'] enciphering g -> e\n", + "Wheels now ['a', 'a', 'e'] enciphering n -> y\n", + "Wheels now ['a', 'b', 'f'] enciphering c -> w\n", + "Wheels now ['a', 'b', 'g'] enciphering s -> e\n", + "Wheels now ['a', 'b', 'h'] enciphering z -> r\n", + "Wheels now ['a', 'b', 'i'] enciphering x -> e\n", + "Wheels now ['a', 'b', 'j'] enciphering l -> d\n", + "Wheels now ['a', 'b', 'k'] enciphering t -> e\n", + "Wheels now ['a', 'b', 'l'] enciphering k -> t\n", + "Wheels now ['a', 'b', 'm'] enciphering z -> e\n", + "Wheels now ['a', 'b', 'n'] enciphering e -> c\n", + "Wheels now ['a', 'b', 'o'] enciphering b -> t\n", + "Wheels now ['a', 'b', 'p'] enciphering g -> e\n", + "Wheels now ['a', 'b', 'q'] enciphering h -> d\n", + "Wheels now ['a', 'b', 'r'] enciphering s -> b\n", + "Wheels now ['a', 'b', 's'] enciphering t -> y\n", + "Wheels now ['a', 'b', 't'] enciphering g -> b\n", + "Wheels now ['a', 'b', 'u'] enciphering y -> r\n", + "Wheels now ['a', 'b', 'v'] enciphering w -> i\n", + "Wheels now ['a', 'b', 'w'] enciphering d -> t\n", + "Wheels now ['a', 'b', 'x'] enciphering m -> i\n", + "Wheels now ['a', 'b', 'y'] enciphering p -> s\n", + "Wheels now ['a', 'b', 'z'] enciphering r -> h\n" + ] + }, + { + "data": { + "text/plain": [ + "('theyweredetectedbybritish', 'Theyw erede tecte d byBri tishs hipsi nclud')" + ] + }, + "execution_count": 206, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "tbt_enigma.encipher(target_ct, debug=True), target_pt" + ] + }, + { + "cell_type": "code", + "execution_count": 207, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('theyweredetectedbybritish', 'Theyw erede tecte d byBri tishs hipsi nclud')" + ] + }, + "execution_count": 207, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "tbt_enigma.encipher(target_ct), target_pt" + ] + }, + { + "cell_type": "code", + "execution_count": 208, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'mdtbjzuvielkawosqrpcghnxyf'" + ] + }, + "execution_count": 208, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat(tbt_enigma.plugboard.forward(l) for l in string.ascii_lowercase)" + ] + }, + { + "cell_type": "code", + "execution_count": 209, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 209, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tbt_enigma.set_wheels('a', 'a', 'a')\n", + "tbt_enigma.left_wheel.position" + ] + }, { "cell_type": "code", "execution_count": null, @@ -2249,9 +3523,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.3+" + "version": "3.5.3" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/enigma.py b/enigma.py index a26d1d3..89758f5 100644 --- a/enigma.py +++ b/enigma.py @@ -60,14 +60,14 @@ wheel_viii_spec = 'fkqhtlxocbjspdzramewniuygv' beta_wheel_spec = 'leyjvcnixwpbqmdrtakzgfuhos' gamma_wheel_spec = 'fsokanuerhmbtiycwlqpzxvgjd' -wheel_i_pegs = ['q'] -wheel_ii_pegs = ['e'] -wheel_iii_pegs = ['v'] -wheel_iv_pegs = ['j'] -wheel_v_pegs = ['z'] -wheel_vi_pegs = ['z', 'm'] -wheel_vii_pegs = ['z', 'm'] -wheel_viii_pegs = ['z', 'm'] +wheel_i_notches = ['q'] +wheel_ii_notches = ['e'] +wheel_iii_notches = ['v'] +wheel_iv_notches = ['j'] +wheel_v_notches = ['z'] +wheel_vi_notches = ['z', 'm'] +wheel_vii_notches = ['z', 'm'] +wheel_viii_notches = ['z', 'm'] reflector_b_spec = 'ay br cu dh eq fs gl ip jx kn mo tz vw' reflector_c_spec = 'af bv cp dj ei go hy kr lz mx nw tq su' @@ -223,7 +223,7 @@ class SimpleWheel(LetterTransformer): class Wheel(SimpleWheel): """A wheel with a movable ring. - The ring holds the letters and the pegs that turn other wheels. The core + The ring holds the letters and the notches that turn other wheels. The core holds the wiring that does the transformation. The ring position is how many steps the core is turned relative to the ring. @@ -236,12 +236,12 @@ class Wheel(SimpleWheel): The position_l is the position of the ring, or what would be observed by the user of the Enigma machine. - The peg_positions are the number of advances of this wheel before it will + The notch_positions are the number of advances of this wheel before it will advance the next wheel. """ - def __init__(self, transform, ring_peg_letters, ring_setting=1, position='a', raw_transform=False): - self.ring_peg_letters = ring_peg_letters + def __init__(self, transform, ring_notch_letters, ring_setting=1, position='a', raw_transform=False): + self.ring_notch_letters = ring_notch_letters self.ring_setting = ring_setting super(Wheel, self).__init__(transform, position=position, raw_transform=raw_transform) self.set_position(position) @@ -257,12 +257,14 @@ class Wheel(SimpleWheel): self.position = (pos(position) - self.ring_setting + 1) % 26 else: self.position = (position - self.ring_setting) % 26 - # self.peg_positions = [(pos(p) - pos(position)) % 26 for p in self.ring_peg_letters] - self.peg_positions = [(pos(p) - (self.position + self.ring_setting - 1)) % 26 for p in self.ring_peg_letters] + # # self.notch_positions = [(pos(p) - pos(position)) % 26 for p in self.ring_notch_letters] + # self.notch_positions = [(pos(p) - (self.position + self.ring_setting - 1)) % 26 for p in self.ring_notch_letters] + self.notch_positions = [(self.position + self.ring_setting - 1 - pos(p)) % 26 for p in self.ring_notch_letters] def advance(self): super(Wheel, self).advance() - self.peg_positions = [(p - 1) % 26 for p in self.peg_positions] + self.notch_positions = [(p + 1) % 26 for p in self.notch_positions] + return self.position class Enigma(object): @@ -271,15 +273,15 @@ class Enigma(object): """ def __init__(self, reflector_spec, - left_wheel_spec, left_wheel_pegs, - middle_wheel_spec, middle_wheel_pegs, - right_wheel_spec, right_wheel_pegs, + left_wheel_spec, left_wheel_notches, + middle_wheel_spec, middle_wheel_notches, + right_wheel_spec, right_wheel_notches, left_ring_setting, middle_ring_setting, right_ring_setting, plugboard_setting): self.reflector = Reflector(reflector_spec) - self.left_wheel = Wheel(left_wheel_spec, left_wheel_pegs, ring_setting=left_ring_setting) - self.middle_wheel = Wheel(middle_wheel_spec, middle_wheel_pegs, ring_setting=middle_ring_setting) - self.right_wheel = Wheel(right_wheel_spec, right_wheel_pegs, ring_setting=right_ring_setting) + self.left_wheel = Wheel(left_wheel_spec, left_wheel_notches, ring_setting=left_ring_setting) + self.middle_wheel = Wheel(middle_wheel_spec, middle_wheel_notches, ring_setting=middle_ring_setting) + self.right_wheel = Wheel(right_wheel_spec, right_wheel_notches, ring_setting=right_ring_setting) self.plugboard = Plugboard(plugboard_setting) def __getattribute__(self,name): @@ -287,8 +289,8 @@ class Enigma(object): return self.left_wheel.position, self.middle_wheel.position, self.right_wheel.position elif name=='wheel_positions_l': return self.left_wheel.position_l, self.middle_wheel.position_l, self.right_wheel.position_l - elif name=='peg_positions': - return self.left_wheel.peg_positions, self.middle_wheel.peg_positions, self.right_wheel.peg_positions + elif name=='notch_positions': + return self.left_wheel.notch_positions, self.middle_wheel.notch_positions, self.right_wheel.notch_positions else: return object.__getattribute__(self, name) @@ -312,9 +314,9 @@ class Enigma(object): def advance(self): advance_middle = False advance_left = False - if 0 in self.right_wheel.peg_positions: + if 0 in self.right_wheel.notch_positions: advance_middle = True - if 0 in self.middle_wheel.peg_positions: + if 0 in self.middle_wheel.notch_positions: advance_left = True advance_middle = True self.right_wheel.advance() @@ -339,7 +341,7 @@ class Enigma(object): # print('enigma.advance()') # print("assert(enigma.wheel_positions == {})".format(enigma.wheel_positions)) # print("assert(cat(enigma.wheel_positions_l) == '{}')".format(cat(enigma.wheel_positions_l))) -# print("assert(enigma.peg_positions == {})".format(enigma.peg_positions)) +# print("assert(enigma.notch_positions == {})".format(enigma.notch_positions)) # print("assert(cat(enigma.lookup(l) for l in string.ascii_lowercase) == '{}')".format(cat(enigma.lookup(l) for l in string.ascii_lowercase))) # print() diff --git a/test_enigma.py b/test_enigma.py index b30be76..5ff8d9f 100644 --- a/test_enigma.py +++ b/test_enigma.py @@ -157,23 +157,23 @@ class SimpleWheelTest(unittest.TestCase): class WheelTest(unittest.TestCase): def test_init1(self): - wheel = Wheel(wheel_iii_spec, wheel_iii_pegs, position='b', + wheel = Wheel(wheel_iii_spec, wheel_iii_notches, position='b', ring_setting=1) self.assertEqual(wheel.position, 1) - self.assertEqual(wheel.peg_positions, [20]) + self.assertEqual(wheel.notch_positions, [6]) self.assertEqual(wheel.position_l, 'b') wheel.advance() self.assertEqual(wheel.position, 2) - self.assertEqual(wheel.peg_positions, [19]) + self.assertEqual(wheel.notch_positions, [7]) self.assertEqual(wheel.position_l, 'c') def test_init2(self): - wheel = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', + wheel = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3) self.assertEqual(wheel.position, 25) - self.assertIn(11, wheel.peg_positions) - self.assertIn(24, wheel.peg_positions) + self.assertIn(2, wheel.notch_positions) + self.assertIn(15, wheel.notch_positions) self.assertEqual(wheel.position_l, 'b') self.assertEqual(cat(wheel.forward(l) for l in string.ascii_lowercase), @@ -183,13 +183,13 @@ class WheelTest(unittest.TestCase): 'ptlyrmidoxbswhnfckquzgeavj') def test_advance(self): - wheel = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', + wheel = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3) wheel.advance() self.assertEqual(wheel.position, 0) - self.assertIn(10, wheel.peg_positions) - self.assertIn(23, wheel.peg_positions) + self.assertIn(3, wheel.notch_positions) + self.assertIn(16, wheel.notch_positions) self.assertEqual(wheel.position_l, 'c') self.assertEqual(cat(wheel.forward(l) for l in string.ascii_lowercase), @@ -199,14 +199,14 @@ class WheelTest(unittest.TestCase): 'skxqlhcnwarvgmebjptyfdzuio') def test_advance_23(self): - wheel = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', + wheel = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3) for _ in range(23): wheel.advance() self.assertEqual(wheel.position, 22) - self.assertIn(1, wheel.peg_positions) - self.assertIn(14, wheel.peg_positions) + self.assertIn(12, wheel.notch_positions) + self.assertIn(25, wheel.notch_positions) self.assertEqual(wheel.position_l, 'y') self.assertEqual(cat(wheel.forward(l) for l in string.ascii_lowercase), @@ -216,14 +216,14 @@ class WheelTest(unittest.TestCase): 'dymswobuplgraevzkqifntxcjh') def test_advance_24(self): - wheel = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', + wheel = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3) for _ in range(24): wheel.advance() self.assertEqual(wheel.position, 23) - self.assertIn(0, wheel.peg_positions) - self.assertIn(13, wheel.peg_positions) + self.assertIn(0, wheel.notch_positions) + self.assertIn(13, wheel.notch_positions) self.assertEqual(wheel.position_l, 'z') self.assertEqual(cat(wheel.forward(l) for l in string.ascii_lowercase), @@ -233,14 +233,14 @@ class WheelTest(unittest.TestCase): 'xlrvnatokfqzduyjphemswbigc') def test_advance_25(self): - wheel = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', + wheel = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3) for _ in range(25): wheel.advance() self.assertEqual(wheel.position, 24) - self.assertIn(25, wheel.peg_positions) - self.assertIn(12, wheel.peg_positions) + self.assertIn(1, wheel.notch_positions) + self.assertIn(14, wheel.notch_positions) self.assertEqual(wheel.position_l, 'a') self.assertEqual(cat(wheel.forward(l) for l in string.ascii_lowercase), @@ -250,14 +250,14 @@ class WheelTest(unittest.TestCase): 'kqumzsnjepyctxiogdlrvahfbw') def test_advance_26(self): - wheel = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', + wheel = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3) for _ in range(26): wheel.advance() self.assertEqual(wheel.position, 25) - self.assertIn(24, wheel.peg_positions) - self.assertIn(11, wheel.peg_positions) + self.assertIn(2, wheel.notch_positions) + self.assertIn(15, wheel.notch_positions) self.assertEqual(wheel.position_l, 'b') self.assertEqual(cat(wheel.forward(l) for l in string.ascii_lowercase), @@ -267,14 +267,14 @@ class WheelTest(unittest.TestCase): 'ptlyrmidoxbswhnfckquzgeavj') def test_advance_27(self): - wheel = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', + wheel = Wheel(wheel_vi_spec, wheel_vi_notches, position='b', ring_setting=3) for _ in range(27): wheel.advance() self.assertEqual(wheel.position, 0) - self.assertIn(23, wheel.peg_positions) - self.assertIn(10, wheel.peg_positions) + self.assertIn(3, wheel.notch_positions) + self.assertIn(16, wheel.notch_positions) self.assertEqual(wheel.position_l, 'c') self.assertEqual(cat(wheel.forward(l) for l in string.ascii_lowercase), @@ -284,60 +284,60 @@ class WheelTest(unittest.TestCase): 'skxqlhcnwarvgmebjptyfdzuio') def test_set_position(self): - wheel_3 = Wheel(wheel_iii_spec, wheel_iii_pegs, ring_setting=3) + wheel_3 = Wheel(wheel_iii_spec, wheel_iii_notches, ring_setting=3) wheel_3.set_position('a') self.assertEqual(wheel_3.position, 24) self.assertEqual(wheel_3.position_l, 'a') - self.assertEqual(wheel_3.peg_positions, [21]) + self.assertEqual(wheel_3.notch_positions, [5]) wheel_3.set_position('z') self.assertEqual(wheel_3.position, 23) self.assertEqual(wheel_3.position_l, 'z') - self.assertEqual(wheel_3.peg_positions, [22]) + self.assertEqual(wheel_3.notch_positions, [4]) wheel_3.set_position(26) self.assertEqual(wheel_3.position, 23) self.assertEqual(wheel_3.position_l, 'z') - self.assertEqual(wheel_3.peg_positions, [22]) + self.assertEqual(wheel_3.notch_positions, [4]) wheel_3.set_position(27) self.assertEqual(wheel_3.position, 24) self.assertEqual(wheel_3.position_l, 'a') - self.assertEqual(wheel_3.peg_positions, [21]) + self.assertEqual(wheel_3.notch_positions, [5]) wheel_3.set_position('f') self.assertEqual(wheel_3.position, 3) self.assertEqual(wheel_3.position_l, 'f') - self.assertEqual(wheel_3.peg_positions, [16]) + self.assertEqual(wheel_3.notch_positions, [10]) wheel_3.set_position(6) self.assertEqual(wheel_3.position, 3) self.assertEqual(wheel_3.position_l, 'f') - self.assertEqual(wheel_3.peg_positions, [16]) + self.assertEqual(wheel_3.notch_positions, [10]) wheel_3.advance() self.assertEqual(wheel_3.position, 4) self.assertEqual(wheel_3.position_l, 'g') - self.assertEqual(wheel_3.peg_positions, [15]) + self.assertEqual(wheel_3.notch_positions, [11]) wheel_3.set_position(12) self.assertEqual(wheel_3.position, 9) self.assertEqual(wheel_3.position_l, 'l') - self.assertEqual(wheel_3.peg_positions, [10]) + self.assertEqual(wheel_3.notch_positions, [16]) wheel_3.advance() self.assertEqual(wheel_3.position, 10) self.assertEqual(wheel_3.position_l, 'm') - self.assertEqual(wheel_3.peg_positions, [9]) + self.assertEqual(wheel_3.notch_positions, [17]) class EnigmaTest(unittest.TestCase): def setUp(self): self.enigma = Enigma(reflector_b_spec, - wheel_i_spec, wheel_i_pegs, - wheel_ii_spec, wheel_ii_pegs, - wheel_iii_spec, wheel_iii_pegs, + wheel_i_spec, wheel_i_notches, + wheel_ii_spec, wheel_ii_notches, + wheel_iii_spec, wheel_iii_notches, 1, 1, 1, '') @@ -345,17 +345,17 @@ class EnigmaTest(unittest.TestCase): # Enigma simulation settings are # http://enigma.louisedade.co.uk/enigma.html?m3;b;b153;AFTX;AJEU;AU-BG-EY-FP-HL-IN-JZ-OS-QR-TX self.enigma31 = Enigma(reflector_b_spec, - wheel_i_spec, wheel_i_pegs, - wheel_v_spec, wheel_v_pegs, - wheel_iii_spec, wheel_iii_pegs, + wheel_i_spec, wheel_i_notches, + wheel_v_spec, wheel_v_notches, + wheel_iii_spec, wheel_iii_notches, 6, 20, 24, 'ua pf rq so ni ey bg hl tx zj') # Settings for Bletchley Park outreach department's Enigma self.enigma_bp = Enigma(reflector_b_spec, - wheel_i_spec, wheel_i_pegs, - wheel_iii_spec, wheel_iii_pegs, - wheel_ii_spec, wheel_ii_pegs, + wheel_i_spec, wheel_i_notches, + wheel_iii_spec, wheel_iii_notches, + wheel_ii_spec, wheel_ii_notches, 1, 26, 26, 'qm we ro tu zj ps dl fg') @@ -364,42 +364,42 @@ class EnigmaTest(unittest.TestCase): self.enigma.set_wheels('a', 'a', 't') self.assertEqual(self.enigma.wheel_positions, (0, 0, 19)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'aat') - self.assertEqual(self.enigma.peg_positions, ([16], [4], [2])) + self.assertEqual(self.enigma.notch_positions, ([10], [22], [24])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'puvioztjdhxmlyeawsrgbcqknf') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (0, 0, 20)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'aau') - self.assertEqual(self.enigma.peg_positions, ([16], [4], [1])) + self.assertEqual(self.enigma.notch_positions, ([10], [22], [25])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'baigpldqcowfyzjehvtsxrkumn') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (0, 0, 21)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'aav') - self.assertEqual(self.enigma.peg_positions, ([16], [4], [0])) + self.assertEqual(self.enigma.notch_positions, ([10], [22], [0])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'mnvfydiwgzsoablrxpkutchqej') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (0, 1, 22)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'abw') - self.assertEqual(self.enigma.peg_positions, ([16], [3], [25])) + self.assertEqual(self.enigma.notch_positions, ([10], [23], [1])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'ulfopcykswhbzvderqixanjtgm') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (0, 1, 23)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'abx') - self.assertEqual(self.enigma.peg_positions, ([16], [3], [24])) + self.assertEqual(self.enigma.notch_positions, ([10], [23], [2])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'qmwftdyovursbzhxaklejicpgn') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (0, 1, 24)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'aby') - self.assertEqual(self.enigma.peg_positions, ([16], [3], [23])) + self.assertEqual(self.enigma.notch_positions, ([10], [23], [3])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'oljmzxrvucybdqasngpwihtfke') @@ -408,42 +408,42 @@ class EnigmaTest(unittest.TestCase): self.enigma.set_wheels('a', 'd', 't') self.assertEqual(self.enigma.wheel_positions, (0, 3, 19)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'adt') - self.assertEqual(self.enigma.peg_positions, ([16], [1], [2])) + self.assertEqual(self.enigma.notch_positions, ([10], [25], [24])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'zcbpqxwsjiuonmldethrkygfva') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (0, 3, 20)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'adu') - self.assertEqual(self.enigma.peg_positions, ([16], [1], [1])) + self.assertEqual(self.enigma.notch_positions, ([10], [25], [25])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'ehprawjbngotxikcsdqlzyfmvu') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (0, 3, 21)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'adv') - self.assertEqual(self.enigma.peg_positions, ([16], [1], [0])) + self.assertEqual(self.enigma.notch_positions, ([10], [25], [0])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'eqzxarpihmnvjkwgbfuyslodtc') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (0, 4, 22)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'aew') - self.assertEqual(self.enigma.peg_positions, ([16], [0], [25])) + self.assertEqual(self.enigma.notch_positions, ([10], [0], [1])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'qedcbtpluzmhkongavwfirsyxj') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (1, 5, 23)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'bfx') - self.assertEqual(self.enigma.peg_positions, ([15], [25], [24])) + self.assertEqual(self.enigma.notch_positions, ([11], [1], [2])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'iwuedhsfazqxytvrkpgncoblmj') self.enigma.advance() self.assertEqual(self.enigma.wheel_positions, (1, 5, 24)) self.assertEqual(cat(self.enigma.wheel_positions_l), 'bfy') - self.assertEqual(self.enigma.peg_positions, ([15], [25], [23])) + self.assertEqual(self.enigma.notch_positions, ([11], [1], [3])) self.assertEqual(cat(self.enigma.lookup(l) for l in string.ascii_lowercase), 'baknstqzrmcxjdvygiefwoulph') @@ -470,35 +470,35 @@ class EnigmaTest(unittest.TestCase): self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (4, 11, 24)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'jev') - self.assertEqual(self.enigma31.peg_positions, ([7], [21], [0])) + self.assertEqual(self.enigma31.notch_positions, ([19], [5], [0])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'mvqjlyowkdieasgzcunxrbhtfp') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (4, 12, 25)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'jfw') - self.assertEqual(self.enigma31.peg_positions, ([7], [20], [25])) + self.assertEqual(self.enigma31.notch_positions, ([19], [6], [1])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'sjolzuyvrbwdpxcmtiaqfhknge') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (4, 12, 0)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'jfx') - self.assertEqual(self.enigma31.peg_positions, ([7], [20], [24])) + self.assertEqual(self.enigma31.notch_positions, ([19], [6], [2])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'qrxedkoywufmlvgsabpzjnicht') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (4, 12, 1)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'jfy') - self.assertEqual(self.enigma31.peg_positions, ([7], [20], [23])) + self.assertEqual(self.enigma31.notch_positions, ([19], [6], [3])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'hpsukliagqefwvtbjxcodnmrzy') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (4, 12, 2)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'jfz') - self.assertEqual(self.enigma31.peg_positions, ([7], [20], [22])) + self.assertEqual(self.enigma31.notch_positions, ([19], [6], [4])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'zevnbpyqowrtxdifhkulscjmga') @@ -509,238 +509,309 @@ class EnigmaTest(unittest.TestCase): self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 3)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ida') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [21])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [5])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'ikhpqrvcambzjondefwyxgsutl') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 4)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idb') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [20])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [6])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'cdabskhgzwfmlqvunyexpojtri') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 5)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idc') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [19])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [7])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'pcbwiqhgemyvjsuaftnroldzkx') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 6)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idd') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [18])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [8])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'xcbfvdnouptmlghjzwykierasq') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 7)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ide') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [17])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [9])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'xfvglbdynuseriwqpmkzjcoaht') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 8)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idf') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [16])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [10])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'tfpqlbouynsewjgcdxkahzmriv') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 9)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idg') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [15])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [11])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'cjaunvlwtbygzexrspqidfhokm') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 10)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idh') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [14])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [12])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'yltxkrqvowebzpingfucshjdam') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 11)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idi') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [13])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [13])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'myktluzrnxceaiqsohpdfwvjbg') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 12)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idj') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [12])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [14])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'pynjrmiugdqxfcvakewzhoslbt') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 13)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idk') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [11])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [15])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'mwvedyplnoxhaijgrqtszcbkfu') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 14)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idl') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [10])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [16])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'qcbrfeutvoxpnmjladzhgiykws') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 15)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idm') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [9])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [17])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'dnoahryetsmukbcvwfjilpqzgx') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 16)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idn') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [8])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [18])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'nidcfehgbqsovalyjzkxwmutpr') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 17)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ido') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [7])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [19])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'joifxdulcarhzpbntkwqgysevm') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 18)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idp') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [6])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [20])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'ptnlsxvozmwdjchayuebrgkfqi') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 19)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idq') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [5])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [21])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'slwopzqnmxybihdeguavrtcjkf') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 20)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idr') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [4])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [22])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'hcbedwlamzogixkytsrqvufnpj') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 21)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ids') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [3])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [23])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'odxbjwzrmelkisavuhnyqpfctg') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 22)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idt') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [2])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [24])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'udgbfeclrwnhxksvtioqapjmzy') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 23)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idu') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [1])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [25])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'nrdczqxmowvshaiufblypkjgte') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 10, 24)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'idv') - self.assertEqual(self.enigma31.peg_positions, ([8], [22], [0])) + self.assertEqual(self.enigma31.notch_positions, ([18], [4], [0])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'hkifjdoacebqtzgulyvmpsxwrn') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 11, 25)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'iew') - self.assertEqual(self.enigma31.peg_positions, ([8], [21], [25])) + self.assertEqual(self.enigma31.notch_positions, ([18], [5], [1])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'yptzuhofqvnmlkgbixwcejsrad') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 11, 0)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'iex') - self.assertEqual(self.enigma31.peg_positions, ([8], [21], [24])) + self.assertEqual(self.enigma31.notch_positions, ([18], [5], [2])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'vkdcwhqfjibzsptngumoraeyxl') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (3, 11, 1)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'iey') - self.assertEqual(self.enigma31.peg_positions, ([8], [21], [23])) + self.assertEqual(self.enigma31.notch_positions, ([18], [5], [3])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'wenpbqrouxlkychdfgzvitajms') def test_double_advance_with_ring_settings_2(self): self.enigma31.set_wheels('a', 'y', 't') + # self.assertEqual(self.enigma31.wheel_positions, (21, 5, 22)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ayt') + # self.assertEqual(self.enigma31.notch_positions, ([16], [1], [2])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (21, 5, 23)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ayu') + # self.assertEqual(self.enigma31.notch_positions, ([16], [1], [1])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (21, 5, 24)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ayv') + # self.assertEqual(self.enigma31.notch_positions, ([16], [1], [0])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (21, 6, 25)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'azw') + # self.assertEqual(self.enigma31.notch_positions, ([16], [0], [25])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (22, 7, 0)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bax') + # self.assertEqual(self.enigma31.notch_positions, ([15], [25], [24])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (22, 7, 1)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bay') + # self.assertEqual(self.enigma31.notch_positions, ([15], [25], [23])) + self.assertEqual(self.enigma31.wheel_positions, (21, 5, 22)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ayt') - self.assertEqual(self.enigma31.peg_positions, ([16], [1], [2])) + self.assertEqual(self.enigma31.notch_positions, ([10], [25], [24])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'izhrgtecaslkywvqpdjfxonumb') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (21, 5, 23)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ayu') - self.assertEqual(self.enigma31.peg_positions, ([16], [1], [1])) + self.assertEqual(self.enigma31.notch_positions, ([10], [25], [25])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'dtoavihgflwjnmcsrqpbzekyxu') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (21, 5, 24)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'ayv') - self.assertEqual(self.enigma31.peg_positions, ([16], [1], [0])) + self.assertEqual(self.enigma31.notch_positions, ([10], [25], [0])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'xquhtpsdwkjonmlfbvgecriazy') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (21, 6, 25)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'azw') - self.assertEqual(self.enigma31.peg_positions, ([16], [0], [25])) + self.assertEqual(self.enigma31.notch_positions, ([10], [0], [1])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'dofapcluvmngjkbezyxwhitsrq') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (22, 7, 0)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bax') - self.assertEqual(self.enigma31.peg_positions, ([15], [25], [24])) + self.assertEqual(self.enigma31.notch_positions, ([11], [1], [2])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'jdlbmswztapcexrkuofiqygnvh') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (22, 7, 1)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bay') - self.assertEqual(self.enigma31.peg_positions, ([15], [25], [23])) + self.assertEqual(self.enigma31.notch_positions, ([11], [1], [3])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'iydcnuhgawsoxelztvkqfrjmbp') + self.enigma31.set_wheels('a', 'z', 't') + # self.assertEqual(self.enigma31.wheel_positions, (21, 6, 22)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'azt') + # self.assertEqual(self.enigma31.notch_positions, ([16], [0], [2])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (22, 7, 23)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bau') + # self.assertEqual(self.enigma31.notch_positions, ([15], [25], [1])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (22, 7, 24)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bav') + # self.assertEqual(self.enigma31.notch_positions, ([15], [25], [0])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (22, 8, 25)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bbw') + # self.assertEqual(self.enigma31.notch_positions, ([15], [24], [25])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (22, 8, 0)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bbx') + # self.assertEqual(self.enigma31.notch_positions, ([15], [24], [24])) + + # self.enigma31.advance() + # self.assertEqual(self.enigma31.wheel_positions, (22, 8, 1)) + # self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bby') + # self.assertEqual(self.enigma31.notch_positions, ([15], [24], [23])) + self.assertEqual(self.enigma31.wheel_positions, (21, 6, 22)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'azt') - self.assertEqual(self.enigma31.peg_positions, ([16], [0], [2])) + self.assertEqual(self.enigma31.notch_positions, ([10], [0], [24])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'idjbptqwacsvnmregokfzlhyxu') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (22, 7, 23)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bau') - self.assertEqual(self.enigma31.peg_positions, ([15], [25], [1])) + self.assertEqual(self.enigma31.notch_positions, ([11], [1], [25])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'rniszouwcxtvqbfymadkglhjpe') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (22, 7, 24)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bav') - self.assertEqual(self.enigma31.peg_positions, ([15], [25], [0])) + self.assertEqual(self.enigma31.notch_positions, ([11], [1], [0])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'qijfsdmkbchugxtwazeolypnvr') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (22, 8, 25)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bbw') - self.assertEqual(self.enigma31.peg_positions, ([15], [24], [25])) + self.assertEqual(self.enigma31.notch_positions, ([11], [2], [1])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'xprtlozyskjewqfbncidvumahg') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (22, 8, 0)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bbx') - self.assertEqual(self.enigma31.peg_positions, ([15], [24], [24])) + self.assertEqual(self.enigma31.notch_positions, ([11], [2], [2])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'vtfuyczoqxmpkwhlisrbdanjeg') self.enigma31.advance() self.assertEqual(self.enigma31.wheel_positions, (22, 8, 1)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'bby') - self.assertEqual(self.enigma31.peg_positions, ([15], [24], [23])) + self.assertEqual(self.enigma31.notch_positions, ([11], [2], [3])) + assert(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase) == 'tjrhzpqdobwxyuifgcvansklme') def test_encipher_with_ring(self): @@ -751,7 +822,7 @@ class EnigmaTest(unittest.TestCase): 'apocwtjuikurcfivlozvhffkoacxufcekthcvodfqpxdjqyckdozlqki') self.assertEqual(self.enigma31.wheel_positions, (4, 9, 10)) self.assertEqual(cat(self.enigma31.wheel_positions_l), 'jch') - self.assertEqual(self.enigma31.peg_positions, ([7], [23], [14])) + self.assertEqual(self.enigma31.notch_positions, ([19], [3], [12])) self.assertEqual(cat(self.enigma31.lookup(l) for l in string.ascii_lowercase), 'mopnigfuesqwadbcktjrhylzvx')