aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJ08nY2024-07-17 15:30:25 +0200
committerJ08nY2024-07-17 15:30:25 +0200
commit33027a201236e6e4aad2d7d637aed85a4f762021 (patch)
tree791faec5053905cdd1b5f473560eaea3c9215f5d
parentd429a996d64e8f8df552ae4a34a04189dc9b82c4 (diff)
downloadpyecsca-codegen-33027a201236e6e4aad2d7d637aed85a4f762021.tar.gz
pyecsca-codegen-33027a201236e6e4aad2d7d637aed85a4f762021.tar.zst
pyecsca-codegen-33027a201236e6e4aad2d7d637aed85a4f762021.zip
Document the scripts.
-rw-r--r--.github/workflows/test.yml2
-rw-r--r--LICENSE2
-rw-r--r--README.md2
-rw-r--r--pyecsca/codegen/builder.py83
-rw-r--r--pyecsca/codegen/client.py199
-rw-r--r--pyecsca/codegen/common.py10
-rw-r--r--pyecsca/codegen/render.py1
-rw-r--r--pyproject.toml14
-rw-r--r--test/test_emulator.py8
-rw-r--r--test/test_encoding.py4
-rw-r--r--test/test_impl.py6
11 files changed, 258 insertions, 73 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f748ff6..f2e480d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
- python-version: ["3.9", "3.10", "3.11"]
+ python-version: ["3.9", "3.10", "3.11", "3.12"]
env:
PYTHON: ${{ matrix.python-version }}
steps:
diff --git a/LICENSE b/LICENSE
index 4b575c2..cc638ca 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2018-2019
+Copyright (c) 2018-2024 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/README.md b/README.md
index c029975..92c2909 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ See [INSTALL](docs/install.rst) for installation instructions.
MIT License
- Copyright (c) 2018-2023 Jan Jancar
+ Copyright (c) 2018-2024 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/pyecsca/codegen/builder.py b/pyecsca/codegen/builder.py
index e9a9144..63e7801 100644
--- a/pyecsca/codegen/builder.py
+++ b/pyecsca/codegen/builder.py
@@ -1,4 +1,45 @@
#!/usr/bin/env python3
+"""
+Builder script.
+
+Use it to render and build ECC implementations.
+
+Examples
+========
+
+To list available implementation choices use the ``list`` subcommand.
+
+.. code-block:: shell
+
+ builder list
+
+To go deeper and examine the coordinates for a given curve model, e.g. the Short-Weierstrass one, use:
+
+.. code-block:: shell
+
+ builder list shortw
+
+To list formulas for a given coordinate system and curve model, e.g. projective on Short-Weierstrass curves, use:
+
+.. code-block:: shell
+
+ builder list shortw projective
+
+The following example builds an implementation for the HOST architecture,
+using the short-Weierstrass curve model, projective coordinates, ``add-2007-bl`` and ``dbl-2007-bl``
+formulas with the left-to-right double-and-add scalar multiplier. Furthermore, it uses Barrett modular
+reduction.
+
+.. code-block:: shell
+
+ builder build --platform HOST --red BARRETT -v shortw projective add-2007-bl dbl-2007-bl "ltr()" .
+
+The following uses different formulas with the comb multiplier and specifies its width.
+
+.. code-block:: shell
+
+ builder build --platform HOST --red BARRETT -v shortw projective add-1998-cmo dbl-1998-cmo "comb(width=5)" .
+"""
import re
import shutil
import subprocess
@@ -15,8 +56,8 @@ from pyecsca.ec.formula import Formula, AdditionFormula
from pyecsca.ec.model import CurveModel
from pyecsca.ec.mult import ScalarMultiplier, AccumulationOrder, ProcessingDirection
-from .render import render
-from .common import Platform, DeviceConfiguration, MULTIPLIERS, wrap_enum, get_model, get_coords
+from pyecsca.codegen.render import render
+from pyecsca.codegen.common import Platform, DeviceConfiguration, MULTIPLIERS, wrap_enum, get_model, get_coords
def get_formula(ctx: click.Context, param, value: Optional[Tuple[str]]) -> List[Formula]:
@@ -28,7 +69,7 @@ def get_formula(ctx: click.Context, param, value: Optional[Tuple[str]]) -> List[
for formula in value:
if formula not in coords.formulas:
raise click.BadParameter(
- "Formula '{}' is not a formula in '{}'.".format(formula, coords))
+ "Formula '{}' is not a formula in '{}'.".format(formula, coords))
result.append(coords.formulas[formula])
if len(set(formula.__class__ for formula in result)) != len(result):
raise click.BadParameter("Duplicate formula types.")
@@ -40,8 +81,8 @@ def get_multiplier(ctx: click.Context, param, value: Optional[str]) -> Optional[
if value is None:
return None
res = re.match(
- "(?P<name>[a-zA-Z\-]+)\((?P<args>([a-zA-Z_]+ *= *[a-zA-Z0-9.]+, ?)*?([a-zA-Z_]+ *= *[a-zA-Z0-9.]+)*)\)",
- value)
+ "(?P<name>[a-zA-Z\-]+)\((?P<args>([a-zA-Z_]+ *= *[a-zA-Z0-9.]+, ?)*?([a-zA-Z_]+ *= *[a-zA-Z0-9.]+)*)\)",
+ value)
if not res:
raise click.BadParameter("Couldn't parse multiplier spec: {}.".format(value))
name = res.group("name")
@@ -59,18 +100,18 @@ def get_multiplier(ctx: click.Context, param, value: Optional[str]) -> Optional[
if not all(
any(issubclass(cls, required) for cls in classes) for required in mult_class.requires):
raise click.BadParameter(
- "Multiplier {} requires formulas: {}, got {}.".format(mult_class.__name__,
- mult_class.requires, classes))
+ "Multiplier {} requires formulas: {}, got {}.".format(mult_class.__name__,
+ mult_class.requires, classes))
globs = dict(globals())
globs["AccumulationOrder"] = AccumulationOrder
globs["ProcessingDirection"] = ProcessingDirection
kwargs = eval("dict(" + args + ")", globs)
required = set(
- filter(lambda formula: any(isinstance(formula, cls) for cls in mult_class.requires),
- formulas))
+ filter(lambda formula: any(isinstance(formula, cls) for cls in mult_class.requires),
+ formulas))
optional = set(
- filter(lambda formula: any(isinstance(formula, cls) for cls in mult_class.optionals),
- formulas))
+ filter(lambda formula: any(isinstance(formula, cls) for cls in mult_class.optionals),
+ formulas))
for formula in required.union(optional):
kwargs[formula.shortname] = formula
mult = mult_class(**kwargs)
@@ -240,27 +281,29 @@ def list_impl(model: Optional[CurveModel], coords: Optional[CoordinateModel],
click.echo(model)
for coord in model.coordinates.values():
click.echo(
- "{}: {}, [{}]".format(coord.name, coord.full_name, ",".join(coord.variables)))
+ "{}: {}, [{}]".format(coord.name, coord.full_name, ",".join(coord.variables)))
return
if not model:
click.echo(
- click.wrap_text("Platform:\n\t" + ", ".join(Platform.names()),
- subsequent_indent="\t"))
+ click.wrap_text("Platform:\n\t" + ", ".join(Platform.names()),
+ subsequent_indent="\t"))
click.echo(
- click.wrap_text("Hash type:\n\t" + ", ".join(HashType.names()),
- subsequent_indent="\t"))
+ click.wrap_text("Hash type:\n\t" + ", ".join(HashType.names()),
+ subsequent_indent="\t"))
click.echo(click.wrap_text("Modular Random:\n\t" + ", ".join(RandomMod.names()),
subsequent_indent="\t"))
click.echo(click.wrap_text("Multiplication:\n\t" + ", ".join(Multiplication.names()),
subsequent_indent="\t"))
click.echo(
- click.wrap_text("Squaring:\n\t" + ", ".join(Squaring.names()),
- subsequent_indent="\t"))
+ click.wrap_text("Squaring:\n\t" + ", ".join(Squaring.names()),
+ subsequent_indent="\t"))
click.echo(click.wrap_text("Modular Reduction:\n\t" + ", ".join(Reduction.names()),
subsequent_indent="\t"))
click.echo(click.wrap_text(
- "Scalar multplier:\n\t" + ", ".join(map(lambda m: m["name"][-1], MULTIPLIERS)),
- subsequent_indent="\t"))
+ "Scalar multplier:\n\t" + ", ".join(map(lambda m: m["name"][-1], MULTIPLIERS)),
+ subsequent_indent="\t"))
+ click.echo(click.wrap_text("Curve Model:\n\t" + ", ".join(["shortw", "montgom", "edwards", "twisted"])))
+
if __name__ == "__main__":
main(obj={})
diff --git a/pyecsca/codegen/client.py b/pyecsca/codegen/client.py
index 6f0321e..228e888 100644
--- a/pyecsca/codegen/client.py
+++ b/pyecsca/codegen/client.py
@@ -1,4 +1,51 @@
#!/usr/bin/env python3
+"""
+Client script.
+
+Use it to interact with the built implementations (and flash them if necessary).
+
+Examples
+========
+
+The following examples use the generated implementation in ``pyecsca-codegen-HOST.elf`` for the host
+architecture, which is assumed to use the Short-Weierstrass curve model with projective coordinates.
+
+The first example generates a keypair and exports it.
+
+.. code-block:: shell-session
+
+ $ client --platform HOST --fw ./pyecsca-codegen-HOST.elf shortw projective gen secg/secp128r1
+ (162938999268550597445809790209592423458, Point([x=111810799217268384317536017529141796945, y=309320541414531923178173772704935971498] in shortw/affine))
+ 0.01743340492248535
+
+The following example does ECDH with the target, which first generates a keypair.
+
+.. code-block:: shell-session
+
+ $ client --platform HOST --fw ./pyecsca-codegen-HOST.elf shortw projective ecdh secg/secp128r1 122835813094999453922649270086793500655,326514220558629293368386081113307347349
+ Keypair: 162938999268550597445809790209592423458, [x=111810799217268384317536017529141796945, y=309320541414531923178173772704935971498]
+ ECDH result: 30567033074c9169e9355a7b348aa7511c3ae605
+
+The following example signs a message ``"something"`` using the target, which first generates a keypair.
+
+.. code-block:: shell-session
+
+ $ client --platform HOST --fw ./pyecsca-codegen-HOST.elf shortw projective ecdsa-sign secg/secp128r1 something
+ Keypair: 162938999268550597445809790209592423458, [x=111810799217268384317536017529141796945, y=309320541414531923178173772704935971498]
+ Signature: 30250211009dc6d5b03cffe0cbd5e829838ecb59e4021023496ba97cf1d816619fe626de2d07b6
+
+The following example verifies a signature on the message ``"something"`` using the target and the provided public key.
+
+.. code-block:: shell-session
+
+ $ client --platform HOST --fw ./pyecsca-codegen-HOST.elf shortw projective ecdsa-verify secg/secp128r1 111810799217268384317536017529141796945,309320541414531923178173772704935971498 something_else 30250211009dc6d5b03cffe0cbd5e829838ecb59e40210171c895d2d4f27850ff5f2a375ea22b7
+ Result: True
+
+.. note::
+ The implementation has a PRNG it uses to get randomness. This PRNG starts with a constant state.
+ You can use the ``--seed`` option to set a custom state.
+
+"""
import bisect
import re
from binascii import hexlify, unhexlify
@@ -12,23 +59,22 @@ import click
import numpy as np
from chipwhisperer.capture.api.programmers import STM32FProgrammer, XMEGAProgrammer
from chipwhisperer.capture.targets import SimpleSerial
+from rainbow.devices import rainbow_stm32f215
+from rainbow import TraceConfig, Print
from public import public
+
from pyecsca.ec.coordinates import CoordinateModel, AffineCoordinateModel
-from pyecsca.ec.mod import Mod
+from pyecsca.ec.mod import mod, Mod
from pyecsca.ec.model import CurveModel
from pyecsca.ec.params import DomainParameters, get_params
from pyecsca.ec.point import Point, InfinityPoint
from pyecsca.sca.target import (Target, SimpleSerialTarget, ChipWhispererTarget, BinaryTarget, Flashable,
SimpleSerialMessage as SMessage)
from pyecsca.sca.trace import Trace
-
-from .common import wrap_enum, Platform, get_model, get_coords
-
-from rainbow.devices import rainbow_stm32f215
-from rainbow import TraceConfig, Print
-
+from pyecsca.codegen.common import wrap_enum, Platform, get_model, get_coords
+@public
class Triggers(IntFlag):
"""
Actions that the implementation can trigger on.
@@ -193,8 +239,8 @@ def cmd_debug() -> str:
return "d"
+@public
class EmulatorTarget(Target):
-
emulator: rainbow_stm32f215
result: list
model: CurveModel
@@ -209,7 +255,7 @@ class EmulatorTarget(Target):
trace_config: TraceConfig = TraceConfig(), allow_breakpoints: bool = False):
super().__init__()
self.emulator = rainbow_stm32f215(print_config=print_config, trace_config=trace_config,
- allow_stubs=True, allow_breakpoints=allow_breakpoints)
+ allow_stubs=True, allow_breakpoints=allow_breakpoints)
self.result = []
self.trace = []
self.model = model
@@ -251,10 +297,10 @@ class EmulatorTarget(Target):
def __scalar_mult_hook(self, emulator) -> None:
point_length = emulator['r1'] // len(self.coords.variables)
res_adress = emulator['r2']
- self.result.append({var: Mod(int.from_bytes(emulator[res_adress + i * point_length:
- res_adress + (i + 1) * point_length], 'big'),
- self.params.curve.prime)
- for i, var in enumerate(self.coords.variables)})
+ self.result.append({var: mod(int.from_bytes(emulator[res_adress + i * point_length:
+ res_adress + (i + 1) * point_length], 'big'),
+ self.params.curve.prime)
+ for i, var in enumerate(self.coords.variables)})
def scalar_mult(self, scalar: int, point: Point) -> Point:
self.result = []
@@ -281,9 +327,9 @@ class EmulatorTarget(Target):
self.__emulate(command, 'cmd_generate')
priv = int.from_bytes(self.result[1], 'big')
pub_x = int.from_bytes(self.result[3][0:self.result[2] // 2], 'big')
- pub_y = int.from_bytes(self.result[3][self.result[2] // 2:self.result[2]] ,'big')
- return priv, Point(AffineCoordinateModel(self.model), x = Mod(pub_x, self.params.curve.prime),
- y = Mod(pub_y, self.params.curve.prime))
+ pub_y = int.from_bytes(self.result[3][self.result[2] // 2:self.result[2]], 'big')
+ return priv, Point(AffineCoordinateModel(self.model), x=mod(pub_x, self.params.curve.prime),
+ y=mod(pub_y, self.params.curve.prime))
def set_privkey(self, privkey: int) -> None:
command = cmd_set_privkey(privkey)
@@ -364,7 +410,7 @@ class EmulatorTarget(Target):
self.emulator.reset()
-
+@public
class ImplTarget(SimpleSerialTarget):
"""
A target that is based on an implementation built by pyecsca-codegen.
@@ -399,14 +445,26 @@ class ImplTarget(SimpleSerialTarget):
self.trigger = None
def init_prng(self, seed: bytes) -> None:
+ """
+ Init the PRNG using the `seed`.
+
+ """
self.send_cmd(SMessage.from_raw(cmd_init_prng(seed)), self.timeout)
self.seed = seed
def set_params(self, params: DomainParameters) -> None:
+ """
+ Set the domain parameters on the target.
+ """
self.send_cmd(SMessage.from_raw(cmd_set_params(params)), self.timeout)
self.params = params
def generate(self) -> Tuple[int, Point]:
+ """
+ Generate a keypair on the target and set it (and export it).
+
+ Requires that domain parameters are set up.
+ """
resp = self.send_cmd(SMessage.from_raw(cmd_generate()), self.timeout)
priv = resp["s"].data
pub = resp["w"].data
@@ -414,52 +472,96 @@ class ImplTarget(SimpleSerialTarget):
pub_len = len(pub)
x = int(pub[:pub_len // 2], 16)
y = int(pub[pub_len // 2:], 16)
- self.pubkey = Point(AffineCoordinateModel(self.model), x=Mod(x, self.params.curve.prime),
- y=Mod(y, self.params.curve.prime))
+ self.pubkey = Point(AffineCoordinateModel(self.model), x=mod(x, self.params.curve.prime),
+ y=mod(y, self.params.curve.prime))
return self.privkey, self.pubkey
def set_privkey(self, privkey: int) -> None:
+ """
+ Set the private key on the target.
+ """
self.send_cmd(SMessage.from_raw(cmd_set_privkey(privkey)), self.timeout)
self.privkey = privkey
def set_pubkey(self, pubkey: Point) -> None:
+ """
+ Set the public key on the target.
+ """
self.send_cmd(SMessage.from_raw(cmd_set_pubkey(pubkey)), self.timeout)
self.pubkey = pubkey
def scalar_mult(self, scalar: int, point: Point) -> Point:
+ """
+ Run scalar multiplication on the target and export the result.
+
+ Requires that domain parameters are set up.
+ """
resp = self.send_cmd(SMessage.from_raw(cmd_scalar_mult(scalar, point)), self.timeout)
result = resp["w"]
plen = ((self.params.curve.prime.bit_length() + 7) // 8) * 2
- params = {var: Mod(int(result.data[i * plen:(i + 1) * plen], 16), self.params.curve.prime)
+ params = {var: mod(int(result.data[i * plen:(i + 1) * plen], 16), self.params.curve.prime)
for
i, var in enumerate(self.coords.variables)}
return Point(self.coords, **params)
def ecdh(self, other_pubkey: Point) -> bytes:
+ """
+ Do ECDH with the target.
+
+ Requires that domain parameters are set up, as well as a private key.
+ """
resp = self.send_cmd(SMessage.from_raw(cmd_ecdh(other_pubkey)), self.timeout)
result = resp["r"]
return unhexlify(result.data)
def ecdsa_sign(self, data: bytes) -> bytes:
+ """
+ Sign a message on the target.
+
+ Requires that domain parameters are set up, as well as a private key.
+ """
resp = self.send_cmd(SMessage.from_raw(cmd_ecdsa_sign(data)), self.timeout)
signature = resp["s"]
return unhexlify(signature.data)
def ecdsa_verify(self, data: bytes, signature: bytes) -> bool:
+ """
+ Verify a signature on the target.
+
+ Requires that domain parameters are set up, as well as a public key.
+ """
resp = self.send_cmd(SMessage.from_raw(cmd_ecdsa_verify(data, signature)), self.timeout)
result = resp["v"]
return unhexlify(result.data)[0] == 1
def debug(self) -> Tuple[str, str]:
+ """
+ Run the debug command on the target.
+
+ Returns the curve model and coordinate model names.
+ """
resp = self.send_cmd(SMessage.from_raw(cmd_debug()), self.timeout)["d"]
model, coords = unhexlify(resp.data).decode().split(",")
return model, coords
def set_trigger(self, actions: Triggers) -> None:
+ """
+ Setup the trigger on the target.
+
+ .. note::
+
+ The triggers are not exclusive and you can set to trigger on multiple actions.
+ However, note that they toggle the trigger signal. For example, if you setup
+ triggers on scalar multiplication and addition (``Triggers.mult | Triggers.add``)
+ the trigger signal will go high once scalar multiplication starts, then go low
+ during each addition operation and finally go low for good after scalar multiplication
+ ends.
+ """
self.send_cmd(SMessage.from_raw(cmd_set_trigger(actions)), self.timeout)
self.trigger = actions
def quit(self):
+ """Turn off the target."""
self.write(b"x\n")
def disconnect(self):
@@ -505,6 +607,7 @@ class HostTarget(ImplTarget, BinaryTarget):
help="The firmware. Either a .hex file for a device platform or .elf for HOST platform.",
required=True)
@click.option("--timeout", type=int, default=15000)
+@click.option("--seed", type=str, help="Set the PRNG seed (hex string).")
@click.argument("model", required=True,
type=click.Choice(["shortw", "montgom", "edwards", "twisted"]),
callback=get_model)
@@ -513,12 +616,13 @@ class HostTarget(ImplTarget, BinaryTarget):
@click.version_option()
@click.pass_context
@public
-def main(ctx, platform, fw, timeout, model, coords):
+def main(ctx, platform, fw, timeout, seed, model, coords):
"""
A tool for communicating with built and flashed ECC implementations.
"""
ctx.ensure_object(dict)
ctx.obj["fw"] = fw
+ ctx.obj["seed"] = seed
if platform != Platform.HOST:
ctx.obj["target"] = DeviceTarget(model, coords, platform, timeout=timeout)
else:
@@ -549,6 +653,8 @@ def generate(ctx: click.Context, curve):
if isinstance(target, Flashable):
target.flash(ctx.obj["fw"])
target.connect()
+ if seed := ctx.obj["seed"]:
+ target.init_prng(bytes.fromhex(seed))
target.set_params(curve)
start = time()
click.echo(target.generate())
@@ -573,8 +679,8 @@ def get_pubkey(ctx: click.Context, param, value: Optional[str]) -> Point:
y = int(ys)
else:
raise click.BadParameter("Couldn't parse pubkey: {}.".format(value))
- x = Mod(x, curve.curve.prime)
- y = Mod(y, curve.curve.prime)
+ x = mod(x, curve.curve.prime)
+ y = mod(y, curve.curve.prime)
return Point(AffineCoordinateModel(curve.curve.model), x=x, y=y)
@@ -590,31 +696,62 @@ def ecdh(ctx: click.Context, curve, pubkey):
if isinstance(target, Flashable):
target.flash(ctx.obj["fw"])
target.connect()
+ if seed := ctx.obj["seed"]:
+ target.init_prng(bytes.fromhex(seed))
target.set_params(curve)
- target.generate()
- click.echo(hexlify(target.ecdh(pubkey)))
+ priv, pub = target.generate()
+ click.echo(f"Keypair: {priv}, {pub}")
+ click.echo(f"ECDH result: {hexlify(target.ecdh(pubkey)).decode()}")
target.quit()
target.disconnect()
@main.command("ecdsa-sign")
@click.argument("curve", required=True, callback=get_curve)
+@click.argument("data", required=True, type=str)
@click.pass_context
@public
-def ecdsa_sign(ctx: click.Context, curve):
+def ecdsa_sign(ctx: click.Context, curve, data):
+ """Sign data using ECDSA."""
ctx.ensure_object(dict)
- # TODO
- click.echo("Not implemented.")
+ target: ImplTarget = ctx.obj["target"]
+ if isinstance(target, Flashable):
+ target.flash(ctx.obj["fw"])
+ target.connect()
+ if seed := ctx.obj["seed"]:
+ target.init_prng(bytes.fromhex(seed))
+ target.set_params(curve)
+ priv, pub = target.generate()
+ click.echo(f"Keypair: {priv}, {pub}")
+ click.echo(f"Signature: {hexlify(target.ecdsa_sign(data.encode())).decode()}")
+ target.quit()
+ target.disconnect()
@main.command("ecdsa-verify")
@click.argument("curve", required=True, callback=get_curve)
+@click.argument("pubkey", required=True, callback=get_pubkey)
+@click.argument("data", required=True, type=str)
+@click.argument("signature", required=True, type=str)
@click.pass_context
@public
-def ecdsa_verify(ctx: click.Context, curve):
+def ecdsa_verify(ctx: click.Context, curve, pubkey, data, signature):
+ """
+ Verify data using ECDSA.
+ """
ctx.ensure_object(dict)
- # TODO
- click.echo("Not implemented.")
+ target: ImplTarget = ctx.obj["target"]
+ if isinstance(target, Flashable):
+ target.flash(ctx.obj["fw"])
+ target.connect()
+ if seed := ctx.obj["seed"]:
+ target.init_prng(bytes.fromhex(seed))
+ target.set_params(curve)
+ target.set_pubkey(pubkey)
+ res = target.ecdsa_verify(data.encode(), unhexlify(signature))
+ click.echo(f"Result: {res}")
+ target.quit()
+ target.disconnect()
if __name__ == "__main__":
diff --git a/pyecsca/codegen/common.py b/pyecsca/codegen/common.py
index ffe4710..3ec91fc 100644
--- a/pyecsca/codegen/common.py
+++ b/pyecsca/codegen/common.py
@@ -1,3 +1,4 @@
+"""Common codegen utilities."""
from dataclasses import dataclass
from typing import Type, Optional, MutableMapping, Any
@@ -21,6 +22,7 @@ from pyecsca.ec.mult import (
FullPrecompMultiplier,
BGMWMultiplier,
CombMultiplier,
+ WindowBoothMultiplier,
)
@@ -62,13 +64,13 @@ MULTIPLIERS = [
{"name": ("wnaf", "WindowNAFMultiplier"), "class": WindowNAFMultiplier},
{"name": ("sliding", "SlidingWindowMultiplier"), "class": SlidingWindowMultiplier},
{"name": ("fixed", "FixedWindowLTRMultiplier"), "class": FixedWindowLTRMultiplier},
+ {"name": ("booth", "WindowBoothMultiplier"), "class": WindowBoothMultiplier},
{"name": ("precomp", "FullPrecompMultiplier"), "class": FullPrecompMultiplier},
{"name": ("bgmw", "BGMWMultiplier"), "class": BGMWMultiplier},
{"name": ("comb", "CombMultiplier"), "class": CombMultiplier},
]
-@public
def wrap_enum(enum_class: Type[EnumDefine]):
def callback(ctx, param, value):
try:
@@ -76,7 +78,7 @@ def wrap_enum(enum_class: Type[EnumDefine]):
return res
except Exception:
raise click.BadParameter(
- "Cannot create {} enum from {}.".format(enum_class.__name__, value))
+ "Cannot create {} enum from {}.".format(enum_class.__name__, value))
return callback
@@ -105,8 +107,8 @@ def get_coords(ctx: click.Context, param, value: Optional[str]) -> Optional[Coor
model = ctx.obj["model"]
if value not in model.coordinates:
raise click.BadParameter(
- "Coordinate model '{}' is not a model in '{}'.".format(value,
- model.__class__.__name__))
+ "Coordinate model '{}' is not a model in '{}'.".format(value,
+ model.__class__.__name__))
coords = model.coordinates[value]
ctx.obj["coords"] = coords
return coords
diff --git a/pyecsca/codegen/render.py b/pyecsca/codegen/render.py
index 241ee6a..692deab 100644
--- a/pyecsca/codegen/render.py
+++ b/pyecsca/codegen/render.py
@@ -1,3 +1,4 @@
+"""Rendering and building of implementation configurations."""
import os
import shutil
import subprocess
diff --git a/pyproject.toml b/pyproject.toml
index ff471c5..41585c7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,7 @@
"Intended Audience :: Developers",
"Intended Audience :: Science/Research"
]
- requires-python = ">=3.8"
+ requires-python = ">=3.9"
dependencies = [
"pyecsca",
"chipwhisperer",
@@ -41,10 +41,10 @@
]
[project.urls]
-"Homepage" = "https://https://neuromancer.sk/pyecsca/"
-"Documentation" = "https://https://neuromancer.sk/pyecsca/"
-"Bug Tracker" = "https://github.com/J08nY/pyecsca/issues"
-"Repository" = "https://github.com/J08nY/pyecsca"
+"Homepage" = "https://pyecsca.org"
+"Documentation" = "https://pyecsca.org"
+"Bug Tracker" = "https://github.com/J08nY/pyecsca-codegen/issues"
+"Repository" = "https://github.com/J08nY/pyecsca-codegen"
[project.scripts]
builder="pyecsca.codegen.builder:main"
@@ -66,5 +66,7 @@ markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
]
filterwarnings = [
- "ignore:Deprecated call to `pkg_resources.declare_namespace"
+ "ignore:(?s).*pkg_resources is deprecated as an API:DeprecationWarning:chipwhisperer.capture.trace.TraceWhisperer", # ChipWhisperer
+ "ignore:Deprecated call to `pkg_resources.declare_namespace",
+ "ignore:(?s).*path is deprecated. Use files() instead:DeprecationWarning:rainbow.devices.stm32" # Rainbow
]
diff --git a/test/test_emulator.py b/test/test_emulator.py
index ab8bf73..072af27 100644
--- a/test/test_emulator.py
+++ b/test/test_emulator.py
@@ -11,7 +11,7 @@ from pyecsca.codegen.builder import build_impl
from pyecsca.codegen.client import EmulatorTarget
from pyecsca.ec.curve import EllipticCurve
-from pyecsca.ec.mod import Mod
+from pyecsca.ec.mod import mod
from pyecsca.ec.model import ShortWeierstrassModel
from pyecsca.ec.params import DomainParameters
from pyecsca.ec.point import InfinityPoint, Point
@@ -23,11 +23,11 @@ def curve32():
model = ShortWeierstrassModel()
coords = model.coordinates["projective"]
p = 0xD7D1247F
- a = Mod(0xA4A44016, p)
- b = Mod(0x73F76716, p)
+ a = mod(0xA4A44016, p)
+ b = mod(0x73F76716, p)
n = 0xD7D2A475
h = 1
- gx, gy, gz = Mod(0x54EED6D7, p), Mod(0x6F1E55AC, p), Mod(1, p)
+ gx, gy, gz = mod(0x54EED6D7, p), mod(0x6F1E55AC, p), mod(1, p)
generator = Point(coords, X=gx, Y=gy, Z=gz)
neutral = InfinityPoint(coords)
diff --git a/test/test_encoding.py b/test/test_encoding.py
index 0684945..f4fc7fa 100644
--- a/test/test_encoding.py
+++ b/test/test_encoding.py
@@ -1,11 +1,11 @@
-from pyecsca.ec.mod import Mod
+from pyecsca.ec.mod import mod
from pyecsca.codegen.client import encode_data, decode_data, encode_scalar
def test_encode_decode():
data = {
"a": encode_scalar(0xCAFEBABE),
- "b": {"c": encode_scalar(Mod(1, 3)), "d": bytes([0x2])},
+ "b": {"c": encode_scalar(mod(1, 3)), "d": bytes([0x2])},
}
encoded = encode_data(None, data)
result = decode_data(encoded)
diff --git a/test/test_impl.py b/test/test_impl.py
index da42c33..34f427b 100644
--- a/test/test_impl.py
+++ b/test/test_impl.py
@@ -4,7 +4,7 @@ import pytest
from click.testing import CliRunner
from pyecsca.ec.key_agreement import ECDH_SHA1
-from pyecsca.ec.mod import Mod
+from pyecsca.ec.mod import mod
from pyecsca.ec.mult import (
LTRMultiplier,
RTLMultiplier,
@@ -323,7 +323,7 @@ def test_ecdh(target, mult, secp128r1):
for other_priv in other_privs:
priv, pub = target.generate()
other_pub = mult.multiply(other_priv)
- ecdh = ECDH_SHA1(copy(mult), secp128r1, other_pub, Mod(priv, secp128r1.order))
+ ecdh = ECDH_SHA1(copy(mult), secp128r1, other_pub, mod(priv, secp128r1.order))
result = target.ecdh(other_pub)
expected = ecdh.perform()
assert result == expected
@@ -343,7 +343,7 @@ def test_ecdsa(target, mult, secp128r1):
secp128r1,
mult.formulas["add"],
pub.to_model(secp128r1.curve.coordinate_model, secp128r1.curve),
- Mod(priv, secp128r1.order),
+ mod(priv, secp128r1.order),
)
signature_data = target.ecdsa_sign(message)