diff options
| author | J08nY | 2019-03-21 14:55:14 +0100 |
|---|---|---|
| committer | J08nY | 2019-03-21 14:55:14 +0100 |
| commit | 647dfbbec29d9a4cabf1ca132390c837870535fd (patch) | |
| tree | ef2c7148bbe6365916abc6b3e4c5f83ccdaa6c49 | |
| parent | 626102a3885d5c9bea88cafcb143fe626685f4b6 (diff) | |
| download | pyecsca-647dfbbec29d9a4cabf1ca132390c837870535fd.tar.gz pyecsca-647dfbbec29d9a4cabf1ca132390c837870535fd.tar.zst pyecsca-647dfbbec29d9a4cabf1ca132390c837870535fd.zip | |
| -rw-r--r-- | pyecsca/ec/coordinates.py | 26 | ||||
| -rw-r--r-- | pyecsca/ec/mod.py | 70 | ||||
| -rw-r--r-- | pyecsca/ec/model.py | 2 | ||||
| -rw-r--r-- | pyecsca/ec/op.py | 8 | ||||
| -rw-r--r-- | pyecsca/ec/point.py | 74 | ||||
| -rw-r--r-- | test/ec/test_coordinates.py | 25 | ||||
| -rw-r--r-- | test/ec/test_mult.py | 1 |
7 files changed, 182 insertions, 24 deletions
diff --git a/pyecsca/ec/coordinates.py b/pyecsca/ec/coordinates.py index 795a935..817bff9 100644 --- a/pyecsca/ec/coordinates.py +++ b/pyecsca/ec/coordinates.py @@ -1,6 +1,6 @@ -from ast import parse, Expression +from ast import parse, Expression, Module from pkg_resources import resource_listdir, resource_isdir, resource_stream -from typing import List, Any, MutableMapping +from typing import List, Any, MutableMapping, Union from .formula import (Formula, EFDFormula, AdditionEFDFormula, DoublingEFDFormula, TriplingEFDFormula, @@ -13,7 +13,7 @@ class CoordinateModel(object): full_name: str curve_model: Any variables: List[str] - satisfying: List[Expression] + satisfying: List[Union[Module, Expression]] parameters: List[str] assumptions: List[Expression] formulas: MutableMapping[str, Formula] @@ -34,15 +34,10 @@ class AffineCoordinateModel(CoordinateModel): 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 + def __eq__(self, other): + if not isinstance(other, AffineCoordinateModel): + return False + return self.curve_model == other.curve_model class EFDCoordinateModel(CoordinateModel): @@ -88,8 +83,11 @@ class EFDCoordinateModel(CoordinateModel): elif line.startswith("variable"): self.variables.append(line[9:]) elif line.startswith("satisfying"): - self.satisfying.append( - parse(line[11:].replace("=", "==").replace("^", "**"), mode="eval")) + try: + code = parse(line[11:].replace("^", "**"), mode="exec") + except SyntaxError: + code = parse(line[11:].replace("=", "==").replace("^", "**"), mode="eval") + self.satisfying.append(code) elif line.startswith("parameter"): self.parameters.append(line[10:]) elif line.startswith("assume"): diff --git a/pyecsca/ec/mod.py b/pyecsca/ec/mod.py index c8c9a92..e9c5657 100644 --- a/pyecsca/ec/mod.py +++ b/pyecsca/ec/mod.py @@ -1,6 +1,7 @@ from functools import wraps from public import public + @public def gcd(a, b): if abs(a) < abs(b): @@ -12,6 +13,7 @@ def gcd(a, b): return a + @public def extgcd(a, b): if abs(b) > abs(a): @@ -43,6 +45,7 @@ def check(func): return method + @public class Mod(object): @@ -141,3 +144,70 @@ class Mod(object): r = (q * r) i = i << 1 return r + + +@public +class Undefined(Mod): + + def __init__(self): + pass + + def __add__(self, other): + raise NotImplementedError + + def __radd__(self, other): + raise NotImplementedError + + def __sub__(self, other): + raise NotImplementedError + + def __rsub__(self, other): + raise NotImplementedError + + def __neg__(self): + raise NotImplementedError + + def __invert__(self): + raise NotImplementedError + + def __mul__(self, other): + raise NotImplementedError + + def __rmul__(self, other): + raise NotImplementedError + + def __truediv__(self, other): + raise NotImplementedError + + def __rtruediv__(self, other): + raise NotImplementedError + + def __floordiv__(self, other): + raise NotImplementedError + + def __rfloordiv__(self, other): + raise NotImplementedError + + def __div__(self, other): + raise NotImplementedError + + def __rdiv__(self, other): + raise NotImplementedError + + def __divmod__(self, divisor): + raise NotImplementedError + + def __int__(self): + raise NotImplementedError + + def __eq__(self, other): + return False + + def __ne__(self, other): + return False + + def __repr__(self): + return "Undefined" + + def __pow__(self, n): + raise NotImplementedError diff --git a/pyecsca/ec/model.py b/pyecsca/ec/model.py index 397b0ee..53d530a 100644 --- a/pyecsca/ec/model.py +++ b/pyecsca/ec/model.py @@ -29,9 +29,9 @@ class EFDCurveModel(CurveModel): _loaded: bool = False def __init__(self, efd_name: str): + self._efd_name = efd_name if self._loaded: return - self._efd_name = efd_name self.__class__._loaded = True self.__class__.coordinates = {} self.__class__.parameter_names = [] diff --git a/pyecsca/ec/op.py b/pyecsca/ec/op.py index b366617..ea2254f 100644 --- a/pyecsca/ec/op.py +++ b/pyecsca/ec/op.py @@ -1,4 +1,5 @@ from ast import Module, walk, Name +from types import CodeType from typing import FrozenSet from .mod import Mod @@ -15,6 +16,7 @@ class Op(object): class CodeOp(Op): code: Module + compiled: CodeType def __init__(self, code: Module): self.code = code @@ -31,8 +33,12 @@ class CodeOp(Op): params.add(name) self.parameters = frozenset(params) self.variables = frozenset(variables) + self.compiled = compile(self.code, "", mode="exec") + + def __repr__(self): + return f"CodeOp({self.result} = f(params={self.parameters}, vars={self.variables}))" def __call__(self, *args, **kwargs) -> Mod: loc = dict(kwargs) - exec(compile(self.code, "", mode="exec"), {}, loc) + exec(self.compiled, {}, loc) return loc[self.result] diff --git a/pyecsca/ec/point.py b/pyecsca/ec/point.py index 0b9e9b3..052165f 100644 --- a/pyecsca/ec/point.py +++ b/pyecsca/ec/point.py @@ -1,10 +1,13 @@ +from copy import copy +from public import public from typing import Mapping -from pyecsca.ec.formula import ScalingFormula -from .coordinates import CoordinateModel +from .coordinates import CoordinateModel, AffineCoordinateModel from .mod import Mod +from .op import CodeOp +@public class Point(object): coordinate_model: CoordinateModel coords: Mapping[str, Mod] @@ -15,14 +18,41 @@ class Point(object): self.coordinate_model = model self.coords = coords + def to_affine(self): + if isinstance(self.coordinate_model, AffineCoordinateModel): + return copy(self) + ops = set() + for s in self.coordinate_model.satisfying: + try: + ops.add(CodeOp(s)) + except: + pass + affine_model = AffineCoordinateModel(self.coordinate_model.curve_model) + # TODO: just fill in with undefined + if not set(map(lambda x: x.result, ops)).issuperset(affine_model.variables): + raise NotImplementedError + result = {} + for op in ops: + result[op.result] = op(**self.coords) + return Point(affine_model, **result) + + @staticmethod + def from_affine(affine_point): + # TODO + pass + + def equals(self, other): + if not isinstance(other, Point): + return False + if self.coordinate_model.curve_model != other.coordinate_model.curve_model: + return False + return self.to_affine() == other.to_affine() + def __eq__(self, other): - # TODO: Somehow compare projective points. Via a map to an affinepoint? - if type(other) is not Point: + if not isinstance(other, Point): return False - if self.coordinate_model != other.coordinate_model: + if self.coordinate_model != other.coordinate_model: return False - self_scaling = list(filter(lambda x: isinstance(x, ScalingFormula), self.coordinate_model.formulas.items())) - other_scaling = list(filter(lambda x: isinstance(x, ScalingFormula), other.coordinate_model.formulas.items())) return self.coords == other.coords def __str__(self): @@ -31,3 +61,33 @@ class Point(object): def __repr__(self): return f"Point([{str(self)}] in {self.coordinate_model})" + + +@public +class InfinityPoint(Point): + + def __init__(self, model: CoordinateModel): + self.coordinate_model = model + self.coords = {} + + def to_affine(self): + return InfinityPoint(AffineCoordinateModel(self.coordinate_model.curve_model)) + + @staticmethod + def from_affine(affine_point): + raise NotImplementedError + + def equals(self, other): + return self == other + + def __eq__(self, other): + if type(other) is not InfinityPoint: + return False + else: + return self.coordinate_model == other.coordinate_model + + def __str__(self): + return "Infinity" + + def __repr__(self): + return f"InfinityPoint({self.coordinate_model})" diff --git a/test/ec/test_coordinates.py b/test/ec/test_coordinates.py new file mode 100644 index 0000000..7532308 --- /dev/null +++ b/test/ec/test_coordinates.py @@ -0,0 +1,25 @@ +from unittest import TestCase + +from pyecsca.ec.curve import EllipticCurve +from pyecsca.ec.mod import Mod +from pyecsca.ec.model import ShortWeierstrassModel +from pyecsca.ec.point import Point + + +class CoordinateTests(TestCase): + + def setUp(self): + self.p = 0xfffffffdffffffffffffffffffffffff + self.coords = ShortWeierstrassModel().coordinates["projective"] + self.secp128r1 = EllipticCurve(ShortWeierstrassModel(), self.coords, + dict(a=0xfffffffdfffffffffffffffffffffffc, + b=0xe87579c11079f43dd824993c2cee5ed3), + Point(self.coords, X=Mod(0, self.p), Y=Mod(1, self.p), + Z=Mod(0, self.p))) + + def test_affine(self): + pt = Point(self.coords, X=Mod(0x161ff7528b899b2d0c28607ca52c5b86, self.p), + Y=Mod(0xcf5ac8395bafeb13c02da292dded7a83, self.p), + Z=Mod(1, self.p)) + affine_Point = pt.to_affine() + assert pt.equals(affine_Point) diff --git a/test/ec/test_mult.py b/test/ec/test_mult.py index 82ed9eb..29e23ba 100644 --- a/test/ec/test_mult.py +++ b/test/ec/test_mult.py @@ -77,7 +77,6 @@ class ScalarMultiplierTests(TestCase): ladder = LadderMultiplier(self.curve25519, self.coords25519.formulas["ladd-1987-m"], self.coords25519.formulas["dbl-1987-m"], self.coords25519.formulas["scale"]) - # TODO: fix this differential = SimpleLadderMultiplier(self.curve25519, self.coords25519.formulas["dadd-1987-m"], self.coords25519.formulas["dbl-1987-m"], |
