#include "amplify_tommath_private.h" #ifdef AMPLIFY_BN_S_MP_EXPTMOD_C /* LibTomMath, multiple-precision integer library -- Tom St Denis */ /* SPDX-License-Identifier: Unlicense */ /* Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. */ #ifdef AMPLIFY_MP_LOW_MEM # define TAB_SIZE 32 # define MAX_WINSIZE 5 #else # define TAB_SIZE 256 # define MAX_WINSIZE 0 #endif amplify_mp_err amplify_s_mp_exptmod(const amplify_mp_int *G, const amplify_mp_int *X, const amplify_mp_int *P, amplify_mp_int *Y, int redmode) { amplify_mp_int M[TAB_SIZE], res, mu; amplify_mp_digit buf; amplify_mp_err err; int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; amplify_mp_err(*redux)(amplify_mp_int *x, const amplify_mp_int *m, const amplify_mp_int *mu); /* find window size */ x = amplify_mp_count_bits(X); if (x <= 7) { winsize = 2; } else if (x <= 36) { winsize = 3; } else if (x <= 140) { winsize = 4; } else if (x <= 450) { winsize = 5; } else if (x <= 1303) { winsize = 6; } else if (x <= 3529) { winsize = 7; } else { winsize = 8; } winsize = MAX_WINSIZE ? AMPLIFY_MP_MIN(MAX_WINSIZE, winsize) : winsize; /* init M array */ /* init first cell */ if ((err = amplify_mp_init(&M[1])) != AMPLIFY_MP_OKAY) { return err; } /* now init the second half of the array */ for (x = 1<<(winsize-1); x < (1 << winsize); x++) { if ((err = amplify_mp_init(&M[x])) != AMPLIFY_MP_OKAY) { for (y = 1<<(winsize-1); y < x; y++) { amplify_mp_clear(&M[y]); } amplify_mp_clear(&M[1]); return err; } } /* create mu, used for Barrett reduction */ if ((err = amplify_mp_init(&mu)) != AMPLIFY_MP_OKAY) goto LBL_M; if (redmode == 0) { if ((err = amplify_mp_reduce_setup(&mu, P)) != AMPLIFY_MP_OKAY) goto LBL_MU; redux = amplify_mp_reduce; } else { if ((err = amplify_mp_reduce_2k_setup_l(P, &mu)) != AMPLIFY_MP_OKAY) goto LBL_MU; redux = amplify_mp_reduce_2k_l; } /* create M table * * The M table contains powers of the base, * e.g. M[x] = G**x mod P * * The first half of the table is not * computed though accept for M[0] and M[1] */ if ((err = amplify_mp_mod(G, P, &M[1])) != AMPLIFY_MP_OKAY) goto LBL_MU; /* compute the value at M[1<<(winsize-1)] by squaring * M[1] (winsize-1) times */ if ((err = amplify_mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != AMPLIFY_MP_OKAY) goto LBL_MU; for (x = 0; x < (winsize - 1); x++) { /* square it */ if ((err = amplify_mp_sqr(&M[(size_t)1 << (winsize - 1)], &M[(size_t)1 << (winsize - 1)])) != AMPLIFY_MP_OKAY) goto LBL_MU; /* reduce modulo P */ if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, &mu)) != AMPLIFY_MP_OKAY) goto LBL_MU; } /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) */ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { if ((err = amplify_mp_mul(&M[x - 1], &M[1], &M[x])) != AMPLIFY_MP_OKAY) goto LBL_MU; if ((err = redux(&M[x], P, &mu)) != AMPLIFY_MP_OKAY) goto LBL_MU; } /* setup result */ if ((err = amplify_mp_init(&res)) != AMPLIFY_MP_OKAY) goto LBL_MU; amplify_mp_set(&res, 1uL); /* set initial mode and bit cnt */ mode = 0; bitcnt = 1; buf = 0; digidx = X->used - 1; bitcpy = 0; bitbuf = 0; for (;;) { /* grab next digit as required */ if (--bitcnt == 0) { /* if digidx == -1 we are out of digits */ if (digidx == -1) { break; } /* read next digit and reset the bitcnt */ buf = X->dp[digidx--]; bitcnt = (int)AMPLIFY_MP_DIGIT_BIT; } /* grab the next msb from the exponent */ y = (buf >> (amplify_mp_digit)(AMPLIFY_MP_DIGIT_BIT - 1)) & 1uL; buf <<= (amplify_mp_digit)1; /* if the bit is zero and mode == 0 then we ignore it * These represent the leading zero bits before the first 1 bit * in the exponent. Technically this opt is not required but it * does lower the # of trivial squaring/reductions used */ if ((mode == 0) && (y == 0)) { continue; } /* if the bit is zero and mode == 1 then we square */ if ((mode == 1) && (y == 0)) { if ((err = amplify_mp_sqr(&res, &res)) != AMPLIFY_MP_OKAY) goto LBL_RES; if ((err = redux(&res, P, &mu)) != AMPLIFY_MP_OKAY) goto LBL_RES; continue; } /* else we add it to the window */ bitbuf |= (y << (winsize - ++bitcpy)); mode = 2; if (bitcpy == winsize) { /* ok window is filled so square as required and multiply */ /* square first */ for (x = 0; x < winsize; x++) { if ((err = amplify_mp_sqr(&res, &res)) != AMPLIFY_MP_OKAY) goto LBL_RES; if ((err = redux(&res, P, &mu)) != AMPLIFY_MP_OKAY) goto LBL_RES; } /* then multiply */ if ((err = amplify_mp_mul(&res, &M[bitbuf], &res)) != AMPLIFY_MP_OKAY) goto LBL_RES; if ((err = redux(&res, P, &mu)) != AMPLIFY_MP_OKAY) goto LBL_RES; /* empty window and reset */ bitcpy = 0; bitbuf = 0; mode = 1; } } /* if bits remain then square/multiply */ if ((mode == 2) && (bitcpy > 0)) { /* square then multiply if the bit is set */ for (x = 0; x < bitcpy; x++) { if ((err = amplify_mp_sqr(&res, &res)) != AMPLIFY_MP_OKAY) goto LBL_RES; if ((err = redux(&res, P, &mu)) != AMPLIFY_MP_OKAY) goto LBL_RES; bitbuf <<= 1; if ((bitbuf & (1 << winsize)) != 0) { /* then multiply */ if ((err = amplify_mp_mul(&res, &M[1], &res)) != AMPLIFY_MP_OKAY) goto LBL_RES; if ((err = redux(&res, P, &mu)) != AMPLIFY_MP_OKAY) goto LBL_RES; } } } amplify_mp_exch(&res, Y); err = AMPLIFY_MP_OKAY; LBL_RES: amplify_mp_clear(&res); LBL_MU: amplify_mp_clear(&mu); LBL_M: amplify_mp_clear(&M[1]); for (x = 1<<(winsize-1); x < (1 << winsize); x++) { amplify_mp_clear(&M[x]); } return err; } #endif