def find_trace(n,m,k): ''' INPUT : an integer n, an integer m, a base field k OUTPUT : a list of integer mod m or a list of a couple of integers mod m Algorithm : If m is a power of p, then we look for class modulo m with order equal to n. Then, we return the list of all such class. If m is a power of prime different from p, we look for a in (Z/m)* such that : - ord_m(a) < ord_m(q/a) and ord_m(a) = n, or - ord_m(q/a) < ord_a and ord_m(q/a) = n. And we return a + q/a. Here a plays the role of one of the two roots of the future characteristic polynomial of the Frobenius of the elliptic curve we'll use; i.e. X^2 - (a + q/a)*X + a*(q/a) = X^2 - t*X + q if we write t = a + q/a. From that, we will pick elliptic curves which have one of the t's as trace of its Frobenius. ''' Zm = Integers(m) p = k.characteristic() q = k.cardinality() sq = sqrt(float(2*q)) q_m = Zm(q) # If m is a multiple of p, then we just need the trace to be of order #exactly n in (Z/m)* if not m.is_prime_power(): raise NotImplementedError elif m%p == 0: sol = [] phi_m = euler_phi(m) alpha = phi_m/n g = Zm.unit_gens()[0] log_t = [i*alpha for i in n.coprime_integers(n)] for t in [g**i for i in log_t]: if abs(t.centerlift()) > sq: continue else: sol.append(t) return set(sol) # We don't want q to be of order n or dividing n, then q/a would be of order # n; which is unacceptable. elif q_m**n == 1: return [] else: sol = [] phi_m = euler_phi(m) alpha = phi_m/phi_m.gcd(n) g = Zm.unit_gens()[0] Zphi_m = Integers(phi_m) log_a = [i*alpha for i in n.coprime_integers(n)] a = [g**i for i in log_a] log_q = q_m.log(g) for i in range(len(log_a)): diff = log_q - log_a[i] b = g**diff ord_b = diff.order() if ord_b <= n: continue elif abs((a[i] + b).centerlift()) > sq: continue else: sol.append(a[i] + b) return set(sol)
def find_trace(n,m,k): ''' INPUT : - ``n`` -- an integer, the degree of the extension, - ``m`` -- an integer, a candidate for the paramater m, - ``k`` -- a finite field, the base field. OUTPUT : - A list of integer modulo m with the good properties. EXAMPLES : sage: n = 281 sage: m = 3373 sage: k = GF(1747) sage: find_trace(n,m,k) {4, 14, 18, 43, 57, 3325, 3337, 3348, 3354, 3357, 3364} ALGORITHM : The algorithm is pretty straightforward. We select all the elements of order n and look for some properties of their class modulo m and add them to list if they meet the requirements. They will be the class candidates for the trace of the future elliptic curves. - If m is a power of p, the characteristic, then we look for all the elements of order n and check if they end in the Hasse interval. - If m is a prime (power) different from p, then we start by computing the logarithm of elements of order n in (Z/m)*. You have the minimal polynomial of the Frobenius equal to X**2 - t*X + q = (X - a)(X - q/a) mod m. We look for a among the element of order n modulo m such that the other root q/a is of greater order. If their sum a + q/a = t falls into the Hasse interval, then we add t in the good candidates. - If m is composite, we raise a NotImplementedError. ''' Zm = Integers(m) p = k.characteristic() q = k.cardinality() sq = sqrt(float(2*q)) q_m = Zm(q) alpha = (m-1)//n if q_m**n == 1: return [] elif m == p: sol = [] g = Zm.unit_gens()[0] log_t = [i*alpha for i in n.coprime_integers(n)] for t in [g**i for i in log_t]: if abs(t.centerlift()) > sq: continue else: sol.append(t) return set(sol) # We don't want q to be of order n or dividing n, then q/a would be of order # n; which is unacceptable => b order n, but why b order n is bad ? else: sol = [] g = Zm.unit_gens()[0] # Computing the logarithm of element of order n. log_a = [i*alpha for i in n.coprime_integers(n)] a = [g**i for i in log_a] log_q = q_m.log(g) for i in range(len(log_a)): diff = log_q - log_a[i] b = g**diff if p == 2: if abs((a[i] + b).centerlift()) > 1: continue else: sol.append((a[i] + b)) if abs((a[i] + b).centerlift()) > sq: continue elif diff%n == 0: continue else: sol.append(a[i] + b) return set(sol)