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;