Breaking hill ciphers done, challenge 6 done.
authorNeil Smith <neil.git@njae.me.uk>
Sun, 30 Nov 2014 16:04:43 +0000 (16:04 +0000)
committerNeil Smith <neil.git@njae.me.uk>
Sun, 30 Nov 2014 16:04:43 +0000 (16:04 +0000)
2014-challenge6.ipynb
2014/4b.ciphertext
cipher.py
cipherbreak.py
hill-ciphers.ipynb

index ebc0e1f7fa5d5de7faf2cb6379b7234797b83abd..fc91ef688b1ae24c4d7c521afe18aeae8d4ecf9e 100644 (file)
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:2fd72ba7fe3bce3be5a85e8242c119102b9a08ef8f13a01e1c8f9d30d9474858"
+  "signature": "sha256:5973034ac2337d403853a03b7c1d5fdb5ce28d6b3ac7e6be40537ee382e9f648"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
@@ -43,7 +43,7 @@
        "output_type": "pyout",
        "prompt_number": 2,
        "text": [
-        "<matplotlib.axes.AxesSubplot at 0x7fe75a5a9358>"
+        "<matplotlib.axes.AxesSubplot at 0x7fc55c2b98d0>"
        ]
       },
       {
@@ -51,7 +51,7 @@
        "output_type": "display_data",
        "png": "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\n",
        "text": [
-        "<matplotlib.figure.Figure at 0x7fe78652d400>"
+        "<matplotlib.figure.Figure at 0x7fc586677dd8>"
        ]
       }
      ],
@@ -70,9 +70,9 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 11,
+       "prompt_number": 3,
        "text": [
-        "<matplotlib.axes.AxesSubplot at 0x7fe74b6dbeb8>"
+        "<matplotlib.axes.AxesSubplot at 0x7fc55a6375c0>"
        ]
       },
       {
        "output_type": "display_data",
        "png": "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\n",
        "text": [
-        "<matplotlib.figure.Figure at 0x7fe75a5558d0>"
+        "<matplotlib.figure.Figure at 0x7fc55a6462b0>"
        ]
       }
      ],
