bn_s_mp_exptmod_fast.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #include "tommath_private.h"
  2. #ifdef BN_S_MP_EXPTMOD_FAST_C
  3. /* LibTomMath, multiple-precision integer library -- Tom St Denis */
  4. /* SPDX-License-Identifier: Unlicense */
  5. /* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
  6. *
  7. * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
  8. * The value of k changes based on the size of the exponent.
  9. *
  10. * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
  11. */
  12. #ifdef MP_LOW_MEM
  13. # define TAB_SIZE 32
  14. # define MAX_WINSIZE 5
  15. #else
  16. # define TAB_SIZE 256
  17. # define MAX_WINSIZE 0
  18. #endif
  19. mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode)
  20. {
  21. mp_int M[TAB_SIZE], res;
  22. mp_digit buf, mp;
  23. int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
  24. mp_err err;
  25. /* use a pointer to the reduction algorithm. This allows us to use
  26. * one of many reduction algorithms without modding the guts of
  27. * the code with if statements everywhere.
  28. */
  29. mp_err(*redux)(mp_int *x, const mp_int *n, mp_digit rho);
  30. /* find window size */
  31. x = mp_count_bits(X);
  32. if (x <= 7) {
  33. winsize = 2;
  34. } else if (x <= 36) {
  35. winsize = 3;
  36. } else if (x <= 140) {
  37. winsize = 4;
  38. } else if (x <= 450) {
  39. winsize = 5;
  40. } else if (x <= 1303) {
  41. winsize = 6;
  42. } else if (x <= 3529) {
  43. winsize = 7;
  44. } else {
  45. winsize = 8;
  46. }
  47. winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize;
  48. /* init M array */
  49. /* init first cell */
  50. if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) {
  51. return err;
  52. }
  53. /* now init the second half of the array */
  54. for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
  55. if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) {
  56. for (y = 1<<(winsize-1); y < x; y++) {
  57. mp_clear(&M[y]);
  58. }
  59. mp_clear(&M[1]);
  60. return err;
  61. }
  62. }
  63. /* determine and setup reduction code */
  64. if (redmode == 0) {
  65. if (MP_HAS(MP_MONTGOMERY_SETUP)) {
  66. /* now setup montgomery */
  67. if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) goto LBL_M;
  68. } else {
  69. err = MP_VAL;
  70. goto LBL_M;
  71. }
  72. /* automatically pick the comba one if available (saves quite a few calls/ifs) */
  73. if (MP_HAS(S_MP_MONTGOMERY_REDUCE_FAST) &&
  74. (((P->used * 2) + 1) < MP_WARRAY) &&
  75. (P->used < MP_MAXFAST)) {
  76. redux = s_mp_montgomery_reduce_fast;
  77. } else if (MP_HAS(MP_MONTGOMERY_REDUCE)) {
  78. /* use slower baseline Montgomery method */
  79. redux = mp_montgomery_reduce;
  80. } else {
  81. err = MP_VAL;
  82. goto LBL_M;
  83. }
  84. } else if (redmode == 1) {
  85. if (MP_HAS(MP_DR_SETUP) && MP_HAS(MP_DR_REDUCE)) {
  86. /* setup DR reduction for moduli of the form B**k - b */
  87. mp_dr_setup(P, &mp);
  88. redux = mp_dr_reduce;
  89. } else {
  90. err = MP_VAL;
  91. goto LBL_M;
  92. }
  93. } else if (MP_HAS(MP_REDUCE_2K_SETUP) && MP_HAS(MP_REDUCE_2K)) {
  94. /* setup DR reduction for moduli of the form 2**k - b */
  95. if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) goto LBL_M;
  96. redux = mp_reduce_2k;
  97. } else {
  98. err = MP_VAL;
  99. goto LBL_M;
  100. }
  101. /* setup result */
  102. if ((err = mp_init_size(&res, P->alloc)) != MP_OKAY) goto LBL_M;
  103. /* create M table
  104. *
  105. *
  106. * The first half of the table is not computed though accept for M[0] and M[1]
  107. */
  108. if (redmode == 0) {
  109. if (MP_HAS(MP_MONTGOMERY_CALC_NORMALIZATION)) {
  110. /* now we need R mod m */
  111. if ((err = mp_montgomery_calc_normalization(&res, P)) != MP_OKAY) goto LBL_RES;
  112. /* now set M[1] to G * R mod m */
  113. if ((err = mp_mulmod(G, &res, P, &M[1])) != MP_OKAY) goto LBL_RES;
  114. } else {
  115. err = MP_VAL;
  116. goto LBL_RES;
  117. }
  118. } else {
  119. mp_set(&res, 1uL);
  120. if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) goto LBL_RES;
  121. }
  122. /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
  123. if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES;
  124. for (x = 0; x < (winsize - 1); x++) {
  125. if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES;
  126. if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, mp)) != MP_OKAY) goto LBL_RES;
  127. }
  128. /* create upper table */
  129. for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
  130. if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) goto LBL_RES;
  131. if ((err = redux(&M[x], P, mp)) != MP_OKAY) goto LBL_RES;
  132. }
  133. /* set initial mode and bit cnt */
  134. mode = 0;
  135. bitcnt = 1;
  136. buf = 0;
  137. digidx = X->used - 1;
  138. bitcpy = 0;
  139. bitbuf = 0;
  140. for (;;) {
  141. /* grab next digit as required */
  142. if (--bitcnt == 0) {
  143. /* if digidx == -1 we are out of digits so break */
  144. if (digidx == -1) {
  145. break;
  146. }
  147. /* read next digit and reset bitcnt */
  148. buf = X->dp[digidx--];
  149. bitcnt = (int)MP_DIGIT_BIT;
  150. }
  151. /* grab the next msb from the exponent */
  152. y = (mp_digit)(buf >> (MP_DIGIT_BIT - 1)) & 1uL;
  153. buf <<= (mp_digit)1;
  154. /* if the bit is zero and mode == 0 then we ignore it
  155. * These represent the leading zero bits before the first 1 bit
  156. * in the exponent. Technically this opt is not required but it
  157. * does lower the # of trivial squaring/reductions used
  158. */
  159. if ((mode == 0) && (y == 0)) {
  160. continue;
  161. }
  162. /* if the bit is zero and mode == 1 then we square */
  163. if ((mode == 1) && (y == 0)) {
  164. if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
  165. if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
  166. continue;
  167. }
  168. /* else we add it to the window */
  169. bitbuf |= (y << (winsize - ++bitcpy));
  170. mode = 2;
  171. if (bitcpy == winsize) {
  172. /* ok window is filled so square as required and multiply */
  173. /* square first */
  174. for (x = 0; x < winsize; x++) {
  175. if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
  176. if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
  177. }
  178. /* then multiply */
  179. if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) goto LBL_RES;
  180. if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
  181. /* empty window and reset */
  182. bitcpy = 0;
  183. bitbuf = 0;
  184. mode = 1;
  185. }
  186. }
  187. /* if bits remain then square/multiply */
  188. if ((mode == 2) && (bitcpy > 0)) {
  189. /* square then multiply if the bit is set */
  190. for (x = 0; x < bitcpy; x++) {
  191. if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
  192. if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
  193. /* get next bit of the window */
  194. bitbuf <<= 1;
  195. if ((bitbuf & (1 << winsize)) != 0) {
  196. /* then multiply */
  197. if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) goto LBL_RES;
  198. if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
  199. }
  200. }
  201. }
  202. if (redmode == 0) {
  203. /* fixup result if Montgomery reduction is used
  204. * recall that any value in a Montgomery system is
  205. * actually multiplied by R mod n. So we have
  206. * to reduce one more time to cancel out the factor
  207. * of R.
  208. */
  209. if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
  210. }
  211. /* swap res with Y */
  212. mp_exch(&res, Y);
  213. err = MP_OKAY;
  214. LBL_RES:
  215. mp_clear(&res);
  216. LBL_M:
  217. mp_clear(&M[1]);
  218. for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
  219. mp_clear(&M[x]);
  220. }
  221. return err;
  222. }
  223. #endif