#pragma once
#include <stdbool.h>
#include <stdint.h>

/**
 * @brief Calculates greatest common divider of two integers using the euclidean
 * algorithm
 *
 * @param a First number
 * @param b Second number
 * @return The greatest common divider
 */
int gcd(int a, int b);

/**
 * @brief Computes Euler's Totient function φ(n), which counts the number of
 *        integers from 1 to n that are coprime to n.
 *
 * @param n The input number.
 * @return The number of integers from 1 to n that are coprime to n.
 */
int totient(int n);

/**
 * @brief Modular exponentiation (a^b) mod m
 *
 * @param a The base
 * @param b The exponent
 * @param m The modulus
 */
uint64_t modexp(uint64_t a, uint64_t b, uint64_t m);

/**
 * @brief Computes the modular inverse of e modulo phi.
 *
 * @param e The integer whose modular inverse is to be found.
 * @param phi The modulus.
 * @return The modular inverse of e modulo phi, or -1 if no inverse exists.
 */
int mod_inverse(int e, int phi);

/**
 * @brief Generates a random prime number within the given range.
 *
 * @param min The lower bound (inclusive).
 * @param max The upper bound (inclusive).
 * @return A prime number in the range [min, max].
 */
uint64_t gen_prime(uint64_t min, uint64_t max);

/**
 * @brief Checks if a number is prime.
 *
 * @param n The number to check.
 * @return true if n is prime, false otherwise.
 */
bool is_prime(int n);

/**
 * @brief Performs the Miller-Rabin primality test to check if a number is
 * probably prime.
 *
 * @param n The number to test for primality.
 * @param k The number of rounds of testing to perform.
 * @return true if n is probably prime, false if n is composite.
 */
bool miller_rabin(int n, int k);