-     "prompt_number": 11
+     "prompt_number": 3
     },
     {
      "cell_type": "code",
@@ -99,9 +99,9 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 6,
+       "prompt_number": 4,
        "text": [
-        "<matplotlib.axes.AxesSubplot at 0x7fe75a546dd8>"
+        "<matplotlib.axes.AxesSubplot at 0x7fc55a642128>"
        ]
       },
       {
        "output_type": "display_data",
        "png": "iVBORw0KGgoAAAANSUhEUgAAAWwAAAD+CAYAAAAeRj9FAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAGMxJREFUeJztnX+QJGV9h5+Fi/Lrlrst8Tg1ugkVglrGU8SYUsuJQWOI\nXCiNVJmkZNVYRg1CoobDigJWqSepxCtNTKJR7lSMEn8gWKjguaNIlMTIIYqAOb0EU96ReJADRIOy\n+ePtcWdnp2e6353pebvneaqmdrrn/cz32++veefTPb0gIiIiIiIiIiIiIiIiIiIiIiIiIjVjA/BR\n4FvAzcCvAnPANcBtwNVZGRERmTC7gJdkz9cBxwIXA3+W7TsP2D6BvEREpItjge/02X8LsCl7fny2\nLSIiE2QLcD1wCfA14D3A0cCdXWVmerZFRGTEHFagzDrgicC7sr/3Att6yixlDxERGRPrCpT5Xvb4\n12z7o8D5wH6CFbIf2Azc0Ss84YQTlvbu3TuaTEVEpocbCe7GCoqssPcDtwMnZtunAt8ErgTOyvad\nBVzeK9y7dy9LS0urHhdccEHf/YMe065JNS816ealJt28hmmAx/ebjIussAHOBi4FHgTsBV4MHA5c\nBrwU2AecWfC92LdvX9GiaiqMoSZOk2peatLNK1ZTdMK+ETilz/5TS0cUEZEoDh/z+1944YUXrtq5\nYcMG5ufnS73RtGtSzUtNunmpSTevYZqLLroI4KLe/TOlIpRnKfNjRESkIDMzM9Bnfi5y0nHktNtt\nNSU1qealJt281KSbV6xmIhO2iIiUR0tERCQxkrJERESkPHrYNdGkmpeadPNSk25esRpX2CIiNUEP\nW0QkMfSwRURqjh52TTSp5qUm3bzUpJtXrMYVtohITdDDFhFJDD1sEZGao4ddE02qealJNy816eYV\nq3GFLSJSE/SwRUQSQw9bRKTm6GHXRJNqXmrSzUtNunnFalxhi4jUBD1sEZHE0MMWEak5etg10aSa\nl5p081KTbl6xGlfYIiI1QQ9bRCQxJu5hz87OMTMzs+oxOztXVQoiIrWmsgn77rvvBJayx+LPnof9\nw0nZV9KLm25NqnmpSTevWI0etohITSjqYe8DDgE/Be4HngzMAR8BHpW9fiZwV4/uZx528GT6+dkz\n6HOLiCyzVg97CWgBTyBM1gDbgGuAE4Hd2baIiIyJMpZI72y/FdiVPd8FnFH8rdolwmaKhH0lvbjp\n1qSal5p084rVlFlhfw74KvCybN8m4ED2/EC2LSIiY6Koh70Z+D5wHMEGORu4AtjYVeYgwdfuRg9b\nRKQkeR72uoL672d//xv4BMHHPgAcD+wnTOh39BMuLCwwPz+fbe0AthDscOi1RjpfEVqtlttuu+32\n1Gy322127twJ0DVfxnEUsD57fjRwHfBs4GLgvGz/NmB7H+1SB2AJlrLHYtfz5TKDWFxcLFSuqZpU\n81KTbl5q0s1rmIb+dkShFfYmwqq6U/5S4GqCn30Z8FKWL+sTEZExUdm9RPSwRUSKMfF7iYiIyNqY\n0ITdLq9I+NrIKjSp5qUm3bzUpJtXrMYVtohITdDDFhFJDD1sEZGao4ddE02qealJNy816eYVq3GF\nLSJSE/SwRUQSQw9bRKTm6GHXRJNqXmrSzUtNunnFalxhi4jUBD3sCGZn53L/2/v69Rs5dOhgxRmJ\nVE/eOHAMrJ08D9sJO4L8Y4E6Ho9IDE0a06mR2EnHdnlFwr5SFceT8vFPuybVvKrUpDqmU64zPWwR\nkQajJRKBlohIs8Z0aiRmiYiISFn0sEeg0cOebk2qeVWpSXVMp1xnetgiIg1GDzsCPWyRZo3p1NDD\nFhGpOXrYI9DoYU+3JtW8qtSkOqZTrjM9bBGRBqOHHYEetkizxnRq6GGLiNQcPewRaPSwp1uTal5V\nalId0ynXmR62iEiD0cOOQA9bpFljOjX0sEVEak7RCftw4Abgymx7DrgGuA24GthQLmy7XHHS9pX0\nsKdbk2peVWpSHdMp19k4PexzgJtZ/v6zjTBhnwjszrZFRGSMFPGwHwHsBN4M/ClwOnAL8AzgAHA8\n4eP1pD5aPWyRhtKkMZ0aa/Gw3w68Dniga98mwmRN9nfTGvMTEZEhrBvy+nOBOwj+dSunzBL5y00W\nFhaYn5/PtnYAW7LnLXp9r46n02q1Vm13+z39Xu+3vWPHDrZs2VK4fLvdZs+ePZx77rkDy3dl3PV8\nvMeT0vH3q4/uHKfteKb1+ANt+vX9VI6nLv253W6zc+dOgK75sjxvAW4Hvgt8H7gX+ADBEjk+K7M5\n2+7HUgdgCZayx2LX8+Uyg1hcXCxUrgrNymOp5nhSOn411cdIUVOHMZ1anRXVkLMILnMd9jOA1xI8\n7IuBHwBvI5xw3ED/E49Z7Gb5XXrYIs0a06kxquuwO62wHXgW4bK+Z2bbIiIyRspM2F8AtmbPDwKn\nEi7rezZwV7mw7XLFSfvaSK/Dnm5NqnlVqUl1TKdcZzEaf+koIlITvJdIBHrYIs0a06nhvURERGqO\n98MegUYPe7o1qeZVpSbVMZ1ynelhi4g0GD3sCPSwRZo1plNDD1tEpOboYY9Ao4c93ZpU86pSk+qY\nTrnO9LBFRBqMHnYEetgizRrTqaGHLSJSc/SwR6DRw55uTap5ValJdUynXGd62CIiDUYPOwI9bJFm\njenU0MMWEak5etgj0OhhT7cm1byq1KQ6plOuMz1sEZEGo4cdgR62SLPGdGroYYuI1Bw97BFo9LCn\nW5NqXlVqUh3TKdeZHraISIPRw45AD1ukWWM6NfSwRURqjh72CDR62NOtSTWvKjWpjumU60wPW0Sk\nwehhR6CHLdKsMZ0aetgiIjVHD3sEGj3s6dakmleVmlTHdMp1Ng4P+wjgemAPcDPw1mz/HHANcBtw\nNbChdGQRESlFEQ/7KOCHwDrgS8Brga3A/wAXA+cBG4FtfbR62LImZmfnuPvuO1ftX79+I4cOHRxr\njFHHaRpNGtOpkedhlznpeBTwBWAB+BjwDOAAcDzh+9BJfTRO2LImqug3tmccTRrTqbGWk46HESyR\nA8Ai8E1gU7ZN9ndTuXTa5YqTtq+kh12Npqp+UzZOynXWtLaZ9nGzrkCZB4AtwLHAZ4Ff73l9ifzl\nCQsLC8zPz2dbO7K36tBeUbZzAK1WayTbe/bsKa3fs2fP0PJ5+Y/7eIpsn3ba6dx33z3048gjj+Gq\nq65c8/Hn1ce4jm+ZPdnf4voq2nPY66n359jjyUrRaY+y/b+K40mxP/c7/na7zc6dOwG65svVlL0O\n+w3AfcAfElppP7CZsPLWEgmvTvR4Us4tBi2RdGnSmE6NWEvkISxfAXIk8CzgBuAK4Kxs/1nA5SPJ\nUkREchk2YW8GPk/4Lno9cCWwG9hOmLxvA56ZbZegXa44aftKqXrY1rMedtPapopxk7JmmId9E/DE\nPvsPAqeWjiYiItF4L5EIUvY8U84tBj3sdGnSmE4N7yUiIlJzvJfICDR62NVo9LDT1aTa11Kus3F4\n2CIiE8PbBqxEDzuClD3PlHOLQQ87XWyb8aGHLSJSc/SwR6DRw65Go4ddTDM7O8fMzMyqx+zs3Nhy\ns22q0bjCFmkYwfPt3OJn8WfP87xgqQ962BGk7KulnFsM+qTlqWqs2TbjQw9bRKTm6GGPQKOHXY1G\nn7S8JtU6qypOym2jhy0i0mD0sCNI2VdLObcY9EnLo4ddf/SwRURqjh72CDR62NVo9EnLa1Kts6ri\npNw2etgiIg1GDzuClH21lHOLQZ+0PHrY9UcPW0Sk5uhhj0Cjh12NRp+0vCbVOqsqTspto4ctItJg\n9LAjSNlXSzm3GPRJy6OHXX/0sEVGSN4tTMvcxlSkLHrYI9DoYVejScknzbuFadHbmE5jnU0iTsr9\nWQ9bRKTB6GFHkLKvlnJuMaTqk6Zcz3rY9UcPW0Sk5uhhj0Cjh12NJlWfNOV6TrfO9LD1sEVEGkwR\nD/vngfcDDyWYSe8G3gHMAR8BHgXsA84E7urR6mFXTMq5xZCqT5pyPeth15+1eNj3A38CPBZ4CvAq\n4NHANuAa4ERgd7YtIiJjosiEvR/Ykz2/B/gW8HBgK7Ar278LOKN42Hbxoh1Fwr6SHnY1mlR90pTr\nOd0608OuwsOeB54AXA9sAg5k+w9k2yIiMibWlSh7DPAx4Bzg7p7XOj/zWsXCwgLz8/PZ1g5gC9DK\nttsrynY+cVqt1qrtVqs18PV+2519Rcv3fuINe305//EfT5nyq3NsLW/1qY+tW5/X99d5Rx55DFdd\ndWXp+qvqeCbdnlW2f/d7Fq+v3u248TAon+X2aK2Kl8rxFM2nqv7c7/jb7TY7d+4E6JovV1P0hzM/\nB3wK+DRh1gW4hdBK+4HNhN/nntSj86RjxYz2BNrk2ybVE1v17AOedKwLaznpOAO8F7iZ5cka4Arg\nrOz5WcDlxdNpFy/aUSTsKzXJw065bVL1Sa2zdOOkPG/EaIpYIk8F/gD4OnBDtu98YDtwGfBSli/r\nExGRMeG9RCJI+WualsgoY+THqWcfmA5LZHZ2LveOievXb+TQoYMjyW2c5FkiZU46iogkz/Ktb/u9\nNu416njxXiIj0OhhV6NJ1Se1zlKOUz5GynON9xIREakJetgR1NO/BD3ssjHy49SzD0yHh51y2xTF\n+2GLiNQcPewRaPSwq9Hok5bXpFtnto0etohIg9HDJv+6zbxrNlP2yPSwRxkjP049+4Ae9qTbpihe\nhz2AvOs2637Npog0Cz3s1apKNHrY5TX6pOU16daZbTOue4lMjLJWRco04eeyIjJZkvawU/XiUvbV\n9LBHGSM/Tso+aarjZrQx8uOk3DZF8TpsEZGaUxsPO12PrBpNyseiH1s+hnVm2zTOwxaJoUnnPpqG\nbbM29LAj4qTsq+lhN6s9Y0h13MRomtY2RdHDFhGpOXrYI4ijh12NJtW2aVqd2TbpavSwRURvuSbo\nYUfESdlX08NuVnvGUNVYs23Ghx62iEjN0cMeQRw97Go0qbZN0fKzs3PMzMz0fczOzg2P0qg6q0pT\nPkbKHrYrbJGKWL4r5BKw2PV8Kfc+MyLd6GFHxEnZV9PDTrc9J98H9LBT6NNF0MMWEak5etgjiDMu\nzVo9z5True5tU32MptVZVZryMfSwJQo9TxHpRg87Ik7KnqcedrPaM4ZU/egYTcr1PE7W4mG/DzgA\n3NS1bw64BrgNuBrYsPYURURkEEUm7EuA5/Ts20aYsE8EdmfbJWiXKx6paZbnV0WMOI0edhUxmlZn\nVWnKxxhnf847L1XsnFSxCftaoNcw3Qrsyp7vAs4oFE1EZIrJOy9V9JxUUQ97HrgSeFy2fSewses9\nDnZtd6OHXWvN5P2+Jvmketjptk1VFD3+cV6H3fm4EBGRMRJ7e9UDwPHAfmAzcEdewYWFBebn57Ot\nHcCW7HmLXn+p4wO1Wq3uvX3L9ivfu71jxw62bNmS+/pq36kN7AHOXRFjcPkORY6nnVu2f/mOprd8\nq2/51fl16nv5/YYfz/Dj76dvtVpD26N7u1cbczzptGfR8h1Nb9lW3/LtdpvTTjud++67h17Wr9/I\nFVd8fFX5lbQp056jO57+5SfTnt3lV76eWn9eWFgA6Jov45ln5VUiFwPnZc+3AdtzdEsdgCVYyh6L\nXc+Xy/QSo+lmcXGxULmycVaWr0qz2KOvQjPaeo7RVNFvmtY2TdJU1TbdpNCfQ7nVFPGw/xF4BvAQ\nwsr6jcAngcuARwL7gDOBu3Im7BBID7uGGj3sdDX186NjNHrYKyliibwwZ/+pBbSV43/OEJEqmMRc\n07h7iaz1spkmXU+a8vXBzbqmuIoYauI05WMU7ZuTmGu8l4iISE1o3L1EmuSrTV6jh52upn7jJkaT\nsoc9zuP3ftgiIjWncR52czVVxIjT6GFXEUNNnKZ8jJT7pitsEZGaoIcdoZm8f1mVRg87XU39xk2M\nRg97Ja6wRWTqWfu/46sGPezaaKqIEafRw64ihpo4TbHya/93fGXzitO4whYRqQl62BGayfuXVWn0\nsNPV1G/cxGgmX88xGj1saQBr/fdIItOOHnZtNFXEiNOkfO+FaW8bNVXEqE7jCltEpCboYUdoJu+R\nVaXJr7OYW0vanmn5pHXQTL6eYzTj87Bj/0WYTDnL9kbv/nGvAUSmFz3s2miqiKEmTlNFDDVxmipi\nVKfRwxYRqQl62BGayXtkVWnq1zYxmsnXc4ymfvUco5l8PcdovA5bRGTq0cOujaaKGGriNFXEUBOn\nqSJGdRpX2CIiNUEPO0IzeY+sKk392iZGM/l6jtHUr55jNJOv5xiNHraIyNSjh10bTRUx1MRpqoih\nJk5TRYzqNK6wRURqgh52hGbyHllVmvq1TYxm8vUco6lfPcdoJl/PMRo9bBGRqWetE/ZzgFuAbwPn\nFZe1I0JNu6aKGGriNFXEUBOnqSJGdZq1TNiHA39NmLQfA7wQeHQx6Z6IcNOuSTUvNenmpSbdvOI0\na5mwnwz8O7APuB/4MPA7xaR3RYSbdk2qealJNy816eYVp1nLhP1w4Pau7e9l+0REZAysZcLOO6Va\ngH1qSmuqiKEmTlNFDDVxmipiVKdZy2V9TwEuJHjYAOcDDwBv6yqzB3j8GmKIiEwjNwJbRvmG64C9\nwDzwIMLkXPCko4iIVM1vAbcSTj6eP+FcREREREQmT5X/4noO+CXgwV37vjig/JHAK4GnEU5wXgv8\nLfCjEeXzmq7nSyzXRedk6l8N0B4G/D7wC8CbgEcCxwP/MqLcOvn15vW/wL+RfwHnEcDzCTbVui7d\nm0aU03XAU4F7WH3SeQk4CPwF8Dd9tCcTcu/mucCnRpRbh1OA17O6Dn5lgCam3rYAT2e5b944JK+Y\n/tyvD3Q/7+2jM8AjWHn1Vkpc0GffKPtn46nqp+kvA74AfAa4CPgs4YTlIN5P+EHOOwg/0Hks8IEC\nmo1d23PA+3LKrgeOIUwkrwAeRrgs8Y+AJw6J8y7g14Dfy7bvyfb1o5PzuUPes5eTs1w6eb2cYEG9\nh/xflX4S2Eq4Lv6e7HFvTtnrsr/3AHf3PA7laJ6a/T2GUH/dj9ks51fnaN8DPK5r+4XAG3PK9stp\nWG4dLgUuIUzAp2ePrUM0ZeoN4Bzgg8BxwKbsed5xd4jpz3l9s1P//fj0kPfsx5mE9gN4A/AJho+B\ntxXc1829LNfvTwn9eX6I5jWUu1z4g4T55qQSmsf02dcaonk1K+eaInwe+O2efe8u+R6V8A3CCqOz\nMjyJ0CkGcXPBfd30W3kO+znRtazs/OuzfYO4oecv5K+wbiYMuK8TPkB6H4PyOqZr+xjCN5KjgG/l\naL4xMOtqeFjO/l8EvkZo+5cRju/YMcS/bniRVZStt5uAo7u2j872DSKmP8f0zV2EH7WVoZP70wi/\nl34ucP0QzQ199g2rg14eTFjIDeJC4JvAl4A/JnxADuKZhJX8NcB3gY8xfLH0DcIiaIYwvt4JfGWI\n5s2Ec3eXEa6UK+JWfJcwhru/afSrx4nz1ezvHsLXTxjeWT9IWMV2eArDVyQ3snISnGN4J7q1Kyey\n57cO0VxP+Gl+p7KPI7/iX02YYH9MaLDux3cGxLiFcPVNhwd35ZUX690M/uo/aX6ZUBefIQyMcfBs\n4L2EFfzzs8fzhmjK1ttNhAVIhyMZ3s9i+nNM37yVsHr9TpbTTYTFwiA6i5rtBKsP8vvYK7L3/GHX\n+99EuKj40iFxepkjTHpFeDxhkrwV2D2k7DpC/b4e+E+G19nRhG89XyFM3q+nmPtwGGGy/jDhON4C\nnDCg/A1Zbu8CrgQ2UHLCXje8yEi4nfD14XLCJ9+d5F813un46wirpdsJPtcjGV7xfwl8mfCpNwO8\ngNDIg3g/wXv+eKY5g7BKGcQ7Cd8QHkpopN8F/jyn7Duyx98RvtIW5VLCB8PlWV6nAx8idK7eD7tO\nnR0OvJjwYfDjbN8w/3bc9E5kc4SOfj3jye0swgfDOsLvAjp8fIDm6ZSrt0sI+Xf3mTzrrcOT6N+f\nbxoQK6Zv/uaQ1/vxX4QPrWcRJu0jyJ+wPkSwXbazvCqFYFf9YEic7r5wGGH8FPWv7wD2ZzGOG1Bu\nN2GMfJmwKn9Sph3ET4D7CB+8RxA+7B4YqAg8kOV0gPAhuRH4KPA54HUDYr0SWCB8Wyplq1R50rFD\ni+CXfQb4vz6vzw/QLgH/MeT9H0v4WrRE8IyGreQheIWdE0hfpNin3qOB38ie7ybfplgLpxB84yXC\nYP9qTrn5Ie+zb3QplWZ+yOv7RhzvVoLtUuaXuPM5+/cN0JzMyhOIw/pMXoxhsWL6ZlmOJqwUv064\n8+ZmwvmGq0ccZ77r+U8IE939QzSvJHjsDwX+CfgIg8f02wmT9I+AfyZYLl8mTMh53AhcQfjweAjw\n94QP7hcM0JwDvIjwAfIPhAXc/YQPom/Tf6X98uy9O5wMvAp4yYA4Io3mEsKHtjSDtxL3i7/1wNmE\nBd6Ph5Q9pc++Fw3RXAQ8Kue1ficxR8IkVtgi4+QWwuomJVtIquNswjeSkwl94Nrs8flJJjUqqvKw\nRariOcOLSIM5gnAu62sMt1tERERERERERERERERERERERBLk/wGh1P0qDD3LLgAAAABJRU5ErkJg\ngg==\n",
        "text": [
-        "<matplotlib.figure.Figure at 0x7fe75a4abe48>"
+        "<matplotlib.figure.Figure at 0x7fc55a5a5400>"
        ]
       }
      ],
