MikroTikPatch/toyecc/EllipticCurve.py

203 lines
6.8 KiB
Python
Raw Normal View History

2024-06-15 02:18:14 +03:00
#
# toyecc - A small Elliptic Curve Cryptography Demonstration.
# Copyright (C) 2011-2022 Johannes Bauer
#
# This file is part of toyecc.
#
# toyecc is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; this program is ONLY licensed under
# version 3 of the License, later versions are explicitly excluded.
#
# toyecc is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with toyecc; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Johannes Bauer <JohannesBauer@gmx.de>
#
from .AffineCurvePoint import AffineCurvePoint
class EllipticCurve(object):
"""Elliptic curve base class. Provides functionality which all curves have
in common."""
def __init__(self, p, n, h, Gx, Gy, **kwargs):
assert(isinstance(p, int)) # Modulus
assert((n is None) or isinstance(n, int)) # Order
assert((h is None) or isinstance(h, int)) # Cofactor
assert((Gx is None) or isinstance(Gx, int)) # Generator Point X
assert((Gy is None) or isinstance(Gy, int)) # Generator Point Y
assert((Gx is None) == (Gy is None)) # Either both X and Y of G are set or none
self._p = p
self._n = n
self._h = h
if (Gx is not None) and (Gy is not None):
self._G = AffineCurvePoint(Gx, Gy, self)
else:
self._G = None
if "quirks" in kwargs:
self._quirks = { quirk.identifier: quirk for quirk in kwargs["quirks"] }
else:
self._quirks = { }
@property
def p(self):
"""Returns the prime modulus which constitutes the finite field in
which the curve lies."""
return self._p
@property
def n(self):
"""Returns the order of the subgroup that is created by the generator
G."""
return self._n
@property
def h(self):
"""Returns the cofactor of the generator subgroup, i.e. h = #E(F_p) /
n. This will always be an integer according to Lagrange's Theorem."""
return self._h
@property
def G(self):
"""Returns the generator point G of the curve or None if no such point
was set. The generator point generates a subgroup over #E(F_p)."""
return self._G
@property
def curve_order(self):
"""Returns the order of the curve in the underlying field, i.e.
#E(F_p). Intuitively, this is the total number of points on the curve
(plus maybe points at ininity, depending on the curve type) that
satisfy the curve equation."""
if (self.h is None) or (self.n is None):
raise Exception("#E(F_p) is unknown for this curve")
return self.h * self.n
@property
def frobenius_trace(self):
"""Returns the Frobenius trace 't' of the curve. Since
#E(F_p) = p + 1 - t it follows that t = p + 1 - #E(F_p)."""
return self.p + 1 - self.curve_order
@property
def domainparams(self):
"""Returns the curve parameters as a named tuple."""
raise Exception(NotImplemented)
@property
def hasgenerator(self):
"""Returns if a generator point was supplied for the curve."""
return self.G is not None
@property
def hasname(self):
"""Returns if the curve is named (i.e. its name is not None)."""
return self.name is not None
@property
def name(self):
"""Returns the name of the curve, if it was given one during
construction. Purely informational."""
return self._name
@property
def prettyname(self):
"""Returns the pretty name of the curve type. This might depend on the
actual curve, since it may also vary on the actual domain parameters to
include if the curve is a Koblitz curve or not."""
return self.pretty_name
@property
def curvetype(self):
"""Returns a string that corresponds to the curve type. For example,
this string can be 'shortweierstrass', 'twistededwards' or
'montgomery'."""
raise Exception(NotImplemented)
@property
def domainparamdict(self):
"""Returns the domain parameters of the curve as a dictionary."""
return dict(self.domainparams._asdict())
@property
def security_bit_estimate(self):
"""Gives a haphazard estimate of the security of the underlying field,
in bits. For most curves, this will be half the bitsize of n (but might
be less, for example for Koblitz curves some bits might be
subtracted)."""
return self.n.bit_length() // 2
def enumerate_points(self):
"""Enumerates all points on the curve, including the point at infinity
(if the curve has such a special point)."""
raise Exception(NotImplemented)
def naive_order_calculation(self):
"""Naively calculates the order #E(F_p) of the curve by enumerating and
counting all points which fulfull the curve equation. Note that this
implementation only works for the smallest of curves and is
computationally infeasible for all practical applications."""
order = 0
for pt in self.enumerate_points():
order += 1
return order
def neutral(self):
"""Returns the neutral element of the curve group (for some curves,
this will be the point at infinity)."""
return AffineCurvePoint(None, None, self)
def is_neutral(self, P):
"""Checks if a given point P is the neutral element of the group."""
return P.x is None
def oncurve(self, P):
"""Checks is a given point P is on the curve."""
raise Exception(NotImplemented)
def point_addition(self, P, Q):
"""Returns the sum of two points P and Q on the curve."""
raise Exception(NotImplemented)
def point_conjugate(self, P):
"""Returns the negated point -P to a given point P."""
raise Exception(NotImplemented)
def compress(self, P):
"""Returns the compressed representation of the point P on the
curve. Not all curves may support this operation."""
raise Exception(NotImplemented)
def uncompress(self, compressed):
"""Returns the uncompressed representation of a point on the curve. Not
all curves may support this operation."""
raise Exception(NotImplemented)
def has_quirk(self, quirk_class):
"""Some elliptic curves may have quirks or tweaks for certain
algorithms. These are attached to the curve using the 'quirks' kwarg of
the constructor. Code that wants to query if a specific quirk is
present may do so by calling 'has_quirk' with the according quirk class
(not a quirk class instance!)."""
return quirk_class.identifier in self._quirks
def get_quirk(self, quirk_class):
"""If a quirk is present for a given elliptic curve, this quirk may
have been parametrized during instanciation. The get_quirk() method
returns that quirk instance when given a specific quirk class as input.
It raises a KeyError if the requested quirk is not present for the
elliptic curve."""
return self._quirks[quirk_class.identifier]
def __eq__(self, other):
return self.domainparams == other.domainparams
def __ne__(self, other):
return not (self == other)