void mpi_divexact(const mpi *a, const mpi *b, mpi *q) { ASSERT(b->size != 0); if (a->size == 0 || a->size < b->size) { /* FIXME: raise an error here? */ mpi_zero(q); return; } if (a == b) { mpi_set_u32(q, 1); return; } mp_size qsize = a->size - b->size + 1; if (a == q || b == q) { mp_digit *quot = MP_TMP_ALLOC(qsize); mp_divexact(a->digits, a->size, b->digits, b->size, quot); MP_NORMALIZE(quot, qsize); MPI_SIZE(q, qsize); mp_copy(quot, qsize, q->digits); MP_TMP_FREE(quot); } else { MPI_MIN_ALLOC(q, qsize); mp_divexact(a->digits, a->size, b->digits, b->size, q->digits); MP_NORMALIZE(q->digits, qsize); } q->size = qsize; q->sign = a->sign ^ b->sign; }
// References : Cohen H., A course in computational algebraic number theory // (1996), page 25. bool multiplicative_order(const Ptr<RCP<const Integer>> &o, const RCP<const Integer> &a, const RCP<const Integer> &n) { integer_class order, p, t; integer_class _a = a->as_integer_class(), _n = mp_abs(n->as_integer_class()); mp_gcd(t, _a, _n); if (t != 1) return false; RCP<const Integer> lambda = carmichael(n); map_integer_uint prime_mul; prime_factor_multiplicities(prime_mul, *lambda); _a %= _n; order = lambda->as_integer_class(); for (const auto it : prime_mul) { p = it.first->as_integer_class(); mp_pow_ui(t, p, it.second); mp_divexact(order, order, t); mp_powm(t, _a, order, _n); while (t != 1) { mp_powm(t, t, p, _n); order *= p; } } *o = integer(std::move(order)); return true; }
RCP<const Integer> totient(const RCP<const Integer> &n) { if (n->is_zero()) return integer(1); integer_class phi = n->as_integer_class(), p; if (phi < 0) phi = -phi; map_integer_uint prime_mul; prime_factor_multiplicities(prime_mul, *n); for (const auto &it : prime_mul) { p = it.first->as_integer_class(); mp_divexact(phi, phi, p); // phi is exactly divisible by p. phi *= p - 1; } return integer(std::move(phi)); }