diff options
Diffstat (limited to 'src/lib/libcrypto/bn/bn_exp.c')
-rw-r--r-- | src/lib/libcrypto/bn/bn_exp.c | 149 |
1 files changed, 100 insertions, 49 deletions
diff --git a/src/lib/libcrypto/bn/bn_exp.c b/src/lib/libcrypto/bn/bn_exp.c index d2c91628ac..afdfd580fb 100644 --- a/src/lib/libcrypto/bn/bn_exp.c +++ b/src/lib/libcrypto/bn/bn_exp.c | |||
@@ -110,38 +110,13 @@ | |||
110 | */ | 110 | */ |
111 | 111 | ||
112 | 112 | ||
113 | #include <stdio.h> | ||
114 | #include "cryptlib.h" | 113 | #include "cryptlib.h" |
115 | #include "bn_lcl.h" | 114 | #include "bn_lcl.h" |
116 | 115 | ||
117 | #define TABLE_SIZE 32 | 116 | #define TABLE_SIZE 32 |
118 | 117 | ||
119 | /* slow but works */ | ||
120 | int BN_mod_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) | ||
121 | { | ||
122 | BIGNUM *t; | ||
123 | int r=0; | ||
124 | |||
125 | bn_check_top(a); | ||
126 | bn_check_top(b); | ||
127 | bn_check_top(m); | ||
128 | |||
129 | BN_CTX_start(ctx); | ||
130 | if ((t = BN_CTX_get(ctx)) == NULL) goto err; | ||
131 | if (a == b) | ||
132 | { if (!BN_sqr(t,a,ctx)) goto err; } | ||
133 | else | ||
134 | { if (!BN_mul(t,a,b,ctx)) goto err; } | ||
135 | if (!BN_mod(ret,t,m,ctx)) goto err; | ||
136 | r=1; | ||
137 | err: | ||
138 | BN_CTX_end(ctx); | ||
139 | return(r); | ||
140 | } | ||
141 | |||
142 | |||
143 | /* this one works - simple but works */ | 118 | /* this one works - simple but works */ |
144 | int BN_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BN_CTX *ctx) | 119 | int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) |
145 | { | 120 | { |
146 | int i,bits,ret=0; | 121 | int i,bits,ret=0; |
147 | BIGNUM *v,*rr; | 122 | BIGNUM *v,*rr; |
@@ -176,7 +151,7 @@ err: | |||
176 | } | 151 | } |
177 | 152 | ||
178 | 153 | ||
179 | int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m, | 154 | int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, |
180 | BN_CTX *ctx) | 155 | BN_CTX *ctx) |
181 | { | 156 | { |
182 | int ret; | 157 | int ret; |
@@ -185,6 +160,40 @@ int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m, | |||
185 | bn_check_top(p); | 160 | bn_check_top(p); |
186 | bn_check_top(m); | 161 | bn_check_top(m); |
187 | 162 | ||
163 | /* For even modulus m = 2^k*m_odd, it might make sense to compute | ||
164 | * a^p mod m_odd and a^p mod 2^k separately (with Montgomery | ||
165 | * exponentiation for the odd part), using appropriate exponent | ||
166 | * reductions, and combine the results using the CRT. | ||
167 | * | ||
168 | * For now, we use Montgomery only if the modulus is odd; otherwise, | ||
169 | * exponentiation using the reciprocal-based quick remaindering | ||
170 | * algorithm is used. | ||
171 | * | ||
172 | * (Timing obtained with expspeed.c [computations a^p mod m | ||
173 | * where a, p, m are of the same length: 256, 512, 1024, 2048, | ||
174 | * 4096, 8192 bits], compared to the running time of the | ||
175 | * standard algorithm: | ||
176 | * | ||
177 | * BN_mod_exp_mont 33 .. 40 % [AMD K6-2, Linux, debug configuration] | ||
178 | * 55 .. 77 % [UltraSparc processor, but | ||
179 | * debug-solaris-sparcv8-gcc conf.] | ||
180 | * | ||
181 | * BN_mod_exp_recp 50 .. 70 % [AMD K6-2, Linux, debug configuration] | ||
182 | * 62 .. 118 % [UltraSparc, debug-solaris-sparcv8-gcc] | ||
183 | * | ||
184 | * On the Sparc, BN_mod_exp_recp was faster than BN_mod_exp_mont | ||
185 | * at 2048 and more bits, but at 512 and 1024 bits, it was | ||
186 | * slower even than the standard algorithm! | ||
187 | * | ||
188 | * "Real" timings [linux-elf, solaris-sparcv9-gcc configurations] | ||
189 | * should be obtained when the new Montgomery reduction code | ||
190 | * has been integrated into OpenSSL.) | ||
191 | */ | ||
192 | |||
193 | #define MONT_MUL_MOD | ||
194 | #define MONT_EXP_WORD | ||
195 | #define RECP_MUL_MOD | ||
196 | |||
188 | #ifdef MONT_MUL_MOD | 197 | #ifdef MONT_MUL_MOD |
189 | /* I have finally been able to take out this pre-condition of | 198 | /* I have finally been able to take out this pre-condition of |
190 | * the top bit being set. It was caused by an error in BN_div | 199 | * the top bit being set. It was caused by an error in BN_div |
@@ -194,12 +203,14 @@ int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m, | |||
194 | 203 | ||
195 | if (BN_is_odd(m)) | 204 | if (BN_is_odd(m)) |
196 | { | 205 | { |
197 | if (a->top == 1) | 206 | # ifdef MONT_EXP_WORD |
207 | if (a->top == 1 && !a->neg) | ||
198 | { | 208 | { |
199 | BN_ULONG A = a->d[0]; | 209 | BN_ULONG A = a->d[0]; |
200 | ret=BN_mod_exp_mont_word(r,A,p,m,ctx,NULL); | 210 | ret=BN_mod_exp_mont_word(r,A,p,m,ctx,NULL); |
201 | } | 211 | } |
202 | else | 212 | else |
213 | # endif | ||
203 | ret=BN_mod_exp_mont(r,a,p,m,ctx,NULL); | 214 | ret=BN_mod_exp_mont(r,a,p,m,ctx,NULL); |
204 | } | 215 | } |
205 | else | 216 | else |
@@ -227,20 +238,35 @@ int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |||
227 | 238 | ||
228 | if (bits == 0) | 239 | if (bits == 0) |
229 | { | 240 | { |
230 | BN_one(r); | 241 | ret = BN_one(r); |
231 | return(1); | 242 | return ret; |
232 | } | 243 | } |
233 | 244 | ||
234 | BN_CTX_start(ctx); | 245 | BN_CTX_start(ctx); |
235 | if ((aa = BN_CTX_get(ctx)) == NULL) goto err; | 246 | if ((aa = BN_CTX_get(ctx)) == NULL) goto err; |
236 | 247 | ||
237 | BN_RECP_CTX_init(&recp); | 248 | BN_RECP_CTX_init(&recp); |
238 | if (BN_RECP_CTX_set(&recp,m,ctx) <= 0) goto err; | 249 | if (m->neg) |
250 | { | ||
251 | /* ignore sign of 'm' */ | ||
252 | if (!BN_copy(aa, m)) goto err; | ||
253 | aa->neg = 0; | ||
254 | if (BN_RECP_CTX_set(&recp,aa,ctx) <= 0) goto err; | ||
255 | } | ||
256 | else | ||
257 | { | ||
258 | if (BN_RECP_CTX_set(&recp,m,ctx) <= 0) goto err; | ||
259 | } | ||
239 | 260 | ||
240 | BN_init(&(val[0])); | 261 | BN_init(&(val[0])); |
241 | ts=1; | 262 | ts=1; |
242 | 263 | ||
243 | if (!BN_mod(&(val[0]),a,m,ctx)) goto err; /* 1 */ | 264 | if (!BN_nnmod(&(val[0]),a,m,ctx)) goto err; /* 1 */ |
265 | if (BN_is_zero(&(val[0]))) | ||
266 | { | ||
267 | ret = BN_zero(r); | ||
268 | goto err; | ||
269 | } | ||
244 | 270 | ||
245 | window = BN_window_bits_for_exponent_size(bits); | 271 | window = BN_window_bits_for_exponent_size(bits); |
246 | if (window > 1) | 272 | if (window > 1) |
@@ -325,13 +351,13 @@ err: | |||
325 | } | 351 | } |
326 | 352 | ||
327 | 353 | ||
328 | int BN_mod_exp_mont(BIGNUM *rr, BIGNUM *a, const BIGNUM *p, | 354 | int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, |
329 | const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) | 355 | const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) |
330 | { | 356 | { |
331 | int i,j,bits,ret=0,wstart,wend,window,wvalue; | 357 | int i,j,bits,ret=0,wstart,wend,window,wvalue; |
332 | int start=1,ts=0; | 358 | int start=1,ts=0; |
333 | BIGNUM *d,*r; | 359 | BIGNUM *d,*r; |
334 | BIGNUM *aa; | 360 | const BIGNUM *aa; |
335 | BIGNUM val[TABLE_SIZE]; | 361 | BIGNUM val[TABLE_SIZE]; |
336 | BN_MONT_CTX *mont=NULL; | 362 | BN_MONT_CTX *mont=NULL; |
337 | 363 | ||
@@ -347,9 +373,10 @@ int BN_mod_exp_mont(BIGNUM *rr, BIGNUM *a, const BIGNUM *p, | |||
347 | bits=BN_num_bits(p); | 373 | bits=BN_num_bits(p); |
348 | if (bits == 0) | 374 | if (bits == 0) |
349 | { | 375 | { |
350 | BN_one(rr); | 376 | ret = BN_one(rr); |
351 | return(1); | 377 | return ret; |
352 | } | 378 | } |
379 | |||
353 | BN_CTX_start(ctx); | 380 | BN_CTX_start(ctx); |
354 | d = BN_CTX_get(ctx); | 381 | d = BN_CTX_get(ctx); |
355 | r = BN_CTX_get(ctx); | 382 | r = BN_CTX_get(ctx); |
@@ -368,14 +395,19 @@ int BN_mod_exp_mont(BIGNUM *rr, BIGNUM *a, const BIGNUM *p, | |||
368 | 395 | ||
369 | BN_init(&val[0]); | 396 | BN_init(&val[0]); |
370 | ts=1; | 397 | ts=1; |
371 | if (BN_ucmp(a,m) >= 0) | 398 | if (a->neg || BN_ucmp(a,m) >= 0) |
372 | { | 399 | { |
373 | if (!BN_mod(&(val[0]),a,m,ctx)) | 400 | if (!BN_nnmod(&(val[0]),a,m,ctx)) |
374 | goto err; | 401 | goto err; |
375 | aa= &(val[0]); | 402 | aa= &(val[0]); |
376 | } | 403 | } |
377 | else | 404 | else |
378 | aa=a; | 405 | aa=a; |
406 | if (BN_is_zero(aa)) | ||
407 | { | ||
408 | ret = BN_zero(rr); | ||
409 | goto err; | ||
410 | } | ||
379 | if (!BN_to_montgomery(&(val[0]),aa,mont,ctx)) goto err; /* 1 */ | 411 | if (!BN_to_montgomery(&(val[0]),aa,mont,ctx)) goto err; /* 1 */ |
380 | 412 | ||
381 | window = BN_window_bits_for_exponent_size(bits); | 413 | window = BN_window_bits_for_exponent_size(bits); |
@@ -475,26 +507,39 @@ int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p, | |||
475 | (/* BN_ucmp(r, (m)) < 0 ? 1 :*/ \ | 507 | (/* BN_ucmp(r, (m)) < 0 ? 1 :*/ \ |
476 | (BN_mod(t, r, m, ctx) && (swap_tmp = r, r = t, t = swap_tmp, 1)))) | 508 | (BN_mod(t, r, m, ctx) && (swap_tmp = r, r = t, t = swap_tmp, 1)))) |
477 | /* BN_MOD_MUL_WORD is only used with 'w' large, | 509 | /* BN_MOD_MUL_WORD is only used with 'w' large, |
478 | * so the BN_ucmp test is probably more overhead | 510 | * so the BN_ucmp test is probably more overhead |
479 | * than always using BN_mod (which uses BN_copy if | 511 | * than always using BN_mod (which uses BN_copy if |
480 | * a similar test returns true). */ | 512 | * a similar test returns true). */ |
513 | /* We can use BN_mod and do not need BN_nnmod because our | ||
514 | * accumulator is never negative (the result of BN_mod does | ||
515 | * not depend on the sign of the modulus). | ||
516 | */ | ||
481 | #define BN_TO_MONTGOMERY_WORD(r, w, mont) \ | 517 | #define BN_TO_MONTGOMERY_WORD(r, w, mont) \ |
482 | (BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx)) | 518 | (BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx)) |
483 | 519 | ||
484 | bn_check_top(p); | 520 | bn_check_top(p); |
485 | bn_check_top(m); | 521 | bn_check_top(m); |
486 | 522 | ||
487 | if (!(m->d[0] & 1)) | 523 | if (m->top == 0 || !(m->d[0] & 1)) |
488 | { | 524 | { |
489 | BNerr(BN_F_BN_MOD_EXP_MONT_WORD,BN_R_CALLED_WITH_EVEN_MODULUS); | 525 | BNerr(BN_F_BN_MOD_EXP_MONT_WORD,BN_R_CALLED_WITH_EVEN_MODULUS); |
490 | return(0); | 526 | return(0); |
491 | } | 527 | } |
528 | if (m->top == 1) | ||
529 | a %= m->d[0]; /* make sure that 'a' is reduced */ | ||
530 | |||
492 | bits = BN_num_bits(p); | 531 | bits = BN_num_bits(p); |
493 | if (bits == 0) | 532 | if (bits == 0) |
494 | { | 533 | { |
495 | BN_one(rr); | 534 | ret = BN_one(rr); |
496 | return(1); | 535 | return ret; |
536 | } | ||
537 | if (a == 0) | ||
538 | { | ||
539 | ret = BN_zero(rr); | ||
540 | return ret; | ||
497 | } | 541 | } |
542 | |||
498 | BN_CTX_start(ctx); | 543 | BN_CTX_start(ctx); |
499 | d = BN_CTX_get(ctx); | 544 | d = BN_CTX_get(ctx); |
500 | r = BN_CTX_get(ctx); | 545 | r = BN_CTX_get(ctx); |
@@ -590,8 +635,9 @@ err: | |||
590 | 635 | ||
591 | 636 | ||
592 | /* The old fallback, simple version :-) */ | 637 | /* The old fallback, simple version :-) */ |
593 | int BN_mod_exp_simple(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m, | 638 | int BN_mod_exp_simple(BIGNUM *r, |
594 | BN_CTX *ctx) | 639 | const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, |
640 | BN_CTX *ctx) | ||
595 | { | 641 | { |
596 | int i,j,bits,ret=0,wstart,wend,window,wvalue,ts=0; | 642 | int i,j,bits,ret=0,wstart,wend,window,wvalue,ts=0; |
597 | int start=1; | 643 | int start=1; |
@@ -602,8 +648,8 @@ int BN_mod_exp_simple(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m, | |||
602 | 648 | ||
603 | if (bits == 0) | 649 | if (bits == 0) |
604 | { | 650 | { |
605 | BN_one(r); | 651 | ret = BN_one(r); |
606 | return(1); | 652 | return ret; |
607 | } | 653 | } |
608 | 654 | ||
609 | BN_CTX_start(ctx); | 655 | BN_CTX_start(ctx); |
@@ -611,7 +657,12 @@ int BN_mod_exp_simple(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m, | |||
611 | 657 | ||
612 | BN_init(&(val[0])); | 658 | BN_init(&(val[0])); |
613 | ts=1; | 659 | ts=1; |
614 | if (!BN_mod(&(val[0]),a,m,ctx)) goto err; /* 1 */ | 660 | if (!BN_nnmod(&(val[0]),a,m,ctx)) goto err; /* 1 */ |
661 | if (BN_is_zero(&(val[0]))) | ||
662 | { | ||
663 | ret = BN_zero(r); | ||
664 | goto err; | ||
665 | } | ||
615 | 666 | ||
616 | window = BN_window_bits_for_exponent_size(bits); | 667 | window = BN_window_bits_for_exponent_size(bits); |
617 | if (window > 1) | 668 | if (window > 1) |