comparison libtommath/bn_mp_log_u32.c @ 1692:1051e4eea25a

Update LibTomMath to 1.2.0 (#84) * update C files * update other files * update headers * update makefiles * remove mp_set/get_double() * use ltm 1.2.0 API * update ltm_desc * use bundled tommath if system-tommath is too old * XMALLOC etc. were changed to MP_MALLOC etc.
author Steffen Jaeckel <s@jaeckel.eu>
date Tue, 26 May 2020 17:36:47 +0200
parents
children
comparison
equal deleted inserted replaced
1691:2d3745d58843 1692:1051e4eea25a
1 #include "tommath_private.h"
2 #ifdef BN_MP_LOG_U32_C
3 /* LibTomMath, multiple-precision integer library -- Tom St Denis */
4 /* SPDX-License-Identifier: Unlicense */
5
6 /* Compute log_{base}(a) */
7 static mp_word s_pow(mp_word base, mp_word exponent)
8 {
9 mp_word result = 1uLL;
10 while (exponent != 0u) {
11 if ((exponent & 1u) == 1u) {
12 result *= base;
13 }
14 exponent >>= 1;
15 base *= base;
16 }
17
18 return result;
19 }
20
21 static mp_digit s_digit_ilogb(mp_digit base, mp_digit n)
22 {
23 mp_word bracket_low = 1uLL, bracket_mid, bracket_high, N;
24 mp_digit ret, high = 1uL, low = 0uL, mid;
25
26 if (n < base) {
27 return 0uL;
28 }
29 if (n == base) {
30 return 1uL;
31 }
32
33 bracket_high = (mp_word) base ;
34 N = (mp_word) n;
35
36 while (bracket_high < N) {
37 low = high;
38 bracket_low = bracket_high;
39 high <<= 1;
40 bracket_high *= bracket_high;
41 }
42
43 while (((mp_digit)(high - low)) > 1uL) {
44 mid = (low + high) >> 1;
45 bracket_mid = bracket_low * s_pow(base, (mp_word)(mid - low));
46
47 if (N < bracket_mid) {
48 high = mid ;
49 bracket_high = bracket_mid ;
50 }
51 if (N > bracket_mid) {
52 low = mid ;
53 bracket_low = bracket_mid ;
54 }
55 if (N == bracket_mid) {
56 return (mp_digit) mid;
57 }
58 }
59
60 if (bracket_high == N) {
61 ret = high;
62 } else {
63 ret = low;
64 }
65
66 return ret;
67 }
68
69 /* TODO: output could be "int" because the output of mp_radix_size is int, too,
70 as is the output of mp_bitcount.
71 With the same problem: max size is INT_MAX * MP_DIGIT not INT_MAX only!
72 */
73 mp_err mp_log_u32(const mp_int *a, uint32_t base, uint32_t *c)
74 {
75 mp_err err;
76 mp_ord cmp;
77 uint32_t high, low, mid;
78 mp_int bracket_low, bracket_high, bracket_mid, t, bi_base;
79
80 err = MP_OKAY;
81
82 if (a->sign == MP_NEG) {
83 return MP_VAL;
84 }
85
86 if (MP_IS_ZERO(a)) {
87 return MP_VAL;
88 }
89
90 if (base < 2u) {
91 return MP_VAL;
92 }
93
94 /* A small shortcut for bases that are powers of two. */
95 if ((base & (base - 1u)) == 0u) {
96 int y, bit_count;
97 for (y=0; (y < 7) && ((base & 1u) == 0u); y++) {
98 base >>= 1;
99 }
100 bit_count = mp_count_bits(a) - 1;
101 *c = (uint32_t)(bit_count/y);
102 return MP_OKAY;
103 }
104
105 if (a->used == 1) {
106 *c = (uint32_t)s_digit_ilogb(base, a->dp[0]);
107 return err;
108 }
109
110 cmp = mp_cmp_d(a, base);
111 if ((cmp == MP_LT) || (cmp == MP_EQ)) {
112 *c = cmp == MP_EQ;
113 return err;
114 }
115
116 if ((err =
117 mp_init_multi(&bracket_low, &bracket_high,
118 &bracket_mid, &t, &bi_base, NULL)) != MP_OKAY) {
119 return err;
120 }
121
122 low = 0u;
123 mp_set(&bracket_low, 1uL);
124 high = 1u;
125
126 mp_set(&bracket_high, base);
127
128 /*
129 A kind of Giant-step/baby-step algorithm.
130 Idea shamelessly stolen from https://programmingpraxis.com/2010/05/07/integer-logarithms/2/
131 The effect is asymptotic, hence needs benchmarks to test if the Giant-step should be skipped
132 for small n.
133 */
134 while (mp_cmp(&bracket_high, a) == MP_LT) {
135 low = high;
136 if ((err = mp_copy(&bracket_high, &bracket_low)) != MP_OKAY) {
137 goto LBL_ERR;
138 }
139 high <<= 1;
140 if ((err = mp_sqr(&bracket_high, &bracket_high)) != MP_OKAY) {
141 goto LBL_ERR;
142 }
143 }
144 mp_set(&bi_base, base);
145
146 while ((high - low) > 1u) {
147 mid = (high + low) >> 1;
148
149 if ((err = mp_expt_u32(&bi_base, (uint32_t)(mid - low), &t)) != MP_OKAY) {
150 goto LBL_ERR;
151 }
152 if ((err = mp_mul(&bracket_low, &t, &bracket_mid)) != MP_OKAY) {
153 goto LBL_ERR;
154 }
155 cmp = mp_cmp(a, &bracket_mid);
156 if (cmp == MP_LT) {
157 high = mid;
158 mp_exch(&bracket_mid, &bracket_high);
159 }
160 if (cmp == MP_GT) {
161 low = mid;
162 mp_exch(&bracket_mid, &bracket_low);
163 }
164 if (cmp == MP_EQ) {
165 *c = mid;
166 goto LBL_END;
167 }
168 }
169
170 *c = (mp_cmp(&bracket_high, a) == MP_EQ) ? high : low;
171
172 LBL_END:
173 LBL_ERR:
174 mp_clear_multi(&bracket_low, &bracket_high, &bracket_mid,
175 &t, &bi_base, NULL);
176 return err;
177 }
178
179
180 #endif