aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pyecsca/sca/re/epa.py28
-rw-r--r--pyecsca/sca/re/rpa.py83
-rw-r--r--test/sca/test_epa.py38
3 files changed, 93 insertions, 56 deletions
diff --git a/pyecsca/sca/re/epa.py b/pyecsca/sca/re/epa.py
index 1f276d9..32abb45 100644
--- a/pyecsca/sca/re/epa.py
+++ b/pyecsca/sca/re/epa.py
@@ -2,34 +2,26 @@
Provides functionality inspired by the Exceptional Procedure Attack [EPA]_.
"""
-from typing import Callable, Literal, Type, Union
+from typing import Callable, Literal, Union
from public import public
-from pyecsca.ec.context import local
-from pyecsca.ec.formula.fake import FakePoint
-from pyecsca.ec.mult import ScalarMultiplier
-from pyecsca.ec.mult.fake import cached_fake_mult
-from pyecsca.ec.params import DomainParameters
+from pyecsca.ec.point import Point
from pyecsca.sca.re.rpa import MultipleContext
@public
def errors_out(
- scalar: int,
- params: DomainParameters,
- mult_class: Type[ScalarMultiplier],
- mult_factory: Callable,
+ ctx: MultipleContext,
+ out: Point,
check_funcs: dict[str, Callable],
check_condition: Union[Literal["all"], Literal["necessary"]],
precomp_to_affine: bool,
) -> bool:
"""
- :param scalar:
- :param params:
- :param mult_class:
- :param mult_factory:
+ :param ctx: The context containing the points and formulas.
+ :param out: The output point to check.
:param check_funcs:
:param check_condition:
:param precomp_to_affine:
@@ -38,14 +30,6 @@ def errors_out(
.. note::
The scalar multiplier must not short-circuit.
"""
- mult = cached_fake_mult(mult_class, mult_factory, params)
- ctx = MultipleContext(keep_base=True)
- with local(ctx, copy=False):
- mult.init(params, FakePoint(params.curve.coordinate_model))
-
- with local(ctx, copy=False):
- out = mult.multiply(scalar)
-
affine_points = {out, *ctx.precomp.values()} if precomp_to_affine else {out}
if check_condition == "all":
points = set(ctx.points.keys())
diff --git a/pyecsca/sca/re/rpa.py b/pyecsca/sca/re/rpa.py
index f9ccd1b..a150b9c 100644
--- a/pyecsca/sca/re/rpa.py
+++ b/pyecsca/sca/re/rpa.py
@@ -15,6 +15,7 @@ from typing import (
Type,
Literal,
Union,
+ Tuple,
)
from sympy import FF, sympify, Poly, symbols
@@ -421,20 +422,14 @@ class RPA(RE):
@public
-def multiples_computed(
+def multiple_graph(
scalar: int,
params: DomainParameters,
mult_class: Type[ScalarMultiplier],
mult_factory: Callable,
use_init: bool = True,
use_multiply: bool = True,
- kind: Union[
- Literal["all"],
- Literal["input"],
- Literal["necessary"],
- Literal["precomp+necessary"],
- ] = "all",
-) -> set[int]:
+) -> Tuple[MultipleContext, Point]:
"""
Compute the multiples computed for a given scalar and multiplier (quickly).
@@ -444,17 +439,8 @@ def multiples_computed(
:param mult_factory: A callable that takes the formulas and instantiates the multiplier.
: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 kind: The kind of multiples to return. Can be one of "all", "input", "necessary", or "precomp+necessary".
- :return: A list of tuples, where the first element is the formula shortname (e.g. "add") and the second is a tuple of the dlog
- relationships to the input of the input points to the formula.
-
- .. note::
- The scalar multiplier must not short-circuit.
- If `kind` is not "all", `use_init` must be `True`.
+ :return: The context with the computed multiples and the resulting point.
"""
- if kind != "all" and not use_init:
- raise ValueError("Cannot use kind other than 'all' with use_init=False.")
-
mult = cached_fake_mult(mult_class, mult_factory, params)
ctx = MultipleContext(keep_base=True)
if use_init:
@@ -468,7 +454,27 @@ def multiples_computed(
out = mult.multiply(scalar)
else:
out = mult.multiply(scalar)
+ return ctx, out
+
+@public
+def multiples_from_graph(
+ ctx: MultipleContext,
+ out: Point,
+ kind: Union[
+ Literal["all"],
+ Literal["input"],
+ Literal["necessary"],
+ Literal["precomp+necessary"],
+ ] = "all",
+):
+ """
+
+ :param ctx:
+ :param out:
+ :param kind:
+ :return: A set of multiples computed for the scalar.
+ """
if kind == "all":
res = set(ctx.points.values())
elif kind == "input":
@@ -496,3 +502,44 @@ def multiples_computed(
else:
raise ValueError(f"Invalid kind {kind}")
return res - {0}
+
+
+@public
+def multiples_computed(
+ scalar: int,
+ params: DomainParameters,
+ mult_class: Type[ScalarMultiplier],
+ mult_factory: Callable,
+ use_init: bool = True,
+ use_multiply: bool = True,
+ kind: Union[
+ Literal["all"],
+ Literal["input"],
+ Literal["necessary"],
+ Literal["precomp+necessary"],
+ ] = "all",
+) -> set[int]:
+ """
+ Compute the multiples computed for a given scalar and multiplier (quickly).
+
+ :param scalar: The scalar to compute for.
+ :param params: The domain parameters to use.
+ :param mult_class: The class of the scalar multiplier to use.
+ :param mult_factory: A callable that takes the formulas and instantiates the multiplier.
+ :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 kind: The kind of multiples to return. Can be one of "all", "input", "necessary", or "precomp+necessary".
+ :return: A set of multiples computed for the scalar.
+
+ .. note::
+ The scalar multiplier must not short-circuit.
+ If `kind` is not "all", `use_init` must be `True`.
+ """
+ if kind != "all" and not use_init:
+ raise ValueError("Cannot use kind other than 'all' with use_init=False.")
+
+ ctx, out = multiple_graph(
+ scalar, params, mult_class, mult_factory, use_init, use_multiply
+ )
+
+ return multiples_from_graph(ctx, out, kind) if ctx else set()
diff --git a/test/sca/test_epa.py b/test/sca/test_epa.py
index 0362e4e..4bb27f0 100644
--- a/test/sca/test_epa.py
+++ b/test/sca/test_epa.py
@@ -1,15 +1,20 @@
from functools import partial
from pyecsca.ec.mult import LTRMultiplier, CombMultiplier
+from pyecsca.sca import multiple_graph
from pyecsca.sca.re.epa import errors_out
def test_errors_out(secp128r1):
- res_empty_checks = errors_out(
+ ctx, out = multiple_graph(
scalar=15,
params=secp128r1,
mult_class=LTRMultiplier,
mult_factory=LTRMultiplier,
+ )
+ res_empty_checks = errors_out(
+ ctx,
+ out,
check_funcs={},
check_condition="all",
precomp_to_affine=True,
@@ -20,10 +25,8 @@ def test_errors_out(secp128r1):
return k == 6
res_check_k_add = errors_out(
- scalar=15,
- params=secp128r1,
- mult_class=LTRMultiplier,
- mult_factory=LTRMultiplier,
+ ctx,
+ out,
check_funcs={"add": add_check},
check_condition="all",
precomp_to_affine=True,
@@ -34,24 +37,29 @@ def test_errors_out(secp128r1):
return k == 15
res_check_k_affine = errors_out(
- scalar=15,
- params=secp128r1,
- mult_class=LTRMultiplier,
- mult_factory=LTRMultiplier,
+ ctx,
+ out,
check_funcs={"affine": affine_check},
check_condition="all",
precomp_to_affine=True,
)
assert res_check_k_affine
- def affine_check_comb(k):
- return k == 2**64
- res_check_k_affine_precomp = errors_out(
+def test_errors_out_comb(secp128r1):
+ ctx, out = multiple_graph(
scalar=15,
params=secp128r1,
mult_class=CombMultiplier,
mult_factory=partial(CombMultiplier, width=2),
+ )
+
+ def affine_check_comb(k):
+ return k == 2**64
+
+ res_check_k_affine_precomp = errors_out(
+ ctx,
+ out,
check_funcs={"affine": affine_check_comb},
check_condition="all",
precomp_to_affine=True,
@@ -59,10 +67,8 @@ def test_errors_out(secp128r1):
assert res_check_k_affine_precomp
res_check_k_no_affine_precomp = errors_out(
- scalar=15,
- params=secp128r1,
- mult_class=CombMultiplier,
- mult_factory=partial(CombMultiplier, width=2),
+ ctx,
+ out,
check_funcs={"affine": affine_check_comb},
check_condition="all",
precomp_to_affine=False,