aboutsummaryrefslogtreecommitdiff
path: root/pyecsca/ec/mult/ladder.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyecsca/ec/mult/ladder.py')
-rw-r--r--pyecsca/ec/mult/ladder.py80
1 files changed, 78 insertions, 2 deletions
diff --git a/pyecsca/ec/mult/ladder.py b/pyecsca/ec/mult/ladder.py
index 3e9e426..f2939af 100644
--- a/pyecsca/ec/mult/ladder.py
+++ b/pyecsca/ec/mult/ladder.py
@@ -72,7 +72,7 @@ class LadderMultiplier(ScalarMultiplier):
if self.complete:
p0 = copy(self._params.curve.neutral)
p1 = self._point
- top = self._params.order.bit_length() - 1
+ top = self._params.full_order.bit_length() - 1
else:
p0 = copy(q)
p1 = self._dbl(q)
@@ -88,6 +88,82 @@ class LadderMultiplier(ScalarMultiplier):
@public
+class SwapLadderMultiplier(ScalarMultiplier):
+ """
+ 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,
+ ladd: LadderFormula,
+ dbl: Optional[DoublingFormula] = None,
+ scl: Optional[ScalingFormula] = None,
+ complete: bool = True,
+ short_circuit: bool = True,
+ ):
+ super().__init__(short_circuit=short_circuit, ladd=ladd, dbl=dbl, scl=scl)
+ self.complete = complete
+ 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.")
+
+ def __hash__(self):
+ return hash((LadderMultiplier, super().__hash__(), self.complete))
+
+ def __eq__(self, other):
+ if not isinstance(other, LadderMultiplier):
+ 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__}({', '.join(map(str, 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.")
+ with ScalarMultiplicationAction(self._point, 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 = self._point
+ top = self._params.full_order.bit_length() - 1
+ else:
+ p0 = copy(q)
+ p1 = self._dbl(q)
+ top = scalar.bit_length() - 2
+ prev_bit = 0
+ for i in range(top, -1, -1):
+ k = (scalar & (1 << i)) >> i
+ swap = prev_bit ^ k
+ prev_bit = k
+ p0, p1 = (p1, p0) if swap else (p0, p1)
+ p0, p1 = self._ladd(q, p0, p1)
+ p0, p1 = (p1, p0) if prev_bit else (p0, p1)
+ if "scl" in self.formulas:
+ p0 = self._scl(p0)
+ return action.exit(p0)
+
+
+@public
class SimpleLadderMultiplier(ScalarMultiplier):
"""
Montgomery ladder multiplier, using addition and doubling formulas.
@@ -200,7 +276,7 @@ class DifferentialLadderMultiplier(ScalarMultiplier):
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
q = self._point