{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Code generation\n", "\n", "**pyecsca** can generate C implementations of ECC crypto for several microprocessor targets, which\n", "are defined by the `Platform` enum." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pyecsca.codegen.common import Platform\n", "\n", "\n", "Platform.names()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To generate an implementation we need an actual configuration which the implementation should\n", "implement, which is stored inside the `Configuration` and `DeviceConfiguration` classes. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from typing import get_args\n", "from pyecsca.codegen.common import DeviceConfiguration\n", "from dataclasses import fields\n", "\n", "for field in fields(DeviceConfiguration):\n", "\tname = field.name\n", "\ttp = field.type\n", "\tdoc = tp.__doc__\n", "\tif get_args(field.type):\n", "\t\tdoc = get_args(field.type)[0].__doc__\n", "\tif tp == bool:\n", "\t\tdoc = \"\"\n", "\tprint(name, tp)\n", "\tprint(\" \", doc)\n", "\tif hasattr(tp, \"names\"):\n", "\t\tfor enum_name in tp.names():\n", "\t\t\tprint(\" \", enum_name)\n", "\tprint()\n", "()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `DeviceConfiguration` class contains a few additional attributes apart from those\n", "in the `Configuration` class: `platform`, `keygen`, `ecdh` and `ecdsa`.\n", "\n", "The `platform` attribute defines for which target the implementation\n", "should be built. The other boolean attributes specify whether particular\n", "functionality should be implemented and enabled in the implementation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Generating\n", "\n", "We will first create a `DeviceConfiguration`, which we will then generate and build." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "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.BASE\n", "inv = Inversion.GCD\n", "\n", "model = ShortWeierstrassModel()\n", "coords = model.coordinates[\"projective\"]\n", "add = coords.formulas[\"add-1998-cmo\"]\n", "dbl = coords.formulas[\"dbl-1998-cmo\"]\n", "scl = coords.formulas[\"z\"]\n", "formulas = [add, dbl, scl]\n", "scalarmult = LTRMultiplier(add, dbl, scl)\n", "\n", "config = DeviceConfiguration(model, coords, formulas, scalarmult, \n", "\t\t\t\t\t\t\t hash_type, mod_rand, mult, sqr, red,\n", "\t\t\t\t\t\t\t inv, platform, True, True, True)\n", "\n", "config" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can render the configuration, which will generate the source files into a\n", "randomly created temporary directory, and return the path to the directory as\n", "well as names of the elf and hex files which will be built in that directory." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pyecsca.codegen.builder import render\n", "\n", "directory, elf_name, hex_name = render(config)\n", "\n", "print(directory)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Building\n", "\n", "When we have the implementation rendered, we can build it using make." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from subprocess import run\n", "\n", "res = run([\"make\"], cwd=directory, capture_output=True)\n", "print(res.stdout.decode())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now the files `elf_name` and `hex_name` in the directory contain the ELF file and HEX file built.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "res = run([\"file\", elf_name], cwd=directory, capture_output=True)\n", "print(res.stdout.decode())\n", "\n", "res = run([\"file\", hex_name], cwd=directory, capture_output=True)\n", "print(res.stdout.decode())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running\n", "\n", "We will now run key generation using the generated implementation on\n", "the `STM32F3` target." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pyecsca.codegen.client import DeviceTarget\n", "from pyecsca.ec.params import get_params\n", "\n", "params = get_params(\"secg\", \"secp128r1\", \"projective\")\n", "target = DeviceTarget(params.curve.model, params.curve.coordinate_model, Platform.STM32F3, timeout=10000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Flash the implementation." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from os.path import join\n", "\n", "target.flash(join(directory, hex_name))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Run the key generation." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "target.connect()\n", "target.set_params(params)\n", "priv, pub = target.generate()\n", "target.disconnect()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we can check that the generated keypair is valid." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(params.curve.is_on_curve(pub))\n", "\n", "print(priv)\n", "print(pub)\n", "print(params.curve.affine_multiply(params.generator.to_affine(), priv))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running on the host\n", "\n", "We can also run the implementation on the host." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "config = DeviceConfiguration(model, coords, formulas, scalarmult, \n", "\t\t\t\t\t\t\t hash_type, mod_rand, mult, sqr, red,\n", "\t\t\t\t\t\t\t inv, Platform.HOST, True, True, True)\n", "\n", "directory, elf_name, hex_name = render(config)\n", "res = run([\"make\"], cwd=directory, capture_output=True)\n", "print(res.stdout.decode())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pyecsca.codegen.client import HostTarget\n", "from os.path import join\n", "\n", "target = HostTarget(params.curve.model, params.curve.coordinate_model, binary=join(directory, elf_name))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "target.connect()\n", "target.set_params(params)\n", "priv, pub = target.generate()\n", "target.disconnect()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(params.curve.is_on_curve(pub))\n", "\n", "print(priv)\n", "print(pub)\n", "print(params.curve.affine_multiply(params.generator.to_affine(), priv))" ] } ], "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.10.8" }, "pycharm": { "stem_cell": { "cell_type": "raw", "metadata": { "collapsed": false }, "source": [] } } }, "nbformat": 4, "nbformat_minor": 4 }