-     "prompt_number": 6
+     "prompt_number": 4
     },
     {
      "cell_type": "code",
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 7,
+       "prompt_number": 5,
        "text": [
         "'mtaeglatcleptenopeautelebiiootatwnantateituiiagaeostgvetabdresiacqobwavgrhrsihssaekajbwwttdrsmeetnyafsegilegtkrreocuantteomsgstnsiaeluutrbaiaeteeserhxgtooarrbhpcklialhnaesvearhbepiydcesewtaxuyaerywoeinhteegeisieireaassrbitnhtuorooleewsttereoahyakhlsmsaeodslthsutigqimnidsgetpmwtrnnotfhvselkaumrndvcnrluceryhyeetlnigouncnanrhpnosbhshpslreclvrinfoehniaeennhcrbenrgunruesmlrehiutgteordroeaeoisoeusiknteeslohthdcrmisuteoteaeoshfaiaesemritrseisaigwyrmhrbtetncoenuhorcadeodlcrncomnctosihudtcinagesntisutigytmshthyalatlsnhilguimtlbfldyhrfrnetsaosteetaefhlgokhretcakuteihrlrtlsetshlcpeadhthyutaeennhryraeennihrnbhnsnehyutsdtoywmtiatalwhvbepetlxihuscrtadtikhnxmsaesnwluevgnrcpegvnhteruigeuealsdntikeaeomctwrybusiilephkyodhrsyhecaatrmrltrarretstuoetnuesiduaidoesisaeetbllerpntroisiatsiasesomihsieiaunsaitneelacrfnrnngvetteenslhvpepteonedtnaooutgsotancetimiiwoetiuihclsewtcniieotslfbeecohenpoelsdoctceeemiiirttmhbiuovecegaitjuaborcleentatruyinetsidlaeehitwencceohwvohoatwkteroarhcseer'"
        ]
       }
      ],
