mpi-div.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* mpi-div.c - MPI functions
  2. * Copyright (C) 1994, 1996, 1998, 2001, 2002,
  3. * 2003 Free Software Foundation, Inc.
  4. *
  5. * This file is part of Libgcrypt.
  6. *
  7. * Note: This code is heavily based on the GNU MP Library.
  8. * Actually it's the same code with only minor changes in the
  9. * way the data is stored; this is to support the abstraction
  10. * of an optional secure memory allocation which may be used
  11. * to avoid revealing of sensitive data due to paging etc.
  12. */
  13. #include "mpi-internal.h"
  14. #include "longlong.h"
  15. int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den);
  16. int mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor)
  17. {
  18. int divisor_sign = divisor->sign;
  19. MPI temp_divisor = NULL;
  20. int err;
  21. /* We need the original value of the divisor after the remainder has been
  22. * preliminary calculated. We have to copy it to temporary space if it's
  23. * the same variable as REM.
  24. */
  25. if (rem == divisor) {
  26. temp_divisor = mpi_copy(divisor);
  27. if (!temp_divisor)
  28. return -ENOMEM;
  29. divisor = temp_divisor;
  30. }
  31. err = mpi_tdiv_r(rem, dividend, divisor);
  32. if (err)
  33. goto free_temp_divisor;
  34. if (((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs)
  35. err = mpi_add(rem, rem, divisor);
  36. free_temp_divisor:
  37. mpi_free(temp_divisor);
  38. return err;
  39. }
  40. /* If den == quot, den needs temporary storage.
  41. * If den == rem, den needs temporary storage.
  42. * If num == quot, num needs temporary storage.
  43. * If den has temporary storage, it can be normalized while being copied,
  44. * i.e no extra storage should be allocated.
  45. */
  46. int mpi_tdiv_r(MPI rem, MPI num, MPI den)
  47. {
  48. return mpi_tdiv_qr(NULL, rem, num, den);
  49. }
  50. int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den)
  51. {
  52. mpi_ptr_t np, dp;
  53. mpi_ptr_t qp, rp;
  54. mpi_size_t nsize = num->nlimbs;
  55. mpi_size_t dsize = den->nlimbs;
  56. mpi_size_t qsize, rsize;
  57. mpi_size_t sign_remainder = num->sign;
  58. mpi_size_t sign_quotient = num->sign ^ den->sign;
  59. unsigned int normalization_steps;
  60. mpi_limb_t q_limb;
  61. mpi_ptr_t marker[5];
  62. int markidx = 0;
  63. int err;
  64. /* Ensure space is enough for quotient and remainder.
  65. * We need space for an extra limb in the remainder, because it's
  66. * up-shifted (normalized) below.
  67. */
  68. rsize = nsize + 1;
  69. err = mpi_resize(rem, rsize);
  70. if (err)
  71. return err;
  72. qsize = rsize - dsize; /* qsize cannot be bigger than this. */
  73. if (qsize <= 0) {
  74. if (num != rem) {
  75. rem->nlimbs = num->nlimbs;
  76. rem->sign = num->sign;
  77. MPN_COPY(rem->d, num->d, nsize);
  78. }
  79. if (quot) {
  80. /* This needs to follow the assignment to rem, in case the
  81. * numerator and quotient are the same.
  82. */
  83. quot->nlimbs = 0;
  84. quot->sign = 0;
  85. }
  86. return 0;
  87. }
  88. if (quot) {
  89. err = mpi_resize(quot, qsize);
  90. if (err)
  91. return err;
  92. }
  93. /* Read pointers here, when reallocation is finished. */
  94. np = num->d;
  95. dp = den->d;
  96. rp = rem->d;
  97. /* Optimize division by a single-limb divisor. */
  98. if (dsize == 1) {
  99. mpi_limb_t rlimb;
  100. if (quot) {
  101. qp = quot->d;
  102. rlimb = mpihelp_divmod_1(qp, np, nsize, dp[0]);
  103. qsize -= qp[qsize - 1] == 0;
  104. quot->nlimbs = qsize;
  105. quot->sign = sign_quotient;
  106. } else
  107. rlimb = mpihelp_mod_1(np, nsize, dp[0]);
  108. rp[0] = rlimb;
  109. rsize = rlimb != 0?1:0;
  110. rem->nlimbs = rsize;
  111. rem->sign = sign_remainder;
  112. return 0;
  113. }
  114. err = -ENOMEM;
  115. if (quot) {
  116. qp = quot->d;
  117. /* Make sure QP and NP point to different objects. Otherwise the
  118. * numerator would be gradually overwritten by the quotient limbs.
  119. */
  120. if (qp == np) { /* Copy NP object to temporary space. */
  121. np = marker[markidx++] = mpi_alloc_limb_space(nsize);
  122. if (!np)
  123. goto out_free_marker;
  124. MPN_COPY(np, qp, nsize);
  125. }
  126. } else /* Put quotient at top of remainder. */
  127. qp = rp + dsize;
  128. normalization_steps = count_leading_zeros(dp[dsize - 1]);
  129. /* Normalize the denominator, i.e. make its most significant bit set by
  130. * shifting it NORMALIZATION_STEPS bits to the left. Also shift the
  131. * numerator the same number of steps (to keep the quotient the same!).
  132. */
  133. if (normalization_steps) {
  134. mpi_ptr_t tp;
  135. mpi_limb_t nlimb;
  136. /* Shift up the denominator setting the most significant bit of
  137. * the most significant word. Use temporary storage not to clobber
  138. * the original contents of the denominator.
  139. */
  140. tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
  141. if (!tp)
  142. goto out_free_marker;
  143. mpihelp_lshift(tp, dp, dsize, normalization_steps);
  144. dp = tp;
  145. /* Shift up the numerator, possibly introducing a new most
  146. * significant word. Move the shifted numerator in the remainder
  147. * meanwhile.
  148. */
  149. nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps);
  150. if (nlimb) {
  151. rp[nsize] = nlimb;
  152. rsize = nsize + 1;
  153. } else
  154. rsize = nsize;
  155. } else {
  156. /* The denominator is already normalized, as required. Copy it to
  157. * temporary space if it overlaps with the quotient or remainder.
  158. */
  159. if (dp == rp || (quot && (dp == qp))) {
  160. mpi_ptr_t tp;
  161. tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
  162. if (!tp)
  163. goto out_free_marker;
  164. MPN_COPY(tp, dp, dsize);
  165. dp = tp;
  166. }
  167. /* Move the numerator to the remainder. */
  168. if (rp != np)
  169. MPN_COPY(rp, np, nsize);
  170. rsize = nsize;
  171. }
  172. q_limb = mpihelp_divrem(qp, 0, rp, rsize, dp, dsize);
  173. if (quot) {
  174. qsize = rsize - dsize;
  175. if (q_limb) {
  176. qp[qsize] = q_limb;
  177. qsize += 1;
  178. }
  179. quot->nlimbs = qsize;
  180. quot->sign = sign_quotient;
  181. }
  182. rsize = dsize;
  183. MPN_NORMALIZE(rp, rsize);
  184. if (normalization_steps && rsize) {
  185. mpihelp_rshift(rp, rp, rsize, normalization_steps);
  186. rsize -= rp[rsize - 1] == 0?1:0;
  187. }
  188. rem->nlimbs = rsize;
  189. rem->sign = sign_remainder;
  190. err = 0;
  191. out_free_marker:
  192. while (markidx) {
  193. markidx--;
  194. mpi_free_limb_space(marker[markidx]);
  195. }
  196. return err;
  197. }