--- /dev/null
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "5c19999b",
+ "metadata": {
+ "Collapsed": "false"
+ },
+ "outputs": [],
+ "source": [
+ "from szyfrow.caesar import *\n",
+ "from szyfrow.affine import *\n",
+ "from szyfrow.keyword_cipher import *\n",
+ "from szyfrow.column_transposition import *\n",
+ "from szyfrow.vigenere import *\n",
+ "from szyfrow.polybius import *\n",
+ "from szyfrow.support.text_prettify import *\n",
+ "\n",
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "import collections\n",
+ "%matplotlib inline"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "d9dd1b5e",
+ "metadata": {
+ "Collapsed": "false"
+ },
+ "outputs": [],
+ "source": [
+ "challenge_number = 7\n",
+ "plaintext_a_filename = f'plaintext.{challenge_number}a.txt'\n",
+ "plaintext_b_filename = f'plaintext.{challenge_number}b.txt'\n",
+ "ciphertext_a_filename = f'ciphertext.{challenge_number}a.txt'\n",
+ "ciphertext_b_filename = f'ciphertext.{challenge_number}b.txt'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "0f1f792a",
+ "metadata": {
+ "Collapsed": "false"
+ },
+ "outputs": [],
+ "source": [
+ "nca = open(ciphertext_a_filename).read()\n",
+ "cb = open(ciphertext_b_filename).read()\n",
+ "\n",
+ "numtrans = ''.maketrans('12345', 'abcde')\n",
+ "ca = nca.translate(numtrans)\n",
+ "\n",
+ "sca = sanitise(ca)\n",
+ "rsca = cat(reversed(sca))\n",
+ "scb = sanitise(cb)\n",
+ "rscb = cat(reversed(scb))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "b8d5f9ec-27f1-498b-8e64-c5eb2424e581",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Counter({'e': 632, 'c': 619, 'a': 714, 'b': 410, 'd': 787})"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sca_counts = collections.Counter(sca)\n",
+ "sca_counts"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "b5cabba1-ac75-46ea-ac05-8699cc88d986",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "<AxesSubplot:>"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ "<Figure size 432x288 with 1 Axes>"
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "pd.Series(sca_counts).sort_index().plot.bar()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "583312cf-a973-4671-9ba8-85fe10cb9e00",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(('alchemy', <KeywordWrapAlphabet.from_a: 1>, 'abcde', 'abcde', False),\n",
+ " -6776.263168839725)"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "key_a, score_a = polybius_break(sca, column_labels='abcde', row_labels='abcde',\n",
+ " fitness=Ptrigrams)\n",
+ "key_a, score_a"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "4262216b-efed-491e-ade1-d7e8dffe4454",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'wemounhtbeattacbehkessayebdhhendntbeunherizdnycoheomandkayesentdnfungkaditopeopieattbeuseklasszdtkdybtbavesidppehpastuslutiucgdizbarrzanhdbahaireahzmdyurehouttbattbezkdybttrztocokkundcatetbdswaztbeconspdraczbahavodhehhetectdonmoroveracenturzsotbezwereunidgeiztokagetbekdstageomsenhdnykessayesexpidcdtizahhressehtooneanotberdtdsaiwazslestnottokageidngsletweenkeklersomanetworganhaweiibdhhenkessayednfungkadiavodhstbatrdsgespecdaiizdmdtdswdheizhdstrdlutehlzoneomtbelotnetworgsidgetbdsonedwastoomocussehontbehecrzptatmdrstanhwasntreahdnywbatdtsadhuntdidmounhbernakestardnylacgatkeattbeenhperbapswesbouihbaveaireahzreaidsehtbattrdndtzcouihlednvoivehlutdtneveroccurrehtoketbatbernakewasanztbdnyotbertbanacodncdhencetbemactsbescbaridesndecesbouihbaveidtuptbeidybtsontbehasbloarhtbouybanhdakworrdehtbatbarrzhdhntradsedtperbapsbedsaireahzsbahowdnyberanhhdhntidgetosazsooutomiozaitzlutbehdhntteiiketbatanhsokebowdtbdngbewouihdtbdngdtskoreidgeiztbatsbeslezonhsuspdcdondnbdskdnhsbebaspiazehandkportantroiednbdsnetworgmormourteenzearsanhtbemacttbatsbekdybtleahoulieayentwdiileareailiowtbatwaslahlutdtwasnttbeworstomdttbehetaditrdndtzydvesontbeconspdraczsrecentactdvdtdesdstruizmrdybtendnywbatcouihtbezwantattbebeartomtbepanhekdcresponseyroupssureiztbezcantbaveleenresponsdliemortbeoutlreaganhwbatweretbezhodnyatcopdhesperateizwanttotagetbdstobarrztotaigtobdkaloutdtluttbemdnaiparayrapbstoppehkednkztracgswbzoneartbhoestrdndtztbdngdkdybtfodntbekwbatbavedsadhorhonetbatwouihkagetbektbdngdcouihleatradtoranhwdiitbatkagebarrzhdstrustketoodknotsuredcantagetbatrdsgdkdybtbavetomdndsbtbdskdssdonaione'"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "word_a, wrap_a, col_a, row_a, col_first_a = key_a\n",
+ "polybius_decipher(sca, keyword=word_a, column_order=col_a, row_order=row_a,\n",
+ " column_first=col_first_a, wrap_alphabet=wrap_a)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "bbe56403-8038-4659-9f3d-7056ef60e665",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'xefpvoduheauuachednettagehiddeoiouhevodesmziogcpdepfaoinageteouiokvolnaimupqepqmeauuhevtenbattziunighuhawetmiqqedqatuvtbvumvclimzhasszaodihadamseadzfigvsedpvuuhauuheznighuuszupcpnnvoicaueuhitxazuhecpotqisaczhadawpideddeuecuipofpspwesaceouvsztpuhezxesevomilemzupnaleuhenitualepfteodiognettageteyqmiciumzaddsetteduppoeaopuhesiuitamxaztbetuopuupnalemioltbeuxeeonenbestpfaoeuxpslaodaxemmhiddeonettageiokvolnaimawpidtuhausitletqeciammzifiuitxidemzditusibvuedbzpoepfuhebpuoeuxpsltmileuhitpoeixatuppfpcvttedpouhedecszquaufistuaodxatouseadiogxhauiutaidvouimifpvodhesoanetuasiogbaclauneauuheeodqeshaqtxethpvmdhaweamseadzseamiteduhauusioiuzcpvmdbeiowpmwedbvuiuoewespccvssedupneuhauhesoanexataozuhiogpuhesuhaoacpiocideoceuhefacuthetchasmietoiecethpvmdhawemiuvquhemighutpouhedathbpasduhpvghaodianxpssieduhauhasszdidousaiteiuqeshaqtheitamseadzthadpxioghesaoddidoumileuptaztppvupfmpzamuzbvuhedidouuemmneuhauaodtpnehpxiuhiolhexpvmdiuhioliutnpsemilemzuhauthetbezpodtvtqicipoiohitniodthehatqmazedaoinqpsuaouspmeiohitoeuxpslfpsfpvsueeozeastaoduhefacuuhauthenighubeadpvbmeageouximmbeaseambmpxuhauxatbadbvuiuxatouuhexpstupfiuuhedeuaimusioiuzgiwetpouhecpotqisacztseceouacuiwiuietitusvmzfsighueoiogxhaucpvmduhezxaouauuheheasupfuheqaodenicsetqpotegspvqttvsemzuhezcaouhawebeeosetqpotibmefpsuhepvubsealaodxhauxeseuhezdpiogaucpqidetqesauemzxaouupualeuhituphasszupuamluphinabpvuiubvuuhefioamqasagsaqhtupqqedneionzusacltxhzpoeasuhdpetusioiuzuhiolinighukpiouhenxhauhaweitaidpsdpoeuhauxpvmdnaleuhenuhiolicpvmdbeausaiupsaodximmuhaunalehasszditusvtuneuppinoputvseicaoualeuhausitlinighuhaweupfioithuhitnittipoampoe'"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "xca = polybius_decipher(sca, keyword='a', column_order=col_a, row_order=row_a,\n",
+ " column_first=col_first_a, wrap_alphabet=wrap_a)\n",
+ "xca"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "81c5bc01-b60b-4d26-9f19-231854f4f6de",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'abcdefghiklmnopqrstuvwxyzj'"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "word_a, _ = monoalphabetic_sa_break(xca)\n",
+ "word_a"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "id": "7aa6dff2-f12c-4212-83df-3a9bb7b76334",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'wefoundtheattachedmessagehiddenintheunderlyingcodeofanimagesentinjunkmailtopeopleattheusembassyitmighthaveslippedpastusbutluckilyharryandihadalreadyfiguredoutthattheymighttrytocommunicatethiswaytheconspiracyhadavoideddetectionforoveracenturysotheywereunlikelytomakethemistakeofsendingmessagesexplicitlyaddressedtooneanotheritisalwaysbestnottomakelinksbetweenmembersofanetworkandawellhiddenmessageinjunkmailavoidsthatriskespeciallyifitiswidelydistributedbyoneofthebotnetworkslikethisoneiwastoofocussedonthedecryptatfirstandwasntreadingwhatitsaiduntilifoundhernamestaringbackatmeattheendperhapsweshouldhavealreadyrealisedthattrinitycouldbeinvolvedbutitneveroccurredtomethathernamewasanythingotherthanacoincidencethefactshescharliesnieceshouldhavelitupthelightsonthedashboardthoughandiamworriedthatharrydidntraiseitperhapsheisalreadyshadowingheranddidntliketosaysooutofloyaltybuthedidnttellmethatandsomehowithinkhewouldithinkitsmorelikelythatshesbeyondsuspicioninhismindshehasplayedanimportantroleinhisnetworkforfourteenyearsandthefactthatshemightbeadoubleagentwillbearealblowthatwasbadbutitwasnttheworstofitthedetailtrinitygivesontheconspiracysrecentactivitiesistrulyfrighteningwhatcouldtheywantattheheartofthepandemicresponsegroupssurelytheycanthavebeenresponsiblefortheoutbreakandwhatweretheydoingatcopidesperatelywanttotakethistoharrytotalktohimaboutitbutthefinalparagraphstoppedmeinmytrackswhyonearthdoestrinitythinkimightjointhemwhathaveisaidordonethatwouldmakethemthinkicouldbeatraitorandwillthatmakeharrydistrustmetooimnotsureicantakethatriskimighthavetofinishthismissionalone'"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "pa = keyword_decipher(xca, word_a)\n",
+ "pa"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "c7f2e770-8062-4d18-b90a-cb2e410ef88c",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "we found the attached message hidden in the underlying code of an image sent in junkmail to people\n",
+ "at the us embassy it might have slipped past us but luckily harry and i had already figured out that\n",
+ "they might try to communicate this way the conspiracy had avoided detection for over a century so\n",
+ "they were unlikely to make the mistake of sending messages explicitly addressed to one another it is\n",
+ "always best not to make links between members of a network and a well hidden message in junkmail\n",
+ "avoids that risk especially if it is widely distributed by one of the bot networks like this one i\n",
+ "was too focussed on the decrypt at first and wasnt reading what it said until i found her name\n",
+ "staring back at meat the end perhaps we should have already realised that trinity could be involved\n",
+ "but it never occurred to me that her name was anything other than a coincidence the fact shes\n",
+ "charlies niece should have lit up the lights on the dashboard though and i am worried that harry\n",
+ "didnt raise it perhaps he is already shadowing her and didnt like to say so out of loyalty but he\n",
+ "didnt tell me that and somehow i think he would i think its more likely that shes beyond suspicion\n",
+ "in his mind she has played an important role in his network for fourteen years and the fact that she\n",
+ "might be a double agent will be a real blow that was bad but it wasnt the worst of it the detail\n",
+ "trinity gives on the conspiracy s recent activities is truly frightening what could they want at the\n",
+ "heart of the pandemic response groups surely they cant have been responsible for the outbreak and\n",
+ "what were they doing at copi desperately want to take this to harry to talk to him about it but the\n",
+ "final paragraph stopped me in my tracks why on earth does trinity think i might join them what have\n",
+ "i said or done that would make them think i could be a traitor and will that make harry distrust me\n",
+ "too im not sure i can take that risk i might have to finish this mission alone\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(prettify(pa))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "6cecddd9",
+ "metadata": {
+ "Collapsed": "false"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1953"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "open(plaintext_a_filename, 'w').write(prettify(pa))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "id": "07c92adb-74e2-476e-adff-887c0145617d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'10101 11000'"
+ ]
+ },
+ "execution_count": 33,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cb[:11]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "id": "832dc153-c9e3-4134-9425-8014847c3870",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "21"
+ ]
+ },
+ "execution_count": 34,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "int('10101', 2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "id": "d7002750-66fd-4435-8ee8-023ae8376f33",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "9865"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "scb = cat(c for c in cb if c in '01')\n",
+ "len(scb)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "id": "f3c2587e-7b76-49fb-ba60-ed3efc148c85",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(0, 25)"
+ ]
+ },
+ "execution_count": 39,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ncb = [int(g, 2) for g in cb.split()]\n",
+ "min(ncb), max(ncb)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "id": "bf189676-3c25-420d-9330-b77cc57c7a82",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'vyietbcbuwabmfbeslwnqafcylayovkbuxrhcwalhlpvknvmpbjszmxrbeonvwwhlznzkgortuilzxvvawmgvvlogumljprqzfmvvvvzqnjxvkbmgyiezrqmvizqlyvkqimewbedramgzrbvvzmniweotlbjigqhlteljmayovbblhcovzlbaggxerktlmfxhbmfxdwsnmfxjkrvmsgwwebnltkmygbkpfzxqgepzbudxprtwaamptzvrlkclfcekxqwvacqmctctbckntelrubaiimcikymzwaabraraomxlarzqehpdfdrzmfxcifbxgzybrmgkhebuatqiciavxbpvcfmwravkeqlglkwruucwdwemhnxiigqoclrbgpxfxrzgwyehmmevfcgklrkbqbfvzidggxcalxpmympwockfnfizctelgpxmmymevxuvfuzqmrxvajmgmpyiimtlxkebzdmyjkvmgrbjbfigbxeovvxckjqaeagmvpnteubkpgpxbbimpbxykfnfmgghikvdbjlvziigrlrvqxhjbkqpqtllkprgtjlfprticwlagwblyztgztrxtwcobtbeohawgkvkgivaxjagwtlndjrzhdhkprzzmovzauxlmjbuimftuzrutggvlomrmguwhzkcttpjpbjxnmjmkcgfbnjecmfnhtewwvtvdxphewhzijteaswkrarbrdxlmkprkhlgvkgqhllnmziwcpzbuahkxfngpxuhitqaeykxmfbvmfgiaqxqtelfutjevagamymvajqejllzrtrntpwsnblmymzmwgndbrzfmgkprlhugjqqmbftmmabaywkprktnttqggblxvlgwpmkbwabacufafqgtxjbvotrbfvvvmmhlzbzzygzanbbmgkpnbbquvqaoksgwzbumfxrzpptchcwtgwgozavwgfximnbzaahquiwfhgmqbaymrafqzlfvvguxygkbuimravknaxutjzrotpwvlnaempgzvwkgmpjhbaykignalgzemqpbquvagizcgkrblbcmfzhvbrteltiocavzntfmlkcatbkbkmqzxqhlzpmlqavpnamctdanteyviwfamfxlsgztuezvtbaphloubacirxrzluxcmsbucazvqimravtvoarafcfmtlwkzlqgemfebzdmnkeuimravgzmtlbrufwtlzignbfwlvtsnhpmyigjnrbyiimickjwaiejrtprkdcwrvqiejmymzicmkzbruldkfugpxdhlvqimgheiekagoverzxqazxcmwmnkbbutqlfceqxygupndxzxvvfmvskvlnbmfxgiesbyljqtvxbtkmnummfrsranpxkpnbmfxbmllhandmabluximczhnxitlmgakpxgmwggtifmcmwzmfbxyfwqallravuocmebmmabacmrtrvmqavqfehpdzvtebrazvbemfbesjmfgzybamxbmfbnsxdnibumkqmvxfigbbgtnvmmozavbmfxyynalmheifqvygxmgipyrnprbackfzawmhhuqrigbavzgmtkpfzxwnrpyigexykvlbqgemymomlrprggwfydvahzxrarbuikpruwragmmwqalhsmdqtpmzxkwpwgtbekrpxpgfbgwmcecpvubftmmomxlvrzegblzfcgahkxsipszphlvqkacvbanvwgtdebvwckzvtqyuxjpbcebclagbkwmfzrkksbkprzwgkvkgtrgyjpretqpfzxqgepzbuclravvvulskvaumpmnclfmxravvrmwdhiarkkcvpbumwgkvkgiinkfippbqkzaxgusmkprwketeqfimghepnagcovzfpbcwrengyphdbuimzxwwemhprfcnvwgpfcylgruvebzdggxnbzbrbkpvvdgmzanzbqdnwebartbqaormnitbdblzeqrkxrkzvvbr'"
+ ]
+ },
+ "execution_count": 40,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "tcb = cat(unpos(n) for n in ncb)\n",
+ "tcb"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "id": "59f072b0-f8ca-4f08-922d-cfb5dfc68fe4",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'beuxmwnprjiztavlsfgkqdyhco'"
+ ]
+ },
+ "execution_count": 41,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "word_b, score_b = monoalphabetic_sa_break(tcb)\n",
+ "word_b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "id": "16210c33-3bcb-43c8-9189-d82eea7cf53b",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "trinity \n",
+ "\n",
+ "charlieidontthinkyoushouldhavecometolondonwecantriskmeetingandyourarrivalhasbeennoticedbybossheighteningsuspicionharrysteamisactivelyinvestigatingourorganisationandwehavetodoeverythingwecantoputthemoffthescentunfortunatelyimworkingwithveryconstrainedresourcesdespiteallourpandemicpreparationsithasbeenhardworkoverthelasteighteenmonthsasplannedweusedthecrisistoembedmoreoperativesattheheartofgovernmentdecisionmakingunderthecoverofsageandtheothernewcommitteeswenowhaveanetworkofscientistsandengineersinwhitehallwiththedirectearofseniorcivilservantsandpoliticianstheyalsohelpedustoinfiltratecopgivingusdirectaccesstoanumberofothergovernmentsthathadremainedbeyondourreachwhilewewerenotabletofullydeliveronourplansforthateventtheconnectionswemadewithsomeoftheworldslargestcompaniesandsmalleststateswillsurelypayoffinthemediumtermonthedownsideihaventhadthecapacityineedtoworkonthebossinvestigationintoourorganisationthatisbeingrunfromthearchaeologydivisionhereatgchqihadhopedthatassignmentmeantthatthecasewasregardedaslowprioritybutharryassignedhisbestagentjodietorunitandgaveheralmostunlimitedresourcesshehasteamsallacrosstheuktrawlingthroughthepapersweleftbehindatthelighthouseandtryingtoworkoutwhattheymeaniamsoangryatmyselfforthatbutihavepersonallycheckedandallthemajoritemsfromthefoundationarchivewereshippedouttomassourieandhavebeensecuredattheparkiassignedateamtomakesurethatthekeydocumentswereproperlyencryptedincasejodiesteamfindsthembutgiventhetalentsheisworkingwithinowthinkwemightneedtotakefurtherstepsandiplantovisitthehqassoonasicangetawaywhetherornotjodieandherteamworkoutwhatwearedoingthebestwaytomakesurethatharrydoesnotfindoutmightbetoconvincehernottotellhimihavebeencarryingoutsomebackgroundchecksandiamwonderingifweshouldjusttrytorecruitherdirectlyifshewasworkingwithusthenimsureshewouldseetheneedforsecrecythedirectapproachisriskybuttheorganisationhasnevershiedawayfromthatbeforeoryouandiwouldntbeworkingforitithinkitisariskworthtakingyourlovingniecetrinity\n"
+ ]
+ }
+ ],
+ "source": [
+ "word_b, score_b = vigenere_frequency_break(tcb, fitness=Ptrigrams)\n",
+ "print(word_b, '\\n')\n",
+ "pb = vigenere_decipher(tcb, word_b)\n",
+ "print(pb)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "id": "fe094361-7c85-40d9-952e-0c84abbcf903",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "charlie i dont think you should have come to london we cant risk meeting and your arrival has been\n",
+ "noticed by boss heightening suspicion harry steam is actively investigating our organisation and we\n",
+ "have to do everything we can to put them off the scent unfortunately im working with very\n",
+ "constrained resources despite all our pandemic preparations it has been hard work over the last\n",
+ "eighteen months as planned we used the crisis to embed more operatives at the heart of government\n",
+ "decisionmaking under the cover of sage and the other new committees we now have a network of\n",
+ "scientists and engineers in whitehall with the direct ear of senior civil servants and politicians\n",
+ "they also helped us to infiltrate cop giving us direct access to a number of other governments that\n",
+ "had remained beyond our reach while we were notable to fully deliver on our plans for that event the\n",
+ "connections we made with some of the worlds largest companies and smallest states will surely payoff\n",
+ "in the medium term on the downside i havent had the capacity i need to work on the boss\n",
+ "investigation into our organisation that is being run from the archaeology division here at gchq i\n",
+ "had hoped that assignment meant that the case was regarded as low priority but harry assigned his\n",
+ "best agent jodie to run it and gave her almost unlimited resources she has teams all across the uk\n",
+ "trawling through the papers we left behind at the lighthouse and trying to workout what they mean i\n",
+ "am so angry at myself for that but i have personally checked and all the major items from the\n",
+ "foundation archive were shipped out to mass our ie and have been secured at the park i assigned a\n",
+ "team to make sure that the key documents were properly encrypted in case jodie steam finds them but\n",
+ "given the talent she is working with i now think we might need to take further steps and i plan to\n",
+ "visit the hq as soon as i can getaway whether or not jodie and her teamwork out what we are doing\n",
+ "the best way to make sure that harry does not find out might be to convince her not to tell him i\n",
+ "have been carrying out some background checks and i am wondering if we should just try to recruit\n",
+ "her directly if she was working with us then im sure she would see the need for secrecy the direct\n",
+ "approach is risky but the organisation has never shied away from that before or you and i wouldnt be\n",
+ "working for it i think it is a risk worth taking your loving niece trinity\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(prettify(pb))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "id": "d12a663c",
+ "metadata": {
+ "Collapsed": "false"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2420"
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "open(plaintext_b_filename, 'w').write(prettify(pb))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "504ec2e2",
+ "metadata": {
+ "Collapsed": "false"
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "jupytext": {
+ "formats": "ipynb,md"
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "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.8.8"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
--- /dev/null
+---
+jupyter:
+ jupytext:
+ formats: ipynb,md
+ text_representation:
+ extension: .md
+ format_name: markdown
+ format_version: '1.3'
+ jupytext_version: 1.11.1
+ kernelspec:
+ display_name: Python 3 (ipykernel)
+ language: python
+ name: python3
+---
+
+```python Collapsed="false"
+from szyfrow.caesar import *
+from szyfrow.affine import *
+from szyfrow.keyword_cipher import *
+from szyfrow.column_transposition import *
+from szyfrow.vigenere import *
+from szyfrow.polybius import *
+from szyfrow.support.text_prettify import *
+
+import numpy as np
+import pandas as pd
+import matplotlib.pyplot as plt
+
+import collections
+%matplotlib inline
+```
+
+```python Collapsed="false"
+challenge_number = 7
+plaintext_a_filename = f'plaintext.{challenge_number}a.txt'
+plaintext_b_filename = f'plaintext.{challenge_number}b.txt'
+ciphertext_a_filename = f'ciphertext.{challenge_number}a.txt'
+ciphertext_b_filename = f'ciphertext.{challenge_number}b.txt'
+```
+
+```python Collapsed="false"
+nca = open(ciphertext_a_filename).read()
+cb = open(ciphertext_b_filename).read()
+
+numtrans = ''.maketrans('12345', 'abcde')
+ca = nca.translate(numtrans)
+
+sca = sanitise(ca)
+rsca = cat(reversed(sca))
+scb = sanitise(cb)
+rscb = cat(reversed(scb))
+```
+
+```python
+sca_counts = collections.Counter(sca)
+sca_counts
+```
+
+```python
+pd.Series(sca_counts).sort_index().plot.bar()
+```
+
+```python
+key_a, score_a = polybius_break(sca, column_labels='abcde', row_labels='abcde',
+ fitness=Ptrigrams)
+key_a, score_a
+```
+
+```python
+word_a, wrap_a, col_a, row_a, col_first_a = key_a
+polybius_decipher(sca, keyword=word_a, column_order=col_a, row_order=row_a,
+ column_first=col_first_a, wrap_alphabet=wrap_a)
+```
+
+```python
+xca = polybius_decipher(sca, keyword='a', column_order=col_a, row_order=row_a,
+ column_first=col_first_a, wrap_alphabet=wrap_a)
+xca
+```
+
+```python
+word_a, _ = monoalphabetic_sa_break(xca)
+word_a
+```
+
+```python
+pa = keyword_decipher(xca, word_a)
+pa
+```
+
+```python
+print(prettify(pa))
+```
+
+```python Collapsed="false"
+open(plaintext_a_filename, 'w').write(prettify(pa))
+```
+
+```python
+cb[:11]
+```
+
+```python
+int('10101', 2)
+```
+
+```python
+scb = cat(c for c in cb if c in '01')
+len(scb)
+```
+
+```python
+ncb = [int(g, 2) for g in cb.split()]
+min(ncb), max(ncb)
+```
+
+```python
+tcb = cat(unpos(n) for n in ncb)
+tcb
+```
+
+```python
+word_b, score_b = monoalphabetic_sa_break(tcb)
+word_b
+```
+
+```python
+word_b, score_b = vigenere_frequency_break(tcb, fitness=Ptrigrams)
+print(word_b, '\n')
+pb = vigenere_decipher(tcb, word_b)
+print(pb)
+```
+
+```python
+print(prettify(pb))
+```
+
+```python Collapsed="false"
+open(plaintext_b_filename, 'w').write(prettify(pb))
+```
+
+```python Collapsed="false"
+
+```