========================= Elliptic Curve arithmetic ========================= The python-ecdsa also provides generic API for performing operations on elliptic curve points. .. warning:: This is documentation of a very low-level API, if you want to handle keys or signatures you should look at documentation of the :py:mod:`~ecdsa.keys` module. Short Weierstrass curves ======================== There are two low-level implementations for :term:`short Weierstrass curves `: :py:class:`~ecdsa.ellipticcurve.Point` and :py:class:`~ecdsa.ellipticcurve.PointJacobi`. Both of them use the curves specified using the :py:class:`~ecdsa.ellipticcurve.CurveFp` object. You can either provide your own curve parameters or use one of the predefined curves. For example, to define a curve :math:`y^2 = x^3 + 1 * x + 4 \text{ mod } 5` use code like this: .. code:: python from ecdsa.ellipticcurve import CurveFp custom_curve = CurveFp(5, 1, 4) The predefined curves are specified in the :py:mod:`~ecdsa.ecdsa` module, but it's much easier to use the helper functions (and proper names) from the :py:mod:`~ecdsa.curves` module. For example, to get the curve parameters for the NIST P-256 curve use this code: .. code:: python from ecdsa.curves import NIST256p curve = NIST256p.curve .. tip:: You can also use :py:class:`~ecdsa.curves.Curve` to get the curve parameters from a PEM or DER file. You can also use :py:func:`~ecdsa.curves.curve_by_name` to get a curve by specifying its name. Or use the :py:func:`~ecdsa.curves.find_curve` to get a curve by specifying its ASN.1 object identifier (OID). Affine coordinates ------------------ After taking hold of curve parameters you can create a point on the curve. The :py:class:`~ecdsa.ellipticcurve.Point` uses affine coordinates, i.e. the :math:`x` and :math:`y` from the curve equation directly. To specify a point (1, 1) on the ``custom_curve`` you can use this code: .. code:: python from ecdsa.ellipticcurve import Point point_a = Point(custom_curve, 1, 1) Then it's possible to either perform scalar multiplication: .. code:: python point_b = point_a * 3 Or specify other points and perform addition: .. code:: python point_b = Point(custom_curve, 3, 2) point_c = point_a + point_b To get the affine coordinates of the point, call the ``x()`` and ``y()`` methods of the object: .. code:: python print("x: {0}, y: {1}".format(point_c.x(), point_c.y())) Projective coordinates ---------------------- When using the Jacobi coordinates, the point is defined by 3 integers, which are related to the :math:`x` and :math:`y` in the following way: .. math:: x = X/Z^2 \\ y = Y/Z^3 That means that if you have point in affine coordinates, it's possible to convert them to Jacobi by simply assuming :math:`Z = 1`. So the same points can be specified as so: .. code:: python from ecdsa.ellipticcurve import PointJacobi point_a = PointJacobi(custom_curve, 1, 1, 1) point_b = PointJacobi(custom_curve, 3, 2, 1) .. note:: Unlike the :py:class:`~ecdsa.ellipticcurve.Point`, the :py:class:`~ecdsa.ellipticcurve.PointJacobi` does **not** check if the coordinates specify a valid point on the curve as that operation is computationally expensive for Jacobi coordinates. If you want to verify if they specify a valid point, you need to convert the point to affine coordinates and use the :py:meth:`~ecdsa.ellipticcurve.CurveFp.contains_point` method. Then all the operations work exactly the same as with regular :py:class:`~ecdsa.ellipticcurve.Point` implementation. While it's not possible to get the internal :math:`X`, :math:`Y`, and :math:`Z` coordinates, it's possible to get the affine projection just like with the regular implementation: .. code:: python point_c = point_a + point_b print("x: {0}, y: {1}".format(point_c.x(), point_c.y())) All the other operations, like scalar multiplication or point addition work on projective points the same as with affine representation, but they are much more effective computationally.