Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
duyuefeng0708
GitHub Repository: duyuefeng0708/Cryptography-From-First-Principle
Path: blob/main/foundations/06-elliptic-curves/sage/06b-point-addition-geometry.ipynb
483 views
unlisted
Kernel: SageMath 10.5

Notebook 06b: Point Addition, The Geometry

Module 06. Elliptic Curves


Motivating Question. We know that an elliptic curve is a set of points satisfying y2=x3+ax+by^2 = x^3 + ax + b. But a set of points is not a group until we define an operation. How do we "add" two points on a curve? The answer is a beautiful geometric construction: draw a line, find the third intersection, reflect. This chord-and-tangent rule turns the curve into an abelian group, the engine behind elliptic curve cryptography.


Prerequisites. You should be comfortable with:

  • Elliptic curves over the reals and the Weierstrass equation (Notebook 06a)

  • The point at infinity O\mathcal{O} and point negation (Notebook 06a)

  • Group axioms: closure, associativity, identity, inverses (Module 01)

Learning objectives. By the end of this notebook you will be able to:

  1. Describe the chord-and-tangent construction for adding two points.

  2. Handle all special cases: distinct points, doubling, vertical lines, identity.

  3. Derive the algebraic formulas for point addition and doubling.

  4. Verify the group axioms computationally.

  5. Visualise the addition operation step by step.

1. The Big Idea: Line, Intersect, Reflect

