1 #include "tommath_private.h"
2 #ifdef BN_S_MP_EXPTMOD_C
3 /* LibTomMath, multiple-precision integer library -- Tom St Denis */
4 /* SPDX-License-Identifier: Unlicense */
11 # define MAX_WINSIZE 0
14 mp_err
s_mp_exptmod(const mp_int
*G
, const mp_int
*X
, const mp_int
*P
, mp_int
*Y
, int redmode
)
16 mp_int M
[TAB_SIZE
], res
, mu
;
19 int bitbuf
, bitcpy
, bitcnt
, mode
, digidx
, x
, y
, winsize
;
20 mp_err(*redux
)(mp_int
*x
, const mp_int
*m
, const mp_int
*mu
);
22 /* find window size */
28 } else if (x
<= 140) {
30 } else if (x
<= 450) {
32 } else if (x
<= 1303) {
34 } else if (x
<= 3529) {
40 winsize
= MAX_WINSIZE
? MP_MIN(MAX_WINSIZE
, winsize
) : winsize
;
44 if ((err
= mp_init(&M
[1])) != MP_OKAY
) {
48 /* now init the second half of the array */
49 for (x
= 1<<(winsize
-1); x
< (1 << winsize
); x
++) {
50 if ((err
= mp_init(&M
[x
])) != MP_OKAY
) {
51 for (y
= 1<<(winsize
-1); y
< x
; y
++) {
59 /* create mu, used for Barrett reduction */
60 if ((err
= mp_init(&mu
)) != MP_OKAY
) goto LBL_M
;
63 if ((err
= mp_reduce_setup(&mu
, P
)) != MP_OKAY
) goto LBL_MU
;
66 if ((err
= mp_reduce_2k_setup_l(P
, &mu
)) != MP_OKAY
) goto LBL_MU
;
67 redux
= mp_reduce_2k_l
;
72 * The M table contains powers of the base,
73 * e.g. M[x] = G**x mod P
75 * The first half of the table is not
76 * computed though accept for M[0] and M[1]
78 if ((err
= mp_mod(G
, P
, &M
[1])) != MP_OKAY
) goto LBL_MU
;
80 /* compute the value at M[1<<(winsize-1)] by squaring
81 * M[1] (winsize-1) times
83 if ((err
= mp_copy(&M
[1], &M
[(size_t)1 << (winsize
- 1)])) != MP_OKAY
) goto LBL_MU
;
85 for (x
= 0; x
< (winsize
- 1); x
++) {
87 if ((err
= mp_sqr(&M
[(size_t)1 << (winsize
- 1)],
88 &M
[(size_t)1 << (winsize
- 1)])) != MP_OKAY
) goto LBL_MU
;
91 if ((err
= redux(&M
[(size_t)1 << (winsize
- 1)], P
, &mu
)) != MP_OKAY
) goto LBL_MU
;
94 /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
95 * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
97 for (x
= (1 << (winsize
- 1)) + 1; x
< (1 << winsize
); x
++) {
98 if ((err
= mp_mul(&M
[x
- 1], &M
[1], &M
[x
])) != MP_OKAY
) goto LBL_MU
;
99 if ((err
= redux(&M
[x
], P
, &mu
)) != MP_OKAY
) goto LBL_MU
;
103 if ((err
= mp_init(&res
)) != MP_OKAY
) goto LBL_MU
;
106 /* set initial mode and bit cnt */
110 digidx
= X
->used
- 1;
115 /* grab next digit as required */
117 /* if digidx == -1 we are out of digits */
121 /* read next digit and reset the bitcnt */
122 buf
= X
->dp
[digidx
--];
123 bitcnt
= (int)MP_DIGIT_BIT
;
126 /* grab the next msb from the exponent */
127 y
= (buf
>> (mp_digit
)(MP_DIGIT_BIT
- 1)) & 1uL;
130 /* if the bit is zero and mode == 0 then we ignore it
131 * These represent the leading zero bits before the first 1 bit
132 * in the exponent. Technically this opt is not required but it
133 * does lower the # of trivial squaring/reductions used
135 if ((mode
== 0) && (y
== 0)) {
139 /* if the bit is zero and mode == 1 then we square */
140 if ((mode
== 1) && (y
== 0)) {
141 if ((err
= mp_sqr(&res
, &res
)) != MP_OKAY
) goto LBL_RES
;
142 if ((err
= redux(&res
, P
, &mu
)) != MP_OKAY
) goto LBL_RES
;
146 /* else we add it to the window */
147 bitbuf
|= (y
<< (winsize
- ++bitcpy
));
150 if (bitcpy
== winsize
) {
151 /* ok window is filled so square as required and multiply */
153 for (x
= 0; x
< winsize
; x
++) {
154 if ((err
= mp_sqr(&res
, &res
)) != MP_OKAY
) goto LBL_RES
;
155 if ((err
= redux(&res
, P
, &mu
)) != MP_OKAY
) goto LBL_RES
;
159 if ((err
= mp_mul(&res
, &M
[bitbuf
], &res
)) != MP_OKAY
) goto LBL_RES
;
160 if ((err
= redux(&res
, P
, &mu
)) != MP_OKAY
) goto LBL_RES
;
162 /* empty window and reset */
169 /* if bits remain then square/multiply */
170 if ((mode
== 2) && (bitcpy
> 0)) {
171 /* square then multiply if the bit is set */
172 for (x
= 0; x
< bitcpy
; x
++) {
173 if ((err
= mp_sqr(&res
, &res
)) != MP_OKAY
) goto LBL_RES
;
174 if ((err
= redux(&res
, P
, &mu
)) != MP_OKAY
) goto LBL_RES
;
177 if ((bitbuf
& (1 << winsize
)) != 0) {
179 if ((err
= mp_mul(&res
, &M
[1], &res
)) != MP_OKAY
) goto LBL_RES
;
180 if ((err
= redux(&res
, P
, &mu
)) != MP_OKAY
) goto LBL_RES
;
193 for (x
= 1<<(winsize
-1); x
< (1 << winsize
); x
++) {