aboutsummaryrefslogtreecommitdiff
path: root/pyecsca/ec/mult
diff options
context:
space:
mode:
authorJ08nY2023-10-04 16:40:31 +0200
committerJ08nY2023-10-04 16:40:31 +0200
commitbff6dc1e9777000d9a1867ce3f0863cbb3900896 (patch)
tree75c3c972853b94ddf3a19536c899e26ca4b63479 /pyecsca/ec/mult
parent1c25c3fa1b752c170092d0fff34e1a14f363c602 (diff)
downloadpyecsca-bff6dc1e9777000d9a1867ce3f0863cbb3900896.tar.gz
pyecsca-bff6dc1e9777000d9a1867ce3f0863cbb3900896.tar.zst
pyecsca-bff6dc1e9777000d9a1867ce3f0863cbb3900896.zip
Diffstat (limited to 'pyecsca/ec/mult')
-rw-r--r--pyecsca/ec/mult/__init__.py1
-rw-r--r--pyecsca/ec/mult/base.py24
-rw-r--r--pyecsca/ec/mult/binary.py29
-rw-r--r--pyecsca/ec/mult/comb.py1
-rw-r--r--pyecsca/ec/mult/ladder.py39
-rw-r--r--pyecsca/ec/mult/naf.py31
-rw-r--r--pyecsca/ec/mult/window.py17
7 files changed, 128 insertions, 14 deletions
diff --git a/pyecsca/ec/mult/__init__.py b/pyecsca/ec/mult/__init__.py
index 419e5ff..e032913 100644
--- a/pyecsca/ec/mult/__init__.py
+++ b/pyecsca/ec/mult/__init__.py
@@ -2,6 +2,7 @@
from .base import *
from .binary import *
+from .comb import *
from .ladder import *
from .naf import *
from .window import *
diff --git a/pyecsca/ec/mult/base.py b/pyecsca/ec/mult/base.py
index a0584d1..5bfef73 100644
--- a/pyecsca/ec/mult/base.py
+++ b/pyecsca/ec/mult/base.py
@@ -1,3 +1,6 @@
+"""Provides (mostly abstract) base classes for scalar multipliers, enums used to specify their parameters
+and actions used in them."""
+
from abc import ABC, abstractmethod
from copy import copy
from enum import Enum
@@ -71,9 +74,9 @@ class ScalarMultiplier(ABC):
"""
requires: ClassVar[Set[Type]] # Type[Formula] but mypy has a false positive
- """The set of formulas that the multiplier requires."""
+ """The set of formula types that the multiplier requires."""
optionals: ClassVar[Set[Type]] # Type[Formula] but mypy has a false positive
- """The optional set of formulas that the multiplier can use."""
+ """The optional set of formula types that the multiplier can use."""
short_circuit: bool
"""Whether the formulas will short-circuit upon input of the point at infinity."""
formulas: Mapping[str, Formula]
@@ -93,9 +96,23 @@ class ScalarMultiplier(ABC):
)
!= 1
):
- raise ValueError
+ raise ValueError("Formulas need to belong to the same coordinate model.")
self.short_circuit = short_circuit
self.formulas = {k: v for k, v in formulas.items() if v is not None}
+ found_required = set()
+ for formula in self.formulas.values():
+ for required in self.requires:
+ if isinstance(formula, required):
+ found_required.add(required)
+ break
+ else:
+ for optional in self.optionals:
+ if isinstance(formula, optional):
+ break
+ else:
+ raise ValueError("Not required or optional formulas provided.")
+ if found_required != self.requires:
+ raise ValueError("Required formulas missing.")
def _add(self, one: Point, other: Point) -> Point:
if "add" not in self.formulas:
@@ -216,6 +233,7 @@ class AccumulatorMultiplier(ScalarMultiplier, ABC):
:param accumulation_order: The order of accumulation of points.
"""
accumulation_order: AccumulationOrder
+ """The order of accumulation of points."""
def __init__(self, *args, accumulation_order: AccumulationOrder = AccumulationOrder.PeqPR, **kwargs):
super().__init__(*args, **kwargs)
diff --git a/pyecsca/ec/mult/binary.py b/pyecsca/ec/mult/binary.py
index 6145828..905646c 100644
--- a/pyecsca/ec/mult/binary.py
+++ b/pyecsca/ec/mult/binary.py
@@ -1,3 +1,4 @@
+"""Provides binary scalar multipliers (LTR and RTL), that process the scalar as-is, bit-by-bit."""
from abc import ABC
from copy import copy
from typing import Optional
@@ -19,16 +20,24 @@ class DoubleAndAddMultiplier(AccumulatorMultiplier, ScalarMultiplier, ABC):
"""
Classic double and add scalar multiplication algorithm.
+ .. note::
+ This is an ABC, you should use the `LTRMultiplier` and `RTLMultiplier` classes.
+
+ :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs
+ of the point at infinity.
:param always: Whether the double and add always method is used.
:param direction: Whether it is LTR or RTL.
:param accumulation_order: The order of accumulation of points.
- :param complete: (Only for LTR, always false for RTL) Whether it starts processing at full order-bit-length.
+ :param complete: Whether it starts processing at full order-bit-length.
"""
requires = {AdditionFormula, DoublingFormula}
optionals = {ScalingFormula}
always: bool
+ """Whether the double and add always method is used."""
direction: ProcessingDirection
+ """Whether it is LTR or RTL."""
complete: bool
+ """Whether it starts processing at full order-bit-length."""
def __init__(
self,
@@ -112,6 +121,12 @@ class DoubleAndAddMultiplier(AccumulatorMultiplier, ScalarMultiplier, ABC):
class LTRMultiplier(DoubleAndAddMultiplier):
"""
Classic double and add scalar multiplication algorithm, that scans the scalar left-to-right (msb to lsb).
+
+ :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs
+ of the point at infinity.
+ :param always: Whether the double and add always method is used.
+ :param accumulation_order: The order of accumulation of points.
+ :param complete: Whether it starts processing at full order-bit-length.
"""
def __init__(
@@ -133,6 +148,12 @@ class LTRMultiplier(DoubleAndAddMultiplier):
class RTLMultiplier(DoubleAndAddMultiplier):
"""
Classic double and add scalar multiplication algorithm, that scans the scalar right-to-left (lsb to msb).
+
+ :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs
+ of the point at infinity.
+ :param always: Whether the double and add always method is used.
+ :param accumulation_order: The order of accumulation of points.
+ :param complete: Whether it starts processing at full order-bit-length.
"""
def __init__(
@@ -155,10 +176,10 @@ class CoronMultiplier(ScalarMultiplier):
"""
Coron's double and add resistant against SPA.
- From:
- **Resistance against Differential Power Analysis for Elliptic Curve Cryptosystems**
+ From [CO2002]_.
- https://link.springer.com/content/pdf/10.1007/3-540-48059-5_25.pdf
+ :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs
+ of the point at infinity.
"""
requires = {AdditionFormula, DoublingFormula}
diff --git a/pyecsca/ec/mult/comb.py b/pyecsca/ec/mult/comb.py
new file mode 100644
index 0000000..f25e177
--- /dev/null
+++ b/pyecsca/ec/mult/comb.py
@@ -0,0 +1 @@
+"""Provides Comb-like scalar multipliers, such as BGMW or Lim-Lee.""" \ No newline at end of file
diff --git a/pyecsca/ec/mult/ladder.py b/pyecsca/ec/mult/ladder.py
index ad90730..2fc1244 100644
--- a/pyecsca/ec/mult/ladder.py
+++ b/pyecsca/ec/mult/ladder.py
@@ -1,3 +1,4 @@
+"""Provides ladder-based scalar multipliers, either using the ladder formula, or (diffadd, dbl) or (add, dbl)."""
from copy import copy
from typing import Optional
from public import public
@@ -15,11 +16,20 @@ from ..point import Point
@public
class LadderMultiplier(ScalarMultiplier):
- """Montgomery ladder multiplier, using a three input, two output ladder formula."""
+ """
+ Montgomery ladder multiplier, using a three input, two output ladder formula.
+
+ Optionally takes a doubling formula, and if `complete` is false, it requires one.
+
+ :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs
+ of the point at infinity.
+ :param complete: Whether it starts processing at full order-bit-length.
+ """
requires = {LadderFormula}
optionals = {DoublingFormula, ScalingFormula}
complete: bool
+ """Whether it starts processing at full order-bit-length."""
def __init__(
self,
@@ -42,6 +52,9 @@ class LadderMultiplier(ScalarMultiplier):
return False
return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.complete == other.complete
+ def __repr__(self):
+ return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, complete={self.complete})"
+
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
@@ -69,11 +82,18 @@ class LadderMultiplier(ScalarMultiplier):
@public
class SimpleLadderMultiplier(ScalarMultiplier):
- """Montgomery ladder multiplier, using addition and doubling formulas."""
+ """
+ Montgomery ladder multiplier, using addition and doubling formulas.
+
+ :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs
+ of the point at infinity.
+ :param complete: Whether it starts processing at full order-bit-length.
+ """
requires = {AdditionFormula, DoublingFormula}
optionals = {ScalingFormula}
complete: bool
+ """Whether it starts processing at full order-bit-length."""
def __init__(
self,
@@ -94,6 +114,9 @@ class SimpleLadderMultiplier(ScalarMultiplier):
return False
return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.complete == other.complete
+ def __repr__(self):
+ return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, complete={self.complete})"
+
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
@@ -120,11 +143,18 @@ class SimpleLadderMultiplier(ScalarMultiplier):
@public
class DifferentialLadderMultiplier(ScalarMultiplier):
- """Montgomery ladder multiplier, using differential addition and doubling formulas."""
+ """
+ Montgomery ladder multiplier, using differential addition and doubling formulas.
+
+ :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs
+ of the point at infinity.
+ :param complete: Whether it starts processing at full order-bit-length.
+ """
requires = {DifferentialAdditionFormula, DoublingFormula}
optionals = {ScalingFormula}
complete: bool
+ """Whether it starts processing at full order-bit-length."""
def __init__(
self,
@@ -145,6 +175,9 @@ class DifferentialLadderMultiplier(ScalarMultiplier):
return False
return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.complete == other.complete
+ def __repr__(self):
+ return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, complete={self.complete})"
+
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
diff --git a/pyecsca/ec/mult/naf.py b/pyecsca/ec/mult/naf.py
index 1cec8b0..9304475 100644
--- a/pyecsca/ec/mult/naf.py
+++ b/pyecsca/ec/mult/naf.py
@@ -1,3 +1,4 @@
+"""Provides scalar multipliers based on the Non Adjacent Form (NAF) recoding."""
from copy import copy
from typing import Optional, List, MutableMapping
from public import public
@@ -17,7 +18,14 @@ from ..scalar import naf, wnaf
@public
class BinaryNAFMultiplier(AccumulatorMultiplier, ScalarMultiplier):
- """Binary NAF (Non Adjacent Form) multiplier."""
+ """
+ Binary NAF (Non Adjacent Form) multiplier.
+
+ :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs
+ of the point at infinity.
+ :param direction: Whether it is LTR or RTL.
+ :param accumulation_order: The order of accumulation of points.
+ """
requires = {AdditionFormula, DoublingFormula, NegationFormula}
optionals = {ScalingFormula}
@@ -45,7 +53,10 @@ class BinaryNAFMultiplier(AccumulatorMultiplier, ScalarMultiplier):
def __eq__(self, other):
if not isinstance(other, BinaryNAFMultiplier):
return False
- return self.formulas == other.formulas and self.short_circuit == other.short_circuit
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.direction == other.direction and self.accumulation_order == other.accumulation_order
+
+ def __repr__(self):
+ return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, direction={self.direction}, accumulation_order={self.accumulation_order})"
def init(self, params: DomainParameters, point: Point):
with PrecomputationAction(params, point):
@@ -93,14 +104,25 @@ class BinaryNAFMultiplier(AccumulatorMultiplier, ScalarMultiplier):
@public
class WindowNAFMultiplier(AccumulatorMultiplier, ScalarMultiplier):
- """Window NAF (Non Adjacent Form) multiplier, left-to-right."""
+ """
+ Window NAF (Non Adjacent Form) multiplier, left-to-right.
+
+ :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs
+ of the point at infinity.
+ :param width: The width of the window.
+ :param accumulation_order: The order of accumulation of points.
+ :param precompute_negation: Whether to precompute the negation of the precomputed points as well.
+ It is computed on the fly otherwise.
+ """
requires = {AdditionFormula, DoublingFormula, NegationFormula}
optionals = {ScalingFormula}
_points: MutableMapping[int, Point]
_points_neg: MutableMapping[int, Point]
precompute_negation: bool = False
+ """Whether to precompute the negation of the precomputed points as well."""
width: int
+ """The width of the window."""
def __init__(
self,
@@ -127,6 +149,9 @@ class WindowNAFMultiplier(AccumulatorMultiplier, ScalarMultiplier):
return False
return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.width == other.width and self.precompute_negation == other.precompute_negation and self.accumulation_order == other.accumulation_order
+ def __repr__(self):
+ return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, precompute_negation={self.precompute_negation}, accumulation_order={self.accumulation_order})"
+
def init(self, params: DomainParameters, point: Point):
with PrecomputationAction(params, point):
super().init(params, point)
diff --git a/pyecsca/ec/mult/window.py b/pyecsca/ec/mult/window.py
index 8b1ae2c..3ee8c50 100644
--- a/pyecsca/ec/mult/window.py
+++ b/pyecsca/ec/mult/window.py
@@ -1,3 +1,4 @@
+"""Provides sliding window and fixed window scalar multipliers (including m-ary, for non power-of-2 m)."""
from copy import copy
from typing import Optional, MutableMapping
from public import public
@@ -49,6 +50,9 @@ class SlidingWindowMultiplier(AccumulatorMultiplier, ScalarMultiplier):
return False
return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.width == other.width and self.recoding_direction == other.recoding_direction and self.accumulation_order == other.accumulation_order
+ def __repr__(self):
+ return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, width={self.width}, recoding_direction={self.recoding_direction}, accumulation_order={self.accumulation_order})"
+
def init(self, params: DomainParameters, point: Point):
with PrecomputationAction(params, point):
super().init(params, point)
@@ -81,7 +85,15 @@ class SlidingWindowMultiplier(AccumulatorMultiplier, ScalarMultiplier):
@public
class FixedWindowLTRMultiplier(AccumulatorMultiplier, ScalarMultiplier):
- """Like LTRMultiplier, but not binary, but m-ary."""
+ """
+ Like LTRMultiplier, but m-ary, not binary.
+
+ For `m` a power-of-2 this is a fixed window multiplier
+ that works on `log_2(m)` wide windows and uses only doublings
+ to perform the multiplication-by-m between each window addition.
+
+ For other `m` values, this is the m-ary multiplier.
+ """
requires = {AdditionFormula, DoublingFormula}
optionals = {ScalingFormula}
@@ -114,6 +126,9 @@ class FixedWindowLTRMultiplier(AccumulatorMultiplier, ScalarMultiplier):
return False
return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.m == other.m and self.accumulation_order == other.accumulation_order
+ def __repr__(self):
+ return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, m={self.m}, accumulation_order={self.accumulation_order})"
+
def init(self, params: DomainParameters, point: Point):
with PrecomputationAction(params, point):
super().init(params, point)