{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e279e88d",
   "metadata": {},
   "source": [
    "# Speck Analysis Notebook"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d689cc8d",
   "metadata": {},
   "source": [
    "The following block initializes the chipwhisperer, as always"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "0cccc556",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:ChipWhisperer Other:ChipWhisperer update available! See https://chipwhisperer.readthedocs.io/en/latest/installing.html for updating instructions\n"
     ]
    }
   ],
   "source": [
    "import chipwhisperer as cw\n",
    "import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "9dd8320a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Path to the Speck .hex file for reflashing\n",
    "PATH=\"/home/msc/documents/obsidian_notes/master-aits/subjects/implementation_attacks_and_countermeasures/praktikum/speck_cpa_cw/cw_firmware/simple-speck-CWLITEARM.hex\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 269,
   "id": "d7f94c82",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 269,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "scope.dis()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "7793787d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO: Found ChipWhispereršŸ˜\n"
     ]
    }
   ],
   "source": [
    "def flash(scope, prog):\n",
    "    cw.program_target(scope, prog, PATH)\n",
    "\n",
    "def reset_target(scope):\n",
    "    scope.io.nrst = 'low'\n",
    "    time.sleep(0.05)\n",
    "    scope.io.nrst = 'high_z'\n",
    "    time.sleep(0.05)\n",
    "\n",
    "try:\n",
    "    if not scope.connectStatus:\n",
    "        scope.con()\n",
    "except NameError:\n",
    "    scope = cw.scope()\n",
    "\n",
    "try:\n",
    "    target = cw.target(scope)\n",
    "except IOError:\n",
    "    print(\"INFO: Caught exception on reconnecting to target - attempting to reconnect to scope first.\")\n",
    "    print(\"INFO: This is a work-around when USB has died without Python knowing. Ignore errors above this line.\")\n",
    "    scope = cw.scope()\n",
    "    target = cw.target(scope)\n",
    "\n",
    "print(\"INFO: Found ChipWhispereršŸ˜\")\n",
    "\n",
    "prog = cw.programmers.STM32FProgrammer\n",
    "time.sleep(0.05)\n",
    "scope.default_setup()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bfd1f6a6",
   "metadata": {},
   "source": [
    "**Reset the target if required:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "4cc49970",
   "metadata": {},
   "outputs": [],
   "source": [
    "reset_target(scope)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fe784f48",
   "metadata": {},
   "source": [
    "**Reflash the target if required:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "de6112ec",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Detected known STMF32: STM32F302xB(C)/303xB(C)\n",
      "Extended erase (0x44), this can take ten seconds or more\n",
      "Attempting to program 5431 bytes at 0x8000000\n",
      "STM32F Programming flash...\n",
      "STM32F Reading flash...\n",
      "Verified flash OK, 5431 bytes\n"
     ]
    }
   ],
   "source": [
    "flash(scope, prog)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86a7ff43",
   "metadata": {},
   "source": [
    "**Set an encryption key:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "id": "103040b9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 32 bytes of encryption key\n",
    "#encryption_key = b\"\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\"\n",
    "\n",
    "# 8 byte encryption key\n",
    "encryption_key = b\"\\x11\\x22\\x33\\x44\\x55\\x66\\x77\\x88\"\n",
    "if len(encryption_key) == 8:\n",
    "    target.simpleserial_write(\"s\", encryption_key)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9bfa204a",
   "metadata": {},
   "source": [
    "**Get the encryption key:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 212,
   "id": "bdfe5aba",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CWbytearray(b'11 22 33 44 55 66 77 88')\n"
     ]
    }
   ],
   "source": [
    "target.simpleserial_write(\"k\", b'\\x00'*4)\n",
    "print(target.simpleserial_read(\"o\", 8))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "512daee1",
   "metadata": {},
   "source": [
    "**Encrypt a 4-byte block:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 213,
   "id": "180eb01b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CWbytearray(b'5d 7c 46 6d')\n"
     ]
    }
   ],
   "source": [
    "#pt = b\"\\x70\\x6f\\x6f\\x6e\\x65\\x72\\x2e\\x20\\x49\\x6e\\x20\\x74\\x68\\x6f\\x73\\x65\"\n",
    "pt = b\"\\x4c\\x69\\x74\\x65\"\n",
    "target.simpleserial_write(\"e\", pt)\n",
    "print(target.simpleserial_read(\"c\", 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95dbb710",
   "metadata": {},
   "source": [
    "## Capturing the Data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4c91b03",
   "metadata": {},
   "source": [
    "The following code snippet traces the encryption process with random plaintetext 2000 times"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 280,
   "id": "a56a4fc2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "aac1578be80b4e7e885cd5f7370256e0",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Capturing traces:   0%|          | 0/2200 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from tqdm.notebook import trange\n",
    "import random\n",
    "import numpy as np\n",
    "\n",
    "ktp = cw.ktp.Basic()\n",
    "trace_array = []\n",
    "textin_array = []\n",
    "\n",
    "pt = b\"\\x4c\\x69\\x74\\x65\" \n",
    "random.seed(0x5222223) \n",
    "\n",
    "\n",
    "N = 2200\n",
    "for i in trange(N, desc='Capturing traces'):\n",
    "    pt = bytes([random.randint(0, 255) for i in range(4)])\n",
    "    scope.arm()\n",
    "    \n",
    "    \n",
    "    target.simpleserial_write('e', pt)\n",
    "    \n",
    "    ret = scope.capture()\n",
    "    if ret:\n",
    "        print(\"Target timed out!\")\n",
    "        continue\n",
    "    \n",
    "    response = target.simpleserial_read('c', 4)\n",
    "    \n",
    "    trace_array.append(scope.get_last_trace())\n",
    "    textin_array.append(pt)\n",
    "\n",
    "    \n",
    "trace_array = np.array(trace_array)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce043125",
   "metadata": {},
   "source": [
    "### Saving the traces"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 281,
   "id": "8755eaae",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.save(\"sample_traces/2200_encryption_traces.npy\", trace_array)\n",
    "np.save(\"sample_traces/2200_plaintext_traces.npy\", textin_array)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34533b9f",
   "metadata": {},
   "source": [
    "## Offline Mode\n",
    "\n",
    "If no CW is available, load the trace array from a file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 210,
   "id": "404a9906",
   "metadata": {},
   "outputs": [],
   "source": [
    "trace_array = np.load(\"sample_traces/650_encryption_traces.npy\")\n",
    "textin_array = np.load(\"sample_traces/650_plaintext_traces.npy\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f647149a",
   "metadata": {},
   "source": [
    "## Plotting the Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "id": "e9c2b26b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "/* Put everything inside the global mpl namespace */\n",
       "/* global mpl */\n",
       "window.mpl = {};\n",
       "\n",
       "mpl.get_websocket_type = function () {\n",
       "    if (typeof WebSocket !== 'undefined') {\n",
       "        return WebSocket;\n",
       "    } else if (typeof MozWebSocket !== 'undefined') {\n",
       "        return MozWebSocket;\n",
       "    } else {\n",
       "        alert(\n",
       "            'Your browser does not have WebSocket support. ' +\n",
       "                'Please try Chrome, Safari or Firefox ā‰„ 6. ' +\n",
       "                'Firefox 4 and 5 are also supported but you ' +\n",
       "                'have to enable WebSockets in about:config.'\n",
       "        );\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n",
       "    this.id = figure_id;\n",
       "\n",
       "    this.ws = websocket;\n",
       "\n",
       "    this.supports_binary = this.ws.binaryType !== undefined;\n",
       "\n",
       "    if (!this.supports_binary) {\n",
       "        var warnings = document.getElementById('mpl-warnings');\n",
       "        if (warnings) {\n",
       "            warnings.style.display = 'block';\n",
       "            warnings.textContent =\n",
       "                'This browser does not support binary websocket messages. ' +\n",
       "                'Performance may be slow.';\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.imageObj = new Image();\n",
       "\n",
       "    this.context = undefined;\n",
       "    this.message = undefined;\n",
       "    this.canvas = undefined;\n",
       "    this.rubberband_canvas = undefined;\n",
       "    this.rubberband_context = undefined;\n",
       "    this.format_dropdown = undefined;\n",
       "\n",
       "    this.image_mode = 'full';\n",
       "\n",
       "    this.root = document.createElement('div');\n",
       "    this.root.setAttribute('style', 'display: inline-block');\n",
       "    this._root_extra_style(this.root);\n",
       "\n",
       "    parent_element.appendChild(this.root);\n",
       "\n",
       "    this._init_header(this);\n",
       "    this._init_canvas(this);\n",
       "    this._init_toolbar(this);\n",
       "\n",
       "    var fig = this;\n",
       "\n",
       "    this.waiting = false;\n",
       "\n",
       "    this.ws.onopen = function () {\n",
       "        fig.send_message('supports_binary', { value: fig.supports_binary });\n",
       "        fig.send_message('send_image_mode', {});\n",
       "        if (fig.ratio !== 1) {\n",
       "            fig.send_message('set_device_pixel_ratio', {\n",
       "                device_pixel_ratio: fig.ratio,\n",
       "            });\n",
       "        }\n",
       "        fig.send_message('refresh', {});\n",
       "    };\n",
       "\n",
       "    this.imageObj.onload = function () {\n",
       "        if (fig.image_mode === 'full') {\n",
       "            // Full images could contain transparency (where diff images\n",
       "            // almost always do), so we need to clear the canvas so that\n",
       "            // there is no ghosting.\n",
       "            fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
       "        }\n",
       "        fig.context.drawImage(fig.imageObj, 0, 0);\n",
       "    };\n",
       "\n",
       "    this.imageObj.onunload = function () {\n",
       "        fig.ws.close();\n",
       "    };\n",
       "\n",
       "    this.ws.onmessage = this._make_on_message_function(this);\n",
       "\n",
       "    this.ondownload = ondownload;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._init_header = function () {\n",
       "    var titlebar = document.createElement('div');\n",
       "    titlebar.classList =\n",
       "        'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
       "    var titletext = document.createElement('div');\n",
       "    titletext.classList = 'ui-dialog-title';\n",
       "    titletext.setAttribute(\n",
       "        'style',\n",
       "        'width: 100%; text-align: center; padding: 3px;'\n",
       "    );\n",
       "    titlebar.appendChild(titletext);\n",
       "    this.root.appendChild(titlebar);\n",
       "    this.header = titletext;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
       "\n",
       "mpl.figure.prototype._init_canvas = function () {\n",
       "    var fig = this;\n",
       "\n",
       "    var canvas_div = (this.canvas_div = document.createElement('div'));\n",
       "    canvas_div.setAttribute(\n",
       "        'style',\n",
       "        'border: 1px solid #ddd;' +\n",
       "            'box-sizing: content-box;' +\n",
       "            'clear: both;' +\n",
       "            'min-height: 1px;' +\n",
       "            'min-width: 1px;' +\n",
       "            'outline: 0;' +\n",
       "            'overflow: hidden;' +\n",
       "            'position: relative;' +\n",
       "            'resize: both;'\n",
       "    );\n",
       "\n",
       "    function on_keyboard_event_closure(name) {\n",
       "        return function (event) {\n",
       "            return fig.key_event(event, name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    canvas_div.addEventListener(\n",
       "        'keydown',\n",
       "        on_keyboard_event_closure('key_press')\n",
       "    );\n",
       "    canvas_div.addEventListener(\n",
       "        'keyup',\n",
       "        on_keyboard_event_closure('key_release')\n",
       "    );\n",
       "\n",
       "    this._canvas_extra_style(canvas_div);\n",
       "    this.root.appendChild(canvas_div);\n",
       "\n",
       "    var canvas = (this.canvas = document.createElement('canvas'));\n",
       "    canvas.classList.add('mpl-canvas');\n",
       "    canvas.setAttribute('style', 'box-sizing: content-box;');\n",
       "\n",
       "    this.context = canvas.getContext('2d');\n",
       "\n",
       "    var backingStore =\n",
       "        this.context.backingStorePixelRatio ||\n",
       "        this.context.webkitBackingStorePixelRatio ||\n",
       "        this.context.mozBackingStorePixelRatio ||\n",
       "        this.context.msBackingStorePixelRatio ||\n",
       "        this.context.oBackingStorePixelRatio ||\n",
       "        this.context.backingStorePixelRatio ||\n",
       "        1;\n",
       "\n",
       "    this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
       "\n",
       "    var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
       "        'canvas'\n",
       "    ));\n",
       "    rubberband_canvas.setAttribute(\n",
       "        'style',\n",
       "        'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
       "    );\n",
       "\n",
       "    // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
       "    if (this.ResizeObserver === undefined) {\n",
       "        if (window.ResizeObserver !== undefined) {\n",
       "            this.ResizeObserver = window.ResizeObserver;\n",
       "        } else {\n",
       "            var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
       "            this.ResizeObserver = obs.ResizeObserver;\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
       "        var nentries = entries.length;\n",
       "        for (var i = 0; i < nentries; i++) {\n",
       "            var entry = entries[i];\n",
       "            var width, height;\n",
       "            if (entry.contentBoxSize) {\n",
       "                if (entry.contentBoxSize instanceof Array) {\n",
       "                    // Chrome 84 implements new version of spec.\n",
       "                    width = entry.contentBoxSize[0].inlineSize;\n",
       "                    height = entry.contentBoxSize[0].blockSize;\n",
       "                } else {\n",
       "                    // Firefox implements old version of spec.\n",
       "                    width = entry.contentBoxSize.inlineSize;\n",
       "                    height = entry.contentBoxSize.blockSize;\n",
       "                }\n",
       "            } else {\n",
       "                // Chrome <84 implements even older version of spec.\n",
       "                width = entry.contentRect.width;\n",
       "                height = entry.contentRect.height;\n",
       "            }\n",
       "\n",
       "            // Keep the size of the canvas and rubber band canvas in sync with\n",
       "            // the canvas container.\n",
       "            if (entry.devicePixelContentBoxSize) {\n",
       "                // Chrome 84 implements new version of spec.\n",
       "                canvas.setAttribute(\n",
       "                    'width',\n",
       "                    entry.devicePixelContentBoxSize[0].inlineSize\n",
       "                );\n",
       "                canvas.setAttribute(\n",
       "                    'height',\n",
       "                    entry.devicePixelContentBoxSize[0].blockSize\n",
       "                );\n",
       "            } else {\n",
       "                canvas.setAttribute('width', width * fig.ratio);\n",
       "                canvas.setAttribute('height', height * fig.ratio);\n",
       "            }\n",
       "            canvas.setAttribute(\n",
       "                'style',\n",
       "                'width: ' + width + 'px; height: ' + height + 'px;'\n",
       "            );\n",
       "\n",
       "            rubberband_canvas.setAttribute('width', width);\n",
       "            rubberband_canvas.setAttribute('height', height);\n",
       "\n",
       "            // And update the size in Python. We ignore the initial 0/0 size\n",
       "            // that occurs as the element is placed into the DOM, which should\n",
       "            // otherwise not happen due to the minimum size styling.\n",
       "            if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
       "                fig.request_resize(width, height);\n",
       "            }\n",
       "        }\n",
       "    });\n",
       "    this.resizeObserverInstance.observe(canvas_div);\n",
       "\n",
       "    function on_mouse_event_closure(name) {\n",
       "        return function (event) {\n",
       "            return fig.mouse_event(event, name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mousedown',\n",
       "        on_mouse_event_closure('button_press')\n",
       "    );\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mouseup',\n",
       "        on_mouse_event_closure('button_release')\n",
       "    );\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'dblclick',\n",
       "        on_mouse_event_closure('dblclick')\n",
       "    );\n",
       "    // Throttle sequential mouse events to 1 every 20ms.\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mousemove',\n",
       "        on_mouse_event_closure('motion_notify')\n",
       "    );\n",
       "\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mouseenter',\n",
       "        on_mouse_event_closure('figure_enter')\n",
       "    );\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mouseleave',\n",
       "        on_mouse_event_closure('figure_leave')\n",
       "    );\n",
       "\n",
       "    canvas_div.addEventListener('wheel', function (event) {\n",
       "        if (event.deltaY < 0) {\n",
       "            event.step = 1;\n",
       "        } else {\n",
       "            event.step = -1;\n",
       "        }\n",
       "        on_mouse_event_closure('scroll')(event);\n",
       "    });\n",
       "\n",
       "    canvas_div.appendChild(canvas);\n",
       "    canvas_div.appendChild(rubberband_canvas);\n",
       "\n",
       "    this.rubberband_context = rubberband_canvas.getContext('2d');\n",
       "    this.rubberband_context.strokeStyle = '#000000';\n",
       "\n",
       "    this._resize_canvas = function (width, height, forward) {\n",
       "        if (forward) {\n",
       "            canvas_div.style.width = width + 'px';\n",
       "            canvas_div.style.height = height + 'px';\n",
       "        }\n",
       "    };\n",
       "\n",
       "    // Disable right mouse context menu.\n",
       "    this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
       "        event.preventDefault();\n",
       "        return false;\n",
       "    });\n",
       "\n",
       "    function set_focus() {\n",
       "        canvas.focus();\n",
       "        canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    window.setTimeout(set_focus, 100);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function () {\n",
       "    var fig = this;\n",
       "\n",
       "    var toolbar = document.createElement('div');\n",
       "    toolbar.classList = 'mpl-toolbar';\n",
       "    this.root.appendChild(toolbar);\n",
       "\n",
       "    function on_click_closure(name) {\n",
       "        return function (_event) {\n",
       "            return fig.toolbar_button_onclick(name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    function on_mouseover_closure(tooltip) {\n",
       "        return function (event) {\n",
       "            if (!event.currentTarget.disabled) {\n",
       "                return fig.toolbar_button_onmouseover(tooltip);\n",
       "            }\n",
       "        };\n",
       "    }\n",
       "\n",
       "    fig.buttons = {};\n",
       "    var buttonGroup = document.createElement('div');\n",
       "    buttonGroup.classList = 'mpl-button-group';\n",
       "    for (var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            /* Instead of a spacer, we start a new button group. */\n",
       "            if (buttonGroup.hasChildNodes()) {\n",
       "                toolbar.appendChild(buttonGroup);\n",
       "            }\n",
       "            buttonGroup = document.createElement('div');\n",
       "            buttonGroup.classList = 'mpl-button-group';\n",
       "            continue;\n",
       "        }\n",
       "\n",
       "        var button = (fig.buttons[name] = document.createElement('button'));\n",
       "        button.classList = 'mpl-widget';\n",
       "        button.setAttribute('role', 'button');\n",
       "        button.setAttribute('aria-disabled', 'false');\n",
       "        button.addEventListener('click', on_click_closure(method_name));\n",
       "        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
       "\n",
       "        var icon_img = document.createElement('img');\n",
       "        icon_img.src = '_images/' + image + '.png';\n",
       "        icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
       "        icon_img.alt = tooltip;\n",
       "        button.appendChild(icon_img);\n",
       "\n",
       "        buttonGroup.appendChild(button);\n",
       "    }\n",
       "\n",
       "    if (buttonGroup.hasChildNodes()) {\n",
       "        toolbar.appendChild(buttonGroup);\n",
       "    }\n",
       "\n",
       "    var fmt_picker = document.createElement('select');\n",
       "    fmt_picker.classList = 'mpl-widget';\n",
       "    toolbar.appendChild(fmt_picker);\n",
       "    this.format_dropdown = fmt_picker;\n",
       "\n",
       "    for (var ind in mpl.extensions) {\n",
       "        var fmt = mpl.extensions[ind];\n",
       "        var option = document.createElement('option');\n",
       "        option.selected = fmt === mpl.default_extension;\n",
       "        option.innerHTML = fmt;\n",
       "        fmt_picker.appendChild(option);\n",
       "    }\n",
       "\n",
       "    var status_bar = document.createElement('span');\n",
       "    status_bar.classList = 'mpl-message';\n",
       "    toolbar.appendChild(status_bar);\n",
       "    this.message = status_bar;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n",
       "    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
       "    // which will in turn request a refresh of the image.\n",
       "    this.send_message('resize', { width: x_pixels, height: y_pixels });\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.send_message = function (type, properties) {\n",
       "    properties['type'] = type;\n",
       "    properties['figure_id'] = this.id;\n",
       "    this.ws.send(JSON.stringify(properties));\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.send_draw_message = function () {\n",
       "    if (!this.waiting) {\n",
       "        this.waiting = true;\n",
       "        this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
       "    var format_dropdown = fig.format_dropdown;\n",
       "    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
       "    fig.ondownload(fig, format);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_resize = function (fig, msg) {\n",
       "    var size = msg['size'];\n",
       "    if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n",
       "        fig._resize_canvas(size[0], size[1], msg['forward']);\n",
       "        fig.send_message('refresh', {});\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
       "    var x0 = msg['x0'] / fig.ratio;\n",
       "    var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
       "    var x1 = msg['x1'] / fig.ratio;\n",
       "    var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n",
       "    x0 = Math.floor(x0) + 0.5;\n",
       "    y0 = Math.floor(y0) + 0.5;\n",
       "    x1 = Math.floor(x1) + 0.5;\n",
       "    y1 = Math.floor(y1) + 0.5;\n",
       "    var min_x = Math.min(x0, x1);\n",
       "    var min_y = Math.min(y0, y1);\n",
       "    var width = Math.abs(x1 - x0);\n",
       "    var height = Math.abs(y1 - y0);\n",
       "\n",
       "    fig.rubberband_context.clearRect(\n",
       "        0,\n",
       "        0,\n",
       "        fig.canvas.width / fig.ratio,\n",
       "        fig.canvas.height / fig.ratio\n",
       "    );\n",
       "\n",
       "    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n",
       "    // Updates the figure title.\n",
       "    fig.header.textContent = msg['label'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n",
       "    fig.rubberband_canvas.style.cursor = msg['cursor'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_message = function (fig, msg) {\n",
       "    fig.message.textContent = msg['message'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n",
       "    // Request the server to send over a new figure.\n",
       "    fig.send_draw_message();\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n",
       "    fig.image_mode = msg['mode'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n",
       "    for (var key in msg) {\n",
       "        if (!(key in fig.buttons)) {\n",
       "            continue;\n",
       "        }\n",
       "        fig.buttons[key].disabled = !msg[key];\n",
       "        fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
       "    if (msg['mode'] === 'PAN') {\n",
       "        fig.buttons['Pan'].classList.add('active');\n",
       "        fig.buttons['Zoom'].classList.remove('active');\n",
       "    } else if (msg['mode'] === 'ZOOM') {\n",
       "        fig.buttons['Pan'].classList.remove('active');\n",
       "        fig.buttons['Zoom'].classList.add('active');\n",
       "    } else {\n",
       "        fig.buttons['Pan'].classList.remove('active');\n",
       "        fig.buttons['Zoom'].classList.remove('active');\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function () {\n",
       "    // Called whenever the canvas gets updated.\n",
       "    this.send_message('ack', {});\n",
       "};\n",
       "\n",
       "// A function to construct a web socket function for onmessage handling.\n",
       "// Called in the figure constructor.\n",
       "mpl.figure.prototype._make_on_message_function = function (fig) {\n",
       "    return function socket_on_message(evt) {\n",
       "        if (evt.data instanceof Blob) {\n",
       "            var img = evt.data;\n",
       "            if (img.type !== 'image/png') {\n",
       "                /* FIXME: We get \"Resource interpreted as Image but\n",
       "                 * transferred with MIME type text/plain:\" errors on\n",
       "                 * Chrome.  But how to set the MIME type?  It doesn't seem\n",
       "                 * to be part of the websocket stream */\n",
       "                img.type = 'image/png';\n",
       "            }\n",
       "\n",
       "            /* Free the memory for the previous frames */\n",
       "            if (fig.imageObj.src) {\n",
       "                (window.URL || window.webkitURL).revokeObjectURL(\n",
       "                    fig.imageObj.src\n",
       "                );\n",
       "            }\n",
       "\n",
       "            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
       "                img\n",
       "            );\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        } else if (\n",
       "            typeof evt.data === 'string' &&\n",
       "            evt.data.slice(0, 21) === 'data:image/png;base64'\n",
       "        ) {\n",
       "            fig.imageObj.src = evt.data;\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        var msg = JSON.parse(evt.data);\n",
       "        var msg_type = msg['type'];\n",
       "\n",
       "        // Call the  \"handle_{type}\" callback, which takes\n",
       "        // the figure and JSON message as its only arguments.\n",
       "        try {\n",
       "            var callback = fig['handle_' + msg_type];\n",
       "        } catch (e) {\n",
       "            console.log(\n",
       "                \"No handler for the '\" + msg_type + \"' message type: \",\n",
       "                msg\n",
       "            );\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        if (callback) {\n",
       "            try {\n",
       "                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
       "                callback(fig, msg);\n",
       "            } catch (e) {\n",
       "                console.log(\n",
       "                    \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
       "                    e,\n",
       "                    e.stack,\n",
       "                    msg\n",
       "                );\n",
       "            }\n",
       "        }\n",
       "    };\n",
       "};\n",
       "\n",
       "// from https://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
       "mpl.findpos = function (e) {\n",
       "    //this section is from http://www.quirksmode.org/js/events_properties.html\n",
       "    var targ;\n",
       "    if (!e) {\n",
       "        e = window.event;\n",
       "    }\n",
       "    if (e.target) {\n",
       "        targ = e.target;\n",
       "    } else if (e.srcElement) {\n",
       "        targ = e.srcElement;\n",
       "    }\n",
       "    if (targ.nodeType === 3) {\n",
       "        // defeat Safari bug\n",
       "        targ = targ.parentNode;\n",
       "    }\n",
       "\n",
       "    // pageX,Y are the mouse positions relative to the document\n",
       "    var boundingRect = targ.getBoundingClientRect();\n",
       "    var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
       "    var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
       "\n",
       "    return { x: x, y: y };\n",
       "};\n",
       "\n",
       "/*\n",
       " * return a copy of an object with only non-object keys\n",
       " * we need this to avoid circular references\n",
       " * https://stackoverflow.com/a/24161582/3208463\n",
       " */\n",
       "function simpleKeys(original) {\n",
       "    return Object.keys(original).reduce(function (obj, key) {\n",
       "        if (typeof original[key] !== 'object') {\n",
       "            obj[key] = original[key];\n",
       "        }\n",
       "        return obj;\n",
       "    }, {});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.mouse_event = function (event, name) {\n",
       "    var canvas_pos = mpl.findpos(event);\n",
       "\n",
       "    if (name === 'button_press') {\n",
       "        this.canvas.focus();\n",
       "        this.canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    var x = canvas_pos.x * this.ratio;\n",
       "    var y = canvas_pos.y * this.ratio;\n",
       "\n",
       "    this.send_message(name, {\n",
       "        x: x,\n",
       "        y: y,\n",
       "        button: event.button,\n",
       "        step: event.step,\n",
       "        guiEvent: simpleKeys(event),\n",
       "    });\n",
       "\n",
       "    /* This prevents the web browser from automatically changing to\n",
       "     * the text insertion cursor when the button is pressed.  We want\n",
       "     * to control all of the cursor setting manually through the\n",
       "     * 'cursor' event from matplotlib */\n",
       "    event.preventDefault();\n",
       "    return false;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n",
       "    // Handle any extra behaviour associated with a key event\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.key_event = function (event, name) {\n",
       "    // Prevent repeat events\n",
       "    if (name === 'key_press') {\n",
       "        if (event.key === this._key) {\n",
       "            return;\n",
       "        } else {\n",
       "            this._key = event.key;\n",
       "        }\n",
       "    }\n",
       "    if (name === 'key_release') {\n",
       "        this._key = null;\n",
       "    }\n",
       "\n",
       "    var value = '';\n",
       "    if (event.ctrlKey && event.key !== 'Control') {\n",
       "        value += 'ctrl+';\n",
       "    }\n",
       "    else if (event.altKey && event.key !== 'Alt') {\n",
       "        value += 'alt+';\n",
       "    }\n",
       "    else if (event.shiftKey && event.key !== 'Shift') {\n",
       "        value += 'shift+';\n",
       "    }\n",
       "\n",
       "    value += 'k' + event.key;\n",
       "\n",
       "    this._key_event_extra(event, name);\n",
       "\n",
       "    this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n",
       "    return false;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n",
       "    if (name === 'download') {\n",
       "        this.handle_save(this, null);\n",
       "    } else {\n",
       "        this.send_message('toolbar_button', { name: name });\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n",
       "    this.message.textContent = tooltip;\n",
       "};\n",
       "\n",
       "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
       "// prettier-ignore\n",
       "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n",
       "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
       "\n",
       "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
       "\n",
       "mpl.default_extension = \"png\";/* global mpl */\n",
       "\n",
       "var comm_websocket_adapter = function (comm) {\n",
       "    // Create a \"websocket\"-like object which calls the given IPython comm\n",
       "    // object with the appropriate methods. Currently this is a non binary\n",
       "    // socket, so there is still some room for performance tuning.\n",
       "    var ws = {};\n",
       "\n",
       "    ws.binaryType = comm.kernel.ws.binaryType;\n",
       "    ws.readyState = comm.kernel.ws.readyState;\n",
       "    function updateReadyState(_event) {\n",
       "        if (comm.kernel.ws) {\n",
       "            ws.readyState = comm.kernel.ws.readyState;\n",
       "        } else {\n",
       "            ws.readyState = 3; // Closed state.\n",
       "        }\n",
       "    }\n",
       "    comm.kernel.ws.addEventListener('open', updateReadyState);\n",
       "    comm.kernel.ws.addEventListener('close', updateReadyState);\n",
       "    comm.kernel.ws.addEventListener('error', updateReadyState);\n",
       "\n",
       "    ws.close = function () {\n",
       "        comm.close();\n",
       "    };\n",
       "    ws.send = function (m) {\n",
       "        //console.log('sending', m);\n",
       "        comm.send(m);\n",
       "    };\n",
       "    // Register the callback with on_msg.\n",
       "    comm.on_msg(function (msg) {\n",
       "        //console.log('receiving', msg['content']['data'], msg);\n",
       "        var data = msg['content']['data'];\n",
       "        if (data['blob'] !== undefined) {\n",
       "            data = {\n",
       "                data: new Blob(msg['buffers'], { type: data['blob'] }),\n",
       "            };\n",
       "        }\n",
       "        // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
       "        ws.onmessage(data);\n",
       "    });\n",
       "    return ws;\n",
       "};\n",
       "\n",
       "mpl.mpl_figure_comm = function (comm, msg) {\n",
       "    // This is the function which gets called when the mpl process\n",
       "    // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
       "\n",
       "    var id = msg.content.data.id;\n",
       "    // Get hold of the div created by the display call when the Comm\n",
       "    // socket was opened in Python.\n",
       "    var element = document.getElementById(id);\n",
       "    var ws_proxy = comm_websocket_adapter(comm);\n",
       "\n",
       "    function ondownload(figure, _format) {\n",
       "        window.open(figure.canvas.toDataURL());\n",
       "    }\n",
       "\n",
       "    var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n",
       "\n",
       "    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
       "    // web socket which is closed, not our websocket->open comm proxy.\n",
       "    ws_proxy.onopen();\n",
       "\n",
       "    fig.parent_element = element;\n",
       "    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
       "    if (!fig.cell_info) {\n",
       "        console.error('Failed to find cell for figure', id, fig);\n",
       "        return;\n",
       "    }\n",
       "    fig.cell_info[0].output_area.element.on(\n",
       "        'cleared',\n",
       "        { fig: fig },\n",
       "        fig._remove_fig_handler\n",
       "    );\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
       "    var width = fig.canvas.width / fig.ratio;\n",
       "    fig.cell_info[0].output_area.element.off(\n",
       "        'cleared',\n",
       "        fig._remove_fig_handler\n",
       "    );\n",
       "    fig.resizeObserverInstance.unobserve(fig.canvas_div);\n",
       "\n",
       "    // Update the output cell to use the data from the current canvas.\n",
       "    fig.push_to_output();\n",
       "    var dataURL = fig.canvas.toDataURL();\n",
       "    // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
       "    // the notebook keyboard shortcuts fail.\n",
       "    IPython.keyboard_manager.enable();\n",
       "    fig.parent_element.innerHTML =\n",
       "        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "    fig.close_ws(fig, msg);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.close_ws = function (fig, msg) {\n",
       "    fig.send_message('closing', msg);\n",
       "    // fig.ws.close()\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n",
       "    // Turn the data on the canvas into data in the output cell.\n",
       "    var width = this.canvas.width / this.ratio;\n",
       "    var dataURL = this.canvas.toDataURL();\n",
       "    this.cell_info[1]['text/html'] =\n",
       "        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function () {\n",
       "    // Tell IPython that the notebook contents must change.\n",
       "    IPython.notebook.set_dirty(true);\n",
       "    this.send_message('ack', {});\n",
       "    var fig = this;\n",
       "    // Wait a second, then push the new image to the DOM so\n",
       "    // that it is saved nicely (might be nice to debounce this).\n",
       "    setTimeout(function () {\n",
       "        fig.push_to_output();\n",
       "    }, 1000);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function () {\n",
       "    var fig = this;\n",
       "\n",
       "    var toolbar = document.createElement('div');\n",
       "    toolbar.classList = 'btn-toolbar';\n",
       "    this.root.appendChild(toolbar);\n",
       "\n",
       "    function on_click_closure(name) {\n",
       "        return function (_event) {\n",
       "            return fig.toolbar_button_onclick(name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    function on_mouseover_closure(tooltip) {\n",
       "        return function (event) {\n",
       "            if (!event.currentTarget.disabled) {\n",
       "                return fig.toolbar_button_onmouseover(tooltip);\n",
       "            }\n",
       "        };\n",
       "    }\n",
       "\n",
       "    fig.buttons = {};\n",
       "    var buttonGroup = document.createElement('div');\n",
       "    buttonGroup.classList = 'btn-group';\n",
       "    var button;\n",
       "    for (var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            /* Instead of a spacer, we start a new button group. */\n",
       "            if (buttonGroup.hasChildNodes()) {\n",
       "                toolbar.appendChild(buttonGroup);\n",
       "            }\n",
       "            buttonGroup = document.createElement('div');\n",
       "            buttonGroup.classList = 'btn-group';\n",
       "            continue;\n",
       "        }\n",
       "\n",
       "        button = fig.buttons[name] = document.createElement('button');\n",
       "        button.classList = 'btn btn-default';\n",
       "        button.href = '#';\n",
       "        button.title = name;\n",
       "        button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n",
       "        button.addEventListener('click', on_click_closure(method_name));\n",
       "        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
       "        buttonGroup.appendChild(button);\n",
       "    }\n",
       "\n",
       "    if (buttonGroup.hasChildNodes()) {\n",
       "        toolbar.appendChild(buttonGroup);\n",
       "    }\n",
       "\n",
       "    // Add the status bar.\n",
       "    var status_bar = document.createElement('span');\n",
       "    status_bar.classList = 'mpl-message pull-right';\n",
       "    toolbar.appendChild(status_bar);\n",
       "    this.message = status_bar;\n",
       "\n",
       "    // Add the close button to the window.\n",
       "    var buttongrp = document.createElement('div');\n",
       "    buttongrp.classList = 'btn-group inline pull-right';\n",
       "    button = document.createElement('button');\n",
       "    button.classList = 'btn btn-mini btn-primary';\n",
       "    button.href = '#';\n",
       "    button.title = 'Stop Interaction';\n",
       "    button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n",
       "    button.addEventListener('click', function (_evt) {\n",
       "        fig.handle_close(fig, {});\n",
       "    });\n",
       "    button.addEventListener(\n",
       "        'mouseover',\n",
       "        on_mouseover_closure('Stop Interaction')\n",
       "    );\n",
       "    buttongrp.appendChild(button);\n",
       "    var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
       "    titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
       "    var fig = event.data.fig;\n",
       "    if (event.target !== this) {\n",
       "        // Ignore bubbled events from children.\n",
       "        return;\n",
       "    }\n",
       "    fig.close_ws(fig, {});\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function (el) {\n",
       "    el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
       "    // this is important to make the div 'focusable\n",
       "    el.setAttribute('tabindex', 0);\n",
       "    // reach out to IPython and tell the keyboard manager to turn it's self\n",
       "    // off when our div gets focus\n",
       "\n",
       "    // location in version 3\n",
       "    if (IPython.notebook.keyboard_manager) {\n",
       "        IPython.notebook.keyboard_manager.register_events(el);\n",
       "    } else {\n",
       "        // location in version 2\n",
       "        IPython.keyboard_manager.register_events(el);\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function (event, _name) {\n",
       "    // Check for shift+enter\n",
       "    if (event.shiftKey && event.which === 13) {\n",
       "        this.canvas_div.blur();\n",
       "        // select the cell after this one\n",
       "        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
       "        IPython.notebook.select(index + 1);\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
       "    fig.ondownload(fig, null);\n",
       "};\n",
       "\n",
       "mpl.find_output_cell = function (html_output) {\n",
       "    // Return the cell and output element which can be found *uniquely* in the notebook.\n",
       "    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
       "    // IPython event is triggered only after the cells have been serialised, which for\n",
       "    // our purposes (turning an active figure into a static one), is too late.\n",
       "    var cells = IPython.notebook.get_cells();\n",
       "    var ncells = cells.length;\n",
       "    for (var i = 0; i < ncells; i++) {\n",
       "        var cell = cells[i];\n",
       "        if (cell.cell_type === 'code') {\n",
       "            for (var j = 0; j < cell.output_area.outputs.length; j++) {\n",
       "                var data = cell.output_area.outputs[j];\n",
       "                if (data.data) {\n",
       "                    // IPython >= 3 moved mimebundle to data attribute of output\n",
       "                    data = data.data;\n",
       "                }\n",
       "                if (data['text/html'] === html_output) {\n",
       "                    return [cell, data, j];\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "};\n",
       "\n",
       "// Register the function which deals with the matplotlib target/channel.\n",
       "// The kernel may be null if the page has been refreshed.\n",
       "if (IPython.notebook.kernel !== null) {\n",
       "    IPython.notebook.kernel.comm_manager.register_target(\n",
       "        'matplotlib',\n",
       "        mpl.mpl_figure_comm\n",
       "    );\n",
       "}\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAPUUlEQVR4nO3WoW1CAQAAUZq/AHXM8AdgA4JmBsIAmIYNECTYigoEAyDQsER3wdEwRhPu6WdO3uQ6/fk8XRa774/77DD+Lde35/l3P2zmw2p7fIxfnHPOOef8vXzy3wGcc84559wAcs4555xzA8g555xzzg0g55xzzjk3gJxzzjnn3AByzjnnnHMDyDnnnHPedgPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx5zA8g555xzHnMDyDnnnHMecwPIOeeccx7zF+UzQZBS2g/0AAAAAElFTkSuQmCC\" width=\"640\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib notebook\n",
    "import matplotlib.pylab as plt\n",
    "plt.figure()\n",
    "plt.plot(trace_array[2], 'orange')\n",
    "#plt.plot(trace_array[4], 'g')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0a304aae",
   "metadata": {},
   "source": [
    "# Hamming Weight and Speck Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "8cfe5d98",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Hamming Weight\n",
    "HW = [bin(n).count(\"1\") for n in range(0, 256)]\n",
    "def popcount(x):\n",
    "    x -= (x >> 1) & 0x5555555555555555\n",
    "    x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)\n",
    "    x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f\n",
    "    return ((x * 0x0101010101010101) & 0xffffffffffffffff ) >> 56"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "335d65f4",
   "metadata": {},
   "source": [
    "### Further functions for Pearson"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "77c909cc",
   "metadata": {},
   "outputs": [],
   "source": [
    "def mean(X):\n",
    "    return np.sum(X, axis=0)/len(X)\n",
    "\n",
    "def std_dev(X, X_bar):\n",
    "    return np.sqrt(np.sum((X-X_bar)**2, axis=0))\n",
    "\n",
    "def cov(X, X_bar, Y, Y_bar):\n",
    "    return np.sum((X-X_bar)*(Y-Y_bar), axis=0)\n",
    "\n",
    "def to16(byte1, byte2):\n",
    "    return int((byte1 << 8) + byte2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1d60ab6",
   "metadata": {},
   "source": [
    "## The Speck Simulation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f60c1e5d",
   "metadata": {},
   "source": [
    "The following Code calculates the basic Speck encryption routine (one xor):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 269,
   "id": "8de1fe36",
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "NUM_ROUNDS = 22\n",
    "BLOCK_SIZE = 32\n",
    "KEY_SIZE = 64\n",
    "WORD_SIZE = 16\n",
    "\n",
    "\n",
    "# SHIFTs for SPECK\n",
    "ALPHA = 7\n",
    "BETA = 2\n",
    "\n",
    "mod_mask = (2 ** WORD_SIZE) -1\n",
    "mod_mask_sub = (2 ** WORD_SIZE)\n",
    "\n",
    "def ER16(x, y, k):\n",
    "\n",
    "    rs_x = ((x << (16 - ALPHA)) + (x >> ALPHA)) & mod_mask\n",
    "\n",
    "    add_sxy = (rs_x + y) & mod_mask\n",
    "\n",
    "    new_x = k ^ add_sxy\n",
    "\n",
    "    ls_y = ((y >> (16 - BETA)) + (y << BETA)) & mod_mask\n",
    "\n",
    "    new_y = new_x ^ ls_y\n",
    "\n",
    "    return new_x, new_y\n",
    "\n",
    "\n",
    "\n",
    "def simple_speck(plaintext, key, arg=None):\n",
    "    Ct_0 = (int(plaintext[1]) << 8) + int(plaintext[0])\n",
    "    Ct_1 = (int(plaintext[3]) << 8) + int(plaintext[2])\n",
    "                                                \n",
    "    \n",
    "    Ct_1, Ct_0 = ER16(Ct_1, Ct_0, key)   # fixed 16 bit key of 0x55\n",
    "    return popcount((Ct_1 << 8) + Ct_0)\n",
    "\n",
    "## According to the Paper \"Breaking Speck using CPA\"\n",
    "def PowerRightHalfKey(plaintext, key, knownkey=None):\n",
    "    y = (int(plaintext[1]) << 8) + int(plaintext[0])\n",
    "    x = (int(plaintext[3]) << 8) + int(plaintext[2])\n",
    "    \n",
    "    x = ((x << (16 - ALPHA)) + (x >> ALPHA)) & mod_mask\n",
    "    x = (x + y) & mod_mask\n",
    "    x = x ^ key\n",
    "    \n",
    "    return popcount(x)\n",
    "\n",
    "## According to the Paper \"Breaking Speck using CPA\" \n",
    "def PowerLeftHalfKeyII(plaintext, key, knownkey):\n",
    "    y = (int(plaintext[1]) << 8) + int(plaintext[0])\n",
    "    x = (int(plaintext[3]) << 8) + int(plaintext[2])\n",
    "       \n",
    "    \n",
    "    # -------------- for one key -----------------#\n",
    "    x = ((x << (16 - ALPHA)) + (x >> ALPHA)) & mod_mask           # x = ROR(x, 7)\n",
    "    x = (x + y) & mod_mask                                        # x = ADD(x, y)\n",
    "    \n",
    "    if knownkey == None or len(knownkey) == 0:\n",
    "        x = x ^ key                                               # x = XOR(x, k)\n",
    "        return popcount(x)\n",
    "    else:\n",
    "        x = x ^ knownkey[0]   \n",
    "    \n",
    "    \n",
    "    # -------------- for second key -----------------#\n",
    "    \n",
    "    \n",
    "    y = ((y >> (16 - BETA)) + (y << BETA)) & mod_mask            # y = ROL(y, 2)\n",
    "    y = y ^ x                                                    # y = XOR(y, x)\n",
    "    x = ((x << (16 - ALPHA)) + (x >> ALPHA)) & mod_mask          # x = ROR(x, 7)\n",
    "    x = (x + y) & mod_mask                                       # x = ADD(x, y)\n",
    "    \n",
    "    \n",
    "    if len(knownkey) == 1:\n",
    "        x = x ^ key                                             # x = XOR(x, k)\n",
    "        return popcount(x)\n",
    "    else:\n",
    "        x = x ^ knownkey[1]                                     # x = XOR(x, k) \n",
    "                                            \n",
    "    \n",
    "    # -------------- for third key -----------------#\n",
    "\n",
    "    y = ((y >> (16 - BETA)) + (y << BETA)) & mod_mask            # y = ROL(y, 2)\n",
    "    y = y ^ x                                                    # y = XOR(y, x)\n",
    "    x = ((x << (16 - ALPHA)) + (x >> ALPHA)) & mod_mask          # x = ROR(x, 7)\n",
    "    x = (x + y) & mod_mask                                       # x = ADD(x, y)\n",
    "    \n",
    "    if len(knownkey) == 2:\n",
    "        x = x ^ key                                              # x = XOR(x, k)\n",
    "    else:\n",
    "        x =  x ^ knownkey[2]                                     # x = XOR(x, k)\n",
    "        \n",
    "    y = ((y >> (16 - BETA)) + (y << BETA)) & mod_mask            # y = ROL(y, 2)\n",
    "    y = y ^ x                                                    # y = XOR(y, x)\n",
    "    \n",
    "    if len(knownkey) == 2:                                       \n",
    "        return popcount(y)   \n",
    "    \n",
    "    \n",
    "    # -------------- for fourth key -----------------#\n",
    "    \n",
    "    x = ((x << (16 - ALPHA)) + (x >> ALPHA)) & mod_mask          # x = ROR(x, 7)\n",
    "    x = (x + y) & mod_mask                                       # x = ADD(x, y)\n",
    "    \n",
    "    if len(knownkey) == 3:\n",
    "        x = x ^ key                                              # x = XOR(x, k)\n",
    "    else:\n",
    "        x =  x ^ knownkey[3]                                     # x = XOR(x, k)\n",
    "        \n",
    "    y = ((y >> (16 - BETA)) + (y << BETA)) & mod_mask            # y = ROL(y, 2)\n",
    "    y = y ^ x                                                    # y = XOR(y, x)\n",
    " \n",
    "    if len(knownkey) == 3:                                       \n",
    "        return popcount(y)   \n",
    "\n",
    "    # -------------- for fith key -----------------#\n",
    "    x = ((x << (16 - ALPHA)) + (x >> ALPHA)) & mod_mask          # x = ROR(x, 7)\n",
    "    x = (x + y) & mod_mask                                       # x = ADD(x, y)\n",
    "    \n",
    "    x =  x ^ key                                                 # x = XOR(x, k)\n",
    "    y = ((y >> (16 - BETA)) + (y << BETA)) & mod_mask            # y = ROL(y, 2)\n",
    "    y = y ^ x                                                    # y = XOR(y, x)\n",
    "    \n",
    "    if len(knownkey) == 4:                                       # x = XOR(x, k)\n",
    "        return popcount(y)   \n",
    "\n",
    "    return popcount(y)\n",
    "    \n",
    "    \n",
    "    ## According to the Paper \"Breaking Speck using CPA\" \n",
    "def PowerLeftHalfKey(plaintext, key, knownkey):\n",
    "    pt2 = (int(plaintext[1]) << 8) + int(plaintext[0])\n",
    "    pt1 = (int(plaintext[3]) << 8) + int(plaintext[2])\n",
    "    \n",
    "    temp = ((pt1 << (16 - ALPHA)) + (pt1 >> ALPHA)) & mod_mask\n",
    "    p1 = (temp + pt2) & mod_mask\n",
    "    \n",
    "    r1 = p1 ^ knownkey\n",
    "    \n",
    "    temp = ((pt2 >> (16 - BETA)) + (pt2 << BETA)) & mod_mask\n",
    "    s1 = temp ^ r1\n",
    "    temp = ((r1 << (16 - ALPHA)) + (r1 >> ALPHA)) & mod_mask\n",
    "    p2 = (temp + s1) & mod_mask\n",
    "    \n",
    "    \n",
    "    intermediate = (p2) ^ key\n",
    "    \n",
    "    \n",
    "    \n",
    "    return popcount(intermediate)\n",
    "\n",
    "def simple_speck_partial(plaintext, key, knownkey):\n",
    "    Ct_0 = (int(plaintext[1]) << 8) + int(plaintext[0])\n",
    "    Ct_1 = (int(plaintext[3]) << 8) + int(plaintext[2])\n",
    "                                                \n",
    "    Ct_1, Ct_0 = ER16(Ct_1, Ct_0, knownkey)\n",
    "    \n",
    "\n",
    "    Ct_1, Ct_0 = ER16(Ct_1, Ct_0, key)   # fixed 16 bit key of 0x55\n",
    "    return popcount((Ct_1 << 8) + Ct_0)\n",
    "\n",
    "\n",
    "def speck_keyschedule(plaintext, key, known_keys):\n",
    "    Ct_0 = (int(plaintext[1]) << 8) + int(plaintext[0])\n",
    "    Ct_1 = (int(plaintext[3]) << 8) + int(plaintext[2])\n",
    "    \n",
    "    for known_key in known_keys:\n",
    "        Ct_1, Ct_0 = ER16(Ct_1, Ct_0, known_key)    \n",
    "\n",
    "    Ct_1, Ct_0 = ER16(Ct_1, Ct_0, key)   # fixed 16 bit key of 0x55\n",
    "    return popcount((Ct_1 << 8) + Ct_0)\n",
    "\n",
    "   \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 262,
   "id": "8b8b655b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 262,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "simple_speck(b'\\xf5\\xf9\\xa97', 0x1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f288ecd4",
   "metadata": {},
   "source": [
    "## This Methods works for calculating the correct key from the Power-Trace"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93fb63b1",
   "metadata": {},
   "source": [
    "For the following C-Implementation, the function `calc_mean_from_trace()` seems to gather the correct key from the trace:\n",
    "\n",
    "```C\n",
    "u16 i;\n",
    "Ct[0]=Pt[0]; Ct[1]=Pt[1];\n",
    "\n",
    "for(i=0;i<22; i++) {\n",
    "    ER16(Ct[1],Ct[0],0x69);\n",
    "}\n",
    "\n",
    "```\n",
    "\n",
    "This also works for 2-byte keys:\n",
    "\n",
    "```C\n",
    "ER16(Ct[1],Ct[0],0xdead);\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d93c131a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "id": "1c35c3ac",
   "metadata": {},
   "outputs": [],
   "source": [
    "def calculate_correlations(traces, plaintexts, model_callback, leftmost=True, other_keybyte=0x00, argument=None):\n",
    "    \n",
    "    maxcpa = [0] * 256   # Correlations\n",
    "    \n",
    "    # Calculate mean and standard derivation\n",
    "    t_bar = mean(traces) \n",
    "    o_t = std_dev(traces, t_bar)\n",
    "    \n",
    "    \n",
    "    for key in range(0, 256):\n",
    "        \n",
    "        # Run the model\n",
    "        if leftmost:\n",
    "            hws = np.array([[model_callback(pt, (key << 8) + other_keybyte, argument) for pt in plaintexts]]).transpose()\n",
    "        elif not leftmost:\n",
    "            hws = np.array([[model_callback(pt, (other_keybyte << 8) + key, argument) for pt in plaintexts]]).transpose()\n",
    "        else:\n",
    "            raise Exception(\"[-] Invalid Key Position\")\n",
    "            \n",
    "        \n",
    "        hws_bar = mean(hws)\n",
    "        o_hws = std_dev(hws, hws_bar)\n",
    "        correlation = cov(traces, t_bar, hws, hws_bar)\n",
    "        cpaoutput = correlation/(o_t*o_hws)\n",
    "        maxcpa[key] = max(abs(cpaoutput))\n",
    "    \n",
    "    # Return the two best guesses\n",
    "    best_guess = int(np.argmax(maxcpa))\n",
    "    second_guess = int(np.argsort(maxcpa, axis=0)[-2])\n",
    "    \n",
    "    return ([best_guess, maxcpa[best_guess]], [second_guess, maxcpa[second_guess]])\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "id": "8a54a633",
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm import tnrange\n",
    "\n",
    "\n",
    "def calc_mean_from_trace(traces, plaintexts):\n",
    "\n",
    "    maxcpa = [0] * 256\n",
    "\n",
    "    t_bar = mean(traces) \n",
    "    o_t = std_dev(traces, t_bar)\n",
    "\n",
    "    for key in range(0, 256):\n",
    "        \n",
    "        hws = np.array([[simple_speck(textin, (key << 8) + 0x00) for textin in textin_array]]).transpose()\n",
    "        \n",
    "        # The following line works for a one byte key\n",
    "        #hws = np.array([[simple_speck(textin, key) for textin in textin_array]]).transpose()\n",
    "        \n",
    "\n",
    "        hws_bar = mean(hws)\n",
    "        o_hws = std_dev(hws, hws_bar)\n",
    "        correlation = cov(traces, t_bar, hws, hws_bar)\n",
    "        cpaoutput = correlation/(o_t*o_hws)\n",
    "        maxcpa[key] = max(abs(cpaoutput))\n",
    "    \n",
    "    plt.figure()\n",
    "    plt.plot(maxcpa, 'orange')\n",
    "    plt.show()\n",
    "    guess = np.argmax(maxcpa)\n",
    "    print(f\"Key guess: (xored with) = \", hex(guess))\n",
    "    return guess\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "4fd256ea",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "/* Put everything inside the global mpl namespace */\n",
       "/* global mpl */\n",
       "window.mpl = {};\n",
       "\n",
       "mpl.get_websocket_type = function () {\n",
       "    if (typeof WebSocket !== 'undefined') {\n",
       "        return WebSocket;\n",
       "    } else if (typeof MozWebSocket !== 'undefined') {\n",
       "        return MozWebSocket;\n",
       "    } else {\n",
       "        alert(\n",
       "            'Your browser does not have WebSocket support. ' +\n",
       "                'Please try Chrome, Safari or Firefox ā‰„ 6. ' +\n",
       "                'Firefox 4 and 5 are also supported but you ' +\n",
       "                'have to enable WebSockets in about:config.'\n",
       "        );\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n",
       "    this.id = figure_id;\n",
       "\n",
       "    this.ws = websocket;\n",
       "\n",
       "    this.supports_binary = this.ws.binaryType !== undefined;\n",
       "\n",
       "    if (!this.supports_binary) {\n",
       "        var warnings = document.getElementById('mpl-warnings');\n",
       "        if (warnings) {\n",
       "            warnings.style.display = 'block';\n",
       "            warnings.textContent =\n",
       "                'This browser does not support binary websocket messages. ' +\n",
       "                'Performance may be slow.';\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.imageObj = new Image();\n",
       "\n",
       "    this.context = undefined;\n",
       "    this.message = undefined;\n",
       "    this.canvas = undefined;\n",
       "    this.rubberband_canvas = undefined;\n",
       "    this.rubberband_context = undefined;\n",
       "    this.format_dropdown = undefined;\n",
       "\n",
       "    this.image_mode = 'full';\n",
       "\n",
       "    this.root = document.createElement('div');\n",
       "    this.root.setAttribute('style', 'display: inline-block');\n",
       "    this._root_extra_style(this.root);\n",
       "\n",
       "    parent_element.appendChild(this.root);\n",
       "\n",
       "    this._init_header(this);\n",
       "    this._init_canvas(this);\n",
       "    this._init_toolbar(this);\n",
       "\n",
       "    var fig = this;\n",
       "\n",
       "    this.waiting = false;\n",
       "\n",
       "    this.ws.onopen = function () {\n",
       "        fig.send_message('supports_binary', { value: fig.supports_binary });\n",
       "        fig.send_message('send_image_mode', {});\n",
       "        if (fig.ratio !== 1) {\n",
       "            fig.send_message('set_device_pixel_ratio', {\n",
       "                device_pixel_ratio: fig.ratio,\n",
       "            });\n",
       "        }\n",
       "        fig.send_message('refresh', {});\n",
       "    };\n",
       "\n",
       "    this.imageObj.onload = function () {\n",
       "        if (fig.image_mode === 'full') {\n",
       "            // Full images could contain transparency (where diff images\n",
       "            // almost always do), so we need to clear the canvas so that\n",
       "            // there is no ghosting.\n",
       "            fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
       "        }\n",
       "        fig.context.drawImage(fig.imageObj, 0, 0);\n",
       "    };\n",
       "\n",
       "    this.imageObj.onunload = function () {\n",
       "        fig.ws.close();\n",
       "    };\n",
       "\n",
       "    this.ws.onmessage = this._make_on_message_function(this);\n",
       "\n",
       "    this.ondownload = ondownload;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._init_header = function () {\n",
       "    var titlebar = document.createElement('div');\n",
       "    titlebar.classList =\n",
       "        'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
       "    var titletext = document.createElement('div');\n",
       "    titletext.classList = 'ui-dialog-title';\n",
       "    titletext.setAttribute(\n",
       "        'style',\n",
       "        'width: 100%; text-align: center; padding: 3px;'\n",
       "    );\n",
       "    titlebar.appendChild(titletext);\n",
       "    this.root.appendChild(titlebar);\n",
       "    this.header = titletext;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
       "\n",
       "mpl.figure.prototype._init_canvas = function () {\n",
       "    var fig = this;\n",
       "\n",
       "    var canvas_div = (this.canvas_div = document.createElement('div'));\n",
       "    canvas_div.setAttribute(\n",
       "        'style',\n",
       "        'border: 1px solid #ddd;' +\n",
       "            'box-sizing: content-box;' +\n",
       "            'clear: both;' +\n",
       "            'min-height: 1px;' +\n",
       "            'min-width: 1px;' +\n",
       "            'outline: 0;' +\n",
       "            'overflow: hidden;' +\n",
       "            'position: relative;' +\n",
       "            'resize: both;'\n",
       "    );\n",
       "\n",
       "    function on_keyboard_event_closure(name) {\n",
       "        return function (event) {\n",
       "            return fig.key_event(event, name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    canvas_div.addEventListener(\n",
       "        'keydown',\n",
       "        on_keyboard_event_closure('key_press')\n",
       "    );\n",
       "    canvas_div.addEventListener(\n",
       "        'keyup',\n",
       "        on_keyboard_event_closure('key_release')\n",
       "    );\n",
       "\n",
       "    this._canvas_extra_style(canvas_div);\n",
       "    this.root.appendChild(canvas_div);\n",
       "\n",
       "    var canvas = (this.canvas = document.createElement('canvas'));\n",
       "    canvas.classList.add('mpl-canvas');\n",
       "    canvas.setAttribute('style', 'box-sizing: content-box;');\n",
       "\n",
       "    this.context = canvas.getContext('2d');\n",
       "\n",
       "    var backingStore =\n",
       "        this.context.backingStorePixelRatio ||\n",
       "        this.context.webkitBackingStorePixelRatio ||\n",
       "        this.context.mozBackingStorePixelRatio ||\n",
       "        this.context.msBackingStorePixelRatio ||\n",
       "        this.context.oBackingStorePixelRatio ||\n",
       "        this.context.backingStorePixelRatio ||\n",
       "        1;\n",
       "\n",
       "    this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
       "\n",
       "    var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
       "        'canvas'\n",
       "    ));\n",
       "    rubberband_canvas.setAttribute(\n",
       "        'style',\n",
       "        'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
       "    );\n",
       "\n",
       "    // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
       "    if (this.ResizeObserver === undefined) {\n",
       "        if (window.ResizeObserver !== undefined) {\n",
       "            this.ResizeObserver = window.ResizeObserver;\n",
       "        } else {\n",
       "            var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
       "            this.ResizeObserver = obs.ResizeObserver;\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
       "        var nentries = entries.length;\n",
       "        for (var i = 0; i < nentries; i++) {\n",
       "            var entry = entries[i];\n",
       "            var width, height;\n",
       "            if (entry.contentBoxSize) {\n",
       "                if (entry.contentBoxSize instanceof Array) {\n",
       "                    // Chrome 84 implements new version of spec.\n",
       "                    width = entry.contentBoxSize[0].inlineSize;\n",
       "                    height = entry.contentBoxSize[0].blockSize;\n",
       "                } else {\n",
       "                    // Firefox implements old version of spec.\n",
       "                    width = entry.contentBoxSize.inlineSize;\n",
       "                    height = entry.contentBoxSize.blockSize;\n",
       "                }\n",
       "            } else {\n",
       "                // Chrome <84 implements even older version of spec.\n",
       "                width = entry.contentRect.width;\n",
       "                height = entry.contentRect.height;\n",
       "            }\n",
       "\n",
       "            // Keep the size of the canvas and rubber band canvas in sync with\n",
       "            // the canvas container.\n",
       "            if (entry.devicePixelContentBoxSize) {\n",
       "                // Chrome 84 implements new version of spec.\n",
       "                canvas.setAttribute(\n",
       "                    'width',\n",
       "                    entry.devicePixelContentBoxSize[0].inlineSize\n",
       "                );\n",
       "                canvas.setAttribute(\n",
       "                    'height',\n",
       "                    entry.devicePixelContentBoxSize[0].blockSize\n",
       "                );\n",
       "            } else {\n",
       "                canvas.setAttribute('width', width * fig.ratio);\n",
       "                canvas.setAttribute('height', height * fig.ratio);\n",
       "            }\n",
       "            canvas.setAttribute(\n",
       "                'style',\n",
       "                'width: ' + width + 'px; height: ' + height + 'px;'\n",
       "            );\n",
       "\n",
       "            rubberband_canvas.setAttribute('width', width);\n",
       "            rubberband_canvas.setAttribute('height', height);\n",
       "\n",
       "            // And update the size in Python. We ignore the initial 0/0 size\n",
       "            // that occurs as the element is placed into the DOM, which should\n",
       "            // otherwise not happen due to the minimum size styling.\n",
       "            if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
       "                fig.request_resize(width, height);\n",
       "            }\n",
       "        }\n",
       "    });\n",
       "    this.resizeObserverInstance.observe(canvas_div);\n",
       "\n",
       "    function on_mouse_event_closure(name) {\n",
       "        return function (event) {\n",
       "            return fig.mouse_event(event, name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mousedown',\n",
       "        on_mouse_event_closure('button_press')\n",
       "    );\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mouseup',\n",
       "        on_mouse_event_closure('button_release')\n",
       "    );\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'dblclick',\n",
       "        on_mouse_event_closure('dblclick')\n",
       "    );\n",
       "    // Throttle sequential mouse events to 1 every 20ms.\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mousemove',\n",
       "        on_mouse_event_closure('motion_notify')\n",
       "    );\n",
       "\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mouseenter',\n",
       "        on_mouse_event_closure('figure_enter')\n",
       "    );\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mouseleave',\n",
       "        on_mouse_event_closure('figure_leave')\n",
       "    );\n",
       "\n",
       "    canvas_div.addEventListener('wheel', function (event) {\n",
       "        if (event.deltaY < 0) {\n",
       "            event.step = 1;\n",
       "        } else {\n",
       "            event.step = -1;\n",
       "        }\n",
       "        on_mouse_event_closure('scroll')(event);\n",
       "    });\n",
       "\n",
       "    canvas_div.appendChild(canvas);\n",
       "    canvas_div.appendChild(rubberband_canvas);\n",
       "\n",
       "    this.rubberband_context = rubberband_canvas.getContext('2d');\n",
       "    this.rubberband_context.strokeStyle = '#000000';\n",
       "\n",
       "    this._resize_canvas = function (width, height, forward) {\n",
       "        if (forward) {\n",
       "            canvas_div.style.width = width + 'px';\n",
       "            canvas_div.style.height = height + 'px';\n",
       "        }\n",
       "    };\n",
       "\n",
       "    // Disable right mouse context menu.\n",
       "    this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
       "        event.preventDefault();\n",
       "        return false;\n",
       "    });\n",
       "\n",
       "    function set_focus() {\n",
       "        canvas.focus();\n",
       "        canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    window.setTimeout(set_focus, 100);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function () {\n",
       "    var fig = this;\n",
       "\n",
       "    var toolbar = document.createElement('div');\n",
       "    toolbar.classList = 'mpl-toolbar';\n",
       "    this.root.appendChild(toolbar);\n",
       "\n",
       "    function on_click_closure(name) {\n",
       "        return function (_event) {\n",
       "            return fig.toolbar_button_onclick(name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    function on_mouseover_closure(tooltip) {\n",
       "        return function (event) {\n",
       "            if (!event.currentTarget.disabled) {\n",
       "                return fig.toolbar_button_onmouseover(tooltip);\n",
       "            }\n",
       "        };\n",
       "    }\n",
       "\n",
       "    fig.buttons = {};\n",
       "    var buttonGroup = document.createElement('div');\n",
       "    buttonGroup.classList = 'mpl-button-group';\n",
       "    for (var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            /* Instead of a spacer, we start a new button group. */\n",
       "            if (buttonGroup.hasChildNodes()) {\n",
       "                toolbar.appendChild(buttonGroup);\n",
       "            }\n",
       "            buttonGroup = document.createElement('div');\n",
       "            buttonGroup.classList = 'mpl-button-group';\n",
       "            continue;\n",
       "        }\n",
       "\n",
       "        var button = (fig.buttons[name] = document.createElement('button'));\n",
       "        button.classList = 'mpl-widget';\n",
       "        button.setAttribute('role', 'button');\n",
       "        button.setAttribute('aria-disabled', 'false');\n",
       "        button.addEventListener('click', on_click_closure(method_name));\n",
       "        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
       "\n",
       "        var icon_img = document.createElement('img');\n",
       "        icon_img.src = '_images/' + image + '.png';\n",
       "        icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
       "        icon_img.alt = tooltip;\n",
       "        button.appendChild(icon_img);\n",
       "\n",
       "        buttonGroup.appendChild(button);\n",
       "    }\n",
       "\n",
       "    if (buttonGroup.hasChildNodes()) {\n",
       "        toolbar.appendChild(buttonGroup);\n",
       "    }\n",
       "\n",
       "    var fmt_picker = document.createElement('select');\n",
       "    fmt_picker.classList = 'mpl-widget';\n",
       "    toolbar.appendChild(fmt_picker);\n",
       "    this.format_dropdown = fmt_picker;\n",
       "\n",
       "    for (var ind in mpl.extensions) {\n",
       "        var fmt = mpl.extensions[ind];\n",
       "        var option = document.createElement('option');\n",
       "        option.selected = fmt === mpl.default_extension;\n",
       "        option.innerHTML = fmt;\n",
       "        fmt_picker.appendChild(option);\n",
       "    }\n",
       "\n",
       "    var status_bar = document.createElement('span');\n",
       "    status_bar.classList = 'mpl-message';\n",
       "    toolbar.appendChild(status_bar);\n",
       "    this.message = status_bar;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n",
       "    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
       "    // which will in turn request a refresh of the image.\n",
       "    this.send_message('resize', { width: x_pixels, height: y_pixels });\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.send_message = function (type, properties) {\n",
       "    properties['type'] = type;\n",
       "    properties['figure_id'] = this.id;\n",
       "    this.ws.send(JSON.stringify(properties));\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.send_draw_message = function () {\n",
       "    if (!this.waiting) {\n",
       "        this.waiting = true;\n",
       "        this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
       "    var format_dropdown = fig.format_dropdown;\n",
       "    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
       "    fig.ondownload(fig, format);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_resize = function (fig, msg) {\n",
       "    var size = msg['size'];\n",
       "    if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n",
       "        fig._resize_canvas(size[0], size[1], msg['forward']);\n",
       "        fig.send_message('refresh', {});\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
       "    var x0 = msg['x0'] / fig.ratio;\n",
       "    var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
       "    var x1 = msg['x1'] / fig.ratio;\n",
       "    var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n",
       "    x0 = Math.floor(x0) + 0.5;\n",
       "    y0 = Math.floor(y0) + 0.5;\n",
       "    x1 = Math.floor(x1) + 0.5;\n",
       "    y1 = Math.floor(y1) + 0.5;\n",
       "    var min_x = Math.min(x0, x1);\n",
       "    var min_y = Math.min(y0, y1);\n",
       "    var width = Math.abs(x1 - x0);\n",
       "    var height = Math.abs(y1 - y0);\n",
       "\n",
       "    fig.rubberband_context.clearRect(\n",
       "        0,\n",
       "        0,\n",
       "        fig.canvas.width / fig.ratio,\n",
       "        fig.canvas.height / fig.ratio\n",
       "    );\n",
       "\n",
       "    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n",
       "    // Updates the figure title.\n",
       "    fig.header.textContent = msg['label'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n",
       "    fig.rubberband_canvas.style.cursor = msg['cursor'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_message = function (fig, msg) {\n",
       "    fig.message.textContent = msg['message'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n",
       "    // Request the server to send over a new figure.\n",
       "    fig.send_draw_message();\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n",
       "    fig.image_mode = msg['mode'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n",
       "    for (var key in msg) {\n",
       "        if (!(key in fig.buttons)) {\n",
       "            continue;\n",
       "        }\n",
       "        fig.buttons[key].disabled = !msg[key];\n",
       "        fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
       "    if (msg['mode'] === 'PAN') {\n",
       "        fig.buttons['Pan'].classList.add('active');\n",
       "        fig.buttons['Zoom'].classList.remove('active');\n",
       "    } else if (msg['mode'] === 'ZOOM') {\n",
       "        fig.buttons['Pan'].classList.remove('active');\n",
       "        fig.buttons['Zoom'].classList.add('active');\n",
       "    } else {\n",
       "        fig.buttons['Pan'].classList.remove('active');\n",
       "        fig.buttons['Zoom'].classList.remove('active');\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function () {\n",
       "    // Called whenever the canvas gets updated.\n",
       "    this.send_message('ack', {});\n",
       "};\n",
       "\n",
       "// A function to construct a web socket function for onmessage handling.\n",
       "// Called in the figure constructor.\n",
       "mpl.figure.prototype._make_on_message_function = function (fig) {\n",
       "    return function socket_on_message(evt) {\n",
       "        if (evt.data instanceof Blob) {\n",
       "            var img = evt.data;\n",
       "            if (img.type !== 'image/png') {\n",
       "                /* FIXME: We get \"Resource interpreted as Image but\n",
       "                 * transferred with MIME type text/plain:\" errors on\n",
       "                 * Chrome.  But how to set the MIME type?  It doesn't seem\n",
       "                 * to be part of the websocket stream */\n",
       "                img.type = 'image/png';\n",
       "            }\n",
       "\n",
       "            /* Free the memory for the previous frames */\n",
       "            if (fig.imageObj.src) {\n",
       "                (window.URL || window.webkitURL).revokeObjectURL(\n",
       "                    fig.imageObj.src\n",
       "                );\n",
       "            }\n",
       "\n",
       "            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
       "                img\n",
       "            );\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        } else if (\n",
       "            typeof evt.data === 'string' &&\n",
       "            evt.data.slice(0, 21) === 'data:image/png;base64'\n",
       "        ) {\n",
       "            fig.imageObj.src = evt.data;\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        var msg = JSON.parse(evt.data);\n",
       "        var msg_type = msg['type'];\n",
       "\n",
       "        // Call the  \"handle_{type}\" callback, which takes\n",
       "        // the figure and JSON message as its only arguments.\n",
       "        try {\n",
       "            var callback = fig['handle_' + msg_type];\n",
       "        } catch (e) {\n",
       "            console.log(\n",
       "                \"No handler for the '\" + msg_type + \"' message type: \",\n",
       "                msg\n",
       "            );\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        if (callback) {\n",
       "            try {\n",
       "                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
       "                callback(fig, msg);\n",
       "            } catch (e) {\n",
       "                console.log(\n",
       "                    \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
       "                    e,\n",
       "                    e.stack,\n",
       "                    msg\n",
       "                );\n",
       "            }\n",
       "        }\n",
       "    };\n",
       "};\n",
       "\n",
       "// from https://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
       "mpl.findpos = function (e) {\n",
       "    //this section is from http://www.quirksmode.org/js/events_properties.html\n",
       "    var targ;\n",
       "    if (!e) {\n",
       "        e = window.event;\n",
       "    }\n",
       "    if (e.target) {\n",
       "        targ = e.target;\n",
       "    } else if (e.srcElement) {\n",
       "        targ = e.srcElement;\n",
       "    }\n",
       "    if (targ.nodeType === 3) {\n",
       "        // defeat Safari bug\n",
       "        targ = targ.parentNode;\n",
       "    }\n",
       "\n",
       "    // pageX,Y are the mouse positions relative to the document\n",
       "    var boundingRect = targ.getBoundingClientRect();\n",
       "    var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
       "    var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
       "\n",
       "    return { x: x, y: y };\n",
       "};\n",
       "\n",
       "/*\n",
       " * return a copy of an object with only non-object keys\n",
       " * we need this to avoid circular references\n",
       " * https://stackoverflow.com/a/24161582/3208463\n",
       " */\n",
       "function simpleKeys(original) {\n",
       "    return Object.keys(original).reduce(function (obj, key) {\n",
       "        if (typeof original[key] !== 'object') {\n",
       "            obj[key] = original[key];\n",
       "        }\n",
       "        return obj;\n",
       "    }, {});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.mouse_event = function (event, name) {\n",
       "    var canvas_pos = mpl.findpos(event);\n",
       "\n",
       "    if (name === 'button_press') {\n",
       "        this.canvas.focus();\n",
       "        this.canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    var x = canvas_pos.x * this.ratio;\n",
       "    var y = canvas_pos.y * this.ratio;\n",
       "\n",
       "    this.send_message(name, {\n",
       "        x: x,\n",
       "        y: y,\n",
       "        button: event.button,\n",
       "        step: event.step,\n",
       "        guiEvent: simpleKeys(event),\n",
       "    });\n",
       "\n",
       "    /* This prevents the web browser from automatically changing to\n",
       "     * the text insertion cursor when the button is pressed.  We want\n",
       "     * to control all of the cursor setting manually through the\n",
       "     * 'cursor' event from matplotlib */\n",
       "    event.preventDefault();\n",
       "    return false;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n",
       "    // Handle any extra behaviour associated with a key event\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.key_event = function (event, name) {\n",
       "    // Prevent repeat events\n",
       "    if (name === 'key_press') {\n",
       "        if (event.key === this._key) {\n",
       "            return;\n",
       "        } else {\n",
       "            this._key = event.key;\n",
       "        }\n",
       "    }\n",
       "    if (name === 'key_release') {\n",
       "        this._key = null;\n",
       "    }\n",
       "\n",
       "    var value = '';\n",
       "    if (event.ctrlKey && event.key !== 'Control') {\n",
       "        value += 'ctrl+';\n",
       "    }\n",
       "    else if (event.altKey && event.key !== 'Alt') {\n",
       "        value += 'alt+';\n",
       "    }\n",
       "    else if (event.shiftKey && event.key !== 'Shift') {\n",
       "        value += 'shift+';\n",
       "    }\n",
       "\n",
       "    value += 'k' + event.key;\n",
       "\n",
       "    this._key_event_extra(event, name);\n",
       "\n",
       "    this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n",
       "    return false;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n",
       "    if (name === 'download') {\n",
       "        this.handle_save(this, null);\n",
       "    } else {\n",
       "        this.send_message('toolbar_button', { name: name });\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n",
       "    this.message.textContent = tooltip;\n",
       "};\n",
       "\n",
       "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
       "// prettier-ignore\n",
       "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n",
       "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
       "\n",
       "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
       "\n",
       "mpl.default_extension = \"png\";/* global mpl */\n",
       "\n",
       "var comm_websocket_adapter = function (comm) {\n",
       "    // Create a \"websocket\"-like object which calls the given IPython comm\n",
       "    // object with the appropriate methods. Currently this is a non binary\n",
       "    // socket, so there is still some room for performance tuning.\n",
       "    var ws = {};\n",
       "\n",
       "    ws.binaryType = comm.kernel.ws.binaryType;\n",
       "    ws.readyState = comm.kernel.ws.readyState;\n",
       "    function updateReadyState(_event) {\n",
       "        if (comm.kernel.ws) {\n",
       "            ws.readyState = comm.kernel.ws.readyState;\n",
       "        } else {\n",
       "            ws.readyState = 3; // Closed state.\n",
       "        }\n",
       "    }\n",
       "    comm.kernel.ws.addEventListener('open', updateReadyState);\n",
       "    comm.kernel.ws.addEventListener('close', updateReadyState);\n",
       "    comm.kernel.ws.addEventListener('error', updateReadyState);\n",
       "\n",
       "    ws.close = function () {\n",
       "        comm.close();\n",
       "    };\n",
       "    ws.send = function (m) {\n",
       "        //console.log('sending', m);\n",
       "        comm.send(m);\n",
       "    };\n",
       "    // Register the callback with on_msg.\n",
       "    comm.on_msg(function (msg) {\n",
       "        //console.log('receiving', msg['content']['data'], msg);\n",
       "        var data = msg['content']['data'];\n",
       "        if (data['blob'] !== undefined) {\n",
       "            data = {\n",
       "                data: new Blob(msg['buffers'], { type: data['blob'] }),\n",
       "            };\n",
       "        }\n",
       "        // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
       "        ws.onmessage(data);\n",
       "    });\n",
       "    return ws;\n",
       "};\n",
       "\n",
       "mpl.mpl_figure_comm = function (comm, msg) {\n",
       "    // This is the function which gets called when the mpl process\n",
       "    // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
       "\n",
       "    var id = msg.content.data.id;\n",
       "    // Get hold of the div created by the display call when the Comm\n",
       "    // socket was opened in Python.\n",
       "    var element = document.getElementById(id);\n",
       "    var ws_proxy = comm_websocket_adapter(comm);\n",
       "\n",
       "    function ondownload(figure, _format) {\n",
       "        window.open(figure.canvas.toDataURL());\n",
       "    }\n",
       "\n",
       "    var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n",
       "\n",
       "    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
       "    // web socket which is closed, not our websocket->open comm proxy.\n",
       "    ws_proxy.onopen();\n",
       "\n",
       "    fig.parent_element = element;\n",
       "    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
       "    if (!fig.cell_info) {\n",
       "        console.error('Failed to find cell for figure', id, fig);\n",
       "        return;\n",
       "    }\n",
       "    fig.cell_info[0].output_area.element.on(\n",
       "        'cleared',\n",
       "        { fig: fig },\n",
       "        fig._remove_fig_handler\n",
       "    );\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
       "    var width = fig.canvas.width / fig.ratio;\n",
       "    fig.cell_info[0].output_area.element.off(\n",
       "        'cleared',\n",
       "        fig._remove_fig_handler\n",
       "    );\n",
       "    fig.resizeObserverInstance.unobserve(fig.canvas_div);\n",
       "\n",
       "    // Update the output cell to use the data from the current canvas.\n",
       "    fig.push_to_output();\n",
       "    var dataURL = fig.canvas.toDataURL();\n",
       "    // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
       "    // the notebook keyboard shortcuts fail.\n",
       "    IPython.keyboard_manager.enable();\n",
       "    fig.parent_element.innerHTML =\n",
       "        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "    fig.close_ws(fig, msg);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.close_ws = function (fig, msg) {\n",
       "    fig.send_message('closing', msg);\n",
       "    // fig.ws.close()\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n",
       "    // Turn the data on the canvas into data in the output cell.\n",
       "    var width = this.canvas.width / this.ratio;\n",
       "    var dataURL = this.canvas.toDataURL();\n",
       "    this.cell_info[1]['text/html'] =\n",
       "        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function () {\n",
       "    // Tell IPython that the notebook contents must change.\n",
       "    IPython.notebook.set_dirty(true);\n",
       "    this.send_message('ack', {});\n",
       "    var fig = this;\n",
       "    // Wait a second, then push the new image to the DOM so\n",
       "    // that it is saved nicely (might be nice to debounce this).\n",
       "    setTimeout(function () {\n",
       "        fig.push_to_output();\n",
       "    }, 1000);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function () {\n",
       "    var fig = this;\n",
       "\n",
       "    var toolbar = document.createElement('div');\n",
       "    toolbar.classList = 'btn-toolbar';\n",
       "    this.root.appendChild(toolbar);\n",
       "\n",
       "    function on_click_closure(name) {\n",
       "        return function (_event) {\n",
       "            return fig.toolbar_button_onclick(name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    function on_mouseover_closure(tooltip) {\n",
       "        return function (event) {\n",
       "            if (!event.currentTarget.disabled) {\n",
       "                return fig.toolbar_button_onmouseover(tooltip);\n",
       "            }\n",
       "        };\n",
       "    }\n",
       "\n",
       "    fig.buttons = {};\n",
       "    var buttonGroup = document.createElement('div');\n",
       "    buttonGroup.classList = 'btn-group';\n",
       "    var button;\n",
       "    for (var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            /* Instead of a spacer, we start a new button group. */\n",
       "            if (buttonGroup.hasChildNodes()) {\n",
       "                toolbar.appendChild(buttonGroup);\n",
       "            }\n",
       "            buttonGroup = document.createElement('div');\n",
       "            buttonGroup.classList = 'btn-group';\n",
       "            continue;\n",
       "        }\n",
       "\n",
       "        button = fig.buttons[name] = document.createElement('button');\n",
       "        button.classList = 'btn btn-default';\n",
       "        button.href = '#';\n",
       "        button.title = name;\n",
       "        button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n",
       "        button.addEventListener('click', on_click_closure(method_name));\n",
       "        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
       "        buttonGroup.appendChild(button);\n",
       "    }\n",
       "\n",
       "    if (buttonGroup.hasChildNodes()) {\n",
       "        toolbar.appendChild(buttonGroup);\n",
       "    }\n",
       "\n",
       "    // Add the status bar.\n",
       "    var status_bar = document.createElement('span');\n",
       "    status_bar.classList = 'mpl-message pull-right';\n",
       "    toolbar.appendChild(status_bar);\n",
       "    this.message = status_bar;\n",
       "\n",
       "    // Add the close button to the window.\n",
       "    var buttongrp = document.createElement('div');\n",
       "    buttongrp.classList = 'btn-group inline pull-right';\n",
       "    button = document.createElement('button');\n",
       "    button.classList = 'btn btn-mini btn-primary';\n",
       "    button.href = '#';\n",
       "    button.title = 'Stop Interaction';\n",
       "    button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n",
       "    button.addEventListener('click', function (_evt) {\n",
       "        fig.handle_close(fig, {});\n",
       "    });\n",
       "    button.addEventListener(\n",
       "        'mouseover',\n",
       "        on_mouseover_closure('Stop Interaction')\n",
       "    );\n",
       "    buttongrp.appendChild(button);\n",
       "    var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
       "    titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
       "    var fig = event.data.fig;\n",
       "    if (event.target !== this) {\n",
       "        // Ignore bubbled events from children.\n",
       "        return;\n",
       "    }\n",
       "    fig.close_ws(fig, {});\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function (el) {\n",
       "    el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
       "    // this is important to make the div 'focusable\n",
       "    el.setAttribute('tabindex', 0);\n",
       "    // reach out to IPython and tell the keyboard manager to turn it's self\n",
       "    // off when our div gets focus\n",
       "\n",
       "    // location in version 3\n",
       "    if (IPython.notebook.keyboard_manager) {\n",
       "        IPython.notebook.keyboard_manager.register_events(el);\n",
       "    } else {\n",
       "        // location in version 2\n",
       "        IPython.keyboard_manager.register_events(el);\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function (event, _name) {\n",
       "    // Check for shift+enter\n",
       "    if (event.shiftKey && event.which === 13) {\n",
       "        this.canvas_div.blur();\n",
       "        // select the cell after this one\n",
       "        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
       "        IPython.notebook.select(index + 1);\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
       "    fig.ondownload(fig, null);\n",
       "};\n",
       "\n",
       "mpl.find_output_cell = function (html_output) {\n",
       "    // Return the cell and output element which can be found *uniquely* in the notebook.\n",
       "    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
       "    // IPython event is triggered only after the cells have been serialised, which for\n",
       "    // our purposes (turning an active figure into a static one), is too late.\n",
       "    var cells = IPython.notebook.get_cells();\n",
       "    var ncells = cells.length;\n",
       "    for (var i = 0; i < ncells; i++) {\n",
       "        var cell = cells[i];\n",
       "        if (cell.cell_type === 'code') {\n",
       "            for (var j = 0; j < cell.output_area.outputs.length; j++) {\n",
       "                var data = cell.output_area.outputs[j];\n",
       "                if (data.data) {\n",
       "                    // IPython >= 3 moved mimebundle to data attribute of output\n",
       "                    data = data.data;\n",
       "                }\n",
       "                if (data['text/html'] === html_output) {\n",
       "                    return [cell, data, j];\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "};\n",
       "\n",
       "// Register the function which deals with the matplotlib target/channel.\n",
       "// The kernel may be null if the page has been refreshed.\n",
       "if (IPython.notebook.kernel !== null) {\n",
       "    IPython.notebook.kernel.comm_manager.register_target(\n",
       "        'matplotlib',\n",
       "        mpl.mpl_figure_comm\n",
       "    );\n",
       "}\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,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m2nVqlX03nvvUYcOHSg7O7vB19bV1dG1115LTzzxRIOv6d+/f0rHkUxuQM1m6W9Y0BU9Z6+ffz/Xr/sHlxc9xuV53+XHcR2DtxUAAECsgACMgAD0YgqYiOill1467Yjho48+Sj179mxwP0YAPST/xyzoit+w1y94kOtLTK/t/IfNqWKzfuyngrcVAABArIAAjIAAJGInkN69e9vqunbt2iQnkAEDBlCnTp0a3F9fX0833HADPfLII40+JhqQC8Tbd+NQe33BT7h+7etcnv9DLstI4JgLg7cVAABArED/HREBKGFghg4dSsXFxdS3b19q164dbd26lYiI+vXrRw8//LD1+rfffpsmTpxIpaWlVFpaSu+//z61b9+enntOTTe+8MILlJubS5s2baIVK1bQI488Qi1atKDFixc32i40IBeIU8e2cfb6hY9w/Zq/cHnut7m87LdmPMDzgrcVAABArED/HREBSMSBoDt16kStWrWibt260bx586x9vXr1oh49eljlt956i66++mpq27YttW/fnq6//np65513qK6uznpN3759qWPHjtSqVSu64IIL6I477khaZ3g60IBcMKkzC7pdc+31MtK3+iUuS2BocRoZ6S50DwAAAID+O0ICMB1BA3LBmE+woDtQZK9f/DjXr3qBy5IbeO2r/DiiXfC2AgAAiBXovyEAXYEG5ILR57Ggq1xrr7e8g5/ncm530yv4n2ZO4DbB2woAACBWoP+GAHQFGpALRn2cBV3VOnv9sj5cv+JZLk+5RqWGSxhE2S0CNxUAAEC8QP8NAeiKQBpQbY1/xw6Tke1NAegIvL38Ka4v/D2XJ17J5bKR/Jg4I3hbAQAAxAoIQAhAV/jegFb+mSinLdHB1f4cP0xGnM2C7vAme33hH7h++e+4PK4jlyummgLQIKqvSz4eAAAA0EggACEAXeF7AxIHiI3/8ef4YZJzlikAt9jri/7I9Uuf5PKYC7m8O08JwLiOigIAAAgECEAIQFf43oCmfSF1tow4MLw1n9uRMnu9lSP411weeS6X9y9XAvDkseDtBQAAEBsgACEAXeF7A5rURcXAixvDW/K5Hd1ur1/1Itcv/qX5OlMoVq1XAvDEoeDtBQAAEBsgACEAXeF7Axp3qTkd+oQ/xw+T7DP53I7tsNevHmimfnuUqL5eib6j29XzmgPh2AwAACAWQABC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MR0/frzap1N3FLu+Q4YMoauuusoZ06+//rrzGrm+8Vx55ZX0yCOP0PLly2nJkiV0zTXXUJ8+fejAgQPha2QMd54k11fGcP0gBmCdMWjQIBo6dKiz78ILL6Thw4fX6Iiyy4gRI+jiiy+OfC6Xy9FZZ51FI0eODPcdPnyYevXqRb/73e+qdYiZxjdQklzT9vZ2ampqopaWlvA1W7dupRNPPJGmTZtWvYPPAHEG4PXXXx/7Hrm+pbFr1y5SStGcOXOISMZwufGvL5GM4XpCDMA64siRI9SlSxcaP368s/+OO+6gyy67rEZHlV1GjBhBPXr0oLPPPpv69etHN954I61fv56IiNavX09KKVq8eLHzns9+9rP0ta99rRaHmzl8AyXJNZ05cyYppWjPnj3Oa97//vfTj3/848ofdIaIMwB79epFvXv3pve85z1066230s6dO8Pn5fqWxtq1a0kpRcuWLSMiGcPlxr++RDKG6wkxAOuIrVu3klKK5s+f7+y/99576YILLqjRUWWXqVOn0tixY2np0qU0ffp0Gjx4MJ155pm0e/dumj9/PimlaOvWrc57vvGNb9AVV1xRoyPOFr6BkuSaaq2pW7dueZ/16U9/mr75zW9W9oAzRpQB2NLSQlOmTKFly5bR448/ThdffDFddNFFYScFub7JyeVydN1119Gll14a7pMxXD6iri+RjOF6QgzAOgIG4IIFC5z999xzD/Xv379GR/XW4cCBA3TmmWfSr371q/BGv23bNuc1t956K1155ZU1OsJsEWcAFrqmcTf3yy+/nL71rW9V9oAzRpQB6LNt2zZqamqicePGEZFc31L49re/TX379nWKC2QMl4+o6xuFjOHaIQZgHSEh4Mpz+eWX09ChQyUEXAYkBFxZkhiARETnn39+mLMm1zcZt99+O5177rm0YcMGZ7+M4fIQd33jkDFcG8QArDMGDRpEt912m7NvwIABUgRSBg4fPkznnHMO3X333WGy9/333x8+f+TIESkCKYG4IpBC1xQJ3qNHjw5fs23bNknwjiCJAbh7927q3r07Pfroo0Qk17cYuVyOvvOd79A73/lOWrNmTeTzMoY7T7HrG4WM4dohBmCdARmYhx9+mFauXEl33nkn9ezZkzZt2lTrQ8scd911Fz3zzDO0YcMGev755+naa6+lU089NbyWI0eOpF69etH48eNp2bJl9OUvf1lkYIqwf/9+am1tpdbWVlJK0QMPPECtra2hTFGSazp06FA699xzacaMGbR48WL65Cc/KRIPAYWu7/79++muu+6iBQsW0MaNG2n27Nn00Y9+lM455xy5vgm57bbbqFevXvTMM884MiQHDx4MXyNjuPMUu74yhusLMQDrkAcffJD69u1L3bp1o4EDBzol9EJyoN/V1NRE73znO+kLX/gCrVixInwegq9nnXUWde/enS677DKnWk3IZ/bs2XkirkopGjJkCBElu6aHDh2i22+/nU4//XQ6+eST6dprr6UtW7bU4Gzqj0LX9+DBg3TFFVdQ7969qampifr06UNDhgzJu3ZyfeOJurZKKXrkkUfC18gY7jzFrq+M4fpCDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBkMMQEEQBEEQhAZDDEBBEARBEIQGQwxAQRAEQRCEBuP/A3xRUDiSWmprAAAAAElFTkSuQmCC\" width=\"640\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Key guess: (xored with) =  0x22\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "34"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "calc_mean_from_trace(trace_array, textin_array)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 257,
   "id": "34b48e29",
   "metadata": {},
   "outputs": [],
   "source": [
    "def calc_mean_from_trace_two_byte_key(traces, plaintexts):\n",
    "\n",
    "    best, second = calculate_correlations(traces, plaintexts, simple_speck, True, 0x00)\n",
    "    print(f\"[+] Highest Correlation: {hex(best[0])} ({best[1]}) and Second Highest: {hex(second[0])} ({second[1]})\")\n",
    "    sbest, ssecond = calculate_correlations(traces, plaintexts, simple_speck, False, best[0])\n",
    "    print(f\"[+] Highest Correlation: {hex(sbest[0])} ({sbest[1]}) and Second Highest: {hex(ssecond[0])} ({ssecond[1]})\")\n",
    "    \n",
    "    \n",
    "    return to16(best[0], sbest[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 274,
   "id": "12cba76a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[+] Highest Correlation: 0x22 (0.44124727149029996) and Second Highest: 0x23 (0.3891480233277513)\n",
      "[+] Highest Correlation: 0x11 (0.4679093960709849) and Second Highest: 0x13 (0.45557360024156474)\n"
     ]
    }
   ],
   "source": [
    "possible_firstkeys = calc_mean_from_trace_two_byte_key(trace_array, textin_array)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "655bc82e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[8723, 8721, 8979, 8977]\n"
     ]
    }
   ],
   "source": [
    "print(possible_firstkeys)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d48ec17d",
   "metadata": {},
   "source": [
    "## Testing the Paper Algos"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fa7f3aa",
   "metadata": {},
   "source": [
    "The two functions `PowerRightHalfKey` and `PowerLeftHalfKey` are implemented like described in the Paper \"Breaking Speck using CPA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 282,
   "id": "707816a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm import tnrange\n",
    "\n",
    "\n",
    "def get_first_keybyte(traces, plaintexts):\n",
    "\n",
    "    best, second = calculate_correlations(traces, plaintexts, PowerRightHalfKey, False, 0x00)\n",
    "    print(f\"[+] Highest Correlation: {hex(best[0])} ({best[1]}) and Second Highest: {hex(second[0])} ({second[1]})\")\n",
    "    sbest, ssecond = calculate_correlations(traces, plaintexts, PowerRightHalfKey, True, best[0])\n",
    "    print(f\"[+] Highest Correlation: {hex(sbest[0])} ({sbest[1]}) and Second Highest: {hex(ssecond[0])} ({ssecond[1]})\")\n",
    "    \n",
    "    print(f\"Key guess: (xored with) = \", hex(best[0]))\n",
    "    return to16(sbest[0], best[0])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 283,
   "id": "e5847cb2",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[+] Highest Correlation: 0x0 (0.842741706428846) and Second Highest: 0x4 (0.7583194127834111)\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_1178962/1194689348.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mget_first_keybyte\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtrace_array\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtextin_array\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m/tmp/ipykernel_1178962/3804549451.py\u001b[0m in \u001b[0;36mget_first_keybyte\u001b[0;34m(traces, plaintexts)\u001b[0m\n\u001b[1;32m      6\u001b[0m     \u001b[0mbest\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msecond\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcalculate_correlations\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtraces\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mplaintexts\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mPowerRightHalfKey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0x00\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m     \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"[+] Highest Correlation: {hex(best[0])} ({best[1]}) and Second Highest: {hex(second[0])} ({second[1]})\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m     \u001b[0msbest\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mssecond\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcalculate_correlations\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtraces\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mplaintexts\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mPowerRightHalfKey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbest\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      9\u001b[0m     \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"[+] Highest Correlation: {hex(sbest[0])} ({sbest[1]}) and Second Highest: {hex(ssecond[0])} ({ssecond[1]})\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/tmp/ipykernel_1178962/2789018864.py\u001b[0m in \u001b[0;36mcalculate_correlations\u001b[0;34m(traces, plaintexts, model_callback, leftmost, other_keybyte, argument)\u001b[0m\n\u001b[1;32m     21\u001b[0m         \u001b[0mhws_bar\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmean\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhws\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     22\u001b[0m         \u001b[0mo_hws\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstd_dev\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhws\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhws_bar\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 23\u001b[0;31m         \u001b[0mcorrelation\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcov\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtraces\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mt_bar\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhws\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhws_bar\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     24\u001b[0m         \u001b[0mcpaoutput\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcorrelation\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mo_t\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mo_hws\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     25\u001b[0m         \u001b[0mmaxcpa\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmax\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mabs\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcpaoutput\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/tmp/ipykernel_1178962/218278146.py\u001b[0m in \u001b[0;36mcov\u001b[0;34m(X, X_bar, Y, Y_bar)\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcov\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mX_bar\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mY\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mY_bar\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0mX_bar\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mY\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0mY_bar\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mto16\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbyte1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbyte2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "get_first_keybyte(trace_array, textin_array)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 177,
   "id": "5d269b9c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm import tnrange\n",
    "\n",
    "\n",
    "def get_keybytel(traces):\n",
    "\n",
    "    maxcpa = [0] * 256\n",
    "\n",
    "    t_bar = mean(traces) \n",
    "    o_t = std_dev(traces, t_bar)\n",
    "\n",
    "    for key in range(0, 256):\n",
    "        \n",
    "        hws = np.array([[speck_keyschedule(textin, (0x00 << 8) + key, [0x2211, 0x00dd, 0xa8dc]) for textin in textin_array]]).transpose()\n",
    "        \n",
    "        # The following line works for a one byte key\n",
    "        #hws = np.array([[simple_speck(textin, key) for textin in textin_array]]).transpose()\n",
    "        \n",
    "\n",
    "        hws_bar = mean(hws)\n",
    "        o_hws = std_dev(hws, hws_bar)\n",
    "        correlation = cov(traces, t_bar, hws, hws_bar)\n",
    "        cpaoutput = correlation/(o_t*o_hws)\n",
    "        maxcpa[key] = max(abs(cpaoutput))\n",
    "    \n",
    "    plt.figure()\n",
    "    plt.plot(maxcpa, 'orange')\n",
    "    plt.show()\n",
    "    guess = np.argmax(maxcpa)\n",
    "    second = np.argsort(maxcpa, axis=0)[-2]\n",
    "    print(f\"Key guess: (xored with) = \", hex(guess))\n",
    "    return maxcpa\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 179,
   "id": "2f80bf9c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "/* Put everything inside the global mpl namespace */\n",
       "/* global mpl */\n",
       "window.mpl = {};\n",
       "\n",
       "mpl.get_websocket_type = function () {\n",
       "    if (typeof WebSocket !== 'undefined') {\n",
       "        return WebSocket;\n",
       "    } else if (typeof MozWebSocket !== 'undefined') {\n",
       "        return MozWebSocket;\n",
       "    } else {\n",
       "        alert(\n",
       "            'Your browser does not have WebSocket support. ' +\n",
       "                'Please try Chrome, Safari or Firefox ā‰„ 6. ' +\n",
       "                'Firefox 4 and 5 are also supported but you ' +\n",
       "                'have to enable WebSockets in about:config.'\n",
       "        );\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n",
       "    this.id = figure_id;\n",
       "\n",
       "    this.ws = websocket;\n",
       "\n",
       "    this.supports_binary = this.ws.binaryType !== undefined;\n",
       "\n",
       "    if (!this.supports_binary) {\n",
       "        var warnings = document.getElementById('mpl-warnings');\n",
       "        if (warnings) {\n",
       "            warnings.style.display = 'block';\n",
       "            warnings.textContent =\n",
       "                'This browser does not support binary websocket messages. ' +\n",
       "                'Performance may be slow.';\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.imageObj = new Image();\n",
       "\n",
       "    this.context = undefined;\n",
       "    this.message = undefined;\n",
       "    this.canvas = undefined;\n",
       "    this.rubberband_canvas = undefined;\n",
       "    this.rubberband_context = undefined;\n",
       "    this.format_dropdown = undefined;\n",
       "\n",
       "    this.image_mode = 'full';\n",
       "\n",
       "    this.root = document.createElement('div');\n",
       "    this.root.setAttribute('style', 'display: inline-block');\n",
       "    this._root_extra_style(this.root);\n",
       "\n",
       "    parent_element.appendChild(this.root);\n",
       "\n",
       "    this._init_header(this);\n",
       "    this._init_canvas(this);\n",
       "    this._init_toolbar(this);\n",
       "\n",
       "    var fig = this;\n",
       "\n",
       "    this.waiting = false;\n",
       "\n",
       "    this.ws.onopen = function () {\n",
       "        fig.send_message('supports_binary', { value: fig.supports_binary });\n",
       "        fig.send_message('send_image_mode', {});\n",
       "        if (fig.ratio !== 1) {\n",
       "            fig.send_message('set_device_pixel_ratio', {\n",
       "                device_pixel_ratio: fig.ratio,\n",
       "            });\n",
       "        }\n",
       "        fig.send_message('refresh', {});\n",
       "    };\n",
       "\n",
       "    this.imageObj.onload = function () {\n",
       "        if (fig.image_mode === 'full') {\n",
       "            // Full images could contain transparency (where diff images\n",
       "            // almost always do), so we need to clear the canvas so that\n",
       "            // there is no ghosting.\n",
       "            fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
       "        }\n",
       "        fig.context.drawImage(fig.imageObj, 0, 0);\n",
       "    };\n",
       "\n",
       "    this.imageObj.onunload = function () {\n",
       "        fig.ws.close();\n",
       "    };\n",
       "\n",
       "    this.ws.onmessage = this._make_on_message_function(this);\n",
       "\n",
       "    this.ondownload = ondownload;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._init_header = function () {\n",
       "    var titlebar = document.createElement('div');\n",
       "    titlebar.classList =\n",
       "        'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
       "    var titletext = document.createElement('div');\n",
       "    titletext.classList = 'ui-dialog-title';\n",
       "    titletext.setAttribute(\n",
       "        'style',\n",
       "        'width: 100%; text-align: center; padding: 3px;'\n",
       "    );\n",
       "    titlebar.appendChild(titletext);\n",
       "    this.root.appendChild(titlebar);\n",
       "    this.header = titletext;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
       "\n",
       "mpl.figure.prototype._init_canvas = function () {\n",
       "    var fig = this;\n",
       "\n",
       "    var canvas_div = (this.canvas_div = document.createElement('div'));\n",
       "    canvas_div.setAttribute(\n",
       "        'style',\n",
       "        'border: 1px solid #ddd;' +\n",
       "            'box-sizing: content-box;' +\n",
       "            'clear: both;' +\n",
       "            'min-height: 1px;' +\n",
       "            'min-width: 1px;' +\n",
       "            'outline: 0;' +\n",
       "            'overflow: hidden;' +\n",
       "            'position: relative;' +\n",
       "            'resize: both;'\n",
       "    );\n",
       "\n",
       "    function on_keyboard_event_closure(name) {\n",
       "        return function (event) {\n",
       "            return fig.key_event(event, name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    canvas_div.addEventListener(\n",
       "        'keydown',\n",
       "        on_keyboard_event_closure('key_press')\n",
       "    );\n",
       "    canvas_div.addEventListener(\n",
       "        'keyup',\n",
       "        on_keyboard_event_closure('key_release')\n",
       "    );\n",
       "\n",
       "    this._canvas_extra_style(canvas_div);\n",
       "    this.root.appendChild(canvas_div);\n",
       "\n",
       "    var canvas = (this.canvas = document.createElement('canvas'));\n",
       "    canvas.classList.add('mpl-canvas');\n",
       "    canvas.setAttribute('style', 'box-sizing: content-box;');\n",
       "\n",
       "    this.context = canvas.getContext('2d');\n",
       "\n",
       "    var backingStore =\n",
       "        this.context.backingStorePixelRatio ||\n",
       "        this.context.webkitBackingStorePixelRatio ||\n",
       "        this.context.mozBackingStorePixelRatio ||\n",
       "        this.context.msBackingStorePixelRatio ||\n",
       "        this.context.oBackingStorePixelRatio ||\n",
       "        this.context.backingStorePixelRatio ||\n",
       "        1;\n",
       "\n",
       "    this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
       "\n",
       "    var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
       "        'canvas'\n",
       "    ));\n",
       "    rubberband_canvas.setAttribute(\n",
       "        'style',\n",
       "        'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
       "    );\n",
       "\n",
       "    // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
       "    if (this.ResizeObserver === undefined) {\n",
       "        if (window.ResizeObserver !== undefined) {\n",
       "            this.ResizeObserver = window.ResizeObserver;\n",
       "        } else {\n",
       "            var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
       "            this.ResizeObserver = obs.ResizeObserver;\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
       "        var nentries = entries.length;\n",
       "        for (var i = 0; i < nentries; i++) {\n",
       "            var entry = entries[i];\n",
       "            var width, height;\n",
       "            if (entry.contentBoxSize) {\n",
       "                if (entry.contentBoxSize instanceof Array) {\n",
       "                    // Chrome 84 implements new version of spec.\n",
       "                    width = entry.contentBoxSize[0].inlineSize;\n",
       "                    height = entry.contentBoxSize[0].blockSize;\n",
       "                } else {\n",
       "                    // Firefox implements old version of spec.\n",
       "                    width = entry.contentBoxSize.inlineSize;\n",
       "                    height = entry.contentBoxSize.blockSize;\n",
       "                }\n",
       "            } else {\n",
       "                // Chrome <84 implements even older version of spec.\n",
       "                width = entry.contentRect.width;\n",
       "                height = entry.contentRect.height;\n",
       "            }\n",
       "\n",
       "            // Keep the size of the canvas and rubber band canvas in sync with\n",
       "            // the canvas container.\n",
       "            if (entry.devicePixelContentBoxSize) {\n",
       "                // Chrome 84 implements new version of spec.\n",
       "                canvas.setAttribute(\n",
       "                    'width',\n",
       "                    entry.devicePixelContentBoxSize[0].inlineSize\n",
       "                );\n",
       "                canvas.setAttribute(\n",
       "                    'height',\n",
       "                    entry.devicePixelContentBoxSize[0].blockSize\n",
       "                );\n",
       "            } else {\n",
       "                canvas.setAttribute('width', width * fig.ratio);\n",
       "                canvas.setAttribute('height', height * fig.ratio);\n",
       "            }\n",
       "            canvas.setAttribute(\n",
       "                'style',\n",
       "                'width: ' + width + 'px; height: ' + height + 'px;'\n",
       "            );\n",
       "\n",
       "            rubberband_canvas.setAttribute('width', width);\n",
       "            rubberband_canvas.setAttribute('height', height);\n",
       "\n",
       "            // And update the size in Python. We ignore the initial 0/0 size\n",
       "            // that occurs as the element is placed into the DOM, which should\n",
       "            // otherwise not happen due to the minimum size styling.\n",
       "            if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
       "                fig.request_resize(width, height);\n",
       "            }\n",
       "        }\n",
       "    });\n",
       "    this.resizeObserverInstance.observe(canvas_div);\n",
       "\n",
       "    function on_mouse_event_closure(name) {\n",
       "        return function (event) {\n",
       "            return fig.mouse_event(event, name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mousedown',\n",
       "        on_mouse_event_closure('button_press')\n",
       "    );\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mouseup',\n",
       "        on_mouse_event_closure('button_release')\n",
       "    );\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'dblclick',\n",
       "        on_mouse_event_closure('dblclick')\n",
       "    );\n",
       "    // Throttle sequential mouse events to 1 every 20ms.\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mousemove',\n",
       "        on_mouse_event_closure('motion_notify')\n",
       "    );\n",
       "\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mouseenter',\n",
       "        on_mouse_event_closure('figure_enter')\n",
       "    );\n",
       "    rubberband_canvas.addEventListener(\n",
       "        'mouseleave',\n",
       "        on_mouse_event_closure('figure_leave')\n",
       "    );\n",
       "\n",
       "    canvas_div.addEventListener('wheel', function (event) {\n",
       "        if (event.deltaY < 0) {\n",
       "            event.step = 1;\n",
       "        } else {\n",
       "            event.step = -1;\n",
       "        }\n",
       "        on_mouse_event_closure('scroll')(event);\n",
       "    });\n",
       "\n",
       "    canvas_div.appendChild(canvas);\n",
       "    canvas_div.appendChild(rubberband_canvas);\n",
       "\n",
       "    this.rubberband_context = rubberband_canvas.getContext('2d');\n",
       "    this.rubberband_context.strokeStyle = '#000000';\n",
       "\n",
       "    this._resize_canvas = function (width, height, forward) {\n",
       "        if (forward) {\n",
       "            canvas_div.style.width = width + 'px';\n",
       "            canvas_div.style.height = height + 'px';\n",
       "        }\n",
       "    };\n",
       "\n",
       "    // Disable right mouse context menu.\n",
       "    this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
       "        event.preventDefault();\n",
       "        return false;\n",
       "    });\n",
       "\n",
       "    function set_focus() {\n",
       "        canvas.focus();\n",
       "        canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    window.setTimeout(set_focus, 100);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function () {\n",
       "    var fig = this;\n",
       "\n",
       "    var toolbar = document.createElement('div');\n",
       "    toolbar.classList = 'mpl-toolbar';\n",
       "    this.root.appendChild(toolbar);\n",
       "\n",
       "    function on_click_closure(name) {\n",
       "        return function (_event) {\n",
       "            return fig.toolbar_button_onclick(name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    function on_mouseover_closure(tooltip) {\n",
       "        return function (event) {\n",
       "            if (!event.currentTarget.disabled) {\n",
       "                return fig.toolbar_button_onmouseover(tooltip);\n",
       "            }\n",
       "        };\n",
       "    }\n",
       "\n",
       "    fig.buttons = {};\n",
       "    var buttonGroup = document.createElement('div');\n",
       "    buttonGroup.classList = 'mpl-button-group';\n",
       "    for (var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            /* Instead of a spacer, we start a new button group. */\n",
       "            if (buttonGroup.hasChildNodes()) {\n",
       "                toolbar.appendChild(buttonGroup);\n",
       "            }\n",
       "            buttonGroup = document.createElement('div');\n",
       "            buttonGroup.classList = 'mpl-button-group';\n",
       "            continue;\n",
       "        }\n",
       "\n",
       "        var button = (fig.buttons[name] = document.createElement('button'));\n",
       "        button.classList = 'mpl-widget';\n",
       "        button.setAttribute('role', 'button');\n",
       "        button.setAttribute('aria-disabled', 'false');\n",
       "        button.addEventListener('click', on_click_closure(method_name));\n",
       "        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
       "\n",
       "        var icon_img = document.createElement('img');\n",
       "        icon_img.src = '_images/' + image + '.png';\n",
       "        icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
       "        icon_img.alt = tooltip;\n",
       "        button.appendChild(icon_img);\n",
       "\n",
       "        buttonGroup.appendChild(button);\n",
       "    }\n",
       "\n",
       "    if (buttonGroup.hasChildNodes()) {\n",
       "        toolbar.appendChild(buttonGroup);\n",
       "    }\n",
       "\n",
       "    var fmt_picker = document.createElement('select');\n",
       "    fmt_picker.classList = 'mpl-widget';\n",
       "    toolbar.appendChild(fmt_picker);\n",
       "    this.format_dropdown = fmt_picker;\n",
       "\n",
       "    for (var ind in mpl.extensions) {\n",
       "        var fmt = mpl.extensions[ind];\n",
       "        var option = document.createElement('option');\n",
       "        option.selected = fmt === mpl.default_extension;\n",
       "        option.innerHTML = fmt;\n",
       "        fmt_picker.appendChild(option);\n",
       "    }\n",
       "\n",
       "    var status_bar = document.createElement('span');\n",
       "    status_bar.classList = 'mpl-message';\n",
       "    toolbar.appendChild(status_bar);\n",
       "    this.message = status_bar;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n",
       "    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
       "    // which will in turn request a refresh of the image.\n",
       "    this.send_message('resize', { width: x_pixels, height: y_pixels });\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.send_message = function (type, properties) {\n",
       "    properties['type'] = type;\n",
       "    properties['figure_id'] = this.id;\n",
       "    this.ws.send(JSON.stringify(properties));\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.send_draw_message = function () {\n",
       "    if (!this.waiting) {\n",
       "        this.waiting = true;\n",
       "        this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
       "    var format_dropdown = fig.format_dropdown;\n",
       "    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
       "    fig.ondownload(fig, format);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_resize = function (fig, msg) {\n",
       "    var size = msg['size'];\n",
       "    if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n",
       "        fig._resize_canvas(size[0], size[1], msg['forward']);\n",
       "        fig.send_message('refresh', {});\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
       "    var x0 = msg['x0'] / fig.ratio;\n",
       "    var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
       "    var x1 = msg['x1'] / fig.ratio;\n",
       "    var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n",
       "    x0 = Math.floor(x0) + 0.5;\n",
       "    y0 = Math.floor(y0) + 0.5;\n",
       "    x1 = Math.floor(x1) + 0.5;\n",
       "    y1 = Math.floor(y1) + 0.5;\n",
       "    var min_x = Math.min(x0, x1);\n",
       "    var min_y = Math.min(y0, y1);\n",
       "    var width = Math.abs(x1 - x0);\n",
       "    var height = Math.abs(y1 - y0);\n",
       "\n",
       "    fig.rubberband_context.clearRect(\n",
       "        0,\n",
       "        0,\n",
       "        fig.canvas.width / fig.ratio,\n",
       "        fig.canvas.height / fig.ratio\n",
       "    );\n",
       "\n",
       "    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n",
       "    // Updates the figure title.\n",
       "    fig.header.textContent = msg['label'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n",
       "    fig.rubberband_canvas.style.cursor = msg['cursor'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_message = function (fig, msg) {\n",
       "    fig.message.textContent = msg['message'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n",
       "    // Request the server to send over a new figure.\n",
       "    fig.send_draw_message();\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n",
       "    fig.image_mode = msg['mode'];\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n",
       "    for (var key in msg) {\n",
       "        if (!(key in fig.buttons)) {\n",
       "            continue;\n",
       "        }\n",
       "        fig.buttons[key].disabled = !msg[key];\n",
       "        fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
       "    if (msg['mode'] === 'PAN') {\n",
       "        fig.buttons['Pan'].classList.add('active');\n",
       "        fig.buttons['Zoom'].classList.remove('active');\n",
       "    } else if (msg['mode'] === 'ZOOM') {\n",
       "        fig.buttons['Pan'].classList.remove('active');\n",
       "        fig.buttons['Zoom'].classList.add('active');\n",
       "    } else {\n",
       "        fig.buttons['Pan'].classList.remove('active');\n",
       "        fig.buttons['Zoom'].classList.remove('active');\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function () {\n",
       "    // Called whenever the canvas gets updated.\n",
       "    this.send_message('ack', {});\n",
       "};\n",
       "\n",
       "// A function to construct a web socket function for onmessage handling.\n",
       "// Called in the figure constructor.\n",
       "mpl.figure.prototype._make_on_message_function = function (fig) {\n",
       "    return function socket_on_message(evt) {\n",
       "        if (evt.data instanceof Blob) {\n",
       "            var img = evt.data;\n",
       "            if (img.type !== 'image/png') {\n",
       "                /* FIXME: We get \"Resource interpreted as Image but\n",
       "                 * transferred with MIME type text/plain:\" errors on\n",
       "                 * Chrome.  But how to set the MIME type?  It doesn't seem\n",
       "                 * to be part of the websocket stream */\n",
       "                img.type = 'image/png';\n",
       "            }\n",
       "\n",
       "            /* Free the memory for the previous frames */\n",
       "            if (fig.imageObj.src) {\n",
       "                (window.URL || window.webkitURL).revokeObjectURL(\n",
       "                    fig.imageObj.src\n",
       "                );\n",
       "            }\n",
       "\n",
       "            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
       "                img\n",
       "            );\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        } else if (\n",
       "            typeof evt.data === 'string' &&\n",
       "            evt.data.slice(0, 21) === 'data:image/png;base64'\n",
       "        ) {\n",
       "            fig.imageObj.src = evt.data;\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        var msg = JSON.parse(evt.data);\n",
       "        var msg_type = msg['type'];\n",
       "\n",
       "        // Call the  \"handle_{type}\" callback, which takes\n",
       "        // the figure and JSON message as its only arguments.\n",
       "        try {\n",
       "            var callback = fig['handle_' + msg_type];\n",
       "        } catch (e) {\n",
       "            console.log(\n",
       "                \"No handler for the '\" + msg_type + \"' message type: \",\n",
       "                msg\n",
       "            );\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        if (callback) {\n",
       "            try {\n",
       "                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
       "                callback(fig, msg);\n",
       "            } catch (e) {\n",
       "                console.log(\n",
       "                    \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
       "                    e,\n",
       "                    e.stack,\n",
       "                    msg\n",
       "                );\n",
       "            }\n",
       "        }\n",
       "    };\n",
       "};\n",
       "\n",
       "// from https://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
       "mpl.findpos = function (e) {\n",
       "    //this section is from http://www.quirksmode.org/js/events_properties.html\n",
       "    var targ;\n",
       "    if (!e) {\n",
       "        e = window.event;\n",
       "    }\n",
       "    if (e.target) {\n",
       "        targ = e.target;\n",
       "    } else if (e.srcElement) {\n",
       "        targ = e.srcElement;\n",
       "    }\n",
       "    if (targ.nodeType === 3) {\n",
       "        // defeat Safari bug\n",
       "        targ = targ.parentNode;\n",
       "    }\n",
       "\n",
       "    // pageX,Y are the mouse positions relative to the document\n",
       "    var boundingRect = targ.getBoundingClientRect();\n",
       "    var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
       "    var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
       "\n",
       "    return { x: x, y: y };\n",
       "};\n",
       "\n",
       "/*\n",
       " * return a copy of an object with only non-object keys\n",
       " * we need this to avoid circular references\n",
       " * https://stackoverflow.com/a/24161582/3208463\n",
       " */\n",
       "function simpleKeys(original) {\n",
       "    return Object.keys(original).reduce(function (obj, key) {\n",
       "        if (typeof original[key] !== 'object') {\n",
       "            obj[key] = original[key];\n",
       "        }\n",
       "        return obj;\n",
       "    }, {});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.mouse_event = function (event, name) {\n",
       "    var canvas_pos = mpl.findpos(event);\n",
       "\n",
       "    if (name === 'button_press') {\n",
       "        this.canvas.focus();\n",
       "        this.canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    var x = canvas_pos.x * this.ratio;\n",
       "    var y = canvas_pos.y * this.ratio;\n",
       "\n",
       "    this.send_message(name, {\n",
       "        x: x,\n",
       "        y: y,\n",
       "        button: event.button,\n",
       "        step: event.step,\n",
       "        guiEvent: simpleKeys(event),\n",
       "    });\n",
       "\n",
       "    /* This prevents the web browser from automatically changing to\n",
       "     * the text insertion cursor when the button is pressed.  We want\n",
       "     * to control all of the cursor setting manually through the\n",
       "     * 'cursor' event from matplotlib */\n",
       "    event.preventDefault();\n",
       "    return false;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n",
       "    // Handle any extra behaviour associated with a key event\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.key_event = function (event, name) {\n",
       "    // Prevent repeat events\n",
       "    if (name === 'key_press') {\n",
       "        if (event.key === this._key) {\n",
       "            return;\n",
       "        } else {\n",
       "            this._key = event.key;\n",
       "        }\n",
       "    }\n",
       "    if (name === 'key_release') {\n",
       "        this._key = null;\n",
       "    }\n",
       "\n",
       "    var value = '';\n",
       "    if (event.ctrlKey && event.key !== 'Control') {\n",
       "        value += 'ctrl+';\n",
       "    }\n",
       "    else if (event.altKey && event.key !== 'Alt') {\n",
       "        value += 'alt+';\n",
       "    }\n",
       "    else if (event.shiftKey && event.key !== 'Shift') {\n",
       "        value += 'shift+';\n",
       "    }\n",
       "\n",
       "    value += 'k' + event.key;\n",
       "\n",
       "    this._key_event_extra(event, name);\n",
       "\n",
       "    this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n",
       "    return false;\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n",
       "    if (name === 'download') {\n",
       "        this.handle_save(this, null);\n",
       "    } else {\n",
       "        this.send_message('toolbar_button', { name: name });\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n",
       "    this.message.textContent = tooltip;\n",
       "};\n",
       "\n",
       "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
       "// prettier-ignore\n",
       "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n",
       "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
       "\n",
       "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
       "\n",
       "mpl.default_extension = \"png\";/* global mpl */\n",
       "\n",
       "var comm_websocket_adapter = function (comm) {\n",
       "    // Create a \"websocket\"-like object which calls the given IPython comm\n",
       "    // object with the appropriate methods. Currently this is a non binary\n",
       "    // socket, so there is still some room for performance tuning.\n",
       "    var ws = {};\n",
       "\n",
       "    ws.binaryType = comm.kernel.ws.binaryType;\n",
       "    ws.readyState = comm.kernel.ws.readyState;\n",
       "    function updateReadyState(_event) {\n",
       "        if (comm.kernel.ws) {\n",
       "            ws.readyState = comm.kernel.ws.readyState;\n",
       "        } else {\n",
       "            ws.readyState = 3; // Closed state.\n",
       "        }\n",
       "    }\n",
       "    comm.kernel.ws.addEventListener('open', updateReadyState);\n",
       "    comm.kernel.ws.addEventListener('close', updateReadyState);\n",
       "    comm.kernel.ws.addEventListener('error', updateReadyState);\n",
       "\n",
       "    ws.close = function () {\n",
       "        comm.close();\n",
       "    };\n",
       "    ws.send = function (m) {\n",
       "        //console.log('sending', m);\n",
       "        comm.send(m);\n",
       "    };\n",
       "    // Register the callback with on_msg.\n",
       "    comm.on_msg(function (msg) {\n",
       "        //console.log('receiving', msg['content']['data'], msg);\n",
       "        var data = msg['content']['data'];\n",
       "        if (data['blob'] !== undefined) {\n",
       "            data = {\n",
       "                data: new Blob(msg['buffers'], { type: data['blob'] }),\n",
       "            };\n",
       "        }\n",
       "        // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
       "        ws.onmessage(data);\n",
       "    });\n",
       "    return ws;\n",
       "};\n",
       "\n",
       "mpl.mpl_figure_comm = function (comm, msg) {\n",
       "    // This is the function which gets called when the mpl process\n",
       "    // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
       "\n",
       "    var id = msg.content.data.id;\n",
       "    // Get hold of the div created by the display call when the Comm\n",
       "    // socket was opened in Python.\n",
       "    var element = document.getElementById(id);\n",
       "    var ws_proxy = comm_websocket_adapter(comm);\n",
       "\n",
       "    function ondownload(figure, _format) {\n",
       "        window.open(figure.canvas.toDataURL());\n",
       "    }\n",
       "\n",
       "    var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n",
       "\n",
       "    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
       "    // web socket which is closed, not our websocket->open comm proxy.\n",
       "    ws_proxy.onopen();\n",
       "\n",
       "    fig.parent_element = element;\n",
       "    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
       "    if (!fig.cell_info) {\n",
       "        console.error('Failed to find cell for figure', id, fig);\n",
       "        return;\n",
       "    }\n",
       "    fig.cell_info[0].output_area.element.on(\n",
       "        'cleared',\n",
       "        { fig: fig },\n",
       "        fig._remove_fig_handler\n",
       "    );\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
       "    var width = fig.canvas.width / fig.ratio;\n",
       "    fig.cell_info[0].output_area.element.off(\n",
       "        'cleared',\n",
       "        fig._remove_fig_handler\n",
       "    );\n",
       "    fig.resizeObserverInstance.unobserve(fig.canvas_div);\n",
       "\n",
       "    // Update the output cell to use the data from the current canvas.\n",
       "    fig.push_to_output();\n",
       "    var dataURL = fig.canvas.toDataURL();\n",
       "    // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
       "    // the notebook keyboard shortcuts fail.\n",
       "    IPython.keyboard_manager.enable();\n",
       "    fig.parent_element.innerHTML =\n",
       "        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "    fig.close_ws(fig, msg);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.close_ws = function (fig, msg) {\n",
       "    fig.send_message('closing', msg);\n",
       "    // fig.ws.close()\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n",
       "    // Turn the data on the canvas into data in the output cell.\n",
       "    var width = this.canvas.width / this.ratio;\n",
       "    var dataURL = this.canvas.toDataURL();\n",
       "    this.cell_info[1]['text/html'] =\n",
       "        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function () {\n",
       "    // Tell IPython that the notebook contents must change.\n",
       "    IPython.notebook.set_dirty(true);\n",
       "    this.send_message('ack', {});\n",
       "    var fig = this;\n",
       "    // Wait a second, then push the new image to the DOM so\n",
       "    // that it is saved nicely (might be nice to debounce this).\n",
       "    setTimeout(function () {\n",
       "        fig.push_to_output();\n",
       "    }, 1000);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function () {\n",
       "    var fig = this;\n",
       "\n",
       "    var toolbar = document.createElement('div');\n",
       "    toolbar.classList = 'btn-toolbar';\n",
       "    this.root.appendChild(toolbar);\n",
       "\n",
       "    function on_click_closure(name) {\n",
       "        return function (_event) {\n",
       "            return fig.toolbar_button_onclick(name);\n",
       "        };\n",
       "    }\n",
       "\n",
       "    function on_mouseover_closure(tooltip) {\n",
       "        return function (event) {\n",
       "            if (!event.currentTarget.disabled) {\n",
       "                return fig.toolbar_button_onmouseover(tooltip);\n",
       "            }\n",
       "        };\n",
       "    }\n",
       "\n",
       "    fig.buttons = {};\n",
       "    var buttonGroup = document.createElement('div');\n",
       "    buttonGroup.classList = 'btn-group';\n",
       "    var button;\n",
       "    for (var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            /* Instead of a spacer, we start a new button group. */\n",
       "            if (buttonGroup.hasChildNodes()) {\n",
       "                toolbar.appendChild(buttonGroup);\n",
       "            }\n",
       "            buttonGroup = document.createElement('div');\n",
       "            buttonGroup.classList = 'btn-group';\n",
       "            continue;\n",
       "        }\n",
       "\n",
       "        button = fig.buttons[name] = document.createElement('button');\n",
       "        button.classList = 'btn btn-default';\n",
       "        button.href = '#';\n",
       "        button.title = name;\n",
       "        button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n",
       "        button.addEventListener('click', on_click_closure(method_name));\n",
       "        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
       "        buttonGroup.appendChild(button);\n",
       "    }\n",
       "\n",
       "    if (buttonGroup.hasChildNodes()) {\n",
       "        toolbar.appendChild(buttonGroup);\n",
       "    }\n",
       "\n",
       "    // Add the status bar.\n",
       "    var status_bar = document.createElement('span');\n",
       "    status_bar.classList = 'mpl-message pull-right';\n",
       "    toolbar.appendChild(status_bar);\n",
       "    this.message = status_bar;\n",
       "\n",
       "    // Add the close button to the window.\n",
       "    var buttongrp = document.createElement('div');\n",
       "    buttongrp.classList = 'btn-group inline pull-right';\n",
       "    button = document.createElement('button');\n",
       "    button.classList = 'btn btn-mini btn-primary';\n",
       "    button.href = '#';\n",
       "    button.title = 'Stop Interaction';\n",
       "    button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n",
       "    button.addEventListener('click', function (_evt) {\n",
       "        fig.handle_close(fig, {});\n",
       "    });\n",
       "    button.addEventListener(\n",
       "        'mouseover',\n",
       "        on_mouseover_closure('Stop Interaction')\n",
       "    );\n",
       "    buttongrp.appendChild(button);\n",
       "    var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
       "    titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
       "    var fig = event.data.fig;\n",
       "    if (event.target !== this) {\n",
       "        // Ignore bubbled events from children.\n",
       "        return;\n",
       "    }\n",
       "    fig.close_ws(fig, {});\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function (el) {\n",
       "    el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
       "    // this is important to make the div 'focusable\n",
       "    el.setAttribute('tabindex', 0);\n",
       "    // reach out to IPython and tell the keyboard manager to turn it's self\n",
       "    // off when our div gets focus\n",
       "\n",
       "    // location in version 3\n",
       "    if (IPython.notebook.keyboard_manager) {\n",
       "        IPython.notebook.keyboard_manager.register_events(el);\n",
       "    } else {\n",
       "        // location in version 2\n",
       "        IPython.keyboard_manager.register_events(el);\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function (event, _name) {\n",
       "    // Check for shift+enter\n",
       "    if (event.shiftKey && event.which === 13) {\n",
       "        this.canvas_div.blur();\n",
       "        // select the cell after this one\n",
       "        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
       "        IPython.notebook.select(index + 1);\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
       "    fig.ondownload(fig, null);\n",
       "};\n",
       "\n",
       "mpl.find_output_cell = function (html_output) {\n",
       "    // Return the cell and output element which can be found *uniquely* in the notebook.\n",
       "    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
       "    // IPython event is triggered only after the cells have been serialised, which for\n",
       "    // our purposes (turning an active figure into a static one), is too late.\n",
       "    var cells = IPython.notebook.get_cells();\n",
       "    var ncells = cells.length;\n",
       "    for (var i = 0; i < ncells; i++) {\n",
       "        var cell = cells[i];\n",
       "        if (cell.cell_type === 'code') {\n",
       "            for (var j = 0; j < cell.output_area.outputs.length; j++) {\n",
       "                var data = cell.output_area.outputs[j];\n",
       "                if (data.data) {\n",
       "                    // IPython >= 3 moved mimebundle to data attribute of output\n",
       "                    data = data.data;\n",
       "                }\n",
       "                if (data['text/html'] === html_output) {\n",
       "                    return [cell, data, j];\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "};\n",
       "\n",
       "// Register the function which deals with the matplotlib target/channel.\n",
       "// The kernel may be null if the page has been refreshed.\n",
       "if (IPython.notebook.kernel !== null) {\n",
       "    IPython.notebook.kernel.comm_manager.register_target(\n",
       "        'matplotlib',\n",
       "        mpl.mpl_figure_comm\n",
       "    );\n",
       "}\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,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\" width=\"640\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Key guess: (xored with) =  0x9c\n"
     ]
    }
   ],
   "source": [
    "cpa2 = get_keybytel(trace_array)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b805e3bd",
   "metadata": {},
   "source": [
    "## The following functions receives a new roundkey"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "129dffd3",
   "metadata": {},
   "source": [
    "This function takes an array of previous roundkeys and try to find the next roundkey"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 279,
   "id": "61faac51",
   "metadata": {},
   "outputs": [],
   "source": [
    "def recv_roundkey(traces, plaintexts, roundkeys):\n",
    "\n",
    "    best, second = calculate_correlations(traces, plaintexts, speck_keyschedule, False, 0x00, roundkeys)\n",
    "    print(f\"[+] Highest Correlation: {hex(best[0])} ({best[1]}) and Second Highest: {hex(second[0])} ({second[1]})\")\n",
    "    sbest, ssecond = calculate_correlations(traces, plaintexts, speck_keyschedule, True, best[0], roundkeys)\n",
    "    print(f\"[+] Highest Correlation: {hex(sbest[0])} ({sbest[1]}) and Second Highest: {hex(ssecond[0])} ({ssecond[1]})\")\n",
    "    \n",
    "    return to16(sbest[0], best[0])\n",
    "    \n",
    "\n",
    "'''\n",
    "    This seems to work most reliable (currently, only one byte is wrong....)\n",
    "'''\n",
    "def recv_roundkey_two(traces, plaintexts, roundkeys):\n",
    "    best, second = calculate_correlations(traces, plaintexts, PowerLeftHalfKeyII, False, 0x00, roundkeys)\n",
    "    print(f\"[+] Highest Correlation: {hex(best[0])} ({best[1]}) and Second Highest: {hex(second[0])} ({second[1]})\")\n",
    "    sbest, ssecond = calculate_correlations(traces, plaintexts, PowerLeftHalfKeyII, True, best[0], roundkeys)\n",
    "    print(f\"[+] Highest Correlation: {hex(sbest[0])} ({sbest[1]}) and Second Highest: {hex(ssecond[0])} ({ssecond[1]})\")\n",
    "    \n",
    "    return to16(sbest[0], best[0])\n",
    "    \n",
    "       "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b05c56c",
   "metadata": {},
   "source": [
    "## Get the required number of round keys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 224,
   "id": "e8c265cd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[+] Highest Correlation: 0xdd (0.9206360077704052) and Second Highest: 0xdf (0.8617017477055349)\n",
      "[+] Highest Correlation: 0x0 (0.7652890259706173) and Second Highest: 0x2 (0.6657780592680524)\n",
      "0xdd00\n"
     ]
    }
   ],
   "source": [
    "a = recv_roundkey_two(trace_array, textin_array, [0x2211])\n",
    "print(hex(a))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 231,
   "id": "b10cb530",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_roundkey(traces, firstkey):\n",
    "    initial_key = [firstkey]\n",
    "    \n",
    "    for i in range(4):\n",
    "        next_rk = recv_roundkey_two(traces, textin_array, initial_key)    \n",
    "        initial_key.append(next_rk)\n",
    "    print([hex(k) for k in initial_key])\n",
    "    return initial_key"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 278,
   "id": "03eb0704",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_key_from_roundkey(roundkey):\n",
    "    if len(roundkey) != 5:\n",
    "        raise Exception(\"Wrong length of roundkey\")\n",
    "    key = [roundkey[0]]\n",
    "    for i in range(4):\n",
    "        for keybyte in range(2**16):\n",
    "            _, out = ER16(keybyte, known_keys[i], i)\n",
    "            if out == roundkey[i+1]:\n",
    "                key.append(keybyte)\n",
    "                print(f\"Found: {hex(keybyte)}\")\n",
    "    return [hex(k) for k in key]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 284,
   "id": "e095746f",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[+] Highest Correlation: 0xdd (0.9278200457894269) and Second Highest: 0xdf (0.8631820447413402)\n",
      "[+] Highest Correlation: 0x0 (0.9278200457894269) and Second Highest: 0x1 (0.8126688581419583)\n",
      "[+] Highest Correlation: 0xdc (0.5462925024514341) and Second Highest: 0xd8 (0.48516519669326075)\n",
      "[+] Highest Correlation: 0xa8 (0.8432509671276792) and Second Highest: 0x88 (0.7925942806028411)\n",
      "[+] Highest Correlation: 0x9c (0.6194829714625257) and Second Highest: 0xdc (0.5587442317020618)\n",
      "[+] Highest Correlation: 0x34 (0.7935821344924826) and Second Highest: 0x14 (0.7829382954252116)\n",
      "[+] Highest Correlation: 0x21 (0.48675689201334293) and Second Highest: 0xde (0.43080062755434895)\n",
      "[+] Highest Correlation: 0x4a (0.8508098840188391) and Second Highest: 0x6a (0.8267326599115615)\n",
      "['0x2211', '0xdd', '0xa8dc', '0x349c', '0x4a21']\n"
     ]
    }
   ],
   "source": [
    "\n",
    "rk = get_roundkey(trace_array, int(0x2211))  # get the roundkeys, based on the first roundkey"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 276,
   "id": "4e03294a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# These are the roundkeys that __should__ be there for the key\n",
    "known_keys = [0x2211, 0x00dd, 0xa8dc, 0x349c, 0xb5de]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 277,
   "id": "17125a64",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found: 0x4433\n",
      "Found: 0x6655\n",
      "Found: 0x8877\n",
      "Found: 0x8899\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "['0x2211', '0x4433', '0x6655', '0x8877', '0x8899']"
      ]
     },
     "execution_count": 277,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_key_from_roundkey(known_keys)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 242,
   "id": "f50a9b00",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found: 0x4433\n",
      "Found: 0x6655\n",
      "Found: 0x8877\n",
      "Found: 0xdb31\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "['0x2211', '0x4433', '0x6655', '0x8877', '0xdb31']"
      ]
     },
     "execution_count": 242,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_key_from_roundkey([8721, 221, 43228, 13468, 18977])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "83d085f6",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5969b0b2",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "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.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}