1 #include "tommath_private.h"
2 #ifdef S_MP_EXPTMOD_FAST_C
3 /* LibTomMath, multiple-precision integer library -- Tom St Denis */
4 /* SPDX-License-Identifier: Unlicense */
6 /* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
8 * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
9 * The value of k changes based on the size of the exponent.
11 * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
16 # define MAX_WINSIZE 5
19 # define MAX_WINSIZE 0
22 mp_err
s_mp_exptmod_fast(const mp_int
*G
, const mp_int
*X
, const mp_int
*P
, mp_int
*Y
, int redmode
)
24 mp_int M
[TAB_SIZE
], res
;
26 int bitbuf
, bitcpy
, bitcnt
, mode
, digidx
, x
, y
, winsize
;
29 /* use a pointer to the reduction algorithm. This allows us to use
30 * one of many reduction algorithms without modding the guts of
31 * the code with if statements everywhere.
33 mp_err(*redux
)(mp_int
*x
, const mp_int
*n
, mp_digit rho
);
35 /* find window size */
41 } else if (x
<= 140) {
43 } else if (x
<= 450) {
45 } else if (x
<= 1303) {
47 } else if (x
<= 3529) {
53 winsize
= MAX_WINSIZE
? MP_MIN(MAX_WINSIZE
, winsize
) : winsize
;
57 if ((err
= mp_init_size(&M
[1], P
->alloc
)) != MP_OKAY
) {
61 /* now init the second half of the array */
62 for (x
= 1<<(winsize
-1); x
< (1 << winsize
); x
++) {
63 if ((err
= mp_init_size(&M
[x
], P
->alloc
)) != MP_OKAY
) {
64 for (y
= 1<<(winsize
-1); y
< x
; y
++) {
72 /* determine and setup reduction code */
74 if (MP_HAS(MP_MONTGOMERY_SETUP
)) {
75 /* now setup montgomery */
76 if ((err
= mp_montgomery_setup(P
, &mp
)) != MP_OKAY
) goto LBL_M
;
82 /* automatically pick the comba one if available (saves quite a few calls/ifs) */
83 if (MP_HAS(S_MP_MONTGOMERY_REDUCE_COMBA
) &&
84 (((P
->used
* 2) + 1) < MP_WARRAY
) &&
85 (P
->used
< MP_MAX_COMBA
)) {
86 redux
= s_mp_montgomery_reduce_comba
;
87 } else if (MP_HAS(MP_MONTGOMERY_REDUCE
)) {
88 /* use slower baseline Montgomery method */
89 redux
= mp_montgomery_reduce
;
94 } else if (redmode
== 1) {
95 if (MP_HAS(MP_DR_SETUP
) && MP_HAS(MP_DR_REDUCE
)) {
96 /* setup DR reduction for moduli of the form B**k - b */
103 } else if (MP_HAS(MP_REDUCE_2K_SETUP
) && MP_HAS(MP_REDUCE_2K
)) {
104 /* setup DR reduction for moduli of the form 2**k - b */
105 if ((err
= mp_reduce_2k_setup(P
, &mp
)) != MP_OKAY
) goto LBL_M
;
106 redux
= mp_reduce_2k
;
113 if ((err
= mp_init_size(&res
, P
->alloc
)) != MP_OKAY
) goto LBL_M
;
119 * The first half of the table is not computed though accept for M[0] and M[1]
123 if (MP_HAS(MP_MONTGOMERY_CALC_NORMALIZATION
)) {
124 /* now we need R mod m */
125 if ((err
= mp_montgomery_calc_normalization(&res
, P
)) != MP_OKAY
) goto LBL_RES
;
127 /* now set M[1] to G * R mod m */
128 if ((err
= mp_mulmod(G
, &res
, P
, &M
[1])) != MP_OKAY
) goto LBL_RES
;
135 if ((err
= mp_mod(G
, P
, &M
[1])) != MP_OKAY
) goto LBL_RES
;
138 /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
139 if ((err
= mp_copy(&M
[1], &M
[(size_t)1 << (winsize
- 1)])) != MP_OKAY
) goto LBL_RES
;
141 for (x
= 0; x
< (winsize
- 1); x
++) {
142 if ((err
= mp_sqr(&M
[(size_t)1 << (winsize
- 1)], &M
[(size_t)1 << (winsize
- 1)])) != MP_OKAY
) goto LBL_RES
;
143 if ((err
= redux(&M
[(size_t)1 << (winsize
- 1)], P
, mp
)) != MP_OKAY
) goto LBL_RES
;
146 /* create upper table */
147 for (x
= (1 << (winsize
- 1)) + 1; x
< (1 << winsize
); x
++) {
148 if ((err
= mp_mul(&M
[x
- 1], &M
[1], &M
[x
])) != MP_OKAY
) goto LBL_RES
;
149 if ((err
= redux(&M
[x
], P
, mp
)) != MP_OKAY
) goto LBL_RES
;
152 /* set initial mode and bit cnt */
156 digidx
= X
->used
- 1;
161 /* grab next digit as required */
163 /* if digidx == -1 we are out of digits so break */
167 /* read next digit and reset bitcnt */
168 buf
= X
->dp
[digidx
--];
169 bitcnt
= (int)MP_DIGIT_BIT
;
172 /* grab the next msb from the exponent */
173 y
= (mp_digit
)(buf
>> (MP_DIGIT_BIT
- 1)) & 1uL;
176 /* if the bit is zero and mode == 0 then we ignore it
177 * These represent the leading zero bits before the first 1 bit
178 * in the exponent. Technically this opt is not required but it
179 * does lower the # of trivial squaring/reductions used
181 if ((mode
== 0) && (y
== 0)) {
185 /* if the bit is zero and mode == 1 then we square */
186 if ((mode
== 1) && (y
== 0)) {
187 if ((err
= mp_sqr(&res
, &res
)) != MP_OKAY
) goto LBL_RES
;
188 if ((err
= redux(&res
, P
, mp
)) != MP_OKAY
) goto LBL_RES
;
192 /* else we add it to the window */
193 bitbuf
|= (y
<< (winsize
- ++bitcpy
));
196 if (bitcpy
== winsize
) {
197 /* ok window is filled so square as required and multiply */
199 for (x
= 0; x
< winsize
; x
++) {
200 if ((err
= mp_sqr(&res
, &res
)) != MP_OKAY
) goto LBL_RES
;
201 if ((err
= redux(&res
, P
, mp
)) != MP_OKAY
) goto LBL_RES
;
205 if ((err
= mp_mul(&res
, &M
[bitbuf
], &res
)) != MP_OKAY
) goto LBL_RES
;
206 if ((err
= redux(&res
, P
, mp
)) != MP_OKAY
) goto LBL_RES
;
208 /* empty window and reset */
215 /* if bits remain then square/multiply */
216 if ((mode
== 2) && (bitcpy
> 0)) {
217 /* square then multiply if the bit is set */
218 for (x
= 0; x
< bitcpy
; x
++) {
219 if ((err
= mp_sqr(&res
, &res
)) != MP_OKAY
) goto LBL_RES
;
220 if ((err
= redux(&res
, P
, mp
)) != MP_OKAY
) goto LBL_RES
;
222 /* get next bit of the window */
224 if ((bitbuf
& (1 << winsize
)) != 0) {
226 if ((err
= mp_mul(&res
, &M
[1], &res
)) != MP_OKAY
) goto LBL_RES
;
227 if ((err
= redux(&res
, P
, mp
)) != MP_OKAY
) goto LBL_RES
;
233 /* fixup result if Montgomery reduction is used
234 * recall that any value in a Montgomery system is
235 * actually multiplied by R mod n. So we have
236 * to reduce one more time to cancel out the factor
239 if ((err
= redux(&res
, P
, mp
)) != MP_OKAY
) goto LBL_RES
;
242 /* swap res with Y */
249 for (x
= 1<<(winsize
-1); x
< (1 << winsize
); x
++) {