Our goal now is to produce the first real application: we want to write a function sum that will compute the sum of two points on an elliptic curve, using the curve's group structure.
Before we start, we have to decide how we want to ``describe'' the curve and arbitrary points. We can start by assuming that the curve is given in Weierstrass form
>>> curve = (0,3,0) >>> curve[0] 0 >>> curve[1] 3 >>> curve[2] 0The first line stores in curve the tuple defining the elliptic curve
Points can be stored in the same way, using tuples with two entries.
>>> p1=(1,2)
Now the idea is simple: if
and
,
satisfies2
with
We write our (first?) version of the sum function. Still working on the elliptic.py file we write:
def sum1(cur,p1,p2):
"""compute p1+p2 on the elliptic curve cur"""
lam = (p2[1]-p1[1])/(p2[0]-p1[0])
nu = p1[1] - lam*p1[0]
x3 = lam**2 - cur[0] - p1[0] - p2[0]
y3 = -(lam * x3 + nu)
return (x3,y3)
Then we reload the elliptic.py file (we won't mention this step
in the future, so make sure you remember to do it on your own). We pick
p2 on the curve and compute p1+p2:
>>> p2=(0,0) >>> elliptic.sum1(curve,p1,(0,0)) (3, -6)Excellent! Now we can play with our sum1 function. According with [1, page 31], the points
>>> curve17=(0,0,17) >>> p1=(-1,4) >>> p2=(2,5) >>> elliptic.sum1(curve17,p1,p2) (-1, -4)So, we obtain
We modify the elliptic.py file to:
from Rat import rat
def on_curve(x,y):
"""See if (x,y) is on the curve y**2==x**3+3x"""
return y**2==x**3+3*x
def sum1(cur,p1,p2):
"""compute p1+p2 on the elliptic curve cur"""
lam = (p2[1]-p1[1])/rat(p2[0]-p1[0])
nu = p1[1] - lam*p1[0]
x3 = lam**2 - cur[0] - p1[0] - p2[0]
y3 = -(lam * x3 + nu)
return (x3,y3)
There are two changes: the first line instructs python to import
the function rat (that creates a rational number) from the file
(module) Rat.py. Then, in the definition of lam we use
rat to turn the denominator into a rational number. This change
will force python to perform a rational quotient so that lam gets the proper value:
>>> elliptic.sum1(curve17,p1,p2) (Rat(-8,9), Rat(-109,27))That is,
Next we want to use sum1 to compute
:
>>> elliptic.sum1(curve17,p1,p1)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "elliptic.py", line 9, in sum1
lam = (p2[1]-p1[1])/rat(p2[0]-p1[0])
File "Rat.py", line 151, in __rdiv__
return Rat(a) / b
File "Rat.py", line 145, in __div__
return rat(a.__num * b.__den, a.__den * b.__num)
File "Rat.py", line 38, in rat
return Rat(num, den)
File "Rat.py", line 45, in __init__
raise ZeroDivisionError, 'rat(x, 0)'
ZeroDivisionError: rat(x, 0)
Wow! That was something... wrong. If you look at the last output line
you will see the key: we are dividing by 0! Why would that be? When
we are trying to compute lam we divide by the difference of the
![]() |
def sum2(cur,p1,p2):
"""compute p1+p2 on the elliptic curve cur"""
if p1==p2:
lam = (3*p1[0]**2 + cur[0]* 2 *p1[0] + cur[1])/rat(2*p1[1])
else:
lam = (p2[1]-p1[1])/rat(p2[0]-p1[0])
nu = p1[1] - lam*p1[0]
x3 = lam**2 - cur[0] - p1[0] - p2[0]
y3 = -(lam * x3 + nu)
return (x3,y3)
Here we use the if ... else construction: it does the obvious
thing, that is, if p1 equals p2 it uses the first
definition of lam, otherwise it uses the second definition.
Notice the important role of indentation: it determines what is
executed in each case (other languages enclose these ``blocks'' of
code with ``{}''; in python it is just indentation).
Now we are ready to compute the sum of two points, even if they are equal:
>>> elliptic.sum2(curve17,p1,p1) (Rat(137,64), Rat(-2651,512))
Did you solve Exercise 4.2? Go ahead: do it!
Now that you tried to compute
, can you see what is
wrong with sum2 in this case? The problem is that even if
, they have the same
-component, so in the computation of
the denominator still vanishes. In order to fix it, we have
to understand what we are doing:
should be the null
element (for the sum on the curve), but that point is the point at
infinity (for the curve in Weierstrass form), which is not given by a
pair of numbers. So we have to represent the null element in some
other way. One possibility is as follows:
def sum3(cur,p1,p2):
"""compute p1+p2 on the elliptic curve cur"""
if p1==p2:
lam = (3*p1[0]**2 + cur[0]* 2 *p1[0] + cur[1])/rat(2*p1[1])
elif p1[0]==p2[0]:
return "null_element"
else:
lam = (p2[1]-p1[1])/rat(p2[0]-p1[0])
nu = p1[1] - lam*p1[0]
x3 = lam**2 - cur[0] - p1[0] - p2[0]
y3 = -(lam * x3 + nu)
return (x3,y3)
That is, when we detect a >>> elliptic.sum3(curve17,p1,(-1,-4)) 'null_element'