aboutsummaryrefslogtreecommitdiffhomepage
path: root/pyecsca/ec/mult
diff options
context:
space:
mode:
authorJ08nY2024-08-28 12:37:38 +0200
committerJ08nY2024-08-28 12:37:38 +0200
commit979d86979313de02c4dab71f99ce1c5dddd5877a (patch)
tree3f6e8930b0d15e293ae16ee2074e41ad8cf40f8c /pyecsca/ec/mult
parentf5af7b538692cdfdeab6f71751149b496062fde4 (diff)
downloadpyecsca-979d86979313de02c4dab71f99ce1c5dddd5877a.tar.gz
pyecsca-979d86979313de02c4dab71f99ce1c5dddd5877a.tar.zst
pyecsca-979d86979313de02c4dab71f99ce1c5dddd5877a.zip
More ladder multipliers.
Diffstat (limited to 'pyecsca/ec/mult')
-rw-r--r--pyecsca/ec/mult/base.py6
-rw-r--r--pyecsca/ec/mult/binary.py4
-rw-r--r--pyecsca/ec/mult/comb.py4
-rw-r--r--pyecsca/ec/mult/fixed.py2
-rw-r--r--pyecsca/ec/mult/ladder.py101
-rw-r--r--pyecsca/ec/mult/naf.py4
-rw-r--r--pyecsca/ec/mult/window.py6
7 files changed, 91 insertions, 36 deletions
diff --git a/pyecsca/ec/mult/base.py b/pyecsca/ec/mult/base.py
index 537f43e..469be39 100644
--- a/pyecsca/ec/mult/base.py
+++ b/pyecsca/ec/mult/base.py
@@ -34,15 +34,17 @@ class ScalarMultiplicationAction(ResultAction):
"""A scalar multiplication of a point on a curve by a scalar."""
point: Point
+ params: DomainParameters
scalar: int
- def __init__(self, point: Point, scalar: int):
+ def __init__(self, point: Point, params: DomainParameters, scalar: int):
super().__init__()
self.point = point
+ self.params = params
self.scalar = scalar
def __repr__(self):
- return f"{self.__class__.__name__}({self.point}, {self.scalar})"
+ return f"{self.__class__.__name__}({self.point}, {self.params}, {self.scalar})"
@public
diff --git a/pyecsca/ec/mult/binary.py b/pyecsca/ec/mult/binary.py
index 9b6a07a..5b6bed7 100644
--- a/pyecsca/ec/mult/binary.py
+++ b/pyecsca/ec/mult/binary.py
@@ -129,7 +129,7 @@ class DoubleAndAddMultiplier(AccumulatorMultiplier, ScalarMultiplier, ABC):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
if self.direction is ProcessingDirection.LTR:
@@ -246,7 +246,7 @@ class CoronMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
q = self._point
diff --git a/pyecsca/ec/mult/comb.py b/pyecsca/ec/mult/comb.py
index 8cea19c..9557fe6 100644
--- a/pyecsca/ec/mult/comb.py
+++ b/pyecsca/ec/mult/comb.py
@@ -100,7 +100,7 @@ class BGMWMultiplier(AccumulatorMultiplier, ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
a = copy(self._params.curve.neutral)
@@ -202,7 +202,7 @@ class CombMultiplier(AccumulatorMultiplier, ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
q = copy(self._params.curve.neutral)
diff --git a/pyecsca/ec/mult/fixed.py b/pyecsca/ec/mult/fixed.py
index afd02e5..2c60be2 100644
--- a/pyecsca/ec/mult/fixed.py
+++ b/pyecsca/ec/mult/fixed.py
@@ -132,7 +132,7 @@ class FullPrecompMultiplier(AccumulatorMultiplier, ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
if self.direction is ProcessingDirection.LTR:
diff --git a/pyecsca/ec/mult/ladder.py b/pyecsca/ec/mult/ladder.py
index f2939af..9f31b7f 100644
--- a/pyecsca/ec/mult/ladder.py
+++ b/pyecsca/ec/mult/ladder.py
@@ -1,4 +1,5 @@
"""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
@@ -24,12 +25,15 @@ class LadderMultiplier(ScalarMultiplier):
: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.
+ :param full: Whether it start processing at top bit of the scalar.
"""
requires = {LadderFormula}
optionals = {DoublingFormula, ScalingFormula}
complete: bool
"""Whether it starts processing at full order-bit-length."""
+ full: bool
+ """Whether it start processing at top bit of the scalar."""
def __init__(
self,
@@ -38,17 +42,27 @@ class LadderMultiplier(ScalarMultiplier):
scl: Optional[ScalingFormula] = None,
complete: bool = True,
short_circuit: bool = True,
+ full: bool = False,
):
super().__init__(short_circuit=short_circuit, ladd=ladd, dbl=dbl, scl=scl)
self.complete = complete
+ self.full = full
+
+ if complete and full:
+ raise ValueError("Only one of `complete` and `full` can be set.")
+
if dbl is None:
- if not complete:
- raise ValueError("When complete is not set LadderMultiplier requires a doubling formula.")
- if short_circuit: # complete = True
- raise ValueError("When short_circuit is set LadderMultiplier requires a doubling formula.")
+ if short_circuit:
+ raise ValueError(
+ "When `short_circuit` is set LadderMultiplier requires a doubling formula."
+ )
+ if not (complete or full):
+ raise ValueError(
+ "When neither `complete` nor `full` is not set LadderMultiplier requires a doubling formula."
+ )
def __hash__(self):
- return hash((LadderMultiplier, super().__hash__(), self.complete))
+ return hash((LadderMultiplier, super().__hash__(), self.complete, self.full))
def __eq__(self, other):
if not isinstance(other, LadderMultiplier):
@@ -57,15 +71,16 @@ class LadderMultiplier(ScalarMultiplier):
self.formulas == other.formulas
and self.short_circuit == other.short_circuit
and self.complete == other.complete
+ and self.full == other.full
)
def __repr__(self):
- return f"{self.__class__.__name__}({', '.join(map(str, self.formulas.values()))}, short_circuit={self.short_circuit}, complete={self.complete})"
+ return f"{self.__class__.__name__}({', '.join(map(str, self.formulas.values()))}, short_circuit={self.short_circuit}, complete={self.complete}, full={self.full})"
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
q = self._point
@@ -73,6 +88,10 @@ class LadderMultiplier(ScalarMultiplier):
p0 = copy(self._params.curve.neutral)
p1 = self._point
top = self._params.full_order.bit_length() - 1
+ elif self.full:
+ p0 = copy(self._params.curve.neutral)
+ p1 = self._point
+ top = scalar.bit_length() - 1
else:
p0 = copy(q)
p1 = self._dbl(q)
@@ -97,12 +116,15 @@ class SwapLadderMultiplier(ScalarMultiplier):
: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.
+ :param full: Whether it start processing at top bit of the scalar.
"""
requires = {LadderFormula}
optionals = {DoublingFormula, ScalingFormula}
complete: bool
"""Whether it starts processing at full order-bit-length."""
+ full: bool
+ """Whether it start processing at top bit of the scalar."""
def __init__(
self,
@@ -111,34 +133,45 @@ class SwapLadderMultiplier(ScalarMultiplier):
scl: Optional[ScalingFormula] = None,
complete: bool = True,
short_circuit: bool = True,
+ full: bool = False,
):
super().__init__(short_circuit=short_circuit, ladd=ladd, dbl=dbl, scl=scl)
self.complete = complete
+ self.full = full
+
+ if complete and full:
+ raise ValueError("Only one of `complete` and `full` can be set.")
+
if dbl is None:
- if not complete:
- raise ValueError("When complete is not set SwapLadderMultiplier requires a doubling formula.")
- if short_circuit: # complete = True
- raise ValueError("When short_circuit is set SwapLadderMultiplier requires a doubling formula.")
+ if short_circuit:
+ raise ValueError(
+ "When `short_circuit` is set SwapLadderMultiplier requires a doubling formula."
+ )
+ if not (complete or full):
+ raise ValueError(
+ "When neither `complete` nor `full` is not set SwapLadderMultiplier requires a doubling formula."
+ )
def __hash__(self):
- return hash((LadderMultiplier, super().__hash__(), self.complete))
+ return hash((SwapLadderMultiplier, super().__hash__(), self.complete, self.full))
def __eq__(self, other):
- if not isinstance(other, LadderMultiplier):
+ if not isinstance(other, SwapLadderMultiplier):
return False
return (
self.formulas == other.formulas
and self.short_circuit == other.short_circuit
and self.complete == other.complete
+ and self.full == other.full
)
def __repr__(self):
- return f"{self.__class__.__name__}({', '.join(map(str, self.formulas.values()))}, short_circuit={self.short_circuit}, complete={self.complete})"
+ return f"{self.__class__.__name__}({', '.join(map(str, self.formulas.values()))}, short_circuit={self.short_circuit}, complete={self.complete}, full={self.full})"
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
q = self._point
@@ -146,6 +179,10 @@ class SwapLadderMultiplier(ScalarMultiplier):
p0 = copy(self._params.curve.neutral)
p1 = self._point
top = self._params.full_order.bit_length() - 1
+ elif self.full:
+ p0 = copy(self._params.curve.neutral)
+ p1 = self._point
+ top = scalar.bit_length() - 1
else:
p0 = copy(q)
p1 = self._dbl(q)
@@ -207,11 +244,11 @@ class SimpleLadderMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
if self.complete:
- top = self._params.order.bit_length() - 1
+ top = self._params.full_order.bit_length() - 1
else:
top = scalar.bit_length() - 1
p0 = copy(self._params.curve.neutral)
@@ -242,6 +279,8 @@ class DifferentialLadderMultiplier(ScalarMultiplier):
optionals = {ScalingFormula}
complete: bool
"""Whether it starts processing at full order-bit-length."""
+ full: bool
+ """Whether it start processing at top bit of the scalar."""
def __init__(
self,
@@ -250,12 +289,19 @@ class DifferentialLadderMultiplier(ScalarMultiplier):
scl: Optional[ScalingFormula] = None,
complete: bool = True,
short_circuit: bool = True,
+ full: bool = False,
):
super().__init__(short_circuit=short_circuit, dadd=dadd, dbl=dbl, scl=scl)
self.complete = complete
+ self.full = full
+
+ if complete and full:
+ raise ValueError("Only one of `complete` and `full` can be set.")
def __hash__(self):
- return hash((DifferentialLadderMultiplier, super().__hash__(), self.complete))
+ return hash(
+ (DifferentialLadderMultiplier, super().__hash__(), self.complete, self.full)
+ )
def __eq__(self, other):
if not isinstance(other, DifferentialLadderMultiplier):
@@ -264,24 +310,31 @@ class DifferentialLadderMultiplier(ScalarMultiplier):
self.formulas == other.formulas
and self.short_circuit == other.short_circuit
and self.complete == other.complete
+ and self.full == other.full
)
def __repr__(self):
- return f"{self.__class__.__name__}({', '.join(map(str, self.formulas.values()))}, short_circuit={self.short_circuit}, complete={self.complete})"
+ return f"{self.__class__.__name__}({', '.join(map(str, self.formulas.values()))}, short_circuit={self.short_circuit}, complete={self.complete}, full={self.full})"
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
+ q = self._point
if self.complete:
+ p0 = copy(self._params.curve.neutral)
+ p1 = copy(q)
top = self._params.full_order.bit_length() - 1
- else:
+ elif self.full:
+ p0 = copy(self._params.curve.neutral)
+ p1 = copy(q)
top = scalar.bit_length() - 1
- q = self._point
- p0 = copy(self._params.curve.neutral)
- p1 = copy(q)
+ else:
+ p0 = copy(q)
+ p1 = self._dbl(q)
+ top = scalar.bit_length() - 2
for i in range(top, -1, -1):
if scalar & (1 << i) == 0:
p1 = self._dadd(q, p0, p1)
diff --git a/pyecsca/ec/mult/naf.py b/pyecsca/ec/mult/naf.py
index 408f489..6fc9131 100644
--- a/pyecsca/ec/mult/naf.py
+++ b/pyecsca/ec/mult/naf.py
@@ -112,7 +112,7 @@ class BinaryNAFMultiplier(AccumulatorMultiplier, ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
scalar_naf = naf(scalar)
@@ -210,7 +210,7 @@ class WindowNAFMultiplier(AccumulatorMultiplier, ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
scalar_naf = wnaf(scalar, self.width)
diff --git a/pyecsca/ec/mult/window.py b/pyecsca/ec/mult/window.py
index b003e40..c200cc5 100644
--- a/pyecsca/ec/mult/window.py
+++ b/pyecsca/ec/mult/window.py
@@ -103,7 +103,7 @@ class SlidingWindowMultiplier(AccumulatorMultiplier, ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
if self.recoding_direction is ProcessingDirection.LTR:
@@ -213,7 +213,7 @@ class FixedWindowLTRMultiplier(AccumulatorMultiplier, ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
# General case (any m) and special case (m = 2^k) are handled together here
@@ -313,7 +313,7 @@ class WindowBoothMultiplier(AccumulatorMultiplier, ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar) as action:
+ with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
scalar_booth = booth_window(