diff options
| author | Andrej Bátora | 2023-10-05 14:45:06 +0200 |
|---|---|---|
| committer | GitHub | 2023-10-05 14:45:06 +0200 |
| commit | 382a5896488f033c8269cf81fcdde3bf1ef98cad (patch) | |
| tree | 6f3ffa714b611b205ecfb6a1399dd8d97ddd393f /pyecsca | |
| parent | 28d3448cec3599559a04e3f0ebe8d175bf6385d1 (diff) | |
| parent | 9b571fdf84732419b52e0465d8354f9d8b6794e5 (diff) | |
| download | pyecsca-382a5896488f033c8269cf81fcdde3bf1ef98cad.tar.gz pyecsca-382a5896488f033c8269cf81fcdde3bf1ef98cad.tar.zst pyecsca-382a5896488f033c8269cf81fcdde3bf1ef98cad.zip | |
Merge branch 'J08nY:master' into CPA_pyecsca
Diffstat (limited to 'pyecsca')
| -rw-r--r-- | pyecsca/ec/mult/__init__.py | 2 | ||||
| -rw-r--r-- | pyecsca/ec/mult/base.py | 24 | ||||
| -rw-r--r-- | pyecsca/ec/mult/binary.py | 31 | ||||
| -rw-r--r-- | pyecsca/ec/mult/comb.py | 183 | ||||
| -rw-r--r-- | pyecsca/ec/mult/fixed.py | 119 | ||||
| -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 | 33 | ||||
| -rw-r--r-- | pyecsca/sca/re/rpa.py | 5 | ||||
| -rw-r--r-- | pyecsca/sca/re/zvp.py | 5 |
10 files changed, 446 insertions, 26 deletions
diff --git a/pyecsca/ec/mult/__init__.py b/pyecsca/ec/mult/__init__.py index 419e5ff..14f1c99 100644 --- a/pyecsca/ec/mult/__init__.py +++ b/pyecsca/ec/mult/__init__.py @@ -2,6 +2,8 @@ from .base import * from .binary import * +from .comb import * +from .fixed 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..f8acb16 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, @@ -55,7 +64,7 @@ class DoubleAndAddMultiplier(AccumulatorMultiplier, ScalarMultiplier, ABC): return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.direction == other.direction and self.accumulation_order == other.accumulation_order and self.always == other.always and self.complete == other.complete def __repr__(self): - return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, accumulation_order={self.accumulation_order}, always={self.always}, complete={self.complete})" + return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, direction={self.direction}, accumulation_order={self.accumulation_order}, always={self.always}, complete={self.complete})" def _ltr(self, scalar: int) -> Point: if self.complete: @@ -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..8d51806 --- /dev/null +++ b/pyecsca/ec/mult/comb.py @@ -0,0 +1,183 @@ +"""Provides Comb-like scalar multipliers, such as BGMW or Lim-Lee.""" +from copy import copy +from math import ceil +from typing import MutableMapping, Optional + +from public import public + +from ..formula import AdditionFormula, DoublingFormula, ScalingFormula +from ..mult import ( + AccumulatorMultiplier, + ScalarMultiplier, + ProcessingDirection, + AccumulationOrder, + PrecomputationAction, + ScalarMultiplicationAction, +) +from ..params import DomainParameters +from ..point import Point +from ..scalar import convert_base + + +@public +class BGMWMultiplier(AccumulatorMultiplier, ScalarMultiplier): + """ + Brickell, Gordon, McCurley and Wilson (BGMW) scalar multiplier, + or rather, its one parametrization. + + Algorithm 3.41 from [GECC]_ + + :param width: Window width. + :param direction: Whether it is LTR or RTL. + :param accumulation_order: The order of accumulation of points. + """ + + requires = {AdditionFormula, DoublingFormula} + optionals = {ScalingFormula} + direction: ProcessingDirection + """Whether it is LTR or RTL.""" + width: int + """Window width.""" + _points: MutableMapping[int, Point] + + def __init__( + self, + add: AdditionFormula, + dbl: DoublingFormula, + width: int, + scl: Optional[ScalingFormula] = None, + direction: ProcessingDirection = ProcessingDirection.LTR, + accumulation_order: AccumulationOrder = AccumulationOrder.PeqPR, + short_circuit: bool = True, + ): + super().__init__( + short_circuit=short_circuit, + accumulation_order=accumulation_order, + add=add, + dbl=dbl, + scl=scl, + ) + self.direction = direction + self.width = width + + def init(self, params: DomainParameters, point: Point): + with PrecomputationAction(params, point): + super().init(params, point) + d = ceil(params.order.bit_length() / self.width) + self._points = {} + current_point = point + for i in range(d): + self._points[i] = current_point + if i != d - 1: + for _ in range(self.width): + current_point = self._dbl(current_point) + + def multiply(self, scalar: int) -> Point: + if not self._initialized: + raise ValueError("ScalarMultiplier not initialized.") + with ScalarMultiplicationAction(self._point, scalar) as action: + if scalar == 0: + return action.exit(copy(self._params.curve.neutral)) + a = copy(self._params.curve.neutral) + b = copy(self._params.curve.neutral) + recoded = convert_base(scalar, 2**self.width) + for j in range(2**self.width - 1, 0, -1): + if self.direction == ProcessingDirection.RTL: + for i, ki in enumerate(recoded): + if ki == j: + b = self._accumulate(b, self._points[i]) + elif self.direction == ProcessingDirection.LTR: + for i, ki in reversed(list(enumerate(recoded))): + if ki == j: + b = self._accumulate(b, self._points[i]) + if self.short_circuit and a == b: + # TODO: Double necessary here for incomplete formulas, maybe another param and not reuse short_cirtuit? + a = self._dbl(b) + else: + a = self._accumulate(a, b) + if "scl" in self.formulas: + a = self._scl(a) + return action.exit(a) + + +@public +class CombMultiplier(AccumulatorMultiplier, ScalarMultiplier): + """ + Comb multiplier. + + Algorithm 3.44 from [GECC]_ + + :param width: Window width (number of comb teeth). + :param accumulation_order: The order of accumulation of points. + """ + + requires = {AdditionFormula, DoublingFormula} + optionals = {ScalingFormula} + width: int + """Window width.""" + _points: MutableMapping[int, Point] + + def __init__( + self, + add: AdditionFormula, + dbl: DoublingFormula, + width: int, + scl: Optional[ScalingFormula] = None, + accumulation_order: AccumulationOrder = AccumulationOrder.PeqPR, + short_circuit: bool = True, + ): + super().__init__( + short_circuit=short_circuit, + accumulation_order=accumulation_order, + add=add, + dbl=dbl, + scl=scl, + ) + self.width = width + + def init(self, params: DomainParameters, point: Point): + with PrecomputationAction(params, point): + super().init(params, point) + d = ceil(params.order.bit_length() / self.width) + base_points = {} + current_point = point + for i in range(self.width): + base_points[i] = current_point + if i != d - 1: + for _ in range(d): + current_point = self._dbl(current_point) + self._points = {} + for j in range(1, 2**self.width): + points = [] + for i in range(self.width): + if j & (1 << i): + points.append(base_points[i]) + self._points[j] = points[0] + for other in points[1:]: + self._points[j] = self._accumulate(self._points[j], other) + + def multiply(self, scalar: int) -> Point: + if not self._initialized: + raise ValueError("ScalarMultiplier not initialized.") + with ScalarMultiplicationAction(self._point, scalar) as action: + if scalar == 0: + return action.exit(copy(self._params.curve.neutral)) + q = copy(self._params.curve.neutral) + d = ceil(self._params.order.bit_length() / self.width) + recoded = convert_base(scalar, 2**d) + if len(recoded) != self.width: + recoded.extend([0] * (self.width - len(recoded))) + for i in range(d - 1, -1, -1): + q = self._dbl(q) + word = 0 + for j in range(self.width): + # get i-th bit of recoded[j] and set it into the j-th bit of word + bit = (recoded[j] >> i) & 1 + word |= bit << j + if word: + q = self._accumulate(q, self._points[word]) + # TODO always + + if "scl" in self.formulas: + q = self._scl(q) + return action.exit(q) diff --git a/pyecsca/ec/mult/fixed.py b/pyecsca/ec/mult/fixed.py new file mode 100644 index 0000000..010767b --- /dev/null +++ b/pyecsca/ec/mult/fixed.py @@ -0,0 +1,119 @@ +"""Provides fixed-base scalar multipliers that do a lot of pre-computation (but not combs).""" +from copy import copy +from typing import MutableMapping, Optional + +from public import public + +from ..formula import AdditionFormula, DoublingFormula, ScalingFormula +from ..mult import AccumulatorMultiplier, ScalarMultiplier, ProcessingDirection, AccumulationOrder, \ + PrecomputationAction, ScalarMultiplicationAction +from ..params import DomainParameters +from ..point import Point + + +@public +class FullPrecompMultiplier(AccumulatorMultiplier, ScalarMultiplier): + """ + See page 104 of [GECC]_: + + For example, if the points `[2]P,[2^2]P,...,[2^t−1]P` are precomputed, then the right-to-left + binary method (Algorithm 3.26) has expected running time `(m/2)A` (all doublings are + eliminated). + + :param always: Whether the addition is always performed. + :param direction: Whether it is LTR or RTL. + :param accumulation_order: The order of accumulation of points. + :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.""" + _points: MutableMapping[int, Point] + + def __init__( + self, + add: AdditionFormula, + dbl: DoublingFormula, + scl: Optional[ScalingFormula] = None, + always: bool = False, + direction: ProcessingDirection = ProcessingDirection.LTR, + accumulation_order: AccumulationOrder = AccumulationOrder.PeqPR, + complete: bool = True, + short_circuit: bool = True, + ): + super().__init__( + short_circuit=short_circuit, accumulation_order=accumulation_order, add=add, dbl=dbl, scl=scl + ) + self.always = always + self.direction = direction + self.complete = complete + + def __hash__(self): + return id(self) + + def __eq__(self, other): + if not isinstance(other, FullPrecompMultiplier): + return False + return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.direction == other.direction and self.accumulation_order == other.accumulation_order and self.always == other.always and self.complete == other.complete + + def __repr__(self): + return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit}, accumulation_order={self.accumulation_order}, always={self.always}, complete={self.complete})" + + def init(self, params: DomainParameters, point: Point): + with PrecomputationAction(params, point): + super().init(params, point) + self._points = {} + current_point = point + for i in range(params.order.bit_length() + 1): + self._points[i] = current_point + if i != params.order.bit_length(): + current_point = self._dbl(current_point) + + def _ltr(self, scalar: int) -> Point: + if self.complete: + top = self._params.order.bit_length() - 1 + else: + top = scalar.bit_length() - 1 + r = copy(self._params.curve.neutral) + for i in range(top, -1, -1): + if scalar & (1 << i) != 0: + r = self._accumulate(r, self._points[i]) + elif self.always: + # dummy add + self._accumulate(r, self._points[i]) + return r + + def _rtl(self, scalar: int) -> Point: + r = copy(self._params.curve.neutral) + if self.complete: + top = self._params.order.bit_length() + else: + top = scalar.bit_length() + for i in range(top): + if scalar & 1 != 0: + r = self._accumulate(r, self._points[i]) + elif self.always: + # dummy add + self._accumulate(r, self._points[i]) + scalar >>= 1 + return r + + def multiply(self, scalar: int) -> Point: + if not self._initialized: + raise ValueError("ScalarMultiplier not initialized.") + with ScalarMultiplicationAction(self._point, scalar) as action: + if scalar == 0: + return action.exit(copy(self._params.curve.neutral)) + if self.direction is ProcessingDirection.LTR: + r = self._ltr(scalar) + elif self.direction is ProcessingDirection.RTL: + r = self._rtl(scalar) + if "scl" in self.formulas: + r = self._scl(r) + return action.exit(r) 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..8317965 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 @@ -16,13 +17,20 @@ from ..scalar import convert_base, sliding_window_rtl, sliding_window_ltr @public class SlidingWindowMultiplier(AccumulatorMultiplier, ScalarMultiplier): - """Sliding window scalar multiplier.""" + """ + Sliding window scalar multiplier. + + :param width: The width of the sliding-window recoding. + :param recoding_direction: The direction for the sliding-window recoding. + :param accumulation_order: The order of accumulation of points. + """ requires = {AdditionFormula, DoublingFormula} optionals = {ScalingFormula} - complete: bool width: int + """The width of the sliding-window recoding.""" recoding_direction: ProcessingDirection + """The direction for the sliding-window recoding.""" _points: MutableMapping[int, Point] def __init__( @@ -49,6 +57,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,12 +92,23 @@ 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. + + :param m: The arity of the multiplier. + :param accumulation_order: The order of accumulation of points. + """ requires = {AdditionFormula, DoublingFormula} optionals = {ScalingFormula} - complete: bool m: int + """The arity of the multiplier.""" _points: MutableMapping[int, Point] def __init__( @@ -114,6 +136,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) diff --git a/pyecsca/sca/re/rpa.py b/pyecsca/sca/re/rpa.py index 5a44a0f..5459ff2 100644 --- a/pyecsca/sca/re/rpa.py +++ b/pyecsca/sca/re/rpa.py @@ -1,8 +1,5 @@ """ -Provides functionality inspired by the Refined-Power Analysis attack by Goubin. - - A Refined Power-Analysis Attack on Elliptic Curve Cryptosystems, Louis Goubin, PKC '03 - `<https://dl.acm.org/doi/10.5555/648120.747060>`_ +Provides functionality inspired by the Refined-Power Analysis attack by Goubin [RPA]_. """ from public import public from typing import MutableMapping, Optional, Callable, List diff --git a/pyecsca/sca/re/zvp.py b/pyecsca/sca/re/zvp.py index 53a38a2..7e3d790 100644 --- a/pyecsca/sca/re/zvp.py +++ b/pyecsca/sca/re/zvp.py @@ -1,8 +1,5 @@ """ -Provides functionality inspired by the Zero-value point attack. - - Zero-Value Point Attacks on Elliptic Curve Cryptosystem, Toru Akishita & Tsuyoshi Takagi , ISC '03 - `<https://doi.org/10.1007/10958513_17>`_ +Provides functionality inspired by the Zero-value point attack [ZVP]_. Implements ZVP point construction from [FFD]_. """ |
