def find_elliptic_curve(k, K, m_t): ''' INPUT: - ``k`` -- a base field - ``K`` -- an extension of K of degree n. - ``m_t`` -- a list of tuple containing a integer and a set of candidates for the trace. OUTPUT: - An elliptic curve defined over k with the required properties. - An integer case, depending on the value of the j-invariant of said elliptic curve. - An integer m statisfying the properties described in isom_elliptic which we will be using to compute Gaussian periods. ..NOTE:: The case j = 0 or 1728 are not implemented yet. They shall raise NotImplementedError. EXAMPLES: sage: R.<X> = PolynomialRing(GF(5)) sage: f = R.irreducible_element(19, algorithm = 'random') sage: K = GF(5**19, names = 'x', modulus = f) sage: m_t = [(229,{0, 1, 3})] sage: find_elliptic(GF(5), K, m_t) (Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 5, 0, 229) ALGORITHM: TODO : Doc is deprecated, to be redone. Function that finds an elliptic curve with the required charateristics, those given in the function isom_elliptic. First, we have to determine if m is composite, a prime power or a power of p, the characteristic of the base field. The first case is not implemented yet. We also note that the m given should satisfies several conditions based on the characteristic and the degree of K. See the docstrings of isom_elliptic for more information. - If m is a power of p, the charateristic of the base field k, then we shall proceed as follow : We pick a random curve E/k and we set down t = Tr_k(Fr_E), for the curve to be what we want, we need : - t not zero, - (Z/m)* = <t> x S or #<t> = n - m divides #E/K but not #E/L, for any intermediate extension L of K/k; so we can construct points of order m such that their abscissas or ordinates span exactly K. Or that we haven't any point of order m in any sub-extension. Then we test those conditions for both E and its quadratic twist, if one of them meet the requirements, we return it and its trace. If no elliptic curves are found an error is returned. - If m is primer power, then we shall proceed as follow : We have m = l^r, for l a prime. For this method to work, we need l to be an Elkies prime. A prime l is an Elkies prime for an elliptic curve if the charateristic polynomial of the aforesaid elliptic curve splits in GF(l). For now, we pick a random curve E/k and for it to work, if we set down t = Tr_k(Fr_E), we need the following : - We have x**2 - tx + q = (x - a)(x - b) mod m, meaning the polynomial splits in Z/m, - (Z/m)* = <a> x S, with #<a> = n, - ord_m(a) < ord_m(b), - m divides #E/K but not #E/L, for any intermediate extension L of K/k; so we can construct points of order m such that their abscissas or ordinates span exactly K. Once again, we test all that for both E and its quadratic twist; if one them meet the requirements, we return it, its trace and a tuple containing the root a and t mod m. If none are found, there is something wrong. - If m is composite, TODO. ''' p = k.characteristic() q = k.cardinality() n = K.degree() m = m_t[0] S_t = m_t[1] compteur = 0 #We start by the special cases j = 1728, 0 E_j1728 = EllipticCurve(j = k(1728)) if q%4 != 1: # If q != 1 mod 4, then there's no 4th root of unity, then magically # all the quartic twist are already in k and the trace is 0. We just # have to test the only curve y² = x³ + x. compteur += 1 if 0 in S_t: return E_j1728, 0, compteur else: # If q = 1 mod 4, then the trace is not 0, and we have to try four # trace to see which is the best candidate. g = k.unit_gens()[0] c = g**((q-1)/4) t = E_j1728.trace_of_frobenius() L = [(t*(c**i).lift(), g**i) for i in range(4)] for i in range(4): compteur += 1 if Integers(m)(L[i][0]) in S_t: # E, case, t return E_j1728.quartic_twist(L[i][1]), 1, compteur E_j0 = EllipticCurve(j = k(0)) if q%6 != 1: # Same as before, if q != 1 mod 6, there's no 6th root of unity in # GF(q) and the trace is 0 (that's pretty quick reasoning.. :D). # Justification will come later. compteur += 1 if 0 in S_t: return E_j0, 0, compteur else: g = k.unit_gens()[0] c = g**((q-1)/6) t = E_j0.trace_of_frobenius() L = [(t*(c**i).lift(), g**i) for i in range(6)] for l in L: if Integers(m)(l[0]) in S_t: return E_j0.sextic_twist(l[1]), 2, compteur # General case for j in k: if j == 0 or j == k(1728): continue E = EllipticCurve(j = j) t = E.trace_of_frobenius() L = [(t, E), (-t, E.quadratic_twist())] for l in L: compteur +=1 if Integers(m)(l[0]) in S_t: return l[1], 0, compteur # If no elliptic curve has been found. return None, -1
def find_elliptic_curve(k, K, m_t): ''' INPUT: - ``k`` -- a base field, - ``K`` -- an extension of K of degree n, - ``m_t`` -- a list of tuple containing an integer and a set of candidates for the trace. OUTPUT: - An elliptic curve defined over k with the required properties. - An integer case, depending on the value of the j-invariant or the the supersingularity of said elliptic curve. EXAMPLES: sage: R.<X> = PolynomialRing(GF(5)) sage: f = R.irreducible_element(19, algorithm = 'random') sage: K = GF(5**19, names = 'x', modulus = f) sage: m_t = (229,{2}) sage: find_elliptic_curve(GF(5), K, m_t) (Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 5, 1) ALGORITHM: The goal is to pick an elliptic curve of which the trace of its Frobenius t is among the right class modulo m, the ones in S_t. We do that in order to have point of order m only on E/GF(q^n) or above, since then the abscissas of a point of order m will span GF(q^n) and we'll be able to compute the elliptic periods as it was planned. We start by looking at the two special cases j = 1728 or 0. If q is not 1 modulo 4 and 3 respectively, then the curves are supersingular (t = 0) and if 0 is among the good traces, they are to be treated like the other curves. If for j = 0 we have q = 1 mod 3, then we have to tests E(j = 0) and all of its sextic twists. Once again if t is in S_t, then we return the right curves and the case 2 to compute the periods accordingly. If for j = 1728 we have q = 1 mod 4, then we have to tests E(j = 1728) and all of its quartic twists. If one the trace is in S_t, we return the right curves and the case 1. If j != 0 and 1728, then we tests all the elements of GF(q) to find the right curve. For each j we test if t or -t is in S_t and return the curve accordingly plus the case 0. If no curves are found, we return None and the case -1, which will raise an runtimeError in the main function. ''' p = k.characteristic() q = k.cardinality() m = m_t[0] S_t = m_t[1] #We start by the special cases j = 1728, 0 E_j1728 = EllipticCurve(j = k(1728)) if q%4 != 1: # If q != 1 mod 4, then there's no 4th root of unity, then magically # all the quartic twist are already in k and the trace is 0. We just # have to test the only curve y� = x� + x. if 0 in S_t: return E_j1728, 0 else: # If q = 1 mod 4, then the trace is not 0, and we have to try four # trace to see which is the best candidate. g = k.unit_gens()[0] c = g**((q-1)/4) t = E_j1728.trace_of_frobenius() L = [(t*(c**i).centerlift(), g**i) for i in range(4)] for i in range(4): if Integers(m)(L[i][0]) in S_t: # E, case, t return E_j1728.quartic_twist(L[i][1]), 1 E_j0 = EllipticCurve(j = k(0)) if q%3 != 1: # Same as before, if q != 1 mod 6, there's no 6th root of unity in # GF(q) and the trace is 0 (that's pretty quick reasoning.. :D). # Justification will come later. Since q = 1 mod 2, if q = 1 mod 3 # then q = 1 mod 6. if 0 in S_t: return E_j0, 0 else: g = k.unit_gens()[0] c = g**((q-1)/6) t = E_j0.trace_of_frobenius() L = [(t*(c**i).centerlift(), g**i) for i in range(6)] for l in L: if Integers(m)(l[0]) in S_t: return E_j0.sextic_twist(l[1]), 2 # General case for j in k: if j == 0 or j == k(1728): continue E = EllipticCurve(j = j) t = E.trace_of_frobenius() L = [(t, E), (-t, E.quadratic_twist())] for l in L: if Integers(m)(l[0]) in S_t: return l[1], 0 # If no elliptic curve has been found. return None, -1