aboutsummaryrefslogtreecommitdiffhomepage
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Measurement\n",
    "\n",
    "This notebook showcases how to use **pyecsca** to generate and measure an ECC implementation.\n",
    "This example use the ChipWhisperer-Lite board, along with the UFO target board (with an `STM32F3` target on top)\n",
    "and a PicoScope 5000 oscilloscope to measure."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Oscilloscope setup\n",
    "\n",
    "First we will setup the scope. Channel `A` will be used for the power signal, so we\n",
    "connect the `MEASURE` SMA plug (on the UFO board) to the scope `A` input via an SMA-BNC cable. Channel\n",
    "`B` will be used for the trigger, so we connect a probe to `TP2` point on the UFO board and connect it\n",
    "to input `B` on the scope. \n",
    "\n",
    "![measurement setup](img/measurement_setup.jpg)\n",
    "\n",
    "Next we connect to the scope and display its identifier."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyecsca.sca.scope.picoscope_sdk import PS6000Scope\n",
    "\n",
    "scope = PS6000Scope()\n",
    "scope.open()\n",
    "print(scope.get_variant())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then we setup the channels, `A` in AC coupling with 0.2 Volt range, `B` in DC coupling with 5 Volt range."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.setup_channel(channel=\"A\", coupling=\"AC\", range=0.2, offset=0.0, enable=True)\n",
    "scope.setup_channel(channel=\"B\", coupling=\"DC\", range=5.0, offset=0.0, enable=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then we set the frequency and amount of samples. We set 6.4 MHz and 16M samples,\n",
    "which should lead to a 3 second capture time (which should cover the long scalar multiplication operation on the chip ~ 2.8s)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "actual_frequency, samples = scope.setup_frequency(frequency=6_400_000, pretrig=500_000, posttrig=15_500_000)\n",
    "print(actual_frequency, samples)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we setup the trigger on channel `B`. We also set channel `A` as the channel to capture. In this example we also capture the `B` channel to showcase the dynamic triggering capabilities."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.setup_trigger(channel=\"B\", threshold=0.5, direction=\"rising\", delay=0, timeout=5000, enable=True)\n",
    "scope.setup_capture(channel=\"A\", enable=True)\n",
    "scope.setup_capture(channel=\"B\", enable=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Device setup\n",
    "\n",
    "The `STM32F3` UFO target board is used next, we now will generate and build an ECC implementation.\n",
    "\n",
    "![measurement ufo](img/measurement_ufo.jpg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tempfile\n",
    "\n",
    "from os.path import join\n",
    "from pyecsca.codegen.common import Platform, DeviceConfiguration\n",
    "from pyecsca.codegen.render import render_and_build\n",
    "from pyecsca.ec.model import ShortWeierstrassModel\n",
    "from pyecsca.ec.mult import LTRMultiplier\n",
    "from pyecsca.ec.configuration import *\n",
    "\n",
    "platform = Platform.STM32F3\n",
    "hash_type = HashType.SHA1\n",
    "mod_rand = RandomMod.REDUCE\n",
    "mult = Multiplication.BASE\n",
    "sqr = Squaring.BASE\n",
    "red = Reduction.BARRETT\n",
    "inv = Inversion.EULER\n",
    "\n",
    "model = ShortWeierstrassModel()\n",
    "coords = model.coordinates[\"projective\"]\n",
    "add = coords.formulas[\"add-1998-cmo\"]\n",
    "dbl = coords.formulas[\"dbl-1998-cmo\"]\n",
    "formulas = [add, dbl]\n",
    "scalarmult = LTRMultiplier(add, dbl)\n",
    "\n",
    "config = DeviceConfiguration(model, coords, formulas, scalarmult, \n",
    "                             hash_type, mod_rand, mult, sqr, red,\n",
    "                             inv, platform, True, True, True)\n",
    "\n",
    "tmpdir = tempfile.TemporaryDirectory()\n",
    "directory, elf_file, hex_file, res = render_and_build(config, tmpdir.name)\n",
    "fw = join(tmpdir.name, hex_file)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we will create a target and flash the implementation on it.\n",
    "The target constructor requires to know some parameters of the configuration,\n",
    "to be able to communicate with it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyecsca.codegen.client import DeviceTarget\n",
    "\n",
    "target = DeviceTarget(model=config.model, coords=config.coords, platform=config.platform, timeout=10000)\n",
    "target.flash(fw)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Measurement\n",
    "\n",
    "We can now connect to the target, arm the scope and generate a keypair on the target while measuring it,\n",
    "then collect the trace."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from time import sleep, time\n",
    "from pyecsca.codegen.client import Triggers\n",
    "from pyecsca.sca.trace import Trace\n",
    "from pyecsca.sca.scope import SampleType\n",
    "from pyecsca.ec.params import get_params\n",
    "params = get_params(\"secg\", \"secp128r1\", \"projective\")\n",
    "\n",
    "print(\"Connect\")\n",
    "target.connect()\n",
    "print(\"Set parameters\")\n",
    "target.set_params(params)\n",
    "print(\"Set trigger\")\n",
    "target.set_trigger(Triggers.keygen)\n",
    "print(\"Init PRNG\")\n",
    "target.init_prng(b\"\\x12\\x23\")\n",
    "\n",
    "print(\"ARM scope\")\n",
    "scope.arm()\n",
    "sleep(5)\n",
    "start = time()\n",
    "priv, pub = target.generate()\n",
    "end = time()\n",
    "print(end - start)\n",
    "scope.capture(10000)\n",
    "\n",
    "print(\"Retrieve\")\n",
    "trace = scope.retrieve(\"A\", SampleType.Volt)\n",
    "trig = scope.retrieve(\"B\", SampleType.Volt)\n",
    "\n",
    "print(\"Disconnect\")\n",
    "target.disconnect()\n",
    "\n",
    "print(priv)\n",
    "print(pub)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After all measurements are done, we disconnect from the scope. And delete the directory\n",
    "with the firmware."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "target.scope.dis()\n",
    "scope.close()\n",
    "tmpdir.cleanup()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Visualization\n",
    "\n",
    "We will now visualize the trace."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyecsca.sca.trace.plot import plot_traces\n",
    "import holoviews as hv\n",
    "\n",
    "hv.extension(\"bokeh\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_traces(trace, trig).opts(width=950, height=600)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "@webio": {
   "lastCommId": "57001c30f0b44a2b8c6e1ed2455e6df9",
   "lastKernelId": "c41aa10d-5e94-483e-a64d-be40efd99bcc"
  },
  "hide_input": false,
  "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.10.9"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}