diff options
| -rw-r--r-- | pyecsca/sca/re/epa.py | 14 | ||||
| -rw-r--r-- | test/sca/perf_epa.py | 38 |
2 files changed, 37 insertions, 15 deletions
diff --git a/pyecsca/sca/re/epa.py b/pyecsca/sca/re/epa.py index 913a1ab..3a243fa 100644 --- a/pyecsca/sca/re/epa.py +++ b/pyecsca/sca/re/epa.py @@ -1,7 +1,7 @@ """ Provides functionality inspired by the Exceptional Procedure Attack [EPA]_. """ - +from operator import itemgetter from typing import Callable, Literal, Union from public import public @@ -19,6 +19,7 @@ def graph_to_check_inputs( precomp_to_affine: bool, use_init: bool = True, use_multiply: bool = True, + check_formulas: set[str] | None = None, ) -> dict[str, set[tuple[int, ...]]]: """ Compute the inputs for the checks based on the context and output point. This function traverses the graph of points @@ -32,6 +33,7 @@ def graph_to_check_inputs( :param precomp_to_affine: Whether to include the precomputed points in the to-affine checks. :param use_init: Whether to consider the point multiples that happen in scalarmult initialization. :param use_multiply: Whether to consider the point multiples that happen in scalarmult multiply (after initialization). + :param check_formulas: If provided, only formulas in this set will be considered for checks. :return: A dictionary mapping formula names to sets of tuples of input multiples. .. note:: @@ -83,12 +85,16 @@ def graph_to_check_inputs( } # This actually passes the multiple itself to the check, not the inputs(parents) # Now handle the regular checks + + def get_point(pt): + return full_ctx.points[pt] + for point in points: formula = full_ctx.formulas[point] - if not formula: + if not formula or (check_formulas is not None and formula not in check_formulas): # Skip input point or infty point (they magically appear and do not have an origin formula) continue - inputs = tuple(map(lambda pt: full_ctx.points[pt], full_ctx.parents[point])) + inputs = tuple(map(get_point, full_ctx.parents[point])) check_list = formula_checks.setdefault(formula, set()) check_list.add(inputs) return formula_checks @@ -127,7 +133,7 @@ def errors_out( precomp_ctx: MultipleContext, full_ctx: MultipleContext, out: Point, - check_funcs: dict[str, Callable[[int, int], bool]], + check_funcs: dict[str, Callable[[int, int], bool] | Callable[[int], bool]], check_condition: Union[Literal["all"], Literal["necessary"]], precomp_to_affine: bool, use_init: bool = True, diff --git a/test/sca/perf_epa.py b/test/sca/perf_epa.py index 3f9a6fc..32648c9 100644 --- a/test/sca/perf_epa.py +++ b/test/sca/perf_epa.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import click +from pyecsca.ec.mod import Mod from pyecsca.ec.mod.flint import has_flint from pyecsca.ec.mod.gmp import has_gmp from pyecsca.ec.params import get_params @@ -26,7 +27,7 @@ from test.utils import Profiler default="flint" if has_flint else "gmp" if has_gmp else "python", envvar="MOD", ) -@click.option("-o", "--operations", type=click.INT, default=1000) +@click.option("-o", "--operations", type=click.INT, default=100) @click.option( "-d", "--directory", @@ -39,29 +40,44 @@ def main(profiler, mod, operations, directory): cfg.ec.mod_implementation = mod p128 = get_params("secg", "secp128r1", "projective") - scalar = 123456789123456789123456789123456789 + scalars = [int(Mod.random(p128.order)) for _ in range(operations)] + ops = [ + multiple_graph(scalar, p128, LTRMultiplier, LTRMultiplier) + for scalar in scalars + ] + click.echo( - f"Profiling {operations} {p128.curve.prime.bit_length()}-bit (k = {scalar}) multiples_computed computations..." + f"Profiling {operations} {p128.curve.prime.bit_length()}-bit graph_to_check_inputs + evaluate_checks computations..." ) with Profiler(profiler, directory, f"epa_p128_ltr_{operations}_{mod}"): - precomp_ctx, full_ctx, out = multiple_graph( - scalar, p128, LTRMultiplier, LTRMultiplier - ) - for _ in range(operations): + for precomp_ctx, full_ctx, out in ops: check_inputs = graph_to_check_inputs( precomp_ctx, full_ctx, out, - check_condition="necessary", + check_condition="all", precomp_to_affine=True, use_init=True, use_multiply=True, + check_formulas={"add"}, ) - for _ in range(32): + c = 0 + for j in range(3220): + i = 0 + + def check_add(x, y): + nonlocal i, c + i += 1 + c += 1 + return (i % (30 * (j+1))) == 0 + + def check_affine(x): + return False + evaluate_checks( check_funcs={ - "add": lambda x, y: False, - "affine": lambda x: False, + "add": check_add, + "affine": check_affine, }, check_inputs=check_inputs, ) |
