diff --git a/demo/test.c b/demo/test.c
index 838f0eddf..4a728f7f2 100644
--- a/demo/test.c
+++ b/demo/test.c
@@ -2326,7 +2326,61 @@ static int test_mp_radix_size(void)
return EXIT_FAILURE;
}
+static int test_mp_radix_size_overestimate(void)
+{
+
+ mp_err err;
+ mp_int a;
+ int radix;
+ size_t size;
+/* *INDENT-OFF* */
+ size_t results[65] = {
+ 0u, 0u, 1627u, 1027u, 814u, 702u, 630u, 581u, 543u,
+ 514u, 491u, 471u, 455u, 441u, 428u, 418u, 408u, 399u,
+ 391u, 384u, 378u, 372u, 366u, 361u, 356u, 352u, 347u,
+ 343u, 340u, 336u, 333u, 330u, 327u, 324u, 321u, 318u,
+ 316u, 314u, 311u, 309u, 307u, 305u, 303u, 301u, 299u,
+ 298u, 296u, 294u, 293u, 291u, 290u, 288u, 287u, 285u,
+ 284u, 283u, 281u, 280u, 279u, 278u, 277u, 276u, 275u,
+ 273u, 272u
+ };
+/* *INDENT-ON* */
+
+ mp_init(&a);
+
+ /* number to result in a different size for every base: 67^(4 * 67) */
+ mp_set(&a, 67);
+ if ((err = mp_expt_u32(&a, 268u, &a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ for (radix = 2; radix < 65; radix++) {
+ if ((err = mp_radix_size_overestimate(&a, radix, &size)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (size < results[radix]) {
+ fprintf(stderr, "mp_radix_size_overestimate: result for base %d was %zu instead of %zu\n",
+ radix, size, results[radix]);
+ goto LTM_ERR;
+ }
+ a.sign = MP_NEG;
+ if ((err = mp_radix_size_overestimate(&a, radix, &size)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (size < results[radix]) {
+ fprintf(stderr, "mp_radix_size_overestimate: result for base %d was %zu instead of %zu\n",
+ radix, size, results[radix]);
+ goto LTM_ERR;
+ }
+ a.sign = MP_ZPOS;
+ }
+
+ mp_clear(&a);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear(&a);
+ return EXIT_FAILURE;
+}
static int test_mp_read_write_ubin(void)
{
@@ -2493,6 +2547,7 @@ static int unit_tests(int argc, char **argv)
T1(mp_reduce_2k, MP_REDUCE_2K),
T1(mp_reduce_2k_l, MP_REDUCE_2K_L),
T1(mp_radix_size, MP_RADIX_SIZE),
+ T1(mp_radix_size_overestimate, MP_RADIX_SIZE_OVERESTIMATE),
#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559)
T1(mp_set_double, MP_SET_DOUBLE),
#endif
diff --git a/libtommath_VS2008.vcproj b/libtommath_VS2008.vcproj
index d59f71cbd..b0196fb86 100644
--- a/libtommath_VS2008.vcproj
+++ b/libtommath_VS2008.vcproj
@@ -684,6 +684,10 @@
RelativePath="mp_radix_size.c"
>
+
+
diff --git a/makefile b/makefile
index f713a8596..9a355d32e 100644
--- a/makefile
+++ b/makefile
@@ -39,17 +39,17 @@ mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o
mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \
mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \
mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_prime_tab.o \
-mp_radix_size.o mp_radix_smap.o mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o \
-mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o \
-mp_root_u32.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o \
-mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o mp_shrink.o mp_signed_rsh.o mp_sqr.o \
-mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o \
-mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_xor.o mp_zero.o s_mp_add.o s_mp_balance_mul.o s_mp_exptmod.o \
-s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod_fast.o s_mp_invmod_slow.o s_mp_karatsuba_mul.o \
-s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o s_mp_montgomery_reduce_fast.o s_mp_mul_digs.o \
-s_mp_mul_digs_fast.o s_mp_mul_high_digs.o s_mp_mul_high_digs_fast.o s_mp_prime_is_divisible.o \
-s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_reverse.o s_mp_sqr.o s_mp_sqr_fast.o s_mp_sub.o \
-s_mp_toom_mul.o s_mp_toom_sqr.o
+mp_radix_size.o mp_radix_size_overestimate.o mp_radix_smap.o mp_rand.o mp_read_radix.o mp_reduce.o \
+mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o \
+mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_u32.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o \
+mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o \
+mp_shrink.o mp_signed_rsh.o mp_sqr.o mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o \
+mp_submod.o mp_to_radix.o mp_to_sbin.o mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_xor.o mp_zero.o s_mp_add.o \
+s_mp_balance_mul.o s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod_fast.o \
+s_mp_invmod_slow.o s_mp_karatsuba_mul.o s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o \
+s_mp_montgomery_reduce_fast.o s_mp_mul_digs.o s_mp_mul_digs_fast.o s_mp_mul_high_digs.o \
+s_mp_mul_high_digs_fast.o s_mp_prime_is_divisible.o s_mp_rand_jenkins.o s_mp_rand_platform.o \
+s_mp_reverse.o s_mp_sqr.o s_mp_sqr_fast.o s_mp_sub.o s_mp_toom_mul.o s_mp_toom_sqr.o
#END_INS
diff --git a/makefile.mingw b/makefile.mingw
index c3a680fd8..99616b4a9 100644
--- a/makefile.mingw
+++ b/makefile.mingw
@@ -42,17 +42,17 @@ mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o
mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \
mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \
mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_prime_tab.o \
-mp_radix_size.o mp_radix_smap.o mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o \
-mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o \
-mp_root_u32.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o \
-mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o mp_shrink.o mp_signed_rsh.o mp_sqr.o \
-mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o \
-mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_xor.o mp_zero.o s_mp_add.o s_mp_balance_mul.o s_mp_exptmod.o \
-s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod_fast.o s_mp_invmod_slow.o s_mp_karatsuba_mul.o \
-s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o s_mp_montgomery_reduce_fast.o s_mp_mul_digs.o \
-s_mp_mul_digs_fast.o s_mp_mul_high_digs.o s_mp_mul_high_digs_fast.o s_mp_prime_is_divisible.o \
-s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_reverse.o s_mp_sqr.o s_mp_sqr_fast.o s_mp_sub.o \
-s_mp_toom_mul.o s_mp_toom_sqr.o
+mp_radix_size.o mp_radix_size_overestimate.o mp_radix_smap.o mp_rand.o mp_read_radix.o mp_reduce.o \
+mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o \
+mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_u32.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o \
+mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o \
+mp_shrink.o mp_signed_rsh.o mp_sqr.o mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o \
+mp_submod.o mp_to_radix.o mp_to_sbin.o mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_xor.o mp_zero.o s_mp_add.o \
+s_mp_balance_mul.o s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod_fast.o \
+s_mp_invmod_slow.o s_mp_karatsuba_mul.o s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o \
+s_mp_montgomery_reduce_fast.o s_mp_mul_digs.o s_mp_mul_digs_fast.o s_mp_mul_high_digs.o \
+s_mp_mul_high_digs_fast.o s_mp_prime_is_divisible.o s_mp_rand_jenkins.o s_mp_rand_platform.o \
+s_mp_reverse.o s_mp_sqr.o s_mp_sqr_fast.o s_mp_sub.o s_mp_toom_mul.o s_mp_toom_sqr.o
HEADERS_PUB=tommath.h
HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB)
diff --git a/makefile.msvc b/makefile.msvc
index 9a13ffede..b07f261a1 100644
--- a/makefile.msvc
+++ b/makefile.msvc
@@ -34,17 +34,17 @@ mp_montgomery_calc_normalization.obj mp_montgomery_reduce.obj mp_montgomery_setu
mp_mul_2d.obj mp_mul_d.obj mp_mulmod.obj mp_neg.obj mp_or.obj mp_pack.obj mp_pack_count.obj mp_prime_fermat.obj \
mp_prime_frobenius_underwood.obj mp_prime_is_prime.obj mp_prime_miller_rabin.obj mp_prime_next_prime.obj \
mp_prime_rabin_miller_trials.obj mp_prime_rand.obj mp_prime_strong_lucas_selfridge.obj mp_prime_tab.obj \
-mp_radix_size.obj mp_radix_smap.obj mp_rand.obj mp_read_radix.obj mp_reduce.obj mp_reduce_2k.obj mp_reduce_2k_l.obj \
-mp_reduce_2k_setup.obj mp_reduce_2k_setup_l.obj mp_reduce_is_2k.obj mp_reduce_is_2k_l.obj mp_reduce_setup.obj \
-mp_root_u32.obj mp_rshd.obj mp_sbin_size.obj mp_set.obj mp_set_double.obj mp_set_i32.obj mp_set_i64.obj mp_set_l.obj \
-mp_set_ll.obj mp_set_u32.obj mp_set_u64.obj mp_set_ul.obj mp_set_ull.obj mp_shrink.obj mp_signed_rsh.obj mp_sqr.obj \
-mp_sqrmod.obj mp_sqrt.obj mp_sqrtmod_prime.obj mp_sub.obj mp_sub_d.obj mp_submod.obj mp_to_radix.obj mp_to_sbin.obj \
-mp_to_ubin.obj mp_ubin_size.obj mp_unpack.obj mp_xor.obj mp_zero.obj s_mp_add.obj s_mp_balance_mul.obj s_mp_exptmod.obj \
-s_mp_exptmod_fast.obj s_mp_get_bit.obj s_mp_invmod_fast.obj s_mp_invmod_slow.obj s_mp_karatsuba_mul.obj \
-s_mp_karatsuba_sqr.obj s_mp_log.obj s_mp_log_d.obj s_mp_montgomery_reduce_fast.obj s_mp_mul_digs.obj \
-s_mp_mul_digs_fast.obj s_mp_mul_high_digs.obj s_mp_mul_high_digs_fast.obj s_mp_prime_is_divisible.obj \
-s_mp_rand_jenkins.obj s_mp_rand_platform.obj s_mp_reverse.obj s_mp_sqr.obj s_mp_sqr_fast.obj s_mp_sub.obj \
-s_mp_toom_mul.obj s_mp_toom_sqr.obj
+mp_radix_size.obj mp_radix_size_overestimate.obj mp_radix_smap.obj mp_rand.obj mp_read_radix.obj mp_reduce.obj \
+mp_reduce_2k.obj mp_reduce_2k_l.obj mp_reduce_2k_setup.obj mp_reduce_2k_setup_l.obj mp_reduce_is_2k.obj \
+mp_reduce_is_2k_l.obj mp_reduce_setup.obj mp_root_u32.obj mp_rshd.obj mp_sbin_size.obj mp_set.obj mp_set_double.obj \
+mp_set_i32.obj mp_set_i64.obj mp_set_l.obj mp_set_ll.obj mp_set_u32.obj mp_set_u64.obj mp_set_ul.obj mp_set_ull.obj \
+mp_shrink.obj mp_signed_rsh.obj mp_sqr.obj mp_sqrmod.obj mp_sqrt.obj mp_sqrtmod_prime.obj mp_sub.obj mp_sub_d.obj \
+mp_submod.obj mp_to_radix.obj mp_to_sbin.obj mp_to_ubin.obj mp_ubin_size.obj mp_unpack.obj mp_xor.obj mp_zero.obj s_mp_add.obj \
+s_mp_balance_mul.obj s_mp_exptmod.obj s_mp_exptmod_fast.obj s_mp_get_bit.obj s_mp_invmod_fast.obj \
+s_mp_invmod_slow.obj s_mp_karatsuba_mul.obj s_mp_karatsuba_sqr.obj s_mp_log.obj s_mp_log_d.obj \
+s_mp_montgomery_reduce_fast.obj s_mp_mul_digs.obj s_mp_mul_digs_fast.obj s_mp_mul_high_digs.obj \
+s_mp_mul_high_digs_fast.obj s_mp_prime_is_divisible.obj s_mp_rand_jenkins.obj s_mp_rand_platform.obj \
+s_mp_reverse.obj s_mp_sqr.obj s_mp_sqr_fast.obj s_mp_sub.obj s_mp_toom_mul.obj s_mp_toom_sqr.obj
HEADERS_PUB=tommath.h
HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB)
diff --git a/makefile.shared b/makefile.shared
index 336d648d9..2ad1394c3 100644
--- a/makefile.shared
+++ b/makefile.shared
@@ -36,17 +36,17 @@ mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o
mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \
mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \
mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_prime_tab.o \
-mp_radix_size.o mp_radix_smap.o mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o \
-mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o \
-mp_root_u32.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o \
-mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o mp_shrink.o mp_signed_rsh.o mp_sqr.o \
-mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o \
-mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_xor.o mp_zero.o s_mp_add.o s_mp_balance_mul.o s_mp_exptmod.o \
-s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod_fast.o s_mp_invmod_slow.o s_mp_karatsuba_mul.o \
-s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o s_mp_montgomery_reduce_fast.o s_mp_mul_digs.o \
-s_mp_mul_digs_fast.o s_mp_mul_high_digs.o s_mp_mul_high_digs_fast.o s_mp_prime_is_divisible.o \
-s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_reverse.o s_mp_sqr.o s_mp_sqr_fast.o s_mp_sub.o \
-s_mp_toom_mul.o s_mp_toom_sqr.o
+mp_radix_size.o mp_radix_size_overestimate.o mp_radix_smap.o mp_rand.o mp_read_radix.o mp_reduce.o \
+mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o \
+mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_u32.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o \
+mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o \
+mp_shrink.o mp_signed_rsh.o mp_sqr.o mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o \
+mp_submod.o mp_to_radix.o mp_to_sbin.o mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_xor.o mp_zero.o s_mp_add.o \
+s_mp_balance_mul.o s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod_fast.o \
+s_mp_invmod_slow.o s_mp_karatsuba_mul.o s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o \
+s_mp_montgomery_reduce_fast.o s_mp_mul_digs.o s_mp_mul_digs_fast.o s_mp_mul_high_digs.o \
+s_mp_mul_high_digs_fast.o s_mp_prime_is_divisible.o s_mp_rand_jenkins.o s_mp_rand_platform.o \
+s_mp_reverse.o s_mp_sqr.o s_mp_sqr_fast.o s_mp_sub.o s_mp_toom_mul.o s_mp_toom_sqr.o
#END_INS
diff --git a/makefile.unix b/makefile.unix
index 9a35dee8e..4ee0b4c62 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -43,17 +43,18 @@ mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o
mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \
mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \
mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_prime_tab.o \
-mp_radix_size.o mp_radix_smap.o mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o \
-mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o \
-mp_root_u32.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o \
-mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o mp_shrink.o mp_signed_rsh.o mp_sqr.o \
-mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o \
-mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_xor.o mp_zero.o s_mp_add.o s_mp_balance_mul.o s_mp_exptmod.o \
-s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod_fast.o s_mp_invmod_slow.o s_mp_karatsuba_mul.o \
-s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o s_mp_montgomery_reduce_fast.o s_mp_mul_digs.o \
-s_mp_mul_digs_fast.o s_mp_mul_high_digs.o s_mp_mul_high_digs_fast.o s_mp_prime_is_divisible.o \
-s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_reverse.o s_mp_sqr.o s_mp_sqr_fast.o s_mp_sub.o \
-s_mp_toom_mul.o s_mp_toom_sqr.o
+mp_radix_size.o mp_radix_size_overestimate.o mp_radix_smap.o mp_rand.o mp_read_radix.o mp_reduce.o \
+mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o \
+mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_u32.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o \
+mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o \
+mp_shrink.o mp_signed_rsh.o mp_sqr.o mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o \
+mp_submod.o mp_to_radix.o mp_to_sbin.o mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_xor.o mp_zero.o s_mp_add.o \
+s_mp_balance_mul.o s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod_fast.o \
+s_mp_invmod_slow.o s_mp_karatsuba_mul.o s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o \
+s_mp_montgomery_reduce_fast.o s_mp_mul_digs.o s_mp_mul_digs_fast.o s_mp_mul_high_digs.o \
+s_mp_mul_high_digs_fast.o s_mp_prime_is_divisible.o s_mp_rand_jenkins.o s_mp_rand_platform.o \
+s_mp_reverse.o s_mp_sqr.o s_mp_sqr_fast.o s_mp_sub.o s_mp_toom_mul.o s_mp_toom_sqr.o
+
HEADERS_PUB=tommath.h
HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB)
diff --git a/mp_fwrite.c b/mp_fwrite.c
index be78f7f28..1b7965443 100644
--- a/mp_fwrite.c
+++ b/mp_fwrite.c
@@ -10,9 +10,14 @@ mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream)
mp_err err;
size_t len, written;
- /* TODO: this function is not in this PR */
- if ((err = mp_radix_size(a, radix, &len)) != MP_OKAY) {
- return err;
+ if (MP_HAS(MP_RADIX_SIZE_OVERESTIMATE)) {
+ if ((err = mp_radix_size_overestimate(a, radix, &len)) != MP_OKAY) {
+ return err;
+ }
+ } else {
+ if ((err = mp_radix_size(a, radix, &len)) != MP_OKAY) {
+ return err;
+ }
}
buf = (char *) MP_MALLOC(len);
diff --git a/mp_radix_size_overestimate.c b/mp_radix_size_overestimate.c
new file mode 100644
index 000000000..f36daacd4
--- /dev/null
+++ b/mp_radix_size_overestimate.c
@@ -0,0 +1,187 @@
+#include "tommath_private.h"
+#ifdef MP_RADIX_SIZE_OVERESTIMATE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+
+
+/* returns size of ASCII representation */
+
+/*
+ Tables of {0, log_2([1..64])} times 2^p where p is the scale
+ factor defined in LTM_RADIX_SIZE_SCALE.
+
+ The tables have been computed with GP/PARI 2.9.4 with the
+ x86-64/GMP-5.1.3 kernel and (unnecessary) 100 decimal digits
+ precision. The fractional parts of the results after the
+ multiplication by 2^p have been discarded (floor(x)).
+
+ The number that measures the number of the digits of the bignum is
+ of type "int" which is at least 16 bits large and is 32 bit on the
+ architectures common at the time of writing. If you have hard- or
+ software that has a different size, please feel free to contact the
+ author, adding another table can be done quite quickly!
+ */
+/* *INDENT-OFF* */
+#if (defined MP_16BIT)
+#define LTM_RADIX_SIZE_SCALE 61
+#define LTM_RADIX_SIZE_HALF_TABLE_SCALE 32
+static const mp_word logbases_high[65] = {
+ 0ul, 0ul, 536870912ul, 850920263ul, 1073741824ul,
+ 1246575653ul, 1387791175ul, 1507187197ul, 1610612736ul, 1701840526ul,
+ 1783446565ul, 1857268208ul, 1924662087ul, 1986658446ul, 2044058109ul,
+ 2097495917ul, 2147483648ul, 2194439903ul, 2238711438ul, 2280588718ul,
+ 2320317477ul, 2358107460ul, 2394139120ul, 2428568832ul, 2461532999ul,
+ 2493151307ul, 2523529358ul, 2552760789ul, 2580929021ul, 2608108687ul,
+ 2634366829ul, 2659763891ul, 2684354560ul, 2708188471ul, 2731310815ul,
+ 2753762851ul, 2775582350ul, 2796803979ul, 2817459630ul, 2837578709ul,
+ 2857188389ul, 2876313830ul, 2894978372ul, 2913203707ul, 2931010032ul,
+ 2948416180ul, 2965439744ul, 2982097182ul, 2998403911ul, 3014374394ul,
+ 3030022219ul, 3045360166ul, 3060400270ul, 3075153878ul, 3089631701ul,
+ 3103843862ul, 3117799933ul, 3131508981ul, 3144979599ul, 3158219938ul,
+ 3171237741ul, 3184040363ul, 3196634803ul, 3209027723ul, 3221225472ul
+};
+static const mp_word logbases_low[65] = {
+ 0ul, 0ul, 0ul, 1065013491ul, 0ul,
+ 3868050815ul, 1065013491ul, 1343271782ul, 0ul, 2130026983ul,
+ 3868050815ul, 427100031ul, 1065013491ul, 1200147405ul, 1343271782ul,
+ 638097011ul, 0ul, 1495425743ul, 2130026983ul, 1083835016ul,
+ 3868050815ul, 2408285274ul, 427100031ul, 3594167896ul, 1065013491ul,
+ 3441134334ul, 1200147405ul, 3195040475ul, 1343271782ul, 1429396043ul,
+ 638097011ul, 1651143338ul, 0ul, 1492113523ul, 1495425743ul,
+ 916355301ul, 2130026983ul, 1832592635ul, 1083835016ul, 2265160897ul,
+ 3868050815ul, 3464916779ul, 2408285274ul, 2621526098ul, 427100031ul,
+ 1703110503ul, 3594167896ul, 2513440227ul, 1065013491ul, 2686543564ul,
+ 3441134334ul, 2560439235ul, 1200147405ul, 1309103046ul, 3195040475ul,
+ 183550ul, 1343271782ul, 2148848508ul, 1429396043ul, 3785381171ul,
+ 638097011ul, 1073048670ul, 1651143338ul, 3473298766ul, 0ul
+};
+/* TODO: This assumes the type "long long" exists. If it doesn't: use the tables for MP_16BIT */
+#elif ( (defined MP_28BIT) || (defined MP_31BIT) || (defined MP_32BIT) || (defined MP_64BIT) )
+#define LTM_RADIX_SIZE_SCALE 61
+#ifdef MP_64BIT
+static const mp_digit logbases[65] = {
+#else
+static const mp_word logbases[65] = {
+#endif
+ 0ull, 0ull, 2305843009213693952ull,
+ 3654674702153732339ull, 4611686018427387904ull, 5354001665492895103ull,
+ 5960517711367426291ull, 6473319721408181094ull, 6917529027641081856ull,
+ 7309349404307464679ull, 7659844674706589055ull, 7976906213687625599ull,
+ 8266360720581120243ull, 8532633055092329421ull, 8779162730621875046ull,
+ 9008676367646627443ull, 9223372036854775808ull, 9425047617917838031ull,
+ 9615192413521158631ull, 9795053960520401544ull, 9965687683920283007ull,
+ 10127994423561913434ull, 10282749222901319551ull, 10430623713119086168ull,
+ 10572203729794814195ull, 10708003330985790206ull, 10838476064306023373ull,
+ 10964024106461197019ull, 11085005739835568998ull, 11201741516507896395ull,
+ 11314519376860321395ull, 11423598928577852074ull, 11529215046068469760ull,
+ 11631580915841357939ull, 11730890627131531983ull, 11827321386901076197ull,
+ 11921035422734852583ull, 12012181624960263419ull, 12100896969734095496ull,
+ 12187307757246061761ull, 12271530693133976959ull, 12353673836347420459ull,
+ 12433837432775607386ull, 12512114650772492370ull, 12588592232115013503ull,
+ 12663351069800359783ull, 12736466722332780120ull, 12808009872697200099ull,
+ 12878046739008508147ull, 12946639442816362188ull, 13013846340199484158ull,
+ 13079722320071570371ull, 13144319073519717325ull, 13207685337486676934ull,
+ 13269867115674890971ull, 13330907879180520702ull, 13390848749049262950ull,
+ 13449728662674133884ull, 13507584525721590347ull, 13564451351070528819ull,
+ 13620362386074015347ull, 13675349229302017118ull, 13729441937791546026ull,
+ 13782669125715645774ull, 13835058055282163712ull
+};
+#else
+# ifdef _MSC_VER
+# pragma message("mp_radix_size_overestimate: unknown or undefined MP_xBIT type")
+# else
+# warning "mp_radix_size_overestimate: unknown or undefined MP_xBIT type"
+# endif
+#endif
+/* *INDENT-ON* */
+
+mp_err mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size)
+{
+ mp_int bi_bit_count, bi_k;
+#ifdef MP_16BIT
+ mp_int bi_k_bis;
+#endif
+ int bit_count;
+ mp_err err = MP_OKAY;
+
+ *size = 0u;
+
+ if ((radix < 2) || (radix > 64)) {
+ return MP_VAL;
+ }
+
+ if (a->used == 0) {
+ *size = 2u;
+ return MP_OKAY;
+ }
+
+ bit_count = mp_count_bits(a);
+
+ /* A small shortcut for powers of two. */
+ if (!(radix&(radix-1))) {
+ unsigned int x = (unsigned int)radix;
+ int y, t;
+ for (y=0; (y < 7) && !(x & 1u); y++) {
+ x >>= 1;
+ }
+ t = bit_count/y;
+ bit_count = bit_count - (t * y);
+ /* Add 1 for the remainder if any and 1 for "\0". */
+ t += ((bit_count == 0) ? 1 : 2) + (a->sign == MP_NEG);
+ *size = (size_t)t;
+ return MP_OKAY;
+ }
+
+ /* d(bitcount,radix) = floor( (bitcount * 2^p) / k(radix) ) + 1 */
+
+ if ((err = mp_init_multi(&bi_bit_count, &bi_k, NULL)) != MP_OKAY) {
+ return err;
+ }
+#ifdef MP_16BIT
+ if ((err = mp_init(&bi_k_bis)) != MP_OKAY) {
+ /* No "goto" to avoid cluttering this code with even more preprocessor branches */
+ mp_clear_multi(&bi_bit_count, &bi_k, NULL);
+ return err;
+ }
+#endif
+ /* "long" is at least as large as "int" according to even the oldest C standards */
+ mp_set_l(&bi_bit_count, bit_count);
+#ifdef MP_16BIT
+ mp_set_u32(&bi_k, logbases_high[radix]);
+ if ((err = mp_mul_2d(&bi_k, LTM_RADIX_SIZE_HALF_TABLE_SCALE, &bi_k)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ mp_set_u32(&bi_k_bis, logbases_low[radix]);
+ if ((err = mp_add(&bi_k_bis, &bi_k, &bi_k)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+#else
+ mp_set_u64(&bi_k, logbases[radix]);
+#endif
+ if ((err = mp_mul_2d(&bi_bit_count, LTM_RADIX_SIZE_SCALE, &bi_bit_count)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = mp_div(&bi_bit_count, &bi_k, &bi_bit_count, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ /*
+ The first addition of one is done because of the truncating division,
+ and the second addition of one is for NIL ('\0').
+
+ Casting from "long" to "int" can be done because "bi_bit_count" fits into an "int"
+ by definition.
+ */
+ *size = (size_t)mp_get_l(&bi_bit_count) + 1 + 1 + (a->sign == MP_NEG);
+
+LTM_ERR:
+ mp_clear_multi(&bi_bit_count, &bi_k, NULL);
+#ifdef MP_16BIT
+ mp_clear(&bi_k_bis);
+#endif
+ return err;
+}
+
+
+
+#endif
diff --git a/tommath.def b/tommath.def
index 7c241bc75..abd533099 100644
--- a/tommath.def
+++ b/tommath.def
@@ -99,6 +99,7 @@ EXPORTS
mp_prime_strong_lucas_selfridge
mp_prime_tab
mp_radix_size
+ mp_radix_size_overestimate
mp_rand
mp_read_radix
mp_reduce
diff --git a/tommath.h b/tommath.h
index a401be471..5daf950d0 100644
--- a/tommath.h
+++ b/tommath.h
@@ -588,7 +588,10 @@ mp_err mp_to_sbin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *wr
mp_err mp_read_radix(mp_int *a, const char *str, int radix) MP_WUR;
mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix) MP_WUR;
+
mp_err mp_radix_size(const mp_int *a, int radix, size_t *size) MP_WUR;
+mp_err mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size) MP_WUR;
+
#ifndef MP_NO_FILE
mp_err mp_fread(mp_int *a, int radix, FILE *stream) MP_WUR;
diff --git a/tommath_class.h b/tommath_class.h
index f7812da01..1e633efe1 100644
--- a/tommath_class.h
+++ b/tommath_class.h
@@ -104,6 +104,7 @@
# define MP_PRIME_STRONG_LUCAS_SELFRIDGE_C
# define MP_PRIME_TAB_C
# define MP_RADIX_SIZE_C
+# define MP_RADIX_SIZE_OVERESTIMATE_C
# define MP_RADIX_SMAP_C
# define MP_RAND_C
# define MP_READ_RADIX_C
@@ -370,6 +371,7 @@
#if defined(MP_FWRITE_C)
# define MP_RADIX_SIZE_C
+# define MP_RADIX_SIZE_OVERESTIMATE_C
# define MP_TO_RADIX_C
#endif
@@ -749,6 +751,17 @@
# define MP_LOG_U32_C
#endif
+#if defined(MP_RADIX_SIZE_OVERESTIMATE_C)
+# define MP_CLEAR_MULTI_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_C
+# define MP_GET_L_C
+# define MP_INIT_MULTI_C
+# define MP_MUL_2D_C
+# define MP_SET_L_C
+# define MP_SET_U64_C
+#endif
+
#if defined(MP_RADIX_SMAP_C)
#endif