diff options
Diffstat (limited to 'pyecsca/ec/mult/ladder.py')
| -rw-r--r-- | pyecsca/ec/mult/ladder.py | 80 |
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 |