-     "prompt_number": 7
+     "prompt_number": 5
     },
     {
      "cell_type": "code",
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 3,
+       "prompt_number": 6,
        "text": [
         "'hwssswxfewhhrfewpdrvttdhxbccleayphalnadhiehaoudrotwnrrvysabjlttbaytmelrkaidopthatlelrtwaamaneksvvzrvllatkcrjquicizgtoqcpnrrkttowandqehtqrvtbaydqealannohulanuzlwextlvjrvivhnohdqmgykaclmswrupdetfioftfelhzpxhaswftwprrsweiseohefpdrvttnvagdvswgoerbetnharvaeevtlltbmgaiatgelinmdawevhatterdhrznbnvoutnefoteveaehlaymhacglzeptvvdimworfisgtuzlwibeqohubtghamqornjnnrumqvjtxeltfovgawdaeevllgrtxibgtibevmpsaateoasevaeyqohameonncfuidoefafattemuimnflznbekofobrliaehhauihnnnwzaeevtlltpaalnanvtzlzuucptaelinanpaahewfthaosetaribnbnvhaevdhyytlmuxb'"
        ]
       }
      ],
-     "prompt_number": 3
+     "prompt_number": 6
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "key_a, score = keyword_break_mp(c6a)\n",
+      "key_a, score = railfence_break(c6as)\n",
       "key_a, score"
      ],
      "language": "python",
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 4,
-       "text": [
-        "(('ad', <KeywordWrapAlphabet.from_a: 1>), -1231.3855550875928)"
-       ]
-      }
-     ],
-     "prompt_number": 4
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "print(' '.join(segment(keyword_decipher(sanitise(c6a), key_a[0], key_a[1]))))"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "output_type": "stream",
-       "stream": "stdout",
+       "prompt_number": 7,
        "text": [
-        "mt aegl at dle pte nope aut elec ii oot a twn an tate itu ii a gae ostg vetacbresiadqocwavgr hrsihssaekajcwwttbrs meet nyafsegilegtkrreodu ant teom sgstnsiaeluutrcaiae teese rhxgtooarrchpdklialh naesvearhcepiybdesew tax uyaerywoeinhteegeisi eire a as src it nh tu or ooleewsttereoahyakhl sms aeobslthsutigqimnibs get pm wtr n not fhvselkaumrnbvdnr luder yhyeetlnigoundnanrhp no schs hp sl red lvr info ehniaeennhdrcenrgun rues mlrehiutgteorbroeaeo is oe us ikn tees loh th bdrm is uteoteaeoshfaiaesemr it rse is aigwyrmhrctetndoenuh or da be obldrndomndtosihubtd in ages ntis utigytmshthyalatlsnh il gui mtl cfl by hr fr net sao steet ae fhlgokhretdakuteihrl rtl sets hldpeabhthyutaeennhr yraeennihrnchnsnehyu tsb toy wmtiatalwhvcepetlxih us dr tab tikhnxmsaesnwluevgnr dpegvnhteruigeuealsb nt ikea eo mdt wrycusiilephkyobhrsy he da at rmrltrarretstuoetnue sibu aibo es is ae etc ller pn troisi at sias eso mi hsie i a unsa it neela dr fnr nng vet teens lhv pep te one bt nao out g sot and e tim i iwo et iuihdlsewtdniieotslf cee do hen poels bod tdeeemiiirttmhciuove de gait jua cordle ent a truy in etsi bla ee hit wend de ohwvohoatwkteroarhd seer\n"
+        "(3, -2314.997881051078)"
        ]
       }
      ],
