diff options
Diffstat (limited to 'pyecsca/ec/params.py')
| -rw-r--r-- | pyecsca/ec/params.py | 155 |
1 files changed, 133 insertions, 22 deletions
diff --git a/pyecsca/ec/params.py b/pyecsca/ec/params.py index 8344901..82a42bd 100644 --- a/pyecsca/ec/params.py +++ b/pyecsca/ec/params.py @@ -4,6 +4,7 @@ Provides functions for obtaining domain parameters from the `std-curves <https:/ It also provides a domain parameter class and a class for a whole category of domain parameters. """ import json +import csv from sympy import Poly, FF, symbols, sympify from astunparse import unparse from io import RawIOBase, BufferedIOBase @@ -41,13 +42,13 @@ class DomainParameters: category: Optional[str] def __init__( - self, - curve: EllipticCurve, - generator: Point, - order: int, - cofactor: int, - name: Optional[str] = None, - category: Optional[str] = None, + self, + curve: EllipticCurve, + generator: Point, + order: int, + cofactor: int, + name: Optional[str] = None, + category: Optional[str] = None, ): self.curve = curve self.generator = generator @@ -60,10 +61,10 @@ class DomainParameters: if not isinstance(other, DomainParameters): return False return ( - self.curve == other.curve - and self.generator == other.generator - and self.order == other.order - and self.cofactor == other.cofactor + self.curve == other.curve + and self.generator == other.generator + and self.order == other.order + and self.cofactor == other.cofactor ) def __hash__(self): @@ -176,9 +177,9 @@ def _create_params(curve, coords, infty): for curve_param, value in params.items(): expr = expr.subs(curve_param, k(value)) if ( - len(expr.free_symbols) > 1 - or (param := str(expr.free_symbols.pop())) - not in coord_model.parameters + len(expr.free_symbols) > 1 + or (param := str(expr.free_symbols.pop())) + not in coord_model.parameters ): raise ValueError( f"This coordinate model couldn't be loaded due to an unsupported assumption ({assumption_string})." @@ -230,9 +231,9 @@ def _create_params(curve, coords, infty): @public def load_category( - file: Union[str, Path, BinaryIO, IO[bytes]], - coords: Union[str, Callable[[str], str]], - infty: Union[bool, Callable[[str], bool]] = True, + file: Union[str, Path, BinaryIO, IO[bytes]], + coords: Union[str, Callable[[str], str]], + infty: Union[bool, Callable[[str], bool]] = True, ) -> DomainParameterCategory: """ Load a category of domain parameters containing several curves from a JSON file. @@ -268,7 +269,7 @@ def load_category( @public def load_params( - file: Union[str, Path, BinaryIO], coords: str, infty: bool = True + file: Union[str, Path, BinaryIO], coords: str, infty: bool = True ) -> DomainParameters: """ Load a curve from a JSON file. @@ -291,10 +292,120 @@ def load_params( @public +def load_params_ecgen( + file: Union[str, Path, BinaryIO], coords: str, infty: bool = True +) -> DomainParameters: + """ + Load a curve from a file that is output of `ecgen <https://github.com/J08nY/ecgen>`_. + + :param file: The file to load from. + :param coords: The name of the coordinate system to use. + :param infty: Whether to use the special :py:class:InfinityPoint (`True`) or try to use the + point at infinity of the coordinate system. + :return: The curve. + """ + if isinstance(file, (str, Path)): + with open(file, "rb") as f: + ecgen = json.load(f) + elif isinstance(file, (RawIOBase, BufferedIOBase, BinaryIO)): + ecgen = json.load(file) + else: + raise TypeError + ecgen = ecgen[0] + if "m" in ecgen["field"]: + raise ValueError("Binary extension field curves not supported") + if len(ecgen["subgroups"]) != 1: + raise ValueError("Can not represent curve with two subgroups.") + curve_dict = { + "form": "Weierstrass", + "field": { + "type": "Prime", + "p": ecgen["field"]["p"] + }, + "order": ecgen["subgroups"][0]["order"], # Take just the first subgroup + "cofactor": ecgen["subgroups"][0]["cofactor"], + "params": { + "a": { + "raw": ecgen["a"] + }, + "b": { + "raw": ecgen["b"] + } + }, + "generator": { + "x": { + "raw": ecgen["subgroups"][0]["x"] + }, + "y": { + "raw": ecgen["subgroups"][0]["y"] + } + }, + "name": None, + "category": None + } + return _create_params(curve_dict, coords, infty) + + +@public +def load_params_ectester( + file: Union[str, Path, BinaryIO], coords: str, infty: bool = True +) -> DomainParameters: + """ + Load a curve from a file that uses the format of `ECTester <https://github.com/crocs-muni/ECTester>`_. + + :param file: The file to load from. + :param coords: The name of the coordinate system to use. + :param infty: Whether to use the special :py:class:InfinityPoint (`True`) or try to use the + point at infinity of the coordinate system. + :return: The curve. + """ + if isinstance(file, (str, Path)): + with open(file, "r") as f: + reader = csv.reader(f) + line = next(iter(reader)) + elif isinstance(file, (RawIOBase, BufferedIOBase, BinaryIO)): + reader = csv.reader(list(map(lambda line: line.decode(), file.readlines()))) + line = next(iter(reader)) + else: + raise TypeError + if len(line) != 7: + raise ValueError("Binary extension field curves not supported") + # line = p,a,b,gx,gy,n,h (all in hex) + curve_dict = { + "form": "Weierstrass", + "field": { + "type": "Prime", + "p": line[0] + }, + "order": line[5], + "cofactor": line[6], + "params": { + "a": { + "raw": line[1] + }, + "b": { + "raw": line[2] + } + }, + "generator": { + "x": { + "raw": line[3] + }, + "y": { + "raw": line[4] + } + }, + "name": None, + "category": None + } + return _create_params(curve_dict, coords, infty) + + +@public def get_category( - category: str, - coords: Union[str, Callable[[str], str]], - infty: Union[bool, Callable[[str], bool]] = True, + category: str, + coords: Union[str, Callable[[str], str]], + infty: Union[bool, Callable[[str], bool]] = True, ) -> DomainParameterCategory: """ Retrieve a category from the std-curves database at https://github.com/J08nY/std-curves. @@ -320,7 +431,7 @@ def get_category( @public def get_params( - category: str, name: str, coords: str, infty: bool = True + category: str, name: str, coords: str, infty: bool = True ) -> DomainParameters: """ Retrieve a curve from a set of stored parameters. |
