Done challenges 1 and 2
authorNeil Smith <neil.git@njae.me.uk>
Wed, 15 Apr 2020 11:21:08 +0000 (12:21 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Wed, 15 Apr 2020 11:21:08 +0000 (12:21 +0100)
2019/2019-challenge9b.ipynb
2020-early/1a.ciphertext [new file with mode: 0644]
2020-early/1a.plaintext [new file with mode: 0644]
2020-early/1b.ciphertext [new file with mode: 0644]
2020-early/1b.plaintext [new file with mode: 0644]
2020-early/2020-a-challenge1.ipynb [new file with mode: 0644]
2020-early/2020-a-challenge2.ipynb [new file with mode: 0644]
2020-early/2a.ciphertext [new file with mode: 0644]
2020-early/2a.plaintext [new file with mode: 0644]
2020-early/2b.ciphertext [new file with mode: 0644]
2020-early/2b.plaintext [new file with mode: 0644]

index 10a38943f0cd7c428f7a7c11aeeac0325c49e95e..77d4004a306dfbc96f8c446754261e5ba129816d 100644 (file)
@@ -45,7 +45,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [],
    "source": [
     "open(plaintext_b_filename, 'w').write(lcat(tpack(segment(pb))))"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def ioc_n(text):\n",
+    "    counts = collections.Counter(text)\n",
+    "    ltrs = set(text)\n",
+    "    denom = len(text) * (len(text) - 1) / len(ltrs)\n",
+    "    return (\n",
+    "        sum(max(counts[l] * counts[l] - 1, 0) for l in ltrs)\n",
+    "        /\n",
+    "        denom\n",
+    "    )"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def ioc_scan_n(text, max_key_length=20):\n",
+    "    \"\"\"Finds the index of coincidence of the text, using different chunk sizes.\"\"\"\n",
+    "    iocs = {}\n",
+    "    for i in range(1, max_key_length + 1):\n",
+    "        splits = every_nth(text, i)\n",
+    "        mean_ioc = sum(ioc_n(s) for s in splits) / i\n",
+    "        iocs[i] = mean_ioc\n",
+    "    return iocs"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1.313469334794217"
+      ]
+     },
+     "execution_count": 25,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ioc_n(scb)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[(28, 1.029237612412878),\n",
+       " (56, 1.0323741101856603),\n",
+       " (14, 1.0886873582571082),\n",
+       " (42, 1.0923459702787721),\n",
+       " (1, 1.313469334794217),\n",
+       " (3, 1.3136724474583705),\n",
+       " (5, 1.3139446514243536),\n",
+       " (7, 1.3141262063060093),\n",
+       " (2, 1.3142346883552642),\n",
+       " (9, 1.3145299178890573),\n",
+       " (6, 1.3146522525866469),\n",
+       " (11, 1.314872121624653),\n",
+       " (10, 1.3153476328760576),\n",
+       " (17, 1.3156082632437882),\n",
+       " (19, 1.3157537470690668),\n",
+       " (15, 1.3158533079430723),\n",
+       " (18, 1.316306072127611),\n",
+       " (4, 1.3163246528314725),\n",
+       " (23, 1.3163277281569055),\n",
+       " (21, 1.3163473471920573),\n",
+       " (25, 1.316655118103681),\n",
+       " (8, 1.317040603398334),\n",
+       " (13, 1.3171605413165643),\n",
+       " (12, 1.3174113735517243),\n",
+       " (22, 1.317528984722072),\n",
+       " (33, 1.317594905094905),\n",
+       " (31, 1.317605231763728),\n",
+       " (27, 1.317688521561938),\n",
+       " (29, 1.3179986584465913),\n",
+       " (16, 1.3180422696887168),\n",
+       " (35, 1.318663902511151),\n",
+       " (38, 1.3186715456762172),\n",
+       " (37, 1.318782979178807),\n",
+       " (30, 1.3189277795375356),\n",
+       " (20, 1.319112577563282),\n",
+       " (41, 1.319293715271584),\n",
+       " (24, 1.319320503943391),\n",
+       " (34, 1.319372128500673),\n",
+       " (26, 1.3195881414435318),\n",
+       " (45, 1.319847955451339),\n",
+       " (51, 1.3198862305977204),\n",
+       " (43, 1.3202263262432186),\n",
+       " (32, 1.3204297829974077),\n",
+       " (46, 1.32083091670564),\n",
+       " (47, 1.320835215197834),\n",
+       " (49, 1.3208992566951445),\n",
+       " (36, 1.320917879222574),\n",
+       " (39, 1.3212746271240052),\n",
+       " (57, 1.3216014658027582),\n",
+       " (55, 1.3216742585772436),\n",
+       " (50, 1.321775386202746),\n",
+       " (40, 1.3220152407245682),\n",
+       " (48, 1.322371313582251),\n",
+       " (54, 1.3229352276740334),\n",
+       " (59, 1.322950472958544),\n",
+       " (44, 1.3231503579952266),\n",
+       " (53, 1.3232741220713358),\n",
+       " (58, 1.3236374480105653),\n",
+       " (52, 1.3262568828142518),\n",
+       " (60, 1.3264573374508233)]"
+      ]
+     },
+     "execution_count": 30,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sorted(ioc_scan_n(scb, max_key_length=60).items(), key=lambda kv: kv[1])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "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": [
+    "ic = ioc_scan_n(scb, max_key_length=60)\n",
+    "plot_frequency_histogram(ic, sort_key=ic.get)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/2020-early/1a.ciphertext b/2020-early/1a.ciphertext
new file mode 100644 (file)
index 0000000..7bfa789
--- /dev/null
@@ -0,0 +1,8 @@
+CVMMT,
+D VH MZVGGT NJMMT OJ WJOCZM TJP, WPO NJHZOCDIB CVN XJHZ PK VIY OCZ NDN VMZ OJJ WPNT OJ CZGK. D VH CJKDIB TJP XVI.
+AJGGJRDIB OCZ DIQVNDJI JA KJGVIY, RZ VMZ VGG JI YJPWGZ YPOT, OMVRGDIB OCMJPBC JGY ADGZN AJM VITOCDIB OCVO HDBCO WZ PNZAPG OJ JPM AMDZIYN DI ZPMJKZ. HT OZVH CVN WZZI VNFZY OJ GJJF VO DIOZGGDBZIXZ ADGZN XJIIZXOZY RDOC VDM OMVINKJMO VIY D RVN BDQZI OCZ CDIYZIWPMB YDNVNOZM OJ XCZXF JPO.
+OCZMZ DNI’O HPXC OJ BJ JI VN HJNO JA OCZ KVKZMN MZXJQZMZY AMJH OCZ RMZXFVBZ RZMZ WVYGT YVHVBZY. RZ YJ CVQZ V GVMBZ IPHWZM JA AMVBHZION JA OMVQZG YJXPHZION RCDXC D CVQZ NZIO OJ OCZ NOVOZ YZKVMOHZIO AJM DY XCZXFN, WPO OCVO RDGG OVFZ V RCDGZ, VIY DI OCZ HZVIODHZ, D CVQZ WZZI ZSVHDIDIB NJHZ JA OCZ HJMZ PIPNPVG DOZHN.
+OCZ HJNO DIOZMZNODIB JIZ DN V XCVMMZY ZIQZGJKZ XVMMTDIB V NRVNODFV VIY HVMFZY YDZ VGXCZHDNOZI. D OCDIF OCVO HDBCO WZ RJMOC DIQZNODBVODIB.
+OCZ XJIOZION RZMZ HDNNDIB, WPO DI OCZ NVHZ ZQDYZIXZ WVB D AJPIY V AMVBHZIO JA OJMI WGPZ KVKZM RDOC V IPHWZM DI OCZ WJOOJH XJMIZM. OCZMZ DN IJ YZNXMDKODJI RDOC DO, WPO D VH BPZNNDIB OCVO OCZT HPNO CVQZ WZZI AJPIY OJBZOCZM. RVOZM CVN YDNNJGQZY VIY JWNXPMZY OCZ IPHWZM NJ D XVI’O MZVY DO VIY D YJI’O MZXJBIDNZ OCZ AJMHVO. JI OCZ JOCZM CVIY, OCZ RVOZM HPNO CVQZ KMJOZXOZY DO AMJH OCZ CZVO JA OCZ AGVHZN VN OCZMZ VMZ IJ WPMI HVMFN VIY D RJIYZMZY DA TJPM S-MVT OZVH HDBCO WZ VWGZ OJ VNNDNO.
+CVQZ TJP NZZI VITOCDIB GDFZ DO WZAJMZ, JM CVQZ TJP CZVMY JA YDZ VGXCZHDNOZI? VITOCDIB TJP CVQZ RJPGY WZ BMZVO. OCVIFN
+KCDG
diff --git a/2020-early/1a.plaintext b/2020-early/1a.plaintext
new file mode 100644 (file)
index 0000000..9a8da83
--- /dev/null
@@ -0,0 +1,8 @@
+HARRY,
+I AM REALLY SORRY TO BOTHER YOU, BUT SOMETHING HAS COME UP AND THE SIS ARE TOO BUSY TO HELP. I AM HOPING YOU CAN.
+FOLLOWING THE INVASION OF POLAND, WE ARE ALL ON DOUBLE DUTY, TRAWLING THROUGH OLD FILES FOR ANYTHING THAT MIGHT BE USEFUL TO OUR FRIENDS IN EUROPE. MY TEAM HAS BEEN ASKED TO LOOK AT INTELLIGENCE FILES CONNECTED WITH AIR TRANSPORT AND I WAS GIVEN THE HINDENBURG DISASTER TO CHECK OUT.
+THERE ISN'T MUCH TO GO ON AS MOST OF THE PAPERS RECOVERED FROM THE WRECKAGE WERE BADLY DAMAGED. WE DO HAVE A LARGE NUMBER OF FRAGMENTS OF TRAVEL DOCUMENTS WHICH I HAVE SENT TO THE STATE DEPARTMENT FOR ID CHECKS, BUT THAT WILL TAKE A WHILE, AND IN THE MEANTIME, I HAVE BEEN EXAMINING SOME OF THE MORE UNUSUAL ITEMS.
+THE MOST INTERESTING ONE IS A CHARRED ENVELOPE CARRYING A SWASTIKA AND MARKED DIE ALCHEMISTEN. I THINK THAT MIGHT BE WORTH INVESTIGATING.
+THE CONTENTS WERE MISSING, BUT IN THE SAME EVIDENCE BAG I FOUND A FRAGMENT OF TORN BLUE PAPER WITH A NUMBER IN THE BOTTOM CORNER. THERE IS NO DESCRIPTION WITH IT, BUT I AM GUESSING THAT THEY MUST HAVE BEEN FOUND TOGETHER. WATER HAS DISSOLVED AND OBSCURED THE NUMBER SO I CAN'T READ IT AND I DON'T RECOGNISE THE FORMAT. ON THE OTHER HAND, THE WATER MUST HAVE PROTECTED IT FROM THE HEAT OF THE FLAMES AS THERE ARE NO BURN MARKS AND I WONDERED IF YOUR X-RAY TEAM MIGHT BE ABLE TO ASSIST.
+HAVE YOU SEEN ANYTHING LIKE IT BEFORE, OR HAVE YOU HEARD OF DIE ALCHEMISTEN? ANYTHING YOU HAVE WOULD BE GREAT. THANKS
+PHIL
diff --git a/2020-early/1b.ciphertext b/2020-early/1b.ciphertext
new file mode 100644 (file)
index 0000000..7e19bde
--- /dev/null
@@ -0,0 +1,4 @@
+XPQT, QB QA OWWL BW PMIZ NZWU GWC. BPQVOA IZM PMKBQK PMZM BWW, JCB QB QA UIQVTG JCZMICKZIKG IA EM BZG BW UISM ACZM ITT BPM JWAA NQMTL IOMVBA PIDM AMKCZM KPIVVMTA WN KWUUCVQKIBQWV IVL ZWCBMA WCB WN BZWCJTM QN BPMG VMML BPMU. QB QA MAAMVBQIT EWZS, JCB Q PIDM JMMV QBKPQVO BW OMB WCB BPMZM EQBP BPMU IVL GWCZ TMBBMZ KIUM IB BPM ZQOPB BQUM.
+Q PIDMV’B PMIZL WN LQM ITKPMUQABMV JMNWZM, JCB QB LWMA ZMUQVL UM WN AWUMBPQVO BPIB Q KIV’B YCQBM XTIKM. Q EQTT OMB JIKS BW GWC QN Q ZMUMUJMZ. BPM VCUJMZ QA ATQOPBTG MIAQMZ. BPQA TWWSA TQSM BPM JWBBWU ZQOPB KWZVMZ WN I JTCMXZQVB IVL Q IAACUM BPM VCUJMZ QA ZMTIBML BW BPM LMAQOV. BPM F-ZIG BMIU BWWS I AVIX EPQKP QVKZMIAML BPM KWVBZIAB IVL Q BPQVS Q KIV UISM WCB BPM TMBBMZA OJ IB BPM ABIZB, EPQKP QA ACOOMABQDM. BPM VMFB BEW LQOQBA IZM VWB KTMIZ, JCB BPMG KWCTL JM MQOPB-BPZMM WZ MQOPB-NQDM. Q PIDM AMVB I ZMYCMAB BW BPM CS UQTQBIZG IBBIKPM BW AMM QN PM ZMKWOVQAMA BPM NWZUIB.
+Q EQTT JM QV BWCKP QV AMDMV LIGA.
+PIZZG
diff --git a/2020-early/1b.plaintext b/2020-early/1b.plaintext
new file mode 100644 (file)
index 0000000..0ac7183
--- /dev/null
@@ -0,0 +1,4 @@
+PHIL, IT IS GOOD TO HEAR FROM YOU. THINGS ARE HECTIC HERE TOO, BUT IT IS MAINLY BUREAUCRACY AS WE TRY TO MAKE SURE ALL THE BOSS FIELD AGENTS HAVE SECURE CHANNELS OF COMMUNICATION AND ROUTES OUT OF TROUBLE IF THEY NEED THEM. IT IS ESSENTIAL WORK, BUT I HAVE BEEN ITCHING TO GET OUT THERE WITH THEM AND YOUR LETTER CAME AT THE RIGHT TIME.
+I HAVEN'T HEARD OF DIE ALCHEMISTEN BEFORE, BUT IT DOES REMIND ME OF SOMETHING THAT I CAN'T QUITE PLACE. I WILL GET BACK TO YOU IF I REMEMBER. THE NUMBER IS SLIGHTLY EASIER. THIS LOOKS LIKE THE BOTTOM RIGHT CORNER OF A BLUEPRINT AND I ASSUME THE NUMBER IS RELATED TO THE DESIGN. THE X-RAY TEAM TOOK A SNAP WHICH INCREASED THE CONTRAST AND I THINK I CAN MAKE OUT THE LETTERS GB AT THE START, WHICH IS SUGGESTIVE. THE NEXT TWO DIGITS ARE NOT CLEAR, BUT THEY COULD BE EIGHT-THREE OR EIGHT-FIVE. I HAVE SENT A REQUEST TO THE UK MILITARY ATTACHE TO SEE IF HE RECOGNISES THE FORMAT.
+I WILL BE IN TOUCH IN SEVEN DAYS.
+HARRY
diff --git a/2020-early/2020-a-challenge1.ipynb b/2020-early/2020-a-challenge1.ipynb
new file mode 100644 (file)
index 0000000..4834440
--- /dev/null
@@ -0,0 +1,173 @@
+{
+ "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 *"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "challenge_number = 1\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": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ca = open(ciphertext_a_filename).read()\n",
+    "cb = open(ciphertext_b_filename).read()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "21 \n",
+      "\n",
+      "HARRY,\n",
+      "I AM REALLY SORRY TO BOTHER YOU, BUT SOMETHING HAS COME UP AND THE SIS ARE TOO BUSY TO HELP. I AM HOPING YOU CAN.\n",
+      "FOLLOWING THE INVASION OF POLAND, WE ARE ALL ON DOUBLE DUTY, TRAWLING THROUGH OLD FILES FOR ANYTHING THAT MIGHT BE USEFUL TO OUR FRIENDS IN EUROPE. MY TEAM HAS BEEN ASKED TO LOOK AT INTELLIGENCE FILES CONNECTED WITH AIR TRANSPORT AND I WAS GIVEN THE HINDENBURG DISASTER TO CHECK OUT.\n",
+      "THERE ISN'T MUCH TO GO ON AS MOST OF THE PAPERS RECOVERED FROM THE WRECKAGE WERE BADLY DAMAGED. WE DO HAVE A LARGE NUMBER OF FRAGMENTS OF TRAVEL DOCUMENTS WHICH I HAVE SENT TO THE STATE DEPARTMENT FOR ID CHECKS, BUT THAT WILL TAKE A WHILE, AND IN THE MEANTIME, I HAVE BEEN EXAMINING SOME OF THE MORE UNUSUAL ITEMS.\n",
+      "THE MOST INTERESTING ONE IS A CHARRED ENVELOPE CARRYING A SWASTIKA AND MARKED DIE ALCHEMISTEN. I THINK THAT MIGHT BE WORTH INVESTIGATING.\n",
+      "THE CONTENTS WERE MISSING, BUT IN THE SAME EVIDENCE BAG I FOUND A FRAGMENT OF TORN BLUE PAPER WITH A NUMBER IN THE BOTTOM CORNER. THERE IS NO DESCRIPTION WITH IT, BUT I AM GUESSING THAT THEY MUST HAVE BEEN FOUND TOGETHER. WATER HAS DISSOLVED AND OBSCURED THE NUMBER SO I CAN'T READ IT AND I DON'T RECOGNISE THE FORMAT. ON THE OTHER HAND, THE WATER MUST HAVE PROTECTED IT FROM THE HEAT OF THE FLAMES AS THERE ARE NO BURN MARKS AND I WONDERED IF YOUR X-RAY TEAM MIGHT BE ABLE TO ASSIST.\n",
+      "HAVE YOU SEEN ANYTHING LIKE IT BEFORE, OR HAVE YOU HEARD OF DIE ALCHEMISTEN? ANYTHING YOU HAVE WOULD BE GREAT. THANKS\n",
+      "PHIL\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "k_a, score_a = caesar_break(ca)\n",
+    "print(k_a, '\\n')\n",
+    "pa = caesar_decipher(ca, k_a)\n",
+    "print(pa)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1466"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "open(plaintext_a_filename, 'w').write(pa)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "8 \n",
+      "\n",
+      "PHIL, IT IS GOOD TO HEAR FROM YOU. THINGS ARE HECTIC HERE TOO, BUT IT IS MAINLY BUREAUCRACY AS WE TRY TO MAKE SURE ALL THE BOSS FIELD AGENTS HAVE SECURE CHANNELS OF COMMUNICATION AND ROUTES OUT OF TROUBLE IF THEY NEED THEM. IT IS ESSENTIAL WORK, BUT I HAVE BEEN ITCHING TO GET OUT THERE WITH THEM AND YOUR LETTER CAME AT THE RIGHT TIME.\n",
+      "I HAVEN'T HEARD OF DIE ALCHEMISTEN BEFORE, BUT IT DOES REMIND ME OF SOMETHING THAT I CAN'T QUITE PLACE. I WILL GET BACK TO YOU IF I REMEMBER. THE NUMBER IS SLIGHTLY EASIER. THIS LOOKS LIKE THE BOTTOM RIGHT CORNER OF A BLUEPRINT AND I ASSUME THE NUMBER IS RELATED TO THE DESIGN. THE X-RAY TEAM TOOK A SNAP WHICH INCREASED THE CONTRAST AND I THINK I CAN MAKE OUT THE LETTERS GB AT THE START, WHICH IS SUGGESTIVE. THE NEXT TWO DIGITS ARE NOT CLEAR, BUT THEY COULD BE EIGHT-THREE OR EIGHT-FIVE. I HAVE SENT A REQUEST TO THE UK MILITARY ATTACHE TO SEE IF HE RECOGNISES THE FORMAT.\n",
+      "I WILL BE IN TOUCH IN SEVEN DAYS.\n",
+      "HARRY\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "k_b, score_b = caesar_break(cb)\n",
+    "print(k_b, '\\n')\n",
+    "pb = caesar_decipher(cb, k_b)\n",
+    "print(pb)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "953"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "open(plaintext_b_filename, 'w').write(pb)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "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.7.4"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/2020-early/2020-a-challenge2.ipynb b/2020-early/2020-a-challenge2.ipynb
new file mode 100644 (file)
index 0000000..20c5da5
--- /dev/null
@@ -0,0 +1,185 @@
+{
+ "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": 8,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from cipher.caesar import *\n",
+    "from cipher.affine import *\n",
+    "\n",
+    "from support.text_prettify import *\n",
+    "from support.utilities import *\n",
+    "from support.plot_frequency_histogram import *"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "challenge_number = 2\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": 9,
+   "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": 14,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(3, 6, True) \n",
+      "\n",
+      "PHIL I HEARD BACK FROM THE BRITISH MILITARY ATTACHE STOP HE SAID THAT THE NUMBER LOOKS LIKE THE FORMAT USED BY THE PATENT OFFICE STOP HE SUGGESTED THAT THE DOCUMENT MIGHT HAVE BEEN A DESIGN DRAWING FOR AN INVENTION STOP ONE OF OUR FIELD AGENTS TRIED TO FIND OUT WHICH ONE BUT THE NUMBERS LOOKED WRONG STOP PATENT NUMBERS STARTING GB EIGHT HAVE NOT BEEN ISSUED YET STOP THE AGENT HAD NOT SEEN THE PHOTO YOU SENT BUT SHE SHOWED INITIATIVE AND TRIED SOME OTHER NUMBERS STOP GB-SIX-THREE-ZERO-SEVEN-TWO-SIX-A WAS THE MOST PROMISING STOP CHECKED WITH OUR EXPERTS AND THEY WERE CONFUSED STOP ACCORDING TO COCKCROFT THE INVENTION IS IMPRACTICAL STOP SOMEONE POINTED OUT THAT IT FITS WITH THE NAME DIE ALCHEMISTEN STOP SEE ATTACHED STOP WILL INVESTIGATE FURTHER STOP NEXT COMMUNICATION IN SEVEN DAYS STOP\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "(ma, ca, za), score_a = affine_break(sca)\n",
+    "print((ma, ca, za), '\\n')\n",
+    "pa = repunctuate(affine_decipher(sca, ma, ca, za), pta)\n",
+    "print(pa)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "797"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "open(plaintext_a_filename, 'w').write(pa)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(3, 6, True) \n",
+      "\n",
+      "PHIL I HEARD BACK FROM THE BRITISH MILITARY ATTACHE STOP HE SAID THAT THE NUMBER LOOKS LIKE THE FORMAT USED BY THE PATENT OFFICE STOP HE SUGGESTED THAT THE DOCUMENT MIGHT HAVE BEEN A DESIGN DRAWING FOR AN INVENTION STOP ONE OF OUR FIELD AGENTS TRIED TO FIND OUT WHICH ONE BUT THE NUMBERS LOOKED WRONG STOP PATENT NUMBERS STARTING GB EIGHT HAVE NOT BEEN ISSUED YET STOP THE AGENT HAD NOT SEEN THE PHOTO YOU SENT BUT SHE SHOWED INITIATIVE AND TRIED SOME OTHER NUMBERS STOP GB-SIX-THREE-ZERO-SEVEN-TWO-SIX-A WAS THE MOST PROMISING STOP CHECKED WITH OUR EXPERTS AND THEY WERE CONFUSED STOP ACCORDING TO COCKCROFT THE INVENTION IS IMPRACTICAL STOP SOMEONE POINTED OUT THAT IT FITS WITH THE NAME DIE ALCHEMISTEN STOP SEE ATTACHED STOP WILL INVESTIGATE FURTHER STOP NEXT COMMUNICATION IN SEVEN DAYS STOP\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "(mb, cb, zb), score_a = affine_break(scb)\n",
+    "print((mb, cb, z) '\\n')\n",
+    "pa = repunctuate(affine_decipher(sca, ma, ca, za), pta)\n",
+    "print(pa)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "21 \n",
+      "\n",
+      "HARRY,\n",
+      "I AM REALLY SORRY TO BOTHER YOU, BUT SOMETHING HAS COME UP AND THE SIS ARE TOO BUSY TO HELP. I AM HOPING YOU CAN.\n",
+      "FOLLOWING THE INVASION OF POLAND, WE ARE ALL ON DOUBLE DUTY, TRAWLING THROUGH OLD FILES FOR ANYTHING THAT MIGHT BE USEFUL TO OUR FRIENDS IN EUROPE. MY TEAM HAS BEEN ASKED TO LOOK AT INTELLIGENCE FILES CONNECTED WITH AIR TRANSPORT AND I WAS GIVEN THE HINDENBURG DISASTER TO CHECK OUT.\n",
+      "THERE ISN'T MUCH TO GO ON AS MOST OF THE PAPERS RECOVERED FROM THE WRECKAGE WERE BADLY DAMAGED. WE DO HAVE A LARGE NUMBER OF FRAGMENTS OF TRAVEL DOCUMENTS WHICH I HAVE SENT TO THE STATE DEPARTMENT FOR ID CHECKS, BUT THAT WILL TAKE A WHILE, AND IN THE MEANTIME, I HAVE BEEN EXAMINING SOME OF THE MORE UNUSUAL ITEMS.\n",
+      "THE MOST INTERESTING ONE IS A CHARRED ENVELOPE CARRYING A SWASTIKA AND MARKED DIE ALCHEMISTEN. I THINK THAT MIGHT BE WORTH INVESTIGATING.\n",
+      "THE CONTENTS WERE MISSING, BUT IN THE SAME EVIDENCE BAG I FOUND A FRAGMENT OF TORN BLUE PAPER WITH A NUMBER IN THE BOTTOM CORNER. THERE IS NO DESCRIPTION WITH IT, BUT I AM GUESSING THAT THEY MUST HAVE BEEN FOUND TOGETHER. WATER HAS DISSOLVED AND OBSCURED THE NUMBER SO I CAN'T READ IT AND I DON'T RECOGNISE THE FORMAT. ON THE OTHER HAND, THE WATER MUST HAVE PROTECTED IT FROM THE HEAT OF THE FLAMES AS THERE ARE NO BURN MARKS AND I WONDERED IF YOUR X-RAY TEAM MIGHT BE ABLE TO ASSIST.\n",
+      "HAVE YOU SEEN ANYTHING LIKE IT BEFORE, OR HAVE YOU HEARD OF DIE ALCHEMISTEN? ANYTHING YOU HAVE WOULD BE GREAT. THANKS\n",
+      "PHIL\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "k_a, score_b = caesar_break(ca)\n",
+    "print(k_a, '\\n')\n",
+    "pa = caesar_decipher(ca, k_a)\n",
+    "print(pa)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "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.7.4"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/2020-early/2a.ciphertext b/2020-early/2a.ciphertext
new file mode 100644 (file)
index 0000000..e59c0e7
--- /dev/null
@@ -0,0 +1 @@
+BDGP G DUIHR LIOM XHYS NDU LHGNGKD SGPGNIHC INNIODU KNYB DU KIGR NDIN NDU VQSLUH PYYMK PGMU NDU XYHSIN QKUR LC NDU BINUVN YXXGOU KNYB DU KQAAUKNUR NDIN NDU RYOQSUVN SGADN DITU LUUV I RUKGAV RHIWGVA XYH IV GVTUVNGYV KNYB YVU YX YQH XGUPR IAUVNK NHGUR NY XGVR YQN WDGOD YVU LQN NDU VQSLUHK PYYMUR WHYVA KNYB BINUVN VQSLUHK KNIHNGVA AL UGADN DITU VYN LUUV GKKQUR CUN KNYB NDU IAUVN DIR VYN KUUV NDU BDYNY CYQ KUVN LQN KDU KDYWUR GVGNGINGTU IVR NHGUR KYSU YNDUH VQSLUHK KNYB AL-KGZ-NDHUU-FUHY-KUTUV-NWY-KGZ-I WIK NDU SYKN BHYSGKGVA KNYB ODUOMUR WGND YQH UZBUHNK IVR NDUC WUHU OYVXQKUR KNYB IOOYHRGVA NY OYOMOHYXN NDU GVTUVNGYV GK GSBHIONGOIP KNYB KYSUYVU BYGVNUR YQN NDIN GN XGNK WGND NDU VISU RGU IPODUSGKNUV KNYB KUU INNIODUR KNYB WGPP GVTUKNGAINU XQHNDUH KNYB VUZN OYSSQVGOINGYV GV KUTUV RICK KNYB
diff --git a/2020-early/2a.plaintext b/2020-early/2a.plaintext
new file mode 100644 (file)
index 0000000..d7e32ba
--- /dev/null
@@ -0,0 +1 @@
+PHIL I HEARD BACK FROM THE BRITISH MILITARY ATTACHE STOP HE SAID THAT THE NUMBER LOOKS LIKE THE FORMAT USED BY THE PATENT OFFICE STOP HE SUGGESTED THAT THE DOCUMENT MIGHT HAVE BEEN A DESIGN DRAWING FOR AN INVENTION STOP ONE OF OUR FIELD AGENTS TRIED TO FIND OUT WHICH ONE BUT THE NUMBERS LOOKED WRONG STOP PATENT NUMBERS STARTING GB EIGHT HAVE NOT BEEN ISSUED YET STOP THE AGENT HAD NOT SEEN THE PHOTO YOU SENT BUT SHE SHOWED INITIATIVE AND TRIED SOME OTHER NUMBERS STOP GB-SIX-THREE-ZERO-SEVEN-TWO-SIX-A WAS THE MOST PROMISING STOP CHECKED WITH OUR EXPERTS AND THEY WERE CONFUSED STOP ACCORDING TO COCKCROFT THE INVENTION IS IMPRACTICAL STOP SOMEONE POINTED OUT THAT IT FITS WITH THE NAME DIE ALCHEMISTEN STOP SEE ATTACHED STOP WILL INVESTIGATE FURTHER STOP NEXT COMMUNICATION IN SEVEN DAYS STOP
diff --git a/2020-early/2b.ciphertext b/2020-early/2b.ciphertext
new file mode 100644 (file)
index 0000000..bfb2350
--- /dev/null
@@ -0,0 +1 @@
+GLKKF, J RGXRPXU BTQ QGX ELQXYQ FBT LNPXU VX LOBTQ. J QGJYP JQ VJDGQ OX KXSLQXU QB L SXRQTKX RBRPRKBAQ UXSJWXKXU LQ QGX JYNQJQTQX BA XSXRQKJRLS XYDJYXXKN BY LEKJS QZXYQF QGJKU YJYXQXXY QGJKQF NJC. QGX QBEJR ZLN "QGX QKLYNVTQLQJBY BA VLQQXK OF GJDG XYXKDF ELKQJRSXN LYU KLUJLQJBYN". DJWXY QGX SLOXS BY QGX GJYUXYOTKD XYWXSBEX J QGJYP QGX ABSSBZJYD XCQKLRQ JN ELKQJRTSLKSF JYQXKXNQJYD: "JY QGX RLNX BA YTRSXLK QKLYNVTQLQJBYN, JQ NXXVN QGLQ QGX SBNN BA VLNN JN EKXRJNXSF XHTLS QB QGX JYRKXLNX JY QGX PJYXQJR XYXKDF QGLQ GLN QLPXY ESLRX. QGJN DJWXN L NQKJPJYD EKBBA BA QGX VBUXKY EGFNJRLS SLZ QGLQ VLNN LYU XYXKDF LKX XHTJWLSXYQ. JY YJYXQXXY QGJKQF QZB RGLUZJRP UJNRBWXKXU QGX YXTQKBY, L YXZ QFEX BA LQBVJR ELKQJRSX ZGJRG GLN YB XSXRQKJR RGLKDX. JQ UBXN YBQ QGXKXABKX JYQXKLRQ ZJQG BQGXK XSXRQKBYN LYU EKBUTRXN YB JBYJNLQJBY ZGXY ELNNJYD QGKBTDG L DLN. JQ JN BA BTQNQLYUJYD JVEBKQLYRX OXRLTNX BA JQN EBZXK QB EKBUTRX QKLYNVTQLQJBYN. QGXKX JN SJQQSX GBEX QGLQ QGJN EKBRXNN RLY OX TNXU BY LY XYDJYXXKJYD NRLSX QB RBYWXKQ VLNN JYQB XYXKDF. NB ALK, BTK SLOBKLQBKF XCEXKJVXYQN EKBUTRX QGX RBYWXKNX KXNTSQ. QGXBKF JYUJRLQXN QGLQ LQ QXVEXKLQTKXN XHTLS QB QGBNX BA QGX JYQXKJBK BA QGX NTY BK NQLKN, JQ VJDGQ OX EBNNJOSX QB RBYWXKQ QGX JYXCEXYNJWX NJVESX XSXVXYQN QB QGX VBKX WLSTLOSX GXLWJXK RBVOJYLQJBYN, OTQ EKLRQJRLSSF, QGXKX JN YB VXQGBU BA EKBUTRJYD QGX XAAXRQN ABKVXKSF LQQKJOTQXU QB QGX 'EGJSBNBEGXK'N NQBYX'."
diff --git a/2020-early/2b.plaintext b/2020-early/2b.plaintext
new file mode 100644 (file)
index 0000000..91002d3
--- /dev/null
@@ -0,0 +1 @@
+HARRY, I CHECKED OUT THE PATENT YOU ASKED ME ABOUT. I THINK IT MIGHT BE RELATED TO A LECTURE COCKCROFT DELIVERED AT THE INSTITUTE OF ELECTRICAL ENGINEERS ON APRIL TWENTY THIRD NINETEEN THIRTY SIX. THE TOPIC WAS "THE TRANSMUTATION OF MATTER BY HIGH ENERGY PARTICLES AND RADIATIONS". GIVEN THE LABEL ON THE HINDENBURG ENVELOPE I THINK THE FOLLOWING EXTRACT IS PARTICULARLY INTERESTING: "IN THE CASE OF NUCLEAR TRANSMUTATIONS, IT SEEMS THAT THE LOSS OF MASS IS PRECISELY EQUAL TO THE INCREASE IN THE KINETIC ENERGY THAT HAS TAKEN PLACE. THIS GIVES A STRIKING PROOF OF THE MODERN PHYSICAL LAW THAT MASS AND ENERGY ARE EQUIVALENT. IN NINETEEN THIRTY TWO CHADWICK DISCOVERED THE NEUTRON, A NEW TYPE OF ATOMIC PARTICLE WHICH HAS NO ELECTRIC CHARGE. IT DOES NOT THEREFORE INTERACT WITH OTHER ELECTRONS AND PRODUCES NO IONISATION WHEN PASSING THROUGH A GAS. IT IS OF OUTSTANDING IMPORTANCE BECAUSE OF ITS POWER TO PRODUCE TRANSMUTATIONS. THERE IS LITTLE HOPE THAT THIS PROCESS CAN BE USED ON AN ENGINEERING SCALE TO CONVERT MASS INTO ENERGY. SO FAR, OUR LABORATORY EXPERIMENTS PRODUCE THE CONVERSE RESULT. THEORY INDICATES THAT AT TEMPERATURES EQUAL TO THOSE OF THE INTERIOR OF THE SUN OR STARS, IT MIGHT BE POSSIBLE TO CONVERT THE INEXPENSIVE SIMPLE ELEMENTS TO THE MORE VALUABLE HEAVIER COMBINATIONS, BUT PRACTICALLY, THERE IS NO METHOD OF PRODUCING THE EFFECTS FORMERLY ATTRIBUTED TO THE 'PHILOSOPHER'S STONE'."