def miller(P, Q, n, denominator=False): # return the miller loop f_{P, n}(Q) for an even embedded degree curve if Q.is_zero(): raise ValueError("Q must be nonzero.") n = ZZ(n) if n.is_zero(): raise ValueError("n must be nonzero.") n_is_negative = False if n < 0: n = n.abs() n_is_negative = True t_num, t_den = 1, 1 V = P S = 2 * V # V=P is in affine coordinates nbin = n.bits() i = n.nbits() - 2 while i > -1: [S, [ell_num, ell_den]] = eval_line(V, V, Q) t_num = (t_num**2) * ell_num if denominator: [R, [vee_num, vee_den]] = eval_line(S, -S, Q) t_den = (t_den**2) * ell_den * vee_num t_num *= vee_den V = S if nbin[i] == 1: [S, [ell_num, ell_den]] = eval_line(V, P, Q) t_num = t_num * ell_num if denominator: [R, [vee_num, vee_den]] = eval_line(S, -S, Q) t_den *= ell_den * vee_num t_num *= vee_den V = S i = i - 1 if not (denominator): t_den = 1 if n_is_negative: t_num, t_den = t_den, t_num S = -S return [S, [t_num, t_den]]
def decompose(P, f, g=None, target=None): """ Compute a polynomial Q of degree target such that compose(Q, f, g). Assumes deg f >= deg g. The result is returned as a list of coefficients. """ def dec(P, f, g, invf, invg): a = f.parent()(0) if P.degree() >= f.degree() + g.degree(): a, P = P.quo_rem(f) return a + (P * invf) % g, (P * invg) % f if g is None: g = f.parent()(1) if target is None: target = ZZ(P.degree() // f.degree()) n, a, b = 0, 1, 1 moduli = [] for bit in reversed(target.bits()): if bit: n1, a1, b1 = n + 1, a * f, b * g else: n1, a1, b1 = n, a, b moduli.append((n1, a1, b1)) n, a, b = n + n1, a * a1, b * b1 res = {0: P} for n, a, b in reversed(moduli): newres = {} _, inva, invb = a.xgcd(b) for i, p in res.iteritems(): p0, p1 = dec(p, a, b, inva, invb) newres[i + n] = p0 + newres.get(i + n, 0) newres[i] = p1 + newres.get(i, 0) res = newres return [res[i] for i in range(len(res))]