In Notebook 06a we saw that a line generically meets an elliptic curve in three points (by Bézout's theorem). This gives us a recipe for addition:

To compute P+QP + Q:

  1. Draw the line \ell through PP and QQ.

  2. Find the third intersection point RR of \ell with the curve.

  3. Reflect RR across the xx-axis: P+Q=R=(xR,yR)P + Q = -R = (x_R, -y_R).

That's it! The reflection step is what makes the operation a group law (it ensures O\mathcal{O} is the identity).

StepGeometric actionAlgebraic result
1Draw line through P,QP, QCompute slope λ\lambda
2Find third intersection RRSolve cubic for xRx_R
3Reflect RR over xx-axisNegate yRy_R
var('x y') # Visualise the full addition P + Q on y^2 = x^3 - 2x + 1 E = EllipticCurve(QQ, [-2, 1]) P = E(-1, 2) Q = E(0, 1) S = P + Q # the result # The third intersection R (before reflection) has same x as S, opposite y R_x, R_y = float(S[0]), float(-S[1]) G = implicit_plot(y^2 - x^3 + 2*x - 1, (x, -2.5, 3.5), (y, -4, 4), color='blue', aspect_ratio=1) # Draw line through P and Q, extended px, py = float(P[0]), float(P[1]) qx, qy = float(Q[0]), float(Q[1]) slope = (qy - py) / (qx - px) G += plot(py + slope * (x - px), (x, -2.5, 3.5), color='red', linestyle='--', alpha=0.7, legend_label='Line through $P, Q$') # Mark points G += point([(px, py)], color='red', size=80, zorder=5) G += text('$P$', (px - 0.3, py + 0.3), fontsize=14, fontweight='bold') G += point([(qx, qy)], color='green', size=80, zorder=5) G += text('$Q$', (qx - 0.3, qy + 0.3), fontsize=14, fontweight='bold') # Mark R (third intersection, before reflection) rx, ry = R_x, R_y G += point([(rx, ry)], color='purple', size=80, zorder=5) G += text('$R$ (3rd intersection)', (rx + 0.3, ry + 0.3), fontsize=11) # Mark P + Q = -R (reflected) sx, sy = float(S[0]), float(S[1]) G += point([(sx, sy)], color='black', size=120, zorder=5, marker='*') G += text('$P + Q = -R$', (sx + 0.3, sy - 0.4), fontsize=14, fontweight='bold') # Dashed vertical line showing reflection G += line([(rx, ry), (rx, sy)], color='black', linestyle=':', alpha=0.5) G += text('reflect', (rx + 0.3, (ry + sy)/2), fontsize=10, color='gray') G.show(figsize=9, title='Point Addition on $y^2 = x^3 - 2x + 1$: $P + Q$') print(f"P = {P}") print(f"Q = {Q}") print(f"R (3rd intersection) = ({R_x}, {R_y})") print(f"P + Q = -R = {S}")

Checkpoint 1. In the plot above, trace the three steps: (1) the red dashed line passes through PP and QQ, (2) it hits the curve a third time at RR, and (3) reflecting RR across the xx-axis gives P+QP + Q. Why is the reflection step necessary? (Hint: without it, the operation would not have O\mathcal{O} as identity.)

2. The Algebraic Formulas

Let E:y2=x3+ax+bE: y^2 = x^3 + ax + b and let P=(x1,y1)P = (x_1, y_1), Q=(x2,y2)Q = (x_2, y_2) be points on EE with PQP \neq -Q.

Case 1: PQP \neq Q (chord)

The slope of the line through PP and QQ is: λ=y2y1x2x1\lambda = \frac{y_2 - y_1}{x_2 - x_1}

Case 2: P=QP = Q (tangent / point doubling)

We use implicit differentiation on y2=x3+ax+by^2 = x^3 + ax + b to get the tangent slope: λ=3x12+a2y1\lambda = \frac{3x_1^2 + a}{2y_1}

(This requires y10y_1 \neq 0; if y1=0y_1 = 0 then the tangent is vertical and 2P=O2P = \mathcal{O}.)

In both cases:

x3=λ2x1x2x_3 = \lambda^2 - x_1 - x_2y3=λ(x1x3)y1y_3 = \lambda(x_1 - x_3) - y_1

The result is P+Q=(x3,y3)P + Q = (x_3, y_3).

Slope λ\lambdaThen
PQP \neq Qy2y1x2x1\frac{y_2 - y_1}{x_2 - x_1}x3=λ2x1x2x_3 = \lambda^2 - x_1 - x_2, y3=λ(x1x3)y1y_3 = \lambda(x_1 - x_3) - y_1
P=QP = Q3x12+a2y1\frac{3x_1^2 + a}{2y_1}Same formulas for x3,y3x_3, y_3 (with x2=x1x_2 = x_1)
# Implement point addition by hand and compare with SageMath def ec_add_manual(E, P, Q): """Add P + Q on elliptic curve E using the explicit formulas.""" O = E(0) # point at infinity # Identity cases if P == O: return Q if Q == O: return P x1, y1 = P[0], P[1] x2, y2 = Q[0], Q[1] a = E.a4() # coefficient of x in short Weierstrass form # Inverse case: P + (-P) = O if x1 == x2 and y1 == -y2: return O # Compute slope if P == Q: # Tangent (doubling) lam = (3 * x1^2 + a) / (2 * y1) else: # Secant (addition) lam = (y2 - y1) / (x2 - x1) # Compute result x3 = lam^2 - x1 - x2 y3 = lam * (x1 - x3) - y1 return E(x3, y3) # Test E = EllipticCurve(QQ, [-2, 1]) P = E(-1, 2) Q = E(0, 1) result_manual = ec_add_manual(E, P, Q) result_sage = P + Q print(f"P = {P}") print(f"Q = {Q}") print(f"P + Q (manual) = {result_manual}") print(f"P + Q (SageMath) = {result_sage}") print(f"Match? {result_manual == result_sage}")

Misconception alert. "Point addition on elliptic curves is the same as adding coordinates." Absolutely not! (x1,y1)+(x2,y2)(x1+x2,y1+y2)(x_1, y_1) + (x_2, y_2) \neq (x_1 + x_2, y_1 + y_2). The elliptic curve group law is a geometric operation defined by line intersections, which happens to produce algebraic formulas involving the curve equation.

3. Point Doubling (P+P=2PP + P = 2P)

When P=QP = Q, there is no "line through two distinct points", instead, we take the tangent line to the curve at PP. This tangent generically meets the curve in one more point (with multiplicity), which we reflect to get 2P2P.

# Visualise point doubling var('x y') E = EllipticCurve(QQ, [-2, 1]) P = E(0, 1) two_P = 2 * P # Tangent slope at P x1, y1 = float(P[0]), float(P[1]) a_val = -2 lam = (3 * x1**2 + a_val) / (2 * y1) # R is the third intersection (before reflection) R_x, R_y = float(two_P[0]), float(-two_P[1]) G = implicit_plot(y^2 - x^3 + 2*x - 1, (x, -2, 4), (y, -5, 5), color='blue', aspect_ratio=1) # Tangent line G += plot(y1 + lam * (x - x1), (x, -2, 4), color='red', linestyle='--', alpha=0.7, legend_label='Tangent at $P$') # Mark P G += point([(x1, y1)], color='red', size=80, zorder=5) G += text('$P$', (x1 - 0.3, y1 + 0.3), fontsize=14, fontweight='bold') # Mark R G += point([(R_x, R_y)], color='purple', size=80, zorder=5) G += text('$R$', (R_x + 0.3, R_y + 0.3), fontsize=12) # Mark 2P sx, sy = float(two_P[0]), float(two_P[1]) G += point([(sx, sy)], color='black', size=120, zorder=5, marker='*') G += text('$2P = -R$', (sx + 0.3, sy - 0.4), fontsize=14, fontweight='bold') # Reflection line G += line([(R_x, R_y), (R_x, sy)], color='black', linestyle=':', alpha=0.5) G.show(figsize=9, title='Point Doubling: $2P$ via tangent line') print(f"P = {P}") print(f"Tangent slope lambda = {lam}") print(f"2P = {two_P}")
# Verify the doubling formula step by step E = EllipticCurve(QQ, [-2, 1]) P = E(0, 1) x1, y1 = P[0], P[1] a = E.a4() print("Step-by-step doubling of P = (0, 1) on y^2 = x^3 - 2x + 1:") print(f" a = {a}") lam = (3*x1^2 + a) / (2*y1) print(f" λ = (3·{x1}² + ({a})) / (2·{y1}) = {lam}") x3 = lam^2 - x1 - x1 print(f" x₃ = {lam}² - {x1} - {x1} = {x3}") y3 = lam * (x1 - x3) - y1 print(f" y₃ = {lam}·({x1} - {x3}) - {y1} = {y3}") print(f"\n 2P = ({x3}, {y3})") print(f" SageMath: 2*P = {2*P}") print(f" Match? {E(x3, y3) == 2*P}")

Checkpoint 2. In the doubling formula, the slope is λ=3x12+a2y1\lambda = \frac{3x_1^2 + a}{2y_1}. What happens when y1=0y_1 = 0? Geometrically, the tangent at a point with y=0y = 0 is vertical, the line goes to O\mathcal{O}, so 2P=O2P = \mathcal{O}. Such points have order 2 in the group.

4. All the Special Cases

The chord-and-tangent rule has several special cases that we must handle:

CaseGeometric situationResult
P+OP + \mathcal{O}PP plus identityPP
P+(P)P + (-P)Vertical line through PP and P-PO\mathcal{O}
P+QP + Q (P±QP \neq \pm Q)Secant line through P,QP, QUse chord formula
P+PP + P (y10y_1 \neq 0)Tangent line at PPUse doubling formula
P+PP + P (y1=0y_1 = 0)Vertical tangentO\mathcal{O}
# Demonstrate all special cases E = EllipticCurve(QQ, [-1, 0]) # y^2 = x^3 - x O = E(0) P = E(1, 0) # a point with y = 0 Q = E(-1, 0) # another point with y = 0 R = E(0, 0) # yet another print("Curve: y^2 = x^3 - x") print(f"Points with y=0 (order 2): {P}, {Q}, {R}") print() # Case 1: P + O = P print(f"Case 1 (identity): P + O = {P + O} [should be P = {P}]") # Case 2: P + (-P) = O # For P = (1,0), -P = (1,-0) = (1,0) = P, so P + P = O print(f"Case 2 (inverse): P + (-P) = P + P = {P + P} [should be O, since y=0]") # Case 3: P + Q (distinct, P ≠ -Q) print(f"Case 3 (chord): P + Q = {P + Q} [P=(1,0), Q=(-1,0)]") # Case 4: Doubling a general point S = E(-1, 0) print(f"Case 5 (y=0 double): S + S = {S + S} [S=(-1,0) has order 2]")
# Visualise the vertical line case (P + (-P) = O) and general chord case var('x y') E = EllipticCurve(QQ, [-2, 1]) P = E(-1, 2) neg_P = -P # Left: P + (-P) = O (vertical line) G1 = implicit_plot(y^2 - x^3 + 2*x - 1, (x, -2.5, 3), (y, -4, 4), color='blue', aspect_ratio=1) px, py = float(P[0]), float(P[1]) G1 += point([(px, py)], color='red', size=80, zorder=5) G1 += text('$P$', (px + 0.3, py + 0.2), fontsize=14) G1 += point([(px, -py)], color='green', size=80, zorder=5) G1 += text('$-P$', (px + 0.3, -py - 0.3), fontsize=14) G1 += line([(px, -4), (px, 4)], color='red', linestyle='--', alpha=0.5) G1 += text('$P + (-P) = \\mathcal{O}$\n(vertical line)', (0.5, 3.5), fontsize=11) # Right: P + Q (general case) Q = E(0, 1) S = P + Q G2 = implicit_plot(y^2 - x^3 + 2*x - 1, (x, -2.5, 4), (y, -5, 5), color='blue', aspect_ratio=1) qx, qy = float(Q[0]), float(Q[1]) slope = (qy - py) / (qx - px) G2 += plot(py + slope * (x - px), (x, -2.5, 4), color='red', linestyle='--', alpha=0.5) G2 += point([(px, py)], color='red', size=80, zorder=5) G2 += text('$P$', (px - 0.3, py + 0.3), fontsize=14) G2 += point([(qx, qy)], color='green', size=80, zorder=5) G2 += text('$Q$', (qx - 0.3, qy + 0.3), fontsize=14) sx, sy = float(S[0]), float(S[1]) G2 += point([(sx, sy)], color='black', size=120, zorder=5, marker='*') G2 += text('$P+Q$', (sx + 0.3, sy - 0.4), fontsize=14) G2 += text('$P + Q$ (general chord case)', (0.5, 4.5), fontsize=11) graphics_array([G1, G2]).show(figsize=[14, 6])

5. Verifying the Group Axioms

For the elliptic curve points to form a group under ++, we need:

  1. Closure: If P,QEP, Q \in E, then P+QEP + Q \in E.

  2. Identity: P+O=PP + \mathcal{O} = P for all PP.

  3. Inverses: For each PP, there exists P-P with P+(P)=OP + (-P) = \mathcal{O}.

  4. Associativity: (P+Q)+R=P+(Q+R)(P + Q) + R = P + (Q + R) for all P,Q,RP, Q, R.

Closure, identity, and inverses are clear from the construction. Associativity is the hard part, the algebraic proof is tedious, so let us verify it computationally.

# Verify group axioms on a concrete curve E = EllipticCurve(QQ, [-2, 1]) O = E(0) P = E(-1, 2) Q = E(0, 1) R = E(1, 0) print("=== Group Axiom Verification ===") print(f"Curve: {E}") print(f"P = {P}, Q = {Q}, R = {R}") print() # 1. Closure S = P + Q print(f"1. Closure: P + Q = {S} ∈ E? {S in E}") # 2. Identity print(f"2. Identity: P + O = {P + O} == P? {P + O == P}") print(f" O + P = {O + P} == P? {O + P == P}") # 3. Inverses neg_P = -P print(f"3. Inverse: -P = {neg_P}") print(f" P + (-P) = {P + neg_P} == O? {P + neg_P == O}") # 4. Associativity lhs = (P + Q) + R rhs = P + (Q + R) print(f"4. Associativity:") print(f" (P + Q) + R = {lhs}") print(f" P + (Q + R) = {rhs}") print(f" Equal? {lhs == rhs}") # 5. Commutativity (bonus, elliptic curve groups are abelian) print(f"5. Commutativity:") print(f" P + Q = {P + Q}") print(f" Q + P = {Q + P}") print(f" Equal? {P + Q == Q + P}")
# Stress-test associativity with random points over a finite field p = 10007 E_fp = EllipticCurve(GF(p), [-2, 1]) num_tests = 100 all_pass = True for i in range(num_tests): P = E_fp.random_point() Q = E_fp.random_point() R = E_fp.random_point() if (P + Q) + R != P + (Q + R): print(f"FAIL at test {i}: P={P}, Q={Q}, R={R}") all_pass = False break print(f"Associativity test: {num_tests} random triples over F_{p}, {'ALL PASSED' if all_pass else 'FAILED'}")

6. Building a Sequence: P,2P,3P,P, 2P, 3P, \ldots

Just as we computed g,g2,g3,g, g^2, g^3, \ldots in Z/pZ\mathbb{Z}/p\mathbb{Z}^* (Module 05), we can compute repeated additions P,2P,3P,P, 2P, 3P, \ldots on an elliptic curve. If PP generates a cyclic subgroup of order nn, then nP=OnP = \mathcal{O} and the sequence cycles back.


Bridge from Module 01. In Module 01, the "power table" of a generator gg in (Z/pZ,×)(\mathbb{Z}/p\mathbb{Z}^*, \times) listed g1,g2,,gp1=1g^1, g^2, \ldots, g^{p-1} = 1. Here we build the analogous "multiple table" for a point PP in (E,+)(E, +): 1P,2P,,nP=O1P, 2P, \ldots, nP = \mathcal{O}. The notation is additive instead of multiplicative, but the structure is identical.

# Compute multiples of a point E = EllipticCurve(QQ, [-2, 1]) P = E(-1, 2) print(f"Multiples of P = {P} on {E}:\n") print("k kP")for k in range(1, 15): kP = k * P coords = f"({kP[0]}, {kP[1]})" if kP != E(0) else "O (identity)" print(f"{k} {coords}")
# Visualise multiples of P on the curve E = EllipticCurve(GF(97), [-2, 1]) P = E(0, 1) n = P.order() G = Graphics() # Plot all multiples xs, ys, ks = [], [], [] for k in range(1, n): kP = k * P xs.append(int(kP[0])) ys.append(int(kP[1])) ks.append(k) # Use a color gradient to show the order from sage.plot.colors import rainbow colors_list = rainbow(len(xs)) for i in range(len(xs)): G += point([(xs[i], ys[i])], color=colors_list[i], size=30, zorder=5) # Highlight first few multiples highlight_colors = ['red', 'green', 'blue', 'purple', 'orange'] for k in range(1, 6): kP = k * P G += point([(int(kP[0]), int(kP[1]))], color=highlight_colors[k-1], size=80, zorder=6) G += text(f'{k}P', (int(kP[0]) + 2, int(kP[1]) + 2), fontsize=9, color=highlight_colors[k-1]) G.show(figsize=8, title=f'Multiples of $P = (0, 1)$ on $E(\\mathbb{{F}}_{{97}})$, Order of $P$: {n}', axes_labels=['$x$', '$y$'], gridlines=True) print(f"Order of P: {n}") print(f"Verification: {n}*P = {n * P}")

Notice how the multiples of PP appear to "scatter" across the finite field, there is no visible pattern. This is the elliptic curve analogue of the "scramble" we saw with discrete exponentiation in Module 05. Given kPkP, recovering kk is the Elliptic Curve Discrete Logarithm Problem (ECDLP).

Crypto foreshadowing. The ECDLP, given PP and Q=kPQ = kP, find kk, is believed to be even harder than the classical DLP in Z/pZ\mathbb{Z}/p\mathbb{Z}^*. The best known attack is Pollard's rho, which runs in O(n)O(\sqrt{n}) time with no sub-exponential shortcuts. This is why 256-bit EC keys provide 128-bit security.

7. Derivation of the Addition Formulas (Optional)

For those who want to see why the formulas work, here is the derivation.

Setup: Let P=(x1,y1)P = (x_1, y_1) and Q=(x2,y2)Q = (x_2, y_2) with x1x2x_1 \neq x_2. The line through them is y=λx+νy = \lambda x + \nu where λ=y2y1x2x1\lambda = \frac{y_2 - y_1}{x_2 - x_1} and ν=y1λx1\nu = y_1 - \lambda x_1.

Substituting into y2=x3+ax+by^2 = x^3 + ax + b:

(λx+ν)2=x3+ax+b(\lambda x + \nu)^2 = x^3 + ax + b

x3λ2x2+(a2λν)x+(bν2)=0x^3 - \lambda^2 x^2 + (a - 2\lambda\nu)x + (b - \nu^2) = 0

This cubic has three roots: x1,x2,x3x_1, x_2, x_3. By Vieta's formulas, the sum of roots equals the coefficient of x2x^2 (with sign):

x1+x2+x3=λ2    x3=λ2x1x2x_1 + x_2 + x_3 = \lambda^2 \implies x_3 = \lambda^2 - x_1 - x_2

Then y3=λ(x1x3)y1y_3 = \lambda(x_1 - x_3) - y_1 (evaluating the line at x3x_3 and negating for the reflection).

# Verify Vieta's formulas E = EllipticCurve(QQ, [-2, 1]) P = E(-1, 2) Q = E(0, 1) S = P + Q # = (x3, y3) after reflection x1, y1 = P[0], P[1] x2, y2 = Q[0], Q[1] lam = (y2 - y1) / (x2 - x1) # x3 from Vieta: x1 + x2 + x3 = λ² x3_vieta = lam^2 - x1 - x2 print(f"λ = {lam}") print(f"Vieta: x₁ + x₂ + x₃ = λ² → x₃ = {x3_vieta}") print(f"Actual x₃ = {S[0]}") print(f"Match? {x3_vieta == S[0]}") print(f"\nSum of roots: {x1} + {x2} + {x3_vieta} = {x1 + x2 + x3_vieta} = λ² = {lam^2}")

Checkpoint 3. Why do we use Vieta's formulas instead of solving the cubic directly? Because Vieta's gives us x3x_3 using only addition and subtraction of the known roots x1,x2x_1, x_2, no need for the cubic formula or numerical methods. This is what makes the group law computationally efficient.

8. Exercises

Exercise 1 (Worked): Manual Point Addition

Problem. On E:y2=x3+1E: y^2 = x^3 + 1 over Q\mathbb{Q}, compute P+QP + Q where P=(0,1)P = (0, 1) and Q=(2,3)Q = (2, 3).

Solution.

Step 1: Compute the slope. λ=y2y1x2x1=3120=22=1\lambda = \frac{y_2 - y_1}{x_2 - x_1} = \frac{3 - 1}{2 - 0} = \frac{2}{2} = 1

Step 2: Compute x3x_3. x3=λ2x1x2=1202=1x_3 = \lambda^2 - x_1 - x_2 = 1^2 - 0 - 2 = -1

Step 3: Compute y3y_3. y3=λ(x1x3)y1=1(0(1))1=11=0y_3 = \lambda(x_1 - x_3) - y_1 = 1 \cdot (0 - (-1)) - 1 = 1 - 1 = 0

So P+Q=(1,0)P + Q = (-1, 0).

# Exercise 1: verification E = EllipticCurve(QQ, [0, 1]) # y^2 = x^3 + 1 P = E(0, 1) Q = E(2, 3) result = P + Q print(f"P + Q = {result}") print(f"Expected: (-1, 0)") print(f"Match? {result == E(-1, 0)}") # Interesting: (-1, 0) has order 2! R = E(-1, 0) print(f"\n2·(-1, 0) = {2*R} (order 2 point!)")

Exercise 2 (Guided): Point Doubling by Hand

Problem. On E:y2=x3x+1E: y^2 = x^3 - x + 1 over Q\mathbb{Q}, compute 2P2P where P=(1,1)P = (1, 1).

Steps:

  1. Compute λ=3x12+a2y1\lambda = \frac{3x_1^2 + a}{2y_1} with a=1a = -1.

  2. Compute x3=λ22x1x_3 = \lambda^2 - 2x_1.

  3. Compute y3=λ(x1x3)y1y_3 = \lambda(x_1 - x_3) - y_1.

  4. Verify with SageMath.

# Exercise 2: fill in the TODOs E = EllipticCurve(QQ, [-1, 1]) # y^2 = x^3 - x + 1 P = E(1, 1) x1, y1 = P[0], P[1] a = E.a4() # TODO 1: Compute the tangent slope # lam = ??? # TODO 2: Compute x3 # x3 = ??? # TODO 3: Compute y3 # y3 = ??? # TODO 4: Verify # print(f"Manual: 2P = ({x3}, {y3})") # print(f"SageMath: 2*P = {2*P}")

Exercise 3 (Independent): Exploring the Group Structure

Problem.

  1. On E:y2=x3+1E: y^2 = x^3 + 1 over Q\mathbb{Q}, start with P=(2,3)P = (2, 3) and compute 2P,3P,4P,5P,6P2P, 3P, 4P, 5P, 6P. At what point does kP=OkP = \mathcal{O}? (This is the order of PP.)

  2. The point (1,0)(-1, 0) has order 2 (since y=0y = 0). Find P+(1,0)P + (-1, 0) for P=(0,1)P = (0, 1) and P=(2,3)P = (2, 3). Is there a pattern?

  3. Verify associativity for three specific points of your choice on E:y2=x32x+1E: y^2 = x^3 - 2x + 1.

# Exercise 3: write your solution here

Summary

ConceptKey Fact
Addition ruleDraw line through P,QP, Q → find 3rd intersection RR → reflect: P+Q=RP + Q = -R
Chord formulaλ=y2y1x2x1\lambda = \frac{y_2 - y_1}{x_2 - x_1}, then x3=λ2x1x2x_3 = \lambda^2 - x_1 - x_2
Doubling formulaλ=3x12+a2y1\lambda = \frac{3x_1^2 + a}{2y_1}, same x3,y3x_3, y_3 formulas
IdentityP+O=PP + \mathcal{O} = P, the point at infinity is the identity
InversesP=(x,y)-P = (x, -y) and P+(P)=OP + (-P) = \mathcal{O}
Vieta's shortcutx3=λ2x1x2x_3 = \lambda^2 - x_1 - x_2 comes from sum-of-roots, avoiding the cubic formula

We now have a complete group law for elliptic curves over any field. In the next notebook, we move from the continuous real line to finite fields Fp\mathbb{F}_p, where the curve becomes a discrete set of points, and where cryptography actually happens.


Next: 06c: Curves over Finite Fields