33/* LibTomMath, multiple-precision integer library -- Tom St Denis */
44/* SPDX-License-Identifier: Unlicense */
55
6- /* returns size of ASCII reprensentation */
6+ /* returns exact size of ASCII reprensentation */
77mp_err mp_radix_size (const mp_int * a , int radix , int * size )
88{
9- mp_err err ;
10- int digs ;
11- mp_int t ;
12- mp_digit d ;
9+ mp_err err ;
10+ mp_int a_ , b ;
11+ int rem , bit_count , ln2 ;
1312
1413 * size = 0 ;
1514
@@ -23,42 +22,66 @@ mp_err mp_radix_size(const mp_int *a, int radix, int *size)
2322 return MP_OKAY ;
2423 }
2524
26- /* special case for binary */
27- if (radix == 2 ) {
28- * size = mp_count_bits (a ) + ((a -> sign == MP_NEG ) ? 1 : 0 ) + 1 ;
25+ /* A small shortcut for powers of two. */
26+ switch (radix ) {
27+ case 4 :
28+ ln2 = 2 ;
29+ break ;
30+ case 8 :
31+ ln2 = 3 ;
32+ break ;
33+ case 16 :
34+ ln2 = 4 ;
35+ break ;
36+ case 32 :
37+ ln2 = 5 ;
38+ break ;
39+ case 64 :
40+ ln2 = 6 ;
41+ break ;
42+ default :
43+ ln2 = 0 ;
44+ break ;
45+ }
46+ if (ln2 != 0 ) {
47+ bit_count = mp_count_bits (a );
48+ * size = bit_count /ln2 ;
49+ rem = bit_count - ((* size ) * ln2 );
50+ /* Add 1 for the remainder if any and 1 for "\0". */
51+ * size += (rem == 0 ) ? 1 : 2 ;
52+ /* And one extra character for the minus sign */
53+ if (a -> sign == MP_NEG ) {
54+ (* size )++ ;
55+ }
2956 return MP_OKAY ;
3057 }
3158
32- /* digs is the digit count */
33- digs = 0 ;
3459
35- /* if it's negative add one for the sign */
36- if (a -> sign == MP_NEG ) {
37- ++ digs ;
60+ if ((err = mp_init (& b )) != MP_OKAY ) {
61+ goto LBL_ERR ;
3862 }
3963
40- /* init a copy of the input */
41- if ((err = mp_init_copy (& t , a )) != MP_OKAY ) {
42- return err ;
64+ a_ = * a ;
65+ a_ .sign = MP_ZPOS ;
66+ if ((err = mp_ilogb (& a_ , (uint32_t )radix , & b )) != MP_OKAY ) {
67+ goto LBL_ERR ;
4368 }
4469
45- /* force temp to positive */
46- t .sign = MP_ZPOS ;
70+ * size = (int )mp_get_l (& b );
4771
48- /* fetch out all of the digits */
49- while (! MP_IS_ZERO ( & t )) {
50- if (( err = mp_div_d ( & t , ( mp_digit ) radix , & t , & d )) != MP_OKAY ) {
51- goto LBL_ERR ;
52- }
53- ++ digs ;
72+ /* mp_ilogb truncates to zero, hence we need one extra put on top. */
73+ ( * size ) ++ ;
74+
75+ /* The sign needs to have a place to live, too*/
76+ if ( a -> sign == MP_NEG ) {
77+ ( * size ) ++ ;
5478 }
5579
56- /* return digs + 1, the 1 is for the NULL byte that would be required. */
57- * size = digs + 1 ;
58- err = MP_OKAY ;
80+ /* return digs + 1, the 1 is for the NUL byte that would be required. */
81+ (* size )++ ;
5982
6083LBL_ERR :
61- mp_clear (& t );
84+ mp_clear (& b );
6285 return err ;
6386}
6487
0 commit comments