00001 #include "multiprec.h"
00002 #include <string.h>
00003
00030 inline size_t
00031 ymp_mulabs(digit_t *result, const digit_t *lhs, const digit_t *rhs,
00032 size_t lhs_len, size_t rhs_len)
00033 {
00034 double_digit_t tmp=0;
00035 size_t i=0, j=0;
00036
00037 if (lhs_len == 0 || rhs_len == 0) return 0;
00038 if ((lhs_len==1 && lhs[0]==0) || (rhs_len==1 && rhs[0]==0)) return 0;
00039
00040 memset(result, 0, (lhs_len+rhs_len)*sizeof(digit_t));
00041 for (i=0; i<lhs_len; ++i)
00042 {
00043 tmp = 0;
00044 for (j=0; j<rhs_len; ++j)
00045 {
00046 tmp += ((double_digit_t)lhs[i]) * rhs[j];
00047 tmp += result[i+j];
00048
00049 result[i+j] = LOW_DIGIT(tmp);
00050 tmp = HIGH_DIGIT(tmp);
00051 }
00052 result[i+j] = LOW_DIGIT(tmp);
00053 }
00054 if (tmp) ++i;
00055 return i+j-1;
00056 }
00057
00058
00059
00060
00061
00075 inline size_t
00076 ymp_mulabs_digit(digit_t *result,
00077 const digit_t *lhs, digit_t rhs, size_t lhs_len)
00078 {
00079 double_digit_t tmp = 0, tmp2, tmp3;
00080 size_t i;
00081 for (i=0; i<lhs_len; ++i)
00082 {
00083 tmp2 = ((double_digit_t)lhs[i]) * rhs;
00084 tmp3 = LOW_DIGIT(tmp);
00085 tmp3 += LOW_DIGIT(tmp2);
00086
00087 result[i] = LOW_DIGIT(tmp3);
00088
00089 tmp = HIGH_DIGIT(tmp);
00090 tmp += HIGH_DIGIT(tmp2);
00091 tmp += HIGH_DIGIT(tmp3);
00092 }
00093 if (LOW_DIGIT(tmp))
00094 {
00095 result[i] = LOW_DIGIT(tmp);
00096 ++i;
00097 }
00098 return i;
00099 }
00100
00101
00119 inline size_t
00120 ymp_modmulabs(digit_t *result,
00121 const digit_t *lhs, const digit_t *rhs, const digit_t *modulus,
00122 size_t lhs_len, size_t rhs_len, size_t modulus_len)
00123 {
00124 digit_t *product_digits;
00125 size_t product_used;
00126
00127 YMP_TEMP_ALLOCATE(product_digits, digit_t, lhs_len+rhs_len);
00128
00129 product_used = ymp_mulabs(product_digits, lhs, rhs, lhs_len, rhs_len);
00130
00131 if (product_used < modulus_len)
00132 {
00133 memcpy(result, product_digits, sizeof(digit_t)*product_used);
00134 return product_used;
00135 }
00136 else
00137 {
00138 return ymp_divmodabs(NULL, result, product_digits, modulus,
00139 product_used, modulus_len);
00140 }
00141 }
00142
00143
00144
00163 inline size_t
00164 ymp_modmulabs_2exp(digit_t *result, const digit_t *lhs, const digit_t *rhs,
00165 size_t pow, size_t lhs_len, size_t rhs_len)
00166 {
00167 size_t n_digits, n_bits;
00168
00169 size_t max_len;
00170 digit_t *product;
00171
00172 double_digit_t tmp;
00173 size_t i, j;
00174
00175 if (lhs_len == 0 || rhs_len == 0) return 0;
00176 if ((lhs_len==1 && lhs[0]==0) || (rhs_len==1 && rhs[0]==0)) return 0;
00177
00178
00179 n_digits = pow / DIGIT_BIT; n_bits = pow % DIGIT_BIT;
00180 max_len = n_digits + (n_bits != 0);
00181
00182 if (result == lhs || result == rhs)
00183 {
00184 YMP_TEMP_ALLOCATE(product, digit_t, max_len);
00185 }
00186 else
00187 {
00188 product = result;
00189 }
00190
00191 memset(product, 0, max_len*sizeof(digit_t));
00192
00193 if (lhs_len > max_len) lhs_len = max_len;
00194 for (i=0; i<lhs_len; ++i)
00195 {
00196 size_t bound = max_len - i;
00197 tmp = 0;
00198 for (j=0; j<rhs_len && j<bound ; ++j)
00199 {
00200 tmp += ((double_digit_t)lhs[i]) * rhs[j];
00201 tmp += product[i+j];
00202
00203 product[i+j] = LOW_DIGIT(tmp);
00204 tmp = HIGH_DIGIT(tmp);
00205 }
00206 if (i+j < max_len) product[i+j] = LOW_DIGIT(tmp);
00207 }
00208
00209 if (n_bits) product[n_digits] &= (1u << n_bits)-1;
00210
00211 while (max_len-- > 0)
00212 {
00213 if (product[max_len]) break;
00214 }
00215 ++max_len;
00216
00217 if (product != result) memcpy(result, product, max_len * sizeof(digit_t));
00218
00219 return max_len;
00220 }
00221
00222
00236 void
00237 ymp_mul(mp_ref_t result, mp_cref_t self, mp_cref_t other)
00238 {
00239 digit_t *self_digits = self->digits;
00240 digit_t *other_digits = other->digits;
00241 if (result == self)
00242 {
00243 YMP_TEMP_ALLOCATE(self_digits, digit_t, self->used);
00244 memcpy(self_digits, self->digits, sizeof(digit_t)*self->used);
00245 }
00246 if (result == other)
00247 {
00248 YMP_TEMP_ALLOCATE(other_digits, digit_t, self->used);
00249 memcpy(other_digits, other->digits, sizeof(digit_t)*self->used);
00250 }
00251
00252 ymp_reserve(result, self->used+other->used);
00253 result->used = ymp_mulabs(result->digits, self_digits, other_digits,
00254 self->used, other->used);
00255
00256 result->sign = self->sign != other->sign;
00257 }
00258
00259
00260
00274 void
00275 ymp_modmul(mp_ref_t result, mp_cref_t self, mp_cref_t other, mp_cref_t modulus)
00276 {
00277 digit_t *self_digits = self->digits;
00278 digit_t *other_digits = other->digits;
00279
00280 if (result == self)
00281 {
00282 YMP_TEMP_ALLOCATE(self_digits, digit_t, self->used);
00283 memcpy(self_digits, self->digits, sizeof(digit_t)*self->used);
00284 }
00285 if (result == other)
00286 {
00287 YMP_TEMP_ALLOCATE(other_digits, digit_t, self->used);
00288 memcpy(other_digits, other->digits, sizeof(digit_t)*self->used);
00289 }
00290
00291 ymp_reserve(result, modulus->used);
00292
00293 result->used = ymp_modmulabs(result->digits,
00294 self_digits, other->digits, modulus->digits,
00295 self->used, other->used, modulus->used);
00296
00297 result->sign = self->sign != other->sign;
00298 }
00299
00300
00314 void
00315 ymp_modmul_2exp(mp_ref_t result, mp_cref_t self, mp_cref_t other, size_t pow)
00316 {
00317 ymp_reserve(result, pow/DIGIT_BIT + 1);
00318
00319 result->used = ymp_modmulabs_2exp(result->digits,
00320 self->digits, other->digits,
00321 pow, self->used, other->used);
00322
00323 result->sign = self->sign != other->sign;
00324 }
00325
00326
00336 void
00337 ymp_mul_digit(mp_ref_t result, mp_cref_t self, digit_t other)
00338 {
00339 ymp_reserve(result, self->used+1);
00340 result->used = ymp_mulabs_digit(result->digits,
00341 self->digits, other, self->used);
00342 result->sign = self->sign;
00343 }
00344
00345
00367 size_t
00368 ymp_modpowabs_z(digit_t *result, const digit_t *source, const digit_t *modulus,
00369 size_t source_len, size_t modulus_len, size_t pow)
00370 {
00371
00372
00373 digit_t *powered_digits;
00374 size_t powered_used;
00375 size_t result_used;
00376
00377
00378 if (result == modulus)
00379 {
00380 digit_t *new_modulus;
00381 YMP_TEMP_ALLOCATE(new_modulus, digit_t, modulus_len);
00382 memcpy(new_modulus, modulus, sizeof(digit_t)*modulus_len);
00383 modulus = new_modulus;
00384 }
00385
00386
00387 YMP_TEMP_ALLOCATE(powered_digits, digit_t, modulus_len*2);
00388 if (source_len < modulus_len)
00389 {
00390 powered_used = source_len;
00391 memcpy(powered_digits, source, source_len*sizeof(digit_t));
00392 }
00393 else
00394 {
00395 powered_used = ymp_divmodabs(NULL, powered_digits,
00396 source, modulus, source_len, modulus_len);
00397
00398 }
00399
00400
00401 result_used = 1; result[0] = 1;
00402
00403 for (;;)
00404 {
00405 if (pow & 0x01)
00406 {
00407 result_used = ymp_modmulabs(result,
00408 result, powered_digits, modulus,
00409 result_used, powered_used, modulus_len);
00410 }
00411
00412 pow >>= 1;
00413 if (!pow) return result_used;
00414
00415 powered_used = ymp_modmulabs(powered_digits,
00416 powered_digits, powered_digits, modulus,
00417 powered_used, powered_used, modulus_len);
00418 }
00419 }
00420
00421
00435 size_t
00436 ymp_modpowabs_2exp_z(digit_t *result, const digit_t *source,
00437 size_t len, size_t emod, size_t pow)
00438 {
00439
00440
00441 digit_t *powered_digits;
00442 size_t powered_used;
00443 size_t result_used;
00444 size_t mod_len = emod / DIGIT_BIT + 1;
00445
00446
00447 YMP_TEMP_ALLOCATE(powered_digits, digit_t, mod_len);
00448 powered_used = ymp_modabs_2exp(powered_digits, source, len, emod);
00449
00450
00451 result_used = 1; result[0] = 1;
00452
00453 for (;;)
00454 {
00455 if (pow & 0x01)
00456 {
00457 result_used = ymp_modmulabs_2exp(result, result, powered_digits,
00458 emod, result_used, powered_used);
00459 }
00460
00461 pow >>= 1;
00462 if (!pow) return result_used;
00463
00464 powered_used = ymp_modmulabs_2exp(powered_digits,
00465 powered_digits, powered_digits,
00466 emod, powered_used, powered_used);
00467 }
00468 }
00469
00470
00471
00490 inline size_t
00491 ymp_modpowabs(digit_t *result,
00492 const digit_t *source, const digit_t *modulus,
00493 const digit_t *pow,
00494 size_t source_len, size_t modulus_len, size_t pow_len)
00495 {
00496
00497
00498 size_t i;
00499 digit_t bit_mask;
00500
00501 digit_t *powered_digits;
00502 size_t powered_used;
00503
00504 size_t result_used;
00505
00506
00507 if (result == modulus)
00508 {
00509 digit_t *new_modulus;
00510 YMP_TEMP_ALLOCATE(new_modulus, digit_t, modulus_len);
00511 memcpy(new_modulus, modulus, sizeof(digit_t)*modulus_len);
00512 modulus = new_modulus;
00513 }
00514
00515
00516 if (result == pow)
00517 {
00518 digit_t *new_pow;
00519 YMP_TEMP_ALLOCATE(new_pow, digit_t, pow_len);
00520 memcpy(new_pow, pow, sizeof(digit_t)*pow_len);
00521 pow = new_pow;
00522 }
00523
00524
00525 YMP_TEMP_ALLOCATE(powered_digits, digit_t, modulus_len*2);
00526 if (source_len < modulus_len)
00527 {
00528 powered_used = source_len;
00529 memcpy(powered_digits, source, sizeof(digit_t)*source_len);
00530 }
00531 else
00532 {
00533 powered_used = ymp_divmodabs(NULL, powered_digits,
00534 source, modulus, source_len, modulus_len);
00535
00536 }
00537
00538
00539 result_used = 1; result[0] = 1;
00540
00541 i=0; bit_mask=1;
00542 for (;;)
00543 {
00544 if (pow[i] & bit_mask)
00545 {
00546 result_used = ymp_modmulabs(result,
00547 result, powered_digits, modulus,
00548 result_used, powered_used, modulus_len);
00549 }
00550
00551 if (bit_mask == DIGIT_HIGHEST_BIT)
00552 {
00553 bit_mask = 1;
00554 ++i;
00555 if (i==pow_len) return result_used;
00556 }
00557 else
00558 {
00559 bit_mask <<= 1;
00560 if (i==pow_len-1 && pow[i] < bit_mask) return result_used;
00561 }
00562
00563 powered_used = ymp_modmulabs(powered_digits,
00564 powered_digits, powered_digits, modulus,
00565 powered_used, powered_used, modulus_len);
00566 }
00567 }
00568
00569
00570
00584 inline size_t
00585 ymp_powabs(digit_t *result, const digit_t *source,
00586 size_t source_len, size_t pow)
00587 {
00588
00589 digit_t *tmp_digits;
00590 digit_t *powered_digits;
00591 size_t powered_used;
00592 size_t result_used;
00593
00594 if (pow == 0)
00595 {
00596 result[0] = 1;
00597 return 1;
00598 }
00599
00600
00601
00602
00603 YMP_TEMP_ALLOCATE(tmp_digits, digit_t, source_len*pow);
00604
00605
00606 YMP_TEMP_ALLOCATE(powered_digits, digit_t, source_len*pow);
00607 powered_used = source_len;
00608 memcpy(powered_digits, source, sizeof(digit_t)*source_len);
00609
00610
00611 result_used = 1; result[0] = 1;
00612
00613
00614
00615
00616 for (;;)
00617 {
00618 if (pow & 0x01)
00619 {
00620 memcpy(tmp_digits, result, sizeof(digit_t)*result_used);
00621 result_used = ymp_mulabs(result, tmp_digits, powered_digits,
00622 result_used, powered_used);
00623 }
00624
00625 pow >>= 1;
00626 if (!pow) return result_used;
00627
00628 memcpy(tmp_digits, powered_digits, sizeof(digit_t)*powered_used);
00629 powered_used = ymp_mulabs(powered_digits, tmp_digits, tmp_digits,
00630 powered_used, powered_used);
00631 }
00632 }
00646 void
00647 ymp_pow(mp_ref_t result, mp_cref_t self, size_t pow)
00648 {
00649
00650 ymp_reserve(result, self->used*MAX(pow, 1));
00651
00652 result->sign = self->sign && (pow & 0x01);
00653 result->used = ymp_powabs(result->digits, self->digits, self->used, pow);
00654 }
00655
00669 void
00670 ymp_modpow_z(mp_ref_t result, mp_cref_t self, mp_cref_t modulus, size_t pow)
00671 {
00672
00673 ymp_reserve(result, modulus->used);
00674
00675 result->sign = self->sign && (pow & 0x01);
00676 result->used = ymp_modpowabs_z(result->digits, self->digits, modulus->digits,
00677 self->used, modulus->used, pow);
00678 }
00679
00680
00694 void
00695 ymp_modpow_2exp_z(mp_ref_t result, mp_cref_t self, size_t emod, size_t pow)
00696 {
00697
00698 ymp_reserve(result, emod / DIGIT_BIT + 1);
00699
00700 result->sign = self->sign && (pow & 0x01);
00701 result->used = ymp_modpowabs_2exp_z(result->digits, self->digits,
00702 self->used, emod, pow);
00703 }
00704
00705
00717 void
00718 ymp_modpow(mp_ref_t result, mp_cref_t self, mp_cref_t modulus, mp_cref_t pow)
00719 {
00720
00721 ymp_reserve(result, modulus->used);
00722
00723 result->sign = self->sign && (pow->used != 0 || (pow->digits[0] & 0x01));
00724 result->used = ymp_modpowabs(result->digits,
00725 self->digits, modulus->digits, pow->digits,
00726 self->used, modulus->used, pow->used);
00727 }
00728
00729