├── modulemap └── module.modulemap ├── logs ├── Makefile ├── index.html ├── README ├── before_after.html ├── graphs.dem └── before_after.dem ├── mp_init_l.c ├── mp_set_u32.c ├── mp_set_u64.c ├── mp_set_ul.c ├── mp_get_mag_u32.c ├── mp_get_mag_u64.c ├── mp_get_mag_ul.c ├── mp_init_i32.c ├── mp_init_i64.c ├── mp_init_u32.c ├── mp_init_u64.c ├── mp_init_ul.c ├── s_mp_warray.c ├── mp_get_l.c ├── mp_set_l.c ├── mp_get_i32.c ├── mp_get_i64.c ├── mp_set_i32.c ├── mp_set_i64.c ├── s_mp_rand_source.c ├── etc ├── 2kprime.1 ├── makefile.msvc ├── timer.asm ├── makefile ├── mont.c ├── makefile.icc ├── drprime.c ├── 2kprime.c └── mersenne.c ├── mp_sbin_size.c ├── mp_zero.c ├── libtommath.pc.in ├── s_mp_log_2expt.c ├── mp_exch.c ├── mp_rand_source.c ├── s_mp_warray_put.c ├── mp_ubin_size.c ├── mp_complement.c ├── mp_init_set.c ├── mp_sqrmod.c ├── mp_pack_count.c ├── mp_addmod.c ├── mp_mulmod.c ├── mp_submod.c ├── mp_set.c ├── mp_clear_multi.c ├── mp_neg.c ├── mp_get_double.c ├── s_mp_zero_buf.c ├── mp_mod.c ├── mp_cutoffs.c ├── mp_dr_setup.c ├── mp_init_copy.c ├── s_mp_zero_digs.c ├── s_mp_warray_get.c ├── s_mp_copy_digs.c ├── mp_radix_size_overestimate.c ├── mp_reduce_setup.c ├── tommath_cutoffs.h ├── mp_clear.c ├── mp_abs.c ├── mp_cmp.c ├── s_mp_get_bit.c ├── mp_log_n.c ├── mp_signed_rsh.c ├── mp_cmp_d.c ├── astylerc ├── mp_from_sbin.c ├── mp_to_sbin.c ├── mtest ├── mpi-types.h ├── logtab.h └── mpi-config.h ├── mp_count_bits.c ├── mp_init.c ├── mp_cmp_mag.c ├── mp_reduce_2k_setup_l.c ├── mp_dr_is_modulus.c ├── mp_shrink.c ├── mp_reduce_2k_setup.c ├── mp_copy.c ├── mp_clamp.c ├── mp_reduce_is_2k_l.c ├── mp_init_size.c ├── mp_error_to_string.c ├── mp_from_ubin.c ├── mp_fwrite.c ├── mp_warray_free.c ├── mp_invmod.c ├── mp_radix_size.c ├── mp_to_ubin.c ├── mp_2expt.c ├── mp_add.c ├── s_mp_prime_is_divisible.c ├── mp_cnt_lsb.c ├── mp_rand.c ├── mp_expt_n.c ├── mp_div_2.c ├── mp_hash.c ├── demo ├── shared.h ├── s_mp_rand_jenkins.c ├── shared.c ├── CMakeLists.txt └── tommath_tests.swift ├── mp_mod_2d.c ├── mp_prime_fermat.c ├── mp_div.c ├── mp_lshd.c ├── mp_reduce_is_2k.c ├── s_mp_radix_map.c ├── mp_rshd.c ├── mp_init_multi.c ├── mp_reduce_2k.c ├── mp_lcm.c ├── mp_reduce_2k_l.c ├── mp_montgomery_setup.c ├── mp_sub.c ├── mp_montgomery_calc_normalization.c ├── mp_grow.c ├── LICENSE ├── mp_set_double.c ├── tommath_c89.h ├── mp_mul_2.c ├── libtommath_VS2008.sln ├── mp_xor.c ├── mp_and.c ├── mp_or.c ├── mp_unpack.c ├── mp_fread.c ├── Package.swift ├── doc └── makefile ├── s_mp_div_3.c ├── s_mp_mul_high.c ├── mp_mul_2d.c ├── s_mp_sub.c ├── mp_div_2d.c ├── mp_sqrt.c ├── mp_prime_rabin_miller_trials.c ├── s_mp_div_small.c ├── mp_mul_d.c ├── s_mp_add.c ├── mp_pack.c ├── s_mp_mul.c ├── mp_read_radix.c ├── mp_sub_d.c ├── mp_dr_reduce.c ├── mp_div_d.c ├── s_mp_mul_balance.c ├── mp_add_d.c ├── mp_reduce.c ├── s_mp_mul_high_comba.c ├── mp_prime_miller_rabin.c ├── mp_exptmod.c ├── s_mp_prime_tab.c ├── mp_to_radix.c ├── s_mp_fp_log_d.c ├── mp_gcd.c ├── s_mp_mul_comba.c ├── s_mp_sqr_comba.c ├── mp_montgomery_reduce.c ├── s_mp_sqr.c ├── mp_exteuclid.c ├── s_mp_sqr_karatsuba.c ├── mp_mul.c ├── tommath.def ├── mp_is_square.c ├── s_mp_radix_size_overestimate.c ├── mp_kronecker.c └── README.md /modulemap/module.modulemap: -------------------------------------------------------------------------------- 1 | module libtommath [extern_c] { 2 | header "../tommath.h" 3 | export * 4 | } 5 | -------------------------------------------------------------------------------- /logs/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | sed -e 's@\.log@-$(VERSION)\.log@g' graphs.dem > graphs-$(VERSION).dem 3 | gnuplot graphs-$(VERSION).dem 4 | 5 | cmp: 6 | gnuplot before_after.dem 7 | 8 | clean: 9 | rm -f *-*.log *.png graphs-*.dem 10 | -------------------------------------------------------------------------------- /mp_init_l.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_L_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_INIT_INT(mp_init_l, mp_set_l, long) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_set_u32.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SET_U32_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_SET_UNSIGNED(mp_set_u32, uint32_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_set_u64.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SET_U64_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_SET_UNSIGNED(mp_set_u64, uint64_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_set_ul.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SET_UL_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_SET_UNSIGNED(mp_set_ul, unsigned long) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_get_mag_u32.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_GET_MAG_U32_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_GET_MAG(mp_get_mag_u32, uint32_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_get_mag_u64.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_GET_MAG_U64_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_GET_MAG(mp_get_mag_u64, uint64_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_get_mag_ul.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_GET_MAG_UL_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_GET_MAG(mp_get_mag_ul, unsigned long) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_init_i32.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_I32_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_INIT_INT(mp_init_i32, mp_set_i32, int32_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_init_i64.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_I64_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_INIT_INT(mp_init_i64, mp_set_i64, int64_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_init_u32.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_U32_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_INIT_INT(mp_init_u32, mp_set_u32, uint32_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_init_u64.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_U64_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_INIT_INT(mp_init_u64, mp_set_u64, uint64_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_init_ul.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_UL_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_INIT_INT(mp_init_ul, mp_set_ul, unsigned long) 7 | #endif 8 | -------------------------------------------------------------------------------- /s_mp_warray.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_WARRAY_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | mp_thread st_warray s_mp_warray = { 0 }; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /mp_get_l.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_GET_L_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_GET_SIGNED(mp_get_l, mp_get_mag_ul, long, unsigned long) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_set_l.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SET_L_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_SET_SIGNED(mp_set_l, mp_set_ul, long, unsigned long) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_get_i32.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_GET_I32_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_GET_SIGNED(mp_get_i32, mp_get_mag_u32, int32_t, uint32_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_get_i64.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_GET_I64_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_GET_SIGNED(mp_get_i64, mp_get_mag_u64, int64_t, uint64_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_set_i32.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SET_I32_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_SET_SIGNED(mp_set_i32, mp_set_u32, int32_t, uint32_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /mp_set_i64.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SET_I64_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | MP_SET_SIGNED(mp_set_i64, mp_set_u64, int64_t, uint64_t) 7 | #endif 8 | -------------------------------------------------------------------------------- /s_mp_rand_source.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_RAND_SOURCE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | mp_err(*s_mp_rand_source)(void *out, size_t size) = s_mp_rand_platform; 7 | #endif 8 | -------------------------------------------------------------------------------- /etc/2kprime.1: -------------------------------------------------------------------------------- 1 | 256-bits (k = 36113) = 115792089237316195423570985008687907853269984665640564039457584007913129603823 2 | 512-bits (k = 38117) = 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006045979 3 | -------------------------------------------------------------------------------- /mp_sbin_size.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SBIN_SIZE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* get the size for an signed equivalent */ 7 | size_t mp_sbin_size(const mp_int *a) 8 | { 9 | return 1u + mp_ubin_size(a); 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /mp_zero.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_ZERO_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* set to zero */ 7 | void mp_zero(mp_int *a) 8 | { 9 | a->sign = MP_ZPOS; 10 | s_mp_zero_digs(a->dp, a->used); 11 | a->used = 0; 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /libtommath.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ 3 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/@PROJECT_NAME@ 4 | 5 | Name: LibTomMath 6 | Description: public domain library for manipulating large integer numbers 7 | Version: @PROJECT_VERSION@ 8 | Libs: -L${libdir} -ltommath 9 | Cflags: -I${includedir} 10 | -------------------------------------------------------------------------------- /s_mp_log_2expt.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_LOG_2EXPT_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | int s_mp_log_2expt(const mp_int *a, mp_digit base) 7 | { 8 | int y; 9 | for (y = 0; (base & 1) == 0; y++, base >>= 1) {} 10 | return (mp_count_bits(a) - 1) / y; 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /mp_exch.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_EXCH_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* swap the elements of two integers, for cases where you can't simply swap the 7 | * mp_int pointers around 8 | */ 9 | void mp_exch(mp_int *a, mp_int *b) 10 | { 11 | MP_EXCH(mp_int, *a, *b); 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /mp_rand_source.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_RAND_SOURCE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | void mp_rand_source(mp_err(*source)(void *out, size_t size)) 6 | { 7 | if (source == NULL) 8 | s_mp_rand_source = s_mp_rand_platform; 9 | else 10 | s_mp_rand_source = source; 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /s_mp_warray_put.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_WARRAY_PUT_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | void s_mp_warray_put(void *w) 7 | { 8 | if (s_mp_warray.w_free || s_mp_warray.w_used != w) 9 | return; 10 | s_mp_warray.w_free = w; 11 | s_mp_warray.w_used = NULL; 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /mp_ubin_size.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_UBIN_SIZE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* get the size for an unsigned equivalent */ 7 | size_t mp_ubin_size(const mp_int *a) 8 | { 9 | size_t size = (size_t)mp_count_bits(a); 10 | return (size / 8u) + (((size & 7u) != 0u) ? 1u : 0u); 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /mp_complement.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_COMPLEMENT_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* b = ~a */ 7 | mp_err mp_complement(const mp_int *a, mp_int *b) 8 | { 9 | mp_int a_ = *a; 10 | a_.sign = ((a_.sign == MP_ZPOS) && !mp_iszero(a)) ? MP_NEG : MP_ZPOS; 11 | return mp_sub_d(&a_, 1uL, b); 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /mp_init_set.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_SET_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* initialize and set a digit */ 7 | mp_err mp_init_set(mp_int *a, mp_digit b) 8 | { 9 | mp_err err; 10 | if ((err = mp_init(a)) != MP_OKAY) { 11 | return err; 12 | } 13 | mp_set(a, b); 14 | return err; 15 | } 16 | #endif 17 | -------------------------------------------------------------------------------- /mp_sqrmod.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SQRMOD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* c = a * a (mod b) */ 7 | mp_err mp_sqrmod(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | mp_err err; 10 | if ((err = mp_sqr(a, c)) != MP_OKAY) { 11 | return err; 12 | } 13 | return mp_mod(c, b, c); 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /mp_pack_count.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_PACK_COUNT_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | size_t mp_pack_count(const mp_int *a, size_t nails, size_t size) 7 | { 8 | size_t bits = (size_t)mp_count_bits(a); 9 | return ((bits / ((size * 8u) - nails)) + (((bits % ((size * 8u) - nails)) != 0u) ? 1u : 0u)); 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /mp_addmod.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_ADDMOD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* d = a + b (mod c) */ 7 | mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) 8 | { 9 | mp_err err; 10 | if ((err = mp_add(a, b, d)) != MP_OKAY) { 11 | return err; 12 | } 13 | return mp_mod(d, c, d); 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /mp_mulmod.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MULMOD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* d = a * b (mod c) */ 7 | mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) 8 | { 9 | mp_err err; 10 | if ((err = mp_mul(a, b, d)) != MP_OKAY) { 11 | return err; 12 | } 13 | return mp_mod(d, c, d); 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /mp_submod.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SUBMOD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* d = a - b (mod c) */ 7 | mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) 8 | { 9 | mp_err err; 10 | if ((err = mp_sub(a, b, d)) != MP_OKAY) { 11 | return err; 12 | } 13 | return mp_mod(d, c, d); 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /mp_set.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SET_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* set to a digit */ 7 | void mp_set(mp_int *a, mp_digit b) 8 | { 9 | int oldused = a->used; 10 | a->dp[0] = b & MP_MASK; 11 | a->sign = MP_ZPOS; 12 | a->used = (a->dp[0] != 0u) ? 1 : 0; 13 | s_mp_zero_digs(a->dp + a->used, oldused - a->used); 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /mp_clear_multi.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_CLEAR_MULTI_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #include 7 | 8 | void mp_clear_multi(mp_int *mp, ...) 9 | { 10 | va_list args; 11 | va_start(args, mp); 12 | while (mp != NULL) { 13 | mp_clear(mp); 14 | mp = va_arg(args, mp_int *); 15 | } 16 | va_end(args); 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /logs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | LibTomMath Log Plots 4 | 5 | 6 | 7 |

Addition and Subtraction

8 |
9 |
10 | 11 |

Multipliers

12 |
13 |
14 | 15 |

Exptmod

16 |
17 |
18 | 19 |

Modular Inverse

20 |
21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /mp_neg.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_NEG_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* b = -a */ 7 | mp_err mp_neg(const mp_int *a, mp_int *b) 8 | { 9 | mp_err err; 10 | if ((err = mp_copy(a, b)) != MP_OKAY) { 11 | return err; 12 | } 13 | 14 | b->sign = ((!mp_iszero(b) && !mp_isneg(b)) ? MP_NEG : MP_ZPOS); 15 | 16 | return MP_OKAY; 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /logs/README: -------------------------------------------------------------------------------- 1 | To use the pretty graphs you have to first build/run the ltmtest from the root directory of the package. 2 | Todo this type 3 | 4 | make timing ; ltmtest 5 | 6 | in the root. It will run for a while [about ten minutes on most PCs] and produce a series of .log files in logs/. 7 | 8 | After doing that run "gnuplot graphs.dem" to make the PNGs. If you managed todo that all so far just open index.html to view 9 | them all :-) 10 | 11 | Have fun 12 | 13 | Tom -------------------------------------------------------------------------------- /etc/makefile.msvc: -------------------------------------------------------------------------------- 1 | #MSVC Makefile 2 | # 3 | #Tom St Denis 4 | 5 | CFLAGS = /I../ /Ox /DWIN32 /W3 6 | 7 | pprime: pprime.obj 8 | cl pprime.obj ../tommath.lib 9 | 10 | mersenne: mersenne.obj 11 | cl mersenne.obj ../tommath.lib 12 | 13 | tune: tune.obj 14 | cl tune.obj ../tommath.lib 15 | 16 | 17 | mont: mont.obj 18 | cl mont.obj ../tommath.lib 19 | 20 | drprime: drprime.obj 21 | cl drprime.obj ../tommath.lib 22 | 23 | 2kprime: 2kprime.obj 24 | cl 2kprime.obj ../tommath.lib 25 | -------------------------------------------------------------------------------- /mp_get_double.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_GET_DOUBLE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | double mp_get_double(const mp_int *a) 7 | { 8 | int i; 9 | double d = 0.0, fac = 1.0; 10 | for (i = 0; i < MP_DIGIT_BIT; ++i) { 11 | fac *= 2.0; 12 | } 13 | for (i = a->used; i --> 0;) { 14 | d = (d * fac) + (double)a->dp[i]; 15 | } 16 | return mp_isneg(a) ? -d : d; 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /s_mp_zero_buf.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_ZERO_BUF_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #ifdef MP_USE_MEMOPS 7 | # include 8 | #endif 9 | 10 | void s_mp_zero_buf(void *mem, size_t size) 11 | { 12 | #ifdef MP_USE_MEMOPS 13 | memset(mem, 0, size); 14 | #else 15 | char *m = (char *)mem; 16 | while (size-- > 0u) { 17 | *m++ = '\0'; 18 | } 19 | #endif 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /mp_mod.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MOD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* c = a mod b, 0 <= c < b if b > 0, b < c <= 0 if b < 0 */ 7 | mp_err mp_mod(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | mp_err err; 10 | if ((err = mp_div(a, b, NULL, c)) != MP_OKAY) { 11 | return err; 12 | } 13 | return mp_iszero(c) || (c->sign == b->sign) ? MP_OKAY : mp_add(b, c, c); 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /mp_cutoffs.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_CUTOFFS_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #ifndef MP_FIXED_CUTOFFS 7 | #include "tommath_cutoffs.h" 8 | int MP_MUL_KARATSUBA_CUTOFF = MP_DEFAULT_MUL_KARATSUBA_CUTOFF, 9 | MP_SQR_KARATSUBA_CUTOFF = MP_DEFAULT_SQR_KARATSUBA_CUTOFF, 10 | MP_MUL_TOOM_CUTOFF = MP_DEFAULT_MUL_TOOM_CUTOFF, 11 | MP_SQR_TOOM_CUTOFF = MP_DEFAULT_SQR_TOOM_CUTOFF; 12 | #endif 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /mp_dr_setup.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_DR_SETUP_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* determines the setup value */ 7 | void mp_dr_setup(const mp_int *a, mp_digit *d) 8 | { 9 | /* the casts are required if MP_DIGIT_BIT is one less than 10 | * the number of bits in a mp_digit [e.g. MP_DIGIT_BIT==31] 11 | */ 12 | *d = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - (mp_word)a->dp[0]); 13 | } 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /mp_init_copy.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_COPY_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* creates "a" then copies b into it */ 7 | mp_err mp_init_copy(mp_int *a, const mp_int *b) 8 | { 9 | mp_err err; 10 | 11 | if ((err = mp_init_size(a, b->used)) != MP_OKAY) { 12 | return err; 13 | } 14 | 15 | if ((err = mp_copy(b, a)) != MP_OKAY) { 16 | mp_clear(a); 17 | } 18 | 19 | return err; 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /s_mp_zero_digs.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_ZERO_DIGS_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #ifdef MP_USE_MEMOPS 7 | # include 8 | #endif 9 | 10 | void s_mp_zero_digs(mp_digit *d, int digits) 11 | { 12 | #ifdef MP_USE_MEMOPS 13 | if (digits > 0) { 14 | memset(d, 0, (size_t)digits * sizeof(mp_digit)); 15 | } 16 | #else 17 | while (digits-- > 0) { 18 | *d++ = 0; 19 | } 20 | #endif 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /s_mp_warray_get.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_WARRAY_GET_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | void *s_mp_warray_get(void) 7 | { 8 | if (s_mp_warray.w_used) 9 | return NULL; 10 | if (s_mp_warray.w_free == NULL) { 11 | s_mp_warray.w_free = MP_CALLOC(MP_WARRAY, sizeof(mp_word)); 12 | } 13 | s_mp_warray.w_used = s_mp_warray.w_free; 14 | s_mp_warray.w_free = NULL; 15 | return s_mp_warray.w_used; 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /s_mp_copy_digs.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_COPY_DIGS_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #ifdef MP_USE_MEMOPS 7 | # include 8 | #endif 9 | 10 | void s_mp_copy_digs(mp_digit *d, const mp_digit *s, int digits) 11 | { 12 | #ifdef MP_USE_MEMOPS 13 | if (digits > 0) { 14 | memcpy(d, s, (size_t)digits * sizeof(mp_digit)); 15 | } 16 | #else 17 | while (digits-- > 0) { 18 | *d++ = *s++; 19 | } 20 | #endif 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /logs/before_after.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | LibTomMath Log Plots 4 | 5 | 6 | 7 |

Addition and Subtraction

8 |
9 |
10 | 11 |

Multiplication

12 |
13 |
14 | 15 |

Squaring

16 |
17 |
18 | 19 |

Exptmod

20 |
21 |
22 | 23 |

Modular Inverse

24 |
25 |
26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /mp_radix_size_overestimate.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_RADIX_SIZE_OVERESTIMATE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | mp_err mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size) 7 | { 8 | if (MP_HAS(S_MP_RADIX_SIZE_OVERESTIMATE)) { 9 | return s_mp_radix_size_overestimate(a, radix, size); 10 | } 11 | if (MP_HAS(MP_RADIX_SIZE)) { 12 | return mp_radix_size(a, radix, size); 13 | } 14 | return MP_ERR; 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /mp_reduce_setup.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_REDUCE_SETUP_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* pre-calculate the value required for Barrett reduction 7 | * For a given modulus "b" it calculates the value required in "a" 8 | */ 9 | mp_err mp_reduce_setup(mp_int *a, const mp_int *b) 10 | { 11 | mp_err err; 12 | if ((err = mp_2expt(a, b->used * 2 * MP_DIGIT_BIT)) != MP_OKAY) { 13 | return err; 14 | } 15 | return mp_div(a, b, a, NULL); 16 | } 17 | #endif 18 | -------------------------------------------------------------------------------- /tommath_cutoffs.h: -------------------------------------------------------------------------------- 1 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | /* 4 | Current values evaluated on an AMD A8-6600K (64-bit). 5 | Type "make tune" to optimize them for your machine but 6 | be aware that it may take a long time. It took 2:30 minutes 7 | on the aforementioned machine for example. 8 | */ 9 | 10 | #define MP_DEFAULT_MUL_KARATSUBA_CUTOFF 80 11 | #define MP_DEFAULT_SQR_KARATSUBA_CUTOFF 120 12 | #define MP_DEFAULT_MUL_TOOM_CUTOFF 350 13 | #define MP_DEFAULT_SQR_TOOM_CUTOFF 400 14 | -------------------------------------------------------------------------------- /mp_clear.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_CLEAR_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* clear one (frees) */ 7 | void mp_clear(mp_int *a) 8 | { 9 | /* only do anything if a hasn't been freed previously */ 10 | if (a->dp != NULL) { 11 | /* free ram */ 12 | MP_FREE_DIGS(a->dp, a->alloc); 13 | 14 | /* reset members to make debugging easier */ 15 | a->dp = NULL; 16 | a->alloc = a->used = 0; 17 | a->sign = MP_ZPOS; 18 | } 19 | } 20 | #endif 21 | -------------------------------------------------------------------------------- /mp_abs.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_ABS_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* b = |a| 7 | * 8 | * Simple function copies the input and fixes the sign to positive 9 | */ 10 | mp_err mp_abs(const mp_int *a, mp_int *b) 11 | { 12 | mp_err err; 13 | 14 | /* copy a to b */ 15 | if ((err = mp_copy(a, b)) != MP_OKAY) { 16 | return err; 17 | } 18 | 19 | /* force the sign of b to positive */ 20 | b->sign = MP_ZPOS; 21 | 22 | return MP_OKAY; 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /mp_cmp.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_CMP_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* compare two ints (signed)*/ 7 | mp_ord mp_cmp(const mp_int *a, const mp_int *b) 8 | { 9 | /* compare based on sign */ 10 | if (a->sign != b->sign) { 11 | return mp_isneg(a) ? MP_LT : MP_GT; 12 | } 13 | 14 | /* if negative compare opposite direction */ 15 | if (mp_isneg(a)) { 16 | MP_EXCH(const mp_int *, a, b); 17 | } 18 | 19 | return mp_cmp_mag(a, b); 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /s_mp_get_bit.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_GET_BIT_C 3 | 4 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 5 | /* SPDX-License-Identifier: Unlicense */ 6 | 7 | /* Get bit at position b and return true if the bit is 1, false if it is 0 */ 8 | bool s_mp_get_bit(const mp_int *a, int b) 9 | { 10 | mp_digit bit; 11 | int limb = b / MP_DIGIT_BIT; 12 | 13 | if (limb < 0 || limb >= a->used) { 14 | return false; 15 | } 16 | 17 | bit = (mp_digit)1 << (b % MP_DIGIT_BIT); 18 | return ((a->dp[limb] & bit) != 0u); 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /mp_log_n.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_LOG_N_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | mp_err mp_log_n(const mp_int *a, int base, int *c) 7 | { 8 | mp_int b; 9 | mp_err err; 10 | 11 | if ((err = mp_init_i32(&b, base)) != MP_OKAY) goto LTM_ERR; 12 | if ((err = mp_log(a, &b, c)) != MP_OKAY) goto LTM_ERR; 13 | 14 | LTM_ERR: 15 | mp_clear(&b); 16 | return err; 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /mp_signed_rsh.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SIGNED_RSH_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* shift right by a certain bit count with sign extension */ 7 | mp_err mp_signed_rsh(const mp_int *a, int b, mp_int *c) 8 | { 9 | mp_err err; 10 | if (!mp_isneg(a)) { 11 | return mp_div_2d(a, b, c, NULL); 12 | } 13 | 14 | if ((err = mp_add_d(a, 1uL, c)) != MP_OKAY) { 15 | return err; 16 | } 17 | 18 | err = mp_div_2d(c, b, c, NULL); 19 | return (err == MP_OKAY) ? mp_sub_d(c, 1uL, c) : err; 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /etc/timer.asm: -------------------------------------------------------------------------------- 1 | ; x86 timer in NASM 2 | ; 3 | ; Tom St Denis, tomstdenis@iahu.ca 4 | [bits 32] 5 | [section .data] 6 | time dd 0, 0 7 | 8 | [section .text] 9 | 10 | %ifdef USE_ELF 11 | [global t_start] 12 | t_start: 13 | %else 14 | [global _t_start] 15 | _t_start: 16 | %endif 17 | push edx 18 | push eax 19 | rdtsc 20 | mov [time+0],edx 21 | mov [time+4],eax 22 | pop eax 23 | pop edx 24 | ret 25 | 26 | %ifdef USE_ELF 27 | [global t_read] 28 | t_read: 29 | %else 30 | [global _t_read] 31 | _t_read: 32 | %endif 33 | rdtsc 34 | sub eax,[time+4] 35 | sbb edx,[time+0] 36 | ret 37 | -------------------------------------------------------------------------------- /mp_cmp_d.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_CMP_D_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* compare a digit */ 7 | mp_ord mp_cmp_d(const mp_int *a, mp_digit b) 8 | { 9 | /* compare based on sign */ 10 | if (mp_isneg(a)) { 11 | return MP_LT; 12 | } 13 | 14 | /* compare based on magnitude */ 15 | if (a->used > 1) { 16 | return MP_GT; 17 | } 18 | 19 | /* compare the only digit of a to b */ 20 | if (a->dp[0] != b) { 21 | return a->dp[0] > b ? MP_GT : MP_LT; 22 | } 23 | 24 | return MP_EQ; 25 | } 26 | #endif 27 | -------------------------------------------------------------------------------- /astylerc: -------------------------------------------------------------------------------- 1 | # Artistic Style, see http://astyle.sourceforge.net/ 2 | # full documentation, see: http://astyle.sourceforge.net/astyle.html 3 | # 4 | # usage: 5 | # astyle --options=astylerc *.[ch] 6 | 7 | # Do not create backup, annoying in the times of git 8 | suffix=none 9 | 10 | ## Bracket Style Options 11 | style=kr 12 | 13 | ## Tab Options 14 | indent=spaces=3 15 | 16 | ## Bracket Modify Options 17 | 18 | ## Indentation Options 19 | min-conditional-indent=0 20 | 21 | ## Padding Options 22 | pad-header 23 | unpad-paren 24 | align-pointer=name 25 | 26 | ## Formatting Options 27 | break-after-logical 28 | max-code-length=120 29 | convert-tabs 30 | mode=c 31 | -------------------------------------------------------------------------------- /mp_from_sbin.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_FROM_SBIN_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* read signed bin, big endian, first byte is 0==positive or 1==negative */ 7 | mp_err mp_from_sbin(mp_int *a, const uint8_t *buf, size_t size) 8 | { 9 | mp_err err; 10 | 11 | /* read magnitude */ 12 | if ((err = mp_from_ubin(a, buf + 1, size - 1u)) != MP_OKAY) { 13 | return err; 14 | } 15 | 16 | /* first byte is 0 for positive, non-zero for negative */ 17 | a->sign = (buf[0] != (uint8_t)0) ? MP_NEG : MP_ZPOS; 18 | 19 | return MP_OKAY; 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /mp_to_sbin.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_TO_SBIN_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* store in signed [big endian] format */ 7 | mp_err mp_to_sbin(const mp_int *a, uint8_t *buf, size_t maxlen, size_t *written) 8 | { 9 | mp_err err; 10 | if (maxlen == 0u) { 11 | return MP_BUF; 12 | } 13 | if ((err = mp_to_ubin(a, buf + 1, maxlen - 1u, written)) != MP_OKAY) { 14 | return err; 15 | } 16 | if (written != NULL) { 17 | (*written)++; 18 | } 19 | buf[0] = mp_isneg(a) ? (uint8_t)1 : (uint8_t)0; 20 | return MP_OKAY; 21 | } 22 | #endif 23 | -------------------------------------------------------------------------------- /mtest/mpi-types.h: -------------------------------------------------------------------------------- 1 | /* Type definitions generated by 'types.pl' */ 2 | typedef char mp_sign; 3 | typedef unsigned short mp_digit; /* 2 byte type */ 4 | typedef unsigned int mp_word; /* 4 byte type */ 5 | typedef unsigned int mp_size; 6 | typedef int mp_err; 7 | 8 | #define MP_DIGIT_BIT (CHAR_BIT*sizeof(mp_digit)) 9 | #define MP_DIGIT_MAX USHRT_MAX 10 | #define MP_WORD_BIT (CHAR_BIT*sizeof(mp_word)) 11 | #define MP_WORD_MAX UINT_MAX 12 | 13 | #define MP_DIGIT_SIZE 2 14 | #define DIGIT_FMT "%04X" 15 | #define RADIX (MP_DIGIT_MAX+1) 16 | 17 | 18 | /* $Source$ */ 19 | /* $Revision$ */ 20 | /* $Date$ */ 21 | -------------------------------------------------------------------------------- /mp_count_bits.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_COUNT_BITS_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* returns the number of bits in an int */ 7 | int mp_count_bits(const mp_int *a) 8 | { 9 | int r; 10 | mp_digit q; 11 | 12 | /* shortcut */ 13 | if (mp_iszero(a)) { 14 | return 0; 15 | } 16 | 17 | /* get number of digits and add that */ 18 | r = (a->used - 1) * MP_DIGIT_BIT; 19 | 20 | /* take the last digit and count the bits in it */ 21 | q = a->dp[a->used - 1]; 22 | while (q > 0u) { 23 | ++r; 24 | q >>= 1u; 25 | } 26 | return r; 27 | } 28 | #endif 29 | -------------------------------------------------------------------------------- /mp_init.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* init a new mp_int */ 7 | mp_err mp_init(mp_int *a) 8 | { 9 | /* allocate memory required and clear it */ 10 | a->dp = (mp_digit *) MP_CALLOC((size_t)MP_DEFAULT_DIGIT_COUNT, sizeof(mp_digit)); 11 | if (a->dp == NULL) { 12 | return MP_MEM; 13 | } 14 | 15 | /* set the used to zero, allocated digits to the default precision 16 | * and sign to positive */ 17 | a->used = 0; 18 | a->alloc = MP_DEFAULT_DIGIT_COUNT; 19 | a->sign = MP_ZPOS; 20 | 21 | return MP_OKAY; 22 | } 23 | #endif 24 | -------------------------------------------------------------------------------- /mp_cmp_mag.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_CMP_MAG_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* compare magnitude of two ints (unsigned) */ 7 | mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b) 8 | { 9 | int n; 10 | 11 | /* compare based on # of non-zero digits */ 12 | if (a->used != b->used) { 13 | return a->used > b->used ? MP_GT : MP_LT; 14 | } 15 | 16 | /* compare based on digits */ 17 | for (n = a->used; n --> 0;) { 18 | if (a->dp[n] != b->dp[n]) { 19 | return a->dp[n] > b->dp[n] ? MP_GT : MP_LT; 20 | } 21 | } 22 | 23 | return MP_EQ; 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /mp_reduce_2k_setup_l.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_REDUCE_2K_SETUP_L_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* determines the setup value */ 7 | mp_err mp_reduce_2k_setup_l(const mp_int *a, mp_int *d) 8 | { 9 | mp_err err; 10 | mp_int tmp; 11 | 12 | if ((err = mp_init(&tmp)) != MP_OKAY) { 13 | return err; 14 | } 15 | 16 | if ((err = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { 17 | goto LBL_ERR; 18 | } 19 | 20 | if ((err = s_mp_sub(&tmp, a, d)) != MP_OKAY) { 21 | goto LBL_ERR; 22 | } 23 | 24 | LBL_ERR: 25 | mp_clear(&tmp); 26 | return err; 27 | } 28 | #endif 29 | -------------------------------------------------------------------------------- /mp_dr_is_modulus.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_DR_IS_MODULUS_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* determines if a number is a valid DR modulus */ 7 | bool mp_dr_is_modulus(const mp_int *a) 8 | { 9 | int ix; 10 | 11 | /* must be at least two digits */ 12 | if (a->used < 2) { 13 | return false; 14 | } 15 | 16 | /* must be of the form b**k - a [a <= b] so all 17 | * but the first digit must be equal to -1 (mod b). 18 | */ 19 | for (ix = 1; ix < a->used; ix++) { 20 | if (a->dp[ix] != MP_MASK) { 21 | return false; 22 | } 23 | } 24 | return true; 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /mp_shrink.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SHRINK_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* shrink a bignum */ 7 | mp_err mp_shrink(mp_int *a) 8 | { 9 | int alloc = MP_MAX(MP_MIN_DIGIT_COUNT, a->used); 10 | if (a->alloc != alloc) { 11 | mp_digit *dp = (mp_digit *) MP_REALLOC(a->dp, 12 | (size_t)a->alloc * sizeof(mp_digit), 13 | (size_t)alloc * sizeof(mp_digit)); 14 | if (dp == NULL) { 15 | return MP_MEM; 16 | } 17 | a->dp = dp; 18 | a->alloc = alloc; 19 | } 20 | return MP_OKAY; 21 | } 22 | #endif 23 | -------------------------------------------------------------------------------- /mp_reduce_2k_setup.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_REDUCE_2K_SETUP_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* determines the setup value */ 7 | mp_err mp_reduce_2k_setup(const mp_int *a, mp_digit *d) 8 | { 9 | mp_err err; 10 | mp_int tmp; 11 | 12 | if ((err = mp_init(&tmp)) != MP_OKAY) { 13 | return err; 14 | } 15 | 16 | if ((err = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { 17 | goto LBL_ERR; 18 | } 19 | 20 | if ((err = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { 21 | goto LBL_ERR; 22 | } 23 | 24 | *d = tmp.dp[0]; 25 | 26 | LBL_ERR: 27 | mp_clear(&tmp); 28 | return err; 29 | } 30 | #endif 31 | -------------------------------------------------------------------------------- /mp_copy.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_COPY_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* copy, b = a */ 7 | mp_err mp_copy(const mp_int *a, mp_int *b) 8 | { 9 | mp_err err; 10 | 11 | /* if dst == src do nothing */ 12 | if (a == b) { 13 | return MP_OKAY; 14 | } 15 | 16 | /* grow dest */ 17 | if ((err = mp_grow(b, a->used)) != MP_OKAY) { 18 | return err; 19 | } 20 | 21 | /* copy everything over and zero high digits */ 22 | s_mp_copy_digs(b->dp, a->dp, a->used); 23 | s_mp_zero_digs(b->dp + a->used, b->used - a->used); 24 | b->used = a->used; 25 | b->sign = a->sign; 26 | 27 | return MP_OKAY; 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /mp_clamp.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_CLAMP_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* trim unused digits 7 | * 8 | * This is used to ensure that leading zero digits are 9 | * trimmed and the leading "used" digit will be non-zero 10 | * Typically very fast. Also fixes the sign if there 11 | * are no more leading digits 12 | */ 13 | void mp_clamp(mp_int *a) 14 | { 15 | /* decrease used while the most significant digit is 16 | * zero. 17 | */ 18 | while ((a->used > 0) && (a->dp[a->used - 1] == 0u)) { 19 | --(a->used); 20 | } 21 | 22 | /* reset the sign flag if zero */ 23 | if (mp_iszero(a)) { 24 | a->sign = MP_ZPOS; 25 | } 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /mp_reduce_is_2k_l.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_REDUCE_IS_2K_L_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* determines if reduce_2k_l can be used */ 7 | bool mp_reduce_is_2k_l(const mp_int *a) 8 | { 9 | if (mp_iszero(a)) { 10 | return false; 11 | } else if (a->used == 1) { 12 | return true; 13 | } else if (a->used > 1) { 14 | /* if more than half of the digits are -1 we're sold */ 15 | int ix, iy; 16 | for (iy = ix = 0; ix < a->used; ix++) { 17 | if (a->dp[ix] == MP_DIGIT_MAX) { 18 | ++iy; 19 | } 20 | } 21 | return (iy >= (a->used/2)); 22 | } else { 23 | return false; 24 | } 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /mp_init_size.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_SIZE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* init an mp_init for a given size */ 7 | mp_err mp_init_size(mp_int *a, int size) 8 | { 9 | if (size < 0) { 10 | return MP_VAL; 11 | } 12 | 13 | size = MP_MAX(MP_MIN_DIGIT_COUNT, size); 14 | 15 | if (size > MP_MAX_DIGIT_COUNT) { 16 | return MP_OVF; 17 | } 18 | 19 | /* alloc mem */ 20 | a->dp = (mp_digit *) MP_CALLOC((size_t)size, sizeof(mp_digit)); 21 | if (a->dp == NULL) { 22 | return MP_MEM; 23 | } 24 | 25 | /* set the members */ 26 | a->used = 0; 27 | a->alloc = size; 28 | a->sign = MP_ZPOS; 29 | 30 | return MP_OKAY; 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /mp_error_to_string.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_ERROR_TO_STRING_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* return a char * string for a given code */ 7 | const char *mp_error_to_string(mp_err code) 8 | { 9 | switch (code) { 10 | case MP_OKAY: 11 | return "Successful"; 12 | case MP_ERR: 13 | return "Unknown error"; 14 | case MP_MEM: 15 | return "Out of heap"; 16 | case MP_VAL: 17 | return "Value out of range"; 18 | case MP_ITER: 19 | return "Max. iterations reached"; 20 | case MP_BUF: 21 | return "Buffer overflow"; 22 | case MP_OVF: 23 | return "Integer overflow"; 24 | default: 25 | return "Invalid error code"; 26 | } 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /logs/graphs.dem: -------------------------------------------------------------------------------- 1 | set terminal png 2 | set ylabel "Cycles per Operation" 3 | set xlabel "Operand size (bits)" 4 | 5 | set output "addsub.png" 6 | plot 'add.log' smooth bezier title "Addition", 'sub.log' smooth bezier title "Subtraction" 7 | 8 | set output "mult.png" 9 | plot 'sqr.log' smooth bezier title "Squaring (without Karatsuba)", 'sqr_kara.log' smooth bezier title "Squaring (Karatsuba)", 'mult.log' smooth bezier title "Multiplication (without Karatsuba)", 'mult_kara.log' smooth bezier title "Multiplication (Karatsuba)" 10 | 11 | set output "expt.png" 12 | plot 'expt.log' smooth bezier title "Exptmod (Montgomery)", 'expt_dr.log' smooth bezier title "Exptmod (Diminished Radix)", 'expt_2k.log' smooth bezier title "Exptmod (2k Reduction)" 13 | 14 | set output "invmod.png" 15 | plot 'invmod.log' smooth bezier title "Modular Inverse" 16 | 17 | -------------------------------------------------------------------------------- /mp_from_ubin.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_FROM_UBIN_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* reads a uint8_t array, assumes the msb is stored first [big endian] */ 7 | mp_err mp_from_ubin(mp_int *a, const uint8_t *buf, size_t size) 8 | { 9 | mp_err err; 10 | 11 | /* make sure there are at least two digits */ 12 | if ((err = mp_grow(a, 2)) != MP_OKAY) { 13 | return err; 14 | } 15 | 16 | /* zero the int */ 17 | mp_zero(a); 18 | 19 | /* read the bytes in */ 20 | while (size-- > 0u) { 21 | if ((err = mp_mul_2d(a, 8, a)) != MP_OKAY) { 22 | return err; 23 | } 24 | a->dp[0] |= *buf++; 25 | a->used += 1; 26 | } 27 | mp_clamp(a); 28 | return MP_OKAY; 29 | } 30 | #endif 31 | -------------------------------------------------------------------------------- /mp_fwrite.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_FWRITE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #ifndef MP_NO_FILE 7 | mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream) 8 | { 9 | char *buf; 10 | mp_err err; 11 | size_t size, written; 12 | 13 | if ((err = mp_radix_size_overestimate(a, radix, &size)) != MP_OKAY) { 14 | return err; 15 | } 16 | 17 | buf = (char *) MP_MALLOC(size); 18 | if (buf == NULL) { 19 | return MP_MEM; 20 | } 21 | 22 | if ((err = mp_to_radix(a, buf, size, &written, radix)) == MP_OKAY) { 23 | written--; 24 | if (fwrite(buf, written, 1uL, stream) != 1uL) { 25 | err = MP_ERR; 26 | } 27 | } 28 | 29 | MP_FREE_BUF(buf, size); 30 | return err; 31 | } 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /mp_warray_free.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_WARRAY_FREE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* static check that the multiplication won't overflow */ 7 | MP_STATIC_ASSERT(warray_free_sz_does_not_overflow, (sizeof(mp_word) * MP_WARRAY) >= MP_WARRAY) 8 | 9 | static int s_warray_free(void) 10 | { 11 | int ret = 0; 12 | if (s_mp_warray.w_used) 13 | return -2; 14 | if (s_mp_warray.w_free) { 15 | s_mp_zero_buf(s_mp_warray.w_free, sizeof(mp_word) * MP_WARRAY); 16 | MP_FREE(s_mp_warray.w_free, sizeof(mp_word) * MP_WARRAY); 17 | s_mp_warray.w_free = NULL; 18 | } 19 | return ret; 20 | } 21 | 22 | int mp_warray_free(void) 23 | { 24 | if (MP_HAS(MP_SMALL_STACK_SIZE)) return s_warray_free(); 25 | return -1; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /mp_invmod.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INVMOD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* hac 14.61, pp608 */ 7 | mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | /* for all n in N and n > 0, n = 0 mod 1 */ 10 | if (!mp_isneg(a) && mp_cmp_d(b, 1uL) == MP_EQ) { 11 | mp_zero(c); 12 | return MP_OKAY; 13 | } 14 | 15 | /* b cannot be negative and has to be >1 */ 16 | if (mp_isneg(b) || (mp_cmp_d(b, 1uL) != MP_GT)) { 17 | return MP_VAL; 18 | } 19 | 20 | /* if the modulus is odd we can use a faster routine instead */ 21 | if (MP_HAS(S_MP_INVMOD_ODD) && mp_isodd(b)) { 22 | return s_mp_invmod_odd(a, b, c); 23 | } 24 | 25 | return MP_HAS(S_MP_INVMOD) 26 | ? s_mp_invmod(a, b, c) 27 | : MP_VAL; 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /mp_radix_size.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_RADIX_SIZE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* returns size of ASCII representation */ 7 | mp_err mp_radix_size(const mp_int *a, int radix, size_t *size) 8 | { 9 | mp_err err; 10 | mp_int a_; 11 | int b; 12 | 13 | /* make sure the radix is in range */ 14 | if ((radix < 2) || (radix > 64)) { 15 | return MP_VAL; 16 | } 17 | 18 | if (mp_iszero(a)) { 19 | *size = 2; 20 | return MP_OKAY; 21 | } 22 | 23 | a_ = *a; 24 | a_.sign = MP_ZPOS; 25 | if ((err = mp_log_n(&a_, radix, &b)) != MP_OKAY) { 26 | return err; 27 | } 28 | 29 | /* mp_ilogb truncates to zero, hence we need one extra put on top and one for `\0`. */ 30 | *size = (size_t)b + 2U + (mp_isneg(a) ? 1U : 0U); 31 | 32 | return MP_OKAY; 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /mp_to_ubin.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_TO_UBIN_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* store in unsigned [big endian] format */ 7 | mp_err mp_to_ubin(const mp_int *a, uint8_t *buf, size_t maxlen, size_t *written) 8 | { 9 | size_t x, count; 10 | mp_err err; 11 | mp_int t; 12 | 13 | count = mp_ubin_size(a); 14 | if (count > maxlen) { 15 | return MP_BUF; 16 | } 17 | 18 | if ((err = mp_init_copy(&t, a)) != MP_OKAY) { 19 | return err; 20 | } 21 | 22 | for (x = count; x --> 0u;) { 23 | buf[x] = (uint8_t)(t.dp[0] & 255u); 24 | if ((err = mp_div_2d(&t, 8, &t, NULL)) != MP_OKAY) { 25 | goto LBL_ERR; 26 | } 27 | } 28 | 29 | if (written != NULL) { 30 | *written = count; 31 | } 32 | 33 | LBL_ERR: 34 | mp_clear(&t); 35 | return err; 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /mp_2expt.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_2EXPT_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* computes a = 2**b 7 | * 8 | * Simple algorithm which zeroes the int, grows it then just sets one bit 9 | * as required. 10 | */ 11 | mp_err mp_2expt(mp_int *a, int b) 12 | { 13 | mp_err err; 14 | 15 | if (b < 0) { 16 | return MP_VAL; 17 | } 18 | 19 | /* zero a as per default */ 20 | mp_zero(a); 21 | 22 | /* grow a to accommodate the single bit */ 23 | if ((err = mp_grow(a, (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) { 24 | return err; 25 | } 26 | 27 | /* set the used count of where the bit will go */ 28 | a->used = (b / MP_DIGIT_BIT) + 1; 29 | 30 | /* put the single bit in its place */ 31 | a->dp[b / MP_DIGIT_BIT] = (mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT); 32 | 33 | return MP_OKAY; 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /mp_add.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_ADD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* high level addition (handles signs) */ 7 | mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | /* handle two cases, not four */ 10 | if (a->sign == b->sign) { 11 | /* both positive or both negative */ 12 | /* add their magnitudes, copy the sign */ 13 | c->sign = a->sign; 14 | return s_mp_add(a, b, c); 15 | } 16 | 17 | /* one positive, the other negative */ 18 | /* subtract the one with the greater magnitude from */ 19 | /* the one of the lesser magnitude. The result gets */ 20 | /* the sign of the one with the greater magnitude. */ 21 | if (mp_cmp_mag(a, b) == MP_LT) { 22 | MP_EXCH(const mp_int *, a, b); 23 | } 24 | 25 | c->sign = a->sign; 26 | return s_mp_sub(a, b, c); 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /s_mp_prime_is_divisible.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_PRIME_IS_DIVISIBLE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* determines if an integers is divisible by one 7 | * of the first PRIME_SIZE primes or not 8 | * 9 | * sets result to 0 if not, 1 if yes 10 | */ 11 | mp_err s_mp_prime_is_divisible(const mp_int *a, bool *result) 12 | { 13 | int i; 14 | for (i = 0; i < MP_PRIME_TAB_SIZE; i++) { 15 | /* what is a mod LBL_prime_tab[i] */ 16 | mp_err err; 17 | mp_digit res; 18 | if ((err = mp_mod_d(a, s_mp_prime_tab[i], &res)) != MP_OKAY) { 19 | return err; 20 | } 21 | 22 | /* is the residue zero? */ 23 | if (res == 0u) { 24 | *result = true; 25 | return MP_OKAY; 26 | } 27 | } 28 | 29 | /* default to not */ 30 | *result = false; 31 | return MP_OKAY; 32 | } 33 | #endif 34 | -------------------------------------------------------------------------------- /mp_cnt_lsb.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_CNT_LSB_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | static const char lnz[16] = { 7 | 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 8 | }; 9 | 10 | /* Counts the number of lsbs which are zero before the first zero bit */ 11 | int mp_cnt_lsb(const mp_int *a) 12 | { 13 | int x; 14 | mp_digit q; 15 | 16 | /* easy out */ 17 | if (mp_iszero(a)) { 18 | return 0; 19 | } 20 | 21 | /* scan lower digits until non-zero */ 22 | for (x = 0; (x < a->used) && (a->dp[x] == 0u); x++) {} 23 | q = a->dp[x]; 24 | x *= MP_DIGIT_BIT; 25 | 26 | /* now scan this digit until a 1 is found */ 27 | if ((q & 1u) == 0u) { 28 | mp_digit p; 29 | do { 30 | p = q & 15u; 31 | x += lnz[p]; 32 | q >>= 4; 33 | } while (p == 0u); 34 | } 35 | return x; 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /mp_rand.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_RAND_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | mp_err mp_rand(mp_int *a, int digits) 7 | { 8 | int i; 9 | mp_err err; 10 | 11 | mp_zero(a); 12 | 13 | if (digits <= 0) { 14 | return MP_OKAY; 15 | } 16 | 17 | if ((err = mp_grow(a, digits)) != MP_OKAY) { 18 | return err; 19 | } 20 | 21 | if ((err = s_mp_rand_source(a->dp, (size_t)digits * sizeof(mp_digit))) != MP_OKAY) { 22 | return err; 23 | } 24 | 25 | /* TODO: We ensure that the highest digit is nonzero. Should this be removed? */ 26 | while ((a->dp[digits - 1] & MP_MASK) == 0u) { 27 | if ((err = s_mp_rand_source(a->dp + digits - 1, sizeof(mp_digit))) != MP_OKAY) { 28 | return err; 29 | } 30 | } 31 | 32 | a->used = digits; 33 | for (i = 0; i < digits; ++i) { 34 | a->dp[i] &= MP_MASK; 35 | } 36 | 37 | return MP_OKAY; 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /mp_expt_n.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_EXPT_N_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* calculate c = a**b using a square-multiply algorithm */ 7 | mp_err mp_expt_n(const mp_int *a, int b, mp_int *c) 8 | { 9 | mp_err err; 10 | mp_int g; 11 | 12 | if ((err = mp_init_copy(&g, a)) != MP_OKAY) { 13 | return err; 14 | } 15 | 16 | /* set initial result */ 17 | mp_set(c, 1uL); 18 | 19 | while (b > 0) { 20 | /* if the bit is set multiply */ 21 | if ((b & 1) != 0) { 22 | if ((err = mp_mul(c, &g, c)) != MP_OKAY) { 23 | goto LBL_ERR; 24 | } 25 | } 26 | 27 | /* square */ 28 | if (b > 1) { 29 | if ((err = mp_sqr(&g, &g)) != MP_OKAY) { 30 | goto LBL_ERR; 31 | } 32 | } 33 | 34 | /* shift to next bit */ 35 | b >>= 1; 36 | } 37 | 38 | LBL_ERR: 39 | mp_clear(&g); 40 | return err; 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /mp_div_2.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_DIV_2_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* b = a/2 */ 7 | mp_err mp_div_2(const mp_int *a, mp_int *b) 8 | { 9 | mp_err err; 10 | int x, oldused; 11 | mp_digit r; 12 | 13 | if ((err = mp_grow(b, a->used)) != MP_OKAY) { 14 | return err; 15 | } 16 | 17 | oldused = b->used; 18 | b->used = a->used; 19 | 20 | /* carry */ 21 | r = 0; 22 | for (x = b->used; x --> 0;) { 23 | /* get the carry for the next iteration */ 24 | mp_digit rr = a->dp[x] & 1u; 25 | 26 | /* shift the current digit, add in carry and store */ 27 | b->dp[x] = (a->dp[x] >> 1) | (r << (MP_DIGIT_BIT - 1)); 28 | 29 | /* forward carry to next iteration */ 30 | r = rr; 31 | } 32 | 33 | /* zero excess digits */ 34 | s_mp_zero_digs(b->dp + b->used, oldused - b->used); 35 | 36 | b->sign = a->sign; 37 | mp_clamp(b); 38 | return MP_OKAY; 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /mp_hash.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_HASH_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #if defined(MP_16BIT) 7 | #define FNV_1A_INIT ((uint32_t)0x811c9dc5) 8 | #define FNV_1A_PRIME ((uint32_t)0x01000193) 9 | #else 10 | #define FNV_1A_INIT ((uint64_t)0xcbf29ce484222325ULL) 11 | #define FNV_1A_PRIME ((uint64_t)0x100000001b3ULL) 12 | #endif 13 | 14 | /* computes hash of mp_int. */ 15 | mp_err mp_hash(const mp_int *a, mp_hval *hash) 16 | { 17 | int x; 18 | mp_hval hval = FNV_1A_INIT; 19 | mp_digit r, mask, shift; 20 | 21 | /* FNV-1a algorithm */ 22 | mask = ((mp_digit)1 << 8) - 1uL; 23 | shift = (mp_digit)(MP_DIGIT_BIT - 8); 24 | r = 0; 25 | for (x = a->used; x --> 0;) { 26 | mp_digit rr = a->dp[x] & mask; 27 | hval ^= (mp_hval)(a->dp[x] >> 8) | (r << shift); 28 | hval *= FNV_1A_PRIME; 29 | r = rr; 30 | } 31 | hval ^= mp_isneg(a) ? (mp_hval)1 : (mp_hval)0; 32 | *hash = hval * FNV_1A_PRIME; 33 | 34 | return MP_OKAY; 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /demo/shared.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | * Configuration 7 | */ 8 | #ifndef LTM_DEMO_TEST_REDUCE_2K_L 9 | /* This test takes a moment so we disable it by default, but it can be: 10 | * 0 to disable testing 11 | * 1 to make the test with P = 2^1024 - 0x2A434 B9FDEC95 D8F9D550 FFFFFFFF FFFFFFFF 12 | * 2 to make the test with P = 2^2048 - 0x1 00000000 00000000 00000000 00000000 4945DDBF 8EA2A91D 5776399B B83E188F 13 | */ 14 | #define LTM_DEMO_TEST_REDUCE_2K_L 0 15 | #endif 16 | 17 | #include "tommath_private.h" 18 | 19 | 20 | #define EXPECT(a) do { if (!(a)) { fprintf(stderr, "%s, line %d: EXPECT(%s) failed\n", __func__, __LINE__, #a); goto LBL_ERR; } } while(0) 21 | #define DO_WHAT(a, what) do { mp_err err; if ((err = (a)) != MP_OKAY) { fprintf(stderr, "%s, line %d: DO(%s) failed: %s\n", __func__, __LINE__, #a, mp_error_to_string(err)); what; } } while(0) 22 | #define DO(a) DO_WHAT(a, goto LBL_ERR) 23 | #define DOR(a) DO_WHAT(a, return EXIT_FAILURE) 24 | 25 | 26 | extern void ndraw(const mp_int* a, const char* name); 27 | extern void print_header(void); 28 | -------------------------------------------------------------------------------- /mp_mod_2d.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MOD_2D_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* calc a value mod 2**b */ 7 | mp_err mp_mod_2d(const mp_int *a, int b, mp_int *c) 8 | { 9 | int x; 10 | mp_err err; 11 | 12 | if (b < 0) { 13 | return MP_VAL; 14 | } 15 | 16 | if (b == 0) { 17 | mp_zero(c); 18 | return MP_OKAY; 19 | } 20 | 21 | /* if the modulus is larger than the value than return */ 22 | if (b >= (a->used * MP_DIGIT_BIT)) { 23 | return mp_copy(a, c); 24 | } 25 | 26 | if ((err = mp_copy(a, c)) != MP_OKAY) { 27 | return err; 28 | } 29 | 30 | /* zero digits above the last digit of the modulus */ 31 | x = (b / MP_DIGIT_BIT) + (((b % MP_DIGIT_BIT) == 0) ? 0 : 1); 32 | s_mp_zero_digs(c->dp + x, c->used - x); 33 | 34 | /* clear the digit that is not completely outside/inside the modulus */ 35 | c->dp[b / MP_DIGIT_BIT] &= 36 | ((mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT)) - (mp_digit)1; 37 | mp_clamp(c); 38 | return MP_OKAY; 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /mp_prime_fermat.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_PRIME_FERMAT_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* performs one Fermat test. 7 | * 8 | * If "a" were prime then b**a == b (mod a) since the order of 9 | * the multiplicative sub-group would be phi(a) = a-1. That means 10 | * it would be the same as b**(a mod (a-1)) == b**1 == b (mod a). 11 | * 12 | * Sets result to 1 if the congruence holds, or zero otherwise. 13 | */ 14 | mp_err mp_prime_fermat(const mp_int *a, const mp_int *b, bool *result) 15 | { 16 | mp_int t; 17 | mp_err err; 18 | 19 | /* ensure b > 1 */ 20 | if (mp_cmp_d(b, 1uL) != MP_GT) { 21 | return MP_VAL; 22 | } 23 | 24 | /* init t */ 25 | if ((err = mp_init(&t)) != MP_OKAY) { 26 | return err; 27 | } 28 | 29 | /* compute t = b**a mod a */ 30 | if ((err = mp_exptmod(b, a, a, &t)) != MP_OKAY) { 31 | goto LBL_ERR; 32 | } 33 | 34 | /* is it equal to b? */ 35 | *result = mp_cmp(&t, b) == MP_EQ; 36 | 37 | LBL_ERR: 38 | mp_clear(&t); 39 | return err; 40 | } 41 | #endif 42 | -------------------------------------------------------------------------------- /mp_div.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_DIV_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) 7 | { 8 | mp_err err; 9 | 10 | /* is divisor zero ? */ 11 | if (mp_iszero(b)) { 12 | return MP_VAL; 13 | } 14 | 15 | /* if a < b then q = 0, r = a */ 16 | if (mp_cmp_mag(a, b) == MP_LT) { 17 | if (d != NULL) { 18 | if ((err = mp_copy(a, d)) != MP_OKAY) { 19 | return err; 20 | } 21 | } 22 | if (c != NULL) { 23 | mp_zero(c); 24 | } 25 | return MP_OKAY; 26 | } 27 | 28 | if (MP_HAS(S_MP_DIV_RECURSIVE) 29 | && (b->used > (2 * MP_MUL_KARATSUBA_CUTOFF)) 30 | && (b->used <= ((a->used/3)*2))) { 31 | err = s_mp_div_recursive(a, b, c, d); 32 | } else if (MP_HAS(S_MP_DIV_SCHOOL)) { 33 | err = s_mp_div_school(a, b, c, d); 34 | } else if (MP_HAS(S_MP_DIV_SMALL)) { 35 | err = s_mp_div_small(a, b, c, d); 36 | } else { 37 | err = MP_VAL; 38 | } 39 | 40 | return err; 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /mp_lshd.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_LSHD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* shift left a certain amount of digits */ 7 | mp_err mp_lshd(mp_int *a, int b) 8 | { 9 | mp_err err; 10 | int x; 11 | 12 | /* if its less than zero return */ 13 | if (b <= 0) { 14 | return MP_OKAY; 15 | } 16 | /* no need to shift 0 around */ 17 | if (mp_iszero(a)) { 18 | return MP_OKAY; 19 | } 20 | 21 | /* grow to fit the new digits */ 22 | if ((err = mp_grow(a, a->used + b)) != MP_OKAY) { 23 | return err; 24 | } 25 | 26 | /* increment the used by the shift amount then copy upwards */ 27 | a->used += b; 28 | 29 | /* much like mp_rshd this is implemented using a sliding window 30 | * except the window goes the other way around. Copying from 31 | * the bottom to the top. see mp_rshd.c for more info. 32 | */ 33 | for (x = a->used; x --> b;) { 34 | a->dp[x] = a->dp[x - b]; 35 | } 36 | 37 | /* zero the lower digits */ 38 | s_mp_zero_digs(a->dp, b); 39 | 40 | return MP_OKAY; 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /mp_reduce_is_2k.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_REDUCE_IS_2K_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* determines if mp_reduce_2k can be used */ 7 | bool mp_reduce_is_2k(const mp_int *a) 8 | { 9 | if (mp_iszero(a)) { 10 | return false; 11 | } else if (a->used == 1) { 12 | return true; 13 | } else if (a->used > 1) { 14 | int ix, iy, iw = 1; 15 | mp_digit iz; 16 | /* Algorithm as implemented does not work if the least significant digit is zero */ 17 | iz = a->dp[0] & MP_MASK; 18 | if (iz == 0u) { 19 | return false; 20 | } 21 | 22 | iy = mp_count_bits(a); 23 | iz = 1; 24 | /* Test every bit from the second digit up, must be 1 */ 25 | for (ix = MP_DIGIT_BIT; ix < iy; ix++) { 26 | if ((a->dp[iw] & iz) == 0u) { 27 | return false; 28 | } 29 | iz <<= 1; 30 | if (iz > MP_DIGIT_MAX) { 31 | ++iw; 32 | iz = 1; 33 | } 34 | } 35 | return true; 36 | } else { 37 | return true; 38 | } 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /s_mp_radix_map.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_RADIX_MAP_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* chars used in radix conversions */ 7 | const char s_mp_radix_map[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; 8 | const uint8_t s_mp_radix_map_reverse[] = { 9 | 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, /* +,-./01234 */ 10 | 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56789:;<=> */ 11 | 0xff, 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, /* ?@ABCDEFGH */ 12 | 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, /* IJKLMNOPQR */ 13 | 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0xff, 0xff, /* STUVWXYZ[\ */ 14 | 0xff, 0xff, 0xff, 0xff, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, /* ]^_`abcdef */ 15 | 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, /* ghijklmnop */ 16 | 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d /* qrstuvwxyz */ 17 | }; 18 | MP_STATIC_ASSERT(correct_radix_map_reverse_size, sizeof(s_mp_radix_map_reverse) == MP_RADIX_MAP_REVERSE_SIZE) 19 | #endif 20 | -------------------------------------------------------------------------------- /mp_rshd.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_RSHD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* shift right a certain amount of digits */ 7 | void mp_rshd(mp_int *a, int b) 8 | { 9 | int x; 10 | 11 | /* if b <= 0 then ignore it */ 12 | if (b <= 0) { 13 | return; 14 | } 15 | 16 | /* if b > used then simply zero it and return */ 17 | if (a->used <= b) { 18 | mp_zero(a); 19 | return; 20 | } 21 | 22 | /* shift the digits down. 23 | * this is implemented as a sliding window where 24 | * the window is b-digits long and digits from 25 | * the top of the window are copied to the bottom 26 | * 27 | * e.g. 28 | 29 | b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> 30 | /\ | ----> 31 | \-------------------/ ----> 32 | */ 33 | for (x = 0; x < (a->used - b); x++) { 34 | a->dp[x] = a->dp[x + b]; 35 | } 36 | 37 | /* zero the top digits */ 38 | s_mp_zero_digs(a->dp + a->used - b, b); 39 | 40 | /* remove excess digits */ 41 | a->used -= b; 42 | } 43 | #endif 44 | -------------------------------------------------------------------------------- /mp_init_multi.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_INIT_MULTI_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #include 7 | 8 | mp_err mp_init_multi(mp_int *mp, ...) 9 | { 10 | mp_err err = MP_OKAY; 11 | int n = 0; /* Number of ok inits */ 12 | mp_int *cur_arg = mp; 13 | va_list args; 14 | 15 | va_start(args, mp); /* init args to next argument from caller */ 16 | while (cur_arg != NULL) { 17 | err = mp_init(cur_arg); 18 | if (err != MP_OKAY) { 19 | /* Oops - error! Back-track and mp_clear what we already 20 | succeeded in init-ing, then return error. 21 | */ 22 | va_list clean_args; 23 | 24 | /* now start cleaning up */ 25 | cur_arg = mp; 26 | va_start(clean_args, mp); 27 | while (n-- != 0) { 28 | mp_clear(cur_arg); 29 | cur_arg = va_arg(clean_args, mp_int *); 30 | } 31 | va_end(clean_args); 32 | break; 33 | } 34 | n++; 35 | cur_arg = va_arg(args, mp_int *); 36 | } 37 | va_end(args); 38 | return err; 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /mp_reduce_2k.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_REDUCE_2K_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* reduces a modulo n where n is of the form 2**p - d */ 7 | mp_err mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d) 8 | { 9 | mp_int q; 10 | mp_err err; 11 | int p; 12 | 13 | if ((err = mp_init(&q)) != MP_OKAY) { 14 | return err; 15 | } 16 | 17 | p = mp_count_bits(n); 18 | for (;;) { 19 | /* q = a/2**p, a = a mod 2**p */ 20 | if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) { 21 | goto LBL_ERR; 22 | } 23 | 24 | if (d != 1u) { 25 | /* q = q * d */ 26 | if ((err = mp_mul_d(&q, d, &q)) != MP_OKAY) { 27 | goto LBL_ERR; 28 | } 29 | } 30 | 31 | /* a = a + q */ 32 | if ((err = s_mp_add(a, &q, a)) != MP_OKAY) { 33 | goto LBL_ERR; 34 | } 35 | 36 | if (mp_cmp_mag(a, n) == MP_LT) { 37 | break; 38 | } 39 | if ((err = s_mp_sub(a, n, a)) != MP_OKAY) { 40 | goto LBL_ERR; 41 | } 42 | } 43 | 44 | LBL_ERR: 45 | mp_clear(&q); 46 | return err; 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /mp_lcm.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_LCM_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* computes least common multiple as |a*b|/(a, b) */ 7 | mp_err mp_lcm(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | mp_err err; 10 | mp_int t1, t2; 11 | 12 | 13 | if ((err = mp_init_multi(&t1, &t2, NULL)) != MP_OKAY) { 14 | return err; 15 | } 16 | 17 | /* t1 = get the GCD of the two inputs */ 18 | if ((err = mp_gcd(a, b, &t1)) != MP_OKAY) { 19 | goto LBL_T; 20 | } 21 | 22 | /* divide the smallest by the GCD */ 23 | if (mp_cmp_mag(a, b) == MP_LT) { 24 | /* store quotient in t2 such that t2 * b is the LCM */ 25 | if ((err = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) { 26 | goto LBL_T; 27 | } 28 | err = mp_mul(b, &t2, c); 29 | } else { 30 | /* store quotient in t2 such that t2 * a is the LCM */ 31 | if ((err = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) { 32 | goto LBL_T; 33 | } 34 | err = mp_mul(a, &t2, c); 35 | } 36 | 37 | /* fix the sign to positive */ 38 | c->sign = MP_ZPOS; 39 | 40 | LBL_T: 41 | mp_clear_multi(&t1, &t2, NULL); 42 | return err; 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /mp_reduce_2k_l.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_REDUCE_2K_L_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* reduces a modulo n where n is of the form 2**p - d 7 | This differs from reduce_2k since "d" can be larger 8 | than a single digit. 9 | */ 10 | mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d) 11 | { 12 | mp_int q; 13 | mp_err err; 14 | int p; 15 | 16 | if ((err = mp_init(&q)) != MP_OKAY) { 17 | return err; 18 | } 19 | 20 | p = mp_count_bits(n); 21 | 22 | for (;;) { 23 | /* q = a/2**p, a = a mod 2**p */ 24 | if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) { 25 | goto LBL_ERR; 26 | } 27 | 28 | /* q = q * d */ 29 | if ((err = mp_mul(&q, d, &q)) != MP_OKAY) { 30 | goto LBL_ERR; 31 | } 32 | 33 | /* a = a + q */ 34 | if ((err = s_mp_add(a, &q, a)) != MP_OKAY) { 35 | goto LBL_ERR; 36 | } 37 | 38 | if (mp_cmp_mag(a, n) == MP_LT) { 39 | break; 40 | } 41 | if ((err = s_mp_sub(a, n, a)) != MP_OKAY) { 42 | goto LBL_ERR; 43 | } 44 | 45 | } 46 | 47 | LBL_ERR: 48 | mp_clear(&q); 49 | return err; 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /mp_montgomery_setup.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MONTGOMERY_SETUP_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* setups the montgomery reduction stuff */ 7 | mp_err mp_montgomery_setup(const mp_int *n, mp_digit *rho) 8 | { 9 | mp_digit x, b; 10 | 11 | /* fast inversion mod 2**k 12 | * 13 | * Based on the fact that 14 | * 15 | * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) 16 | * => 2*X*A - X*X*A*A = 1 17 | * => 2*(1) - (1) = 1 18 | */ 19 | b = n->dp[0]; 20 | 21 | if ((b & 1u) == 0u) { 22 | return MP_VAL; 23 | } 24 | 25 | x = (((b + 2u) & 4u) << 1) + b; /* here x*a==1 mod 2**4 */ 26 | x *= 2u - (b * x); /* here x*a==1 mod 2**8 */ 27 | x *= 2u - (b * x); /* here x*a==1 mod 2**16 */ 28 | #if defined(MP_64BIT) || !(defined(MP_16BIT)) 29 | x *= 2u - (b * x); /* here x*a==1 mod 2**32 */ 30 | #endif 31 | #ifdef MP_64BIT 32 | x *= 2u - (b * x); /* here x*a==1 mod 2**64 */ 33 | #endif 34 | 35 | /* rho = -1/m mod b */ 36 | *rho = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - x) & MP_MASK; 37 | 38 | return MP_OKAY; 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /mp_sub.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SUB_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* high level subtraction (handles signs) */ 7 | mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | if (a->sign != b->sign) { 10 | /* subtract a negative from a positive, OR */ 11 | /* subtract a positive from a negative. */ 12 | /* In either case, ADD their magnitudes, */ 13 | /* and use the sign of the first number. */ 14 | c->sign = a->sign; 15 | return s_mp_add(a, b, c); 16 | } 17 | 18 | /* subtract a positive from a positive, OR */ 19 | /* subtract a negative from a negative. */ 20 | /* First, take the difference between their */ 21 | /* magnitudes, then... */ 22 | if (mp_cmp_mag(a, b) == MP_LT) { 23 | /* The second has a larger magnitude */ 24 | /* The result has the *opposite* sign from */ 25 | /* the first number. */ 26 | c->sign = (!mp_isneg(a) ? MP_NEG : MP_ZPOS); 27 | MP_EXCH(const mp_int *, a, b); 28 | } else { 29 | /* The first has a larger or equal magnitude */ 30 | /* Copy the sign from the first */ 31 | c->sign = a->sign; 32 | } 33 | return s_mp_sub(a, b, c); 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /mp_montgomery_calc_normalization.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MONTGOMERY_CALC_NORMALIZATION_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* 7 | * shifts with subtractions when the result is greater than b. 8 | * 9 | * The method is slightly modified to shift B unconditionally upto just under 10 | * the leading bit of b. This saves a lot of multiple precision shifting. 11 | */ 12 | mp_err mp_montgomery_calc_normalization(mp_int *a, const mp_int *b) 13 | { 14 | int x, bits; 15 | mp_err err; 16 | 17 | /* how many bits of last digit does b use */ 18 | bits = mp_count_bits(b) % MP_DIGIT_BIT; 19 | 20 | if (b->used > 1) { 21 | if ((err = mp_2expt(a, ((b->used - 1) * MP_DIGIT_BIT) + bits - 1)) != MP_OKAY) { 22 | return err; 23 | } 24 | } else { 25 | mp_set(a, 1uL); 26 | bits = 1; 27 | } 28 | 29 | /* now compute C = A * B mod b */ 30 | for (x = bits - 1; x < (int)MP_DIGIT_BIT; x++) { 31 | if ((err = mp_mul_2(a, a)) != MP_OKAY) { 32 | return err; 33 | } 34 | if (mp_cmp_mag(a, b) != MP_LT) { 35 | if ((err = s_mp_sub(a, b, a)) != MP_OKAY) { 36 | return err; 37 | } 38 | } 39 | } 40 | 41 | return MP_OKAY; 42 | } 43 | #endif 44 | -------------------------------------------------------------------------------- /mp_grow.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_GROW_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* grow as required */ 7 | mp_err mp_grow(mp_int *a, int size) 8 | { 9 | if (size < 0) { 10 | return MP_VAL; 11 | } 12 | 13 | /* if the alloc size is smaller alloc more ram */ 14 | if (a->alloc < size) { 15 | mp_digit *dp; 16 | 17 | if (size > MP_MAX_DIGIT_COUNT) { 18 | return MP_OVF; 19 | } 20 | 21 | /* reallocate the array a->dp 22 | * 23 | * We store the return in a temporary variable 24 | * in case the operation failed we don't want 25 | * to overwrite the dp member of a. 26 | */ 27 | dp = (mp_digit *) MP_REALLOC(a->dp, 28 | (size_t)a->alloc * sizeof(mp_digit), 29 | (size_t)size * sizeof(mp_digit)); 30 | if (dp == NULL) { 31 | /* reallocation failed but "a" is still valid [can be freed] */ 32 | return MP_MEM; 33 | } 34 | 35 | /* reallocation succeeded so set a->dp */ 36 | a->dp = dp; 37 | 38 | /* zero excess digits */ 39 | s_mp_zero_digs(a->dp + a->alloc, size - a->alloc); 40 | a->alloc = size; 41 | } 42 | return MP_OKAY; 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The LibTom license 2 | 3 | This is free and unencumbered software released into the public domain. 4 | 5 | Anyone is free to copy, modify, publish, use, compile, sell, or 6 | distribute this software, either in source code form or as a compiled 7 | binary, for any purpose, commercial or non-commercial, and by any 8 | means. 9 | 10 | In jurisdictions that recognize copyright laws, the author or authors 11 | of this software dedicate any and all copyright interest in the 12 | software to the public domain. We make this dedication for the benefit 13 | of the public at large and to the detriment of our heirs and 14 | successors. We intend this dedication to be an overt act of 15 | relinquishment in perpetuity of all present and future rights to this 16 | software under copyright law. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | For more information, please refer to 27 | -------------------------------------------------------------------------------- /mtest/logtab.h: -------------------------------------------------------------------------------- 1 | const float s_logv_2[] = { 2 | 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* 0 1 2 3 */ 3 | 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */ 4 | 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */ 5 | 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */ 6 | 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */ 7 | 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */ 8 | 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */ 9 | 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */ 10 | 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */ 11 | 0.193426404, 0.191958720, 0.190551412, 0.189200360, /* 36 37 38 39 */ 12 | 0.187901825, 0.186652411, 0.185449023, 0.184288833, /* 40 41 42 43 */ 13 | 0.183169251, 0.182087900, 0.181042597, 0.180031327, /* 44 45 46 47 */ 14 | 0.179052232, 0.178103594, 0.177183820, 0.176291434, /* 48 49 50 51 */ 15 | 0.175425064, 0.174583430, 0.173765343, 0.172969690, /* 52 53 54 55 */ 16 | 0.172195434, 0.171441601, 0.170707280, 0.169991616, /* 56 57 58 59 */ 17 | 0.169293808, 0.168613099, 0.167948779, 0.167300179, /* 60 61 62 63 */ 18 | 0.166666667 19 | }; 20 | 21 | 22 | /* $Source$ */ 23 | /* $Revision$ */ 24 | /* $Date$ */ 25 | -------------------------------------------------------------------------------- /mp_set_double.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SET_DOUBLE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #if defined(MP_HAS_SET_DOUBLE) 7 | mp_err mp_set_double(mp_int *a, double b) 8 | { 9 | uint64_t frac; 10 | int exp; 11 | mp_err err; 12 | union { 13 | double dbl; 14 | uint64_t bits; 15 | } cast; 16 | cast.dbl = b; 17 | 18 | exp = (int)((unsigned)(cast.bits >> 52) & 0x7FFu); 19 | frac = (cast.bits & (((uint64_t)1 << 52) - (uint64_t)1)) | ((uint64_t)1 << 52); 20 | 21 | if (exp == 0x7FF) { /* +-inf, NaN */ 22 | return MP_VAL; 23 | } 24 | exp -= 1023 + 52; 25 | 26 | mp_set_u64(a, frac); 27 | 28 | err = (exp < 0) ? mp_div_2d(a, -exp, a, NULL) : mp_mul_2d(a, exp, a); 29 | if (err != MP_OKAY) { 30 | return err; 31 | } 32 | 33 | if (((cast.bits >> 63) != 0u) && !mp_iszero(a)) { 34 | a->sign = MP_NEG; 35 | } 36 | 37 | return MP_OKAY; 38 | } 39 | #else 40 | /* pragma message() not supported by several compilers (in mostly older but still used versions) */ 41 | # ifdef _MSC_VER 42 | # pragma message("mp_set_double implementation is only available on platforms with IEEE754 floating point format") 43 | # else 44 | # warning "mp_set_double implementation is only available on platforms with IEEE754 floating point format" 45 | # endif 46 | #endif 47 | #endif 48 | -------------------------------------------------------------------------------- /etc/makefile: -------------------------------------------------------------------------------- 1 | LTM_TUNE_CFLAGS = $(CFLAGS) $(LTM_CFLAGS) -Wall -W -Wextra -Wshadow -O3 -I../ 2 | 3 | # default lib name (requires install with root) 4 | # LIBNAME=-ltommath 5 | 6 | # libname when you can't install the lib with install 7 | LIBNAME=../libtommath.a 8 | 9 | all: pprime tune test_standalone mersenne drprime 2kprime mont 10 | 11 | #provable primes 12 | pprime: pprime.o 13 | $(CC) $(LTM_TUNE_CFLAGS) pprime.o $(LIBNAME) -o pprime 14 | 15 | # portable [well requires clock()] tuning app 16 | tune: tune.o 17 | $(CC) $(LTM_TUNE_CFLAGS) tune.o $(LIBNAME) -o tune 18 | ./tune_it.sh 19 | 20 | test_standalone: tune.o 21 | # The benchmark program works as a testtool, too 22 | $(CC) $(LTM_TUNE_CFLAGS) tune.o $(LIBNAME) -o test 23 | 24 | # spits out mersenne primes 25 | mersenne: mersenne.o 26 | $(CC) $(LTM_TUNE_CFLAGS) mersenne.o $(LIBNAME) -o mersenne 27 | 28 | # finds DR safe primes for the given config 29 | drprime: drprime.o 30 | $(CC) $(LTM_TUNE_CFLAGS) drprime.o $(LIBNAME) -o drprime 31 | 32 | # finds 2k safe primes for the given config 33 | 2kprime: 2kprime.o 34 | $(CC) $(LTM_TUNE_CFLAGS) 2kprime.o $(LIBNAME) -o 2kprime 35 | 36 | mont: mont.o 37 | $(CC) $(LTM_TUNE_CFLAGS) mont.o $(LIBNAME) -o mont 38 | 39 | 40 | clean: 41 | rm -f *.log *.o *.obj *.exe pprime tune mersenne drprime mont 2kprime pprime.dat \ 42 | tuning_list multiplying squaring test *.da *.dyn *.dpi *~ 43 | rm -rf .libs 44 | 45 | .PHONY: tune 46 | -------------------------------------------------------------------------------- /tommath_c89.h: -------------------------------------------------------------------------------- 1 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | 4 | /* 5 | * This header defines custom types which 6 | * are used in c89 mode. 7 | * 8 | * By default, the source uses stdbool.h 9 | * and stdint.h. The command `make c89` 10 | * can be used to convert the source, 11 | * such that this header is used instead. 12 | * Use `make c99` to convert back. 13 | * 14 | * Please adapt the following definitions to your needs! 15 | */ 16 | 17 | /* stdbool.h replacement types */ 18 | typedef enum { MP_NO, MP_YES } mp_bool; 19 | 20 | /* stdint.h replacement types */ 21 | typedef __INT8_TYPE__ mp_i8; 22 | typedef __INT16_TYPE__ mp_i16; 23 | typedef __INT32_TYPE__ mp_i32; 24 | typedef __INT64_TYPE__ mp_i64; 25 | typedef __UINT8_TYPE__ mp_u8; 26 | typedef __UINT16_TYPE__ mp_u16; 27 | typedef __UINT32_TYPE__ mp_u32; 28 | typedef __UINT64_TYPE__ mp_u64; 29 | # if __WORDSIZE == 64 30 | typedef __UINT64_TYPE__ mp_uintptr; 31 | # else 32 | typedef __UINT32_TYPE__ mp_uintptr; 33 | # endif 34 | 35 | /* inttypes.h replacement, printf format specifier */ 36 | # if __WORDSIZE == 64 37 | # define MP_PRI64_PREFIX "l" 38 | # else 39 | # define MP_PRI64_PREFIX "ll" 40 | # endif 41 | #define MP_PRIi64 MP_PRI64_PREFIX "i" 42 | #define MP_PRIu64 MP_PRI64_PREFIX "u" 43 | #define MP_PRIx64 MP_PRI64_PREFIX "x" 44 | #define MP_PRIo64 MP_PRI64_PREFIX "o" 45 | 46 | #define MP_FUNCTION_NAME __func__ 47 | -------------------------------------------------------------------------------- /mp_mul_2.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MUL_2_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* b = a*2 */ 7 | mp_err mp_mul_2(const mp_int *a, mp_int *b) 8 | { 9 | mp_err err; 10 | int x, oldused; 11 | mp_digit r; 12 | 13 | /* grow to accommodate result */ 14 | if ((err = mp_grow(b, a->used + 1)) != MP_OKAY) { 15 | return err; 16 | } 17 | 18 | oldused = b->used; 19 | b->used = a->used; 20 | 21 | /* carry */ 22 | r = 0; 23 | for (x = 0; x < a->used; x++) { 24 | 25 | /* get what will be the *next* carry bit from the 26 | * MSB of the current digit 27 | */ 28 | mp_digit rr = a->dp[x] >> (mp_digit)(MP_DIGIT_BIT - 1); 29 | 30 | /* now shift up this digit, add in the carry [from the previous] */ 31 | b->dp[x] = ((a->dp[x] << 1uL) | r) & MP_MASK; 32 | 33 | /* copy the carry that would be from the source 34 | * digit into the next iteration 35 | */ 36 | r = rr; 37 | } 38 | 39 | /* new leading digit? */ 40 | if (r != 0u) { 41 | /* add a MSB which is always 1 at this point */ 42 | b->dp[b->used++] = 1; 43 | } 44 | 45 | /* now zero any excess digits on the destination 46 | * that we didn't write to 47 | */ 48 | s_mp_zero_digs(b->dp + b->used, oldused - b->used); 49 | 50 | b->sign = a->sign; 51 | return MP_OKAY; 52 | } 53 | #endif 54 | -------------------------------------------------------------------------------- /libtommath_VS2008.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tommath", "libtommath_VS2008.vcproj", "{42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|Win32.Build.0 = Debug|Win32 16 | {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|x64.ActiveCfg = Debug|x64 17 | {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|x64.Build.0 = Debug|x64 18 | {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|Win32.ActiveCfg = Release|Win32 19 | {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|Win32.Build.0 = Release|Win32 20 | {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|x64.ActiveCfg = Release|x64 21 | {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | GlobalSection(ExtensibilityGlobals) = postSolution 27 | SolutionGuid = {83B84178-7B4F-4B78-9C5D-17B8201D5B61} 28 | EndGlobalSection 29 | EndGlobal 30 | -------------------------------------------------------------------------------- /demo/s_mp_rand_jenkins.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_RAND_JENKINS_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* Bob Jenkins' http://burtleburtle.net/bob/rand/smallprng.html */ 7 | /* Chosen for speed and a good "mix" */ 8 | 9 | /* TODO: jenkins prng is not thread safe as of now */ 10 | 11 | typedef struct { 12 | uint64_t a; 13 | uint64_t b; 14 | uint64_t c; 15 | uint64_t d; 16 | } ranctx; 17 | 18 | static ranctx jenkins_x; 19 | 20 | #define rot(x,k) (((x)<<(k))|((x)>>(64-(k)))) 21 | static uint64_t s_rand_jenkins_val(void) 22 | { 23 | uint64_t e = jenkins_x.a - rot(jenkins_x.b, 7); 24 | jenkins_x.a = jenkins_x.b ^ rot(jenkins_x.c, 13); 25 | jenkins_x.b = jenkins_x.c + rot(jenkins_x.d, 37); 26 | jenkins_x.c = jenkins_x.d + e; 27 | jenkins_x.d = e + jenkins_x.a; 28 | return jenkins_x.d; 29 | } 30 | 31 | static void s_mp_rand_jenkins_init(uint64_t seed) 32 | { 33 | int i; 34 | jenkins_x.a = 0xF1EA5EEDuL; 35 | jenkins_x.b = jenkins_x.c = jenkins_x.d = seed; 36 | for (i = 0; i < 20; ++i) { 37 | (void)s_rand_jenkins_val(); 38 | } 39 | } 40 | 41 | static mp_err s_mp_rand_jenkins(void *p, size_t n) 42 | { 43 | char *q = (char *)p; 44 | while (n > 0u) { 45 | int i; 46 | uint64_t x = s_rand_jenkins_val(); 47 | for (i = 0; (i < 8) && (n > 0u); ++i, --n) { 48 | *q++ = (char)(x & 0xFFu); 49 | x >>= 8; 50 | } 51 | } 52 | return MP_OKAY; 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /mp_xor.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_XOR_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* two complement xor */ 7 | mp_err mp_xor(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | int used = MP_MAX(a->used, b->used) + 1, i; 10 | mp_err err; 11 | mp_digit ac = 1, bc = 1, cc = 1; 12 | bool neg = (a->sign != b->sign); 13 | 14 | if ((err = mp_grow(c, used)) != MP_OKAY) { 15 | return err; 16 | } 17 | 18 | for (i = 0; i < used; i++) { 19 | mp_digit x, y; 20 | 21 | /* convert to two complement if negative */ 22 | if (mp_isneg(a)) { 23 | ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK); 24 | x = ac & MP_MASK; 25 | ac >>= MP_DIGIT_BIT; 26 | } else { 27 | x = (i >= a->used) ? 0uL : a->dp[i]; 28 | } 29 | 30 | /* convert to two complement if negative */ 31 | if (mp_isneg(b)) { 32 | bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK); 33 | y = bc & MP_MASK; 34 | bc >>= MP_DIGIT_BIT; 35 | } else { 36 | y = (i >= b->used) ? 0uL : b->dp[i]; 37 | } 38 | 39 | c->dp[i] = x ^ y; 40 | 41 | /* convert to to sign-magnitude if negative */ 42 | if (neg) { 43 | cc += ~c->dp[i] & MP_MASK; 44 | c->dp[i] = cc & MP_MASK; 45 | cc >>= MP_DIGIT_BIT; 46 | } 47 | } 48 | 49 | c->used = used; 50 | c->sign = (neg ? MP_NEG : MP_ZPOS); 51 | mp_clamp(c); 52 | return MP_OKAY; 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /mp_and.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_AND_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* two complement and */ 7 | mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | int used = MP_MAX(a->used, b->used) + 1, i; 10 | mp_err err; 11 | mp_digit ac = 1, bc = 1, cc = 1; 12 | bool neg = (mp_isneg(a) && mp_isneg(b)); 13 | 14 | if ((err = mp_grow(c, used)) != MP_OKAY) { 15 | return err; 16 | } 17 | 18 | for (i = 0; i < used; i++) { 19 | mp_digit x, y; 20 | 21 | /* convert to two complement if negative */ 22 | if (mp_isneg(a)) { 23 | ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK); 24 | x = ac & MP_MASK; 25 | ac >>= MP_DIGIT_BIT; 26 | } else { 27 | x = (i >= a->used) ? 0uL : a->dp[i]; 28 | } 29 | 30 | /* convert to two complement if negative */ 31 | if (mp_isneg(b)) { 32 | bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK); 33 | y = bc & MP_MASK; 34 | bc >>= MP_DIGIT_BIT; 35 | } else { 36 | y = (i >= b->used) ? 0uL : b->dp[i]; 37 | } 38 | 39 | c->dp[i] = x & y; 40 | 41 | /* convert to to sign-magnitude if negative */ 42 | if (neg) { 43 | cc += ~c->dp[i] & MP_MASK; 44 | c->dp[i] = cc & MP_MASK; 45 | cc >>= MP_DIGIT_BIT; 46 | } 47 | } 48 | 49 | c->used = used; 50 | c->sign = (neg ? MP_NEG : MP_ZPOS); 51 | mp_clamp(c); 52 | return MP_OKAY; 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /mp_or.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_OR_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* two complement or */ 7 | mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | int used = MP_MAX(a->used, b->used) + 1, i; 10 | mp_err err; 11 | mp_digit ac = 1, bc = 1, cc = 1; 12 | bool neg = (mp_isneg(a) || mp_isneg(b)); 13 | 14 | if ((err = mp_grow(c, used)) != MP_OKAY) { 15 | return err; 16 | } 17 | 18 | for (i = 0; i < used; i++) { 19 | mp_digit x, y; 20 | 21 | /* convert to two complement if negative */ 22 | if (mp_isneg(a)) { 23 | ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK); 24 | x = ac & MP_MASK; 25 | ac >>= MP_DIGIT_BIT; 26 | } else { 27 | x = (i >= a->used) ? 0uL : a->dp[i]; 28 | } 29 | 30 | /* convert to two complement if negative */ 31 | if (mp_isneg(b)) { 32 | bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK); 33 | y = bc & MP_MASK; 34 | bc >>= MP_DIGIT_BIT; 35 | } else { 36 | y = (i >= b->used) ? 0uL : b->dp[i]; 37 | } 38 | 39 | c->dp[i] = x | y; 40 | 41 | /* convert to to sign-magnitude if negative */ 42 | if (neg) { 43 | cc += ~c->dp[i] & MP_MASK; 44 | c->dp[i] = cc & MP_MASK; 45 | cc >>= MP_DIGIT_BIT; 46 | } 47 | } 48 | 49 | c->used = used; 50 | c->sign = (neg ? MP_NEG : MP_ZPOS); 51 | mp_clamp(c); 52 | return MP_OKAY; 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /mp_unpack.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_UNPACK_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* based on gmp's mpz_import. 7 | * see http://gmplib.org/manual/Integer-Import-and-Export.html 8 | */ 9 | mp_err mp_unpack(mp_int *rop, size_t count, mp_order order, size_t size, 10 | mp_endian endian, size_t nails, const void *op) 11 | { 12 | mp_err err; 13 | size_t odd_nails, nail_bytes, i, j; 14 | uint8_t odd_nail_mask; 15 | 16 | mp_zero(rop); 17 | 18 | if (endian == MP_NATIVE_ENDIAN) { 19 | MP_GET_ENDIANNESS(endian); 20 | } 21 | 22 | odd_nails = (nails % 8u); 23 | odd_nail_mask = 0xff; 24 | for (i = 0; i < odd_nails; ++i) { 25 | odd_nail_mask ^= (uint8_t)(1u << (7u - i)); 26 | } 27 | nail_bytes = nails / 8u; 28 | 29 | for (i = 0; i < count; ++i) { 30 | for (j = 0; j < (size - nail_bytes); ++j) { 31 | uint8_t byte = *((const uint8_t *)op + 32 | (((order == MP_MSB_FIRST) ? i : ((count - 1u) - i)) * size) + 33 | ((endian == MP_BIG_ENDIAN) ? (j + nail_bytes) : (((size - 1u) - j) - nail_bytes))); 34 | 35 | if ((err = mp_mul_2d(rop, (j == 0u) ? (int)(8u - odd_nails) : 8, rop)) != MP_OKAY) { 36 | return err; 37 | } 38 | 39 | rop->dp[0] |= (j == 0u) ? (mp_digit)(byte & odd_nail_mask) : (mp_digit)byte; 40 | rop->used += 1; 41 | } 42 | } 43 | 44 | mp_clamp(rop); 45 | 46 | return MP_OKAY; 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /mp_fread.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_FREAD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | #ifndef MP_NO_FILE 7 | /* read a bigint from a file stream in ASCII */ 8 | mp_err mp_fread(mp_int *a, int radix, FILE *stream) 9 | { 10 | mp_err err; 11 | mp_sign sign = MP_ZPOS; 12 | int ch; 13 | 14 | /* make sure the radix is ok */ 15 | if ((radix < 2) || (radix > 64)) { 16 | return MP_VAL; 17 | } 18 | 19 | /* if first digit is - then set negative */ 20 | ch = fgetc(stream); 21 | if (ch == (int)'-') { 22 | sign = MP_NEG; 23 | ch = fgetc(stream); 24 | } 25 | 26 | /* no digits, return error */ 27 | if (ch == EOF) { 28 | return MP_ERR; 29 | } 30 | 31 | /* clear a */ 32 | mp_zero(a); 33 | 34 | do { 35 | uint8_t y; 36 | unsigned pos; 37 | ch = (radix <= 36) ? MP_TOUPPER(ch) : ch; 38 | pos = (unsigned)(ch - (int)'+'); 39 | if (MP_RADIX_MAP_REVERSE_SIZE <= pos) { 40 | break; 41 | } 42 | 43 | y = s_mp_radix_map_reverse[pos]; 44 | 45 | if (y >= radix) { 46 | break; 47 | } 48 | 49 | /* shift up and add */ 50 | if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) { 51 | return err; 52 | } 53 | if ((err = mp_add_d(a, y, a)) != MP_OKAY) { 54 | return err; 55 | } 56 | } while ((ch = fgetc(stream)) != EOF); 57 | 58 | if (!mp_iszero(a)) { 59 | a->sign = sign; 60 | } 61 | 62 | return MP_OKAY; 63 | } 64 | #endif 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /demo/shared.c: -------------------------------------------------------------------------------- 1 | #include "shared.h" 2 | 3 | void ndraw(const mp_int *a, const char *name) 4 | { 5 | char *buf; 6 | size_t size = 0; 7 | mp_err err; 8 | 9 | if ((err = mp_radix_size_overestimate(a, 10, &size)) != MP_OKAY) { 10 | fprintf(stderr, "\nndraw: mp_radix_size_overestimate(a, 10, %zu) failed - %s\n", size, mp_error_to_string(err)); 11 | exit(EXIT_FAILURE); 12 | } 13 | buf = (char *)malloc(size); 14 | if (buf == NULL) { 15 | fprintf(stderr, "\nndraw: malloc(%zu) failed\n", size); 16 | exit(EXIT_FAILURE); 17 | } 18 | 19 | printf("%s: ", name); 20 | if ((err = mp_to_decimal(a, buf, size)) != MP_OKAY) { 21 | fprintf(stderr, "\nndraw: mp_to_decimal(a, buf, %zu) failed - %s\n", size, mp_error_to_string(err)); 22 | exit(EXIT_FAILURE); 23 | } 24 | printf("%s\n", buf); 25 | if ((err = mp_to_hex(a, buf, size)) != MP_OKAY) { 26 | fprintf(stderr, "\nndraw: mp_to_hex(a, buf, %zu) failed - %s\n", size, mp_error_to_string(err)); 27 | exit(EXIT_FAILURE); 28 | } 29 | printf("0x%s\n", buf); 30 | 31 | free(buf); 32 | } 33 | 34 | void print_header(void) 35 | { 36 | #ifdef MP_16BIT 37 | printf("Digit size 16 Bit \n"); 38 | #endif 39 | #ifdef MP_32BIT 40 | printf("Digit size 32 Bit \n"); 41 | #endif 42 | #ifdef MP_64BIT 43 | printf("Digit size 64 Bit \n"); 44 | #endif 45 | printf("Size of mp_digit: %u\n", (unsigned int)sizeof(mp_digit)); 46 | printf("Size of mp_word: %u\n", (unsigned int)sizeof(mp_word)); 47 | printf("MP_DIGIT_BIT: %d\n", MP_DIGIT_BIT); 48 | printf("MP_DEFAULT_DIGIT_COUNT: %d\n", MP_DEFAULT_DIGIT_COUNT); 49 | } 50 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "tommath", 8 | platforms: [ 9 | .macOS(.v10_10), .iOS(.v9), .tvOS(.v9) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries a package produces, and make them visible to other packages. 13 | .library( 14 | name: "libtommath", 15 | targets: ["libtommath"]) 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 24 | .target( 25 | name: "libtommath", 26 | path: ".", 27 | exclude: ["demo", "doc", "etc", "logs", "mtest"], 28 | sources: ["."], 29 | publicHeadersPath: "modulemap", 30 | cSettings: [ 31 | .unsafeFlags(["-flto=thin"]) // for Dead Code Elimination 32 | ]), 33 | .testTarget(name: "TommathTests", 34 | dependencies: ["libtommath"], 35 | path: "demo", 36 | sources: ["tommath_tests.swift"]) 37 | ], 38 | cLanguageStandard: .gnu11, 39 | cxxLanguageStandard: .gnucxx14 40 | ) 41 | -------------------------------------------------------------------------------- /doc/makefile: -------------------------------------------------------------------------------- 1 | ifeq ($V,1) 2 | silent_stdout= 3 | else 4 | silent_stdout= > /dev/null 5 | endif 6 | 7 | PLATFORM := $(shell uname | sed -e 's/_.*//') 8 | ifeq ($(PLATFORM), Darwin) 9 | err: 10 | $(error Docs can't be built on Mac) 11 | 12 | docs mandvi manual: err 13 | endif 14 | 15 | docs: manual 16 | 17 | #LTM user manual 18 | mandvi: bn.tex 19 | cp bn.tex bn.bak 20 | touch --reference=bn.tex bn.bak 21 | (printf "%s" "\def\fixedpdfdate{"; date +'D:%Y%m%d%H%M%S%:z' -d @$$(stat --format=%Y bn.tex) | sed "s/:\([0-9][0-9]\)$$/'\1'}/g") > bn-deterministic.tex 22 | printf "%s\n" "\pdfinfo{" >> bn-deterministic.tex 23 | printf "%s\n" " /CreationDate (\fixedpdfdate)" >> bn-deterministic.tex 24 | printf "%s\n}\n" " /ModDate (\fixedpdfdate)" >> bn-deterministic.tex 25 | cat bn.tex >> bn-deterministic.tex 26 | mv bn-deterministic.tex bn.tex 27 | touch --reference=bn.bak bn.tex 28 | echo "hello" > bn.ind 29 | latex bn ${silent_stdout} 30 | latex bn ${silent_stdout} 31 | makeindex bn 32 | latex bn ${silent_stdout} 33 | 34 | #LTM user manual [pdf] 35 | manual: mandvi 36 | pdflatex bn >/dev/null 37 | sed -b -i 's,^/ID \[.*\]$$,/ID [<0> <0>],g' bn.pdf 38 | mv bn.bak bn.tex 39 | rm -f bn.aux bn.dvi bn.log bn.idx bn.lof bn.out bn.toc 40 | 41 | # The file latexindent.pl is in several LaTeX distributions, if not: 42 | # https://ctan.org/pkg/latexindent 43 | # Its configuration is well documented 44 | # http://mirrors.ctan.org/support/latexindent/documentation/latexindent.pdf 45 | pretty: 46 | latexindent -s -w -m -l=.latexindent.yaml bn.tex 47 | 48 | clean: 49 | rm -f *.idx *.toc *.log *.aux *.dvi *.lof *.ind *.ilg *.ps *.log tommath.tex 50 | -------------------------------------------------------------------------------- /s_mp_div_3.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_DIV_3_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* divide by three (based on routine from MPI and the GMP manual) */ 7 | mp_err s_mp_div_3(const mp_int *a, mp_int *c, mp_digit *d) 8 | { 9 | mp_int q; 10 | mp_word w; 11 | mp_digit b; 12 | mp_err err; 13 | int ix; 14 | 15 | /* b = 2**MP_DIGIT_BIT / 3 */ 16 | b = ((mp_word)1 << (mp_word)MP_DIGIT_BIT) / (mp_word)3; 17 | 18 | if ((err = mp_init_size(&q, a->used)) != MP_OKAY) { 19 | return err; 20 | } 21 | 22 | q.used = a->used; 23 | q.sign = a->sign; 24 | w = 0; 25 | for (ix = a->used; ix --> 0;) { 26 | mp_word t; 27 | w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix]; 28 | 29 | if (w >= 3u) { 30 | /* multiply w by [1/3] */ 31 | t = (w * (mp_word)b) >> (mp_word)MP_DIGIT_BIT; 32 | 33 | /* now subtract 3 * [w/3] from w, to get the remainder */ 34 | w -= t+t+t; 35 | 36 | /* fixup the remainder as required since 37 | * the optimization is not exact. 38 | */ 39 | while (w >= 3u) { 40 | t += 1u; 41 | w -= 3u; 42 | } 43 | } else { 44 | t = 0; 45 | } 46 | q.dp[ix] = (mp_digit)t; 47 | } 48 | 49 | /* [optional] store the remainder */ 50 | if (d != NULL) { 51 | *d = (mp_digit)w; 52 | } 53 | 54 | /* [optional] store the quotient */ 55 | if (c != NULL) { 56 | mp_clamp(&q); 57 | mp_exch(&q, c); 58 | } 59 | mp_clear(&q); 60 | 61 | return MP_OKAY; 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /s_mp_mul_high.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_MUL_HIGH_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* multiplies |a| * |b| and does not compute the lower digs digits 7 | * [meant to get the higher part of the product] 8 | */ 9 | mp_err s_mp_mul_high(const mp_int *a, const mp_int *b, mp_int *c, int digs) 10 | { 11 | mp_int t; 12 | int pa, pb, ix; 13 | mp_err err; 14 | 15 | if (digs < 0) { 16 | return MP_VAL; 17 | } 18 | 19 | /* can we use the fast multiplier? */ 20 | if (MP_HAS(S_MP_MUL_HIGH_COMBA) 21 | && ((a->used + b->used + 1) < MP_WARRAY) 22 | && (MP_MIN(a->used, b->used) < MP_MAX_COMBA)) { 23 | return s_mp_mul_high_comba(a, b, c, digs); 24 | } 25 | 26 | if ((err = mp_init_size(&t, a->used + b->used + 1)) != MP_OKAY) { 27 | return err; 28 | } 29 | t.used = a->used + b->used + 1; 30 | 31 | pa = a->used; 32 | pb = b->used; 33 | for (ix = 0; ix < pa; ix++) { 34 | int iy; 35 | mp_digit u = 0; 36 | 37 | for (iy = digs - ix; iy < pb; iy++) { 38 | /* calculate the double precision result */ 39 | mp_word r = (mp_word)t.dp[ix + iy] + 40 | ((mp_word)a->dp[ix] * (mp_word)b->dp[iy]) + 41 | (mp_word)u; 42 | 43 | /* get the lower part */ 44 | t.dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK); 45 | 46 | /* carry the carry */ 47 | u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); 48 | } 49 | t.dp[ix + pb] = u; 50 | } 51 | mp_clamp(&t); 52 | mp_exch(&t, c); 53 | mp_clear(&t); 54 | return MP_OKAY; 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /mp_mul_2d.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MUL_2D_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* shift left by a certain bit count */ 7 | mp_err mp_mul_2d(const mp_int *a, int b, mp_int *c) 8 | { 9 | mp_err err; 10 | 11 | if (b < 0) { 12 | return MP_VAL; 13 | } 14 | 15 | if ((err = mp_copy(a, c)) != MP_OKAY) { 16 | return err; 17 | } 18 | 19 | if ((err = mp_grow(c, c->used + (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) { 20 | return err; 21 | } 22 | 23 | /* shift by as many digits in the bit count */ 24 | if (b >= MP_DIGIT_BIT) { 25 | if ((err = mp_lshd(c, b / MP_DIGIT_BIT)) != MP_OKAY) { 26 | return err; 27 | } 28 | } 29 | 30 | /* shift any bit count < MP_DIGIT_BIT */ 31 | b %= MP_DIGIT_BIT; 32 | if (b != 0u) { 33 | mp_digit shift, mask, r; 34 | int x; 35 | 36 | /* bitmask for carries */ 37 | mask = ((mp_digit)1 << b) - (mp_digit)1; 38 | 39 | /* shift for msbs */ 40 | shift = (mp_digit)(MP_DIGIT_BIT - b); 41 | 42 | /* carry */ 43 | r = 0; 44 | for (x = 0; x < c->used; x++) { 45 | /* get the higher bits of the current word */ 46 | mp_digit rr = (c->dp[x] >> shift) & mask; 47 | 48 | /* shift the current word and OR in the carry */ 49 | c->dp[x] = ((c->dp[x] << b) | r) & MP_MASK; 50 | 51 | /* set the carry to the carry bits of the current word */ 52 | r = rr; 53 | } 54 | 55 | /* set final carry */ 56 | if (r != 0u) { 57 | c->dp[(c->used)++] = r; 58 | } 59 | } 60 | mp_clamp(c); 61 | return MP_OKAY; 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /s_mp_sub.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_SUB_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ 7 | mp_err s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | int oldused = c->used, min = b->used, max = a->used, i; 10 | mp_digit u; 11 | mp_err err; 12 | 13 | /* init result */ 14 | if ((err = mp_grow(c, max)) != MP_OKAY) { 15 | return err; 16 | } 17 | 18 | c->used = max; 19 | 20 | /* set carry to zero */ 21 | u = 0; 22 | for (i = 0; i < min; i++) { 23 | /* T[i] = A[i] - B[i] - U */ 24 | c->dp[i] = (a->dp[i] - b->dp[i]) - u; 25 | 26 | /* U = carry bit of T[i] 27 | * Note this saves performing an AND operation since 28 | * if a carry does occur it will propagate all the way to the 29 | * MSB. As a result a single shift is enough to get the carry 30 | */ 31 | u = c->dp[i] >> (MP_SIZEOF_BITS(mp_digit) - 1u); 32 | 33 | /* Clear carry from T[i] */ 34 | c->dp[i] &= MP_MASK; 35 | } 36 | 37 | /* now copy higher words if any, e.g. if A has more digits than B */ 38 | for (; i < max; i++) { 39 | /* T[i] = A[i] - U */ 40 | c->dp[i] = a->dp[i] - u; 41 | 42 | /* U = carry bit of T[i] */ 43 | u = c->dp[i] >> (MP_SIZEOF_BITS(mp_digit) - 1u); 44 | 45 | /* Clear carry from T[i] */ 46 | c->dp[i] &= MP_MASK; 47 | } 48 | 49 | /* clear digits above used (since we may not have grown result above) */ 50 | s_mp_zero_digs(c->dp + c->used, oldused - c->used); 51 | 52 | mp_clamp(c); 53 | return MP_OKAY; 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /mp_div_2d.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_DIV_2D_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* shift right by a certain bit count (store quotient in c, optional remainder in d) */ 7 | mp_err mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d) 8 | { 9 | mp_err err; 10 | 11 | if (b < 0) { 12 | return MP_VAL; 13 | } 14 | 15 | if ((err = mp_copy(a, c)) != MP_OKAY) { 16 | return err; 17 | } 18 | 19 | /* 'a' should not be used after here - it might be the same as d */ 20 | 21 | /* get the remainder */ 22 | if (d != NULL) { 23 | if ((err = mp_mod_2d(a, b, d)) != MP_OKAY) { 24 | return err; 25 | } 26 | } 27 | 28 | /* shift by as many digits in the bit count */ 29 | if (b >= MP_DIGIT_BIT) { 30 | mp_rshd(c, b / MP_DIGIT_BIT); 31 | } 32 | 33 | /* shift any bit count < MP_DIGIT_BIT */ 34 | b %= MP_DIGIT_BIT; 35 | if (b != 0u) { 36 | int x; 37 | mp_digit r, mask, shift; 38 | 39 | /* mask */ 40 | mask = ((mp_digit)1 << b) - 1uL; 41 | 42 | /* shift for lsb */ 43 | shift = (mp_digit)(MP_DIGIT_BIT - b); 44 | 45 | /* carry */ 46 | r = 0; 47 | for (x = c->used; x --> 0;) { 48 | /* get the lower bits of this word in a temp */ 49 | mp_digit rr = c->dp[x] & mask; 50 | 51 | /* shift the current word and mix in the carry bits from the previous word */ 52 | c->dp[x] = (c->dp[x] >> b) | (r << shift); 53 | 54 | /* set the carry to the carry bits of the current word found above */ 55 | r = rr; 56 | } 57 | } 58 | mp_clamp(c); 59 | return MP_OKAY; 60 | } 61 | #endif 62 | -------------------------------------------------------------------------------- /mp_sqrt.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SQRT_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* this function is less generic than mp_n_root, simpler and faster */ 7 | mp_err mp_sqrt(const mp_int *arg, mp_int *ret) 8 | { 9 | mp_err err; 10 | mp_int t1, t2; 11 | 12 | /* must be positive */ 13 | if (mp_isneg(arg)) { 14 | return MP_VAL; 15 | } 16 | 17 | /* easy out */ 18 | if (mp_iszero(arg)) { 19 | mp_zero(ret); 20 | return MP_OKAY; 21 | } 22 | 23 | if ((err = mp_init_copy(&t1, arg)) != MP_OKAY) { 24 | return err; 25 | } 26 | 27 | if ((err = mp_init(&t2)) != MP_OKAY) { 28 | goto LBL_ERR2; 29 | } 30 | 31 | /* First approx. (not very bad for large arg) */ 32 | mp_rshd(&t1, t1.used/2); 33 | 34 | /* t1 > 0 */ 35 | if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) { 36 | goto LBL_ERR1; 37 | } 38 | if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) { 39 | goto LBL_ERR1; 40 | } 41 | if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) { 42 | goto LBL_ERR1; 43 | } 44 | /* And now t1 > sqrt(arg) */ 45 | do { 46 | if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) { 47 | goto LBL_ERR1; 48 | } 49 | if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) { 50 | goto LBL_ERR1; 51 | } 52 | if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) { 53 | goto LBL_ERR1; 54 | } 55 | /* t1 >= sqrt(arg) >= t2 at this point */ 56 | } while (mp_cmp_mag(&t1, &t2) == MP_GT); 57 | 58 | mp_exch(&t1, ret); 59 | 60 | LBL_ERR1: 61 | mp_clear(&t2); 62 | LBL_ERR2: 63 | mp_clear(&t1); 64 | return err; 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /mp_prime_rabin_miller_trials.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_PRIME_RABIN_MILLER_TRIALS_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | static const struct { 7 | int k, t; 8 | } sizes[] = { 9 | { 80, -1 }, /* Use deterministic algorithm for size <= 80 bits */ 10 | { 81, 37 }, /* max. error = 2^(-96)*/ 11 | { 96, 32 }, /* max. error = 2^(-96)*/ 12 | { 128, 40 }, /* max. error = 2^(-112)*/ 13 | { 160, 35 }, /* max. error = 2^(-112)*/ 14 | { 256, 27 }, /* max. error = 2^(-128)*/ 15 | { 384, 16 }, /* max. error = 2^(-128)*/ 16 | { 512, 18 }, /* max. error = 2^(-160)*/ 17 | { 768, 11 }, /* max. error = 2^(-160)*/ 18 | { 896, 10 }, /* max. error = 2^(-160)*/ 19 | { 1024, 12 }, /* max. error = 2^(-192)*/ 20 | { 1536, 8 }, /* max. error = 2^(-192)*/ 21 | { 2048, 6 }, /* max. error = 2^(-192)*/ 22 | { 3072, 4 }, /* max. error = 2^(-192)*/ 23 | { 4096, 5 }, /* max. error = 2^(-256)*/ 24 | { 5120, 4 }, /* max. error = 2^(-256)*/ 25 | { 6144, 4 }, /* max. error = 2^(-256)*/ 26 | { 8192, 3 }, /* max. error = 2^(-256)*/ 27 | { 9216, 3 }, /* max. error = 2^(-256)*/ 28 | { 10240, 2 } /* For bigger keysizes use always at least 2 Rounds */ 29 | }; 30 | 31 | /* returns # of RM trials required for a given bit size */ 32 | int mp_prime_rabin_miller_trials(int size) 33 | { 34 | int x; 35 | 36 | for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) { 37 | if (sizes[x].k == size) { 38 | return sizes[x].t; 39 | } 40 | if (sizes[x].k > size) { 41 | return (x == 0) ? sizes[0].t : sizes[x - 1].t; 42 | } 43 | } 44 | return sizes[x-1].t; 45 | } 46 | 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /etc/mont.c: -------------------------------------------------------------------------------- 1 | /* tests the montgomery routines */ 2 | #include 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | mp_int modulus, R, p, pp; 9 | mp_digit mp; 10 | mp_err err; 11 | int x, y; 12 | 13 | srand(time(NULL)); 14 | if ((err = mp_init_multi(&modulus, &R, &p, &pp, NULL)) != MP_OKAY) goto LTM_ERR; 15 | 16 | /* loop through various sizes */ 17 | for (x = 4; x < 256; x++) { 18 | printf("DIGITS == %3d...", x); 19 | fflush(stdout); 20 | 21 | /* make up the odd modulus */ 22 | if ((err = mp_rand(&modulus, x)) != MP_OKAY) goto LTM_ERR; 23 | modulus.dp[0] |= 1uL; 24 | 25 | /* now find the R value */ 26 | if ((err = mp_montgomery_calc_normalization(&R, &modulus)) != MP_OKAY) goto LTM_ERR; 27 | if ((err = mp_montgomery_setup(&modulus, &mp)) != MP_OKAY) goto LTM_ERR; 28 | 29 | /* now run through a bunch tests */ 30 | for (y = 0; y < 1000; y++) { 31 | /* p = random */ 32 | if ((err = mp_rand(&p, x/2)) != MP_OKAY) goto LTM_ERR; 33 | /* pp = R * p */ 34 | if ((err = mp_mul(&p, &R, &pp)) != MP_OKAY) goto LTM_ERR; 35 | if ((err = mp_montgomery_reduce(&pp, &modulus, mp)) != MP_OKAY) goto LTM_ERR; 36 | 37 | /* should be equal to p */ 38 | if (mp_cmp(&pp, &p) != MP_EQ) { 39 | printf("FAILURE!\n"); 40 | exit(-1); 41 | } 42 | } 43 | printf("PASSED\n"); 44 | } 45 | 46 | LTM_ERR: 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /s_mp_div_small.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_DIV_SMALL_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* slower bit-bang division... also smaller */ 7 | mp_err s_mp_div_small(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) 8 | { 9 | mp_int ta, tb, tq, q; 10 | int n; 11 | bool neg; 12 | mp_err err; 13 | 14 | /* init our temps */ 15 | if ((err = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) { 16 | return err; 17 | } 18 | 19 | mp_set(&tq, 1uL); 20 | n = mp_count_bits(a) - mp_count_bits(b); 21 | if ((err = mp_abs(a, &ta)) != MP_OKAY) goto LBL_ERR; 22 | if ((err = mp_abs(b, &tb)) != MP_OKAY) goto LBL_ERR; 23 | if ((err = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) goto LBL_ERR; 24 | if ((err = mp_mul_2d(&tq, n, &tq)) != MP_OKAY) goto LBL_ERR; 25 | 26 | while (n-- >= 0) { 27 | if (mp_cmp(&tb, &ta) != MP_GT) { 28 | if ((err = mp_sub(&ta, &tb, &ta)) != MP_OKAY) goto LBL_ERR; 29 | if ((err = mp_add(&q, &tq, &q)) != MP_OKAY) goto LBL_ERR; 30 | } 31 | if ((err = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) goto LBL_ERR; 32 | if ((err = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY) goto LBL_ERR; 33 | } 34 | 35 | /* now q == quotient and ta == remainder */ 36 | 37 | neg = (a->sign != b->sign); 38 | if (c != NULL) { 39 | mp_exch(c, &q); 40 | c->sign = ((neg && !mp_iszero(c)) ? MP_NEG : MP_ZPOS); 41 | } 42 | if (d != NULL) { 43 | mp_exch(d, &ta); 44 | d->sign = (mp_iszero(d) ? MP_ZPOS : a->sign); 45 | } 46 | LBL_ERR: 47 | mp_clear_multi(&ta, &tb, &tq, &q, NULL); 48 | return err; 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /mp_mul_d.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MUL_D_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* multiply by a digit */ 7 | mp_err mp_mul_d(const mp_int *a, mp_digit b, mp_int *c) 8 | { 9 | mp_digit u; 10 | mp_err err; 11 | int ix, oldused; 12 | 13 | if (b == 1u) { 14 | return mp_copy(a, c); 15 | } 16 | 17 | /* power of two ? */ 18 | if (MP_HAS(MP_MUL_2) && (b == 2u)) { 19 | return mp_mul_2(a, c); 20 | } 21 | if (MP_HAS(MP_MUL_2D) && MP_IS_2EXPT(b)) { 22 | ix = 1; 23 | while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<used + 1)) != MP_OKAY) { 31 | return err; 32 | } 33 | 34 | /* get the original destinations used count */ 35 | oldused = c->used; 36 | 37 | /* set the sign */ 38 | c->sign = a->sign; 39 | 40 | /* zero carry */ 41 | u = 0; 42 | 43 | /* compute columns */ 44 | for (ix = 0; ix < a->used; ix++) { 45 | /* compute product and carry sum for this term */ 46 | mp_word r = (mp_word)u + ((mp_word)a->dp[ix] * (mp_word)b); 47 | 48 | /* mask off higher bits to get a single digit */ 49 | c->dp[ix] = (mp_digit)(r & (mp_word)MP_MASK); 50 | 51 | /* send carry into next iteration */ 52 | u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); 53 | } 54 | 55 | /* store final carry [if any] and increment ix offset */ 56 | c->dp[ix] = u; 57 | 58 | /* set used count */ 59 | c->used = a->used + 1; 60 | 61 | /* now zero digits above the top */ 62 | s_mp_zero_digs(c->dp + c->used, oldused - c->used); 63 | 64 | mp_clamp(c); 65 | 66 | return MP_OKAY; 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /s_mp_add.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_ADD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* low level addition, based on HAC pp.594, Algorithm 14.7 */ 7 | mp_err s_mp_add(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | int oldused, min, max, i; 10 | mp_digit u; 11 | mp_err err; 12 | 13 | /* find sizes, we let |a| <= |b| which means we have to sort 14 | * them. "x" will point to the input with the most digits 15 | */ 16 | if (a->used < b->used) { 17 | MP_EXCH(const mp_int *, a, b); 18 | } 19 | 20 | min = b->used; 21 | max = a->used; 22 | 23 | /* init result */ 24 | if ((err = mp_grow(c, max + 1)) != MP_OKAY) { 25 | return err; 26 | } 27 | 28 | /* get old used digit count and set new one */ 29 | oldused = c->used; 30 | c->used = max + 1; 31 | 32 | /* zero the carry */ 33 | u = 0; 34 | for (i = 0; i < min; i++) { 35 | /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ 36 | c->dp[i] = a->dp[i] + b->dp[i] + u; 37 | 38 | /* U = carry bit of T[i] */ 39 | u = c->dp[i] >> (mp_digit)MP_DIGIT_BIT; 40 | 41 | /* take away carry bit from T[i] */ 42 | c->dp[i] &= MP_MASK; 43 | } 44 | 45 | /* now copy higher words if any, that is in A+B 46 | * if A or B has more digits add those in 47 | */ 48 | if (min != max) { 49 | for (; i < max; i++) { 50 | /* T[i] = A[i] + U */ 51 | c->dp[i] = a->dp[i] + u; 52 | 53 | /* U = carry bit of T[i] */ 54 | u = c->dp[i] >> (mp_digit)MP_DIGIT_BIT; 55 | 56 | /* take away carry bit from T[i] */ 57 | c->dp[i] &= MP_MASK; 58 | } 59 | } 60 | 61 | /* add carry */ 62 | c->dp[i] = u; 63 | 64 | /* clear digits above oldused */ 65 | s_mp_zero_digs(c->dp + c->used, oldused - c->used); 66 | 67 | mp_clamp(c); 68 | return MP_OKAY; 69 | } 70 | #endif 71 | -------------------------------------------------------------------------------- /mp_pack.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_PACK_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* based on gmp's mpz_export. 7 | * see http://gmplib.org/manual/Integer-Import-and-Export.html 8 | */ 9 | mp_err mp_pack(void *rop, size_t maxcount, size_t *written, mp_order order, size_t size, 10 | mp_endian endian, size_t nails, const mp_int *op) 11 | { 12 | mp_err err; 13 | size_t odd_nails, nail_bytes, i, j, count; 14 | uint8_t odd_nail_mask; 15 | 16 | mp_int t; 17 | 18 | count = mp_pack_count(op, nails, size); 19 | 20 | if (count > maxcount) { 21 | return MP_BUF; 22 | } 23 | 24 | if ((err = mp_init_copy(&t, op)) != MP_OKAY) { 25 | return err; 26 | } 27 | 28 | if (endian == MP_NATIVE_ENDIAN) { 29 | MP_GET_ENDIANNESS(endian); 30 | } 31 | 32 | odd_nails = (nails % 8u); 33 | odd_nail_mask = 0xff; 34 | for (i = 0u; i < odd_nails; ++i) { 35 | odd_nail_mask ^= (uint8_t)(1u << (7u - i)); 36 | } 37 | nail_bytes = nails / 8u; 38 | 39 | for (i = 0u; i < count; ++i) { 40 | for (j = 0u; j < size; ++j) { 41 | uint8_t *byte = (uint8_t *)rop + 42 | (((order == MP_LSB_FIRST) ? i : ((count - 1u) - i)) * size) + 43 | ((endian == MP_LITTLE_ENDIAN) ? j : ((size - 1u) - j)); 44 | 45 | if (j >= (size - nail_bytes)) { 46 | *byte = 0; 47 | continue; 48 | } 49 | 50 | *byte = (uint8_t)((j == ((size - nail_bytes) - 1u)) ? (t.dp[0] & odd_nail_mask) : (t.dp[0] & 0xFFuL)); 51 | 52 | if ((err = mp_div_2d(&t, (j == ((size - nail_bytes) - 1u)) ? (int)(8u - odd_nails) : 8, &t, NULL)) != MP_OKAY) { 53 | goto LBL_ERR; 54 | } 55 | 56 | } 57 | } 58 | 59 | if (written != NULL) { 60 | *written = count; 61 | } 62 | err = MP_OKAY; 63 | 64 | LBL_ERR: 65 | mp_clear(&t); 66 | return err; 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /etc/makefile.icc: -------------------------------------------------------------------------------- 1 | CC = icc 2 | 3 | CFLAGS += -I../ 4 | 5 | # optimize for SPEED 6 | # 7 | # -mcpu= can be pentium, pentiumpro (covers PII through PIII) or pentium4 8 | # -ax? specifies make code specifically for ? but compatible with IA-32 9 | # -x? specifies compile solely for ? [not specifically IA-32 compatible] 10 | # 11 | # where ? is 12 | # K - PIII 13 | # W - first P4 [Williamette] 14 | # N - P4 Northwood 15 | # P - P4 Prescott 16 | # B - Blend of P4 and PM [mobile] 17 | # 18 | # Default to just generic max opts 19 | CFLAGS += -O3 -xP -ip 20 | 21 | # default lib name (requires install with root) 22 | # LIBNAME=-ltommath 23 | 24 | # libname when you can't install the lib with install 25 | LIBNAME=../libtommath.a 26 | 27 | #provable primes 28 | pprime: pprime.o 29 | $(CC) pprime.o $(LIBNAME) -o pprime 30 | 31 | tune: tune.o 32 | $(CC) $(CFLAGS) tune.o $(LIBNAME) -o tune 33 | ./tune_it.sh 34 | 35 | # same app but using RDTSC for higher precision [requires 80586+], coff based gcc installs [e.g. ming, cygwin, djgpp] 36 | tune86: tune.c 37 | nasm -f coff timer.asm 38 | $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86 39 | 40 | # for cygwin 41 | tune86c: tune.c 42 | nasm -f gnuwin32 timer.asm 43 | $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86 44 | 45 | #make tune86 for linux or any ELF format 46 | tune86l: tune.c 47 | nasm -f elf -DUSE_ELF timer.asm 48 | $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86l 49 | 50 | # spits out mersenne primes 51 | mersenne: mersenne.o 52 | $(CC) mersenne.o $(LIBNAME) -o mersenne 53 | 54 | # fines DR safe primes for the given config 55 | drprime: drprime.o 56 | $(CC) drprime.o $(LIBNAME) -o drprime 57 | 58 | # fines 2k safe primes for the given config 59 | 2kprime: 2kprime.o 60 | $(CC) 2kprime.o $(LIBNAME) -o 2kprime 61 | 62 | mont: mont.o 63 | $(CC) mont.o $(LIBNAME) -o mont 64 | 65 | 66 | clean: 67 | rm -f *.log *.o *.obj *.exe pprime tune mersenne drprime tune86 tune86l mont 2kprime pprime.dat *.il tuning_list 68 | -------------------------------------------------------------------------------- /s_mp_mul.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_MUL_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* multiplies |a| * |b| and only computes upto digs digits of result 7 | * HAC pp. 595, Algorithm 14.12 Modified so you can control how 8 | * many digits of output are created. 9 | */ 10 | mp_err s_mp_mul(const mp_int *a, const mp_int *b, mp_int *c, int digs) 11 | { 12 | mp_int t; 13 | mp_err err; 14 | int pa, ix; 15 | 16 | if (digs < 0) { 17 | return MP_VAL; 18 | } 19 | 20 | /* can we use the fast multiplier? */ 21 | if ((digs < MP_WARRAY) && 22 | (MP_MIN(a->used, b->used) < MP_MAX_COMBA)) { 23 | return s_mp_mul_comba(a, b, c, digs); 24 | } 25 | 26 | if ((err = mp_init_size(&t, digs)) != MP_OKAY) { 27 | return err; 28 | } 29 | t.used = digs; 30 | 31 | /* compute the digits of the product directly */ 32 | pa = a->used; 33 | for (ix = 0; ix < pa; ix++) { 34 | int iy, pb; 35 | mp_digit u = 0; 36 | 37 | /* limit ourselves to making digs digits of output */ 38 | pb = MP_MIN(b->used, digs - ix); 39 | 40 | /* compute the columns of the output and propagate the carry */ 41 | for (iy = 0; iy < pb; iy++) { 42 | /* compute the column as a mp_word */ 43 | mp_word r = (mp_word)t.dp[ix + iy] + 44 | ((mp_word)a->dp[ix] * (mp_word)b->dp[iy]) + 45 | (mp_word)u; 46 | 47 | /* the new column is the lower part of the result */ 48 | t.dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK); 49 | 50 | /* get the carry word from the result */ 51 | u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); 52 | } 53 | /* set carry if it is placed below digs */ 54 | if ((ix + iy) < digs) { 55 | t.dp[ix + pb] = u; 56 | } 57 | } 58 | 59 | mp_clamp(&t); 60 | mp_exch(&t, c); 61 | 62 | mp_clear(&t); 63 | return MP_OKAY; 64 | } 65 | #endif 66 | -------------------------------------------------------------------------------- /mp_read_radix.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_READ_RADIX_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* read a string [ASCII] in a given radix */ 7 | mp_err mp_read_radix(mp_int *a, const char *str, int radix) 8 | { 9 | mp_err err; 10 | mp_sign sign = MP_ZPOS; 11 | 12 | /* make sure the radix is ok */ 13 | if ((radix < 2) || (radix > 64)) { 14 | return MP_VAL; 15 | } 16 | 17 | /* if the leading digit is a 18 | * minus set the sign to negative. 19 | */ 20 | if (*str == '-') { 21 | ++str; 22 | sign = MP_NEG; 23 | } 24 | 25 | /* set the integer to the default of zero */ 26 | mp_zero(a); 27 | 28 | /* process each digit of the string */ 29 | while (*str != '\0') { 30 | /* if the radix <= 36 the conversion is case insensitive 31 | * this allows numbers like 1AB and 1ab to represent the same value 32 | * [e.g. in hex] 33 | */ 34 | uint8_t y; 35 | char ch = (radix <= 36) ? (char)MP_TOUPPER((int)*str) : *str; 36 | unsigned pos = (unsigned)(ch - '+'); 37 | if (MP_RADIX_MAP_REVERSE_SIZE <= pos) { 38 | break; 39 | } 40 | y = s_mp_radix_map_reverse[pos]; 41 | 42 | /* if the char was found in the map 43 | * and is less than the given radix add it 44 | * to the number, otherwise exit the loop. 45 | */ 46 | if (y >= radix) { 47 | break; 48 | } 49 | if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) { 50 | return err; 51 | } 52 | if ((err = mp_add_d(a, y, a)) != MP_OKAY) { 53 | return err; 54 | } 55 | ++str; 56 | } 57 | 58 | /* if an illegal character was found, fail. */ 59 | if ((*str != '\0') && (*str != '\r') && (*str != '\n')) { 60 | return MP_VAL; 61 | } 62 | 63 | /* set the sign only if a != 0 */ 64 | if (!mp_iszero(a)) { 65 | a->sign = sign; 66 | } 67 | return MP_OKAY; 68 | } 69 | #endif 70 | -------------------------------------------------------------------------------- /mp_sub_d.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_SUB_D_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* single digit subtraction */ 7 | mp_err mp_sub_d(const mp_int *a, mp_digit b, mp_int *c) 8 | { 9 | mp_err err; 10 | int oldused; 11 | 12 | /* fast path for a == c */ 13 | if (a == c) { 14 | if ((c->sign == MP_NEG) && 15 | ((c->dp[0] + b) < MP_DIGIT_MAX)) { 16 | c->dp[0] += b; 17 | return MP_OKAY; 18 | } 19 | if ((c->sign == MP_ZPOS) && 20 | (c->dp[0] > b)) { 21 | c->dp[0] -= b; 22 | return MP_OKAY; 23 | } 24 | } 25 | 26 | /* grow c as required */ 27 | if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) { 28 | return err; 29 | } 30 | 31 | /* if a is negative just do an unsigned 32 | * addition [with fudged signs] 33 | */ 34 | if (a->sign == MP_NEG) { 35 | mp_int a_ = *a; 36 | a_.sign = MP_ZPOS; 37 | err = mp_add_d(&a_, b, c); 38 | c->sign = MP_NEG; 39 | 40 | /* clamp */ 41 | mp_clamp(c); 42 | 43 | return err; 44 | } 45 | 46 | oldused = c->used; 47 | 48 | /* if a <= b simply fix the single digit */ 49 | if (((a->used == 1) && (a->dp[0] <= b)) || mp_iszero(a)) { 50 | c->dp[0] = (a->used == 1) ? b - a->dp[0] : b; 51 | 52 | /* negative/1digit */ 53 | c->sign = MP_NEG; 54 | c->used = 1; 55 | } else { 56 | int i; 57 | mp_digit mu = b; 58 | 59 | /* positive/size */ 60 | c->sign = MP_ZPOS; 61 | c->used = a->used; 62 | 63 | /* subtract digits, mu is carry */ 64 | for (i = 0; i < a->used; i++) { 65 | c->dp[i] = a->dp[i] - mu; 66 | mu = c->dp[i] >> (MP_SIZEOF_BITS(mp_digit) - 1u); 67 | c->dp[i] &= MP_MASK; 68 | } 69 | } 70 | 71 | /* zero excess digits */ 72 | s_mp_zero_digs(c->dp + c->used, oldused - c->used); 73 | 74 | mp_clamp(c); 75 | return MP_OKAY; 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /logs/before_after.dem: -------------------------------------------------------------------------------- 1 | set terminal png 2 | set ylabel "Cycles per Operation" 3 | set xlabel "Operand size (bits)" 4 | 5 | set output "addsub-ba.png" 6 | plot 'add-before.log' smooth bezier title "Addition (before)", \ 7 | 'add-after.log' smooth bezier title "Addition (after)", \ 8 | 'sub-before.log' smooth bezier title "Subtraction (before)", \ 9 | 'sub-after.log' smooth bezier title "Subtraction (after)" 10 | 11 | set output "mult-ba.png" 12 | plot 'mult-before.log' smooth bezier title "Multiplication (without Karatsuba) (before)", \ 13 | 'mult-after.log' smooth bezier title "Multiplication (without Karatsuba) (after)", \ 14 | 'mult_kara-before.log' smooth bezier title "Multiplication (Karatsuba) (before)", \ 15 | 'mult_kara-after.log' smooth bezier title "Multiplication (Karatsuba) (after)" 16 | 17 | set output "sqr-ba.png" 18 | plot 'sqr-before.log' smooth bezier title "Squaring (without Karatsuba) (before)", \ 19 | 'sqr-after.log' smooth bezier title "Squaring (without Karatsuba) (after)", \ 20 | 'sqr_kara-before.log' smooth bezier title "Squaring (Karatsuba) (before)", \ 21 | 'sqr_kara-after.log' smooth bezier title "Squaring (Karatsuba) (after)" 22 | 23 | set output "expt-ba.png" 24 | plot 'expt-before.log' smooth bezier title "Exptmod (Montgomery) (before)", \ 25 | 'expt-after.log' smooth bezier title "Exptmod (Montgomery) (after)", \ 26 | 'expt_dr-before.log' smooth bezier title "Exptmod (Diminished Radix) (before)", \ 27 | 'expt_dr-after.log' smooth bezier title "Exptmod (Diminished Radix) (after)", \ 28 | 'expt_2k-before.log' smooth bezier title "Exptmod (2k Reduction) (before)", \ 29 | 'expt_2k-after.log' smooth bezier title "Exptmod (2k Reduction) (after)", \ 30 | 'expt_2kl-before.log' smooth bezier title "Exptmod (2k-l Reduction) (before)", \ 31 | 'expt_2kl-after.log' smooth bezier title "Exptmod (2k-l Reduction) (after)" 32 | 33 | set output "invmod-ba.png" 34 | plot 'invmod-before.log' smooth bezier title "Modular Inverse (before)", \ 35 | 'invmod-after.log' smooth bezier title "Modular Inverse (after)" 36 | 37 | -------------------------------------------------------------------------------- /mp_dr_reduce.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_DR_REDUCE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* reduce "x" in place modulo "n" using the Diminished Radix algorithm. 7 | * 8 | * Based on algorithm from the paper 9 | * 10 | * "Generating Efficient Primes for Discrete Log Cryptosystems" 11 | * Chae Hoon Lim, Pil Joong Lee, 12 | * POSTECH Information Research Laboratories 13 | * 14 | * The modulus must be of a special format [see manual] 15 | * 16 | * Has been modified to use algorithm 7.10 from the LTM book instead 17 | * 18 | * Input x must be in the range 0 <= x <= (n-1)**2 19 | */ 20 | mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k) 21 | { 22 | mp_err err; 23 | 24 | /* m = digits in modulus */ 25 | int m = n->used; 26 | 27 | /* ensure that "x" has at least 2m digits */ 28 | if ((err = mp_grow(x, m + m)) != MP_OKAY) { 29 | return err; 30 | } 31 | 32 | /* top of loop, this is where the code resumes if 33 | * another reduction pass is required. 34 | */ 35 | for (;;) { 36 | int i; 37 | mp_digit mu = 0; 38 | 39 | /* compute (x mod B**m) + k * [x/B**m] inline and inplace */ 40 | for (i = 0; i < m; i++) { 41 | mp_word r = ((mp_word)x->dp[i + m] * (mp_word)k) + x->dp[i] + mu; 42 | x->dp[i] = (mp_digit)(r & MP_MASK); 43 | mu = (mp_digit)(r >> ((mp_word)MP_DIGIT_BIT)); 44 | } 45 | 46 | /* set final carry */ 47 | x->dp[i] = mu; 48 | 49 | /* zero words above m */ 50 | s_mp_zero_digs(x->dp + m + 1, (x->used - m) - 1); 51 | 52 | /* clamp, sub and return */ 53 | mp_clamp(x); 54 | 55 | /* if x >= n then subtract and reduce again 56 | * Each successive "recursion" makes the input smaller and smaller. 57 | */ 58 | if (mp_cmp_mag(x, n) == MP_LT) { 59 | break; 60 | } 61 | 62 | if ((err = s_mp_sub(x, n, x)) != MP_OKAY) { 63 | return err; 64 | } 65 | } 66 | return MP_OKAY; 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /mp_div_d.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_DIV_D_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* single digit division (based on routine from MPI) */ 7 | mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d) 8 | { 9 | mp_int q; 10 | mp_word w; 11 | mp_err err; 12 | int ix; 13 | 14 | /* cannot divide by zero */ 15 | if (b == 0u) { 16 | return MP_VAL; 17 | } 18 | 19 | /* quick outs */ 20 | if ((b == 1u) || mp_iszero(a)) { 21 | if (d != NULL) { 22 | *d = 0; 23 | } 24 | if (c != NULL) { 25 | return mp_copy(a, c); 26 | } 27 | return MP_OKAY; 28 | } 29 | 30 | /* power of two ? */ 31 | if (MP_HAS(MP_DIV_2) && (b == 2u)) { 32 | if (d != NULL) { 33 | *d = mp_isodd(a) ? 1u : 0u; 34 | } 35 | return (c == NULL) ? MP_OKAY : mp_div_2(a, c); 36 | } 37 | if (MP_HAS(MP_DIV_2D) && MP_IS_2EXPT(b)) { 38 | ix = 1; 39 | while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<dp[0] & (((mp_digit)1<<(mp_digit)ix) - 1uL); 44 | } 45 | return (c == NULL) ? MP_OKAY : mp_div_2d(a, ix, c, NULL); 46 | } 47 | 48 | /* three? */ 49 | if (MP_HAS(S_MP_DIV_3) && (b == 3u)) { 50 | return s_mp_div_3(a, c, d); 51 | } 52 | 53 | /* no easy answer [c'est la vie]. Just division */ 54 | if ((err = mp_init_size(&q, a->used)) != MP_OKAY) { 55 | return err; 56 | } 57 | 58 | q.used = a->used; 59 | q.sign = a->sign; 60 | w = 0; 61 | for (ix = a->used; ix --> 0;) { 62 | mp_digit t = 0; 63 | w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix]; 64 | if (w >= b) { 65 | t = (mp_digit)(w / b); 66 | w -= (mp_word)t * (mp_word)b; 67 | } 68 | q.dp[ix] = t; 69 | } 70 | 71 | if (d != NULL) { 72 | *d = (mp_digit)w; 73 | } 74 | 75 | if (c != NULL) { 76 | mp_clamp(&q); 77 | mp_exch(&q, c); 78 | } 79 | mp_clear(&q); 80 | 81 | return MP_OKAY; 82 | } 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /s_mp_mul_balance.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_MUL_BALANCE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* single-digit multiplication with the smaller number as the single-digit */ 7 | mp_err s_mp_mul_balance(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | mp_int a0, tmp, r; 10 | mp_err err; 11 | int i, j, 12 | nblocks = MP_MAX(a->used, b->used) / MP_MIN(a->used, b->used), 13 | bsize = MP_MIN(a->used, b->used); 14 | 15 | if ((err = mp_init_size(&a0, bsize + 2)) != MP_OKAY) { 16 | return err; 17 | } 18 | if ((err = mp_init_multi(&tmp, &r, NULL)) != MP_OKAY) { 19 | mp_clear(&a0); 20 | return err; 21 | } 22 | 23 | /* Make sure that A is the larger one*/ 24 | if (a->used < b->used) { 25 | MP_EXCH(const mp_int *, a, b); 26 | } 27 | 28 | for (i = 0, j=0; i < nblocks; i++) { 29 | /* Cut a slice off of a */ 30 | a0.used = bsize; 31 | s_mp_copy_digs(a0.dp, a->dp + j, a0.used); 32 | j += a0.used; 33 | mp_clamp(&a0); 34 | 35 | /* Multiply with b */ 36 | if ((err = mp_mul(&a0, b, &tmp)) != MP_OKAY) { 37 | goto LBL_ERR; 38 | } 39 | /* Shift tmp to the correct position */ 40 | if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) { 41 | goto LBL_ERR; 42 | } 43 | /* Add to output. No carry needed */ 44 | if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) { 45 | goto LBL_ERR; 46 | } 47 | } 48 | /* The left-overs; there are always left-overs */ 49 | if (j < a->used) { 50 | a0.used = a->used - j; 51 | s_mp_copy_digs(a0.dp, a->dp + j, a0.used); 52 | j += a0.used; 53 | mp_clamp(&a0); 54 | 55 | if ((err = mp_mul(&a0, b, &tmp)) != MP_OKAY) { 56 | goto LBL_ERR; 57 | } 58 | if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) { 59 | goto LBL_ERR; 60 | } 61 | if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) { 62 | goto LBL_ERR; 63 | } 64 | } 65 | 66 | mp_exch(&r,c); 67 | LBL_ERR: 68 | mp_clear_multi(&a0, &tmp, &r,NULL); 69 | return err; 70 | } 71 | #endif 72 | -------------------------------------------------------------------------------- /mp_add_d.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_ADD_D_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* single digit addition */ 7 | mp_err mp_add_d(const mp_int *a, mp_digit b, mp_int *c) 8 | { 9 | mp_err err; 10 | int oldused; 11 | 12 | /* fast path for a == c */ 13 | if (a == c) { 14 | if (!mp_isneg(c) && 15 | !mp_iszero(c) && 16 | ((c->dp[0] + b) < MP_DIGIT_MAX)) { 17 | c->dp[0] += b; 18 | return MP_OKAY; 19 | } 20 | if (mp_isneg(c) && 21 | (c->dp[0] > b)) { 22 | c->dp[0] -= b; 23 | return MP_OKAY; 24 | } 25 | } 26 | 27 | /* grow c as required */ 28 | if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) { 29 | return err; 30 | } 31 | 32 | /* if a is negative and |a| >= b, call c = |a| - b */ 33 | if (mp_isneg(a) && ((a->used > 1) || (a->dp[0] >= b))) { 34 | mp_int a_ = *a; 35 | /* temporarily fix sign of a */ 36 | a_.sign = MP_ZPOS; 37 | 38 | /* c = |a| - b */ 39 | err = mp_sub_d(&a_, b, c); 40 | 41 | /* fix sign */ 42 | c->sign = MP_NEG; 43 | 44 | /* clamp */ 45 | mp_clamp(c); 46 | 47 | return err; 48 | } 49 | 50 | /* old number of used digits in c */ 51 | oldused = c->used; 52 | 53 | /* if a is positive */ 54 | if (!mp_isneg(a)) { 55 | /* add digits, mu is carry */ 56 | int i; 57 | mp_digit mu = b; 58 | for (i = 0; i < a->used; i++) { 59 | c->dp[i] = a->dp[i] + mu; 60 | mu = c->dp[i] >> MP_DIGIT_BIT; 61 | c->dp[i] &= MP_MASK; 62 | } 63 | /* set final carry */ 64 | c->dp[i] = mu; 65 | 66 | /* setup size */ 67 | c->used = a->used + 1; 68 | } else { 69 | /* a was negative and |a| < b */ 70 | c->used = 1; 71 | 72 | /* the result is a single digit */ 73 | c->dp[0] = (a->used == 1) ? b - a->dp[0] : b; 74 | } 75 | 76 | /* sign always positive */ 77 | c->sign = MP_ZPOS; 78 | 79 | /* now zero to oldused */ 80 | s_mp_zero_digs(c->dp + c->used, oldused - c->used); 81 | mp_clamp(c); 82 | 83 | return MP_OKAY; 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /demo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Unlicense 2 | # 3 | # LibTomMath, a free open source portable number theoretic multiple-precision 4 | # integer (MPI) library written entirely in C. 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.10) 8 | 9 | set(LTM_TEST test-ltm) 10 | 11 | # This file can be included from the top level or used stand-alone 12 | if(PROJECT_NAME) 13 | set(LIBRARY_NAME ${PROJECT_NAME}) 14 | else() 15 | # Define an independent project and all the necessary stuff around 16 | project(${LTM_TEST} 17 | LANGUAGES C) 18 | set(LIBRARY_NAME libtommath) 19 | find_package(${LIBRARY_NAME}) 20 | include(CTest) 21 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 22 | set(CMAKE_BUILD_TYPE "Release") 23 | endif() 24 | endif() 25 | 26 | #----------------------------------------------------------------------------- 27 | # Compose CFLAGS etc. 28 | #----------------------------------------------------------------------------- 29 | 30 | if(NOT MSVC) 31 | set(CMAKE_C_FLAGS_DEBUG "-g3 -O1") 32 | endif() 33 | 34 | #----------------------------------------------------------------------------- 35 | # demo target 36 | #----------------------------------------------------------------------------- 37 | 38 | add_executable(${LTM_TEST} 39 | ${CMAKE_CURRENT_SOURCE_DIR}/shared.c 40 | ${CMAKE_CURRENT_SOURCE_DIR}/test.c 41 | ) 42 | 43 | target_include_directories(${LTM_TEST} PRIVATE 44 | ${CMAKE_CURRENT_SOURCE_DIR} 45 | $<$:${CMAKE_CURRENT_SOURCE_DIR}/..> 46 | ) 47 | 48 | target_link_libraries(${LTM_TEST} PRIVATE 49 | ${LIBRARY_NAME} 50 | ) 51 | 52 | target_compile_options(${LTM_TEST} PRIVATE 53 | $<$,SHARED_LIBRARY>:-DLTM_TEST_DYNAMIC> 54 | ${LTM_C_FLAGS} 55 | ) 56 | target_link_options(${LTM_TEST} BEFORE PUBLIC 57 | ${LTM_LD_FLAGS} 58 | ) 59 | 60 | #----------------------------------------------------------------------------- 61 | # CTest 62 | #----------------------------------------------------------------------------- 63 | add_test(NAME ${LTM_TEST} COMMAND ${LTM_TEST}) 64 | 65 | find_program(MEMORYCHECK_COMMAND valgrind) 66 | set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full") 67 | -------------------------------------------------------------------------------- /mp_reduce.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_REDUCE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* reduces x mod m, assumes 0 < x < m**2, mu is 7 | * precomputed via mp_reduce_setup. 8 | * From HAC pp.604 Algorithm 14.42 9 | */ 10 | mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu) 11 | { 12 | mp_int q; 13 | mp_err err; 14 | int um = m->used; 15 | 16 | /* q = x */ 17 | if ((err = mp_init_copy(&q, x)) != MP_OKAY) { 18 | return err; 19 | } 20 | 21 | /* q1 = x / b**(k-1) */ 22 | mp_rshd(&q, um - 1); 23 | 24 | /* according to HAC this optimization is ok */ 25 | if ((mp_digit)um > ((mp_digit)1 << (MP_DIGIT_BIT - 1))) { 26 | if ((err = mp_mul(&q, mu, &q)) != MP_OKAY) { 27 | goto LBL_ERR; 28 | } 29 | } else if (MP_HAS(S_MP_MUL_HIGH)) { 30 | if ((err = s_mp_mul_high(&q, mu, &q, um)) != MP_OKAY) { 31 | goto LBL_ERR; 32 | } 33 | } else if (MP_HAS(S_MP_MUL_HIGH_COMBA)) { 34 | if ((err = s_mp_mul_high_comba(&q, mu, &q, um)) != MP_OKAY) { 35 | goto LBL_ERR; 36 | } 37 | } else { 38 | err = MP_VAL; 39 | goto LBL_ERR; 40 | } 41 | 42 | /* q3 = q2 / b**(k+1) */ 43 | mp_rshd(&q, um + 1); 44 | 45 | /* x = x mod b**(k+1), quick (no division) */ 46 | if ((err = mp_mod_2d(x, MP_DIGIT_BIT * (um + 1), x)) != MP_OKAY) { 47 | goto LBL_ERR; 48 | } 49 | 50 | /* q = q * m mod b**(k+1), quick (no division) */ 51 | if ((err = s_mp_mul(&q, m, &q, um + 1)) != MP_OKAY) { 52 | goto LBL_ERR; 53 | } 54 | 55 | /* x = x - q */ 56 | if ((err = mp_sub(x, &q, x)) != MP_OKAY) { 57 | goto LBL_ERR; 58 | } 59 | 60 | /* If x < 0, add b**(k+1) to it */ 61 | if (mp_cmp_d(x, 0uL) == MP_LT) { 62 | mp_set(&q, 1uL); 63 | if ((err = mp_lshd(&q, um + 1)) != MP_OKAY) { 64 | goto LBL_ERR; 65 | } 66 | if ((err = mp_add(x, &q, x)) != MP_OKAY) { 67 | goto LBL_ERR; 68 | } 69 | } 70 | 71 | /* Back off if it's too big */ 72 | while (mp_cmp(x, m) != MP_LT) { 73 | if ((err = s_mp_sub(x, m, x)) != MP_OKAY) { 74 | goto LBL_ERR; 75 | } 76 | } 77 | 78 | LBL_ERR: 79 | mp_clear(&q); 80 | 81 | return err; 82 | } 83 | #endif 84 | -------------------------------------------------------------------------------- /s_mp_mul_high_comba.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_MUL_HIGH_COMBA_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* this is a modified version of s_mp_mul_comba that only produces 7 | * output digits *above* digs. See the comments for s_mp_mul_comba 8 | * to see how it works. 9 | * 10 | * This is used in the Barrett reduction since for one of the multiplications 11 | * only the higher digits were needed. This essentially halves the work. 12 | * 13 | * Based on Algorithm 14.12 on pp.595 of HAC. 14 | */ 15 | mp_err s_mp_mul_high_comba(const mp_int *a, const mp_int *b, mp_int *c, int digs) 16 | { 17 | int oldused, pa, ix; 18 | mp_err err; 19 | mp_digit MP_ALLOC_WARRAY(W); 20 | mp_word _W; 21 | 22 | MP_CHECK_WARRAY(W); 23 | 24 | if (digs < 0) { 25 | MP_FREE_WARRAY(W); 26 | return MP_VAL; 27 | } 28 | 29 | /* grow the destination as required */ 30 | pa = a->used + b->used; 31 | if ((err = mp_grow(c, pa)) != MP_OKAY) { 32 | MP_FREE_WARRAY(W); 33 | return err; 34 | } 35 | 36 | /* number of output digits to produce */ 37 | pa = a->used + b->used; 38 | _W = 0; 39 | for (ix = digs; ix < pa; ix++) { 40 | int tx, ty, iy, iz; 41 | 42 | /* get offsets into the two bignums */ 43 | ty = MP_MIN(b->used-1, ix); 44 | tx = ix - ty; 45 | 46 | /* this is the number of times the loop will iterate, essentially its 47 | while (tx++ < a->used && ty-- >= 0) { ... } 48 | */ 49 | iy = MP_MIN(a->used-tx, ty+1); 50 | 51 | /* execute loop */ 52 | for (iz = 0; iz < iy; iz++) { 53 | _W += (mp_word)a->dp[tx + iz] * (mp_word)b->dp[ty - iz]; 54 | } 55 | 56 | /* store term */ 57 | W[ix] = (mp_digit)_W & MP_MASK; 58 | 59 | /* make next carry */ 60 | _W = _W >> (mp_word)MP_DIGIT_BIT; 61 | } 62 | 63 | /* setup dest */ 64 | oldused = c->used; 65 | c->used = pa; 66 | 67 | for (ix = digs; ix < pa; ix++) { 68 | /* now extract the previous digit [below the carry] */ 69 | c->dp[ix] = W[ix]; 70 | } 71 | 72 | /* clear unused digits [that existed in the old copy of c] */ 73 | s_mp_zero_digs(c->dp + c->used, oldused - c->used); 74 | 75 | mp_clamp(c); 76 | MP_FREE_WARRAY(W); 77 | return MP_OKAY; 78 | } 79 | #endif 80 | -------------------------------------------------------------------------------- /mtest/mpi-config.h: -------------------------------------------------------------------------------- 1 | /* Default configuration for MPI library */ 2 | /* $Id$ */ 3 | 4 | #ifndef MPI_CONFIG_H_ 5 | #define MPI_CONFIG_H_ 6 | 7 | /* 8 | For boolean options, 9 | 0 = no 10 | 1 = yes 11 | 12 | Other options are documented individually. 13 | 14 | */ 15 | 16 | #ifndef MP_IOFUNC 17 | #define MP_IOFUNC 0 /* include mp_print() ? */ 18 | #endif 19 | 20 | #ifndef MP_MODARITH 21 | #define MP_MODARITH 1 /* include modular arithmetic ? */ 22 | #endif 23 | 24 | #ifndef MP_NUMTH 25 | #define MP_NUMTH 1 /* include number theoretic functions? */ 26 | #endif 27 | 28 | #ifndef MP_LOGTAB 29 | #define MP_LOGTAB 1 /* use table of logs instead of log()? */ 30 | #endif 31 | 32 | #ifndef MP_MEMSET 33 | #define MP_MEMSET 1 /* use memset() to zero buffers? */ 34 | #endif 35 | 36 | #ifndef MP_MEMCPY 37 | #define MP_MEMCPY 1 /* use memcpy() to copy buffers? */ 38 | #endif 39 | 40 | #ifndef MP_CRYPTO 41 | #define MP_CRYPTO 1 /* erase memory on free? */ 42 | #endif 43 | 44 | #ifndef MP_ARGCHK 45 | /* 46 | 0 = no parameter checks 47 | 1 = runtime checks, continue execution and return an error to caller 48 | 2 = assertions; dump core on parameter errors 49 | */ 50 | #define MP_ARGCHK 2 /* how to check input arguments */ 51 | #endif 52 | 53 | #ifndef MP_DEBUG 54 | #define MP_DEBUG 0 /* print diagnostic output? */ 55 | #endif 56 | 57 | #ifndef MP_DEFPREC 58 | #define MP_DEFPREC 64 /* default precision, in digits */ 59 | #endif 60 | 61 | #ifndef MP_MACRO 62 | #define MP_MACRO 1 /* use macros for frequent calls? */ 63 | #endif 64 | 65 | #ifndef MP_SQUARE 66 | #define MP_SQUARE 1 /* use separate squaring code? */ 67 | #endif 68 | 69 | #ifndef MP_PTAB_SIZE 70 | /* 71 | When building mpprime.c, we build in a table of small prime 72 | values to use for primality testing. The more you include, 73 | the more space they take up. See primes.c for the possible 74 | values (currently 16, 32, 64, 128, 256, and 6542) 75 | */ 76 | #define MP_PTAB_SIZE 128 /* how many built-in primes? */ 77 | #endif 78 | 79 | #ifndef MP_COMPAT_MACROS 80 | #define MP_COMPAT_MACROS 1 /* define compatibility macros? */ 81 | #endif 82 | 83 | #endif /* ifndef MPI_CONFIG_H_ */ 84 | 85 | 86 | /* crc==3287762869, version==2, Sat Feb 02 06:43:53 2002 */ 87 | 88 | /* $Source$ */ 89 | /* $Revision$ */ 90 | /* $Date$ */ 91 | -------------------------------------------------------------------------------- /mp_prime_miller_rabin.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_PRIME_MILLER_RABIN_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* Miller-Rabin test of "a" to the base of "b" as described in 7 | * HAC pp. 139 Algorithm 4.24 8 | * 9 | * Sets result to 0 if definitely composite or 1 if probably prime. 10 | * Randomly the chance of error is no more than 1/4 and often 11 | * very much lower. 12 | */ 13 | mp_err mp_prime_miller_rabin(const mp_int *a, const mp_int *b, bool *result) 14 | { 15 | mp_int n1, y, r; 16 | mp_err err; 17 | int s, j; 18 | 19 | /* ensure b > 1 */ 20 | if (mp_cmp_d(b, 1uL) != MP_GT) { 21 | return MP_VAL; 22 | } 23 | 24 | /* get n1 = a - 1 */ 25 | if ((err = mp_init_copy(&n1, a)) != MP_OKAY) { 26 | return err; 27 | } 28 | if ((err = mp_sub_d(&n1, 1uL, &n1)) != MP_OKAY) { 29 | goto LBL_ERR1; 30 | } 31 | 32 | /* set 2**s * r = n1 */ 33 | if ((err = mp_init_copy(&r, &n1)) != MP_OKAY) { 34 | goto LBL_ERR1; 35 | } 36 | 37 | /* count the number of least significant bits 38 | * which are zero 39 | */ 40 | s = mp_cnt_lsb(&r); 41 | 42 | /* now divide n - 1 by 2**s */ 43 | if ((err = mp_div_2d(&r, s, &r, NULL)) != MP_OKAY) { 44 | goto LBL_ERR2; 45 | } 46 | 47 | /* compute y = b**r mod a */ 48 | if ((err = mp_init(&y)) != MP_OKAY) { 49 | goto LBL_ERR2; 50 | } 51 | if ((err = mp_exptmod(b, &r, a, &y)) != MP_OKAY) { 52 | goto LBL_END; 53 | } 54 | 55 | /* if y != 1 and y != n1 do */ 56 | if ((mp_cmp_d(&y, 1uL) != MP_EQ) && (mp_cmp(&y, &n1) != MP_EQ)) { 57 | j = 1; 58 | /* while j <= s-1 and y != n1 */ 59 | while ((j <= (s - 1)) && (mp_cmp(&y, &n1) != MP_EQ)) { 60 | if ((err = mp_sqrmod(&y, a, &y)) != MP_OKAY) { 61 | goto LBL_END; 62 | } 63 | 64 | /* if y == 1 then composite */ 65 | if (mp_cmp_d(&y, 1uL) == MP_EQ) { 66 | *result = false; 67 | goto LBL_END; 68 | } 69 | 70 | ++j; 71 | } 72 | 73 | /* if y != n1 then composite */ 74 | if (mp_cmp(&y, &n1) != MP_EQ) { 75 | *result = false; 76 | goto LBL_END; 77 | } 78 | } 79 | 80 | /* probably prime now */ 81 | *result = true; 82 | 83 | LBL_END: 84 | mp_clear(&y); 85 | LBL_ERR2: 86 | mp_clear(&r); 87 | LBL_ERR1: 88 | mp_clear(&n1); 89 | return err; 90 | } 91 | #endif 92 | -------------------------------------------------------------------------------- /mp_exptmod.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_EXPTMOD_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* this is a shell function that calls either the normal or Montgomery 7 | * exptmod functions. Originally the call to the montgomery code was 8 | * embedded in the normal function but that wasted a lot of stack space 9 | * for nothing (since 99% of the time the Montgomery code would be called) 10 | */ 11 | mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y) 12 | { 13 | int dr; 14 | 15 | /* modulus P must be positive */ 16 | if (mp_isneg(P)) { 17 | return MP_VAL; 18 | } 19 | 20 | /* if exponent X is negative we have to recurse */ 21 | if (mp_isneg(X)) { 22 | mp_int tmpG, tmpX; 23 | mp_err err; 24 | 25 | if (!MP_HAS(MP_INVMOD)) { 26 | return MP_VAL; 27 | } 28 | 29 | if ((err = mp_init_multi(&tmpG, &tmpX, NULL)) != MP_OKAY) { 30 | return err; 31 | } 32 | 33 | /* first compute 1/G mod P */ 34 | if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { 35 | goto LBL_ERR; 36 | } 37 | 38 | /* now get |X| */ 39 | if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { 40 | goto LBL_ERR; 41 | } 42 | 43 | /* and now compute (1/G)**|X| instead of G**X [X < 0] */ 44 | err = mp_exptmod(&tmpG, &tmpX, P, Y); 45 | LBL_ERR: 46 | mp_clear_multi(&tmpG, &tmpX, NULL); 47 | return err; 48 | } 49 | 50 | /* modified diminished radix reduction */ 51 | if (MP_HAS(MP_REDUCE_IS_2K_L) && MP_HAS(MP_REDUCE_2K_L) && MP_HAS(S_MP_EXPTMOD) && 52 | mp_reduce_is_2k_l(P)) { 53 | return s_mp_exptmod(G, X, P, Y, 1); 54 | } 55 | 56 | /* is it a DR modulus? default to no */ 57 | dr = (MP_HAS(MP_DR_IS_MODULUS) && mp_dr_is_modulus(P)) ? 1 : 0; 58 | 59 | /* if not, is it a unrestricted DR modulus? */ 60 | if (MP_HAS(MP_REDUCE_IS_2K) && (dr == 0)) { 61 | dr = (mp_reduce_is_2k(P)) ? 2 : 0; 62 | } 63 | 64 | /* if the modulus is odd or dr != 0 use the montgomery method */ 65 | if (MP_HAS(S_MP_EXPTMOD_FAST) && (mp_isodd(P) || (dr != 0))) { 66 | return s_mp_exptmod_fast(G, X, P, Y, dr); 67 | } 68 | 69 | /* otherwise use the generic Barrett reduction technique */ 70 | if (MP_HAS(S_MP_EXPTMOD)) { 71 | return s_mp_exptmod(G, X, P, Y, 0); 72 | } 73 | 74 | /* no exptmod for evens */ 75 | return MP_VAL; 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /s_mp_prime_tab.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_PRIME_TAB_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | const mp_digit s_mp_prime_tab[] = { 7 | 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, 8 | 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, 9 | 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, 10 | 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, 11 | 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, 12 | 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, 13 | 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, 14 | 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, 15 | 16 | 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, 17 | 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, 18 | 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, 19 | 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, 20 | 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, 21 | 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, 22 | 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, 23 | 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, 24 | 25 | 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, 26 | 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, 27 | 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, 28 | 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, 29 | 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, 30 | 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, 31 | 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, 32 | 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, 33 | 34 | 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, 35 | 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, 36 | 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, 37 | 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, 38 | 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, 39 | 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, 40 | 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, 41 | 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /mp_to_radix.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_TO_RADIX_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* reverse an array, used for radix code */ 7 | static void s_reverse(char *s, size_t len) 8 | { 9 | size_t ix = 0, iy = len - 1u; 10 | while (ix < iy) { 11 | MP_EXCH(char, s[ix], s[iy]); 12 | ++ix; 13 | --iy; 14 | } 15 | } 16 | 17 | /* stores a bignum as a ASCII string in a given radix (2..64) 18 | * 19 | * Stores upto "size - 1" chars and always a NULL byte, puts the number of characters 20 | * written, including the '\0', in "written". 21 | */ 22 | mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix) 23 | { 24 | size_t digs; 25 | mp_err err; 26 | mp_int t; 27 | mp_digit d; 28 | char *_s = str; 29 | 30 | /* check range of radix and size*/ 31 | if (maxlen < 2u) { 32 | return MP_BUF; 33 | } 34 | if ((radix < 2) || (radix > 64)) { 35 | return MP_VAL; 36 | } 37 | 38 | /* quick out if its zero */ 39 | if (mp_iszero(a)) { 40 | *str++ = '0'; 41 | *str = '\0'; 42 | if (written != NULL) { 43 | *written = 2u; 44 | } 45 | return MP_OKAY; 46 | } 47 | 48 | if ((err = mp_init_copy(&t, a)) != MP_OKAY) { 49 | return err; 50 | } 51 | 52 | /* if it is negative output a - */ 53 | if (mp_isneg(&t)) { 54 | /* we have to reverse our digits later... but not the - sign!! */ 55 | ++_s; 56 | 57 | /* store the flag and mark the number as positive */ 58 | *str++ = '-'; 59 | t.sign = MP_ZPOS; 60 | 61 | /* subtract a char */ 62 | --maxlen; 63 | } 64 | digs = 0u; 65 | while (!mp_iszero(&t)) { 66 | if (--maxlen < 1u) { 67 | /* no more room */ 68 | err = MP_BUF; 69 | goto LBL_ERR; 70 | } 71 | if ((err = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) { 72 | goto LBL_ERR; 73 | } 74 | *str++ = s_mp_radix_map[d]; 75 | ++digs; 76 | } 77 | /* reverse the digits of the string. In this case _s points 78 | * to the first digit [excluding the sign] of the number 79 | */ 80 | s_reverse(_s, digs); 81 | 82 | /* append a NULL so the string is properly terminated */ 83 | *str = '\0'; 84 | digs++; 85 | 86 | if (written != NULL) { 87 | *written = mp_isneg(a) ? (digs + 1u): digs; 88 | } 89 | 90 | LBL_ERR: 91 | mp_clear(&t); 92 | return err; 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /s_mp_fp_log_d.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_FP_LOG_D_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | static mp_word s_mp_flog2_mp_word_d(mp_word value) 7 | { 8 | mp_word r = 0u; 9 | while ((value >>= 1) != 0u) { 10 | r++; 11 | } 12 | return r; 13 | } 14 | 15 | /* Fixed point bitwise logarithm base two of "x" with precision "p" */ 16 | static mp_err s_mp_fp_log_fraction_d(mp_word x, int p, mp_word *c) 17 | { 18 | mp_word b, L_out, L, a_bar, twoep; 19 | int i; 20 | 21 | L = s_mp_flog2_mp_word_d(x); 22 | 23 | if ((L + (mp_word)p) > MP_UPPER_LIMIT_FIXED_LOG) { 24 | return MP_VAL; 25 | } 26 | 27 | a_bar = ((mp_word)p < L) ? x << (L - (mp_word)p) : x << ((mp_word)p - L); 28 | b = (mp_word)(1u) << (p - 1); 29 | L_out = L << p; 30 | 31 | twoep = (mp_word)(1u) << (p + 1); 32 | 33 | for (i = 0; i < p; i++) { 34 | a_bar = (a_bar * a_bar) >> p; 35 | if (a_bar >= twoep) { 36 | a_bar >>= 1u; 37 | L_out += b; 38 | } 39 | b >>= 1u; 40 | } 41 | *c = L_out; 42 | return MP_OKAY; 43 | } 44 | 45 | /* Approximate the base two logarithm of "a" */ 46 | mp_err s_mp_fp_log_d(const mp_int *a, mp_word *c) 47 | { 48 | mp_err err; 49 | int la; 50 | int prec = MP_PRECISION_FIXED_LOG; 51 | mp_word tmp, la_word; 52 | mp_int t; 53 | 54 | la = mp_count_bits(a) - 1; 55 | 56 | /* We don't use the whole number, just the most significant "prec" bits */ 57 | if (la > prec) { 58 | if ((err = mp_init(&t)) != MP_OKAY) goto LTM_ERR; 59 | /* Get enough msb-bits for the chosen precision */ 60 | if ((err = mp_div_2d(a, la - prec, &t, NULL)) != MP_OKAY) goto LTM_ERR; 61 | tmp = mp_get_u64(&t); 62 | /* Compute the low precision approximation for the fractional part */ 63 | if ((err = s_mp_fp_log_fraction_d(tmp, prec, &la_word)) != MP_OKAY) goto LTM_ERR; 64 | /* Compute the integer part and add it */ 65 | tmp = ((mp_word)(la - prec))< 0) { 39 | /* divide the power of two out */ 40 | if ((err = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { 41 | goto LBL_V; 42 | } 43 | 44 | if ((err = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { 45 | goto LBL_V; 46 | } 47 | } 48 | 49 | /* divide any remaining factors of two out */ 50 | if (u_lsb != k) { 51 | if ((err = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { 52 | goto LBL_V; 53 | } 54 | } 55 | 56 | if (v_lsb != k) { 57 | if ((err = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { 58 | goto LBL_V; 59 | } 60 | } 61 | 62 | while (!mp_iszero(&v)) { 63 | /* make sure v is the largest */ 64 | if (mp_cmp_mag(&u, &v) == MP_GT) { 65 | /* swap u and v to make sure v is >= u */ 66 | mp_exch(&u, &v); 67 | } 68 | 69 | /* subtract smallest from largest */ 70 | if ((err = s_mp_sub(&v, &u, &v)) != MP_OKAY) { 71 | goto LBL_V; 72 | } 73 | 74 | /* Divide out all factors of two */ 75 | if ((err = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) { 76 | goto LBL_V; 77 | } 78 | } 79 | 80 | /* multiply by 2**k which we divided out at the beginning */ 81 | if ((err = mp_mul_2d(&u, k, c)) != MP_OKAY) { 82 | goto LBL_V; 83 | } 84 | c->sign = MP_ZPOS; 85 | err = MP_OKAY; 86 | LBL_V: 87 | mp_clear(&v); 88 | LBL_U: 89 | mp_clear(&u); 90 | return err; 91 | } 92 | #endif 93 | -------------------------------------------------------------------------------- /s_mp_mul_comba.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_MUL_COMBA_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* Fast (comba) multiplier 7 | * 8 | * This is the fast column-array [comba] multiplier. It is 9 | * designed to compute the columns of the product first 10 | * then handle the carries afterwards. This has the effect 11 | * of making the nested loops that compute the columns very 12 | * simple and schedulable on super-scalar processors. 13 | * 14 | * This has been modified to produce a variable number of 15 | * digits of output so if say only a half-product is required 16 | * you don't have to compute the upper half (a feature 17 | * required for fast Barrett reduction). 18 | * 19 | * Based on Algorithm 14.12 on pp.595 of HAC. 20 | * 21 | */ 22 | mp_err s_mp_mul_comba(const mp_int *a, const mp_int *b, mp_int *c, int digs) 23 | { 24 | int oldused, pa, ix; 25 | mp_err err; 26 | mp_digit MP_ALLOC_WARRAY(W); 27 | mp_word _W; 28 | 29 | MP_CHECK_WARRAY(W); 30 | 31 | if (digs < 0) { 32 | MP_FREE_WARRAY(W); 33 | return MP_VAL; 34 | } 35 | 36 | /* grow the destination as required */ 37 | if ((err = mp_grow(c, digs)) != MP_OKAY) { 38 | MP_FREE_WARRAY(W); 39 | return err; 40 | } 41 | 42 | /* number of output digits to produce */ 43 | pa = MP_MIN(digs, a->used + b->used); 44 | 45 | /* clear the carry */ 46 | _W = 0; 47 | for (ix = 0; ix < pa; ix++) { 48 | int tx, ty, iy, iz; 49 | 50 | /* get offsets into the two bignums */ 51 | ty = MP_MIN(b->used-1, ix); 52 | tx = ix - ty; 53 | 54 | /* this is the number of times the loop will iterate, essentially 55 | while (tx++ < a->used && ty-- >= 0) { ... } 56 | */ 57 | iy = MP_MIN(a->used-tx, ty+1); 58 | 59 | /* execute loop */ 60 | for (iz = 0; iz < iy; ++iz) { 61 | _W += (mp_word)a->dp[tx + iz] * (mp_word)b->dp[ty - iz]; 62 | } 63 | 64 | /* store term */ 65 | W[ix] = (mp_digit)_W & MP_MASK; 66 | 67 | /* make next carry */ 68 | _W = _W >> (mp_word)MP_DIGIT_BIT; 69 | } 70 | 71 | /* setup dest */ 72 | oldused = c->used; 73 | c->used = pa; 74 | 75 | for (ix = 0; ix < pa; ix++) { 76 | /* now extract the previous digit [below the carry] */ 77 | c->dp[ix] = W[ix]; 78 | } 79 | 80 | /* clear unused digits [that existed in the old copy of c] */ 81 | s_mp_zero_digs(c->dp + c->used, oldused - c->used); 82 | 83 | mp_clamp(c); 84 | MP_FREE_WARRAY(W); 85 | return MP_OKAY; 86 | } 87 | #endif 88 | -------------------------------------------------------------------------------- /etc/drprime.c: -------------------------------------------------------------------------------- 1 | /* Makes safe primes of a DR nature */ 2 | #include 3 | 4 | static int sizes[] = { 1+256/MP_DIGIT_BIT, 1+512/MP_DIGIT_BIT, 1+768/MP_DIGIT_BIT, 1+1024/MP_DIGIT_BIT, 1+2048/MP_DIGIT_BIT, 1+4096/MP_DIGIT_BIT }; 5 | 6 | int main(void) 7 | { 8 | bool res; 9 | int x, y; 10 | char buf[4096]; 11 | FILE *out; 12 | mp_int a, b; 13 | mp_err err; 14 | 15 | if ((err = mp_init(&a)) != MP_OKAY) goto LTM_ERR; 16 | if ((err = mp_init(&b)) != MP_OKAY) goto LTM_ERR; 17 | 18 | out = fopen("drprimes.txt", "w"); 19 | if (out != NULL) { 20 | for (x = 0; x < (int)(sizeof(sizes)/sizeof(sizes[0])); x++) { 21 | top: 22 | printf("Seeking a %d-bit safe prime\n", sizes[x] * MP_DIGIT_BIT); 23 | if ((err = mp_grow(&a, sizes[x])) != MP_OKAY) goto LTM_ERR; 24 | mp_zero(&a); 25 | for (y = 1; y < sizes[x]; y++) { 26 | a.dp[y] = MP_MASK; 27 | } 28 | 29 | /* make a DR modulus */ 30 | a.dp[0] = -1; 31 | a.used = sizes[x]; 32 | 33 | /* now loop */ 34 | res = false; 35 | for (;;) { 36 | a.dp[0] += 4uL; 37 | if (a.dp[0] >= MP_MASK) break; 38 | if ((err = mp_prime_is_prime(&a, 1, &res)) != MP_OKAY) goto LTM_ERR; 39 | if (!res) continue; 40 | printf("."); 41 | fflush(stdout); 42 | if ((err = mp_sub_d(&a, 1uL, &b)) != MP_OKAY) goto LTM_ERR; 43 | if ((err = mp_div_2(&b, &b)) != MP_OKAY) goto LTM_ERR; 44 | if ((err = mp_prime_is_prime(&b, 3, &res)) != MP_OKAY) goto LTM_ERR; 45 | if (!res) continue; 46 | if ((err = mp_prime_is_prime(&a, 3, &res)) != MP_OKAY) goto LTM_ERR; 47 | if (res) break; 48 | } 49 | 50 | if (!res) { 51 | printf("Error not DR modulus\n"); 52 | sizes[x] += 1; 53 | goto top; 54 | } else { 55 | if ((err = mp_to_decimal(&a, buf, sizeof(buf))) != MP_OKAY) goto LTM_ERR; 56 | printf("\n\np == %s\n\n", buf); 57 | fprintf(out, "%d-bit prime:\np == %s\n\n", mp_count_bits(&a), buf); 58 | fflush(out); 59 | } 60 | } 61 | fclose(out); 62 | } 63 | 64 | LTM_ERR: 65 | mp_clear(&a); 66 | mp_clear(&b); 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /s_mp_sqr_comba.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_SQR_COMBA_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* the jist of squaring... 7 | * you do like mult except the offset of the tmpx [one that 8 | * starts closer to zero] can't equal the offset of tmpy. 9 | * So basically you set up iy like before then you min it with 10 | * (ty-tx) so that it never happens. You double all those 11 | * you add in the inner loop 12 | 13 | After that loop you do the squares and add them in. 14 | */ 15 | 16 | mp_err s_mp_sqr_comba(const mp_int *a, mp_int *b) 17 | { 18 | int oldused, pa, ix; 19 | mp_digit MP_ALLOC_WARRAY(W); 20 | mp_word W1; 21 | mp_err err; 22 | 23 | MP_CHECK_WARRAY(W); 24 | 25 | /* grow the destination as required */ 26 | pa = a->used + a->used; 27 | if ((err = mp_grow(b, pa)) != MP_OKAY) { 28 | MP_FREE_WARRAY(W); 29 | return err; 30 | } 31 | 32 | /* number of output digits to produce */ 33 | W1 = 0; 34 | for (ix = 0; ix < pa; ix++) { 35 | int tx, ty, iy, iz; 36 | mp_word _W; 37 | 38 | /* clear counter */ 39 | _W = 0; 40 | 41 | /* get offsets into the two bignums */ 42 | ty = MP_MIN(a->used-1, ix); 43 | tx = ix - ty; 44 | 45 | /* this is the number of times the loop will iterate, essentially 46 | while (tx++ < a->used && ty-- >= 0) { ... } 47 | */ 48 | iy = MP_MIN(a->used-tx, ty+1); 49 | 50 | /* now for squaring tx can never equal ty 51 | * we halve the distance since they approach at a rate of 2x 52 | * and we have to round because odd cases need to be executed 53 | */ 54 | iy = MP_MIN(iy, ((ty-tx)+1)>>1); 55 | 56 | /* execute loop */ 57 | for (iz = 0; iz < iy; iz++) { 58 | _W += (mp_word)a->dp[tx + iz] * (mp_word)a->dp[ty - iz]; 59 | } 60 | 61 | /* double the inner product and add carry */ 62 | _W = _W + _W + W1; 63 | 64 | /* even columns have the square term in them */ 65 | if (((unsigned)ix & 1u) == 0u) { 66 | _W += (mp_word)a->dp[ix>>1] * (mp_word)a->dp[ix>>1]; 67 | } 68 | 69 | /* store it */ 70 | W[ix] = (mp_digit)_W & MP_MASK; 71 | 72 | /* make next carry */ 73 | W1 = _W >> (mp_word)MP_DIGIT_BIT; 74 | } 75 | 76 | /* setup dest */ 77 | oldused = b->used; 78 | b->used = a->used+a->used; 79 | 80 | for (ix = 0; ix < pa; ix++) { 81 | b->dp[ix] = W[ix] & MP_MASK; 82 | } 83 | 84 | /* clear unused digits [that existed in the old copy of c] */ 85 | s_mp_zero_digs(b->dp + b->used, oldused - b->used); 86 | 87 | mp_clamp(b); 88 | MP_FREE_WARRAY(W); 89 | return MP_OKAY; 90 | } 91 | #endif 92 | -------------------------------------------------------------------------------- /mp_montgomery_reduce.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MONTGOMERY_REDUCE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* computes xR**-1 == x (mod N) via Montgomery Reduction */ 7 | mp_err mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho) 8 | { 9 | mp_err err; 10 | int ix, digs; 11 | 12 | /* can the fast reduction [comba] method be used? 13 | * 14 | * Note that unlike in mul you're safely allowed *less* 15 | * than the available columns [255 per default] since carries 16 | * are fixed up in the inner loop. 17 | */ 18 | digs = (n->used * 2) + 1; 19 | if ((digs < MP_WARRAY) && 20 | (x->used <= MP_WARRAY) && 21 | (n->used < MP_MAX_COMBA)) { 22 | return s_mp_montgomery_reduce_comba(x, n, rho); 23 | } 24 | 25 | /* grow the input as required */ 26 | if ((err = mp_grow(x, digs)) != MP_OKAY) { 27 | return err; 28 | } 29 | x->used = digs; 30 | 31 | for (ix = 0; ix < n->used; ix++) { 32 | int iy; 33 | mp_digit u, mu; 34 | 35 | /* mu = ai * rho mod b 36 | * 37 | * The value of rho must be precalculated via 38 | * montgomery_setup() such that 39 | * it equals -1/n0 mod b this allows the 40 | * following inner loop to reduce the 41 | * input one digit at a time 42 | */ 43 | mu = (mp_digit)(((mp_word)x->dp[ix] * (mp_word)rho) & MP_MASK); 44 | 45 | /* a = a + mu * m * b**i */ 46 | 47 | /* Multiply and add in place */ 48 | u = 0; 49 | for (iy = 0; iy < n->used; iy++) { 50 | /* compute product and sum */ 51 | mp_word r = ((mp_word)mu * (mp_word)n->dp[iy]) + 52 | (mp_word)u + (mp_word)x->dp[ix + iy]; 53 | 54 | /* get carry */ 55 | u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); 56 | 57 | /* fix digit */ 58 | x->dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK); 59 | } 60 | /* At this point the ix'th digit of x should be zero */ 61 | 62 | /* propagate carries upwards as required*/ 63 | while (u != 0u) { 64 | x->dp[ix + iy] += u; 65 | u = x->dp[ix + iy] >> MP_DIGIT_BIT; 66 | x->dp[ix + iy] &= MP_MASK; 67 | ++iy; 68 | } 69 | } 70 | 71 | /* at this point the n.used'th least 72 | * significant digits of x are all zero 73 | * which means we can shift x to the 74 | * right by n.used digits and the 75 | * residue is unchanged. 76 | */ 77 | 78 | /* x = x/b**n.used */ 79 | mp_clamp(x); 80 | mp_rshd(x, n->used); 81 | 82 | /* if x >= n then x = x - n */ 83 | if (mp_cmp_mag(x, n) != MP_LT) { 84 | return s_mp_sub(x, n, x); 85 | } 86 | 87 | return MP_OKAY; 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /s_mp_sqr.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_SQR_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ 7 | mp_err s_mp_sqr(const mp_int *a, mp_int *b) 8 | { 9 | mp_int t; 10 | int ix, pa; 11 | mp_err err; 12 | 13 | pa = a->used; 14 | if ((err = mp_init_size(&t, (2 * pa) + 1)) != MP_OKAY) { 15 | return err; 16 | } 17 | 18 | /* default used is maximum possible size */ 19 | t.used = (2 * pa) + 1; 20 | 21 | for (ix = 0; ix < pa; ix++) { 22 | mp_digit u; 23 | int iy; 24 | 25 | /* first calculate the digit at 2*ix */ 26 | /* calculate double precision result */ 27 | mp_word r = (mp_word)t.dp[2*ix] + 28 | ((mp_word)a->dp[ix] * (mp_word)a->dp[ix]); 29 | 30 | /* store lower part in result */ 31 | t.dp[ix+ix] = (mp_digit)(r & (mp_word)MP_MASK); 32 | 33 | /* get the carry */ 34 | u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); 35 | 36 | for (iy = ix + 1; iy < pa; iy++) { 37 | /* first calculate the product */ 38 | r = (mp_word)a->dp[ix] * (mp_word)a->dp[iy]; 39 | 40 | /* now calculate the double precision result, note we use 41 | * addition instead of *2 since it's easier to optimize. 42 | */ 43 | /* Some architectures and/or compilers seem to prefer a bit-shift nowadays */ 44 | r = (mp_word)t.dp[ix + iy] + (r<<1) + (mp_word)u; 45 | 46 | /* store lower part */ 47 | t.dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK); 48 | 49 | /* get carry */ 50 | u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); 51 | } 52 | /* propagate upwards */ 53 | while (u != 0uL) { 54 | mp_digit tmp; 55 | /* 56 | "u" can get bigger than MP_DIGIT_MAX and would need a bigger type 57 | for the sum (mp_word). That is costly if mp_word is not a native 58 | integer but a bigint from the compiler library. We do a manual 59 | multiword addition instead. 60 | */ 61 | /* t.dp[ix + iy] has been masked off by MP_MASK and is hence of the correct size 62 | and we can just add the lower part of "u". Carry is guaranteed to fit into 63 | the type used for mp_digit, too, so we can extract it later. */ 64 | tmp = t.dp[ix + iy] + (u & MP_MASK); 65 | /* t.dp[ix + iy] is set to the result minus the carry, carry is still in "tmp" */ 66 | t.dp[ix + iy] = tmp & MP_MASK; 67 | /* Add high part of "u" and the carry from "tmp" to get the next "u" */ 68 | u = (u >> MP_DIGIT_BIT) + (tmp >> MP_DIGIT_BIT); 69 | ++iy; 70 | } 71 | } 72 | 73 | mp_clamp(&t); 74 | mp_exch(&t, b); 75 | mp_clear(&t); 76 | return MP_OKAY; 77 | } 78 | #endif 79 | -------------------------------------------------------------------------------- /mp_exteuclid.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_EXTEUCLID_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* Extended euclidean algorithm of (a, b) produces 7 | a*u1 + b*u2 = u3 8 | */ 9 | mp_err mp_exteuclid(const mp_int *a, const mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3) 10 | { 11 | mp_int u1, u2, u3, v1, v2, v3, t1, t2, t3, q, tmp; 12 | mp_err err; 13 | 14 | if ((err = mp_init_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL)) != MP_OKAY) { 15 | return err; 16 | } 17 | 18 | /* initialize, (u1,u2,u3) = (1,0,a) */ 19 | mp_set(&u1, 1uL); 20 | if ((err = mp_copy(a, &u3)) != MP_OKAY) goto LBL_ERR; 21 | 22 | /* initialize, (v1,v2,v3) = (0,1,b) */ 23 | mp_set(&v2, 1uL); 24 | if ((err = mp_copy(b, &v3)) != MP_OKAY) goto LBL_ERR; 25 | 26 | /* loop while v3 != 0 */ 27 | while (!mp_iszero(&v3)) { 28 | /* q = u3/v3 */ 29 | if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) goto LBL_ERR; 30 | 31 | /* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */ 32 | if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) goto LBL_ERR; 33 | if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) goto LBL_ERR; 34 | if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) goto LBL_ERR; 35 | if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) goto LBL_ERR; 36 | if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) goto LBL_ERR; 37 | if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) goto LBL_ERR; 38 | 39 | /* (u1,u2,u3) = (v1,v2,v3) */ 40 | if ((err = mp_copy(&v1, &u1)) != MP_OKAY) goto LBL_ERR; 41 | if ((err = mp_copy(&v2, &u2)) != MP_OKAY) goto LBL_ERR; 42 | if ((err = mp_copy(&v3, &u3)) != MP_OKAY) goto LBL_ERR; 43 | 44 | /* (v1,v2,v3) = (t1,t2,t3) */ 45 | if ((err = mp_copy(&t1, &v1)) != MP_OKAY) goto LBL_ERR; 46 | if ((err = mp_copy(&t2, &v2)) != MP_OKAY) goto LBL_ERR; 47 | if ((err = mp_copy(&t3, &v3)) != MP_OKAY) goto LBL_ERR; 48 | } 49 | 50 | /* make sure U3 >= 0 */ 51 | if (mp_isneg(&u3)) { 52 | if ((err = mp_neg(&u1, &u1)) != MP_OKAY) goto LBL_ERR; 53 | if ((err = mp_neg(&u2, &u2)) != MP_OKAY) goto LBL_ERR; 54 | if ((err = mp_neg(&u3, &u3)) != MP_OKAY) goto LBL_ERR; 55 | } 56 | 57 | /* copy result out */ 58 | if (U1 != NULL) { 59 | mp_exch(U1, &u1); 60 | } 61 | if (U2 != NULL) { 62 | mp_exch(U2, &u2); 63 | } 64 | if (U3 != NULL) { 65 | mp_exch(U3, &u3); 66 | } 67 | 68 | LBL_ERR: 69 | mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL); 70 | return err; 71 | } 72 | #endif 73 | -------------------------------------------------------------------------------- /s_mp_sqr_karatsuba.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_SQR_KARATSUBA_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* Karatsuba squaring, computes b = a*a using three 7 | * half size squarings 8 | * 9 | * See comments of mul_karatsuba for details. It 10 | * is essentially the same algorithm but merely 11 | * tuned to perform recursive squarings. 12 | */ 13 | mp_err s_mp_sqr_karatsuba(const mp_int *a, mp_int *b) 14 | { 15 | mp_int x0, x1, t1, t2, x0x0, x1x1; 16 | int B; 17 | mp_err err; 18 | 19 | /* min # of digits */ 20 | B = a->used; 21 | 22 | /* now divide in two */ 23 | B = B >> 1; 24 | 25 | /* init copy all the temps */ 26 | if ((err = mp_init_size(&x0, B)) != MP_OKAY) 27 | goto LBL_ERR; 28 | if ((err = mp_init_size(&x1, a->used - B)) != MP_OKAY) 29 | goto X0; 30 | 31 | /* init temps */ 32 | if ((err = mp_init_size(&t1, a->used * 2)) != MP_OKAY) 33 | goto X1; 34 | if ((err = mp_init_size(&t2, a->used * 2)) != MP_OKAY) 35 | goto T1; 36 | if ((err = mp_init_size(&x0x0, B * 2)) != MP_OKAY) 37 | goto T2; 38 | if ((err = mp_init_size(&x1x1, (a->used - B) * 2)) != MP_OKAY) 39 | goto X0X0; 40 | 41 | /* now shift the digits */ 42 | x0.used = B; 43 | x1.used = a->used - B; 44 | s_mp_copy_digs(x0.dp, a->dp, x0.used); 45 | s_mp_copy_digs(x1.dp, a->dp + B, x1.used); 46 | mp_clamp(&x0); 47 | 48 | /* now calc the products x0*x0 and x1*x1 */ 49 | if ((err = mp_sqr(&x0, &x0x0)) != MP_OKAY) 50 | goto X1X1; /* x0x0 = x0*x0 */ 51 | if ((err = mp_sqr(&x1, &x1x1)) != MP_OKAY) 52 | goto X1X1; /* x1x1 = x1*x1 */ 53 | 54 | /* now calc (x1+x0)**2 */ 55 | if ((err = s_mp_add(&x1, &x0, &t1)) != MP_OKAY) 56 | goto X1X1; /* t1 = x1 - x0 */ 57 | if ((err = mp_sqr(&t1, &t1)) != MP_OKAY) 58 | goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */ 59 | 60 | /* add x0y0 */ 61 | if ((err = s_mp_add(&x0x0, &x1x1, &t2)) != MP_OKAY) 62 | goto X1X1; /* t2 = x0x0 + x1x1 */ 63 | if ((err = s_mp_sub(&t1, &t2, &t1)) != MP_OKAY) 64 | goto X1X1; /* t1 = (x1+x0)**2 - (x0x0 + x1x1) */ 65 | 66 | /* shift by B */ 67 | if ((err = mp_lshd(&t1, B)) != MP_OKAY) 68 | goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))< 3 | #include 4 | 5 | static int sizes[] = {256, 512, 768, 1024, 1536, 2048, 3072, 4096}; 6 | 7 | int main(void) 8 | { 9 | char buf[2000]; 10 | size_t x; 11 | bool y; 12 | mp_int q, p; 13 | mp_err err; 14 | FILE *out; 15 | clock_t t1; 16 | mp_digit z; 17 | 18 | if ((err = mp_init_multi(&q, &p, NULL)) != MP_OKAY) goto LTM_ERR; 19 | 20 | out = fopen("2kprime.1", "w"); 21 | if (out != NULL) { 22 | for (x = 0; x < (sizeof(sizes) / sizeof(sizes[0])); x++) { 23 | top: 24 | if ((err = mp_2expt(&q, sizes[x])) != MP_OKAY) goto LTM_ERR; 25 | if ((err = mp_add_d(&q, 3uL, &q)) != MP_OKAY) goto LTM_ERR; 26 | z = -3; 27 | 28 | t1 = clock(); 29 | for (;;) { 30 | if ((err = mp_sub_d(&q, 4uL, &q)) != MP_OKAY) goto LTM_ERR; 31 | z += 4uL; 32 | 33 | if (z > MP_MASK) { 34 | printf("No primes of size %d found\n", sizes[x]); 35 | break; 36 | } 37 | 38 | if ((clock() - t1) > CLOCKS_PER_SEC) { 39 | printf("."); 40 | fflush(stdout); 41 | /* sleep((clock() - t1 + CLOCKS_PER_SEC/2)/CLOCKS_PER_SEC); */ 42 | t1 = clock(); 43 | } 44 | 45 | /* quick test on q */ 46 | if ((err = mp_prime_is_prime(&q, 1, &y)) != MP_OKAY) goto LTM_ERR; 47 | if (!y) { 48 | continue; 49 | } 50 | 51 | /* find (q-1)/2 */ 52 | if ((err = mp_sub_d(&q, 1uL, &p)) != MP_OKAY) goto LTM_ERR; 53 | if ((err = mp_div_2(&p, &p)) != MP_OKAY) goto LTM_ERR; 54 | if ((err = mp_prime_is_prime(&p, 3, &y)) != MP_OKAY) goto LTM_ERR; 55 | if (!y) { 56 | continue; 57 | } 58 | 59 | /* test on q */ 60 | if ((err = mp_prime_is_prime(&q, 3, &y)) != MP_OKAY) goto LTM_ERR; 61 | if (!y) { 62 | continue; 63 | } 64 | 65 | break; 66 | } 67 | 68 | if (!y) { 69 | ++sizes[x]; 70 | goto top; 71 | } 72 | 73 | if ((err = mp_to_decimal(&q, buf, sizeof(buf))) != MP_OKAY) goto LTM_ERR; 74 | printf("\n\n%d-bits (k = %lu) = %s\n", sizes[x], z, buf); 75 | fprintf(out, "%d-bits (k = %lu) = %s\n", sizes[x], z, buf); 76 | fflush(out); 77 | } 78 | fclose(out); 79 | } 80 | LTM_ERR: 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /mp_mul.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_MUL_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* high level multiplication (handles sign) */ 7 | mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c) 8 | { 9 | mp_err err; 10 | int min = MP_MIN(a->used, b->used), 11 | max = MP_MAX(a->used, b->used), 12 | digs = a->used + b->used + 1; 13 | bool neg = (a->sign != b->sign); 14 | 15 | if ((a == b) && 16 | MP_HAS(S_MP_SQR_TOOM) && /* use Toom-Cook? */ 17 | (a->used >= MP_SQR_TOOM_CUTOFF)) { 18 | err = s_mp_sqr_toom(a, c); 19 | } else if ((a == b) && 20 | MP_HAS(S_MP_SQR_KARATSUBA) && /* Karatsuba? */ 21 | (a->used >= MP_SQR_KARATSUBA_CUTOFF)) { 22 | err = s_mp_sqr_karatsuba(a, c); 23 | } else if ((a == b) && 24 | MP_HAS(S_MP_SQR_COMBA) && /* can we use the fast comba multiplier? */ 25 | (((a->used * 2) + 1) < MP_WARRAY) && 26 | (a->used <= MP_MAX_COMBA)) { 27 | err = s_mp_sqr_comba(a, c); 28 | } else if ((a == b) && 29 | MP_HAS(S_MP_SQR)) { 30 | err = s_mp_sqr(a, c); 31 | } else if (MP_HAS(S_MP_MUL_BALANCE) && 32 | /* Check sizes. The smaller one needs to be larger than the Karatsuba cut-off. 33 | * The bigger one needs to be at least about one MP_MUL_KARATSUBA_CUTOFF bigger 34 | * to make some sense, but it depends on architecture, OS, position of the 35 | * stars... so YMMV. 36 | * Using it to cut the input into slices small enough for s_mp_mul_comba 37 | * was actually slower on the author's machine, but YMMV. 38 | */ 39 | (min >= MP_MUL_KARATSUBA_CUTOFF) && 40 | ((max / 2) >= MP_MUL_KARATSUBA_CUTOFF) && 41 | /* Not much effect was observed below a ratio of 1:2, but again: YMMV. */ 42 | (max >= (2 * min))) { 43 | err = s_mp_mul_balance(a,b,c); 44 | } else if (MP_HAS(S_MP_MUL_TOOM) && 45 | (min >= MP_MUL_TOOM_CUTOFF)) { 46 | err = s_mp_mul_toom(a, b, c); 47 | } else if (MP_HAS(S_MP_MUL_KARATSUBA) && 48 | (min >= MP_MUL_KARATSUBA_CUTOFF)) { 49 | err = s_mp_mul_karatsuba(a, b, c); 50 | } else if (MP_HAS(S_MP_MUL_COMBA) && 51 | /* can we use the fast multiplier? 52 | * 53 | * The fast multiplier can be used if the output will 54 | * have less than MP_WARRAY digits and the number of 55 | * digits won't affect carry propagation 56 | */ 57 | (digs < MP_WARRAY) && 58 | (min <= MP_MAX_COMBA)) { 59 | err = s_mp_mul_comba(a, b, c, digs); 60 | } else if (MP_HAS(S_MP_MUL)) { 61 | err = s_mp_mul(a, b, c, digs); 62 | } else { 63 | err = MP_VAL; 64 | } 65 | c->sign = ((c->used > 0) && neg) ? MP_NEG : MP_ZPOS; 66 | return err; 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /tommath.def: -------------------------------------------------------------------------------- 1 | ; libtommath 2 | ; 3 | ; Use this command to produce a 32-bit .lib file, for use in any MSVC version 4 | ; lib -machine:X86 -name:libtommath.dll -def:tommath.def -out:tommath.lib 5 | ; Use this command to produce a 64-bit .lib file, for use in any MSVC version 6 | ; lib -machine:X64 -name:libtommath.dll -def:tommath.def -out:tommath.lib 7 | ; 8 | EXPORTS 9 | mp_2expt 10 | mp_abs 11 | mp_add 12 | mp_add_d 13 | mp_addmod 14 | mp_and 15 | mp_clamp 16 | mp_clear 17 | mp_clear_multi 18 | mp_cmp 19 | mp_cmp_d 20 | mp_cmp_mag 21 | mp_cnt_lsb 22 | mp_complement 23 | mp_copy 24 | mp_count_bits 25 | mp_div 26 | mp_div_2 27 | mp_div_2d 28 | mp_div_d 29 | mp_dr_is_modulus 30 | mp_dr_reduce 31 | mp_dr_setup 32 | mp_error_to_string 33 | mp_exch 34 | mp_expt_n 35 | mp_exptmod 36 | mp_exteuclid 37 | mp_fread 38 | mp_from_sbin 39 | mp_from_ubin 40 | mp_fwrite 41 | mp_gcd 42 | mp_get_double 43 | mp_get_i32 44 | mp_get_i64 45 | mp_get_l 46 | mp_get_mag_u32 47 | mp_get_mag_u64 48 | mp_get_mag_ul 49 | mp_grow 50 | mp_hash 51 | mp_init 52 | mp_init_copy 53 | mp_init_i32 54 | mp_init_i64 55 | mp_init_l 56 | mp_init_multi 57 | mp_init_set 58 | mp_init_size 59 | mp_init_u32 60 | mp_init_u64 61 | mp_init_ul 62 | mp_invmod 63 | mp_is_square 64 | mp_kronecker 65 | mp_lcm 66 | mp_log 67 | mp_log_n 68 | mp_lshd 69 | mp_mod 70 | mp_mod_2d 71 | mp_montgomery_calc_normalization 72 | mp_montgomery_reduce 73 | mp_montgomery_setup 74 | mp_mul 75 | mp_mul_2 76 | mp_mul_2d 77 | mp_mul_d 78 | mp_mulmod 79 | mp_neg 80 | mp_or 81 | mp_pack 82 | mp_pack_count 83 | mp_prime_fermat 84 | mp_prime_frobenius_underwood 85 | mp_prime_is_prime 86 | mp_prime_miller_rabin 87 | mp_prime_next_prime 88 | mp_prime_rabin_miller_trials 89 | mp_prime_rand 90 | mp_prime_strong_lucas_selfridge 91 | mp_radix_size 92 | mp_radix_size_overestimate 93 | mp_rand 94 | mp_rand_source 95 | mp_read_radix 96 | mp_reduce 97 | mp_reduce_2k 98 | mp_reduce_2k_l 99 | mp_reduce_2k_setup 100 | mp_reduce_2k_setup_l 101 | mp_reduce_is_2k 102 | mp_reduce_is_2k_l 103 | mp_reduce_setup 104 | mp_root_n 105 | mp_rshd 106 | mp_sbin_size 107 | mp_set 108 | mp_set_double 109 | mp_set_i32 110 | mp_set_i64 111 | mp_set_l 112 | mp_set_u32 113 | mp_set_u64 114 | mp_set_ul 115 | mp_shrink 116 | mp_signed_rsh 117 | mp_sqrmod 118 | mp_sqrt 119 | mp_sqrtmod_prime 120 | mp_sub 121 | mp_sub_d 122 | mp_submod 123 | mp_to_radix 124 | mp_to_sbin 125 | mp_to_ubin 126 | mp_ubin_size 127 | mp_unpack 128 | mp_warray_free 129 | mp_xor 130 | mp_zero 131 | MP_MUL_KARATSUBA_CUTOFF 132 | MP_SQR_KARATSUBA_CUTOFF 133 | MP_MUL_TOOM_CUTOFF 134 | MP_SQR_TOOM_CUTOFF 135 | -------------------------------------------------------------------------------- /etc/mersenne.c: -------------------------------------------------------------------------------- 1 | /* Finds Mersenne primes using the Lucas-Lehmer test 2 | * 3 | * Tom St Denis, tomstdenis@gmail.com 4 | */ 5 | #include 6 | #include 7 | 8 | static mp_err is_mersenne(long s, bool *pp) 9 | { 10 | mp_int n, u; 11 | mp_err res; 12 | int k; 13 | 14 | *pp = false; 15 | 16 | if ((res = mp_init(&n)) != MP_OKAY) { 17 | return res; 18 | } 19 | 20 | if ((res = mp_init(&u)) != MP_OKAY) { 21 | goto LBL_N; 22 | } 23 | 24 | /* n = 2^s - 1 */ 25 | if ((res = mp_2expt(&n, (int)s)) != MP_OKAY) { 26 | goto LBL_MU; 27 | } 28 | if ((res = mp_sub_d(&n, 1uL, &n)) != MP_OKAY) { 29 | goto LBL_MU; 30 | } 31 | 32 | /* set u=4 */ 33 | mp_set(&u, 4uL); 34 | 35 | /* for k=1 to s-2 do */ 36 | for (k = 1; k <= (s - 2); k++) { 37 | /* u = u^2 - 2 mod n */ 38 | if ((res = mp_sqr(&u, &u)) != MP_OKAY) { 39 | goto LBL_MU; 40 | } 41 | if ((res = mp_sub_d(&u, 2uL, &u)) != MP_OKAY) { 42 | goto LBL_MU; 43 | } 44 | 45 | /* make sure u is positive */ 46 | while (mp_isneg(&u)) { 47 | if ((res = mp_add(&u, &n, &u)) != MP_OKAY) { 48 | goto LBL_MU; 49 | } 50 | } 51 | 52 | /* reduce */ 53 | if ((res = mp_reduce_2k(&u, &n, 1uL)) != MP_OKAY) { 54 | goto LBL_MU; 55 | } 56 | } 57 | 58 | /* if u == 0 then its prime */ 59 | if (mp_iszero(&u)) { 60 | if ((res = mp_prime_is_prime(&n, 8, pp)) != MP_OKAY) { 61 | goto LBL_MU; 62 | } 63 | if (!*pp) printf("FAILURE\n"); 64 | } 65 | 66 | res = MP_OKAY; 67 | LBL_MU: 68 | mp_clear(&u); 69 | LBL_N: 70 | mp_clear(&n); 71 | return res; 72 | } 73 | 74 | /* square root of a long < 65536 */ 75 | static long i_sqrt(long x) 76 | { 77 | long x1, x2; 78 | 79 | x2 = 16; 80 | do { 81 | x1 = x2; 82 | x2 = x1 - ((x1 * x1) - x) / (2 * x1); 83 | } while (x1 != x2); 84 | 85 | if ((x1 * x1) > x) { 86 | --x1; 87 | } 88 | 89 | return x1; 90 | } 91 | 92 | /* is the long prime by brute force */ 93 | static int isprime(long k) 94 | { 95 | long y, z; 96 | 97 | y = i_sqrt(k); 98 | for (z = 2; z <= y; z++) { 99 | if ((k % z) == 0) 100 | return 0; 101 | } 102 | return 1; 103 | } 104 | 105 | 106 | int main(void) 107 | { 108 | bool pp; 109 | long k; 110 | clock_t tt; 111 | 112 | k = 3; 113 | 114 | for (;;) { 115 | /* start time */ 116 | tt = clock(); 117 | 118 | /* test if 2^k - 1 is prime */ 119 | if (is_mersenne(k, &pp) != MP_OKAY) { 120 | printf("Whoa error\n"); 121 | return -1; 122 | } 123 | 124 | if (pp) { 125 | /* count time */ 126 | tt = clock() - tt; 127 | 128 | /* display if prime */ 129 | printf("2^%-5ld - 1 is prime, test took %ld ticks\n", k, (long)tt); 130 | } 131 | 132 | /* goto next odd exponent */ 133 | k += 2; 134 | 135 | /* but make sure its prime */ 136 | while (isprime(k) == 0) { 137 | k += 2; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /mp_is_square.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_IS_SQUARE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* Check if remainders are possible squares - fast exclude non-squares */ 7 | static const char rem_128[128] = { 8 | 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 9 | 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 10 | 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 11 | 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 12 | 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 13 | 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 14 | 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 15 | 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 16 | }; 17 | 18 | static const char rem_105[105] = { 19 | 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 20 | 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 21 | 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 22 | 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 23 | 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 24 | 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 25 | 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 26 | }; 27 | 28 | /* Store non-zero to ret if arg is square, and zero if not */ 29 | mp_err mp_is_square(const mp_int *arg, bool *ret) 30 | { 31 | mp_err err; 32 | mp_digit c; 33 | mp_int t; 34 | uint32_t r; 35 | 36 | /* Default to Non-square :) */ 37 | *ret = false; 38 | 39 | if (mp_isneg(arg)) { 40 | return MP_VAL; 41 | } 42 | 43 | if (mp_iszero(arg)) { 44 | *ret = true; 45 | return MP_OKAY; 46 | } 47 | 48 | /* First check mod 128 (suppose that MP_DIGIT_BIT is at least 7) */ 49 | if (rem_128[127u & arg->dp[0]] == (char)1) { 50 | return MP_OKAY; 51 | } 52 | 53 | /* Next check mod 105 (3*5*7) */ 54 | if ((err = mp_mod_d(arg, 105uL, &c)) != MP_OKAY) { 55 | return err; 56 | } 57 | if (rem_105[c] == (char)1) { 58 | return MP_OKAY; 59 | } 60 | 61 | 62 | if ((err = mp_init_u32(&t, 11u*13u*17u*19u*23u*29u*31u)) != MP_OKAY) { 63 | return err; 64 | } 65 | if ((err = mp_mod(arg, &t, &t)) != MP_OKAY) { 66 | goto LBL_ERR; 67 | } 68 | r = mp_get_u32(&t); 69 | /* Check for other prime modules, note it's not an ERROR but we must 70 | * free "t" so the easiest way is to goto LBL_ERR. We know that err 71 | * is already equal to MP_OKAY from the mp_mod call 72 | */ 73 | if (((1uL<<(r%11uL)) & 0x5C4uL) != 0uL) goto LBL_ERR; 74 | if (((1uL<<(r%13uL)) & 0x9E4uL) != 0uL) goto LBL_ERR; 75 | if (((1uL<<(r%17uL)) & 0x5CE8uL) != 0uL) goto LBL_ERR; 76 | if (((1uL<<(r%19uL)) & 0x4F50CuL) != 0uL) goto LBL_ERR; 77 | if (((1uL<<(r%23uL)) & 0x7ACCA0uL) != 0uL) goto LBL_ERR; 78 | if (((1uL<<(r%29uL)) & 0xC2EDD0CuL) != 0uL) goto LBL_ERR; 79 | if (((1uL<<(r%31uL)) & 0x6DE2B848uL) != 0uL) goto LBL_ERR; 80 | 81 | /* Final check - is sqr(sqrt(arg)) == arg ? */ 82 | if ((err = mp_sqrt(arg, &t)) != MP_OKAY) { 83 | goto LBL_ERR; 84 | } 85 | if ((err = mp_sqr(&t, &t)) != MP_OKAY) { 86 | goto LBL_ERR; 87 | } 88 | 89 | *ret = (mp_cmp_mag(&t, arg) == MP_EQ); 90 | LBL_ERR: 91 | mp_clear(&t); 92 | return err; 93 | } 94 | #endif 95 | -------------------------------------------------------------------------------- /demo/tommath_tests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import libtommath 3 | 4 | /* ---> Basic Manipulations <--- */ 5 | 6 | extension mp_int { 7 | var isZero: Bool { used == 0 } 8 | var isNeg: Bool { sign == MP_NEG } 9 | var isEven: Bool { used == 0 || (dp[0] & 1) == 0 } 10 | var isOdd: Bool { !isEven } 11 | } 12 | 13 | func mp_get_u32(_ a: UnsafePointer) -> UInt32 { 14 | return UInt32(bitPattern: mp_get_i32(a)) 15 | } 16 | 17 | class LibTommathTests: XCTestCase { 18 | 19 | override func setUpWithError() throws { 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | override func tearDownWithError() throws { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | } 26 | 27 | func testTrivialStuff() throws { 28 | var a = mp_int() 29 | var b = mp_int() 30 | var c = mp_int() 31 | var d = mp_int() 32 | 33 | XCTAssertEqual(mp_init(&a), MP_OKAY) 34 | XCTAssertEqual(mp_init(&b), MP_OKAY) 35 | XCTAssertEqual(mp_init(&c), MP_OKAY) 36 | XCTAssertEqual(mp_init(&d), MP_OKAY) 37 | 38 | defer { 39 | mp_clear(&a) 40 | mp_clear(&b) 41 | mp_clear(&c) 42 | mp_clear(&d) 43 | } 44 | 45 | XCTAssert(mp_error_to_string(MP_OKAY) != nil) 46 | 47 | /* a: 0->5 */ 48 | mp_set(&a, 5) 49 | /* a: 5-> b: -5 */ 50 | XCTAssertEqual(mp_neg(&a, &b), MP_OKAY) 51 | XCTAssertEqual(mp_cmp(&a, &b), MP_GT) 52 | XCTAssertEqual(mp_cmp(&b, &a), MP_LT) 53 | XCTAssertTrue(b.isNeg) 54 | /* a: 5-> a: -5 */ 55 | var t = a // Fix compiler error: Overlapping accesses to 'a', but modification requires exclusive access; consider copying to a local variable 56 | XCTAssertEqual(mp_neg(&t, &a), MP_OKAY) 57 | XCTAssertEqual(mp_cmp(&b, &a), MP_EQ) 58 | XCTAssertTrue(a.isNeg) 59 | /* a: -5-> b: 5 */ 60 | XCTAssertEqual(mp_abs(&a, &b), MP_OKAY) 61 | XCTAssertTrue(!b.isNeg) 62 | /* a: -5-> b: -4 */ 63 | XCTAssertEqual(mp_add_d(&a, 1, &b), MP_OKAY) 64 | XCTAssertTrue(b.isNeg) 65 | XCTAssertEqual(mp_get_i32(&b), -4) 66 | XCTAssertEqual(mp_get_u32(&b), UInt32(bitPattern: -4)) 67 | XCTAssertEqual(mp_get_mag_u32(&b), 4) 68 | /* a: -5-> b: 1 */ 69 | XCTAssertEqual(mp_add_d(&a, 6, &b), MP_OKAY) 70 | XCTAssertEqual(mp_get_u32(&b), 1) 71 | /* a: -5-> a: 1 */ 72 | t = a 73 | XCTAssertEqual(mp_add_d(&t, 6, &a), MP_OKAY) 74 | XCTAssertEqual(mp_get_u32(&a), 1) 75 | mp_zero(&a); 76 | /* a: 0-> a: 6 */ 77 | t = a 78 | XCTAssertEqual(mp_add_d(&t, 6, &a), MP_OKAY) 79 | XCTAssertEqual(mp_get_u32(&a), 6) 80 | 81 | mp_set(&a, 42) 82 | mp_set(&b, 1) 83 | t = b 84 | XCTAssertEqual(mp_neg(&t, &b), MP_OKAY) 85 | mp_set(&c, 1) 86 | XCTAssertEqual(mp_exptmod(&a, &b, &c, &d), MP_OKAY) 87 | 88 | mp_set(&c, 7) 89 | /* same here */ 90 | XCTAssertTrue(mp_exptmod(&a, &b, &c, &d) != MP_OKAY) 91 | 92 | XCTAssertTrue(a.isEven != a.isOdd) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /s_mp_radix_size_overestimate.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef S_MP_RADIX_SIZE_OVERESTIMATE_C 3 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 4 | /* SPDX-License-Identifier: Unlicense */ 5 | 6 | /* 7 | Overestimate the size needed for the bigint to string conversion by a very small amount. 8 | The error is about 10^-8; it will overestimate the result by at most 11 elements for 9 | a number of the size 2^(2^31)-1 which is currently the largest possible in this library. 10 | Some short tests gave no results larger than 5 (plus 2 for sign and EOS). 11 | */ 12 | 13 | /* 14 | Table of {0, INT(log_2([1..64])*2^p)+1 } where p is the scale 15 | factor defined in MP_RADIX_SIZE_SCALE and INT() extracts the integer part (truncating). 16 | Good for 32 bit "int". Set MP_RADIX_SIZE_SCALE = 61 and recompute values 17 | for 64 bit "int". 18 | */ 19 | /* *INDENT-OFF* */ 20 | #define MP_RADIX_SIZE_SCALE 29 21 | static const uint32_t s_log_bases[65] = { 22 | 0u, 0u, 0x20000001u, 0x14309399u, 0x10000001u, 23 | 0xdc81a35u, 0xc611924u, 0xb660c9eu, 0xaaaaaabu, 0xa1849cdu, 24 | 0x9a209a9u, 0x94004e1u, 0x8ed19c2u, 0x8a5ca7du, 0x867a000u, 25 | 0x830cee3u, 0x8000001u, 0x7d42d60u, 0x7ac8b32u, 0x7887847u, 26 | 0x7677349u, 0x749131fu, 0x72d0163u, 0x712f657u, 0x6fab5dbu, 27 | 0x6e40d1bu, 0x6ced0d0u, 0x6badbdeu, 0x6a80e3bu, 0x6964c19u, 28 | 0x6857d31u, 0x6758c38u, 0x6666667u, 0x657fb21u, 0x64a3b9fu, 29 | 0x63d1ab4u, 0x6308c92u, 0x624869eu, 0x618ff47u, 0x60dedeau, 30 | 0x6034ab0u, 0x5f90e7bu, 0x5ef32cbu, 0x5e5b1b2u, 0x5dc85c3u, 31 | 0x5d3aa02u, 0x5cb19d9u, 0x5c2d10fu, 0x5bacbbfu, 0x5b3064fu, 32 | 0x5ab7d68u, 0x5a42df0u, 0x59d1506u, 0x5962ffeu, 0x58f7c57u, 33 | 0x588f7bcu, 0x582a000u, 0x57c7319u, 0x5766f1du, 0x5709243u, 34 | 0x56adad9u, 0x565474du, 0x55fd61fu, 0x55a85e8u, 0x5555556u 35 | }; 36 | /* *INDENT-ON* */ 37 | 38 | mp_err s_mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size) 39 | { 40 | int bit_count; 41 | mp_int bi_bit_count, bi_k; 42 | mp_err err = MP_OKAY; 43 | 44 | if ((radix < 2) || (radix > 64)) { 45 | return MP_VAL; 46 | } 47 | 48 | if (mp_iszero(a)) { 49 | *size = 2U; 50 | return MP_OKAY; 51 | } 52 | 53 | if (MP_HAS(S_MP_LOG_2EXPT) && MP_IS_2EXPT((mp_digit)radix)) { 54 | /* floor(log_{2^n}(a)) + 1 + EOS + sign */ 55 | *size = (size_t)(s_mp_log_2expt(a, (mp_digit)radix) + 3); 56 | return MP_OKAY; 57 | } 58 | 59 | if ((err = mp_init_multi(&bi_bit_count, &bi_k, NULL)) != MP_OKAY) { 60 | return err; 61 | } 62 | 63 | /* la = floor(log_2(a)) + 1 */ 64 | bit_count = mp_count_bits(a); 65 | 66 | mp_set_u32(&bi_bit_count, (uint32_t)bit_count); 67 | /* k = floor(2^29/log_2(radix)) + 1 */ 68 | mp_set_u32(&bi_k, s_log_bases[radix]); 69 | /* n = floor((la * k) / 2^29) + 1 */ 70 | if ((err = mp_mul(&bi_bit_count, &bi_k, &bi_bit_count)) != MP_OKAY) goto LBL_ERR; 71 | if ((err = mp_div_2d(&bi_bit_count, MP_RADIX_SIZE_SCALE, &bi_bit_count, NULL)) != MP_OKAY) goto LBL_ERR; 72 | 73 | /* The "+1" here is the "+1" in "floor((la * k) / 2^29) + 1" */ 74 | /* n = n + 1 + EOS + sign */ 75 | *size = (size_t)(mp_get_u64(&bi_bit_count) + 3U); 76 | 77 | LBL_ERR: 78 | mp_clear_multi(&bi_bit_count, &bi_k, NULL); 79 | return err; 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /mp_kronecker.c: -------------------------------------------------------------------------------- 1 | #include "tommath_private.h" 2 | #ifdef MP_KRONECKER_C 3 | 4 | /* LibTomMath, multiple-precision integer library -- Tom St Denis */ 5 | /* SPDX-License-Identifier: Unlicense */ 6 | 7 | /* 8 | Kronecker symbol (a|p) 9 | Straightforward implementation of algorithm 1.4.10 in 10 | Henri Cohen: "A Course in Computational Algebraic Number Theory" 11 | 12 | @book{cohen2013course, 13 | title={A course in computational algebraic number theory}, 14 | author={Cohen, Henri}, 15 | volume={138}, 16 | year={2013}, 17 | publisher={Springer Science \& Business Media} 18 | } 19 | */ 20 | mp_err mp_kronecker(const mp_int *a, const mp_int *p, int *c) 21 | { 22 | mp_int a1, p1, r; 23 | mp_err err; 24 | int v, k; 25 | 26 | static const int8_t table[] = {0, 1, 0, -1, 0, -1, 0, 1}; 27 | 28 | if (mp_iszero(p)) { 29 | if ((a->used == 1) && (a->dp[0] == 1u)) { 30 | *c = 1; 31 | } else { 32 | *c = 0; 33 | } 34 | return MP_OKAY; 35 | } 36 | 37 | if (mp_iseven(a) && mp_iseven(p)) { 38 | *c = 0; 39 | return MP_OKAY; 40 | } 41 | 42 | if ((err = mp_init_copy(&a1, a)) != MP_OKAY) { 43 | return err; 44 | } 45 | if ((err = mp_init_copy(&p1, p)) != MP_OKAY) { 46 | goto LBL_KRON_0; 47 | } 48 | 49 | v = mp_cnt_lsb(&p1); 50 | if ((err = mp_div_2d(&p1, v, &p1, NULL)) != MP_OKAY) { 51 | goto LBL_KRON_1; 52 | } 53 | 54 | if ((v & 1) == 0) { 55 | k = 1; 56 | } else { 57 | k = table[a->dp[0] & 7u]; 58 | } 59 | 60 | if (mp_isneg(&p1)) { 61 | p1.sign = MP_ZPOS; 62 | if (mp_isneg(&a1)) { 63 | k = -k; 64 | } 65 | } 66 | 67 | if ((err = mp_init(&r)) != MP_OKAY) { 68 | goto LBL_KRON_1; 69 | } 70 | 71 | for (;;) { 72 | if (mp_iszero(&a1)) { 73 | if (mp_cmp_d(&p1, 1uL) == MP_EQ) { 74 | *c = k; 75 | goto LBL_KRON; 76 | } else { 77 | *c = 0; 78 | goto LBL_KRON; 79 | } 80 | } 81 | 82 | v = mp_cnt_lsb(&a1); 83 | if ((err = mp_div_2d(&a1, v, &a1, NULL)) != MP_OKAY) { 84 | goto LBL_KRON; 85 | } 86 | 87 | if ((v & 1) == 1) { 88 | k = k * table[p1.dp[0] & 7u]; 89 | } 90 | 91 | if (mp_isneg(&a1)) { 92 | /* 93 | * Compute k = (-1)^((a1)*(p1-1)/4) * k 94 | * a1.dp[0] + 1 cannot overflow because the MSB 95 | * of the type mp_digit is not set by definition 96 | */ 97 | if (((a1.dp[0] + 1u) & p1.dp[0] & 2u) != 0u) { 98 | k = -k; 99 | } 100 | } else { 101 | /* compute k = (-1)^((a1-1)*(p1-1)/4) * k */ 102 | if ((a1.dp[0] & p1.dp[0] & 2u) != 0u) { 103 | k = -k; 104 | } 105 | } 106 | 107 | if ((err = mp_copy(&a1, &r)) != MP_OKAY) { 108 | goto LBL_KRON; 109 | } 110 | r.sign = MP_ZPOS; 111 | if ((err = mp_mod(&p1, &r, &a1)) != MP_OKAY) { 112 | goto LBL_KRON; 113 | } 114 | if ((err = mp_copy(&r, &p1)) != MP_OKAY) { 115 | goto LBL_KRON; 116 | } 117 | } 118 | 119 | LBL_KRON: 120 | mp_clear(&r); 121 | LBL_KRON_1: 122 | mp_clear(&p1); 123 | LBL_KRON_0: 124 | mp_clear(&a1); 125 | 126 | return err; 127 | } 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libtommath 2 | 3 | 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. 4 | 5 | ## Build Status 6 | 7 | ### Travis CI 8 | 9 | master: [![Build Status](https://github.com/libtom/libtommath/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/libtom/libtommath/actions/workflows/main.yml?query=branch%3Amaster+++) 10 | 11 | develop: [![Build Status](https://github.com/libtom/libtommath/actions/workflows/main.yml/badge.svg?branch=develop)](https://github.com/libtom/libtommath/actions/workflows/main.yml?query=branch%3Adevelop+++) 12 | 13 | ### AppVeyor 14 | 15 | master: [![Build status](https://ci.appveyor.com/api/projects/status/b80lpolw3i8m6hsh/branch/master?svg=true)](https://ci.appveyor.com/project/libtom/libtommath/branch/master) 16 | 17 | develop: [![Build status](https://ci.appveyor.com/api/projects/status/b80lpolw3i8m6hsh/branch/develop?svg=true)](https://ci.appveyor.com/project/libtom/libtommath/branch/develop) 18 | 19 | ### ABI Laboratory 20 | 21 | API/ABI changes: [check here](https://abi-laboratory.pro/tracker/timeline/libtommath/) 22 | 23 | ### Pre-built packages 24 | 25 | We sometimes upload `deb` packages of the latest state from the develop branch to [packagecloud.io](https://packagecloud.io/libtom/packages). 26 | 27 | Use those packages with caution and at your own discretion. 28 | 29 | ## Summary 30 | 31 | The `develop` branch contains the in-development version. Stable releases are tagged. 32 | 33 | Documentation is built from the LaTeX file `doc/bn.tex` and available as PDF for each release. 34 | This PDF is also created as build artifact on each CI run. 35 | 36 | There is also limited documentation in `tommath.h`. 37 | 38 | Originally the library contained a document, `tommath.pdf`, which describes the goals of the project and many of the algorithms used at the time. 39 | This document has been removed since it can't be built anymore and nobody spent the time to fix and update it. 40 | The latest valid update to that document was done in version [`0.39`](https://github.com/libtom/libtommath/releases/tag/0.39) of the library and it is contained within that tarball. 41 | 42 | The project can be build by using `make`. Along with the usual `make`, `make clean` and `make install`, 43 | there are several other build targets, see the makefile for details. 44 | There are also makefiles for certain specific platforms. 45 | 46 | ## Testing 47 | 48 | Tests are located in `demo/` and can be built in two flavors. 49 | * `make test` creates a stand-alone test binary that executes several test routines. 50 | * `make mtest_opponent` creates a test binary that is intended to be run against `mtest`. 51 | `mtest` can be built with `make mtest` and test execution is done like `./mtest/mtest | ./mtest_opponent`. 52 | `mtest` is creating test vectors using an alternative MPI library and `test` is consuming these vectors to verify correct behavior of ltm 53 | 54 | ## Building and Installing 55 | 56 | Building is straightforward for GNU Linux only, the section "Building LibTomMath" in the documentation in `doc/bn.pdf` has the details. 57 | 58 | ### CMake support 59 | 60 | The project provides support for the CMake build system. 61 | 62 | ``` 63 | git clone https://github.com/libtom/libtommath.git 64 | mkdir -p libtommath/build 65 | cd libtommath/build 66 | cmake .. 67 | make -j$(nproc) 68 | ``` 69 | 70 | A shared library build can be done by setting `-DBUILD_SHARED_LIBS=On` when invoking the `cmake` command. 71 | --------------------------------------------------------------------------------