diff options
Diffstat (limited to 'pyecsca')
| -rw-r--r-- | pyecsca/ec/curve.py | 6 | ||||
| -rw-r--r-- | pyecsca/ec/model.py | 68 | ||||
| -rw-r--r-- | pyecsca/ec/mult.py | 104 | ||||
| -rw-r--r-- | pyecsca/ec/naf.py | 30 | ||||
| -rw-r--r-- | pyecsca/sca/trace_set/inspector.py | 2 | ||||
| -rw-r--r-- | pyecsca/sca/ttest.py | 6 |
6 files changed, 169 insertions, 47 deletions
diff --git a/pyecsca/ec/curve.py b/pyecsca/ec/curve.py index d4cef5d..bf2cb36 100644 --- a/pyecsca/ec/curve.py +++ b/pyecsca/ec/curve.py @@ -1,4 +1,4 @@ -from typing import Type, Mapping +from typing import Mapping from .point import Point from .coordinates import CoordinateModel @@ -6,12 +6,12 @@ from .model import CurveModel class EllipticCurve(object): - model: Type[CurveModel] + model: CurveModel coordinate_model: CoordinateModel parameters: Mapping[str, int] neutral: Point - def __init__(self, model: Type[CurveModel], coordinate_model: CoordinateModel, + def __init__(self, model: CurveModel, coordinate_model: CoordinateModel, parameters: Mapping[str, int], neutral: Point): if coordinate_model not in model.coordinates.values(): raise ValueError diff --git a/pyecsca/ec/model.py b/pyecsca/ec/model.py index 84928bc..749dbbf 100644 --- a/pyecsca/ec/model.py +++ b/pyecsca/ec/model.py @@ -8,6 +8,7 @@ from .coordinates import CoordinateModel class CurveModel(object): _efd_name: str + _loaded: bool = False name: str coordinates: MutableMapping[str, CoordinateModel] parameter_names: List[str] @@ -21,28 +22,32 @@ class CurveModel(object): to_weierstrass: List[Module] from_weierstrass: List[Module] - def __init_subclass__(cls, efd_name: str = "", **kwargs): - cls._efd_name = efd_name + def __init__(self, efd_name: str): + self._efd_name = efd_name + if self._loaded: + return + else: + self.__class__._loaded = True + self.__class__.coordinates = {} + self.__class__.parameter_names = [] + self.__class__.coordinate_names = [] + self.__class__.base_addition = [] + self.__class__.base_doubling = [] + self.__class__.base_negation = [] + self.__class__.base_neutral = [] + self.__class__.full_weierstrass = [] + self.__class__.to_weierstrass = [] + self.__class__.from_weierstrass = [] + files = resource_listdir(__name__, "efd/" + efd_name) - cls.coordinates = {} - cls.parameter_names = [] - cls.coordinate_names = [] - cls.base_addition = [] - cls.base_doubling = [] - cls.base_negation = [] - cls.base_neutral = [] - cls.full_weierstrass = [] - cls.to_weierstrass = [] - cls.from_weierstrass = [] for fname in files: file_path = "efd/" + efd_name + "/" + fname if resource_isdir(__name__, file_path): - cls.__read_coordinate_dir(file_path, fname) + self.__read_coordinate_dir(file_path, fname) else: - cls.__read_curve_file(file_path) + self.__read_curve_file(self.__class__, file_path) - @classmethod - def __read_curve_file(cls, file_path): + def __read_curve_file(self, cls, file_path): def format_eq(line, mode="exec"): return parse(line.replace("^", "**"), mode=mode) @@ -69,31 +74,38 @@ class CurveModel(object): elif line.startswith("toweierstrass"): cls.to_weierstrass.append(format_eq(line[14:])) elif line.startswith("fromweierstrass"): - cls.to_weierstrass.append(format_eq(line[16:])) + cls.from_weierstrass.append(format_eq(line[16:])) else: cls.full_weierstrass.append(format_eq(line)) line = f.readline() - @classmethod - def __read_coordinate_dir(cls, dir_path, name): - cls.coordinates[name] = CoordinateModel(dir_path, name, cls) + def __read_coordinate_dir(self, dir_path, name): + self.coordinates[name] = CoordinateModel(dir_path, name, self) @public -class ShortWeierstrassModel(CurveModel, efd_name="shortw"): - pass +class ShortWeierstrassModel(CurveModel): + + def __init__(self): + super().__init__("shortw") @public -class MontgomeryModel(CurveModel, efd_name="montgom"): - pass +class MontgomeryModel(CurveModel): + + def __init__(self): + super().__init__("montgom") @public -class EdwardsModel(CurveModel, efd_name="edwards"): - pass +class EdwardsModel(CurveModel): + + def __init__(self): + super().__init__("edwards") @public -class TwistedEdwardsModel(CurveModel, efd_name="twisted"): - pass +class TwistedEdwardsModel(CurveModel): + + def __init__(self): + super().__init__("twisted") diff --git a/pyecsca/ec/mult.py b/pyecsca/ec/mult.py index 9255342..9870296 100644 --- a/pyecsca/ec/mult.py +++ b/pyecsca/ec/mult.py @@ -1,6 +1,7 @@ from copy import copy -from typing import Mapping, Tuple, Optional +from typing import Mapping, Tuple, Optional, List +from pyecsca.ec.naf import naf, wnaf from .context import Context from .curve import EllipticCurve from .formula import Formula, AdditionFormula, DoublingFormula, ScalingFormula, LadderFormula @@ -11,6 +12,7 @@ class ScalarMultiplier(object): curve: EllipticCurve formulas: Mapping[str, Formula] context: Context + _point: Optional[Point] = None def __init__(self, curve: EllipticCurve, ctx: Context = None, **formulas: Optional[Formula]): for formula in formulas.values(): @@ -44,13 +46,20 @@ class ScalarMultiplier(object): raise NotImplementedError return self.context.execute(self.formulas["scl"], point, **self.curve.parameters)[0] - def _ladd(self, start: Point, to_dbl: Point, to_add: Point) -> Tuple[Point, Point]: + def _ladd(self, start: Point, to_dbl: Point, to_add: Point) -> Tuple[Point, ...]: if "ladd" not in self.formulas: raise NotImplementedError return self.context.execute(self.formulas["ladd"], start, to_dbl, to_add, **self.curve.parameters) - def multiply(self, scalar: int, point: Point) -> Point: + def _neg(self, point: Point) -> Point: + #TODO + raise NotImplementedError + + def init(self, point: Point): + raise NotImplementedError + + def multiply(self, scalar: int, point: Optional[Point]) -> Point: raise NotImplementedError @@ -63,14 +72,19 @@ class LTRMultiplier(ScalarMultiplier): super().__init__(curve, ctx, add=add, dbl=dbl, scl=scl) self.always = always - def multiply(self, scalar: int, point: Point) -> Point: + def init(self, point: Point): + self._point = point + + def multiply(self, scalar: int, point: Optional[Point]) -> Point: + if point is not None and self._point != point: + self.init(point) r = copy(self.curve.neutral) for i in range(scalar.bit_length(), -1, -1): r = self._dbl(r) if scalar & (1 << i) != 0: - r = self._add(r, point) + r = self._add(r, self._point) elif self.always: - self._add(r, point) + self._add(r, self._point) if "scl" in self.formulas: r = self._scl(r) return r @@ -85,8 +99,14 @@ class RTLMultiplier(ScalarMultiplier): super().__init__(curve, ctx, add=add, dbl=dbl, scl=scl) self.always = always - def multiply(self, scalar: int, point: Point) -> Point: + def init(self, point: Point): + self._point = point + + def multiply(self, scalar: int, point: Optional[Point]) -> Point: + if point is not None and self._point != point: + self.init(point) r = copy(self.curve.neutral) + point = self._point while scalar > 0: if scalar & 1 != 0: r = self._add(r, point) @@ -105,14 +125,74 @@ class LadderMultiplier(ScalarMultiplier): ctx: Context = None): super().__init__(curve, ctx, ladd=ladd, scl=scl) - def multiply(self, scalar: int, point: Point) -> Point: - p0 = copy(point) - p1 = self._ladd(self.curve.neutral, point, point)[1] + def init(self, point: Point): + self._point = point + + def multiply(self, scalar: int, point: Optional[Point]) -> Point: + if point is not None and self._point != point: + self.init(point) + p0 = copy(self._point) + p1 = self._ladd(self.curve.neutral, self._point, self._point)[1] for i in range(scalar.bit_length(), -1, -1): if scalar & i != 0: - p0, p1 = self._ladd(point, p1, p0) + p0, p1 = self._ladd(self._point, p1, p0) else: - p0, p1 = self._ladd(point, p0, p1) + p0, p1 = self._ladd(self._point, p0, p1) if "scl" in self.formulas: p0 = self._scl(p0) return p0 + + +class BinaryNAFMultiplier(ScalarMultiplier): + _point_neg: Point + + def __init__(self, curve: EllipticCurve, add: AdditionFormula, dbl: DoublingFormula, + scl: ScalingFormula = None, + ctx: Context = None): + super().__init__(curve, ctx, add=add, dbl=dbl, scl=scl) + + def init(self, point: Point): + self._point = point + self._point_neg = self._neg(point) + + def multiply(self, scalar: int, point: Optional[Point]) -> Point: + if point is not None and self._point != point: + self.init(point) + bnaf = naf(scalar) + q = copy(self.curve.neutral) + for val in bnaf: + q = self._dbl(q) + if val == 1: + q = self._add(q, self._point) + if val == -1: + q = self._add(q, self._point_neg) + return q + + +class WindowNAFMultiplier(ScalarMultiplier): + _points: List[Point] + _width: int + + def __init__(self, curve: EllipticCurve, add: AdditionFormula, dbl: DoublingFormula, width: int, + scl: ScalingFormula = None, + ctx: Context = None): + super().__init__(curve, ctx, add=add, dbl=dbl, scl=scl) + self._width = width + + def init(self, point: Point): + self._point = point + # TODO: precompute {1, 3, 5, upto 2^(w-1)-1} + + def multiply(self, scalar: int, point: Optional[Point]): + if point is not None and self._point != point: + self.init(point) + naf = wnaf(scalar, self._width) + q = copy(self.curve.neutral) + for val in naf: + q = self._dbl(q) + if val > 0: + q = self._add(q, self._points[val]) + elif val < 0: + neg = self._neg(self._points[-val]) + q = self._add(q, neg) + return q diff --git a/pyecsca/ec/naf.py b/pyecsca/ec/naf.py new file mode 100644 index 0000000..855ffd1 --- /dev/null +++ b/pyecsca/ec/naf.py @@ -0,0 +1,30 @@ +from public import public +from typing import List + + +@public +def wnaf(k: int, w: int) -> List[int]: + half_width = 2 ** (w - 1) + full_width = half_width * 2 + + def mods(val: int): + val_mod = val % full_width + if val_mod > half_width: + val_mod -= full_width + return val_mod + + result = [] + while k >= 1: + if k & 1: + k_val = mods(k) + result.insert(0, k_val) + k -= k_val + else: + result.insert(0, 0) + k >>= 1 + return result + + +@public +def naf(k: int) -> List[int]: + return wnaf(k, 2) diff --git a/pyecsca/sca/trace_set/inspector.py b/pyecsca/sca/trace_set/inspector.py index bcffb94..634b960 100644 --- a/pyecsca/sca/trace_set/inspector.py +++ b/pyecsca/sca/trace_set/inspector.py @@ -100,7 +100,7 @@ class InspectorTraceSet(TraceSet): external_clock_frequencty: float = 0 external_clock_time_base: int = 0 - _raw_traces: List[Trace] = None + _raw_traces: Optional[List[Trace]] = None _tag_parsers: dict = { 0x41: ("num_traces", 4, Parsers.read_int, Parsers.write_int), 0x42: ("num_samples", 4, Parsers.read_int, Parsers.write_int), diff --git a/pyecsca/sca/ttest.py b/pyecsca/sca/ttest.py index b9ecd36..34e631c 100644 --- a/pyecsca/sca/ttest.py +++ b/pyecsca/sca/ttest.py @@ -6,7 +6,7 @@ from typing import Sequence, Optional from .trace import Trace, CombinedTrace -def ttest(first_set: Sequence[Trace], second_set: Sequence[Trace], +def ttest_func(first_set: Sequence[Trace], second_set: Sequence[Trace], equal_var: bool) -> Optional[CombinedTrace]: if not first_set or not second_set or len(first_set) == 0 or len(second_set) == 0: return None @@ -25,7 +25,7 @@ def welch_ttest(first_set: Sequence[Trace], second_set: Sequence[Trace]) -> Comb :param second_set: :return: Welch's t-values (samplewise) """ - return ttest(first_set, second_set, False) + return ttest_func(first_set, second_set, False) @public def student_ttest(first_set: Sequence[Trace], second_set: Sequence[Trace]) -> CombinedTrace: @@ -37,4 +37,4 @@ def student_ttest(first_set: Sequence[Trace], second_set: Sequence[Trace]) -> Co :param second_set: :return: Student's t-values (samplewise) """ - return ttest(first_set, second_set, True) + return ttest_func(first_set, second_set, True) |