-     "prompt_number": 5
+     "prompt_number": 7
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "key_a, score = column_transposition_break_mp(c6as)\n",
-      "key_a, score"
+      "' '.join(segment(railfence_decipher(c6as, key_a)))"
      ],
      "language": "python",
      "metadata": {},
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 10,
+       "prompt_number": 8,
        "text": [
-        "(((0, 4, 3, 7, 2, 1, 5, 6, 8), False, True), -2617.4798034835794)"
-       ]
-      }
-     ],
-     "prompt_number": 10
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "print(' '.join(segment(sanitise(column_transposition_decipher(sanitise(c6as), key_a[0], \n",
-      "                                                              fillcolumnwise=key_a[1], \n",
-      "                                                              emptycolumnwise=key_a[2])))))"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "mferkepsethibrsnbeal sir nth ce gate wr so go in olohhlkghcuipeahw tue ssn try uav ilp cer ongaro ltm rtn tee echo trs clparoecilstkblopavd eu temes ron tees geico et wg vs ntp in ssn of cehctthmoearotntieeu leese hhetrnrirsnmetueauii ill hoe iea ie so algie iberhueaeritcyuuunt is a a tenn to hd krash mole h blach tco las irb a pdsid tbi tel man neu wac set en ondra tier vahneeklgentcoeeauct hods acne aym see rrgtunlrofuaetcthmne ii a thx crs tteosgtnmjuesutwnlu in it or grain hioyvebahugabehogrdq ruti ray tir stu cerc mb i et loa in hi ege seni pln tete ad ces engng sk plot vneglhhraeiseikvdt thn tay prr art plo eoubnimhdpeydbswnht air hut are en entre soo ess in syn it in gnvhessaeyoeedoichtt acted qymfranuloushhaasabt hvb to i ewst serokeadhepmunhvtyli rtti go a kylgetryladtsewhwauc rose rmt meat lnstlrsraociisnernhc hand we c test hv tte hosa i cast d hall nxticwewgruumrvkhuly oimoaviuaeiihjbmcetw so beter no uaw pl ryu ett we by we tew ttfhosioktllyeiuttdx dei die eri yen u harsh hth ace om url tilo a esf nedss rec rieoehhtrnggewfcnteo estas ya tui ici eads nss na efta cia i ersion eei seks a ieee ght nr to miner ebtrlxehalsiemtp all tg sans ef rta eos rbs\n"
+        "'mark the last message told usa lot the scuttling equipment is designed to pump water in and out of the vessel like a submarine dive control but clearly they werent planning to turn a container ship into a sub this ship is a largescale version of something i have seen in the caribbean drug runners use a similar technique to get below radar coverage for inshore runs sinking the vessel so that the deck remains just below the wave tops the fda pirates seem more interested in staying away from shore but getting close enough to track and record electronic communications without detection i am guessing this scuttling system is what they call nautilus in their log but i am still baffled by the references to seahorse the next page of the log looks harder to crack but the cipher clerk tells me it is a hill cipher and that they must have been in a hurry or have been enciphering by hand since they just used a two by two matrix actually we have been pretty lax with our security and i think the next message is end will use avi genere cipher given that we are using secure cables i dont think we have too much to worry about so i will keep the keyword short say three characters more later harry'"
        ]
       }
      ],
