blob: 39a13c9734b287a7a7dbea194d9e118b54ea9902 [file] [log] [blame]
=========================
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 <short Weierstrass curve>`:
: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.