bn_mp_dr_reduce.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #include "tommath_private.h"
  2. #ifdef BN_MP_DR_REDUCE_C
  3. /* LibTomMath, multiple-precision integer library -- Tom St Denis */
  4. /* SPDX-License-Identifier: Unlicense */
  5. /* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
  6. *
  7. * Based on algorithm from the paper
  8. *
  9. * "Generating Efficient Primes for Discrete Log Cryptosystems"
  10. * Chae Hoon Lim, Pil Joong Lee,
  11. * POSTECH Information Research Laboratories
  12. *
  13. * The modulus must be of a special format [see manual]
  14. *
  15. * Has been modified to use algorithm 7.10 from the LTM book instead
  16. *
  17. * Input x must be in the range 0 <= x <= (n-1)**2
  18. */
  19. mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k)
  20. {
  21. mp_err err;
  22. int i, m;
  23. mp_word r;
  24. mp_digit mu, *tmpx1, *tmpx2;
  25. /* m = digits in modulus */
  26. m = n->used;
  27. /* ensure that "x" has at least 2m digits */
  28. if (x->alloc < (m + m)) {
  29. if ((err = mp_grow(x, m + m)) != MP_OKAY) {
  30. return err;
  31. }
  32. }
  33. /* top of loop, this is where the code resumes if
  34. * another reduction pass is required.
  35. */
  36. top:
  37. /* aliases for digits */
  38. /* alias for lower half of x */
  39. tmpx1 = x->dp;
  40. /* alias for upper half of x, or x/B**m */
  41. tmpx2 = x->dp + m;
  42. /* set carry to zero */
  43. mu = 0;
  44. /* compute (x mod B**m) + k * [x/B**m] inline and inplace */
  45. for (i = 0; i < m; i++) {
  46. r = ((mp_word)*tmpx2++ * (mp_word)k) + *tmpx1 + mu;
  47. *tmpx1++ = (mp_digit)(r & MP_MASK);
  48. mu = (mp_digit)(r >> ((mp_word)MP_DIGIT_BIT));
  49. }
  50. /* set final carry */
  51. *tmpx1++ = mu;
  52. /* zero words above m */
  53. MP_ZERO_DIGITS(tmpx1, (x->used - m) - 1);
  54. /* clamp, sub and return */
  55. mp_clamp(x);
  56. /* if x >= n then subtract and reduce again
  57. * Each successive "recursion" makes the input smaller and smaller.
  58. */
  59. if (mp_cmp_mag(x, n) != MP_LT) {
  60. if ((err = s_mp_sub(x, n, x)) != MP_OKAY) {
  61. return err;
  62. }
  63. goto top;
  64. }
  65. return MP_OKAY;
  66. }
  67. #endif