diff options
| author | J08nY | 2025-03-12 20:01:29 +0100 |
|---|---|---|
| committer | J08nY | 2025-03-12 20:01:29 +0100 |
| commit | 4440cf1e5fd28456d8b259d498f9831d46acef73 (patch) | |
| tree | d232b04b6d588477e1401fbd8d7ae769066d8ad5 /pyecsca/ec | |
| parent | 345d5883e5e75ed02282107127a8e65b67435247 (diff) | |
| download | pyecsca-4440cf1e5fd28456d8b259d498f9831d46acef73.tar.gz pyecsca-4440cf1e5fd28456d8b259d498f9831d46acef73.tar.zst pyecsca-4440cf1e5fd28456d8b259d498f9831d46acef73.zip | |
Docs for countermeasures.
Diffstat (limited to 'pyecsca/ec')
| -rw-r--r-- | pyecsca/ec/countermeasures.py | 152 | ||||
| -rw-r--r-- | pyecsca/ec/mult/base.py | 2 |
2 files changed, 116 insertions, 38 deletions
diff --git a/pyecsca/ec/countermeasures.py b/pyecsca/ec/countermeasures.py index 5c52f35..8a479b6 100644 --- a/pyecsca/ec/countermeasures.py +++ b/pyecsca/ec/countermeasures.py @@ -7,7 +7,7 @@ from public import public from pyecsca.ec.formula import AdditionFormula from pyecsca.ec.mod import Mod, mod -from pyecsca.ec.mult import ScalarMultiplier +from pyecsca.ec.mult import ScalarMultiplier, ScalarMultiplicationAction from pyecsca.ec.params import DomainParameters from pyecsca.ec.point import Point @@ -29,102 +29,180 @@ class ScalarMultiplierCountermeasure(ABC): self.mult = mult def init(self, params: DomainParameters, point: Point): + """Initialize the countermeasure with the parameters and the point.""" self.params = params self.point = point self.mult.init(self.params, self.point) @abstractmethod def multiply(self, scalar: int) -> Point: + """ + Multiply the point with the scalar using the countermeasure. + + .. note:: + The countermeasure may compute multiple scalar multiplications internally. + Thus, it may call the init method of the scalar multiplier multiple times. + """ raise NotImplementedError @public class GroupScalarRandomization(ScalarMultiplierCountermeasure): + r""" + Group scalar randomization countermeasure. + + Samples a random multiple, multiplies the order with it and adds it to the scalar. + + .. math:: + :class: frame + + &r \xleftarrow{\$} \{0, 1, \ldots, 2^{\text{rand_bits}}\} \\ + &\textbf{return}\ [k + r n]G + + """ rand_bits: int def __init__(self, mult: ScalarMultiplier, rand_bits: int = 32): + """ + :param mult: The multiplier to use. + :param rand_bits: How many random bits to sample. + """ super().__init__(mult) self.rand_bits = rand_bits def multiply(self, scalar: int) -> Point: if self.params is None or self.point is None: raise ValueError("Not initialized.") - order = self.params.order - mask = int(Mod.random(1 << self.rand_bits)) - masked_scalar = scalar + mask * order - return self.mult.multiply(masked_scalar) + with ScalarMultiplicationAction(self.point, self.params, scalar) as action: + order = self.params.order + mask = int(Mod.random(1 << self.rand_bits)) + masked_scalar = scalar + mask * order + return action.exit(self.mult.multiply(masked_scalar)) @public class AdditiveSplitting(ScalarMultiplierCountermeasure): + r""" + Additive splitting countermeasure. + + Splits the scalar into two parts additively, multiplies the point with them and adds the results. + + .. math:: + :class: frame + + &r \xleftarrow{\$} \{0, 1, \ldots, n\} \\ + &\textbf{return}\ [k - r]G + [r]G + + """ add: Optional[AdditionFormula] def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None): + """ + :param mult: The multiplier to use. + :param add: Addition formula to use, if None, the formula from the multiplier is used. + """ super().__init__(mult) self.add = add def multiply(self, scalar: int) -> Point: if self.params is None or self.point is None: raise ValueError("Not initialized.") - - order = self.params.order - r = Mod.random(order) - s = scalar - r - R = self.mult.multiply(int(r)) - S = self.mult.multiply(int(s)) - if self.add is None: - return self.mult._add(R, S) # noqa: This is OK. - else: - return self.add( - self.params.curve.prime, R, S, **self.params.curve.parameters - )[0] + with ScalarMultiplicationAction(self.point, self.params, scalar) as action: + order = self.params.order + r = Mod.random(order) + s = scalar - r + R = self.mult.multiply(int(r)) + S = self.mult.multiply(int(s)) + if self.add is None: + res = self.mult._add(R, S) # noqa: This is OK. + else: + res = self.add(self.params.curve.prime, R, S, **self.params.curve.parameters)[0] + return action.exit(res) @public class MultiplicativeSplitting(ScalarMultiplierCountermeasure): + r""" + Multiplicative splitting countermeasure. + + Splits the scalar into two parts multiplicatively, multiplies the point with them and adds the results. + + .. math:: + :class: frame + + &r \xleftarrow{\$} \{0, 1, \ldots, 2^{\text{rand_bits}}\} \\ + &S = [r]G \\ + &\textbf{return}\ [k r^{-1} \mod n]S + + """ rand_bits: int def __init__(self, mult: ScalarMultiplier, rand_bits: int = 32): + """ + :param mult: The multiplier to use. + :param rand_bits: How many random bits to sample. + """ super().__init__(mult) self.rand_bits = rand_bits def multiply(self, scalar: int) -> Point: if self.params is None or self.point is None: raise ValueError("Not initialized.") - r = Mod.random(1 << self.rand_bits) - R = self.mult.multiply(int(r)) + with ScalarMultiplicationAction(self.point, self.params, scalar) as action: + r = Mod.random(1 << self.rand_bits) + R = self.mult.multiply(int(r)) - self.mult.init(self.params, R) - kr_inv = scalar * mod(int(r), self.params.order).inverse() - return self.mult.multiply(int(kr_inv)) + self.mult.init(self.params, R) + kr_inv = scalar * mod(int(r), self.params.order).inverse() + return action.exit(self.mult.multiply(int(kr_inv))) @public class EuclideanSplitting(ScalarMultiplierCountermeasure): + r""" + Euclidean splitting countermeasure. + + Picks a random value half the size of the curve, then splits the scalar + into the remainder and the quotient of the division by the random value. + + .. math:: + :class: frame + + &r \xleftarrow{\$} \{0, 1, \ldots, 2^{\log_2{(n)}/2}\} \\ + &S = [r]G \\ + &k_1 = k \mod r \\ + &k_2 = \lfloor \frac{k}{r} \rfloor \\ + &\textbf{return}\ [k_1]G + [k_2]S + + """ add: Optional[AdditionFormula] def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None): + """ + :param mult: The multiplier to use. + :param add: Addition formula to use, if None, the formula from the multiplier is used. + """ super().__init__(mult) self.add = add def multiply(self, scalar: int) -> Point: if self.params is None or self.point is None: raise ValueError("Not initialized.") + with ScalarMultiplicationAction(self.point, self.params, scalar) as action: + order = self.params.order + half_bits = order.bit_length() // 2 + r = Mod.random(1 << half_bits) + R = self.mult.multiply(int(r)) - order = self.params.order - half_bits = order.bit_length() // 2 - r = Mod.random(1 << half_bits) - R = self.mult.multiply(int(r)) + k1 = scalar % int(r) + k2 = scalar // int(r) + T = self.mult.multiply(k1) - k1 = scalar % int(r) - k2 = scalar // int(r) - T = self.mult.multiply(k1) + self.mult.init(self.params, R) + S = self.mult.multiply(k2) - self.mult.init(self.params, R) - S = self.mult.multiply(k2) - if self.add is None: - return self.mult._add(S, T) # noqa: This is OK. - else: - return self.add( - self.params.curve.prime, S, T, **self.params.curve.parameters - )[0] + if self.add is None: + res = self.mult._add(S, T) # noqa: This is OK. + else: + res = self.add(self.params.curve.prime, S, T, **self.params.curve.parameters)[0] + return action.exit(res) diff --git a/pyecsca/ec/mult/base.py b/pyecsca/ec/mult/base.py index 1c51271..f7a8c5b 100644 --- a/pyecsca/ec/mult/base.py +++ b/pyecsca/ec/mult/base.py @@ -7,7 +7,7 @@ from enum import Enum from public import public from typing import Mapping, Tuple, Optional, ClassVar, Set, Type -from pyecsca.ec.context import ResultAction, Action +from pyecsca.ec.context import ResultAction from pyecsca.ec.formula import Formula from pyecsca.ec.params import DomainParameters from pyecsca.ec.point import Point |
