--- /dev/null
+{
+ "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",
+ "\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 = 6\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": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAa0AAAEiCAYAAABKsI06AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAVkElEQVR4nO3dfbBkdX3n8fcn4BMYw8NcDDCMF63RBE2y4EhhjFsGTERRIbWwC1EZXaxZIz4khuiwbgrLXSpjtNZNalc2I7CMKwthiQoJJpEgBhMFHIan4cEwCyOMEBlFicAGGPnuH31m6zre4Z7bDzPzm/t+Vd3qPr/z+/X5dt/u+7m/06dPp6qQJKkFP7WzC5AkqS9DS5LUDENLktQMQ0uS1AxDS5LUDENLktSMPXd2AQCLFi2q6enpnV2GJGkXcMMNN3y3qqZmW7dLhNb09DRr167d2WVIknYBSb61vXXuHpQkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNWPO0EpyfpIHk6zfpv29Sb6Z5LYkfzij/cwkG7p1r5tE0ZKkhanPh4svAP4r8JmtDUl+FTge+MWqejzJAV37YcDJwEuBg4C/SfLiqvrRuAuXJC08c860quoa4KFtmn8LWFVVj3d9HuzajwcurqrHq+oeYANw5BjrlSQtYMOexunFwKuTnA38M3BGVX0DOBi4dka/TV3bT0iyAlgBsGTJkiHLkCRN0vTKK3r33bjquAlWMjDsgRh7AvsCRwG/B1ySJEBm6Vuz3UBVra6qZVW1bGpq1vMiSpL0Y4YNrU3A52rgeuApYFHXfsiMfouB+0crUZKkgWFD6wvA0QBJXgw8E/gucDlwcpJnJTkUWApcP45CJUma8z2tJBcBrwEWJdkEnAWcD5zfHQb/BLC8qgq4LcklwO3AFuB0jxyUJI3LnKFVVadsZ9Vbt9P/bODsUYqSJGk2nhFDktQMQ0uS1AxDS5LUDENLktQMQ0uS1AxDS5LUDENLktQMQ0uS1AxDS5LUDENLktQMQ0uS1AxDS5LUDENLktQMQ0uS1AxDS5LUDENLktQMQ0uS1AxDS5LUDENLktQMQ0uS1AxDS5LUjDlDK8n5SR5Msn6WdWckqSSLuuUk+eMkG5LckuSISRQtSVqY+sy0LgCO3bYxySHArwH3zmh+PbC0+1kBnDN6iZIkDcwZWlV1DfDQLKs+CXwQqBltxwOfqYFrgX2SHDiWSiVJC95Q72kleTPw7aq6eZtVBwP3zVje1LVJkjSyPec7IMlewIeBX59t9SxtNUsbSVYw2IXIkiVL5luGJGkBGmam9SLgUODmJBuBxcC6JD/LYGZ1yIy+i4H7Z7uRqlpdVcuqatnU1NQQZUiSFpp5h1ZV3VpVB1TVdFVNMwiqI6rqH4HLgVO7owiPAh6uqgfGW7IkaaHqc8j7RcDXgZck2ZTktKfp/kXgbmAD8Gng3WOpUpIkerynVVWnzLF+esb1Ak4fvSxJkn6SZ8SQJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1Y87v05Ik7R6mV17Ru+/GVcdNsJLhOdOSJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1Y87QSnJ+kgeTrJ/R9vEkdya5Jcnnk+wzY92ZSTYk+WaS102qcEnSwtNnpnUBcOw2bVcCL6uqXwT+ATgTIMlhwMnAS7sxn0qyx9iqlSQtaHOGVlVdAzy0TduXqmpLt3gtsLi7fjxwcVU9XlX3ABuAI8dYryRpARvHe1r/FvjL7vrBwH0z1m3q2iRJGtlIoZXkw8AW4MKtTbN0q+2MXZFkbZK1mzdvHqUMSdICMXRoJVkOvBF4S1VtDaZNwCEzui0G7p9tfFWtrqplVbVsampq2DIkSQvIUKGV5FjgQ8Cbq+qxGasuB05O8qwkhwJLgetHL1OSpB5neU9yEfAaYFGSTcBZDI4WfBZwZRKAa6vqXVV1W5JLgNsZ7DY8vap+NKniJUkLy5yhVVWnzNJ83tP0Pxs4e5SiJEmajWfEkCQ1w9CSJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1w9CSJDXD0JIkNcPQkiQ1Y84vgZQk7VqmV17Ru+/GVcdNsJIdz5mWJKkZhpYkqRmGliSpGYaWJKkZhpYkqRlzhlaS85M8mGT9jLb9klyZ5K7uct+uPUn+OMmGJLckOWKSxUuSFpY+M60LgGO3aVsJXFVVS4GrumWA1wNLu58VwDnjKVOSpB6hVVXXAA9t03w8sKa7vgY4YUb7Z2rgWmCfJAeOq1hJ0sI27Htaz6+qBwC6ywO69oOB+2b029S1SZI0snEfiJFZ2mrWjsmKJGuTrN28efOYy5Ak7Y6GDa3vbN3t110+2LVvAg6Z0W8xcP9sN1BVq6tqWVUtm5qaGrIMSdJCMmxoXQ4s764vBy6b0X5qdxThUcDDW3cjSpI0qjlPmJvkIuA1wKIkm4CzgFXAJUlOA+4FTuq6fxF4A7ABeAx4xwRqliQtUHOGVlWdsp1Vx8zSt4DTRy1KkqTZeEYMSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSM/bc2QVI0kI1vfKK3n03rjpugpW0w5mWJKkZhpYkqRnuHpSkMXBX344xUmgl+R3gnUABtwLvAA4ELgb2A9YBb6uqJ0asU5J2CMNn1zb07sEkBwPvA5ZV1cuAPYCTgY8Bn6yqpcD3gdPGUagkSaPuHtwTeE6SJ4G9gAeAo4Hf7NavAT4CnDPidiRpXpwx7Z6GnmlV1beBTwD3Mgirh4EbgB9U1Zau2ybg4NnGJ1mRZG2StZs3bx62DEnSAjLK7sF9geOBQ4GDgL2B18/StWYbX1Wrq2pZVS2bmpoatgxJ0gIyyiHvrwXuqarNVfUk8Dngl4F9kmzd7bgYuH/EGiVJAkYLrXuBo5LslSTAMcDtwNXAiV2f5cBlo5UoSdLAKO9pXQdcyuCw9lu721oNfAj4QJINwP7AeWOoU5Kk0Y4erKqzgLO2ab4bOHKU25UkaTaexkmS1AxDS5LUDENLktQMQ0uS1AzP8i5pl+bpmDSTMy1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMzx6UNIO45GAGpUzLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzRgqtJPskuTTJnUnuSPLKJPsluTLJXd3lvuMqVpK0sI060/oj4K+q6ueAXwLuAFYCV1XVUuCqblmSpJENHVpJngf8S+A8gKp6oqp+ABwPrOm6rQFOGLVISZJgtJnWC4HNwP9IcmOSc5PsDTy/qh4A6C4PmG1wkhVJ1iZZu3nz5hHKkCQtFKOE1p7AEcA5VXU48Cjz2BVYVaurallVLZuamhqhDEnSQjFKaG0CNlXVdd3ypQxC7DtJDgToLh8crURJkgaGDq2q+kfgviQv6ZqOAW4HLgeWd23LgctGqlCSpM6eI45/L3BhkmcCdwPvYBCElyQ5DbgXOGnEbUiSBIwYWlV1E7BsllXHjHK7kiTNxjNiSJKaYWhJkpphaEmSmmFoSZKaYWhJkpphaEmSmmFoSZKaYWhJkpphaEmSmmFoSZKaYWhJkpphaEmSmmFoSZKaYWhJkpphaEmSmmFoSZKaYWhJkpox0jcXS1qYplde0bvvxlXHTbASLTTOtCRJzXCmJS1gzpjUGkNL2k0YQFoI3D0oSWrGyKGVZI8kNyb5i2750CTXJbkryZ8meeboZUqSNJ6Z1vuBO2Ysfwz4ZFUtBb4PnDaGbUiSNFpoJVkMHAec2y0HOBq4tOuyBjhhlG1IkrTVqDOt/wJ8EHiqW94f+EFVbemWNwEHzzYwyYoka5Os3bx584hlSJIWgqFDK8kbgQer6oaZzbN0rdnGV9XqqlpWVcumpqaGLUOStICMcsj7q4A3J3kD8GzgeQxmXvsk2bObbS0G7h+9TEmSRphpVdWZVbW4qqaBk4EvV9VbgKuBE7tuy4HLRq5SkiQm8zmtDwEfSLKBwXtc501gG5KkBWgsZ8Soqq8AX+mu3w0cOY7blSRpJs+IIUlqhqElSWqGoSVJaoahJUlqhqElSWqGoSVJaoahJUlqhqElSWqGoSVJaoahJUlqhqElSWrGWM49KGl8plde0bvvxlXHTbASadfjTEuS1AxDS5LUDHcPShPibj5p/JxpSZKa4UxL6sFZk7RrMLTUpGFDxPCR2ubuQUlSMwwtSVIzDC1JUjMMLUlSM4YOrSSHJLk6yR1Jbkvy/q59vyRXJrmru9x3fOVKkhayUWZaW4DfraqfB44CTk9yGLASuKqqlgJXdcuSJI1s6NCqqgeqal13/YfAHcDBwPHAmq7bGuCEUYuUJAnG9DmtJNPA4cB1wPOr6gEYBFuSA7YzZgWwAmDJkiXjKEMN8nNTkuZj5AMxkjwX+DPgt6vqn/qOq6rVVbWsqpZNTU2NWoYkaQEYKbSSPINBYF1YVZ/rmr+T5MBu/YHAg6OVKEnSwNC7B5MEOA+4o6r+84xVlwPLgVXd5WUjVahmuKtP0qSN8p7Wq4C3Abcmualr+/cMwuqSJKcB9wInjVaiJEkDQ4dWVf0dkO2sPmbY25UkaXs8y/tuzDOhS9rdeBonSVIzDC1JUjPcPdgId9lJkjMtSVJDDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIzDC1JUjMMLUlSMwwtSVIz/BLIIQ37pYx+maMkDW9iM60kxyb5ZpINSVZOajuSpIVjIqGVZA/gvwGvBw4DTkly2CS2JUlaOCa1e/BIYENV3Q2Q5GLgeOD2CW0PcJedJO3uJrV78GDgvhnLm7o2SZKGlqoa/40mJwGvq6p3dstvA46sqvfO6LMCWNEtvgT45tgLGVgEfHcXH9dCjcOOs8bxjGuhxmHHWeN4xrVQY18vqKqpWddU1dh/gFcCfz1j+UzgzElsq0cta3f1cS3UuDvfN2v0vu1K29qdaxzHz6R2D34DWJrk0CTPBE4GLp/QtiRJC8REDsSoqi1J3gP8NbAHcH5V3TaJbUmSFo6Jfbi4qr4IfHFStz8PqxsY10KNw46zxvGMa6HGYcdZ43jGtVDjyCZyIIYkSZPguQclSc1YMKGV5CNJzujRbzrJ+h1Rk7Yvydd2dg27iiT7JHn3Dtze+5LckeTCHbS9R+bZf96v0ZZe1z73n96CCS21pap+eWfXsAvZBxgptDLQ9/X+buANVfWWUbap4fjcf3q7dWgl+XB30t6/YfAB5vmOf2GSG5O8Yo5+r0hyS5JnJ9k7yW1JXtbj9n/sv78kZyT5SI9xeye5IsnNSdYn+Tc9789bk1yf5KYkf9KdI7LPuA9021mf5Ld7jvmPSd4/Y/nsJO/rM7br3/u/7yTv6u7TTUnuSXL1PMb+fpI7k1yZ5KK5ZuNJPjZz1tPN4H93jjEf3Hrfk3wyyZe768ck+WyPMlcBL+ru38d79N+63eluxvQpYB1wSI8x/x14IXB5kt+Zx7b+/2utz+M4BnsmWdO97i5NslePMXsk+XT3+vxSkudsr2P32N2Z5NzueX9hktcm+fskdyU5cq6NJTm1q+/mJP+z7x0bcuZ5R9/7ts24O+f7OCb5QpIbum2tmKv/2O2MD4ftiB/g5cCtwF7A84ANwBk9xk0D6xmE3I3Av+i5vf8EfILBiYJ7fZB667ZmLJ8BfKTHuH8FfHrG8s/0GPPzwJ8Dz+iWPwWcOo/HcW/gucBtwOE979u67vpPAf8H2H8ev79HhvidPwP4KvCmnv2XATcBzwF+GrhrrucIcDjwtzOWbweWzDHmKOB/d9e/Clzf1XoW8O/m+zyZx+MxDTwFHDXPcRuBRfPoP9RrbdjfdXe/CnhVt3x+j9/bNLBl6+sZuAR4a4/+v9A9f2/othMG51H9whzbeymDs/ws6pb3m/Dj0fu+jfI4zrwv3etm/Xxe1+P42Z1nWq8GPl9Vj1XVPzG/DzdPAZcx+MXf1HPMR4FfY/CH8A/nVen83Qq8tvuv/9VV9XCPMccw+OPyjSQ3dcsv7DHuVxg8jo9W1SPA5xg8tk+rqjYC30tyOPDrwI1V9b0e2xvFHwFfrqo/79n/V4DLqur/VtUPGYT606qqG4EDkhyU5JeA71fVvXMMuwF4eZKfBh4Hvs7gefJqBiE2Sd+qqmsnvI1RXmvDuq+q/r67/lkGv8u53DPj9XwDgz/ac/W/taqeYvDP2lU1+Gt9a4+xRwOXVtV3AarqoR71jWK+922rYR7H9yW5GbiWwex96XwKHdXu/iWQwx7P/zCDE/6+isGTtY/9GMxEngE8G3i0x5gt/Pgu2mf32VBV/UOSlwNvAP4gyZeq6qNzDAuwpqrO7LONbcYN61zg7cDPMvgvbmKSvB14AfCe+QwbcnOXAicyuF8Xz9W5qp5MshF4B/A14BbgV4EXAXcMWUNffZ6H47CjPzuz7fb6bP/xGdd/xGCm0Lf/UzOWn2Luv53pWdO4zPe+bTWvxzHJa4DXAq+sqseSfIWef7fGZXeeaV0D/EaS53T/4b5pHmOfAE4ATk3ymz3HrAZ+H7gQ+FjPMd9h8F/7/kmeBbyxz6AkBwGPVdVnGeySPKLHsKuAE5Mc0N3Gfkle0GPcNcAJSfZKsjfwG/SfHXweOBZ4BYOzo0xEF+BnMJgZPzWPoX8HvKl7L/K5QN/vnbmYwanJTmQQYH1c09V4DYPH713ATd1/7nP5IYPdl7uqUV5rw1qS5JXd9VMY/C53JVcB/zrJ/jB4ve3kerZnvo/jzzDYu/BYkp9jsOt7h9ptZ1pVtS7JnzJ4z+JbzHM3TFU9muSNwJVJHq2qy7bXN8mpwJaq+l/dwQ1fS3J0VX15jm08meSjwHXAPcCdPcv7BeDjSZ4CngR+q8f9uT3JfwC+lMFRZE8CpzN4bJ5u3LokFzB4Hwbg3G4X2Zyq6onuoIgfVNWP+oyZOXwefd/DYKZ7dRIYnMjznT3q+0aSy4GbGTwOaxnMsucad1v3x/nbVfVAzxq/CnwY+Hr33Ppnej4nq+p73QEA64G/rKrf67nNHWLU19qQ7gCWJ/kTBu9FnrMDttlb9xw5G/jbJD9i8P7423duVbOa7+P4V8C7ktzC4D27Se96/gmeEUMT04XjOuCkqrprHuP2Z3AQR5+Z4EiSPLeqHumOmroGWFFV6ya93d1ZBkfAPlJVn9jZtWj7kkwDf1FVcx7pvCvZnXcPaidKchiDo8iummdgHcTgQIUd9QdvdXdgyjrgzwwsadfmTEuS1AxnWpKkZhhakqRmGFqSpGYYWpKkZhhakqRmGFqSpGb8Px5ODz4dpDLoAAAAAElFTkSuQmCC\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": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "('norway', <KeywordWrapAlphabet.from_last: 2>)"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "(kworda, kwrapa), score = keyword_break_mp(sca, fitness=Ptrigrams)\n",
+ "kworda, kwrapa"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "harryiguessyouhaveheardbynowabouttheinvasionithascomeasnoshocktoanyonethebritishhadbeenopenlydiscussingacountermanoeuvreandthatisnowasignificantpartofthenazipropagandatheofficiallineisthewehrmachtaretheretoprotectthecountrysneutralityagainstfrancobritishaggressiontheattachedinvasionorderswereinterceptedbybossagentsinthecapitalwhohaveestablishedaheadquartersnexttothetelephoneexchangeasfaraswecantelltheirtapintothesecuretelegraphicsystemhasnotyetbeendetectedbutwewillneedtolookoutforfakeintelligenceincasethatchangesunsurprisinglytheordersusethemostsecurecipherwehaveseenyetacolumnartranspositionluckilyihadsomeideawhattolookforsincenorskhydrowasanimportanttargetforthereichserziehungsministeriumandthatgavemeabigcluethemessagemakesmeverygladthatmonsieurallierwasabletoevacuatetheheavywaternowthatthesshavetakencontrolofrjukanitisonlyamatteroftimeuntiltheybuilduptheirownstocksbutthatwilltakeawhileandwecanusethatperiodtoworkoutwhattodonextwewillberelyingheavilyonyournetworkinthecountrytofeeduswithintelligenceonthefactorywhichiswhyiaskedourcommunicationsteamtosetupthismoresecurechannelifwecanbreakthetelegraphsystemweshouldassumethatthenaziscantooiwouldlikeustomovetousingvigenereciphersforourfuturemessagesstaysafephil\n"
+ ]
+ }
+ ],
+ "source": [
+ "pa = cat(reversed(keyword_decipher(sca, kworda, kwrapa)))\n",
+ "print(pa)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "harry i guess you have heard by now about the invasion it has come as no shock to anyone the british\n",
+ "had been openly discussing a counter manoeuvre and that is now a significant part of the nazi\n",
+ "propaganda the official line is the wehrmacht are there to protect the country s neutrality against\n",
+ "franco british aggression the attached invasion orders were intercepted by boss agents in the\n",
+ "capital who have established a headquarters next to the telephone exchange as far as we can tell\n",
+ "their tap into the secure telegraphic system has not yet been detected but we will need to lookout\n",
+ "for fake intelligence in case that changes unsurprisingly the orders use the most secure cipher we\n",
+ "have seen yet a columnar transposition luckily i had some idea what to look for since norsk hydro\n",
+ "was an important target for the reichs erziehung s ministerium and that gave me a big clue the\n",
+ "message makes me very glad that monsieur allier was able to evacuate the heavy water now that the ss\n",
+ "have taken control of rj uk an it is only a matter of time until they buildup their own stocks but\n",
+ "that will take a while and we can use that period to workout what to do next we will be relying\n",
+ "heavily on your network in the country to feed us with intelligence on the factory which is why i\n",
+ "asked our communications team to setup this more secure channel if we can break the telegraph system\n",
+ "we should assume that the nazis can too i would like us to move to using vi genere ciphers for our\n",
+ "future messages stay safe phil\n"
+ ]
+ }
+ ],
+ "source": [
+ "fpa = lcat(tpack(segment(pa)))\n",
+ "print(fpa)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1501"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "open(plaintext_a_filename, 'w').write(fpa)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "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": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'\\nTRSXS EYHHN LASOR ILHRN NZCHT LYRON AEHSN UIPCN EOLDO ADPNC TRHRS ATORS ONAWT EETDD RYTNO DBEIF INCTR MIEOT ASSGR TRDPE SVBHL OAHEE ACMCE OMLTE RLEFY AYOFS OTAEN REAEO ENBAS OTEVA ENRNN UVJIE NTARL EEMID ATTOD ITRUE UDRRI FRAEB FHDHH UWUSS ESRCC UESEE NVAIE SATSI ACOSA AOENI AWTED OEIHN RELEU IENUR NICNR YEYCT ITDTS TELRY FOAOF WNAAC YSUNE HAVTL STRAU SBDRT TATTT RSHOS KEHHU DLDRE OESOC SIDHE HEEHT SCLNE ENEAE BANVT INSRL PJASH HIEIH TTTUI TRRUN LWEIU RITNI TAHUL BFSAC TENER LONRE IOILH HTUTS ASDRL OTSES REREE LRARN ARLEH OOCPE DBHAE KDRUN EEDRD RDSPP ETLWE NUYDN TEABA IHFRF HNOSP OYRAO PTCTD AMEIF ENENV UEERF IBTHO IMOAG DOSYF NXFRC KPHOE ETMOO EDLFN RTSFO IIGIH EALOR UDCEA TDRSL ETSCI TLPER UOWME ISNIP OKFTK IHCAH OGAUA DUELF TANWA EOONH UEVOT UHYTU LDEEE OAWTE ADLES IRTUL ETEIF ASCDR TISAR TWJEL EPRDL STRAL ECBGU WENEE AICTN HMNDM OINHY REASO RSGTC YNTIU REWSE EFRIM TMHEE TOWSE RDPEF TDENH ODLEP ATRVT TLCEY CINRT YOOCL SRSAC AMDNE DGURP IHTIL ETHLD SWHCR UOEDC NUEUL TRERE OOBAC NNTUW EOYCT AOOKE NEETE EKTSA ODRDE BEKTA IEABS MEOTO ITLTR JRYNC IRNII SOEEN'"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "rscb = cat(reversed(cb))\n",
+ "rscb"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(((3, 1, 4, 2, 0), False, True), -3026.420927215971)"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "(kwordb, fillb, emptyb), score = column_transposition_break_mp(scb, fitness=Ptrigrams)\n",
+ "(kwordb, fillb, emptyb), score"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'uranprojektspecialordersforsixtyninthinfantrydivisioncommandedbygeneralmajorhermanntitteloncetheinitialobjectivesofunternehmenweseruebunghavebeenachievedanelitetaskforceistobeassembledandorderedtoproceedatallspeedtorjukanwheretheyaretotakepossessionofthenorskhydrofactorystaffatthefacilityaretobetreatedwellbutmustnotunderanycircumstancesbeallowedtoleavetheareathepowerplantshouldbesurveyedsecuredandplacedundertwentyfourhourguardstocksofheavywatershouldbeheldinthemostprotectedlocationwithinthefacilitypreferablyundergroundandcertainlyunderarmedguardoncetheareaissecurethesswilltakecontrolofnorskhydroitsoperationsanditssecuritythewehrmachtwillcontinuetoprovideareapatrolsandtopolicelocalresidentsoncetheplantissecuredanditsstaffhavebeenplacedunderhousearrestyouwillcontactthereichserziehungsministeriumwhowillfurnishfurtherordersnhstaffwillbeundertheauthorityoftheministryexercisedthroughthess'"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "pb = column_transposition_decipher(scb, kwordb, fillcolumnwise=fillb, emptycolumnwise=emptyb)\n",
+ "pb"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "uran projekt special orders for sixty ninth infantry division commanded by general major hermann\n",
+ "tittel once the initial objectives of unternehmen we serue bung have been achieved an elite\n",
+ "taskforce is to be assembled and ordered to proceed at all speed to rj uk an where they are to take\n",
+ "possession of the norsk hydro factory staff at the facility are to be treated well but must not\n",
+ "under any circumstances be allowed to leave the area the powerplant should be surveyed secured and\n",
+ "placed under twenty four hour guard stocks of heavy water should beheld in the most protected\n",
+ "location within the facility preferably underground and certainly under armed guard once the area is\n",
+ "secure the ss will take control of norsk hydro its operations and its security the wehrmacht will\n",
+ "continue to provide area patrols and to police local residents once the plant is secured and its\n",
+ "staff have been placed under house arrest you will contact the reichs erziehung s ministerium who\n",
+ "will furnish further orders nh staff will be under the authority of the ministry exercised through\n",
+ "the ss\n"
+ ]
+ }
+ ],
+ "source": [
+ "fpb = lcat(tpack(segment(pb)))\n",
+ "print(fpb)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1077"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "open(plaintext_b_filename, 'w').write(fpb)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['penal',\n",
+ " 'reich',\n",
+ " 'renal',\n",
+ " 'ripen',\n",
+ " 'scram',\n",
+ " 'scrap',\n",
+ " 'sepal',\n",
+ " 'shoal',\n",
+ " 'shock',\n",
+ " 'shrek',\n",
+ " 'siren',\n",
+ " 'sloan',\n",
+ " 'venal',\n",
+ " 'verdi',\n",
+ " 'vetch',\n",
+ " 'viral',\n",
+ " 'vireo',\n",
+ " 'virgo',\n",
+ " 'vital',\n",
+ " 'voter',\n",
+ " 'votes',\n",
+ " 'welch',\n",
+ " 'wench',\n",
+ " 'wendi',\n",
+ " 'wesak',\n",
+ " 'wiser',\n",
+ " 'wives',\n",
+ " 'yowls',\n",
+ " 'remake',\n",
+ " 'remark',\n",
+ " 'rename',\n",
+ " 'repair',\n",
+ " 'repeal',\n",
+ " 'scrams',\n",
+ " 'scraps',\n",
+ " 'sepals',\n",
+ " 'serape',\n",
+ " 'shoals',\n",
+ " 'shocks',\n",
+ " 'shreks',\n",
+ " 'sirens',\n",
+ " 'tercel',\n",
+ " 'terran',\n",
+ " 'thrall',\n",
+ " 'tirana',\n",
+ " 'tishri',\n",
+ " 'unsnap',\n",
+ " 'virgil',\n",
+ " 'virgin',\n",
+ " 'wesaks',\n",
+ " 'within',\n",
+ " 'seepage',\n",
+ " 'serapes',\n",
+ " 'teenage',\n",
+ " 'tishris',\n",
+ " 'unsnaps',\n",
+ " 'wendell',\n",
+ " 'wittier',\n",
+ " 'remedied',\n",
+ " 'repairer',\n",
+ " 'repealer',\n",
+ " 'ringling',\n",
+ " 'riparian',\n",
+ " 'seepages',\n",
+ " 'selassie',\n",
+ " 'singling',\n",
+ " 'teetotal',\n",
+ " 'terraria',\n",
+ " 'tingling',\n",
+ " 'wittiest',\n",
+ " 'selassies']"
+ ]
+ },
+ "execution_count": 19,
+ "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
+}
--- /dev/null
+---
+jupyter:
+ jupytext:
+ formats: ipynb,md
+ text_representation:
+ extension: .md
+ format_name: markdown
+ format_version: '1.2'
+ jupytext_version: 1.3.4
+ kernelspec:
+ display_name: Python 3
+ language: python
+ name: python3
+---
+
+```python
+import os,sys,inspect
+currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parentdir = os.path.dirname(currentdir)
+sys.path.insert(0,parentdir)
+```
+
+```python
+from cipher.caesar import *
+from cipher.affine import *
+from cipher.keyword_cipher import *
+from cipher.column_transposition import *
+
+from support.text_prettify import *
+from support.utilities import *
+from support.plot_frequency_histogram import *
+%matplotlib inline
+```
+
+```python
+challenge_number = 6
+plaintext_a_filename = f'{challenge_number}a.plaintext'
+plaintext_b_filename = f'{challenge_number}b.plaintext'
+ciphertext_a_filename = f'{challenge_number}a.ciphertext'
+ciphertext_b_filename = f'{challenge_number}b.ciphertext'
+```
+
+```python
+ca = open(ciphertext_a_filename).read()
+cb = open(ciphertext_b_filename).read()
+
+sca = sanitise(ca)
+pca = letters(ca)
+pta = depunctuate(ca)
+
+scb = sanitise(cb)
+pcb = letters(cb)
+ptb = depunctuate(cb)
+```
+
+```python
+fc = collections.Counter(sca)
+plot_frequency_histogram(fc, sort_key=fc.get)
+```
+
+```python
+(kworda, kwrapa), score = keyword_break_mp(sca, fitness=Ptrigrams)
+kworda, kwrapa
+```
+
+```python
+pa = cat(reversed(keyword_decipher(sca, kworda, kwrapa)))
+print(pa)
+```
+
+```python
+fpa = lcat(tpack(segment(pa)))
+print(fpa)
+```
+
+```python
+open(plaintext_a_filename, 'w').write(fpa)
+```
+
+```python
+fc = collections.Counter(scb)
+plot_frequency_histogram(fc, sort_key=fc.get)
+```
+
+```python
+rscb = cat(reversed(cb))
+rscb
+```
+
+```python
+(kwordb, fillb, emptyb), score = column_transposition_break_mp(scb, fitness=Ptrigrams)
+(kwordb, fillb, emptyb), score
+```
+
+```python
+pb = column_transposition_decipher(scb, kwordb, fillcolumnwise=fillb, emptycolumnwise=emptyb)
+pb
+```
+
+```python
+fpb = lcat(tpack(segment(pb)))
+print(fpb)
+```
+
+```python
+open(plaintext_b_filename, 'w').write(fpb)
+```
+
+```python
+transpositions[kwordb]
+```
+
+```python
+
+```