int mpz_millerrabin (mpz_srcptr n, int reps) { int r; mpz_t nm1, nm3, x, y, q; unsigned long int k; gmp_randstate_t rstate; int is_prime; TMP_DECL; TMP_MARK; MPZ_TMP_INIT (nm1, SIZ (n) + 1); mpz_sub_ui (nm1, n, 1L); MPZ_TMP_INIT (x, SIZ (n) + 1); MPZ_TMP_INIT (y, 2 * SIZ (n)); /* mpz_powm_ui needs excessive memory!!! */ /* Perform a Fermat test. */ mpz_set_ui (x, 210L); mpz_powm (y, x, nm1, n); if (mpz_cmp_ui (y, 1L) != 0) { TMP_FREE; return 0; } MPZ_TMP_INIT (q, SIZ (n)); /* Find q and k, where q is odd and n = 1 + 2**k * q. */ k = mpz_scan1 (nm1, 0L); mpz_tdiv_q_2exp (q, nm1, k); /* n-3 */ MPZ_TMP_INIT (nm3, SIZ (n) + 1); mpz_sub_ui (nm3, n, 3L); ASSERT (mpz_cmp_ui (nm3, 1L) >= 0); gmp_randinit_default (rstate); is_prime = 1; for (r = 0; r < reps && is_prime; r++) { /* 2 to n-2 inclusive, don't want 1, 0 or -1 */ mpz_urandomm (x, rstate, nm3); mpz_add_ui (x, x, 2L); is_prime = millerrabin (n, nm1, x, y, q, k); } gmp_randclear (rstate); TMP_FREE; return is_prime; }
void mpz_cdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor) { mp_size_t divisor_size = SIZ (divisor); mp_size_t xsize; mpz_t temp_divisor; /* N.B.: lives until function returns! */ TMP_DECL; TMP_MARK; /* We need the original value of the divisor after the quotient and remainder have been preliminary calculated. We have to copy it to temporary space if it's the same variable as either QUOT or REM. */ if (quot == divisor || rem == divisor) { MPZ_TMP_INIT (temp_divisor, (int) ABS (divisor_size)); // (int) added by PM mpz_set (temp_divisor, divisor); divisor = temp_divisor; } xsize = SIZ (dividend) ^ divisor_size;; mpz_tdiv_qr (quot, rem, dividend, divisor); if (xsize >= 0 && SIZ (rem) != 0) { mpz_add_ui (quot, quot, 1L); mpz_sub (rem, rem, divisor); } TMP_FREE; }
void mpz_mod (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor) { mp_size_t divisor_size = divisor->_mp_size; mpz_t temp_divisor; /* N.B.: lives until function returns! */ TMP_DECL (marker); TMP_MARK (marker); /* We need the original value of the divisor after the remainder has been preliminary calculated. We have to copy it to temporary space if it's the same variable as REM. */ if (rem == divisor) { MPZ_TMP_INIT (temp_divisor, ABS (divisor_size)); mpz_set (temp_divisor, divisor); divisor = temp_divisor; } mpz_tdiv_r (rem, dividend, divisor); if (rem->_mp_size != 0) { if (dividend->_mp_size < 0) { if (divisor->_mp_size < 0) mpz_sub (rem, rem, divisor); else mpz_add (rem, rem, divisor); } } TMP_FREE (marker); }
void mpz_fdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor) { mp_size_t divisor_size = divisor->_mp_size; mp_size_t xsize; mpz_t temp_divisor; /* N.B.: lives until function returns! */ TMP_DECL (marker); TMP_MARK (marker); /* We need the original value of the divisor after the quotient and remainder have been preliminary calculated. We have to copy it to temporary space if it's the same variable as either QUOT or REM. */ if (quot == divisor || rem == divisor) { MPZ_TMP_INIT (temp_divisor, ABS (divisor_size)); mpz_set (temp_divisor, divisor); divisor = temp_divisor; } xsize = dividend->_mp_size ^ divisor_size;; mpz_tdiv_qr (quot, rem, dividend, divisor); if (xsize < 0 && rem->_mp_size != 0) { mpz_sub_ui (quot, quot, 1L); mpz_add (rem, rem, divisor); } TMP_FREE (marker); }
void mpz_fdiv_r (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor) { mp_size_t divisor_size = SIZ (divisor); mpz_t temp_divisor; /* N.B.: lives until function returns! */ TMP_DECL; TMP_MARK; /* We need the original value of the divisor after the remainder has been preliminary calculated. We have to copy it to temporary space if it's the same variable as REM. */ if (rem == divisor) { MPZ_TMP_INIT (temp_divisor, ABS (divisor_size)); mpz_set (temp_divisor, divisor); divisor = temp_divisor; } mpz_tdiv_r (rem, dividend, divisor); if ((divisor_size ^ SIZ (dividend)) < 0 && SIZ (rem) != 0) mpz_add (rem, rem, divisor); TMP_FREE; }
int mpz_invert (mpz_ptr inverse, mpz_srcptr x, mpz_srcptr n) { mpz_t gcd, tmp; mp_size_t xsize, nsize, size; TMP_DECL (marker); xsize = SIZ (x); nsize = SIZ (n); xsize = ABS (xsize); nsize = ABS (nsize); size = MAX (xsize, nsize) + 1; /* No inverse exists if the leftside operand is 0. Likewise, no inverse exists if the mod operand is 1. */ if (xsize == 0 || (nsize == 1 && (PTR (n))[0] == 1)) return 0; TMP_MARK (marker); MPZ_TMP_INIT (gcd, size); MPZ_TMP_INIT (tmp, size); mpz_gcdext (gcd, tmp, (mpz_ptr) 0, x, n); /* If no inverse existed, return with an indication of that. */ if (SIZ (gcd) != 1 || PTR(gcd)[0] != 1) { TMP_FREE (marker); return 0; } /* Make sure we return a positive inverse. */ if (SIZ (tmp) < 0) { if (SIZ (n) < 0) mpz_sub (inverse, tmp, n); else mpz_add (inverse, tmp, n); } else mpz_set (inverse, tmp); TMP_FREE (marker); return 1; }
void mpz_lcm (mpz_ptr r, mpz_srcptr u, mpz_srcptr v) { mpz_t g; mp_size_t usize, vsize; TMP_DECL; usize = SIZ (u); vsize = SIZ (v); if (usize == 0 || vsize == 0) { SIZ (r) = 0; return; } usize = ABS (usize); vsize = ABS (vsize); if (vsize == 1 || usize == 1) { mp_limb_t vl, gl, c; mp_srcptr up; mp_ptr rp; if (usize == 1) { usize = vsize; MPZ_SRCPTR_SWAP (u, v); } MPZ_REALLOC (r, usize+1); up = PTR(u); vl = PTR(v)[0]; gl = mpn_gcd_1 (up, usize, vl); vl /= gl; rp = PTR(r); c = mpn_mul_1 (rp, up, usize, vl); rp[usize] = c; usize += (c != 0); SIZ(r) = usize; return; } TMP_MARK; MPZ_TMP_INIT (g, usize); /* v != 0 implies |gcd(u,v)| <= |u| */ mpz_gcd (g, u, v); mpz_divexact (g, u, g); mpz_mul (r, g, v); SIZ (r) = ABS (SIZ (r)); /* result always positive */ TMP_FREE; }
mp_limb_t random_word (gmp_randstate_ptr rs) { mpz_t x; mp_limb_t r; TMP_DECL; TMP_MARK; MPZ_TMP_INIT (x, 2); mpz_urandomb (x, rs, 32); r = mpz_get_ui (x); TMP_FREE; return r; }
void mpz_fdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor) { mp_size_t dividend_size = dividend->_mp_size; mp_size_t divisor_size = divisor->_mp_size; mpz_t rem; TMP_DECL; TMP_MARK; MPZ_TMP_INIT (rem, ABS (divisor_size)); mpz_tdiv_qr (quot, rem, dividend, divisor); if ((divisor_size ^ dividend_size) < 0 && rem->_mp_size != 0) mpz_sub_ui (quot, quot, 1L); TMP_FREE; }
void mpz_cdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor) { mp_size_t dividend_size = SIZ (dividend); mp_size_t divisor_size = SIZ (divisor); mpz_t rem; TMP_DECL; TMP_MARK; MPZ_TMP_INIT (rem, ABS (divisor_size)); mpz_tdiv_qr (quot, rem, dividend, divisor); if ((divisor_size ^ dividend_size) >= 0 && SIZ (rem) != 0) mpz_add_ui (quot, quot, 1L); TMP_FREE; }
void mpz_gcdext (mpz_ptr g, mpz_ptr s, mpz_ptr t, mpz_srcptr a, mpz_srcptr b) { mp_size_t asize, bsize, usize, vsize; mp_srcptr ap, bp; mp_ptr up, vp; mp_size_t gsize, ssize, tmp_ssize; mp_ptr gp, sp, tmp_gp, tmp_sp; mpz_srcptr u, v; mpz_ptr ss, tt; __mpz_struct stmp, gtmp; TMP_DECL; TMP_MARK; /* mpn_gcdext requires that U >= V. Therefore, we often have to swap U and V. This in turn leads to a lot of complications. The computed cofactor will be the wrong one, so we have to fix that up at the end. */ asize = ABS (SIZ (a)); bsize = ABS (SIZ (b)); ap = PTR (a); bp = PTR (b); if (asize > bsize || (asize == bsize && mpn_cmp (ap, bp, asize) > 0)) { usize = asize; vsize = bsize; up = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB); vp = (mp_ptr) TMP_ALLOC ((vsize + 1) * BYTES_PER_MP_LIMB); MPN_COPY (up, ap, usize); MPN_COPY (vp, bp, vsize); u = a; v = b; ss = s; tt = t; } else { usize = bsize; vsize = asize; up = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB); vp = (mp_ptr) TMP_ALLOC ((vsize + 1) * BYTES_PER_MP_LIMB); MPN_COPY (up, bp, usize); MPN_COPY (vp, ap, vsize); u = b; v = a; ss = t; tt = s; } tmp_gp = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB); tmp_sp = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB); if (vsize == 0) { tmp_sp[0] = 1; tmp_ssize = 1; MPN_COPY (tmp_gp, up, usize); gsize = usize; } else gsize = mpn_gcdext (tmp_gp, tmp_sp, &tmp_ssize, up, usize, vp, vsize); ssize = ABS (tmp_ssize); PTR (>mp) = tmp_gp; SIZ (>mp) = gsize; PTR (&stmp) = tmp_sp; SIZ (&stmp) = (tmp_ssize ^ SIZ (u)) >= 0 ? ssize : -ssize; if (tt != NULL) { if (SIZ (v) == 0) SIZ (tt) = 0; else { mpz_t x; MPZ_TMP_INIT (x, ssize + usize + 1); mpz_mul (x, &stmp, u); mpz_sub (x, >mp, x); mpz_tdiv_q (tt, x, v); } } if (ss != NULL) { if (ALLOC (ss) < ssize) _mpz_realloc (ss, ssize); sp = PTR (ss); MPN_COPY (sp, tmp_sp, ssize); SIZ (ss) = SIZ (&stmp); } if (ALLOC (g) < gsize) _mpz_realloc (g, gsize); gp = PTR (g); MPN_COPY (gp, tmp_gp, gsize); SIZ (g) = gsize; TMP_FREE; }
int mpz_perfect_power_p (mpz_srcptr u) { unsigned long int prime; unsigned long int n, n2; int i; unsigned long int rem; mpz_t u2, q; int exact; mp_size_t uns; mp_size_t usize = SIZ (u); TMP_DECL; if (mpz_cmpabs_ui (u, 1) <= 0) return 1; /* -1, 0, and +1 are perfect powers */ n2 = mpz_scan1 (u, 0); if (n2 == 1) return 0; /* 2 divides exactly once. */ TMP_MARK; uns = ABS (usize) - n2 / BITS_PER_MP_LIMB; MPZ_TMP_INIT (q, uns); MPZ_TMP_INIT (u2, uns); mpz_tdiv_q_2exp (u2, u, n2); mpz_abs (u2, u2); if (mpz_cmp_ui (u2, 1) == 0) { TMP_FREE; /* factoring completed; consistent power */ return ! (usize < 0 && POW2P(n2)); } if (isprime (n2)) goto n2prime; for (i = 1; primes[i] != 0; i++) { prime = primes[i]; if (mpz_cmp_ui (u2, prime) < 0) break; if (mpz_divisible_ui_p (u2, prime)) /* divisible by this prime? */ { rem = mpz_tdiv_q_ui (q, u2, prime * prime); if (rem != 0) { TMP_FREE; return 0; /* prime divides exactly once, reject */ } mpz_swap (q, u2); for (n = 2;;) { rem = mpz_tdiv_q_ui (q, u2, prime); if (rem != 0) break; mpz_swap (q, u2); n++; } n2 = gcd (n2, n); if (n2 == 1) { TMP_FREE; return 0; /* we have multiplicity 1 of some factor */ } if (mpz_cmp_ui (u2, 1) == 0) { TMP_FREE; /* factoring completed; consistent power */ return ! (usize < 0 && POW2P(n2)); } /* As soon as n2 becomes a prime number, stop factoring. Either we have u=x^n2 or u is not a perfect power. */ if (isprime (n2)) goto n2prime; } } if (n2 == 0) { /* We found no factors above; have to check all values of n. */ unsigned long int nth; for (nth = usize < 0 ? 3 : 2;; nth++) { if (! isprime (nth)) continue; #if 0 exact = mpz_padic_root (q, u2, nth, PTH); if (exact) #endif exact = mpz_root (q, u2, nth); if (exact) { TMP_FREE; return 1; } if (mpz_cmp_ui (q, SMALLEST_OMITTED_PRIME) < 0) { TMP_FREE; return 0; } } } else { unsigned long int nth; if (usize < 0 && POW2P(n2)) { TMP_FREE; return 0; } /* We found some factors above. We just need to consider values of n that divides n2. */ for (nth = 2; nth <= n2; nth++) { if (! isprime (nth)) continue; if (n2 % nth != 0) continue; #if 0 exact = mpz_padic_root (q, u2, nth, PTH); if (exact) #endif exact = mpz_root (q, u2, nth); if (exact) { if (! (usize < 0 && POW2P(nth))) { TMP_FREE; return 1; } } if (mpz_cmp_ui (q, SMALLEST_OMITTED_PRIME) < 0) { TMP_FREE; return 0; } } TMP_FREE; return 0; } n2prime: if (usize < 0 && POW2P(n2)) { TMP_FREE; return 0; } exact = mpz_root (NULL, u2, n2); TMP_FREE; return exact; }
void mpz_gcdext (mpz_ptr g, mpz_ptr s, mpz_ptr t, mpz_srcptr a, mpz_srcptr b) { mp_size_t asize, bsize; mp_ptr tmp_ap, tmp_bp; mp_size_t gsize, ssize, tmp_ssize; mp_ptr gp, tmp_gp, tmp_sp; TMP_DECL; /* mpn_gcdext requires that Usize >= Vsize. Therefore, we often have to swap U and V. The computed cofactor will be the "smallest" one, which is faster to produce. The wanted one will be computed here; this is needed anyway when both are requested. */ asize = ABSIZ (a); bsize = ABSIZ (b); if (asize < bsize) { MPZ_SRCPTR_SWAP (a, b); MP_SIZE_T_SWAP (asize, bsize); MPZ_PTR_SWAP (s, t); } if (bsize == 0) { /* g = |a|, s = sgn(a), t = 0. */ ssize = SIZ (a) >= 0 ? (asize != 0) : -1; gp = MPZ_REALLOC (g, asize); MPN_COPY (gp, PTR (a), asize); SIZ (g) = asize; if (t != NULL) SIZ (t) = 0; if (s != NULL) { SIZ (s) = ssize; PTR (s)[0] = 1; } return; } TMP_MARK; TMP_ALLOC_LIMBS_2 (tmp_ap, asize, tmp_bp, bsize); MPN_COPY (tmp_ap, PTR (a), asize); MPN_COPY (tmp_bp, PTR (b), bsize); TMP_ALLOC_LIMBS_2 (tmp_gp, bsize, tmp_sp, bsize + 1); gsize = mpn_gcdext (tmp_gp, tmp_sp, &tmp_ssize, tmp_ap, asize, tmp_bp, bsize); ssize = ABS (tmp_ssize); tmp_ssize = SIZ (a) >= 0 ? tmp_ssize : -tmp_ssize; if (t != NULL) { mpz_t x; __mpz_struct gtmp, stmp; PTR (>mp) = tmp_gp; SIZ (>mp) = gsize; PTR (&stmp) = tmp_sp; SIZ (&stmp) = tmp_ssize; MPZ_TMP_INIT (x, ssize + asize + 1); mpz_mul (x, &stmp, a); mpz_sub (x, >mp, x); mpz_divexact (t, x, b); } if (s != NULL) { mp_ptr sp; sp = MPZ_REALLOC (s, ssize); MPN_COPY (sp, tmp_sp, ssize); SIZ (s) = tmp_ssize; } gp = MPZ_REALLOC (g, gsize); MPN_COPY (gp, tmp_gp, gsize); SIZ (g) = gsize; TMP_FREE; }
/* For now, also disable REDC when MOD is even, as the inverse can't handle that. At some point, we might want to make the code faster for that case, perhaps using CRR. */ #ifndef POWM_THRESHOLD #define POWM_THRESHOLD ((8 * SQR_KARATSUBA_THRESHOLD) / 3) #endif #define HANDLE_NEGATIVE_EXPONENT 1 #undef REDUCE_EXPONENT void #ifndef BERKELEY_MP mpz_powm (mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m) #else /* BERKELEY_MP */ pow (mpz_srcptr b, mpz_srcptr e, mpz_srcptr m, mpz_ptr r) #endif /* BERKELEY_MP */ { mp_ptr xp, tp, qp, gp, this_gp; mp_srcptr bp, ep, mp; mp_size_t bn, es, en, mn, xn; mp_limb_t invm, c; unsigned long int enb; mp_size_t i, K, j, l, k; int m_zero_cnt, e_zero_cnt; int sh; int use_redc; #if HANDLE_NEGATIVE_EXPONENT mpz_t new_b; #endif #if REDUCE_EXPONENT mpz_t new_e; #endif TMP_DECL (marker); mp = PTR(m); mn = ABSIZ (m); if (mn == 0) DIVIDE_BY_ZERO; TMP_MARK (marker); es = SIZ (e); if (es <= 0) { if (es == 0) { /* Exponent is zero, result is 1 mod m, i.e., 1 or 0 depending on if m equals 1. */ SIZ(r) = (mn == 1 && mp[0] == 1) ? 0 : 1; PTR(r)[0] = 1; TMP_FREE (marker); /* we haven't really allocated anything here */ return; } #if HANDLE_NEGATIVE_EXPONENT MPZ_TMP_INIT (new_b, mn + 1); if (! mpz_invert (new_b, b, m)) DIVIDE_BY_ZERO; b = new_b; es = -es; #else DIVIDE_BY_ZERO; #endif } en = es; #if REDUCE_EXPONENT /* Reduce exponent by dividing it by phi(m) when m small. */ if (mn == 1 && mp[0] < 0x7fffffffL && en * GMP_NUMB_BITS > 150) { MPZ_TMP_INIT (new_e, 2); mpz_mod_ui (new_e, e, phi (mp[0])); e = new_e; } #endif use_redc = mn < POWM_THRESHOLD && mp[0] % 2 != 0; if (use_redc) { /* invm = -1/m mod 2^BITS_PER_MP_LIMB, must have m odd */ modlimb_invert (invm, mp[0]); invm = -invm; } else { /* Normalize m (i.e. make its most significant bit set) as required by division functions below. */ count_leading_zeros (m_zero_cnt, mp[mn - 1]); m_zero_cnt -= GMP_NAIL_BITS; if (m_zero_cnt != 0) { mp_ptr new_mp; new_mp = TMP_ALLOC_LIMBS (mn); mpn_lshift (new_mp, mp, mn, m_zero_cnt); mp = new_mp; } } /* Determine optimal value of k, the number of exponent bits we look at at a time. */ count_leading_zeros (e_zero_cnt, PTR(e)[en - 1]); e_zero_cnt -= GMP_NAIL_BITS; enb = en * GMP_NUMB_BITS - e_zero_cnt; /* number of bits of exponent */ k = 1; K = 2; while (2 * enb > K * (2 + k * (3 + k))) { k++; K *= 2; } tp = TMP_ALLOC_LIMBS (2 * mn + 1); qp = TMP_ALLOC_LIMBS (mn + 1); gp = __GMP_ALLOCATE_FUNC_LIMBS (K / 2 * mn); /* Compute x*R^n where R=2^BITS_PER_MP_LIMB. */ bn = ABSIZ (b); bp = PTR(b); /* Handle |b| >= m by computing b mod m. FIXME: It is not strictly necessary for speed or correctness to do this when b and m have the same number of limbs, perhaps remove mpn_cmp call. */ if (bn > mn || (bn == mn && mpn_cmp (bp, mp, mn) >= 0)) { /* Reduce possibly huge base while moving it to gp[0]. Use a function call to reduce, since we don't want the quotient allocation to live until function return. */ if (use_redc) { reduce (tp + mn, bp, bn, mp, mn); /* b mod m */ MPN_ZERO (tp, mn); mpn_tdiv_qr (qp, gp, 0L, tp, 2 * mn, mp, mn); /* unnormnalized! */ } else { reduce (gp, bp, bn, mp, mn); } } else { /* |b| < m. We pad out operands to become mn limbs, which simplifies the rest of the function, but slows things down when the |b| << m. */ if (use_redc) { MPN_ZERO (tp, mn); MPN_COPY (tp + mn, bp, bn); MPN_ZERO (tp + mn + bn, mn - bn); mpn_tdiv_qr (qp, gp, 0L, tp, 2 * mn, mp, mn); } else { MPN_COPY (gp, bp, bn); MPN_ZERO (gp + bn, mn - bn); } } /* Compute xx^i for odd g < 2^i. */ xp = TMP_ALLOC_LIMBS (mn); mpn_sqr_n (tp, gp, mn); if (use_redc) redc (xp, mp, mn, invm, tp); /* xx = x^2*R^n */ else mpn_tdiv_qr (qp, xp, 0L, tp, 2 * mn, mp, mn); this_gp = gp; for (i = 1; i < K / 2; i++) { mpn_mul_n (tp, this_gp, xp, mn); this_gp += mn; if (use_redc) redc (this_gp, mp, mn, invm, tp); /* g[i] = x^(2i+1)*R^n */ else mpn_tdiv_qr (qp, this_gp, 0L, tp, 2 * mn, mp, mn); } /* Start the real stuff. */ ep = PTR (e); i = en - 1; /* current index */ c = ep[i]; /* current limb */ sh = GMP_NUMB_BITS - e_zero_cnt; /* significant bits in ep[i] */ sh -= k; /* index of lower bit of ep[i] to take into account */ if (sh < 0) { /* k-sh extra bits are needed */ if (i > 0) { i--; c <<= (-sh); sh += GMP_NUMB_BITS; c |= ep[i] >> sh; } }