Recall from the discussion in Group Theory, we learnt how a generator point can be added to itself repeatedly to generate every element of the group. In this section, we'll understand how to perform this addition, and implement it in Python.

#### The theory behind point addition

To add two points $P$and $Q$ on an elliptic curve, find the third point $R$ where line joining $P$ and $Q$ intersects. This value of $R$ is equal to $-(P+Q)$. Reflecting the point along the X-axis will give us $P+Q$. Addition of two points on an elliptic curve over a field of real numbers.
To find the coordinates of the third point of intersection, simply calculate the slope between P and Q, and extrapolate it using the general equation of elliptic curve. Addition of two points on an elliptic curve over a finite field.

#### Implementation in Python

from typing import Optional
inf = float("inf")
@dataclass
class Point:
x: Optional[int]
y: Optional[int]
curve: EllipticCurve
def __post_init__(self):
# Ignore validation for I
if self.x is None and self.y is None:
return
# Encapsulate int coordinates in FieldElement
self.x = FieldElement(self.x, self.curve.field)
self.y = FieldElement(self.y, self.curve.field)
# Verify if the point satisfies the curve equation
if self not in self.curve:
raise ValueError
#################################################################
# Point Addition for P₁ or P₂ = I (identity) #
# #
# Formula: #
# P + I = P #
# I + P = P #
#################################################################
if self == I:
return other
if other == I:
return self
#################################################################
# #
# Formula: #
# P + (-P) = I #
# (-P) + P = I #
#################################################################
if self.x == other.x and self.y == (-1 * other.y):
return I
#################################################################
# Point Addition for X₁ ≠ X₂ (line with slope) #
# #
# Formula: #
# S = (Y₂ - Y₁) / (X₂ - X₁) #
# X₃ = S² - X₁ - X₂ #
# Y₃ = S(X₁ - X₃) - Y₁ #
#################################################################
if self.x != other.x:
x1, x2 = self.x, other.x
y1, y2 = self.y, other.y
s = (y2 - y1) / (x2 - x1)
x3 = s ** 2 - x1 - x2
y3 = s * (x1 - x3) - y1
return Point(
x=x3.value,
y=y3.value,
curve=secp256k1
)
#################################################################
# Point Addition for P₁ = P₂ (vertical tangent) #
# #
# Formula: #
# S = ∞ #
# (X₃, Y₃) = I #
#################################################################
if self == other and self.y == inf:
return I
#################################################################
# Point Addition for P₁ = P₂ (tangent with slope) #
# #
# Formula: #
# S = (3X₁² + a) / 2Y₁ .. ∂(Y²) = ∂(X² + aX + b) #
# X₃ = S² - 2X₁ #
# Y₃ = S(X₁ - X₃) - Y₁ #
#################################################################
if self == other:
x1, y1, a = self.x, self.y, self.curve.a
s = (3 * x1 ** 2 + a) / (2 * y1)
x3 = s ** 2 - 2 * x1
y3 = s * (x1 - x3) - y1
return Point(
x=x3.value,
y=y3.value,
curve=secp256k1
)
Point at Infinity
Also known as the identity point, it is the third point where P and Q meet, in the figure below.
$P + (-P) = I$ Point at infinity is the third point where the line joining P and Q meets the curve.
We can initialise the point at infinity like this:
I = Point(x=None, y=None, curve=secp256k1)