Implemented Bifid ciphers, solved 2016 week 7
authorNeil Smith <neil.git@njae.me.uk>
Fri, 16 Dec 2016 15:23:02 +0000 (15:23 +0000)
committerNeil Smith <neil.git@njae.me.uk>
Wed, 4 Oct 2017 08:24:00 +0000 (09:24 +0100)
2016/2016-challenge7.ipynb [new file with mode: 0644]
2016/7a.ciphertext [new file with mode: 0644]
2016/7b.ciphertext [new file with mode: 0644]
bifid-ciphers.ipynb [new file with mode: 0644]
cipher.py
cipherbreak.py
hill-ciphers.ipynb

diff --git a/2016/2016-challenge7.ipynb b/2016/2016-challenge7.ipynb
new file mode 100644 (file)
index 0000000..0b1cf5b
--- /dev/null
@@ -0,0 +1,259 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import os,sys,inspect\n",
+    "currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))\n",
+    "parentdir = os.path.dirname(currentdir)\n",
+    "sys.path.insert(0,parentdir) \n",
+    "\n",
+    "import matplotlib.pyplot as plt\n",
+    "%matplotlib inline\n",
+    "\n",
+    "from cipherbreak import *\n",
+    "\n",
+    "c7a = open('7a.ciphertext').read()\n",
+    "c7b = open('7b.ciphertext').read()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'ELUOP PAIJO NPAVX VHLDQ ZCDUY LZVJK WTDVL VGZZE LLWKU AYMLF KUSSK PLOJZ EXHPK LZYGH VLHZD MSMXX PEXFV UHPPP ARAXP YQHXF INPJF EEHZT BHQJI QYQAE ZNQZT SEJIP XWZXS BEPDL MDYMP EYEEF LOLUE JIYJI YXFCE DMYIL HTRVV VLMLP DHLQY SEGOA VHLEA YIVHF JTSYX YHZLY SFYWW MKELC NOVHB AGLYG KILUN TLUCK MOAMO XFYPH BLFFI TEKHV WNYTM OXXIP CCAGA JCLMS GSYGL PASFI OWTPX KYHOV HLLUP OZLLW ELQWA HWPTC BUSUL LXTHH OISOV HXKLP OVBXG HZOMD RAAYT AVPUM TEMUI ZNELP AIJUH LMISL SWPSP PQFSR QOAGH SEWII JUJPP AXSBE OVHSD MZCIL RJIYT OUMNC WSBVF WLLJM OXLUS EMCIA FPMMD WWCCL QKMKV FDAAM XIPYW YSWFW PLHXA WJMLL XUYEZ ZWKFC PMPAS TYCLL UEJYS EWUEW HZSBP AFITE IJMFO XXWJR AYCLG LLLYG PQSIT YHCIT PSXLT TLQSD DTMNE LIZQM OXFCY LUVAW BEEIO XVHLC WUCSL EYQAV SGDTB JIHMF DMOXL USEGA RAUEC MJVSY YSBPA WPPTT LFWQD YWPWM FNYWJ IUHLW TPINL FDVLZ WMCFW MCLHP HBYIV HFDQR RSVZW AVIZN OYIKI JIETV VQYHT PJLVS GCTND EDYSE UVVXX YLWAW DFLNT SEVYS NBHAQ FPDWS GYHTP JZMVH LVVHF WBEEI FKGFZ YPJIL LPECW QGWZE AZIUW LOMZM JISEC HRMHT POHKF YZEGJ EJCAD VVGXI DPOYE ZWRYQ KRWJW TIIRG XPDIL PWLDL EAGWJ DFALL LYWWM KELCN CMYYL WLQCU EEMXC ILLLL ZQARV GQSNQ OAELT QEHPS IEOMN RGFPM OUEJY SEIOX WFTMW TIZNO PEVLK YNLZA PDUNL TSEUY SEMRE EIEOM DSDFL YMLFV USPPS MLHFD VVMLM PFYLV GGJYI YIOMY LWAHW MFQMY XUYAD CZIZN EFJYI FCLEM YRGLP JEHPS YGLPV XWPTE KLPDI NRVPO UUSLN VVWVX PUHVG ZWLCZ YFODL EAMLU SEBBS VYEYQ VTWQC PGDED MTSTS EUIEO MKRSG POGSH WNLPX LVVHL OMAEL CRLGS LYCSP UHGWV ENMWW MMPSB ZMZNE FWIEV YVDIU IZQYZ QAEYC EDMCR ALPOV BHGCC PXLLL AYTZB HZWYL ZIIEU DPPAX SXPZM KMNHP ENVWS QYZQA TALND MKWJU XWIKK FCSNB HQFUX ZEHXS BEOMJ MLIYZ ASEWQ CPDLA GBHPQ CVWNY TBHHW VTCKZ IVYSD MPXAP TEKHI ZNSEQ DHWCW WIAIJ YSEAA MKCGD QOXSB EOMDS ZMDTA FPSHL CMOXJ OQOVH OFUMD QOXXI PRIAS GZJMJ VPWPP TZAIJ IEEVL WWLPH AARWA LSKUE JVZWA VRSHT XQOJG YRLBV SXXLS MDXSB EPDLM DYMZB KIEYP DMOKF CCZBP RGGYP MIHSB PHSUE TMDTE ZIZNX ZZMOF UMEVL VWZQT LFPWL TEVLR SNFZJ HKFCV WIAWS QENMW WMMPS BAEZN EYMYE HJLPU HGWVE TZLZW QZSOU MFITE ALYIL PSBYY XLPOV BINCE NMSPG WPSBF FFYVL BUIWV OLPUS ANNLZ LLLLF QWUSK XYFWM RWYMO IOWWM DPVRE WQZYB HLLXY LMZMU LPIMA EZYET PDEKU HEQKI ECLWK LLKCS ENVCL CWLOL PWBEE CVFSX PRVLP DUSNV LLOSE TZBGW MDVVH FWBEQ WAWWN YZQAE JNPYM WIUHL WMLVX UYZVV MLCOP XEIYH TSAPL HUQZB YEHML PDPXU YWWWJ IZNQZ NSEZY MYWKI LCDTD KEZYS EIOXV YXTIS GWBOY IRRSV LQWFF TIWPP ARAGT SNVIY UEZWM HSBPH BHLLX PWILZ WLPHZ LHJUS RVPLK OASBB SEIEO VHLYH TGQSI FIPXW ZVGZQ QWSPW QZZBL FGNOP ZHIHJ LPPAE ZNEFW KILHT ZXLAF YSHVL ZWYGC MZIJB DLKZM ZNAPS LLWLP SEUMS FAIMA SFXWF WDVGN ZYLSY GWPSA PLLHZ OMZWW LAYMO ALOME VBSUW LVVHF SYGLP VXLIY OVHWA MLMPZ EUUYZ GSIJC EYMRV GQZEL LQAUW NMOXK LTQBH WLHPX MNRSL CLTHM UHLYQ MWLWP AABWW BEZBK IFLFE MDOFU MDAPA KYSEP AMOJT SAUSA NLWMY WJIYJ IYXLO ZMIUA GHVJL HIJFL DIDXS BHWIL ZWLZE BVRWL LNOUM CUEEQ AYGVL VTHXG NOPZH TWLAE WUWSQ OYIKR ABPMB HLLFW LBMID XLSMO XSBEO MAELM ENMWW MMPSB KPABN LAHIJ YSEMT MLZZE VBSEU PWJHV WXTDV VGSNY PXZIZ NDPON YKMNT BZMJY ENIYE ZWPNQ VZLUS EBJEX YSEMA MHMPO TSELU VFMOX ZNTHA RRAFZ YLUYG ZDRVP KFIWP JZXUY ADCZI ZNQZP JVSYD LVVMK MPCXW SXIWZ WAEWL PHALW SVLEI KEFXE LPAKF CELBZ WAMJW IUEJI QPTWQ SMLYL HIVCG ZZWSL MEDMB UWLOP ABJWL PSVPX JUXPJ VXKYX LRKIL WPAAB WWQEL PAPSY GPZAS FXTOM DXMVC ZVFEJ NYTBY EEZZO VHXUY ADCZI ZNQZA JMJNP XWPFW BEYML ALYMY WPXSF PCZVG XIPPZ NIVBR TPHHW QZSAZ MKSWL VHWWC ETZVL LOLJB PWJYG TVBIZ NSEQD XMIOP SJIZW JCWAW KCSWM AEZWF PVUMW WYPQJ WJYEF XTSUH TPUTE JAZCX LXSOO LZNEE ICQBB SHICO ILFGN OPUPE DWOYI UMLLL XALQS DQZMT EFYSE VPWLH PXCJS VSETB UIVCJ EQSEM KSRQO KFCJC ZHGKU HEKLT KODPP AWAHX ZZMWH YCOVH EKHTX MJRSX YPBAE FCCZV FEJNY TBYEE BETED IAPCP BUMEI CQALX GH\\n'"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c7as = sanitise(c7a)\n",
+    "c7ar = cat(reversed(c7as))\n",
+    "c7a"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('esullih', -3786.443520764479)"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "key_a, score = vigenere_frequency_break(sanitise(c7a))\n",
+    "key_a, score"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('usehill', -3786.443520764477)"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "key_a, score = vigenere_frequency_break(sanitise(c7ar))\n",
+    "key_a, score"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "notes from interview with martin traynor in attendance mins a and reps from n is the suspect was carrying high quality identity documents in the name of james martin and claimed to be a dropout from a graduate programme in computer science in neuchatel his story checked out with the university authorities analysis showed a high degree of correlation between the biometrics of the suspect and of martin traynor but we did not reveal that we suspected james to be martin he refused requests to provide a dna sample for analysis stating that dna databases were a tool of oppression a search of the suspects belongings found no links with the uk at all despite the fact that voice characteristics suggest he spent a considerable amount of time there as a child the suspect stated that he had left all that behind and was not prepared to talkabout it taking care not to reveal what was already known about traynor s relationship with the swiss bank we turned to the suspects financial arrangements at first he claimed to work entirely on a cash basis and not to have a bank account but when pressed on this he could not or would not explain where he kept his cash reserve even when we pointed out that he appeared to be too well off for someone living hand to mouth pushing harder we revealed that we had footage of him in the lobby of a bank and he claimed that he had visited on behalf of the collective as part of a phishing expedition on a freelance penetration test of the banks security when challenged about the legality of this he claimed it was a white hat exercise and that no weaknesses had been found sono further action had been taken by the collective under further questioning however it became apparent that the suspect was talking about an entirely different bank from the swiss bank we had been monitoring he seemed to believe that we had footage of him in an oslo branch agents were sent to retrieve lobby footage of this bank and further analysis showed that his visits there tallied with the activities he described at interview however we also noticed that a woman matching dal mars description was often video ed at the same branch during the period under investigation when asked about this the suspect became highly agitated and repeatedly demanded to call his lawyer we pointed out that it was unusual for a member of a hacking collective to have a lawyer on retainer but the suspect refused to answer anymore questions until he had been allowed to make the call a call trace showed the mobile that he rang belonged to a lawfirm which works for the arms manufacturer citadelle the suspect was released on bail pending charges of conspiracy to engage in unauthorised access to computer technology at the bank and is being closely watched all calls to and from the lawfirm are being monitored and the oslo bank is under twentyfourseven surveillance conclusions we believe with near certainty that the suspect is martin traynor and that the woman in the footage is jamelia dal mar we believe they are in communication with one another and are both being protected by citadelle or one of its subsidiaries we believe that they are both living in or near oslo and that they are both now highly likely to be aware that the net is closing in we do not understand how dal mar contrived to fake her death and we still do not have a clear picture of the interaction between the pds syndicate dynamix and citadelle nor do we fully understand why they have a strong interest in traynor and dal mar we believe that some or all of that information maybe contained in the encrypted files on traynor s laptop which has been passed to forensics for analysis and to secure the data\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(wcat(segment(vigenere_decipher(sanitise(c7ar), key_a))))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'HTPEG WEEHW AOHCP NIRXE IEXZG OGDQK UEGBY KHWAO CDOTQ OTSLY OELDU MOSEQ OQYTP RNNIG ABADV QIAXV OODEE GWSSF QRGGS YEGWS SEQSX BTKBR FTGBY KBKEU QNETC KSOQB FOTSY QEOSU RBCTE KYORM TPLRA TTKMO BKEUO KCNDZ MROTR NCOYW QKPSH VTCVN FTQET CALWA VVFUK BSKFH RASAQ VFCRS GBTTT QWNEV YFRHE AQCHS QQTNN DPBTC PZEGR EAKKO HURRO CXNQG KNCQS TBSNQ BMTZO OSEBO RXKDE HEHRO YKEOB BFIKQ TTCIZ CCORU IHGYT IMBAH OAWOO ZSOQR OCDSS OQDGE YMKLO AQKXO BKPSF HSVLK WTEHN ATKTO UKNSI OCYDL TQGIT NUOCR KCEPO SRQCQ QCQSR HLWNO SKENN BTFLO LENAW BOCYT NETRN OWDEK SOQIP DWHEA WLOVV YFSCD OTLIN SOSYQ OPYNH TOCON RPTHN AWCOO DYTCO RETHL ULAEQ RPBNZ CSEHC ISDNR TNDTS PSQFC RBNPS YSRBE UELKE QTEYQ QLZLY KSOBD KNTGT WBURR BLQAK BSCVL IIUVT FQBPA KGSTC LSFSC KSKSO BAORE BQEVC BHQBL SVIQO ULKOT HQNFO IOSAH RATKT OXQUE HRYNB KPSKQ OFNWS EUOCX SOQYO VEFSC NREQS PUOED LFWKF ORUIN GTKGO ASDQS GEYMK QOPIO DEVSF NCERS QUPES OQYWB EKBQK PIADC OIUGN CTOII VOQBT ZCPEN BHZKA GOYCQ PCDET MIWFE BGEUE ORYCG SYEKM OQIPD AOCUI NGTHW AOQVT ETVCU BTOYS OQYBQ YBGLT NKVTF VQTFH STQES RQDEU MUKNS IOCYF ERRBL SRHQS THKPE TRPEW BEOSB QKQMP ZBRUE BLHTH HCSBD ACIGC YRENT HRAUQ NENKT ONOTW THUIK HIOOS GQEGO HXIRW TEINS QYFFQ NKTLT RSCNE TRGEY DANRL HFPTK TOFDQ TSOQR AGFTL HVNTS NYIIV OQETS BKFYO SEPQI VLTOY EHMIR WHEAW GOTBO QXRHR AKBRR GTXPR SEHFL RBIFL QOODE GAENO OUXWL ELSEH THMIR UDKQA DVTIH ROICC QTOYE HMIRI HWOIB CRQLP LWHEA WXOBO FYQEV RTRGX QLBQN TBYYR EBTRT TEENR MSDHQ OQXTC LOIFE QTHUA TOOUW BNTSI BDUKH SNQVR ARCTH VRSEC QSNSO QYSFH RGUTR OUREI OVUQP UTTLA VNVMT SLXDN HOAWB OEPGQ ECKEO THEAU OTUVL CLBPE QGCEE KQNTB GEUEO RYEBT QGELR SOQYV TTYHM IRVTT XHQOV FOKRK QFENK NOBLE LCQRR WGOEO LSOGE YNHUA TOVUF NHTZX DSTUL QFSCQ QGHYC NVSCU EURLK ASLOD TSBQR MRPET LMENH TASGS TFOTD HQTUN IWQIP OKOME GGFTT GOEXV TCMBM ARGEY NKFOS KTYEO BDUKB SEMCT RQVRI UITZB RYDCF SOSCQ RLIQO EAEBB SRQGP ECDAQ VBDUB GCYEQ ETSBK FYGEY NOUTE QTTNG SUQDK SYSGB ZUFKR LOBGT VWIWS OQOKD YSGBZ UCKRG EYIGO ENKKO MANE'"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c7bs = sanitise(c7b)\n",
+    "c7br = cat(reversed(c7bs))\n",
+    "c7b"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[('o', 138),\n",
+       " ('t', 126),\n",
+       " ('e', 124),\n",
+       " ('q', 109),\n",
+       " ('s', 103),\n",
+       " ('r', 90),\n",
+       " ('b', 77),\n",
+       " ('k', 75),\n",
+       " ('n', 73),\n",
+       " ('c', 70),\n",
+       " ('h', 63),\n",
+       " ('g', 58),\n",
+       " ('y', 57),\n",
+       " ('i', 54),\n",
+       " ('u', 54),\n",
+       " ('l', 52),\n",
+       " ('a', 51),\n",
+       " ('f', 46),\n",
+       " ('d', 43),\n",
+       " ('v', 42),\n",
+       " ('w', 37),\n",
+       " ('p', 37),\n",
+       " ('m', 25),\n",
+       " ('x', 20),\n",
+       " ('z', 15)]"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "collections.Counter(c7bs).most_common()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(('ligo', <KeywordWrapAlphabet.from_a: 1>), -2505.924490942904)"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_break_mp(c7bs, wordlist=['gravity', 'ligo'])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'martin we have made a dreadful mistake and i have been too slow to admit that to myself i have had a visit from the woman from the syndicate and i confronted her about the source of the templates she confirmed my worst fears and now i want to crawl away and die what have we done our software has led to so much suffering when it was designed to do the opposite i asked her how the cabinet office could possibly have authorised this and she laughed and explained that the syndicate no longer worked for the british government call it private enterprises he said we have always been good at that my horror must have been written all over myfaces he didnt seem surprised at my reaction but equally she didnt take it well and civility was abandoned i asked her how it could be legal let alone moral to do what they proposed and her answer was that it was necessary i said we wouldnt help them and she said it was necessary that we did i said i wouldnt be able to face my family and friends if we cooperated and she said i wouldnt have to worry about that for long one way or another the pds syndicate were going to make sure we both disappeared looking back i can see that from the start this whole thing has acted to draw us into its centre and now i am at the event horizon almost unable to escape its pull but i think we have one last chance i am sure she will be visiting you as well she thinks we have no choice but i think a choice is all we have whatever you do hold out for better terms she has to believe that you are on side and motivated by greed so that she wont worry about any qualms you might have convince her that you will convince me to cooperate tell her that you think you should work from the collective in oslo and that you want payment via the bank in switzerland i got the impression that money is not a problem with money in a swiss bank and the expertise and connectivity afforded by the collective i think we have a chance to escape and to try to stop them perhaps we will survive this perhaps we can bring them down'"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "wcat(segment(bifid_decipher(c7bs, 'ligo', KeywordWrapAlphabet.from_a, period=4)))"
+   ]
+  },
+  {
+   "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.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}
diff --git a/2016/7a.ciphertext b/2016/7a.ciphertext
new file mode 100644 (file)
index 0000000..1a7c8d8
--- /dev/null
@@ -0,0 +1 @@
+ELUOP PAIJO NPAVX VHLDQ ZCDUY LZVJK WTDVL VGZZE LLWKU AYMLF KUSSK PLOJZ EXHPK LZYGH VLHZD MSMXX PEXFV UHPPP ARAXP YQHXF INPJF EEHZT BHQJI QYQAE ZNQZT SEJIP XWZXS BEPDL MDYMP EYEEF LOLUE JIYJI YXFCE DMYIL HTRVV VLMLP DHLQY SEGOA VHLEA YIVHF JTSYX YHZLY SFYWW MKELC NOVHB AGLYG KILUN TLUCK MOAMO XFYPH BLFFI TEKHV WNYTM OXXIP CCAGA JCLMS GSYGL PASFI OWTPX KYHOV HLLUP OZLLW ELQWA HWPTC BUSUL LXTHH OISOV HXKLP OVBXG HZOMD RAAYT AVPUM TEMUI ZNELP AIJUH LMISL SWPSP PQFSR QOAGH SEWII JUJPP AXSBE OVHSD MZCIL RJIYT OUMNC WSBVF WLLJM OXLUS EMCIA FPMMD WWCCL QKMKV FDAAM XIPYW YSWFW PLHXA WJMLL XUYEZ ZWKFC PMPAS TYCLL UEJYS EWUEW HZSBP AFITE IJMFO XXWJR AYCLG LLLYG PQSIT YHCIT PSXLT TLQSD DTMNE LIZQM OXFCY LUVAW BEEIO XVHLC WUCSL EYQAV SGDTB JIHMF DMOXL USEGA RAUEC MJVSY YSBPA WPPTT LFWQD YWPWM FNYWJ IUHLW TPINL FDVLZ WMCFW MCLHP HBYIV HFDQR RSVZW AVIZN OYIKI JIETV VQYHT PJLVS GCTND EDYSE UVVXX YLWAW DFLNT SEVYS NBHAQ FPDWS GYHTP JZMVH LVVHF WBEEI FKGFZ YPJIL LPECW QGWZE AZIUW LOMZM JISEC HRMHT POHKF YZEGJ EJCAD VVGXI DPOYE ZWRYQ KRWJW TIIRG XPDIL PWLDL EAGWJ DFALL LYWWM KELCN CMYYL WLQCU EEMXC ILLLL ZQARV GQSNQ OAELT QEHPS IEOMN RGFPM OUEJY SEIOX WFTMW TIZNO PEVLK YNLZA PDUNL TSEUY SEMRE EIEOM DSDFL YMLFV USPPS MLHFD VVMLM PFYLV GGJYI YIOMY LWAHW MFQMY XUYAD CZIZN EFJYI FCLEM YRGLP JEHPS YGLPV XWPTE KLPDI NRVPO UUSLN VVWVX PUHVG ZWLCZ YFODL EAMLU SEBBS VYEYQ VTWQC PGDED MTSTS EUIEO MKRSG POGSH WNLPX LVVHL OMAEL CRLGS LYCSP UHGWV ENMWW MMPSB ZMZNE FWIEV YVDIU IZQYZ QAEYC EDMCR ALPOV BHGCC PXLLL AYTZB HZWYL ZIIEU DPPAX SXPZM KMNHP ENVWS QYZQA TALND MKWJU XWIKK FCSNB HQFUX ZEHXS BEOMJ MLIYZ ASEWQ CPDLA GBHPQ CVWNY TBHHW VTCKZ IVYSD MPXAP TEKHI ZNSEQ DHWCW WIAIJ YSEAA MKCGD QOXSB EOMDS ZMDTA FPSHL CMOXJ OQOVH OFUMD QOXXI PRIAS GZJMJ VPWPP TZAIJ IEEVL WWLPH AARWA LSKUE JVZWA VRSHT XQOJG YRLBV SXXLS MDXSB EPDLM DYMZB KIEYP DMOKF CCZBP RGGYP MIHSB PHSUE TMDTE ZIZNX ZZMOF UMEVL VWZQT LFPWL TEVLR SNFZJ HKFCV WIAWS QENMW WMMPS BAEZN EYMYE HJLPU HGWVE TZLZW QZSOU MFITE ALYIL PSBYY XLPOV BINCE NMSPG WPSBF FFYVL BUIWV OLPUS ANNLZ LLLLF QWUSK XYFWM RWYMO IOWWM DPVRE WQZYB HLLXY LMZMU LPIMA EZYET PDEKU HEQKI ECLWK LLKCS ENVCL CWLOL PWBEE CVFSX PRVLP DUSNV LLOSE TZBGW MDVVH FWBEQ WAWWN YZQAE JNPYM WIUHL WMLVX UYZVV MLCOP XEIYH TSAPL HUQZB YEHML PDPXU YWWWJ IZNQZ NSEZY MYWKI LCDTD KEZYS EIOXV YXTIS GWBOY IRRSV LQWFF TIWPP ARAGT SNVIY UEZWM HSBPH BHLLX PWILZ WLPHZ LHJUS RVPLK OASBB SEIEO VHLYH TGQSI FIPXW ZVGZQ QWSPW QZZBL FGNOP ZHIHJ LPPAE ZNEFW KILHT ZXLAF YSHVL ZWYGC MZIJB DLKZM ZNAPS LLWLP SEUMS FAIMA SFXWF WDVGN ZYLSY GWPSA PLLHZ OMZWW LAYMO ALOME VBSUW LVVHF SYGLP VXLIY OVHWA MLMPZ EUUYZ GSIJC EYMRV GQZEL LQAUW NMOXK LTQBH WLHPX MNRSL CLTHM UHLYQ MWLWP AABWW BEZBK IFLFE MDOFU MDAPA KYSEP AMOJT SAUSA NLWMY WJIYJ IYXLO ZMIUA GHVJL HIJFL DIDXS BHWIL ZWLZE BVRWL LNOUM CUEEQ AYGVL VTHXG NOPZH TWLAE WUWSQ OYIKR ABPMB HLLFW LBMID XLSMO XSBEO MAELM ENMWW MMPSB KPABN LAHIJ YSEMT MLZZE VBSEU PWJHV WXTDV VGSNY PXZIZ NDPON YKMNT BZMJY ENIYE ZWPNQ VZLUS EBJEX YSEMA MHMPO TSELU VFMOX ZNTHA RRAFZ YLUYG ZDRVP KFIWP JZXUY ADCZI ZNQZP JVSYD LVVMK MPCXW SXIWZ WAEWL PHALW SVLEI KEFXE LPAKF CELBZ WAMJW IUEJI QPTWQ SMLYL HIVCG ZZWSL MEDMB UWLOP ABJWL PSVPX JUXPJ VXKYX LRKIL WPAAB WWQEL PAPSY GPZAS FXTOM DXMVC ZVFEJ NYTBY EEZZO VHXUY ADCZI ZNQZA JMJNP XWPFW BEYML ALYMY WPXSF PCZVG XIPPZ NIVBR TPHHW QZSAZ MKSWL VHWWC ETZVL LOLJB PWJYG TVBIZ NSEQD XMIOP SJIZW JCWAW KCSWM AEZWF PVUMW WYPQJ WJYEF XTSUH TPUTE JAZCX LXSOO LZNEE ICQBB SHICO ILFGN OPUPE DWOYI UMLLL XALQS DQZMT EFYSE VPWLH PXCJS VSETB UIVCJ EQSEM KSRQO KFCJC ZHGKU HEKLT KODPP AWAHX ZZMWH YCOVH EKHTX MJRSX YPBAE FCCZV FEJNY TBYEE BETED IAPCP BUMEI CQALX GH
diff --git a/2016/7b.ciphertext b/2016/7b.ciphertext
new file mode 100644 (file)
index 0000000..d097a1f
--- /dev/null
@@ -0,0 +1 @@
+HTPEG WEEHW AOHCP NIRXE IEXZG OGDQK UEGBY KHWAO CDOTQ OTSLY OELDU MOSEQ OQYTP RNNIG ABADV QIAXV OODEE GWSSF QRGGS YEGWS SEQSX BTKBR FTGBY KBKEU QNETC KSOQB FOTSY QEOSU RBCTE KYORM TPLRA TTKMO BKEUO KCNDZ MROTR NCOYW QKPSH VTCVN FTQET CALWA VVFUK BSKFH RASAQ VFCRS GBTTT QWNEV YFRHE AQCHS QQTNN DPBTC PZEGR EAKKO HURRO CXNQG KNCQS TBSNQ BMTZO OSEBO RXKDE HEHRO YKEOB BFIKQ TTCIZ CCORU IHGYT IMBAH OAWOO ZSOQR OCDSS OQDGE YMKLO AQKXO BKPSF HSVLK WTEHN ATKTO UKNSI OCYDL TQGIT NUOCR KCEPO SRQCQ QCQSR HLWNO SKENN BTFLO LENAW BOCYT NETRN OWDEK SOQIP DWHEA WLOVV YFSCD OTLIN SOSYQ OPYNH TOCON RPTHN AWCOO DYTCO RETHL ULAEQ RPBNZ CSEHC ISDNR TNDTS PSQFC RBNPS YSRBE UELKE QTEYQ QLZLY KSOBD KNTGT WBURR BLQAK BSCVL IIUVT FQBPA KGSTC LSFSC KSKSO BAORE BQEVC BHQBL SVIQO ULKOT HQNFO IOSAH RATKT OXQUE HRYNB KPSKQ OFNWS EUOCX SOQYO VEFSC NREQS PUOED LFWKF ORUIN GTKGO ASDQS GEYMK QOPIO DEVSF NCERS QUPES OQYWB EKBQK PIADC OIUGN CTOII VOQBT ZCPEN BHZKA GOYCQ PCDET MIWFE BGEUE ORYCG SYEKM OQIPD AOCUI NGTHW AOQVT ETVCU BTOYS OQYBQ YBGLT NKVTF VQTFH STQES RQDEU MUKNS IOCYF ERRBL SRHQS THKPE TRPEW BEOSB QKQMP ZBRUE BLHTH HCSBD ACIGC YRENT HRAUQ NENKT ONOTW THUIK HIOOS GQEGO HXIRW TEINS QYFFQ NKTLT RSCNE TRGEY DANRL HFPTK TOFDQ TSOQR AGFTL HVNTS NYIIV OQETS BKFYO SEPQI VLTOY EHMIR WHEAW GOTBO QXRHR AKBRR GTXPR SEHFL RBIFL QOODE GAENO OUXWL ELSEH THMIR UDKQA DVTIH ROICC QTOYE HMIRI HWOIB CRQLP LWHEA WXOBO FYQEV RTRGX QLBQN TBYYR EBTRT TEENR MSDHQ OQXTC LOIFE QTHUA TOOUW BNTSI BDUKH SNQVR ARCTH VRSEC QSNSO QYSFH RGUTR OUREI OVUQP UTTLA VNVMT SLXDN HOAWB OEPGQ ECKEO THEAU OTUVL CLBPE QGCEE KQNTB GEUEO RYEBT QGELR SOQYV TTYHM IRVTT XHQOV FOKRK QFENK NOBLE LCQRR WGOEO LSOGE YNHUA TOVUF NHTZX DSTUL QFSCQ QGHYC NVSCU EURLK ASLOD TSBQR MRPET LMENH TASGS TFOTD HQTUN IWQIP OKOME GGFTT GOEXV TCMBM ARGEY NKFOS KTYEO BDUKB SEMCT RQVRI UITZB RYDCF SOSCQ RLIQO EAEBB SRQGP ECDAQ VBDUB GCYEQ ETSBK FYGEY NOUTE QTTNG SUQDK SYSGB ZUFKR LOBGT VWIWS OQOKD YSGBZ UCKRG EYIGO ENKKO MANE
\ No newline at end of file
diff --git a/bifid-ciphers.ipynb b/bifid-ciphers.ipynb
new file mode 100644 (file)
index 0000000..ad0906d
--- /dev/null
@@ -0,0 +1,1121 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "import matplotlib.pyplot as plt\n",
+    "import pandas as pd\n",
+    "import collections\n",
+    "import string\n",
+    "import numpy as np\n",
+    "from numpy import matrix\n",
+    "from numpy import linalg\n",
+    "%matplotlib inline\n",
+    "\n",
+    "from multiprocessing import Pool\n",
+    "\n",
+    "\n",
+    "from cipher import *\n",
+    "from cipherbreak import *\n",
+    "\n",
+    "c7b = open('2016/7b.ciphertext').read()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 108,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "c7bs = sanitise(c7b)\n",
+    "c7br = cat(reversed(c7bs))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def bifid_grid(keyword, wrap_alphabet, letter_mapping):\n",
+    "    cipher_alphabet = keyword_cipher_alphabet_of(keyword, wrap_alphabet)\n",
+    "    if letter_mapping is None:\n",
+    "        letter_mapping = {'j': 'i'}\n",
+    "    translation = ''.maketrans(letter_mapping)\n",
+    "    cipher_alphabet = cat(collections.OrderedDict.fromkeys(cipher_alphabet.translate(translation)))\n",
+    "    f_grid = {k: ((i // 5) + 1, (i % 5) + 1) \n",
+    "              for i, k in enumerate(cipher_alphabet)}\n",
+    "    r_grid = {((i // 5) + 1, (i % 5) + 1): k \n",
+    "              for i, k in enumerate(cipher_alphabet)}\n",
+    "    return translation, f_grid, r_grid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 156,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import pprint"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 157,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "({106: 'i'},\n",
+      " {'a': (1, 4),\n",
+      "  'b': (2, 1),\n",
+      "  'c': (2, 2),\n",
+      "  'd': (2, 3),\n",
+      "  'e': (2, 4),\n",
+      "  'f': (2, 5),\n",
+      "  'g': (1, 2),\n",
+      "  'h': (3, 1),\n",
+      "  'i': (1, 1),\n",
+      "  'k': (3, 2),\n",
+      "  'l': (3, 3),\n",
+      "  'm': (3, 4),\n",
+      "  'n': (1, 5),\n",
+      "  'o': (3, 5),\n",
+      "  'p': (4, 1),\n",
+      "  'q': (4, 2),\n",
+      "  'r': (4, 3),\n",
+      "  's': (4, 4),\n",
+      "  't': (4, 5),\n",
+      "  'u': (1, 3),\n",
+      "  'v': (5, 1),\n",
+      "  'w': (5, 2),\n",
+      "  'x': (5, 3),\n",
+      "  'y': (5, 4),\n",
+      "  'z': (5, 5)},\n",
+      " {(1, 1): 'i',\n",
+      "  (1, 2): 'g',\n",
+      "  (1, 3): 'u',\n",
+      "  (1, 4): 'a',\n",
+      "  (1, 5): 'n',\n",
+      "  (2, 1): 'b',\n",
+      "  (2, 2): 'c',\n",
+      "  (2, 3): 'd',\n",
+      "  (2, 4): 'e',\n",
+      "  (2, 5): 'f',\n",
+      "  (3, 1): 'h',\n",
+      "  (3, 2): 'k',\n",
+      "  (3, 3): 'l',\n",
+      "  (3, 4): 'm',\n",
+      "  (3, 5): 'o',\n",
+      "  (4, 1): 'p',\n",
+      "  (4, 2): 'q',\n",
+      "  (4, 3): 'r',\n",
+      "  (4, 4): 's',\n",
+      "  (4, 5): 't',\n",
+      "  (5, 1): 'v',\n",
+      "  (5, 2): 'w',\n",
+      "  (5, 3): 'x',\n",
+      "  (5, 4): 'y',\n",
+      "  (5, 5): 'z'})\n"
+     ]
+    }
+   ],
+   "source": [
+    "pprint.pprint(bifid_grid('iguana', KeywordWrapAlphabet.from_a, None))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 158,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "({106: 'i'},\n",
+      " {'a': (1, 2),\n",
+      "  'b': (1, 3),\n",
+      "  'c': (1, 4),\n",
+      "  'd': (1, 5),\n",
+      "  'e': (2, 1),\n",
+      "  'f': (2, 2),\n",
+      "  'g': (2, 3),\n",
+      "  'h': (2, 4),\n",
+      "  'i': (2, 5),\n",
+      "  'k': (3, 1),\n",
+      "  'l': (3, 2),\n",
+      "  'm': (3, 3),\n",
+      "  'n': (3, 4),\n",
+      "  'o': (3, 5),\n",
+      "  'p': (4, 1),\n",
+      "  'q': (4, 2),\n",
+      "  'r': (4, 3),\n",
+      "  's': (4, 4),\n",
+      "  't': (4, 5),\n",
+      "  'u': (5, 1),\n",
+      "  'v': (5, 2),\n",
+      "  'w': (5, 3),\n",
+      "  'x': (5, 4),\n",
+      "  'y': (5, 5),\n",
+      "  'z': (1, 1)},\n",
+      " {(1, 1): 'z',\n",
+      "  (1, 2): 'a',\n",
+      "  (1, 3): 'b',\n",
+      "  (1, 4): 'c',\n",
+      "  (1, 5): 'd',\n",
+      "  (2, 1): 'e',\n",
+      "  (2, 2): 'f',\n",
+      "  (2, 3): 'g',\n",
+      "  (2, 4): 'h',\n",
+      "  (2, 5): 'i',\n",
+      "  (3, 1): 'k',\n",
+      "  (3, 2): 'l',\n",
+      "  (3, 3): 'm',\n",
+      "  (3, 4): 'n',\n",
+      "  (3, 5): 'o',\n",
+      "  (4, 1): 'p',\n",
+      "  (4, 2): 'q',\n",
+      "  (4, 3): 'r',\n",
+      "  (4, 4): 's',\n",
+      "  (4, 5): 't',\n",
+      "  (5, 1): 'u',\n",
+      "  (5, 2): 'v',\n",
+      "  (5, 3): 'w',\n",
+      "  (5, 4): 'x',\n",
+      "  (5, 5): 'y'})\n"
+     ]
+    }
+   ],
+   "source": [
+    "pprint.pprint(bifid_grid('z', KeywordWrapAlphabet.from_a, None))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 159,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "({113: 'p'},\n",
+      " {'a': (1, 4),\n",
+      "  'b': (2, 1),\n",
+      "  'c': (2, 2),\n",
+      "  'd': (2, 3),\n",
+      "  'e': (2, 4),\n",
+      "  'f': (2, 5),\n",
+      "  'g': (1, 2),\n",
+      "  'h': (3, 1),\n",
+      "  'i': (1, 1),\n",
+      "  'j': (3, 2),\n",
+      "  'k': (3, 3),\n",
+      "  'l': (3, 4),\n",
+      "  'm': (3, 5),\n",
+      "  'n': (1, 5),\n",
+      "  'o': (4, 1),\n",
+      "  'p': (4, 2),\n",
+      "  'r': (4, 3),\n",
+      "  's': (4, 4),\n",
+      "  't': (4, 5),\n",
+      "  'u': (1, 3),\n",
+      "  'v': (5, 1),\n",
+      "  'w': (5, 2),\n",
+      "  'x': (5, 3),\n",
+      "  'y': (5, 4),\n",
+      "  'z': (5, 5)},\n",
+      " {(1, 1): 'i',\n",
+      "  (1, 2): 'g',\n",
+      "  (1, 3): 'u',\n",
+      "  (1, 4): 'a',\n",
+      "  (1, 5): 'n',\n",
+      "  (2, 1): 'b',\n",
+      "  (2, 2): 'c',\n",
+      "  (2, 3): 'd',\n",
+      "  (2, 4): 'e',\n",
+      "  (2, 5): 'f',\n",
+      "  (3, 1): 'h',\n",
+      "  (3, 2): 'j',\n",
+      "  (3, 3): 'k',\n",
+      "  (3, 4): 'l',\n",
+      "  (3, 5): 'm',\n",
+      "  (4, 1): 'o',\n",
+      "  (4, 2): 'p',\n",
+      "  (4, 3): 'r',\n",
+      "  (4, 4): 's',\n",
+      "  (4, 5): 't',\n",
+      "  (5, 1): 'v',\n",
+      "  (5, 2): 'w',\n",
+      "  (5, 3): 'x',\n",
+      "  (5, 4): 'y',\n",
+      "  (5, 5): 'z'})\n"
+     ]
+    }
+   ],
+   "source": [
+    "pprint.pprint(bifid_grid('iguana', KeywordWrapAlphabet.from_a, {'q': 'p'}))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 87,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# def bifid_decipher(message, keyword, wrap_alphabet=KeywordWrapAlphabet.from_a, \n",
+    "#                    letter_mapping=None, period=None):\n",
+    "#     translation, f_grid, r_grid = bifid_grid(keyword, wrap_alphabet, letter_mapping)\n",
+    "    \n",
+    "#     t_message = message.translate(translation)\n",
+    "#     pairs0 = [f_grid[l] for l in t_message]\n",
+    "#     items = sum([list(p) for p in pairs0], [])\n",
+    "#     gap = len(message)\n",
+    "#     pairs1 = [(items[i//2], items[i//2+gap]) for i in range(0, len(items), 2)]\n",
+    "#     return cat(r_grid[p] for p in pairs1)\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 162,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def bifid_encipher(message, keyword, wrap_alphabet=KeywordWrapAlphabet.from_a, \n",
+    "                   letter_mapping=None, period=None, fillvalue=None):\n",
+    "    translation, f_grid, r_grid = bifid_grid(keyword, wrap_alphabet, letter_mapping)\n",
+    "    \n",
+    "    t_message = message.translate(translation)\n",
+    "    pairs0 = [f_grid[l] for l in sanitise(t_message)]\n",
+    "    if period:\n",
+    "        chunked_pairs = [pairs0[i:i+period] for i in range(0, len(pairs0), period)]\n",
+    "        if len(chunked_pairs[-1]) < period and fillvalue:\n",
+    "            chunked_pairs[-1] += [f_grid[fillvalue]] * (period - len(chunked_pairs[-1]))\n",
+    "    else:\n",
+    "        chunked_pairs = [pairs0]\n",
+    "    \n",
+    "    pairs1 = []\n",
+    "    for c in chunked_pairs:\n",
+    "        items = sum(list(list(i) for i in zip(*c)), [])\n",
+    "        p = [(items[i], items[i+1]) for i in range(0, len(items), 2)]\n",
+    "        pairs1 += p\n",
+    "    \n",
+    "    return cat(r_grid[p] for p in pairs1)\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 163,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'nkklawamdkoedysipdesltirsnoesqlvvaloderbhel'"
+      ]
+     },
+     "execution_count": 163,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_encipher('this is a test message for the keyword decipherment', 'elephant', wrap_alphabet=KeywordWrapAlphabet.from_last)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 83,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "ot, ofg, org = bifid_grid('iguana', KeywordWrapAlphabet.from_a, None)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 85,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[(1, 1),\n",
+       " (1, 5),\n",
+       " (2, 3),\n",
+       " (1, 1),\n",
+       " (1, 4),\n",
+       " (2, 2),\n",
+       " (1, 3),\n",
+       " (4, 3),\n",
+       " (4, 3),\n",
+       " (5, 4)]"
+      ]
+     },
+     "execution_count": 85,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "op0 = [ofg[l] for l in \"indiacurry\"]\n",
+    "op0"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 86,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[[(1, 1), (1, 5), (2, 3), (1, 1)],\n",
+       " [(1, 4), (2, 2), (1, 3), (4, 3)],\n",
+       " [(4, 3), (5, 4), (1, 4), (1, 4)]]"
+      ]
+     },
+     "execution_count": 86,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ocp = chunks(op0, 4, fillvalue=[[ofg['a']]])\n",
+    "acc = []\n",
+    "ocp"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 87,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[(1, 1),\n",
+       " (2, 1),\n",
+       " (1, 5),\n",
+       " (3, 1),\n",
+       " (1, 2),\n",
+       " (1, 4),\n",
+       " (4, 2),\n",
+       " (3, 3),\n",
+       " (4, 5),\n",
+       " (1, 1),\n",
+       " (3, 4),\n",
+       " (4, 4)]"
+      ]
+     },
+     "execution_count": 87,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "acc=[]\n",
+    "for c in ocp:\n",
+    "    items = sum(list(list(i) for i in zip(*c)), [])\n",
+    "    p = [(items[i], items[i+1]) for i in range(0, len(items), 2)]\n",
+    "    acc += p\n",
+    "acc"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 88,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'ibnhgaqltims'"
+      ]
+     },
+     "execution_count": 88,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "cat(org[p] for p in acc)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 164,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def bifid_decipher(message, keyword, wrap_alphabet=KeywordWrapAlphabet.from_a, \n",
+    "                   letter_mapping=None, period=None, fillvalue=None):\n",
+    "    translation, f_grid, r_grid = bifid_grid(keyword, wrap_alphabet, letter_mapping)\n",
+    "    \n",
+    "    t_message = message.translate(translation)\n",
+    "    pairs0 = [f_grid[l] for l in sanitise(t_message)]\n",
+    "    if period:\n",
+    "        chunked_pairs = [pairs0[i:i+period] for i in range(0, len(pairs0), period)]\n",
+    "        if len(chunked_pairs[-1]) < period and fillvalue:\n",
+    "            chunked_pairs[-1] += [f_grid[fillvalue]] * (period - len(chunked_pairs[-1]))\n",
+    "    else:\n",
+    "        chunked_pairs = [pairs0]\n",
+    "        \n",
+    "    pairs1 = []\n",
+    "    for c in chunked_pairs:\n",
+    "        items = [j for i in c for j in i]\n",
+    "        gap = len(c)\n",
+    "        p = [(items[i], items[i+gap]) for i in range(gap)]\n",
+    "        pairs1 += p\n",
+    "\n",
+    "    return cat(r_grid[p] for p in pairs1)    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "({106: 'i'},\n",
+       " {'a': (1, 4),\n",
+       "  'b': (2, 1),\n",
+       "  'c': (2, 2),\n",
+       "  'd': (2, 3),\n",
+       "  'e': (2, 4),\n",
+       "  'f': (2, 5),\n",
+       "  'g': (1, 2),\n",
+       "  'h': (3, 1),\n",
+       "  'i': (1, 1),\n",
+       "  'k': (3, 2),\n",
+       "  'l': (3, 3),\n",
+       "  'm': (3, 4),\n",
+       "  'n': (1, 5),\n",
+       "  'o': (3, 5),\n",
+       "  'p': (4, 1),\n",
+       "  'q': (4, 2),\n",
+       "  'r': (4, 3),\n",
+       "  's': (4, 4),\n",
+       "  't': (4, 5),\n",
+       "  'u': (1, 3),\n",
+       "  'v': (5, 1),\n",
+       "  'w': (5, 2),\n",
+       "  'x': (5, 3),\n",
+       "  'y': (5, 4),\n",
+       "  'z': (5, 5)},\n",
+       " {(1, 1): 'i',\n",
+       "  (1, 2): 'g',\n",
+       "  (1, 3): 'u',\n",
+       "  (1, 4): 'a',\n",
+       "  (1, 5): 'n',\n",
+       "  (2, 1): 'b',\n",
+       "  (2, 2): 'c',\n",
+       "  (2, 3): 'd',\n",
+       "  (2, 4): 'e',\n",
+       "  (2, 5): 'f',\n",
+       "  (3, 1): 'h',\n",
+       "  (3, 2): 'k',\n",
+       "  (3, 3): 'l',\n",
+       "  (3, 4): 'm',\n",
+       "  (3, 5): 'o',\n",
+       "  (4, 1): 'p',\n",
+       "  (4, 2): 'q',\n",
+       "  (4, 3): 'r',\n",
+       "  (4, 4): 's',\n",
+       "  (4, 5): 't',\n",
+       "  (5, 1): 'v',\n",
+       "  (5, 2): 'w',\n",
+       "  (5, 3): 'x',\n",
+       "  (5, 4): 'y',\n",
+       "  (5, 5): 'z'})"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_grid('iguana', KeywordWrapAlphabet.from_a, None)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 139,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'ibidonhprm'"
+      ]
+     },
+     "execution_count": 139,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_encipher(\"indiajelly\", 'iguana')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 140,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'indiaielly'"
+      ]
+     },
+     "execution_count": 140,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_decipher('ibidonhprm', 'iguana')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 137,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'ibnhgaqltm'"
+      ]
+     },
+     "execution_count": 137,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_encipher(\"indiacurry\", 'iguana', period=4)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 138,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'indiacurry'"
+      ]
+     },
+     "execution_count": 138,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_decipher(\"ibnhgaqltm\", 'iguana', period=4)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 144,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'ibnhgaqltzml'"
+      ]
+     },
+     "execution_count": 144,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_encipher(\"indiacurry\", 'iguana', period=4, fillvalue='x')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 146,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'indiacurryxx'"
+      ]
+     },
+     "execution_count": 146,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_decipher(\"ibnhgaqltzml\", 'iguana', period=4)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 101,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "p0 = [(1, 1), (2, 1), (1, 5), (3, 1)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 103,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[1, 1, 2, 1, 1, 5, 3, 1]"
+      ]
+     },
+     "execution_count": 103,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "t0 = [j for i in p0 for j in i]\n",
+    "t0"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 104,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[(1, 1), (1, 5), (2, 3), (1, 1)]"
+      ]
+     },
+     "execution_count": 104,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[(t0[i], t0[i+4]) for i in range(4)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 130,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'martinwehavemadeadreadfulmistakeandihavebeentooslowtoadmitthattomyselfihavehadavisitfromthewomanfromthesyndicateandiconfrontedheraboutthesourceofthetemplatessheconfirmedmyworstfearsandnowiwanttocrawlawayanddiewhathavewedoneoursoftwarehasledtosomuchsufferingwhenitwasdesignedtodotheoppositeiaskedherhowthecabinetofficecouldpossiblyhaveauthorisedthisandshelaughedandexplainedthatthesyndicatenolongerworkedforthebritishgovernmentcallitprivateenterpriseshesaidwehavealwaysbeengoodatthatmyhorrormusthavebeenwrittenallovermyfaceshedidntseemsurprisedatmyreactionbutequallyshedidnttakeitwellandcivilitywasabandonediaskedherhowitcouldbelegalletalonemoraltodowhattheyproposedandheranswerwasthatitwasnecessaryisaidwewouldnthelpthemandshesaiditwasnecessarythatwedidisaidiwouldntbeabletofacemyfamilyandfriendsifwecooperatedandshesaidiwouldnthavetoworryaboutthatforlongonewayoranotherthepdssyndicateweregoingtomakesurewebothdisappearedlookingbackicanseethatfromthestartthiswholethinghasactedtodrawusintoitscentreandnowiamattheeventhorizonalmostunabletoescapeitspullbutithinkwehaveonelastchanceiamsureshewillbevisitingyouaswellshethinkswehavenochoicebutithinkachoiceisallwehavewhateveryoudoholdoutforbettertermsshehastobelievethatyouareonsideandmotivatedbygreedsothatshewontworryaboutanyqualmsyoumighthaveconvinceherthatyouwillconvincemetocooperatetellherthatyouthinkyoushouldworkfromthecollectiveinosloandthatyouwantpaymentviathebankinswitzerlandigottheimpressionthatmoneyisnotaproblemwithmoneyinaswissbankandtheexpertiseandconnectivityaffordedbythecollectiveithinkwehaveachancetoescapeandtotrytostopthemperhapswewillsurvivethisperhapswecanbringthemdown'"
+      ]
+     },
+     "execution_count": 130,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_decipher(c7bs, 'ligo', KeywordWrapAlphabet.from_a, period=4, fillvalue=None)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 147,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'martin we have made a dreadful mistake and i have been too slow to admit that to myself i have had a visit from the woman from the syndicate and i confronted her about the source of the templates she confirmed my worst fears and now i want to crawl away and die what have we done our software has led to so much suffering when it was designed to do the opposite i asked her how the cabinet office could possibly have authorised this and she laughed and explained that the syndicate no longer worked for the british government call it private enterprises he said we have always been good at that my horror must have been written all over myfaces he didnt seem surprised at my reaction but equally she didnt take it well and civility was abandoned i asked her how it could be legal let alone moral to do what they proposed and her answer was that it was necessary i said we wouldnt help them and she said it was necessary that we did i said i wouldnt be able to face my family and friends if we cooperated and she said i wouldnt have to worry about that for long one way or another the pds syndicate were going to make sure we both disappeared looking back i can see that from the start this whole thing has acted to draw us into its centre and now i am at the event horizon almost unable to escape its pull but i think we have one last chance i am sure she will be visiting you as well she thinks we have no choice but i think a choice is all we have whatever you do hold out for better terms she has to believe that you are on side and motivated by greed so that she wont worry about any qualms you might have convince her that you will convince me to cooperate tell her that you think you should work from the collective in oslo and that you want payment via the bank in switzerland i got the impression that money is not a problem with money in a swiss bank and the expertise and connectivity afforded by the collective i think we have a chance to escape and to try to stop them perhaps we will survive this perhaps we can bring them down'"
+      ]
+     },
+     "execution_count": 147,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "wcat(segment(bifid_decipher(c7bs, 'ligo', KeywordWrapAlphabet.from_a, period=4)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 49,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "p0 = [(2, 1), (3, 3), (3, 3), (5, 1), (1, 4)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 54,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[2, 1, 3, 3, 3, 3, 5, 1, 1, 4]"
+      ]
+     },
+     "execution_count": 54,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "items = sum([list(p) for p in p0], [])\n",
+    "items"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 55,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[(2, 3), (1, 5), (3, 1), (3, 1), (3, 4)]"
+      ]
+     },
+     "execution_count": 55,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "gap=5\n",
+    "[(items[i//2], items[i//2+gap]) for i in range(0, len(items), 2)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 91,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "c7bs = sanitise(c7b)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 115,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def bifid_break_mp(message, wordlist=keywords, fitness=Pletters,\n",
+    "                     number_of_solutions=1, chunksize=500):\n",
+    "    \"\"\"Breaks a keyword substitution cipher using a dictionary and\n",
+    "    frequency analysis\n",
+    "\n",
+    "    >>> keyword_break_mp(keyword_encipher('this is a test message for the ' \\\n",
+    "          'keyword decipherment', 'elephant', KeywordWrapAlphabet.from_last), \\\n",
+    "          wordlist=['cat', 'elephant', 'kangaroo']) # doctest: +ELLIPSIS\n",
+    "    (('elephant', <KeywordWrapAlphabet.from_last: 2>), -52.834575011...)\n",
+    "    >>> keyword_break_mp(keyword_encipher('this is a test message for the ' \\\n",
+    "          'keyword decipherment', 'elephant', KeywordWrapAlphabet.from_last), \\\n",
+    "          wordlist=['cat', 'elephant', 'kangaroo'], \\\n",
+    "          number_of_solutions=2) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE\n",
+    "    [(('elephant', <KeywordWrapAlphabet.from_last: 2>), -52.834575011...), \n",
+    "    (('elephant', <KeywordWrapAlphabet.from_largest: 3>), -52.834575011...)]\n",
+    "    \"\"\"\n",
+    "    with Pool() as pool:\n",
+    "        helper_args = [(message, word, wrap, fitness)\n",
+    "                       for word in wordlist\n",
+    "                       for wrap in KeywordWrapAlphabet]\n",
+    "        # Gotcha: the helper function here needs to be defined at the top level\n",
+    "        #   (limitation of Pool.starmap)\n",
+    "        breaks = pool.starmap(bifid_break_worker, helper_args, chunksize)\n",
+    "        if number_of_solutions == 1:\n",
+    "            return max(breaks, key=lambda k: k[1])\n",
+    "        else:\n",
+    "            return sorted(breaks, key=lambda k: k[1], reverse=True)[:number_of_solutions]\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 116,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def bifid_break_worker(message, keyword, wrap_alphabet, fitness):\n",
+    "    plaintext = bifid_decipher(message, keyword, wrap_alphabet)\n",
+    "    fit = fitness(plaintext)\n",
+    "    logger.debug('Keyword break attempt using key {0} (wrap={1}) gives fit of '\n",
+    "                 '{2} and decrypt starting: {3}'.format(keyword, \n",
+    "                     wrap_alphabet, fit, sanitise(plaintext)[:50]))\n",
+    "    return (keyword, wrap_alphabet), fit"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 107,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'enamokkneogiyegrkcuzbgsydkoqoswiwvtgbolrkfuzbgsyskdqusgnttqetuonyegyfkbsteqeycgbudbvqadcepgqrsbbeaeoqilrqcsosfcdyrbztiuirvqrtcmesbkudboeytksofknyegrambmctvxeogttfggemokopiqwinutqhdtoftsgsathnemlteprmrqbstdolsaklrueucsvncyhgqqcsfqlutsdxzthnfuvotauhnyegosloeogwrrqclelbonknefqkrkofvoqhxttvrimhyttvyqosrlegqtbeyroeuegbtnqkeecgqepblclvutouaehtoekceqgpeobwaohndxlstmvnvalttupquvoieruortugrhfsyqosnsqcesrvhtcrarvqnshkudbistnbwuootauhtqefiolctxqoqhdsmrneettrtberyybtnqblqxgrtrveqyfoboxwaehwlplqrcbiowhirimheyotqcciorhitvdaqkdurimhtheslelwxuooneagedooqlfibrlfhesrpxtgrrbkarhrxqobtogwaehwrimheyotlviqpesoyfkbsteqoviiynstnvhltfgarqostqdfotktpfhlrnadyegrtencsrtltknqffyqsnietwrixhogeqgsooihkiuhtwtonotknenquarhtnerycgicadbschhthlbeurbzpmqkqbsoebweprtepkhtsqhrslbrrefycoisnkumuedqrseqtshftqvftvkntlgbyqbyqosyotbucvtetvqoawhtgniucoadpiqomkeysgcyroeuegbefwimtedcpqcyogakzhbnepcztbqoviiotcnguiocdaipkqbkebwyqosepuqsrecnfsvedoipoqkmyegsqdsaogktgniurofkwfldeoupsqerncsfevoyqosxcoueswnfoqkspkbnyrheuqxotktarhasoiofnqhtokluoqivslbqhbcveqberoaboskskcsfslctsgkapbqftvuiilvcsbkaqlbrrubwtgtnkdboskylzlqqyetqekleuebrsyspnbrcfqspstdntrndsichescznbprqealulhteroctydoocwanhtprnocothnypoqysosniltodcsfyvvolwaehwdpiqoskedwonrtentycobwanelolftbnneksonwlhrsqcqqcqrsopeckrcountigqtldycoisnkuotktanhetwklvshfspkboxkqaolkmyegdqossdcorqoszoowaohabmityghiurocczicttqkifbboekyorhehedkxrobesooztmbqnsbtsqcnkgqnxcorruhokkaergezpctbpdnntqqshcqaehrfyvenwqtttbgsrcfvqasarhfksbkufvvawlacteqtfnvctvhspkqwyocnrtormzdnckouekbomkttarlptmroyketcbrusoeqystofbqoskctenquekbkybgtfrbktbxsqesswgeysggrqfsswgeedoovxaiqvdabaginnrptyqoqesomudleoylstoqtodcoawhkybgeukqdgogzxeiexrinpchoawheewgepth'"
+      ]
+     },
+     "execution_count": 107,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c7bs = sanitise(c7b)\n",
+    "c7br = cat(reversed(c7bs))\n",
+    "c7br"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 148,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(('ligo', <KeywordWrapAlphabet.from_a: 1>), -2505.924490942904)"
+      ]
+     },
+     "execution_count": 148,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_break_mp(c7bs, wordlist=['gravity', 'ligo'])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 102,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'ksotagstmczesqstldwfasoehepicltaryruvgstiwbtylwzlanehrdmthhlqzeohpsdytllgdxfcetbiislqetoukobnterkoyonsetkodhtymxuefpdtnhnsulwnnurhiotctcrwhprbssrdblxanlrxadxgxatetsegdoeuhawberbaswolpqkrkpfcxufohcyefaeabqtkbrykbdonghsbaodvongcfdvngmeslhetnytkocenotirklsatenkdeeyoentbryuoleqoefcuxpqbsirotbogkvtqbrqgyoqamkninrfottolgmynbsekmeouwueklcpqrekyylvronsntcotrrctdvoyfthkgalscldypooicxrtpdyttohfoqtprrbgtwepsycwpswuylkedbiglsylbctcfecisumvrbyparteagabdqouuttohvbtcdtxczusxrtleburbtkapmsfctmokootcoibkclbetoaralxzdnlpanenadkhhgtsldnyrupnqsravhtpohmplgtaacuhfpttdebroaqhedgvooyyneoebrfudfodroyklhsheqheeqhdinusytmhdqqedsbbdzcylgukonttacivvvcrprteautwrxhdmczntnixhzbeasmboscsyeqdtsxxeiodohrnofaidlbabrobumelkaeuvnlylglqnfpeqklhwlqeselhameievlbeawrlnllyetoeolencrduoghqqoeqyhlqidrrvndrrwnfhmottqllpayunortyoeariuhharstrhnsfaaoqlipqkohcrnldicnlshnysnrtdbiggeonatcseqosygonehtdutacbzdbstdcrzttntrbtunrotcuewfslftkgdruetlrxrgbmvegfsqieybgqtfxaxrvqbybcaibhoeoolnpxnrdatsspxotloerkwotcheutoerrufnprncktohsqarexdccnbtbekxtqtcrtbaqsottmbltovlurbeoolrtpksbtpyvrasrbtkfricyeremtpaqunucemnterrmdpoldyaicofeoppgepxtdaioeesqqysthohkeotktnstxntgtmhqvyhoythkeanebdshlmtrnqhrunweeeozctiofegqolrfmmdbdacryrmqrypwuwvcntdyqksdamrsglgisanncrmoerfveprpkgbagkerobderbnbatdnedugenxarredlduheegqbrycawnknbnylomloetokdolqreyuecvufbrpsmsptadqthkuotdvknhuyetldctwotidfglrgspmhokusbvtpvbeietnxqbirwhspqetmyotewabodyfppaoacoequgsrrgtyqfsnegmtfvzelmfwosrutwpvnamanthhgcnepsepeguldrhaenwolwhhohnsrlpxnsdhenvadcbyqicaboptfaoknvcmeoerqbtlyovbbddommednhlmrlcyaeflratepytylrnpcantuepwpxxanfthsdnowzirihfqqcedlewwhkcelinfwniiohclardlbqqokzrwvdswbufemcsqqveqnbruynipgrbaytsqkkkyodugayche'"
+      ]
+     },
+     "execution_count": 102,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_decipher(c7bs, 'capris', KeywordWrapAlphabet.from_a )"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 104,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'dnrobchyoikvkwtucnsiganmyoanfatckweqpwxwehfdpoxqdvtworugsnpsxanmycvirrgedmuihpienwfnpwyzdffaqsxsoutvbvqlovoplenqrnktqlernruwptiswodnhaxomrtwbmpunnbnolcrvsasmcblsvawegytshecczeperucfeqlrcosbfdhdkcaeipnsligmsnapleqpoutoqgtcobyzorcehvvkkrhoxngkavnolkcrncshwetpocgnysxewemonekysintysuqrlntykpvsckgenbecfybfmycsrtzrxfckstgbirtnmnhdhcetfvuttwptpbigplyctfisoxttslhhbvtnotminnusfcqobdtnlhnpbnhxhpirckoatchwiaofaloprrbyonlouscekwlsnboyciswcoosyirodpwsgghcqhofeuosmtqfhqsztrsscwxfzwrnhhnphtpvwnurikaeoxgftoyodrmaqnosloukciskmbycicidsgeofsbrfodhsrtskwtpbtgnsmnyncrvsrhtwrsiolhlylrnntvrkenffvgfypknntxryqqgonspndmocrhcpfrnbgerwqncuiciqverfealtrnoomnwdnenepldpgatsbbffsaogoynownnotoxbeckllrnonbknycsensfleqbctonegzaccsifmnuezvlfqsurrgwviiuwrdcgoininoyseugowzkpntfctreowotnetkswlctahmgrpoypohsnoqnqooogboctspteznllttcurbcbiewnslipsshliwsybvalnlosrrtpcfzepwsnonktceovhhrnqfeilrkmsrlseoinyfsfunulffevuofwrenqbrettkrtkbnkelciibvsysafkrisombfmsqgwlfbnekikdyreipgzshnonclsrzgyceeanhlvcluucfsomraasehigprxbmfiftdnhgxhfbnzopntrsgcudoigstteflifktxiewbaqltwevuznctfgxhgtihgeruomubtgsvaxgoysnontudtebmabnbvsnsrqffslnigcfnemqgnhfckqpncoewfrnmbictedfkwaateghravmulprcftrqngazecectflxcicnhhwllbrwpoiitgqvknmogoeckpsqtvofttwbhpsntarshokvnigrlypropqiitoznlghoknmifdedtapmpisprrsfewfnqttitvnkoaltfmfqicnsaedyxuaklctantctroesoorbkkmpktnwnoulfnmrvougqstqkfdtttvarerhylgfoimeanomleupotornghfryklsyfgtnxdnnsttsoitriyisennougsveatellinkpetkaxodulaihaoebevagqodofghminllhpelcnszrbagvzsclxphrvplbhossnckahwaeroakctnekodiwgfinquogmgraqpgqafienectgnwoeusnilosiptysyfxuydrdxsgtcoucislntosflhttnogzrlntrwkrxiokklphbagvsufdlxpuhpnoqwuukirefqweuxtrtbtnnwrshqneawdghirfaturhpwesptebb'"
+      ]
+     },
+     "execution_count": 104,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bifid_decipher(c7br, 'trinket', KeywordWrapAlphabet.from_a)"
+   ]
+  },
+  {
+   "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.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
index 979426bcb4ea80e9b64e550c22ff1cc3857fb91d..1c71b5c205567807332accf8d3fbada74b1c0c28 100644 (file)
--- a/cipher.py
+++ b/cipher.py
@@ -7,6 +7,7 @@ import numpy as np
 from numpy import matrix
 from numpy import linalg
 from language_models import *
+import pprint
 
 
 ## Utility functions
@@ -942,6 +943,82 @@ def amsco_transposition_decipher(message, keyword,
     return cat(plaintext_list)
 
 
+def bifid_grid(keyword, wrap_alphabet, letter_mapping):
+    """Create the grids for a Bifid cipher
+    """
+    cipher_alphabet = keyword_cipher_alphabet_of(keyword, wrap_alphabet)
+    if letter_mapping is None:
+        letter_mapping = {'j': 'i'}
+    translation = ''.maketrans(letter_mapping)
+    cipher_alphabet = cat(collections.OrderedDict.fromkeys(cipher_alphabet.translate(translation)))
+    f_grid = {k: ((i // 5) + 1, (i % 5) + 1) 
+              for i, k in enumerate(cipher_alphabet)}
+    r_grid = {((i // 5) + 1, (i % 5) + 1): k 
+              for i, k in enumerate(cipher_alphabet)}
+    return translation, f_grid, r_grid
+
+def bifid_encipher(message, keyword, wrap_alphabet=KeywordWrapAlphabet.from_a, 
+                   letter_mapping=None, period=None, fillvalue=None):
+    """Bifid cipher
+
+    >>> bifid_encipher("indiajelly", 'iguana')
+    'ibidonhprm'
+    >>> bifid_encipher("indiacurry", 'iguana', period=4)
+    'ibnhgaqltm'
+    >>> bifid_encipher("indiacurry", 'iguana', period=4, fillvalue='x')
+    'ibnhgaqltzml'
+    """
+    translation, f_grid, r_grid = bifid_grid(keyword, wrap_alphabet, letter_mapping)
+    
+    t_message = message.translate(translation)
+    pairs0 = [f_grid[l] for l in sanitise(t_message)]
+    if period:
+        chunked_pairs = [pairs0[i:i+period] for i in range(0, len(pairs0), period)]
+        if len(chunked_pairs[-1]) < period and fillvalue:
+            chunked_pairs[-1] += [f_grid[fillvalue]] * (period - len(chunked_pairs[-1]))
+    else:
+        chunked_pairs = [pairs0]
+    
+    pairs1 = []
+    for c in chunked_pairs:
+        items = sum(list(list(i) for i in zip(*c)), [])
+        p = [(items[i], items[i+1]) for i in range(0, len(items), 2)]
+        pairs1 += p
+    
+    return cat(r_grid[p] for p in pairs1)
+
+
+def bifid_decipher(message, keyword, wrap_alphabet=KeywordWrapAlphabet.from_a, 
+                   letter_mapping=None, period=None, fillvalue=None):
+    """Decipher with bifid cipher
+
+    >>> bifid_decipher('ibidonhprm', 'iguana')
+    'indiaielly'
+    >>> bifid_decipher("ibnhgaqltm", 'iguana', period=4)
+    'indiacurry'
+    >>> bifid_decipher("ibnhgaqltzml", 'iguana', period=4)
+    'indiacurryxx'
+    """
+    translation, f_grid, r_grid = bifid_grid(keyword, wrap_alphabet, letter_mapping)
+    
+    t_message = message.translate(translation)
+    pairs0 = [f_grid[l] for l in sanitise(t_message)]
+    if period:
+        chunked_pairs = [pairs0[i:i+period] for i in range(0, len(pairs0), period)]
+        if len(chunked_pairs[-1]) < period and fillvalue:
+            chunked_pairs[-1] += [f_grid[fillvalue]] * (period - len(chunked_pairs[-1]))
+    else:
+        chunked_pairs = [pairs0]
+        
+    pairs1 = []
+    for c in chunked_pairs:
+        items = [j for i in c for j in i]
+        gap = len(c)
+        p = [(items[i], items[i+gap]) for i in range(gap)]
+        pairs1 += p
+
+    return cat(r_grid[p] for p in pairs1) 
+
 class PocketEnigma(object):
     """A pocket enigma machine
     The wheel is internally represented as a 26-element list self.wheel_map, 
index d5d3aa76422c6b0109ee91d55b482d87c66c97a0..0ca46062ddf4db5244f63402c60f91deb043c6f0 100644 (file)
@@ -569,6 +569,42 @@ def hill_break_worker(message, matrix, fitness):
                      fit, sanitise(plaintext)[:50]))
     return matrix, fit
 
+def bifid_break_mp(message, wordlist=keywords, fitness=Pletters,
+                     number_of_solutions=1, chunksize=500):
+    """Breaks a keyword substitution cipher using a dictionary and
+    frequency analysis
+
+    >>> bifid_break_mp(bifid_encipher('this is a test message for the ' \
+          'keyword decipherment', 'elephant', wrap_alphabet=KeywordWrapAlphabet.from_last), \
+          wordlist=['cat', 'elephant', 'kangaroo']) # doctest: +ELLIPSIS
+    (('elephant', <KeywordWrapAlphabet.from_last: 2>), -52.834575011...)
+    >>> bifid_break_mp(bifid_encipher('this is a test message for the ' \
+          'keyword decipherment', 'elephant', wrap_alphabet=KeywordWrapAlphabet.from_last), \
+          wordlist=['cat', 'elephant', 'kangaroo'], \
+          number_of_solutions=2) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
+    [(('elephant', <KeywordWrapAlphabet.from_last: 2>), -52.834575011...), 
+    (('elephant', <KeywordWrapAlphabet.from_largest: 3>), -52.834575011...)]
+    """
+    with Pool() as pool:
+        helper_args = [(message, word, wrap, fitness)
+                       for word in wordlist
+                       for wrap in KeywordWrapAlphabet]
+        # Gotcha: the helper function here needs to be defined at the top level
+        #   (limitation of Pool.starmap)
+        breaks = pool.starmap(bifid_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 bifid_break_worker(message, keyword, wrap_alphabet, fitness):
+    plaintext = bifid_decipher(message, keyword, wrap_alphabet)
+    fit = fitness(plaintext)
+    logger.debug('Keyword break attempt using key {0} (wrap={1}) gives fit of '
+                 '{2} and decrypt starting: {3}'.format(keyword, 
+                     wrap_alphabet, fit, sanitise(plaintext)[:50]))
+    return (keyword, wrap_alphabet), 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
index 2019dd5b600618d8d93d69e6ad5cf79b60aa45bf..bd07c69ff5f08ec9421452aca4e35cb2b2b39e08 100644 (file)
 {
- "metadata": {
-  "name": "",
-  "signature": "sha256:112d1c84c318592f927e18c5b0f15ed60ac8418ca15cb79596ba6212ff2d7e3f"
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
+ "cells": [
   {
-   "cells": [
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "import matplotlib.pyplot as plt\n",
-      "import pandas as pd\n",
-      "import collections\n",
-      "import string\n",
-      "import numpy as np\n",
-      "from numpy import matrix\n",
-      "from numpy import linalg\n",
-      "%matplotlib inline\n",
-      "\n",
-      "from cipher import *\n",
-      "from cipherbreak import *\n",
-      "\n",
-      "c6a = open('2014/6a.ciphertext').read()\n",
-      "c6b = open('2014/6b.ciphertext').read()"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [],
-     "prompt_number": 54
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "key_a, score = railfence_break(sanitise(c6a))\n",
-      "key_a, score"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 3,
-       "text": [
-        "(3, -2314.997881051078)"
-       ]
-      }
-     ],
-     "prompt_number": 3
-    },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "' '.join(segment(railfence_decipher(sanitise(c6a), key_a)))"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 4,
-       "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'"
-       ]
-      }
-     ],
-     "prompt_number": 4
-    },
+   "cell_type": "code",
+   "execution_count": 54,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "import matplotlib.pyplot as plt\n",
+    "import pandas as pd\n",
+    "import collections\n",
+    "import string\n",
+    "import numpy as np\n",
+    "from numpy import matrix\n",
+    "from numpy import linalg\n",
+    "%matplotlib inline\n",
+    "\n",
+    "from cipher import *\n",
+    "from cipherbreak import *\n",
+    "\n",
+    "c6a = open('2014/6a.ciphertext').read()\n",
+    "c6b = open('2014/6b.ciphertext').read()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "c6bs = sanitise(c6b)\n",
-      "c6bs"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "(3, -2314.997881051078)"
+      ]
+     },
+     "execution_count": 3,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 7,
-       "text": [
-        "'hwssswxfewhhrfewpdrvttdhxbccleayphalnadhiehaoudrotwnrrvysabjlttbaytmelrkaidopthatlelrtwaamaneksvvzrvllatkcrjquicizgtoqcpnrrkttowandqehtqrvtbaydqealannohulanuzlwextlvjrvivhnohdqmgykaclmswrupdetfioftfelhzpxhaswftwprrsweiseohefpdrvttnvagdvswgoerbetnharvaeevtlltbmgaiatgelinmdawevhatterdhrznbnvoutnefoteveaehlaymhacglzeptvvdimworfisgtuzlwibeqohubtghamqornjnnrumqvjtxeltfovgawdaeevllgrtxibgtibevmpsaateoasevaeyqohameonncfuidoefafattemuimnflznbekofobrliaehhauihnnnwzaeevtlltpaalnanvtzlzuucptaelinanpaahewfthaosetaribnbnvhaevdhyytlmuxb'"
-       ]
-      }
-     ],
-     "prompt_number": 7
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "key_a, score = railfence_break(sanitise(c6a))\n",
+    "key_a, score"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "c6b_nums = [ord(c) - ord('a') for c in c6bs]\n",
-      "c6b_nums"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'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'"
+      ]
+     },
+     "execution_count": 4,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 17,
-       "text": [
-        "[7,\n",
-        " 22,\n",
-        " 18,\n",
-        " 18,\n",
-        " 18,\n",
-        " 22,\n",
-        " 23,\n",
-        " 5,\n",
-        " 4,\n",
-        " 22,\n",
-        " 7,\n",
-        " 7,\n",
-        " 17,\n",
-        " 5,\n",
-        " 4,\n",
-        " 22,\n",
-        " 15,\n",
-        " 3,\n",
-        " 17,\n",
-        " 21,\n",
-        " 19,\n",
-        " 19,\n",
-        " 3,\n",
-        " 7,\n",
-        " 23,\n",
-        " 1,\n",
-        " 2,\n",
-        " 2,\n",
-        " 11,\n",
-        " 4,\n",
-        " 0,\n",
-        " 24,\n",
-        " 15,\n",
-        " 7,\n",
-        " 0,\n",
-        " 11,\n",
-        " 13,\n",
-        " 0,\n",
-        " 3,\n",
-        " 7,\n",
-        " 8,\n",
-        " 4,\n",
-        " 7,\n",
-        " 0,\n",
-        " 14,\n",
-        " 20,\n",
-        " 3,\n",
-        " 17,\n",
-        " 14,\n",
-        " 19,\n",
-        " 22,\n",
-        " 13,\n",
-        " 17,\n",
-        " 17,\n",
-        " 21,\n",
-        " 24,\n",
-        " 18,\n",
-        " 0,\n",
-        " 1,\n",
-        " 9,\n",
-        " 11,\n",
-        " 19,\n",
-        " 19,\n",
-        " 1,\n",
-        " 0,\n",
-        " 24,\n",
-        " 19,\n",
-        " 12,\n",
-        " 4,\n",
-        " 11,\n",
-        " 17,\n",
-        " 10,\n",
-        " 0,\n",
-        " 8,\n",
-        " 3,\n",
-        " 14,\n",
-        " 15,\n",
-        " 19,\n",
-        " 7,\n",
-        " 0,\n",
-        " 19,\n",
-        " 11,\n",
-        " 4,\n",
-        " 11,\n",
-        " 17,\n",
-        " 19,\n",
-        " 22,\n",
-        " 0,\n",
-        " 0,\n",
-        " 12,\n",
-        " 0,\n",
-        " 13,\n",
-        " 4,\n",
-        " 10,\n",
-        " 18,\n",
-        " 21,\n",
-        " 21,\n",
-        " 25,\n",
-        " 17,\n",
-        " 21,\n",
-        " 11,\n",
-        " 11,\n",
-        " 0,\n",
-        " 19,\n",
-        " 10,\n",
-        " 2,\n",
-        " 17,\n",
-        " 9,\n",
-        " 16,\n",
-        " 20,\n",
-        " 8,\n",
-        " 2,\n",
-        " 8,\n",
-        " 25,\n",
-        " 6,\n",
-        " 19,\n",
-        " 14,\n",
-        " 16,\n",
-        " 2,\n",
-        " 15,\n",
-        " 13,\n",
-        " 17,\n",
-        " 17,\n",
-        " 10,\n",
-        " 19,\n",
-        " 19,\n",
-        " 14,\n",
-        " 22,\n",
-        " 0,\n",
-        " 13,\n",
-        " 3,\n",
-        " 16,\n",
-        " 4,\n",
-        " 7,\n",
-        " 19,\n",
-        " 16,\n",
-        " 17,\n",
-        " 21,\n",
-        " 19,\n",
-        " 1,\n",
-        " 0,\n",
-        " 24,\n",
-        " 3,\n",
-        " 16,\n",
-        " 4,\n",
-        " 0,\n",
-        " 11,\n",
-        " 0,\n",
-        " 13,\n",
-        " 13,\n",
-        " 14,\n",
-        " 7,\n",
-        " 20,\n",
-        " 11,\n",
-        " 0,\n",
-        " 13,\n",
-        " 20,\n",
-        " 25,\n",
-        " 11,\n",
-        " 22,\n",
-        " 4,\n",
-        " 23,\n",
-        " 19,\n",
-        " 11,\n",
-        " 21,\n",
-        " 9,\n",
-        " 17,\n",
-        " 21,\n",
-        " 8,\n",
-        " 21,\n",
-        " 7,\n",
-        " 13,\n",
-        " 14,\n",
-        " 7,\n",
-        " 3,\n",
-        " 16,\n",
-        " 12,\n",
-        " 6,\n",
-        " 24,\n",
-        " 10,\n",
-        " 0,\n",
-        " 2,\n",
-        " 11,\n",
-        " 12,\n",
-        " 18,\n",
-        " 22,\n",
-        " 17,\n",
-        " 20,\n",
-        " 15,\n",
-        " 3,\n",
-        " 4,\n",
-        " 19,\n",
-        " 5,\n",
-        " 8,\n",
-        " 14,\n",
-        " 5,\n",
-        " 19,\n",
-        " 5,\n",
-        " 4,\n",
-        " 11,\n",
-        " 7,\n",
-        " 25,\n",
-        " 15,\n",
-        " 23,\n",
-        " 7,\n",
-        " 0,\n",
-        " 18,\n",
-        " 22,\n",
-        " 5,\n",
-        " 19,\n",
-        " 22,\n",
-        " 15,\n",
-        " 17,\n",
-        " 17,\n",
-        " 18,\n",
-        " 22,\n",
-        " 4,\n",
-        " 8,\n",
-        " 18,\n",
-        " 4,\n",
-        " 14,\n",
-        " 7,\n",
-        " 4,\n",
-        " 5,\n",
-        " 15,\n",
-        " 3,\n",
-        " 17,\n",
-        " 21,\n",
-        " 19,\n",
-        " 19,\n",
-        " 13,\n",
-        " 21,\n",
-        " 0,\n",
-        " 6,\n",
-        " 3,\n",
-        " 21,\n",
-        " 18,\n",
-        " 22,\n",
-        " 6,\n",
-        " 14,\n",
-        " 4,\n",
-        " 17,\n",
-        " 1,\n",
-        " 4,\n",
-        " 19,\n",
-        " 13,\n",
-        " 7,\n",
-        " 0,\n",
-        " 17,\n",
-        " 21,\n",
-        " 0,\n",
-        " 4,\n",
-        " 4,\n",
-        " 21,\n",
-        " 19,\n",
-        " 11,\n",
-        " 11,\n",
-        " 19,\n",
-        " 1,\n",
-        " 12,\n",
-        " 6,\n",
-        " 0,\n",
-        " 8,\n",
-        " 0,\n",
-        " 19,\n",
-        " 6,\n",
-        " 4,\n",
-        " 11,\n",
-        " 8,\n",
-        " 13,\n",
-        " 12,\n",
-        " 3,\n",
-        " 0,\n",
-        " 22,\n",
-        " 4,\n",
-        " 21,\n",
-        " 7,\n",
-        " 0,\n",
-        " 19,\n",
-        " 19,\n",
-        " 4,\n",
-        " 17,\n",
-        " 3,\n",
-        " 7,\n",
-        " 17,\n",
-        " 25,\n",
-        " 13,\n",
-        " 1,\n",
-        " 13,\n",
-        " 21,\n",
-        " 14,\n",
-        " 20,\n",
-        " 19,\n",
-        " 13,\n",
-        " 4,\n",
-        " 5,\n",
-        " 14,\n",
-        " 19,\n",
-        " 4,\n",
-        " 21,\n",
-        " 4,\n",
-        " 0,\n",
-        " 4,\n",
-        " 7,\n",
-        " 11,\n",
-        " 0,\n",
-        " 24,\n",
-        " 12,\n",
-        " 7,\n",
-        " 0,\n",
-        " 2,\n",
-        " 6,\n",
-        " 11,\n",
-        " 25,\n",
-        " 4,\n",
-        " 15,\n",
-        " 19,\n",
-        " 21,\n",
-        " 21,\n",
-        " 3,\n",
-        " 8,\n",
-        " 12,\n",
-        " 22,\n",
-        " 14,\n",
-        " 17,\n",
-        " 5,\n",
-        " 8,\n",
-        " 18,\n",
-        " 6,\n",
-        " 19,\n",
-        " 20,\n",
-        " 25,\n",
-        " 11,\n",
-        " 22,\n",
-        " 8,\n",
-        " 1,\n",
-        " 4,\n",
-        " 16,\n",
-        " 14,\n",
-        " 7,\n",
-        " 20,\n",
-        " 1,\n",
-        " 19,\n",
-        " 6,\n",
-        " 7,\n",
-        " 0,\n",
-        " 12,\n",
-        " 16,\n",
-        " 14,\n",
-        " 17,\n",
-        " 13,\n",
-        " 9,\n",
-        " 13,\n",
-        " 13,\n",
-        " 17,\n",
-        " 20,\n",
-        " 12,\n",
-        " 16,\n",
-        " 21,\n",
-        " 9,\n",
-        " 19,\n",
-        " 23,\n",
-        " 4,\n",
-        " 11,\n",
-        " 19,\n",
-        " 5,\n",
-        " 14,\n",
-        " 21,\n",
-        " 6,\n",
-        " 0,\n",
-        " 22,\n",
-        " 3,\n",
-        " 0,\n",
-        " 4,\n",
-        " 4,\n",
-        " 21,\n",
-        " 11,\n",
-        " 11,\n",
-        " 6,\n",
-        " 17,\n",
-        " 19,\n",
-        " 23,\n",
-        " 8,\n",
-        " 1,\n",
-        " 6,\n",
-        " 19,\n",
-        " 8,\n",
-        " 1,\n",
-        " 4,\n",
-        " 21,\n",
-        " 12,\n",
-        " 15,\n",
-        " 18,\n",
-        " 0,\n",
-        " 0,\n",
-        " 19,\n",
-        " 4,\n",
-        " 14,\n",
-        " 0,\n",
-        " 18,\n",
-        " 4,\n",
-        " 21,\n",
-        " 0,\n",
-        " 4,\n",
-        " 24,\n",
-        " 16,\n",
-        " 14,\n",
-        " 7,\n",
-        " 0,\n",
-        " 12,\n",
-        " 4,\n",
-        " 14,\n",
-        " 13,\n",
-        " 13,\n",
-        " 2,\n",
-        " 5,\n",
-        " 20,\n",
-        " 8,\n",
-        " 3,\n",
-        " 14,\n",
-        " 4,\n",
-        " 5,\n",
-        " 0,\n",
-        " 5,\n",
-        " 0,\n",
-        " 19,\n",
-        " 19,\n",
-        " 4,\n",
-        " 12,\n",
-        " 20,\n",
-        " 8,\n",
-        " 12,\n",
-        " 13,\n",
-        " 5,\n",
-        " 11,\n",
-        " 25,\n",
-        " 13,\n",
-        " 1,\n",
-        " 4,\n",
-        " 10,\n",
-        " 14,\n",
-        " 5,\n",
-        " 14,\n",
-        " 1,\n",
-        " 17,\n",
-        " 11,\n",
-        " 8,\n",
-        " 0,\n",
-        " 4,\n",
-        " 7,\n",
-        " 7,\n",
-        " 0,\n",
-        " 20,\n",
-        " 8,\n",
-        " 7,\n",
-        " 13,\n",
-        " 13,\n",
-        " 13,\n",
-        " 22,\n",
-        " 25,\n",
-        " 0,\n",
-        " 4,\n",
-        " 4,\n",
-        " 21,\n",
-        " 19,\n",
-        " 11,\n",
-        " 11,\n",
-        " 19,\n",
-        " 15,\n",
-        " 0,\n",
-        " 0,\n",
-        " 11,\n",
-        " 13,\n",
-        " 0,\n",
-        " 13,\n",
-        " 21,\n",
-        " 19,\n",
-        " 25,\n",
-        " 11,\n",
-        " 25,\n",
-        " 20,\n",
-        " 20,\n",
-        " 2,\n",
-        " 15,\n",
-        " 19,\n",
-        " 0,\n",
-        " 4,\n",
-        " 11,\n",
-        " 8,\n",
-        " 13,\n",
-        " 0,\n",
-        " 13,\n",
-        " 15,\n",
-        " 0,\n",
-        " 0,\n",
-        " 7,\n",
-        " 4,\n",
-        " 22,\n",
-        " 5,\n",
-        " 19,\n",
-        " 7,\n",
-        " 0,\n",
-        " 14,\n",
-        " 18,\n",
-        " 4,\n",
-        " 19,\n",
-        " 0,\n",
-        " 17,\n",
-        " 8,\n",
-        " 1,\n",
-        " 13,\n",
-        " 1,\n",
-        " 13,\n",
-        " 21,\n",
-        " 7,\n",
-        " 0,\n",
-        " 4,\n",
-        " 21,\n",
-        " 3,\n",
-        " 7,\n",
-        " 24,\n",
-        " 24,\n",
-        " 19,\n",
-        " 11,\n",
-        " 12,\n",
-        " 20,\n",
-        " 23,\n",
-        " 1]"
-       ]
-      }
-     ],
-     "prompt_number": 17
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "' '.join(segment(railfence_decipher(sanitise(c6a), key_a)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "m = np.matrix([[7,8], [11,11]])\n",
-      "m"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'hwssswxfewhhrfewpdrvttdhxbccleayphalnadhiehaoudrotwnrrvysabjlttbaytmelrkaidopthatlelrtwaamaneksvvzrvllatkcrjquicizgtoqcpnrrkttowandqehtqrvtbaydqealannohulanuzlwextlvjrvivhnohdqmgykaclmswrupdetfioftfelhzpxhaswftwprrsweiseohefpdrvttnvagdvswgoerbetnharvaeevtlltbmgaiatgelinmdawevhatterdhrznbnvoutnefoteveaehlaymhacglzeptvvdimworfisgtuzlwibeqohubtghamqornjnnrumqvjtxeltfovgawdaeevllgrtxibgtibevmpsaateoasevaeyqohameonncfuidoefafattemuimnflznbekofobrliaehhauihnnnwzaeevtlltpaalnanvtzlzuucptaelinanpaahewfthaosetaribnbnvhaevdhyytlmuxb'"
+      ]
+     },
+     "execution_count": 7,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 106,
-       "text": [
-        "matrix([[ 7,  8],\n",
-        "        [11, 11]])"
-       ]
-      }
-     ],
-     "prompt_number": 106
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c6bs = sanitise(c6b)\n",
+    "c6bs"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "np.linalg.det(m)"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "[7,\n",
+       " 22,\n",
+       " 18,\n",
+       " 18,\n",
+       " 18,\n",
+       " 22,\n",
+       " 23,\n",
+       " 5,\n",
+       " 4,\n",
+       " 22,\n",
+       " 7,\n",
+       " 7,\n",
+       " 17,\n",
+       " 5,\n",
+       " 4,\n",
+       " 22,\n",
+       " 15,\n",
+       " 3,\n",
+       " 17,\n",
+       " 21,\n",
+       " 19,\n",
+       " 19,\n",
+       " 3,\n",
+       " 7,\n",
+       " 23,\n",
+       " 1,\n",
+       " 2,\n",
+       " 2,\n",
+       " 11,\n",
+       " 4,\n",
+       " 0,\n",
+       " 24,\n",
+       " 15,\n",
+       " 7,\n",
+       " 0,\n",
+       " 11,\n",
+       " 13,\n",
+       " 0,\n",
+       " 3,\n",
+       " 7,\n",
+       " 8,\n",
+       " 4,\n",
+       " 7,\n",
+       " 0,\n",
+       " 14,\n",
+       " 20,\n",
+       " 3,\n",
+       " 17,\n",
+       " 14,\n",
+       " 19,\n",
+       " 22,\n",
+       " 13,\n",
+       " 17,\n",
+       " 17,\n",
+       " 21,\n",
+       " 24,\n",
+       " 18,\n",
+       " 0,\n",
+       " 1,\n",
+       " 9,\n",
+       " 11,\n",
+       " 19,\n",
+       " 19,\n",
+       " 1,\n",
+       " 0,\n",
+       " 24,\n",
+       " 19,\n",
+       " 12,\n",
+       " 4,\n",
+       " 11,\n",
+       " 17,\n",
+       " 10,\n",
+       " 0,\n",
+       " 8,\n",
+       " 3,\n",
+       " 14,\n",
+       " 15,\n",
+       " 19,\n",
+       " 7,\n",
+       " 0,\n",
+       " 19,\n",
+       " 11,\n",
+       " 4,\n",
+       " 11,\n",
+       " 17,\n",
+       " 19,\n",
+       " 22,\n",
+       " 0,\n",
+       " 0,\n",
+       " 12,\n",
+       " 0,\n",
+       " 13,\n",
+       " 4,\n",
+       " 10,\n",
+       " 18,\n",
+       " 21,\n",
+       " 21,\n",
+       " 25,\n",
+       " 17,\n",
+       " 21,\n",
+       " 11,\n",
+       " 11,\n",
+       " 0,\n",
+       " 19,\n",
+       " 10,\n",
+       " 2,\n",
+       " 17,\n",
+       " 9,\n",
+       " 16,\n",
+       " 20,\n",
+       " 8,\n",
+       " 2,\n",
+       " 8,\n",
+       " 25,\n",
+       " 6,\n",
+       " 19,\n",
+       " 14,\n",
+       " 16,\n",
+       " 2,\n",
+       " 15,\n",
+       " 13,\n",
+       " 17,\n",
+       " 17,\n",
+       " 10,\n",
+       " 19,\n",
+       " 19,\n",
+       " 14,\n",
+       " 22,\n",
+       " 0,\n",
+       " 13,\n",
+       " 3,\n",
+       " 16,\n",
+       " 4,\n",
+       " 7,\n",
+       " 19,\n",
+       " 16,\n",
+       " 17,\n",
+       " 21,\n",
+       " 19,\n",
+       " 1,\n",
+       " 0,\n",
+       " 24,\n",
+       " 3,\n",
+       " 16,\n",
+       " 4,\n",
+       " 0,\n",
+       " 11,\n",
+       " 0,\n",
+       " 13,\n",
+       " 13,\n",
+       " 14,\n",
+       " 7,\n",
+       " 20,\n",
+       " 11,\n",
+       " 0,\n",
+       " 13,\n",
+       " 20,\n",
+       " 25,\n",
+       " 11,\n",
+       " 22,\n",
+       " 4,\n",
+       " 23,\n",
+       " 19,\n",
+       " 11,\n",
+       " 21,\n",
+       " 9,\n",
+       " 17,\n",
+       " 21,\n",
+       " 8,\n",
+       " 21,\n",
+       " 7,\n",
+       " 13,\n",
+       " 14,\n",
+       " 7,\n",
+       " 3,\n",
+       " 16,\n",
+       " 12,\n",
+       " 6,\n",
+       " 24,\n",
+       " 10,\n",
+       " 0,\n",
+       " 2,\n",
+       " 11,\n",
+       " 12,\n",
+       " 18,\n",
+       " 22,\n",
+       " 17,\n",
+       " 20,\n",
+       " 15,\n",
+       " 3,\n",
+       " 4,\n",
+       " 19,\n",
+       " 5,\n",
+       " 8,\n",
+       " 14,\n",
+       " 5,\n",
+       " 19,\n",
+       " 5,\n",
+       " 4,\n",
+       " 11,\n",
+       " 7,\n",
+       " 25,\n",
+       " 15,\n",
+       " 23,\n",
+       " 7,\n",
+       " 0,\n",
+       " 18,\n",
+       " 22,\n",
+       " 5,\n",
+       " 19,\n",
+       " 22,\n",
+       " 15,\n",
+       " 17,\n",
+       " 17,\n",
+       " 18,\n",
+       " 22,\n",
+       " 4,\n",
+       " 8,\n",
+       " 18,\n",
+       " 4,\n",
+       " 14,\n",
+       " 7,\n",
+       " 4,\n",
+       " 5,\n",
+       " 15,\n",
+       " 3,\n",
+       " 17,\n",
+       " 21,\n",
+       " 19,\n",
+       " 19,\n",
+       " 13,\n",
+       " 21,\n",
+       " 0,\n",
+       " 6,\n",
+       " 3,\n",
+       " 21,\n",
+       " 18,\n",
+       " 22,\n",
+       " 6,\n",
+       " 14,\n",
+       " 4,\n",
+       " 17,\n",
+       " 1,\n",
+       " 4,\n",
+       " 19,\n",
+       " 13,\n",
+       " 7,\n",
+       " 0,\n",
+       " 17,\n",
+       " 21,\n",
+       " 0,\n",
+       " 4,\n",
+       " 4,\n",
+       " 21,\n",
+       " 19,\n",
+       " 11,\n",
+       " 11,\n",
+       " 19,\n",
+       " 1,\n",
+       " 12,\n",
+       " 6,\n",
+       " 0,\n",
+       " 8,\n",
+       " 0,\n",
+       " 19,\n",
+       " 6,\n",
+       " 4,\n",
+       " 11,\n",
+       " 8,\n",
+       " 13,\n",
+       " 12,\n",
+       " 3,\n",
+       " 0,\n",
+       " 22,\n",
+       " 4,\n",
+       " 21,\n",
+       " 7,\n",
+       " 0,\n",
+       " 19,\n",
+       " 19,\n",
+       " 4,\n",
+       " 17,\n",
+       " 3,\n",
+       " 7,\n",
+       " 17,\n",
+       " 25,\n",
+       " 13,\n",
+       " 1,\n",
+       " 13,\n",
+       " 21,\n",
+       " 14,\n",
+       " 20,\n",
+       " 19,\n",
+       " 13,\n",
+       " 4,\n",
+       " 5,\n",
+       " 14,\n",
+       " 19,\n",
+       " 4,\n",
+       " 21,\n",
+       " 4,\n",
+       " 0,\n",
+       " 4,\n",
+       " 7,\n",
+       " 11,\n",
+       " 0,\n",
+       " 24,\n",
+       " 12,\n",
+       " 7,\n",
+       " 0,\n",
+       " 2,\n",
+       " 6,\n",
+       " 11,\n",
+       " 25,\n",
+       " 4,\n",
+       " 15,\n",
+       " 19,\n",
+       " 21,\n",
+       " 21,\n",
+       " 3,\n",
+       " 8,\n",
+       " 12,\n",
+       " 22,\n",
+       " 14,\n",
+       " 17,\n",
+       " 5,\n",
+       " 8,\n",
+       " 18,\n",
+       " 6,\n",
+       " 19,\n",
+       " 20,\n",
+       " 25,\n",
+       " 11,\n",
+       " 22,\n",
+       " 8,\n",
+       " 1,\n",
+       " 4,\n",
+       " 16,\n",
+       " 14,\n",
+       " 7,\n",
+       " 20,\n",
+       " 1,\n",
+       " 19,\n",
+       " 6,\n",
+       " 7,\n",
+       " 0,\n",
+       " 12,\n",
+       " 16,\n",
+       " 14,\n",
+       " 17,\n",
+       " 13,\n",
+       " 9,\n",
+       " 13,\n",
+       " 13,\n",
+       " 17,\n",
+       " 20,\n",
+       " 12,\n",
+       " 16,\n",
+       " 21,\n",
+       " 9,\n",
+       " 19,\n",
+       " 23,\n",
+       " 4,\n",
+       " 11,\n",
+       " 19,\n",
+       " 5,\n",
+       " 14,\n",
+       " 21,\n",
+       " 6,\n",
+       " 0,\n",
+       " 22,\n",
+       " 3,\n",
+       " 0,\n",
+       " 4,\n",
+       " 4,\n",
+       " 21,\n",
+       " 11,\n",
+       " 11,\n",
+       " 6,\n",
+       " 17,\n",
+       " 19,\n",
+       " 23,\n",
+       " 8,\n",
+       " 1,\n",
+       " 6,\n",
+       " 19,\n",
+       " 8,\n",
+       " 1,\n",
+       " 4,\n",
+       " 21,\n",
+       " 12,\n",
+       " 15,\n",
+       " 18,\n",
+       " 0,\n",
+       " 0,\n",
+       " 19,\n",
+       " 4,\n",
+       " 14,\n",
+       " 0,\n",
+       " 18,\n",
+       " 4,\n",
+       " 21,\n",
+       " 0,\n",
+       " 4,\n",
+       " 24,\n",
+       " 16,\n",
+       " 14,\n",
+       " 7,\n",
+       " 0,\n",
+       " 12,\n",
+       " 4,\n",
+       " 14,\n",
+       " 13,\n",
+       " 13,\n",
+       " 2,\n",
+       " 5,\n",
+       " 20,\n",
+       " 8,\n",
+       " 3,\n",
+       " 14,\n",
+       " 4,\n",
+       " 5,\n",
+       " 0,\n",
+       " 5,\n",
+       " 0,\n",
+       " 19,\n",
+       " 19,\n",
+       " 4,\n",
+       " 12,\n",
+       " 20,\n",
+       " 8,\n",
+       " 12,\n",
+       " 13,\n",
+       " 5,\n",
+       " 11,\n",
+       " 25,\n",
+       " 13,\n",
+       " 1,\n",
+       " 4,\n",
+       " 10,\n",
+       " 14,\n",
+       " 5,\n",
+       " 14,\n",
+       " 1,\n",
+       " 17,\n",
+       " 11,\n",
+       " 8,\n",
+       " 0,\n",
+       " 4,\n",
+       " 7,\n",
+       " 7,\n",
+       " 0,\n",
+       " 20,\n",
+       " 8,\n",
+       " 7,\n",
+       " 13,\n",
+       " 13,\n",
+       " 13,\n",
+       " 22,\n",
+       " 25,\n",
+       " 0,\n",
+       " 4,\n",
+       " 4,\n",
+       " 21,\n",
+       " 19,\n",
+       " 11,\n",
+       " 11,\n",
+       " 19,\n",
+       " 15,\n",
+       " 0,\n",
+       " 0,\n",
+       " 11,\n",
+       " 13,\n",
+       " 0,\n",
+       " 13,\n",
+       " 21,\n",
+       " 19,\n",
+       " 25,\n",
+       " 11,\n",
+       " 25,\n",
+       " 20,\n",
+       " 20,\n",
+       " 2,\n",
+       " 15,\n",
+       " 19,\n",
+       " 0,\n",
+       " 4,\n",
+       " 11,\n",
+       " 8,\n",
+       " 13,\n",
+       " 0,\n",
+       " 13,\n",
+       " 15,\n",
+       " 0,\n",
+       " 0,\n",
+       " 7,\n",
+       " 4,\n",
+       " 22,\n",
+       " 5,\n",
+       " 19,\n",
+       " 7,\n",
+       " 0,\n",
+       " 14,\n",
+       " 18,\n",
+       " 4,\n",
+       " 19,\n",
+       " 0,\n",
+       " 17,\n",
+       " 8,\n",
+       " 1,\n",
+       " 13,\n",
+       " 1,\n",
+       " 13,\n",
+       " 21,\n",
+       " 7,\n",
+       " 0,\n",
+       " 4,\n",
+       " 21,\n",
+       " 3,\n",
+       " 7,\n",
+       " 24,\n",
+       " 24,\n",
+       " 19,\n",
+       " 11,\n",
+       " 12,\n",
+       " 20,\n",
+       " 23,\n",
+       " 1]"
+      ]
+     },
+     "execution_count": 17,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 107,
-       "text": [
-        "-11.000000000000002"
-       ]
-      }
-     ],
-     "prompt_number": 107
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c6b_nums = [ord(c) - ord('a') for c in c6bs]\n",
+    "c6b_nums"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 106,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "m.I"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[ 7,  8],\n",
+       "        [11, 11]])"
+      ]
+     },
+     "execution_count": 106,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 108,
-       "text": [
-        "matrix([[-1.        ,  0.72727273],\n",
-        "        [ 1.        , -0.63636364]])"
-       ]
-      }
-     ],
-     "prompt_number": 108
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "m = np.matrix([[7,8], [11,11]])\n",
+    "m"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 107,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "v = np.matrix([[7], [22]])\n",
-      "v"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "-11.000000000000002"
+      ]
+     },
+     "execution_count": 107,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 37,
-       "text": [
-        "matrix([[ 7],\n",
-        "        [22]])"
-       ]
-      }
-     ],
-     "prompt_number": 37
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "np.linalg.det(m)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 108,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "c = (m*v) % 26\n",
-      "c"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[-1.        ,  0.72727273],\n",
+       "        [ 1.        , -0.63636364]])"
+      ]
+     },
+     "execution_count": 108,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 46,
-       "text": [
-        "matrix([[9],\n",
-        "        [5]])"
-       ]
-      }
-     ],
-     "prompt_number": 46
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "m.I"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "np.linalg.solve(m, c) % 26"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[ 7],\n",
+       "        [22]])"
+      ]
+     },
+     "execution_count": 37,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 48,
-       "text": [
-        "matrix([[  7.],\n",
-        "        [ 22.]])"
-       ]
-      }
-     ],
-     "prompt_number": 48
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "v = np.matrix([[7], [22]])\n",
+    "v"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 46,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "m*v"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[9],\n",
+       "        [5]])"
+      ]
+     },
+     "execution_count": 46,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 40,
-       "text": [
-        "matrix([[ 87],\n",
-        "        [109]])"
-       ]
-      }
-     ],
-     "prompt_number": 40
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "c = (m*v) % 26\n",
+    "c"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 48,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "(m*v)%26"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[  7.],\n",
+       "        [ 22.]])"
+      ]
+     },
+     "execution_count": 48,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 41,
-       "text": [
-        "matrix([[9],\n",
-        "        [5]])"
-       ]
-      }
-     ],
-     "prompt_number": 41
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "np.linalg.solve(m, c) % 26"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "np.linalg.solve(m, (m*v)%26)%26"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[ 87],\n",
+       "        [109]])"
+      ]
+     },
+     "execution_count": 40,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 42,
-       "text": [
-        "matrix([[  7.],\n",
-        "        [ 22.]])"
-       ]
-      }
-     ],
-     "prompt_number": 42
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "m*v"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 41,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "len(m)"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[9],\n",
+       "        [5]])"
+      ]
+     },
+     "execution_count": 41,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 51,
-       "text": [
-        "2"
-       ]
-      }
-     ],
-     "prompt_number": 51
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "(m*v)%26"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "def hill_encipher(matrix, message_letters, fillvalue='a'):\n",
-      "    n = len(matrix)\n",
-      "    sanitised_message = sanitise(message_letters)\n",
-      "    if len(sanitised_message) % n != 0:\n",
-      "        padding = fillvalue[0] * (n - len(sanitised_message) % n)\n",
-      "    else:\n",
-      "        padding = ''\n",
-      "    message = [ord(c) - ord('a') for c in sanitised_message + padding]\n",
-      "    message_chunks = [message[i:i+n] for i in range(0, len(message), n)]\n",
-      "    # message_chunks = chunks(message, len(matrix), fillvalue=None)\n",
-      "    enciphered_chunks = [((matrix * np.matrix(c).T).T).tolist()[0] for c in message_chunks]\n",
-      "    return ''.join([chr(int(round(l)) % 26 + ord('a')) for l in sum(enciphered_chunks, [])])"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[  7.],\n",
+       "        [ 22.]])"
+      ]
+     },
+     "execution_count": 42,
      "metadata": {},
-     "outputs": [],
-     "prompt_number": 181
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "np.linalg.solve(m, (m*v)%26)%26"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 51,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "hill_encipher(m, 'hellothere')"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "2"
+      ]
+     },
+     "execution_count": 51,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 156,
-       "text": [
-        "'drjiqzdrvx'"
-       ]
-      }
-     ],
-     "prompt_number": 156
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(m)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 181,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def hill_encipher(matrix, message_letters, fillvalue='a'):\n",
+    "    n = len(matrix)\n",
+    "    sanitised_message = sanitise(message_letters)\n",
+    "    if len(sanitised_message) % n != 0:\n",
+    "        padding = fillvalue[0] * (n - len(sanitised_message) % n)\n",
+    "    else:\n",
+    "        padding = ''\n",
+    "    message = [ord(c) - ord('a') for c in sanitised_message + padding]\n",
+    "    message_chunks = [message[i:i+n] for i in range(0, len(message), n)]\n",
+    "    # message_chunks = chunks(message, len(matrix), fillvalue=None)\n",
+    "    enciphered_chunks = [((matrix * np.matrix(c).T).T).tolist()[0] for c in message_chunks]\n",
+    "    return ''.join([chr(int(round(l)) % 26 + ord('a')) for l in sum(enciphered_chunks, [])])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 156,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "msg = [ord(c) - ord('a') for c in 'hellothere']\n",
-      "msg"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'drjiqzdrvx'"
+      ]
+     },
+     "execution_count": 156,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 68,
-       "text": [
-        "[7, 4, 11, 11, 14, 19, 7, 4, 17, 4]"
-       ]
-      }
-     ],
-     "prompt_number": 68
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "hill_encipher(m, 'hellothere')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 68,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "msgc = [msg[i:i+len(m)] for i in range(0, len(msg), len(m))]\n",
-      "msgc"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "[7, 4, 11, 11, 14, 19, 7, 4, 17, 4]"
+      ]
+     },
+     "execution_count": 68,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 112,
-       "text": [
-        "[[7, 11], [14, 25], [21, 14], [7, 11], [11, 15], [0, 0]]"
-       ]
-      }
-     ],
-     "prompt_number": 112
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "msg = [ord(c) - ord('a') for c in 'hellothere']\n",
+    "msg"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 112,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "((m*np.matrix(msgc[0]).T).T % 26).tolist()[0]"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "[[7, 11], [14, 25], [21, 14], [7, 11], [11, 15], [0, 0]]"
+      ]
+     },
+     "execution_count": 112,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 87,
-       "text": [
-        "[7, 11]"
-       ]
-      }
-     ],
-     "prompt_number": 87
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "msgc = [msg[i:i+len(m)] for i in range(0, len(msg), len(m))]\n",
+    "msgc"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 87,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "def hill_decipher(matrix, message, fillvalue='a'):\n",
-      "    adjugate = linalg.det(matrix)*linalg.inv(matrix)\n",
-      "    inverse_determinant = modular_division_table[int(round(linalg.det(matrix))) % 26][1]\n",
-      "    inverse_matrix = (inverse_determinant * adjugate) % 26\n",
-      "    return hill_encipher(inverse_matrix, message, fillvalue)                                                 "
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "[7, 11]"
+      ]
+     },
+     "execution_count": 87,
      "metadata": {},
-     "outputs": [],
-     "prompt_number": 195
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "((m*np.matrix(msgc[0]).T).T % 26).tolist()[0]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 195,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "def hill_decipher(matrix, message, fillvalue='a'):\n",
+    "    adjugate = linalg.det(matrix)*linalg.inv(matrix)\n",
+    "    inverse_determinant = modular_division_table[int(round(linalg.det(matrix))) % 26][1]\n",
+    "    inverse_matrix = (inverse_determinant * adjugate) % 26\n",
+    "    return hill_encipher(inverse_matrix, message, fillvalue)                                                 "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 161,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "hill_decipher(m, 'drjiqzdrvx')"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'hellothere'"
+      ]
+     },
+     "execution_count": 161,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 161,
-       "text": [
-        "'hellothere'"
-       ]
-      }
-     ],
-     "prompt_number": 161
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "hill_decipher(m, 'drjiqzdrvx')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 114,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "msg = [ord(c) - ord('a') for c in 'drjiqzdrvxaa']\n",
-      "msg"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "[3, 17, 9, 8, 16, 25, 3, 17, 21, 23, 0, 0]"
+      ]
+     },
+     "execution_count": 114,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 114,
-       "text": [
-        "[3, 17, 9, 8, 16, 25, 3, 17, 21, 23, 0, 0]"
-       ]
-      }
-     ],
-     "prompt_number": 114
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "msg = [ord(c) - ord('a') for c in 'drjiqzdrvxaa']\n",
+    "msg"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 115,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "msgc = [msg[i:i+len(m)] for i in range(0, len(msg), len(m))]\n",
-      "msgc"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "[[3, 17], [9, 8], [16, 25], [3, 17], [21, 23], [0, 0]]"
+      ]
+     },
+     "execution_count": 115,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 115,
-       "text": [
-        "[[3, 17], [9, 8], [16, 25], [3, 17], [21, 23], [0, 0]]"
-       ]
-      }
-     ],
-     "prompt_number": 115
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "msgc = [msg[i:i+len(m)] for i in range(0, len(msg), len(m))]\n",
+    "msgc"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 116,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "(np.linalg.solve(m, np.matrix(msgc[0]).T).T % 26)"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[  9.36363636,  18.18181818]])"
+      ]
+     },
+     "execution_count": 116,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 116,
-       "text": [
-        "matrix([[  9.36363636,  18.18181818]])"
-       ]
-      }
-     ],
-     "prompt_number": 116
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "(np.linalg.solve(m, np.matrix(msgc[0]).T).T % 26)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 142,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "m_adj = linalg.det(m)*linalg.inv(m)\n",
-      "m_adj"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[ 11.,  -8.],\n",
+       "        [-11.,   7.]])"
+      ]
+     },
+     "execution_count": 142,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 142,
-       "text": [
-        "matrix([[ 11.,  -8.],\n",
-        "        [-11.,   7.]])"
-       ]
-      }
-     ],
-     "prompt_number": 142
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "m_adj = linalg.det(m)*linalg.inv(m)\n",
+    "m_adj"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 148,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "modular_division_table[int(round(linalg.det(m))) % 26][1]"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "7"
+      ]
+     },
+     "execution_count": 148,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 148,
-       "text": [
-        "7"
-       ]
-      }
-     ],
-     "prompt_number": 148
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "modular_division_table[int(round(linalg.det(m))) % 26][1]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 150,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "m_inv = (modular_division_table[int(round(linalg.det(m))) % 26][1] * m_adj) % 26\n",
-      "m_inv"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[ 25.,  22.],\n",
+       "        [  1.,  23.]])"
+      ]
+     },
+     "execution_count": 150,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 150,
-       "text": [
-        "matrix([[ 25.,  22.],\n",
-        "        [  1.,  23.]])"
-       ]
-      }
-     ],
-     "prompt_number": 150
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "m_inv = (modular_division_table[int(round(linalg.det(m))) % 26][1] * m_adj) % 26\n",
+    "m_inv"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 157,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "hill_encipher(m_inv, 'drjiqzdrvx')"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'hellothere'"
+      ]
+     },
+     "execution_count": 157,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 157,
-       "text": [
-        "'hellothere'"
-       ]
-      }
-     ],
-     "prompt_number": 157
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "hill_encipher(m_inv, 'drjiqzdrvx')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 120,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "np.dot(m , 1/linalg.det(m) * mc)"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[ 1.,  0.],\n",
+       "        [ 0.,  1.]])"
+      ]
+     },
+     "execution_count": 120,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 120,
-       "text": [
-        "matrix([[ 1.,  0.],\n",
-        "        [ 0.,  1.]])"
-       ]
-      }
-     ],
-     "prompt_number": 120
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "np.dot(m , 1/linalg.det(m) * mc)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 122,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "ml = np.matrix([[6, 24, 1], [13, 16, 10], [20, 17, 15]])\n",
-      "ml"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[ 6, 24,  1],\n",
+       "        [13, 16, 10],\n",
+       "        [20, 17, 15]])"
+      ]
+     },
+     "execution_count": 122,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 122,
-       "text": [
-        "matrix([[ 6, 24,  1],\n",
-        "        [13, 16, 10],\n",
-        "        [20, 17, 15]])"
-       ]
-      }
-     ],
-     "prompt_number": 122
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ml = np.matrix([[6, 24, 1], [13, 16, 10], [20, 17, 15]])\n",
+    "ml"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 137,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "ml_adj = linalg.det(ml)*linalg.inv(ml) % 26\n",
-      "ml_adj"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[ 18.,  21.,  16.],\n",
+       "        [  5.,  18.,   5.],\n",
+       "        [  5.,  14.,  18.]])"
+      ]
+     },
+     "execution_count": 137,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 137,
-       "text": [
-        "matrix([[ 18.,  21.,  16.],\n",
-        "        [  5.,  18.,   5.],\n",
-        "        [  5.,  14.,  18.]])"
-       ]
-      }
-     ],
-     "prompt_number": 137
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ml_adj = linalg.det(ml)*linalg.inv(ml) % 26\n",
+    "ml_adj"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 138,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "modular_division_table[int(linalg.det(ml) % 26)][1]"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "25"
+      ]
+     },
+     "execution_count": 138,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 138,
-       "text": [
-        "25"
-       ]
-      }
-     ],
-     "prompt_number": 138
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "modular_division_table[int(linalg.det(ml) % 26)][1]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 139,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "ml_inv = (modular_division_table[int(linalg.det(ml) % 26)][1] * ml_adj) % 26\n",
-      "ml_inv"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "matrix([[  8.,   5.,  10.],\n",
+       "        [ 21.,   8.,  21.],\n",
+       "        [ 21.,  12.,   8.]])"
+      ]
+     },
+     "execution_count": 139,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 139,
-       "text": [
-        "matrix([[  8.,   5.,  10.],\n",
-        "        [ 21.,   8.,  21.],\n",
-        "        [ 21.,  12.,   8.]])"
-       ]
-      }
-     ],
-     "prompt_number": 139
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ml_inv = (modular_division_table[int(linalg.det(ml) % 26)][1] * ml_adj) % 26\n",
+    "ml_inv"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 193,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "hill_encipher(ml, 'hello there')"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'tfjflpznvyac'"
+      ]
+     },
+     "execution_count": 193,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 193,
-       "text": [
-        "'tfjflpznvyac'"
-       ]
-      }
-     ],
-     "prompt_number": 193
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "hill_encipher(ml, 'hello there')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 196,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "hill_decipher(ml, 'tfjflpznvyac')"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'hellothereaa'"
+      ]
+     },
+     "execution_count": 196,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 196,
-       "text": [
-        "'hellothereaa'"
-       ]
-      }
-     ],
-     "prompt_number": 196
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "hill_decipher(ml, 'tfjflpznvyac')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 182,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "hill_encipher(ml, 'act')"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'poh'"
+      ]
+     },
+     "execution_count": 182,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 182,
-       "text": [
-        "'poh'"
-       ]
-      }
-     ],
-     "prompt_number": 182
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "hill_encipher(ml, 'act')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 192,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "hill_decipher(ml, 'poh')"
-     ],
-     "language": "python",
-     "metadata": {},
-     "outputs": [
-      {
-       "output_type": "stream",
-       "stream": "stdout",
-       "text": [
-        "[[  8.   5.  10.]\n",
-        " [ 21.   8.  21.]\n",
-        " [ 21.  12.   8.]]\n"
-       ]
-      },
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 192,
-       "text": [
-        "'act'"
-       ]
-      }
-     ],
-     "prompt_number": 192
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[[  8.   5.  10.]\n",
+      " [ 21.   8.  21.]\n",
+      " [ 21.  12.   8.]]\n"
+     ]
     },
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "[chr(int(round(i)) % 26 + ord('a')) for i in (ml_inv * np.matrix([ord(c) - ord('a') for c in 'poh']).T).T.tolist()[0]]"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "'act'"
+      ]
+     },
+     "execution_count": 192,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 180,
-       "text": [
-        "['a', 'c', 't']"
-       ]
-      }
-     ],
-     "prompt_number": 180
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "hill_decipher(ml, 'poh')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 180,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "hill_encipher(ml_inv, 'poh')"
-     ],
-     "language": "python",
+     "data": {
+      "text/plain": [
+       "['a', 'c', 't']"
+      ]
+     },
+     "execution_count": 180,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 184,
-       "text": [
-        "'act'"
-       ]
-      }
-     ],
-     "prompt_number": 184
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[chr(int(round(i)) % 26 + ord('a')) for i in (ml_inv * np.matrix([ord(c) - ord('a') for c in 'poh']).T).T.tolist()[0]]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 184,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "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",
+     "data": {
+      "text/plain": [
+       "'act'"
+      ]
+     },
+     "execution_count": 184,
      "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
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "hill_encipher(ml_inv, 'poh')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 203,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "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
-    },
+     "ename": "KeyboardInterrupt",
+     "evalue": "",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
+      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
+     ]
+    }
+   ],
+   "source": [
+    "len([list(m) for m in itertools.product([list(r) for r in itertools.product(range(26), repeat=3)], repeat=3)])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 202,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "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",
+     "data": {
+      "text/plain": [
+       "19683"
+      ]
+     },
+     "execution_count": 202,
      "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
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "(3**3)**3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 206,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "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",
+     "data": {
+      "text/plain": [
+       "[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]])]"
+      ]
+     },
+     "execution_count": 206,
      "metadata": {},
-     "outputs": [
-      {
-       "metadata": {},
-       "output_type": "pyout",
-       "prompt_number": 215,
-       "text": [
-        "157248"
-       ]
-      }
-     ],
-     "prompt_number": 215
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "[np.matrix(list(m)) for m in itertools.product([list(r) for r in itertools.product(range(3), repeat=2)], repeat=2)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 215,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "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",
+     "data": {
+      "text/plain": [
+       "157248"
+      ]
+     },
+     "execution_count": 215,
      "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
-    },
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "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)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 216,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "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
-    },
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "done\n",
+      "done\n",
+      "done\n",
+      "done\n",
+      "1 loops, best of 3: 10 s per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%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')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 217,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [],
-     "language": "python",
-     "metadata": {},
-     "outputs": []
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "done\n",
+      "done\n",
+      "done\n",
+      "done\n",
+      "1 loops, best of 3: 20.4 s per loop\n"
+     ]
     }
    ],
-   "metadata": {}
+   "source": [
+    "%%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')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": []
   }
- ]
-}
\ No newline at end of file
+ ],
+ "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.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}