-     "prompt_number": 13
+     "prompt_number": 8
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "key_a, score = railfence_break(c6as)\n",
-      "key_a, score"
+      "key_b, score = hill_break(c6bs)\n",
+      "key_b, score"
      ],
      "language": "python",
      "metadata": {},
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 16,
+       "prompt_number": 14,
        "text": [
-        "(3, -2314.997881051078)"
+        "(matrix([[0, 1],\n",
+        "         [1, 1]]), -666.1299098341699)"
        ]
       }
      ],
-     "prompt_number": 16
+     "prompt_number": 14
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "' '.join(segment(railfence_decipher(c6as, key_a)))"
+      "' '.join(segment(hill_decipher(key_b, c6bs)))"
      ],
      "language": "python",
      "metadata": {},
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 17,
+       "prompt_number": 13,
        "text": [
-        "'mark the last message told usa lot the scuttling equipment is designed to pump water in and out of the vessel like a submarine dive control but clearly they werent planning to turn a container ship into a sub this ship is a largescale version of something i have seen in the caribbean drug runners use a similar technique to get below radar coverage for inshore runs sinking the vessel so that the deck remains just below the wave tops the fda pirates seem more interested in staying away from shore but getting close enough to track and record electronic communications without detection i am guessing this scuttling system is what they call nautilus in their log but i am still baffled by the references to seahorse the next page of the log looks harder to crack but the cipher clerk tells me it is a hill cipher and that they must have been in a hurry or have been enciphering by hand since they just used a two by two matrix actually we have been pretty lax with our security and i think the next message is end will use avi genere cipher given that we are using secure cables i dont think we have too much to worry about so i will keep the keyword short say three characters more later harry'"
+        "'phase six seahorse operated exactly as planned with good forward visibility at the trial depths the crew managed several tasks requiring concentration and dexterity and we plan to run a full test overnight on dummy cables dropped from the ship the software seems to be operating as designed but there are still bugs in the firmware that need ironing out before we deploy the collective is working full time to hunt them down and remove them though we are all getting tired mistakes are easy to make and could be fatal time is no longer on our side though and we are still planning to launch the final phase of the operation in three days timex'"
        ]
       }
      ],
