#ifndef IMATH_H_
#define IMATH_H_
#include <limits.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned char mp_sign;
typedef unsigned int mp_size;
typedef int mp_result;
typedef long mp_small;
typedef unsigned long mp_usmall;
#ifdef USE_LONG_LONG
typedef unsigned int mp_digit;
typedef unsigned long long mp_word;
#else
typedef unsigned short mp_digit;
typedef unsigned int mp_word;
#endif
typedef struct mpz {
mp_digit single;
mp_digit *digits;
mp_size alloc;
mp_size used;
mp_sign sign;
} mpz_t, *mp_int;
#define MP_DIGITS(Z) ((Z)->digits)
#define MP_ALLOC(Z) ((Z)->alloc)
#define MP_USED(Z) ((Z)->used)
#define MP_SIGN(Z) ((Z)->sign)
extern const mp_result MP_OK;
extern const mp_result MP_FALSE;
extern const mp_result MP_TRUE;
extern const mp_result MP_MEMORY;
extern const mp_result MP_RANGE;
extern const mp_result MP_UNDEF;
extern const mp_result MP_TRUNC;
extern const mp_result MP_BADARG;
extern const mp_result MP_MINERR;
#define MP_DIGIT_BIT (sizeof(mp_digit) * CHAR_BIT)
#define MP_WORD_BIT (sizeof(mp_word) * CHAR_BIT)
#define MP_SMALL_MIN LONG_MIN
#define MP_SMALL_MAX LONG_MAX
#define MP_USMALL_MIN ULONG_MIN
#define MP_USMALL_MAX ULONG_MAX
#ifdef USE_LONG_LONG
# ifndef ULONG_LONG_MAX
# ifdef ULLONG_MAX
# define ULONG_LONG_MAX ULLONG_MAX
# else
# error "Maximum value of unsigned long long not defined!"
# endif
# endif
# define MP_DIGIT_MAX (ULONG_MAX * 1ULL)
# define MP_WORD_MAX ULONG_LONG_MAX
#else
# define MP_DIGIT_MAX (USHRT_MAX * 1UL)
# define MP_WORD_MAX (UINT_MAX * 1UL)
#endif
#define MP_MIN_RADIX 2
#define MP_MAX_RADIX 36
#define MP_MULT_THRESH 22
#define MP_DEFAULT_PREC 8
extern const mp_sign MP_NEG;
extern const mp_sign MP_ZPOS;
#define mp_int_is_odd(Z) ((Z)->digits[0] & 1)
#define mp_int_is_even(Z) !((Z)->digits[0] & 1)
mp_result mp_int_init(mp_int z);
mp_int mp_int_alloc(void);
mp_result mp_int_init_size(mp_int z, mp_size prec);
mp_result mp_int_init_copy(mp_int z, mp_int old);
mp_result mp_int_init_value(mp_int z, mp_small value);
mp_result mp_int_set_value(mp_int z, mp_small value);
void mp_int_clear(mp_int z);
void mp_int_free(mp_int z);
mp_result mp_int_copy(mp_int a, mp_int c);
void mp_int_swap(mp_int a, mp_int c);
void mp_int_zero(mp_int z);
mp_result mp_int_abs(mp_int a, mp_int c);
mp_result mp_int_neg(mp_int a, mp_int c);
mp_result mp_int_add(mp_int a, mp_int b, mp_int c);
mp_result mp_int_add_value(mp_int a, mp_small value, mp_int c);
mp_result mp_int_sub(mp_int a, mp_int b, mp_int c);
mp_result mp_int_sub_value(mp_int a, mp_small value, mp_int c);
mp_result mp_int_mul(mp_int a, mp_int b, mp_int c);
mp_result mp_int_mul_value(mp_int a, mp_small value, mp_int c);
mp_result mp_int_mul_pow2(mp_int a, mp_small p2, mp_int c);
mp_result mp_int_sqr(mp_int a, mp_int c);
mp_result mp_int_div(mp_int a, mp_int b,
mp_int q, mp_int r);
mp_result mp_int_div_value(mp_int a, mp_small value,
mp_int q, mp_small *r);
mp_result mp_int_div_pow2(mp_int a, mp_small p2,
mp_int q, mp_int r);
mp_result mp_int_mod(mp_int a, mp_int m, mp_int c);
#define mp_int_mod_value(A, V, R) mp_int_div_value((A), (V), 0, (R))
mp_result mp_int_expt(mp_int a, mp_small b, mp_int c);
mp_result mp_int_expt_value(mp_small a, mp_small b, mp_int c);
int mp_int_compare(mp_int a, mp_int b);
int mp_int_compare_unsigned(mp_int a, mp_int b);
int mp_int_compare_zero(mp_int z);
int mp_int_compare_value(mp_int z, mp_small value);
int mp_int_divisible_value(mp_int a, mp_small v);
int mp_int_is_pow2(mp_int z);
mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m,
mp_int c);
mp_result mp_int_exptmod_evalue(mp_int a, mp_small value,
mp_int m, mp_int c);
mp_result mp_int_exptmod_bvalue(mp_small value, mp_int b,
mp_int m, mp_int c);
mp_result mp_int_exptmod_known(mp_int a, mp_int b,
mp_int m, mp_int mu,
mp_int c);
mp_result mp_int_redux_const(mp_int m, mp_int c);
mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c);
mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c);
mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c,
mp_int x, mp_int y);
mp_result mp_int_lcm(mp_int a, mp_int b, mp_int c);
mp_result mp_int_root(mp_int a, mp_small b, mp_int c);
#define mp_int_sqrt(a, c) mp_int_root(a, 2, c)
mp_result mp_int_to_int(mp_int z, mp_small *out);
mp_result mp_int_to_uint(mp_int z, mp_usmall *out);
mp_result mp_int_to_string(mp_int z, mp_size radix,
char *str, int limit);
mp_result mp_int_string_len(mp_int z, mp_size radix);
mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str);
mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str,
char **end);
mp_result mp_int_count_bits(mp_int z);
mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit);
mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len);
mp_result mp_int_binary_len(mp_int z);
mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit);
mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len);
mp_result mp_int_unsigned_len(mp_int z);
const char *mp_error_string(mp_result res);
#if DEBUG
void s_print(char *tag, mp_int z);
void s_print_buf(char *tag, mp_digit *buf, mp_size num);
#endif
#ifdef __cplusplus
}
#endif
#endif