From 1e65c0bfe4fd11e7d81dbcd3df78b9d77cf21a65 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Fri, 11 Oct 2019 00:06:45 +0200 Subject: [PATCH] Introduction of a fast but slightly over-estimating radix_size --- demo/shared.c | 4 +- demo/test.c | 104 +++++++++++++++++++++++++++++++++ doc/bn.tex | 16 ++++- libtommath_VS2008.vcproj | 8 +++ makefile | 23 ++++---- makefile.mingw | 23 ++++---- makefile.msvc | 23 ++++---- makefile.shared | 23 ++++---- makefile.unix | 24 ++++---- mp_fwrite.c | 2 +- mp_radix_size_overestimate.c | 17 ++++++ s_mp_radix_size_overestimate.c | 87 +++++++++++++++++++++++++++ tommath.def | 1 + tommath.h | 2 + tommath_class.h | 20 ++++++- tommath_private.h | 1 + tommath_superclass.h | 3 + 17 files changed, 321 insertions(+), 60 deletions(-) create mode 100644 mp_radix_size_overestimate.c create mode 100644 s_mp_radix_size_overestimate.c diff --git a/demo/shared.c b/demo/shared.c index 7ef4756..85c26ed 100644 --- a/demo/shared.c +++ b/demo/shared.c @@ -6,8 +6,8 @@ void ndraw(const mp_int *a, const char *name) size_t size = 0; mp_err err; - if ((err = mp_radix_size(a, 10, &size)) != MP_OKAY) { - fprintf(stderr, "\nndraw: mp_radix_size(a, 10, %zu) failed - %s\n", size, mp_error_to_string(err)); + if ((err = mp_radix_size_overestimate(a, 10, &size)) != MP_OKAY) { + fprintf(stderr, "\nndraw: mp_radix_size_overestimate(a, 10, %zu) failed - %s\n", size, mp_error_to_string(err)); exit(EXIT_FAILURE); } buf = (char *)malloc(size); diff --git a/demo/test.c b/demo/test.c index e1b6f0f..32652d0 100644 --- a/demo/test.c +++ b/demo/test.c @@ -2016,6 +2016,7 @@ LBL_ERR: return EXIT_FAILURE; } + static int test_mp_radix_size(void) { mp_int a; @@ -2201,6 +2202,108 @@ LBL_ERR: } +static int test_s_mp_radix_size_overestimate(void) +{ + + mp_err err; + mp_int a; + int radix; + size_t size; +/* *INDENT-OFF* */ + size_t results[65] = { + 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 + }; +#ifdef MP_RADIX_SIZE_OVERESTIMATE_TEST_BIG + size_t big_results[65] = { + 0u, 0u, 0u, 1354911329u, 1073741825u, + 924870867u, 830760078u, 764949110u, 715827883u, 677455665u, + 646456994u, 620761988u, 599025415u, 580332018u, 564035582u, + 549665673u, 536870913u, 525383039u, 514993351u, 505536793u, + 496880930u, 488918137u, 481559946u, 474732892u, 468375401u, + 462435434u, 456868672u, 451637110u, 446707948u, 442052707u, + 437646532u, 433467613u, 429496730u, 425716865u, 422112892u, + 418671312u, 415380039u, 412228213u, 409206043u, 406304679u, + 403516096u, 400833001u, 398248746u, 395757256u, 393352972u, + 391030789u, 388786017u, 386614331u, 384511740u, 382474555u, + 380499357u, 378582973u, 376722456u, 374915062u, 373158233u, + 371449582u, 369786879u, 368168034u, 366591092u, 365054217u, + 363555684u, 362093873u, 360667257u, 359274399u, 357913942 + }; +#endif + +/* *INDENT-ON* */ + if ((err = mp_init(&a)) != MP_OKAY) goto LBL_ERR; + + /* number to result in a different size for every base: 67^(4 * 67) */ + mp_set(&a, 67); + if ((err = mp_expt_n(&a, 268, &a)) != MP_OKAY) { + goto LBL_ERR; + } + + for (radix = 2; radix < 65; radix++) { + if ((err = s_mp_radix_size_overestimate(&a, radix, &size)) != MP_OKAY) { + goto LBL_ERR; + } + if (size < results[radix]) { + fprintf(stderr, "s_mp_radix_size_overestimate: result for base %d was %zu instead of %zu\n", + radix, size, results[radix]); + goto LBL_ERR; + } + a.sign = MP_NEG; + if ((err = s_mp_radix_size_overestimate(&a, radix, &size)) != MP_OKAY) { + goto LBL_ERR; + } + if (size < results[radix]) { + fprintf(stderr, "s_mp_radix_size_overestimate: result for base %d was %zu instead of %zu\n", + radix, size, results[radix]); + goto LBL_ERR; + } + a.sign = MP_ZPOS; + } +#ifdef MP_RADIX_SIZE_OVERESTIMATE_TEST_BIG + if ((err = mp_2expt(&a, INT_MAX - 1)) != MP_OKAY) { + goto LBL_ERR; + } + printf("bitcount = %d, alloc = %d\n", mp_count_bits(&a), a.alloc); + /* Start at 3 to avoid integer overflow */ + for (radix = 3; radix < 65; radix++) { + printf("radix = %d, ",radix); + if ((err = s_mp_radix_size_overestimate(&a, radix, &size)) != MP_OKAY) { + goto LBL_ERR; + } + printf("size = %zu, diff = %zu\n", size, size - big_results[radix]); + if (size < big_results[radix]) { + fprintf(stderr, "s_mp_radix_size_overestimate: result for base %d was %zu instead of %zu\n", + radix, size, results[radix]); + goto LBL_ERR; + } + a.sign = MP_NEG; + if ((err = s_mp_radix_size_overestimate(&a, radix, &size)) != MP_OKAY) { + goto LBL_ERR; + } + if (size < big_results[radix]) { + fprintf(stderr, "s_mp_radix_size_overestimate: result for base %d was %zu instead of %zu\n", + radix, size, results[radix]); + goto LBL_ERR; + } + a.sign = MP_ZPOS; + } +#endif + mp_clear(&a); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear(&a); + return EXIT_FAILURE; +} + + static int test_mp_read_write_ubin(void) { mp_int a, b, c; @@ -2359,6 +2462,7 @@ static int unit_tests(int argc, char **argv) T1(mp_reduce_2k, MP_REDUCE_2K), T1(mp_reduce_2k_l, MP_REDUCE_2K_L), T1(mp_radix_size, MP_RADIX_SIZE), + T1(s_mp_radix_size_overestimate, S_MP_RADIX_SIZE_OVERESTIMATE), #if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) T1(mp_set_double, MP_SET_DOUBLE), #endif diff --git a/doc/bn.tex b/doc/bn.tex index 711ebf8..a0956b3 100644 --- a/doc/bn.tex +++ b/doc/bn.tex @@ -2380,7 +2380,21 @@ mp_err mp_radix_size (const mp_int *a, int radix, int *size) \end{alltt} This stores in \texttt{size} the number of characters (including space for the \texttt{NUL} terminator) required. Upon error this function returns an error code and \texttt{size} will be -zero. +zero. This version of \texttt{mp\_radix\_size} uses \texttt{mp\_log} to calculate the size. It +is exact but slow for larger numbers. + +\index{mp\_radix\_size\_overestimate} +\begin{alltt} +mp_err mp_radix_size_overestimate (const mp_int *a, int radix, int *size) +\end{alltt} +This stores in \texttt{size} the number of characters (including space for the \texttt{NUL} +terminator) required. Upon error this function returns an error code and \texttt{size} will be +zero. This version of \texttt{mp\_radix\_size} is much faster than the exact version above but +introduces the relative error $\approx 10^{-8}$. That would be $22$ for $2^{2^{31}}-1$, the +largest possible number in LibTomMath. Experiments gave no absolute error over $+5$. + +The result is \emph{always} either exact or too large but it is \emph{never} too small. + If \texttt{MP\_NO\_FILE} is not defined a function to write to a file is also available. diff --git a/libtommath_VS2008.vcproj b/libtommath_VS2008.vcproj index 6f1a423..192ed0f 100644 --- a/libtommath_VS2008.vcproj +++ b/libtommath_VS2008.vcproj @@ -640,6 +640,10 @@ RelativePath="mp_radix_size.c" > + + @@ -884,6 +888,10 @@ RelativePath="s_mp_radix_map.c" > + + diff --git a/makefile b/makefile index 63930bc..1cd5778 100644 --- a/makefile +++ b/makefile @@ -38,17 +38,18 @@ mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \ mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \ mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_radix_size.o \ -mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o \ -mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_n.o mp_rshd.o \ -mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_u32.o mp_set_u64.o \ -mp_set_ul.o mp_shrink.o mp_signed_rsh.o 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_copy_digs.o s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o \ -s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log.o s_mp_log_2expt.o \ -s_mp_log_d.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o \ -s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_prime_is_divisible.o \ -s_mp_prime_tab.o s_mp_radix_map.o s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_sqr.o s_mp_sqr_comba.o \ -s_mp_sqr_karatsuba.o s_mp_sqr_toom.o s_mp_sub.o s_mp_zero_buf.o s_mp_zero_digs.o +mp_radix_size_overestimate.o mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o \ +mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o \ +mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o \ +mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o 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_copy_digs.o s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o \ +s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log.o \ +s_mp_log_2expt.o s_mp_log_d.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o \ +s_mp_mul_comba.o s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o \ +s_mp_prime_is_divisible.o s_mp_prime_tab.o s_mp_radix_map.o s_mp_radix_size_overestimate.o \ +s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_sqr.o s_mp_sqr_comba.o s_mp_sqr_karatsuba.o s_mp_sqr_toom.o \ +s_mp_sub.o s_mp_zero_buf.o s_mp_zero_digs.o #END_INS diff --git a/makefile.mingw b/makefile.mingw index ae98a5c..aab267f 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -40,17 +40,18 @@ mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \ mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \ mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_radix_size.o \ -mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o \ -mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_n.o mp_rshd.o \ -mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_u32.o mp_set_u64.o \ -mp_set_ul.o mp_shrink.o mp_signed_rsh.o 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_copy_digs.o s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o \ -s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log.o s_mp_log_2expt.o \ -s_mp_log_d.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o \ -s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_prime_is_divisible.o \ -s_mp_prime_tab.o s_mp_radix_map.o s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_sqr.o s_mp_sqr_comba.o \ -s_mp_sqr_karatsuba.o s_mp_sqr_toom.o s_mp_sub.o s_mp_zero_buf.o s_mp_zero_digs.o +mp_radix_size_overestimate.o mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o \ +mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o \ +mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o \ +mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o 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_copy_digs.o s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o \ +s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log.o \ +s_mp_log_2expt.o s_mp_log_d.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o \ +s_mp_mul_comba.o s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o \ +s_mp_prime_is_divisible.o s_mp_prime_tab.o s_mp_radix_map.o s_mp_radix_size_overestimate.o \ +s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_sqr.o s_mp_sqr_comba.o s_mp_sqr_karatsuba.o s_mp_sqr_toom.o \ +s_mp_sub.o s_mp_zero_buf.o s_mp_zero_digs.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 7dcbf3d..031f1c8 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -33,17 +33,18 @@ mp_montgomery_calc_normalization.obj mp_montgomery_reduce.obj mp_montgomery_setu mp_mul_2d.obj mp_mul_d.obj mp_mulmod.obj mp_neg.obj mp_or.obj mp_pack.obj mp_pack_count.obj mp_prime_fermat.obj \ mp_prime_frobenius_underwood.obj mp_prime_is_prime.obj mp_prime_miller_rabin.obj mp_prime_next_prime.obj \ mp_prime_rabin_miller_trials.obj mp_prime_rand.obj mp_prime_strong_lucas_selfridge.obj mp_radix_size.obj \ -mp_rand.obj mp_read_radix.obj mp_reduce.obj mp_reduce_2k.obj mp_reduce_2k_l.obj mp_reduce_2k_setup.obj \ -mp_reduce_2k_setup_l.obj mp_reduce_is_2k.obj mp_reduce_is_2k_l.obj mp_reduce_setup.obj mp_root_n.obj mp_rshd.obj \ -mp_sbin_size.obj mp_set.obj mp_set_double.obj mp_set_i32.obj mp_set_i64.obj mp_set_l.obj mp_set_u32.obj mp_set_u64.obj \ -mp_set_ul.obj mp_shrink.obj mp_signed_rsh.obj 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_copy_digs.obj s_mp_div_3.obj s_mp_div_recursive.obj s_mp_div_school.obj s_mp_div_small.obj s_mp_exptmod.obj \ -s_mp_exptmod_fast.obj s_mp_get_bit.obj s_mp_invmod.obj s_mp_invmod_odd.obj s_mp_log.obj s_mp_log_2expt.obj \ -s_mp_log_d.obj s_mp_montgomery_reduce_comba.obj s_mp_mul.obj s_mp_mul_balance.obj s_mp_mul_comba.obj \ -s_mp_mul_high.obj s_mp_mul_high_comba.obj s_mp_mul_karatsuba.obj s_mp_mul_toom.obj s_mp_prime_is_divisible.obj \ -s_mp_prime_tab.obj s_mp_radix_map.obj s_mp_rand_jenkins.obj s_mp_rand_platform.obj s_mp_sqr.obj s_mp_sqr_comba.obj \ -s_mp_sqr_karatsuba.obj s_mp_sqr_toom.obj s_mp_sub.obj s_mp_zero_buf.obj s_mp_zero_digs.obj +mp_radix_size_overestimate.obj mp_rand.obj mp_read_radix.obj mp_reduce.obj mp_reduce_2k.obj mp_reduce_2k_l.obj \ +mp_reduce_2k_setup.obj mp_reduce_2k_setup_l.obj mp_reduce_is_2k.obj mp_reduce_is_2k_l.obj mp_reduce_setup.obj \ +mp_root_n.obj mp_rshd.obj mp_sbin_size.obj mp_set.obj mp_set_double.obj mp_set_i32.obj mp_set_i64.obj mp_set_l.obj \ +mp_set_u32.obj mp_set_u64.obj mp_set_ul.obj mp_shrink.obj mp_signed_rsh.obj 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_copy_digs.obj s_mp_div_3.obj s_mp_div_recursive.obj s_mp_div_school.obj s_mp_div_small.obj \ +s_mp_exptmod.obj s_mp_exptmod_fast.obj s_mp_get_bit.obj s_mp_invmod.obj s_mp_invmod_odd.obj s_mp_log.obj \ +s_mp_log_2expt.obj s_mp_log_d.obj s_mp_montgomery_reduce_comba.obj s_mp_mul.obj s_mp_mul_balance.obj \ +s_mp_mul_comba.obj s_mp_mul_high.obj s_mp_mul_high_comba.obj s_mp_mul_karatsuba.obj s_mp_mul_toom.obj \ +s_mp_prime_is_divisible.obj s_mp_prime_tab.obj s_mp_radix_map.obj s_mp_radix_size_overestimate.obj \ +s_mp_rand_jenkins.obj s_mp_rand_platform.obj s_mp_sqr.obj s_mp_sqr_comba.obj s_mp_sqr_karatsuba.obj s_mp_sqr_toom.obj \ +s_mp_sub.obj s_mp_zero_buf.obj s_mp_zero_digs.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 2e24a43..5e19c3b 100644 --- a/makefile.shared +++ b/makefile.shared @@ -35,17 +35,18 @@ mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \ mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \ mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_radix_size.o \ -mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o \ -mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_n.o mp_rshd.o \ -mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_u32.o mp_set_u64.o \ -mp_set_ul.o mp_shrink.o mp_signed_rsh.o 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_copy_digs.o s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o \ -s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log.o s_mp_log_2expt.o \ -s_mp_log_d.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o \ -s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_prime_is_divisible.o \ -s_mp_prime_tab.o s_mp_radix_map.o s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_sqr.o s_mp_sqr_comba.o \ -s_mp_sqr_karatsuba.o s_mp_sqr_toom.o s_mp_sub.o s_mp_zero_buf.o s_mp_zero_digs.o +mp_radix_size_overestimate.o mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o \ +mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o \ +mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o \ +mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o 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_copy_digs.o s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o \ +s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log.o \ +s_mp_log_2expt.o s_mp_log_d.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o \ +s_mp_mul_comba.o s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o \ +s_mp_prime_is_divisible.o s_mp_prime_tab.o s_mp_radix_map.o s_mp_radix_size_overestimate.o \ +s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_sqr.o s_mp_sqr_comba.o s_mp_sqr_karatsuba.o s_mp_sqr_toom.o \ +s_mp_sub.o s_mp_zero_buf.o s_mp_zero_digs.o #END_INS diff --git a/makefile.unix b/makefile.unix index 2b2589c..f2a918c 100644 --- a/makefile.unix +++ b/makefile.unix @@ -41,17 +41,19 @@ mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \ mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \ mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_radix_size.o \ -mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o \ -mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_n.o mp_rshd.o \ -mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_u32.o mp_set_u64.o \ -mp_set_ul.o mp_shrink.o mp_signed_rsh.o 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_copy_digs.o s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o \ -s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log.o s_mp_log_2expt.o \ -s_mp_log_d.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o \ -s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_prime_is_divisible.o \ -s_mp_prime_tab.o s_mp_radix_map.o s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_sqr.o s_mp_sqr_comba.o \ -s_mp_sqr_karatsuba.o s_mp_sqr_toom.o s_mp_sub.o s_mp_zero_buf.o s_mp_zero_digs.o +mp_radix_size_overestimate.o mp_rand.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o mp_reduce_2k_l.o \ +mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o mp_reduce_setup.o \ +mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o mp_set_l.o \ +mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o 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_copy_digs.o s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o \ +s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log.o \ +s_mp_log_2expt.o s_mp_log_d.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o \ +s_mp_mul_comba.o s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o \ +s_mp_prime_is_divisible.o s_mp_prime_tab.o s_mp_radix_map.o s_mp_radix_size_overestimate.o \ +s_mp_rand_jenkins.o s_mp_rand_platform.o s_mp_sqr.o s_mp_sqr_comba.o s_mp_sqr_karatsuba.o s_mp_sqr_toom.o \ +s_mp_sub.o s_mp_zero_buf.o s_mp_zero_digs.o + HEADERS_PUB=tommath.h HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB) diff --git a/mp_fwrite.c b/mp_fwrite.c index 6b8ea13..3d8141f 100644 --- a/mp_fwrite.c +++ b/mp_fwrite.c @@ -10,7 +10,7 @@ mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream) mp_err err; size_t size, written; - if ((err = mp_radix_size(a, radix, &size)) != MP_OKAY) { + if ((err = mp_radix_size_overestimate(a, radix, &size)) != MP_OKAY) { return err; } diff --git a/mp_radix_size_overestimate.c b/mp_radix_size_overestimate.c new file mode 100644 index 0000000..3fe81d7 --- /dev/null +++ b/mp_radix_size_overestimate.c @@ -0,0 +1,17 @@ +#include "tommath_private.h" +#ifdef MP_RADIX_SIZE_OVERESTIMATE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +mp_err mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size) +{ + if (MP_HAS(S_MP_RADIX_SIZE_OVERESTIMATE)) { + return s_mp_radix_size_overestimate(a, radix, size); + } + if (MP_HAS(MP_RADIX_SIZE)) { + return mp_radix_size(a, radix, size); + } + return MP_ERR; +} + +#endif diff --git a/s_mp_radix_size_overestimate.c b/s_mp_radix_size_overestimate.c new file mode 100644 index 0000000..35dd1e6 --- /dev/null +++ b/s_mp_radix_size_overestimate.c @@ -0,0 +1,87 @@ +#include "tommath_private.h" +#ifdef S_MP_RADIX_SIZE_OVERESTIMATE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* + Overestimate the size needed for the bigint to string conversion by a very small amount. + The error is about 10^-8; it will overestimate the result by at most 11 elements for + a number of the size 2^(2^31)-1 which is currently the largest possible in this library. + Some short tests gave no results larger than 5 (plus 2 for sign and EOS). + */ + +/* + Table of {0, INT(log_2([1..64])*2^p)+1 } where p is the scale + factor defined in MP_RADIX_SIZE_SCALE and INT() extracts the integer part (truncating). + Good for 32 bit "int". Set MP_RADIX_SIZE_SCALE = 61 and recompute values + for 64 bit "int". + */ +/* *INDENT-OFF* */ +#define MP_RADIX_SIZE_SCALE 29 +static const uint32_t s_log_bases[65] = { + 0u, 0u, 0x20000001u, 0x14309399u, 0x10000001u, + 0xdc81a35u, 0xc611924u, 0xb660c9eu, 0xaaaaaabu, 0xa1849cdu, + 0x9a209a9u, 0x94004e1u, 0x8ed19c2u, 0x8a5ca7du, 0x867a000u, + 0x830cee3u, 0x8000001u, 0x7d42d60u, 0x7ac8b32u, 0x7887847u, + 0x7677349u, 0x749131fu, 0x72d0163u, 0x712f657u, 0x6fab5dbu, + 0x6e40d1bu, 0x6ced0d0u, 0x6badbdeu, 0x6a80e3bu, 0x6964c19u, + 0x6857d31u, 0x6758c38u, 0x6666667u, 0x657fb21u, 0x64a3b9fu, + 0x63d1ab4u, 0x6308c92u, 0x624869eu, 0x618ff47u, 0x60dedeau, + 0x6034ab0u, 0x5f90e7bu, 0x5ef32cbu, 0x5e5b1b2u, 0x5dc85c3u, + 0x5d3aa02u, 0x5cb19d9u, 0x5c2d10fu, 0x5bacbbfu, 0x5b3064fu, + 0x5ab7d68u, 0x5a42df0u, 0x59d1506u, 0x5962ffeu, 0x58f7c57u, + 0x588f7bcu, 0x582a000u, 0x57c7319u, 0x5766f1du, 0x5709243u, + 0x56adad9u, 0x565474du, 0x55fd61fu, 0x55a85e8u, 0x5555556u +}; +/* *INDENT-ON* */ + +mp_err s_mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size) +{ + int bit_count; + mp_int bi_bit_count, bi_k; + mp_err err = MP_OKAY; + + if ((radix < 2) || (radix > 64)) { + return MP_VAL; + } + + if (mp_iszero(a)) { + *size = 2U; + return MP_OKAY; + } + + if (MP_HAS(S_MP_LOG_2EXPT) && MP_IS_2EXPT((mp_digit)radix)) { + /* floor(log_{2^n}(a)) + 1 + EOS + sign */ + *size = (size_t)(s_mp_log_2expt(a, (mp_digit)radix)); + /* Would overflow with base 2 otherwise */ + if (*size > (INT_MAX - 4)) { + return MP_VAL; + } + *size += 3u; + return MP_OKAY; + } + + if ((err = mp_init_multi(&bi_bit_count, &bi_k, NULL)) != MP_OKAY) { + return err; + } + + /* la = floor(log_2(a)) + 1 */ + bit_count = mp_count_bits(a); + + mp_set_u32(&bi_bit_count, (uint32_t)bit_count); + /* k = floor(2^29/log_2(radix)) + 1 */ + mp_set_u32(&bi_k, s_log_bases[radix]); + /* n = floor((la * k) / 2^29) + 1 */ + if ((err = mp_mul(&bi_bit_count, &bi_k, &bi_bit_count)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_div_2d(&bi_bit_count, MP_RADIX_SIZE_SCALE, &bi_bit_count, NULL)) != MP_OKAY) goto LBL_ERR; + + /* The "+1" here is the "+1" in "floor((la * k) / 2^29) + 1" */ + /* n = n + 1 + EOS + sign */ + *size = (size_t)(mp_get_u64(&bi_bit_count) + 3U); + +LBL_ERR: + mp_clear_multi(&bi_bit_count, &bi_k, NULL); + return err; +} + +#endif diff --git a/tommath.def b/tommath.def index 88733ca..7d53508 100644 --- a/tommath.def +++ b/tommath.def @@ -87,6 +87,7 @@ EXPORTS mp_prime_rand mp_prime_strong_lucas_selfridge mp_radix_size + mp_radix_size_overestimate mp_rand mp_read_radix mp_reduce diff --git a/tommath.h b/tommath.h index 95f7127..a2e7585 100644 --- a/tommath.h +++ b/tommath.h @@ -565,7 +565,9 @@ mp_err mp_to_sbin(const mp_int *a, uint8_t *buf, size_t maxlen, size_t *written) mp_err mp_read_radix(mp_int *a, const char *str, int radix) MP_WUR; mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix) MP_WUR; + mp_err mp_radix_size(const mp_int *a, int radix, size_t *size) MP_WUR; +mp_err mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size) MP_WUR; #ifndef MP_NO_FILE mp_err mp_fread(mp_int *a, int radix, FILE *stream) MP_WUR; diff --git a/tommath_class.h b/tommath_class.h index 936a17e..5e76e6a 100644 --- a/tommath_class.h +++ b/tommath_class.h @@ -93,6 +93,7 @@ # define MP_PRIME_RAND_C # define MP_PRIME_STRONG_LUCAS_SELFRIDGE_C # define MP_RADIX_SIZE_C +# define MP_RADIX_SIZE_OVERESTIMATE_C # define MP_RAND_C # define MP_READ_RADIX_C # define MP_REDUCE_C @@ -154,6 +155,7 @@ # define S_MP_PRIME_IS_DIVISIBLE_C # define S_MP_PRIME_TAB_C # define S_MP_RADIX_MAP_C +# define S_MP_RADIX_SIZE_OVERESTIMATE_C # define S_MP_RAND_JENKINS_C # define S_MP_RAND_PLATFORM_C # define S_MP_SQR_C @@ -339,7 +341,7 @@ #endif #if defined(MP_FWRITE_C) -# define MP_RADIX_SIZE_C +# define MP_RADIX_SIZE_OVERESTIMATE_C # define MP_TO_RADIX_C # define S_MP_ZERO_BUF_C #endif @@ -688,6 +690,11 @@ # define MP_LOG_N_C #endif +#if defined(MP_RADIX_SIZE_OVERESTIMATE_C) +# define MP_RADIX_SIZE_C +# define S_MP_RADIX_SIZE_OVERESTIMATE_C +#endif + #if defined(MP_RAND_C) # define MP_GROW_C # define MP_RAND_SOURCE_C @@ -1172,6 +1179,17 @@ #if defined(S_MP_RADIX_MAP_C) #endif +#if defined(S_MP_RADIX_SIZE_OVERESTIMATE_C) +# define MP_CLEAR_MULTI_C +# define MP_COUNT_BITS_C +# define MP_DIV_2D_C +# define MP_GET_I64_C +# define MP_INIT_MULTI_C +# define MP_MUL_C +# define MP_SET_U32_C +# define S_MP_LOG_2EXPT_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 eb566dd..24e7781 100644 --- a/tommath_private.h +++ b/tommath_private.h @@ -192,6 +192,7 @@ MP_PRIVATE mp_err s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; MP_PRIVATE void s_mp_copy_digs(mp_digit *d, const mp_digit *s, int digits); MP_PRIVATE void s_mp_zero_buf(void *mem, size_t size); MP_PRIVATE void s_mp_zero_digs(mp_digit *d, int digits); +MP_PRIVATE mp_err s_mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size); /* 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; diff --git a/tommath_superclass.h b/tommath_superclass.h index 9e85d98..9245e00 100644 --- a/tommath_superclass.h +++ b/tommath_superclass.h @@ -28,6 +28,7 @@ # define MP_NEG_C # define MP_PRIME_FROBENIUS_UNDERWOOD_C # define MP_RADIX_SIZE_C +# define MP_RADIX_SIZE_OVERESTIMATE_C # define MP_LOG_N_C # define MP_RAND_C # define MP_REDUCE_C @@ -36,6 +37,8 @@ # define MP_ROOT_N_C # define MP_SET_L_C # define MP_SET_UL_C +# define MP_SET_U64_C +# define MP_SET_I64_C # define MP_SBIN_SIZE_C # define MP_TO_RADIX_C # define MP_TO_SBIN_C