/* assume m is invertible */ void dirichlet_char_log(dirichlet_char_t x, const dirichlet_group_t G, ulong m) { slong k; /* even part */ if (G->neven >= 1) { x->log[0] = (m % 4 == 3); if (G->neven == 2) { ulong m2 = (x->log[0]) ? -m % G->q_even : m % G->q_even; if (G->P[1].dlog == NULL) x->log[1] = dlog_mod2e_1mod4(m2, G->P[1].e, nmod_inv(5, G->P[1].pe), G->P[1].pe); else x->log[1] = dlog_precomp(G->P[1].dlog, m2); } } /* odd part */ for (k = G->neven; k < G->num; k++) { dirichlet_prime_group_struct P = G->P[k]; if (P.dlog == NULL) { x->log[k] = dlog_once(m % P.pe.n, P.g, P.pe, P.phi.n); } else { x->log[k] = dlog_precomp(P.dlog, m % P.pe.n); } } /* keep value m */ x->n = m; }
static void dirichlet_group_lift_generators(dirichlet_group_t G) { slong k; dirichlet_prime_group_struct * P = G->P; G->expo = G->phi_q = 1; if (G->neven) { G->phi_q = G->q_even / 2; G->expo = P[G->neven - 1].phi.n; } for (k = G->neven; k < G->num; k++) { G->phi_q *= P[k].phi.n; G->expo *= P[k].phi.n / n_gcd(G->expo, P[k].p - 1); } for (k = 0; k < G->num; k++) { nmod_t pe; ulong qpe, v; G->PHI[k] = G->expo / G->P[k].phi.n; /* lift generators mod q */ /* u * p^e + v * q/p^e = 1 -> g mod q = 1 + (g-1) * v*(q/p^e) */ pe = G->P[k].pe; qpe = G->q / pe.n; if (G->q < G->P[k].pe.n) { flint_printf("lift generator %wu from %wu to %wu e=%wu\n", G->P[k].g, G->P[k].pe.n, G->q, G->P[k].e); } v = nmod_inv(qpe % pe.n, pe); /* no overflow since v * qpe < q */ G->generators[k] = (1 + (G->P[k].g-1) * v * qpe) % G->q; } }