+ {
+ "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"
+ ]
+ },