diff --git a/demo/test.c b/demo/test.c
index 838f0eddf..8ea6a555f 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)
{
@@ -1559,6 +1559,8 @@ static mp_err s_rs(const mp_int *a, int radix, uint32_t *size)
}
static int test_mp_log_u32(void)
{
+ int z;
+ for (z = 0; z < 100; ++z) {
mp_int a;
mp_digit d;
uint32_t base, lb, size;
@@ -1644,6 +1646,7 @@ static int test_mp_log_u32(void)
/* radix_size includes the memory needed for '\0', too*/
size -= 2;
if (lb != size) {
+ printf("NE1 %d\n", base);
goto LBL_ERR;
}
}
@@ -1664,6 +1667,7 @@ static int test_mp_log_u32(void)
}
size -= 2;
if (lb != size) {
+ printf("NE2 %d %d %d\n", base, lb, size);
goto LBL_ERR;
}
}
@@ -1684,10 +1688,12 @@ static int test_mp_log_u32(void)
}
mp_clear(&a);
- return EXIT_SUCCESS;
+ continue;
LBL_ERR:
mp_clear(&a);
return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
}
static int test_mp_incr(void)
@@ -2279,14 +2285,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 +2332,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..a3c459cd9 100644
--- a/libtommath_VS2008.vcproj
+++ b/libtommath_VS2008.vcproj
@@ -884,10 +884,18 @@
RelativePath="s_mp_log.c"
>
+
+
+
+
diff --git a/makefile b/makefile
index f713a8596..866a54ad0 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_log10.o s_mp_log_d.o s_mp_log_pow2.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..e6da7f345 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_log10.o s_mp_log_d.o s_mp_log_pow2.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..b2adac474 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_log10.obj s_mp_log_d.obj s_mp_log_pow2.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..15e57de88 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_log10.o s_mp_log_d.o s_mp_log_pow2.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..055340a50 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_log10.o s_mp_log_d.o s_mp_log_pow2.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_log_u32.c b/mp_log_u32.c
index 2b49fe17b..4492668d6 100644
--- a/mp_log_u32.c
+++ b/mp_log_u32.c
@@ -17,14 +17,12 @@ mp_err mp_log_u32(const mp_int *a, uint32_t base, uint32_t *c)
return MP_VAL;
}
- /* A small shortcut for bases that are powers of two. */
- if ((base & (base - 1u)) == 0u) {
- int y, bit_count;
- for (y=0; (y < 7) && ((base & 1u) == 0u); y++) {
- base >>= 1;
- }
- bit_count = mp_count_bits(a) - 1;
- *c = (uint32_t)(bit_count/y);
+ if (MP_HAS(S_MP_LOG10) && (base == 10u)) {
+ return s_mp_log10(a, c);
+ }
+
+ if (MP_HAS(S_MP_LOG_POW2) && (base & (base - 1u)) == 0u) {
+ *c = s_mp_log_pow2(a, base);
return MP_OKAY;
}
diff --git a/s_mp_log10.c b/s_mp_log10.c
new file mode 100644
index 000000000..7291226c9
--- /dev/null
+++ b/s_mp_log10.c
@@ -0,0 +1,70 @@
+#include "tommath_private.h"
+#ifdef S_MP_LOG10_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifdef MP_16BIT
+static mp_err s_mp_add_u32(mp_int *a, uint32_t x)
+{
+ mp_int t;
+ mp_err err;
+ if ((err = mp_init_u32(&t, x)) != MP_OKAY) {
+ return err;
+ }
+ err = mp_add(a, &t, a);
+ mp_clear(&t);
+ return err;
+}
+#endif
+
+mp_err s_mp_log10(const mp_int *a, uint32_t *c)
+{
+ /*
+ 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_err err;
+ mp_int bit_count, k;
+
+#ifdef MP_16BIT
+ if ((err = mp_init_u32(&k, 0x4d104d42UL)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_mul_2d(&k, 32, &k)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+ if ((err = s_mp_add32(&k, 0x7de7fbccUL)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+#else
+ if ((err = mp_init_u64(&k, 0x4d104d427de7fbccULL)) != MP_OKAY) {
+ return err;
+ }
+#endif
+
+ if ((err = mp_init_l(&bit_count, mp_count_bits(a) - 1)) != MP_OKAY) {
+ goto LBL_ERR1;
+ }
+ if ((err = mp_mul(&bit_count, &k, &k)) != MP_OKAY) {
+ goto LBL_ERR2;
+ }
+ if ((err = mp_div_2d(&k, 64, &k, NULL)) != MP_OKAY) {
+ goto LBL_ERR2;
+ }
+ *c = mp_get_u32(&k);
+
+LBL_ERR2:
+ mp_clear(&bit_count);
+LBL_ERR1:
+ mp_clear(&k);
+ return err;
+}
+
+#endif
diff --git a/s_mp_log_pow2.c b/s_mp_log_pow2.c
new file mode 100644
index 000000000..74271c68f
--- /dev/null
+++ b/s_mp_log_pow2.c
@@ -0,0 +1,12 @@
+#include "tommath_private.h"
+#ifdef S_MP_LOG_POW2_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+uint32_t s_mp_log_pow2(const mp_int *a, uint32_t base)
+{
+ int y;
+ for (y = 0; (base & 1u) == 0u; y++, base >>= 1) {}
+ return (uint32_t)((mp_count_bits(a) - 1) / y);
+}
+#endif
diff --git a/tommath_class.h b/tommath_class.h
index f7812da01..908a666b5 100644
--- a/tommath_class.h
+++ b/tommath_class.h
@@ -154,7 +154,9 @@
# define S_MP_KARATSUBA_MUL_C
# define S_MP_KARATSUBA_SQR_C
# define S_MP_LOG_C
+# define S_MP_LOG10_C
# define S_MP_LOG_D_C
+# define S_MP_LOG_POW2_C
# define S_MP_MONTGOMERY_REDUCE_FAST_C
# define S_MP_MUL_DIGS_C
# define S_MP_MUL_DIGS_FAST_C
@@ -531,9 +533,10 @@
#endif
#if defined(MP_LOG_U32_C)
-# define MP_COUNT_BITS_C
+# define S_MP_LOG10_C
# define S_MP_LOG_C
# define S_MP_LOG_D_C
+# define S_MP_LOG_POW2_C
#endif
#if defined(MP_LSHD_C)
@@ -1127,9 +1130,23 @@
# define MP_SQR_C
#endif
+#if defined(S_MP_LOG10_C)
+# define MP_CLEAR_C
+# define MP_COUNT_BITS_C
+# define MP_DIV_2D_C
+# define MP_GET_I32_C
+# define MP_INIT_L_C
+# define MP_INIT_U64_C
+# define MP_MUL_C
+#endif
+
#if defined(S_MP_LOG_D_C)
#endif
+#if defined(S_MP_LOG_POW2_C)
+# define MP_COUNT_BITS_C
+#endif
+
#if defined(S_MP_MONTGOMERY_REDUCE_FAST_C)
# define MP_CLAMP_C
# define MP_CMP_MAG_C
diff --git a/tommath_private.h b/tommath_private.h
index 8fcc99138..4cc756157 100644
--- a/tommath_private.h
+++ b/tommath_private.h
@@ -212,6 +212,8 @@ MP_PRIVATE void s_mp_reverse(unsigned char *s, size_t len);
MP_PRIVATE mp_err s_mp_prime_is_divisible(const mp_int *a, mp_bool *result);
MP_PRIVATE mp_digit s_mp_log_d(mp_digit base, mp_digit n);
MP_PRIVATE mp_err s_mp_log(const mp_int *a, uint32_t base, uint32_t *c);
+MP_PRIVATE mp_err s_mp_log10(const mp_int *a, uint32_t *c);
+MP_PRIVATE uint32_t s_mp_log_pow2(const mp_int *a, uint32_t base);
/* TODO: jenkins prng is not thread safe as of now */
MP_PRIVATE mp_err s_mp_rand_jenkins(void *p, size_t n) MP_WUR;