Skip to content

Instantly share code, notes, and snippets.

@amadhurkant
Created July 21, 2025 06:33
Show Gist options
  • Save amadhurkant/5301c47eef51e679b1ac396b7a3d81e2 to your computer and use it in GitHub Desktop.
Save amadhurkant/5301c47eef51e679b1ac396b7a3d81e2 to your computer and use it in GitHub Desktop.
Isogeny of elliptic curve demonstration using sagemath.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~ Construction of an Isogeny Between Elliptic Curves ~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Field and Curve Definitions
p = 97
F = GF(p)
E1 = EllipticCurve(F, [1, 24])
E2 = EllipticCurve(F, [42, 46])
# Initial Data
print(f"E1: {E1}, j(E1) = {E1.j_invariant()}, |E1(F_p)| = {E1.order()}")
print(f"E2: {E2}, j(E2) = {E2.j_invariant()}, |E2(F_p)| = {E2.order()}")
print("-" * 70)
# Determine the degree via modular polynomials
print("Determining the degree of the isogeny φ: E1 → E2")
degree = None
j1, j2 = E1.j_invariant(), E2.j_invariant()
# Test small prime degrees
for l in [3, 5, 7, 11, 13]:
Phi_l = classical_modular_polynomial(l)
result = Phi_l(j1, j2) % p
print(f" Testing Φ_{l}(j1, j2) mod {p}: Result = {result}")
if result == 0:
degree = l
break
if degree is None:
raise ValueError("No isogeny of small prime degree found between the curves.")
else:
print(f"The modular polynomial condition holds for l = {degree}. This is the degree.")
print("-" * 70)
# Kernel Construction
print(f"Kernel of the {degree}-isogeny:")
order = E1.order()
if order % degree == 0:
print(f"Since deg(φ) divides |E1(F_p)|, the kernel is a rational subgroup.")
cofactor = order // degree
P_gen = E1.gen(0)
kernel_generator = cofactor * P_gen
print(f"The kernel G = <P>, where P = {kernel_generator.xy()}, has order {kernel_generator.order()}.")
else:
raise ValueError("The kernel is not rational; a different construction method is needed.")
print("-" * 70)
# Isogeny Construction and Explicit Formulas
print("Isogeny Construction (via Vélu's formulas):")
# Construct the isogeny from the specified kernel
phi = E1.isogeny(kernel_generator)
print(f"The isogeny constructed from G has codomain: {phi.codomain()}")
print("\nThe rational maps defining φ are:")
Rx, Ry = phi.rational_maps()
print(f"φ_x(x) = {Rx}")
print(f"\nφ_y(x, y) = {Ry}")
print("-" * 70)
# Verification of the Map
print("Verification:")
# Use a generator of the full group as a test point
P_test = E1.gen(0)
Q_image = phi(P_test)
print(f"The map φ sends the point P = {P_test.xy()} on E1")
print(f"to its image Q = {Q_image.xy()}.")
is_on_target = Q_image in E2
print(f"Check: Is Q in E2? --> {is_on_target}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment