aboutsummaryrefslogtreecommitdiffhomepage
path: root/pyecsca/ec/coordinates.py
blob: f8642cfb1205421671e072713b1f9eb131463cd6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
from ast import parse, Expression, Module
from os.path import join
from typing import List, Any, MutableMapping

from pkg_resources import resource_listdir, resource_isdir, resource_stream
from public import public

from .formula import (Formula, EFDFormula, AdditionEFDFormula, DoublingEFDFormula,
                      TriplingEFDFormula,
                      DifferentialAdditionEFDFormula, LadderEFDFormula, ScalingEFDFormula,
                      NegationEFDFormula)


@public
class CoordinateModel(object):
    """A coordinate system for a particular model(form) of an elliptic curve."""
    name: str
    full_name: str
    curve_model: Any
    variables: List[str]
    satisfying: List[Module]
    parameters: List[str]
    assumptions: List[Module]
    neutral: List[Module]
    formulas: MutableMapping[str, Formula]

    def __repr__(self):
        return f"{self.__class__.__name__}(\"{self.name}\" on {self.curve_model.name})"


@public
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.neutral = []
        self.formulas = {}

    def __eq__(self, other):
        if not isinstance(other, AffineCoordinateModel):
            return False
        return self.curve_model == other.curve_model


class EFDCoordinateModel(CoordinateModel):

    def __init__(self, dir_path: str, name: str, curve_model: Any):
        self.name = name
        self.curve_model = curve_model
        self.variables = []
        self.satisfying = []
        self.parameters = []
        self.assumptions = []
        self.neutral = []
        self.formulas = {}
        for fname in resource_listdir(__name__, dir_path):
            file_path = join(dir_path, fname)
            if resource_isdir(__name__, file_path):
                self.__read_formula_dir(file_path, fname)
            else:
                self.__read_coordinates_file(file_path)

    def __read_formula_dir(self, dir_path, formula_type):
        for fname in resource_listdir(__name__, dir_path):
            if fname.endswith(".op3"):
                continue
            formula_types = {
                "addition": AdditionEFDFormula,
                "doubling": DoublingEFDFormula,
                "tripling": TriplingEFDFormula,
                "diffadd": DifferentialAdditionEFDFormula,
                "ladder": LadderEFDFormula,
                "scaling": ScalingEFDFormula,
                "negation": NegationEFDFormula
            }
            cls = formula_types.get(formula_type, EFDFormula)
            self.formulas[fname] = cls(join(dir_path, fname), fname, self)

    def __read_coordinates_file(self, file_path):
        with resource_stream(__name__, file_path) as f:
            line = f.readline().decode("ascii")
            while line:
                line = line[:-1]
                if line.startswith("name"):
                    self.full_name = line[5:]
                elif line.startswith("variable"):
                    self.variables.append(line[9:])
                elif line.startswith("neutral"):
                    try:
                        code = parse(line[8:].replace("^", "**"), mode="exec")
                        self.neutral.append(code)
                    except SyntaxError:
                        pass
                elif line.startswith("satisfying"):
                    try:
                        code = parse(line[11:].replace("^", "**"), mode="exec")
                        self.satisfying.append(code)
                    except SyntaxError:
                        pass
                elif line.startswith("parameter"):
                    self.parameters.append(line[10:])
                elif line.startswith("assume"):
                    self.assumptions.append(
                            parse(line[7:].replace("^", "**"), mode="exec"))
                line = f.readline().decode("ascii")

    def __eq__(self, other):
        if not isinstance(other, EFDCoordinateModel):
            return False
        return self.curve_model == other.curve_model and self.name == other.name

    def __hash__(self):
        return hash(self.curve_model) + hash(self.name)