aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-07-11 16:08:16 +0100
committergingerBill <bill@gingerbill.org>2021-07-11 16:08:16 +0100
commit460e14e5860a503b8e7716ce18a29eb99f517cf7 (patch)
tree058edb259fd5e6cab889f7b12156938c748509c0 /src
parentebcabb8a27ace67c3cd869a573df62b260000ee8 (diff)
Change the compiler's big integer library to use libTomMath
This now replaces Bill's crappy big int implementation
Diffstat (limited to 'src')
-rw-r--r--src/big_int.cpp1211
-rw-r--r--src/check_builtin.cpp26
-rw-r--r--src/check_expr.cpp20
-rw-r--r--src/check_type.cpp8
-rw-r--r--src/exact_value.cpp5
-rw-r--r--src/libtommath/LICENSE26
-rw-r--r--src/libtommath/README.md44
-rw-r--r--src/libtommath/mp_2expt.c31
-rw-r--r--src/libtommath/mp_abs.c24
-rw-r--r--src/libtommath/mp_add.c29
-rw-r--r--src/libtommath/mp_add_d.c86
-rw-r--r--src/libtommath/mp_addmod.c15
-rw-r--r--src/libtommath/mp_and.c54
-rw-r--r--src/libtommath/mp_clamp.c27
-rw-r--r--src/libtommath/mp_clear.c20
-rw-r--r--src/libtommath/mp_clear_multi.c18
-rw-r--r--src/libtommath/mp_cmp.c21
-rw-r--r--src/libtommath/mp_cmp_d.c26
-rw-r--r--src/libtommath/mp_cmp_mag.c25
-rw-r--r--src/libtommath/mp_cnt_lsb.c38
-rw-r--r--src/libtommath/mp_complement.c13
-rw-r--r--src/libtommath/mp_copy.c29
-rw-r--r--src/libtommath/mp_count_bits.c28
-rw-r--r--src/libtommath/mp_cutoffs.c14
-rw-r--r--src/libtommath/mp_div.c42
-rw-r--r--src/libtommath/mp_div_2.c40
-rw-r--r--src/libtommath/mp_div_2d.c61
-rw-r--r--src/libtommath/mp_div_d.c84
-rw-r--r--src/libtommath/mp_dr_is_modulus.c27
-rw-r--r--src/libtommath/mp_dr_reduce.c68
-rw-r--r--src/libtommath/mp_dr_setup.c15
-rw-r--r--src/libtommath/mp_error_to_string.c29
-rw-r--r--src/libtommath/mp_exch.c13
-rw-r--r--src/libtommath/mp_expt_n.c43
-rw-r--r--src/libtommath/mp_exptmod.c78
-rw-r--r--src/libtommath/mp_exteuclid.c72
-rw-r--r--src/libtommath/mp_fread.c66
-rw-r--r--src/libtommath/mp_from_sbin.c21
-rw-r--r--src/libtommath/mp_from_ubin.c30
-rw-r--r--src/libtommath/mp_fwrite.c33
-rw-r--r--src/libtommath/mp_gcd.c92
-rw-r--r--src/libtommath/mp_get_double.c18
-rw-r--r--src/libtommath/mp_get_i32.c7
-rw-r--r--src/libtommath/mp_get_i64.c7
-rw-r--r--src/libtommath/mp_get_l.c7
-rw-r--r--src/libtommath/mp_get_mag_u32.c7
-rw-r--r--src/libtommath/mp_get_mag_u64.c7
-rw-r--r--src/libtommath/mp_get_mag_ul.c7
-rw-r--r--src/libtommath/mp_grow.c40
-rw-r--r--src/libtommath/mp_init.c23
-rw-r--r--src/libtommath/mp_init_copy.c21
-rw-r--r--src/libtommath/mp_init_i32.c7
-rw-r--r--src/libtommath/mp_init_i64.c7
-rw-r--r--src/libtommath/mp_init_l.c7
-rw-r--r--src/libtommath/mp_init_multi.c41
-rw-r--r--src/libtommath/mp_init_set.c16
-rw-r--r--src/libtommath/mp_init_size.c28
-rw-r--r--src/libtommath/mp_init_u32.c7
-rw-r--r--src/libtommath/mp_init_u64.c7
-rw-r--r--src/libtommath/mp_init_ul.c7
-rw-r--r--src/libtommath/mp_invmod.c29
-rw-r--r--src/libtommath/mp_is_square.c93
-rw-r--r--src/libtommath/mp_kronecker.c129
-rw-r--r--src/libtommath/mp_lcm.c44
-rw-r--r--src/libtommath/mp_log_n.c29
-rw-r--r--src/libtommath/mp_lshd.c42
-rw-r--r--src/libtommath/mp_mod.c15
-rw-r--r--src/libtommath/mp_mod_2d.c40
-rw-r--r--src/libtommath/mp_montgomery_calc_normalization.c43
-rw-r--r--src/libtommath/mp_montgomery_reduce.c89
-rw-r--r--src/libtommath/mp_montgomery_setup.c40
-rw-r--r--src/libtommath/mp_mul.c68
-rw-r--r--src/libtommath/mp_mul_2.c53
-rw-r--r--src/libtommath/mp_mul_2d.c63
-rw-r--r--src/libtommath/mp_mul_d.c68
-rw-r--r--src/libtommath/mp_mulmod.c15
-rw-r--r--src/libtommath/mp_neg.c18
-rw-r--r--src/libtommath/mp_or.c54
-rw-r--r--src/libtommath/mp_pack.c69
-rw-r--r--src/libtommath/mp_pack_count.c12
-rw-r--r--src/libtommath/mp_prime_fermat.c41
-rw-r--r--src/libtommath/mp_prime_frobenius_underwood.c127
-rw-r--r--src/libtommath/mp_prime_is_prime.c282
-rw-r--r--src/libtommath/mp_prime_miller_rabin.c91
-rw-r--r--src/libtommath/mp_prime_next_prime.c127
-rw-r--r--src/libtommath/mp_prime_rabin_miller_trials.c48
-rw-r--r--src/libtommath/mp_prime_rand.c123
-rw-r--r--src/libtommath/mp_prime_strong_lucas_selfridge.c281
-rw-r--r--src/libtommath/mp_radix_size.c34
-rw-r--r--src/libtommath/mp_radix_size_overestimate.c17
-rw-r--r--src/libtommath/mp_rand.c39
-rw-r--r--src/libtommath/mp_rand_source.c12
-rw-r--r--src/libtommath/mp_read_radix.c69
-rw-r--r--src/libtommath/mp_reduce.c83
-rw-r--r--src/libtommath/mp_reduce_2k.c49
-rw-r--r--src/libtommath/mp_reduce_2k_l.c52
-rw-r--r--src/libtommath/mp_reduce_2k_setup.c30
-rw-r--r--src/libtommath/mp_reduce_2k_setup_l.c28
-rw-r--r--src/libtommath/mp_reduce_is_2k.c34
-rw-r--r--src/libtommath/mp_reduce_is_2k_l.c27
-rw-r--r--src/libtommath/mp_reduce_setup.c17
-rw-r--r--src/libtommath/mp_root_n.c141
-rw-r--r--src/libtommath/mp_rshd.c43
-rw-r--r--src/libtommath/mp_sbin_size.c11
-rw-r--r--src/libtommath/mp_set.c15
-rw-r--r--src/libtommath/mp_set_double.c47
-rw-r--r--src/libtommath/mp_set_i32.c7
-rw-r--r--src/libtommath/mp_set_i64.c7
-rw-r--r--src/libtommath/mp_set_l.c7
-rw-r--r--src/libtommath/mp_set_u32.c7
-rw-r--r--src/libtommath/mp_set_u64.c7
-rw-r--r--src/libtommath/mp_set_ul.c7
-rw-r--r--src/libtommath/mp_shrink.c22
-rw-r--r--src/libtommath/mp_signed_rsh.c21
-rw-r--r--src/libtommath/mp_sqrmod.c15
-rw-r--r--src/libtommath/mp_sqrt.c67
-rw-r--r--src/libtommath/mp_sqrtmod_prime.c133
-rw-r--r--src/libtommath/mp_sub.c36
-rw-r--r--src/libtommath/mp_sub_d.c78
-rw-r--r--src/libtommath/mp_submod.c15
-rw-r--r--src/libtommath/mp_to_radix.c95
-rw-r--r--src/libtommath/mp_to_sbin.c22
-rw-r--r--src/libtommath/mp_to_ubin.c37
-rw-r--r--src/libtommath/mp_ubin_size.c12
-rw-r--r--src/libtommath/mp_unpack.c49
-rw-r--r--src/libtommath/mp_xor.c54
-rw-r--r--src/libtommath/mp_zero.c13
-rw-r--r--src/libtommath/s_mp_add.c70
-rw-r--r--src/libtommath/s_mp_copy_digs.c23
-rw-r--r--src/libtommath/s_mp_div_3.c64
-rw-r--r--src/libtommath/s_mp_div_recursive.c159
-rw-r--r--src/libtommath/s_mp_div_school.c156
-rw-r--r--src/libtommath/s_mp_div_small.c51
-rw-r--r--src/libtommath/s_mp_exptmod.c198
-rw-r--r--src/libtommath/s_mp_exptmod_fast.c254
-rw-r--r--src/libtommath/s_mp_get_bit.c21
-rw-r--r--src/libtommath/s_mp_invmod.c117
-rw-r--r--src/libtommath/s_mp_invmod_odd.c116
-rw-r--r--src/libtommath/s_mp_log.c81
-rw-r--r--src/libtommath/s_mp_log_2expt.c12
-rw-r--r--src/libtommath/s_mp_log_d.c65
-rw-r--r--src/libtommath/s_mp_montgomery_reduce_comba.c119
-rw-r--r--src/libtommath/s_mp_mul.c61
-rw-r--r--src/libtommath/s_mp_mul_balance.c71
-rw-r--r--src/libtommath/s_mp_mul_comba.c78
-rw-r--r--src/libtommath/s_mp_mul_high.c52
-rw-r--r--src/libtommath/s_mp_mul_high_comba.c70
-rw-r--r--src/libtommath/s_mp_mul_karatsuba.c151
-rw-r--r--src/libtommath/s_mp_mul_toom.c202
-rw-r--r--src/libtommath/s_mp_prime_is_divisible.c33
-rw-r--r--src/libtommath/s_mp_prime_tab.c44
-rw-r--r--src/libtommath/s_mp_radix_map.c19
-rw-r--r--src/libtommath/s_mp_radix_size_overestimate.c82
-rw-r--r--src/libtommath/s_mp_rand_platform.c149
-rw-r--r--src/libtommath/s_mp_sqr.c65
-rw-r--r--src/libtommath/s_mp_sqr_comba.c87
-rw-r--r--src/libtommath/s_mp_sqr_karatsuba.c92
-rw-r--r--src/libtommath/s_mp_sqr_toom.c133
-rw-r--r--src/libtommath/s_mp_sub.c56
-rw-r--r--src/libtommath/s_mp_zero_buf.c22
-rw-r--r--src/libtommath/s_mp_zero_digs.c23
-rw-r--r--src/libtommath/tommath.h587
-rw-r--r--src/libtommath/tommath_c89.h40
-rw-r--r--src/libtommath/tommath_class.h1260
-rw-r--r--src/libtommath/tommath_cutoffs.h13
-rw-r--r--src/libtommath/tommath_private.h279
-rw-r--r--src/libtommath/tommath_superclass.h113
-rw-r--r--src/llvm_backend.cpp74
-rw-r--r--src/main.cpp1
169 files changed, 10728 insertions, 1150 deletions
diff --git a/src/big_int.cpp b/src/big_int.cpp
index 168e53fb2..f42c2e466 100644
--- a/src/big_int.cpp
+++ b/src/big_int.cpp
@@ -1,59 +1,14 @@
-struct BigInt {
- union {
- u64 word;
- u64 *words;
- } d;
- i32 len;
- b32 neg;
-};
-
-
-BigInt const BIG_INT_ZERO = {{0}, 0, false};
-BigInt const BIG_INT_ONE = {{1}, 1, false};
-BigInt const BIG_INT_NEG_ONE = {{1}, 1, true};
-
-
-gb_global Arena global_big_int_arena = {0};
-
-#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT)
-// URL(bill): https://stackoverflow.com/questions/8453146/128-bit-division-intrinsic-in-visual-c/8456388#8456388
-u8 udiv128_data[] = {
- 0x48, 0x89, 0xD0, // mov rax,rdx
- 0x48, 0x89, 0xCA, // mov rdx,rcx
- 0x49, 0xF7, 0xF0, // div r8
- 0x49, 0x89, 0x11, // mov [r9],rdx
- 0xC3 // ret
-};
-u64 (__fastcall *unsafe_udiv128)(u64 numhi, u64 numlo, u64 den, u64* rem) = (u64 (__fastcall *)(u64, u64, u64, u64*))&udiv128_data[0];
-#endif
-
-void global_big_int_init(void) {
- arena_init(&global_big_int_arena, heap_allocator());
+#pragma warning(push)
+#pragma warning(disable: 4146)
+#include "libtommath/tommath.h"
+#pragma warning(pop)
-#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT)
- DWORD dummy;
- VirtualProtect(udiv128_data, sizeof(udiv128_data), PAGE_EXECUTE_READWRITE, &dummy);
+#ifndef MAX_BIG_INT_SHIFT
+#define MAX_BIG_INT_SHIFT 1024
#endif
-}
-// IMPORTANT NOTE LEAK(bill): This entire BigInt library leaks memory like there is no tomorrow
-// However, this isn't really a problem as the vast majority of BigInt operations will not use
-// more than 1 word.
-// I could track how much this does leaks because I use an arena_allocator but I doubt I will require
-// it any time soon
-gb_inline gbAllocator big_int_allocator(void) {
- return arena_allocator(&global_big_int_arena);
-}
+typedef mp_int BigInt;
-void big_int_alloc(BigInt *dst, isize word_len, isize word_cap) {
- GB_ASSERT_MSG(word_len <= word_cap, "%td %td", word_len, word_cap);
- if (word_cap < dst->len) {
- dst->len = cast(i32)word_len;
- } else {
- dst->len = cast(i32)word_len;
- dst->d.words = gb_alloc_array(big_int_allocator(), u64, word_cap);
- }
-}
void big_int_from_u64(BigInt *dst, u64 x);
void big_int_from_i64(BigInt *dst, i64 x);
@@ -61,10 +16,7 @@ void big_int_init (BigInt *dst, BigInt const *src);
void big_int_from_string(BigInt *dst, String const &s);
void big_int_dealloc(BigInt *dst) {
- if (dst->len > 1) {
- gb_free(big_int_allocator(), dst->d.words);
- }
- zero_item(dst);
+ mp_clear(dst);
}
BigInt big_int_make(BigInt const *b, bool abs=false);
@@ -77,19 +29,6 @@ i64 big_int_to_i64 (BigInt const *x);
f64 big_int_to_f64 (BigInt const *x);
String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base = 10);
-gb_inline u64 const *big_int_ptr(BigInt const *b) {
- if (b->len <= 1) {
- return &b->d.word;
- }
- return b->d.words;
-}
-gb_inline u64 *big_int_ptr(BigInt *b) {
- if (b->len <= 1) {
- return &b->d.word;
- }
- return b->d.words;
-}
-
void big_int_add (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_sub (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_shl (BigInt *dst, BigInt const *x, BigInt const *y);
@@ -101,9 +40,6 @@ void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q, BigInt *r);
void big_int_quo (BigInt *z, BigInt const *x, BigInt const *y);
void big_int_rem (BigInt *z, BigInt const *x, BigInt const *y);
-void big_int_euclidean_div(BigInt *z, BigInt const *x, BigInt const *y);
-void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y);
-
void big_int_and (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_xor (BigInt *dst, BigInt const *x, BigInt const *y);
@@ -159,99 +95,37 @@ void big_int_rem_eq(BigInt *dst, BigInt const *x) {
-void big_int_normalize(BigInt *dst) {
- if (dst->len == 1 && dst->d.word == 0) {
- dst->len = 0;
- return;
- }
- u64 const *words = big_int_ptr(dst);
-
- i32 count_minus_one = -1;
- for (i32 i = 0; i < dst->len; i++) {
- u64 word = words[i];
- if (word != 0) {
- count_minus_one = i;
- }
- }
-
- if (count_minus_one < 0) {
- dst->neg = false;
- if (words[0] == 0) {
- dst->len = 0;
- return;
- }
- }
- dst->len = count_minus_one+1;
- if (count_minus_one == 0) {
- dst->d.word = words[0];
- }
-}
-
i64 big_int_sign(BigInt const *x) {
- if (x->len == 0) {
+ if (mp_iszero(x)) {
return 0;
}
- return x->neg ? -1 : +1;
+ return x->sign == MP_ZPOS ? +1 : -1;
}
void big_int_from_u64(BigInt *dst, u64 x) {
- if (x == 0) {
- dst->len = 0;
- dst->neg = false;
- } else {
- dst->len = 1;
- dst->d.word = x;
- dst->neg = false;
- }
+ mp_init_u64(dst, x);
}
void big_int_from_i64(BigInt *dst, i64 x) {
- if (x >= 0) {
- big_int_from_u64(dst, cast(u64)x);
- return;
- } else {
- dst->len = 1;
- dst->d.word = (cast(u64)(-(x+1ll))) + 1ull;
- dst->neg = true;
- }
+ mp_init_i64(dst, x);
}
void big_int_init(BigInt *dst, BigInt const *src) {
if (dst == src) {
return;
}
- if (src->len == 0) {
- big_int_from_u64(dst, 0);
- return;
- } else if (src->len == 1) {
- dst->len = 1;
- dst->d.word = src->d.word;
- dst->neg = src->neg;
- return;
- }
-
-
- dst->neg = src->neg;
- big_int_alloc(dst, src->len, src->len);
- u64 const *s = big_int_ptr(src);
- gb_memmove(dst->d.words, s, gb_size_of(u64)*dst->len);
- big_int_normalize(dst);
+ mp_init_copy(dst, src);
}
BigInt big_int_make(BigInt const *b, bool abs) {
BigInt i = {};
big_int_init(&i, b);
- if (abs) i.neg = false;
+ if (abs) mp_abs(&i, &i);
return i;
}
BigInt big_int_make_abs(BigInt const *b) {
return big_int_make(b, true);
}
-BigInt big_int_alias_abs(BigInt const *b) {
- BigInt x = *b;
- x.neg = false;
- return x;
-}
BigInt big_int_make_u64(u64 x) {
@@ -289,7 +163,7 @@ void big_int_from_string(BigInt *dst, String const &s) {
BigInt b = {};
big_int_from_u64(&b, base);
- big_int_init(dst, &BIG_INT_ZERO);
+ mp_zero(dst);
isize i = 0;
for (; i < len; i++) {
@@ -331,476 +205,79 @@ void big_int_from_string(BigInt *dst, String const &s) {
big_int_mul_eq(dst, &b);
}
}
- big_int_normalize(dst);
}
u64 big_int_to_u64(BigInt const *x) {
- GB_ASSERT(!x->neg);
- switch (x->len) {
- case 0: return 0;
- case 1: return x->d.word;
- }
- GB_PANIC("BigInt too big for u64");
- return 0;
+ GB_ASSERT(x->sign == 0);
+ return mp_get_u64(x);
}
i64 big_int_to_i64(BigInt const *x) {
- switch (x->len) {
- case 0:
- return 0;
- case 1:
- if (x->neg) {
- if (x->d.word <= 9223372036854775808ull) { // 2^63 - 1
- return (-cast(i64)(x->d.word-1ull)) - 1ll;
- } else {
- GB_PANIC("BigInt too big for i64");
- }
- } else {
- return cast(i64)x->d.word;
- }
- break;
- }
-
- GB_PANIC("BigInt too big for i64");
- return 0;
+ return mp_get_i64(x);
}
f64 big_int_to_f64(BigInt const *x) {
- switch (x->len) {
- case 0:
- return 0.0;
- case 1:
- if (x->neg) {
- i64 i = big_int_to_i64(x);
- return cast(f64)i;
- } else {
- u64 u = big_int_to_u64(x);
- return cast(f64)u;
- }
- }
-
-
- u64 const *words = big_int_ptr(x);
- f64 base = pow(2.0, gb_size_of(u64));
- // TODO(bill): clean up this code and make it more accurate
- f64 res = 0;
- for (isize i = x->len-1; i >= 0; i--) {
- res *= base;
- u64 w = words[i];
- res += cast(f64)w;
- }
- return res;
-}
-
-bool bi__alias(BigInt const *dst, BigInt const *src) {
- if (dst == src) {
- return true;
- }
- if (dst->len > 1 && src->len > 1) {
- return dst->d.words == src->d.words;
- }
- return false;
+ return mp_get_double(x);
}
void big_int_neg(BigInt *dst, BigInt const *x) {
- big_int_init(dst, x);
- dst->neg = !dst->neg;
- big_int_normalize(dst);
+ mp_neg(x, dst);
}
int big_int_cmp(BigInt const *x, BigInt const *y) {
- if (x == y) {
- return 0;
- } else if (x->neg && !y->neg) {
- return -1;
- } else if (!x->neg && y->neg) {
- return +1;
- } else if (x->len > y->len) {
- return x->neg ? -1 : +1;
- } else if (y->len > x->len) {
- return x->neg ? +1 : -1;
- } else if (x->len == 0) {
- return 0;
- }
-
- u64 const *xd = big_int_ptr(x);
- u64 const *yd = big_int_ptr(y);
-
- for (i32 i = x->len-1; i >= 0; i--) {
- u64 a = xd[i];
- u64 b = yd[i];
-
- if (a > b) {
- return x->neg ? -1 : +1;
- }
- if (a < b) {
- return x->neg ? +1 : -1;
- }
- }
-
- return 0;
+ return mp_cmp(x, y);
}
int big_int_cmp_zero(BigInt const *x) {
- if (x->len == 0) {
+ if (mp_iszero(x)) {
return 0;
}
- return x->neg ? -1 : +1;
+ return x->sign ? -1 : +1;
}
bool big_int_is_zero(BigInt const *x) {
- if (x->len == 0) {
- return true;
- }
- return false;
+ return mp_iszero(x);
}
void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
- if (x->len == 0) {
- big_int_init(dst, y);
- return;
- }
- if (y->len == 0) {
- big_int_init(dst, x);
- return;
- }
-
- if (x->neg == y->neg) {
- dst->neg = x->neg;
-
- u64 const *x_words = big_int_ptr(x);
- u64 const *y_words = big_int_ptr(y);
- u64 overflow = cast(u64)add_overflow_u64(x_words[0], y_words[0], &dst->d.word);
- if (overflow == 0 && x->len == 1 && y->len == 1) {
- dst->len = 1;
- big_int_normalize(dst);
- return;
- }
-
- u64 first_word = dst->d.word;
- big_int_alloc(dst, 0, gb_max(x->len, y->len)+1);
- dst->d.words[0] = first_word;
-
- i32 i = 1;
- for (;;) {
- u64 v = overflow;
- overflow = 0;
-
- bool found_word = false;
- if (i < x->len) {
- found_word = true;
- overflow += add_overflow_u64(v, x_words[i], &v);
- }
- if (i < y->len) {
- found_word = true;
- overflow += add_overflow_u64(v, y_words[i], &v);
- }
-
- dst->d.words[i] = v;
- i += 1;
-
- if (!found_word) {
- dst->len = i;
- big_int_normalize(dst);
- return;
- }
- }
- } else {
- BigInt const *pos = nullptr;
- BigInt const *neg = nullptr;
- if (x->neg) {
- neg = x;
- pos = y;
- } else {
- GB_ASSERT(y->neg);
- pos = x;
- neg = y;
- }
-
- BigInt neg_abs = {};
- big_int_neg(&neg_abs, neg);
- BigInt const *bigger = nullptr;
- BigInt const *smaller = nullptr;
-
- int cmp = big_int_cmp(pos, &neg_abs);
- dst->neg = cmp < 0;
- switch (cmp) {
- case 0:
- big_int_from_u64(dst, 0);
- return;
- case -1:
- bigger = &neg_abs;
- smaller = pos;
- break;
- case +1:
- bigger = pos;
- smaller = &neg_abs;
- break;
- default:
- GB_PANIC("Invalid big_int_cmp value");
- return;
- }
-
- u64 const *bigger_words = big_int_ptr(bigger);
- u64 const *smaller_words = big_int_ptr(smaller);
- u64 overflow = cast(u64)sub_overflow_u64(bigger_words[0], smaller_words[0], &dst->d.word);
- if (overflow == 0 && bigger->len == 1 && smaller->len == 1) {
- dst->len = 1;
- big_int_normalize(dst);
- return;
- }
-
- u64 first_word = dst->d.word;
- big_int_alloc(dst, 0, bigger->len);
- dst->d.words[0] = first_word;
-
- i32 i = 0;
- while (i < bigger->len) {
- u64 v = bigger_words[i];
- u64 prev_overflow = overflow;
- overflow = 0;
-
- bool found_word = false;
- if (i < smaller->len) {
- found_word = true;
- overflow += sub_overflow_u64(v, smaller_words[i], &v);
- }
- if (sub_overflow_u64(v, prev_overflow, &v)) {
- found_word = true;
- overflow += 1;
- } else {
- // IMPORTANT TODO(bill): Is this mathematics correct here?
- v += overflow;
- }
- dst->d.words[i] = v;
- i += 1;
-
- if (!found_word) {
- break;
- }
- }
-
- if (overflow != 0) {
- GB_ASSERT_MSG(overflow == 0, "%p %p %p", dst, x, y);
- }
- dst->len = i;
- big_int_normalize(dst);
- return;
- }
+ mp_add(x, y, dst);
}
void big_int_sub(BigInt *dst, BigInt const *x, BigInt const *y) {
- BigInt neg_y = {};
- big_int_neg(&neg_y, y);
- big_int_add(dst, x, &neg_y);
- big_int_normalize(dst);
- return;
+ mp_sub(x, y, dst);
}
void big_int_shl(BigInt *dst, BigInt const *x, BigInt const *y) {
- GB_ASSERT(!y->neg);
-
- if (x->len == 0) {
- big_int_from_u64(dst, 0);
- return;
- }
-
- if (x->len == 1 && x->d.word == 0) {
- big_int_from_u64(dst, 0);
- return;
- }
-
- if (y->len == 0) {
- big_int_init(dst, x);
- return;
- }
-
- if (y->len == 0) {
- big_int_from_u64(dst, 0);
- return;
- }
-
- if (y->len != 1) {
- GB_PANIC("SHL value greater than 64 bits!");
- }
-
- u64 const *xd = big_int_ptr(x);
- u64 shift_amount = big_int_to_u64(y);
- if (x->len == 1 && shift_amount < 64) {
- dst->d.word = xd[0] << shift_amount;
- if (dst->d.word > xd[0]) {
- dst->len = 1;
- dst->neg = x->neg;
- big_int_normalize(dst);
- return;
- }
- }
-
- u64 word_shift_len = shift_amount / 64;
- u64 remaining_shift_len = shift_amount % 64;
-
- big_int_alloc(dst, cast(i32)word_shift_len, x->len + word_shift_len + 1);
- GB_ASSERT((x->len + word_shift_len + 1) > 1);
-
- u64 carry = 0;
- for (i32 i = 0; i < x->len; i++) {
- u64 word = xd[i];
- dst->d.words[dst->len] = carry | (word << remaining_shift_len);
- dst->len += 1;
- if (remaining_shift_len > 0) {
- carry = word >> (64 - remaining_shift_len);
- } else {
- carry = 0;
- }
- }
- big_int_normalize(dst);
+ u32 yy = mp_get_u32(y);
+ mp_mul_2d(x, yy, dst);
}
void big_int_shr(BigInt *dst, BigInt const *x, BigInt const *y) {
- GB_ASSERT(!y->neg);
-
- if (x->len == 0) {
- big_int_from_u64(dst, 0);
- return;
- }
- if (x->len == 1 && x->d.word == 0) {
- big_int_from_u64(dst, 0);
- return;
- }
-
- if (y->len == 0) {
- big_int_init(dst, x);
- return;
- }
-
- if (y->len != 1) {
- GB_PANIC("SHR value greater than 64 bits!");
- }
-
- u64 const *xd = big_int_ptr(x);
- u64 shift_amount = big_int_to_u64(y);
-
- if (x->len == 1) {
- dst->d.word = xd[0] >> shift_amount;
- dst->len = 1;
- dst->neg = x->neg;
- big_int_normalize(dst);
- return;
- }
-
- u64 word_shift_len = shift_amount / 64ull;
- u64 remaining_shift_len = shift_amount % 64ull;
-
- if (word_shift_len >= x->len) {
- big_int_from_u64(dst, 0);
- return;
- }
-
- i32 len = cast(i32)(x->len - word_shift_len);
- i32 cap = gb_max(len, dst->len);
- big_int_alloc(dst, len, cap);
- GB_ASSERT(dst->len >= 1);
-
- u64 carry = 0;
- for (i32 src_idx = x->len - 1; src_idx >= 0; src_idx--) {
- u64 v = xd[src_idx];
- u64 dst_idx = src_idx - word_shift_len;
-
- dst->d.words[dst_idx] = carry | (v >> remaining_shift_len);
-
- carry = v << (64ull - remaining_shift_len);
- }
- big_int_normalize(dst);
+ u32 yy = mp_get_u32(y);
+ BigInt d = {};
+ mp_div_2d(x, yy, dst, &d);
+ mp_clear(&d);
}
void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) {
- BigInt v64 = {};
- big_int_from_u64(&v64, 64);
-
- big_int_from_u64(dst, 0);
-
- u64 const *xd = big_int_ptr(x);
- for (i32 i = x->len-1; i >= 0; i--) {
- BigInt shifted = {};
- big_int_shl(&shifted, dst, &v64);
-
- u64 result_u64 = 0;
- u64 carry_u64 = 0;
- mul_overflow_u64(y, xd[i], &result_u64, &carry_u64);
-
- BigInt result;
- BigInt carry;
- BigInt carry_shifted;
- big_int_from_u64(&result, result_u64);
- big_int_from_u64(&carry, carry_u64);
- big_int_shl(&carry_shifted, &carry, &v64);
-
- BigInt tmp;
- big_int_add(&tmp, &shifted, &carry_shifted);
- big_int_add(dst, &tmp, &result);
- }
- big_int_normalize(dst);
+ BigInt d = {};
+ big_int_from_u64(&d, y);
+ mp_mul(x, &d, dst);
+ mp_clear(&d);
}
-void big_int_mul(BigInt *z, BigInt const *x, BigInt const *y) {
- if (x->len == 0 || y->len == 0) {
- return big_int_from_u64(z, 0);
- }
- u64 const *xd = big_int_ptr(x);
- u64 const *yd = big_int_ptr(y);
-
- u64 carry = 0;
- mul_overflow_u64(xd[0], yd[0], &z->d.word, &carry);
- if (carry == 0 && x->len == 1 && y->len == 1) {
- z->neg = (x->neg != y->neg);
- z->len = 1;
- big_int_normalize(z);
- return;
- }
-
- big_int_from_u64(z, 0);
- i32 len = x->len+y->len;
- big_int_alloc(z, len, len);
- u64 *zd = big_int_ptr(z);
-
- for (i32 i = 0; i < y->len; i++) {
- u64 d = yd[i];
- if (d != 0) {
- u64 *z = zd+i;
- i32 n = x->len;
- u64 c = 0;
- for (i32 j = 0; j < n; j++) {
- u64 z1 = 0;
- u64 z00 = 0;
- mul_overflow_u64(xd[j], d, &z00, &z1);
- u64 z0 = z00 + z[j];
- if (z0 < z00) {
- z1 += 1;
- }
- z[j] = z0 + c;
- c = 0;
- if (z[j] < z0) {
- c = 1;
- }
- c += z1;
- }
-
- zd[n+i] = c;
- }
- }
-
- z->neg = (x->neg != y->neg);
- big_int_normalize(z);
+void big_int_mul(BigInt *dst, BigInt const *x, BigInt const *y) {
+ mp_mul(x, y, dst);
}
@@ -813,216 +290,6 @@ u64 leading_zeros_u64(u64 x) {
}
-void bi__divWW(u64 u1, u64 u0, u64 y, u64 *q, u64 *r) {
-#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT)
- *q = unsafe_udiv128(u1, u0, y, r);
-#else
- // NOTE(bill): q = (u1<<64 + u0 - r)/y
- // Hacker's Delight page 152
- if (u1 >= y) {
- *q = ~cast(u64)0ull;
- *r = ~cast(u64)0ull;
- return;
- }
-
-
- u64 s = leading_zeros_u64(y);
- y <<= s;
-
- static u64 const B = 1ull<<32ull;
- static u64 const M = B-1ull;
-
- u64 vn1 = y >> 32ull;
- u64 vn0 = y & M;
- u64 un32 = (u1<<s) | (u0>>(64ull-s));
- u64 un10 = u0 << s;
- u64 un1 = un10 >> 32ull;
- u64 un0 = un10 & M;
- u64 q1 = un32 / vn1;
- u64 rhat = un32 - (q1*vn1);
-
- while ((q1 >= B) || ((q1*vn0) > (B*rhat+un1))) {
- q1 -= 1;
- rhat += vn1;
- if (rhat >= B) {
- break;
- }
- }
-
- u64 un21 = (un32*B) + un1 - (q1*y);
- u64 q0 = un21 / vn1;
- rhat = un21 - (q0*vn1);
-
- while ((q0 >= B) || ((q0*vn0) > (B*rhat+un0))) {
- q0 -= 1;
- rhat += vn1;
- if (rhat >= B) {
- break;
- }
- }
-
- *q = q1*B + q0;
- *r = (un21*B + un0 - q0*y) >> s;
-#endif
-}
-
-
-void bi__divWVW(BigInt *z, u64 xn, BigInt const *x, u64 y, u64 *r_) {
- GB_ASSERT(x->len >= z->len);
- u64 r = xn;
- u64 const *xd = big_int_ptr(x);
- u64 *zd = big_int_ptr(z);
- for (i32 i = z->len-1; i >= 0; i--) {
- u64 u1 = r;
- u64 u0 = xd[i];
- bi__divWW(r, xd[i], y, &zd[i], &r);
- }
- if (r_) *r_ = r;
-}
-
-void bi__divW(BigInt const *x, u64 y, BigInt *q_, u64 *r_) {
- BigInt q = {};
- u64 r = 0;
- i32 m = x->len;
- if (y == 0) {
- GB_PANIC("division by zero");
- } else if (y == 1) {
- q = *x;
- } else if (m == 0) {
- // okay
- } else {
- big_int_alloc(&q, m, m);
- bi__divWVW(&q, 0, x, y, &r);
- big_int_normalize(&q);
- }
- if (q_) *q_ = q;
- if (r_) *r_ = r;
-}
-
-u64 shlVU(BigInt *z, BigInt const *x, u64 s) {
- u64 c = 0;
- i32 n = z->len;
-
- u64 const *xd = big_int_ptr(x);
- u64 *zd = big_int_ptr(z);
-
- if (n > 0) {
- u64 s1 = 64 - s;
- u64 w1 = xd[n-1];
- c = w1 >> s1;
- for (i32 i = n-1; i > 0; i--) {
- u64 w = w1;
- w1 = xd[i-1];
- zd[i] = (w<<s) | (w1>>s1);
- }
- zd[0] = w1 << s;
- }
- return c;
-}
-
-u64 mulAddVWW(BigInt *z, BigInt const *x, u64 y, u64 r) {
- u64 c = r;
- u64 const *xd = big_int_ptr(x);
- u64 *zd = big_int_ptr(z);
-
- for (i32 i = 0; i < z->len; i++) {
- u64 a, b;
- mul_overflow_u64(xd[i], y, &a, &b);
- zd[i] = b + c;
- if (zd[i] < b) {
- a += 1;
- }
- c = a;
- }
- return c;
-}
-
-bool bi__greater_than(u64 x1, u64 x2, u64 y1, u64 y2) {
- return x1 > y1 || (x1 == x2 && x2 > y2);
-}
-
-void bi__div_large(BigInt const *a, BigInt const *b, BigInt *q, BigInt *r) {
- i32 n = b->len;
- i32 m = a->len - n;
-
- BigInt u = *a;
- BigInt v = *b;
-
- big_int_alloc(q, m+1, m+1);
-
- BigInt qhatv = {{cast(u64)n+1ull}, 1, false};
-
- big_int_alloc(&u, a->len+1, a->len+1);
-
- u64 *ud = big_int_ptr(&u);
- u64 *vd = big_int_ptr(&v);
-
- u64 shift = leading_zeros_u64(vd[n-1]);
- if (shift > 0) {
- BigInt v1 = {{cast(u64)n}, 1, false};
- shlVU(&v1, &v, shift);
- v = v1;
- vd = big_int_ptr(&v);
- }
-
- BigInt uu = u;
- uu.len = a->len;
- ud[a->len] = shlVU(&uu, a, shift);
-}
-
-void big_int_quo_rem_unsigned(BigInt const *a, BigInt const *b, BigInt *q_, BigInt *r_) {
- if (b->len == 0) {
- GB_PANIC("division by zero");
- } else if (b->len == 1 && b->d.word == 0) {
- GB_PANIC("division by zero");
- }
-
- BigInt x = *a; x.neg = false;
- BigInt y = *b; y.neg = false;
- BigInt q = {};
- BigInt r = {};
-
- int cmp = big_int_cmp(&x, &y);
-
- if (cmp < 0) {
- q = BIG_INT_ZERO;
- r = x;
- goto end;
- } else if (cmp == 0) {
- q = BIG_INT_ONE;
- r = BIG_INT_ZERO;
- goto end;
- }
-
- if (y.len == 1) {
- if (y.d.word == 0) {
- GB_PANIC("division by zero");
- } else if (y.d.word == 1) {
- q = x;
- r = BIG_INT_ZERO;
- goto end;
- } else if (x.len == 0) {
- q = BIG_INT_ZERO;
- r = BIG_INT_ZERO;
- goto end;
- }
- u64 rr = 0;
- bi__divW(&x, y.d.word, &q, &rr);
- big_int_from_u64(&r, rr);
- goto end;
- }
-
- GB_PANIC("Division of a large denominator not yet supported");
- bi__div_large(&x, &y, &q, &r);
-
-end:
- big_int_normalize(&q);
- big_int_normalize(&r);
- if (q_) *q_ = q;
- if (r_) *r_ = r;
- return;
-}
-
// `big_int_quo_rem` sets z to the quotient x/y and r to the remainder x%y
// and returns the pair (z, r) for y != 0.
// if y == 0, a division-by-zero run-time panic occurs.
@@ -1030,52 +297,29 @@ end:
// q = x/y with the result truncated to zero
// r = x - y*q
void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q_, BigInt *r_) {
- BigInt q = {};
- BigInt r = {};
-
- big_int_quo_rem_unsigned(x, y, &q, &r);
- q.neg = q.len > 0 && x->neg != y->neg;
- r.neg = r.len > 0 && x->neg;
-
- if (q_) *q_ = q;
- if (r_) *r_ = r;
+ mp_div(x, y, q_, r_);
}
void big_int_quo(BigInt *z, BigInt const *x, BigInt const *y) {
BigInt r = {};
- big_int_quo_rem_unsigned(x, y, z, &r);
- z->neg = z->len > 0 && x->neg != y->neg;
+ big_int_quo_rem(x, y, z, &r);
+ mp_clear(&r);
}
void big_int_rem(BigInt *z, BigInt const *x, BigInt const *y) {
BigInt q = {};
- big_int_quo_rem_unsigned(x, y, &q, z);
- z->neg = z->len > 0 && x->neg;
-}
-
-
-
-void big_int_euclidean_div(BigInt *z, BigInt const *x, BigInt const *y) {
- BigInt r = {};
- big_int_quo_rem(x, y, z, &r);
- if (r.neg) {
- if (y->neg) {
- big_int_add(z, z, &BIG_INT_ONE);
- } else {
- big_int_sub(z, z, &BIG_INT_ONE);
- }
- }
+ big_int_quo_rem(x, y, &q, z);
+ mp_clear(&q);
}
-
void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y) {
BigInt y0 = {};
big_int_init(&y0, y);
BigInt q = {};
big_int_quo_rem(x, y, &q, z);
- if (z->neg) {
- if (y0.neg) {
+ if (z->sign) {
+ if (y0.sign) {
big_int_sub(z, z, &y0);
} else {
big_int_add(z, z, &y0);
@@ -1084,360 +328,127 @@ void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y) {
}
-void big_int_and(BigInt *dst, BigInt const *x, BigInt const *y) {
- if (x->len == 0 || y->len == 0) {
- big_int_from_u64(dst, 0);
- return;
- }
- if (x->neg == y->neg) {
- if (x->neg) {
- // (-x) & (-y) == ~(x-1) & ~(x-y) == ~((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
- BigInt x1 = big_int_make_abs(x);
- BigInt y1 = big_int_make_abs(y);
- BigInt z1 = {};
-
- big_int_sub_eq(&x1, &BIG_INT_ONE);
- big_int_sub_eq(&y1, &BIG_INT_ONE);
- big_int_or(&z1, &x1, &y1);
- big_int_add(dst, &z1, &BIG_INT_ONE);
- dst->neg = true; // NOTE(bill): dst cannot be 0 as x and y are both negative
- big_int_normalize(dst);
- return;
- }
- u64 const *xd = big_int_ptr(x);
- u64 const *yd = big_int_ptr(y);
-
- if (x->len == 1 && y->len == 1) {
- dst->len = 1;
- dst->d.word = xd[0] & yd[0];
- return;
- }
-
- i32 len = gb_max(x->len, y->len);
- big_int_alloc(dst, len, len);
- GB_ASSERT(dst->len > 1);
-
- i32 i = 0;
- for (; i < x->len && i < y->len; i++) {
- dst->d.words[i] = xd[i] & yd[i];
- }
- for (; i < len; i++) {
- dst->d.words[i] = 0;
- }
- dst->neg = false;
- big_int_normalize(dst);
- return;
- }
- if (x->neg) {
- BigInt const *tmp = x;
- x = y;
- y = tmp;
- // NOTE(bill): AND is symmetric
- }
-
-
- // x & (-y) == x &~ (y-1)
-
- dst->neg = false;
- BigInt x1 = big_int_make_abs(x);
- BigInt y1 = big_int_make_abs(y);
- big_int_sub_eq(&y1, &BIG_INT_ONE);
- big_int_and_not(dst, &x1, &y1);
- big_int_normalize(dst);
-}
-
-void big_int__and_not_abs(BigInt *dst, BigInt const *x, BigInt const *y) {
- u64 const *xd = big_int_ptr(x);
- u64 const *yd = big_int_ptr(y);
-
- if (x->len == 1 && y->len == 1) {
- dst->len = 1;
- dst->d.word = xd[0] & (~yd[0]);
- return;
- }
-
- i32 len = gb_max(x->len, y->len);
- big_int_alloc(dst, len, len);
- GB_ASSERT(dst->len > 1);
-
- i32 i = 0;
- for (; i < x->len && i < y->len; i++) {
- dst->d.words[i] = xd[i] & (~yd[i]);
- }
- if (i < x->len) {
- for (; i < len; i++) {
- dst->d.words[i] = xd[i];
- }
- }
- if (i < y->len) {
- for (; i < len; i++) {
- dst->d.words[i] = yd[i];
- }
- }
- big_int_normalize(dst);
+void big_int_and(BigInt *dst, BigInt const *x, BigInt const *y) {
+ mp_and(x, y, dst);
}
void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y) {
- if (x->len == 0) {
+ if (mp_iszero(x)) {
big_int_init(dst, y);
return;
}
- if (y->len == 0) {
+ if (mp_iszero(y)) {
big_int_init(dst, x);
return;
}
- if (x->neg == y->neg) {
- if (x->neg) {
+ if (x->sign == y->sign) {
+ if (x->sign) {
// (-x) &~ (-y) == ~(x-1) &~ ~(y-1) == ~(x-1) & (y-1) == (y-1) &~ (x-1)
BigInt x1 = big_int_make_abs(x);
BigInt y1 = big_int_make_abs(y);
- big_int_sub_eq(&x1, &BIG_INT_ONE);
- big_int_sub_eq(&y1, &BIG_INT_ONE);
+ mp_decr(&x1);
+ mp_decr(&y1);
- big_int__and_not_abs(dst, &y1, &x1);
- dst->neg = false;
- big_int_normalize(dst);
+ BigInt ny1 = {};
+ mp_complement(&y1, &ny1);
+ mp_and(&x1, &ny1, dst);
+
+ mp_clear(&x1);
+ mp_clear(&y1);
+ mp_clear(&ny1);
return;
}
- big_int__and_not_abs(dst, x, y);
- dst->neg = false;
- big_int_normalize(dst);
+ BigInt ny = {};
+ mp_complement(y, &ny);
+ mp_and(x, &ny, dst);
+
+ mp_clear(&ny);
return;
}
- if (x->neg) {
+ if (x->sign) {
// (-x) &~ y == ~(x-1) &~ y == ~(x-1) & ~y == ~((x-1) | y) == -(((x-1) | y) + 1)
BigInt x1 = big_int_make_abs(x);
BigInt y1 = big_int_make_abs(y);
- big_int_sub_eq(&x1, &BIG_INT_ONE);
+ mp_decr(&x1);
BigInt z1 = {};
big_int_or(&z1, &x1, &y1);
- big_int_add(dst, &z1, &BIG_INT_ONE);
- dst->neg = true;
- big_int_normalize(dst);
+ mp_add_d(&z1, 1, dst);
+
+ mp_clear(&x1);
+ mp_clear(&y1);
+ mp_clear(&z1);
return;
}
// x &~ (-y) == x &~ ~(y-1) == x & (y-1)
BigInt x1 = big_int_make_abs(x);
BigInt y1 = big_int_make_abs(y);
- big_int_sub_eq(&y1, &BIG_INT_ONE);
+ mp_decr(&y1);
big_int_and(dst, &x1, &y1);
- dst->neg = false;
- big_int_normalize(dst);
- return;
-}
-
-
-void big_int__xor_abs(BigInt *dst, BigInt const *x, BigInt const *y) {
- u64 const *xd = big_int_ptr(x);
- u64 const *yd = big_int_ptr(y);
-
- if (x->len == 1 && y->len == 1) {
- dst->len = 1;
- dst->d.word = xd[0] ^ yd[0];
- big_int_normalize(dst);
- return;
- }
-
- i32 len = gb_max(x->len, y->len);
- big_int_alloc(dst, len, len);
- GB_ASSERT(dst->len > 1);
- i32 i = 0;
- for (; i < x->len && i < y->len; i++) {
- dst->d.words[i] = xd[i] ^ yd[i];
- }
- for (; i < len; i++) {
- if (i < x->len) {
- dst->d.words[i] = xd[i];
- }
- if (i < y->len) {
- dst->d.words[i] = yd[i];
- }
- }
- big_int_normalize(dst);
+ mp_clear(&x1);
+ mp_clear(&y1);
+ return;
}
void big_int_xor(BigInt *dst, BigInt const *x, BigInt const *y) {
- if (x->len == 0) {
- big_int_init(dst, y);
- return;
- } else if (y->len == 0) {
- big_int_init(dst, x);
- return;
- }
-
- if (x->neg == y->neg) {
- if (x->neg) {
- // (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
- BigInt x1 = big_int_make_abs(x);
- BigInt y1 = big_int_make_abs(y);
- big_int_sub_eq(&x1, &BIG_INT_ONE);
- big_int_sub_eq(&y1, &BIG_INT_ONE);
- big_int__xor_abs(dst, &x1, &y1);
- dst->neg = false;
- return;
- }
-
- big_int__xor_abs(dst, x, y);
- dst->neg = false;
- return;
- }
-
- // x->neg != y->neg
- if (x->neg) {
- BigInt const *tmp = x;
- x = y;
- y = tmp;
- }
- dst->neg = false;
- if (y->neg) {
- // x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
- BigInt y1 = big_int_make_abs(y);
- big_int_sub_eq(&y1, &BIG_INT_ONE);
- big_int__xor_abs(dst, x, &y1);
- big_int_add_eq(dst, &BIG_INT_ONE);
- dst->neg = true;
- }
- return;
+ mp_xor(x, y, dst);
}
void big_int_or(BigInt *dst, BigInt const *x, BigInt const *y) {
- if (x->len == 0) {
- big_int_init(dst, y);
- return;
- } else if (y->len == 0) {
- big_int_init(dst, x);
- return;
- }
-
- if (x->neg == y->neg) {
- if (x->neg) {
- // (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
- BigInt x1 = big_int_make_abs(x);
- BigInt y1 = big_int_make_abs(y);
- big_int_sub_eq(&x1, &BIG_INT_ONE);
- big_int_sub_eq(&y1, &BIG_INT_ONE);
- big_int_and(dst, &x1, &y1);
- big_int_add_eq(dst, &BIG_INT_ONE);
- dst->neg = true;
- return;
- }
-
- dst->neg = x->neg;
- u64 const *xd = big_int_ptr(x);
- u64 const *yd = big_int_ptr(y);
-
- if (x->len == 1 && y->len == 1) {
- dst->len = 1;
- dst->d.word = xd[0] | yd[0];
- return;
- }
-
- i32 len = gb_max(x->len, y->len);
- big_int_alloc(dst, len, len);
- GB_ASSERT(dst->len > 1);
-
- for (i32 i = 0; i < len; i++) {
- u64 word = 0;
- if (i < x->len) {
- word |= xd[i];
- }
- if (i < y->len) {
- word |= yd[i];
- }
-
- dst->d.words[i] = word;
- }
- big_int_normalize(dst);
- }
+ mp_or(x, y, dst);
+}
- if (x->neg) {
- BigInt const *tmp = x;
- x = y;
- y = tmp;
- }
- dst->neg = false;
- if (y->neg) {
- // x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(~((y-1) &~ x) + 1)
- BigInt y1 = big_int_make_abs(y);
- big_int_sub_eq(&y1, &BIG_INT_ONE);
- big_int__and_not_abs(dst, &y1, x);
- big_int_add_eq(dst, &BIG_INT_ONE);
- dst->neg = true;
- }
- return;
+void debug_print_big_int(BigInt const *x) {
+ String s = big_int_to_string(temporary_allocator(), x, 10);
+ gb_printf_err("[DEBUG] %.*s\n", LIT(s));
}
-void big_int_not(BigInt *dst, BigInt const *x, u64 bit_count, bool is_signed) {
+void big_int_not(BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed) {
+ GB_ASSERT(bit_count >= 0);
if (bit_count == 0) {
big_int_from_u64(dst, 0);
return;
}
- // TODO(bill): Is this fast enough?
+ BigInt pow2b = {};
+ mp_2expt(&pow2b, bit_count);
- dst->neg = false;
- u64 const *xd = big_int_ptr(x);
- if (bit_count <= 64) {
- dst->len = 1;
- if (x->len == 0) {
- if (bit_count == 64) {
- dst->d.word = ~cast(u64)0ull;
- } else {
- dst->d.word = (1ull << bit_count) - 1ull;
- }
- } else if (x->len == 1) {
- dst->d.word = ~xd[0];
- if (bit_count != 64) {
- u64 mask = (1ull << bit_count) - 1ull;
- dst->d.word &= mask;
- }
- }
- } else {
- dst->len = cast(i32)((bit_count+63ull) / 64ull);
- GB_ASSERT(dst->len >= x->len);
- big_int_alloc(dst, dst->len, dst->len);
- GB_ASSERT(dst->len > 1);
-
- i32 i = 0;
- for (; i < x->len; i++) {
- dst->d.words[i] = ~xd[i];
- }
- for (; i < dst->len; i++) {
- dst->d.words[i] = ~cast(u64)0ull;
- }
+ BigInt mask = {};
+ mp_2expt(&mask, bit_count);
+ mp_decr(&mask);
- i32 word_idx = cast(i32)(cast(u64)dst->len - (bit_count/64ull)-1ull);
- u32 word_bit_idx = bit_count % 64;
- if (word_idx < dst->len) {
- u64 mask = (1ull << word_bit_idx) - 1ull;
- dst->d.words[word_idx] &= mask;
- }
- }
+ BigInt v = {};
+ mp_init_copy(&v, x);
+ mp_mod_2d(&v, bit_count, &v);
- big_int_normalize(dst);
+ mp_xor(&v, &mask, dst);
if (is_signed) {
- BigInt prec = big_int_make_u64(bit_count-1);
- BigInt mask = {};
- BigInt mask_minus_one = {};
- big_int_shl(&mask, &BIG_INT_ONE, &prec);
- big_int_sub(&mask_minus_one, &mask, &BIG_INT_ONE);
+ BigInt pmask = {};
+ BigInt pmask_minus_one = {};
+ mp_2expt(&pmask, bit_count-1);
+ mp_sub_d(&pmask, 1, &pmask_minus_one);
BigInt a = {};
BigInt b = {};
- big_int_and(&a, dst, &mask_minus_one);
- big_int_and(&b, dst, &mask);
+ big_int_and(&a, dst, &pmask_minus_one);
+ big_int_and(&b, dst, &pmask);
big_int_sub(dst, &a, &b);
+ mp_clear(&a);
+ mp_clear(&b);
}
+
+ mp_clear(&pow2b);
+ mp_clear(&mask);
+ mp_clear(&v);
}
@@ -1454,7 +465,7 @@ char digit_to_char(u8 digit) {
String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
GB_ASSERT(base <= 16);
- if ((x->len == 0) && (x->len == 1 && x->d.word == 0)) {
+ if (mp_iszero(x)) {
u8 *buf = gb_alloc_array(allocator, u8, 1);
buf[0] = '0';
return make_string(buf, 1);
@@ -1463,12 +474,12 @@ String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
Array<char> buf = {};
array_init(&buf, allocator, 0, 32);
- BigInt v = *x;
+ BigInt v = {};
+ mp_init_copy(&v, x);
- if (v.neg) {
+ if (v.sign) {
array_add(&buf, '-');
- v.neg = false;
- big_int_normalize(&v);
+ mp_abs(&v, &v);
}
isize first_word_idx = buf.count;
@@ -1488,6 +499,8 @@ String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
digit = cast(u8)big_int_to_u64(&r);
array_add(&buf, digit_to_char(digit));
+ mp_clear(&r);
+ mp_clear(&b);
for (isize i = first_word_idx; i < buf.count/2; i++) {
isize j = buf.count + first_word_idx - i - 1;
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 2d25aaae4..3beaba2e8 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -745,7 +745,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
return false;
}
- if (op.value.value_integer.neg) {
+ if (op.value.value_integer.sign) {
error(op.expr, "Negative 'swizzle' index");
return false;
}
@@ -795,10 +795,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false;
if (x.mode == Addressing_Constant &&
y.mode == Addressing_Constant) {
- if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) {
+ x.value = exact_value_to_float(x.value);
+ y.value = exact_value_to_float(y.value);
+ if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) {
x.type = t_untyped_float;
}
- if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) {
+ if (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) {
y.type = t_untyped_float;
}
}
@@ -882,16 +884,20 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
y.mode == Addressing_Constant &&
z.mode == Addressing_Constant &&
w.mode == Addressing_Constant) {
- if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) {
+ x.value = exact_value_to_float(x.value);
+ y.value = exact_value_to_float(y.value);
+ z.value = exact_value_to_float(z.value);
+ w.value = exact_value_to_float(w.value);
+ if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) {
x.type = t_untyped_float;
}
- if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) {
+ if (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) {
y.type = t_untyped_float;
}
- if (is_type_numeric(z.type) && exact_value_imag(z.value).value_float == 0) {
+ if (is_type_numeric(z.type) && z.value.kind == ExactValue_Float) {
z.type = t_untyped_float;
}
- if (is_type_numeric(w.type) && exact_value_imag(w.value).value_float == 0) {
+ if (is_type_numeric(w.type) && w.value.kind == ExactValue_Float) {
w.type = t_untyped_float;
}
}
@@ -1484,7 +1490,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (operand->mode == Addressing_Constant) {
switch (operand->value.kind) {
case ExactValue_Integer:
- operand->value.value_integer.neg = false;
+ mp_abs(&operand->value.value_integer, &operand->value.value_integer);
break;
case ExactValue_Float:
operand->value.value_float = gb_abs(operand->value.value_float);
@@ -1837,7 +1843,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
operand->type = t_invalid;
return false;
}
- if (x.value.value_integer.neg) {
+ if (x.value.value_integer.sign) {
error(call, "Negative vector element length");
operand->mode = Addressing_Type;
operand->type = t_invalid;
@@ -1877,7 +1883,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
operand->type = t_invalid;
return false;
}
- if (x.value.value_integer.neg) {
+ if (x.value.value_integer.sign) {
error(call, "Negative array element length");
operand->mode = Addressing_Type;
operand->type = t_invalid;
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 54d610c0f..2e552ee79 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -1503,13 +1503,13 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
big_int_from_i64(&bi127, 127);
big_int_shl_eq(&umax, &bi128);
- big_int_sub_eq(&umax, &BIG_INT_ONE);
+ mp_decr(&umax);
big_int_shl_eq(&imin, &bi127);
big_int_neg(&imin, &imin);
big_int_shl_eq(&imax, &bi127);
- big_int_sub_eq(&imax, &BIG_INT_ONE);
+ mp_decr(&imax);
}
switch (type->Basic.kind) {
@@ -1555,7 +1555,7 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
{
// return 0ull <= i && i <= umax;
int b = big_int_cmp(&i, &umax);
- return !i.neg && (b <= 0);
+ return !i.sign && (b <= 0);
}
case Basic_UntypedInteger:
@@ -1758,12 +1758,6 @@ void check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) {
if (!is_type_integer(o->type) && is_type_integer(type)) {
error(o->expr, "'%s' truncated to '%s'", a, b);
} else {
- #if 0
- gb_printf_err("AddressingMode, %d\n", o->mode);
- gb_printf_err("ExactValueKind, %d\n", o->value.kind);
- bool ok = check_representable_as_constant(ctx, o->value, type, &out_value);
- gb_printf_err("ok, %d\n", ok);
- #endif
error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s", a, b, c);
check_assignment_error_suggestion(ctx, o, type);
}
@@ -2206,7 +2200,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
}
BigInt max_shift = {};
- big_int_from_u64(&max_shift, 128);
+ big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT);
if (big_int_cmp(&y_val.value_integer, &max_shift) > 0) {
gbString err_str = expr_to_string(y->expr);
@@ -2248,7 +2242,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
}
}
- if (y->mode == Addressing_Constant && y->value.value_integer.neg) {
+ if (y->mode == Addressing_Constant && y->value.value_integer.sign) {
gbString err_str = expr_to_string(y->expr);
error(node, "Shift amount cannot be negative: '%s'", err_str);
gb_string_free(err_str);
@@ -3320,7 +3314,7 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
if (operand.mode == Addressing_Constant &&
(c->state_flags & StateFlag_no_bounds_check) == 0) {
BigInt i = exact_value_to_integer(operand.value).value_integer;
- if (i.neg && !is_type_enum(index_type)) {
+ if (i.sign && !is_type_enum(index_type)) {
gbString expr_str = expr_to_string(operand.expr);
error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
gb_string_free(expr_str);
@@ -3366,7 +3360,7 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
} else { // NOTE(bill): Do array bound checking
i64 v = -1;
- if (i.len <= 1) {
+ if (i.used <= 1) {
v = big_int_to_i64(&i);
}
if (value) *value = v;
diff --git a/src/check_type.cpp b/src/check_type.cpp
index cc4ffebca..e8000d66c 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -207,7 +207,7 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
if (is_type_untyped(type) || is_type_integer(type)) {
if (o.value.kind == ExactValue_Integer) {
BigInt v = o.value.value_integer;
- if (v.len > 1) {
+ if (v.used > 1) {
gbAllocator a = heap_allocator();
String str = big_int_to_string(a, &v);
error(node, "#align too large, %.*s", LIT(str));
@@ -1998,16 +1998,16 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
if (is_type_untyped(type) || is_type_integer(type)) {
if (o->value.kind == ExactValue_Integer) {
BigInt count = o->value.value_integer;
- if (o->value.value_integer.neg) {
+ if (o->value.value_integer.sign) {
gbAllocator a = heap_allocator();
String str = big_int_to_string(a, &count);
error(e, "Invalid negative array count, %.*s", LIT(str));
gb_free(a, str.text);
return 0;
}
- switch (count.len) {
+ switch (count.used) {
case 0: return 0;
- case 1: return count.d.word;
+ case 1: return big_int_to_u64(&count);
}
gbAllocator a = heap_allocator();
String str = big_int_to_string(a, &count);
diff --git a/src/exact_value.cpp b/src/exact_value.cpp
index 9bcaf76de..cd5ba6579 100644
--- a/src/exact_value.cpp
+++ b/src/exact_value.cpp
@@ -75,8 +75,8 @@ HashKey hash_exact_value(ExactValue v) {
}
case ExactValue_Integer:
{
- HashKey key = hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64));
- u8 last = (u8)v.value_integer.neg;
+ HashKey key = hashing_proc(v.value_integer.dp, gb_size_of(*v.value_integer.dp) * v.value_integer.used);
+ u8 last = (u8)v.value_integer.sign;
key.key = (key.key ^ last) * 0x100000001b3ll;
return key;
}
@@ -719,7 +719,6 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
case Token_Shr: big_int_shr(&c, a, b); break;
default: goto error;
}
- big_int_normalize(&c);
ExactValue res = {ExactValue_Integer};
res.value_integer = c;
return res;
diff --git a/src/libtommath/LICENSE b/src/libtommath/LICENSE
new file mode 100644
index 000000000..b23b3c867
--- /dev/null
+++ b/src/libtommath/LICENSE
@@ -0,0 +1,26 @@
+ The LibTom license
+
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/src/libtommath/README.md b/src/libtommath/README.md
new file mode 100644
index 000000000..be5b20783
--- /dev/null
+++ b/src/libtommath/README.md
@@ -0,0 +1,44 @@
+# libtommath
+
+This is the git repository for [LibTomMath](http://www.libtom.net/LibTomMath/), a free open source portable number theoretic multiple-precision integer (MPI) library written entirely in C.
+
+## Build Status
+
+### Travis CI
+
+master: [![Build Status](https://api.travis-ci.org/libtom/libtommath.png?branch=master)](https://travis-ci.org/libtom/libtommath)
+
+develop: [![Build Status](https://api.travis-ci.org/libtom/libtommath.png?branch=develop)](https://travis-ci.org/libtom/libtommath)
+
+### AppVeyor
+
+master: [![Build status](https://ci.appveyor.com/api/projects/status/b80lpolw3i8m6hsh/branch/master?svg=true)](https://ci.appveyor.com/project/libtom/libtommath/branch/master)
+
+develop: [![Build status](https://ci.appveyor.com/api/projects/status/b80lpolw3i8m6hsh/branch/develop?svg=true)](https://ci.appveyor.com/project/libtom/libtommath/branch/develop)
+
+### ABI Laboratory
+
+API/ABI changes: [check here](https://abi-laboratory.pro/tracker/timeline/libtommath/)
+
+## Summary
+
+The `develop` branch contains the in-development version. Stable releases are tagged.
+
+Documentation is built from the LaTeX file `bn.tex`. There is also limited documentation in `tommath.h`.
+There is also a document, `tommath.pdf`, which describes the goals of the project and many of the algorithms used.
+
+The project can be build by using `make`. Along with the usual `make`, `make clean` and `make install`,
+there are several other build targets, see the makefile for details.
+There are also makefiles for certain specific platforms.
+
+## Testing
+
+Tests are located in `demo/` and can be built in two flavors.
+* `make test` creates a stand-alone test binary that executes several test routines.
+* `make mtest_opponent` creates a test binary that is intended to be run against `mtest`.
+ `mtest` can be built with `make mtest` and test execution is done like `./mtest/mtest | ./mtest_opponent`.
+ `mtest` is creating test vectors using an alternative MPI library and `test` is consuming these vectors to verify correct behavior of ltm
+
+## Building and Installing
+
+Building is straightforward for GNU Linux only, the section "Building LibTomMath" in the documentation in `doc/bn.pdf` has the details.
diff --git a/src/libtommath/mp_2expt.c b/src/libtommath/mp_2expt.c
new file mode 100644
index 000000000..66e857478
--- /dev/null
+++ b/src/libtommath/mp_2expt.c
@@ -0,0 +1,31 @@
+#include "tommath_private.h"
+#ifdef MP_2EXPT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes a = 2**b
+ *
+ * Simple algorithm which zeroes the int, grows it then just sets one bit
+ * as required.
+ */
+mp_err mp_2expt(mp_int *a, int b)
+{
+ mp_err err;
+
+ /* zero a as per default */
+ mp_zero(a);
+
+ /* grow a to accomodate the single bit */
+ if ((err = mp_grow(a, (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* set the used count of where the bit will go */
+ a->used = (b / MP_DIGIT_BIT) + 1;
+
+ /* put the single bit in its place */
+ a->dp[b / MP_DIGIT_BIT] = (mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT);
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_abs.c b/src/libtommath/mp_abs.c
new file mode 100644
index 000000000..a87cc0cb9
--- /dev/null
+++ b/src/libtommath/mp_abs.c
@@ -0,0 +1,24 @@
+#include "tommath_private.h"
+#ifdef MP_ABS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = |a|
+ *
+ * Simple function copies the input and fixes the sign to positive
+ */
+mp_err mp_abs(const mp_int *a, mp_int *b)
+{
+ mp_err err;
+
+ /* copy a to b */
+ if ((err = mp_copy(a, b)) != MP_OKAY) {
+ return err;
+ }
+
+ /* force the sign of b to positive */
+ b->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_add.c b/src/libtommath/mp_add.c
new file mode 100644
index 000000000..bf7a61e25
--- /dev/null
+++ b/src/libtommath/mp_add.c
@@ -0,0 +1,29 @@
+#include "tommath_private.h"
+#ifdef MP_ADD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* high level addition (handles signs) */
+mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ /* handle two cases, not four */
+ if (a->sign == b->sign) {
+ /* both positive or both negative */
+ /* add their magnitudes, copy the sign */
+ c->sign = a->sign;
+ return s_mp_add(a, b, c);
+ }
+
+ /* one positive, the other negative */
+ /* subtract the one with the greater magnitude from */
+ /* the one of the lesser magnitude. The result gets */
+ /* the sign of the one with the greater magnitude. */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ MP_EXCH(const mp_int *, a, b);
+ }
+
+ c->sign = a->sign;
+ return s_mp_sub(a, b, c);
+}
+
+#endif
diff --git a/src/libtommath/mp_add_d.c b/src/libtommath/mp_add_d.c
new file mode 100644
index 000000000..c57a80db3
--- /dev/null
+++ b/src/libtommath/mp_add_d.c
@@ -0,0 +1,86 @@
+#include "tommath_private.h"
+#ifdef MP_ADD_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* single digit addition */
+mp_err mp_add_d(const mp_int *a, mp_digit b, mp_int *c)
+{
+ mp_err err;
+ int oldused;
+
+ /* fast path for a == c */
+ if (a == c) {
+ if (!mp_isneg(c) &&
+ !mp_iszero(c) &&
+ ((c->dp[0] + b) < MP_DIGIT_MAX)) {
+ c->dp[0] += b;
+ return MP_OKAY;
+ }
+ if (mp_isneg(c) &&
+ (c->dp[0] > b)) {
+ c->dp[0] -= b;
+ return MP_OKAY;
+ }
+ }
+
+ /* grow c as required */
+ if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* if a is negative and |a| >= b, call c = |a| - b */
+ if (mp_isneg(a) && ((a->used > 1) || (a->dp[0] >= b))) {
+ mp_int a_ = *a;
+ /* temporarily fix sign of a */
+ a_.sign = MP_ZPOS;
+
+ /* c = |a| - b */
+ err = mp_sub_d(&a_, b, c);
+
+ /* fix sign */
+ c->sign = MP_NEG;
+
+ /* clamp */
+ mp_clamp(c);
+
+ return err;
+ }
+
+ /* old number of used digits in c */
+ oldused = c->used;
+
+ /* if a is positive */
+ if (!mp_isneg(a)) {
+ /* add digits, mu is carry */
+ int i;
+ mp_digit mu = b;
+ for (i = 0; i < a->used; i++) {
+ c->dp[i] = a->dp[i] + mu;
+ mu = c->dp[i] >> MP_DIGIT_BIT;
+ c->dp[i] &= MP_MASK;
+ }
+ /* set final carry */
+ c->dp[i] = mu;
+
+ /* setup size */
+ c->used = a->used + 1;
+ } else {
+ /* a was negative and |a| < b */
+ c->used = 1;
+
+ /* the result is a single digit */
+ c->dp[0] = (a->used == 1) ? b - a->dp[0] : b;
+ }
+
+ /* sign always positive */
+ c->sign = MP_ZPOS;
+
+ /* now zero to oldused */
+ s_mp_zero_digs(c->dp + c->used, oldused - c->used);
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+
+#endif
diff --git a/src/libtommath/mp_addmod.c b/src/libtommath/mp_addmod.c
new file mode 100644
index 000000000..91e2087e5
--- /dev/null
+++ b/src/libtommath/mp_addmod.c
@@ -0,0 +1,15 @@
+#include "tommath_private.h"
+#ifdef MP_ADDMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* d = a + b (mod c) */
+mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d)
+{
+ mp_err err;
+ if ((err = mp_add(a, b, d)) != MP_OKAY) {
+ return err;
+ }
+ return mp_mod(d, c, d);
+}
+#endif
diff --git a/src/libtommath/mp_and.c b/src/libtommath/mp_and.c
new file mode 100644
index 000000000..b5230c4d1
--- /dev/null
+++ b/src/libtommath/mp_and.c
@@ -0,0 +1,54 @@
+#include "tommath_private.h"
+#ifdef MP_AND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* two complement and */
+mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int used = MP_MAX(a->used, b->used) + 1, i;
+ mp_err err;
+ mp_digit ac = 1, bc = 1, cc = 1;
+ bool neg = (mp_isneg(a) && mp_isneg(b));
+
+ if ((err = mp_grow(c, used)) != MP_OKAY) {
+ return err;
+ }
+
+ for (i = 0; i < used; i++) {
+ mp_digit x, y;
+
+ /* convert to two complement if negative */
+ if (mp_isneg(a)) {
+ ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
+ x = ac & MP_MASK;
+ ac >>= MP_DIGIT_BIT;
+ } else {
+ x = (i >= a->used) ? 0uL : a->dp[i];
+ }
+
+ /* convert to two complement if negative */
+ if (mp_isneg(b)) {
+ bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
+ y = bc & MP_MASK;
+ bc >>= MP_DIGIT_BIT;
+ } else {
+ y = (i >= b->used) ? 0uL : b->dp[i];
+ }
+
+ c->dp[i] = x & y;
+
+ /* convert to to sign-magnitude if negative */
+ if (neg) {
+ cc += ~c->dp[i] & MP_MASK;
+ c->dp[i] = cc & MP_MASK;
+ cc >>= MP_DIGIT_BIT;
+ }
+ }
+
+ c->used = used;
+ c->sign = (neg ? MP_NEG : MP_ZPOS);
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_clamp.c b/src/libtommath/mp_clamp.c
new file mode 100644
index 000000000..ae59c4016
--- /dev/null
+++ b/src/libtommath/mp_clamp.c
@@ -0,0 +1,27 @@
+#include "tommath_private.h"
+#ifdef MP_CLAMP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* trim unused digits
+ *
+ * This is used to ensure that leading zero digits are
+ * trimed and the leading "used" digit will be non-zero
+ * Typically very fast. Also fixes the sign if there
+ * are no more leading digits
+ */
+void mp_clamp(mp_int *a)
+{
+ /* decrease used while the most significant digit is
+ * zero.
+ */
+ while ((a->used > 0) && (a->dp[a->used - 1] == 0u)) {
+ --(a->used);
+ }
+
+ /* reset the sign flag if zero */
+ if (mp_iszero(a)) {
+ a->sign = MP_ZPOS;
+ }
+}
+#endif
diff --git a/src/libtommath/mp_clear.c b/src/libtommath/mp_clear.c
new file mode 100644
index 000000000..11094b262
--- /dev/null
+++ b/src/libtommath/mp_clear.c
@@ -0,0 +1,20 @@
+#include "tommath_private.h"
+#ifdef MP_CLEAR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* clear one (frees) */
+void mp_clear(mp_int *a)
+{
+ /* only do anything if a hasn't been freed previously */
+ if (a->dp != NULL) {
+ /* free ram */
+ MP_FREE_DIGS(a->dp, a->alloc);
+
+ /* reset members to make debugging easier */
+ a->dp = NULL;
+ a->alloc = a->used = 0;
+ a->sign = MP_ZPOS;
+ }
+}
+#endif
diff --git a/src/libtommath/mp_clear_multi.c b/src/libtommath/mp_clear_multi.c
new file mode 100644
index 000000000..9c7aed831
--- /dev/null
+++ b/src/libtommath/mp_clear_multi.c
@@ -0,0 +1,18 @@
+#include "tommath_private.h"
+#ifdef MP_CLEAR_MULTI_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include <stdarg.h>
+
+void mp_clear_multi(mp_int *mp, ...)
+{
+ va_list args;
+ va_start(args, mp);
+ while (mp != NULL) {
+ mp_clear(mp);
+ mp = va_arg(args, mp_int *);
+ }
+ va_end(args);
+}
+#endif
diff --git a/src/libtommath/mp_cmp.c b/src/libtommath/mp_cmp.c
new file mode 100644
index 000000000..9f3847b84
--- /dev/null
+++ b/src/libtommath/mp_cmp.c
@@ -0,0 +1,21 @@
+#include "tommath_private.h"
+#ifdef MP_CMP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* compare two ints (signed)*/
+mp_ord mp_cmp(const mp_int *a, const mp_int *b)
+{
+ /* compare based on sign */
+ if (a->sign != b->sign) {
+ return mp_isneg(a) ? MP_LT : MP_GT;
+ }
+
+ /* if negative compare opposite direction */
+ if (mp_isneg(a)) {
+ MP_EXCH(const mp_int *, a, b);
+ }
+
+ return mp_cmp_mag(a, b);
+}
+#endif
diff --git a/src/libtommath/mp_cmp_d.c b/src/libtommath/mp_cmp_d.c
new file mode 100644
index 000000000..42f7b1600
--- /dev/null
+++ b/src/libtommath/mp_cmp_d.c
@@ -0,0 +1,26 @@
+#include "tommath_private.h"
+#ifdef MP_CMP_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* compare a digit */
+mp_ord mp_cmp_d(const mp_int *a, mp_digit b)
+{
+ /* compare based on sign */
+ if (mp_isneg(a)) {
+ return MP_LT;
+ }
+
+ /* compare based on magnitude */
+ if (a->used > 1) {
+ return MP_GT;
+ }
+
+ /* compare the only digit of a to b */
+ if (a->dp[0] != b) {
+ return a->dp[0] > b ? MP_GT : MP_LT;
+ }
+
+ return MP_EQ;
+}
+#endif
diff --git a/src/libtommath/mp_cmp_mag.c b/src/libtommath/mp_cmp_mag.c
new file mode 100644
index 000000000..e5e502b8c
--- /dev/null
+++ b/src/libtommath/mp_cmp_mag.c
@@ -0,0 +1,25 @@
+#include "tommath_private.h"
+#ifdef MP_CMP_MAG_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* compare maginitude of two ints (unsigned) */
+mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b)
+{
+ int n;
+
+ /* compare based on # of non-zero digits */
+ if (a->used != b->used) {
+ return a->used > b->used ? MP_GT : MP_LT;
+ }
+
+ /* compare based on digits */
+ for (n = a->used; n --> 0;) {
+ if (a->dp[n] != b->dp[n]) {
+ return a->dp[n] > b->dp[n] ? MP_GT : MP_LT;
+ }
+ }
+
+ return MP_EQ;
+}
+#endif
diff --git a/src/libtommath/mp_cnt_lsb.c b/src/libtommath/mp_cnt_lsb.c
new file mode 100644
index 000000000..8519ad1b0
--- /dev/null
+++ b/src/libtommath/mp_cnt_lsb.c
@@ -0,0 +1,38 @@
+#include "tommath_private.h"
+#ifdef MP_CNT_LSB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+static const char lnz[16] = {
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(const mp_int *a)
+{
+ int x;
+ mp_digit q;
+
+ /* easy out */
+ if (mp_iszero(a)) {
+ return 0;
+ }
+
+ /* scan lower digits until non-zero */
+ for (x = 0; (x < a->used) && (a->dp[x] == 0u); x++) {}
+ q = a->dp[x];
+ x *= MP_DIGIT_BIT;
+
+ /* now scan this digit until a 1 is found */
+ if ((q & 1u) == 0u) {
+ mp_digit p;
+ do {
+ p = q & 15u;
+ x += lnz[p];
+ q >>= 4;
+ } while (p == 0u);
+ }
+ return x;
+}
+
+#endif
diff --git a/src/libtommath/mp_complement.c b/src/libtommath/mp_complement.c
new file mode 100644
index 000000000..c16e25f9d
--- /dev/null
+++ b/src/libtommath/mp_complement.c
@@ -0,0 +1,13 @@
+#include "tommath_private.h"
+#ifdef MP_COMPLEMENT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = ~a */
+mp_err mp_complement(const mp_int *a, mp_int *b)
+{
+ mp_int a_ = *a;
+ a_.sign = ((a_.sign == MP_ZPOS) && !mp_iszero(a)) ? MP_NEG : MP_ZPOS;
+ return mp_sub_d(&a_, 1uL, b);
+}
+#endif
diff --git a/src/libtommath/mp_copy.c b/src/libtommath/mp_copy.c
new file mode 100644
index 000000000..d79e2b8bf
--- /dev/null
+++ b/src/libtommath/mp_copy.c
@@ -0,0 +1,29 @@
+#include "tommath_private.h"
+#ifdef MP_COPY_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* copy, b = a */
+mp_err mp_copy(const mp_int *a, mp_int *b)
+{
+ mp_err err;
+
+ /* if dst == src do nothing */
+ if (a == b) {
+ return MP_OKAY;
+ }
+
+ /* grow dest */
+ if ((err = mp_grow(b, a->used)) != MP_OKAY) {
+ return err;
+ }
+
+ /* copy everything over and zero high digits */
+ s_mp_copy_digs(b->dp, a->dp, a->used);
+ s_mp_zero_digs(b->dp + a->used, b->used - a->used);
+ b->used = a->used;
+ b->sign = a->sign;
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_count_bits.c b/src/libtommath/mp_count_bits.c
new file mode 100644
index 000000000..52b463d46
--- /dev/null
+++ b/src/libtommath/mp_count_bits.c
@@ -0,0 +1,28 @@
+#include "tommath_private.h"
+#ifdef MP_COUNT_BITS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* returns the number of bits in an int */
+int mp_count_bits(const mp_int *a)
+{
+ int r;
+ mp_digit q;
+
+ /* shortcut */
+ if (mp_iszero(a)) {
+ return 0;
+ }
+
+ /* get number of digits and add that */
+ r = (a->used - 1) * MP_DIGIT_BIT;
+
+ /* take the last digit and count the bits in it */
+ q = a->dp[a->used - 1];
+ while (q > 0u) {
+ ++r;
+ q >>= 1u;
+ }
+ return r;
+}
+#endif
diff --git a/src/libtommath/mp_cutoffs.c b/src/libtommath/mp_cutoffs.c
new file mode 100644
index 000000000..45b0beec1
--- /dev/null
+++ b/src/libtommath/mp_cutoffs.c
@@ -0,0 +1,14 @@
+#include "tommath_private.h"
+#ifdef MP_CUTOFFS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef MP_FIXED_CUTOFFS
+#include "tommath_cutoffs.h"
+int MP_MUL_KARATSUBA_CUTOFF = MP_DEFAULT_MUL_KARATSUBA_CUTOFF,
+ MP_SQR_KARATSUBA_CUTOFF = MP_DEFAULT_SQR_KARATSUBA_CUTOFF,
+ MP_MUL_TOOM_CUTOFF = MP_DEFAULT_MUL_TOOM_CUTOFF,
+ MP_SQR_TOOM_CUTOFF = MP_DEFAULT_SQR_TOOM_CUTOFF;
+#endif
+
+#endif
diff --git a/src/libtommath/mp_div.c b/src/libtommath/mp_div.c
new file mode 100644
index 000000000..b092d7bb0
--- /dev/null
+++ b/src/libtommath/mp_div.c
@@ -0,0 +1,42 @@
+#include "tommath_private.h"
+#ifdef MP_DIV_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d)
+{
+ mp_err err;
+
+ /* is divisor zero ? */
+ if (mp_iszero(b)) {
+ return MP_VAL;
+ }
+
+ /* if a < b then q = 0, r = a */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ if (d != NULL) {
+ if ((err = mp_copy(a, d)) != MP_OKAY) {
+ return err;
+ }
+ }
+ if (c != NULL) {
+ mp_zero(c);
+ }
+ return MP_OKAY;
+ }
+
+ if (MP_HAS(S_MP_DIV_RECURSIVE)
+ && (b->used > (2 * MP_MUL_KARATSUBA_CUTOFF))
+ && (b->used <= ((a->used/3)*2))) {
+ err = s_mp_div_recursive(a, b, c, d);
+ } else if (MP_HAS(S_MP_DIV_SCHOOL)) {
+ err = s_mp_div_school(a, b, c, d);
+ } else if (MP_HAS(S_MP_DIV_SMALL)) {
+ err = s_mp_div_small(a, b, c, d);
+ } else {
+ err = MP_VAL;
+ }
+
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_div_2.c b/src/libtommath/mp_div_2.c
new file mode 100644
index 000000000..8ab9bcb9c
--- /dev/null
+++ b/src/libtommath/mp_div_2.c
@@ -0,0 +1,40 @@
+#include "tommath_private.h"
+#ifdef MP_DIV_2_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = a/2 */
+mp_err mp_div_2(const mp_int *a, mp_int *b)
+{
+ mp_err err;
+ int x, oldused;
+ mp_digit r;
+
+ if ((err = mp_grow(b, a->used)) != MP_OKAY) {
+ return err;
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+
+ /* carry */
+ r = 0;
+ for (x = b->used; x --> 0;) {
+ /* get the carry for the next iteration */
+ mp_digit rr = a->dp[x] & 1u;
+
+ /* shift the current digit, add in carry and store */
+ b->dp[x] = (a->dp[x] >> 1) | (r << (MP_DIGIT_BIT - 1));
+
+ /* forward carry to next iteration */
+ r = rr;
+ }
+
+ /* zero excess digits */
+ s_mp_zero_digs(b->dp + b->used, oldused - b->used);
+
+ b->sign = a->sign;
+ mp_clamp(b);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_div_2d.c b/src/libtommath/mp_div_2d.c
new file mode 100644
index 000000000..e523465af
--- /dev/null
+++ b/src/libtommath/mp_div_2d.c
@@ -0,0 +1,61 @@
+#include "tommath_private.h"
+#ifdef MP_DIV_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
+mp_err mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d)
+{
+ mp_err err;
+
+ if (b < 0) {
+ return MP_VAL;
+ }
+
+ if ((err = mp_copy(a, c)) != MP_OKAY) {
+ return err;
+ }
+
+ /* 'a' should not be used after here - it might be the same as d */
+
+ /* get the remainder */
+ if (d != NULL) {
+ if ((err = mp_mod_2d(a, b, d)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= MP_DIGIT_BIT) {
+ mp_rshd(c, b / MP_DIGIT_BIT);
+ }
+
+ /* shift any bit count < MP_DIGIT_BIT */
+ b %= MP_DIGIT_BIT;
+ if (b != 0u) {
+ int x;
+ mp_digit r, mask, shift;
+
+ /* mask */
+ mask = ((mp_digit)1 << b) - 1uL;
+
+ /* shift for lsb */
+ shift = (mp_digit)(MP_DIGIT_BIT - b);
+
+ /* carry */
+ r = 0;
+ for (x = c->used; x --> 0;) {
+ /* get the lower bits of this word in a temp */
+ mp_digit rr = c->dp[x] & mask;
+
+ /* shift the current word and mix in the carry bits from the previous word */
+ c->dp[x] = (c->dp[x] >> b) | (r << shift);
+
+ /* set the carry to the carry bits of the current word found above */
+ r = rr;
+ }
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_div_d.c b/src/libtommath/mp_div_d.c
new file mode 100644
index 000000000..5697e545c
--- /dev/null
+++ b/src/libtommath/mp_div_d.c
@@ -0,0 +1,84 @@
+#include "tommath_private.h"
+#ifdef MP_DIV_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* single digit division (based on routine from MPI) */
+mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d)
+{
+ mp_int q;
+ mp_word w;
+ mp_err err;
+ int ix;
+
+ /* cannot divide by zero */
+ if (b == 0u) {
+ return MP_VAL;
+ }
+
+ /* quick outs */
+ if ((b == 1u) || mp_iszero(a)) {
+ if (d != NULL) {
+ *d = 0;
+ }
+ if (c != NULL) {
+ return mp_copy(a, c);
+ }
+ return MP_OKAY;
+ }
+
+ /* power of two ? */
+ if (MP_HAS(MP_DIV_2) && (b == 2u)) {
+ if (d != NULL) {
+ *d = mp_isodd(a) ? 1u : 0u;
+ }
+ return (c == NULL) ? MP_OKAY : mp_div_2(a, c);
+ }
+ if (MP_HAS(MP_DIV_2D) && MP_IS_2EXPT(b)) {
+ ix = 1;
+ while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<<ix))) {
+ ix++;
+ }
+ if (d != NULL) {
+ *d = a->dp[0] & (((mp_digit)1<<(mp_digit)ix) - 1uL);
+ }
+ return (c == NULL) ? MP_OKAY : mp_div_2d(a, ix, c, NULL);
+ }
+
+ /* three? */
+ if (MP_HAS(S_MP_DIV_3) && (b == 3u)) {
+ return s_mp_div_3(a, c, d);
+ }
+
+ /* no easy answer [c'est la vie]. Just division */
+ if ((err = mp_init_size(&q, a->used)) != MP_OKAY) {
+ return err;
+ }
+
+ q.used = a->used;
+ q.sign = a->sign;
+ w = 0;
+ for (ix = a->used; ix --> 0;) {
+ mp_digit t = 0;
+ w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix];
+ if (w >= b) {
+ t = (mp_digit)(w / b);
+ w -= (mp_word)t * (mp_word)b;
+ }
+ q.dp[ix] = t;
+ }
+
+ if (d != NULL) {
+ *d = (mp_digit)w;
+ }
+
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ }
+ mp_clear(&q);
+
+ return MP_OKAY;
+}
+
+#endif
diff --git a/src/libtommath/mp_dr_is_modulus.c b/src/libtommath/mp_dr_is_modulus.c
new file mode 100644
index 000000000..72b3c9681
--- /dev/null
+++ b/src/libtommath/mp_dr_is_modulus.c
@@ -0,0 +1,27 @@
+#include "tommath_private.h"
+#ifdef MP_DR_IS_MODULUS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines if a number is a valid DR modulus */
+bool mp_dr_is_modulus(const mp_int *a)
+{
+ int ix;
+
+ /* must be at least two digits */
+ if (a->used < 2) {
+ return false;
+ }
+
+ /* must be of the form b**k - a [a <= b] so all
+ * but the first digit must be equal to -1 (mod b).
+ */
+ for (ix = 1; ix < a->used; ix++) {
+ if (a->dp[ix] != MP_MASK) {
+ return false;
+ }
+ }
+ return true;
+}
+
+#endif
diff --git a/src/libtommath/mp_dr_reduce.c b/src/libtommath/mp_dr_reduce.c
new file mode 100644
index 000000000..f0f6f35e6
--- /dev/null
+++ b/src/libtommath/mp_dr_reduce.c
@@ -0,0 +1,68 @@
+#include "tommath_private.h"
+#ifdef MP_DR_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
+ *
+ * Based on algorithm from the paper
+ *
+ * "Generating Efficient Primes for Discrete Log Cryptosystems"
+ * Chae Hoon Lim, Pil Joong Lee,
+ * POSTECH Information Research Laboratories
+ *
+ * The modulus must be of a special format [see manual]
+ *
+ * Has been modified to use algorithm 7.10 from the LTM book instead
+ *
+ * Input x must be in the range 0 <= x <= (n-1)**2
+ */
+mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k)
+{
+ mp_err err;
+
+ /* m = digits in modulus */
+ int m = n->used;
+
+ /* ensure that "x" has at least 2m digits */
+ if ((err = mp_grow(x, m + m)) != MP_OKAY) {
+ return err;
+ }
+
+ /* top of loop, this is where the code resumes if
+ * another reduction pass is required.
+ */
+ for (;;) {
+ int i;
+ mp_digit mu = 0;
+
+ /* compute (x mod B**m) + k * [x/B**m] inline and inplace */
+ for (i = 0; i < m; i++) {
+ mp_word r = ((mp_word)x->dp[i + m] * (mp_word)k) + x->dp[i] + mu;
+ x->dp[i] = (mp_digit)(r & MP_MASK);
+ mu = (mp_digit)(r >> ((mp_word)MP_DIGIT_BIT));
+ }
+
+ /* set final carry */
+ x->dp[i] = mu;
+
+ /* zero words above m */
+ s_mp_zero_digs(x->dp + m + 1, (x->used - m) - 1);
+
+ /* clamp, sub and return */
+ mp_clamp(x);
+
+ /* if x >= n then subtract and reduce again
+ * Each successive "recursion" makes the input smaller and smaller.
+ */
+ if (mp_cmp_mag(x, n) == MP_LT) {
+ break;
+ }
+
+ if ((err = s_mp_sub(x, n, x)) != MP_OKAY) {
+ return err;
+ }
+ }
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_dr_setup.c b/src/libtommath/mp_dr_setup.c
new file mode 100644
index 000000000..c5bb359a3
--- /dev/null
+++ b/src/libtommath/mp_dr_setup.c
@@ -0,0 +1,15 @@
+#include "tommath_private.h"
+#ifdef MP_DR_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines the setup value */
+void mp_dr_setup(const mp_int *a, mp_digit *d)
+{
+ /* the casts are required if MP_DIGIT_BIT is one less than
+ * the number of bits in a mp_digit [e.g. MP_DIGIT_BIT==31]
+ */
+ *d = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - (mp_word)a->dp[0]);
+}
+
+#endif
diff --git a/src/libtommath/mp_error_to_string.c b/src/libtommath/mp_error_to_string.c
new file mode 100644
index 000000000..39adcd124
--- /dev/null
+++ b/src/libtommath/mp_error_to_string.c
@@ -0,0 +1,29 @@
+#include "tommath_private.h"
+#ifdef MP_ERROR_TO_STRING_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* return a char * string for a given code */
+const char *mp_error_to_string(mp_err code)
+{
+ switch (code) {
+ case MP_OKAY:
+ return "Successful";
+ case MP_ERR:
+ return "Unknown error";
+ case MP_MEM:
+ return "Out of heap";
+ case MP_VAL:
+ return "Value out of range";
+ case MP_ITER:
+ return "Max. iterations reached";
+ case MP_BUF:
+ return "Buffer overflow";
+ case MP_OVF:
+ return "Integer overflow";
+ default:
+ return "Invalid error code";
+ }
+}
+
+#endif
diff --git a/src/libtommath/mp_exch.c b/src/libtommath/mp_exch.c
new file mode 100644
index 000000000..50b97d963
--- /dev/null
+++ b/src/libtommath/mp_exch.c
@@ -0,0 +1,13 @@
+#include "tommath_private.h"
+#ifdef MP_EXCH_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* swap the elements of two integers, for cases where you can't simply swap the
+ * mp_int pointers around
+ */
+void mp_exch(mp_int *a, mp_int *b)
+{
+ MP_EXCH(mp_int, *a, *b);
+}
+#endif
diff --git a/src/libtommath/mp_expt_n.c b/src/libtommath/mp_expt_n.c
new file mode 100644
index 000000000..93f9249a7
--- /dev/null
+++ b/src/libtommath/mp_expt_n.c
@@ -0,0 +1,43 @@
+#include "tommath_private.h"
+#ifdef MP_EXPT_N_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* calculate c = a**b using a square-multiply algorithm */
+mp_err mp_expt_n(const mp_int *a, int b, mp_int *c)
+{
+ mp_err err;
+ mp_int g;
+
+ if ((err = mp_init_copy(&g, a)) != MP_OKAY) {
+ return err;
+ }
+
+ /* set initial result */
+ mp_set(c, 1uL);
+
+ while (b > 0) {
+ /* if the bit is set multiply */
+ if ((b & 1) != 0) {
+ if ((err = mp_mul(c, &g, c)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* square */
+ if (b > 1) {
+ if ((err = mp_sqr(&g, &g)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* shift to next bit */
+ b >>= 1;
+ }
+
+LBL_ERR:
+ mp_clear(&g);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_exptmod.c b/src/libtommath/mp_exptmod.c
new file mode 100644
index 000000000..b8a5dccc2
--- /dev/null
+++ b/src/libtommath/mp_exptmod.c
@@ -0,0 +1,78 @@
+#include "tommath_private.h"
+#ifdef MP_EXPTMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions. Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted alot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y)
+{
+ int dr;
+
+ /* modulus P must be positive */
+ if (mp_isneg(P)) {
+ return MP_VAL;
+ }
+
+ /* if exponent X is negative we have to recurse */
+ if (mp_isneg(X)) {
+ mp_int tmpG, tmpX;
+ mp_err err;
+
+ if (!MP_HAS(MP_INVMOD)) {
+ return MP_VAL;
+ }
+
+ if ((err = mp_init_multi(&tmpG, &tmpX, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* first compute 1/G mod P */
+ if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* now get |X| */
+ if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* and now compute (1/G)**|X| instead of G**X [X < 0] */
+ err = mp_exptmod(&tmpG, &tmpX, P, Y);
+LBL_ERR:
+ mp_clear_multi(&tmpG, &tmpX, NULL);
+ return err;
+ }
+
+ /* modified diminished radix reduction */
+ if (MP_HAS(MP_REDUCE_IS_2K_L) && MP_HAS(MP_REDUCE_2K_L) && MP_HAS(S_MP_EXPTMOD) &&
+ mp_reduce_is_2k_l(P)) {
+ return s_mp_exptmod(G, X, P, Y, 1);
+ }
+
+ /* is it a DR modulus? default to no */
+ dr = (MP_HAS(MP_DR_IS_MODULUS) && mp_dr_is_modulus(P)) ? 1 : 0;
+
+ /* if not, is it a unrestricted DR modulus? */
+ if (MP_HAS(MP_REDUCE_IS_2K) && (dr == 0)) {
+ dr = (mp_reduce_is_2k(P)) ? 2 : 0;
+ }
+
+ /* if the modulus is odd or dr != 0 use the montgomery method */
+ if (MP_HAS(S_MP_EXPTMOD_FAST) && (mp_isodd(P) || (dr != 0))) {
+ return s_mp_exptmod_fast(G, X, P, Y, dr);
+ }
+
+ /* otherwise use the generic Barrett reduction technique */
+ if (MP_HAS(S_MP_EXPTMOD)) {
+ return s_mp_exptmod(G, X, P, Y, 0);
+ }
+
+ /* no exptmod for evens */
+ return MP_VAL;
+}
+
+#endif
diff --git a/src/libtommath/mp_exteuclid.c b/src/libtommath/mp_exteuclid.c
new file mode 100644
index 000000000..649c4ca85
--- /dev/null
+++ b/src/libtommath/mp_exteuclid.c
@@ -0,0 +1,72 @@
+#include "tommath_private.h"
+#ifdef MP_EXTEUCLID_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Extended euclidean algorithm of (a, b) produces
+ a*u1 + b*u2 = u3
+ */
+mp_err mp_exteuclid(const mp_int *a, const mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3)
+{
+ mp_int u1, u2, u3, v1, v2, v3, t1, t2, t3, q, tmp;
+ mp_err err;
+
+ if ((err = mp_init_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* initialize, (u1,u2,u3) = (1,0,a) */
+ mp_set(&u1, 1uL);
+ if ((err = mp_copy(a, &u3)) != MP_OKAY) goto LBL_ERR;
+
+ /* initialize, (v1,v2,v3) = (0,1,b) */
+ mp_set(&v2, 1uL);
+ if ((err = mp_copy(b, &v3)) != MP_OKAY) goto LBL_ERR;
+
+ /* loop while v3 != 0 */
+ while (!mp_iszero(&v3)) {
+ /* q = u3/v3 */
+ if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) goto LBL_ERR;
+
+ /* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */
+ if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) goto LBL_ERR;
+
+ /* (u1,u2,u3) = (v1,v2,v3) */
+ if ((err = mp_copy(&v1, &u1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&v2, &u2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&v3, &u3)) != MP_OKAY) goto LBL_ERR;
+
+ /* (v1,v2,v3) = (t1,t2,t3) */
+ if ((err = mp_copy(&t1, &v1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&t2, &v2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&t3, &v3)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* make sure U3 >= 0 */
+ if (mp_isneg(&u3)) {
+ if ((err = mp_neg(&u1, &u1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_neg(&u2, &u2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_neg(&u3, &u3)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* copy result out */
+ if (U1 != NULL) {
+ mp_exch(U1, &u1);
+ }
+ if (U2 != NULL) {
+ mp_exch(U2, &u2);
+ }
+ if (U3 != NULL) {
+ mp_exch(U3, &u3);
+ }
+
+LBL_ERR:
+ mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_fread.c b/src/libtommath/mp_fread.c
new file mode 100644
index 000000000..53c35e822
--- /dev/null
+++ b/src/libtommath/mp_fread.c
@@ -0,0 +1,66 @@
+#include "tommath_private.h"
+#ifdef MP_FREAD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef MP_NO_FILE
+/* read a bigint from a file stream in ASCII */
+mp_err mp_fread(mp_int *a, int radix, FILE *stream)
+{
+ mp_err err;
+ mp_sign sign = MP_ZPOS;
+ int ch;
+
+ /* make sure the radix is ok */
+ if ((radix < 2) || (radix > 64)) {
+ return MP_VAL;
+ }
+
+ /* if first digit is - then set negative */
+ ch = fgetc(stream);
+ if (ch == (int)'-') {
+ sign = MP_NEG;
+ ch = fgetc(stream);
+ }
+
+ /* no digits, return error */
+ if (ch == EOF) {
+ return MP_ERR;
+ }
+
+ /* clear a */
+ mp_zero(a);
+
+ do {
+ uint8_t y;
+ unsigned pos;
+ ch = (radix <= 36) ? MP_TOUPPER(ch) : ch;
+ pos = (unsigned)(ch - (int)'+');
+ if (MP_RADIX_MAP_REVERSE_SIZE <= pos) {
+ break;
+ }
+
+ y = s_mp_radix_map_reverse[pos];
+
+ if (y >= radix) {
+ break;
+ }
+
+ /* shift up and add */
+ if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_add_d(a, y, a)) != MP_OKAY) {
+ return err;
+ }
+ } while ((ch = fgetc(stream)) != EOF);
+
+ if (!mp_iszero(a)) {
+ a->sign = sign;
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+#endif
diff --git a/src/libtommath/mp_from_sbin.c b/src/libtommath/mp_from_sbin.c
new file mode 100644
index 000000000..26eb0f120
--- /dev/null
+++ b/src/libtommath/mp_from_sbin.c
@@ -0,0 +1,21 @@
+#include "tommath_private.h"
+#ifdef MP_FROM_SBIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* read signed bin, big endian, first byte is 0==positive or 1==negative */
+mp_err mp_from_sbin(mp_int *a, const uint8_t *buf, size_t size)
+{
+ mp_err err;
+
+ /* read magnitude */
+ if ((err = mp_from_ubin(a, buf + 1, size - 1u)) != MP_OKAY) {
+ return err;
+ }
+
+ /* first byte is 0 for positive, non-zero for negative */
+ a->sign = (buf[0] != (uint8_t)0) ? MP_NEG : MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_from_ubin.c b/src/libtommath/mp_from_ubin.c
new file mode 100644
index 000000000..8272185b8
--- /dev/null
+++ b/src/libtommath/mp_from_ubin.c
@@ -0,0 +1,30 @@
+#include "tommath_private.h"
+#ifdef MP_FROM_UBIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reads a uint8_t array, assumes the msb is stored first [big endian] */
+mp_err mp_from_ubin(mp_int *a, const uint8_t *buf, size_t size)
+{
+ mp_err err;
+
+ /* make sure there are at least two digits */
+ if ((err = mp_grow(a, 2)) != MP_OKAY) {
+ return err;
+ }
+
+ /* zero the int */
+ mp_zero(a);
+
+ /* read the bytes in */
+ while (size-- > 0u) {
+ if ((err = mp_mul_2d(a, 8, a)) != MP_OKAY) {
+ return err;
+ }
+ a->dp[0] |= *buf++;
+ a->used += 1;
+ }
+ mp_clamp(a);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_fwrite.c b/src/libtommath/mp_fwrite.c
new file mode 100644
index 000000000..3d8141f06
--- /dev/null
+++ b/src/libtommath/mp_fwrite.c
@@ -0,0 +1,33 @@
+#include "tommath_private.h"
+#ifdef MP_FWRITE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef MP_NO_FILE
+mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream)
+{
+ char *buf;
+ mp_err err;
+ size_t size, written;
+
+ if ((err = mp_radix_size_overestimate(a, radix, &size)) != MP_OKAY) {
+ return err;
+ }
+
+ buf = (char *) MP_MALLOC(size);
+ if (buf == NULL) {
+ return MP_MEM;
+ }
+
+ if ((err = mp_to_radix(a, buf, size, &written, radix)) == MP_OKAY) {
+ if (fwrite(buf, written, 1uL, stream) != 1uL) {
+ err = MP_ERR;
+ }
+ }
+
+ MP_FREE_BUF(buf, size);
+ return err;
+}
+#endif
+
+#endif
diff --git a/src/libtommath/mp_gcd.c b/src/libtommath/mp_gcd.c
new file mode 100644
index 000000000..4f6b6cc29
--- /dev/null
+++ b/src/libtommath/mp_gcd.c
@@ -0,0 +1,92 @@
+#include "tommath_private.h"
+#ifdef MP_GCD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Greatest Common Divisor using the binary method */
+mp_err mp_gcd(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int u, v;
+ int k, u_lsb, v_lsb;
+ mp_err err;
+
+ /* either zero than gcd is the largest */
+ if (mp_iszero(a)) {
+ return mp_abs(b, c);
+ }
+ if (mp_iszero(b)) {
+ return mp_abs(a, c);
+ }
+
+ /* get copies of a and b we can modify */
+ if ((err = mp_init_copy(&u, a)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_init_copy(&v, b)) != MP_OKAY) {
+ goto LBL_U;
+ }
+
+ /* must be positive for the remainder of the algorithm */
+ u.sign = v.sign = MP_ZPOS;
+
+ /* B1. Find the common power of two for u and v */
+ u_lsb = mp_cnt_lsb(&u);
+ v_lsb = mp_cnt_lsb(&v);
+ k = MP_MIN(u_lsb, v_lsb);
+
+ if (k > 0) {
+ /* divide the power of two out */
+ if ((err = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+
+ if ((err = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ /* divide any remaining factors of two out */
+ if (u_lsb != k) {
+ if ((err = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ if (v_lsb != k) {
+ if ((err = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ while (!mp_iszero(&v)) {
+ /* make sure v is the largest */
+ if (mp_cmp_mag(&u, &v) == MP_GT) {
+ /* swap u and v to make sure v is >= u */
+ mp_exch(&u, &v);
+ }
+
+ /* subtract smallest from largest */
+ if ((err = s_mp_sub(&v, &u, &v)) != MP_OKAY) {
+ goto LBL_V;
+ }
+
+ /* Divide out all factors of two */
+ if ((err = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ /* multiply by 2**k which we divided out at the beginning */
+ if ((err = mp_mul_2d(&u, k, c)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ c->sign = MP_ZPOS;
+ err = MP_OKAY;
+LBL_V:
+ mp_clear(&u);
+LBL_U:
+ mp_clear(&v);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_get_double.c b/src/libtommath/mp_get_double.c
new file mode 100644
index 000000000..f462eb8e0
--- /dev/null
+++ b/src/libtommath/mp_get_double.c
@@ -0,0 +1,18 @@
+#include "tommath_private.h"
+#ifdef MP_GET_DOUBLE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+double mp_get_double(const mp_int *a)
+{
+ int i;
+ double d = 0.0, fac = 1.0;
+ for (i = 0; i < MP_DIGIT_BIT; ++i) {
+ fac *= 2.0;
+ }
+ for (i = a->used; i --> 0;) {
+ d = (d * fac) + (double)a->dp[i];
+ }
+ return mp_isneg(a) ? -d : d;
+}
+#endif
diff --git a/src/libtommath/mp_get_i32.c b/src/libtommath/mp_get_i32.c
new file mode 100644
index 000000000..6b3b6addf
--- /dev/null
+++ b/src/libtommath/mp_get_i32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_GET_I32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_SIGNED(mp_get_i32, mp_get_mag_u32, int32_t, uint32_t)
+#endif
diff --git a/src/libtommath/mp_get_i64.c b/src/libtommath/mp_get_i64.c
new file mode 100644
index 000000000..8d38a1f25
--- /dev/null
+++ b/src/libtommath/mp_get_i64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_GET_I64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_SIGNED(mp_get_i64, mp_get_mag_u64, int64_t, uint64_t)
+#endif
diff --git a/src/libtommath/mp_get_l.c b/src/libtommath/mp_get_l.c
new file mode 100644
index 000000000..3a1a2f7bc
--- /dev/null
+++ b/src/libtommath/mp_get_l.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_GET_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_SIGNED(mp_get_l, mp_get_mag_ul, long, unsigned long)
+#endif
diff --git a/src/libtommath/mp_get_mag_u32.c b/src/libtommath/mp_get_mag_u32.c
new file mode 100644
index 000000000..acddc5872
--- /dev/null
+++ b/src/libtommath/mp_get_mag_u32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_GET_MAG_U32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_MAG(mp_get_mag_u32, uint32_t)
+#endif
diff --git a/src/libtommath/mp_get_mag_u64.c b/src/libtommath/mp_get_mag_u64.c
new file mode 100644
index 000000000..f75463929
--- /dev/null
+++ b/src/libtommath/mp_get_mag_u64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_GET_MAG_U64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_MAG(mp_get_mag_u64, uint64_t)
+#endif
diff --git a/src/libtommath/mp_get_mag_ul.c b/src/libtommath/mp_get_mag_ul.c
new file mode 100644
index 000000000..5c6043052
--- /dev/null
+++ b/src/libtommath/mp_get_mag_ul.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_GET_MAG_UL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_MAG(mp_get_mag_ul, unsigned long)
+#endif
diff --git a/src/libtommath/mp_grow.c b/src/libtommath/mp_grow.c
new file mode 100644
index 000000000..5bca1b5ff
--- /dev/null
+++ b/src/libtommath/mp_grow.c
@@ -0,0 +1,40 @@
+#include "tommath_private.h"
+#ifdef MP_GROW_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* grow as required */
+mp_err mp_grow(mp_int *a, int size)
+{
+ /* if the alloc size is smaller alloc more ram */
+ if (a->alloc < size) {
+ mp_digit *dp;
+
+ if (size > MP_MAX_DIGIT_COUNT) {
+ return MP_OVF;
+ }
+
+ /* reallocate the array a->dp
+ *
+ * We store the return in a temporary variable
+ * in case the operation failed we don't want
+ * to overwrite the dp member of a.
+ */
+ dp = (mp_digit *) MP_REALLOC(a->dp,
+ (size_t)a->alloc * sizeof(mp_digit),
+ (size_t)size * sizeof(mp_digit));
+ if (dp == NULL) {
+ /* reallocation failed but "a" is still valid [can be freed] */
+ return MP_MEM;
+ }
+
+ /* reallocation succeeded so set a->dp */
+ a->dp = dp;
+
+ /* zero excess digits */
+ s_mp_zero_digs(a->dp + a->alloc, size - a->alloc);
+ a->alloc = size;
+ }
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_init.c b/src/libtommath/mp_init.c
new file mode 100644
index 000000000..af1674481
--- /dev/null
+++ b/src/libtommath/mp_init.c
@@ -0,0 +1,23 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* init a new mp_int */
+mp_err mp_init(mp_int *a)
+{
+ /* allocate memory required and clear it */
+ a->dp = (mp_digit *) MP_CALLOC((size_t)MP_DEFAULT_DIGIT_COUNT, sizeof(mp_digit));
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the used to zero, allocated digits to the default precision
+ * and sign to positive */
+ a->used = 0;
+ a->alloc = MP_DEFAULT_DIGIT_COUNT;
+ a->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_init_copy.c b/src/libtommath/mp_init_copy.c
new file mode 100644
index 000000000..4d0773bad
--- /dev/null
+++ b/src/libtommath/mp_init_copy.c
@@ -0,0 +1,21 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_COPY_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* creates "a" then copies b into it */
+mp_err mp_init_copy(mp_int *a, const mp_int *b)
+{
+ mp_err err;
+
+ if ((err = mp_init_size(a, b->used)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_copy(b, a)) != MP_OKAY) {
+ mp_clear(a);
+ }
+
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_init_i32.c b/src/libtommath/mp_init_i32.c
new file mode 100644
index 000000000..434788f8c
--- /dev/null
+++ b/src/libtommath/mp_init_i32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_I32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_i32, mp_set_i32, int32_t)
+#endif
diff --git a/src/libtommath/mp_init_i64.c b/src/libtommath/mp_init_i64.c
new file mode 100644
index 000000000..718567809
--- /dev/null
+++ b/src/libtommath/mp_init_i64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_I64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_i64, mp_set_i64, int64_t)
+#endif
diff --git a/src/libtommath/mp_init_l.c b/src/libtommath/mp_init_l.c
new file mode 100644
index 000000000..16be8f63f
--- /dev/null
+++ b/src/libtommath/mp_init_l.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_l, mp_set_l, long)
+#endif
diff --git a/src/libtommath/mp_init_multi.c b/src/libtommath/mp_init_multi.c
new file mode 100644
index 000000000..908b4df45
--- /dev/null
+++ b/src/libtommath/mp_init_multi.c
@@ -0,0 +1,41 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_MULTI_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include <stdarg.h>
+
+mp_err mp_init_multi(mp_int *mp, ...)
+{
+ mp_err err = MP_OKAY;
+ int n = 0; /* Number of ok inits */
+ mp_int *cur_arg = mp;
+ va_list args;
+
+ va_start(args, mp); /* init args to next argument from caller */
+ while (cur_arg != NULL) {
+ err = mp_init(cur_arg);
+ if (err != MP_OKAY) {
+ /* Oops - error! Back-track and mp_clear what we already
+ succeeded in init-ing, then return error.
+ */
+ va_list clean_args;
+
+ /* now start cleaning up */
+ cur_arg = mp;
+ va_start(clean_args, mp);
+ while (n-- != 0) {
+ mp_clear(cur_arg);
+ cur_arg = va_arg(clean_args, mp_int *);
+ }
+ va_end(clean_args);
+ break;
+ }
+ n++;
+ cur_arg = va_arg(args, mp_int *);
+ }
+ va_end(args);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_init_set.c b/src/libtommath/mp_init_set.c
new file mode 100644
index 000000000..e1f2ee94d
--- /dev/null
+++ b/src/libtommath/mp_init_set.c
@@ -0,0 +1,16 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_SET_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* initialize and set a digit */
+mp_err mp_init_set(mp_int *a, mp_digit b)
+{
+ mp_err err;
+ if ((err = mp_init(a)) != MP_OKAY) {
+ return err;
+ }
+ mp_set(a, b);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_init_size.c b/src/libtommath/mp_init_size.c
new file mode 100644
index 000000000..e28a3cd49
--- /dev/null
+++ b/src/libtommath/mp_init_size.c
@@ -0,0 +1,28 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* init an mp_init for a given size */
+mp_err mp_init_size(mp_int *a, int size)
+{
+ size = MP_MAX(MP_MIN_DIGIT_COUNT, size);
+
+ if (size > MP_MAX_DIGIT_COUNT) {
+ return MP_OVF;
+ }
+
+ /* alloc mem */
+ a->dp = (mp_digit *) MP_CALLOC((size_t)size, sizeof(mp_digit));
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the members */
+ a->used = 0;
+ a->alloc = size;
+ a->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_init_u32.c b/src/libtommath/mp_init_u32.c
new file mode 100644
index 000000000..d5a2b8f82
--- /dev/null
+++ b/src/libtommath/mp_init_u32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_U32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_u32, mp_set_u32, uint32_t)
+#endif
diff --git a/src/libtommath/mp_init_u64.c b/src/libtommath/mp_init_u64.c
new file mode 100644
index 000000000..ca7508405
--- /dev/null
+++ b/src/libtommath/mp_init_u64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_U64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_u64, mp_set_u64, uint64_t)
+#endif
diff --git a/src/libtommath/mp_init_ul.c b/src/libtommath/mp_init_ul.c
new file mode 100644
index 000000000..21ca3be51
--- /dev/null
+++ b/src/libtommath/mp_init_ul.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_INIT_UL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_ul, mp_set_ul, unsigned long)
+#endif
diff --git a/src/libtommath/mp_invmod.c b/src/libtommath/mp_invmod.c
new file mode 100644
index 000000000..2494acbf6
--- /dev/null
+++ b/src/libtommath/mp_invmod.c
@@ -0,0 +1,29 @@
+#include "tommath_private.h"
+#ifdef MP_INVMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* hac 14.61, pp608 */
+mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ /* for all n in N and n > 0, n = 0 mod 1 */
+ if (!mp_isneg(a) && mp_cmp_d(b, 1uL) == MP_EQ) {
+ mp_zero(c);
+ return MP_OKAY;
+ }
+
+ /* b cannot be negative and has to be >1 */
+ if (mp_isneg(b) || (mp_cmp_d(b, 1uL) != MP_GT)) {
+ return MP_VAL;
+ }
+
+ /* if the modulus is odd we can use a faster routine instead */
+ if (MP_HAS(S_MP_INVMOD_ODD) && mp_isodd(b)) {
+ return s_mp_invmod_odd(a, b, c);
+ }
+
+ return MP_HAS(S_MP_INVMOD)
+ ? s_mp_invmod(a, b, c)
+ : MP_VAL;
+}
+#endif
diff --git a/src/libtommath/mp_is_square.c b/src/libtommath/mp_is_square.c
new file mode 100644
index 000000000..db1cb3fb3
--- /dev/null
+++ b/src/libtommath/mp_is_square.c
@@ -0,0 +1,93 @@
+#include "tommath_private.h"
+#ifdef MP_IS_SQUARE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Check if remainders are possible squares - fast exclude non-squares */
+static const char rem_128[128] = {
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1
+};
+
+static const char rem_105[105] = {
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1
+};
+
+/* Store non-zero to ret if arg is square, and zero if not */
+mp_err mp_is_square(const mp_int *arg, bool *ret)
+{
+ mp_err err;
+ mp_digit c;
+ mp_int t;
+ uint32_t r;
+
+ /* Default to Non-square :) */
+ *ret = false;
+
+ if (mp_isneg(arg)) {
+ return MP_VAL;
+ }
+
+ if (mp_iszero(arg)) {
+ return MP_OKAY;
+ }
+
+ /* First check mod 128 (suppose that MP_DIGIT_BIT is at least 7) */
+ if (rem_128[127u & arg->dp[0]] == (char)1) {
+ return MP_OKAY;
+ }
+
+ /* Next check mod 105 (3*5*7) */
+ if ((err = mp_mod_d(arg, 105uL, &c)) != MP_OKAY) {
+ return err;
+ }
+ if (rem_105[c] == (char)1) {
+ return MP_OKAY;
+ }
+
+
+ if ((err = mp_init_u32(&t, 11u*13u*17u*19u*23u*29u*31u)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_mod(arg, &t, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ r = mp_get_u32(&t);
+ /* Check for other prime modules, note it's not an ERROR but we must
+ * free "t" so the easiest way is to goto LBL_ERR. We know that err
+ * is already equal to MP_OKAY from the mp_mod call
+ */
+ if (((1uL<<(r%11uL)) & 0x5C4uL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%13uL)) & 0x9E4uL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%17uL)) & 0x5CE8uL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%19uL)) & 0x4F50CuL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%23uL)) & 0x7ACCA0uL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%29uL)) & 0xC2EDD0CuL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%31uL)) & 0x6DE2B848uL) != 0uL) goto LBL_ERR;
+
+ /* Final check - is sqr(sqrt(arg)) == arg ? */
+ if ((err = mp_sqrt(arg, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_sqr(&t, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ *ret = (mp_cmp_mag(&t, arg) == MP_EQ);
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_kronecker.c b/src/libtommath/mp_kronecker.c
new file mode 100644
index 000000000..e6bedc891
--- /dev/null
+++ b/src/libtommath/mp_kronecker.c
@@ -0,0 +1,129 @@
+#include "tommath_private.h"
+#ifdef MP_KRONECKER_C
+
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ Kronecker symbol (a|p)
+ Straightforward implementation of algorithm 1.4.10 in
+ Henri Cohen: "A Course in Computational Algebraic Number Theory"
+
+ @book{cohen2013course,
+ title={A course in computational algebraic number theory},
+ author={Cohen, Henri},
+ volume={138},
+ year={2013},
+ publisher={Springer Science \& Business Media}
+ }
+ */
+mp_err mp_kronecker(const mp_int *a, const mp_int *p, int *c)
+{
+ mp_int a1, p1, r;
+ mp_err err;
+ int v, k;
+
+ static const char table[] = {0, 1, 0, -1, 0, -1, 0, 1};
+
+ if (mp_iszero(p)) {
+ if ((a->used == 1) && (a->dp[0] == 1u)) {
+ *c = 1;
+ } else {
+ *c = 0;
+ }
+ return MP_OKAY;
+ }
+
+ if (mp_iseven(a) && mp_iseven(p)) {
+ *c = 0;
+ return MP_OKAY;
+ }
+
+ if ((err = mp_init_copy(&a1, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_init_copy(&p1, p)) != MP_OKAY) {
+ goto LBL_KRON_0;
+ }
+
+ v = mp_cnt_lsb(&p1);
+ if ((err = mp_div_2d(&p1, v, &p1, NULL)) != MP_OKAY) {
+ goto LBL_KRON_1;
+ }
+
+ if ((v & 1) == 0) {
+ k = 1;
+ } else {
+ k = table[a->dp[0] & 7u];
+ }
+
+ if (mp_isneg(&p1)) {
+ p1.sign = MP_ZPOS;
+ if (mp_isneg(&a1)) {
+ k = -k;
+ }
+ }
+
+ if ((err = mp_init(&r)) != MP_OKAY) {
+ goto LBL_KRON_1;
+ }
+
+ for (;;) {
+ if (mp_iszero(&a1)) {
+ if (mp_cmp_d(&p1, 1uL) == MP_EQ) {
+ *c = k;
+ goto LBL_KRON;
+ } else {
+ *c = 0;
+ goto LBL_KRON;
+ }
+ }
+
+ v = mp_cnt_lsb(&a1);
+ if ((err = mp_div_2d(&a1, v, &a1, NULL)) != MP_OKAY) {
+ goto LBL_KRON;
+ }
+
+ if ((v & 1) == 1) {
+ k = k * table[p1.dp[0] & 7u];
+ }
+
+ if (mp_isneg(&a1)) {
+ /*
+ * Compute k = (-1)^((a1)*(p1-1)/4) * k
+ * a1.dp[0] + 1 cannot overflow because the MSB
+ * of the type mp_digit is not set by definition
+ */
+ if (((a1.dp[0] + 1u) & p1.dp[0] & 2u) != 0u) {
+ k = -k;
+ }
+ } else {
+ /* compute k = (-1)^((a1-1)*(p1-1)/4) * k */
+ if ((a1.dp[0] & p1.dp[0] & 2u) != 0u) {
+ k = -k;
+ }
+ }
+
+ if ((err = mp_copy(&a1, &r)) != MP_OKAY) {
+ goto LBL_KRON;
+ }
+ r.sign = MP_ZPOS;
+ if ((err = mp_mod(&p1, &r, &a1)) != MP_OKAY) {
+ goto LBL_KRON;
+ }
+ if ((err = mp_copy(&r, &p1)) != MP_OKAY) {
+ goto LBL_KRON;
+ }
+ }
+
+LBL_KRON:
+ mp_clear(&r);
+LBL_KRON_1:
+ mp_clear(&p1);
+LBL_KRON_0:
+ mp_clear(&a1);
+
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_lcm.c b/src/libtommath/mp_lcm.c
new file mode 100644
index 000000000..f2044f0e5
--- /dev/null
+++ b/src/libtommath/mp_lcm.c
@@ -0,0 +1,44 @@
+#include "tommath_private.h"
+#ifdef MP_LCM_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes least common multiple as |a*b|/(a, b) */
+mp_err mp_lcm(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_err err;
+ mp_int t1, t2;
+
+
+ if ((err = mp_init_multi(&t1, &t2, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* t1 = get the GCD of the two inputs */
+ if ((err = mp_gcd(a, b, &t1)) != MP_OKAY) {
+ goto LBL_T;
+ }
+
+ /* divide the smallest by the GCD */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ /* store quotient in t2 such that t2 * b is the LCM */
+ if ((err = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_T;
+ }
+ err = mp_mul(b, &t2, c);
+ } else {
+ /* store quotient in t2 such that t2 * a is the LCM */
+ if ((err = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_T;
+ }
+ err = mp_mul(a, &t2, c);
+ }
+
+ /* fix the sign to positive */
+ c->sign = MP_ZPOS;
+
+LBL_T:
+ mp_clear_multi(&t1, &t2, NULL);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_log_n.c b/src/libtommath/mp_log_n.c
new file mode 100644
index 000000000..4de1e3993
--- /dev/null
+++ b/src/libtommath/mp_log_n.c
@@ -0,0 +1,29 @@
+#include "tommath_private.h"
+#ifdef MP_LOG_N_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_err mp_log_n(const mp_int *a, int base, int *c)
+{
+ if (mp_isneg(a) || mp_iszero(a) || (base < 2) || (unsigned)base > (unsigned)MP_DIGIT_MAX) {
+ return MP_VAL;
+ }
+
+ if (MP_HAS(S_MP_LOG_2EXPT) && MP_IS_2EXPT((mp_digit)base)) {
+ *c = s_mp_log_2expt(a, (mp_digit)base);
+ return MP_OKAY;
+ }
+
+ if (MP_HAS(S_MP_LOG_D) && (a->used == 1)) {
+ *c = s_mp_log_d((mp_digit)base, a->dp[0]);
+ return MP_OKAY;
+ }
+
+ if (MP_HAS(S_MP_LOG)) {
+ return s_mp_log(a, (mp_digit)base, c);
+ }
+
+ return MP_VAL;
+}
+
+#endif
diff --git a/src/libtommath/mp_lshd.c b/src/libtommath/mp_lshd.c
new file mode 100644
index 000000000..bfa8af88b
--- /dev/null
+++ b/src/libtommath/mp_lshd.c
@@ -0,0 +1,42 @@
+#include "tommath_private.h"
+#ifdef MP_LSHD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift left a certain amount of digits */
+mp_err mp_lshd(mp_int *a, int b)
+{
+ mp_err err;
+ int x;
+
+ /* if its less than zero return */
+ if (b <= 0) {
+ return MP_OKAY;
+ }
+ /* no need to shift 0 around */
+ if (mp_iszero(a)) {
+ return MP_OKAY;
+ }
+
+ /* grow to fit the new digits */
+ if ((err = mp_grow(a, a->used + b)) != MP_OKAY) {
+ return err;
+ }
+
+ /* increment the used by the shift amount then copy upwards */
+ a->used += b;
+
+ /* much like mp_rshd this is implemented using a sliding window
+ * except the window goes the otherway around. Copying from
+ * the bottom to the top. see mp_rshd.c for more info.
+ */
+ for (x = a->used; x --> b;) {
+ a->dp[x] = a->dp[x - b];
+ }
+
+ /* zero the lower digits */
+ s_mp_zero_digs(a->dp, b);
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_mod.c b/src/libtommath/mp_mod.c
new file mode 100644
index 000000000..beae13e72
--- /dev/null
+++ b/src/libtommath/mp_mod.c
@@ -0,0 +1,15 @@
+#include "tommath_private.h"
+#ifdef MP_MOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* c = a mod b, 0 <= c < b if b > 0, b < c <= 0 if b < 0 */
+mp_err mp_mod(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_err err;
+ if ((err = mp_div(a, b, NULL, c)) != MP_OKAY) {
+ return err;
+ }
+ return mp_iszero(c) || (c->sign == b->sign) ? MP_OKAY : mp_add(b, c, c);
+}
+#endif
diff --git a/src/libtommath/mp_mod_2d.c b/src/libtommath/mp_mod_2d.c
new file mode 100644
index 000000000..82c64f05f
--- /dev/null
+++ b/src/libtommath/mp_mod_2d.c
@@ -0,0 +1,40 @@
+#include "tommath_private.h"
+#ifdef MP_MOD_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* calc a value mod 2**b */
+mp_err mp_mod_2d(const mp_int *a, int b, mp_int *c)
+{
+ int x;
+ mp_err err;
+
+ if (b < 0) {
+ return MP_VAL;
+ }
+
+ if (b == 0) {
+ mp_zero(c);
+ return MP_OKAY;
+ }
+
+ /* if the modulus is larger than the value than return */
+ if (b >= (a->used * MP_DIGIT_BIT)) {
+ return mp_copy(a, c);
+ }
+
+ if ((err = mp_copy(a, c)) != MP_OKAY) {
+ return err;
+ }
+
+ /* zero digits above the last digit of the modulus */
+ x = (b / MP_DIGIT_BIT) + (((b % MP_DIGIT_BIT) == 0) ? 0 : 1);
+ s_mp_zero_digs(c->dp + x, c->used - x);
+
+ /* clear the digit that is not completely outside/inside the modulus */
+ c->dp[b / MP_DIGIT_BIT] &=
+ ((mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT)) - (mp_digit)1;
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_montgomery_calc_normalization.c b/src/libtommath/mp_montgomery_calc_normalization.c
new file mode 100644
index 000000000..cc07799dc
--- /dev/null
+++ b/src/libtommath/mp_montgomery_calc_normalization.c
@@ -0,0 +1,43 @@
+#include "tommath_private.h"
+#ifdef MP_MONTGOMERY_CALC_NORMALIZATION_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ * shifts with subtractions when the result is greater than b.
+ *
+ * The method is slightly modified to shift B unconditionally upto just under
+ * the leading bit of b. This saves alot of multiple precision shifting.
+ */
+mp_err mp_montgomery_calc_normalization(mp_int *a, const mp_int *b)
+{
+ int x, bits;
+ mp_err err;
+
+ /* how many bits of last digit does b use */
+ bits = mp_count_bits(b) % MP_DIGIT_BIT;
+
+ if (b->used > 1) {
+ if ((err = mp_2expt(a, ((b->used - 1) * MP_DIGIT_BIT) + bits - 1)) != MP_OKAY) {
+ return err;
+ }
+ } else {
+ mp_set(a, 1uL);
+ bits = 1;
+ }
+
+ /* now compute C = A * B mod b */
+ for (x = bits - 1; x < (int)MP_DIGIT_BIT; x++) {
+ if ((err = mp_mul_2(a, a)) != MP_OKAY) {
+ return err;
+ }
+ if (mp_cmp_mag(a, b) != MP_LT) {
+ if ((err = s_mp_sub(a, b, a)) != MP_OKAY) {
+ return err;
+ }
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_montgomery_reduce.c b/src/libtommath/mp_montgomery_reduce.c
new file mode 100644
index 000000000..dbf45d3cf
--- /dev/null
+++ b/src/libtommath/mp_montgomery_reduce.c
@@ -0,0 +1,89 @@
+#include "tommath_private.h"
+#ifdef MP_MONTGOMERY_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction */
+mp_err mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho)
+{
+ mp_err err;
+ int ix, digs;
+
+ /* can the fast reduction [comba] method be used?
+ *
+ * Note that unlike in mul you're safely allowed *less*
+ * than the available columns [255 per default] since carries
+ * are fixed up in the inner loop.
+ */
+ digs = (n->used * 2) + 1;
+ if ((digs < MP_WARRAY) &&
+ (x->used <= MP_WARRAY) &&
+ (n->used < MP_MAX_COMBA)) {
+ return s_mp_montgomery_reduce_comba(x, n, rho);
+ }
+
+ /* grow the input as required */
+ if ((err = mp_grow(x, digs)) != MP_OKAY) {
+ return err;
+ }
+ x->used = digs;
+
+ for (ix = 0; ix < n->used; ix++) {
+ int iy;
+ mp_digit u, mu;
+
+ /* mu = ai * rho mod b
+ *
+ * The value of rho must be precalculated via
+ * montgomery_setup() such that
+ * it equals -1/n0 mod b this allows the
+ * following inner loop to reduce the
+ * input one digit at a time
+ */
+ mu = (mp_digit)(((mp_word)x->dp[ix] * (mp_word)rho) & MP_MASK);
+
+ /* a = a + mu * m * b**i */
+
+ /* Multiply and add in place */
+ u = 0;
+ for (iy = 0; iy < n->used; iy++) {
+ /* compute product and sum */
+ mp_word r = ((mp_word)mu * (mp_word)n->dp[iy]) +
+ (mp_word)u + (mp_word)x->dp[ix + iy];
+
+ /* get carry */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+
+ /* fix digit */
+ x->dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK);
+ }
+ /* At this point the ix'th digit of x should be zero */
+
+ /* propagate carries upwards as required*/
+ while (u != 0u) {
+ x->dp[ix + iy] += u;
+ u = x->dp[ix + iy] >> MP_DIGIT_BIT;
+ x->dp[ix + iy] &= MP_MASK;
+ ++iy;
+ }
+ }
+
+ /* at this point the n.used'th least
+ * significant digits of x are all zero
+ * which means we can shift x to the
+ * right by n.used digits and the
+ * residue is unchanged.
+ */
+
+ /* x = x/b**n.used */
+ mp_clamp(x);
+ mp_rshd(x, n->used);
+
+ /* if x >= n then x = x - n */
+ if (mp_cmp_mag(x, n) != MP_LT) {
+ return s_mp_sub(x, n, x);
+ }
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_montgomery_setup.c b/src/libtommath/mp_montgomery_setup.c
new file mode 100644
index 000000000..de57dc342
--- /dev/null
+++ b/src/libtommath/mp_montgomery_setup.c
@@ -0,0 +1,40 @@
+#include "tommath_private.h"
+#ifdef MP_MONTGOMERY_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* setups the montgomery reduction stuff */
+mp_err mp_montgomery_setup(const mp_int *n, mp_digit *rho)
+{
+ mp_digit x, b;
+
+ /* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
+ * => 2*X*A - X*X*A*A = 1
+ * => 2*(1) - (1) = 1
+ */
+ b = n->dp[0];
+
+ if ((b & 1u) == 0u) {
+ return MP_VAL;
+ }
+
+ x = (((b + 2u) & 4u) << 1) + b; /* here x*a==1 mod 2**4 */
+ x *= 2u - (b * x); /* here x*a==1 mod 2**8 */
+ x *= 2u - (b * x); /* here x*a==1 mod 2**16 */
+#if defined(MP_64BIT) || !(defined(MP_16BIT))
+ x *= 2u - (b * x); /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+ x *= 2u - (b * x); /* here x*a==1 mod 2**64 */
+#endif
+
+ /* rho = -1/m mod b */
+ *rho = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - x) & MP_MASK;
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_mul.c b/src/libtommath/mp_mul.c
new file mode 100644
index 000000000..d35fa8ef4
--- /dev/null
+++ b/src/libtommath/mp_mul.c
@@ -0,0 +1,68 @@
+#include "tommath_private.h"
+#ifdef MP_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* high level multiplication (handles sign) */
+mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_err err;
+ int min = MP_MIN(a->used, b->used),
+ max = MP_MAX(a->used, b->used),
+ digs = a->used + b->used + 1;
+ bool neg = (a->sign != b->sign);
+
+ if ((a == b) &&
+ MP_HAS(S_MP_SQR_TOOM) && /* use Toom-Cook? */
+ (a->used >= MP_SQR_TOOM_CUTOFF)) {
+ err = s_mp_sqr_toom(a, c);
+ } else if ((a == b) &&
+ MP_HAS(S_MP_SQR_KARATSUBA) && /* Karatsuba? */
+ (a->used >= MP_SQR_KARATSUBA_CUTOFF)) {
+ err = s_mp_sqr_karatsuba(a, c);
+ } else if ((a == b) &&
+ MP_HAS(S_MP_SQR_COMBA) && /* can we use the fast comba multiplier? */
+ (((a->used * 2) + 1) < MP_WARRAY) &&
+ (a->used < (MP_MAX_COMBA / 2))) {
+ err = s_mp_sqr_comba(a, c);
+ } else if ((a == b) &&
+ MP_HAS(S_MP_SQR)) {
+ err = s_mp_sqr(a, c);
+ } else if (MP_HAS(S_MP_MUL_BALANCE) &&
+ /* Check sizes. The smaller one needs to be larger than the Karatsuba cut-off.
+ * The bigger one needs to be at least about one MP_MUL_KARATSUBA_CUTOFF bigger
+ * to make some sense, but it depends on architecture, OS, position of the
+ * stars... so YMMV.
+ * Using it to cut the input into slices small enough for s_mp_mul_comba
+ * was actually slower on the author's machine, but YMMV.
+ */
+ (min >= MP_MUL_KARATSUBA_CUTOFF) &&
+ ((max / 2) >= MP_MUL_KARATSUBA_CUTOFF) &&
+ /* Not much effect was observed below a ratio of 1:2, but again: YMMV. */
+ (max >= (2 * min))) {
+ err = s_mp_mul_balance(a,b,c);
+ } else if (MP_HAS(S_MP_MUL_TOOM) &&
+ (min >= MP_MUL_TOOM_CUTOFF)) {
+ err = s_mp_mul_toom(a, b, c);
+ } else if (MP_HAS(S_MP_MUL_KARATSUBA) &&
+ (min >= MP_MUL_KARATSUBA_CUTOFF)) {
+ err = s_mp_mul_karatsuba(a, b, c);
+ } else if (MP_HAS(S_MP_MUL_COMBA) &&
+ /* can we use the fast multiplier?
+ *
+ * The fast multiplier can be used if the output will
+ * have less than MP_WARRAY digits and the number of
+ * digits won't affect carry propagation
+ */
+ (digs < MP_WARRAY) &&
+ (min <= MP_MAX_COMBA)) {
+ err = s_mp_mul_comba(a, b, c, digs);
+ } else if (MP_HAS(S_MP_MUL)) {
+ err = s_mp_mul(a, b, c, digs);
+ } else {
+ err = MP_VAL;
+ }
+ c->sign = ((c->used > 0) && neg) ? MP_NEG : MP_ZPOS;
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_mul_2.c b/src/libtommath/mp_mul_2.c
new file mode 100644
index 000000000..7d7084b31
--- /dev/null
+++ b/src/libtommath/mp_mul_2.c
@@ -0,0 +1,53 @@
+#include "tommath_private.h"
+#ifdef MP_MUL_2_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = a*2 */
+mp_err mp_mul_2(const mp_int *a, mp_int *b)
+{
+ mp_err err;
+ int x, oldused;
+ mp_digit r;
+
+ /* grow to accomodate result */
+ if ((err = mp_grow(b, a->used + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < a->used; x++) {
+
+ /* get what will be the *next* carry bit from the
+ * MSB of the current digit
+ */
+ mp_digit rr = a->dp[x] >> (mp_digit)(MP_DIGIT_BIT - 1);
+
+ /* now shift up this digit, add in the carry [from the previous] */
+ b->dp[x] = ((a->dp[x] << 1uL) | r) & MP_MASK;
+
+ /* copy the carry that would be from the source
+ * digit into the next iteration
+ */
+ r = rr;
+ }
+
+ /* new leading digit? */
+ if (r != 0u) {
+ /* add a MSB which is always 1 at this point */
+ b->dp[b->used++] = 1;
+ }
+
+ /* now zero any excess digits on the destination
+ * that we didn't write to
+ */
+ s_mp_zero_digs(b->dp + b->used, oldused - b->used);
+
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_mul_2d.c b/src/libtommath/mp_mul_2d.c
new file mode 100644
index 000000000..e4581375b
--- /dev/null
+++ b/src/libtommath/mp_mul_2d.c
@@ -0,0 +1,63 @@
+#include "tommath_private.h"
+#ifdef MP_MUL_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift left by a certain bit count */
+mp_err mp_mul_2d(const mp_int *a, int b, mp_int *c)
+{
+ mp_err err;
+
+ if (b < 0) {
+ return MP_VAL;
+ }
+
+ if ((err = mp_copy(a, c)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_grow(c, c->used + (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= MP_DIGIT_BIT) {
+ if ((err = mp_lshd(c, b / MP_DIGIT_BIT)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* shift any bit count < MP_DIGIT_BIT */
+ b %= MP_DIGIT_BIT;
+ if (b != 0u) {
+ mp_digit shift, mask, r;
+ int x;
+
+ /* bitmask for carries */
+ mask = ((mp_digit)1 << b) - (mp_digit)1;
+
+ /* shift for msbs */
+ shift = (mp_digit)(MP_DIGIT_BIT - b);
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < c->used; x++) {
+ /* get the higher bits of the current word */
+ mp_digit rr = (c->dp[x] >> shift) & mask;
+
+ /* shift the current word and OR in the carry */
+ c->dp[x] = ((c->dp[x] << b) | r) & MP_MASK;
+
+ /* set the carry to the carry bits of the current word */
+ r = rr;
+ }
+
+ /* set final carry */
+ if (r != 0u) {
+ c->dp[(c->used)++] = r;
+ }
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_mul_d.c b/src/libtommath/mp_mul_d.c
new file mode 100644
index 000000000..258505543
--- /dev/null
+++ b/src/libtommath/mp_mul_d.c
@@ -0,0 +1,68 @@
+#include "tommath_private.h"
+#ifdef MP_MUL_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* multiply by a digit */
+mp_err mp_mul_d(const mp_int *a, mp_digit b, mp_int *c)
+{
+ mp_digit u;
+ mp_err err;
+ int ix, oldused;
+
+ if (b == 1u) {
+ return mp_copy(a, c);
+ }
+
+ /* power of two ? */
+ if (MP_HAS(MP_MUL_2) && (b == 2u)) {
+ return mp_mul_2(a, c);
+ }
+ if (MP_HAS(MP_MUL_2D) && MP_IS_2EXPT(b)) {
+ ix = 1;
+ while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<<ix))) {
+ ix++;
+ }
+ return mp_mul_2d(a, ix, c);
+ }
+
+ /* make sure c is big enough to hold a*b */
+ if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* get the original destinations used count */
+ oldused = c->used;
+
+ /* set the sign */
+ c->sign = a->sign;
+
+ /* zero carry */
+ u = 0;
+
+ /* compute columns */
+ for (ix = 0; ix < a->used; ix++) {
+ /* compute product and carry sum for this term */
+ mp_word r = (mp_word)u + ((mp_word)a->dp[ix] * (mp_word)b);
+
+ /* mask off higher bits to get a single digit */
+ c->dp[ix] = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* send carry into next iteration */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ }
+
+ /* store final carry [if any] and increment ix offset */
+ c->dp[ix] = u;
+
+ /* set used count */
+ c->used = a->used + 1;
+
+ /* now zero digits above the top */
+ s_mp_zero_digs(c->dp + c->used, oldused - c->used);
+
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_mulmod.c b/src/libtommath/mp_mulmod.c
new file mode 100644
index 000000000..e158693b9
--- /dev/null
+++ b/src/libtommath/mp_mulmod.c
@@ -0,0 +1,15 @@
+#include "tommath_private.h"
+#ifdef MP_MULMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* d = a * b (mod c) */
+mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d)
+{
+ mp_err err;
+ if ((err = mp_mul(a, b, d)) != MP_OKAY) {
+ return err;
+ }
+ return mp_mod(d, c, d);
+}
+#endif
diff --git a/src/libtommath/mp_neg.c b/src/libtommath/mp_neg.c
new file mode 100644
index 000000000..b445cd409
--- /dev/null
+++ b/src/libtommath/mp_neg.c
@@ -0,0 +1,18 @@
+#include "tommath_private.h"
+#ifdef MP_NEG_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = -a */
+mp_err mp_neg(const mp_int *a, mp_int *b)
+{
+ mp_err err;
+ if ((err = mp_copy(a, b)) != MP_OKAY) {
+ return err;
+ }
+
+ b->sign = ((!mp_iszero(b) && !mp_isneg(b)) ? MP_NEG : MP_ZPOS);
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_or.c b/src/libtommath/mp_or.c
new file mode 100644
index 000000000..15958524e
--- /dev/null
+++ b/src/libtommath/mp_or.c
@@ -0,0 +1,54 @@
+#include "tommath_private.h"
+#ifdef MP_OR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* two complement or */
+mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int used = MP_MAX(a->used, b->used) + 1, i;
+ mp_err err;
+ mp_digit ac = 1, bc = 1, cc = 1;
+ bool neg = (mp_isneg(a) || mp_isneg(b));
+
+ if ((err = mp_grow(c, used)) != MP_OKAY) {
+ return err;
+ }
+
+ for (i = 0; i < used; i++) {
+ mp_digit x, y;
+
+ /* convert to two complement if negative */
+ if (mp_isneg(a)) {
+ ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
+ x = ac & MP_MASK;
+ ac >>= MP_DIGIT_BIT;
+ } else {
+ x = (i >= a->used) ? 0uL : a->dp[i];
+ }
+
+ /* convert to two complement if negative */
+ if (mp_isneg(b)) {
+ bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
+ y = bc & MP_MASK;
+ bc >>= MP_DIGIT_BIT;
+ } else {
+ y = (i >= b->used) ? 0uL : b->dp[i];
+ }
+
+ c->dp[i] = x | y;
+
+ /* convert to to sign-magnitude if negative */
+ if (neg) {
+ cc += ~c->dp[i] & MP_MASK;
+ c->dp[i] = cc & MP_MASK;
+ cc >>= MP_DIGIT_BIT;
+ }
+ }
+
+ c->used = used;
+ c->sign = (neg ? MP_NEG : MP_ZPOS);
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_pack.c b/src/libtommath/mp_pack.c
new file mode 100644
index 000000000..447f1fdf9
--- /dev/null
+++ b/src/libtommath/mp_pack.c
@@ -0,0 +1,69 @@
+#include "tommath_private.h"
+#ifdef MP_PACK_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* based on gmp's mpz_export.
+ * see http://gmplib.org/manual/Integer-Import-and-Export.html
+ */
+mp_err mp_pack(void *rop, size_t maxcount, size_t *written, mp_order order, size_t size,
+ mp_endian endian, size_t nails, const mp_int *op)
+{
+ mp_err err;
+ size_t odd_nails, nail_bytes, i, j, count;
+ uint8_t odd_nail_mask;
+
+ mp_int t;
+
+ count = mp_pack_count(op, nails, size);
+
+ if (count > maxcount) {
+ return MP_BUF;
+ }
+
+ if ((err = mp_init_copy(&t, op)) != MP_OKAY) {
+ return err;
+ }
+
+ if (endian == MP_NATIVE_ENDIAN) {
+ MP_GET_ENDIANNESS(endian);
+ }
+
+ odd_nails = (nails % 8u);
+ odd_nail_mask = 0xff;
+ for (i = 0u; i < odd_nails; ++i) {
+ odd_nail_mask ^= (uint8_t)(1u << (7u - i));
+ }
+ nail_bytes = nails / 8u;
+
+ for (i = 0u; i < count; ++i) {
+ for (j = 0u; j < size; ++j) {
+ uint8_t *byte = (uint8_t *)rop +
+ (((order == MP_LSB_FIRST) ? i : ((count - 1u) - i)) * size) +
+ ((endian == MP_LITTLE_ENDIAN) ? j : ((size - 1u) - j));
+
+ if (j >= (size - nail_bytes)) {
+ *byte = 0;
+ continue;
+ }
+
+ *byte = (uint8_t)((j == ((size - nail_bytes) - 1u)) ? (t.dp[0] & odd_nail_mask) : (t.dp[0] & 0xFFuL));
+
+ if ((err = mp_div_2d(&t, (j == ((size - nail_bytes) - 1u)) ? (int)(8u - odd_nails) : 8, &t, NULL)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ }
+ }
+
+ if (written != NULL) {
+ *written = count;
+ }
+ err = MP_OKAY;
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_pack_count.c b/src/libtommath/mp_pack_count.c
new file mode 100644
index 000000000..aa682ba6c
--- /dev/null
+++ b/src/libtommath/mp_pack_count.c
@@ -0,0 +1,12 @@
+#include "tommath_private.h"
+#ifdef MP_PACK_COUNT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+size_t mp_pack_count(const mp_int *a, size_t nails, size_t size)
+{
+ size_t bits = (size_t)mp_count_bits(a);
+ return ((bits / ((size * 8u) - nails)) + (((bits % ((size * 8u) - nails)) != 0u) ? 1u : 0u));
+}
+
+#endif
diff --git a/src/libtommath/mp_prime_fermat.c b/src/libtommath/mp_prime_fermat.c
new file mode 100644
index 000000000..ac8116fef
--- /dev/null
+++ b/src/libtommath/mp_prime_fermat.c
@@ -0,0 +1,41 @@
+#include "tommath_private.h"
+#ifdef MP_PRIME_FERMAT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* performs one Fermat test.
+ *
+ * If "a" were prime then b**a == b (mod a) since the order of
+ * the multiplicative sub-group would be phi(a) = a-1. That means
+ * it would be the same as b**(a mod (a-1)) == b**1 == b (mod a).
+ *
+ * Sets result to 1 if the congruence holds, or zero otherwise.
+ */
+mp_err mp_prime_fermat(const mp_int *a, const mp_int *b, bool *result)
+{
+ mp_int t;
+ mp_err err;
+
+ /* ensure b > 1 */
+ if (mp_cmp_d(b, 1uL) != MP_GT) {
+ return MP_VAL;
+ }
+
+ /* init t */
+ if ((err = mp_init(&t)) != MP_OKAY) {
+ return err;
+ }
+
+ /* compute t = b**a mod a */
+ if ((err = mp_exptmod(b, a, a, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* is it equal to b? */
+ *result = mp_cmp(&t, b) == MP_EQ;
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_prime_frobenius_underwood.c b/src/libtommath/mp_prime_frobenius_underwood.c
new file mode 100644
index 000000000..62d3476a9
--- /dev/null
+++ b/src/libtommath/mp_prime_frobenius_underwood.c
@@ -0,0 +1,127 @@
+#include "tommath_private.h"
+#ifdef MP_PRIME_FROBENIUS_UNDERWOOD_C
+
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ * See file mp_prime_is_prime.c or the documentation in doc/bn.tex for the details
+ */
+#ifndef LTM_USE_ONLY_MR
+
+/*
+ * floor of positive solution of
+ * (2^16)-1 = (a+4)*(2*a+5)
+ * TODO: Both values are smaller than N^(1/4), would have to use a bigint
+ * for a instead but any a biger than about 120 are already so rare that
+ * it is possible to ignore them and still get enough pseudoprimes.
+ * But it is still a restriction of the set of available pseudoprimes
+ * which makes this implementation less secure if used stand-alone.
+ */
+#define LTM_FROBENIUS_UNDERWOOD_A 32764
+
+mp_err mp_prime_frobenius_underwood(const mp_int *N, bool *result)
+{
+ mp_int T1z, T2z, Np1z, sz, tz;
+ int a, ap2, i;
+ mp_err err;
+
+ if ((err = mp_init_multi(&T1z, &T2z, &Np1z, &sz, &tz, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ for (a = 0; a < LTM_FROBENIUS_UNDERWOOD_A; a++) {
+ int j;
+
+ /* TODO: That's ugly! No, really, it is! */
+ if ((a==2) || (a==4) || (a==7) || (a==8) || (a==10) ||
+ (a==14) || (a==18) || (a==23) || (a==26) || (a==28)) {
+ continue;
+ }
+
+ mp_set_i32(&T1z, (int32_t)((a * a) - 4));
+
+ if ((err = mp_kronecker(&T1z, N, &j)) != MP_OKAY) goto LBL_END;
+
+ if (j == -1) {
+ break;
+ }
+
+ if (j == 0) {
+ /* composite */
+ *result = false;
+ goto LBL_END;
+ }
+ }
+ /* Tell it a composite and set return value accordingly */
+ if (a >= LTM_FROBENIUS_UNDERWOOD_A) {
+ err = MP_ITER;
+ goto LBL_END;
+ }
+ /* Composite if N and (a+4)*(2*a+5) are not coprime */
+ mp_set_u32(&T1z, (uint32_t)((a+4)*((2*a)+5)));
+
+ if ((err = mp_gcd(N, &T1z, &T1z)) != MP_OKAY) goto LBL_END;
+
+ if (!((T1z.used == 1) && (T1z.dp[0] == 1u))) {
+ /* composite */
+ *result = false;
+ goto LBL_END;
+ }
+
+ ap2 = a + 2;
+ if ((err = mp_add_d(N, 1uL, &Np1z)) != MP_OKAY) goto LBL_END;
+
+ mp_set(&sz, 1uL);
+ mp_set(&tz, 2uL);
+
+ for (i = mp_count_bits(&Np1z) - 2; i >= 0; i--) {
+ /*
+ * temp = (sz*(a*sz+2*tz))%N;
+ * tz = ((tz-sz)*(tz+sz))%N;
+ * sz = temp;
+ */
+ if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_END;
+
+ /* a = 0 at about 50% of the cases (non-square and odd input) */
+ if (a != 0) {
+ if ((err = mp_mul_d(&sz, (mp_digit)a, &T1z)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_add(&T1z, &T2z, &T2z)) != MP_OKAY) goto LBL_END;
+ }
+
+ if ((err = mp_mul(&T2z, &sz, &T1z)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_sub(&tz, &sz, &T2z)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_add(&sz, &tz, &sz)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_mul(&sz, &T2z, &tz)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_mod(&tz, N, &tz)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_mod(&T1z, N, &sz)) != MP_OKAY) goto LBL_END;
+ if (s_mp_get_bit(&Np1z, i)) {
+ /*
+ * temp = (a+2) * sz + tz
+ * tz = 2 * tz - sz
+ * sz = temp
+ */
+ if (a == 0) {
+ if ((err = mp_mul_2(&sz, &T1z)) != MP_OKAY) goto LBL_END;
+ } else {
+ if ((err = mp_mul_d(&sz, (mp_digit)ap2, &T1z)) != MP_OKAY) goto LBL_END;
+ }
+ if ((err = mp_add(&T1z, &tz, &T1z)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_sub(&T2z, &sz, &tz)) != MP_OKAY) goto LBL_END;
+ mp_exch(&sz, &T1z);
+ }
+ }
+
+ mp_set_u32(&T1z, (uint32_t)((2 * a) + 5));
+ if ((err = mp_mod(&T1z, N, &T1z)) != MP_OKAY) goto LBL_END;
+
+ *result = mp_iszero(&sz) && (mp_cmp(&tz, &T1z) == MP_EQ);
+
+LBL_END:
+ mp_clear_multi(&tz, &sz, &Np1z, &T2z, &T1z, NULL);
+ return err;
+}
+
+#endif
+#endif
diff --git a/src/libtommath/mp_prime_is_prime.c b/src/libtommath/mp_prime_is_prime.c
new file mode 100644
index 000000000..7d73864c7
--- /dev/null
+++ b/src/libtommath/mp_prime_is_prime.c
@@ -0,0 +1,282 @@
+#include "tommath_private.h"
+#ifdef MP_PRIME_IS_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* portable integer log of two with small footprint */
+static unsigned int s_floor_ilog2(int value)
+{
+ unsigned int r = 0;
+ while ((value >>= 1) != 0) {
+ r++;
+ }
+ return r;
+}
+
+mp_err mp_prime_is_prime(const mp_int *a, int t, bool *result)
+{
+ mp_int b;
+ int ix;
+ bool res;
+ mp_err err;
+
+ /* default to no */
+ *result = false;
+
+ /* Some shortcuts */
+ /* N > 3 */
+ if (a->used == 1) {
+ if ((a->dp[0] == 0u) || (a->dp[0] == 1u)) {
+ *result = false;
+ return MP_OKAY;
+ }
+ if (a->dp[0] == 2u) {
+ *result = true;
+ return MP_OKAY;
+ }
+ }
+
+ /* N must be odd */
+ if (mp_iseven(a)) {
+ return MP_OKAY;
+ }
+ /* N is not a perfect square: floor(sqrt(N))^2 != N */
+ if ((err = mp_is_square(a, &res)) != MP_OKAY) {
+ return err;
+ }
+ if (res) {
+ return MP_OKAY;
+ }
+
+ /* is the input equal to one of the primes in the table? */
+ for (ix = 0; ix < MP_PRIME_TAB_SIZE; ix++) {
+ if (mp_cmp_d(a, s_mp_prime_tab[ix]) == MP_EQ) {
+ *result = true;
+ return MP_OKAY;
+ }
+ }
+ /* first perform trial division */
+ if ((err = s_mp_prime_is_divisible(a, &res)) != MP_OKAY) {
+ return err;
+ }
+
+ /* return if it was trivially divisible */
+ if (res) {
+ return MP_OKAY;
+ }
+
+ /*
+ Run the Miller-Rabin test with base 2 for the BPSW test.
+ */
+ if ((err = mp_init_set(&b, 2uL)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (!res) {
+ goto LBL_B;
+ }
+ /*
+ Rumours have it that Mathematica does a second M-R test with base 3.
+ Other rumours have it that their strong L-S test is slightly different.
+ It does not hurt, though, beside a bit of extra runtime.
+ */
+ b.dp[0]++;
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (!res) {
+ goto LBL_B;
+ }
+
+ /*
+ * Both, the Frobenius-Underwood test and the the Lucas-Selfridge test are quite
+ * slow so if speed is an issue, define LTM_USE_ONLY_MR to use M-R tests with
+ * bases 2, 3 and t random bases.
+ */
+#ifndef LTM_USE_ONLY_MR
+ if (t >= 0) {
+#ifdef LTM_USE_FROBENIUS_TEST
+ err = mp_prime_frobenius_underwood(a, &res);
+ if ((err != MP_OKAY) && (err != MP_ITER)) {
+ goto LBL_B;
+ }
+ if (!res) {
+ goto LBL_B;
+ }
+#else
+ if ((err = mp_prime_strong_lucas_selfridge(a, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (!res) {
+ goto LBL_B;
+ }
+#endif
+ }
+#endif
+
+ /* run at least one Miller-Rabin test with a random base */
+ if (t == 0) {
+ t = 1;
+ }
+
+ /*
+ Only recommended if the input range is known to be < 3317044064679887385961981
+
+ It uses the bases necessary for a deterministic M-R test if the input is
+ smaller than 3317044064679887385961981
+ The caller has to check the size.
+ TODO: can be made a bit finer grained but comparing is not free.
+ */
+ if (t < 0) {
+ int p_max = 0;
+
+ /*
+ Sorenson, Jonathan; Webster, Jonathan (2015).
+ "Strong Pseudoprimes to Twelve Prime Bases".
+ */
+ /* 0x437ae92817f9fc85b7e5 = 318665857834031151167461 */
+ if ((err = mp_read_radix(&b, "437ae92817f9fc85b7e5", 16)) != MP_OKAY) {
+ goto LBL_B;
+ }
+
+ if (mp_cmp(a, &b) == MP_LT) {
+ p_max = 12;
+ } else {
+ /* 0x2be6951adc5b22410a5fd = 3317044064679887385961981 */
+ if ((err = mp_read_radix(&b, "2be6951adc5b22410a5fd", 16)) != MP_OKAY) {
+ goto LBL_B;
+ }
+
+ if (mp_cmp(a, &b) == MP_LT) {
+ p_max = 13;
+ } else {
+ err = MP_VAL;
+ goto LBL_B;
+ }
+ }
+
+ /* we did bases 2 and 3 already, skip them */
+ for (ix = 2; ix < p_max; ix++) {
+ mp_set(&b, s_mp_prime_tab[ix]);
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (!res) {
+ goto LBL_B;
+ }
+ }
+ }
+ /*
+ Do "t" M-R tests with random bases between 3 and "a".
+ See Fips 186.4 p. 126ff
+ */
+ else if (t > 0) {
+ unsigned int mask;
+ int size_a;
+
+ /*
+ * The mp_digit's have a defined bit-size but the size of the
+ * array a.dp is a simple 'int' and this library can not assume full
+ * compliance to the current C-standard (ISO/IEC 9899:2011) because
+ * it gets used for small embeded processors, too. Some of those MCUs
+ * have compilers that one cannot call standard compliant by any means.
+ * Hence the ugly type-fiddling in the following code.
+ */
+ size_a = mp_count_bits(a);
+ mask = (1u << s_floor_ilog2(size_a)) - 1u;
+ /*
+ Assuming the General Rieman hypothesis (never thought to write that in a
+ comment) the upper bound can be lowered to 2*(log a)^2.
+ E. Bach, "Explicit bounds for primality testing and related problems,"
+ Math. Comp. 55 (1990), 355-380.
+
+ size_a = (size_a/10) * 7;
+ len = 2 * (size_a * size_a);
+
+ E.g.: a number of size 2^2048 would be reduced to the upper limit
+
+ floor(2048/10)*7 = 1428
+ 2 * 1428^2 = 4078368
+
+ (would have been ~4030331.9962 with floats and natural log instead)
+ That number is smaller than 2^28, the default bit-size of mp_digit.
+ */
+
+ /*
+ How many tests, you might ask? Dana Jacobsen of Math::Prime::Util fame
+ does exactly 1. In words: one. Look at the end of _GMP_is_prime() in
+ Math-Prime-Util-GMP-0.50/primality.c if you do not believe it.
+
+ The function mp_rand() goes to some length to use a cryptographically
+ good PRNG. That also means that the chance to always get the same base
+ in the loop is non-zero, although very low.
+ If the BPSW test and/or the addtional Frobenious test have been
+ performed instead of just the Miller-Rabin test with the bases 2 and 3,
+ a single extra test should suffice, so such a very unlikely event
+ will not do much harm.
+
+ To preemptivly answer the dangling question: no, a witness does not
+ need to be prime.
+ */
+ for (ix = 0; ix < t; ix++) {
+ unsigned int fips_rand;
+ int len;
+
+ /* mp_rand() guarantees the first digit to be non-zero */
+ if ((err = mp_rand(&b, 1)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ /*
+ * Reduce digit before casting because mp_digit might be bigger than
+ * an unsigned int and "mask" on the other side is most probably not.
+ */
+ fips_rand = (unsigned int)(b.dp[0] & (mp_digit) mask);
+ if (fips_rand > (unsigned int)(INT_MAX - MP_DIGIT_BIT)) {
+ len = INT_MAX / MP_DIGIT_BIT;
+ } else {
+ len = (((int)fips_rand + MP_DIGIT_BIT) / MP_DIGIT_BIT);
+ }
+ /* Unlikely. */
+ if (len < 0) {
+ ix--;
+ continue;
+ }
+ if ((err = mp_rand(&b, len)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ /*
+ * That number might got too big and the witness has to be
+ * smaller than "a"
+ */
+ len = mp_count_bits(&b);
+ if (len >= size_a) {
+ len = (len - size_a) + 1;
+ if ((err = mp_div_2d(&b, len, &b, NULL)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ }
+ /* Although the chance for b <= 3 is miniscule, try again. */
+ if (mp_cmp_d(&b, 3uL) != MP_GT) {
+ ix--;
+ continue;
+ }
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (!res) {
+ goto LBL_B;
+ }
+ }
+ }
+
+ /* passed the test */
+ *result = true;
+LBL_B:
+ mp_clear(&b);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_prime_miller_rabin.c b/src/libtommath/mp_prime_miller_rabin.c
new file mode 100644
index 000000000..4c23a9f28
--- /dev/null
+++ b/src/libtommath/mp_prime_miller_rabin.c
@@ -0,0 +1,91 @@
+#include "tommath_private.h"
+#ifdef MP_PRIME_MILLER_RABIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Miller-Rabin test of "a" to the base of "b" as described in
+ * HAC pp. 139 Algorithm 4.24
+ *
+ * Sets result to 0 if definitely composite or 1 if probably prime.
+ * Randomly the chance of error is no more than 1/4 and often
+ * very much lower.
+ */
+mp_err mp_prime_miller_rabin(const mp_int *a, const mp_int *b, bool *result)
+{
+ mp_int n1, y, r;
+ mp_err err;
+ int s, j;
+
+ /* ensure b > 1 */
+ if (mp_cmp_d(b, 1uL) != MP_GT) {
+ return MP_VAL;
+ }
+
+ /* get n1 = a - 1 */
+ if ((err = mp_init_copy(&n1, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_sub_d(&n1, 1uL, &n1)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+
+ /* set 2**s * r = n1 */
+ if ((err = mp_init_copy(&r, &n1)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+
+ /* count the number of least significant bits
+ * which are zero
+ */
+ s = mp_cnt_lsb(&r);
+
+ /* now divide n - 1 by 2**s */
+ if ((err = mp_div_2d(&r, s, &r, NULL)) != MP_OKAY) {
+ goto LBL_ERR2;
+ }
+
+ /* compute y = b**r mod a */
+ if ((err = mp_init(&y)) != MP_OKAY) {
+ goto LBL_ERR2;
+ }
+ if ((err = mp_exptmod(b, &r, a, &y)) != MP_OKAY) {
+ goto LBL_END;
+ }
+
+ /* if y != 1 and y != n1 do */
+ if ((mp_cmp_d(&y, 1uL) != MP_EQ) && (mp_cmp(&y, &n1) != MP_EQ)) {
+ j = 1;
+ /* while j <= s-1 and y != n1 */
+ while ((j <= (s - 1)) && (mp_cmp(&y, &n1) != MP_EQ)) {
+ if ((err = mp_sqrmod(&y, a, &y)) != MP_OKAY) {
+ goto LBL_END;
+ }
+
+ /* if y == 1 then composite */
+ if (mp_cmp_d(&y, 1uL) == MP_EQ) {
+ *result = false;
+ goto LBL_END;
+ }
+
+ ++j;
+ }
+
+ /* if y != n1 then composite */
+ if (mp_cmp(&y, &n1) != MP_EQ) {
+ *result = false;
+ goto LBL_END;
+ }
+ }
+
+ /* probably prime now */
+ *result = true;
+
+LBL_END:
+ mp_clear(&y);
+LBL_ERR2:
+ mp_clear(&r);
+LBL_ERR1:
+ mp_clear(&n1);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_prime_next_prime.c b/src/libtommath/mp_prime_next_prime.c
new file mode 100644
index 000000000..6faa08de7
--- /dev/null
+++ b/src/libtommath/mp_prime_next_prime.c
@@ -0,0 +1,127 @@
+#include "tommath_private.h"
+#ifdef MP_PRIME_NEXT_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* finds the next prime after the number "a" using "t" trials
+ * of Miller-Rabin.
+ *
+ * bbs_style = true means the prime must be congruent to 3 mod 4
+ */
+mp_err mp_prime_next_prime(mp_int *a, int t, bool bbs_style)
+{
+ int x;
+ mp_err err;
+ bool res = false;
+ mp_digit res_tab[MP_PRIME_TAB_SIZE], kstep;
+ mp_int b;
+
+ /* force positive */
+ a->sign = MP_ZPOS;
+
+ /* simple algo if a is less than the largest prime in the table */
+ if (mp_cmp_d(a, s_mp_prime_tab[MP_PRIME_TAB_SIZE-1]) == MP_LT) {
+ /* find which prime it is bigger than "a" */
+ for (x = 0; x < MP_PRIME_TAB_SIZE; x++) {
+ mp_ord cmp = mp_cmp_d(a, s_mp_prime_tab[x]);
+ if (cmp == MP_EQ) {
+ continue;
+ }
+ if (cmp != MP_GT) {
+ if ((bbs_style) && ((s_mp_prime_tab[x] & 3u) != 3u)) {
+ /* try again until we get a prime congruent to 3 mod 4 */
+ continue;
+ } else {
+ mp_set(a, s_mp_prime_tab[x]);
+ return MP_OKAY;
+ }
+ }
+ }
+ /* fall through to the sieve */
+ }
+
+ /* generate a prime congruent to 3 mod 4 or 1/3 mod 4? */
+ kstep = bbs_style ? 4 : 2;
+
+ /* at this point we will use a combination of a sieve and Miller-Rabin */
+
+ if (bbs_style) {
+ /* if a mod 4 != 3 subtract the correct value to make it so */
+ if ((a->dp[0] & 3u) != 3u) {
+ if ((err = mp_sub_d(a, (a->dp[0] & 3u) + 1u, a)) != MP_OKAY) {
+ return err;
+ }
+ }
+ } else {
+ if (mp_iseven(a)) {
+ /* force odd */
+ if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) {
+ return err;
+ }
+ }
+ }
+
+ /* generate the restable */
+ for (x = 1; x < MP_PRIME_TAB_SIZE; x++) {
+ if ((err = mp_mod_d(a, s_mp_prime_tab[x], res_tab + x)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* init temp used for Miller-Rabin Testing */
+ if ((err = mp_init(&b)) != MP_OKAY) {
+ return err;
+ }
+
+ for (;;) {
+ mp_digit step = 0;
+ bool y;
+ /* skip to the next non-trivially divisible candidate */
+ do {
+ /* y == true if any residue was zero [e.g. cannot be prime] */
+ y = false;
+
+ /* increase step to next candidate */
+ step += kstep;
+
+ /* compute the new residue without using division */
+ for (x = 1; x < MP_PRIME_TAB_SIZE; x++) {
+ /* add the step to each residue */
+ res_tab[x] += kstep;
+
+ /* subtract the modulus [instead of using division] */
+ if (res_tab[x] >= s_mp_prime_tab[x]) {
+ res_tab[x] -= s_mp_prime_tab[x];
+ }
+
+ /* set flag if zero */
+ if (res_tab[x] == 0u) {
+ y = true;
+ }
+ }
+ } while (y && (step < (((mp_digit)1 << MP_DIGIT_BIT) - kstep)));
+
+ /* add the step */
+ if ((err = mp_add_d(a, step, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* if didn't pass sieve and step == MP_MAX then skip test */
+ if (y && (step >= (((mp_digit)1 << MP_DIGIT_BIT) - kstep))) {
+ continue;
+ }
+
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (res) {
+ break;
+ }
+ }
+
+LBL_ERR:
+ mp_clear(&b);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_prime_rabin_miller_trials.c b/src/libtommath/mp_prime_rabin_miller_trials.c
new file mode 100644
index 000000000..9f66f8d77
--- /dev/null
+++ b/src/libtommath/mp_prime_rabin_miller_trials.c
@@ -0,0 +1,48 @@
+#include "tommath_private.h"
+#ifdef MP_PRIME_RABIN_MILLER_TRIALS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+static const struct {
+ int k, t;
+} sizes[] = {
+ { 80, -1 }, /* Use deterministic algorithm for size <= 80 bits */
+ { 81, 37 }, /* max. error = 2^(-96)*/
+ { 96, 32 }, /* max. error = 2^(-96)*/
+ { 128, 40 }, /* max. error = 2^(-112)*/
+ { 160, 35 }, /* max. error = 2^(-112)*/
+ { 256, 27 }, /* max. error = 2^(-128)*/
+ { 384, 16 }, /* max. error = 2^(-128)*/
+ { 512, 18 }, /* max. error = 2^(-160)*/
+ { 768, 11 }, /* max. error = 2^(-160)*/
+ { 896, 10 }, /* max. error = 2^(-160)*/
+ { 1024, 12 }, /* max. error = 2^(-192)*/
+ { 1536, 8 }, /* max. error = 2^(-192)*/
+ { 2048, 6 }, /* max. error = 2^(-192)*/
+ { 3072, 4 }, /* max. error = 2^(-192)*/
+ { 4096, 5 }, /* max. error = 2^(-256)*/
+ { 5120, 4 }, /* max. error = 2^(-256)*/
+ { 6144, 4 }, /* max. error = 2^(-256)*/
+ { 8192, 3 }, /* max. error = 2^(-256)*/
+ { 9216, 3 }, /* max. error = 2^(-256)*/
+ { 10240, 2 } /* For bigger keysizes use always at least 2 Rounds */
+};
+
+/* returns # of RM trials required for a given bit size */
+int mp_prime_rabin_miller_trials(int size)
+{
+ int x;
+
+ for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) {
+ if (sizes[x].k == size) {
+ return sizes[x].t;
+ }
+ if (sizes[x].k > size) {
+ return (x == 0) ? sizes[0].t : sizes[x - 1].t;
+ }
+ }
+ return sizes[x-1].t;
+}
+
+
+#endif
diff --git a/src/libtommath/mp_prime_rand.c b/src/libtommath/mp_prime_rand.c
new file mode 100644
index 000000000..c5cebbda7
--- /dev/null
+++ b/src/libtommath/mp_prime_rand.c
@@ -0,0 +1,123 @@
+#include "tommath_private.h"
+#ifdef MP_PRIME_RAND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* makes a truly random prime of a given size (bits),
+ *
+ * Flags are as follows:
+ *
+ * MP_PRIME_BBS - make prime congruent to 3 mod 4
+ * MP_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies MP_PRIME_BBS)
+ * MP_PRIME_2MSB_ON - make the 2nd highest bit one
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ */
+
+/* This is possibly the mother of all prime generation functions, muahahahahaha! */
+mp_err mp_prime_rand(mp_int *a, int t, int size, int flags)
+{
+ uint8_t *tmp, maskAND, maskOR_msb, maskOR_lsb;
+ int bsize, maskOR_msb_offset;
+ bool res;
+ mp_err err;
+
+ /* sanity check the input */
+ if ((size <= 1) || (t <= 0)) {
+ return MP_VAL;
+ }
+
+ /* MP_PRIME_SAFE implies MP_PRIME_BBS */
+ if ((flags & MP_PRIME_SAFE) != 0) {
+ flags |= MP_PRIME_BBS;
+ }
+
+ /* calc the byte size */
+ bsize = (size>>3) + ((size&7)?1:0);
+
+ /* we need a buffer of bsize bytes */
+ tmp = (uint8_t *) MP_MALLOC((size_t)bsize);
+ if (tmp == NULL) {
+ return MP_MEM;
+ }
+
+ /* calc the maskAND value for the MSbyte*/
+ maskAND = ((size&7) == 0) ? 0xFFu : (uint8_t)(0xFFu >> (8 - (size & 7)));
+
+ /* calc the maskOR_msb */
+ maskOR_msb = 0;
+ maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0;
+ if ((flags & MP_PRIME_2MSB_ON) != 0) {
+ maskOR_msb |= (uint8_t)(0x80 >> ((9 - size) & 7));
+ }
+
+ /* get the maskOR_lsb */
+ maskOR_lsb = 1u;
+ if ((flags & MP_PRIME_BBS) != 0) {
+ maskOR_lsb |= 3u;
+ }
+
+ do {
+ /* read the bytes */
+ if ((err = s_mp_rand_source(tmp, (size_t)bsize)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* work over the MSbyte */
+ tmp[0] &= maskAND;
+ tmp[0] |= (uint8_t)(1 << ((size - 1) & 7));
+
+ /* mix in the maskORs */
+ tmp[maskOR_msb_offset] |= maskOR_msb;
+ tmp[bsize-1] |= maskOR_lsb;
+
+ /* read it in */
+ /* TODO: casting only for now until all lengths have been changed to the type "size_t"*/
+ if ((err = mp_from_ubin(a, tmp, (size_t)bsize)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* is it prime? */
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (!res) {
+ continue;
+ }
+
+ if ((flags & MP_PRIME_SAFE) != 0) {
+ /* see if (a-1)/2 is prime */
+ if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_div_2(a, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* is it prime? */
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ } while (!res);
+
+ if ((flags & MP_PRIME_SAFE) != 0) {
+ /* restore a to the original value */
+ if ((err = mp_mul_2(a, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_add_d(a, 1uL, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ err = MP_OKAY;
+LBL_ERR:
+ MP_FREE_BUF(tmp, (size_t)bsize);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_prime_strong_lucas_selfridge.c b/src/libtommath/mp_prime_strong_lucas_selfridge.c
new file mode 100644
index 000000000..ffbd9d34f
--- /dev/null
+++ b/src/libtommath/mp_prime_strong_lucas_selfridge.c
@@ -0,0 +1,281 @@
+#include "tommath_private.h"
+#ifdef MP_PRIME_STRONG_LUCAS_SELFRIDGE_C
+
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ * See file mp_prime_is_prime.c or the documentation in doc/bn.tex for the details
+ */
+#ifndef LTM_USE_ONLY_MR
+
+/*
+ * multiply bigint a with int d and put the result in c
+ * Like mp_mul_d() but with a signed long as the small input
+ */
+static mp_err s_mul_si(const mp_int *a, int32_t d, mp_int *c)
+{
+ mp_int t;
+ mp_err err;
+
+ if ((err = mp_init(&t)) != MP_OKAY) {
+ return err;
+ }
+
+ /*
+ * mp_digit might be smaller than a long, which excludes
+ * the use of mp_mul_d() here.
+ */
+ mp_set_i32(&t, d);
+ err = mp_mul(a, &t, c);
+ mp_clear(&t);
+ return err;
+}
+/*
+ Strong Lucas-Selfridge test.
+ returns true if it is a strong L-S prime, false if it is composite
+
+ Code ported from Thomas Ray Nicely's implementation of the BPSW test
+ at http://www.trnicely.net/misc/bpsw.html
+
+ Freeware copyright (C) 2016 Thomas R. Nicely <http://www.trnicely.net>.
+ Released into the public domain by the author, who disclaims any legal
+ liability arising from its use
+
+ The multi-line comments are made by Thomas R. Nicely and are copied verbatim.
+ Additional comments marked "CZ" (without the quotes) are by the code-portist.
+
+ (If that name sounds familiar, he is the guy who found the fdiv bug in the
+ Pentium (P5x, I think) Intel processor)
+*/
+mp_err mp_prime_strong_lucas_selfridge(const mp_int *a, bool *result)
+{
+ /* CZ TODO: choose better variable names! */
+ mp_int Dz, gcd, Np1, Uz, Vz, U2mz, V2mz, Qmz, Q2mz, Qkdz, T1z, T2z, T3z, T4z, Q2kdz;
+ int32_t D, Ds, J, sign, P, Q, r, s, u, Nbits;
+ mp_err err;
+ bool oddness;
+
+ *result = false;
+ /*
+ Find the first element D in the sequence {5, -7, 9, -11, 13, ...}
+ such that Jacobi(D,N) = -1 (Selfridge's algorithm). Theory
+ indicates that, if N is not a perfect square, D will "nearly
+ always" be "small." Just in case, an overflow trap for D is
+ included.
+ */
+
+ if ((err = mp_init_multi(&Dz, &gcd, &Np1, &Uz, &Vz, &U2mz, &V2mz, &Qmz, &Q2mz, &Qkdz, &T1z, &T2z, &T3z, &T4z, &Q2kdz,
+ NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ D = 5;
+ sign = 1;
+
+ for (;;) {
+ Ds = sign * D;
+ sign = -sign;
+ mp_set_u32(&Dz, (uint32_t)D);
+ if ((err = mp_gcd(a, &Dz, &gcd)) != MP_OKAY) goto LBL_LS_ERR;
+
+ /* if 1 < GCD < N then N is composite with factor "D", and
+ Jacobi(D,N) is technically undefined (but often returned
+ as zero). */
+ if ((mp_cmp_d(&gcd, 1uL) == MP_GT) && (mp_cmp(&gcd, a) == MP_LT)) {
+ goto LBL_LS_ERR;
+ }
+ if (Ds < 0) {
+ Dz.sign = MP_NEG;
+ }
+ if ((err = mp_kronecker(&Dz, a, &J)) != MP_OKAY) goto LBL_LS_ERR;
+
+ if (J == -1) {
+ break;
+ }
+ D += 2;
+
+ if (D > (INT_MAX - 2)) {
+ err = MP_VAL;
+ goto LBL_LS_ERR;
+ }
+ }
+
+
+
+ P = 1; /* Selfridge's choice */
+ Q = (1 - Ds) / 4; /* Required so D = P*P - 4*Q */
+
+ /* NOTE: The conditions (a) N does not divide Q, and
+ (b) D is square-free or not a perfect square, are included by
+ some authors; e.g., "Prime numbers and computer methods for
+ factorization," Hans Riesel (2nd ed., 1994, Birkhauser, Boston),
+ p. 130. For this particular application of Lucas sequences,
+ these conditions were found to be immaterial. */
+
+ /* Now calculate N - Jacobi(D,N) = N + 1 (even), and calculate the
+ odd positive integer d and positive integer s for which
+ N + 1 = 2^s*d (similar to the step for N - 1 in Miller's test).
+ The strong Lucas-Selfridge test then returns N as a strong
+ Lucas probable prime (slprp) if any of the following
+ conditions is met: U_d=0, V_d=0, V_2d=0, V_4d=0, V_8d=0,
+ V_16d=0, ..., etc., ending with V_{2^(s-1)*d}=V_{(N+1)/2}=0
+ (all equalities mod N). Thus d is the highest index of U that
+ must be computed (since V_2m is independent of U), compared
+ to U_{N+1} for the standard Lucas-Selfridge test; and no
+ index of V beyond (N+1)/2 is required, just as in the
+ standard Lucas-Selfridge test. However, the quantity Q^d must
+ be computed for use (if necessary) in the latter stages of
+ the test. The result is that the strong Lucas-Selfridge test
+ has a running time only slightly greater (order of 10 %) than
+ that of the standard Lucas-Selfridge test, while producing
+ only (roughly) 30 % as many pseudoprimes (and every strong
+ Lucas pseudoprime is also a standard Lucas pseudoprime). Thus
+ the evidence indicates that the strong Lucas-Selfridge test is
+ more effective than the standard Lucas-Selfridge test, and a
+ Baillie-PSW test based on the strong Lucas-Selfridge test
+ should be more reliable. */
+
+ if ((err = mp_add_d(a, 1uL, &Np1)) != MP_OKAY) goto LBL_LS_ERR;
+ s = mp_cnt_lsb(&Np1);
+
+ /* CZ
+ * This should round towards zero because
+ * Thomas R. Nicely used GMP's mpz_tdiv_q_2exp()
+ * and mp_div_2d() is equivalent. Additionally:
+ * dividing an even number by two does not produce
+ * any leftovers.
+ */
+ if ((err = mp_div_2d(&Np1, s, &Dz, NULL)) != MP_OKAY) goto LBL_LS_ERR;
+ /* We must now compute U_d and V_d. Since d is odd, the accumulated
+ values U and V are initialized to U_1 and V_1 (if the target
+ index were even, U and V would be initialized instead to U_0=0
+ and V_0=2). The values of U_2m and V_2m are also initialized to
+ U_1 and V_1; the FOR loop calculates in succession U_2 and V_2,
+ U_4 and V_4, U_8 and V_8, etc. If the corresponding bits
+ (1, 2, 3, ...) of t are on (the zero bit having been accounted
+ for in the initialization of U and V), these values are then
+ combined with the previous totals for U and V, using the
+ composition formulas for addition of indices. */
+
+ mp_set(&Uz, 1uL); /* U=U_1 */
+ mp_set(&Vz, (mp_digit)P); /* V=V_1 */
+ mp_set(&U2mz, 1uL); /* U_1 */
+ mp_set(&V2mz, (mp_digit)P); /* V_1 */
+
+ mp_set_i32(&Qmz, Q);
+ if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ /* Initializes calculation of Q^d */
+ mp_set_i32(&Qkdz, Q);
+
+ Nbits = mp_count_bits(&Dz);
+
+ for (u = 1; u < Nbits; u++) { /* zero bit off, already accounted for */
+ /* Formulas for doubling of indices (carried out mod N). Note that
+ * the indices denoted as "2m" are actually powers of 2, specifically
+ * 2^(ul-1) beginning each loop and 2^ul ending each loop.
+ *
+ * U_2m = U_m*V_m
+ * V_2m = V_m*V_m - 2*Q^m
+ */
+
+ if ((err = mp_mul(&U2mz, &V2mz, &U2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&U2mz, a, &U2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_sqr(&V2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_sub(&V2mz, &Q2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&V2mz, a, &V2mz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ /* Must calculate powers of Q for use in V_2m, also for Q^d later */
+ if ((err = mp_sqr(&Qmz, &Qmz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ /* prevents overflow */ /* CZ still necessary without a fixed prealloc'd mem.? */
+ if ((err = mp_mod(&Qmz, a, &Qmz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ if (s_mp_get_bit(&Dz, u)) {
+ /* Formulas for addition of indices (carried out mod N);
+ *
+ * U_(m+n) = (U_m*V_n + U_n*V_m)/2
+ * V_(m+n) = (V_m*V_n + D*U_m*U_n)/2
+ *
+ * Be careful with division by 2 (mod N)!
+ */
+ if ((err = mp_mul(&U2mz, &Vz, &T1z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul(&Uz, &V2mz, &T2z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul(&V2mz, &Vz, &T3z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul(&U2mz, &Uz, &T4z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = s_mul_si(&T4z, Ds, &T4z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_add(&T1z, &T2z, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ if (mp_isodd(&Uz)) {
+ if ((err = mp_add(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ /* CZ
+ * This should round towards negative infinity because
+ * Thomas R. Nicely used GMP's mpz_fdiv_q_2exp().
+ * But mp_div_2() does not do so, it is truncating instead.
+ */
+ oddness = mp_isodd(&Uz);
+ if ((err = mp_div_2(&Uz, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ if (mp_isneg(&Uz) && oddness) {
+ if ((err = mp_sub_d(&Uz, 1uL, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ if ((err = mp_add(&T3z, &T4z, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if (mp_isodd(&Vz)) {
+ if ((err = mp_add(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ oddness = mp_isodd(&Vz);
+ if ((err = mp_div_2(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if (mp_isneg(&Vz) && oddness) {
+ if ((err = mp_sub_d(&Vz, 1uL, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ if ((err = mp_mod(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ /* Calculating Q^d for later use */
+ if ((err = mp_mul(&Qkdz, &Qmz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ }
+
+ /* If U_d or V_d is congruent to 0 mod N, then N is a prime or a
+ strong Lucas pseudoprime. */
+ if (mp_iszero(&Uz) || mp_iszero(&Vz)) {
+ *result = true;
+ goto LBL_LS_ERR;
+ }
+
+ /* NOTE: Ribenboim ("The new book of prime number records," 3rd ed.,
+ 1995/6) omits the condition V0 on p.142, but includes it on
+ p. 130. The condition is NECESSARY; otherwise the test will
+ return false negatives---e.g., the primes 29 and 2000029 will be
+ returned as composite. */
+
+ /* Otherwise, we must compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d}
+ by repeated use of the formula V_2m = V_m*V_m - 2*Q^m. If any of
+ these are congruent to 0 mod N, then N is a prime or a strong
+ Lucas pseudoprime. */
+
+ /* Initialize 2*Q^(d*2^r) for V_2m */
+ if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ for (r = 1; r < s; r++) {
+ if ((err = mp_sqr(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_sub(&Vz, &Q2kdz, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if (mp_iszero(&Vz)) {
+ *result = true;
+ goto LBL_LS_ERR;
+ }
+ /* Calculate Q^{d*2^r} for next r (final iteration irrelevant). */
+ if (r < (s - 1)) {
+ if ((err = mp_sqr(&Qkdz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ }
+LBL_LS_ERR:
+ mp_clear_multi(&Q2kdz, &T4z, &T3z, &T2z, &T1z, &Qkdz, &Q2mz, &Qmz, &V2mz, &U2mz, &Vz, &Uz, &Np1, &gcd, &Dz, NULL);
+ return err;
+}
+#endif
+#endif
diff --git a/src/libtommath/mp_radix_size.c b/src/libtommath/mp_radix_size.c
new file mode 100644
index 000000000..ca08438bc
--- /dev/null
+++ b/src/libtommath/mp_radix_size.c
@@ -0,0 +1,34 @@
+#include "tommath_private.h"
+#ifdef MP_RADIX_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* returns size of ASCII representation */
+mp_err mp_radix_size(const mp_int *a, int radix, size_t *size)
+{
+ mp_err err;
+ mp_int a_;
+ int b;
+
+ /* make sure the radix is in range */
+ if ((radix < 2) || (radix > 64)) {
+ return MP_VAL;
+ }
+
+ if (mp_iszero(a)) {
+ *size = 2;
+ return MP_OKAY;
+ }
+
+ a_ = *a;
+ a_.sign = MP_ZPOS;
+ if ((err = mp_log_n(&a_, radix, &b)) != MP_OKAY) {
+ return err;
+ }
+
+ /* mp_ilogb truncates to zero, hence we need one extra put on top and one for `\0`. */
+ *size = (size_t)b + 2U + (mp_isneg(a) ? 1U : 0U);
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_radix_size_overestimate.c b/src/libtommath/mp_radix_size_overestimate.c
new file mode 100644
index 000000000..3fe81d79d
--- /dev/null
+++ b/src/libtommath/mp_radix_size_overestimate.c
@@ -0,0 +1,17 @@
+#include "tommath_private.h"
+#ifdef MP_RADIX_SIZE_OVERESTIMATE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_err mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size)
+{
+ if (MP_HAS(S_MP_RADIX_SIZE_OVERESTIMATE)) {
+ return s_mp_radix_size_overestimate(a, radix, size);
+ }
+ if (MP_HAS(MP_RADIX_SIZE)) {
+ return mp_radix_size(a, radix, size);
+ }
+ return MP_ERR;
+}
+
+#endif
diff --git a/src/libtommath/mp_rand.c b/src/libtommath/mp_rand.c
new file mode 100644
index 000000000..19364755a
--- /dev/null
+++ b/src/libtommath/mp_rand.c
@@ -0,0 +1,39 @@
+#include "tommath_private.h"
+#ifdef MP_RAND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_err mp_rand(mp_int *a, int digits)
+{
+ int i;
+ mp_err err;
+
+ mp_zero(a);
+
+ if (digits <= 0) {
+ return MP_OKAY;
+ }
+
+ if ((err = mp_grow(a, digits)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = s_mp_rand_source(a->dp, (size_t)digits * sizeof(mp_digit))) != MP_OKAY) {
+ return err;
+ }
+
+ /* TODO: We ensure that the highest digit is nonzero. Should this be removed? */
+ while ((a->dp[digits - 1] & MP_MASK) == 0u) {
+ if ((err = s_mp_rand_source(a->dp + digits - 1, sizeof(mp_digit))) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ a->used = digits;
+ for (i = 0; i < digits; ++i) {
+ a->dp[i] &= MP_MASK;
+ }
+
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_rand_source.c b/src/libtommath/mp_rand_source.c
new file mode 100644
index 000000000..e9e876948
--- /dev/null
+++ b/src/libtommath/mp_rand_source.c
@@ -0,0 +1,12 @@
+#include "tommath_private.h"
+#ifdef MP_RAND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_err(*s_mp_rand_source)(void *out, size_t size) = s_mp_rand_platform;
+
+void mp_rand_source(mp_err(*source)(void *out, size_t size))
+{
+ s_mp_rand_source = (source == NULL) ? s_mp_rand_platform : source;
+}
+#endif
diff --git a/src/libtommath/mp_read_radix.c b/src/libtommath/mp_read_radix.c
new file mode 100644
index 000000000..28e6eb60a
--- /dev/null
+++ b/src/libtommath/mp_read_radix.c
@@ -0,0 +1,69 @@
+#include "tommath_private.h"
+#ifdef MP_READ_RADIX_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* read a string [ASCII] in a given radix */
+mp_err mp_read_radix(mp_int *a, const char *str, int radix)
+{
+ mp_err err;
+ mp_sign sign = MP_ZPOS;
+
+ /* make sure the radix is ok */
+ if ((radix < 2) || (radix > 64)) {
+ return MP_VAL;
+ }
+
+ /* if the leading digit is a
+ * minus set the sign to negative.
+ */
+ if (*str == '-') {
+ ++str;
+ sign = MP_NEG;
+ }
+
+ /* set the integer to the default of zero */
+ mp_zero(a);
+
+ /* process each digit of the string */
+ while (*str != '\0') {
+ /* if the radix <= 36 the conversion is case insensitive
+ * this allows numbers like 1AB and 1ab to represent the same value
+ * [e.g. in hex]
+ */
+ uint8_t y;
+ char ch = (radix <= 36) ? (char)MP_TOUPPER((int)*str) : *str;
+ unsigned pos = (unsigned)(ch - '+');
+ if (MP_RADIX_MAP_REVERSE_SIZE <= pos) {
+ break;
+ }
+ y = s_mp_radix_map_reverse[pos];
+
+ /* if the char was found in the map
+ * and is less than the given radix add it
+ * to the number, otherwise exit the loop.
+ */
+ if (y >= radix) {
+ break;
+ }
+ if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_add_d(a, y, a)) != MP_OKAY) {
+ return err;
+ }
+ ++str;
+ }
+
+ /* if an illegal character was found, fail. */
+ if ((*str != '\0') && (*str != '\r') && (*str != '\n')) {
+ return MP_VAL;
+ }
+
+ /* set the sign only if a != 0 */
+ if (!mp_iszero(a)) {
+ a->sign = sign;
+ }
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_reduce.c b/src/libtommath/mp_reduce.c
new file mode 100644
index 000000000..b6fae55cc
--- /dev/null
+++ b/src/libtommath/mp_reduce.c
@@ -0,0 +1,83 @@
+#include "tommath_private.h"
+#ifdef MP_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reduces x mod m, assumes 0 < x < m**2, mu is
+ * precomputed via mp_reduce_setup.
+ * From HAC pp.604 Algorithm 14.42
+ */
+mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu)
+{
+ mp_int q;
+ mp_err err;
+ int um = m->used;
+
+ /* q = x */
+ if ((err = mp_init_copy(&q, x)) != MP_OKAY) {
+ return err;
+ }
+
+ /* q1 = x / b**(k-1) */
+ mp_rshd(&q, um - 1);
+
+ /* according to HAC this optimization is ok */
+ if ((mp_digit)um > ((mp_digit)1 << (MP_DIGIT_BIT - 1))) {
+ if ((err = mp_mul(&q, mu, &q)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else if (MP_HAS(S_MP_MUL_HIGH)) {
+ if ((err = s_mp_mul_high(&q, mu, &q, um)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else if (MP_HAS(S_MP_MUL_HIGH_COMBA)) {
+ if ((err = s_mp_mul_high_comba(&q, mu, &q, um)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else {
+ err = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* q3 = q2 / b**(k+1) */
+ mp_rshd(&q, um + 1);
+
+ /* x = x mod b**(k+1), quick (no division) */
+ if ((err = mp_mod_2d(x, MP_DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* q = q * m mod b**(k+1), quick (no division) */
+ if ((err = s_mp_mul(&q, m, &q, um + 1)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* x = x - q */
+ if ((err = mp_sub(x, &q, x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* If x < 0, add b**(k+1) to it */
+ if (mp_cmp_d(x, 0uL) == MP_LT) {
+ mp_set(&q, 1uL);
+ if ((err = mp_lshd(&q, um + 1)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_add(x, &q, x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* Back off if it's too big */
+ while (mp_cmp(x, m) != MP_LT) {
+ if ((err = s_mp_sub(x, m, x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+LBL_ERR:
+ mp_clear(&q);
+
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_reduce_2k.c b/src/libtommath/mp_reduce_2k.c
new file mode 100644
index 000000000..e635f5b90
--- /dev/null
+++ b/src/libtommath/mp_reduce_2k.c
@@ -0,0 +1,49 @@
+#include "tommath_private.h"
+#ifdef MP_REDUCE_2K_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reduces a modulo n where n is of the form 2**p - d */
+mp_err mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d)
+{
+ mp_int q;
+ mp_err err;
+ int p;
+
+ if ((err = mp_init(&q)) != MP_OKAY) {
+ return err;
+ }
+
+ p = mp_count_bits(n);
+ for (;;) {
+ /* q = a/2**p, a = a mod 2**p */
+ if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if (d != 1u) {
+ /* q = q * d */
+ if ((err = mp_mul_d(&q, d, &q)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* a = a + q */
+ if ((err = s_mp_add(a, &q, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if (mp_cmp_mag(a, n) == MP_LT) {
+ break;
+ }
+ if ((err = s_mp_sub(a, n, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+LBL_ERR:
+ mp_clear(&q);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_reduce_2k_l.c b/src/libtommath/mp_reduce_2k_l.c
new file mode 100644
index 000000000..31d9a1882
--- /dev/null
+++ b/src/libtommath/mp_reduce_2k_l.c
@@ -0,0 +1,52 @@
+#include "tommath_private.h"
+#ifdef MP_REDUCE_2K_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reduces a modulo n where n is of the form 2**p - d
+ This differs from reduce_2k since "d" can be larger
+ than a single digit.
+*/
+mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d)
+{
+ mp_int q;
+ mp_err err;
+ int p;
+
+ if ((err = mp_init(&q)) != MP_OKAY) {
+ return err;
+ }
+
+ p = mp_count_bits(n);
+
+ for (;;) {
+ /* q = a/2**p, a = a mod 2**p */
+ if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* q = q * d */
+ if ((err = mp_mul(&q, d, &q)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* a = a + q */
+ if ((err = s_mp_add(a, &q, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if (mp_cmp_mag(a, n) == MP_LT) {
+ break;
+ }
+ if ((err = s_mp_sub(a, n, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ }
+
+LBL_ERR:
+ mp_clear(&q);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_reduce_2k_setup.c b/src/libtommath/mp_reduce_2k_setup.c
new file mode 100644
index 000000000..51f884134
--- /dev/null
+++ b/src/libtommath/mp_reduce_2k_setup.c
@@ -0,0 +1,30 @@
+#include "tommath_private.h"
+#ifdef MP_REDUCE_2K_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines the setup value */
+mp_err mp_reduce_2k_setup(const mp_int *a, mp_digit *d)
+{
+ mp_err err;
+ mp_int tmp;
+
+ if ((err = mp_init(&tmp)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((err = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ *d = tmp.dp[0];
+
+LBL_ERR:
+ mp_clear(&tmp);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_reduce_2k_setup_l.c b/src/libtommath/mp_reduce_2k_setup_l.c
new file mode 100644
index 000000000..b647c9d88
--- /dev/null
+++ b/src/libtommath/mp_reduce_2k_setup_l.c
@@ -0,0 +1,28 @@
+#include "tommath_private.h"
+#ifdef MP_REDUCE_2K_SETUP_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines the setup value */
+mp_err mp_reduce_2k_setup_l(const mp_int *a, mp_int *d)
+{
+ mp_err err;
+ mp_int tmp;
+
+ if ((err = mp_init(&tmp)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((err = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+LBL_ERR:
+ mp_clear(&tmp);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_reduce_is_2k.c b/src/libtommath/mp_reduce_is_2k.c
new file mode 100644
index 000000000..9774f96e9
--- /dev/null
+++ b/src/libtommath/mp_reduce_is_2k.c
@@ -0,0 +1,34 @@
+#include "tommath_private.h"
+#ifdef MP_REDUCE_IS_2K_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines if mp_reduce_2k can be used */
+bool mp_reduce_is_2k(const mp_int *a)
+{
+ if (mp_iszero(a)) {
+ return false;
+ } else if (a->used == 1) {
+ return true;
+ } else if (a->used > 1) {
+ int ix, iy = mp_count_bits(a), iw = 1;
+ mp_digit iz = 1;
+
+ /* Test every bit from the second digit up, must be 1 */
+ for (ix = MP_DIGIT_BIT; ix < iy; ix++) {
+ if ((a->dp[iw] & iz) == 0u) {
+ return false;
+ }
+ iz <<= 1;
+ if (iz > MP_DIGIT_MAX) {
+ ++iw;
+ iz = 1;
+ }
+ }
+ return true;
+ } else {
+ return true;
+ }
+}
+
+#endif
diff --git a/src/libtommath/mp_reduce_is_2k_l.c b/src/libtommath/mp_reduce_is_2k_l.c
new file mode 100644
index 000000000..101b4a185
--- /dev/null
+++ b/src/libtommath/mp_reduce_is_2k_l.c
@@ -0,0 +1,27 @@
+#include "tommath_private.h"
+#ifdef MP_REDUCE_IS_2K_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines if reduce_2k_l can be used */
+bool mp_reduce_is_2k_l(const mp_int *a)
+{
+ if (mp_iszero(a)) {
+ return false;
+ } else if (a->used == 1) {
+ return true;
+ } else if (a->used > 1) {
+ /* if more than half of the digits are -1 we're sold */
+ int ix, iy;
+ for (iy = ix = 0; ix < a->used; ix++) {
+ if (a->dp[ix] == MP_DIGIT_MAX) {
+ ++iy;
+ }
+ }
+ return (iy >= (a->used/2));
+ } else {
+ return false;
+ }
+}
+
+#endif
diff --git a/src/libtommath/mp_reduce_setup.c b/src/libtommath/mp_reduce_setup.c
new file mode 100644
index 000000000..e12056e1e
--- /dev/null
+++ b/src/libtommath/mp_reduce_setup.c
@@ -0,0 +1,17 @@
+#include "tommath_private.h"
+#ifdef MP_REDUCE_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* pre-calculate the value required for Barrett reduction
+ * For a given modulus "b" it calulates the value required in "a"
+ */
+mp_err mp_reduce_setup(mp_int *a, const mp_int *b)
+{
+ mp_err err;
+ if ((err = mp_2expt(a, b->used * 2 * MP_DIGIT_BIT)) != MP_OKAY) {
+ return err;
+ }
+ return mp_div(a, b, a, NULL);
+}
+#endif
diff --git a/src/libtommath/mp_root_n.c b/src/libtommath/mp_root_n.c
new file mode 100644
index 000000000..d904df883
--- /dev/null
+++ b/src/libtommath/mp_root_n.c
@@ -0,0 +1,141 @@
+#include "tommath_private.h"
+#ifdef MP_ROOT_N_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* find the n'th root of an integer
+ *
+ * Result found such that (c)**b <= a and (c+1)**b > a
+ *
+ * This algorithm uses Newton's approximation
+ * x[i+1] = x[i] - f(x[i])/f'(x[i])
+ * which will find the root in log(N) time where
+ * each step involves a fair bit.
+ */
+mp_err mp_root_n(const mp_int *a, int b, mp_int *c)
+{
+ mp_int t1, t2, t3, a_;
+ int ilog2;
+ mp_err err;
+
+ if (b < 0 || (unsigned)b > (unsigned)MP_DIGIT_MAX) {
+ return MP_VAL;
+ }
+
+ /* input must be positive if b is even */
+ if (((b & 1) == 0) && mp_isneg(a)) {
+ return MP_VAL;
+ }
+
+ if ((err = mp_init_multi(&t1, &t2, &t3, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* if a is negative fudge the sign but keep track */
+ a_ = *a;
+ a_.sign = MP_ZPOS;
+
+ /* Compute seed: 2^(log_2(n)/b + 2)*/
+ ilog2 = mp_count_bits(a);
+
+ /*
+ If "b" is larger than INT_MAX it is also larger than
+ log_2(n) because the bit-length of the "n" is measured
+ with an int and hence the root is always < 2 (two).
+ */
+ if (b > INT_MAX/2) {
+ mp_set(c, 1uL);
+ c->sign = a->sign;
+ err = MP_OKAY;
+ goto LBL_ERR;
+ }
+
+ /* "b" is smaller than INT_MAX, we can cast safely */
+ if (ilog2 < b) {
+ mp_set(c, 1uL);
+ c->sign = a->sign;
+ err = MP_OKAY;
+ goto LBL_ERR;
+ }
+ ilog2 = ilog2 / b;
+ if (ilog2 == 0) {
+ mp_set(c, 1uL);
+ c->sign = a->sign;
+ err = MP_OKAY;
+ goto LBL_ERR;
+ }
+ /* Start value must be larger than root */
+ ilog2 += 2;
+ if ((err = mp_2expt(&t2,ilog2)) != MP_OKAY) goto LBL_ERR;
+ do {
+ /* t1 = t2 */
+ if ((err = mp_copy(&t2, &t1)) != MP_OKAY) goto LBL_ERR;
+
+ /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
+
+ /* t3 = t1**(b-1) */
+ if ((err = mp_expt_n(&t1, b - 1, &t3)) != MP_OKAY) goto LBL_ERR;
+
+ /* numerator */
+ /* t2 = t1**b */
+ if ((err = mp_mul(&t3, &t1, &t2)) != MP_OKAY) goto LBL_ERR;
+
+ /* t2 = t1**b - a */
+ if ((err = mp_sub(&t2, &a_, &t2)) != MP_OKAY) goto LBL_ERR;
+
+ /* denominator */
+ /* t3 = t1**(b-1) * b */
+ if ((err = mp_mul_d(&t3, (mp_digit)b, &t3)) != MP_OKAY) goto LBL_ERR;
+
+ /* t3 = (t1**b - a)/(b * t1**(b-1)) */
+ if ((err = mp_div(&t2, &t3, &t3, NULL)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&t1, &t3, &t2)) != MP_OKAY) goto LBL_ERR;
+
+ /*
+ Number of rounds is at most log_2(root). If it is more it
+ got stuck, so break out of the loop and do the rest manually.
+ */
+ if (ilog2-- == 0) {
+ break;
+ }
+ } while (mp_cmp(&t1, &t2) != MP_EQ);
+
+ /* result can be off by a few so check */
+ /* Loop beneath can overshoot by one if found root is smaller than actual root */
+ for (;;) {
+ mp_ord cmp;
+ if ((err = mp_expt_n(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR;
+ cmp = mp_cmp(&t2, &a_);
+ if (cmp == MP_EQ) {
+ err = MP_OKAY;
+ goto LBL_ERR;
+ }
+ if (cmp == MP_LT) {
+ if ((err = mp_add_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR;
+ } else {
+ break;
+ }
+ }
+ /* correct overshoot from above or from recurrence */
+ for (;;) {
+ if ((err = mp_expt_n(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR;
+ if (mp_cmp(&t2, &a_) == MP_GT) {
+ if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR;
+ } else {
+ break;
+ }
+ }
+
+ /* set the result */
+ mp_exch(&t1, c);
+
+ /* set the sign of the result */
+ c->sign = a->sign;
+
+LBL_ERR:
+ mp_clear_multi(&t1, &t2, &t3, NULL);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_rshd.c b/src/libtommath/mp_rshd.c
new file mode 100644
index 000000000..3f0a9416e
--- /dev/null
+++ b/src/libtommath/mp_rshd.c
@@ -0,0 +1,43 @@
+#include "tommath_private.h"
+#ifdef MP_RSHD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift right a certain amount of digits */
+void mp_rshd(mp_int *a, int b)
+{
+ int x;
+
+ /* if b <= 0 then ignore it */
+ if (b <= 0) {
+ return;
+ }
+
+ /* if b > used then simply zero it and return */
+ if (a->used <= b) {
+ mp_zero(a);
+ return;
+ }
+
+ /* shift the digits down.
+ * this is implemented as a sliding window where
+ * the window is b-digits long and digits from
+ * the top of the window are copied to the bottom
+ *
+ * e.g.
+
+ b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
+ /\ | ---->
+ \-------------------/ ---->
+ */
+ for (x = 0; x < (a->used - b); x++) {
+ a->dp[x] = a->dp[x + b];
+ }
+
+ /* zero the top digits */
+ s_mp_zero_digs(a->dp + a->used - b, b);
+
+ /* remove excess digits */
+ a->used -= b;
+}
+#endif
diff --git a/src/libtommath/mp_sbin_size.c b/src/libtommath/mp_sbin_size.c
new file mode 100644
index 000000000..2f40df3e1
--- /dev/null
+++ b/src/libtommath/mp_sbin_size.c
@@ -0,0 +1,11 @@
+#include "tommath_private.h"
+#ifdef MP_SBIN_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* get the size for an signed equivalent */
+size_t mp_sbin_size(const mp_int *a)
+{
+ return 1u + mp_ubin_size(a);
+}
+#endif
diff --git a/src/libtommath/mp_set.c b/src/libtommath/mp_set.c
new file mode 100644
index 000000000..bc0c4da76
--- /dev/null
+++ b/src/libtommath/mp_set.c
@@ -0,0 +1,15 @@
+#include "tommath_private.h"
+#ifdef MP_SET_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* set to a digit */
+void mp_set(mp_int *a, mp_digit b)
+{
+ int oldused = a->used;
+ a->dp[0] = b & MP_MASK;
+ a->sign = MP_ZPOS;
+ a->used = (a->dp[0] != 0u) ? 1 : 0;
+ s_mp_zero_digs(a->dp + a->used, oldused - a->used);
+}
+#endif
diff --git a/src/libtommath/mp_set_double.c b/src/libtommath/mp_set_double.c
new file mode 100644
index 000000000..0ede359c6
--- /dev/null
+++ b/src/libtommath/mp_set_double.c
@@ -0,0 +1,47 @@
+#include "tommath_private.h"
+#ifdef MP_SET_DOUBLE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#if defined(MP_HAS_SET_DOUBLE)
+mp_err mp_set_double(mp_int *a, double b)
+{
+ uint64_t frac;
+ int exp;
+ mp_err err;
+ union {
+ double dbl;
+ uint64_t bits;
+ } cast;
+ cast.dbl = b;
+
+ exp = (int)((unsigned)(cast.bits >> 52) & 0x7FFu);
+ frac = (cast.bits & (((uint64_t)1 << 52) - (uint64_t)1)) | ((uint64_t)1 << 52);
+
+ if (exp == 0x7FF) { /* +-inf, NaN */
+ return MP_VAL;
+ }
+ exp -= 1023 + 52;
+
+ mp_set_u64(a, frac);
+
+ err = (exp < 0) ? mp_div_2d(a, -exp, a, NULL) : mp_mul_2d(a, exp, a);
+ if (err != MP_OKAY) {
+ return err;
+ }
+
+ if (((cast.bits >> 63) != 0u) && !mp_iszero(a)) {
+ a->sign = MP_NEG;
+ }
+
+ return MP_OKAY;
+}
+#else
+/* pragma message() not supported by several compilers (in mostly older but still used versions) */
+# ifdef _MSC_VER
+# pragma message("mp_set_double implementation is only available on platforms with IEEE754 floating point format")
+# else
+# warning "mp_set_double implementation is only available on platforms with IEEE754 floating point format"
+# endif
+#endif
+#endif
diff --git a/src/libtommath/mp_set_i32.c b/src/libtommath/mp_set_i32.c
new file mode 100644
index 000000000..123613ecc
--- /dev/null
+++ b/src/libtommath/mp_set_i32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_SET_I32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_SIGNED(mp_set_i32, mp_set_u32, int32_t, uint32_t)
+#endif
diff --git a/src/libtommath/mp_set_i64.c b/src/libtommath/mp_set_i64.c
new file mode 100644
index 000000000..4635ca3a5
--- /dev/null
+++ b/src/libtommath/mp_set_i64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_SET_I64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_SIGNED(mp_set_i64, mp_set_u64, int64_t, uint64_t)
+#endif
diff --git a/src/libtommath/mp_set_l.c b/src/libtommath/mp_set_l.c
new file mode 100644
index 000000000..411f6eb08
--- /dev/null
+++ b/src/libtommath/mp_set_l.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_SET_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_SIGNED(mp_set_l, mp_set_ul, long, unsigned long)
+#endif
diff --git a/src/libtommath/mp_set_u32.c b/src/libtommath/mp_set_u32.c
new file mode 100644
index 000000000..8ff84dc22
--- /dev/null
+++ b/src/libtommath/mp_set_u32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_SET_U32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_UNSIGNED(mp_set_u32, uint32_t)
+#endif
diff --git a/src/libtommath/mp_set_u64.c b/src/libtommath/mp_set_u64.c
new file mode 100644
index 000000000..9acb1fefe
--- /dev/null
+++ b/src/libtommath/mp_set_u64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_SET_U64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_UNSIGNED(mp_set_u64, uint64_t)
+#endif
diff --git a/src/libtommath/mp_set_ul.c b/src/libtommath/mp_set_ul.c
new file mode 100644
index 000000000..baf8e186e
--- /dev/null
+++ b/src/libtommath/mp_set_ul.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef MP_SET_UL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_UNSIGNED(mp_set_ul, unsigned long)
+#endif
diff --git a/src/libtommath/mp_shrink.c b/src/libtommath/mp_shrink.c
new file mode 100644
index 000000000..3d9b1626d
--- /dev/null
+++ b/src/libtommath/mp_shrink.c
@@ -0,0 +1,22 @@
+#include "tommath_private.h"
+#ifdef MP_SHRINK_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shrink a bignum */
+mp_err mp_shrink(mp_int *a)
+{
+ int alloc = MP_MAX(MP_MIN_DIGIT_COUNT, a->used);
+ if (a->alloc != alloc) {
+ mp_digit *dp = (mp_digit *) MP_REALLOC(a->dp,
+ (size_t)a->alloc * sizeof(mp_digit),
+ (size_t)alloc * sizeof(mp_digit));
+ if (dp == NULL) {
+ return MP_MEM;
+ }
+ a->dp = dp;
+ a->alloc = alloc;
+ }
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_signed_rsh.c b/src/libtommath/mp_signed_rsh.c
new file mode 100644
index 000000000..3b7e232e5
--- /dev/null
+++ b/src/libtommath/mp_signed_rsh.c
@@ -0,0 +1,21 @@
+#include "tommath_private.h"
+#ifdef MP_SIGNED_RSH_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift right by a certain bit count with sign extension */
+mp_err mp_signed_rsh(const mp_int *a, int b, mp_int *c)
+{
+ mp_err err;
+ if (!mp_isneg(a)) {
+ return mp_div_2d(a, b, c, NULL);
+ }
+
+ if ((err = mp_add_d(a, 1uL, c)) != MP_OKAY) {
+ return err;
+ }
+
+ err = mp_div_2d(c, b, c, NULL);
+ return (err == MP_OKAY) ? mp_sub_d(c, 1uL, c) : err;
+}
+#endif
diff --git a/src/libtommath/mp_sqrmod.c b/src/libtommath/mp_sqrmod.c
new file mode 100644
index 000000000..bce2af090
--- /dev/null
+++ b/src/libtommath/mp_sqrmod.c
@@ -0,0 +1,15 @@
+#include "tommath_private.h"
+#ifdef MP_SQRMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* c = a * a (mod b) */
+mp_err mp_sqrmod(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_err err;
+ if ((err = mp_sqr(a, c)) != MP_OKAY) {
+ return err;
+ }
+ return mp_mod(c, b, c);
+}
+#endif
diff --git a/src/libtommath/mp_sqrt.c b/src/libtommath/mp_sqrt.c
new file mode 100644
index 000000000..1a9dca7da
--- /dev/null
+++ b/src/libtommath/mp_sqrt.c
@@ -0,0 +1,67 @@
+#include "tommath_private.h"
+#ifdef MP_SQRT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* this function is less generic than mp_n_root, simpler and faster */
+mp_err mp_sqrt(const mp_int *arg, mp_int *ret)
+{
+ mp_err err;
+ mp_int t1, t2;
+
+ /* must be positive */
+ if (mp_isneg(arg)) {
+ return MP_VAL;
+ }
+
+ /* easy out */
+ if (mp_iszero(arg)) {
+ mp_zero(ret);
+ return MP_OKAY;
+ }
+
+ if ((err = mp_init_copy(&t1, arg)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_init(&t2)) != MP_OKAY) {
+ goto LBL_ERR2;
+ }
+
+ /* First approx. (not very bad for large arg) */
+ mp_rshd(&t1, t1.used/2);
+
+ /* t1 > 0 */
+ if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+ if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+ /* And now t1 > sqrt(arg) */
+ do {
+ if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+ if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+ /* t1 >= sqrt(arg) >= t2 at this point */
+ } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+ mp_exch(&t1, ret);
+
+LBL_ERR1:
+ mp_clear(&t2);
+LBL_ERR2:
+ mp_clear(&t1);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_sqrtmod_prime.c b/src/libtommath/mp_sqrtmod_prime.c
new file mode 100644
index 000000000..0fae1d02a
--- /dev/null
+++ b/src/libtommath/mp_sqrtmod_prime.c
@@ -0,0 +1,133 @@
+#include "tommath_private.h"
+#ifdef MP_SQRTMOD_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Tonelli-Shanks algorithm
+ * https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
+ * https://gmplib.org/list-archives/gmp-discuss/2013-April/005300.html
+ *
+ */
+
+mp_err mp_sqrtmod_prime(const mp_int *n, const mp_int *prime, mp_int *ret)
+{
+ mp_err err;
+ int legendre;
+ /* The type is "int" because of the types in the mp_int struct.
+ Don't forget to change them here when you change them there! */
+ int S, M, i;
+ mp_int t1, C, Q, Z, T, R, two;
+
+ /* first handle the simple cases */
+ if (mp_cmp_d(n, 0uL) == MP_EQ) {
+ mp_zero(ret);
+ return MP_OKAY;
+ }
+ /* "prime" must be odd and > 2 */
+ if (mp_iseven(prime) || (mp_cmp_d(prime, 3uL) == MP_LT)) return MP_VAL;
+ if ((err = mp_kronecker(n, prime, &legendre)) != MP_OKAY) return err;
+ /* n \not\cong 0 (mod p) and n \cong r^2 (mod p) for some r \in N^+ */
+ if (legendre != 1) return MP_VAL;
+
+ if ((err = mp_init_multi(&t1, &C, &Q, &Z, &T, &R, &two, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* SPECIAL CASE: if prime mod 4 == 3
+ * compute directly: err = n^(prime+1)/4 mod prime
+ * Handbook of Applied Cryptography algorithm 3.36
+ */
+ /* x%4 == x&3 for x in N and x>0 */
+ if ((prime->dp[0] & 3u) == 3u) {
+ if ((err = mp_add_d(prime, 1uL, &t1)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_exptmod(n, &t1, prime, ret)) != MP_OKAY) goto LBL_END;
+ err = MP_OKAY;
+ goto LBL_END;
+ }
+
+ /* NOW: Tonelli-Shanks algorithm */
+
+ /* factor out powers of 2 from prime-1, defining Q and S as: prime-1 = Q*2^S */
+ if ((err = mp_copy(prime, &Q)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_sub_d(&Q, 1uL, &Q)) != MP_OKAY) goto LBL_END;
+ /* Q = prime - 1 */
+ S = 0;
+ /* S = 0 */
+ while (mp_iseven(&Q)) {
+ if ((err = mp_div_2(&Q, &Q)) != MP_OKAY) goto LBL_END;
+ /* Q = Q / 2 */
+ S++;
+ /* S = S + 1 */
+ }
+
+ /* find a Z such that the Legendre symbol (Z|prime) == -1 */
+ mp_set(&Z, 2uL);
+ /* Z = 2 */
+ for (;;) {
+ if ((err = mp_kronecker(&Z, prime, &legendre)) != MP_OKAY) goto LBL_END;
+ /* If "prime" (p) is an odd prime Jacobi(k|p) = 0 for k \cong 0 (mod p) */
+ /* but there is at least one non-quadratic residue before k>=p if p is an odd prime. */
+ if (legendre == 0) {
+ err = MP_VAL;
+ goto LBL_END;
+ }
+ if (legendre == -1) break;
+ if ((err = mp_add_d(&Z, 1uL, &Z)) != MP_OKAY) goto LBL_END;
+ /* Z = Z + 1 */
+ }
+
+ if ((err = mp_exptmod(&Z, &Q, prime, &C)) != MP_OKAY) goto LBL_END;
+ /* C = Z ^ Q mod prime */
+ if ((err = mp_add_d(&Q, 1uL, &t1)) != MP_OKAY) goto LBL_END;
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto LBL_END;
+ /* t1 = (Q + 1) / 2 */
+ if ((err = mp_exptmod(n, &t1, prime, &R)) != MP_OKAY) goto LBL_END;
+ /* R = n ^ ((Q + 1) / 2) mod prime */
+ if ((err = mp_exptmod(n, &Q, prime, &T)) != MP_OKAY) goto LBL_END;
+ /* T = n ^ Q mod prime */
+ M = S;
+ /* M = S */
+ mp_set(&two, 2uL);
+
+ for (;;) {
+ if ((err = mp_copy(&T, &t1)) != MP_OKAY) goto LBL_END;
+ i = 0;
+ for (;;) {
+ if (mp_cmp_d(&t1, 1uL) == MP_EQ) break;
+ /* No exponent in the range 0 < i < M found
+ (M is at least 1 in the first round because "prime" > 2) */
+ if (M == i) {
+ err = MP_VAL;
+ goto LBL_END;
+ }
+ if ((err = mp_exptmod(&t1, &two, prime, &t1)) != MP_OKAY) goto LBL_END;
+ i++;
+ }
+ if (i == 0) {
+ if ((err = mp_copy(&R, ret)) != MP_OKAY) goto LBL_END;
+ err = MP_OKAY;
+ goto LBL_END;
+ }
+ mp_set_i32(&t1, M - i - 1);
+ if ((err = mp_exptmod(&two, &t1, prime, &t1)) != MP_OKAY) goto LBL_END;
+ /* t1 = 2 ^ (M - i - 1) */
+ if ((err = mp_exptmod(&C, &t1, prime, &t1)) != MP_OKAY) goto LBL_END;
+ /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */
+ if ((err = mp_sqrmod(&t1, prime, &C)) != MP_OKAY) goto LBL_END;
+ /* C = (t1 * t1) mod prime */
+ if ((err = mp_mulmod(&R, &t1, prime, &R)) != MP_OKAY) goto LBL_END;
+ /* R = (R * t1) mod prime */
+ if ((err = mp_mulmod(&T, &C, prime, &T)) != MP_OKAY) goto LBL_END;
+ /* T = (T * C) mod prime */
+ M = i;
+ /* M = i */
+ }
+
+LBL_END:
+ mp_clear_multi(&t1, &C, &Q, &Z, &T, &R, &two, NULL);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_sub.c b/src/libtommath/mp_sub.c
new file mode 100644
index 000000000..1c95ad544
--- /dev/null
+++ b/src/libtommath/mp_sub.c
@@ -0,0 +1,36 @@
+#include "tommath_private.h"
+#ifdef MP_SUB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* high level subtraction (handles signs) */
+mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ if (a->sign != b->sign) {
+ /* subtract a negative from a positive, OR */
+ /* subtract a positive from a negative. */
+ /* In either case, ADD their magnitudes, */
+ /* and use the sign of the first number. */
+ c->sign = a->sign;
+ return s_mp_add(a, b, c);
+ }
+
+ /* subtract a positive from a positive, OR */
+ /* subtract a negative from a negative. */
+ /* First, take the difference between their */
+ /* magnitudes, then... */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ /* The second has a larger magnitude */
+ /* The result has the *opposite* sign from */
+ /* the first number. */
+ c->sign = (!mp_isneg(a) ? MP_NEG : MP_ZPOS);
+ MP_EXCH(const mp_int *, a, b);
+ } else {
+ /* The first has a larger or equal magnitude */
+ /* Copy the sign from the first */
+ c->sign = a->sign;
+ }
+ return s_mp_sub(a, b, c);
+}
+
+#endif
diff --git a/src/libtommath/mp_sub_d.c b/src/libtommath/mp_sub_d.c
new file mode 100644
index 000000000..b2b4d723d
--- /dev/null
+++ b/src/libtommath/mp_sub_d.c
@@ -0,0 +1,78 @@
+#include "tommath_private.h"
+#ifdef MP_SUB_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* single digit subtraction */
+mp_err mp_sub_d(const mp_int *a, mp_digit b, mp_int *c)
+{
+ mp_err err;
+ int oldused;
+
+ /* fast path for a == c */
+ if (a == c) {
+ if ((c->sign == MP_NEG) &&
+ ((c->dp[0] + b) < MP_DIGIT_MAX)) {
+ c->dp[0] += b;
+ return MP_OKAY;
+ }
+ if ((c->sign == MP_ZPOS) &&
+ (c->dp[0] > b)) {
+ c->dp[0] -= b;
+ return MP_OKAY;
+ }
+ }
+
+ /* grow c as required */
+ if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* if a is negative just do an unsigned
+ * addition [with fudged signs]
+ */
+ if (a->sign == MP_NEG) {
+ mp_int a_ = *a;
+ a_.sign = MP_ZPOS;
+ err = mp_add_d(&a_, b, c);
+ c->sign = MP_NEG;
+
+ /* clamp */
+ mp_clamp(c);
+
+ return err;
+ }
+
+ oldused = c->used;
+
+ /* if a <= b simply fix the single digit */
+ if (((a->used == 1) && (a->dp[0] <= b)) || mp_iszero(a)) {
+ c->dp[0] = (a->used == 1) ? b - a->dp[0] : b;
+
+ /* negative/1digit */
+ c->sign = MP_NEG;
+ c->used = 1;
+ } else {
+ int i;
+ mp_digit mu = b;
+
+ /* positive/size */
+ c->sign = MP_ZPOS;
+ c->used = a->used;
+
+ /* subtract digits, mu is carry */
+ for (i = 0; i < a->used; i++) {
+ c->dp[i] = a->dp[i] - mu;
+ mu = c->dp[i] >> (MP_SIZEOF_BITS(mp_digit) - 1u);
+ c->dp[i] &= MP_MASK;
+ }
+ }
+
+ /* zero excess digits */
+ s_mp_zero_digs(c->dp + c->used, oldused - c->used);
+
+ mp_clamp(c);
+ return MP_OKAY;
+}
+
+#endif
diff --git a/src/libtommath/mp_submod.c b/src/libtommath/mp_submod.c
new file mode 100644
index 000000000..6e4d4f712
--- /dev/null
+++ b/src/libtommath/mp_submod.c
@@ -0,0 +1,15 @@
+#include "tommath_private.h"
+#ifdef MP_SUBMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* d = a - b (mod c) */
+mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d)
+{
+ mp_err err;
+ if ((err = mp_sub(a, b, d)) != MP_OKAY) {
+ return err;
+ }
+ return mp_mod(d, c, d);
+}
+#endif
diff --git a/src/libtommath/mp_to_radix.c b/src/libtommath/mp_to_radix.c
new file mode 100644
index 000000000..1e5e67110
--- /dev/null
+++ b/src/libtommath/mp_to_radix.c
@@ -0,0 +1,95 @@
+#include "tommath_private.h"
+#ifdef MP_TO_RADIX_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reverse an array, used for radix code */
+static void s_reverse(char *s, size_t len)
+{
+ size_t ix = 0, iy = len - 1u;
+ while (ix < iy) {
+ MP_EXCH(char, s[ix], s[iy]);
+ ++ix;
+ --iy;
+ }
+}
+
+/* stores a bignum as a ASCII string in a given radix (2..64)
+ *
+ * Stores upto "size - 1" chars and always a NULL byte, puts the number of characters
+ * written, including the '\0', in "written".
+ */
+mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix)
+{
+ size_t digs;
+ mp_err err;
+ mp_int t;
+ mp_digit d;
+ char *_s = str;
+
+ /* check range of radix and size*/
+ if (maxlen < 2u) {
+ return MP_BUF;
+ }
+ if ((radix < 2) || (radix > 64)) {
+ return MP_VAL;
+ }
+
+ /* quick out if its zero */
+ if (mp_iszero(a)) {
+ *str++ = '0';
+ *str = '\0';
+ if (written != NULL) {
+ *written = 2u;
+ }
+ return MP_OKAY;
+ }
+
+ if ((err = mp_init_copy(&t, a)) != MP_OKAY) {
+ return err;
+ }
+
+ /* if it is negative output a - */
+ if (mp_isneg(&t)) {
+ /* we have to reverse our digits later... but not the - sign!! */
+ ++_s;
+
+ /* store the flag and mark the number as positive */
+ *str++ = '-';
+ t.sign = MP_ZPOS;
+
+ /* subtract a char */
+ --maxlen;
+ }
+ digs = 0u;
+ while (!mp_iszero(&t)) {
+ if (--maxlen < 1u) {
+ /* no more room */
+ err = MP_BUF;
+ goto LBL_ERR;
+ }
+ if ((err = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ *str++ = s_mp_radix_map[d];
+ ++digs;
+ }
+ /* reverse the digits of the string. In this case _s points
+ * to the first digit [excluding the sign] of the number
+ */
+ s_reverse(_s, digs);
+
+ /* append a NULL so the string is properly terminated */
+ *str = '\0';
+ digs++;
+
+ if (written != NULL) {
+ *written = mp_isneg(a) ? (digs + 1u): digs;
+ }
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/mp_to_sbin.c b/src/libtommath/mp_to_sbin.c
new file mode 100644
index 000000000..00884c3be
--- /dev/null
+++ b/src/libtommath/mp_to_sbin.c
@@ -0,0 +1,22 @@
+#include "tommath_private.h"
+#ifdef MP_TO_SBIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* store in signed [big endian] format */
+mp_err mp_to_sbin(const mp_int *a, uint8_t *buf, size_t maxlen, size_t *written)
+{
+ mp_err err;
+ if (maxlen == 0u) {
+ return MP_BUF;
+ }
+ if ((err = mp_to_ubin(a, buf + 1, maxlen - 1u, written)) != MP_OKAY) {
+ return err;
+ }
+ if (written != NULL) {
+ (*written)++;
+ }
+ buf[0] = mp_isneg(a) ? (uint8_t)1 : (uint8_t)0;
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_to_ubin.c b/src/libtommath/mp_to_ubin.c
new file mode 100644
index 000000000..e8643cc07
--- /dev/null
+++ b/src/libtommath/mp_to_ubin.c
@@ -0,0 +1,37 @@
+#include "tommath_private.h"
+#ifdef MP_TO_UBIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* store in unsigned [big endian] format */
+mp_err mp_to_ubin(const mp_int *a, uint8_t *buf, size_t maxlen, size_t *written)
+{
+ size_t x, count;
+ mp_err err;
+ mp_int t;
+
+ count = mp_ubin_size(a);
+ if (count > maxlen) {
+ return MP_BUF;
+ }
+
+ if ((err = mp_init_copy(&t, a)) != MP_OKAY) {
+ return err;
+ }
+
+ for (x = count; x --> 0u;) {
+ buf[x] = (uint8_t)(t.dp[0] & 255u);
+ if ((err = mp_div_2d(&t, 8, &t, NULL)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ if (written != NULL) {
+ *written = count;
+ }
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
diff --git a/src/libtommath/mp_ubin_size.c b/src/libtommath/mp_ubin_size.c
new file mode 100644
index 000000000..4f16404f4
--- /dev/null
+++ b/src/libtommath/mp_ubin_size.c
@@ -0,0 +1,12 @@
+#include "tommath_private.h"
+#ifdef MP_UBIN_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* get the size for an unsigned equivalent */
+size_t mp_ubin_size(const mp_int *a)
+{
+ size_t size = (size_t)mp_count_bits(a);
+ return (size / 8u) + (((size & 7u) != 0u) ? 1u : 0u);
+}
+#endif
diff --git a/src/libtommath/mp_unpack.c b/src/libtommath/mp_unpack.c
new file mode 100644
index 000000000..f0127fa44
--- /dev/null
+++ b/src/libtommath/mp_unpack.c
@@ -0,0 +1,49 @@
+#include "tommath_private.h"
+#ifdef MP_UNPACK_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* based on gmp's mpz_import.
+ * see http://gmplib.org/manual/Integer-Import-and-Export.html
+ */
+mp_err mp_unpack(mp_int *rop, size_t count, mp_order order, size_t size,
+ mp_endian endian, size_t nails, const void *op)
+{
+ mp_err err;
+ size_t odd_nails, nail_bytes, i, j;
+ uint8_t odd_nail_mask;
+
+ mp_zero(rop);
+
+ if (endian == MP_NATIVE_ENDIAN) {
+ MP_GET_ENDIANNESS(endian);
+ }
+
+ odd_nails = (nails % 8u);
+ odd_nail_mask = 0xff;
+ for (i = 0; i < odd_nails; ++i) {
+ odd_nail_mask ^= (uint8_t)(1u << (7u - i));
+ }
+ nail_bytes = nails / 8u;
+
+ for (i = 0; i < count; ++i) {
+ for (j = 0; j < (size - nail_bytes); ++j) {
+ uint8_t byte = *((const uint8_t *)op +
+ (((order == MP_MSB_FIRST) ? i : ((count - 1u) - i)) * size) +
+ ((endian == MP_BIG_ENDIAN) ? (j + nail_bytes) : (((size - 1u) - j) - nail_bytes)));
+
+ if ((err = mp_mul_2d(rop, (j == 0u) ? (int)(8u - odd_nails) : 8, rop)) != MP_OKAY) {
+ return err;
+ }
+
+ rop->dp[0] |= (j == 0u) ? (mp_digit)(byte & odd_nail_mask) : (mp_digit)byte;
+ rop->used += 1;
+ }
+ }
+
+ mp_clamp(rop);
+
+ return MP_OKAY;
+}
+
+#endif
diff --git a/src/libtommath/mp_xor.c b/src/libtommath/mp_xor.c
new file mode 100644
index 000000000..ff264192c
--- /dev/null
+++ b/src/libtommath/mp_xor.c
@@ -0,0 +1,54 @@
+#include "tommath_private.h"
+#ifdef MP_XOR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* two complement xor */
+mp_err mp_xor(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int used = MP_MAX(a->used, b->used) + 1, i;
+ mp_err err;
+ mp_digit ac = 1, bc = 1, cc = 1;
+ bool neg = (a->sign != b->sign);
+
+ if ((err = mp_grow(c, used)) != MP_OKAY) {
+ return err;
+ }
+
+ for (i = 0; i < used; i++) {
+ mp_digit x, y;
+
+ /* convert to two complement if negative */
+ if (mp_isneg(a)) {
+ ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
+ x = ac & MP_MASK;
+ ac >>= MP_DIGIT_BIT;
+ } else {
+ x = (i >= a->used) ? 0uL : a->dp[i];
+ }
+
+ /* convert to two complement if negative */
+ if (mp_isneg(b)) {
+ bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
+ y = bc & MP_MASK;
+ bc >>= MP_DIGIT_BIT;
+ } else {
+ y = (i >= b->used) ? 0uL : b->dp[i];
+ }
+
+ c->dp[i] = x ^ y;
+
+ /* convert to to sign-magnitude if negative */
+ if (neg) {
+ cc += ~c->dp[i] & MP_MASK;
+ c->dp[i] = cc & MP_MASK;
+ cc >>= MP_DIGIT_BIT;
+ }
+ }
+
+ c->used = used;
+ c->sign = (neg ? MP_NEG : MP_ZPOS);
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/mp_zero.c b/src/libtommath/mp_zero.c
new file mode 100644
index 000000000..48b60e458
--- /dev/null
+++ b/src/libtommath/mp_zero.c
@@ -0,0 +1,13 @@
+#include "tommath_private.h"
+#ifdef MP_ZERO_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* set to zero */
+void mp_zero(mp_int *a)
+{
+ a->sign = MP_ZPOS;
+ s_mp_zero_digs(a->dp, a->used);
+ a->used = 0;
+}
+#endif
diff --git a/src/libtommath/s_mp_add.c b/src/libtommath/s_mp_add.c
new file mode 100644
index 000000000..2bda2fe1b
--- /dev/null
+++ b/src/libtommath/s_mp_add.c
@@ -0,0 +1,70 @@
+#include "tommath_private.h"
+#ifdef S_MP_ADD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* low level addition, based on HAC pp.594, Algorithm 14.7 */
+mp_err s_mp_add(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int oldused, min, max, i;
+ mp_digit u;
+ mp_err err;
+
+ /* find sizes, we let |a| <= |b| which means we have to sort
+ * them. "x" will point to the input with the most digits
+ */
+ if (a->used < b->used) {
+ MP_EXCH(const mp_int *, a, b);
+ }
+
+ min = b->used;
+ max = a->used;
+
+ /* init result */
+ if ((err = mp_grow(c, max + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* get old used digit count and set new one */
+ oldused = c->used;
+ c->used = max + 1;
+
+ /* zero the carry */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
+ c->dp[i] = a->dp[i] + b->dp[i] + u;
+
+ /* U = carry bit of T[i] */
+ u = c->dp[i] >> (mp_digit)MP_DIGIT_BIT;
+
+ /* take away carry bit from T[i] */
+ c->dp[i] &= MP_MASK;
+ }
+
+ /* now copy higher words if any, that is in A+B
+ * if A or B has more digits add those in
+ */
+ if (min != max) {
+ for (; i < max; i++) {
+ /* T[i] = A[i] + U */
+ c->dp[i] = a->dp[i] + u;
+
+ /* U = carry bit of T[i] */
+ u = c->dp[i] >> (mp_digit)MP_DIGIT_BIT;
+
+ /* take away carry bit from T[i] */
+ c->dp[i] &= MP_MASK;
+ }
+ }
+
+ /* add carry */
+ c->dp[i] = u;
+
+ /* clear digits above oldused */
+ s_mp_zero_digs(c->dp + c->used, oldused - c->used);
+
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/s_mp_copy_digs.c b/src/libtommath/s_mp_copy_digs.c
new file mode 100644
index 000000000..4079c33a6
--- /dev/null
+++ b/src/libtommath/s_mp_copy_digs.c
@@ -0,0 +1,23 @@
+#include "tommath_private.h"
+#ifdef S_MP_COPY_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifdef MP_USE_MEMOPS
+# include <string.h>
+#endif
+
+void s_mp_copy_digs(mp_digit *d, const mp_digit *s, int digits)
+{
+#ifdef MP_USE_MEMOPS
+ if (digits > 0) {
+ memcpy(d, s, (size_t)digits * sizeof(mp_digit));
+ }
+#else
+ while (digits-- > 0) {
+ *d++ = *s++;
+ }
+#endif
+}
+
+#endif
diff --git a/src/libtommath/s_mp_div_3.c b/src/libtommath/s_mp_div_3.c
new file mode 100644
index 000000000..1cc6d3d8c
--- /dev/null
+++ b/src/libtommath/s_mp_div_3.c
@@ -0,0 +1,64 @@
+#include "tommath_private.h"
+#ifdef S_MP_DIV_3_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* divide by three (based on routine from MPI and the GMP manual) */
+mp_err s_mp_div_3(const mp_int *a, mp_int *c, mp_digit *d)
+{
+ mp_int q;
+ mp_word w;
+ mp_digit b;
+ mp_err err;
+ int ix;
+
+ /* b = 2**MP_DIGIT_BIT / 3 */
+ b = ((mp_word)1 << (mp_word)MP_DIGIT_BIT) / (mp_word)3;
+
+ if ((err = mp_init_size(&q, a->used)) != MP_OKAY) {
+ return err;
+ }
+
+ q.used = a->used;
+ q.sign = a->sign;
+ w = 0;
+ for (ix = a->used; ix --> 0;) {
+ mp_word t;
+ w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix];
+
+ if (w >= 3u) {
+ /* multiply w by [1/3] */
+ t = (w * (mp_word)b) >> (mp_word)MP_DIGIT_BIT;
+
+ /* now subtract 3 * [w/3] from w, to get the remainder */
+ w -= t+t+t;
+
+ /* fixup the remainder as required since
+ * the optimization is not exact.
+ */
+ while (w >= 3u) {
+ t += 1u;
+ w -= 3u;
+ }
+ } else {
+ t = 0;
+ }
+ q.dp[ix] = (mp_digit)t;
+ }
+
+ /* [optional] store the remainder */
+ if (d != NULL) {
+ *d = (mp_digit)w;
+ }
+
+ /* [optional] store the quotient */
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ }
+ mp_clear(&q);
+
+ return MP_OKAY;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_div_recursive.c b/src/libtommath/s_mp_div_recursive.c
new file mode 100644
index 000000000..d719c4e28
--- /dev/null
+++ b/src/libtommath/s_mp_div_recursive.c
@@ -0,0 +1,159 @@
+#include "tommath_private.h"
+#ifdef S_MP_DIV_RECURSIVE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ Direct implementation of algorithms 1.8 "RecursiveDivRem" and 1.9 "UnbalancedDivision"
+ from:
+
+ Brent, Richard P., and Paul Zimmermann. "Modern computer arithmetic"
+ Vol. 18. Cambridge University Press, 2010
+ Available online at https://arxiv.org/pdf/1004.4710
+
+ pages 19ff. in the above online document.
+*/
+
+static mp_err s_recursion(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r)
+{
+ mp_err err;
+ mp_int A1, A2, B1, B0, Q1, Q0, R1, R0, t;
+ int m = a->used - b->used, k = m/2;
+
+ if (m < (MP_MUL_KARATSUBA_CUTOFF)) {
+ return s_mp_div_school(a, b, q, r);
+ }
+
+ if ((err = mp_init_multi(&A1, &A2, &B1, &B0, &Q1, &Q0, &R1, &R0, &t, NULL)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* B1 = b / beta^k, B0 = b % beta^k*/
+ if ((err = mp_div_2d(b, k * MP_DIGIT_BIT, &B1, &B0)) != MP_OKAY) goto LBL_ERR;
+
+ /* (Q1, R1) = RecursiveDivRem(A / beta^(2k), B1) */
+ if ((err = mp_div_2d(a, 2*k * MP_DIGIT_BIT, &A1, &t)) != MP_OKAY) goto LBL_ERR;
+ if ((err = s_recursion(&A1, &B1, &Q1, &R1)) != MP_OKAY) goto LBL_ERR;
+
+ /* A1 = (R1 * beta^(2k)) + (A % beta^(2k)) - (Q1 * B0 * beta^k) */
+ if ((err = mp_lshd(&R1, 2*k)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&R1, &t, &A1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul(&Q1, &B0, &t)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&t, k)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&A1, &t, &A1)) != MP_OKAY) goto LBL_ERR;
+
+ /* while A1 < 0 do Q1 = Q1 - 1, A1 = A1 + (beta^k * B) */
+ if (mp_cmp_d(&A1, 0uL) == MP_LT) {
+ if ((err = mp_mul_2d(b, k * MP_DIGIT_BIT, &t)) != MP_OKAY) goto LBL_ERR;
+ do {
+ if ((err = mp_decr(&Q1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&A1, &t, &A1)) != MP_OKAY) goto LBL_ERR;
+ } while (mp_cmp_d(&A1, 0uL) == MP_LT);
+ }
+ /* (Q0, R0) = RecursiveDivRem(A1 / beta^(k), B1) */
+ if ((err = mp_div_2d(&A1, k * MP_DIGIT_BIT, &A1, &t)) != MP_OKAY) goto LBL_ERR;
+ if ((err = s_recursion(&A1, &B1, &Q0, &R0)) != MP_OKAY) goto LBL_ERR;
+
+ /* A2 = (R0*beta^k) + (A1 % beta^k) - (Q0*B0) */
+ if ((err = mp_lshd(&R0, k)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&R0, &t, &A2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul(&Q0, &B0, &t)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&A2, &t, &A2)) != MP_OKAY) goto LBL_ERR;
+
+ /* while A2 < 0 do Q0 = Q0 - 1, A2 = A2 + B */
+ while (mp_cmp_d(&A2, 0uL) == MP_LT) {
+ if ((err = mp_decr(&Q0)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&A2, b, &A2)) != MP_OKAY) goto LBL_ERR;
+ }
+ /* return q = (Q1*beta^k) + Q0, r = A2 */
+ if ((err = mp_lshd(&Q1, k)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&Q1, &Q0, q)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_copy(&A2, r)) != MP_OKAY) goto LBL_ERR;
+
+LBL_ERR:
+ mp_clear_multi(&A1, &A2, &B1, &B0, &Q1, &Q0, &R1, &R0, &t, NULL);
+ return err;
+}
+
+
+mp_err s_mp_div_recursive(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r)
+{
+ int j, m, n, sigma;
+ mp_err err;
+ bool neg;
+ mp_digit msb_b, msb;
+ mp_int A, B, Q, Q1, R, A_div, A_mod;
+
+ if ((err = mp_init_multi(&A, &B, &Q, &Q1, &R, &A_div, &A_mod, NULL)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* most significant bit of a limb */
+ /* assumes MP_DIGIT_MAX < (sizeof(mp_digit) * CHAR_BIT) */
+ msb = (MP_DIGIT_MAX + (mp_digit)(1)) >> 1;
+ sigma = 0;
+ msb_b = b->dp[b->used - 1];
+ while (msb_b < msb) {
+ sigma++;
+ msb_b <<= 1;
+ }
+ /* Use that sigma to normalize B */
+ if ((err = mp_mul_2d(b, sigma, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_mul_2d(a, sigma, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* fix the sign */
+ neg = (a->sign != b->sign);
+ A.sign = B.sign = MP_ZPOS;
+
+ /*
+ If the magnitude of "A" is not more more than twice that of "B" we can work
+ on them directly, otherwise we need to work at "A" in chunks
+ */
+ n = B.used;
+ m = A.used - B.used;
+
+ /* Q = 0 */
+ mp_zero(&Q);
+ while (m > n) {
+ /* (q, r) = RecursiveDivRem(A / (beta^(m-n)), B) */
+ j = (m - n) * MP_DIGIT_BIT;
+ if ((err = mp_div_2d(&A, j, &A_div, &A_mod)) != MP_OKAY) goto LBL_ERR;
+ if ((err = s_recursion(&A_div, &B, &Q1, &R)) != MP_OKAY) goto LBL_ERR;
+ /* Q = (Q*beta!(n)) + q */
+ if ((err = mp_mul_2d(&Q, n * MP_DIGIT_BIT, &Q)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&Q, &Q1, &Q)) != MP_OKAY) goto LBL_ERR;
+ /* A = (r * beta^(m-n)) + (A % beta^(m-n))*/
+ if ((err = mp_mul_2d(&R, (m - n) * MP_DIGIT_BIT, &R)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&R, &A_mod, &A)) != MP_OKAY) goto LBL_ERR;
+ /* m = m - n */
+ m = m - n;
+ }
+ /* (q, r) = RecursiveDivRem(A, B) */
+ if ((err = s_recursion(&A, &B, &Q1, &R)) != MP_OKAY) goto LBL_ERR;
+ /* Q = (Q * beta^m) + q, R = r */
+ if ((err = mp_mul_2d(&Q, m * MP_DIGIT_BIT, &Q)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&Q, &Q1, &Q)) != MP_OKAY) goto LBL_ERR;
+
+ /* get sign before writing to c */
+ R.sign = (mp_iszero(&Q) ? MP_ZPOS : a->sign);
+
+ if (q != NULL) {
+ mp_exch(&Q, q);
+ q->sign = (neg ? MP_NEG : MP_ZPOS);
+ }
+ if (r != NULL) {
+ /* de-normalize the remainder */
+ if ((err = mp_div_2d(&R, sigma, &R, NULL)) != MP_OKAY) goto LBL_ERR;
+ mp_exch(&R, r);
+ }
+LBL_ERR:
+ mp_clear_multi(&A, &B, &Q, &Q1, &R, &A_div, &A_mod, NULL);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_div_school.c b/src/libtommath/s_mp_div_school.c
new file mode 100644
index 000000000..b6a615d10
--- /dev/null
+++ b/src/libtommath/s_mp_div_school.c
@@ -0,0 +1,156 @@
+#include "tommath_private.h"
+#ifdef S_MP_DIV_SCHOOL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* integer signed division.
+ * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
+ * HAC pp.598 Algorithm 14.20
+ *
+ * Note that the description in HAC is horribly
+ * incomplete. For example, it doesn't consider
+ * the case where digits are removed from 'x' in
+ * the inner loop. It also doesn't consider the
+ * case that y has fewer than three digits, etc..
+ *
+ * The overall algorithm is as described as
+ * 14.20 from HAC but fixed to treat these cases.
+*/
+mp_err s_mp_div_school(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d)
+{
+ mp_int q, x, y, t1, t2;
+ int n, t, i, norm;
+ bool neg;
+ mp_err err;
+
+ if ((err = mp_init_size(&q, a->used + 2)) != MP_OKAY) {
+ return err;
+ }
+ q.used = a->used + 2;
+
+ if ((err = mp_init(&t1)) != MP_OKAY) goto LBL_Q;
+ if ((err = mp_init(&t2)) != MP_OKAY) goto LBL_T1;
+ if ((err = mp_init_copy(&x, a)) != MP_OKAY) goto LBL_T2;
+ if ((err = mp_init_copy(&y, b)) != MP_OKAY) goto LBL_X;
+
+ /* fix the sign */
+ neg = (a->sign != b->sign);
+ x.sign = y.sign = MP_ZPOS;
+
+ /* normalize both x and y, ensure that y >= b/2, [b == 2**MP_DIGIT_BIT] */
+ norm = mp_count_bits(&y) % MP_DIGIT_BIT;
+ if (norm < (MP_DIGIT_BIT - 1)) {
+ norm = (MP_DIGIT_BIT - 1) - norm;
+ if ((err = mp_mul_2d(&x, norm, &x)) != MP_OKAY) goto LBL_Y;
+ if ((err = mp_mul_2d(&y, norm, &y)) != MP_OKAY) goto LBL_Y;
+ } else {
+ norm = 0;
+ }
+
+ /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
+ n = x.used - 1;
+ t = y.used - 1;
+
+ /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
+ /* y = y*b**{n-t} */
+ if ((err = mp_lshd(&y, n - t)) != MP_OKAY) goto LBL_Y;
+
+ while (mp_cmp(&x, &y) != MP_LT) {
+ ++(q.dp[n - t]);
+ if ((err = mp_sub(&x, &y, &x)) != MP_OKAY) goto LBL_Y;
+ }
+
+ /* reset y by shifting it back down */
+ mp_rshd(&y, n - t);
+
+ /* step 3. for i from n down to (t + 1) */
+ for (i = n; i >= (t + 1); i--) {
+ if (i > x.used) {
+ continue;
+ }
+
+ /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
+ * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
+ if (x.dp[i] == y.dp[t]) {
+ q.dp[(i - t) - 1] = ((mp_digit)1 << (mp_digit)MP_DIGIT_BIT) - (mp_digit)1;
+ } else {
+ mp_word tmp;
+ tmp = (mp_word)x.dp[i] << (mp_word)MP_DIGIT_BIT;
+ tmp |= (mp_word)x.dp[i - 1];
+ tmp /= (mp_word)y.dp[t];
+ if (tmp > (mp_word)MP_MASK) {
+ tmp = MP_MASK;
+ }
+ q.dp[(i - t) - 1] = (mp_digit)(tmp & (mp_word)MP_MASK);
+ }
+
+ /* while (q{i-t-1} * (yt * b + y{t-1})) >
+ xi * b**2 + xi-1 * b + xi-2
+
+ do q{i-t-1} -= 1;
+ */
+ q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] + 1uL) & (mp_digit)MP_MASK;
+ do {
+ q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & (mp_digit)MP_MASK;
+
+ /* find left hand */
+ mp_zero(&t1);
+ t1.dp[0] = ((t - 1) < 0) ? 0u : y.dp[t - 1];
+ t1.dp[1] = y.dp[t];
+ t1.used = 2;
+ if ((err = mp_mul_d(&t1, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y;
+
+ /* find right hand */
+ t2.dp[0] = ((i - 2) < 0) ? 0u : x.dp[i - 2];
+ t2.dp[1] = x.dp[i - 1]; /* i >= 1 always holds */
+ t2.dp[2] = x.dp[i];
+ t2.used = 3;
+ } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+ /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
+ if ((err = mp_mul_d(&y, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y;
+ if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y;
+ if ((err = mp_sub(&x, &t1, &x)) != MP_OKAY) goto LBL_Y;
+
+ /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
+ if (mp_isneg(&x)) {
+ if ((err = mp_copy(&y, &t1)) != MP_OKAY) goto LBL_Y;
+ if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y;
+ if ((err = mp_add(&x, &t1, &x)) != MP_OKAY) goto LBL_Y;
+
+ q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & MP_MASK;
+ }
+ }
+
+ /* now q is the quotient and x is the remainder
+ * [which we have to normalize]
+ */
+
+ /* get sign before writing to c */
+ x.sign = mp_iszero(&x) ? MP_ZPOS : a->sign;
+
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ c->sign = (neg ? MP_NEG : MP_ZPOS);
+ }
+
+ if (d != NULL) {
+ if ((err = mp_div_2d(&x, norm, &x, NULL)) != MP_OKAY) goto LBL_Y;
+ mp_exch(&x, d);
+ }
+
+LBL_Y:
+ mp_clear(&y);
+LBL_X:
+ mp_clear(&x);
+LBL_T2:
+ mp_clear(&t2);
+LBL_T1:
+ mp_clear(&t1);
+LBL_Q:
+ mp_clear(&q);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_div_small.c b/src/libtommath/s_mp_div_small.c
new file mode 100644
index 000000000..2d951be1c
--- /dev/null
+++ b/src/libtommath/s_mp_div_small.c
@@ -0,0 +1,51 @@
+#include "tommath_private.h"
+#ifdef S_MP_DIV_SMALL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* slower bit-bang division... also smaller */
+mp_err s_mp_div_small(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d)
+{
+ mp_int ta, tb, tq, q;
+ int n;
+ bool neg;
+ mp_err err;
+
+ /* init our temps */
+ if ((err = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ mp_set(&tq, 1uL);
+ n = mp_count_bits(a) - mp_count_bits(b);
+ if ((err = mp_abs(a, &ta)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_abs(b, &tb)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul_2d(&tq, n, &tq)) != MP_OKAY) goto LBL_ERR;
+
+ while (n-- >= 0) {
+ if (mp_cmp(&tb, &ta) != MP_GT) {
+ if ((err = mp_sub(&ta, &tb, &ta)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&q, &tq, &q)) != MP_OKAY) goto LBL_ERR;
+ }
+ if ((err = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* now q == quotient and ta == remainder */
+
+ neg = (a->sign != b->sign);
+ if (c != NULL) {
+ mp_exch(c, &q);
+ c->sign = ((neg && !mp_iszero(c)) ? MP_NEG : MP_ZPOS);
+ }
+ if (d != NULL) {
+ mp_exch(d, &ta);
+ d->sign = (mp_iszero(d) ? MP_ZPOS : a->sign);
+ }
+LBL_ERR:
+ mp_clear_multi(&ta, &tb, &tq, &q, NULL);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_exptmod.c b/src/libtommath/s_mp_exptmod.c
new file mode 100644
index 000000000..2a89a2cbf
--- /dev/null
+++ b/src/libtommath/s_mp_exptmod.c
@@ -0,0 +1,198 @@
+#include "tommath_private.h"
+#ifdef S_MP_EXPTMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifdef MP_LOW_MEM
+# define TAB_SIZE 32
+# define MAX_WINSIZE 5
+#else
+# define TAB_SIZE 256
+# define MAX_WINSIZE 0
+#endif
+
+mp_err s_mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res, mu;
+ mp_digit buf;
+ mp_err err;
+ int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+ mp_err(*redux)(mp_int *x, const mp_int *m, const mp_int *mu);
+
+ /* find window size */
+ x = mp_count_bits(X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+ winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize;
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init(&M[1])) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init(&M[x])) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear(&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* create mu, used for Barrett reduction */
+ if ((err = mp_init(&mu)) != MP_OKAY) goto LBL_M;
+
+ if (redmode == 0) {
+ if ((err = mp_reduce_setup(&mu, P)) != MP_OKAY) goto LBL_MU;
+ redux = mp_reduce;
+ } else {
+ if ((err = mp_reduce_2k_setup_l(P, &mu)) != MP_OKAY) goto LBL_MU;
+ redux = mp_reduce_2k_l;
+ }
+
+ /* create M table
+ *
+ * The M table contains powers of the base,
+ * e.g. M[x] = G**x mod P
+ *
+ * The first half of the table is not
+ * computed though accept for M[0] and M[1]
+ */
+ if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) goto LBL_MU;
+
+ /* compute the value at M[1<<(winsize-1)] by squaring
+ * M[1] (winsize-1) times
+ */
+ if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_MU;
+
+ for (x = 0; x < (winsize - 1); x++) {
+ /* square it */
+ if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)],
+ &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_MU;
+
+ /* reduce modulo P */
+ if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, &mu)) != MP_OKAY) goto LBL_MU;
+ }
+
+ /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
+ * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
+ */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) goto LBL_MU;
+ if ((err = redux(&M[x], P, &mu)) != MP_OKAY) goto LBL_MU;
+ }
+
+ /* setup result */
+ if ((err = mp_init(&res)) != MP_OKAY) goto LBL_MU;
+ mp_set(&res, 1uL);
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset the bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int)MP_DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (buf >> (mp_digit)(MP_DIGIT_BIT - 1)) & 1uL;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if ((mode == 0) && (y == 0)) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if ((mode == 1) && (y == 0)) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* then multiply */
+ if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if ((mode == 2) && (bitcpy > 0)) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+ }
+ }
+ }
+
+ mp_exch(&res, Y);
+ err = MP_OKAY;
+LBL_RES:
+ mp_clear(&res);
+LBL_MU:
+ mp_clear(&mu);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear(&M[x]);
+ }
+ return err;
+}
+#endif
diff --git a/src/libtommath/s_mp_exptmod_fast.c b/src/libtommath/s_mp_exptmod_fast.c
new file mode 100644
index 000000000..e7729f49d
--- /dev/null
+++ b/src/libtommath/s_mp_exptmod_fast.c
@@ -0,0 +1,254 @@
+#include "tommath_private.h"
+#ifdef S_MP_EXPTMOD_FAST_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+ *
+ * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
+ * The value of k changes based on the size of the exponent.
+ *
+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+ */
+
+#ifdef MP_LOW_MEM
+# define TAB_SIZE 32
+# define MAX_WINSIZE 5
+#else
+# define TAB_SIZE 256
+# define MAX_WINSIZE 0
+#endif
+
+mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res;
+ mp_digit buf, mp;
+ int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+ mp_err err;
+
+ /* use a pointer to the reduction algorithm. This allows us to use
+ * one of many reduction algorithms without modding the guts of
+ * the code with if statements everywhere.
+ */
+ mp_err(*redux)(mp_int *x, const mp_int *n, mp_digit rho);
+
+ /* find window size */
+ x = mp_count_bits(X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+ winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize;
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear(&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* determine and setup reduction code */
+ if (redmode == 0) {
+ if (MP_HAS(MP_MONTGOMERY_SETUP)) {
+ /* now setup montgomery */
+ if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) goto LBL_M;
+ } else {
+ err = MP_VAL;
+ goto LBL_M;
+ }
+
+ /* automatically pick the comba one if available (saves quite a few calls/ifs) */
+ if (MP_HAS(S_MP_MONTGOMERY_REDUCE_COMBA) &&
+ (((P->used * 2) + 1) < MP_WARRAY) &&
+ (P->used < MP_MAX_COMBA)) {
+ redux = s_mp_montgomery_reduce_comba;
+ } else if (MP_HAS(MP_MONTGOMERY_REDUCE)) {
+ /* use slower baseline Montgomery method */
+ redux = mp_montgomery_reduce;
+ } else {
+ err = MP_VAL;
+ goto LBL_M;
+ }
+ } else if (redmode == 1) {
+ if (MP_HAS(MP_DR_SETUP) && MP_HAS(MP_DR_REDUCE)) {
+ /* setup DR reduction for moduli of the form B**k - b */
+ mp_dr_setup(P, &mp);
+ redux = mp_dr_reduce;
+ } else {
+ err = MP_VAL;
+ goto LBL_M;
+ }
+ } else if (MP_HAS(MP_REDUCE_2K_SETUP) && MP_HAS(MP_REDUCE_2K)) {
+ /* setup DR reduction for moduli of the form 2**k - b */
+ if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) goto LBL_M;
+ redux = mp_reduce_2k;
+ } else {
+ err = MP_VAL;
+ goto LBL_M;
+ }
+
+ /* setup result */
+ if ((err = mp_init_size(&res, P->alloc)) != MP_OKAY) goto LBL_M;
+
+ /* create M table
+ *
+
+ *
+ * The first half of the table is not computed though accept for M[0] and M[1]
+ */
+
+ if (redmode == 0) {
+ if (MP_HAS(MP_MONTGOMERY_CALC_NORMALIZATION)) {
+ /* now we need R mod m */
+ if ((err = mp_montgomery_calc_normalization(&res, P)) != MP_OKAY) goto LBL_RES;
+
+ /* now set M[1] to G * R mod m */
+ if ((err = mp_mulmod(G, &res, P, &M[1])) != MP_OKAY) goto LBL_RES;
+ } else {
+ err = MP_VAL;
+ goto LBL_RES;
+ }
+ } else {
+ mp_set(&res, 1uL);
+ if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
+ if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES;
+
+ for (x = 0; x < (winsize - 1); x++) {
+ if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* create upper table */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&M[x], P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits so break */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int)MP_DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (mp_digit)(buf >> (MP_DIGIT_BIT - 1)) & 1uL;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if ((mode == 0) && (y == 0)) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if ((mode == 1) && (y == 0)) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* then multiply */
+ if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if ((mode == 2) && (bitcpy > 0)) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+
+ /* get next bit of the window */
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+ }
+ }
+
+ if (redmode == 0) {
+ /* fixup result if Montgomery reduction is used
+ * recall that any value in a Montgomery system is
+ * actually multiplied by R mod n. So we have
+ * to reduce one more time to cancel out the factor
+ * of R.
+ */
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* swap res with Y */
+ mp_exch(&res, Y);
+ err = MP_OKAY;
+LBL_RES:
+ mp_clear(&res);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear(&M[x]);
+ }
+ return err;
+}
+#endif
diff --git a/src/libtommath/s_mp_get_bit.c b/src/libtommath/s_mp_get_bit.c
new file mode 100644
index 000000000..a509bcecb
--- /dev/null
+++ b/src/libtommath/s_mp_get_bit.c
@@ -0,0 +1,21 @@
+#include "tommath_private.h"
+#ifdef S_MP_GET_BIT_C
+
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Get bit at position b and return true if the bit is 1, false if it is 0 */
+bool s_mp_get_bit(const mp_int *a, int b)
+{
+ mp_digit bit;
+ int limb = b / MP_DIGIT_BIT;
+
+ if (limb < 0 || limb >= a->used) {
+ return false;
+ }
+
+ bit = (mp_digit)1 << (b % MP_DIGIT_BIT);
+ return ((a->dp[limb] & bit) != 0u);
+}
+
+#endif
diff --git a/src/libtommath/s_mp_invmod.c b/src/libtommath/s_mp_invmod.c
new file mode 100644
index 000000000..f3b3f436f
--- /dev/null
+++ b/src/libtommath/s_mp_invmod.c
@@ -0,0 +1,117 @@
+#include "tommath_private.h"
+#ifdef S_MP_INVMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* hac 14.61, pp608 */
+mp_err s_mp_invmod(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int x, y, u, v, A, B, C, D;
+ mp_err err;
+
+ /* b cannot be negative */
+ if ((b->sign == MP_NEG) || mp_iszero(b)) {
+ return MP_VAL;
+ }
+
+ /* init temps */
+ if ((err = mp_init_multi(&x, &y, &u, &v,
+ &A, &B, &C, &D, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* x = a, y = b */
+ if ((err = mp_mod(a, b, &x)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(b, &y)) != MP_OKAY) goto LBL_ERR;
+
+ /* 2. [modified] if x,y are both even then return an error! */
+ if (mp_iseven(&x) && mp_iseven(&y)) {
+ err = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+ if ((err = mp_copy(&x, &u)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&y, &v)) != MP_OKAY) goto LBL_ERR;
+ mp_set(&A, 1uL);
+ mp_set(&D, 1uL);
+
+ do {
+ /* 4. while u is even do */
+ while (mp_iseven(&u)) {
+ /* 4.1 u = u/2 */
+ if ((err = mp_div_2(&u, &u)) != MP_OKAY) goto LBL_ERR;
+
+ /* 4.2 if A or B is odd then */
+ if (mp_isodd(&A) || mp_isodd(&B)) {
+ /* A = (A+y)/2, B = (B-x)/2 */
+ if ((err = mp_add(&A, &y, &A)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&B, &x, &B)) != MP_OKAY) goto LBL_ERR;
+ }
+ /* A = A/2, B = B/2 */
+ if ((err = mp_div_2(&A, &A)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_div_2(&B, &B)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* 5. while v is even do */
+ while (mp_iseven(&v)) {
+ /* 5.1 v = v/2 */
+ if ((err = mp_div_2(&v, &v)) != MP_OKAY) goto LBL_ERR;
+
+ /* 5.2 if C or D is odd then */
+ if (mp_isodd(&C) || mp_isodd(&D)) {
+ /* C = (C+y)/2, D = (D-x)/2 */
+ if ((err = mp_add(&C, &y, &C)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&D, &x, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+ /* C = C/2, D = D/2 */
+ if ((err = mp_div_2(&C, &C)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_div_2(&D, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* 6. if u >= v then */
+ if (mp_cmp(&u, &v) != MP_LT) {
+ /* u = u - v, A = A - C, B = B - D */
+ if ((err = mp_sub(&u, &v, &u)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&A, &C, &A)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&B, &D, &B)) != MP_OKAY) goto LBL_ERR;
+ } else {
+ /* v - v - u, C = C - A, D = D - B */
+ if ((err = mp_sub(&v, &u, &v)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&C, &A, &C)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&D, &B, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* if not zero goto step 4 */
+ } while (!mp_iszero(&u));
+
+ /* now a = C, b = D, gcd == g*v */
+
+ /* if v != 1 then there is no inverse */
+ if (mp_cmp_d(&v, 1uL) != MP_EQ) {
+ err = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* if its too low */
+ while (mp_cmp_d(&C, 0uL) == MP_LT) {
+ if ((err = mp_add(&C, b, &C)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* too big */
+ while (mp_cmp_mag(&C, b) != MP_LT) {
+ if ((err = mp_sub(&C, b, &C)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* C is now the inverse */
+ mp_exch(&C, c);
+
+LBL_ERR:
+ mp_clear_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL);
+ return err;
+}
+#endif
diff --git a/src/libtommath/s_mp_invmod_odd.c b/src/libtommath/s_mp_invmod_odd.c
new file mode 100644
index 000000000..e12dfa17f
--- /dev/null
+++ b/src/libtommath/s_mp_invmod_odd.c
@@ -0,0 +1,116 @@
+#include "tommath_private.h"
+#ifdef S_MP_INVMOD_ODD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes the modular inverse via binary extended euclidean algorithm,
+ * that is c = 1/a mod b
+ *
+ * Based on slow invmod except this is optimized for the case where b is
+ * odd as per HAC Note 14.64 on pp. 610
+ */
+mp_err s_mp_invmod_odd(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int x, y, u, v, B, D;
+ mp_sign sign;
+ mp_err err;
+
+ /* 2. [modified] b must be odd */
+ if (mp_iseven(b)) {
+ return MP_VAL;
+ }
+
+ /* init all our temps */
+ if ((err = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* x == modulus, y == value to invert */
+ if ((err = mp_copy(b, &x)) != MP_OKAY) goto LBL_ERR;
+
+ /* we need y = |a| */
+ if ((err = mp_mod(a, b, &y)) != MP_OKAY) goto LBL_ERR;
+
+ /* if one of x,y is zero return an error! */
+ if (mp_iszero(&x) || mp_iszero(&y)) {
+ err = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+ if ((err = mp_copy(&x, &u)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&y, &v)) != MP_OKAY) goto LBL_ERR;
+ mp_set(&D, 1uL);
+
+ do {
+ /* 4. while u is even do */
+ while (mp_iseven(&u)) {
+ /* 4.1 u = u/2 */
+ if ((err = mp_div_2(&u, &u)) != MP_OKAY) goto LBL_ERR;
+
+ /* 4.2 if B is odd then */
+ if (mp_isodd(&B)) {
+ if ((err = mp_sub(&B, &x, &B)) != MP_OKAY) goto LBL_ERR;
+ }
+ /* B = B/2 */
+ if ((err = mp_div_2(&B, &B)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* 5. while v is even do */
+ while (mp_iseven(&v)) {
+ /* 5.1 v = v/2 */
+ if ((err = mp_div_2(&v, &v)) != MP_OKAY) goto LBL_ERR;
+
+ /* 5.2 if D is odd then */
+ if (mp_isodd(&D)) {
+ /* D = (D-x)/2 */
+ if ((err = mp_sub(&D, &x, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+ /* D = D/2 */
+ if ((err = mp_div_2(&D, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* 6. if u >= v then */
+ if (mp_cmp(&u, &v) != MP_LT) {
+ /* u = u - v, B = B - D */
+ if ((err = mp_sub(&u, &v, &u)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&B, &D, &B)) != MP_OKAY) goto LBL_ERR;
+ } else {
+ /* v - v - u, D = D - B */
+ if ((err = mp_sub(&v, &u, &v)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&D, &B, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* if not zero goto step 4 */
+ } while (!mp_iszero(&u));
+
+ /* now a = C, b = D, gcd == g*v */
+
+ /* if v != 1 then there is no inverse */
+ if (mp_cmp_d(&v, 1uL) != MP_EQ) {
+ err = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* b is now the inverse */
+ sign = a->sign;
+ while (mp_isneg(&D)) {
+ if ((err = mp_add(&D, b, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* too big */
+ while (mp_cmp_mag(&D, b) != MP_LT) {
+ if ((err = mp_sub(&D, b, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ mp_exch(&D, c);
+ c->sign = sign;
+ err = MP_OKAY;
+
+LBL_ERR:
+ mp_clear_multi(&x, &y, &u, &v, &B, &D, NULL);
+ return err;
+}
+#endif
diff --git a/src/libtommath/s_mp_log.c b/src/libtommath/s_mp_log.c
new file mode 100644
index 000000000..d1ac73b1a
--- /dev/null
+++ b/src/libtommath/s_mp_log.c
@@ -0,0 +1,81 @@
+#include "tommath_private.h"
+#ifdef S_MP_LOG_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_err s_mp_log(const mp_int *a, mp_digit base, int *c)
+{
+ mp_err err;
+ int high, low;
+ mp_int bracket_low, bracket_high, bracket_mid, t, bi_base;
+
+ mp_ord cmp = mp_cmp_d(a, base);
+ if ((cmp == MP_LT) || (cmp == MP_EQ)) {
+ *c = cmp == MP_EQ;
+ return MP_OKAY;
+ }
+
+ if ((err =
+ mp_init_multi(&bracket_low, &bracket_high,
+ &bracket_mid, &t, &bi_base, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ low = 0;
+ mp_set(&bracket_low, 1uL);
+ high = 1;
+
+ mp_set(&bracket_high, base);
+
+ /*
+ A kind of Giant-step/baby-step algorithm.
+ Idea shamelessly stolen from https://programmingpraxis.com/2010/05/07/integer-logarithms/2/
+ The effect is asymptotic, hence needs benchmarks to test if the Giant-step should be skipped
+ for small n.
+ */
+ while (mp_cmp(&bracket_high, a) == MP_LT) {
+ low = high;
+ if ((err = mp_copy(&bracket_high, &bracket_low)) != MP_OKAY) {
+ goto LBL_END;
+ }
+ high <<= 1;
+ if ((err = mp_sqr(&bracket_high, &bracket_high)) != MP_OKAY) {
+ goto LBL_END;
+ }
+ }
+ mp_set(&bi_base, base);
+
+ while ((high - low) > 1) {
+ int mid = (high + low) >> 1;
+
+ if ((err = mp_expt_n(&bi_base, mid - low, &t)) != MP_OKAY) {
+ goto LBL_END;
+ }
+ if ((err = mp_mul(&bracket_low, &t, &bracket_mid)) != MP_OKAY) {
+ goto LBL_END;
+ }
+ cmp = mp_cmp(a, &bracket_mid);
+ if (cmp == MP_LT) {
+ high = mid;
+ mp_exch(&bracket_mid, &bracket_high);
+ }
+ if (cmp == MP_GT) {
+ low = mid;
+ mp_exch(&bracket_mid, &bracket_low);
+ }
+ if (cmp == MP_EQ) {
+ *c = mid;
+ goto LBL_END;
+ }
+ }
+
+ *c = (mp_cmp(&bracket_high, a) == MP_EQ) ? high : low;
+
+LBL_END:
+ mp_clear_multi(&bracket_low, &bracket_high, &bracket_mid,
+ &t, &bi_base, NULL);
+ return err;
+}
+
+
+#endif
diff --git a/src/libtommath/s_mp_log_2expt.c b/src/libtommath/s_mp_log_2expt.c
new file mode 100644
index 000000000..ec0fda3b7
--- /dev/null
+++ b/src/libtommath/s_mp_log_2expt.c
@@ -0,0 +1,12 @@
+#include "tommath_private.h"
+#ifdef S_MP_LOG_2EXPT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+int s_mp_log_2expt(const mp_int *a, mp_digit base)
+{
+ int y;
+ for (y = 0; (base & 1) == 0; y++, base >>= 1) {}
+ return (mp_count_bits(a) - 1) / y;
+}
+#endif
diff --git a/src/libtommath/s_mp_log_d.c b/src/libtommath/s_mp_log_d.c
new file mode 100644
index 000000000..5ff6c1fba
--- /dev/null
+++ b/src/libtommath/s_mp_log_d.c
@@ -0,0 +1,65 @@
+#include "tommath_private.h"
+#ifdef S_MP_LOG_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+static mp_word s_pow(mp_word base, mp_word exponent)
+{
+ mp_word result = 1u;
+ while (exponent != 0u) {
+ if ((exponent & 1u) == 1u) {
+ result *= base;
+ }
+ exponent >>= 1;
+ base *= base;
+ }
+
+ return result;
+}
+
+int s_mp_log_d(mp_digit base, mp_digit n)
+{
+ mp_word bracket_low = 1uLL, bracket_high = base, N = n;
+ int ret, high = 1, low = 0;
+
+ if (n < base) {
+ return 0;
+ }
+ if (n == base) {
+ return 1;
+ }
+
+ while (bracket_high < N) {
+ low = high;
+ bracket_low = bracket_high;
+ high <<= 1;
+ bracket_high *= bracket_high;
+ }
+
+ while (((mp_digit)(high - low)) > 1uL) {
+ int mid = (low + high) >> 1;
+ mp_word bracket_mid = bracket_low * s_pow(base, (mp_word)(mid - low));
+
+ if (N < bracket_mid) {
+ high = mid ;
+ bracket_high = bracket_mid ;
+ }
+ if (N > bracket_mid) {
+ low = mid ;
+ bracket_low = bracket_mid ;
+ }
+ if (N == bracket_mid) {
+ return mid;
+ }
+ }
+
+ if (bracket_high == N) {
+ ret = high;
+ } else {
+ ret = low;
+ }
+
+ return ret;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_montgomery_reduce_comba.c b/src/libtommath/s_mp_montgomery_reduce_comba.c
new file mode 100644
index 000000000..6f249c49f
--- /dev/null
+++ b/src/libtommath/s_mp_montgomery_reduce_comba.c
@@ -0,0 +1,119 @@
+#include "tommath_private.h"
+#ifdef S_MP_MONTGOMERY_REDUCE_COMBA_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction
+ *
+ * This is an optimized implementation of montgomery_reduce
+ * which uses the comba method to quickly calculate the columns of the
+ * reduction.
+ *
+ * Based on Algorithm 14.32 on pp.601 of HAC.
+*/
+mp_err s_mp_montgomery_reduce_comba(mp_int *x, const mp_int *n, mp_digit rho)
+{
+ int ix, oldused;
+ mp_err err;
+ mp_word W[MP_WARRAY];
+
+ if (x->used > MP_WARRAY) {
+ return MP_VAL;
+ }
+
+ /* get old used count */
+ oldused = x->used;
+
+ /* grow a as required */
+ if ((err = mp_grow(x, n->used + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* first we have to get the digits of the input into
+ * an array of double precision words W[...]
+ */
+
+ /* copy the digits of a into W[0..a->used-1] */
+ for (ix = 0; ix < x->used; ix++) {
+ W[ix] = x->dp[ix];
+ }
+
+ /* zero the high words of W[a->used..m->used*2] */
+ if (ix < ((n->used * 2) + 1)) {
+ s_mp_zero_buf(W + x->used, sizeof(mp_word) * (size_t)(((n->used * 2) + 1) - ix));
+ }
+
+ /* now we proceed to zero successive digits
+ * from the least significant upwards
+ */
+ for (ix = 0; ix < n->used; ix++) {
+ int iy;
+ mp_digit mu;
+
+ /* mu = ai * m' mod b
+ *
+ * We avoid a double precision multiplication (which isn't required)
+ * by casting the value down to a mp_digit. Note this requires
+ * that W[ix-1] have the carry cleared (see after the inner loop)
+ */
+ mu = ((W[ix] & MP_MASK) * rho) & MP_MASK;
+
+ /* a = a + mu * m * b**i
+ *
+ * This is computed in place and on the fly. The multiplication
+ * by b**i is handled by offseting which columns the results
+ * are added to.
+ *
+ * Note the comba method normally doesn't handle carries in the
+ * inner loop In this case we fix the carry from the previous
+ * column since the Montgomery reduction requires digits of the
+ * result (so far) [see above] to work. This is
+ * handled by fixing up one carry after the inner loop. The
+ * carry fixups are done in order so after these loops the
+ * first m->used words of W[] have the carries fixed
+ */
+ for (iy = 0; iy < n->used; iy++) {
+ W[ix + iy] += (mp_word)mu * (mp_word)n->dp[iy];
+ }
+
+ /* now fix carry for next digit, W[ix+1] */
+ W[ix + 1] += W[ix] >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* now we have to propagate the carries and
+ * shift the words downward [all those least
+ * significant digits we zeroed].
+ */
+
+ for (; ix < (n->used * 2); ix++) {
+ W[ix + 1] += W[ix] >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* copy out, A = A/b**n
+ *
+ * The result is A/b**n but instead of converting from an
+ * array of mp_word to mp_digit than calling mp_rshd
+ * we just copy them in the right order
+ */
+
+ for (ix = 0; ix < (n->used + 1); ix++) {
+ x->dp[ix] = W[n->used + ix] & (mp_word)MP_MASK;
+ }
+
+ /* set the max used */
+ x->used = n->used + 1;
+
+ /* zero oldused digits, if the input a was larger than
+ * m->used+1 we'll have to clear the digits
+ */
+ s_mp_zero_digs(x->dp + x->used, oldused - x->used);
+
+ mp_clamp(x);
+
+ /* if A >= m then A = A - m */
+ if (mp_cmp_mag(x, n) != MP_LT) {
+ return s_mp_sub(x, n, x);
+ }
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/s_mp_mul.c b/src/libtommath/s_mp_mul.c
new file mode 100644
index 000000000..fb99d8054
--- /dev/null
+++ b/src/libtommath/s_mp_mul.c
@@ -0,0 +1,61 @@
+#include "tommath_private.h"
+#ifdef S_MP_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* multiplies |a| * |b| and only computes upto digs digits of result
+ * HAC pp. 595, Algorithm 14.12 Modified so you can control how
+ * many digits of output are created.
+ */
+mp_err s_mp_mul(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ mp_int t;
+ mp_err err;
+ int pa, ix;
+
+ /* can we use the fast multiplier? */
+ if ((digs < MP_WARRAY) &&
+ (MP_MIN(a->used, b->used) < MP_MAX_COMBA)) {
+ return s_mp_mul_comba(a, b, c, digs);
+ }
+
+ if ((err = mp_init_size(&t, digs)) != MP_OKAY) {
+ return err;
+ }
+ t.used = digs;
+
+ /* compute the digits of the product directly */
+ pa = a->used;
+ for (ix = 0; ix < pa; ix++) {
+ int iy, pb;
+ mp_digit u = 0;
+
+ /* limit ourselves to making digs digits of output */
+ pb = MP_MIN(b->used, digs - ix);
+
+ /* compute the columns of the output and propagate the carry */
+ for (iy = 0; iy < pb; iy++) {
+ /* compute the column as a mp_word */
+ mp_word r = (mp_word)t.dp[ix + iy] +
+ ((mp_word)a->dp[ix] * (mp_word)b->dp[iy]) +
+ (mp_word)u;
+
+ /* the new column is the lower part of the result */
+ t.dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* get the carry word from the result */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ }
+ /* set carry if it is placed below digs */
+ if ((ix + iy) < digs) {
+ t.dp[ix + pb] = u;
+ }
+ }
+
+ mp_clamp(&t);
+ mp_exch(&t, c);
+
+ mp_clear(&t);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/s_mp_mul_balance.c b/src/libtommath/s_mp_mul_balance.c
new file mode 100644
index 000000000..f36f0d30b
--- /dev/null
+++ b/src/libtommath/s_mp_mul_balance.c
@@ -0,0 +1,71 @@
+#include "tommath_private.h"
+#ifdef S_MP_MUL_BALANCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* single-digit multiplication with the smaller number as the single-digit */
+mp_err s_mp_mul_balance(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int a0, tmp, r;
+ mp_err err;
+ int i, j,
+ nblocks = MP_MAX(a->used, b->used) / MP_MIN(a->used, b->used),
+ bsize = MP_MIN(a->used, b->used);
+
+ if ((err = mp_init_size(&a0, bsize + 2)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_init_multi(&tmp, &r, NULL)) != MP_OKAY) {
+ mp_clear(&a0);
+ return err;
+ }
+
+ /* Make sure that A is the larger one*/
+ if (a->used < b->used) {
+ MP_EXCH(const mp_int *, a, b);
+ }
+
+ for (i = 0, j=0; i < nblocks; i++) {
+ /* Cut a slice off of a */
+ a0.used = bsize;
+ s_mp_copy_digs(a0.dp, a->dp + j, a0.used);
+ j += a0.used;
+ mp_clamp(&a0);
+
+ /* Multiply with b */
+ if ((err = mp_mul(&a0, b, &tmp)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* Shift tmp to the correct position */
+ if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* Add to output. No carry needed */
+ if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* The left-overs; there are always left-overs */
+ if (j < a->used) {
+ a0.used = a->used - j;
+ s_mp_copy_digs(a0.dp, a->dp + j, a0.used);
+ j += a0.used;
+ mp_clamp(&a0);
+
+ if ((err = mp_mul(&a0, b, &tmp)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ mp_exch(&r,c);
+LBL_ERR:
+ mp_clear_multi(&a0, &tmp, &r,NULL);
+ return err;
+}
+#endif
diff --git a/src/libtommath/s_mp_mul_comba.c b/src/libtommath/s_mp_mul_comba.c
new file mode 100644
index 000000000..07dd7913d
--- /dev/null
+++ b/src/libtommath/s_mp_mul_comba.c
@@ -0,0 +1,78 @@
+#include "tommath_private.h"
+#ifdef S_MP_MUL_COMBA_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Fast (comba) multiplier
+ *
+ * This is the fast column-array [comba] multiplier. It is
+ * designed to compute the columns of the product first
+ * then handle the carries afterwards. This has the effect
+ * of making the nested loops that compute the columns very
+ * simple and schedulable on super-scalar processors.
+ *
+ * This has been modified to produce a variable number of
+ * digits of output so if say only a half-product is required
+ * you don't have to compute the upper half (a feature
+ * required for fast Barrett reduction).
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ *
+ */
+mp_err s_mp_mul_comba(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ int oldused, pa, ix;
+ mp_err err;
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
+ /* grow the destination as required */
+ if ((err = mp_grow(c, digs)) != MP_OKAY) {
+ return err;
+ }
+
+ /* number of output digits to produce */
+ pa = MP_MIN(digs, a->used + b->used);
+
+ /* clear the carry */
+ _W = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty, iy, iz;
+
+ /* get offsets into the two bignums */
+ ty = MP_MIN(b->used-1, ix);
+ tx = ix - ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MP_MIN(a->used-tx, ty+1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; ++iz) {
+ _W += (mp_word)a->dp[tx + iz] * (mp_word)b->dp[ty - iz];
+ }
+
+ /* store term */
+ W[ix] = (mp_digit)_W & MP_MASK;
+
+ /* make next carry */
+ _W = _W >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* setup dest */
+ oldused = c->used;
+ c->used = pa;
+
+ for (ix = 0; ix < pa; ix++) {
+ /* now extract the previous digit [below the carry] */
+ c->dp[ix] = W[ix];
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ s_mp_zero_digs(c->dp + c->used, oldused - c->used);
+
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/s_mp_mul_high.c b/src/libtommath/s_mp_mul_high.c
new file mode 100644
index 000000000..1bde00aa9
--- /dev/null
+++ b/src/libtommath/s_mp_mul_high.c
@@ -0,0 +1,52 @@
+#include "tommath_private.h"
+#ifdef S_MP_MUL_HIGH_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* multiplies |a| * |b| and does not compute the lower digs digits
+ * [meant to get the higher part of the product]
+ */
+mp_err s_mp_mul_high(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ mp_int t;
+ int pa, pb, ix;
+ mp_err err;
+
+ /* can we use the fast multiplier? */
+ if (MP_HAS(S_MP_MUL_HIGH_COMBA)
+ && ((a->used + b->used + 1) < MP_WARRAY)
+ && (MP_MIN(a->used, b->used) < MP_MAX_COMBA)) {
+ return s_mp_mul_high_comba(a, b, c, digs);
+ }
+
+ if ((err = mp_init_size(&t, a->used + b->used + 1)) != MP_OKAY) {
+ return err;
+ }
+ t.used = a->used + b->used + 1;
+
+ pa = a->used;
+ pb = b->used;
+ for (ix = 0; ix < pa; ix++) {
+ int iy;
+ mp_digit u = 0;
+
+ for (iy = digs - ix; iy < pb; iy++) {
+ /* calculate the double precision result */
+ mp_word r = (mp_word)t.dp[ix + iy] +
+ ((mp_word)a->dp[ix] * (mp_word)b->dp[iy]) +
+ (mp_word)u;
+
+ /* get the lower part */
+ t.dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* carry the carry */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ }
+ t.dp[ix + pb] = u;
+ }
+ mp_clamp(&t);
+ mp_exch(&t, c);
+ mp_clear(&t);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/s_mp_mul_high_comba.c b/src/libtommath/s_mp_mul_high_comba.c
new file mode 100644
index 000000000..317346dfa
--- /dev/null
+++ b/src/libtommath/s_mp_mul_high_comba.c
@@ -0,0 +1,70 @@
+#include "tommath_private.h"
+#ifdef S_MP_MUL_HIGH_COMBA_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* this is a modified version of s_mp_mul_comba that only produces
+ * output digits *above* digs. See the comments for s_mp_mul_comba
+ * to see how it works.
+ *
+ * This is used in the Barrett reduction since for one of the multiplications
+ * only the higher digits were needed. This essentially halves the work.
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ */
+mp_err s_mp_mul_high_comba(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ int oldused, pa, ix;
+ mp_err err;
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
+ /* grow the destination as required */
+ pa = a->used + b->used;
+ if ((err = mp_grow(c, pa)) != MP_OKAY) {
+ return err;
+ }
+
+ /* number of output digits to produce */
+ pa = a->used + b->used;
+ _W = 0;
+ for (ix = digs; ix < pa; ix++) {
+ int tx, ty, iy, iz;
+
+ /* get offsets into the two bignums */
+ ty = MP_MIN(b->used-1, ix);
+ tx = ix - ty;
+
+ /* this is the number of times the loop will iterrate, essentially its
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MP_MIN(a->used-tx, ty+1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; iz++) {
+ _W += (mp_word)a->dp[tx + iz] * (mp_word)b->dp[ty - iz];
+ }
+
+ /* store term */
+ W[ix] = (mp_digit)_W & MP_MASK;
+
+ /* make next carry */
+ _W = _W >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* setup dest */
+ oldused = c->used;
+ c->used = pa;
+
+ for (ix = digs; ix < pa; ix++) {
+ /* now extract the previous digit [below the carry] */
+ c->dp[ix] = W[ix];
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ s_mp_zero_digs(c->dp + c->used, oldused - c->used);
+
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/s_mp_mul_karatsuba.c b/src/libtommath/s_mp_mul_karatsuba.c
new file mode 100644
index 000000000..bf9271f3b
--- /dev/null
+++ b/src/libtommath/s_mp_mul_karatsuba.c
@@ -0,0 +1,151 @@
+#include "tommath_private.h"
+#ifdef S_MP_MUL_KARATSUBA_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* c = |a| * |b| using Karatsuba Multiplication using
+ * three half size multiplications
+ *
+ * Let B represent the radix [e.g. 2**MP_DIGIT_BIT] and
+ * let n represent half of the number of digits in
+ * the min(a,b)
+ *
+ * a = a1 * B**n + a0
+ * b = b1 * B**n + b0
+ *
+ * Then, a * b =>
+ a1b1 * B**2n + ((a1 + a0)(b1 + b0) - (a0b0 + a1b1)) * B + a0b0
+ *
+ * Note that a1b1 and a0b0 are used twice and only need to be
+ * computed once. So in total three half size (half # of
+ * digit) multiplications are performed, a0b0, a1b1 and
+ * (a1+b1)(a0+b0)
+ *
+ * Note that a multiplication of half the digits requires
+ * 1/4th the number of single precision multiplications so in
+ * total after one call 25% of the single precision multiplications
+ * are saved. Note also that the call to mp_mul can end up back
+ * in this function if the a0, a1, b0, or b1 are above the threshold.
+ * This is known as divide-and-conquer and leads to the famous
+ * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than
+ * the standard O(N**2) that the baseline/comba methods use.
+ * Generally though the overhead of this method doesn't pay off
+ * until a certain size (N ~ 80) is reached.
+ */
+mp_err s_mp_mul_karatsuba(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int x0, x1, y0, y1, t1, x0y0, x1y1;
+ int B;
+ mp_err err;
+
+ /* min # of digits */
+ B = MP_MIN(a->used, b->used);
+
+ /* now divide in two */
+ B = B >> 1;
+
+ /* init copy all the temps */
+ if ((err = mp_init_size(&x0, B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_init_size(&x1, a->used - B)) != MP_OKAY) {
+ goto X0;
+ }
+ if ((err = mp_init_size(&y0, B)) != MP_OKAY) {
+ goto X1;
+ }
+ if ((err = mp_init_size(&y1, b->used - B)) != MP_OKAY) {
+ goto Y0;
+ }
+
+ /* init temps */
+ if ((err = mp_init_size(&t1, B * 2)) != MP_OKAY) {
+ goto Y1;
+ }
+ if ((err = mp_init_size(&x0y0, B * 2)) != MP_OKAY) {
+ goto T1;
+ }
+ if ((err = mp_init_size(&x1y1, B * 2)) != MP_OKAY) {
+ goto X0Y0;
+ }
+
+ /* now shift the digits */
+ x0.used = y0.used = B;
+ x1.used = a->used - B;
+ y1.used = b->used - B;
+
+ /* we copy the digits directly instead of using higher level functions
+ * since we also need to shift the digits
+ */
+ s_mp_copy_digs(x0.dp, a->dp, x0.used);
+ s_mp_copy_digs(y0.dp, b->dp, y0.used);
+ s_mp_copy_digs(x1.dp, a->dp + B, x1.used);
+ s_mp_copy_digs(y1.dp, b->dp + B, y1.used);
+
+ /* only need to clamp the lower words since by definition the
+ * upper words x1/y1 must have a known number of digits
+ */
+ mp_clamp(&x0);
+ mp_clamp(&y0);
+
+ /* now calc the products x0y0 and x1y1 */
+ /* after this x0 is no longer required, free temp [x0==t2]! */
+ if ((err = mp_mul(&x0, &y0, &x0y0)) != MP_OKAY) {
+ goto X1Y1; /* x0y0 = x0*y0 */
+ }
+ if ((err = mp_mul(&x1, &y1, &x1y1)) != MP_OKAY) {
+ goto X1Y1; /* x1y1 = x1*y1 */
+ }
+
+ /* now calc x1+x0 and y1+y0 */
+ if ((err = s_mp_add(&x1, &x0, &t1)) != MP_OKAY) {
+ goto X1Y1; /* t1 = x1 - x0 */
+ }
+ if ((err = s_mp_add(&y1, &y0, &x0)) != MP_OKAY) {
+ goto X1Y1; /* t2 = y1 - y0 */
+ }
+ if ((err = mp_mul(&t1, &x0, &t1)) != MP_OKAY) {
+ goto X1Y1; /* t1 = (x1 + x0) * (y1 + y0) */
+ }
+
+ /* add x0y0 */
+ if ((err = mp_add(&x0y0, &x1y1, &x0)) != MP_OKAY) {
+ goto X1Y1; /* t2 = x0y0 + x1y1 */
+ }
+ if ((err = s_mp_sub(&t1, &x0, &t1)) != MP_OKAY) {
+ goto X1Y1; /* t1 = (x1+x0)*(y1+y0) - (x1y1 + x0y0) */
+ }
+
+ /* shift by B */
+ if ((err = mp_lshd(&t1, B)) != MP_OKAY) {
+ goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<<B */
+ }
+ if ((err = mp_lshd(&x1y1, B * 2)) != MP_OKAY) {
+ goto X1Y1; /* x1y1 = x1y1 << 2*B */
+ }
+
+ if ((err = mp_add(&x0y0, &t1, &t1)) != MP_OKAY) {
+ goto X1Y1; /* t1 = x0y0 + t1 */
+ }
+ if ((err = mp_add(&t1, &x1y1, c)) != MP_OKAY) {
+ goto X1Y1; /* t1 = x0y0 + t1 + x1y1 */
+ }
+
+X1Y1:
+ mp_clear(&x1y1);
+X0Y0:
+ mp_clear(&x0y0);
+T1:
+ mp_clear(&t1);
+Y1:
+ mp_clear(&y1);
+Y0:
+ mp_clear(&y0);
+X1:
+ mp_clear(&x1);
+X0:
+ mp_clear(&x0);
+LBL_ERR:
+ return err;
+}
+#endif
diff --git a/src/libtommath/s_mp_mul_toom.c b/src/libtommath/s_mp_mul_toom.c
new file mode 100644
index 000000000..f6c2b103a
--- /dev/null
+++ b/src/libtommath/s_mp_mul_toom.c
@@ -0,0 +1,202 @@
+#include "tommath_private.h"
+#ifdef S_MP_MUL_TOOM_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* multiplication using the Toom-Cook 3-way algorithm
+ *
+ * Much more complicated than Karatsuba but has a lower
+ * asymptotic running time of O(N**1.464). This algorithm is
+ * only particularly useful on VERY large inputs
+ * (we're talking 1000s of digits here...).
+*/
+
+/*
+ This file contains code from J. Arndt's book "Matters Computational"
+ and the accompanying FXT-library with permission of the author.
+*/
+
+/*
+ Setup from
+
+ Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae."
+ 18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007.
+
+ The interpolation from above needed one temporary variable more
+ than the interpolation here:
+
+ Bodrato, Marco, and Alberto Zanoni. "What about Toom-Cook matrices optimality."
+ Centro Vito Volterra Universita di Roma Tor Vergata (2006)
+*/
+
+mp_err s_mp_mul_toom(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int S1, S2, T1, a0, a1, a2, b0, b1, b2;
+ int B;
+ mp_err err;
+
+ /* init temps */
+ if ((err = mp_init_multi(&S1, &S2, &T1, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* B */
+ B = MP_MIN(a->used, b->used) / 3;
+
+ /** a = a2 * x^2 + a1 * x + a0; */
+ if ((err = mp_init_size(&a0, B)) != MP_OKAY) goto LBL_ERRa0;
+ if ((err = mp_init_size(&a1, B)) != MP_OKAY) goto LBL_ERRa1;
+ if ((err = mp_init_size(&a2, a->used - 2 * B)) != MP_OKAY) goto LBL_ERRa2;
+
+ a0.used = a1.used = B;
+ a2.used = a->used - 2 * B;
+ s_mp_copy_digs(a0.dp, a->dp, a0.used);
+ s_mp_copy_digs(a1.dp, a->dp + B, a1.used);
+ s_mp_copy_digs(a2.dp, a->dp + 2 * B, a2.used);
+ mp_clamp(&a0);
+ mp_clamp(&a1);
+ mp_clamp(&a2);
+
+ /** b = b2 * x^2 + b1 * x + b0; */
+ if ((err = mp_init_size(&b0, B)) != MP_OKAY) goto LBL_ERRb0;
+ if ((err = mp_init_size(&b1, B)) != MP_OKAY) goto LBL_ERRb1;
+ if ((err = mp_init_size(&b2, b->used - 2 * B)) != MP_OKAY) goto LBL_ERRb2;
+
+ b0.used = b1.used = B;
+ b2.used = b->used - 2 * B;
+ s_mp_copy_digs(b0.dp, b->dp, b0.used);
+ s_mp_copy_digs(b1.dp, b->dp + B, b1.used);
+ s_mp_copy_digs(b2.dp, b->dp + 2 * B, b2.used);
+ mp_clamp(&b0);
+ mp_clamp(&b1);
+ mp_clamp(&b2);
+
+ /** \\ S1 = (a2+a1+a0) * (b2+b1+b0); */
+ /** T1 = a2 + a1; */
+ if ((err = mp_add(&a2, &a1, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = T1 + a0; */
+ if ((err = mp_add(&T1, &a0, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** c = b2 + b1; */
+ if ((err = mp_add(&b2, &b1, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = c + b0; */
+ if ((err = mp_add(c, &b0, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = S1 * S2; */
+ if ((err = mp_mul(&S1, &S2, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S2 = (4*a2+2*a1+a0) * (4*b2+2*b1+b0); */
+ /** T1 = T1 + a2; */
+ if ((err = mp_add(&T1, &a2, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** T1 = T1 << 1; */
+ if ((err = mp_mul_2(&T1, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** T1 = T1 + a0; */
+ if ((err = mp_add(&T1, &a0, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** c = c + b2; */
+ if ((err = mp_add(c, &b2, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** c = c << 1; */
+ if ((err = mp_mul_2(c, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** c = c + b0; */
+ if ((err = mp_add(c, &b0, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = T1 * c; */
+ if ((err = mp_mul(&T1, c, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S3 = (a2-a1+a0) * (b2-b1+b0); */
+ /** a1 = a2 - a1; */
+ if ((err = mp_sub(&a2, &a1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = a1 + a0; */
+ if ((err = mp_add(&a1, &a0, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** b1 = b2 - b1; */
+ if ((err = mp_sub(&b2, &b1, &b1)) != MP_OKAY) goto LBL_ERR;
+
+ /** b1 = b1 + b0; */
+ if ((err = mp_add(&b1, &b0, &b1)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = a1 * b1; */
+ if ((err = mp_mul(&a1, &b1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** b1 = a2 * b2; */
+ if ((err = mp_mul(&a2, &b2, &b1)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S2 = (S2 - S3)/3; */
+ /** S2 = S2 - a1; */
+ if ((err = mp_sub(&S2, &a1, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = S2 / 3; \\ this is an exact division */
+ if ((err = s_mp_div_3(&S2, &S2, NULL)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = S1 - a1; */
+ if ((err = mp_sub(&S1, &a1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = a1 >> 1; */
+ if ((err = mp_div_2(&a1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** a0 = a0 * b0; */
+ if ((err = mp_mul(&a0, &b0, &a0)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = S1 - a0; */
+ if ((err = mp_sub(&S1, &a0, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = S2 - S1; */
+ if ((err = mp_sub(&S2, &S1, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = S2 >> 1; */
+ if ((err = mp_div_2(&S2, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = S1 - a1; */
+ if ((err = mp_sub(&S1, &a1, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = S1 - b1; */
+ if ((err = mp_sub(&S1, &b1, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** T1 = b1 << 1; */
+ if ((err = mp_mul_2(&b1, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = S2 - T1; */
+ if ((err = mp_sub(&S2, &T1, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = a1 - S2; */
+ if ((err = mp_sub(&a1, &S2, &a1)) != MP_OKAY) goto LBL_ERR;
+
+
+ /** P = b1*x^4+ S2*x^3+ S1*x^2+ a1*x + a0; */
+ if ((err = mp_lshd(&b1, 4 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&S2, 3 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&b1, &S2, &b1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&S1, 2 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&b1, &S1, &b1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&a1, 1 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&b1, &a1, &b1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&b1, &a0, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** a * b - P */
+
+
+LBL_ERR:
+ mp_clear(&b2);
+LBL_ERRb2:
+ mp_clear(&b1);
+LBL_ERRb1:
+ mp_clear(&b0);
+LBL_ERRb0:
+ mp_clear(&a2);
+LBL_ERRa2:
+ mp_clear(&a1);
+LBL_ERRa1:
+ mp_clear(&a0);
+LBL_ERRa0:
+ mp_clear_multi(&S1, &S2, &T1, NULL);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_prime_is_divisible.c b/src/libtommath/s_mp_prime_is_divisible.c
new file mode 100644
index 000000000..63b2405ab
--- /dev/null
+++ b/src/libtommath/s_mp_prime_is_divisible.c
@@ -0,0 +1,33 @@
+#include "tommath_private.h"
+#ifdef S_MP_PRIME_IS_DIVISIBLE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines if an integers is divisible by one
+ * of the first PRIME_SIZE primes or not
+ *
+ * sets result to 0 if not, 1 if yes
+ */
+mp_err s_mp_prime_is_divisible(const mp_int *a, bool *result)
+{
+ int i;
+ for (i = 0; i < MP_PRIME_TAB_SIZE; i++) {
+ /* what is a mod LBL_prime_tab[i] */
+ mp_err err;
+ mp_digit res;
+ if ((err = mp_mod_d(a, s_mp_prime_tab[i], &res)) != MP_OKAY) {
+ return err;
+ }
+
+ /* is the residue zero? */
+ if (res == 0u) {
+ *result = true;
+ return MP_OKAY;
+ }
+ }
+
+ /* default to not */
+ *result = false;
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/s_mp_prime_tab.c b/src/libtommath/s_mp_prime_tab.c
new file mode 100644
index 000000000..87c07fd95
--- /dev/null
+++ b/src/libtommath/s_mp_prime_tab.c
@@ -0,0 +1,44 @@
+#include "tommath_private.h"
+#ifdef S_MP_PRIME_TAB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+const mp_digit s_mp_prime_tab[] = {
+ 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+ 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
+ 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
+ 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083,
+ 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
+ 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
+ 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
+ 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
+
+ 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
+ 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
+ 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
+ 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
+ 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
+ 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
+ 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
+ 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
+
+ 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
+ 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
+ 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
+ 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
+ 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
+ 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
+ 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
+ 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
+
+ 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
+ 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
+ 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
+ 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
+ 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
+ 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
+ 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
+ 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
+};
+
+#endif
diff --git a/src/libtommath/s_mp_radix_map.c b/src/libtommath/s_mp_radix_map.c
new file mode 100644
index 000000000..68e21f32e
--- /dev/null
+++ b/src/libtommath/s_mp_radix_map.c
@@ -0,0 +1,19 @@
+#include "tommath_private.h"
+#ifdef S_MP_RADIX_MAP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* chars used in radix conversions */
+const char s_mp_radix_map[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+const uint8_t s_mp_radix_map_reverse[] = {
+ 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, /* +,-./01234 */
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56789:;<=> */
+ 0xff, 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, /* ?@ABCDEFGH */
+ 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, /* IJKLMNOPQR */
+ 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0xff, 0xff, /* STUVWXYZ[\ */
+ 0xff, 0xff, 0xff, 0xff, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, /* ]^_`abcdef */
+ 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, /* ghijklmnop */
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d /* qrstuvwxyz */
+};
+MP_STATIC_ASSERT(correct_radix_map_reverse_size, sizeof(s_mp_radix_map_reverse) == MP_RADIX_MAP_REVERSE_SIZE)
+#endif
diff --git a/src/libtommath/s_mp_radix_size_overestimate.c b/src/libtommath/s_mp_radix_size_overestimate.c
new file mode 100644
index 000000000..4f0599732
--- /dev/null
+++ b/src/libtommath/s_mp_radix_size_overestimate.c
@@ -0,0 +1,82 @@
+#include "tommath_private.h"
+#ifdef S_MP_RADIX_SIZE_OVERESTIMATE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ Overestimate the size needed for the bigint to string conversion by a very small amount.
+ The error is about 10^-8; it will overestimate the result by at most 11 elements for
+ a number of the size 2^(2^31)-1 which is currently the largest possible in this library.
+ Some short tests gave no results larger than 5 (plus 2 for sign and EOS).
+ */
+
+/*
+ Table of {0, INT(log_2([1..64])*2^p)+1 } where p is the scale
+ factor defined in MP_RADIX_SIZE_SCALE and INT() extracts the integer part (truncating).
+ Good for 32 bit "int". Set MP_RADIX_SIZE_SCALE = 61 and recompute values
+ for 64 bit "int".
+ */
+/* *INDENT-OFF* */
+#define MP_RADIX_SIZE_SCALE 29
+static const uint32_t s_log_bases[65] = {
+ 0u, 0u, 0x20000001u, 0x14309399u, 0x10000001u,
+ 0xdc81a35u, 0xc611924u, 0xb660c9eu, 0xaaaaaabu, 0xa1849cdu,
+ 0x9a209a9u, 0x94004e1u, 0x8ed19c2u, 0x8a5ca7du, 0x867a000u,
+ 0x830cee3u, 0x8000001u, 0x7d42d60u, 0x7ac8b32u, 0x7887847u,
+ 0x7677349u, 0x749131fu, 0x72d0163u, 0x712f657u, 0x6fab5dbu,
+ 0x6e40d1bu, 0x6ced0d0u, 0x6badbdeu, 0x6a80e3bu, 0x6964c19u,
+ 0x6857d31u, 0x6758c38u, 0x6666667u, 0x657fb21u, 0x64a3b9fu,
+ 0x63d1ab4u, 0x6308c92u, 0x624869eu, 0x618ff47u, 0x60dedeau,
+ 0x6034ab0u, 0x5f90e7bu, 0x5ef32cbu, 0x5e5b1b2u, 0x5dc85c3u,
+ 0x5d3aa02u, 0x5cb19d9u, 0x5c2d10fu, 0x5bacbbfu, 0x5b3064fu,
+ 0x5ab7d68u, 0x5a42df0u, 0x59d1506u, 0x5962ffeu, 0x58f7c57u,
+ 0x588f7bcu, 0x582a000u, 0x57c7319u, 0x5766f1du, 0x5709243u,
+ 0x56adad9u, 0x565474du, 0x55fd61fu, 0x55a85e8u, 0x5555556u
+};
+/* *INDENT-ON* */
+
+mp_err s_mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size)
+{
+ int bit_count;
+ mp_int bi_bit_count, bi_k;
+ mp_err err = MP_OKAY;
+
+ if ((radix < 2) || (radix > 64)) {
+ return MP_VAL;
+ }
+
+ if (mp_iszero(a)) {
+ *size = 2U;
+ return MP_OKAY;
+ }
+
+ if (MP_HAS(S_MP_LOG_2EXPT) && MP_IS_2EXPT((mp_digit)radix)) {
+ /* floor(log_{2^n}(a)) + 1 + EOS + sign */
+ *size = (size_t)(s_mp_log_2expt(a, (mp_digit)radix) + 3);
+ return MP_OKAY;
+ }
+
+ if ((err = mp_init_multi(&bi_bit_count, &bi_k, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* la = floor(log_2(a)) + 1 */
+ bit_count = mp_count_bits(a);
+
+ mp_set_u32(&bi_bit_count, (uint32_t)bit_count);
+ /* k = floor(2^29/log_2(radix)) + 1 */
+ mp_set_u32(&bi_k, s_log_bases[radix]);
+ /* n = floor((la * k) / 2^29) + 1 */
+ if ((err = mp_mul(&bi_bit_count, &bi_k, &bi_bit_count)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_div_2d(&bi_bit_count, MP_RADIX_SIZE_SCALE, &bi_bit_count, NULL)) != MP_OKAY) goto LBL_ERR;
+
+ /* The "+1" here is the "+1" in "floor((la * k) / 2^29) + 1" */
+ /* n = n + 1 + EOS + sign */
+ *size = (size_t)(mp_get_u64(&bi_bit_count) + 3U);
+
+LBL_ERR:
+ mp_clear_multi(&bi_bit_count, &bi_k, NULL);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_rand_platform.c b/src/libtommath/s_mp_rand_platform.c
new file mode 100644
index 000000000..06b2f1bda
--- /dev/null
+++ b/src/libtommath/s_mp_rand_platform.c
@@ -0,0 +1,149 @@
+#include "tommath_private.h"
+#ifdef S_MP_RAND_PLATFORM_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* First the OS-specific special cases
+ * - *BSD
+ * - Windows
+ */
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+#define S_READ_ARC4RANDOM_C
+static mp_err s_read_arc4random(void *p, size_t n)
+{
+ arc4random_buf(p, n);
+ return MP_OKAY;
+}
+#endif
+
+#if defined(_WIN32)
+#define S_READ_WINCSP_C
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#ifndef WINVER
+#define WINVER 0x0501
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <wincrypt.h>
+
+static mp_err s_read_wincsp(void *p, size_t n)
+{
+ static HCRYPTPROV hProv = 0;
+ if (hProv == 0) {
+ HCRYPTPROV h = 0;
+ if (!CryptAcquireContextW(&h, NULL, MS_DEF_PROV_W, PROV_RSA_FULL,
+ (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
+ !CryptAcquireContextW(&h, NULL, MS_DEF_PROV_W, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) {
+ return MP_ERR;
+ }
+ hProv = h;
+ }
+ return CryptGenRandom(hProv, (DWORD)n, (BYTE *)p) == TRUE ? MP_OKAY : MP_ERR;
+}
+#endif /* WIN32 */
+
+#if !defined(S_READ_WINCSP_C) && defined(__linux__) && defined(__GLIBC_PREREQ)
+#if __GLIBC_PREREQ(2, 25)
+#define S_READ_GETRANDOM_C
+#include <sys/random.h>
+#include <errno.h>
+
+static mp_err s_read_getrandom(void *p, size_t n)
+{
+ char *q = (char *)p;
+ while (n > 0u) {
+ ssize_t ret = getrandom(q, n, 0);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return MP_ERR;
+ }
+ q += ret;
+ n -= (size_t)ret;
+ }
+ return MP_OKAY;
+}
+#endif
+#endif
+
+/* We assume all platforms besides windows provide "/dev/urandom".
+ * In case yours doesn't, define MP_NO_DEV_URANDOM at compile-time.
+ */
+#if !defined(S_READ_WINCSP_C) && !defined(MP_NO_DEV_URANDOM)
+#define S_READ_URANDOM_C
+#ifndef MP_DEV_URANDOM
+#define MP_DEV_URANDOM "/dev/urandom"
+#endif
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+static mp_err s_read_urandom(void *p, size_t n)
+{
+ int fd;
+ char *q = (char *)p;
+
+ do {
+ fd = open(MP_DEV_URANDOM, O_RDONLY);
+ } while ((fd == -1) && (errno == EINTR));
+ if (fd == -1) return MP_ERR;
+
+ while (n > 0u) {
+ ssize_t ret = read(fd, p, n);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ close(fd);
+ return MP_ERR;
+ }
+ q += ret;
+ n -= (size_t)ret;
+ }
+
+ close(fd);
+ return MP_OKAY;
+}
+#endif
+
+mp_err s_read_arc4random(void *p, size_t n);
+mp_err s_read_wincsp(void *p, size_t n);
+mp_err s_read_getrandom(void *p, size_t n);
+mp_err s_read_urandom(void *p, size_t n);
+
+/*
+ * Note: libtommath relies on dead code elimination
+ * for the configuration system, i.e., the MP_HAS macro.
+ *
+ * If you observe linking errors in this functions,
+ * your compiler does not perform the dead code compilation
+ * such that the unused functions are still referenced.
+ *
+ * This happens for example for MSVC if the /Od compilation
+ * option is given. The option /Od instructs MSVC to
+ * not perform any "optimizations", not even removal of
+ * dead code wrapped in `if (0)` blocks.
+ *
+ * If you still insist on compiling with /Od, simply
+ * comment out the lines which result in linking errors.
+ *
+ * We intentionally don't fix this issue in order
+ * to have a single point of failure for misconfigured compilers.
+ */
+mp_err s_mp_rand_platform(void *p, size_t n)
+{
+ mp_err err = MP_ERR;
+ if ((err != MP_OKAY) && MP_HAS(S_READ_ARC4RANDOM)) err = s_read_arc4random(p, n);
+ if ((err != MP_OKAY) && MP_HAS(S_READ_WINCSP)) err = s_read_wincsp(p, n);
+ if ((err != MP_OKAY) && MP_HAS(S_READ_GETRANDOM)) err = s_read_getrandom(p, n);
+ if ((err != MP_OKAY) && MP_HAS(S_READ_URANDOM)) err = s_read_urandom(p, n);
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_sqr.c b/src/libtommath/s_mp_sqr.c
new file mode 100644
index 000000000..4a2030638
--- /dev/null
+++ b/src/libtommath/s_mp_sqr.c
@@ -0,0 +1,65 @@
+#include "tommath_private.h"
+#ifdef S_MP_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
+mp_err s_mp_sqr(const mp_int *a, mp_int *b)
+{
+ mp_int t;
+ int ix, pa;
+ mp_err err;
+
+ pa = a->used;
+ if ((err = mp_init_size(&t, (2 * pa) + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* default used is maximum possible size */
+ t.used = (2 * pa) + 1;
+
+ for (ix = 0; ix < pa; ix++) {
+ mp_digit u;
+ int iy;
+
+ /* first calculate the digit at 2*ix */
+ /* calculate double precision result */
+ mp_word r = (mp_word)t.dp[2*ix] +
+ ((mp_word)a->dp[ix] * (mp_word)a->dp[ix]);
+
+ /* store lower part in result */
+ t.dp[ix+ix] = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* get the carry */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+
+ for (iy = ix + 1; iy < pa; iy++) {
+ /* first calculate the product */
+ r = (mp_word)a->dp[ix] * (mp_word)a->dp[iy];
+
+ /* now calculate the double precision result, note we use
+ * addition instead of *2 since it's easier to optimize
+ */
+ r = (mp_word)t.dp[ix + iy] + r + r + (mp_word)u;
+
+ /* store lower part */
+ t.dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* get carry */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ }
+ /* propagate upwards */
+ while (u != 0uL) {
+ r = (mp_word)t.dp[ix + iy] + (mp_word)u;
+ t.dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK);
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ ++iy;
+ }
+ }
+
+ mp_clamp(&t);
+ mp_exch(&t, b);
+ mp_clear(&t);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/s_mp_sqr_comba.c b/src/libtommath/s_mp_sqr_comba.c
new file mode 100644
index 000000000..cb88dcc9e
--- /dev/null
+++ b/src/libtommath/s_mp_sqr_comba.c
@@ -0,0 +1,87 @@
+#include "tommath_private.h"
+#ifdef S_MP_SQR_COMBA_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* the jist of squaring...
+ * you do like mult except the offset of the tmpx [one that
+ * starts closer to zero] can't equal the offset of tmpy.
+ * So basically you set up iy like before then you min it with
+ * (ty-tx) so that it never happens. You double all those
+ * you add in the inner loop
+
+After that loop you do the squares and add them in.
+*/
+
+mp_err s_mp_sqr_comba(const mp_int *a, mp_int *b)
+{
+ int oldused, pa, ix;
+ mp_digit W[MP_WARRAY];
+ mp_word W1;
+ mp_err err;
+
+ /* grow the destination as required */
+ pa = a->used + a->used;
+ if ((err = mp_grow(b, pa)) != MP_OKAY) {
+ return err;
+ }
+
+ /* number of output digits to produce */
+ W1 = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty, iy, iz;
+ mp_word _W;
+
+ /* clear counter */
+ _W = 0;
+
+ /* get offsets into the two bignums */
+ ty = MP_MIN(a->used-1, ix);
+ tx = ix - ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MP_MIN(a->used-tx, ty+1);
+
+ /* now for squaring tx can never equal ty
+ * we halve the distance since they approach at a rate of 2x
+ * and we have to round because odd cases need to be executed
+ */
+ iy = MP_MIN(iy, ((ty-tx)+1)>>1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; iz++) {
+ _W += (mp_word)a->dp[tx + iz] * (mp_word)a->dp[ty - iz];
+ }
+
+ /* double the inner product and add carry */
+ _W = _W + _W + W1;
+
+ /* even columns have the square term in them */
+ if (((unsigned)ix & 1u) == 0u) {
+ _W += (mp_word)a->dp[ix>>1] * (mp_word)a->dp[ix>>1];
+ }
+
+ /* store it */
+ W[ix] = (mp_digit)_W & MP_MASK;
+
+ /* make next carry */
+ W1 = _W >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* setup dest */
+ oldused = b->used;
+ b->used = a->used+a->used;
+
+ for (ix = 0; ix < pa; ix++) {
+ b->dp[ix] = W[ix] & MP_MASK;
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ s_mp_zero_digs(b->dp + b->used, oldused - b->used);
+
+ mp_clamp(b);
+ return MP_OKAY;
+}
+#endif
diff --git a/src/libtommath/s_mp_sqr_karatsuba.c b/src/libtommath/s_mp_sqr_karatsuba.c
new file mode 100644
index 000000000..f064b46a1
--- /dev/null
+++ b/src/libtommath/s_mp_sqr_karatsuba.c
@@ -0,0 +1,92 @@
+#include "tommath_private.h"
+#ifdef S_MP_SQR_KARATSUBA_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Karatsuba squaring, computes b = a*a using three
+ * half size squarings
+ *
+ * See comments of mul_karatsuba for details. It
+ * is essentially the same algorithm but merely
+ * tuned to perform recursive squarings.
+ */
+mp_err s_mp_sqr_karatsuba(const mp_int *a, mp_int *b)
+{
+ mp_int x0, x1, t1, t2, x0x0, x1x1;
+ int B;
+ mp_err err;
+
+ /* min # of digits */
+ B = a->used;
+
+ /* now divide in two */
+ B = B >> 1;
+
+ /* init copy all the temps */
+ if ((err = mp_init_size(&x0, B)) != MP_OKAY)
+ goto LBL_ERR;
+ if ((err = mp_init_size(&x1, a->used - B)) != MP_OKAY)
+ goto X0;
+
+ /* init temps */
+ if ((err = mp_init_size(&t1, a->used * 2)) != MP_OKAY)
+ goto X1;
+ if ((err = mp_init_size(&t2, a->used * 2)) != MP_OKAY)
+ goto T1;
+ if ((err = mp_init_size(&x0x0, B * 2)) != MP_OKAY)
+ goto T2;
+ if ((err = mp_init_size(&x1x1, (a->used - B) * 2)) != MP_OKAY)
+ goto X0X0;
+
+ /* now shift the digits */
+ x0.used = B;
+ x1.used = a->used - B;
+ s_mp_copy_digs(x0.dp, a->dp, x0.used);
+ s_mp_copy_digs(x1.dp, a->dp + B, x1.used);
+ mp_clamp(&x0);
+
+ /* now calc the products x0*x0 and x1*x1 */
+ if ((err = mp_sqr(&x0, &x0x0)) != MP_OKAY)
+ goto X1X1; /* x0x0 = x0*x0 */
+ if ((err = mp_sqr(&x1, &x1x1)) != MP_OKAY)
+ goto X1X1; /* x1x1 = x1*x1 */
+
+ /* now calc (x1+x0)**2 */
+ if ((err = s_mp_add(&x1, &x0, &t1)) != MP_OKAY)
+ goto X1X1; /* t1 = x1 - x0 */
+ if ((err = mp_sqr(&t1, &t1)) != MP_OKAY)
+ goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */
+
+ /* add x0y0 */
+ if ((err = s_mp_add(&x0x0, &x1x1, &t2)) != MP_OKAY)
+ goto X1X1; /* t2 = x0x0 + x1x1 */
+ if ((err = s_mp_sub(&t1, &t2, &t1)) != MP_OKAY)
+ goto X1X1; /* t1 = (x1+x0)**2 - (x0x0 + x1x1) */
+
+ /* shift by B */
+ if ((err = mp_lshd(&t1, B)) != MP_OKAY)
+ goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))<<B */
+ if ((err = mp_lshd(&x1x1, B * 2)) != MP_OKAY)
+ goto X1X1; /* x1x1 = x1x1 << 2*B */
+
+ if ((err = mp_add(&x0x0, &t1, &t1)) != MP_OKAY)
+ goto X1X1; /* t1 = x0x0 + t1 */
+ if ((err = mp_add(&t1, &x1x1, b)) != MP_OKAY)
+ goto X1X1; /* t1 = x0x0 + t1 + x1x1 */
+
+X1X1:
+ mp_clear(&x1x1);
+X0X0:
+ mp_clear(&x0x0);
+T2:
+ mp_clear(&t2);
+T1:
+ mp_clear(&t1);
+X1:
+ mp_clear(&x1);
+X0:
+ mp_clear(&x0);
+LBL_ERR:
+ return err;
+}
+#endif
diff --git a/src/libtommath/s_mp_sqr_toom.c b/src/libtommath/s_mp_sqr_toom.c
new file mode 100644
index 000000000..fd70a3dac
--- /dev/null
+++ b/src/libtommath/s_mp_sqr_toom.c
@@ -0,0 +1,133 @@
+#include "tommath_private.h"
+#ifdef S_MP_SQR_TOOM_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* squaring using Toom-Cook 3-way algorithm */
+
+/*
+ This file contains code from J. Arndt's book "Matters Computational"
+ and the accompanying FXT-library with permission of the author.
+*/
+
+/* squaring using Toom-Cook 3-way algorithm */
+/*
+ Setup and interpolation from algorithm SQR_3 in
+
+ Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae."
+ 18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007.
+
+*/
+mp_err s_mp_sqr_toom(const mp_int *a, mp_int *b)
+{
+ mp_int S0, a0, a1, a2;
+ int B;
+ mp_err err;
+
+ /* init temps */
+ if ((err = mp_init(&S0)) != MP_OKAY) {
+ return err;
+ }
+
+ /* B */
+ B = a->used / 3;
+
+ /** a = a2 * x^2 + a1 * x + a0; */
+ if ((err = mp_init_size(&a0, B)) != MP_OKAY) goto LBL_ERRa0;
+ if ((err = mp_init_size(&a1, B)) != MP_OKAY) goto LBL_ERRa1;
+ if ((err = mp_init_size(&a2, a->used - (2 * B))) != MP_OKAY) goto LBL_ERRa2;
+
+ a0.used = a1.used = B;
+ a2.used = a->used - 2 * B;
+ s_mp_copy_digs(a0.dp, a->dp, a0.used);
+ s_mp_copy_digs(a1.dp, a->dp + B, a1.used);
+ s_mp_copy_digs(a2.dp, a->dp + 2 * B, a2.used);
+ mp_clamp(&a0);
+ mp_clamp(&a1);
+ mp_clamp(&a2);
+
+ /** S0 = a0^2; */
+ if ((err = mp_sqr(&a0, &S0)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S1 = (a2 + a1 + a0)^2 */
+ /** \\S2 = (a2 - a1 + a0)^2 */
+ /** \\S1 = a0 + a2; */
+ /** a0 = a0 + a2; */
+ if ((err = mp_add(&a0, &a2, &a0)) != MP_OKAY) goto LBL_ERR;
+ /** \\S2 = S1 - a1; */
+ /** b = a0 - a1; */
+ if ((err = mp_sub(&a0, &a1, b)) != MP_OKAY) goto LBL_ERR;
+ /** \\S1 = S1 + a1; */
+ /** a0 = a0 + a1; */
+ if ((err = mp_add(&a0, &a1, &a0)) != MP_OKAY) goto LBL_ERR;
+ /** \\S1 = S1^2; */
+ /** a0 = a0^2; */
+ if ((err = mp_sqr(&a0, &a0)) != MP_OKAY) goto LBL_ERR;
+ /** \\S2 = S2^2; */
+ /** b = b^2; */
+ if ((err = mp_sqr(b, b)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\ S3 = 2 * a1 * a2 */
+ /** \\S3 = a1 * a2; */
+ /** a1 = a1 * a2; */
+ if ((err = mp_mul(&a1, &a2, &a1)) != MP_OKAY) goto LBL_ERR;
+ /** \\S3 = S3 << 1; */
+ /** a1 = a1 << 1; */
+ if ((err = mp_mul_2(&a1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S4 = a2^2; */
+ /** a2 = a2^2; */
+ if ((err = mp_sqr(&a2, &a2)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\ tmp = (S1 + S2)/2 */
+ /** \\tmp = S1 + S2; */
+ /** b = a0 + b; */
+ if ((err = mp_add(&a0, b, b)) != MP_OKAY) goto LBL_ERR;
+ /** \\tmp = tmp >> 1; */
+ /** b = b >> 1; */
+ if ((err = mp_div_2(b, b)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\ S1 = S1 - tmp - S3 */
+ /** \\S1 = S1 - tmp; */
+ /** a0 = a0 - b; */
+ if ((err = mp_sub(&a0, b, &a0)) != MP_OKAY) goto LBL_ERR;
+ /** \\S1 = S1 - S3; */
+ /** a0 = a0 - a1; */
+ if ((err = mp_sub(&a0, &a1, &a0)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S2 = tmp - S4 -S0 */
+ /** \\S2 = tmp - S4; */
+ /** b = b - a2; */
+ if ((err = mp_sub(b, &a2, b)) != MP_OKAY) goto LBL_ERR;
+ /** \\S2 = S2 - S0; */
+ /** b = b - S0; */
+ if ((err = mp_sub(b, &S0, b)) != MP_OKAY) goto LBL_ERR;
+
+
+ /** \\P = S4*x^4 + S3*x^3 + S2*x^2 + S1*x + S0; */
+ /** P = a2*x^4 + a1*x^3 + b*x^2 + a0*x + S0; */
+
+ if ((err = mp_lshd(&a2, 4 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&a1, 3 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(b, 2 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&a0, 1 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&a2, &a1, &a2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&a2, b, b)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(b, &a0, b)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(b, &S0, b)) != MP_OKAY) goto LBL_ERR;
+ /** a^2 - P */
+
+
+LBL_ERR:
+ mp_clear(&a2);
+LBL_ERRa2:
+ mp_clear(&a1);
+LBL_ERRa1:
+ mp_clear(&a0);
+LBL_ERRa0:
+ mp_clear(&S0);
+
+ return err;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_sub.c b/src/libtommath/s_mp_sub.c
new file mode 100644
index 000000000..b1a749e35
--- /dev/null
+++ b/src/libtommath/s_mp_sub.c
@@ -0,0 +1,56 @@
+#include "tommath_private.h"
+#ifdef S_MP_SUB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
+mp_err s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int oldused = c->used, min = b->used, max = a->used, i;
+ mp_digit u;
+ mp_err err;
+
+ /* init result */
+ if ((err = mp_grow(c, max)) != MP_OKAY) {
+ return err;
+ }
+
+ c->used = max;
+
+ /* set carry to zero */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* T[i] = A[i] - B[i] - U */
+ c->dp[i] = (a->dp[i] - b->dp[i]) - u;
+
+ /* U = carry bit of T[i]
+ * Note this saves performing an AND operation since
+ * if a carry does occur it will propagate all the way to the
+ * MSB. As a result a single shift is enough to get the carry
+ */
+ u = c->dp[i] >> (MP_SIZEOF_BITS(mp_digit) - 1u);
+
+ /* Clear carry from T[i] */
+ c->dp[i] &= MP_MASK;
+ }
+
+ /* now copy higher words if any, e.g. if A has more digits than B */
+ for (; i < max; i++) {
+ /* T[i] = A[i] - U */
+ c->dp[i] = a->dp[i] - u;
+
+ /* U = carry bit of T[i] */
+ u = c->dp[i] >> (MP_SIZEOF_BITS(mp_digit) - 1u);
+
+ /* Clear carry from T[i] */
+ c->dp[i] &= MP_MASK;
+ }
+
+ /* clear digits above used (since we may not have grown result above) */
+ s_mp_zero_digs(c->dp + c->used, oldused - c->used);
+
+ mp_clamp(c);
+ return MP_OKAY;
+}
+
+#endif
diff --git a/src/libtommath/s_mp_zero_buf.c b/src/libtommath/s_mp_zero_buf.c
new file mode 100644
index 000000000..23a458dcd
--- /dev/null
+++ b/src/libtommath/s_mp_zero_buf.c
@@ -0,0 +1,22 @@
+#include "tommath_private.h"
+#ifdef S_MP_ZERO_BUF_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifdef MP_USE_MEMOPS
+# include <string.h>
+#endif
+
+void s_mp_zero_buf(void *mem, size_t size)
+{
+#ifdef MP_USE_MEMOPS
+ memset(mem, 0, size);
+#else
+ char *m = (char *)mem;
+ while (size-- > 0u) {
+ *m++ = '\0';
+ }
+#endif
+}
+
+#endif
diff --git a/src/libtommath/s_mp_zero_digs.c b/src/libtommath/s_mp_zero_digs.c
new file mode 100644
index 000000000..79e837796
--- /dev/null
+++ b/src/libtommath/s_mp_zero_digs.c
@@ -0,0 +1,23 @@
+#include "tommath_private.h"
+#ifdef S_MP_ZERO_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifdef MP_USE_MEMOPS
+# include <string.h>
+#endif
+
+void s_mp_zero_digs(mp_digit *d, int digits)
+{
+#ifdef MP_USE_MEMOPS
+ if (digits > 0) {
+ memset(d, 0, (size_t)digits * sizeof(mp_digit));
+ }
+#else
+ while (digits-- > 0) {
+ *d++ = 0;
+ }
+#endif
+}
+
+#endif
diff --git a/src/libtommath/tommath.h b/src/libtommath/tommath.h
new file mode 100644
index 000000000..ae633d1e1
--- /dev/null
+++ b/src/libtommath/tommath.h
@@ -0,0 +1,587 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef TOMMATH_H_
+#define TOMMATH_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifndef MP_NO_FILE
+# include <stdio.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* MS Visual C++ doesn't have a 128bit type for words, so fall back to 32bit MPI's (where words are 64bit) */
+#if (defined(_MSC_VER) || defined(__LLP64__) || defined(__e2k__) || defined(__LCC__)) && !defined(MP_64BIT)
+# define MP_32BIT
+#endif
+
+/* detect 64-bit mode if possible */
+#if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || \
+ defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || \
+ defined(__s390x__) || defined(__arch64__) || defined(__aarch64__) || \
+ defined(__sparcv9) || defined(__sparc_v9__) || defined(__sparc64__) || \
+ defined(__ia64) || defined(__ia64__) || defined(__itanium__) || defined(_M_IA64) || \
+ defined(__LP64__) || defined(_LP64) || defined(__64BIT__)
+# if !(defined(MP_64BIT) || defined(MP_32BIT) || defined(MP_16BIT))
+# if defined(__GNUC__) && !defined(__hppa)
+/* we support 128bit integers only via: __attribute__((mode(TI))) */
+# define MP_64BIT
+# else
+/* otherwise we fall back to MP_32BIT even on 64bit platforms */
+# define MP_32BIT
+# endif
+# endif
+#endif
+
+#ifdef MP_DIGIT_BIT
+# error Defining MP_DIGIT_BIT is disallowed, use MP_16/31/32/64BIT
+#endif
+
+/* some default configurations.
+ *
+ * A "mp_digit" must be able to hold MP_DIGIT_BIT + 1 bits
+ * A "mp_word" must be able to hold 2*MP_DIGIT_BIT + 1 bits
+ *
+ * At the very least a mp_digit must be able to hold 7 bits
+ * [any size beyond that is ok provided it doesn't overflow the data type]
+ */
+
+#if defined(MP_16BIT)
+typedef uint16_t mp_digit;
+# define MP_DIGIT_BIT 15
+#elif defined(MP_64BIT)
+typedef uint64_t mp_digit;
+# define MP_DIGIT_BIT 60
+#else
+typedef uint32_t mp_digit;
+# ifdef MP_31BIT
+/*
+ * This is an extension that uses 31-bit digits.
+ * Please be aware that not all functions support this size, especially s_mp_mul_comba
+ * will be reduced to work on small numbers only:
+ * Up to 8 limbs, 248 bits instead of up to 512 limbs, 15872 bits with MP_28BIT.
+ */
+# define MP_DIGIT_BIT 31
+# else
+/* default case is 28-bit digits, defines MP_28BIT as a handy macro to test */
+# define MP_DIGIT_BIT 28
+# define MP_28BIT
+# endif
+#endif
+
+#define MP_MASK ((((mp_digit)1)<<((mp_digit)MP_DIGIT_BIT))-((mp_digit)1))
+#define MP_DIGIT_MAX MP_MASK
+
+/* Primality generation flags */
+#define MP_PRIME_BBS 0x0001 /* BBS style prime */
+#define MP_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */
+#define MP_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */
+
+typedef enum {
+ MP_ZPOS = 0, /* positive */
+ MP_NEG = 1 /* negative */
+} mp_sign;
+
+typedef enum {
+ MP_LT = -1, /* less than */
+ MP_EQ = 0, /* equal */
+ MP_GT = 1 /* greater than */
+} mp_ord;
+
+typedef enum {
+ MP_OKAY = 0, /* no error */
+ MP_ERR = -1, /* unknown error */
+ MP_MEM = -2, /* out of mem */
+ MP_VAL = -3, /* invalid input */
+ MP_ITER = -4, /* maximum iterations reached */
+ MP_BUF = -5, /* buffer overflow, supplied buffer too small */
+ MP_OVF = -6 /* mp_int overflow, too many digits */
+} mp_err;
+
+typedef enum {
+ MP_LSB_FIRST = -1,
+ MP_MSB_FIRST = 1
+} mp_order;
+
+typedef enum {
+ MP_LITTLE_ENDIAN = -1,
+ MP_NATIVE_ENDIAN = 0,
+ MP_BIG_ENDIAN = 1
+} mp_endian;
+
+/* tunable cutoffs */
+#ifndef MP_FIXED_CUTOFFS
+extern int
+MP_MUL_KARATSUBA_CUTOFF,
+MP_SQR_KARATSUBA_CUTOFF,
+MP_MUL_TOOM_CUTOFF,
+MP_SQR_TOOM_CUTOFF;
+#endif
+
+/* define this to use lower memory usage routines (exptmods mostly) */
+/* #define MP_LOW_MEM */
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define MP_NULL_TERMINATED __attribute__((sentinel))
+#else
+# define MP_NULL_TERMINATED
+#endif
+
+/*
+ * MP_WUR - warn unused result
+ * ---------------------------
+ *
+ * The result of functions annotated with MP_WUR must be
+ * checked and cannot be ignored.
+ *
+ * Most functions in libtommath return an error code.
+ * This error code must be checked in order to prevent crashes or invalid
+ * results.
+ */
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define MP_WUR __attribute__((warn_unused_result))
+#else
+# define MP_WUR
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 405)
+# define MP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x)))
+#elif defined(_MSC_VER) && _MSC_VER >= 1500
+# define MP_DEPRECATED(x) __declspec(deprecated("replaced by " #x))
+#else
+# define MP_DEPRECATED(x)
+#endif
+
+#ifndef MP_NO_DEPRECATED_PRAGMA
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 301)
+# define PRIVATE_MP_DEPRECATED_PRAGMA(s) _Pragma(#s)
+# define MP_DEPRECATED_PRAGMA(s) PRIVATE_MP_DEPRECATED_PRAGMA(GCC warning s)
+#elif defined(_MSC_VER) && _MSC_VER >= 1500
+# define MP_DEPRECATED_PRAGMA(s) __pragma(message(s))
+#endif
+#endif
+
+#ifndef MP_DEPRECATED_PRAGMA
+# define MP_DEPRECATED_PRAGMA(s)
+#endif
+
+/* the infamous mp_int structure */
+typedef struct {
+ int used, alloc;
+ mp_sign sign;
+ mp_digit *dp;
+} mp_int;
+
+/* error code to char* string */
+const char *mp_error_to_string(mp_err code) MP_WUR;
+
+/* ---> init and deinit bignum functions <--- */
+/* init a bignum */
+mp_err mp_init(mp_int *a) MP_WUR;
+
+/* free a bignum */
+void mp_clear(mp_int *a);
+
+/* init a null terminated series of arguments */
+mp_err mp_init_multi(mp_int *mp, ...) MP_NULL_TERMINATED MP_WUR;
+
+/* clear a null terminated series of arguments */
+void mp_clear_multi(mp_int *mp, ...) MP_NULL_TERMINATED;
+
+/* exchange two ints */
+void mp_exch(mp_int *a, mp_int *b);
+
+/* shrink ram required for a bignum */
+mp_err mp_shrink(mp_int *a) MP_WUR;
+
+/* grow an int to a given size */
+mp_err mp_grow(mp_int *a, int size) MP_WUR;
+
+/* init to a given number of digits */
+mp_err mp_init_size(mp_int *a, int size) MP_WUR;
+
+/* ---> Basic Manipulations <--- */
+#define mp_iszero(a) ((a)->used == 0)
+#define mp_isneg(a) ((a)->sign == MP_NEG)
+#define mp_iseven(a) (((a)->used == 0) || (((a)->dp[0] & 1u) == 0u))
+#define mp_isodd(a) (!mp_iseven(a))
+
+/* set to zero */
+void mp_zero(mp_int *a);
+
+/* get and set doubles */
+double mp_get_double(const mp_int *a) MP_WUR;
+mp_err mp_set_double(mp_int *a, double b) MP_WUR;
+
+/* get integer, set integer and init with integer (int32_t) */
+int32_t mp_get_i32(const mp_int *a) MP_WUR;
+void mp_set_i32(mp_int *a, int32_t b);
+mp_err mp_init_i32(mp_int *a, int32_t b) MP_WUR;
+
+/* get integer, set integer and init with integer, behaves like two complement for negative numbers (uint32_t) */
+#define mp_get_u32(a) ((uint32_t)mp_get_i32(a))
+void mp_set_u32(mp_int *a, uint32_t b);
+mp_err mp_init_u32(mp_int *a, uint32_t b) MP_WUR;
+
+/* get integer, set integer and init with integer (int64_t) */
+int64_t mp_get_i64(const mp_int *a) MP_WUR;
+void mp_set_i64(mp_int *a, int64_t b);
+mp_err mp_init_i64(mp_int *a, int64_t b) MP_WUR;
+
+/* get integer, set integer and init with integer, behaves like two complement for negative numbers (uint64_t) */
+#define mp_get_u64(a) ((uint64_t)mp_get_i64(a))
+void mp_set_u64(mp_int *a, uint64_t b);
+mp_err mp_init_u64(mp_int *a, uint64_t b) MP_WUR;
+
+/* get magnitude */
+uint32_t mp_get_mag_u32(const mp_int *a) MP_WUR;
+uint64_t mp_get_mag_u64(const mp_int *a) MP_WUR;
+unsigned long mp_get_mag_ul(const mp_int *a) MP_WUR;
+
+/* get integer, set integer (long) */
+long mp_get_l(const mp_int *a) MP_WUR;
+void mp_set_l(mp_int *a, long b);
+mp_err mp_init_l(mp_int *a, long b) MP_WUR;
+
+/* get integer, set integer (unsigned long) */
+#define mp_get_ul(a) ((unsigned long)mp_get_l(a))
+void mp_set_ul(mp_int *a, unsigned long b);
+mp_err mp_init_ul(mp_int *a, unsigned long b) MP_WUR;
+
+/* set to single unsigned digit, up to MP_DIGIT_MAX */
+void mp_set(mp_int *a, mp_digit b);
+mp_err mp_init_set(mp_int *a, mp_digit b) MP_WUR;
+
+/* copy, b = a */
+mp_err mp_copy(const mp_int *a, mp_int *b) MP_WUR;
+
+/* inits and copies, a = b */
+mp_err mp_init_copy(mp_int *a, const mp_int *b) MP_WUR;
+
+/* trim unused digits */
+void mp_clamp(mp_int *a);
+
+/* unpack binary data */
+mp_err mp_unpack(mp_int *rop, size_t count, mp_order order, size_t size, mp_endian endian,
+ size_t nails, const void *op) MP_WUR;
+
+/* pack binary data */
+size_t mp_pack_count(const mp_int *a, size_t nails, size_t size) MP_WUR;
+mp_err mp_pack(void *rop, size_t maxcount, size_t *written, mp_order order, size_t size,
+ mp_endian endian, size_t nails, const mp_int *op) MP_WUR;
+
+/* ---> digit manipulation <--- */
+
+/* right shift by "b" digits */
+void mp_rshd(mp_int *a, int b);
+
+/* left shift by "b" digits */
+mp_err mp_lshd(mp_int *a, int b) MP_WUR;
+
+/* c = a / 2**b, implemented as c = a >> b */
+mp_err mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d) MP_WUR;
+
+/* b = a/2 */
+mp_err mp_div_2(const mp_int *a, mp_int *b) MP_WUR;
+
+/* c = a * 2**b, implemented as c = a << b */
+mp_err mp_mul_2d(const mp_int *a, int b, mp_int *c) MP_WUR;
+
+/* b = a*2 */
+mp_err mp_mul_2(const mp_int *a, mp_int *b) MP_WUR;
+
+/* c = a mod 2**b */
+mp_err mp_mod_2d(const mp_int *a, int b, mp_int *c) MP_WUR;
+
+/* computes a = 2**b */
+mp_err mp_2expt(mp_int *a, int b) MP_WUR;
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(const mp_int *a) MP_WUR;
+
+/* I Love Earth! */
+
+/* makes a pseudo-random mp_int of a given size */
+// mp_err mp_rand(mp_int *a, int digits) MP_WUR;
+/* use custom random data source instead of source provided the platform */
+// void mp_rand_source(mp_err(*source)(void *out, size_t size));
+
+/* ---> binary operations <--- */
+
+/* c = a XOR b (two complement) */
+mp_err mp_xor(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = a OR b (two complement) */
+mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = a AND b (two complement) */
+mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* b = ~a (bitwise not, two complement) */
+mp_err mp_complement(const mp_int *a, mp_int *b) MP_WUR;
+
+/* right shift with sign extension */
+mp_err mp_signed_rsh(const mp_int *a, int b, mp_int *c) MP_WUR;
+
+/* ---> Basic arithmetic <--- */
+
+/* b = -a */
+mp_err mp_neg(const mp_int *a, mp_int *b) MP_WUR;
+
+/* b = |a| */
+mp_err mp_abs(const mp_int *a, mp_int *b) MP_WUR;
+
+/* compare a to b */
+mp_ord mp_cmp(const mp_int *a, const mp_int *b) MP_WUR;
+
+/* compare |a| to |b| */
+mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b) MP_WUR;
+
+/* c = a + b */
+mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = a - b */
+mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = a * b */
+mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* b = a*a */
+#define mp_sqr(a, b) mp_mul((a), (a), (b))
+
+/* a/b => cb + d == a */
+mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) MP_WUR;
+
+/* c = a mod b, 0 <= c < b */
+mp_err mp_mod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* Increment "a" by one like "a++". Changes input! */
+#define mp_incr(a) mp_add_d((a), 1u, (a))
+
+/* Decrement "a" by one like "a--". Changes input! */
+#define mp_decr(a) mp_sub_d((a), 1u, (a))
+
+/* ---> single digit functions <--- */
+
+/* compare against a single digit */
+mp_ord mp_cmp_d(const mp_int *a, mp_digit b) MP_WUR;
+
+/* c = a + b */
+mp_err mp_add_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR;
+
+/* c = a - b */
+mp_err mp_sub_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR;
+
+/* c = a * b */
+mp_err mp_mul_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR;
+
+/* a/b => cb + d == a */
+mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d) MP_WUR;
+
+/* c = a mod b, 0 <= c < b */
+#define mp_mod_d(a, b, c) mp_div_d((a), (b), NULL, (c))
+
+/* ---> number theory <--- */
+
+/* d = a + b (mod c) */
+mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) MP_WUR;
+
+/* d = a - b (mod c) */
+mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) MP_WUR;
+
+/* d = a * b (mod c) */
+mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) MP_WUR;
+
+/* c = a * a (mod b) */
+mp_err mp_sqrmod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = 1/a (mod b) */
+mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = (a, b) */
+mp_err mp_gcd(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* produces value such that U1*a + U2*b = U3 */
+mp_err mp_exteuclid(const mp_int *a, const mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3) MP_WUR;
+
+/* c = [a, b] or (a*b)/(a, b) */
+mp_err mp_lcm(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* Integer logarithm to integer base */
+mp_err mp_log_n(const mp_int *a, int base, int *c) MP_WUR;
+
+/* c = a**b */
+mp_err mp_expt_n(const mp_int *a, int b, mp_int *c) MP_WUR;
+
+/* finds one of the b'th root of a, such that |c|**b <= |a|
+ *
+ * returns error if a < 0 and b is even
+ */
+mp_err mp_root_n(const mp_int *a, int b, mp_int *c) MP_WUR;
+
+/* special sqrt algo */
+mp_err mp_sqrt(const mp_int *arg, mp_int *ret) MP_WUR;
+
+/* special sqrt (mod prime) */
+mp_err mp_sqrtmod_prime(const mp_int *n, const mp_int *prime, mp_int *ret) MP_WUR;
+
+/* is number a square? */
+mp_err mp_is_square(const mp_int *arg, bool *ret) MP_WUR;
+
+/* computes the Kronecker symbol c = (a | p) (like jacobi() but with {a,p} in Z */
+mp_err mp_kronecker(const mp_int *a, const mp_int *p, int *c) MP_WUR;
+
+/* used to setup the Barrett reduction for a given modulus b */
+mp_err mp_reduce_setup(mp_int *a, const mp_int *b) MP_WUR;
+
+/* Barrett Reduction, computes a (mod b) with a precomputed value c
+ *
+ * Assumes that 0 < x <= m*m, note if 0 > x > -(m*m) then you can merely
+ * compute the reduction as -1 * mp_reduce(mp_abs(x)) [pseudo code].
+ */
+mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu) MP_WUR;
+
+/* setups the montgomery reduction */
+mp_err mp_montgomery_setup(const mp_int *n, mp_digit *rho) MP_WUR;
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+mp_err mp_montgomery_calc_normalization(mp_int *a, const mp_int *b) MP_WUR;
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+mp_err mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho) MP_WUR;
+
+/* returns 1 if a is a valid DR modulus */
+bool mp_dr_is_modulus(const mp_int *a) MP_WUR;
+
+/* sets the value of "d" required for mp_dr_reduce */
+void mp_dr_setup(const mp_int *a, mp_digit *d);
+
+/* reduces a modulo n using the Diminished Radix method */
+mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k) MP_WUR;
+
+/* returns true if a can be reduced with mp_reduce_2k */
+bool mp_reduce_is_2k(const mp_int *a) MP_WUR;
+
+/* determines k value for 2k reduction */
+mp_err mp_reduce_2k_setup(const mp_int *a, mp_digit *d) MP_WUR;
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+mp_err mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d) MP_WUR;
+
+/* returns true if a can be reduced with mp_reduce_2k_l */
+bool mp_reduce_is_2k_l(const mp_int *a) MP_WUR;
+
+/* determines k value for 2k reduction */
+mp_err mp_reduce_2k_setup_l(const mp_int *a, mp_int *d) MP_WUR;
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d) MP_WUR;
+
+/* Y = G**X (mod P) */
+mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y) MP_WUR;
+
+/* ---> Primes <--- */
+
+/* performs one Fermat test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+mp_err mp_prime_fermat(const mp_int *a, const mp_int *b, bool *result) MP_WUR;
+
+/* performs one Miller-Rabin test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+mp_err mp_prime_miller_rabin(const mp_int *a, const mp_int *b, bool *result) MP_WUR;
+
+/* This gives [for a given bit size] the number of trials required
+ * such that Miller-Rabin gives a prob of failure lower than 2^-96
+ */
+int mp_prime_rabin_miller_trials(int size) MP_WUR;
+
+/* performs one strong Lucas-Selfridge test of "a".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+mp_err mp_prime_strong_lucas_selfridge(const mp_int *a, bool *result) MP_WUR;
+
+/* performs one Frobenius test of "a" as described by Paul Underwood.
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+mp_err mp_prime_frobenius_underwood(const mp_int *N, bool *result) MP_WUR;
+
+/* performs t random rounds of Miller-Rabin on "a" additional to
+ * bases 2 and 3. Also performs an initial sieve of trial
+ * division. Determines if "a" is prime with probability
+ * of error no more than (1/4)**t.
+ * Both a strong Lucas-Selfridge to complete the BPSW test
+ * and a separate Frobenius test are available at compile time.
+ * With t<0 a deterministic test is run for primes up to
+ * 318665857834031151167461. With t<13 (abs(t)-13) additional
+ * tests with sequential small primes are run starting at 43.
+ * Is Fips 186.4 compliant if called with t as computed by
+ * mp_prime_rabin_miller_trials();
+ *
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+mp_err mp_prime_is_prime(const mp_int *a, int t, bool *result) MP_WUR;
+
+/* finds the next prime after the number "a" using "t" trials
+ * of Miller-Rabin.
+ *
+ * bbs_style = true means the prime must be congruent to 3 mod 4
+ */
+mp_err mp_prime_next_prime(mp_int *a, int t, bool bbs_style) MP_WUR;
+
+/* makes a truly random prime of a given size (bits),
+ *
+ * Flags are as follows:
+ *
+ * MP_PRIME_BBS - make prime congruent to 3 mod 4
+ * MP_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies MP_PRIME_BBS)
+ * MP_PRIME_2MSB_ON - make the 2nd highest bit one
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ */
+// mp_err mp_prime_rand(mp_int *a, int t, int size, int flags) MP_WUR;
+
+/* ---> radix conversion <--- */
+int mp_count_bits(const mp_int *a) MP_WUR;
+
+size_t mp_ubin_size(const mp_int *a) MP_WUR;
+mp_err mp_from_ubin(mp_int *a, const uint8_t *buf, size_t size) MP_WUR;
+mp_err mp_to_ubin(const mp_int *a, uint8_t *buf, size_t maxlen, size_t *written) MP_WUR;
+
+size_t mp_sbin_size(const mp_int *a) MP_WUR;
+mp_err mp_from_sbin(mp_int *a, const uint8_t *buf, size_t size) MP_WUR;
+mp_err mp_to_sbin(const mp_int *a, uint8_t *buf, size_t maxlen, size_t *written) MP_WUR;
+
+mp_err mp_read_radix(mp_int *a, const char *str, int radix) MP_WUR;
+mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix) MP_WUR;
+
+mp_err mp_radix_size(const mp_int *a, int radix, size_t *size) MP_WUR;
+mp_err mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size) MP_WUR;
+
+#ifndef MP_NO_FILE
+mp_err mp_fread(mp_int *a, int radix, FILE *stream) MP_WUR;
+mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream) MP_WUR;
+#endif
+
+#define mp_to_binary(M, S, N) mp_to_radix((M), (S), (N), NULL, 2)
+#define mp_to_octal(M, S, N) mp_to_radix((M), (S), (N), NULL, 8)
+#define mp_to_decimal(M, S, N) mp_to_radix((M), (S), (N), NULL, 10)
+#define mp_to_hex(M, S, N) mp_to_radix((M), (S), (N), NULL, 16)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libtommath/tommath_c89.h b/src/libtommath/tommath_c89.h
new file mode 100644
index 000000000..e7b87f105
--- /dev/null
+++ b/src/libtommath/tommath_c89.h
@@ -0,0 +1,40 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ * This header defines custom types which
+ * are used in c89 mode.
+ *
+ * By default, the source uses stdbool.h
+ * and stdint.h. The command `make c89`
+ * can be used to convert the source,
+ * such that this header is used instead.
+ * Use `make c99` to convert back.
+ *
+ * Please adapt the following definitions to your needs!
+ */
+
+/* stdbool.h replacement types */
+typedef enum { MP_NO, MP_YES } mp_bool;
+
+/* stdint.h replacement types */
+typedef __INT8_TYPE__ mp_i8;
+typedef __INT16_TYPE__ mp_i16;
+typedef __INT32_TYPE__ mp_i32;
+typedef __INT64_TYPE__ mp_i64;
+typedef __UINT8_TYPE__ mp_u8;
+typedef __UINT16_TYPE__ mp_u16;
+typedef __UINT32_TYPE__ mp_u32;
+typedef __UINT64_TYPE__ mp_u64;
+
+/* inttypes.h replacement, printf format specifier */
+# if __WORDSIZE == 64
+# define MP_PRI64_PREFIX "l"
+# else
+# define MP_PRI64_PREFIX "ll"
+# endif
+#define MP_PRIi64 MP_PRI64_PREFIX "i"
+#define MP_PRIu64 MP_PRI64_PREFIX "u"
+#define MP_PRIx64 MP_PRI64_PREFIX "x"
+
+#define MP_FUNCTION_NAME __func__
diff --git a/src/libtommath/tommath_class.h b/src/libtommath/tommath_class.h
new file mode 100644
index 000000000..da9c5ea72
--- /dev/null
+++ b/src/libtommath/tommath_class.h
@@ -0,0 +1,1260 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))
+#define LTM_INSIDE
+#if defined(LTM2)
+# define LTM3
+#endif
+#if defined(LTM1)
+# define LTM2
+#endif
+#define LTM1
+#if defined(LTM_ALL)
+# define MP_2EXPT_C
+# define MP_ABS_C
+# define MP_ADD_C
+# define MP_ADD_D_C
+# define MP_ADDMOD_C
+# define MP_AND_C
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_C
+# define MP_CMP_D_C
+# define MP_CMP_MAG_C
+# define MP_CNT_LSB_C
+# define MP_COMPLEMENT_C
+# define MP_COPY_C
+# define MP_COUNT_BITS_C
+# define MP_CUTOFFS_C
+# define MP_DIV_C
+# define MP_DIV_2_C
+# define MP_DIV_2D_C
+# define MP_DIV_D_C
+# define MP_DR_IS_MODULUS_C
+# define MP_DR_REDUCE_C
+# define MP_DR_SETUP_C
+# define MP_ERROR_TO_STRING_C
+# define MP_EXCH_C
+# define MP_EXPT_N_C
+# define MP_EXPTMOD_C
+# define MP_EXTEUCLID_C
+# define MP_FREAD_C
+# define MP_FROM_SBIN_C
+# define MP_FROM_UBIN_C
+# define MP_FWRITE_C
+# define MP_GCD_C
+# define MP_GET_DOUBLE_C
+# define MP_GET_I32_C
+# define MP_GET_I64_C
+# define MP_GET_L_C
+# define MP_GET_MAG_U32_C
+# define MP_GET_MAG_U64_C
+# define MP_GET_MAG_UL_C
+# define MP_GROW_C
+# define MP_INIT_C
+# define MP_INIT_COPY_C
+# define MP_INIT_I32_C
+# define MP_INIT_I64_C
+# define MP_INIT_L_C
+# define MP_INIT_MULTI_C
+# define MP_INIT_SET_C
+# define MP_INIT_SIZE_C
+# define MP_INIT_U32_C
+# define MP_INIT_U64_C
+# define MP_INIT_UL_C
+# define MP_INVMOD_C
+# define MP_IS_SQUARE_C
+# define MP_KRONECKER_C
+# define MP_LCM_C
+# define MP_LOG_N_C
+# define MP_LSHD_C
+# define MP_MOD_C
+# define MP_MOD_2D_C
+# define MP_MONTGOMERY_CALC_NORMALIZATION_C
+# define MP_MONTGOMERY_REDUCE_C
+# define MP_MONTGOMERY_SETUP_C
+# define MP_MUL_C
+# define MP_MUL_2_C
+# define MP_MUL_2D_C
+# define MP_MUL_D_C
+# define MP_MULMOD_C
+# define MP_NEG_C
+# define MP_OR_C
+# define MP_PACK_C
+# define MP_PACK_COUNT_C
+# define MP_PRIME_FERMAT_C
+# define MP_PRIME_FROBENIUS_UNDERWOOD_C
+# define MP_PRIME_IS_PRIME_C
+# define MP_PRIME_MILLER_RABIN_C
+# define MP_PRIME_NEXT_PRIME_C
+# define MP_PRIME_RABIN_MILLER_TRIALS_C
+# define MP_PRIME_RAND_C
+# define MP_PRIME_STRONG_LUCAS_SELFRIDGE_C
+# define MP_RADIX_SIZE_C
+# define MP_RADIX_SIZE_OVERESTIMATE_C
+# define MP_RAND_C
+# define MP_RAND_SOURCE_C
+# define MP_READ_RADIX_C
+# define MP_REDUCE_C
+# define MP_REDUCE_2K_C
+# define MP_REDUCE_2K_L_C
+# define MP_REDUCE_2K_SETUP_C
+# define MP_REDUCE_2K_SETUP_L_C
+# define MP_REDUCE_IS_2K_C
+# define MP_REDUCE_IS_2K_L_C
+# define MP_REDUCE_SETUP_C
+# define MP_ROOT_N_C
+# define MP_RSHD_C
+# define MP_SBIN_SIZE_C
+# define MP_SET_C
+# define MP_SET_DOUBLE_C
+# define MP_SET_I32_C
+# define MP_SET_I64_C
+# define MP_SET_L_C
+# define MP_SET_U32_C
+# define MP_SET_U64_C
+# define MP_SET_UL_C
+# define MP_SHRINK_C
+# define MP_SIGNED_RSH_C
+# define MP_SQRMOD_C
+# define MP_SQRT_C
+# define MP_SQRTMOD_PRIME_C
+# define MP_SUB_C
+# define MP_SUB_D_C
+# define MP_SUBMOD_C
+# define MP_TO_RADIX_C
+# define MP_TO_SBIN_C
+# define MP_TO_UBIN_C
+# define MP_UBIN_SIZE_C
+# define MP_UNPACK_C
+# define MP_XOR_C
+# define MP_ZERO_C
+# define S_MP_ADD_C
+# define S_MP_COPY_DIGS_C
+# define S_MP_DIV_3_C
+# define S_MP_DIV_RECURSIVE_C
+# define S_MP_DIV_SCHOOL_C
+# define S_MP_DIV_SMALL_C
+# define S_MP_EXPTMOD_C
+# define S_MP_EXPTMOD_FAST_C
+# define S_MP_GET_BIT_C
+# define S_MP_INVMOD_C
+# define S_MP_INVMOD_ODD_C
+# define S_MP_LOG_C
+# define S_MP_LOG_2EXPT_C
+# define S_MP_LOG_D_C
+# define S_MP_MONTGOMERY_REDUCE_COMBA_C
+# define S_MP_MUL_C
+# define S_MP_MUL_BALANCE_C
+# define S_MP_MUL_COMBA_C
+# define S_MP_MUL_HIGH_C
+# define S_MP_MUL_HIGH_COMBA_C
+# define S_MP_MUL_KARATSUBA_C
+# define S_MP_MUL_TOOM_C
+# define S_MP_PRIME_IS_DIVISIBLE_C
+# define S_MP_PRIME_TAB_C
+# define S_MP_RADIX_MAP_C
+# define S_MP_RADIX_SIZE_OVERESTIMATE_C
+# define S_MP_RAND_PLATFORM_C
+# define S_MP_SQR_C
+# define S_MP_SQR_COMBA_C
+# define S_MP_SQR_KARATSUBA_C
+# define S_MP_SQR_TOOM_C
+# define S_MP_SUB_C
+# define S_MP_ZERO_BUF_C
+# define S_MP_ZERO_DIGS_C
+#endif
+#endif
+#if defined(MP_2EXPT_C)
+# define MP_GROW_C
+# define MP_ZERO_C
+#endif
+
+#if defined(MP_ABS_C)
+# define MP_COPY_C
+#endif
+
+#if defined(MP_ADD_C)
+# define MP_CMP_MAG_C
+# define S_MP_ADD_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_ADD_D_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+# define MP_SUB_D_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_ADDMOD_C)
+# define MP_ADD_C
+# define MP_MOD_C
+#endif
+
+#if defined(MP_AND_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+#endif
+
+#if defined(MP_CLAMP_C)
+#endif
+
+#if defined(MP_CLEAR_C)
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_CLEAR_MULTI_C)
+# define MP_CLEAR_C
+#endif
+
+#if defined(MP_CMP_C)
+# define MP_CMP_MAG_C
+#endif
+
+#if defined(MP_CMP_D_C)
+#endif
+
+#if defined(MP_CMP_MAG_C)
+#endif
+
+#if defined(MP_CNT_LSB_C)
+#endif
+
+#if defined(MP_COMPLEMENT_C)
+# define MP_SUB_D_C
+#endif
+
+#if defined(MP_COPY_C)
+# define MP_GROW_C
+# define S_MP_COPY_DIGS_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_COUNT_BITS_C)
+#endif
+
+#if defined(MP_CUTOFFS_C)
+#endif
+
+#if defined(MP_DIV_C)
+# define MP_CMP_MAG_C
+# define MP_COPY_C
+# define MP_ZERO_C
+# define S_MP_DIV_RECURSIVE_C
+# define S_MP_DIV_SCHOOL_C
+# define S_MP_DIV_SMALL_C
+#endif
+
+#if defined(MP_DIV_2_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_DIV_2D_C)
+# define MP_CLAMP_C
+# define MP_COPY_C
+# define MP_MOD_2D_C
+# define MP_RSHD_C
+#endif
+
+#if defined(MP_DIV_D_C)
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_COPY_C
+# define MP_DIV_2D_C
+# define MP_DIV_2_C
+# define MP_EXCH_C
+# define MP_INIT_SIZE_C
+# define S_MP_DIV_3_C
+#endif
+
+#if defined(MP_DR_IS_MODULUS_C)
+#endif
+
+#if defined(MP_DR_REDUCE_C)
+# define MP_CLAMP_C
+# define MP_CMP_MAG_C
+# define MP_GROW_C
+# define S_MP_SUB_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_DR_SETUP_C)
+#endif
+
+#if defined(MP_ERROR_TO_STRING_C)
+#endif
+
+#if defined(MP_EXCH_C)
+#endif
+
+#if defined(MP_EXPT_N_C)
+# define MP_CLEAR_C
+# define MP_INIT_COPY_C
+# define MP_MUL_C
+# define MP_SET_C
+#endif
+
+#if defined(MP_EXPTMOD_C)
+# define MP_ABS_C
+# define MP_CLEAR_MULTI_C
+# define MP_DR_IS_MODULUS_C
+# define MP_INIT_MULTI_C
+# define MP_INVMOD_C
+# define MP_REDUCE_IS_2K_C
+# define MP_REDUCE_IS_2K_L_C
+# define S_MP_EXPTMOD_C
+# define S_MP_EXPTMOD_FAST_C
+#endif
+
+#if defined(MP_EXTEUCLID_C)
+# define MP_CLEAR_MULTI_C
+# define MP_COPY_C
+# define MP_DIV_C
+# define MP_EXCH_C
+# define MP_INIT_MULTI_C
+# define MP_MUL_C
+# define MP_NEG_C
+# define MP_SET_C
+# define MP_SUB_C
+#endif
+
+#if defined(MP_FREAD_C)
+# define MP_ADD_D_C
+# define MP_MUL_D_C
+# define MP_ZERO_C
+#endif
+
+#if defined(MP_FROM_SBIN_C)
+# define MP_FROM_UBIN_C
+#endif
+
+#if defined(MP_FROM_UBIN_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+# define MP_MUL_2D_C
+# define MP_ZERO_C
+#endif
+
+#if defined(MP_FWRITE_C)
+# define MP_RADIX_SIZE_OVERESTIMATE_C
+# define MP_TO_RADIX_C
+# define S_MP_ZERO_BUF_C
+#endif
+
+#if defined(MP_GCD_C)
+# define MP_ABS_C
+# define MP_CLEAR_C
+# define MP_CMP_MAG_C
+# define MP_CNT_LSB_C
+# define MP_DIV_2D_C
+# define MP_EXCH_C
+# define MP_INIT_COPY_C
+# define MP_MUL_2D_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_GET_DOUBLE_C)
+#endif
+
+#if defined(MP_GET_I32_C)
+# define MP_GET_MAG_U32_C
+#endif
+
+#if defined(MP_GET_I64_C)
+# define MP_GET_MAG_U64_C
+#endif
+
+#if defined(MP_GET_L_C)
+# define MP_GET_MAG_UL_C
+#endif
+
+#if defined(MP_GET_MAG_U32_C)
+#endif
+
+#if defined(MP_GET_MAG_U64_C)
+#endif
+
+#if defined(MP_GET_MAG_UL_C)
+#endif
+
+#if defined(MP_GROW_C)
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_INIT_C)
+#endif
+
+#if defined(MP_INIT_COPY_C)
+# define MP_CLEAR_C
+# define MP_COPY_C
+# define MP_INIT_SIZE_C
+#endif
+
+#if defined(MP_INIT_I32_C)
+# define MP_INIT_C
+# define MP_SET_I32_C
+#endif
+
+#if defined(MP_INIT_I64_C)
+# define MP_INIT_C
+# define MP_SET_I64_C
+#endif
+
+#if defined(MP_INIT_L_C)
+# define MP_INIT_C
+# define MP_SET_L_C
+#endif
+
+#if defined(MP_INIT_MULTI_C)
+# define MP_CLEAR_C
+# define MP_INIT_C
+#endif
+
+#if defined(MP_INIT_SET_C)
+# define MP_INIT_C
+# define MP_SET_C
+#endif
+
+#if defined(MP_INIT_SIZE_C)
+#endif
+
+#if defined(MP_INIT_U32_C)
+# define MP_INIT_C
+# define MP_SET_U32_C
+#endif
+
+#if defined(MP_INIT_U64_C)
+# define MP_INIT_C
+# define MP_SET_U64_C
+#endif
+
+#if defined(MP_INIT_UL_C)
+# define MP_INIT_C
+# define MP_SET_UL_C
+#endif
+
+#if defined(MP_INVMOD_C)
+# define MP_CMP_D_C
+# define MP_ZERO_C
+# define S_MP_INVMOD_C
+# define S_MP_INVMOD_ODD_C
+#endif
+
+#if defined(MP_IS_SQUARE_C)
+# define MP_CLEAR_C
+# define MP_CMP_MAG_C
+# define MP_DIV_D_C
+# define MP_GET_I32_C
+# define MP_INIT_U32_C
+# define MP_MOD_C
+# define MP_MUL_C
+# define MP_SQRT_C
+#endif
+
+#if defined(MP_KRONECKER_C)
+# define MP_CLEAR_C
+# define MP_CMP_D_C
+# define MP_CNT_LSB_C
+# define MP_COPY_C
+# define MP_DIV_2D_C
+# define MP_INIT_C
+# define MP_INIT_COPY_C
+# define MP_MOD_C
+#endif
+
+#if defined(MP_LCM_C)
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_MAG_C
+# define MP_DIV_C
+# define MP_GCD_C
+# define MP_INIT_MULTI_C
+# define MP_MUL_C
+#endif
+
+#if defined(MP_LOG_N_C)
+# define S_MP_LOG_2EXPT_C
+# define S_MP_LOG_C
+# define S_MP_LOG_D_C
+#endif
+
+#if defined(MP_LSHD_C)
+# define MP_GROW_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_MOD_C)
+# define MP_ADD_C
+# define MP_DIV_C
+#endif
+
+#if defined(MP_MOD_2D_C)
+# define MP_CLAMP_C
+# define MP_COPY_C
+# define MP_ZERO_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_MONTGOMERY_CALC_NORMALIZATION_C)
+# define MP_2EXPT_C
+# define MP_CMP_MAG_C
+# define MP_COUNT_BITS_C
+# define MP_MUL_2_C
+# define MP_SET_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_MONTGOMERY_REDUCE_C)
+# define MP_CLAMP_C
+# define MP_CMP_MAG_C
+# define MP_GROW_C
+# define MP_RSHD_C
+# define S_MP_MONTGOMERY_REDUCE_COMBA_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_MONTGOMERY_SETUP_C)
+#endif
+
+#if defined(MP_MUL_C)
+# define S_MP_MUL_BALANCE_C
+# define S_MP_MUL_C
+# define S_MP_MUL_COMBA_C
+# define S_MP_MUL_KARATSUBA_C
+# define S_MP_MUL_TOOM_C
+# define S_MP_SQR_C
+# define S_MP_SQR_COMBA_C
+# define S_MP_SQR_KARATSUBA_C
+# define S_MP_SQR_TOOM_C
+#endif
+
+#if defined(MP_MUL_2_C)
+# define MP_GROW_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_MUL_2D_C)
+# define MP_CLAMP_C
+# define MP_COPY_C
+# define MP_GROW_C
+# define MP_LSHD_C
+#endif
+
+#if defined(MP_MUL_D_C)
+# define MP_CLAMP_C
+# define MP_COPY_C
+# define MP_GROW_C
+# define MP_MUL_2D_C
+# define MP_MUL_2_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_MULMOD_C)
+# define MP_MOD_C
+# define MP_MUL_C
+#endif
+
+#if defined(MP_NEG_C)
+# define MP_COPY_C
+#endif
+
+#if defined(MP_OR_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+#endif
+
+#if defined(MP_PACK_C)
+# define MP_CLEAR_C
+# define MP_DIV_2D_C
+# define MP_INIT_COPY_C
+# define MP_PACK_COUNT_C
+#endif
+
+#if defined(MP_PACK_COUNT_C)
+# define MP_COUNT_BITS_C
+#endif
+
+#if defined(MP_PRIME_FERMAT_C)
+# define MP_CLEAR_C
+# define MP_CMP_C
+# define MP_CMP_D_C
+# define MP_EXPTMOD_C
+# define MP_INIT_C
+#endif
+
+#if defined(MP_PRIME_FROBENIUS_UNDERWOOD_C)
+# define MP_ADD_C
+# define MP_ADD_D_C
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_C
+# define MP_COUNT_BITS_C
+# define MP_EXCH_C
+# define MP_GCD_C
+# define MP_INIT_MULTI_C
+# define MP_KRONECKER_C
+# define MP_MOD_C
+# define MP_MUL_2_C
+# define MP_MUL_C
+# define MP_MUL_D_C
+# define MP_SET_C
+# define MP_SET_I32_C
+# define MP_SET_U32_C
+# define MP_SUB_C
+# define S_MP_GET_BIT_C
+#endif
+
+#if defined(MP_PRIME_IS_PRIME_C)
+# define MP_CLEAR_C
+# define MP_CMP_C
+# define MP_CMP_D_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_2D_C
+# define MP_INIT_SET_C
+# define MP_IS_SQUARE_C
+# define MP_PRIME_MILLER_RABIN_C
+# define MP_PRIME_STRONG_LUCAS_SELFRIDGE_C
+# define MP_RAND_C
+# define MP_READ_RADIX_C
+# define MP_SET_C
+# define S_MP_PRIME_IS_DIVISIBLE_C
+#endif
+
+#if defined(MP_PRIME_MILLER_RABIN_C)
+# define MP_CLEAR_C
+# define MP_CMP_C
+# define MP_CMP_D_C
+# define MP_CNT_LSB_C
+# define MP_DIV_2D_C
+# define MP_EXPTMOD_C
+# define MP_INIT_C
+# define MP_INIT_COPY_C
+# define MP_SQRMOD_C
+# define MP_SUB_D_C
+#endif
+
+#if defined(MP_PRIME_NEXT_PRIME_C)
+# define MP_ADD_D_C
+# define MP_CLEAR_C
+# define MP_CMP_D_C
+# define MP_DIV_D_C
+# define MP_INIT_C
+# define MP_PRIME_IS_PRIME_C
+# define MP_SET_C
+# define MP_SUB_D_C
+#endif
+
+#if defined(MP_PRIME_RABIN_MILLER_TRIALS_C)
+#endif
+
+#if defined(MP_PRIME_RAND_C)
+# define MP_ADD_D_C
+# define MP_DIV_2_C
+# define MP_FROM_UBIN_C
+# define MP_MUL_2_C
+# define MP_PRIME_IS_PRIME_C
+# define MP_SUB_D_C
+# define S_MP_RAND_SOURCE_C
+# define S_MP_ZERO_BUF_C
+#endif
+
+#if defined(MP_PRIME_STRONG_LUCAS_SELFRIDGE_C)
+# define MP_ADD_C
+# define MP_ADD_D_C
+# define MP_CLEAR_C
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_C
+# define MP_CMP_D_C
+# define MP_CNT_LSB_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_2D_C
+# define MP_DIV_2_C
+# define MP_GCD_C
+# define MP_INIT_C
+# define MP_INIT_MULTI_C
+# define MP_KRONECKER_C
+# define MP_MOD_C
+# define MP_MUL_2_C
+# define MP_MUL_C
+# define MP_SET_C
+# define MP_SET_I32_C
+# define MP_SET_U32_C
+# define MP_SUB_C
+# define MP_SUB_D_C
+# define S_MP_GET_BIT_C
+#endif
+
+#if defined(MP_RADIX_SIZE_C)
+# define MP_LOG_N_C
+#endif
+
+#if defined(MP_RADIX_SIZE_OVERESTIMATE_C)
+# define MP_RADIX_SIZE_C
+# define S_MP_RADIX_SIZE_OVERESTIMATE_C
+#endif
+
+#if defined(MP_RAND_C)
+# define MP_GROW_C
+# define MP_ZERO_C
+# define S_MP_RAND_SOURCE_C
+#endif
+
+#if defined(MP_RAND_SOURCE_C)
+# define S_MP_RAND_PLATFORM_C
+#endif
+
+#if defined(MP_READ_RADIX_C)
+# define MP_ADD_D_C
+# define MP_MUL_D_C
+# define MP_ZERO_C
+#endif
+
+#if defined(MP_REDUCE_C)
+# define MP_ADD_C
+# define MP_CLEAR_C
+# define MP_CMP_C
+# define MP_CMP_D_C
+# define MP_INIT_COPY_C
+# define MP_LSHD_C
+# define MP_MOD_2D_C
+# define MP_MUL_C
+# define MP_RSHD_C
+# define MP_SET_C
+# define MP_SUB_C
+# define S_MP_MUL_C
+# define S_MP_MUL_HIGH_C
+# define S_MP_MUL_HIGH_COMBA_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_REDUCE_2K_C)
+# define MP_CLEAR_C
+# define MP_CMP_MAG_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_2D_C
+# define MP_INIT_C
+# define MP_MUL_D_C
+# define S_MP_ADD_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_REDUCE_2K_L_C)
+# define MP_CLEAR_C
+# define MP_CMP_MAG_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_2D_C
+# define MP_INIT_C
+# define MP_MUL_C
+# define S_MP_ADD_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_REDUCE_2K_SETUP_C)
+# define MP_2EXPT_C
+# define MP_CLEAR_C
+# define MP_COUNT_BITS_C
+# define MP_INIT_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_REDUCE_2K_SETUP_L_C)
+# define MP_2EXPT_C
+# define MP_CLEAR_C
+# define MP_COUNT_BITS_C
+# define MP_INIT_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_REDUCE_IS_2K_C)
+# define MP_COUNT_BITS_C
+#endif
+
+#if defined(MP_REDUCE_IS_2K_L_C)
+#endif
+
+#if defined(MP_REDUCE_SETUP_C)
+# define MP_2EXPT_C
+# define MP_DIV_C
+#endif
+
+#if defined(MP_ROOT_N_C)
+# define MP_2EXPT_C
+# define MP_ADD_D_C
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_C
+# define MP_COPY_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_C
+# define MP_EXCH_C
+# define MP_EXPT_N_C
+# define MP_INIT_MULTI_C
+# define MP_MUL_C
+# define MP_MUL_D_C
+# define MP_SET_C
+# define MP_SUB_C
+# define MP_SUB_D_C
+#endif
+
+#if defined(MP_RSHD_C)
+# define MP_ZERO_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_SBIN_SIZE_C)
+# define MP_UBIN_SIZE_C
+#endif
+
+#if defined(MP_SET_C)
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_SET_DOUBLE_C)
+# define MP_DIV_2D_C
+# define MP_MUL_2D_C
+# define MP_SET_U64_C
+#endif
+
+#if defined(MP_SET_I32_C)
+# define MP_SET_U32_C
+#endif
+
+#if defined(MP_SET_I64_C)
+# define MP_SET_U64_C
+#endif
+
+#if defined(MP_SET_L_C)
+# define MP_SET_UL_C
+#endif
+
+#if defined(MP_SET_U32_C)
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_SET_U64_C)
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_SET_UL_C)
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_SHRINK_C)
+#endif
+
+#if defined(MP_SIGNED_RSH_C)
+# define MP_ADD_D_C
+# define MP_DIV_2D_C
+# define MP_SUB_D_C
+#endif
+
+#if defined(MP_SQRMOD_C)
+# define MP_MOD_C
+# define MP_MUL_C
+#endif
+
+#if defined(MP_SQRT_C)
+# define MP_ADD_C
+# define MP_CLEAR_C
+# define MP_CMP_MAG_C
+# define MP_DIV_2_C
+# define MP_DIV_C
+# define MP_EXCH_C
+# define MP_INIT_C
+# define MP_INIT_COPY_C
+# define MP_RSHD_C
+# define MP_ZERO_C
+#endif
+
+#if defined(MP_SQRTMOD_PRIME_C)
+# define MP_ADD_D_C
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_D_C
+# define MP_COPY_C
+# define MP_DIV_2_C
+# define MP_EXPTMOD_C
+# define MP_INIT_MULTI_C
+# define MP_KRONECKER_C
+# define MP_MULMOD_C
+# define MP_SET_C
+# define MP_SET_I32_C
+# define MP_SQRMOD_C
+# define MP_SUB_D_C
+# define MP_ZERO_C
+#endif
+
+#if defined(MP_SUB_C)
+# define MP_CMP_MAG_C
+# define S_MP_ADD_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(MP_SUB_D_C)
+# define MP_ADD_D_C
+# define MP_CLAMP_C
+# define MP_GROW_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(MP_SUBMOD_C)
+# define MP_MOD_C
+# define MP_SUB_C
+#endif
+
+#if defined(MP_TO_RADIX_C)
+# define MP_CLEAR_C
+# define MP_DIV_D_C
+# define MP_INIT_COPY_C
+#endif
+
+#if defined(MP_TO_SBIN_C)
+# define MP_TO_UBIN_C
+#endif
+
+#if defined(MP_TO_UBIN_C)
+# define MP_CLEAR_C
+# define MP_DIV_2D_C
+# define MP_INIT_COPY_C
+# define MP_UBIN_SIZE_C
+#endif
+
+#if defined(MP_UBIN_SIZE_C)
+# define MP_COUNT_BITS_C
+#endif
+
+#if defined(MP_UNPACK_C)
+# define MP_CLAMP_C
+# define MP_MUL_2D_C
+# define MP_ZERO_C
+#endif
+
+#if defined(MP_XOR_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+#endif
+
+#if defined(MP_ZERO_C)
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(S_MP_ADD_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(S_MP_COPY_DIGS_C)
+#endif
+
+#if defined(S_MP_DIV_3_C)
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_EXCH_C
+# define MP_INIT_SIZE_C
+#endif
+
+#if defined(S_MP_DIV_RECURSIVE_C)
+# define MP_ADD_C
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_D_C
+# define MP_COPY_C
+# define MP_DIV_2D_C
+# define MP_EXCH_C
+# define MP_INIT_MULTI_C
+# define MP_LSHD_C
+# define MP_MUL_2D_C
+# define MP_MUL_C
+# define MP_SUB_C
+# define MP_SUB_D_C
+# define MP_ZERO_C
+# define S_MP_DIV_SCHOOL_C
+#endif
+
+#if defined(S_MP_DIV_SCHOOL_C)
+# define MP_ADD_C
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_CMP_C
+# define MP_CMP_MAG_C
+# define MP_COPY_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_2D_C
+# define MP_EXCH_C
+# define MP_INIT_C
+# define MP_INIT_COPY_C
+# define MP_INIT_SIZE_C
+# define MP_LSHD_C
+# define MP_MUL_2D_C
+# define MP_MUL_D_C
+# define MP_RSHD_C
+# define MP_SUB_C
+# define MP_ZERO_C
+#endif
+
+#if defined(S_MP_DIV_SMALL_C)
+# define MP_ABS_C
+# define MP_ADD_C
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_2D_C
+# define MP_EXCH_C
+# define MP_INIT_MULTI_C
+# define MP_MUL_2D_C
+# define MP_SET_C
+# define MP_SUB_C
+#endif
+
+#if defined(S_MP_EXPTMOD_C)
+# define MP_CLEAR_C
+# define MP_COPY_C
+# define MP_COUNT_BITS_C
+# define MP_EXCH_C
+# define MP_INIT_C
+# define MP_MOD_C
+# define MP_MUL_C
+# define MP_REDUCE_2K_L_C
+# define MP_REDUCE_2K_SETUP_L_C
+# define MP_REDUCE_C
+# define MP_REDUCE_SETUP_C
+# define MP_SET_C
+#endif
+
+#if defined(S_MP_EXPTMOD_FAST_C)
+# define MP_CLEAR_C
+# define MP_COPY_C
+# define MP_COUNT_BITS_C
+# define MP_DR_REDUCE_C
+# define MP_DR_SETUP_C
+# define MP_EXCH_C
+# define MP_INIT_SIZE_C
+# define MP_MOD_C
+# define MP_MONTGOMERY_CALC_NORMALIZATION_C
+# define MP_MONTGOMERY_REDUCE_C
+# define MP_MONTGOMERY_SETUP_C
+# define MP_MULMOD_C
+# define MP_MUL_C
+# define MP_REDUCE_2K_C
+# define MP_REDUCE_2K_SETUP_C
+# define MP_SET_C
+# define S_MP_MONTGOMERY_REDUCE_COMBA_C
+#endif
+
+#if defined(S_MP_GET_BIT_C)
+#endif
+
+#if defined(S_MP_INVMOD_C)
+# define MP_ADD_C
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_C
+# define MP_CMP_D_C
+# define MP_CMP_MAG_C
+# define MP_COPY_C
+# define MP_DIV_2_C
+# define MP_EXCH_C
+# define MP_INIT_MULTI_C
+# define MP_MOD_C
+# define MP_SET_C
+# define MP_SUB_C
+#endif
+
+#if defined(S_MP_INVMOD_ODD_C)
+# define MP_ADD_C
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_C
+# define MP_CMP_D_C
+# define MP_CMP_MAG_C
+# define MP_COPY_C
+# define MP_DIV_2_C
+# define MP_EXCH_C
+# define MP_INIT_MULTI_C
+# define MP_MOD_C
+# define MP_SET_C
+# define MP_SUB_C
+#endif
+
+#if defined(S_MP_LOG_C)
+# define MP_CLEAR_MULTI_C
+# define MP_CMP_C
+# define MP_CMP_D_C
+# define MP_COPY_C
+# define MP_EXCH_C
+# define MP_EXPT_N_C
+# define MP_INIT_MULTI_C
+# define MP_MUL_C
+# define MP_SET_C
+#endif
+
+#if defined(S_MP_LOG_2EXPT_C)
+# define MP_COUNT_BITS_C
+#endif
+
+#if defined(S_MP_LOG_D_C)
+#endif
+
+#if defined(S_MP_MONTGOMERY_REDUCE_COMBA_C)
+# define MP_CLAMP_C
+# define MP_CMP_MAG_C
+# define MP_GROW_C
+# define S_MP_SUB_C
+# define S_MP_ZERO_BUF_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(S_MP_MUL_C)
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_EXCH_C
+# define MP_INIT_SIZE_C
+# define S_MP_MUL_COMBA_C
+#endif
+
+#if defined(S_MP_MUL_BALANCE_C)
+# define MP_ADD_C
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_CLEAR_MULTI_C
+# define MP_EXCH_C
+# define MP_INIT_MULTI_C
+# define MP_INIT_SIZE_C
+# define MP_LSHD_C
+# define MP_MUL_C
+# define S_MP_COPY_DIGS_C
+#endif
+
+#if defined(S_MP_MUL_COMBA_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(S_MP_MUL_HIGH_C)
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_EXCH_C
+# define MP_INIT_SIZE_C
+# define S_MP_MUL_HIGH_COMBA_C
+#endif
+
+#if defined(S_MP_MUL_HIGH_COMBA_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(S_MP_MUL_KARATSUBA_C)
+# define MP_ADD_C
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_INIT_SIZE_C
+# define MP_LSHD_C
+# define MP_MUL_C
+# define S_MP_ADD_C
+# define S_MP_COPY_DIGS_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(S_MP_MUL_TOOM_C)
+# define MP_ADD_C
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_CLEAR_MULTI_C
+# define MP_DIV_2_C
+# define MP_INIT_MULTI_C
+# define MP_INIT_SIZE_C
+# define MP_LSHD_C
+# define MP_MUL_2_C
+# define MP_MUL_C
+# define MP_SUB_C
+# define S_MP_COPY_DIGS_C
+# define S_MP_DIV_3_C
+#endif
+
+#if defined(S_MP_PRIME_IS_DIVISIBLE_C)
+# define MP_DIV_D_C
+#endif
+
+#if defined(S_MP_PRIME_TAB_C)
+#endif
+
+#if defined(S_MP_RADIX_MAP_C)
+#endif
+
+#if defined(S_MP_RADIX_SIZE_OVERESTIMATE_C)
+# define MP_CLEAR_MULTI_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_2D_C
+# define MP_GET_I64_C
+# define MP_INIT_MULTI_C
+# define MP_MUL_C
+# define MP_SET_U32_C
+# define S_MP_LOG_2EXPT_C
+#endif
+
+#if defined(S_MP_RAND_PLATFORM_C)
+#endif
+
+#if defined(S_MP_SQR_C)
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_EXCH_C
+# define MP_INIT_SIZE_C
+#endif
+
+#if defined(S_MP_SQR_COMBA_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(S_MP_SQR_KARATSUBA_C)
+# define MP_ADD_C
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_INIT_SIZE_C
+# define MP_LSHD_C
+# define MP_MUL_C
+# define S_MP_ADD_C
+# define S_MP_COPY_DIGS_C
+# define S_MP_SUB_C
+#endif
+
+#if defined(S_MP_SQR_TOOM_C)
+# define MP_ADD_C
+# define MP_CLAMP_C
+# define MP_CLEAR_C
+# define MP_DIV_2_C
+# define MP_INIT_C
+# define MP_INIT_SIZE_C
+# define MP_LSHD_C
+# define MP_MUL_2_C
+# define MP_MUL_C
+# define MP_SUB_C
+# define S_MP_COPY_DIGS_C
+#endif
+
+#if defined(S_MP_SUB_C)
+# define MP_CLAMP_C
+# define MP_GROW_C
+# define S_MP_ZERO_DIGS_C
+#endif
+
+#if defined(S_MP_ZERO_BUF_C)
+#endif
+
+#if defined(S_MP_ZERO_DIGS_C)
+#endif
+
+#ifdef LTM_INSIDE
+#undef LTM_INSIDE
+#ifdef LTM3
+# define LTM_LAST
+#endif
+
+#include "tommath_superclass.h"
+#include "tommath_class.h"
+#else
+# define LTM_LAST
+#endif
diff --git a/src/libtommath/tommath_cutoffs.h b/src/libtommath/tommath_cutoffs.h
new file mode 100644
index 000000000..fb8416013
--- /dev/null
+++ b/src/libtommath/tommath_cutoffs.h
@@ -0,0 +1,13 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+/*
+ Current values evaluated on an AMD A8-6600K (64-bit).
+ Type "make tune" to optimize them for your machine but
+ be aware that it may take a long time. It took 2:30 minutes
+ on the aforementioned machine for example.
+ */
+
+#define MP_DEFAULT_MUL_KARATSUBA_CUTOFF 80
+#define MP_DEFAULT_SQR_KARATSUBA_CUTOFF 120
+#define MP_DEFAULT_MUL_TOOM_CUTOFF 350
+#define MP_DEFAULT_SQR_TOOM_CUTOFF 400
diff --git a/src/libtommath/tommath_private.h b/src/libtommath/tommath_private.h
new file mode 100644
index 000000000..42920519c
--- /dev/null
+++ b/src/libtommath/tommath_private.h
@@ -0,0 +1,279 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef TOMMATH_PRIVATE_H_
+#define TOMMATH_PRIVATE_H_
+
+#include "tommath.h"
+#include "tommath_class.h"
+#include <limits.h>
+
+/*
+ * Private symbols
+ * ---------------
+ *
+ * On Unix symbols can be marked as hidden if libtommath is compiled
+ * as a shared object. By default, symbols are visible.
+ * On Win32 a .def file must be used to specify the exported symbols.
+ */
+#if defined(__GNUC__) && __GNUC__ >= 4 && !defined(_WIN32) && !defined(__CYGWIN__)
+# define MP_PRIVATE __attribute__ ((visibility ("hidden")))
+#else
+# define MP_PRIVATE
+#endif
+
+/* Hardening libtommath
+ * --------------------
+ *
+ * By default memory is zeroed before calling
+ * MP_FREE to avoid leaking data. This is good
+ * practice in cryptographical applications.
+ *
+ * Note however that memory allocators used
+ * in cryptographical applications can often
+ * be configured by itself to clear memory,
+ * rendering the clearing in tommath unnecessary.
+ * See for example https://github.com/GrapheneOS/hardened_malloc
+ * and the option CONFIG_ZERO_ON_FREE.
+ *
+ * Furthermore there are applications which
+ * value performance more and want this
+ * feature to be disabled. For such applications
+ * define MP_NO_ZERO_ON_FREE during compilation.
+ */
+#ifdef MP_NO_ZERO_ON_FREE
+# define MP_FREE_BUF(mem, size) MP_FREE((mem), (size))
+# define MP_FREE_DIGS(mem, digits) MP_FREE((mem), sizeof (mp_digit) * (size_t)(digits))
+#else
+# define MP_FREE_BUF(mem, size) \
+do { \
+ size_t fs_ = (size); \
+ void* fm_ = (mem); \
+ if (fm_ != NULL) { \
+ s_mp_zero_buf(fm_, fs_); \
+ MP_FREE(fm_, fs_); \
+ } \
+} while (0)
+# define MP_FREE_DIGS(mem, digits) \
+do { \
+ int fd_ = (digits); \
+ mp_digit* fm_ = (mem); \
+ if (fm_ != NULL) { \
+ s_mp_zero_digs(fm_, fd_); \
+ MP_FREE(fm_, sizeof (mp_digit) * (size_t)fd_); \
+ } \
+} while (0)
+#endif
+
+/* Tunable cutoffs
+ * ---------------
+ *
+ * - In the default settings, a cutoff X can be modified at runtime
+ * by adjusting the corresponding X_CUTOFF variable.
+ *
+ * - Tunability of the library can be disabled at compile time
+ * by defining the MP_FIXED_CUTOFFS macro.
+ *
+ * - There is an additional file tommath_cutoffs.h, which defines
+ * the default cutoffs. These can be adjusted manually or by the
+ * autotuner.
+ *
+ */
+
+#ifdef MP_FIXED_CUTOFFS
+# include "tommath_cutoffs.h"
+# define MP_MUL_KARATSUBA_CUTOFF MP_DEFAULT_MUL_KARATSUBA_CUTOFF
+# define MP_SQR_KARATSUBA_CUTOFF MP_DEFAULT_SQR_KARATSUBA_CUTOFF
+# define MP_MUL_TOOM_CUTOFF MP_DEFAULT_MUL_TOOM_CUTOFF
+# define MP_SQR_TOOM_CUTOFF MP_DEFAULT_SQR_TOOM_CUTOFF
+#endif
+
+/* define heap macros */
+#ifndef MP_MALLOC
+/* default to libc stuff */
+# include <stdlib.h>
+# define MP_MALLOC(size) malloc(size)
+# define MP_REALLOC(mem, oldsize, newsize) realloc((mem), (newsize))
+# define MP_CALLOC(nmemb, size) calloc((nmemb), (size))
+# define MP_FREE(mem, size) free(mem)
+#else
+/* prototypes for our heap functions */
+extern void *MP_MALLOC(size_t size);
+extern void *MP_REALLOC(void *mem, size_t oldsize, size_t newsize);
+extern void *MP_CALLOC(size_t nmemb, size_t size);
+extern void MP_FREE(void *mem, size_t size);
+#endif
+
+/* feature detection macro */
+#ifdef _MSC_VER
+/* Prevent false positive: not enough arguments for function-like macro invocation */
+#pragma warning(disable: 4003)
+#endif
+#define MP_STRINGIZE(x) MP__STRINGIZE(x)
+#define MP__STRINGIZE(x) ""#x""
+#define MP_HAS(x) (sizeof(MP_STRINGIZE(x##_C)) == 1u)
+
+#define MP_MIN(x, y) (((x) < (y)) ? (x) : (y))
+#define MP_MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+#define MP_TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (((c) + 'A') - 'a') : (c))
+
+#define MP_EXCH(t, a, b) do { t _c = a; a = b; b = _c; } while (0)
+
+#define MP_IS_2EXPT(x) (((x) != 0u) && (((x) & ((x) - 1u)) == 0u))
+
+/* Static assertion */
+#define MP_STATIC_ASSERT(msg, cond) typedef char mp_static_assert_##msg[(cond) ? 1 : -1];
+
+#define MP_SIZEOF_BITS(type) ((size_t)CHAR_BIT * sizeof(type))
+
+#define MP_MAX_COMBA (int)(1uL << (MP_SIZEOF_BITS(mp_word) - (2u * (size_t)MP_DIGIT_BIT)))
+#define MP_WARRAY (int)(1uL << ((MP_SIZEOF_BITS(mp_word) - (2u * (size_t)MP_DIGIT_BIT)) + 1u))
+
+#if defined(MP_16BIT)
+typedef uint32_t mp_word;
+#elif defined(MP_64BIT)
+typedef unsigned long mp_word __attribute__((mode(TI)));
+#else
+typedef uint64_t mp_word;
+#endif
+
+MP_STATIC_ASSERT(correct_word_size, sizeof(mp_word) == (2u * sizeof(mp_digit)))
+
+/* default number of digits */
+#ifndef MP_DEFAULT_DIGIT_COUNT
+# ifndef MP_LOW_MEM
+# define MP_DEFAULT_DIGIT_COUNT 32
+# else
+# define MP_DEFAULT_DIGIT_COUNT 8
+# endif
+#endif
+
+/* Minimum number of available digits in mp_int, MP_DEFAULT_DIGIT_COUNT >= MP_MIN_DIGIT_COUNT
+ * - Must be at least 3 for s_mp_div_school.
+ * - Must be large enough such that the mp_set_u64 setter can
+ * store uint64_t in the mp_int without growing
+ */
+#define MP_MIN_DIGIT_COUNT MP_MAX(3, (((int)MP_SIZEOF_BITS(uint64_t) + MP_DIGIT_BIT) - 1) / MP_DIGIT_BIT)
+MP_STATIC_ASSERT(prec_geq_min_prec, MP_DEFAULT_DIGIT_COUNT >= MP_MIN_DIGIT_COUNT)
+
+/* Maximum number of digits.
+ * - Must be small enough such that mp_bit_count does not overflow.
+ * - Must be small enough such that mp_radix_size for base 2 does not overflow.
+ * mp_radix_size needs two additional bytes for zero termination and sign.
+ */
+#define MP_MAX_DIGIT_COUNT ((INT_MAX - 2) / MP_DIGIT_BIT)
+
+#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) \
+ || defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) \
+ || defined(__i386__) || defined(_M_X86) || defined(_M_IX86) \
+ || defined(__aarch64__) || defined(__arm__)
+#define MP_HAS_SET_DOUBLE
+#endif
+
+/* random number source */
+extern MP_PRIVATE mp_err(*s_mp_rand_source)(void *out, size_t size);
+
+/* lowlevel functions, do not call! */
+MP_PRIVATE bool s_mp_get_bit(const mp_int *a, int b) MP_WUR;
+MP_PRIVATE int s_mp_log_2expt(const mp_int *a, mp_digit base) MP_WUR;
+MP_PRIVATE int s_mp_log_d(mp_digit base, mp_digit n) MP_WUR;
+MP_PRIVATE mp_err s_mp_add(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_div_3(const mp_int *a, mp_int *c, mp_digit *d) MP_WUR;
+MP_PRIVATE mp_err s_mp_div_recursive(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r) MP_WUR;
+MP_PRIVATE mp_err s_mp_div_school(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) MP_WUR;
+MP_PRIVATE mp_err s_mp_div_small(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) MP_WUR;
+MP_PRIVATE mp_err s_mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) MP_WUR;
+MP_PRIVATE mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) MP_WUR;
+MP_PRIVATE mp_err s_mp_invmod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_invmod_odd(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_log(const mp_int *a, mp_digit base, int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_montgomery_reduce_comba(mp_int *x, const mp_int *n, mp_digit rho) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_balance(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_comba(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_high(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_high_comba(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_karatsuba(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_toom(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_prime_is_divisible(const mp_int *a, bool *result) MP_WUR;
+MP_PRIVATE mp_err s_mp_rand_platform(void *p, size_t n) MP_WUR;
+MP_PRIVATE mp_err s_mp_sqr(const mp_int *a, mp_int *b) MP_WUR;
+MP_PRIVATE mp_err s_mp_sqr_comba(const mp_int *a, mp_int *b) MP_WUR;
+MP_PRIVATE mp_err s_mp_sqr_karatsuba(const mp_int *a, mp_int *b) MP_WUR;
+MP_PRIVATE mp_err s_mp_sqr_toom(const mp_int *a, mp_int *b) MP_WUR;
+MP_PRIVATE mp_err s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE void s_mp_copy_digs(mp_digit *d, const mp_digit *s, int digits);
+MP_PRIVATE void s_mp_zero_buf(void *mem, size_t size);
+MP_PRIVATE void s_mp_zero_digs(mp_digit *d, int digits);
+MP_PRIVATE mp_err s_mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size);
+
+#define MP_RADIX_MAP_REVERSE_SIZE 80u
+extern MP_PRIVATE const char s_mp_radix_map[];
+extern MP_PRIVATE const uint8_t s_mp_radix_map_reverse[];
+extern MP_PRIVATE const mp_digit s_mp_prime_tab[];
+
+/* number of primes */
+#define MP_PRIME_TAB_SIZE 256
+
+#define MP_GET_ENDIANNESS(x) \
+ do{\
+ int16_t n = 0x1; \
+ char *p = (char *)&n; \
+ x = (p[0] == '\x01') ? MP_LITTLE_ENDIAN : MP_BIG_ENDIAN; \
+ } while (0)
+
+/* code-generating macros */
+#define MP_SET_UNSIGNED(name, type) \
+ void name(mp_int * a, type b) \
+ { \
+ int i = 0; \
+ while (b != 0u) { \
+ a->dp[i++] = ((mp_digit)b & MP_MASK); \
+ if (MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) { break; } \
+ b >>= ((MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) ? 0 : MP_DIGIT_BIT); \
+ } \
+ a->used = i; \
+ a->sign = MP_ZPOS; \
+ s_mp_zero_digs(a->dp + a->used, a->alloc - a->used); \
+ }
+
+#define MP_SET_SIGNED(name, uname, type, utype) \
+ void name(mp_int * a, type b) \
+ { \
+ uname(a, (b < 0) ? -(utype)b : (utype)b); \
+ if (b < 0) { a->sign = MP_NEG; } \
+ }
+
+#define MP_INIT_INT(name , set, type) \
+ mp_err name(mp_int * a, type b) \
+ { \
+ mp_err err; \
+ if ((err = mp_init(a)) != MP_OKAY) { \
+ return err; \
+ } \
+ set(a, b); \
+ return MP_OKAY; \
+ }
+
+#define MP_GET_MAG(name, type) \
+ type name(const mp_int* a) \
+ { \
+ int i = MP_MIN(a->used, (int)((MP_SIZEOF_BITS(type) + MP_DIGIT_BIT - 1) / MP_DIGIT_BIT)); \
+ type res = 0u; \
+ while (i --> 0) { \
+ res <<= ((MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) ? 0 : MP_DIGIT_BIT); \
+ res |= (type)a->dp[i]; \
+ if (MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) { break; } \
+ } \
+ return res; \
+ }
+
+#define MP_GET_SIGNED(name, mag, type, utype) \
+ type name(const mp_int* a) \
+ { \
+ utype res = mag(a); \
+ return mp_isneg(a) ? (type)-res : (type)res; \
+ }
+
+#endif
diff --git a/src/libtommath/tommath_superclass.h b/src/libtommath/tommath_superclass.h
new file mode 100644
index 000000000..9245e0020
--- /dev/null
+++ b/src/libtommath/tommath_superclass.h
@@ -0,0 +1,113 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* super class file for PK algos */
+
+/* default ... include all MPI */
+#ifndef LTM_NOTHING
+#define LTM_ALL
+#endif
+
+/* RSA only (does not support DH/DSA/ECC) */
+/* #define SC_RSA_1 */
+/* #define SC_RSA_1_WITH_TESTS */
+
+/* For reference.... On an Athlon64 optimizing for speed...
+
+ LTM's mpi.o with all functions [striped] is 142KiB in size.
+
+*/
+
+#ifdef SC_RSA_1_WITH_TESTS
+# define MP_ERROR_TO_STRING_C
+# define MP_FREAD_C
+# define MP_FWRITE_C
+# define MP_INCR_C
+# define MP_ISEVEN_C
+# define MP_ISODD_C
+# define MP_NEG_C
+# define MP_PRIME_FROBENIUS_UNDERWOOD_C
+# define MP_RADIX_SIZE_C
+# define MP_RADIX_SIZE_OVERESTIMATE_C
+# define MP_LOG_N_C
+# define MP_RAND_C
+# define MP_REDUCE_C
+# define MP_REDUCE_2K_L_C
+# define MP_FROM_SBIN_C
+# define MP_ROOT_N_C
+# define MP_SET_L_C
+# define MP_SET_UL_C
+# define MP_SET_U64_C
+# define MP_SET_I64_C
+# define MP_SBIN_SIZE_C
+# define MP_TO_RADIX_C
+# define MP_TO_SBIN_C
+# define S_MP_RAND_JENKINS_C
+# define S_MP_RAND_PLATFORM_C
+#endif
+
+/* Works for RSA only, mpi.o is 68KiB */
+#if defined(SC_RSA_1) || defined (SC_RSA_1_WITH_TESTS)
+# define MP_CUTOFFS_C
+# define MP_ADDMOD_C
+# define MP_CLEAR_MULTI_C
+# define MP_EXPTMOD_C
+# define MP_GCD_C
+# define MP_INIT_MULTI_C
+# define MP_INVMOD_C
+# define MP_LCM_C
+# define MP_MOD_C
+# define MP_MOD_D_C
+# define MP_MULMOD_C
+# define MP_PRIME_IS_PRIME_C
+# define MP_PRIME_RABIN_MILLER_TRIALS_C
+# define MP_PRIME_RAND_C
+# define MP_SET_INT_C
+# define MP_SHRINK_C
+# define MP_TO_UNSIGNED_BIN_C
+# define MP_UNSIGNED_BIN_SIZE_C
+# define S_MP_PRIME_TAB_C
+# define S_MP_RADIX_MAP_C
+
+/* other modifiers */
+
+
+
+/* here we are on the last pass so we turn things off. The functions classes are still there
+ * but we remove them specifically from the build. This also invokes tweaks in functions
+ * like removing support for even moduli, etc...
+ */
+# ifdef LTM_LAST
+# undef MP_DR_IS_MODULUS_C
+# undef MP_DR_REDUCE_C
+# undef MP_DR_SETUP_C
+# undef MP_REDUCE_2K_C
+# undef MP_REDUCE_2K_SETUP_C
+# undef MP_REDUCE_IS_2K_C
+# undef MP_REDUCE_SETUP_C
+# undef S_MP_DIV_3_C
+# undef S_MP_EXPTMOD_C
+# undef S_MP_INVMOD_ODD_C
+# undef S_MP_MUL_BALANCE_C
+# undef S_MP_MUL_HIGH_C
+# undef S_MP_MUL_HIGH_COMBA_C
+# undef S_MP_MUL_KARATSUBA_C
+# undef S_MP_MUL_TOOM_C
+# undef S_MP_SQR_KARATSUBA_C
+# undef S_MP_SQR_TOOM_C
+
+# ifndef SC_RSA_1_WITH_TESTS
+# undef MP_REDUCE_C
+# endif
+
+/* To safely undefine these you have to make sure your RSA key won't exceed the Comba threshold
+ * which is roughly 255 digits [7140 bits for 32-bit machines, 15300 bits for 64-bit machines]
+ * which means roughly speaking you can handle upto 2536-bit RSA keys with these defined without
+ * trouble.
+ */
+# undef MP_MONTGOMERY_REDUCE_C
+# undef S_MP_MUL_C
+# undef S_MP_SQR_C
+# endif
+
+#endif
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index c351876d4..fa45583d6 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -6558,36 +6558,70 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
case ExactValue_Integer:
if (is_type_pointer(type)) {
- unsigned len = cast(unsigned)value.value_integer.len;
LLVMTypeRef t = lb_type(m, original_type);
- if (len == 0) {
+ if (mp_iszero(&value.value_integer)) {
res.value = LLVMConstNull(t);
} else {
- LLVMValueRef i = LLVMConstIntOfArbitraryPrecision(lb_type(m, t_uintptr), len, big_int_ptr(&value.value_integer));
+ unsigned len = cast(unsigned)value.value_integer.used;
+ u64 v = mp_get_u64(&value.value_integer);
+ LLVMValueRef i = LLVMConstInt(lb_type(m, t_uintptr), cast(unsigned long long)v, false);
res.value = LLVMConstIntToPtr(i, t);
}
} else {
- unsigned len = cast(unsigned)value.value_integer.len;
- if (len == 0) {
+ if (mp_iszero(&value.value_integer)) {
res.value = LLVMConstNull(lb_type(m, original_type));
} else {
- u64 *words = big_int_ptr(&value.value_integer);
- if (is_type_different_to_arch_endianness(type)) {
- // NOTE(bill): Swap byte order for different endianness
- i64 sz = type_size_of(type);
- isize byte_len = gb_size_of(u64)*len;
- u8 *old_bytes = cast(u8 *)words;
- // TODO(bill): Use a different allocator here for a temporary allocation
- u8 *new_bytes = cast(u8 *)gb_alloc_align(permanent_allocator(), byte_len, gb_align_of(u64));
- for (i64 i = 0; i < sz; i++) {
- new_bytes[i] = old_bytes[sz-1-i];
- }
- words = cast(u64 *)new_bytes;
- }
- res.value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), len, words);
- if (value.value_integer.neg) {
+ mp_int *a = &value.value_integer;
+
+ u8 *rop = nullptr;
+ size_t max_count = 0;
+ size_t written = 0;
+ size_t size = 1;
+ size_t nails = 0;
+ mp_endian endian = MP_NATIVE_ENDIAN;
+ if (is_type_endian_little(type)) {
+ endian = MP_LITTLE_ENDIAN;
+ } else if (is_type_endian_big(type)) {
+ endian = MP_BIG_ENDIAN;
+ }
+
+ max_count = mp_pack_count(a, nails, size);
+ rop = cast(u8 *)gb_alloc_align(permanent_allocator(), max_count, gb_align_of(u64));
+ mp_err err = mp_pack(rop, max_count, &written,
+ MP_LSB_FIRST,
+ size, endian, nails,
+ &value.value_integer);
+ GB_ASSERT(err == MP_OKAY);
+
+ res.value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)((written+7)/8), cast(u64 *)rop);
+ if (value.value_integer.sign) {
res.value = LLVMConstNeg(res.value);
}
+
+ // size_t written = 0;
+ // size_t max_bytes = (value.value_integer.used*gb_size_of(mp_digit)+7)&~7;
+ // u8 *buf = cast(u8 *)gb_alloc_align(permanent_allocator(), max_bytes, gb_align_of(u64));
+ // mp_to_ubin(&value.value_integer, buf, max_bytes, &written);
+
+ // gb_printf_err("%tu %tu", written, max_bytes);
+ // for (size_t i = 0; i < written; i++) {
+ // gb_printf_err("%02x", buf[i]);
+ // }
+ // gb_printf_err("\n");
+ // gb_exit(1);
+
+ // if (is_type_different_to_arch_endianness(type)) {
+ // u8 *old_bytes = buf;
+ // u8 *new_bytes = cast(u8 *)gb_alloc_align(permanent_allocator(), max_bytes, gb_align_of(u64));
+ // for (size_t i = 0; i < written; i++) {
+ // new_bytes[i] = old_bytes[written-1-i];
+ // }
+ // buf = new_bytes;
+ // }
+ // res.value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)((written+7)/8), cast(u64 *)buf);
+ // if (value.value_integer.sign) {
+ // res.value = LLVMConstNeg(res.value);
+ // }
}
}
return res;
diff --git a/src/main.cpp b/src/main.cpp
index 345642cc6..8c4eb7d7c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1970,7 +1970,6 @@ int main(int arg_count, char const **arg_ptr) {
init_string_interner();
init_global_error_collector();
init_keyword_hash_table();
- global_big_int_init();
init_type_mutex();
if (!check_env()) {