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[];