Done challenge 8
[cipher-tools.git] / 2020-early / 2020-a-challenge8.ipynb
diff --git a/2020-early/2020-a-challenge8.ipynb b/2020-early/2020-a-challenge8.ipynb
new file mode 100644 (file)
index 0000000..9789c1e
--- /dev/null
@@ -0,0 +1,405 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "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) "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from cipher.caesar import *\n",
+    "from cipher.affine import *\n",
+    "from cipher.keyword_cipher import *\n",
+    "from cipher.column_transposition import *\n",
+    "from cipher.vigenere import *\n",
+    "\n",
+    "from support.text_prettify import *\n",
+    "from support.utilities import *\n",
+    "from support.plot_frequency_histogram import *\n",
+    "%matplotlib inline"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "challenge_number = 8\n",
+    "plaintext_a_filename = f'{challenge_number}a.plaintext'\n",
+    "plaintext_b_filename = f'{challenge_number}b.plaintext'\n",
+    "ciphertext_a_filename = f'{challenge_number}a.ciphertext'\n",
+    "ciphertext_b_filename = f'{challenge_number}b.ciphertext'"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ca = open(ciphertext_a_filename).read()\n",
+    "cb = open(ciphertext_b_filename).read()\n",
+    "\n",
+    "sca = sanitise(ca)\n",
+    "pca = letters(ca)\n",
+    "pta = depunctuate(ca)\n",
+    "\n",
+    "scb = sanitise(cb)\n",
+    "pcb = letters(cb)\n",
+    "ptb = depunctuate(cb)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "/home/neil/Programming/cipher-tools/support/plot_frequency_histogram.py:11: UserWarning: Matplotlib is currently using module://ipykernel.pylab.backend_inline, which is a non-GUI backend, so cannot show the figure.\n",
+      "  f.show()\n"
+     ]
+    },
+    {
+     "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": [
+    "fc = collections.Counter(sca)\n",
+    "plot_frequency_histogram(fc, sort_key=fc.get)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'low'"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "kworda, score = vigenere_frequency_break(sca, fitness=Ptrigrams)\n",
+    "kworda"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'harrywemanagedtotapthephonelinesinosloandinterceptedgermanmilitarypolicereportstothessheadquarterstheyestablishedthatthegunnersideoperationwaseffectiveinwipingouttheexistingstocksofheavywaterbutthatthenaziengineerswereabletorestartproductionthiswasconfirmedincommunicationssmuggledoutoftheplantbyjomarbrunandeinnarskinnerlandthechiefengineeranddesigneroftheplantwhoarestillworkingthereassoeagentstheinformationwassenttointelligenceheadquartersinlondonintoothpastetubesusingacipherdevelopedforbossbyleomarksthisintelligencewaspassedtousaafwhostartedtodevelopaplantobombtheplantrunningtheriskofsignificantcivilianlossesluckilyoneofourbossofficialsspottedthemaponthewallofabriefingroomduringaprotocolvisitandrealisedwhatitwasheflaggedtheoperationandgotmeinvolvediwasabletocontactswallowviatheoslobranchofmilorgandwehavebeenworkingtogetherwithusaaftorefinethemissiondespitetheriskstheyagreedtoadaylightraidinthehopethattheaddedaccuracywouldreducenorwegiancasualtiesunfortunatelytheraidwasamixedsuccessasyoucanseefromtheattachedreportitisdoubleencryptedagainbutwasalottoughertocracktheyhaveusedanaffineshiftforthesubstitutionphasebeforeusingthesamesortoftranspositiontakealookandletmeknowwhatyouthinkmeanwhileiwilltrytocontactronnenbergtoseewhathewantstodonextgiventheneedtoprotectournetworkiwillincreasethekeylengthformymessagetoyounextweektoatleastsix'"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pa = vigenere_decipher(sca, kworda)\n",
+    "pa"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "harry we managed to tap the phone lines in oslo and intercepted german military police reports to\n",
+      "the ss headquarters they established that the gunner side operation was effective in wiping out the\n",
+      "existing stocks of heavy water but that the nazi engineers were able to restart production this was\n",
+      "confirmed in communications smuggled out of the plant by jomar brun and e in nar skinner land the\n",
+      "chief engineer and designer of the plant who are still working there as soe agents the information\n",
+      "was sent to intelligence headquarters in london in toothpaste tubes using a cipher developed for\n",
+      "boss by leo marks this intelligence was passed to usaaf who started to develop a plan to bomb the\n",
+      "plant running the risk of significant civilian losses luckily one of our boss officials spotted the\n",
+      "map on the wall of a briefing room during a protocol visit and realised what it was he flagged the\n",
+      "operation and got me involved i was able to contact swallow via the oslo branch of mil org and we\n",
+      "have been working together with usaaf to refine the mission despite the risks they agreed to a\n",
+      "daylight raid in the hope that the added accuracy would reduce norwegian casualties unfortunately\n",
+      "the raid was a mixed success as you can see from the attached report it is double encrypted again\n",
+      "but was alot tougher to crack they have used an affine shift for the substitution phase before using\n",
+      "the same sort of transposition take a look and let me know what you think meanwhile i will try to\n",
+      "contact ronn enberg to see what he wants to do next given the need to protect our network i will\n",
+      "increase the key length for my message to you next week to atleast six\n"
+     ]
+    }
+   ],
+   "source": [
+    "fpa = lcat(tpack(segment(pa)))\n",
+    "print(fpa)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1644"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "open(plaintext_a_filename, 'w').write(fpa)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "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": [
+    "fc = collections.Counter(scb)\n",
+    "plot_frequency_histogram(fc, sort_key=fc.get)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(11, 5, True)"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "(kmb, kab, kob), score = affine_break(scb, fitness=Pletters)\n",
+    "kmb, kab, kob"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'etmhbnboiagoriendvrmaokaswciroredudtiudrnlagyhingtvnoobesmetirxnetetahheatstcaqkuodornincsisotnhfgttinreapelsnlesiiptonottogwrsucpeahamnkwiguotronhsnaetterwgtchsiphaapdreebthoeoetnkrdshpryoeotwriastaotnnnhderietaaptltnethiermsltetehoetaesttahtkascwtnaorfeoenesnwoirantsirtpecdteeabcyieorvnrladflaoetthakatcgirnaacirsfmtehteoeatvrnuerfemdretohsmoisynieieewtesnstsesaatthntrittmeintletdocuvcaoeeprpeaordsdtiprhuttetactuakhtbtaermjyiottoefhlxepiossvoaerduintyrhtnteosdrweprdoptweiehhvrhiygcaacuocryhniteatnrptnelntaotltywhooternetisohhtoterwpeasottnniahdetefirncosreutdrucwtrhietosttowhdesofrtetohsalsahtutoesbmifbadldetaaomtgrehueebtiuldrteemieuercltyoslscfiaiialtonydnusrectwookesfyahvtwwaeeerropcrtdteetbsyheeevtnesooyrseffriconrcecdotrnebeeaowhvoeehvroetprwaepinltethslbafsnemedeaagndhadsitsoercndaditopnhnleaaterihsstoeipslbsiyiattuthonrieehemseaevasngtrwnokigiwitthndiincissunisotwfihcfoilirasdofmaiheliecmesrtnpoguhibtanesecdeeihddttafthiaectlhiylosuedubsothdewsnxntiitgksofscoahweveaytnroadstpausyimodhrdxiieblwlhepsitepdhortebliaaorrtsioedannmauafucntragiflciiiietsenagrfnmyfotrurhrerehninmcentxadrpeeeiamnottiinngvetehsrfikclooeailsaopnwgieenlwldesetniogiinfcytalhecnaeensrcyuirftoitphsaeorotiinlnfawlhyelosuodtnttheaetthakatclkdiletewynetornnogwneivcaiiislaitnhsslivbuaaplperaaoganddaronueasgneatridtonihgeerhbseetrdalnidonntonnorseuhettanhtewoirepagnuotplniaodusnentrawdishosotabflmtoersheeelendseasdsteh'"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "acb = affine_decipher(scb, kmb, kab, kob)\n",
+    "acb"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(((2, 0, 5, 1, 3, 8, 6, 4, 7), False, False), -4688.2791775857195)"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "(kwordb, fillb, emptyb), score = column_transposition_break_mp(acb, fitness=Ptrigrams)\n",
+    "(kwordb, fillb, emptyb), score"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'thebombingraidonvemorkwascarriedoutduringdaylightonnovembersixteenththeattacksquadronconsistingofthirteenplanessplitintotwogroupseachmakingtworunsonthetargetswhichappearedtobethenorskhydropowerstationandthenitrateplantthreemilestotheeasttheattackwasnotforeseennorwasitinterceptedbyaircoverandalloftheattackingaircraftseemtohavereturnedfromthemissioneyewitnessesstatethatintermittentcloudcoverappearedtodisrupttheattackbutthemajorityoftheexplosivesaroundthirtytonsweredroppedwithveryhighaccuracyonthenitrateplantonlytwotothreetonshitthepowerstationandthereinforcedstructurewithstoodtheworstoftheassaultthebombsfailedtodamagetherebuiltdeuteriumelectrolysisfacilityandournewstocksofheavywaterwereprotectedbythesevenstoreysofreinforcedconcreteabovehoweverthepowerplantitselfhasbeendamagedandthissecondraidontheplantraisesthepossibilitythatourenemieshaveagentsworkingwithinitindiscussionwithofficialsfromdiealchemistengroupithasbeendecidedthatthefacilityshouldbeshutdownexistingstocksofheavywaterandpotassiumhydroxidewillbeshippedtotheirlaboratoriesandmanufacturingfacilitiesingermanyforfurtherenrichmentandexperimentationgiventheriskoflocalespionagewewillneedtosignificantlyenhancesecurityforthisoperationfinallyweshouldnotethattheattackkilledtwentyonenorwegianciviliansthisisvaluablepropagandaandouragentsaredoingtheirbesthereandinlondontoensurethatthenorwegianpopulationunderstandswhoistoblamefortheseneedlessdeaths'"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "pb = column_transposition_decipher(acb, kwordb, fillcolumnwise=fillb, emptycolumnwise=emptyb)\n",
+    "pb"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "the bombing raid on ve mork was carried out during daylight on november sixteenth the attack\n",
+      "squadron consisting of thirteen planes split into two groups each making two runs on the targets\n",
+      "which appeared to be the norsk hydropower station and the nitrate plant three miles to the east the\n",
+      "attack was not foreseen nor was it intercepted by air cover and all of the attacking aircraft seem\n",
+      "to have returned from the mission eyewitnesses state that intermittent cloud cover appeared to\n",
+      "disrupt the attack but the majority of the explosives around thirty tons were dropped with very high\n",
+      "accuracy on the nitrate plant only two to three tons hit the powerstation and the reinforced\n",
+      "structure withstood the worst of the assault the bombs failed to damage the rebuilt deuterium\n",
+      "electrolysis facility and our new stocks of heavy water were protected by the seven storeys of\n",
+      "reinforced concrete above however the powerplant itself has been damaged and this second raid on the\n",
+      "plant raises the possibility that our enemies have agents working within it in discussion with\n",
+      "officials from die alchemist en group it has been decided that the facility should be shutdown\n",
+      "existing stocks of heavy water and potassium hydroxide will be shipped to their laboratories and\n",
+      "manufacturing facilities in germany for further enrichment and experimentation given the risk of\n",
+      "local espionage we will need to significantly enhance security for this operation finally we should\n",
+      "note that the attack killed twentyone norwegian civilians this is valuable propaganda and our agents\n",
+      "are doing their best here and in london to ensure that the norwegian population understands who is\n",
+      "to blame for these needless deaths\n"
+     ]
+    }
+   ],
+   "source": [
+    "fpb = lcat(tpack(segment(pb)))\n",
+    "print(fpb)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1686"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "open(plaintext_b_filename, 'w').write(fpb)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['clampdown']"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "transpositions[kwordb]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "jupytext": {
+   "formats": "ipynb,md"
+  },
+  "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.7.4"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}