summaryrefslogtreecommitdiff
path: root/docs/source/ec_arithmetic.rst
blob: 39a13c9734b287a7a7dbea194d9e118b54ea9902 (plain)
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
=========================
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.