aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJán Jančár2023-10-08 21:12:06 +0200
committerGitHub2023-10-08 21:12:06 +0200
commitffbaa1ae62095eb644eda67571aa8845aa6fb09d (patch)
treedfdfbf9a12acd1662cba56b46b30d8337ae81918
parent9c6acdd2409c49c2ae64a8c41df315a1eca3eea7 (diff)
parent1c2e383d8e8df323b4cebb302869fc15599961a0 (diff)
downloadpyecsca-codegen-ffbaa1ae62095eb644eda67571aa8845aa6fb09d.tar.gz
pyecsca-codegen-ffbaa1ae62095eb644eda67571aa8845aa6fb09d.tar.zst
pyecsca-codegen-ffbaa1ae62095eb644eda67571aa8845aa6fb09d.zip
Merge pull request #4 from J08nY/feat/more-mults
More scalar multipliers
-rw-r--r--.github/workflows/test.yml9
-rw-r--r--.gitignore1
m---------ext/libtommath0
-rw-r--r--pyecsca/codegen/bn/bn.c222
-rw-r--r--pyecsca/codegen/bn/bn.h27
-rw-r--r--pyecsca/codegen/builder.py61
-rw-r--r--pyecsca/codegen/common.py71
-rw-r--r--pyecsca/codegen/point.h2
-rw-r--r--pyecsca/codegen/prng/KeccakP-200-compact.c4
-rw-r--r--pyecsca/codegen/render.py47
-rw-r--r--pyecsca/codegen/templates/Makefile4
-rw-r--r--pyecsca/codegen/templates/formula_add.c4
-rw-r--r--pyecsca/codegen/templates/formula_dadd.c4
-rw-r--r--pyecsca/codegen/templates/formula_dbl.c4
-rw-r--r--pyecsca/codegen/templates/formula_ladd.c4
-rw-r--r--pyecsca/codegen/templates/formula_neg.c4
-rw-r--r--pyecsca/codegen/templates/formula_scl.c4
-rw-r--r--pyecsca/codegen/templates/formula_tpl.c4
-rw-r--r--pyecsca/codegen/templates/main.c20
-rw-r--r--pyecsca/codegen/templates/mult.c24
-rw-r--r--pyecsca/codegen/templates/mult_bgmw.c64
-rw-r--r--pyecsca/codegen/templates/mult_bnaf.c48
-rw-r--r--pyecsca/codegen/templates/mult_comb.c77
-rw-r--r--pyecsca/codegen/templates/mult_fixed_w.c63
-rw-r--r--pyecsca/codegen/templates/mult_ltr.c4
-rw-r--r--pyecsca/codegen/templates/mult_precomp.c85
-rw-r--r--pyecsca/codegen/templates/mult_rtl.c4
-rw-r--r--pyecsca/codegen/templates/mult_sliding_w.c43
-rw-r--r--pyecsca/codegen/templates/mult_wnaf.c60
-rw-r--r--pyecsca/codegen/templates/point.c8
-rw-r--r--test/Makefile3
-rw-r--r--test/test_bn.c91
-rw-r--r--test/test_impl.py583
-rw-r--r--test/test_simulator.py6
34 files changed, 1276 insertions, 383 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index fddf6f7..797ce52 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -3,12 +3,12 @@ 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 gcc-arm-none-eabi binutils-arm-none-eabi libnewlib-arm-none-eabi libnewlib-nano-arm-none-eabi
+ LLVM_CONFIG: /usr/bin/llvm-config-14
+ OTHER_PACKAGES: swig libpcsclite-dev llvm-14 libllvm14 llvm-14-dev valgrind gcc gcc-arm-none-eabi binutils-arm-none-eabi libnewlib-arm-none-eabi
jobs:
test:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10"]
@@ -48,6 +48,9 @@ jobs:
- name: Test
run: |
make test
+ - name: Test (C)
+ run: |
+ cd test && make test_bn && ./test_bn && cd ..
- name: Code coverage
uses: codecov/codecov-action@v3
if: ${{ matrix.python-version == 3.9 }}
diff --git a/.gitignore b/.gitignore
index 58caf65..9e55abb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
htmlcov/
/build/
__pycache__
+/test/test_bn
pyecsca-codegen-*.elf
pyecsca-codegen-*.hex \ No newline at end of file
diff --git a/ext/libtommath b/ext/libtommath
-Subproject 5167f6c14a8b9524ca42e45a41aa71856769540
+Subproject 8314bde5e5c8e5d9331460130a9d1066e324f09
diff --git a/pyecsca/codegen/bn/bn.c b/pyecsca/codegen/bn/bn.c
index 53777db..148403c 100644
--- a/pyecsca/codegen/bn/bn.c
+++ b/pyecsca/codegen/bn/bn.c
@@ -53,7 +53,7 @@ bn_err bn_from_int(unsigned int value, bn_t *out) {
} else {
mp_set_u32(out, value);
}
- return MP_OKAY;
+ return BN_OKAY;
}
bn_err bn_to_binpad(const bn_t *one, uint8_t *data, size_t size) {
@@ -71,6 +71,10 @@ size_t bn_to_bin_size(const bn_t *one) {
return mp_ubin_size(one);
}
+unsigned int bn_to_int(const bn_t *one) {
+ return mp_get_mag_ul(one);
+}
+
bn_err bn_rand_mod_sample(bn_t *out, const bn_t *mod) {
int mod_len = bn_bit_length(mod);
@@ -162,7 +166,11 @@ bn_err bn_mod(const bn_t *one, const bn_t *mod, bn_t *out) {
bn_err bn_red_init(red_t *out) {
#if REDUCTION == RED_MONTGOMERY
- return bn_init(&out->montgomery_renorm);
+ bn_err err;
+ if ((err = bn_init(&out->montgomery_renorm)) != BN_OKAY) {
+ return err;
+ }
+ return bn_init(&out->montgomery_renorm_sqr);
#elif REDUCTION == RED_BARRETT
return bn_init(&out->barrett);
#endif
@@ -333,6 +341,7 @@ bn_err bn_red_reduce(const bn_t *mod, const red_t *red, bn_t *what) {
void bn_red_clear(red_t *out) {
#if REDUCTION == RED_MONTGOMERY
bn_clear(&out->montgomery_renorm);
+ bn_clear(&out->montgomery_renorm_sqr);
#elif REDUCTION == RED_BARRETT
bn_clear(&out->barrett);
#endif
@@ -346,6 +355,10 @@ bn_err bn_rsh(const bn_t *one, int amount, bn_t *out) {
return mp_div_2d(one, amount, out, NULL);
}
+bn_err bn_and(const bn_t *one, const bn_t *other, bn_t *out) {
+ return mp_and(one, other, out);
+}
+
bool bn_eq(const bn_t *one, const bn_t *other) {
return mp_cmp_mag(one, other) == MP_EQ;
}
@@ -448,4 +461,209 @@ exit_full_width:
wnaf_t *bn_bnaf(const bn_t *bn) {
return bn_wnaf(bn, 2);
+}
+
+wsliding_t *bn_wsliding_ltr(const bn_t *bn, int w) {
+ if (w > 8 || w < 2) {
+ return NULL;
+ }
+
+ wsliding_t *result = NULL;
+
+ int blen = bn_bit_length(bn);
+ uint8_t arr[blen];
+ memset(arr, 0, blen * sizeof(uint8_t));
+
+ int b = blen - 1;
+ int u = 0;
+ int c = 0;
+ bn_t mask;
+ if (mp_init(&mask) != BN_OKAY) {
+ goto exit_mask;
+ }
+
+ int i = 0;
+ while (b >= 0) {
+ if (!bn_get_bit(bn, b)) {
+ arr[i++] = 0; // result.append(0)
+ b--; // b -= 1
+ } else {
+ u = 0; // u = 0
+ for (int v = 1; v <= w; v++) { // for v in range(1, w + 1):
+ if (b + 1 < v) { // if b + 1 < v:
+ break;
+ }
+ bn_from_int((1 << v) - 1, &mask); // mask = ((2**v) - 1) << (b - v + 1)
+ bn_lsh(&mask, b - v + 1, &mask);
+ bn_and(&mask, bn, &mask); // mask = (i & mask)
+ bn_rsh(&mask, b - v + 1, &mask); // mask = mask >> (b - v + 1)
+ if (bn_get_bit(&mask, 0)) { // if c & 1:
+ u = (int) bn_to_int(&mask); // u = c
+ }
+ }
+ c = u;
+ while (u) { // k = u.bit_length()
+ arr[i++] = 0; // result.extend([0] * (k - 1))
+ b--; // b -= k
+ u >>= 1;
+ }
+ arr[i - 1] = c; // result.append(u)
+ }
+ }
+ bn_clear(&mask);
+
+ result = malloc(sizeof(wsliding_t));
+ result->w = w;
+ result->length = 0;
+ result->data = NULL;
+ // Strip the repr and return.
+ for (int j = 0; j < i; j++) {
+ if (result->data == NULL) {
+ if (arr[j]) {
+ result->length = i - j;
+ result->data = calloc(result->length, sizeof(uint8_t));
+ result->data[0] = arr[j];
+ }
+ } else {
+ result->data[j - (i - result->length)] = arr[j];
+ }
+ }
+exit_mask:
+ return result;
+}
+
+wsliding_t *bn_wsliding_rtl(const bn_t *bn, int w) {
+ if (w > 8 || w < 2) {
+ return NULL;
+ }
+
+ wsliding_t *result = NULL;
+
+ int blen = bn_bit_length(bn);
+ uint8_t arr[blen + 2];
+ memset(arr, 0, (blen + 2) * sizeof(uint8_t));
+
+ bn_t k;
+ if (mp_init(&k) != BN_OKAY) {
+ goto exit_k;
+ }
+ bn_copy(bn, &k);
+
+ bn_t mask;
+ if (mp_init(&mask) != BN_OKAY) {
+ goto exit_mask;
+ }
+
+ int i = 0;
+ while (!bn_is_0(&k) && !(bn_get_sign(&k) == BN_NEG)) {
+ if (!bn_get_bit(&k, 0)) {
+ arr[i++] = 0;
+ bn_rsh(&k, 1, &k);
+ } else {
+ bn_from_int((1 << w) - 1, &mask); // mask = ((2**w) - 1)
+ bn_and(&mask, &k, &mask);
+ arr[i++] = bn_to_int(&mask);
+ for (int j = 0; j < w - 1; j++) {
+ arr[i++] = 0;
+ }
+ bn_rsh(&k, w, &k);
+ }
+ }
+ bn_clear(&mask);
+
+ result = malloc(sizeof(wsliding_t));
+ result->w = w;
+ result->length = 0;
+ result->data = NULL;
+ // Revert, strip the repr and return.
+ for (int j = i - 1; j >= 0; j--) {
+ if (result->data == NULL) {
+ if (arr[j]) {
+ result->length = j + 1;
+ result->data = calloc(result->length, sizeof(uint8_t));
+ result->data[0] = arr[j];
+ }
+ } else {
+ result->data[result->length - j - 1] = arr[j];
+ }
+ }
+
+exit_mask:
+ bn_clear(&k);
+exit_k:
+ return result;
+}
+
+small_base_t *bn_convert_base_small(const bn_t *bn, int m) {
+ small_base_t *result = NULL;
+
+ bn_t k;
+ if (mp_init(&k) != BN_OKAY) {
+ goto exit_k;
+ }
+ bn_copy(bn, &k);
+
+ int len = 0;
+ if (mp_log_n(&k, m, &len) != BN_OKAY) {
+ goto exit_len;
+ }
+
+ result = malloc(sizeof(small_base_t));
+ result->length = len + 1;
+ result->data = calloc(result->length, sizeof(int));
+ result->m = m;
+
+ int i = 0;
+ mp_digit val = 0;
+ while (!bn_is_0(&k) && !(bn_get_sign(&k) == BN_NEG)) {
+ if (mp_div_d(&k, m, &k, &val) != BN_OKAY) {
+ free(result->data);
+ free(result);
+ goto exit_len;
+ }
+ result->data[i++] = val;
+ }
+
+exit_len:
+ bn_clear(&k);
+exit_k:
+ return result;
+}
+
+large_base_t *bn_convert_base_large(const bn_t *bn, const bn_t *m) {
+ large_base_t *result = NULL;
+
+ bn_t k;
+ if (mp_init(&k) != BN_OKAY) {
+ goto exit_k;
+ }
+ bn_copy(bn, &k);
+
+ int len = 0;
+ if (mp_log(&k, m, &len) != BN_OKAY) {
+ goto exit_len;
+ }
+
+ result = malloc(sizeof(large_base_t));
+ result->length = len + 1;
+ result->data = calloc(result->length, sizeof(bn_t));
+ bn_init(&result->m);
+ bn_copy(m, &result->m);
+
+ int i = 0;
+ while (!bn_is_0(&k) && !(bn_get_sign(&k) == BN_NEG)) {
+ bn_init(&result->data[i]);
+ if (mp_div(&k, m, &k, &result->data[i]) != BN_OKAY) {
+ free(result->data);
+ bn_clear(&result->m);
+ free(result);
+ goto exit_len;
+ }
+ i++;
+ }
+
+exit_len:
+ bn_clear(&k);
+exit_k:
+ return result;
} \ No newline at end of file
diff --git a/pyecsca/codegen/bn/bn.h b/pyecsca/codegen/bn/bn.h
index ed29970..7c25c22 100644
--- a/pyecsca/codegen/bn/bn.h
+++ b/pyecsca/codegen/bn/bn.h
@@ -58,6 +58,24 @@ typedef struct {
int w;
} wnaf_t;
+typedef struct {
+ uint8_t *data;
+ size_t length;
+ int w;
+} wsliding_t;
+
+typedef struct {
+ int *data;
+ size_t length;
+ int m;
+} small_base_t;
+
+typedef struct {
+ bn_t *data;
+ size_t length;
+ bn_t m;
+} large_base_t;
+
void math_init(void);
bn_err bn_init(bn_t *bn);
@@ -73,6 +91,7 @@ bn_err bn_from_int(unsigned int value, bn_t *out);
bn_err bn_to_binpad(const bn_t *one, uint8_t *data, size_t size);
bn_err bn_to_bin(const bn_t *one, uint8_t *data);
size_t bn_to_bin_size(const bn_t *one);
+unsigned int bn_to_int(const bn_t *one);
bn_err bn_rand_mod_sample(bn_t *out, const bn_t *mod);
bn_err bn_rand_mod_reduce(bn_t *out, const bn_t *mod);
@@ -104,6 +123,7 @@ void bn_red_clear(red_t *out);
bn_err bn_lsh(const bn_t *one, int amount, bn_t *out);
bn_err bn_rsh(const bn_t *one, int amount, bn_t *out);
+bn_err bn_and(const bn_t *one, const bn_t *other, bn_t *out);
bool bn_eq(const bn_t *one, const bn_t *other);
bool bn_is_0(const bn_t *one);
@@ -112,7 +132,14 @@ bn_sign bn_get_sign(const bn_t *one);
int bn_get_bit(const bn_t *bn, int which);
int bn_bit_length(const bn_t *bn);
+
wnaf_t *bn_wnaf(const bn_t *bn, int w);
wnaf_t *bn_bnaf(const bn_t *bn);
+wsliding_t *bn_wsliding_ltr(const bn_t *bn, int w);
+wsliding_t *bn_wsliding_rtl(const bn_t *bn, int w);
+
+small_base_t *bn_convert_base_small(const bn_t *bn, int m);
+large_base_t *bn_convert_base_large(const bn_t *bn, const bn_t *m);
+
#endif //BN_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/builder.py b/pyecsca/codegen/builder.py
index 2cd572b..e9a9144 100644
--- a/pyecsca/codegen/builder.py
+++ b/pyecsca/codegen/builder.py
@@ -4,7 +4,7 @@ import shutil
import subprocess
from copy import copy
from os import path
-from typing import List, Optional, Tuple, Type, MutableMapping
+from typing import List, Optional, Tuple, Type, MutableMapping, Any
import click
from public import public
@@ -13,7 +13,7 @@ from pyecsca.ec.configuration import (Multiplication, Squaring, Reduction, HashT
from pyecsca.ec.coordinates import CoordinateModel
from pyecsca.ec.formula import Formula, AdditionFormula
from pyecsca.ec.model import CurveModel
-from pyecsca.ec.mult import ScalarMultiplier
+from pyecsca.ec.mult import ScalarMultiplier, AccumulationOrder, ProcessingDirection
from .render import render
from .common import Platform, DeviceConfiguration, MULTIPLIERS, wrap_enum, get_model, get_coords
@@ -40,7 +40,7 @@ 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]+)*)\)",
+ "(?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))
@@ -61,7 +61,10 @@ def get_multiplier(ctx: click.Context, param, value: Optional[str]) -> Optional[
raise click.BadParameter(
"Multiplier {} requires formulas: {}, got {}.".format(mult_class.__name__,
mult_class.requires, classes))
- kwargs = eval("dict(" + args + ")")
+ 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))
@@ -74,6 +77,20 @@ def get_multiplier(ctx: click.Context, param, value: Optional[str]) -> Optional[
return mult
+def get_define(ctx: click.Context, param, values: Optional[List[str]]) -> Optional[MutableMapping[str, Any]]:
+ if values is None:
+ return None
+ res = {}
+ for val in values:
+ try:
+ k, v = val.split("=")
+ except:
+ k = val
+ v = 1
+ res[k] = v
+ return res
+
+
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
@click.version_option()
@public
@@ -119,6 +136,8 @@ def main():
show_default=True)
@click.option("--ecdsa/--no-ecdsa", help="Whether to enable ECDSA.", is_flag=True, default=True,
show_default=True)
+@click.option("-D", "--define", help="Set a custom C define.", multiple=True,
+ type=str, callback=get_define)
@click.option("--strip", help="Whether to strip the binary or not.", is_flag=True)
@click.option("--remove/--no-remove", help="Whether to remove the dir.", is_flag=True, default=True,
show_default=True)
@@ -135,7 +154,7 @@ def main():
@click.argument("outdir")
@click.pass_context
@public
-def build_impl(ctx, platform, hash, rand, mul, sqr, red, inv, keygen, ecdh, ecdsa, strip, remove,
+def build_impl(ctx, platform, hash, rand, mul, sqr, red, inv, keygen, ecdh, ecdsa, define, strip, remove,
verbose, model, coords, formulas, scalarmult, outdir):
"""This command builds an ECC implementation.
@@ -153,26 +172,30 @@ def build_impl(ctx, platform, hash, rand, mul, sqr, red, inv, keygen, ecdh, ecds
click.echo("[ ] Rendering...")
config = DeviceConfiguration(model, coords, formulas, scalarmult, hash, rand, mul, sqr, red,
- inv, platform, keygen, ecdh, ecdsa)
+ inv, platform, keygen, ecdh, ecdsa, define)
dir, elf_file, hex_file = render(config)
click.echo("[*] Rendered.")
click.echo("[ ] Building...")
- subprocess.run(["make"], cwd=dir, capture_output=not verbose)
- click.echo("[*] Built.")
-
- if strip:
- subprocess.run(["make", "strip"], cwd=dir, capture_output=not verbose)
- full_elf_path = path.join(dir, elf_file)
- full_hex_path = path.join(dir, hex_file)
- shutil.copy(full_elf_path, outdir)
- shutil.copy(full_hex_path, outdir)
- click.echo(elf_file)
- click.echo(hex_file)
- if remove:
+ result = subprocess.run(["make"], cwd=dir, capture_output=not verbose)
+ if result.returncode != 0:
+ click.echo("[x] Build failed.")
shutil.rmtree(dir)
else:
- click.echo(dir)
+ click.echo("[*] Built.")
+
+ if strip:
+ subprocess.run(["make", "strip"], cwd=dir, capture_output=not verbose)
+ full_elf_path = path.join(dir, elf_file)
+ full_hex_path = path.join(dir, hex_file)
+ shutil.copy(full_elf_path, outdir)
+ shutil.copy(full_hex_path, outdir)
+ click.echo(elf_file)
+ click.echo(hex_file)
+ if remove:
+ shutil.rmtree(dir)
+ else:
+ click.echo(dir)
@main.command("list")
diff --git a/pyecsca/codegen/common.py b/pyecsca/codegen/common.py
index 56ca261..ffe4710 100644
--- a/pyecsca/codegen/common.py
+++ b/pyecsca/codegen/common.py
@@ -1,5 +1,5 @@
from dataclasses import dataclass
-from typing import Type, Optional
+from typing import Type, Optional, MutableMapping, Any
import click
from public import public
@@ -7,9 +7,21 @@ from pyecsca.ec.configuration import EnumDefine, Configuration
from pyecsca.ec.coordinates import CoordinateModel
from pyecsca.ec.model import (CurveModel, ShortWeierstrassModel, MontgomeryModel, EdwardsModel,
TwistedEdwardsModel)
-from pyecsca.ec.mult import (LTRMultiplier, RTLMultiplier, CoronMultiplier,
- LadderMultiplier, SimpleLadderMultiplier, DifferentialLadderMultiplier,
- WindowNAFMultiplier, BinaryNAFMultiplier)
+from pyecsca.ec.mult import (
+ LTRMultiplier,
+ RTLMultiplier,
+ CoronMultiplier,
+ LadderMultiplier,
+ SimpleLadderMultiplier,
+ DifferentialLadderMultiplier,
+ WindowNAFMultiplier,
+ BinaryNAFMultiplier,
+ SlidingWindowMultiplier,
+ FixedWindowLTRMultiplier,
+ FullPrecompMultiplier,
+ BGMWMultiplier,
+ CombMultiplier,
+)
@public
@@ -28,44 +40,31 @@ class DeviceConfiguration(Configuration):
"""A device configuration that includes the platform and choices
specific to the pyecsca-codegened implementations."""
platform: Platform
+ """The platform to build for."""
keygen: bool
+ """Whether the key-generation command is present."""
ecdh: bool
+ """Whether the ECDH command is present."""
ecdsa: bool
+ """Whether the ECDSA command is present."""
+ defines: Optional[MutableMapping[str, Any]] = None
+ """Optional defines passed to the compilation."""
MULTIPLIERS = [
- {
- "name": ("ltr", "LTRMultiplier"),
- "class": LTRMultiplier
- },
- {
- "name": ("rtl", "RTLMultiplier"),
- "class": RTLMultiplier
- },
- {
- "name": ("coron", "CoronMultiplier"),
- "class": CoronMultiplier
- },
- {
- "name": ("ldr", "LadderMultiplier"),
- "class": LadderMultiplier
- },
- {
- "name": ("simple-ldr", "SimpleLadderMultiplier"),
- "class": SimpleLadderMultiplier
- },
- {
- "name": ("diff-ldr", "DifferentialLadderMultiplier"),
- "class": DifferentialLadderMultiplier
- },
- {
- "name": ("naf", "bnaf", "BinaryNAFMultiplier"),
- "class": BinaryNAFMultiplier
- },
- {
- "name": ("wnaf", "WindowNAFMultiplier"),
- "class": WindowNAFMultiplier
- }
+ {"name": ("ltr", "LTRMultiplier"), "class": LTRMultiplier},
+ {"name": ("rtl", "RTLMultiplier"), "class": RTLMultiplier},
+ {"name": ("coron", "CoronMultiplier"), "class": CoronMultiplier},
+ {"name": ("ldr", "LadderMultiplier"), "class": LadderMultiplier},
+ {"name": ("simple-ldr", "SimpleLadderMultiplier"), "class": SimpleLadderMultiplier},
+ {"name": ("diff-ldr", "DifferentialLadderMultiplier"), "class": DifferentialLadderMultiplier},
+ {"name": ("naf", "bnaf", "BinaryNAFMultiplier"), "class": BinaryNAFMultiplier},
+ {"name": ("wnaf", "WindowNAFMultiplier"), "class": WindowNAFMultiplier},
+ {"name": ("sliding", "SlidingWindowMultiplier"), "class": SlidingWindowMultiplier},
+ {"name": ("fixed", "FixedWindowLTRMultiplier"), "class": FixedWindowLTRMultiplier},
+ {"name": ("precomp", "FullPrecompMultiplier"), "class": FullPrecompMultiplier},
+ {"name": ("bgmw", "BGMWMultiplier"), "class": BGMWMultiplier},
+ {"name": ("comb", "CombMultiplier"), "class": CombMultiplier},
]
diff --git a/pyecsca/codegen/point.h b/pyecsca/codegen/point.h
index 01dd4b4..fd3736e 100644
--- a/pyecsca/codegen/point.h
+++ b/pyecsca/codegen/point.h
@@ -51,4 +51,6 @@ void point_ladd(const point_t *one, const point_t *other, const point_t *diff, c
bool point_ladd_init(void);
void point_ladd_clear(void);
+void point_accumulate(const point_t *one, const point_t *other, const curve_t *curve, point_t *out_one);
+
#endif //POINT_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/prng/KeccakP-200-compact.c b/pyecsca/codegen/prng/KeccakP-200-compact.c
index 42c972b..f07bae9 100644
--- a/pyecsca/codegen/prng/KeccakP-200-compact.c
+++ b/pyecsca/codegen/prng/KeccakP-200-compact.c
@@ -169,7 +169,9 @@ void KeccakP200_Permute_18rounds(void *argState)
void KeccakP200_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length)
{
- memcpy(data, (UINT8*)state+offset, length);
+ if (length) {
+ memcpy(data, (UINT8*)state+offset, length);
+ }
}
/* ---------------------------------------------------------------- */
diff --git a/pyecsca/codegen/render.py b/pyecsca/codegen/render.py
index 7202e86..241ee6a 100644
--- a/pyecsca/codegen/render.py
+++ b/pyecsca/codegen/render.py
@@ -7,15 +7,30 @@ from os import makedirs
from typing import Optional, List, Set, Mapping, MutableMapping, Any, Tuple
from jinja2 import Environment, PackageLoader
-from importlib_resources import files, as_file
+from importlib_resources import files
from public import public
from pyecsca.ec.configuration import HashType, RandomMod, Reduction, Multiplication, Squaring
from pyecsca.ec.coordinates import CoordinateModel
from pyecsca.ec.formula import Formula
from pyecsca.ec.model import CurveModel
-from pyecsca.ec.mult import (ScalarMultiplier, LTRMultiplier, RTLMultiplier, CoronMultiplier,
- LadderMultiplier, SimpleLadderMultiplier, DifferentialLadderMultiplier,
- BinaryNAFMultiplier)
+from pyecsca.ec.mult import (
+ ScalarMultiplier,
+ LTRMultiplier,
+ RTLMultiplier,
+ CoronMultiplier,
+ LadderMultiplier,
+ SimpleLadderMultiplier,
+ DifferentialLadderMultiplier,
+ BinaryNAFMultiplier,
+ WindowNAFMultiplier,
+ SlidingWindowMultiplier,
+ FixedWindowLTRMultiplier,
+ FullPrecompMultiplier,
+ BGMWMultiplier,
+ CombMultiplier,
+ AccumulationOrder,
+ ProcessingDirection
+)
from pyecsca.ec.op import OpType, CodeOp
from pyecsca.codegen.common import Platform, DeviceConfiguration
@@ -25,6 +40,9 @@ env = Environment(
)
env.globals["isinstance"] = isinstance
+env.globals["bin"] = bin
+env.globals["AccumulationOrder"] = AccumulationOrder
+env.globals["ProcessingDirection"] = ProcessingDirection
def render_op(op: OpType, result: str, left: str, right: str, mod: str, red: str) -> Optional[str]:
@@ -148,7 +166,7 @@ def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str],
frees=frees, returns=returns)
-def render_coords_impl(coords: CoordinateModel) -> str:
+def render_coords_impl(coords: CoordinateModel, accumulation_order: Optional[AccumulationOrder]) -> str:
ops = []
for s in coords.satisfying:
try:
@@ -168,7 +186,8 @@ def render_coords_impl(coords: CoordinateModel) -> str:
namespace["frees"] = {}
return env.get_template("point.c").render(variables=coords.variables, **namespace,
- to_affine_rets=returns, to_affine_frees=frees)
+ to_affine_rets=returns, to_affine_frees=frees,
+ accumulation_order=accumulation_order)
def render_formulas_impl(formulas: Set[Formula]) -> str:
@@ -205,7 +224,13 @@ def render_scalarmult_impl(scalarmult: ScalarMultiplier) -> str:
LadderMultiplier=LadderMultiplier,
SimpleLadderMultiplier=SimpleLadderMultiplier,
DifferentialLadderMultiplier=DifferentialLadderMultiplier,
- BinaryNAFMultiplier=BinaryNAFMultiplier)
+ BinaryNAFMultiplier=BinaryNAFMultiplier,
+ WindowNAFMultiplier=WindowNAFMultiplier,
+ SlidingWindowMultiplier=SlidingWindowMultiplier,
+ FixedWindowLTRMultiplier=FixedWindowLTRMultiplier,
+ FullPrecompMultiplier=FullPrecompMultiplier,
+ BGMWMultiplier=BGMWMultiplier,
+ CombMultiplier=CombMultiplier)
def render_action() -> str:
@@ -225,10 +250,10 @@ def render_main(model: CurveModel, coords: CoordinateModel, keygen: bool, ecdh:
def render_makefile(platform: Platform, hash_type: HashType, mod_rand: RandomMod,
- reduction: Reduction, mul: Multiplication, sqr: Squaring) -> str:
+ reduction: Reduction, mul: Multiplication, sqr: Squaring, defines: Optional[MutableMapping[str, Any]]) -> str:
return env.get_template("Makefile").render(platform=str(platform), hash_type=str(hash_type),
mod_rand=str(mod_rand), reduction=str(reduction),
- mul=str(mul), sqr=str(sqr))
+ mul=str(mul), sqr=str(sqr), defines=defines)
def save_render(dir: str, fname: str, rendered: str):
@@ -253,11 +278,11 @@ def render(config: DeviceConfiguration) -> Tuple[str, str, str]:
makedirs(gen_dir, exist_ok=True)
save_render(temp, "Makefile",
- render_makefile(config.platform, config.hash_type, config.mod_rand, config.red, config.mult, config.sqr))
+ render_makefile(config.platform, config.hash_type, config.mod_rand, config.red, config.mult, config.sqr, config.defines))
save_render(temp, "main.c",
render_main(config.model, config.coords, config.keygen, config.ecdh, config.ecdsa))
save_render(gen_dir, "defs.h", render_defs(config.model, config.coords))
- save_render(gen_dir, "point.c", render_coords_impl(config.coords))
+ save_render(gen_dir, "point.c", render_coords_impl(config.coords, getattr(config.scalarmult, "accumulation_order", None)))
save_render(gen_dir, "formulas.c", render_formulas_impl(config.formulas))
for formula in config.formulas:
save_render(gen_dir, f"formula_{formula.shortname}.c",
diff --git a/pyecsca/codegen/templates/Makefile b/pyecsca/codegen/templates/Makefile
index 79e5c20..1b6922c 100644
--- a/pyecsca/codegen/templates/Makefile
+++ b/pyecsca/codegen/templates/Makefile
@@ -6,6 +6,10 @@ PLATFORM = {{ platform }}
CDEFS += -DHASH={{ hash_type }} -DMOD_RAND={{ mod_rand }} -DREDUCTION={{ reduction }} -DMUL={{ mul }} -DSQR={{ sqr }}
+{%- if defines %}
+CDEFS += {%- for def, value in defines.items() -%}-D{{def}}={{value}} {%- endfor -%}
+{%- endif %}
+
MKDIR_LIST += hash prng asn1 bn gen
EXTRAINCDIRS += hash prng asn1 bn gen tommath
diff --git a/pyecsca/codegen/templates/formula_add.c b/pyecsca/codegen/templates/formula_add.c
index 3d7e394..39d12b6 100644
--- a/pyecsca/codegen/templates/formula_add.c
+++ b/pyecsca/codegen/templates/formula_add.c
@@ -10,7 +10,7 @@
void point_add(const point_t *one, const point_t *other, const curve_t *curve, point_t *out_one) {
{{ start_action("add") }}
- NOP_128();
+ //NOP_128();
{%- if short_circuit %}
if (point_equals(one, curve->neutral)) {
point_set(other, out_one);
@@ -24,6 +24,6 @@ void point_add(const point_t *one, const point_t *other, const curve_t *curve, p
{{ ops.render_initializations(initializations) }}
{{ ops.render_ops(operations) }}
{{ ops.render_returns(returns) }}
- NOP_128();
+ //NOP_128();
{{ end_action("add") }}
} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/formula_dadd.c b/pyecsca/codegen/templates/formula_dadd.c
index 0605b23..855cf5d 100644
--- a/pyecsca/codegen/templates/formula_dadd.c
+++ b/pyecsca/codegen/templates/formula_dadd.c
@@ -10,11 +10,11 @@
void point_dadd(const point_t *one, const point_t *other, const point_t *diff, const curve_t *curve, point_t *out_one) {
{{ start_action("dadd") }}
- NOP_128();
+ //NOP_128();
// TODO: short-circuits
{{ ops.render_initializations(initializations) }}
{{ ops.render_ops(operations) }}
{{ ops.render_returns(returns) }}
- NOP_128();
+ //NOP_128();
{{ end_action("dadd") }}
}
diff --git a/pyecsca/codegen/templates/formula_dbl.c b/pyecsca/codegen/templates/formula_dbl.c
index b741572..3c10bd7 100644
--- a/pyecsca/codegen/templates/formula_dbl.c
+++ b/pyecsca/codegen/templates/formula_dbl.c
@@ -10,7 +10,7 @@
void point_dbl(const point_t *one, const curve_t *curve, point_t *out_one) {
{{ start_action("dbl") }}
- NOP_128();
+ //NOP_128();
{%- if short_circuit %}
if (point_equals(one, curve->neutral)) {
point_set(one, out_one);
@@ -20,6 +20,6 @@ void point_dbl(const point_t *one, const curve_t *curve, point_t *out_one) {
{{ ops.render_initializations(initializations) }}
{{ ops.render_ops(operations) }}
{{ ops.render_returns(returns) }}
- NOP_128();
+ //NOP_128();
{{ end_action("dbl") }}
} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/formula_ladd.c b/pyecsca/codegen/templates/formula_ladd.c
index 6155185..2eaa531 100644
--- a/pyecsca/codegen/templates/formula_ladd.c
+++ b/pyecsca/codegen/templates/formula_ladd.c
@@ -10,11 +10,11 @@
void point_ladd(const point_t *one, const point_t *other, const point_t *diff, const curve_t *curve, point_t *out_one, point_t *out_other) {
{{ start_action("ladd") }}
- NOP_128();
+ //NOP_128();
// TODO: short-circuits
{{ ops.render_initializations(initializations) }}
{{ ops.render_ops(operations) }}
{{ ops.render_returns(returns) }}
- NOP_128();
+ //NOP_128();
{{ end_action("ladd") }}
} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/formula_neg.c b/pyecsca/codegen/templates/formula_neg.c
index f8d0e14..4eaf62d 100644
--- a/pyecsca/codegen/templates/formula_neg.c
+++ b/pyecsca/codegen/templates/formula_neg.c
@@ -10,7 +10,7 @@
void point_neg(const point_t *one, const curve_t *curve, point_t *out_one) {
{{ start_action("neg") }}
- NOP_128();
+ //NOP_128();
{%- if short_circuit %}
if (point_equals(one, curve->neutral)) {
point_set(one, out_one);
@@ -20,6 +20,6 @@ void point_neg(const point_t *one, const curve_t *curve, point_t *out_one) {
{{ ops.render_initializations(initializations) }}
{{ ops.render_ops(operations) }}
{{ ops.render_returns(returns) }}
- NOP_128();
+ //NOP_128();
{{ end_action("neg") }}
} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/formula_scl.c b/pyecsca/codegen/templates/formula_scl.c
index 8a840e9..dfcfcbe 100644
--- a/pyecsca/codegen/templates/formula_scl.c
+++ b/pyecsca/codegen/templates/formula_scl.c
@@ -10,7 +10,7 @@
void point_scl(const point_t *one, const curve_t *curve, point_t *out_one) {
{{ start_action("scl") }}
- NOP_128();
+ //NOP_128();
{%- if short_circuit %}
if (point_equals(one, curve->neutral)) {
point_set(one, out_one);
@@ -20,6 +20,6 @@ void point_scl(const point_t *one, const curve_t *curve, point_t *out_one) {
{{ ops.render_initializations(initializations) }}
{{ ops.render_ops(operations) }}
{{ ops.render_returns(returns) }}
- NOP_128();
+ //NOP_128();
{{ end_action("scl") }}
} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/formula_tpl.c b/pyecsca/codegen/templates/formula_tpl.c
index 08a6278..40cf114 100644
--- a/pyecsca/codegen/templates/formula_tpl.c
+++ b/pyecsca/codegen/templates/formula_tpl.c
@@ -10,7 +10,7 @@
void point_tpl(const point_t *one, const curve_t *curve, point_t *out_one) {
{{ start_action("tpl") }}
- NOP_128();
+ //NOP_128();
{%- if short_circuit %}
if (point_equals(one, curve->neutral)) {
point_set(one, out_one);
@@ -20,6 +20,6 @@ void point_tpl(const point_t *one, const curve_t *curve, point_t *out_one) {
{{ ops.render_initializations(initializations) }}
{{ ops.render_ops(operations) }}
{{ ops.render_returns(returns) }}
- NOP_128();
+ //NOP_128();
{{ end_action("tpl") }}
} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/main.c b/pyecsca/codegen/templates/main.c
index 4d50cc2..8aed65a 100644
--- a/pyecsca/codegen/templates/main.c
+++ b/pyecsca/codegen/templates/main.c
@@ -562,15 +562,6 @@ static uint8_t cmd_set_trigger(uint8_t *data, uint16_t len) {
return 0;
}
-__attribute__((noinline)) void init(void) {
- // Initalize the platform, UART, triggers.
- platform_init();
- init_uart();
- trigger_setup();
-
- init_implementation();
-}
-
__attribute__((noinline)) void init_implementation(void) {
// Initialize some components that preallocate stuff.
prng_init();
@@ -583,6 +574,15 @@ __attribute__((noinline)) void init_implementation(void) {
bn_init(&privkey);
}
+__attribute__((noinline)) void init(void) {
+ // Initalize the platform, UART, triggers.
+ platform_init();
+ init_uart();
+ trigger_setup();
+
+ init_implementation();
+}
+
__attribute__((noinline)) void deinit(void) {
// Clear up allocated stuff.
bn_clear(&privkey);
@@ -616,7 +616,7 @@ int main(void) {
// Execute commands while SimpleSerial is alive.
//led_ok(1);
- while(simpleserial_get());
+ while(simpleserial_get()) {}
//led_ok(0);
deinit();
diff --git a/pyecsca/codegen/templates/mult.c b/pyecsca/codegen/templates/mult.c
index 0603bc0..22a385d 100644
--- a/pyecsca/codegen/templates/mult.c
+++ b/pyecsca/codegen/templates/mult.c
@@ -27,6 +27,30 @@
{% include "mult_bnaf.c" %}
+{%- elif isinstance(scalarmult, WindowNAFMultiplier) -%}
+
+ {% include "mult_wnaf.c" %}
+
+{%- elif isinstance(scalarmult, SlidingWindowMultiplier) -%}
+
+ {% include "mult_sliding_w.c" %}
+
+{%- elif isinstance(scalarmult, FixedWindowLTRMultiplier) -%}
+
+ {% include "mult_fixed_w.c" %}
+
+{%- elif isinstance(scalarmult, FullPrecompMultiplier) -%}
+
+ {% include "mult_precomp.c" %}
+
+{%- elif isinstance(scalarmult, BGMWMultiplier) -%}
+
+ {% include "mult_bgmw.c" %}
+
+{%- elif isinstance(scalarmult, CombMultiplier) -%}
+
+ {% include "mult_comb.c" %}
+
{%- endif %}
diff --git a/pyecsca/codegen/templates/mult_bgmw.c b/pyecsca/codegen/templates/mult_bgmw.c
new file mode 100644
index 0000000..5298fb1
--- /dev/null
+++ b/pyecsca/codegen/templates/mult_bgmw.c
@@ -0,0 +1,64 @@
+#include "mult.h"
+#include "point.h"
+
+
+
+static void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) {
+ point_t *a = point_copy(curve->neutral);
+ point_t *b = point_copy(curve->neutral);
+
+ int order_blen = bn_bit_length(&curve->n);
+ int d = (order_blen + {{ scalarmult.width }} - 1) / {{ scalarmult.width }};
+
+ point_t **points = malloc(sizeof(point_t *) * d);
+
+ point_t *current = point_copy(point);
+ for (int i = 0; i < d; i++) {
+ points[i] = point_copy(current);
+ if (i != d - 1) {
+ for (int j = 0; j < {{ scalarmult.width }}; j++) {
+ point_dbl(current, curve, current);
+ }
+ }
+ }
+ point_free(current);
+
+ small_base_t *bs = bn_convert_base_small(scalar, {{ 2**scalarmult.width }});
+
+ for (int j = {{ 2**scalarmult.width }}; j > 0; j--) {
+ {%- if scalarmult.direction == ProcessingDirection.RTL %}
+ for (int i = 0; i < bs->length; i++) {
+ if (bs->data[i] == j) {
+ point_accumulate(b, points[i], curve, b);
+ }
+ }
+ {%- else %}
+ for (int i = bs->length - 1; i >= 0; i--) {
+ if (bs->data[i] == j) {
+ point_accumulate(b, points[i], curve, b);
+ }
+ }
+ {%- endif -%}
+
+ {%- if scalarmult.short_circuit %}
+ if (point_equals(a, b)) {
+ point_dbl(b, curve, a);
+ continue;
+ }
+ {%- endif %}
+ point_accumulate(a, b, curve, a);
+ }
+ free(bs->data);
+ free(bs);
+
+ {%- if "scl" in scalarmult.formulas %}
+ point_scl(a, curve, a);
+ {%- endif %}
+ point_set(a, out);
+ for (long i = 0; i < d; i++) {
+ point_free(points[i]);
+ }
+ free(points);
+ point_free(a);
+ point_free(b);
+} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/mult_bnaf.c b/pyecsca/codegen/templates/mult_bnaf.c
index 33e7302..68d1569 100644
--- a/pyecsca/codegen/templates/mult_bnaf.c
+++ b/pyecsca/codegen/templates/mult_bnaf.c
@@ -1,22 +1,50 @@
#include "mult.h"
#include "point.h"
-static void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) {
- point_t *neg = point_new();
- point_neg(point, curve, neg);
- point_t *q = point_copy(curve->neutral);
-
- wnaf_t *naf = bn_bnaf(scalar);
-
+point_t *scalar_mult_ltr(point_t *point, point_t *neg, curve_t *curve, wnaf_t *naf) {
+ point_t *q = point_copy(curve->neutral);
for (long i = naf->length - 1; i >= 0; i--) {
point_dbl(q, curve, q);
if (naf->data[i] == 1) {
- point_add(q, point, curve, q);
+ point_accumulate(q, point, curve, q);
} else if (naf->data[i] == -1) {
- point_add(q, neg, curve, q);
+ point_accumulate(q, neg, curve, q);
}
}
- free(naf->data);
+ return q;
+}
+
+point_t* scalar_mult_rtl(point_t *point, point_t *neg, curve_t *curve, wnaf_t *naf) {
+ point_t *r = point_copy(point);
+ point_t *q = point_copy(curve->neutral);
+ point_t *r_neg = point_new();
+ for (long i = 0; i < naf->length; i++) {
+ if (naf->data[i] == 1) {
+ point_accumulate(q, r, curve, q);
+ } else if (naf->data[i] == -1) {
+ point_neg(r, curve, r_neg);
+ point_accumulate(q, r_neg, curve, q);
+ }
+ point_dbl(r, curve, r);
+ }
+ point_free(r_neg);
+ point_free(r);
+
+ return q;
+}
+
+static void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) {
+ point_t *neg = point_new();
+ point_neg(point, curve, neg);
+ wnaf_t *naf = bn_bnaf(scalar);
+
+ {% if scalarmult.direction == ProcessingDirection.LTR %}
+ point_t *q = scalar_mult_ltr(point, neg, curve, naf);
+ {% elif scalarmult.direction == ProcessingDirection.RTL %}
+ point_t *q = scalar_mult_rtl(point, neg, curve, naf);
+ {% endif %}
+
+ free(naf->data);
free(naf);
{%- if "scl" in scalarmult.formulas %}
diff --git a/pyecsca/codegen/templates/mult_comb.c b/pyecsca/codegen/templates/mult_comb.c
new file mode 100644
index 0000000..9df9796
--- /dev/null
+++ b/pyecsca/codegen/templates/mult_comb.c
@@ -0,0 +1,77 @@
+#include "mult.h"
+#include "point.h"
+
+static void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) {
+ point_t *q = point_copy(curve->neutral);
+
+ int order_blen = bn_bit_length(&curve->n);
+ int d = (order_blen + {{ scalarmult.width }} - 1) / {{ scalarmult.width }};
+
+ point_t *base_points[{{ scalarmult.width }}];
+
+ point_t *current = point_copy(point);
+ for (int i = 0; i < {{ scalarmult.width }}; i++) {
+ base_points[i] = point_copy(current);
+ if (i != d - 1) {
+ for (int j = 0; j < d; j++) {
+ point_dbl(current, curve, current);
+ }
+ }
+ }
+ point_free(current);
+
+ point_t *points[{{ 2**scalarmult.width }}];
+ for (int j = 0; j < {{ 2**scalarmult.width }}; j++) {
+ point_t *alloc_point = NULL;
+ for (int i = 0; i < {{ scalarmult.width }}; i++) {
+ if (j & (1 << i)) {
+ if (alloc_point) {
+ point_accumulate(alloc_point, base_points[i], curve, alloc_point);
+ } else {
+ alloc_point = point_copy(base_points[i]);
+ }
+ }
+ }
+ points[j] = alloc_point;
+ }
+
+ bn_t base; bn_init(&base);
+ bn_from_int(1, &base);
+ bn_lsh(&base, d, &base);
+
+ large_base_t *bs = bn_convert_base_large(scalar, &base);
+ for (int i = d - 1; i >= 0; i--) {
+ point_dbl(q, curve, q);
+ int word = 0;
+ for (int j = 0; j < {{ scalarmult.width }}; j++) {
+ if (j < bs->length) {
+ word |= bn_get_bit(&bs->data[j], i) << j;
+ }
+ }
+ if (word) {
+ point_accumulate(q, points[word], curve, q);
+ }
+ }
+ for (int i = 0; i < bs->length; i++) {
+ bn_clear(&bs->data[i]);
+ }
+ free(bs->data);
+ bn_clear(&bs->m);
+ free(bs);
+ bn_clear(&base);
+
+
+ {%- if "scl" in scalarmult.formulas %}
+ point_scl(a, curve, a);
+ {%- endif %}
+ point_set(q, out);
+ for (int i = 0; i < {{ scalarmult.width }}; i++) {
+ point_free(base_points[i]);
+ }
+ for (int i = 0; i < {{ 2**scalarmult.width }}; i++) {
+ if (points[i]) {
+ point_free(points[i]);
+ }
+ }
+ point_free(q);
+} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/mult_fixed_w.c b/pyecsca/codegen/templates/mult_fixed_w.c
new file mode 100644
index 0000000..b0a4bb0
--- /dev/null
+++ b/pyecsca/codegen/templates/mult_fixed_w.c
@@ -0,0 +1,63 @@
+#include "mult.h"
+#include "point.h"
+
+void scalar_mult_by_m_pow2(point_t *point, curve_t *curve) {
+ unsigned int m = {{ scalarmult.m }} >> 1;
+ while (m) {
+ point_dbl(point, curve, point);
+ m >>= 1;
+ }
+}
+
+void scalar_mult_by_m_base(point_t *point, curve_t *curve) {
+ point_t *orig = point_copy(point);
+ point_dbl(orig, curve, point);
+ for (int i = 0; i < {{ scalarmult.m - 2}}; i++) {
+ point_add(point, orig, curve, point);
+ }
+ point_free(orig);
+}
+
+static void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) {
+ point_t *q = point_copy(curve->neutral);
+ point_t *points[{{ scalarmult.m }}];
+
+ point_t *current = point_copy(point);
+ point_t *dbl = point_new();
+ point_dbl(current, curve, dbl);
+ points[0] = point_copy(current);
+ points[1] = point_copy(dbl);
+ point_set(dbl, current);
+ for (long i = 2; i < {{ scalarmult.m }}; i++) {
+ point_add(current, point, curve, current);
+ points[i] = point_copy(current);
+ }
+ point_free(current);
+ point_free(dbl);
+
+ small_base_t *bs = bn_convert_base_small(scalar, {{ scalarmult.m }});
+
+ for (long i = bs->length - 1; i >= 0; i--) {
+ {%- if bin(scalarmult.m).count("1") == 1 %}
+ scalar_mult_by_m_pow2(q, curve);
+ {%- else %}
+ scalar_mult_by_m_base(q, curve);
+ {%- endif %}
+
+ int val = bs->data[i];
+ if (val) {
+ point_accumulate(q, points[val-1], curve, q);
+ }
+ }
+ free(bs->data);
+ free(bs);
+
+ {%- if "scl" in scalarmult.formulas %}
+ point_scl(q, curve, q);
+ {%- endif %}
+ point_set(q, out);
+ for (long i = 0; i < {{ scalarmult.m }}; i++) {
+ point_free(points[i]);
+ }
+ point_free(q);
+} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/mult_ltr.c b/pyecsca/codegen/templates/mult_ltr.c
index f8bee19..d4aaf10 100644
--- a/pyecsca/codegen/templates/mult_ltr.c
+++ b/pyecsca/codegen/templates/mult_ltr.c
@@ -19,10 +19,10 @@ void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *ou
for (int i = nbits; i >= 0; i--) {
point_dbl(r, curve, r);
if (bn_get_bit(scalar, i) == 1) {
- point_add(r, q, curve, r);
+ point_accumulate(r, q, curve, r);
} else {
{%- if scalarmult.always %}
- point_add(r, q, curve, dummy);
+ point_accumulate(r, q, curve, dummy);
{%- endif %}
}
}
diff --git a/pyecsca/codegen/templates/mult_precomp.c b/pyecsca/codegen/templates/mult_precomp.c
new file mode 100644
index 0000000..cafa0a9
--- /dev/null
+++ b/pyecsca/codegen/templates/mult_precomp.c
@@ -0,0 +1,85 @@
+#include "mult.h"
+#include "point.h"
+
+void scalar_mult_ltr(int order_blen, point_t **points, bn_t *scalar, point_t *point, curve_t *curve) {
+ {%- if scalarmult.complete %}
+ int nbits = order_blen - 1;
+ {%- else %}
+ int nbits = bn_bit_length(scalar) - 1;
+ {%- endif %}
+
+ {%- if scalarmult.always %}
+ point_t *dummy = point_new();
+ {%- endif %}
+
+ for (int i = nbits; i >= 0; i--) {
+ if (bn_get_bit(scalar, i) == 1) {
+ point_accumulate(point, points[i], curve, point);
+ } else {
+ {%- if scalarmult.always %}
+ point_accumulate(point, points[i], curve, dummy);
+ {%- endif %}
+ }
+ }
+
+ {%- if scalarmult.always %}
+ point_free(dummy);
+ {%- endif %}
+}
+
+void scalar_mult_rtl(int order_blen, point_t **points, bn_t *scalar, point_t *point, curve_t *curve) {
+ {%- if scalarmult.complete %}
+ int nbits = order_blen;
+ {%- else %}
+ int nbits = bn_bit_length(scalar);
+ {%- endif %}
+
+ {%- if scalarmult.always %}
+ point_t *dummy = point_new();
+ {%- endif %}
+
+ for (int i = 0; i < nbits; i++) {
+ if (bn_get_bit(scalar, i) == 1) {
+ point_accumulate(point, points[i], curve, point);
+ } else {
+ {%- if scalarmult.always %}
+ point_accumulate(point, points[i], curve, dummy);
+ {%- endif %}
+ }
+ }
+
+ {%- if scalarmult.always %}
+ point_free(dummy);
+ {%- endif %}
+}
+
+static void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) {
+ point_t *q = point_copy(curve->neutral);
+ int order_blen = bn_bit_length(&curve->n);
+ point_t **points = malloc(sizeof(point_t *) * (order_blen + 1));
+
+ point_t *current = point_copy(point);
+ for (int i = 0; i < order_blen + 1; i++) {
+ points[i] = point_copy(current);
+ if (i != order_blen) {
+ point_dbl(current, curve, current);
+ }
+ }
+ point_free(current);
+
+ {%- if scalarmult.direction == ProcessingDirection.LTR %}
+ scalar_mult_ltr(order_blen, points, scalar, q, curve);
+ {%- else %}
+ scalar_mult_rtl(order_blen, points, scalar, q, curve);
+ {%- endif %}
+
+ {%- if "scl" in scalarmult.formulas %}
+ point_scl(q, curve, q);
+ {%- endif %}
+ point_set(q, out);
+ for (int i = 0; i < order_blen + 1; i++) {
+ point_free(points[i]);
+ }
+ free(points);
+ point_free(q);
+} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/mult_rtl.c b/pyecsca/codegen/templates/mult_rtl.c
index 9db12fb..71949b4 100644
--- a/pyecsca/codegen/templates/mult_rtl.c
+++ b/pyecsca/codegen/templates/mult_rtl.c
@@ -14,10 +14,10 @@ void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *ou
while (!bn_is_0(&copy)) {
if (bn_get_bit(&copy, 0) == 1) {
- point_add(r, q, curve, r);
+ point_accumulate(r, q, curve, r);
} else {
{%- if scalarmult.always %}
- point_add(r, q, curve, dummy);
+ point_accumulate(r, q, curve, dummy);
{%- endif %}
}
point_dbl(q, curve, q);
diff --git a/pyecsca/codegen/templates/mult_sliding_w.c b/pyecsca/codegen/templates/mult_sliding_w.c
new file mode 100644
index 0000000..1e80a84
--- /dev/null
+++ b/pyecsca/codegen/templates/mult_sliding_w.c
@@ -0,0 +1,43 @@
+#include "mult.h"
+#include "point.h"
+
+static void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) {
+ point_t *q = point_copy(curve->neutral);
+ point_t *points[{{ 2 ** (scalarmult.width - 1) }}];
+
+ point_t *current = point_copy(point);
+ point_t *dbl = point_new();
+ point_dbl(current, curve, dbl);
+ for (long i = 0; i < {{ 2 ** (scalarmult.width - 1) }}; i++) {
+ points[i] = point_copy(current);
+ point_add(current, dbl, curve, current);
+ }
+ point_free(current);
+ point_free(dbl);
+
+ {% if scalarmult.recoding_direction == ProcessingDirection.LTR %}
+ wsliding_t *ws = bn_wsliding_ltr(scalar, {{ scalarmult.width }});
+ {% elif scalarmult.recoding_direction == ProcessingDirection.RTL %}
+ wsliding_t *ws = bn_wsliding_rtl(scalar, {{ scalarmult.width }});
+ {% endif %}
+
+ for (long i = 0; i < ws->length; i++) {
+ point_dbl(q, curve, q);
+ uint8_t val = ws->data[i];
+ if (val) {
+ point_accumulate(q, points[(val - 1) / 2], curve, q);
+ }
+ }
+
+ {%- if "scl" in scalarmult.formulas %}
+ point_scl(q, curve, q);
+ {%- endif %}
+ point_set(q, out);
+
+ free(ws->data);
+ free(ws);
+ for (long i = 0; i < {{ 2 ** (scalarmult.width - 1) }}; i++) {
+ point_free(points[i]);
+ }
+ point_free(q);
+} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/mult_wnaf.c b/pyecsca/codegen/templates/mult_wnaf.c
new file mode 100644
index 0000000..3c5f2b2
--- /dev/null
+++ b/pyecsca/codegen/templates/mult_wnaf.c
@@ -0,0 +1,60 @@
+#include "mult.h"
+#include "point.h"
+
+static void scalar_mult_inner(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) {
+ point_t *q = point_copy(curve->neutral);
+ point_t *points[{{ 2 ** (scalarmult.width - 2) }}];
+ {%- if scalarmult.precompute_negation %}
+ point_t *points_neg[{{ 2 ** (scalarmult.width - 2) }}];
+ {%- else %}
+ point_t *neg = point_new();
+ {%- endif %}
+
+ point_t *current = point_copy(point);
+ point_t *dbl = point_new();
+ point_dbl(current, curve, dbl);
+ for (long i = 0; i < {{ 2 ** (scalarmult.width - 2) }}; i++) {
+ points[i] = point_copy(current);
+ {%- if scalarmult.precompute_negation %}
+ points_neg[i] = point_copy(current);
+ point_neg(points_neg[i], curve, points_neg[i]);
+ {%- endif %}
+ point_add(current, dbl, curve, current);
+ }
+ point_free(current);
+ point_free(dbl);
+
+ wnaf_t *naf = bn_wnaf(scalar, {{ scalarmult.width }});
+
+ for (long i = naf->length - 1; i >= 0; i--) {
+ point_dbl(q, curve, q);
+ int8_t val = naf->data[i];
+ if (val > 0) {
+ point_accumulate(q, points[(val - 1) / 2], curve, q);
+ } else if (val < 0) {
+ {%- if scalarmult.precompute_negation %}
+ point_accumulate(q, points_neg[(-val - 1) / 2], curve, q);
+ {%- else %}
+ point_neg(points[(-val - 1) / 2], curve, neg);
+ point_accumulate(q, neg, curve, q);
+ {%- endif %}
+ }
+ }
+ free(naf->data);
+ free(naf);
+
+ {%- if "scl" in scalarmult.formulas %}
+ point_scl(q, curve, q);
+ {%- endif %}
+ point_set(q, out);
+ for (long i = 0; i < {{ 2 ** (scalarmult.width - 2) }}; i++) {
+ point_free(points[i]);
+ {%- if scalarmult.precompute_negation %}
+ point_free(points_neg[i]);
+ {%- endif %}
+ }
+ {%- if not scalarmult.precompute_negation %}
+ point_free(neg);
+ {%- endif %}
+ point_free(q);
+} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/point.c b/pyecsca/codegen/templates/point.c
index e87ae36..bad232a 100644
--- a/pyecsca/codegen/templates/point.c
+++ b/pyecsca/codegen/templates/point.c
@@ -137,3 +137,11 @@ void point_from_affine(bn_t *x, bn_t *y, const curve_t *curve, point_t *out) {
{%- endfor %}
{{ end_action("coord_map") }}
}
+
+void point_accumulate(const point_t *one, const point_t *other, const curve_t *curve, point_t *out_one) {
+ {% if accumulation_order == AccumulationOrder.PeqPR %}
+ point_add(one, other, curve, out_one);
+ {% elif accumulation_order == AccumulationOrder.PeqRP %}
+ point_add(other, one, curve, out_one);
+ {% endif %}
+} \ No newline at end of file
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..d13b487
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,3 @@
+
+test_bn: test_bn.c ../pyecsca/codegen/bn/bn.c
+ gcc -o $@ $^ -fsanitize=address -fsanitize=undefined -I ../pyecsca/codegen/ -I ../pyecsca/codegen/tommath/ -L ../pyecsca/codegen/tommath/ -l:libtommath-HOST.a \ No newline at end of file
diff --git a/test/test_bn.c b/test/test_bn.c
new file mode 100644
index 0000000..66de22f
--- /dev/null
+++ b/test/test_bn.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "bn/bn.h"
+
+int test_wsliding_ltr() {
+ printf("test_wsliding_ltr: ");
+ bn_t bn;
+ bn_init(&bn);
+ bn_from_int(181, &bn);
+ wsliding_t *ws = bn_wsliding_ltr(&bn, 3);
+ if (ws == NULL) {
+ printf("NULL\n");
+ return 1;
+ }
+ if (ws->length != 6) {
+ printf("Bad length (%li instead of 6)\n", ws->length);
+ return 1;
+ }
+ uint8_t expected[6] = {5, 0, 0, 5, 0, 1};
+ for (int i = 0; i < 6; i++) {
+ if (ws->data[i] != expected[i]) {
+ printf("Bad data (%i instead of %i)\n", ws->data[i], expected[i]);
+ return 1;
+ }
+ }
+ printf("OK\n");
+ bn_clear(&bn);
+ free(ws->data);
+ free(ws);
+ return 0;
+}
+
+int test_wsliding_rtl() {
+ printf("test_wsliding_rtl: ");
+ bn_t bn;
+ bn_init(&bn);
+ bn_from_int(181, &bn);
+ wsliding_t *ws = bn_wsliding_rtl(&bn, 3);
+ if (ws == NULL) {
+ printf("NULL\n");
+ return 1;
+ }
+ if (ws->length != 8) {
+ printf("Bad length (%li instead of 8)\n", ws->length);
+ return 1;
+ }
+ uint8_t expected[8] = {1, 0, 0, 3, 0, 0, 0, 5};
+ for (int i = 0; i < 8; i++) {
+ if (ws->data[i] != expected[i]) {
+ printf("Bad data (%i instead of %i)\n", ws->data[i], expected[i]);
+ return 1;
+ }
+ }
+ printf("OK\n");
+ bn_clear(&bn);
+ free(ws->data);
+ free(ws);
+ return 0;
+}
+
+int test_convert_base() {
+ printf("test_convert_base: ");
+ bn_t bn;
+ bn_init(&bn);
+ bn_from_int(11, &bn);
+ small_base_t *bs = bn_convert_base_small(&bn, 2);
+ if (bs == NULL) {
+ printf("NULL\n");
+ return 1;
+ }
+ if (bs->length != 4) {
+ printf("Bad length (%li instead of 4)\n", bs->length);
+ return 1;
+ }
+ uint8_t expected[4] = {1, 1, 0, 1};
+ for (int i = 0; i < 4; i++) {
+ if (bs->data[i] != expected[i]) {
+ printf("Bad data (%i insead of %i)\n", bs->data[i], expected[i]);
+ return 1;
+ }
+ }
+ printf("OK\n");
+ bn_clear(&bn);
+ free(bs->data);
+ free(bs);
+ return 0;
+}
+
+int main(void) {
+ return test_wsliding_ltr() + test_wsliding_rtl() + test_convert_base();
+}
diff --git a/test/test_impl.py b/test/test_impl.py
index 6c58315..da42c33 100644
--- a/test/test_impl.py
+++ b/test/test_impl.py
@@ -1,318 +1,355 @@
from copy import copy
from os.path import join
import pytest
+from click.testing import CliRunner
from pyecsca.ec.key_agreement import ECDH_SHA1
+from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import (
LTRMultiplier,
RTLMultiplier,
CoronMultiplier,
BinaryNAFMultiplier,
+ WindowNAFMultiplier,
+ SlidingWindowMultiplier,
+ AccumulationOrder,
+ ProcessingDirection,
+ ScalarMultiplier,
+ FixedWindowLTRMultiplier,
+ FullPrecompMultiplier,
+ BGMWMultiplier,
+ CombMultiplier,
)
from pyecsca.ec.signature import ECDSA_SHA1, SignatureResult
from pyecsca.codegen.builder import build_impl
-from pyecsca.codegen.client import HostTarget
+from pyecsca.codegen.client import HostTarget, ImplTarget
-def do_basic_test(
- callback,
- runner,
- params,
- mult_class,
- formulas,
- mult_name,
- ecdsa,
- ecdh,
- **mult_kwargs,
-):
- other_args = [
- ("--mul", "KARATSUBA", "--sqr", "KARATSUBA"),
- ("--mul", "TOOM_COOK", "--sqr", "TOOM_COOK"),
- ("--red", "BARRETT"),
- ("--red", "MONTGOMERY"),
- ]
- for additional in other_args:
- with runner.isolated_filesystem() as tmpdir:
- runner.invoke(
- build_impl,
- [
- "--platform",
- "HOST",
- *additional,
- "--ecdsa" if ecdsa else "--no-ecdsa",
- "--ecdh" if ecdh else "--no-ecdh",
- params.curve.model.shortname,
- params.curve.coordinate_model.name,
- *formulas,
- f"{mult_name}({','.join(f'{key}={value}' for key, value in mult_kwargs.items())})",
- ".",
- ],
- )
- target = HostTarget(
- params.curve.model,
- params.curve.coordinate_model,
- binary=join(tmpdir, "pyecsca-codegen-HOST.elf"),
- )
- target.connect()
- target.set_params(params)
- formula_instances = [
- params.curve.coordinate_model.formulas[formula] for formula in formulas
- ]
- mult = mult_class(*formula_instances, **mult_kwargs)
- mult.init(params, params.generator)
- callback(target, mult, params)
- target.disconnect()
-
+@pytest.fixture(
+ scope="module",
+ params=[
+ pytest.param(("--mul", "KARATSUBA", "--sqr", "KARATSUBA"), id="Karatsuba"),
+ pytest.param(("--mul", "TOOM_COOK", "--sqr", "TOOM_COOK"), id="ToomCook"),
+ pytest.param(("--red", "BARRETT"), id="Barrett"),
+ pytest.param(("--red", "MONTGOMERY"), id="Montgomery"),
+ ],
+)
+def additional(request):
+ return request.param
-def test_init(cli_runner, secp128r1):
- def callback(target, mult, params):
- target.init_prng(bytes([0x12, 0x34, 0x56, 0x78]))
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- LTRMultiplier,
- ["add-1998-cmo", "dbl-1998-cmo"],
- "ltr",
- False,
- False,
- )
+@pytest.fixture(
+ scope="module",
+ params=[
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": False},
+ ),
+ id="LTR1",
+ ),
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": True},
+ ),
+ id="LTR2",
+ ),
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": False, "always": True},
+ ),
+ id="LTR3",
+ ),
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": True, "always": True},
+ ),
+ id="LTR4",
+ ),
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": False, "accumulation_order": AccumulationOrder.PeqRP},
+ ),
+ id="LTR5",
+ ),
+ pytest.param(
+ (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
+ id="RTL1",
+ ),
+ pytest.param(
+ (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
+ id="RTL2",
+ ),
+ pytest.param(
+ (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}), id="Coron"
+ ),
+ pytest.param(
+ (
+ BinaryNAFMultiplier,
+ "bnaf",
+ ["add-1998-cmo", "dbl-1998-cmo", "neg"],
+ {"direction": ProcessingDirection.LTR},
+ ),
+ id="BNAF1",
+ ),
+ pytest.param(
+ (
+ BinaryNAFMultiplier,
+ "bnaf",
+ ["add-1998-cmo", "dbl-1998-cmo", "neg"],
+ {"direction": ProcessingDirection.RTL},
+ ),
+ id="BNAF2",
+ ),
+ pytest.param(
+ (
+ WindowNAFMultiplier,
+ "wnaf",
+ ["add-1998-cmo", "dbl-1998-cmo", "neg"],
+ {"width": 3},
+ ),
+ id="WNAF1",
+ ),
+ pytest.param(
+ (
+ WindowNAFMultiplier,
+ "wnaf",
+ ["add-1998-cmo", "dbl-1998-cmo", "neg"],
+ {"width": 3, "precompute_negation": True},
+ ),
+ id="WNAF2",
+ ),
+ pytest.param(
+ (
+ SlidingWindowMultiplier,
+ "sliding",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 3},
+ ),
+ id="SLI1",
+ ),
+ pytest.param(
+ (
+ SlidingWindowMultiplier,
+ "sliding",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 3, "recoding_direction": ProcessingDirection.RTL},
+ ),
+ id="SLI2",
+ ),
+ pytest.param(
+ (
+ FixedWindowLTRMultiplier,
+ "fixed",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"m": 4},
+ ),
+ id="FIX1",
+ ),
+ pytest.param(
+ (
+ FixedWindowLTRMultiplier,
+ "fixed",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"m": 5},
+ ),
+ id="FIX2",
+ ),
+ pytest.param(
+ (
+ FullPrecompMultiplier,
+ "precomp",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"direction": ProcessingDirection.LTR},
+ ),
+ id="PRE1",
+ ),
+ pytest.param(
+ (
+ FullPrecompMultiplier,
+ "precomp",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"direction": ProcessingDirection.RTL},
+ ),
+ id="PRE2",
+ ),
+ pytest.param(
+ (
+ BGMWMultiplier,
+ "bgmw",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 3, "direction": ProcessingDirection.LTR},
+ ),
+ id="BGMW1",
+ ),
+ pytest.param(
+ (
+ BGMWMultiplier,
+ "bgmw",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 5, "direction": ProcessingDirection.RTL},
+ ),
+ id="BGMW2",
+ ),
+ pytest.param(
+ (
+ CombMultiplier,
+ "comb",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 3},
+ ),
+ id="Comb1",
+ ),
+ pytest.param(
+ (
+ CombMultiplier,
+ "comb",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 5},
+ ),
+ id="Comb2",
+ ),
+ ],
+)
+def target(request, additional, secp128r1) -> ImplTarget:
+ mult_class, mult_name, formulas, mult_kwargs = request.param
+ runner = CliRunner()
+ with runner.isolated_filesystem() as tmpdir:
+ res = runner.invoke(
+ build_impl,
+ [
+ "--platform",
+ "HOST",
+ *additional,
+ "--ecdsa",
+ "--ecdh",
+ secp128r1.curve.model.shortname,
+ secp128r1.curve.coordinate_model.name,
+ *formulas,
+ f"{mult_name}({','.join(f'{key}={value}' for key, value in mult_kwargs.items())})",
+ ".",
+ ],
+ env={
+ "CFLAGS": "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all"
+ },
+ )
+ assert res.exit_code == 0
+ target = HostTarget(
+ secp128r1.curve.model,
+ secp128r1.curve.coordinate_model,
+ binary=join(tmpdir, "pyecsca-codegen-HOST.elf"),
+ )
+ formula_instances = [
+ secp128r1.curve.coordinate_model.formulas[formula] for formula in formulas
+ ]
+ mult = mult_class(*formula_instances, **mult_kwargs)
+ target.mult = mult
+ yield target
-def test_setup(cli_runner, secp128r1):
- def callback(target, mult, params):
- priv = 57
- pub = mult.multiply(priv).to_affine()
- target.set_privkey(priv)
- target.set_pubkey(pub)
+@pytest.fixture(scope="module")
+def mult(target) -> ScalarMultiplier:
+ return target.mult # noqa
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- LTRMultiplier,
- ["add-1998-cmo", "dbl-1998-cmo"],
- "ltr",
- False,
- False,
- )
+def test_init(target):
+ target.connect()
+ target.init_prng(bytes([0x12, 0x34, 0x56, 0x78]))
+ target.disconnect()
-def test_debug(cli_runner, secp128r1):
- def callback(target, mult, params):
- model, coords = target.debug()
- assert model == params.curve.model.shortname
- assert coords == params.curve.coordinate_model.name
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- LTRMultiplier,
- ["add-1998-cmo", "dbl-1998-cmo"],
- "ltr",
- False,
- False,
- )
+def test_setup(target, mult, secp128r1):
+ priv = 57
+ mult.init(secp128r1, secp128r1.generator)
+ pub = mult.multiply(priv).to_affine()
+ target.connect()
+ target.set_privkey(priv)
+ target.set_pubkey(pub)
+ target.disconnect()
-@pytest.mark.parametrize(
- "mult_class,mult_name,formulas,mult_kwargs",
- [
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": False}),
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": True}),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": False, "always": True},
- ),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": True, "always": True},
- ),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
- (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}),
- (BinaryNAFMultiplier, "bnaf", ["add-1998-cmo", "dbl-1998-cmo", "neg"], {}),
- ],
-)
-def test_keygen(mult_class, mult_name, mult_kwargs, formulas, cli_runner, secp128r1):
- def callback(target, mult, params):
- for _ in range(10):
- priv, pub = target.generate()
- assert params.curve.is_on_curve(pub)
- expected = mult.multiply(priv).to_affine()
- assert pub == expected
+def test_debug(target, secp128r1):
+ target.connect()
+ model, coords = target.debug()
+ assert model == secp128r1.curve.model.shortname
+ assert coords == secp128r1.curve.coordinate_model.name
+ target.disconnect()
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- mult_class,
- formulas,
- mult_name,
- False,
- False,
- **mult_kwargs,
- )
- # def test_ladder(self):
- # runner = CliRunner()
- # self.do_keygen_test(runner, self.curve25519, LadderMultiplier, ["ladd-1987-m", "dbl-1987-m"], "ldr")
- # # TODO: what about coords where generator is not affine?
+def test_keygen(target, mult, secp128r1):
+ target.connect()
+ target.set_params(secp128r1)
+ mult.init(secp128r1, secp128r1.generator)
+ for _ in range(10):
+ priv, pub = target.generate()
+ assert secp128r1.curve.is_on_curve(pub)
+ expected = mult.multiply(priv).to_affine()
+ assert pub == expected
+ target.disconnect()
-@pytest.mark.parametrize(
- "mult_class,mult_name,formulas,mult_kwargs",
- [
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": False}),
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": True}),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": False, "always": True},
- ),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": True, "always": True},
- ),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
- (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}),
- (BinaryNAFMultiplier, "bnaf", ["add-1998-cmo", "dbl-1998-cmo", "neg"], {}),
- ],
-)
-def test_scalarmult(
- mult_class, mult_name, mult_kwargs, formulas, cli_runner, secp128r1
-):
+def test_scalarmult(target, mult, secp128r1):
+ target.connect()
+ target.set_params(secp128r1)
+ mult.init(secp128r1, secp128r1.generator)
values = [15, 2355498743, 3253857901321912443757746]
+ for value in values:
+ result = target.scalar_mult(value, target.params.generator)
+ expected = mult.multiply(value)
+ assert result == expected
+ target.disconnect()
- def callback(target, mult, params):
- for value in values:
- result = target.scalar_mult(value, params.generator)
- expected = mult.multiply(value)
- assert result == expected
-
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- mult_class,
- formulas,
- mult_name,
- False,
- False,
- **mult_kwargs,
- )
-
-@pytest.mark.parametrize(
- "mult_class,mult_name,formulas,mult_kwargs",
- [
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": False}),
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": True}),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": False, "always": True},
- ),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": True, "always": True},
- ),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
- (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}),
- (BinaryNAFMultiplier, "bnaf", ["add-1998-cmo", "dbl-1998-cmo", "neg"], {}),
- ],
-)
-def test_ecdh(mult_class, mult_name, mult_kwargs, formulas, cli_runner, secp128r1):
+def test_ecdh(target, mult, secp128r1):
+ target.connect()
+ target.set_params(secp128r1)
+ mult.init(secp128r1, secp128r1.generator)
other_privs = [15, 2355498743, 3253857901321912443757746]
-
- def callback(target, mult, params):
- for other_priv in other_privs:
- priv, pub = target.generate()
- other_pub = mult.multiply(other_priv)
- ecdh = ECDH_SHA1(copy(mult), params, other_pub, priv)
- result = target.ecdh(other_pub)
- expected = ecdh.perform()
- assert result == expected
-
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- mult_class,
- formulas,
- mult_name,
- False,
- True,
- **mult_kwargs,
- )
+ 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))
+ result = target.ecdh(other_pub)
+ expected = ecdh.perform()
+ assert result == expected
+ target.disconnect()
-@pytest.mark.parametrize(
- "mult_class,mult_name,formulas,mult_kwargs",
- [
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": False}),
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": True}),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": False, "always": True},
- ),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": True, "always": True},
- ),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
- (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}),
- (BinaryNAFMultiplier, "bnaf", ["add-1998-cmo", "dbl-1998-cmo", "neg"], {}),
- ],
-)
-def test_ecdsa(mult_class, mult_name, mult_kwargs, formulas, cli_runner, secp128r1):
- data = b"something"
+def test_ecdsa(target, mult, secp128r1):
+ target.connect()
+ target.set_params(secp128r1)
+ mult.init(secp128r1, secp128r1.generator)
- def callback(target, mult, params):
+ messages = [b"something", b"something quite a bit longer than the hash thing"]
+ for message in messages:
priv, pub = target.generate()
ecdsa = ECDSA_SHA1(
copy(mult),
- params,
+ secp128r1,
mult.formulas["add"],
- pub.to_model(params.curve.coordinate_model, params.curve),
- priv,
+ pub.to_model(secp128r1.curve.coordinate_model, secp128r1.curve),
+ Mod(priv, secp128r1.order),
)
- signature_data = target.ecdsa_sign(data)
+ signature_data = target.ecdsa_sign(message)
result = SignatureResult.from_DER(signature_data)
- assert ecdsa.verify_data(result, data)
-
- expected = ecdsa.sign_data(data).to_DER()
- assert target.ecdsa_verify(data, expected)
+ assert ecdsa.verify_data(result, message)
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- mult_class,
- formulas,
- mult_name,
- True,
- False,
- **mult_kwargs,
- )
+ expected = ecdsa.sign_data(message).to_DER()
+ assert target.ecdsa_verify(message, expected)
+ target.disconnect()
diff --git a/test/test_simulator.py b/test/test_simulator.py
index e5a1c9d..89819b1 100644
--- a/test/test_simulator.py
+++ b/test/test_simulator.py
@@ -5,6 +5,7 @@ import pytest
from pyecsca.ec.key_agreement import ECDH_SHA1
from pyecsca.ec.mult import LTRMultiplier, RTLMultiplier
from pyecsca.ec.signature import ECDSA_SHA1, SignatureResult
+from rainbow import TraceConfig, HammingWeight
from pyecsca.codegen.builder import build_impl
from pyecsca.codegen.client import SimulatorTarget
@@ -46,6 +47,10 @@ def do_basic_test(
"STM32F3",
"--ecdsa" if ecdsa else "--no-ecdsa",
"--ecdh" if ecdh else "--no-ecdh",
+ "--red",
+ "MONTGOMERY",
+ "-D",
+ "BN_NON_CONST",
params.curve.model.shortname,
params.curve.coordinate_model.name,
*formulas,
@@ -193,6 +198,7 @@ def test_ecdh(mult_name, mult_class, cli_runner, curve32):
)
+@pytest.mark.xfail(reason="Simulator bug #3")
@pytest.mark.parametrize(
"mult_name,mult_class", [("ltr", LTRMultiplier), ("rtl", RTLMultiplier)]
)