-     "prompt_number": 17
+     "prompt_number": 13
     },
     {
      "cell_type": "code",
index cf2c74b3c4f02756337af569050f27642969fade..cd9848f99f7c39d7a2461ba012e6083b01d9f70e 100644 (file)
@@ -1 +1,2 @@
-PRSAO EGERA UIADM WEHDN ISNRA SAWUA AESSR EFGDO SOGVO RBEEE AARTE SCTDF MENUI BRTTL MEYTU MTMEU AIKWH UTKWE RWAHM NPWRA EESON ONESE BATOI HACIN EETBR OTADA KTGFE ESYIO FLTTL STIIA EOSVI EONSR RTAUP MNNOA ENCOC NUVRS CLVDR GCTAI IHRIC IAIHR SDUOM RLEMC RNGLE OMARF HIUEW HALCS ASRAC UFRAW WSMEH ULSTO AOHCE LETMT OILSE PDMUM TPTRS LYRHH NTPAN WPMOA DPPDW BESEO ASSLT MLPES LETUN CORER LCLIT AOSVS INIIF WSEAF ORTAA DUYEN ENONN SOPFH ONTWK OERTC SLYVO EIOHL UFOEI OETST HTSBR ENEVE AOUEP GIEES OBDUO RSFEE RCDYA DUTAE PEADR DIGSE EBFUO GGOPO GALYF EWSOE EMDNT OHREB HAAES NEWOR GNFIA ULNLW ADUEO DCOTR ARGVU ENEWH IERTL AUILM SONIO TMUIN EWAIU EWLOE RSTTT ISDRS ASNUS SIESM ERDHE TRYRH PNLRT EREAD MREDE BNNTR NENWM OUTRD OSANE OWOMC GIDCI ASAON TIIOI ASCES ISSUP CRMOY BRINE YWEEL AYLEW TYRTI LHSTO
\ No newline at end of file
+PRSAO EGERA UIADM WE
+HDN ISNRA SAWUA AESSR EFGDO SOGVO RBEEE AARTE SCTDF MENUI BRTTL MEYTU MTMEU AIKWH UTKWE RWAHM NPWRA EESON ONESE BATOI HACIN EETBR OTADA KTGFE ESYIO FLTTL STIIA EOSVI EONSR RTAUP MNNOA ENCOC NUVRS CLVDR GCTAI IHRIC IAIHR SDUOM RLEMC RNGLE OMARF HIUEW HALCS ASRAC UFRAW WSMEH ULSTO AOHCE LETMT OILSE PDMUM TPTRS LYRHH NTPAN WPMOA DPPDW BESEO ASSLT MLPES LETUN CORER LCLIT AOSVS INIIF WSEAF ORTAA DUYEN ENONN SOPFH ONTWK OERTC SLYVO EIOHL UFOEI OETST HTSBR ENEVE AOUEP GIEES OBDUO RSFEE RCDYA DUTAE PEADR DIGSE EBFUO GGOPO GALYF EWSOE EMDNT OHREB HAAES NEWOR GNFIA ULNLW ADUEO DCOTR ARGVU ENEWH IERTL AUILM SONIO TMUIN EWAIU EWLOE RSTTT ISDRS ASNUS SIESM ERDHE TRYRH PNLRT EREAD MREDE BNNTR NENWM OUTRD OSANE OWOMC GIDCI ASAON TIIOI ASCES ISSUP CRMOY BRINE YWEEL AYLEW TYRTI LHSTO
\ No newline at end of file
index cd75d2cc505f61d788ac190cc186810ff32f6b04..91e64e51e6f6fc403f088dd44b20db11b5f4593a 100644 (file)
--- a/cipher.py
+++ b/cipher.py
@@ -656,7 +656,6 @@ def hill_encipher(matrix, message_letters, fillvalue='a'):
     return ''.join([chr(int(round(l)) % 26 + ord('a')) 
             for l in sum(enciphered_chunks, [])])
 
-
 def hill_decipher(matrix, message, fillvalue='a'):
     """Hill cipher
 
@@ -671,6 +670,7 @@ def hill_decipher(matrix, message, fillvalue='a'):
     inverse_matrix = (inverse_determinant * adjoint) % 26
     return hill_encipher(inverse_matrix, message, fillvalue)          
 
+
 class PocketEnigma(object):
     """A pocket enigma machine
     The wheel is internally represented as a 26-element list self.wheel_map, 
index e563b81c071410c0bfc2350687d955942076da1f..b1af48c2e40d1ba60b948e75c758ab162f242233 100644 (file)
@@ -416,6 +416,19 @@ def scytale_break_mp(message, max_key_length=20,
 scytale_break = scytale_break_mp
 
 
+def railfence_break(message, max_key_length=20,
+                     fitness=Pletters, chunksize=500):
+    """Breaks a hill cipher using a matrix of given rank and letter frequencies
+
+    
+    """
+    
+    sanitised_message = sanitise(message)
+    results = starmap(worker, [(sanitised_message, i, fitness)
+                               for i in range(2, max_key_length+1)])
+    return max(results, key=lambda k: k[1])
+
+
 def railfence_break(message, max_key_length=20,
                      fitness=Pbigrams, chunksize=500):
     """Breaks a railfence cipher using a range of lengths and
@@ -445,13 +458,45 @@ def railfence_break(message, max_key_length=20,
         plaintext = railfence_decipher(message, height)
         fit = fitness(plaintext)
         return height, fit
-        
+
     sanitised_message = sanitise(message)
     results = starmap(worker, [(sanitised_message, i, fitness)
                                for i in range(2, max_key_length+1)])
     return max(results, key=lambda k: k[1])
 
 
+def hill_break(message, matrix_size=2, fitness=Pletters, 
+    number_of_solutions=1, chunksize=500):
+
+    all_matrices = [np.matrix(list(m)) 
+        for m in itertools.product([list(r) 
+            for r in itertools.product(range(26), repeat=matrix_size)], 
+        repeat=matrix_size)]
+    valid_matrices = [m for m, d in 
+        zip(all_matrices, (int(round(linalg.det(m))) for m in all_matrices))
+                  if d != 0
+                  if d % 2 != 0
+                  if d % 13 != 0 ]
+    with Pool() as pool:
+        helper_args = [(message, matrix, fitness)
+                       for matrix in valid_matrices]
+        # Gotcha: the helper function here needs to be defined at the top level
+        #   (limitation of Pool.starmap)
+        breaks = pool.starmap(hill_break_worker, helper_args, chunksize)
+        if number_of_solutions == 1:
+            return max(breaks, key=lambda k: k[1])
+        else:
+            return sorted(breaks, key=lambda k: k[1], reverse=True)[:number_of_solutions]
+
+def hill_break_worker(message, matrix, fitness):
+    plaintext = hill_decipher(matrix, message)
+    fit = fitness(plaintext)
+    logger.debug('Hill cipher break attempt using key {0} gives fit of '
+                 '{1} and decrypt starting: {2}'.format(matrix, 
+                     fit, sanitise(plaintext)[:50]))
+    return matrix, fit
+
+
 def pocket_enigma_break_by_crib(message, wheel_spec, crib, crib_position):
     """Break a pocket enigma using a crib (some plaintext that's expected to
     be in a certain position). Returns a list of possible starting wheel
index 909828a7128a24b58686adbd0085daeaa71d8ab7..2019dd5b600618d8d93d69e6ad5cf79b60aa45bf 100644 (file)
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:0fe9165e4a65606dd93377df5e8d4ccf8671a4edf4adc8d5da4b33f83316516f"
+  "signature": "sha256:112d1c84c318592f927e18c5b0f15ed60ac8418ca15cb79596ba6212ff2d7e3f"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
      ],
      "prompt_number": 184
     },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "len([list(m) for m in itertools.product([list(r) for r in itertools.product(range(26), repeat=3)], repeat=3)])"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "ename": "KeyboardInterrupt",
