packages feed

egison-5.1.0: sample/math/number/elliptic-curve-over-F7.egi

--
-- Point counting and the group law on an elliptic curve over F7
--
-- The quotient mechanism (design/type-cas-quotient.md) makes Z/7Z a
-- first-class nominal ring: `declare cas-quotient` derives the homomorphic
-- ring operations with per-operation reduction and a type-dispatched
-- equality, and checks the congruence laws at declaration time.
--

declare cas-quotient Mod7 := Integer by (\n -> modulo n 7)

-- E : y^2 = x^3 + 2 over F7
def rhs (x : Mod7) : Mod7 := x * x * x + projMod7 2

def elems := map projMod7 (between 0 6)

-- affine points: pairs (x, y) with y^2 = x^3 + 2
def affineCount :=
  sum (map (\x -> length (filter (\y -> (y * y) == rhs x) elems)) elems)

assertEqual "affine points of y^2 = x^3 + 2 over F7" affineCount 8

-- the projective count adds the point at infinity
def pointCount := affineCount + 1
assertEqual "#E(F7) = 9" pointCount 9

-- Hasse bound: |#E(F7) - (7 + 1)| <= 2 sqrt 7 < 6
assertEqual "Hasse bound"
  ((pointCount >= 3) && (pointCount <= 13)) True

--
-- Group law: doubling P = (3, 1) along the tangent line.
-- Field inversion comes from Fermat's little theorem, a^(-1) = a^5 in F7 —
-- a non-homomorphic (pattern-2) operation defined directly on the quotient.
--

def inv7 (a : Mod7) : Mod7 := a * a * a * a * a

def px := projMod7 3
def py := projMod7 1
assertEqual "P = (3, 1) lies on E" ((py * py) == rhs px) True

-- lambda = (3 x^2) / (2 y),  x' = lambda^2 - 2 x,  y' = lambda (x - x') - y
def lam := (projMod7 3 * px * px) * inv7 (projMod7 2 * py)
def qx := lam * lam - projMod7 2 * px
def qy := lam * (px - qx) - py

assertEqual "2P = (3, 6)" ((qx == projMod7 3) && (qy == projMod7 6)) True
assertEqual "2P lies on E" ((qy * qy) == rhs qx) True
-- 2P = -P, so P has order 3 — consistent with #E(F7) = 9