diff options
| author | Andrej Bátora | 2023-04-08 18:08:06 +0200 |
|---|---|---|
| committer | GitHub | 2023-04-08 18:08:06 +0200 |
| commit | 75a8b9349890668099cb4ac296eb52f20e931b24 (patch) | |
| tree | ec2f73375de48c20905600d3361160588b9707a4 | |
| parent | e2acae5b7e0d5ff0a0c35189ddb67d404ca6716d (diff) | |
| parent | 0eb176e35702a87470f642bc4cc1158c61c66961 (diff) | |
| download | pyecsca-codegen-75a8b9349890668099cb4ac296eb52f20e931b24.tar.gz pyecsca-codegen-75a8b9349890668099cb4ac296eb52f20e931b24.tar.zst pyecsca-codegen-75a8b9349890668099cb4ac296eb52f20e931b24.zip | |
Merge branch 'J08nY:master' into feat/simulator
| -rw-r--r-- | .coveragerc | 1 | ||||
| -rw-r--r-- | .github/workflows/test.yml | 54 | ||||
| -rw-r--r-- | .travis.yml | 37 | ||||
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | docs/INSTALL.md | 16 | ||||
| -rw-r--r-- | docs/install.rst | 16 | ||||
| -rw-r--r-- | pyecsca/codegen/render.py | 42 | ||||
| -rw-r--r-- | pyecsca/codegen/templates/action.c | 6 | ||||
| -rw-r--r-- | pyecsca/codegen/templates/main.c | 3 | ||||
| -rw-r--r-- | pyecsca/codegen/templates/ops.c | 6 | ||||
| -rw-r--r-- | pyecsca/codegen/templates/point.c | 6 | ||||
| -rw-r--r-- | test/test_impl.py | 9 |
12 files changed, 126 insertions, 76 deletions
diff --git a/.coveragerc b/.coveragerc index 33d3f05..52944ef 100644 --- a/.coveragerc +++ b/.coveragerc @@ -5,6 +5,7 @@ omit = setup.py pyecsca/codegen/templates/* ext/pyecsca/* + pyecsca-upstream/* [report] exclude_lines = diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..82ccd60 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,54 @@ +name: Test + +on: [push, pull_request] + +env: + LLVM_CONFIG: /usr/bin/llvm-config-10 + OTHER_PACKAGES: swig gcc libpcsclite-dev llvm-10 libllvm10 llvm-10-dev + +jobs: + test: + runs-on: ubuntu-20.04 + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10"] + env: + PYTHON: ${{ matrix.python-version }} + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: pip-${{ runner.os }}-${{ matrix.gmp }}-${{ matrix.python-version }}-${{ hashFiles('setup.py') }} + restore-keys: | + pip-${{ runner.os }}-${{ matrix.gmp }}-${{ matrix.python-version }}- + pip-${{ runner.os }}-${{ matrix.gmp }}- + pip-${{ runner.os }}- + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y $OTHER_PACKAGES + - name: Build libtommath + run: | + cd ext && make host && cd .. + - name: Install dependencies + run: | + pip install -U pip setuptools wheel + - name: Install pyecsca + run: | + git clone https://github.com/J08nY/pyecsca pyecsca-upstream && cd pyecsca-upstream && git submodule update --init && pip install -e ".[chipwhisperer, test, dev]" && cd .. + - name: Install pyecsca-codegen + run: | + pip install -e ".[test, dev]" + - name: Test + run: | + make test + - name: Code coverage + uses: codecov/codecov-action@v3 + if: ${{ matrix.python-version == 3.9 }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b6f64c8..0000000 --- a/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -os: linux -language: python -dist: focal -python: - - "3.8" - - "3.9" - -addons: - apt: - packages: - - swig - - gcc - - llvm-10 - - libllvm10 - - llvm-10-dev - -env: - - LLVM_CONFIG=/usr/bin/llvm-config-10 - -install: - - pip install codecov - - cd ext/ - - make host - - git clone https://github.com/J08nY/pyecsca - - cd pyecsca/ - - git submodule update --init --recursive - - pip install -e ".[chipwhisperer]" - - cd ../.. - - pip install -e ".[test, dev]" - -script: - - make -i typecheck - - make -i codestyle - - make test - -after_success: - - codecov @@ -1,18 +1,18 @@ # pyecsca-codegen -[](https://travis-ci.com/J08nY/pyecsca-codegen)  [](https://codecov.io/gh/J08nY/pyecsca-codegen) +[](https://github.com/J08nY/pyecsca-codegen/actions/workflows/test.yml)  [](https://codecov.io/gh/J08nY/pyecsca-codegen) **Py**thon **E**lliptic **C**urve cryptography **S**ide-**C**hannel **A**nalysis toolkit. Codegen package. See the [main repo](https://github.com/J08nY/pyecsca) for more information. -See [INSTALL](docs/INSTALL.md) for installation instructions. +See [INSTALL](docs/install.rst) for installation instructions. ## License MIT License - Copyright (c) 2018-2020 Jan Jancar + Copyright (c) 2018-2023 Jan Jancar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/INSTALL.md b/docs/INSTALL.md deleted file mode 100644 index 7533529..0000000 --- a/docs/INSTALL.md +++ /dev/null @@ -1,16 +0,0 @@ -# Installation - -This assumes that both *pyecsca* and the *pyecsca-codegen* -packages are installed as editable. - -1. Checkout the ext/libtommath submodule: -`git submodule update --init` -2. Build the libtommath library to prepare it for the future -build processes steps. -``` -cd ext -make host stm32f0 stm32f3 -``` - -Now the package should be ready with the necessary versions of -libtommath built for the host and the STM32F0 and F3 targets. diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 0000000..dbff34f --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,16 @@ +============ +Installation +============ + +This assumes that both **pyecsca** and the **pyecsca-codegen** +packages are installed as editable. + +1. Checkout the ext/libtommath submodule: :code:`git submodule update --init` +2. Build the libtommath library to prepare it for the future build processes steps. + +.. code-block:: shell + cd ext + make host stm32f0 stm32f3 + +Now the package should be ready with the necessary versions of +libtommath built for the host and the STM32F0 and F3 targets. diff --git a/pyecsca/codegen/render.py b/pyecsca/codegen/render.py index d4d1d7f..19d395f 100644 --- a/pyecsca/codegen/render.py +++ b/pyecsca/codegen/render.py @@ -2,7 +2,6 @@ import os import shutil import subprocess import tempfile -from _ast import Pow from os import path from os import makedirs from typing import Optional, List, Set, Mapping, MutableMapping, Any, Tuple @@ -82,6 +81,13 @@ def render_curve_impl(model: CurveModel) -> str: def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], renames: Mapping[str, str] = None) -> MutableMapping[Any, Any]: + """ + Transform a list of CodeOps, parameters, outputs and renames into a mapping + that will be used by the ops template macros to render the ops. + + This tracks allocations and frees, also creates a mapping of constants + to variable names. + """ def rename(name: str): if renames is not None and name not in outputs: return renames.get(name, name) @@ -92,6 +98,11 @@ def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], const_mapping = {} operations = [] frees = [] + # Go over the ops, track allocations needed for intermediates and constants. + # There are two kinds of constants, encoded and not-encoded. The encoded + # ones are default, the non-encoded ones are only in the exponents, where + # you don't want to encode using the reduction object (i.e. Montgomery form). + # Also constructs a mapping from raw constants to their variable names. for op in ops: if op.result not in allocations: allocations.append(op.result) @@ -100,23 +111,32 @@ def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], if param not in allocations and param not in parameters: raise ValueError("Should be allocated or parameter: {}".format(param)) for const in op.constants: - name = "c" + str(const) + if op.operator == OpType.Pow: + name = "cu" + str(const) + encode = False + else: + name = "c" + str(const) + encode = True if name not in allocations: allocations.append(name) - initializations[name] = const - const_mapping[const] = name + initializations[name] = (const, encode) + const_mapping[(const, encode)] = name frees.append(name) operations.append((op.operator, op.result, rename(op.left), rename(op.right))) mapped = [] + # Go over the operations and map constants to their variable names, + # make sure the encoded/non-encoded version is used where appropriate. for op in operations: o2 = op[2] - if o2 in const_mapping: - o2 = const_mapping[o2] + if (o2, True) in const_mapping: + o2 = const_mapping[(o2, True)] o3 = op[3] - if o3 in const_mapping and not (isinstance(op[0], Pow) and o3 == 2): - o3 = const_mapping[o3] + o3_enc = op[0] != OpType.Pow + if (o3, o3_enc) in const_mapping: + o3 = const_mapping[(o3, o3_enc)] mapped.append((op[0], op[1], o2, o3)) returns = {} + # Handle renames in the returns. if renames: for r_from, r_to in renames.items(): if r_from in outputs: @@ -128,12 +148,6 @@ def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], frees=frees, returns=returns) -def render_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], - renames: Mapping[str, str] = None) -> str: - namespace = transform_ops(ops, parameters, outputs, renames) - return env.get_template("ops.c").render(namespace) - - def render_coords_impl(coords: CoordinateModel) -> str: ops = [] for s in coords.satisfying: diff --git a/pyecsca/codegen/templates/action.c b/pyecsca/codegen/templates/action.c index 939c6a0..75f3f7a 100644 --- a/pyecsca/codegen/templates/action.c +++ b/pyecsca/codegen/templates/action.c @@ -1,4 +1,7 @@ {% macro start_action(action) %} + {# // Macro for starting a given "action". + // If the trigger is setup to fire on that action + // then this will toggle the trigger value. #} {% if action == "add" %} action_start((uint32_t) (1 << 0)); {% elif action == "dadd" %} @@ -31,6 +34,9 @@ {%- endmacro %} {% macro end_action(action) %} + {# // Macro for ending a given "action". + // If the trigger is setup to fire on that action + // then this will toggle the trigger value. #} {% if action == "add" %} action_end((uint32_t) (1 << 0)); {% elif action == "dadd" %} diff --git a/pyecsca/codegen/templates/main.c b/pyecsca/codegen/templates/main.c index 9014c9a..af82603 100644 --- a/pyecsca/codegen/templates/main.c +++ b/pyecsca/codegen/templates/main.c @@ -125,6 +125,9 @@ static uint8_t cmd_set_params(uint8_t *data, uint16_t len) { if (!curve->neutral->infinity) { point_red_encode(curve->neutral, curve); } + {%- for param in curve_parameters %} + bn_red_encode(&curve->{{ param }}, &curve->p, &curve->p_red); + {%- endfor %} bn_t x; bn_init(&x); bn_t y; bn_init(&y); diff --git a/pyecsca/codegen/templates/ops.c b/pyecsca/codegen/templates/ops.c index 12b126f..ee322a8 100644 --- a/pyecsca/codegen/templates/ops.c +++ b/pyecsca/codegen/templates/ops.c @@ -16,9 +16,11 @@ {%- endmacro %} {% macro render_initializations(initializations) -%} - {%- for init, value in initializations.items() %} + {%- for init, (value, encode) in initializations.items() %} bn_from_int({{ value }}, &{{ init }}); - bn_red_encode(&{{ init }}, &curve->p, &curve->p_red); + {%- if encode %} + bn_red_encode(&{{ init }}, &curve->p, &curve->p_red); + {%- endif %} {%- endfor %} {%- endmacro %} diff --git a/pyecsca/codegen/templates/point.c b/pyecsca/codegen/templates/point.c index 8b7b07e..e87ae36 100644 --- a/pyecsca/codegen/templates/point.c +++ b/pyecsca/codegen/templates/point.c @@ -4,6 +4,9 @@ {% import "ops.c" as ops %} {% from "action.c" import start_action, end_action %} +/** + * Constructs (allocates) a new point. + */ point_t *point_new(void) { point_t *result = malloc(sizeof(point_t)); {%- for variable in variables %} @@ -13,6 +16,9 @@ point_t *point_new(void) { return result; } +/** + * Creates a copy of a point. + */ point_t *point_copy(const point_t *from) { point_t *result = point_new(); point_set(from, result); diff --git a/test/test_impl.py b/test/test_impl.py index a061a74..ea92f8a 100644 --- a/test/test_impl.py +++ b/test/test_impl.py @@ -1,4 +1,3 @@ -from binascii import hexlify from copy import copy from os.path import join from unittest import TestCase @@ -7,7 +6,6 @@ from click.testing import CliRunner from pyecsca.ec.params import get_params from pyecsca.ec.key_agreement import ECDH_SHA1 from pyecsca.ec.mult import LTRMultiplier, RTLMultiplier, CoronMultiplier, BinaryNAFMultiplier -from pyecsca.ec.point import Point from pyecsca.ec.signature import ECDSA_SHA1, SignatureResult from pyecsca.codegen.builder import build_impl @@ -30,7 +28,8 @@ class ImplTests(TestCase): other_args = [ ("--mul", "KARATSUBA", "--sqr", "KARATSUBA"), ("--mul", "TOOM_COOK", "--sqr", "TOOM_COOK"), - ("--red", "BARRETT") + ("--red", "BARRETT"), + ("--red", "MONTGOMERY") ] for additional in other_args: with runner.isolated_filesystem() as tmpdir: @@ -83,13 +82,16 @@ class SetupTests(ImplTests): def test_debug(self): runner = CliRunner() + def callback(target, mult, params): model, coords = target.debug() self.assertEqual(model, params.curve.model.shortname) self.assertEqual(coords, params.curve.coordinate_model.name) + self.do_basic_test(callback, runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], "ltr", False, False, complete=False) + class KeyGenerationTests(ImplTests): def do_keygen_test(self, runner, params, mult_class, formulas, mult_name, **mult_kwargs): @@ -234,7 +236,6 @@ class ECDSATests(ImplTests): ecdsa = ECDSA_SHA1(copy(mult), params, mult.formulas["add"], pub.to_model(params.curve.coordinate_model, params.curve), priv) - signature_data = target.ecdsa_sign(data) result = SignatureResult.from_DER(signature_data) self.assertTrue(ecdsa.verify_data(result, data)) |