+       "evalue": "",
+       "output_type": "pyerr",
+       "traceback": [
+        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
+        "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
+       ]
+      }
+     ],
+     "prompt_number": 203
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "(3**3)**3"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 202,
+       "text": [
+        "19683"
+       ]
+      }
+     ],
+     "prompt_number": 202
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "[np.matrix(list(m)) for m in itertools.product([list(r) for r in itertools.product(range(3), repeat=2)], repeat=2)]"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 206,
+       "text": [
+        "[matrix([[0, 0],\n",
+        "         [0, 0]]), matrix([[0, 0],\n",
+        "         [0, 1]]), matrix([[0, 0],\n",
+        "         [0, 2]]), matrix([[0, 0],\n",
+        "         [1, 0]]), matrix([[0, 0],\n",
+        "         [1, 1]]), matrix([[0, 0],\n",
+        "         [1, 2]]), matrix([[0, 0],\n",
+        "         [2, 0]]), matrix([[0, 0],\n",
+        "         [2, 1]]), matrix([[0, 0],\n",
+        "         [2, 2]]), matrix([[0, 1],\n",
+        "         [0, 0]]), matrix([[0, 1],\n",
+        "         [0, 1]]), matrix([[0, 1],\n",
+        "         [0, 2]]), matrix([[0, 1],\n",
+        "         [1, 0]]), matrix([[0, 1],\n",
+        "         [1, 1]]), matrix([[0, 1],\n",
+        "         [1, 2]]), matrix([[0, 1],\n",
+        "         [2, 0]]), matrix([[0, 1],\n",
+        "         [2, 1]]), matrix([[0, 1],\n",
+        "         [2, 2]]), matrix([[0, 2],\n",
+        "         [0, 0]]), matrix([[0, 2],\n",
+        "         [0, 1]]), matrix([[0, 2],\n",
+        "         [0, 2]]), matrix([[0, 2],\n",
+        "         [1, 0]]), matrix([[0, 2],\n",
+        "         [1, 1]]), matrix([[0, 2],\n",
+        "         [1, 2]]), matrix([[0, 2],\n",
+        "         [2, 0]]), matrix([[0, 2],\n",
+        "         [2, 1]]), matrix([[0, 2],\n",
+        "         [2, 2]]), matrix([[1, 0],\n",
+        "         [0, 0]]), matrix([[1, 0],\n",
+        "         [0, 1]]), matrix([[1, 0],\n",
+        "         [0, 2]]), matrix([[1, 0],\n",
+        "         [1, 0]]), matrix([[1, 0],\n",
+        "         [1, 1]]), matrix([[1, 0],\n",
+        "         [1, 2]]), matrix([[1, 0],\n",
+        "         [2, 0]]), matrix([[1, 0],\n",
+        "         [2, 1]]), matrix([[1, 0],\n",
+        "         [2, 2]]), matrix([[1, 1],\n",
+        "         [0, 0]]), matrix([[1, 1],\n",
+        "         [0, 1]]), matrix([[1, 1],\n",
+        "         [0, 2]]), matrix([[1, 1],\n",
+        "         [1, 0]]), matrix([[1, 1],\n",
+        "         [1, 1]]), matrix([[1, 1],\n",
+        "         [1, 2]]), matrix([[1, 1],\n",
+        "         [2, 0]]), matrix([[1, 1],\n",
+        "         [2, 1]]), matrix([[1, 1],\n",
+        "         [2, 2]]), matrix([[1, 2],\n",
+        "         [0, 0]]), matrix([[1, 2],\n",
+        "         [0, 1]]), matrix([[1, 2],\n",
+        "         [0, 2]]), matrix([[1, 2],\n",
+        "         [1, 0]]), matrix([[1, 2],\n",
+        "         [1, 1]]), matrix([[1, 2],\n",
+        "         [1, 2]]), matrix([[1, 2],\n",
+        "         [2, 0]]), matrix([[1, 2],\n",
+        "         [2, 1]]), matrix([[1, 2],\n",
+        "         [2, 2]]), matrix([[2, 0],\n",
+        "         [0, 0]]), matrix([[2, 0],\n",
+        "         [0, 1]]), matrix([[2, 0],\n",
+        "         [0, 2]]), matrix([[2, 0],\n",
+        "         [1, 0]]), matrix([[2, 0],\n",
+        "         [1, 1]]), matrix([[2, 0],\n",
+        "         [1, 2]]), matrix([[2, 0],\n",
+        "         [2, 0]]), matrix([[2, 0],\n",
+        "         [2, 1]]), matrix([[2, 0],\n",
+        "         [2, 2]]), matrix([[2, 1],\n",
+        "         [0, 0]]), matrix([[2, 1],\n",
+        "         [0, 1]]), matrix([[2, 1],\n",
+        "         [0, 2]]), matrix([[2, 1],\n",
+        "         [1, 0]]), matrix([[2, 1],\n",
+        "         [1, 1]]), matrix([[2, 1],\n",
+        "         [1, 2]]), matrix([[2, 1],\n",
+        "         [2, 0]]), matrix([[2, 1],\n",
+        "         [2, 1]]), matrix([[2, 1],\n",
+        "         [2, 2]]), matrix([[2, 2],\n",
+        "         [0, 0]]), matrix([[2, 2],\n",
+        "         [0, 1]]), matrix([[2, 2],\n",
+        "         [0, 2]]), matrix([[2, 2],\n",
+        "         [1, 0]]), matrix([[2, 2],\n",
+        "         [1, 1]]), matrix([[2, 2],\n",
+        "         [1, 2]]), matrix([[2, 2],\n",
+        "         [2, 0]]), matrix([[2, 2],\n",
+        "         [2, 1]]), matrix([[2, 2],\n",
+        "         [2, 2]])]"
+       ]
+      }
+     ],
+     "prompt_number": 206
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "all_matrices = [np.matrix(list(m)) for m in itertools.product([list(r) for r in itertools.product(range(26), repeat=2)], repeat=2)]\n",
+      "valid_matrices = [m for m, d in zip(all_matrices, (int(round(linalg.det(m))) for m in all_matrices))\n",
+      "                  if d != 0\n",
+      "                  if d % 2 != 0\n",
+      "                  if d % 13 != 0 ]\n",
+      "len(valid_matrices)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "metadata": {},
+       "output_type": "pyout",
+       "prompt_number": 215,
+       "text": [
+        "157248"
+       ]
+      }
+     ],
+     "prompt_number": 215
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "%%timeit\n",
+      "[m for m, d in zip(all_matrices, (int(round(linalg.det(m))) for m in all_matrices))\n",
+      "                  if d != 0\n",
+      "                  if d % 2 != 0\n",
+      "                  if d % 13 != 0 ]\n",
+      "print('done')"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "done\n",
+        "done"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "done"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "done"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "1 loops, best of 3: 10 s per loop\n"
+       ]
+      }
+     ],
+     "prompt_number": 216
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "%%timeit\n",
+      "[m for m in all_matrices\n",
+      "                  if int(round(linalg.det(m))) != 0\n",
+      "                  if int(round(linalg.det(m))) % 2 != 0\n",
+      "                  if int(round(linalg.det(m))) % 13 != 0 ]\n",
+      "print('done')"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "done\n",
+        "done"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "done"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "done"
+       ]
+      },
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "\n",
+        "1 loops, best of 3: 20.4 s per loop\n"
+       ]
+      }
+     ],
+     "prompt_number": 217
+    },
     {
      "cell_type": "code",
      "collapsed": false,