static __inline__ int n_is_strong_probabprime2_preinv_speedup(mp_limb_t n, mp_limb_t ninv, mp_limb_t a, mp_limb_t d) /* this subroutine does Miller-Rabin test and returns positive iff test passes hacked by Денис Крыськов to count n-1 once */ { mp_limb_t t = d; mp_limb_t y; y = n_powmod2_ui_preinv(a, t, n, ninv); if (y == UWORD(1)) return 1; t <<= 1; d = n-1; // Денис Крыськов was here while ((t != d) && (y != d)) // and here { y = n_mulmod2_preinv(y, y, n, ninv); t <<= 1; } return y == d; // and here }
mp_limb_t n_powmod2_preinv(mp_limb_t a, mp_limb_signed_t exp, mp_limb_t n, mp_limb_t ninv) { if (exp < WORD(0)) { a = n_invmod(a, n); exp = -exp; } return n_powmod2_ui_preinv(a, exp, n, ninv); }
void nmod_poly_pow(nmod_poly_t res, const nmod_poly_t poly, ulong e) { const slong len = poly->length; slong rlen; if ((len < 2) | (e < UWORD(3))) { if (len == 0) nmod_poly_zero(res); else if (len == 1) { nmod_poly_fit_length(res, 1); res->coeffs[0] = n_powmod2_ui_preinv(poly->coeffs[0], e, poly->mod.n, poly->mod.ninv); res->length = 1; _nmod_poly_normalise(res); } else if (e == UWORD(0)) { nmod_poly_set_coeff_ui(res, 0, UWORD(1)); res->length = 1; _nmod_poly_normalise(res); } else if (e == UWORD(1)) nmod_poly_set(res, poly); else /* e == UWORD(2) */ nmod_poly_mul(res, poly, poly); return; } rlen = (slong) e * (len - 1) + 1; if (res != poly) { nmod_poly_fit_length(res, rlen); _nmod_poly_pow(res->coeffs, poly->coeffs, len, e, poly->mod); } else { nmod_poly_t t; nmod_poly_init2(t, poly->mod.n, rlen); _nmod_poly_pow(t->coeffs, poly->coeffs, len, e, poly->mod); nmod_poly_swap(res, t); nmod_poly_clear(t); } res->length = rlen; _nmod_poly_normalise(res); }
mp_limb_t n_sqrtmod(mp_limb_t a, mp_limb_t p) { slong i, r, m; mp_limb_t p1, k, b, g, bpow, gpow, res; mp_limb_t pinv; if (a <= 1) { return a; } pinv = n_preinvert_limb(p); if (n_jacobi_unsigned(a, p) == -1) return 0; if ((p & UWORD(3)) == 3) { return n_powmod2_ui_preinv(a, (p + 1) / 4, p, pinv); } r = 0; p1 = p - 1; do { p1 >>= UWORD(1); r++; } while ((p1 & UWORD(1)) == 0); b = n_powmod2_ui_preinv(a, p1, p, pinv); for (k = 2; ; k++) { if (n_jacobi_unsigned(k, p) == -1) break; } g = n_powmod2_ui_preinv(k, p1, p, pinv); res = n_powmod2_ui_preinv(a, (p1 + 1) / 2, p, pinv); while (b != 1) { bpow = b; m = 0; do { bpow = n_mulmod2_preinv(bpow, bpow, p, pinv); m++; } while (m < r && bpow != 1); gpow = g; for (i = 1; i < r - m; i++) { gpow = n_mulmod2_preinv(gpow, gpow, p, pinv); } res = n_mulmod2_preinv(res, gpow, p, pinv); g = n_mulmod2_preinv(gpow, gpow, p, pinv); b = n_mulmod2_preinv(b, g, p, pinv); r = m; } return res; }