diff options
| author | Ján Jančár | 2023-10-08 21:12:06 +0200 |
|---|---|---|
| committer | GitHub | 2023-10-08 21:12:06 +0200 |
| commit | ffbaa1ae62095eb644eda67571aa8845aa6fb09d (patch) | |
| tree | dfdfbf9a12acd1662cba56b46b30d8337ae81918 | |
| parent | 9c6acdd2409c49c2ae64a8c41df315a1eca3eea7 (diff) | |
| parent | 1c2e383d8e8df323b4cebb302869fc15599961a0 (diff) | |
| download | pyecsca-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
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 }} @@ -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(©)) { if (bn_get_bit(©, 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)] ) |
