diff options
| author | J08nY | 2023-08-04 14:37:37 +0200 |
|---|---|---|
| committer | J08nY | 2023-08-04 14:37:37 +0200 |
| commit | e54a414a9dd303dac78e435df9d84fe1bcef4676 (patch) | |
| tree | 7d3250777e63f26ce328c756c0d4ac0f64e7280a /pyecsca/ec | |
| parent | 1a98db475e5ecd757411b368dd65f8f894665178 (diff) | |
| download | pyecsca-e54a414a9dd303dac78e435df9d84fe1bcef4676.tar.gz pyecsca-e54a414a9dd303dac78e435df9d84fe1bcef4676.tar.zst pyecsca-e54a414a9dd303dac78e435df9d84fe1bcef4676.zip | |
Add .to_coords to domain params and curve objects.
Also adds coordinate assumption validation to ec curve constructor.
Diffstat (limited to 'pyecsca/ec')
| -rw-r--r-- | pyecsca/ec/curve.py | 91 | ||||
| -rw-r--r-- | pyecsca/ec/divpoly.py | 4 | ||||
| -rw-r--r-- | pyecsca/ec/params.py | 31 |
3 files changed, 106 insertions, 20 deletions
diff --git a/pyecsca/ec/curve.py b/pyecsca/ec/curve.py index 8fc2793..18dd9cf 100644 --- a/pyecsca/ec/curve.py +++ b/pyecsca/ec/curve.py @@ -1,14 +1,18 @@ """Provides an elliptic curve class.""" from ast import Module +from astunparse import unparse from copy import copy -from typing import MutableMapping, Union, List, Optional +from typing import MutableMapping, Union, List, Optional, Dict from public import public +from sympy import FF, symbols, Poly, sympify from .coordinates import CoordinateModel, AffineCoordinateModel +from .error import raise_unsatisified_assumption from .mod import Mod from .model import CurveModel from .point import Point, InfinityPoint +from ..misc.cfg import getconfig @public @@ -27,21 +31,21 @@ class EllipticCurve: """The neutral point on the curve.""" def __init__( - self, - model: CurveModel, - coordinate_model: CoordinateModel, - prime: int, - neutral: Point, - parameters: MutableMapping[str, Union[Mod, int]], + self, + model: CurveModel, + coordinate_model: CoordinateModel, + prime: int, + neutral: Point, + parameters: MutableMapping[str, Union[Mod, int]], ): if coordinate_model not in model.coordinates.values() and not isinstance( - coordinate_model, AffineCoordinateModel + coordinate_model, AffineCoordinateModel ): raise ValueError if ( - set(model.parameter_names) - .union(coordinate_model.parameters) - .symmetric_difference(parameters.keys()) + set(model.parameter_names) + .union(coordinate_model.parameters) + .symmetric_difference(parameters.keys()) ): raise ValueError self.model = model @@ -56,6 +60,48 @@ class EllipticCurve: value = Mod(value, prime) self.parameters[name] = value self.neutral = neutral + self.__validate_coord_assumptions() + + def __validate_coord_assumptions(self): + for assumption in self.coordinate_model.assumptions: + # Try to execute assumption, if it works, check with curve parameters + # if it doesn't work, move all over to rhs and construct a sympy polynomial of it + # then find roots and take first one for new value for new coordinate parameter. + try: + alocals: Dict[str, Union[Mod, int]] = {} + compiled = compile(assumption, "", mode="exec") + exec(compiled, None, alocals) + for param, value in alocals.items(): + if self.parameters[param] != value: + raise_unsatisified_assumption( + getconfig().ec.unsatisfied_coordinate_assumption_action, + f"Coordinate model {self.coordinate_model} has an unsatisifed assumption on the {param} parameter (= {value}).", + ) + except NameError: + k = FF(self.prime) + assumption_string = unparse(assumption) + lhs, rhs = assumption_string.split(" = ") + expr = sympify(f"{rhs} - {lhs}") + for curve_param, value in self.parameters.items(): + expr = expr.subs(curve_param, k(value)) + if ( + len(expr.free_symbols) > 1 + or (param := str(expr.free_symbols.pop())) + not in self.coordinate_model.parameters + ): + raise ValueError( + f"This coordinate model couldn't be loaded due to an unsupported assumption ({assumption_string})." + ) + poly = Poly(expr, symbols(param), domain=k) + roots = poly.ground_roots() + for root in roots: + self.parameters[param] = Mod(int(root), self.prime) + break + else: + raise_unsatisified_assumption( + getconfig().ec.unsatisfied_coordinate_assumption_action, + f"Coordinate model {self.coordinate_model} has an unsatisifed assumption on the {param} parameter (0 = {expr})." + ) def _execute_base_formulas(self, formulas: List[Module], *points: Point) -> Point: for point in points: @@ -195,6 +241,18 @@ class EllipticCurve: loc = {**self.parameters, **point.to_affine().coords} return eval(compile(self.model.equation, "", mode="eval"), loc) + def to_coords(self, coordinate_model: CoordinateModel) -> "EllipticCurve": + """ + Convert this curve into a different coordinate model, only possible if it is currently affine. + + :param coordinate_model: The target coordinate model. + :return: The transformed elliptic curve. + """ + if not isinstance(self.coordinate_model, AffineCoordinateModel): + raise ValueError + return EllipticCurve(self.model, coordinate_model, self.prime, self.neutral.to_model(coordinate_model, self), + self.parameters) # type: ignore[arg-type] + def to_affine(self) -> "EllipticCurve": """ Convert this curve into the affine coordinate model, if possible. @@ -202,7 +260,8 @@ class EllipticCurve: :return: The transformed elliptic curve. """ coord_model = AffineCoordinateModel(self.model) - return EllipticCurve(self.model, coord_model, self.prime, self.neutral.to_affine(), self.parameters) # type: ignore[arg-type] + return EllipticCurve(self.model, coord_model, self.prime, self.neutral.to_affine(), + self.parameters) # type: ignore[arg-type] def decode_point(self, encoded: bytes) -> Point: """ @@ -270,10 +329,10 @@ class EllipticCurve: if not isinstance(other, EllipticCurve): return False return ( - self.model == other.model - and self.coordinate_model == other.coordinate_model - and self.prime == other.prime - and self.parameters == other.parameters + self.model == other.model + and self.coordinate_model == other.coordinate_model + and self.prime == other.prime + and self.parameters == other.parameters ) def __hash__(self): diff --git a/pyecsca/ec/divpoly.py b/pyecsca/ec/divpoly.py index c92ef64..a616801 100644 --- a/pyecsca/ec/divpoly.py +++ b/pyecsca/ec/divpoly.py @@ -194,6 +194,8 @@ def divpoly(curve: EllipticCurve, n: int, two_torsion_multiplicity: int = 2) -> return f * divpoly0(curve, -1)[-1] else: return f + else: + raise ValueError def mult_by_n(curve: EllipticCurve, n: int) -> Tuple[Tuple[Poly, Poly], Tuple[Poly, Poly]]: @@ -211,7 +213,7 @@ def mult_by_n(curve: EllipticCurve, n: int) -> Tuple[Tuple[Poly, Poly], Tuple[Po Kxy = lambda r: Poly(r, xs, ys, domain=K) # noqa if n == 1: - return x, y + return (x, Kxy(1)), (y, Kxy(1)) a1, a2, a3, a4, a6 = a_invariants(curve) diff --git a/pyecsca/ec/params.py b/pyecsca/ec/params.py index 82a42bd..1b1edda 100644 --- a/pyecsca/ec/params.py +++ b/pyecsca/ec/params.py @@ -17,7 +17,7 @@ from public import public from .coordinates import AffineCoordinateModel, CoordinateModel from .curve import EllipticCurve -from .error import UnsatisfiedAssumptionError, raise_unsatisified_assumption +from .error import raise_unsatisified_assumption from .mod import Mod from .model import ( CurveModel, @@ -70,6 +70,29 @@ class DomainParameters: def __hash__(self): return hash((self.curve, self.generator, self.order, self.cofactor)) + def to_coords(self, coordinate_model: CoordinateModel) -> "DomainParameters": + """ + Convert the domain parameters into a different coordinate model, only possible if they are currently affine. + + :param coordinate_model: The target coordinate model. + :return: The transformed domain parameters + """ + if not isinstance(self.curve.coordinate_model, AffineCoordinateModel): + raise ValueError + curve = self.curve.to_coords(coordinate_model) + generator = self.generator.to_model(coordinate_model, curve) + return DomainParameters(curve, generator, self.order, self.cofactor, self.name, self.category) + + def to_affine(self) -> "DomainParameters": + """ + Convert the domain parameters into the affine coordinate model, if possible. + + :return: The transformed domain parameters + """ + curve = self.curve.to_affine() + generator = self.generator.to_affine() + return DomainParameters(curve, generator, self.order, self.cofactor, self.name, self.category) + def __get_name(self): if self.name and self.category: return f"{self.category}/{self.name}" @@ -153,7 +176,7 @@ def _create_params(curve, coords, infty): coord_model = AffineCoordinateModel(model) else: if coords not in model.coordinates: - raise ValueError("Coordinate model not supported for curve.") + raise ValueError("Coordinate model not supported for curve model.") coord_model = model.coordinates[coords] for assumption in coord_model.assumptions: # Try to execute assumption, if it works, check with curve parameters @@ -188,9 +211,11 @@ def _create_params(curve, coords, infty): roots = poly.ground_roots() for root in roots: params[param] = Mod(int(root), field) + print("here", model, coords, param, root) break else: - raise UnsatisfiedAssumptionError( + raise_unsatisified_assumption( + getconfig().ec.unsatisfied_coordinate_assumption_action, f"Coordinate model {coord_model} has an unsatisifed assumption on the {param} parameter (0 = {expr})." ) |
