From 3ee4c5ebe32e5dc6da734b7d10924bb27dec2521 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Tue, 20 Aug 2019 17:10:44 -0400 Subject: [PATCH 1/7] Replace the mp_to_decimal macro with a function... that chooses a new internal function that uses Barrett reduction to speed up stringifying large integers to base 10 if it's available and the number is above a cutoff size, otherwise it just falls back to mp_to_radix. --- bn_mp_to_decimal.c | 23 ++++ bn_s_mp_to_decimal_fast.c | 234 ++++++++++++++++++++++++++++++++++++++ demo/test.c | 50 ++++++++ libtommath_VS2008.vcproj | 8 ++ makefile | 15 +-- makefile.mingw | 15 +-- makefile.msvc | 15 +-- makefile.shared | 15 +-- makefile.unix | 15 +-- tommath.def | 1 + tommath.h | 2 +- tommath_class.h | 27 +++++ tommath_private.h | 1 + 13 files changed, 385 insertions(+), 36 deletions(-) create mode 100644 bn_mp_to_decimal.c create mode 100644 bn_s_mp_to_decimal_fast.c diff --git a/bn_mp_to_decimal.c b/bn_mp_to_decimal.c new file mode 100644 index 000000000..43398dd64 --- /dev/null +++ b/bn_mp_to_decimal.c @@ -0,0 +1,23 @@ +#include "tommath_private.h" +#ifdef BN_MP_TO_DECIMAL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* stores a bignum as a decimal ASCII string, using Barrett + * reduction if available. + */ + +mp_err mp_to_decimal(const mp_int *a, char *str, size_t maxlen) +{ + mp_err err; + + if (MP_HAS(S_MP_TO_DECIMAL_FAST) && (a->used > 10)) { + err = s_mp_to_decimal_fast(a, str, maxlen); + } else { + err = mp_to_radix(a, str, maxlen, 10); + } + + return err; +} + +#endif diff --git a/bn_s_mp_to_decimal_fast.c b/bn_s_mp_to_decimal_fast.c new file mode 100644 index 000000000..5ce597b57 --- /dev/null +++ b/bn_s_mp_to_decimal_fast.c @@ -0,0 +1,234 @@ +#include "tommath_private.h" +#include +#ifdef BN_S_MP_TO_DECIMAL_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* store a bignum as a decimal ASCII string */ +mp_err s_mp_to_decimal_fast_rec(const mp_int *number, mp_int *nL, mp_int *shiftL, mp_int *mL, int precalc_array_index, + int left, + char **result, + size_t *maxlen) +{ + mp_int q, nLq, r; + mp_err err; + + if (precalc_array_index < 0) { + int n = mp_get_i32(number), n2 = n, t = 0, c; + char *i = *result; + char s[4] = "000"; + + while (n) { + s[2 - t] = mp_s_rmap[n % 10]; + t++; + n /= 10; + } + + if (!left && n2 < 100) { + t++; + if (n2 < 10) { + t++; + } + if (n2 == 0) { + t++; + } + } + + if (*maxlen < (size_t)t || (*maxlen -= (size_t)t) < 1) { + /* no more room */ + return MP_VAL; + } + + for (c = 0; c < t; c++) { + i[c] = s[3 - t + c]; + } + + *result += t; + + return MP_OKAY; + } + + if ((err = mp_init_multi(&q, &nLq, &r, NULL)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_mul(number, &mL[precalc_array_index], &q)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_div_2d(&q, mp_get_i32(&shiftL[precalc_array_index]), &q, NULL)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((err = mp_mul(&nL[precalc_array_index], &q, &nLq)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((err = mp_sub(number, &nLq, &r)) != MP_OKAY) { + goto LBL_ERR; + } + + if (mp_isneg(&r)) { + if ((err = mp_sub_d(&q, 1, &q)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_add(&r, &nL[precalc_array_index], &r)) != MP_OKAY) { + goto LBL_ERR; + } + } + + --precalc_array_index; + if (left && mp_iszero(&q)) { + if ((err = s_mp_to_decimal_fast_rec(&r, nL, shiftL, mL, precalc_array_index, 1, result, maxlen)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + if ((err = s_mp_to_decimal_fast_rec(&q, nL, shiftL, mL, precalc_array_index, left, result, maxlen)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = s_mp_to_decimal_fast_rec(&r, nL, shiftL, mL, precalc_array_index, 0, result, maxlen)) != MP_OKAY) { + goto LBL_ERR; + } + } + + err = MP_OKAY; + +LBL_ERR: + mp_clear_multi(&q, &nLq, &r, NULL); + return err; +} + +mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) +{ + mp_int number, n, shift, M, M2, M22, M4, M44; + mp_int nL[20], shiftL[20], mL[20]; + mp_err err; + char **result_addr = &result; + int precalc_array_index = 1, c; + + if ((err = mp_init_multi(&n, &M, &M2, &M22, &M4, &M44, &mL[0], NULL)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((err = mp_init_copy(&number, a)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_isneg(&number)) { + if ((err = mp_neg(&number, &number)) != MP_OKAY) { + goto LBL_ERR; + } + result[0] = '-'; + *result_addr += 1; + maxlen -= 1; + } + mp_set_u32(&n, 1000); + + if ((err = mp_init_copy(&nL[0], &n)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((err = mp_init_set(&shift, (mp_digit)20)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((err = mp_init_copy(&shiftL[0], &shift)) != MP_OKAY) { + goto LBL_ERR; + } + + /* (8 * 2**$shift) / $n rounded up */ + mp_set_u32(&M, 8389); + + /* $M / 8, rounded up */ + mp_set_u32(&mL[0], 1049); + + while (1) { + if ((err = mp_sqr(&n, &n)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_cmp(&n, &number) == MP_GT) { + break; + } + + if ((err = mp_mul_2(&shift, &shift)) != MP_OKAY) { + goto LBL_ERR; + } + + /* The following is a Newton-Raphson step, to restore the invariant + * that $M is (8 * 2**$shift) / $n, rounded up. */ + { + if ((err = mp_sqr(&M, &M2)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_sqr(&M2, &M4)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((err = mp_mul(&M4, &n, &M4)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_div_2d(&M4, mp_get_i32(&shift) + 6, &M4, NULL)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_mul_2(&M2, &M2)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_sub(&M4, &M2, &M4)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_add_d(&M4, 1, &M4)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_div_2d(&M4, 3, &M4, NULL)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_sub_d(&M4, 1, &M4)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_neg(&M4, &M)) != MP_OKAY) { + goto LBL_ERR; + } + } + + if ((err = mp_init_copy(&nL[precalc_array_index], &n)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_init_copy(&shiftL[precalc_array_index], &shift)) != MP_OKAY) { + goto LBL_ERR; + } + + /* Divide by 8, round up */ + { + if ((err = mp_add_d(&M4, 1, &M4)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_div_2d(&M4, 3, &M4, NULL)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_sub_d(&M4, 1, &M4)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_neg(&M4, &M4)) != MP_OKAY) { + goto LBL_ERR; + } + } + if ((err = mp_init_copy(&mL[precalc_array_index], &M4)) != MP_OKAY) { + goto LBL_ERR; + } + precalc_array_index++; + } + + if ((err = s_mp_to_decimal_fast_rec(&number, nL, shiftL, mL, precalc_array_index - 1, 1, result_addr, + &maxlen)) != MP_OKAY) { + goto LBL_ERR; + } + *result_addr[0] = '\0'; + + err = MP_OKAY; + +LBL_ERR: + mp_clear_multi(&number, &n, &shift, &M, &M2, &M22, &M4, &M44, NULL); + for (c = 0; c < precalc_array_index; c++) { + mp_clear_multi(&nL[c], &shiftL[c], &mL[c], NULL); + } + return err; +} + +#endif diff --git a/demo/test.c b/demo/test.c index 79cfb3855..f4a406dca 100644 --- a/demo/test.c +++ b/demo/test.c @@ -2214,6 +2214,54 @@ static int test_s_mp_toom_sqr(void) return EXIT_FAILURE; } +static int test_mp_to_decimal(void) +{ + mp_int a, b; + int size, err, strlength; + char *str; + + if ((err = mp_init_multi(&a, &b, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + for (size = 1; size < 1000; size += 10) { + int times; + printf("Testing mp_to_decimal: %5d bits \r", size); + fflush(stdout); + for (times = 0; times < 5; times++) { + if ((err = mp_rand(&a, size)) != MP_OKAY) { + goto LTM_ERR; + } + if (times % 2) { + /* also test some negative numbers */ + if ((err = mp_neg(&a, &a)) != MP_OKAY) { + goto LTM_ERR; + } + } + if ((err = mp_radix_size(&a, 10, &strlength)) != MP_OKAY) { + goto LTM_ERR; + } + str = (char *)malloc((size_t)strlength); + if ((err = mp_to_decimal(&a, str, (size_t)strlength)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = mp_read_radix(&b, str, 10)) != MP_OKAY) { + goto LTM_ERR; + } + free(str); + if (mp_cmp(&a, &b) != MP_EQ) { + fprintf(stderr, "s_mp_to_decimal_fast failed at size %d\n", size); + goto LTM_ERR; + } + } + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + int unit_tests(int argc, char **argv) { static const struct { @@ -2264,8 +2312,10 @@ int unit_tests(int argc, char **argv) T1(s_mp_karatsuba_sqr, S_MP_KARATSUBA_SQR), T1(s_mp_toom_mul, S_MP_TOOM_MUL), T1(s_mp_toom_sqr, S_MP_TOOM_SQR), + T1(mp_to_decimal, S_MP_TO_DECIMAL_FAST) #undef T2 #undef T1 +#undef T }; unsigned long i, ok, fail, nop; uint64_t t; diff --git a/libtommath_VS2008.vcproj b/libtommath_VS2008.vcproj index f61123e2a..e8b5b6adf 100644 --- a/libtommath_VS2008.vcproj +++ b/libtommath_VS2008.vcproj @@ -816,6 +816,10 @@ RelativePath="bn_mp_submod.c" > + + @@ -936,6 +940,10 @@ RelativePath="bn_s_mp_sub.c" > + + diff --git a/makefile b/makefile index 89d2b3b89..f7aa5a826 100644 --- a/makefile +++ b/makefile @@ -48,13 +48,14 @@ bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32. bn_mp_set.o bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o \ bn_mp_set_u32.o bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_bin_size.o \ bn_mp_signed_rsh.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o \ -bn_mp_submod.o bn_mp_to_radix.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o \ -bn_mp_to_unsigned_bin_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o bn_prime_tab.o bn_s_mp_add.o \ -bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o \ -bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o \ -bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o \ -bn_s_mp_prime_is_divisible.o bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o \ -bn_s_mp_sqr.o bn_s_mp_sqr_fast.o bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o +bn_mp_submod.o bn_mp_to_decimal.o bn_mp_to_radix.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o \ +bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o \ +bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \ +bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \ +bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \ +bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \ +bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \ +bn_s_mp_sub.o bn_s_mp_to_decimal_fast.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o #END_INS diff --git a/makefile.mingw b/makefile.mingw index 5497a1f7a..3b858385b 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -51,13 +51,14 @@ bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32. bn_mp_set.o bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o \ bn_mp_set_u32.o bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_bin_size.o \ bn_mp_signed_rsh.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o \ -bn_mp_submod.o bn_mp_to_radix.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o \ -bn_mp_to_unsigned_bin_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o bn_prime_tab.o bn_s_mp_add.o \ -bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o \ -bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o \ -bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o \ -bn_s_mp_prime_is_divisible.o bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o \ -bn_s_mp_sqr.o bn_s_mp_sqr_fast.o bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o +bn_mp_submod.o bn_mp_to_decimal.o bn_mp_to_radix.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o \ +bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o \ +bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \ +bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \ +bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \ +bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \ +bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \ +bn_s_mp_sub.o bn_s_mp_to_decimal_fast.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o HEADERS_PUB=tommath.h HEADERS=tommath_private.h tommath_class.h tommath_superclass.h $(HEADERS_PUB) diff --git a/makefile.msvc b/makefile.msvc index bddadd100..e06a47cbb 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -43,13 +43,14 @@ bn_mp_reduce_is_2k.obj bn_mp_reduce_is_2k_l.obj bn_mp_reduce_setup.obj bn_mp_roo bn_mp_set.obj bn_mp_set_double.obj bn_mp_set_i32.obj bn_mp_set_i64.obj bn_mp_set_l.obj bn_mp_set_ll.obj \ bn_mp_set_u32.obj bn_mp_set_u64.obj bn_mp_set_ul.obj bn_mp_set_ull.obj bn_mp_shrink.obj bn_mp_signed_bin_size.obj \ bn_mp_signed_rsh.obj bn_mp_sqr.obj bn_mp_sqrmod.obj bn_mp_sqrt.obj bn_mp_sqrtmod_prime.obj bn_mp_sub.obj bn_mp_sub_d.obj \ -bn_mp_submod.obj bn_mp_to_radix.obj bn_mp_to_signed_bin.obj bn_mp_to_signed_bin_n.obj bn_mp_to_unsigned_bin.obj \ -bn_mp_to_unsigned_bin_n.obj bn_mp_unsigned_bin_size.obj bn_mp_xor.obj bn_mp_zero.obj bn_prime_tab.obj bn_s_mp_add.obj \ -bn_s_mp_balance_mul.obj bn_s_mp_exptmod.obj bn_s_mp_exptmod_fast.obj bn_s_mp_get_bit.obj bn_s_mp_invmod_fast.obj \ -bn_s_mp_invmod_slow.obj bn_s_mp_karatsuba_mul.obj bn_s_mp_karatsuba_sqr.obj bn_s_mp_montgomery_reduce_fast.obj \ -bn_s_mp_mul_digs.obj bn_s_mp_mul_digs_fast.obj bn_s_mp_mul_high_digs.obj bn_s_mp_mul_high_digs_fast.obj \ -bn_s_mp_prime_is_divisible.obj bn_s_mp_rand_jenkins.obj bn_s_mp_rand_platform.obj bn_s_mp_reverse.obj \ -bn_s_mp_sqr.obj bn_s_mp_sqr_fast.obj bn_s_mp_sub.obj bn_s_mp_toom_mul.obj bn_s_mp_toom_sqr.obj +bn_mp_submod.obj bn_mp_to_decimal.obj bn_mp_to_radix.obj bn_mp_to_signed_bin.obj bn_mp_to_signed_bin_n.obj \ +bn_mp_to_unsigned_bin.obj bn_mp_to_unsigned_bin_n.obj bn_mp_unsigned_bin_size.obj bn_mp_xor.obj bn_mp_zero.obj \ +bn_prime_tab.obj bn_s_mp_add.obj bn_s_mp_balance_mul.obj bn_s_mp_exptmod.obj bn_s_mp_exptmod_fast.obj \ +bn_s_mp_get_bit.obj bn_s_mp_invmod_fast.obj bn_s_mp_invmod_slow.obj bn_s_mp_karatsuba_mul.obj \ +bn_s_mp_karatsuba_sqr.obj bn_s_mp_montgomery_reduce_fast.obj bn_s_mp_mul_digs.obj bn_s_mp_mul_digs_fast.obj \ +bn_s_mp_mul_high_digs.obj bn_s_mp_mul_high_digs_fast.obj bn_s_mp_prime_is_divisible.obj \ +bn_s_mp_rand_jenkins.obj bn_s_mp_rand_platform.obj bn_s_mp_reverse.obj bn_s_mp_sqr.obj bn_s_mp_sqr_fast.obj \ +bn_s_mp_sub.obj bn_s_mp_to_decimal_fast.obj bn_s_mp_toom_mul.obj bn_s_mp_toom_sqr.obj HEADERS_PUB=tommath.h HEADERS=tommath_private.h tommath_class.h tommath_superclass.h $(HEADERS_PUB) diff --git a/makefile.shared b/makefile.shared index f77b5e592..6dd88dd2c 100644 --- a/makefile.shared +++ b/makefile.shared @@ -45,13 +45,14 @@ bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32. bn_mp_set.o bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o \ bn_mp_set_u32.o bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_bin_size.o \ bn_mp_signed_rsh.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o \ -bn_mp_submod.o bn_mp_to_radix.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o \ -bn_mp_to_unsigned_bin_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o bn_prime_tab.o bn_s_mp_add.o \ -bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o \ -bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o \ -bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o \ -bn_s_mp_prime_is_divisible.o bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o \ -bn_s_mp_sqr.o bn_s_mp_sqr_fast.o bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o +bn_mp_submod.o bn_mp_to_decimal.o bn_mp_to_radix.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o \ +bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o \ +bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \ +bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \ +bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \ +bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \ +bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \ +bn_s_mp_sub.o bn_s_mp_to_decimal_fast.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o #END_INS diff --git a/makefile.unix b/makefile.unix index 4bdb5d5b6..365036578 100644 --- a/makefile.unix +++ b/makefile.unix @@ -52,13 +52,14 @@ bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32. bn_mp_set.o bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o \ bn_mp_set_u32.o bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_bin_size.o \ bn_mp_signed_rsh.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o \ -bn_mp_submod.o bn_mp_to_radix.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o \ -bn_mp_to_unsigned_bin_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o bn_prime_tab.o bn_s_mp_add.o \ -bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o \ -bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o \ -bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o \ -bn_s_mp_prime_is_divisible.o bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o \ -bn_s_mp_sqr.o bn_s_mp_sqr_fast.o bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o +bn_mp_submod.o bn_mp_to_decimal.o bn_mp_to_radix.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o \ +bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o \ +bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \ +bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \ +bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \ +bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \ +bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \ +bn_s_mp_sub.o bn_s_mp_to_decimal_fast.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o HEADERS_PUB=tommath.h HEADERS=tommath_private.h tommath_class.h tommath_superclass.h $(HEADERS_PUB) diff --git a/tommath.def b/tommath.def index 1deeb948b..9a2614e3c 100644 --- a/tommath.def +++ b/tommath.def @@ -136,6 +136,7 @@ EXPORTS mp_sub mp_sub_d mp_submod + mp_to_decimal mp_to_radix mp_to_signed_bin mp_to_signed_bin_n diff --git a/tommath.h b/tommath.h index 8550340cd..126eaab83 100644 --- a/tommath.h +++ b/tommath.h @@ -703,6 +703,7 @@ MP_DEPRECATED(mp_to_radix) mp_err mp_toradix(const mp_int *a, char *str, int rad MP_DEPRECATED(mp_to_radix) mp_err mp_toradix_n(const mp_int *a, char *str, int radix, int maxlen) MP_WUR; mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, int radix) MP_WUR; mp_err mp_radix_size(const mp_int *a, int radix, int *size) MP_WUR; +mp_err mp_to_decimal(const mp_int *a, char *str, size_t maxlen) MP_WUR; #ifndef MP_NO_FILE mp_err mp_fread(mp_int *a, int radix, FILE *stream) MP_WUR; @@ -723,7 +724,6 @@ mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream) MP_WUR; #define mp_to_binary(M, S, N) mp_to_radix((M), (S), (N), 2) #define mp_to_octal(M, S, N) mp_to_radix((M), (S), (N), 8) -#define mp_to_decimal(M, S, N) mp_to_radix((M), (S), (N), 10) #define mp_to_hex(M, S, N) mp_to_radix((M), (S), (N), 16) #ifdef __cplusplus diff --git a/tommath_class.h b/tommath_class.h index 32d1b2dcf..8a921d063 100644 --- a/tommath_class.h +++ b/tommath_class.h @@ -137,6 +137,7 @@ # define BN_MP_SUB_C # define BN_MP_SUB_D_C # define BN_MP_SUBMOD_C +# define BN_MP_TO_DECIMAL_C # define BN_MP_TO_RADIX_C # define BN_MP_TO_SIGNED_BIN_C # define BN_MP_TO_SIGNED_BIN_N_C @@ -167,6 +168,7 @@ # define BN_S_MP_SQR_C # define BN_S_MP_SQR_FAST_C # define BN_S_MP_SUB_C +# define BN_S_MP_TO_DECIMAL_FAST_C # define BN_S_MP_TOOM_MUL_C # define BN_S_MP_TOOM_SQR_C #endif @@ -1052,6 +1054,11 @@ # define BN_MP_SUB_C #endif +#if defined(BN_MP_TO_DECIMAL_C) +# define BN_MP_TO_RADIX_C +# define BN_S_MP_TO_DECIMAL_FAST_C +#endif + #if defined(BN_MP_TO_RADIX_C) # define BN_MP_CLEAR_C # define BN_MP_DIV_D_C @@ -1267,6 +1274,26 @@ # define BN_MP_GROW_C #endif +#if defined(BN_S_MP_TO_DECIMAL_FAST_C) +# define BN_MP_ADD_C +# define BN_MP_ADD_D_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_C +# define BN_MP_DIV_2D_C +# define BN_MP_GET_I32_C +# define BN_MP_INIT_COPY_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_INIT_SET_C +# define BN_MP_MUL_2_C +# define BN_MP_MUL_C +# define BN_MP_NEG_C +# define BN_MP_SET_U32_C +# define BN_MP_SQR_C +# define BN_MP_SUB_C +# define BN_MP_SUB_D_C +# define BN_S_MP_TO_DECIMAL_FAST_REC_C +#endif + #if defined(BN_S_MP_TOOM_MUL_C) # define BN_MP_ADD_C # define BN_MP_CLAMP_C diff --git a/tommath_private.h b/tommath_private.h index b5650424a..a98fee515 100644 --- a/tommath_private.h +++ b/tommath_private.h @@ -205,6 +205,7 @@ MP_PRIVATE mp_err s_mp_rand_platform(void *p, size_t n) MP_WUR; MP_PRIVATE mp_err s_mp_prime_random_ex(mp_int *a, int t, int size, int flags, private_mp_prime_callback cb, void *dat); MP_PRIVATE void s_mp_reverse(unsigned char *s, int len); MP_PRIVATE mp_err s_mp_prime_is_divisible(const mp_int *a, mp_bool *result); +MP_PRIVATE mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) MP_WUR; /* 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; From 3c0162d29268f3c74e9047f313a5a11996a0a4ec Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Fri, 6 Sep 2019 16:43:50 -0400 Subject: [PATCH 2/7] Address comments --- bn_s_mp_to_decimal_fast.c | 62 ++++++++++++++++++++++----------------- demo/test.c | 6 ++-- tommath_class.h | 4 ++- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/bn_s_mp_to_decimal_fast.c b/bn_s_mp_to_decimal_fast.c index 5ce597b57..0f836d466 100644 --- a/bn_s_mp_to_decimal_fast.c +++ b/bn_s_mp_to_decimal_fast.c @@ -14,36 +14,37 @@ mp_err s_mp_to_decimal_fast_rec(const mp_int *number, mp_int *nL, mp_int *shiftL mp_err err; if (precalc_array_index < 0) { - int n = mp_get_i32(number), n2 = n, t = 0, c; - char *i = *result; - char s[4] = "000"; + int n = mp_get_i32(number), n_orig = n, digits_to_copy = 0, copy_counter; + char *result_str = *result; + char sprintf_str[4] = "000"; while (n) { - s[2 - t] = mp_s_rmap[n % 10]; - t++; + sprintf_str[2 - digits_to_copy] = mp_s_rmap[n % 10]; + digits_to_copy++; n /= 10; } - if (!left && n2 < 100) { - t++; - if (n2 < 10) { - t++; + if (!left && n_orig < 100) { + digits_to_copy++; + if (n_orig < 10) { + digits_to_copy++; } - if (n2 == 0) { - t++; + if (n_orig == 0) { + digits_to_copy++; } } - if (*maxlen < (size_t)t || (*maxlen -= (size_t)t) < 1) { + if (*maxlen < ((size_t)digits_to_copy + 1)) { /* no more room */ return MP_VAL; } - for (c = 0; c < t; c++) { - i[c] = s[3 - t + c]; + for (copy_counter = 0; copy_counter < digits_to_copy; copy_counter++) { + result_str[copy_counter] = sprintf_str[3 - digits_to_copy + copy_counter]; } - *result += t; + *maxlen -= (size_t)digits_to_copy; + *result += digits_to_copy; return MP_OKAY; } @@ -67,7 +68,7 @@ mp_err s_mp_to_decimal_fast_rec(const mp_int *number, mp_int *nL, mp_int *shiftL } if (mp_isneg(&r)) { - if ((err = mp_sub_d(&q, 1, &q)) != MP_OKAY) { + if ((err = mp_decr(&q)) != MP_OKAY) { goto LBL_ERR; } if ((err = mp_add(&r, &nL[precalc_array_index], &r)) != MP_OKAY) { @@ -104,11 +105,16 @@ mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) char **result_addr = &result; int precalc_array_index = 1, c; - if ((err = mp_init_multi(&n, &M, &M2, &M22, &M4, &M44, &mL[0], NULL)) != MP_OKAY) { + /* check range of the maxlen */ + if (maxlen < 2) { + return MP_VAL; + } + + if ((err = mp_init_multi(&number, &n, &shift, &M, &M2, &M22, &M4, &M44, &nL[0], &shiftL[0], &mL[0], NULL)) != MP_OKAY) { goto LBL_ERR; } - if ((err = mp_init_copy(&number, a)) != MP_OKAY) { + if ((err = mp_copy(a, &number)) != MP_OKAY) { goto LBL_ERR; } if (mp_isneg(&number)) { @@ -121,15 +127,13 @@ mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) } mp_set_u32(&n, 1000); - if ((err = mp_init_copy(&nL[0], &n)) != MP_OKAY) { + if ((err = mp_copy(&n, &nL[0])) != MP_OKAY) { goto LBL_ERR; } - if ((err = mp_init_set(&shift, (mp_digit)20)) != MP_OKAY) { - goto LBL_ERR; - } + mp_set_u32(&shift, 20); - if ((err = mp_init_copy(&shiftL[0], &shift)) != MP_OKAY) { + if ((err = mp_copy(&shift, &shiftL[0])) != MP_OKAY) { goto LBL_ERR; } @@ -173,13 +177,13 @@ mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) if ((err = mp_sub(&M4, &M2, &M4)) != MP_OKAY) { goto LBL_ERR; } - if ((err = mp_add_d(&M4, 1, &M4)) != MP_OKAY) { + if ((err = mp_incr(&M4)) != MP_OKAY) { goto LBL_ERR; } if ((err = mp_div_2d(&M4, 3, &M4, NULL)) != MP_OKAY) { goto LBL_ERR; } - if ((err = mp_sub_d(&M4, 1, &M4)) != MP_OKAY) { + if ((err = mp_decr(&M4)) != MP_OKAY) { goto LBL_ERR; } if ((err = mp_neg(&M4, &M)) != MP_OKAY) { @@ -209,6 +213,10 @@ mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) goto LBL_ERR; } } + if (precalc_array_index >= 20) { + err = MP_VAL; + goto LBL_ERR; + } if ((err = mp_init_copy(&mL[precalc_array_index], &M4)) != MP_OKAY) { goto LBL_ERR; } @@ -224,8 +232,8 @@ mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) err = MP_OKAY; LBL_ERR: - mp_clear_multi(&number, &n, &shift, &M, &M2, &M22, &M4, &M44, NULL); - for (c = 0; c < precalc_array_index; c++) { + mp_clear_multi(&number, &n, &shift, &M, &M2, &M22, &M4, &M44, &nL[0], &shiftL[0], &mL[0], NULL); + for (c = 1; c < precalc_array_index; c++) { mp_clear_multi(&nL[c], &shiftL[c], &mL[c], NULL); } return err; diff --git a/demo/test.c b/demo/test.c index f4a406dca..5623cee0e 100644 --- a/demo/test.c +++ b/demo/test.c @@ -2223,9 +2223,9 @@ static int test_mp_to_decimal(void) if ((err = mp_init_multi(&a, &b, NULL)) != MP_OKAY) { goto LTM_ERR; } - for (size = 1; size < 1000; size += 10) { + for (size = 1; size <= 1001; size += 10) { int times; - printf("Testing mp_to_decimal: %5d bits \r", size); + printf("Testing mp_to_decimal: %5d digits \r", size); fflush(stdout); for (times = 0; times < 5; times++) { if ((err = mp_rand(&a, size)) != MP_OKAY) { @@ -2249,7 +2249,7 @@ static int test_mp_to_decimal(void) } free(str); if (mp_cmp(&a, &b) != MP_EQ) { - fprintf(stderr, "s_mp_to_decimal_fast failed at size %d\n", size); + fprintf(stderr, "mp_to_decimal failed at size %d\n", size); goto LTM_ERR; } } diff --git a/tommath_class.h b/tommath_class.h index 8a921d063..5baf8c0d7 100644 --- a/tommath_class.h +++ b/tommath_class.h @@ -1279,11 +1279,13 @@ # define BN_MP_ADD_D_C # define BN_MP_CLEAR_MULTI_C # define BN_MP_CMP_C +# define BN_MP_COPY_C +# define BN_MP_DECR_C # define BN_MP_DIV_2D_C # define BN_MP_GET_I32_C +# define BN_MP_INCR_C # define BN_MP_INIT_COPY_C # define BN_MP_INIT_MULTI_C -# define BN_MP_INIT_SET_C # define BN_MP_MUL_2_C # define BN_MP_MUL_C # define BN_MP_NEG_C From 91543f4d1069bc37a2a688e83ca2e38c1dc9cf60 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Sat, 7 Sep 2019 11:59:40 -0400 Subject: [PATCH 3/7] Turn while into a for --- bn_s_mp_to_decimal_fast.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bn_s_mp_to_decimal_fast.c b/bn_s_mp_to_decimal_fast.c index 0f836d466..c8b7aa227 100644 --- a/bn_s_mp_to_decimal_fast.c +++ b/bn_s_mp_to_decimal_fast.c @@ -143,7 +143,7 @@ mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) /* $M / 8, rounded up */ mp_set_u32(&mL[0], 1049); - while (1) { + for (precalc_array_index = 1; precalc_array_index < 20; precalc_array_index++) { if ((err = mp_sqr(&n, &n)) != MP_OKAY) { goto LBL_ERR; } @@ -213,14 +213,13 @@ mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) goto LBL_ERR; } } - if (precalc_array_index >= 20) { - err = MP_VAL; - goto LBL_ERR; - } if ((err = mp_init_copy(&mL[precalc_array_index], &M4)) != MP_OKAY) { goto LBL_ERR; } - precalc_array_index++; + } + if (precalc_array_index >= 20) { + err = MP_VAL; + goto LBL_ERR; } if ((err = s_mp_to_decimal_fast_rec(&number, nL, shiftL, mL, precalc_array_index - 1, 1, result_addr, From 8d0387838285c40d551b163c3161d438e5ddd60d Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Sat, 7 Sep 2019 12:58:12 -0400 Subject: [PATCH 4/7] Fix undef in test.c --- demo/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/test.c b/demo/test.c index 5623cee0e..57eda2c79 100644 --- a/demo/test.c +++ b/demo/test.c @@ -2315,7 +2315,7 @@ int unit_tests(int argc, char **argv) T1(mp_to_decimal, S_MP_TO_DECIMAL_FAST) #undef T2 #undef T1 -#undef T +#undef T0 }; unsigned long i, ok, fail, nop; uint64_t t; From 8f8a58b33d53e3a019573b369cf8e322e6ddcdca Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Sat, 7 Sep 2019 15:23:53 -0400 Subject: [PATCH 5/7] Add BN_MP_TO_DECIMAL_C to tommath_superclass.h --- tommath_superclass.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tommath_superclass.h b/tommath_superclass.h index b007c243d..e2b13b521 100644 --- a/tommath_superclass.h +++ b/tommath_superclass.h @@ -37,6 +37,7 @@ # define BN_MP_SET_UL_C # define BN_MP_SIGNED_BIN_SIZE_C # define BN_MP_TO_RADIX_C +# define BN_MP_TO_DECIMAL_C # define BN_MP_TO_SIGNED_BIN_C # define BN_S_MP_RAND_JENKINS_C # define BN_S_MP_RAND_PLATFORM_C From fee03ddcfed4098c4035892fd6419ba4dc748557 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Sun, 8 Sep 2019 08:01:33 -0400 Subject: [PATCH 6/7] Zero-out arrays after declaration --- bn_s_mp_to_decimal_fast.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bn_s_mp_to_decimal_fast.c b/bn_s_mp_to_decimal_fast.c index c8b7aa227..533f3f632 100644 --- a/bn_s_mp_to_decimal_fast.c +++ b/bn_s_mp_to_decimal_fast.c @@ -110,6 +110,10 @@ mp_err s_mp_to_decimal_fast(const mp_int *a, char *result, size_t maxlen) return MP_VAL; } + MP_ZERO_BUFFER(nL, sizeof(nL)); + MP_ZERO_BUFFER(shiftL, sizeof(shiftL)); + MP_ZERO_BUFFER(mL, sizeof(mL)); + if ((err = mp_init_multi(&number, &n, &shift, &M, &M2, &M22, &M4, &M44, &nL[0], &shiftL[0], &mL[0], NULL)) != MP_OKAY) { goto LBL_ERR; } From d2678b00f547fc83be7413dd02285df55f3c609e Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Wed, 11 Sep 2019 11:00:08 -0400 Subject: [PATCH 7/7] Make s_mp_to_decimal_fast_rec static --- bn_s_mp_to_decimal_fast.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bn_s_mp_to_decimal_fast.c b/bn_s_mp_to_decimal_fast.c index 533f3f632..476f786a2 100644 --- a/bn_s_mp_to_decimal_fast.c +++ b/bn_s_mp_to_decimal_fast.c @@ -5,10 +5,11 @@ /* SPDX-License-Identifier: Unlicense */ /* store a bignum as a decimal ASCII string */ -mp_err s_mp_to_decimal_fast_rec(const mp_int *number, mp_int *nL, mp_int *shiftL, mp_int *mL, int precalc_array_index, - int left, - char **result, - size_t *maxlen) +static mp_err s_mp_to_decimal_fast_rec(const mp_int *number, mp_int *nL, mp_int *shiftL, mp_int *mL, + int precalc_array_index, + int left, + char **result, + size_t *maxlen) { mp_int q, nLq, r; mp_err err;