aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2018-12-18 18:28:25 +0100
committerJ08nY2019-03-21 11:00:14 +0100
commit70636c48d6177b50cb6237c2649b3e36d04eaaf4 (patch)
treef56f16bf6cdd6325ddbd981d4cc9b9330799df87
parent2fb59321e1b12afee26cccab216d7587940e9aee (diff)
downloadpyecsca-70636c48d6177b50cb6237c2649b3e36d04eaaf4.tar.gz
pyecsca-70636c48d6177b50cb6237c2649b3e36d04eaaf4.tar.zst
pyecsca-70636c48d6177b50cb6237c2649b3e36d04eaaf4.zip
-rw-r--r--pyecsca/ec/coordinates.py32
-rw-r--r--pyecsca/ec/curve.py12
-rw-r--r--pyecsca/ec/formula.py2
-rw-r--r--pyecsca/ec/model.py31
-rw-r--r--pyecsca/ec/mult.py72
-rw-r--r--pyecsca/ec/naf.py17
-rw-r--r--pyecsca/ec/point.py4
-rw-r--r--pyecsca/sca/trace.py19
-rw-r--r--pyecsca/sca/trace_set/inspector.py8
9 files changed, 125 insertions, 72 deletions
diff --git a/pyecsca/ec/coordinates.py b/pyecsca/ec/coordinates.py
index 61ee5bf..e8f4710 100644
--- a/pyecsca/ec/coordinates.py
+++ b/pyecsca/ec/coordinates.py
@@ -16,6 +16,35 @@ class CoordinateModel(object):
assumptions: List[Expression]
formulas: MutableMapping[str, Formula]
+ def __repr__(self):
+ return f"{self.__class__.__name__}(\"{self.name}\" on {self.curve_model.name})"
+
+
+class AffineCoordinateModel(CoordinateModel):
+ name = "affine"
+ full_name = "Affine coordinates"
+
+ def __init__(self, curve_model: Any):
+ self.curve_model = curve_model
+ self.variables = ["x", "y"]
+ self.satisfying = []
+ self.parameters = []
+ self.assumptions = []
+ self.formulas = {}
+
+ def from_other(self, point):
+ if point.coordinate_model.curve_model != self.curve_model:
+ raise ValueError
+ # TODO
+ pass
+
+ def to_other(self, other: CoordinateModel, point):
+ # TODO
+ pass
+
+
+class EFDCoordinateModel(CoordinateModel):
+
def __init__(self, dir_path: str, name: str, curve_model: Any):
self.name = name
self.curve_model = curve_model
@@ -69,6 +98,3 @@ class CoordinateModel(object):
self.assumptions.append(
parse(line[7:].replace("=", "==").replace("^", "**"), mode="eval"))
line = f.readline().decode("ascii")
-
- def __repr__(self):
- return "CoordinateModel(\"{}\" on {})".format(self.name, self.curve_model.name)
diff --git a/pyecsca/ec/curve.py b/pyecsca/ec/curve.py
index bf2cb36..4c9d401 100644
--- a/pyecsca/ec/curve.py
+++ b/pyecsca/ec/curve.py
@@ -1,8 +1,8 @@
from typing import Mapping
-from .point import Point
from .coordinates import CoordinateModel
from .model import CurveModel
+from .point import Point
class EllipticCurve(object):
@@ -23,3 +23,13 @@ class EllipticCurve(object):
self.coordinate_model = coordinate_model
self.parameters = dict(parameters)
self.neutral = neutral
+
+ def is_on_curve(self, point: Point) -> bool:
+ pass
+
+ def is_neutral(self, point: Point) -> bool:
+ return self.neutral == point
+
+ def __repr__(self):
+ params = ", ".join((f"{key}={val}" for key, val in self.parameters.items()))
+ return f"EllipticCurve([{params}] on {self.model} using {self.coordinate_model})"
diff --git a/pyecsca/ec/formula.py b/pyecsca/ec/formula.py
index 80139b7..897a44b 100644
--- a/pyecsca/ec/formula.py
+++ b/pyecsca/ec/formula.py
@@ -50,7 +50,7 @@ class Formula(object):
return self._outputs
def __repr__(self):
- return self.__class__.__name__ + "({} for {})".format(self.name, self.coordinate_model)
+ return f"{self.__class__.__name__}({self.name} for {self.coordinate_model})"
class AdditionFormula(Formula):
diff --git a/pyecsca/ec/model.py b/pyecsca/ec/model.py
index 749dbbf..40c19e9 100644
--- a/pyecsca/ec/model.py
+++ b/pyecsca/ec/model.py
@@ -3,12 +3,10 @@ from pkg_resources import resource_listdir, resource_isdir, resource_stream
from public import public
from typing import List, MutableMapping
-from .coordinates import CoordinateModel
+from .coordinates import EFDCoordinateModel, CoordinateModel
class CurveModel(object):
- _efd_name: str
- _loaded: bool = False
name: str
coordinates: MutableMapping[str, CoordinateModel]
parameter_names: List[str]
@@ -22,6 +20,11 @@ class CurveModel(object):
to_weierstrass: List[Module]
from_weierstrass: List[Module]
+
+class EFDCurveModel(CurveModel):
+ _efd_name: str
+ _loaded: bool = False
+
def __init__(self, efd_name: str):
self._efd_name = efd_name
if self._loaded:
@@ -43,7 +46,7 @@ class CurveModel(object):
for fname in files:
file_path = "efd/" + efd_name + "/" + fname
if resource_isdir(__name__, file_path):
- self.__read_coordinate_dir(file_path, fname)
+ self.__read_coordinate_dir(self.__class__, file_path, fname)
else:
self.__read_curve_file(self.__class__, file_path)
@@ -79,33 +82,41 @@ class CurveModel(object):
cls.full_weierstrass.append(format_eq(line))
line = f.readline()
- def __read_coordinate_dir(self, dir_path, name):
- self.coordinates[name] = CoordinateModel(dir_path, name, self)
+ def __read_coordinate_dir(self, cls, dir_path, name):
+ cls.coordinates[name] = EFDCoordinateModel(dir_path, name, self)
+
+ def __eq__(self, other):
+ if not isinstance(other, EFDCurveModel):
+ return False
+ return self._efd_name == other._efd_name
+
+ def __repr__(self):
+ return f"{self.__class__.__name__}()"
@public
-class ShortWeierstrassModel(CurveModel):
+class ShortWeierstrassModel(EFDCurveModel):
def __init__(self):
super().__init__("shortw")
@public
-class MontgomeryModel(CurveModel):
+class MontgomeryModel(EFDCurveModel):
def __init__(self):
super().__init__("montgom")
@public
-class EdwardsModel(CurveModel):
+class EdwardsModel(EFDCurveModel):
def __init__(self):
super().__init__("edwards")
@public
-class TwistedEdwardsModel(CurveModel):
+class TwistedEdwardsModel(EFDCurveModel):
def __init__(self):
super().__init__("twisted")
diff --git a/pyecsca/ec/mult.py b/pyecsca/ec/mult.py
index 9870296..a623fd0 100644
--- a/pyecsca/ec/mult.py
+++ b/pyecsca/ec/mult.py
@@ -12,7 +12,7 @@ class ScalarMultiplier(object):
curve: EllipticCurve
formulas: Mapping[str, Formula]
context: Context
- _point: Optional[Point] = None
+ _point: Point = None
def __init__(self, curve: EllipticCurve, ctx: Context = None, **formulas: Optional[Formula]):
for formula in formulas.values():
@@ -53,13 +53,22 @@ class ScalarMultiplier(object):
**self.curve.parameters)
def _neg(self, point: Point) -> Point:
- #TODO
+ # TODO
raise NotImplementedError
def init(self, point: Point):
- raise NotImplementedError
+ self._point = point
+
+ def _init_multiply(self, point: Optional[Point]) -> Point:
+ if point is None:
+ if self._point is None:
+ raise ValueError
+ else:
+ if self._point != point:
+ self.init(point)
+ return self._point
- def multiply(self, scalar: int, point: Optional[Point]) -> Point:
+ def multiply(self, scalar: int, point: Optional[Point] = None) -> Point:
raise NotImplementedError
@@ -72,19 +81,15 @@ class LTRMultiplier(ScalarMultiplier):
super().__init__(curve, ctx, add=add, dbl=dbl, scl=scl)
self.always = always
- 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)
+ def multiply(self, scalar: int, point: Optional[Point] = None) -> Point:
+ q = self._init_multiply(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, self._point)
+ r = self._add(r, q)
elif self.always:
- self._add(r, self._point)
+ self._add(r, q)
if "scl" in self.formulas:
r = self._scl(r)
return r
@@ -99,20 +104,15 @@ class RTLMultiplier(ScalarMultiplier):
super().__init__(curve, ctx, add=add, dbl=dbl, scl=scl)
self.always = always
- 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)
+ def multiply(self, scalar: int, point: Optional[Point] = None) -> Point:
+ q = self._init_multiply(point)
r = copy(self.curve.neutral)
- point = self._point
while scalar > 0:
if scalar & 1 != 0:
- r = self._add(r, point)
+ r = self._add(r, q)
elif self.always:
- self._add(r, point)
- point = self._dbl(point)
+ self._add(r, q)
+ q = self._dbl(q)
scalar >>= 1
if "scl" in self.formulas:
r = self._scl(r)
@@ -125,19 +125,15 @@ class LadderMultiplier(ScalarMultiplier):
ctx: Context = None):
super().__init__(curve, ctx, ladd=ladd, scl=scl)
- 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]
+ def multiply(self, scalar: int, point: Optional[Point] = None) -> Point:
+ q = self._init_multiply(point)
+ p0 = copy(q)
+ p1 = self._ladd(self.curve.neutral, q, q)[1]
for i in range(scalar.bit_length(), -1, -1):
if scalar & i != 0:
- p0, p1 = self._ladd(self._point, p1, p0)
+ p0, p1 = self._ladd(q, p1, p0)
else:
- p0, p1 = self._ladd(self._point, p0, p1)
+ p0, p1 = self._ladd(q, p0, p1)
if "scl" in self.formulas:
p0 = self._scl(p0)
return p0
@@ -152,12 +148,11 @@ class BinaryNAFMultiplier(ScalarMultiplier):
super().__init__(curve, ctx, add=add, dbl=dbl, scl=scl)
def init(self, point: Point):
- self._point = point
+ super().init(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)
+ def multiply(self, scalar: int, point: Optional[Point] = None) -> Point:
+ self._init_multiply(point)
bnaf = naf(scalar)
q = copy(self.curve.neutral)
for val in bnaf:
@@ -183,9 +178,8 @@ class WindowNAFMultiplier(ScalarMultiplier):
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)
+ def multiply(self, scalar: int, point: Optional[Point] = None):
+ self._init_multiply(point)
naf = wnaf(scalar, self._width)
q = copy(self.curve.neutral)
for val in naf:
diff --git a/pyecsca/ec/naf.py b/pyecsca/ec/naf.py
index 855ffd1..8f07c9f 100644
--- a/pyecsca/ec/naf.py
+++ b/pyecsca/ec/naf.py
@@ -4,16 +4,23 @@ from typing import List
@public
def wnaf(k: int, w: int) -> List[int]:
+ """
+ Compute width `w` NAF (Non-Adjacent Form) of the scalar `k`.
+
+ :param k:
+ :param w:
+ :return:
+ """
half_width = 2 ** (w - 1)
full_width = half_width * 2
- def mods(val: int):
+ def mods(val: int) -> int:
val_mod = val % full_width
if val_mod > half_width:
val_mod -= full_width
return val_mod
- result = []
+ result: List[int] = []
while k >= 1:
if k & 1:
k_val = mods(k)
@@ -27,4 +34,10 @@ def wnaf(k: int, w: int) -> List[int]:
@public
def naf(k: int) -> List[int]:
+ """
+ Compute the NAF (Non-Adjacent Form) of the scalar `k`.
+
+ :param k:
+ :return:
+ """
return wnaf(k, 2)
diff --git a/pyecsca/ec/point.py b/pyecsca/ec/point.py
index e81b028..265a0ea 100644
--- a/pyecsca/ec/point.py
+++ b/pyecsca/ec/point.py
@@ -20,5 +20,5 @@ class Point(object):
return self.coordinate_model == other.coordinate_model and self.coords == other.coords
def __repr__(self):
- args = ", ".join(["{}={}".format(key, value) for key, value in self.coords.items()])
- return "Point([{}] in {})".format(args, self.coordinate_model)
+ args = ", ".join([f"{key}={val}" for key, val in self.coords.items()])
+ return f"Point([{args}] in {self.coordinate_model})"
diff --git a/pyecsca/sca/trace.py b/pyecsca/sca/trace.py
index a9d6892..5324a37 100644
--- a/pyecsca/sca/trace.py
+++ b/pyecsca/sca/trace.py
@@ -1,37 +1,38 @@
import weakref
from numpy import ndarray
-from typing import Optional, Sequence
-
from public import public
+from typing import Optional, Sequence, Any
@public
class Trace(object):
"""A power trace, which has an optional title, optional data bytes and mandatory samples."""
+ title: Optional[str]
+ data: Optional[bytes]
+ samples: ndarray
def __init__(self, title: Optional[str], data: Optional[bytes],
- samples: ndarray, trace_set=None):
+ samples: ndarray, trace_set: Any = None):
self.title = title
self.data = data
self.samples = samples
self.trace_set = trace_set
@property
- def trace_set(self):
+ def trace_set(self) -> Any:
if self._trace_set is None:
return None
return self._trace_set()
@trace_set.setter
- def trace_set(self, trace_set):
+ def trace_set(self, trace_set: Any):
if trace_set is None:
self._trace_set = None
else:
self._trace_set = weakref.ref(trace_set)
def __repr__(self):
- return "Trace(title={!r}, data={!r}, samples={!r}, trace_set={!r})".format(
- self.title, self.data, self.samples, self.trace_set)
+ return f"Trace(title={self.title!r}, data={self.data!r}, samples={self.samples!r}, trace_set={self.trace_set!r})"
@public
@@ -46,6 +47,4 @@ class CombinedTrace(Trace):
self.parents = weakref.WeakSet(parents)
def __repr__(self):
- return "CombinedTrace(title={!r}, data={!r}, samples={!r}, trace_set={!r}, parents={})".format(
- self.title, self.data, self.samples, self.trace_set,
- self.parents)
+ return f"CombinedTrace(title={self.title!r}, data={self.data!r}, samples={self.samples!r}, trace_set={self.trace_set!r}, parents={self.parents})"
diff --git a/pyecsca/sca/trace_set/inspector.py b/pyecsca/sca/trace_set/inspector.py
index 634b960..067d348 100644
--- a/pyecsca/sca/trace_set/inspector.py
+++ b/pyecsca/sca/trace_set/inspector.py
@@ -267,7 +267,7 @@ class InspectorTraceSet(TraceSet):
return int(1 / self.x_scale)
def __repr__(self):
- args = ", ".join(["{}={!r}".format(self._tag_parsers[set_tag][0],
- getattr(self, self._tag_parsers[set_tag][0]))
- for set_tag in self._set_tags])
- return "InspectorTraceSet({})".format(args)
+ args = ", ".join(
+ [f"{self._tag_parsers[set_tag][0]}={getattr(self, self._tag_parsers[set_tag][0])!r}"
+ for set_tag in self._set_tags])
+ return f"InspectorTraceSet({args})"