Path: blob/master/shared/complex_multiplication.py
2587 views
import logging12from sage.all import EllipticCurve3from sage.all import GF4from sage.all import hilbert_class_polynomial5from sage.all import is_prime_power678def elementary_symmetric_function(x, k):9assert k > 01011if k > len(x):12return 01314e = [0] * k15for i, xi in enumerate(x):16ej = e[0]17e[0] += xi18ej_1 = ej19for j in range(1, min(k, i + 1)):20ej = e[j]21e[j] += xi * ej_122ej_1 = ej2324return e[k - 1]252627def hilbert_class_polynomial_roots(D, gf):28"""29Computes the roots of H_D(X) mod q given D and GF(q).30TODO: implement "Accelerating the CM method" by Sutherland.31:param D: the CM discriminant (negative)32:param gf: the finite field GF(q)33:return: a generator generating the roots (values j)34"""35assert D < 0 and (D % 4 == 0 or D % 4 == 1), "D must be negative and a discriminant"36H = hilbert_class_polynomial(D)37pr = gf["x"]38for j in pr(H).roots(multiplicities=False):39yield j404142def generate_curve(gf, k, c=None):43"""44Generates an Elliptic Curve given GF(q), k, and parameter c45:param gf: the finite field GF(q)46:param k: j / (j - 1728)47:param c: an optional parameter c which is used to generate random a and b values (default: random element in Zmod(q))48:return:49"""50c_ = c if c is not None else 051while c_ == 0:52c_ = gf.random_element()5354a = 3 * k * c_ ** 255b = 2 * k * c_ ** 356return EllipticCurve(gf, [a, b])575859def solve_cm(D, q, c=None):60"""61Solves a Complex Multiplication equation for a given discriminant D, prime q, and parameter c.62:param D: the CM discriminant (negative)63:param q: the prime q64:param c: an optional parameter c which is used to generate random a and b values (default: random element in Zmod(q))65:return: a generator generating elliptic curves in Zmod(q) with random a and b values66"""67assert is_prime_power(q)6869logging.debug(f"Solving CM equation for {q = } using {D = } and {c = }")70gf = GF(q)71if gf.characteristic() == 2 or gf.characteristic() == 3:72return7374ks = []75for j in hilbert_class_polynomial_roots(D, gf):76if j != 0 and j != gf(1728):77k = j / (1728 - j)78yield generate_curve(gf, k, c)79ks.append(k)8081while len(ks) > 0:82for k in ks:83yield generate_curve(gf, k, c)848586