comparison libtommath/bn_mp_exptmod_fast.c @ 1655:f52919ffd3b1

update ltm to 1.1.0 and enable FIPS 186.4 compliant key-generation (#79) * make key-generation compliant to FIPS 186.4 * fix includes in tommath_class.h * update fuzzcorpus instead of error-out * fixup fuzzing make-targets * update Makefile.in * apply necessary patches to ltm sources * clean-up not required ltm files * update to vanilla ltm 1.1.0 this already only contains the required files * remove set/get double
author Steffen Jaeckel <s_jaeckel@gmx.de>
date Mon, 16 Sep 2019 15:50:38 +0200
parents 8bba51a55704
children
comparison
equal deleted inserted replaced
1654:cc0fc5131c5c 1655:f52919ffd3b1
1 #include <tommath_private.h> 1 #include "tommath_private.h"
2 #ifdef BN_MP_EXPTMOD_FAST_C 2 #ifdef BN_MP_EXPTMOD_FAST_C
3 /* LibTomMath, multiple-precision integer library -- Tom St Denis 3 /* LibTomMath, multiple-precision integer library -- Tom St Denis
4 * 4 *
5 * LibTomMath is a library that provides multiple-precision 5 * LibTomMath is a library that provides multiple-precision
6 * integer arithmetic as well as number theoretic functionality. 6 * integer arithmetic as well as number theoretic functionality.
7 * 7 *
8 * The library was designed directly after the MPI library by 8 * The library was designed directly after the MPI library by
9 * Michael Fromberger but has been written from scratch with 9 * Michael Fromberger but has been written from scratch with
10 * additional optimizations in place. 10 * additional optimizations in place.
11 * 11 *
12 * The library is free for all purposes without any express 12 * SPDX-License-Identifier: Unlicense
13 * guarantee it works.
14 *
15 * Tom St Denis, [email protected], http://libtom.org
16 */ 13 */
17 14
18 /* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 15 /* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
19 * 16 *
20 * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. 17 * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
22 * 19 *
23 * Uses Montgomery or Diminished Radix reduction [whichever appropriate] 20 * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
24 */ 21 */
25 22
26 #ifdef MP_LOW_MEM 23 #ifdef MP_LOW_MEM
27 #define TAB_SIZE 32 24 # define TAB_SIZE 32
28 #else 25 #else
29 #define TAB_SIZE 256 26 # define TAB_SIZE 256
30 #endif 27 #endif
31 28
32 int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) 29 int mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode)
33 { 30 {
34 mp_int M[TAB_SIZE], res; 31 mp_int M[TAB_SIZE], res;
35 mp_digit buf, mp; 32 mp_digit buf, mp;
36 int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; 33 int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
37 34
38 /* use a pointer to the reduction algorithm. This allows us to use 35 /* use a pointer to the reduction algorithm. This allows us to use
39 * one of many reduction algorithms without modding the guts of 36 * one of many reduction algorithms without modding the guts of
40 * the code with if statements everywhere. 37 * the code with if statements everywhere.
41 */ 38 */
42 int (*redux)(mp_int*,mp_int*,mp_digit); 39 int (*redux)(mp_int *x, const mp_int *n, mp_digit rho);
43 40
44 /* find window size */ 41 /* find window size */
45 x = mp_count_bits (X); 42 x = mp_count_bits(X);
46 if (x <= 7) { 43 if (x <= 7) {
47 winsize = 2; 44 winsize = 2;
48 } else if (x <= 36) { 45 } else if (x <= 36) {
49 winsize = 3; 46 winsize = 3;
50 } else if (x <= 140) { 47 } else if (x <= 140) {
51 winsize = 4; 48 winsize = 4;
52 } else if (x <= 450) { 49 } else if (x <= 450) {
53 winsize = 5; 50 winsize = 5;
54 } else if (x <= 1303) { 51 } else if (x <= 1303) {
55 winsize = 6; 52 winsize = 6;
56 } else if (x <= 3529) { 53 } else if (x <= 3529) {
57 winsize = 7; 54 winsize = 7;
58 } else { 55 } else {
59 winsize = 8; 56 winsize = 8;
60 } 57 }
61 58
62 #ifdef MP_LOW_MEM 59 #ifdef MP_LOW_MEM
63 if (winsize > 5) { 60 if (winsize > 5) {
64 winsize = 5; 61 winsize = 5;
65 } 62 }
66 #endif 63 #endif
67 64
68 /* init M array */ 65 /* init M array */
69 /* init first cell */ 66 /* init first cell */
70 if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) { 67 if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) {
71 return err;
72 }
73
74 /* now init the second half of the array */
75 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
76 if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) {
77 for (y = 1<<(winsize-1); y < x; y++) {
78 mp_clear (&M[y]);
79 }
80 mp_clear(&M[1]);
81 return err; 68 return err;
82 } 69 }
83 } 70
84 71 /* now init the second half of the array */
85 /* determine and setup reduction code */ 72 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
86 if (redmode == 0) { 73 if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) {
87 #ifdef BN_MP_MONTGOMERY_SETUP_C 74 for (y = 1<<(winsize-1); y < x; y++) {
88 /* now setup montgomery */ 75 mp_clear(&M[y]);
89 if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { 76 }
90 goto LBL_M; 77 mp_clear(&M[1]);
91 } 78 return err;
92 #else 79 }
93 err = MP_VAL; 80 }
94 goto LBL_M; 81
95 #endif 82 /* determine and setup reduction code */
96 83 if (redmode == 0) {
97 /* automatically pick the comba one if available (saves quite a few calls/ifs) */ 84 #ifdef BN_MP_MONTGOMERY_SETUP_C
85 /* now setup montgomery */
86 if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) {
87 goto LBL_M;
88 }
89 #else
90 err = MP_VAL;
91 goto LBL_M;
92 #endif
93
94 /* automatically pick the comba one if available (saves quite a few calls/ifs) */
98 #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C 95 #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
99 if ((((P->used * 2) + 1) < MP_WARRAY) && 96 if ((((P->used * 2) + 1) < (int)MP_WARRAY) &&
100 (P->used < (1 << ((CHAR_BIT * sizeof(mp_word)) - (2 * DIGIT_BIT))))) { 97 (P->used < (1 << ((CHAR_BIT * sizeof(mp_word)) - (2 * DIGIT_BIT))))) {
101 redux = fast_mp_montgomery_reduce; 98 redux = fast_mp_montgomery_reduce;
102 } else 99 } else
103 #endif 100 #endif
104 { 101 {
105 #ifdef BN_MP_MONTGOMERY_REDUCE_C 102 #ifdef BN_MP_MONTGOMERY_REDUCE_C
106 /* use slower baseline Montgomery method */ 103 /* use slower baseline Montgomery method */
107 redux = mp_montgomery_reduce; 104 redux = mp_montgomery_reduce;
108 #else 105 #else
109 err = MP_VAL; 106 err = MP_VAL;
110 goto LBL_M; 107 goto LBL_M;
111 #endif 108 #endif
112 } 109 }
113 } else if (redmode == 1) { 110 } else if (redmode == 1) {
114 #if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) 111 #if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
115 /* setup DR reduction for moduli of the form B**k - b */ 112 /* setup DR reduction for moduli of the form B**k - b */
116 mp_dr_setup(P, &mp); 113 mp_dr_setup(P, &mp);
117 redux = mp_dr_reduce; 114 redux = mp_dr_reduce;
118 #else 115 #else
119 err = MP_VAL; 116 err = MP_VAL;
120 goto LBL_M; 117 goto LBL_M;
121 #endif 118 #endif
122 } else { 119 } else {
123 #if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) 120 #if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
124 /* setup DR reduction for moduli of the form 2**k - b */ 121 /* setup DR reduction for moduli of the form 2**k - b */
125 if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { 122 if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
126 goto LBL_M; 123 goto LBL_M;
127 } 124 }
128 redux = mp_reduce_2k; 125 redux = mp_reduce_2k;
129 #else 126 #else
130 err = MP_VAL; 127 err = MP_VAL;
131 goto LBL_M; 128 goto LBL_M;
132 #endif 129 #endif
133 } 130 }
134 131
135 /* setup result */ 132 /* setup result */
136 if ((err = mp_init_size (&res, P->alloc)) != MP_OKAY) { 133 if ((err = mp_init_size(&res, P->alloc)) != MP_OKAY) {
137 goto LBL_M; 134 goto LBL_M;
138 } 135 }
139 136
140 /* create M table 137 /* create M table
141 * 138 *
142 139
143 * 140 *
144 * The first half of the table is not computed though accept for M[0] and M[1] 141 * The first half of the table is not computed though accept for M[0] and M[1]
145 */ 142 */
146 143
147 if (redmode == 0) { 144 if (redmode == 0) {
148 #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C 145 #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
149 /* now we need R mod m */ 146 /* now we need R mod m */
150 if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { 147 if ((err = mp_montgomery_calc_normalization(&res, P)) != MP_OKAY) {
151 goto LBL_RES; 148 goto LBL_RES;
152 } 149 }
153 150
154 /* now set M[1] to G * R mod m */ 151 /* now set M[1] to G * R mod m */
155 if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { 152 if ((err = mp_mulmod(G, &res, P, &M[1])) != MP_OKAY) {
156 goto LBL_RES; 153 goto LBL_RES;
157 } 154 }
158 #else 155 #else
159 err = MP_VAL; 156 err = MP_VAL;
160 goto LBL_RES;
161 #endif
162 } else {
163 mp_set(&res, 1);
164 if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
165 goto LBL_RES;
166 }
167 }
168
169 /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
170 if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
171 goto LBL_RES;
172 }
173
174 for (x = 0; x < (winsize - 1); x++) {
175 if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
176 goto LBL_RES; 157 goto LBL_RES;
177 } 158 #endif
178 if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { 159 } else {
160 mp_set(&res, 1uL);
161 if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
162 goto LBL_RES;
163 }
164 }
165
166 /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
167 if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) {
179 goto LBL_RES; 168 goto LBL_RES;
180 } 169 }
181 } 170
182 171 for (x = 0; x < (winsize - 1); x++) {
183 /* create upper table */ 172 if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) {
184 for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { 173 goto LBL_RES;
185 if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { 174 }
186 goto LBL_RES; 175 if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, mp)) != MP_OKAY) {
187 } 176 goto LBL_RES;
188 if ((err = redux (&M[x], P, mp)) != MP_OKAY) { 177 }
189 goto LBL_RES; 178 }
190 } 179
191 } 180 /* create upper table */
192 181 for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
193 /* set initial mode and bit cnt */ 182 if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
194 mode = 0; 183 goto LBL_RES;
195 bitcnt = 1; 184 }
196 buf = 0; 185 if ((err = redux(&M[x], P, mp)) != MP_OKAY) {
197 digidx = X->used - 1; 186 goto LBL_RES;
198 bitcpy = 0; 187 }
199 bitbuf = 0; 188 }
200 189
201 for (;;) { 190 /* set initial mode and bit cnt */
202 /* grab next digit as required */ 191 mode = 0;
203 if (--bitcnt == 0) { 192 bitcnt = 1;
204 /* if digidx == -1 we are out of digits so break */ 193 buf = 0;
205 if (digidx == -1) { 194 digidx = X->used - 1;
206 break; 195 bitcpy = 0;
207 } 196 bitbuf = 0;
208 /* read next digit and reset bitcnt */ 197
209 buf = X->dp[digidx--]; 198 for (;;) {
210 bitcnt = (int)DIGIT_BIT; 199 /* grab next digit as required */
211 } 200 if (--bitcnt == 0) {
212 201 /* if digidx == -1 we are out of digits so break */
213 /* grab the next msb from the exponent */ 202 if (digidx == -1) {
214 y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; 203 break;
215 buf <<= (mp_digit)1; 204 }
216 205 /* read next digit and reset bitcnt */
217 /* if the bit is zero and mode == 0 then we ignore it 206 buf = X->dp[digidx--];
218 * These represent the leading zero bits before the first 1 bit 207 bitcnt = (int)DIGIT_BIT;
219 * in the exponent. Technically this opt is not required but it 208 }
220 * does lower the # of trivial squaring/reductions used 209
221 */ 210 /* grab the next msb from the exponent */
222 if ((mode == 0) && (y == 0)) { 211 y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
223 continue; 212 buf <<= (mp_digit)1;
224 } 213
225 214 /* if the bit is zero and mode == 0 then we ignore it
226 /* if the bit is zero and mode == 1 then we square */ 215 * These represent the leading zero bits before the first 1 bit
227 if ((mode == 1) && (y == 0)) { 216 * in the exponent. Technically this opt is not required but it
228 if ((err = mp_sqr (&res, &res)) != MP_OKAY) { 217 * does lower the # of trivial squaring/reductions used
229 goto LBL_RES; 218 */
230 } 219 if ((mode == 0) && (y == 0)) {
231 if ((err = redux (&res, P, mp)) != MP_OKAY) { 220 continue;
232 goto LBL_RES; 221 }
233 } 222
234 continue; 223 /* if the bit is zero and mode == 1 then we square */
235 } 224 if ((mode == 1) && (y == 0)) {
236 225 if ((err = mp_sqr(&res, &res)) != MP_OKAY) {
237 /* else we add it to the window */ 226 goto LBL_RES;
238 bitbuf |= (y << (winsize - ++bitcpy)); 227 }
239 mode = 2; 228 if ((err = redux(&res, P, mp)) != MP_OKAY) {
240 229 goto LBL_RES;
241 if (bitcpy == winsize) { 230 }
242 /* ok window is filled so square as required and multiply */ 231 continue;
243 /* square first */ 232 }
244 for (x = 0; x < winsize; x++) { 233
245 if ((err = mp_sqr (&res, &res)) != MP_OKAY) { 234 /* else we add it to the window */
246 goto LBL_RES; 235 bitbuf |= (y << (winsize - ++bitcpy));
247 } 236 mode = 2;
248 if ((err = redux (&res, P, mp)) != MP_OKAY) { 237
249 goto LBL_RES; 238 if (bitcpy == winsize) {
250 } 239 /* ok window is filled so square as required and multiply */
251 } 240 /* square first */
252 241 for (x = 0; x < winsize; x++) {
253 /* then multiply */ 242 if ((err = mp_sqr(&res, &res)) != MP_OKAY) {
254 if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { 243 goto LBL_RES;
255 goto LBL_RES; 244 }
256 } 245 if ((err = redux(&res, P, mp)) != MP_OKAY) {
257 if ((err = redux (&res, P, mp)) != MP_OKAY) { 246 goto LBL_RES;
258 goto LBL_RES; 247 }
259 } 248 }
260 249
261 /* empty window and reset */ 250 /* then multiply */
262 bitcpy = 0; 251 if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) {
263 bitbuf = 0; 252 goto LBL_RES;
264 mode = 1; 253 }
265 } 254 if ((err = redux(&res, P, mp)) != MP_OKAY) {
266 } 255 goto LBL_RES;
267 256 }
268 /* if bits remain then square/multiply */ 257
269 if ((mode == 2) && (bitcpy > 0)) { 258 /* empty window and reset */
270 /* square then multiply if the bit is set */ 259 bitcpy = 0;
271 for (x = 0; x < bitcpy; x++) { 260 bitbuf = 0;
272 if ((err = mp_sqr (&res, &res)) != MP_OKAY) { 261 mode = 1;
273 goto LBL_RES; 262 }
274 } 263 }
275 if ((err = redux (&res, P, mp)) != MP_OKAY) { 264
276 goto LBL_RES; 265 /* if bits remain then square/multiply */
277 } 266 if ((mode == 2) && (bitcpy > 0)) {
278 267 /* square then multiply if the bit is set */
279 /* get next bit of the window */ 268 for (x = 0; x < bitcpy; x++) {
280 bitbuf <<= 1; 269 if ((err = mp_sqr(&res, &res)) != MP_OKAY) {
281 if ((bitbuf & (1 << winsize)) != 0) { 270 goto LBL_RES;
282 /* then multiply */ 271 }
283 if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { 272 if ((err = redux(&res, P, mp)) != MP_OKAY) {
284 goto LBL_RES; 273 goto LBL_RES;
285 } 274 }
286 if ((err = redux (&res, P, mp)) != MP_OKAY) { 275
287 goto LBL_RES; 276 /* get next bit of the window */
288 } 277 bitbuf <<= 1;
289 } 278 if ((bitbuf & (1 << winsize)) != 0) {
290 } 279 /* then multiply */
291 } 280 if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) {
292 281 goto LBL_RES;
293 if (redmode == 0) { 282 }
294 /* fixup result if Montgomery reduction is used 283 if ((err = redux(&res, P, mp)) != MP_OKAY) {
295 * recall that any value in a Montgomery system is 284 goto LBL_RES;
296 * actually multiplied by R mod n. So we have 285 }
297 * to reduce one more time to cancel out the factor 286 }
298 * of R. 287 }
299 */ 288 }
300 if ((err = redux(&res, P, mp)) != MP_OKAY) { 289
301 goto LBL_RES; 290 if (redmode == 0) {
302 } 291 /* fixup result if Montgomery reduction is used
303 } 292 * recall that any value in a Montgomery system is
304 293 * actually multiplied by R mod n. So we have
305 /* swap res with Y */ 294 * to reduce one more time to cancel out the factor
306 mp_exch (&res, Y); 295 * of R.
307 err = MP_OKAY; 296 */
308 LBL_RES:mp_clear (&res); 297 if ((err = redux(&res, P, mp)) != MP_OKAY) {
298 goto LBL_RES;
299 }
300 }
301
302 /* swap res with Y */
303 mp_exch(&res, Y);
304 err = MP_OKAY;
305 LBL_RES:
306 mp_clear(&res);
309 LBL_M: 307 LBL_M:
310 mp_clear(&M[1]); 308 mp_clear(&M[1]);
311 for (x = 1<<(winsize-1); x < (1 << winsize); x++) { 309 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
312 mp_clear (&M[x]); 310 mp_clear(&M[x]);
313 } 311 }
314 return err; 312 return err;
315 } 313 }
316 #endif 314 #endif
317 315
318 316
319 /* ref: $Format:%D$ */ 317 /* ref: HEAD -> master, tag: v1.1.0 */
320 /* git commit: $Format:%H$ */ 318 /* git commit: 08549ad6bc8b0cede0b357a9c341c5c6473a9c55 */
321 /* commit time: $Format:%ai$ */ 319 /* commit time: 2019-01-28 20:32:32 +0100 */