def isogenous_curves(j, l=None, Phi=None, multiplicities=True, E=None): field = j.parent() x = PolynomialRing(field, 'x').gen() if Phi == None: Phi = ClassicalModularPolynomialDatabase()[l] f = Phi(x, j) if not multiplicities: if E == None: return [i[0] for i in f.roots() for _ in range(i[1])] return [(i[0], elkies_mod_poly(E, i[0], Phi.degree() // 2)) for i in f.roots() for _ in range(i[1])] return f.roots()
def is_supersingular(E): p = E.base_field().characteristic() j = E.j_invariant() if not j in GF(p**2): return False if p <= 3: return j == 0 F = ClassicalModularPolynomialDatabase()[2] x = PolynomialRing(GF(p**2), 'x').gen() f = F(x, j) roots = [i[0] for i in f.roots() for _ in range(i[1])] if len(roots) < 3: return False vertices = [j, j, j] m = floor(log(p, 2)) + 1 for k in range(1, m + 1): for i in range(3): f = F(x, roots[i]) g = x - vertices[i] a = f.quo_rem(g)[0] vertices[i] = roots[i] attempt = a.roots() if len(attempt) == 0: return False roots[i] = attempt[0][0] return True
def is_torsion_bicyclic(E, l): order = E.order() v = ZZ.valuation(l) n = v(order) if n < 2: return False D = E.trace_of_frobenius()**2 - 4 * E.base_field().order() if not (l**2).divides(D): return False Phi = ClassicalModularPolynomialDatabase()[l] x = PolynomialRing(E.base_field(), 'x').gen() return len(Phi(E.j_invariant(), x).roots()) > 2
def elkies_mod_poly(E, j2, l): j = E.j_invariant() Phi = ClassicalModularPolynomialDatabase()[l] x = PolynomialRing(E.base_field(), 'x').gen() f = Phi(j2, x) F1 = f.derivative()(j) g = Phi(j, x) F2 = g.derivative()(j2) try: lam = E.a6() / E.a4() * F1 / F2 * j * (-18) / l aa = -lam**2 / (j2 * (j2 - 1728) * l**4 * 48) bb = -lam**3 / (j2**2 * (j2 - 1728) * l**6 * 864) return EllipticCurve(E.base_field(), [aa, bb]) except: return None
def endomorphism_index(self): j = self._j_invariant field = j.parent() t = self._domain.trace_of_frobenius() self._trace = t Dv = t**2 - 4 * self._domain.base_field().order() D = Dv.squarefree_part() v = Dv // D if D % 4 != 1: v = v // 4 ls = [(i[0], i[1] // 2) for i in list(factor(v)) if i[1] >= 2] u = 1 for a in ls: l = a[0] Phi = ClassicalModularPolynomialDatabase()[l] dist = len(find_descending_path(j, Phi, l, special=False)) - 1 ex = a[1] - dist u *= l**ex self._index = u
def elkies_first_step(E, l, lam): q = E.base_field().order() lam = GF(l)(lam) Phi = ClassicalModularPolynomialDatabase()[l] x = PolynomialRing(E.base_field(), 'x').gen() f = Phi(x, E.j_invariant()) j_1, j_2 = f.roots()[0][0], f.roots()[1][0] E1 = elkies_mod_poly(E, j_1, l) try: I = EllipticCurveIsogeny(E, None, E1, l) except: I = l_isogeny(E, E1, l) r = lam.multiplicative_order() k = GF(q ** r) ext = extend_field(E, r) try: P = ext.lift_x(I.kernel_polynomial().any_root(k)) except: return j_2 if ext(P[0] ** q, P[1] ** q) == Integer(lam) * P: return j_1 else: return j_2
def hecke_matrix(self, L): r""" This function returns the `L^{\text{th}}` Hecke matrix. INPUT: - ``self`` -- SupersingularModule object - ``L`` -- integer, positive OUTPUT: matrix -- sparse integer matrix EXAMPLES: This example computes the action of the Hecke operator `T_2` on the module of supersingular points on `X_0(1)/F_{37}`:: sage: S = SupersingularModule(37) sage: M = S.hecke_matrix(2) sage: M [1 1 1] [1 0 2] [1 2 0] This example computes the action of the Hecke operator `T_3` on the module of supersingular points on `X_0(1)/F_{67}`:: sage: S = SupersingularModule(67) sage: M = S.hecke_matrix(3) sage: M [0 0 0 0 2 2] [0 0 1 1 1 1] [0 1 0 2 0 1] [0 1 2 0 1 0] [1 1 0 1 0 1] [1 1 1 0 1 0] .. note:: The first list --- list_j --- returned by the supersingular_points function are the rows *and* column indexes of the above hecke matrices and its ordering should be kept in mind when interpreting these matrices. AUTHORS: - David Kohel -- [email protected] - Iftikhar Burhanuddin -- [email protected] """ if L in self.__hecke_matrices: return self.__hecke_matrices[L] SS, II = self.supersingular_points() if L == 2: # since T_2 gets computed as a side effect of computing the supersingular points return self.__hecke_matrices[2] Fp2 = self.__finite_field h = len(SS) R = self.base_ring() T_L = MatrixSpace(R, h)(0) S, X = Fp2['x'].objgen() if L in [3, 5, 7, 11]: for i in range(len(SS)): ss_i = SS[i] phi_L_in_x = Phi_polys(L, X, ss_i) rts = phi_L_in_x.roots() for r in rts: T_L[i, int(II[r[0]])] = r[1] else: DBMP = ClassicalModularPolynomialDatabase() phi_L = DBMP[L] M, (x, y) = Fp2['x,y'].objgens() phi_L = phi_L(x, y) # As an optimization, we compute the coefficients of y and evaluate # them, since univariate polynomial evaluation is much faster than # multivariate evaluation (in Sage :-( ). uni_coeff = [phi_L(x,0).univariate_polynomial()] + \ [phi_L.coefficient(y**i).univariate_polynomial() for i in range(1,phi_L.degree(y)+1)] for i in range(len(SS)): ss_i = SS[i] ## We would do the eval below, but it is too slow (right now). #phi_L_in_x = phi_L(X, ss_i) phi_L_in_x = S([f(ss_i) for f in uni_coeff]) rts = phi_L_in_x.roots() for r in rts: T_L[i, int(II[r[0]])] = r[1] self.__hecke_matrices[L] = T_L return T_L
def elkies_next_step(j_0, j_1, l, lam): Phi = ClassicalModularPolynomialDatabase()[l] R = PolynomialRing(j_0.parent(), 'x') x = R.gen() f = R(Phi(x, j_1) / (x - j_0)) return f.roots()[0][0]