diff --git a/demo/test.c b/demo/test.c
index 838f0eddf..61a220c08 100644
--- a/demo/test.c
+++ b/demo/test.c
@@ -1524,8 +1524,8 @@ static int test_mp_reduce_2k_l(void)
return EXIT_SUCCESS;
# endif /* LTM_DEMO_TEST_REDUCE_2K_L */
}
-/* stripped down version of mp_radix_size. The faster version can be off by up t
-o +3 */
+
+/* stripped down version of mp_radix_size. The faster version can be off by up to +3 */
/* TODO: This function should be removed, replaced by mp_radix_size, mp_radix_size_overestimate in 2.0 */
static mp_err s_rs(const mp_int *a, int radix, uint32_t *size)
{
@@ -2279,14 +2279,14 @@ static int test_mp_radix_size(void)
size_t size;
/* *INDENT-OFF* */
size_t results[65] = {
- 0, 0, 1627, 1027, 814, 702, 630, 581, 543,
- 514, 491, 471, 455, 441, 428, 418, 408, 399,
- 391, 384, 378, 372, 366, 361, 356, 352, 347,
- 343, 340, 336, 333, 330, 327, 324, 321, 318,
- 316, 314, 311, 309, 307, 305, 303, 301, 299,
- 298, 296, 294, 293, 291, 290, 288, 287, 285,
- 284, 283, 281, 280, 279, 278, 277, 276, 275,
- 273, 272
+ 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* */
@@ -2326,8 +2326,6 @@ static int test_mp_radix_size(void)
return EXIT_FAILURE;
}
-
-
static int test_mp_read_write_ubin(void)
{
mp_int a, b, c;
diff --git a/libtommath_VS2008.vcproj b/libtommath_VS2008.vcproj
index d59f71cbd..0e49d6f3e 100644
--- a/libtommath_VS2008.vcproj
+++ b/libtommath_VS2008.vcproj
@@ -888,6 +888,10 @@
RelativePath="s_mp_log_d.c"
>
+
+
@@ -912,6 +916,10 @@
RelativePath="s_mp_prime_is_divisible.c"
>
+
+
diff --git a/makefile b/makefile
index f713a8596..da5092783 100644
--- a/makefile
+++ b/makefile
@@ -46,10 +46,10 @@ mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o mp_shrink.o mp_si
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
+s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o s_mp_log_power_of_two.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_radix_size_radix_10.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..5d8e99147 100644
--- a/makefile.mingw
+++ b/makefile.mingw
@@ -49,10 +49,10 @@ mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o mp_shrink.o mp_si
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
+s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o s_mp_log_power_of_two.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_radix_size_radix_10.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..071432de5 100644
--- a/makefile.msvc
+++ b/makefile.msvc
@@ -41,10 +41,10 @@ mp_set_ll.obj mp_set_u32.obj mp_set_u64.obj mp_set_ul.obj mp_set_ull.obj mp_shri
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
+s_mp_karatsuba_sqr.obj s_mp_log.obj s_mp_log_d.obj s_mp_log_power_of_two.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_radix_size_radix_10.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..6993e18ab 100644
--- a/makefile.shared
+++ b/makefile.shared
@@ -43,10 +43,10 @@ mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o mp_shrink.o mp_si
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
+s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o s_mp_log_power_of_two.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_radix_size_radix_10.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..1e9cc36f6 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -50,10 +50,10 @@ mp_set_ll.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_set_ull.o mp_shrink.o mp_si
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
+s_mp_karatsuba_sqr.o s_mp_log.o s_mp_log_d.o s_mp_log_power_of_two.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_radix_size_radix_10.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_radix_size.c b/mp_radix_size.c
index 6c3e58220..2f2c2233e 100644
--- a/mp_radix_size.c
+++ b/mp_radix_size.c
@@ -6,10 +6,13 @@
/* returns size of ASCII representation */
mp_err mp_radix_size(const mp_int *a, int radix, size_t *size)
{
+
mp_err err;
mp_int a_;
uint32_t b;
+ *size = 0;
+
/* make sure the radix is in range */
if ((radix < 2) || (radix > 64)) {
return MP_VAL;
@@ -20,6 +23,10 @@ mp_err mp_radix_size(const mp_int *a, int radix, size_t *size)
return MP_OKAY;
}
+ if (radix == 10) {
+ return s_mp_radix_size_radix_10(a, size);
+ }
+
a_ = *a;
a_.sign = MP_ZPOS;
if ((err = mp_log_u32(&a_, (uint32_t)radix, &b)) != MP_OKAY) {
@@ -29,6 +36,11 @@ mp_err mp_radix_size(const mp_int *a, int radix, size_t *size)
/* mp_ilogb truncates to zero, hence we need one extra put on top and one for `\0`. */
*size = (size_t)b + 2U + ((a->sign == MP_NEG) ? 1U : 0U);
+ /* This can overflow for e.g.: radix = 2 and bit_count >= 2147483645 with a 32 bit "int" */
+ if (*size > (size_t)(INT_MAX - 3)) {
+ return MP_VAL;
+ }
+
LBL_ERR:
return err;
}
diff --git a/s_mp_log_power_of_two.c b/s_mp_log_power_of_two.c
new file mode 100644
index 000000000..bc16db6a5
--- /dev/null
+++ b/s_mp_log_power_of_two.c
@@ -0,0 +1,19 @@
+#include "tommath_private.h"
+#ifdef S_MP_LOG_POWER_OF_TWO_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+
+
+int s_mp_log_power_of_two(const mp_int *a, int p_of_2)
+{
+ int x, bit_count;
+ for (x = 0; (x < 7) && !((unsigned int)p_of_2 & 1u); x++) {
+ p_of_2 >>= 1;
+ }
+ bit_count = mp_count_bits(a) - 1;
+ return (bit_count/x);
+}
+
+
+#endif
diff --git a/s_mp_radix_size_radix_10.c b/s_mp_radix_size_radix_10.c
new file mode 100644
index 000000000..93ba6973b
--- /dev/null
+++ b/s_mp_radix_size_radix_10.c
@@ -0,0 +1,65 @@
+#include "tommath_private.h"
+#ifdef S_MP_RADIX_SIZE_RADIX_10_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#define LTM_RADIX_SIZE_SCALE 64
+int s_mp_radix_size_radix_10(const mp_int *a, size_t *size)
+{
+ mp_err err;
+ /*
+ floor(2^64/log_2(10)) = 5553023288523357132
+
+ We need that much precision. Example:
+
+ log_2(x) = log(x)/log(2)
+ 198096465/log_2(10) = 59632978.000000002598316594477929217520
+
+ Which are more than 16 decimal digits, so with BINARY_64 (C's "double")
+ a 'ceil(198096465/log_2(10))' would result wrongly in 59632978.0.
+ */
+ mp_int bi_bit_count, bi_k, t;
+ int bit_count;
+
+#ifdef MP_16BIT
+#define LTM_RADIX_SIZE_CONST_SHIFT 32
+ const uint32_t inv_log_2_10[2] = {0x4d104d42UL, 0x7de7fbccUL};
+#endif
+ if ((err = mp_init_multi(&bi_bit_count, &bi_k, &t, NULL)) != MP_OKAY) {
+ return err;
+ }
+#ifdef MP_16BIT
+ mp_set_u32(&t, inv_log_2_10[0]);
+ if ((err = mp_mul_2d(&bi_k, LTM_RADIX_SIZE_CONST_SHIFT, &bi_k)) != MP_OKAY) {
+ goto LTM_E1;
+ }
+ if ((err = mp_add(&bi_k, &t, &bi_k)) != MP_OKAY) {
+ goto LTM_E1;
+ }
+ mp_set_u32(&t, inv_log_2_10[1]);
+ if ((err = mp_mul_2d(&bi_k, LTM_RADIX_SIZE_CONST_SHIFT, &bi_k)) != MP_OKAY) {
+ goto LTM_E1;
+ }
+ if ((err = mp_add(&bi_k, &t, &bi_k)) != MP_OKAY) {
+ goto LTM_E1;
+ }
+#else
+ mp_set_u64(&bi_k, 0x4d104d427de7fbccULL);
+#endif
+ bit_count = mp_count_bits(a) + 1;
+ mp_set_l(&bi_bit_count, bit_count);
+ if ((err = mp_mul(&bi_bit_count, &bi_k, &bi_k)) != MP_OKAY) {
+ goto LTM_E1;
+ }
+ if ((err = mp_div_2d(&bi_k, LTM_RADIX_SIZE_SCALE, &bi_k, NULL)) != MP_OKAY) {
+ goto LTM_E1;
+ }
+ *size = (size_t)mp_get_ul(&bi_k);
+ *size += 2u + (size_t)(a->sign == MP_NEG);
+LTM_E1:
+ mp_clear_multi(&bi_bit_count, &bi_k, &t, NULL);
+ return err;
+}
+
+
+#endif
diff --git a/tommath_class.h b/tommath_class.h
index f7812da01..43adad174 100644
--- a/tommath_class.h
+++ b/tommath_class.h
@@ -155,12 +155,14 @@
# define S_MP_KARATSUBA_SQR_C
# define S_MP_LOG_C
# define S_MP_LOG_D_C
+# define S_MP_LOG_POWER_OF_TWO_C
# define S_MP_MONTGOMERY_REDUCE_FAST_C
# define S_MP_MUL_DIGS_C
# define S_MP_MUL_DIGS_FAST_C
# define S_MP_MUL_HIGH_DIGS_C
# define S_MP_MUL_HIGH_DIGS_FAST_C
# define S_MP_PRIME_IS_DIVISIBLE_C
+# define S_MP_RADIX_SIZE_RADIX_10_C
# define S_MP_RAND_JENKINS_C
# define S_MP_RAND_PLATFORM_C
# define S_MP_REVERSE_C
@@ -747,6 +749,7 @@
#if defined(MP_RADIX_SIZE_C)
# define MP_LOG_U32_C
+# define S_MP_RADIX_SIZE_RADIX_10_C
#endif
#if defined(MP_RADIX_SMAP_C)
@@ -1130,6 +1133,10 @@
#if defined(S_MP_LOG_D_C)
#endif
+#if defined(S_MP_LOG_POWER_OF_TWO_C)
+# define MP_COUNT_BITS_C
+#endif
+
#if defined(S_MP_MONTGOMERY_REDUCE_FAST_C)
# define MP_CLAMP_C
# define MP_CMP_MAG_C
@@ -1167,6 +1174,17 @@
# define MP_MOD_D_C
#endif
+#if defined(S_MP_RADIX_SIZE_RADIX_10_C)
+# define MP_CLEAR_MULTI_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_2D_C
+# define MP_GET_L_C
+# define MP_INIT_MULTI_C
+# define MP_MUL_C
+# define MP_SET_L_C
+# define MP_SET_U64_C
+#endif
+
#if defined(S_MP_RAND_JENKINS_C)
# define S_MP_RAND_JENKINS_INIT_C
#endif
diff --git a/tommath_private.h b/tommath_private.h
index 8fcc99138..375b515c5 100644
--- a/tommath_private.h
+++ b/tommath_private.h
@@ -217,6 +217,11 @@ MP_PRIVATE mp_err s_mp_log(const mp_int *a, uint32_t base, uint32_t *c);
MP_PRIVATE mp_err s_mp_rand_jenkins(void *p, size_t n) MP_WUR;
MP_PRIVATE void s_mp_rand_jenkins_init(uint64_t seed);
+/* Expects a power of two as the input "p_of_2" and 2 <= "p_of_2" <= 64*/
+MP_PRIVATE int s_mp_log_power_of_two(const mp_int *a, int p_of_2) MP_WUR;
+/* Like mp_radix_size but for radix 10 only */
+MP_PRIVATE int s_mp_radix_size_radix_10(const mp_int *a, size_t *size) MP_WUR;
+
#define MP_RMAP_REVERSE_SIZE 88
extern MP_PRIVATE const char s_mp_rmap[];
extern MP_PRIVATE const uint8_t s_mp_rmap_reverse[];