diff options
| author | J08nY | 2023-10-04 16:40:31 +0200 |
|---|---|---|
| committer | J08nY | 2023-10-04 16:40:31 +0200 |
| commit | bff6dc1e9777000d9a1867ce3f0863cbb3900896 (patch) | |
| tree | 75c3c972853b94ddf3a19536c899e26ca4b63479 /pyecsca/ec/mult | |
| parent | 1c25c3fa1b752c170092d0fff34e1a14f363c602 (diff) | |
| download | pyecsca-bff6dc1e9777000d9a1867ce3f0863cbb3900896.tar.gz pyecsca-bff6dc1e9777000d9a1867ce3f0863cbb3900896.tar.zst pyecsca-bff6dc1e9777000d9a1867ce3f0863cbb3900896.zip | |
Diffstat (limited to 'pyecsca/ec/mult')
| -rw-r--r-- | pyecsca/ec/mult/__init__.py | 1 | ||||
| -rw-r--r-- | pyecsca/ec/mult/base.py | 24 | ||||
| -rw-r--r-- | pyecsca/ec/mult/binary.py | 29 | ||||
| -rw-r--r-- | pyecsca/ec/mult/comb.py | 1 | ||||
| -rw-r--r-- | pyecsca/ec/mult/ladder.py | 39 | ||||
| -rw-r--r-- | pyecsca/ec/mult/naf.py | 31 | ||||
| -rw-r--r-- | pyecsca/ec/mult/window.py | 17 |
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) |
