#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#ifdef USE_FAST_MATH
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/tfm.h>
#include <wolfcrypt/src/asm.c>
#include <wolfssl/wolfcrypt/wolfmath.h>
#include <wolfssl/wolfcrypt/logging.h>
#ifdef WOLFSSL_ESPIDF
#include <esp_log.h>
#include <wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h>
#endif
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI)
static const char* TAG = "TFM";
#if !defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI)
#define WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL
#define WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD
#define WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD
#endif
#if defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL)
#undef WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL
#endif
#if defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD)
#undef WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD
#endif
#if defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD)
#undef WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD
#endif
#endif
#if defined(FREESCALE_LTC_TFM)
#include <wolfssl/wolfcrypt/port/nxp/ksdk_port.h>
#endif
#ifdef WOLFSSL_DEBUG_MATH
#include <stdio.h>
#endif
#if defined(WOLFSSL_HAVE_SP_RSA) || defined(WOLFSSL_HAVE_SP_DH)
#ifdef __cplusplus
extern "C" {
#endif
WOLFSSL_LOCAL int sp_ModExp_1024(mp_int* base, mp_int* exp, mp_int* mod,
mp_int* res);
WOLFSSL_LOCAL int sp_ModExp_1536(mp_int* base, mp_int* exp, mp_int* mod,
mp_int* res);
WOLFSSL_LOCAL int sp_ModExp_2048(mp_int* base, mp_int* exp, mp_int* mod,
mp_int* res);
WOLFSSL_LOCAL int sp_ModExp_3072(mp_int* base, mp_int* exp, mp_int* mod,
mp_int* res);
WOLFSSL_LOCAL int sp_ModExp_4096(mp_int* base, mp_int* exp, mp_int* mod,
mp_int* res);
#ifdef __cplusplus
}
#endif
#endif
#if !defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_SP_MATH_ALL)
word32 CheckRunTimeSettings(void)
{
return CTC_SETTINGS;
}
word32 CheckRunTimeFastMath(void)
{
return FP_SIZE;
}
#endif
int fp_add(fp_int *a, fp_int *b, fp_int *c)
{
int sa, sb;
int ret = FP_OKAY;
sa = a->sign;
sb = b->sign;
if (sa == sb) {
c->sign = sa;
ret = s_fp_add (a, b, c);
} else {
if (fp_cmp_mag (a, b) == FP_LT) {
c->sign = sb;
s_fp_sub (b, a, c);
} else {
c->sign = sa;
s_fp_sub (a, b, c);
}
}
return ret;
}
int s_fp_add(fp_int *a, fp_int *b, fp_int *c)
{
int x, y, oldused;
fp_word t;
y = MAX(a->used, b->used);
oldused = MIN(c->used, FP_SIZE);
c->used = y;
t = 0;
#ifdef HONOR_MATH_USED_LENGTH
for (x = 0; x < y; x++) {
if ( (x < a->used) && (x < b->used) ) {
t += ((fp_word)a->dp[x]) + ((fp_word)b->dp[x]);
}
else {
if ((x >= a->used) && (x < b->used)) {
t += ((fp_word)b->dp[x]);
}
else {
if ((x < a->used) && (x >= b->used)) {
t += ((fp_word)a->dp[x]) ;
}
else {
}
}
}
c->dp[x] = (fp_digit)t;
t >>= DIGIT_BIT;
}
#else
for (x = 0; x < y; x++) {
t += ((fp_word)a->dp[x]) + ((fp_word)b->dp[x]);
c->dp[x] = (fp_digit)t;
t >>= DIGIT_BIT;
}
#endif
if (t != 0) {
if (x == FP_SIZE)
return FP_VAL;
c->dp[c->used++] = (fp_digit)t;
++x;
}
c->used = x;
for (; x < oldused; x++) {
c->dp[x] = 0;
}
fp_clamp(c);
return FP_OKAY;
}
int fp_sub(fp_int *a, fp_int *b, fp_int *c)
{
int sa, sb;
int ret = FP_OKAY;
sa = a->sign;
sb = b->sign;
if (sa != sb) {
c->sign = sa;
ret = s_fp_add (a, b, c);
} else {
if (fp_cmp_mag (a, b) != FP_LT) {
c->sign = sa;
s_fp_sub (a, b, c);
} else {
c->sign = (sa == FP_ZPOS) ? FP_NEG : FP_ZPOS;
s_fp_sub (b, a, c);
}
}
return ret;
}
void s_fp_sub(fp_int *a, fp_int *b, fp_int *c)
{
int x, oldbused, oldused;
fp_word t;
oldused = c->used;
oldbused = b->used;
c->used = a->used;
t = 0;
for (x = 0; x < oldbused; x++) {
t = ((fp_word)a->dp[x]) - (((fp_word)b->dp[x]) + t);
c->dp[x] = (fp_digit)t;
t = (t >> DIGIT_BIT)&1;
}
for (; x < a->used; x++) {
t = ((fp_word)a->dp[x]) - t;
c->dp[x] = (fp_digit)t;
t = (t >> DIGIT_BIT)&1;
}
for (; x < oldused; x++) {
c->dp[x] = 0;
}
fp_clamp(c);
}
int fp_mul(fp_int *A, fp_int *B, fp_int *C)
{
int ret = FP_OKAY;
int y, yy, oldused;
oldused = C->used;
y = MAX(A->used, B->used);
yy = MIN(A->used, B->used);
if (y + yy >= FP_SIZE) {
ret = FP_VAL;
goto clean;
}
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL)
if (esp_hw_validation_active()) {
ESP_LOGV(TAG, "Skipping call to esp_mp_mul "
"during active validation.");
}
else {
ret = esp_mp_mul(A, B, C);
switch (ret) {
case MP_OKAY:
goto clean;
break;
case WC_NO_ERR_TRACE(WC_HW_WAIT_E):
case MP_HW_FALLBACK:
case MP_HW_VALIDATION_ACTIVE:
break;
default:
goto clean;
break;
}
}
#endif
#if defined(TFM_MUL3) && FP_SIZE >= 6
if (y <= 3) {
ret = fp_mul_comba3(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL4) && FP_SIZE >= 8
if (y == 4) {
ret = fp_mul_comba4(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL6) && FP_SIZE >= 12
if (y <= 6) {
ret = fp_mul_comba6(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL7) && FP_SIZE >= 14
if (y == 7) {
ret = fp_mul_comba7(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL8) && FP_SIZE >= 16
if (y == 8) {
ret = fp_mul_comba8(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL9) && FP_SIZE >= 18
if (y == 9) {
ret = fp_mul_comba9(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL12) && FP_SIZE >= 24
if (y <= 12) {
ret = fp_mul_comba12(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL17) && FP_SIZE >= 34
if (y <= 17) {
ret = fp_mul_comba17(A,B,C);
goto clean;
}
#endif
#if defined(TFM_SMALL_SET) && FP_SIZE >= 32
if (y <= 16) {
ret = fp_mul_comba_small(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL20) && FP_SIZE >= 40
if (y <= 20) {
ret = fp_mul_comba20(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL24) && FP_SIZE >= 48
if (yy >= 16 && y <= 24) {
ret = fp_mul_comba24(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL28) && FP_SIZE >= 56
if (yy >= 20 && y <= 28) {
ret = fp_mul_comba28(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL32) && FP_SIZE >= 64
if (yy >= 24 && y <= 32) {
ret = fp_mul_comba32(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL48) && FP_SIZE >= 96
if (yy >= 40 && y <= 48) {
ret = fp_mul_comba48(A,B,C);
goto clean;
}
#endif
#if defined(TFM_MUL64) && FP_SIZE >= 128
if (yy >= 56 && y <= 64) {
ret = fp_mul_comba64(A,B,C);
goto clean;
}
#endif
ret = fp_mul_comba(A,B,C);
clean:
for (y = C->used; y >= 0 && y < oldused; y++) {
C->dp[y] = 0;
}
return ret;
}
int fp_mul_2(fp_int * a, fp_int * b)
{
int x, oldused;
if ((a->used > (FP_SIZE-1)) || ((a->used == (FP_SIZE - 1)) &&
((a->dp[FP_SIZE - 1] & ((fp_digit)1 << (DIGIT_BIT - 1))) != 0))) {
return FP_VAL;
}
oldused = b->used;
b->used = a->used;
{
fp_digit r, rr, *tmpa, *tmpb;
tmpa = a->dp;
tmpb = b->dp;
r = 0;
for (x = 0; x < a->used; x++) {
rr = *tmpa >> ((fp_digit)(DIGIT_BIT - 1));
*tmpb++ = ((*tmpa++ << ((fp_digit)1)) | r);
r = rr;
}
if (r != 0) {
*tmpb = 1;
++(b->used);
}
tmpb = b->dp + b->used;
for (x = b->used; x < oldused; x++) {
*tmpb++ = 0;
}
}
b->sign = a->sign;
return FP_OKAY;
}
int fp_mul_d(fp_int *a, fp_digit b, fp_int *c)
{
fp_word w;
int x, oldused;
oldused = c->used;
c->used = a->used;
c->sign = a->sign;
w = 0;
for (x = 0; x < a->used; x++) {
w = ((fp_word)a->dp[x]) * ((fp_word)b) + w;
c->dp[x] = (fp_digit)w;
w = w >> DIGIT_BIT;
}
if (w != 0) {
if (a->used == FP_SIZE)
return FP_VAL;
c->dp[c->used++] = (fp_digit) w;
++x;
}
for (; x < oldused && x < FP_SIZE; x++) {
c->dp[x] = 0;
}
fp_clamp(c);
return FP_OKAY;
}
int fp_mul_2d(fp_int *a, int b, fp_int *c)
{
fp_digit carry, carrytmp, shift;
int x;
fp_copy(a, c);
if (b >= DIGIT_BIT) {
int ret = fp_lshd(c, b/DIGIT_BIT);
if (ret != FP_OKAY)
return ret;
}
b %= DIGIT_BIT;
if (b != 0) {
carry = 0;
shift = DIGIT_BIT - b;
for (x = 0; x < c->used; x++) {
carrytmp = c->dp[x] >> shift;
c->dp[x] = (c->dp[x] << b) + carry;
carry = carrytmp;
}
if (carry && x < FP_SIZE) {
c->dp[c->used++] = carry;
}
if (x == FP_SIZE)
return FP_VAL;
}
fp_clamp(c);
return FP_OKAY;
}
#if defined(HAVE_INTEL_MULX)
WC_INLINE static int fp_mul_comba_mulx(fp_int *A, fp_int *B, fp_int *C)
{
int ix, iy, iz, pa;
fp_int *dst;
WC_DECLARE_VAR(tmp, fp_int, 1, 0);
fp_digit carry;
(void)ix; (void)iy; (void)iz;
WC_ALLOC_VAR_EX(tmp, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT,
return FP_MEM);
pa = A->used + B->used;
if (pa >= FP_SIZE) {
pa = FP_SIZE-1;
}
if (1) {
fp_init(tmp);
dst = tmp;
}
TFM_INTEL_MUL_COMBA(A, B, carry, dst) ;
dst->used = pa;
dst->sign = A->sign ^ B->sign;
fp_clamp(dst);
fp_copy(dst, C);
WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
#endif
int fp_mul_comba(fp_int *A, fp_int *B, fp_int *C)
{
int ret = 0;
int ix, iy, iz, tx, ty, pa;
fp_digit c0, c1, c2, *tmpx, *tmpy;
fp_int *dst;
WC_DECLARE_VAR(tmp, fp_int, 1, 0);
if (A->used + B->used >= FP_SIZE) return FP_VAL;
IF_HAVE_INTEL_MULX(ret = fp_mul_comba_mulx(A, B, C), return ret) ;
WC_ALLOC_VAR_EX(tmp, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT,
return FP_MEM);
COMBA_START;
COMBA_CLEAR;
pa = A->used + B->used;
if (pa >= FP_SIZE) {
pa = FP_SIZE-1;
}
if (1) {
fp_init(tmp);
dst = tmp;
}
for (ix = 0; ix < pa; ix++) {
ty = MIN(ix, (B->used > 0 ? B->used - 1 : 0));
tx = ix - ty;
tmpx = A->dp + tx;
tmpy = B->dp + ty;
iy = MIN(A->used-tx, ty+1);
COMBA_FORWARD;
for (iz = 0; iz < iy; ++iz) {
fp_digit _tmpx = *tmpx++;
fp_digit _tmpy = *tmpy--;
MULADD(_tmpx, _tmpy);
}
COMBA_STORE(dst->dp[ix]);
}
COMBA_FINI;
dst->used = pa;
dst->sign = A->sign ^ B->sign;
fp_clamp(dst);
fp_copy(dst, C);
(void)c0; (void)c1; (void)c2;
WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
{
int n, t, i, norm, neg;
int ret;
#ifndef WOLFSSL_SMALL_STACK
fp_int q[1], x[1], y[1], t1[1], t2[1];
#else
fp_int *q, *x, *y, *t1, *t2;
#endif
if (fp_iszero (b) == FP_YES) {
return FP_VAL;
}
if (fp_cmp_mag (a, b) == FP_LT)
{
if (d != NULL) {
fp_copy (a, d);
}
if (c != NULL) {
fp_zero (c);
}
return FP_OKAY;
}
#ifdef WOLFSSL_SMALL_STACK
q = (fp_int*)XMALLOC(sizeof(fp_int) * 5, NULL, DYNAMIC_TYPE_BIGINT);
if (q == NULL) {
return FP_MEM;
}
x = &q[1]; y = &q[2]; t1 = &q[3]; t2 = &q[4];
#endif
fp_init(q);
q->used = a->used;
fp_init(t1);
fp_init(t2);
fp_init(x);
fp_copy(a, x);
fp_init(y);
fp_copy(b, y);
neg = (a->sign == b->sign) ? FP_ZPOS : FP_NEG;
x->sign = y->sign = FP_ZPOS;
norm = fp_count_bits(y) % DIGIT_BIT;
if (norm < (int)(DIGIT_BIT-1)) {
norm = (DIGIT_BIT-1) - norm;
ret = fp_mul_2d (x, norm, x);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
ret = fp_mul_2d (y, norm, y);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
} else {
norm = 0;
}
n = x->used - 1;
t = y->used - 1;
ret = fp_lshd (y, n - t);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
while (fp_cmp (x, y) != FP_LT) {
++(q->dp[n - t]);
ret = fp_sub (x, y, x);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
}
fp_rshd (y, n - t);
for (i = n; i >= (t + 1); i--) {
if (i > x->used) {
continue;
}
if (x->dp[i] == y->dp[t]) {
q->dp[i - t - 1] = (fp_digit) ((((fp_word)1) << DIGIT_BIT) - 1);
} else {
fp_word tmp;
tmp = ((fp_word) x->dp[i]) << ((fp_word) DIGIT_BIT);
tmp |= ((fp_word) x->dp[i - 1]);
#ifdef WOLFSSL_LINUXKM
do_div(tmp, (fp_word)y->dp[t]);
#else
tmp /= ((fp_word)y->dp[t]);
#endif
q->dp[i - t - 1] = (fp_digit) (tmp);
}
q->dp[i - t - 1] = (q->dp[i - t - 1] + 1);
do {
q->dp[i - t - 1] = (q->dp[i - t - 1] - 1);
fp_zero (t1);
t1->dp[0] = (t - 1 < 0) ? 0 : y->dp[t - 1];
t1->dp[1] = y->dp[t];
t1->used = 2;
ret = fp_mul_d (t1, q->dp[i - t - 1], t1);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
t2->dp[0] = (i - 2 < 0) ? 0 : x->dp[i - 2];
t2->dp[1] = (i - 1 < 0) ? 0 : x->dp[i - 1];
t2->dp[2] = x->dp[i];
t2->used = 3;
} while (fp_cmp_mag(t1, t2) == FP_GT);
ret = fp_mul_d (y, q->dp[i - t - 1], t1);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
ret = fp_lshd (t1, i - t - 1);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
ret = fp_sub (x, t1, x);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
if (x->sign == FP_NEG) {
fp_copy (y, t1);
ret = fp_lshd (t1, i - t - 1);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
ret = fp_add (x, t1, x);
if (ret != FP_OKAY) {
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
q->dp[i - t - 1] = q->dp[i - t - 1] - 1;
}
}
x->sign = x->used == 0 ? FP_ZPOS : a->sign;
if (c != NULL) {
fp_clamp (q);
fp_copy (q, c);
c->sign = neg;
}
if (d != NULL) {
fp_div_2d (x, norm, x, NULL);
for (i = b->used; i < x->used; i++) {
x->dp[i] = 0;
}
fp_clamp(x);
fp_copy (x, d);
}
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
void fp_div_2(fp_int * a, fp_int * b)
{
int x, oldused;
oldused = b->used;
b->used = a->used;
{
fp_digit r, rr, *tmpa, *tmpb;
tmpa = a->dp + b->used - 1;
tmpb = b->dp + b->used - 1;
r = 0;
for (x = b->used - 1; x >= 0; x--) {
rr = *tmpa & 1;
*tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
r = rr;
}
tmpb = b->dp + b->used;
for (x = b->used; x < oldused; x++) {
*tmpb++ = 0;
}
}
b->sign = a->sign;
fp_clamp (b);
}
int fp_div_2_mod_ct(fp_int *a, fp_int *b, fp_int *c)
{
fp_word w = 0;
fp_digit mask;
int i;
mask = (fp_digit)0 - (a->dp[0] & 1);
for (i = 0; i < b->used; i++) {
fp_digit mask_a = (fp_digit)0 - (i < a->used);
w += b->dp[i] & mask;
w += a->dp[i] & mask_a;
c->dp[i] = (fp_digit)w;
w >>= DIGIT_BIT;
}
for (i = 0; i < b->used-1; i++) {
c->dp[i] = (c->dp[i] >> 1) | (c->dp[i+1] << (DIGIT_BIT - 1));
}
c->dp[i] = (c->dp[i] >> 1) | ((fp_digit)w << (DIGIT_BIT - 1));
c->used = i + 1;
c->sign = FP_ZPOS;
fp_clamp(c);
return FP_OKAY;
}
void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d)
{
int D;
if (b <= 0) {
fp_copy (a, c);
if (d != NULL) {
fp_zero (d);
}
return;
}
if (a == c && d != NULL) {
fp_mod_2d (a, b, d);
}
fp_copy(a, c);
if (b >= (int)DIGIT_BIT) {
fp_rshd (c, b / DIGIT_BIT);
}
D = (b % DIGIT_BIT);
if (D != 0) {
fp_rshb(c, D);
}
if (a != c && d != NULL) {
fp_mod_2d (a, b, d);
}
fp_clamp (c);
}
int fp_mod(fp_int *a, fp_int *b, fp_int *c)
{
WC_DECLARE_VAR(t, fp_int, 1, 0);
int err;
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(t);
err = fp_div(a, b, NULL, t);
if (err == FP_OKAY) {
if (!fp_iszero(t) && (t->sign != b->sign)) {
err = fp_add(t, b, c);
} else {
fp_copy(t, c);
}
}
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
void fp_mod_2d(fp_int *a, int b, fp_int *c)
{
unsigned int x;
unsigned int bmax;
if (b <= 0) {
fp_zero(c);
return;
}
fp_copy(a, c);
if (c->sign == FP_ZPOS && b >= (DIGIT_BIT * a->used)) {
return;
}
bmax = ((unsigned int)b + DIGIT_BIT - 1) / DIGIT_BIT;
if (c->sign == FP_NEG && bmax >= FP_SIZE) {
return;
}
for (x = bmax; x < (unsigned int)c->used; x++) {
c->dp[x] = 0;
}
if (c->sign == FP_NEG) {
fp_digit carry = 0;
for (x = 0; x < (unsigned int)c->used; x++) {
fp_digit next = c->dp[x] > 0;
c->dp[x] = (fp_digit)0 - c->dp[x] - carry;
carry |= next;
}
for (; x < bmax; x++) {
c->dp[x] = (fp_digit)0 - carry;
}
c->used = (int)bmax;
c->sign = FP_ZPOS;
}
x = DIGIT_BIT - (b % DIGIT_BIT);
if (x != DIGIT_BIT) {
c->dp[bmax - 1] &= ~((fp_digit)0) >> x;
}
fp_clamp (c);
}
static int fp_invmod_slow (fp_int * a, fp_int * b, fp_int * c)
{
#ifndef WOLFSSL_SMALL_STACK
fp_int x[1], y[1], u[1], v[1], A[1], B[1], C[1], D[1];
#else
fp_int *x, *y, *u, *v, *A, *B, *C, *D;
#endif
int err;
if (b->sign == FP_NEG || fp_iszero(b) == FP_YES) {
return FP_VAL;
}
if (fp_iszero(a) == FP_YES) {
return FP_VAL;
}
#ifdef WOLFSSL_SMALL_STACK
x = (fp_int*)XMALLOC(sizeof(fp_int) * 8, NULL, DYNAMIC_TYPE_BIGINT);
if (x == NULL) {
return FP_MEM;
}
y = &x[1]; u = &x[2]; v = &x[3]; A = &x[4]; B = &x[5]; C = &x[6]; D = &x[7];
#endif
fp_init(x); fp_init(y);
fp_init(u); fp_init(v);
fp_init(A); fp_init(B);
fp_init(C); fp_init(D);
if ((err = fp_mod(a, b, x)) != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
fp_copy(b, y);
if (fp_iszero(x) == FP_YES) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return FP_VAL;
}
if (fp_iseven(x) == FP_YES && fp_iseven(y) == FP_YES) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return FP_VAL;
}
fp_copy (x, u);
fp_copy (y, v);
fp_set (A, 1);
fp_set (D, 1);
top:
while (fp_iseven (u) == FP_YES) {
fp_div_2 (u, u);
if (fp_isodd (A) == FP_YES || fp_isodd (B) == FP_YES) {
err = fp_add (A, y, A);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_sub (B, x, B);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
fp_div_2 (A, A);
fp_div_2 (B, B);
}
while (fp_iseven (v) == FP_YES) {
fp_div_2 (v, v);
if (fp_isodd (C) == FP_YES || fp_isodd (D) == FP_YES) {
err = fp_add (C, y, C);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_sub (D, x, D);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
fp_div_2 (C, C);
fp_div_2 (D, D);
}
if (fp_cmp (u, v) != FP_LT) {
err = fp_sub (u, v, u);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_sub (A, C, A);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_sub (B, D, B);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
} else {
err = fp_sub (v, u, v);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_sub (C, A, C);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_sub (D, B, D);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
if (fp_iszero (u) == FP_NO)
goto top;
if (fp_cmp_d (v, 1) != FP_EQ) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return FP_VAL;
}
while (fp_cmp_d(C, 0) == FP_LT) {
err = fp_add(C, b, C);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
while (fp_cmp_mag(C, b) != FP_LT) {
err = fp_sub(C, b, C);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
fp_copy(C, c);
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
int fp_invmod(fp_int *a, fp_int *b, fp_int *c)
{
#ifndef WOLFSSL_SMALL_STACK
fp_int x[1], y[1], u[1], v[1], B[1], D[1];
#else
fp_int *x, *y, *u, *v, *B, *D;
#endif
int err;
if (b->sign == FP_NEG || fp_iszero(b) == FP_YES) {
return FP_VAL;
}
if (fp_iszero(a) == FP_YES) {
return FP_VAL;
}
if (fp_iseven(b) == FP_YES) {
return fp_invmod_slow(a,b,c);
}
#ifdef WOLFSSL_SMALL_STACK
x = (fp_int*)XMALLOC(sizeof(fp_int) * 6, NULL, DYNAMIC_TYPE_BIGINT);
if (x == NULL) {
return FP_MEM;
}
y = &x[1]; u = &x[2]; v = &x[3]; B = &x[4]; D = &x[5];
#endif
fp_init(x); fp_init(y);
fp_init(u); fp_init(v);
fp_init(B); fp_init(D);
if (fp_iszero(a) == FP_YES) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return FP_VAL;
}
fp_copy(b, x);
if ((err = mp_mod(a, b, y)) != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
if (fp_iszero(y) == FP_YES) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return FP_VAL;
}
fp_copy(x, u);
fp_copy(y, v);
fp_set (D, 1);
top:
while (fp_iseven (u) == FP_YES) {
fp_div_2 (u, u);
if (fp_isodd (B) == FP_YES) {
err = fp_sub (B, x, B);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
fp_div_2 (B, B);
}
while (fp_iseven (v) == FP_YES) {
fp_div_2 (v, v);
if (fp_isodd (D) == FP_YES) {
err = fp_sub (D, x, D);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
fp_div_2 (D, D);
}
if (fp_cmp (u, v) != FP_LT) {
err = fp_sub (u, v, u);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_sub (B, D, B);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
} else {
err = fp_sub (v, u, v);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_sub (D, B, D);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
if (fp_iszero (u) == FP_NO) {
goto top;
}
if (fp_cmp_d (v, 1) != FP_EQ) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return FP_VAL;
}
while (D->sign == FP_NEG) {
err = fp_add (D, b, D);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
}
while (fp_cmp_mag(D, b) != FP_LT) {
err = fp_sub(D, b, D);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
fp_copy (D, c);
WC_FREE_VAR_EX(x, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
#define CT_INV_MOD_PRE_CNT 8
int fp_invmod_mont_ct(fp_int *a, fp_int *b, fp_int *c, fp_digit mp)
{
int i, j, err = FP_OKAY;
#ifndef WOLFSSL_SMALL_STACK
fp_int t[1], e[1];
fp_int pre[CT_INV_MOD_PRE_CNT];
#else
fp_int* t;
fp_int* e;
fp_int* pre;
#endif
if ((a->used * 2 > FP_SIZE) || (b->used * 2 > FP_SIZE)) {
return FP_VAL;
}
#ifdef WOLFSSL_SMALL_STACK
t = (fp_int*)XMALLOC(sizeof(fp_int) * (2 + CT_INV_MOD_PRE_CNT), NULL,
DYNAMIC_TYPE_BIGINT);
if (t == NULL)
return FP_MEM;
e = t + 1;
pre = t + 2;
#endif
fp_init(t);
fp_init(e);
fp_init(&pre[0]);
fp_copy(a, &pre[0]);
for (i = 1; i < CT_INV_MOD_PRE_CNT; i++) {
fp_init(&pre[i]);
err |= fp_sqr(&pre[i-1], &pre[i]);
err |= fp_montgomery_reduce(&pre[i], b, mp);
err |= fp_mul(&pre[i], a, &pre[i]);
err |= fp_montgomery_reduce(&pre[i], b, mp);
}
err |= fp_sub_d(b, 2, e);
j = 1;
for (i = fp_count_bits(e)-2; i >= 0; i--) {
if (!fp_is_bit_set(e, i) || j == CT_INV_MOD_PRE_CNT)
break;
j++;
}
fp_copy(&pre[j-1], t);
j = 0;
for (; i >= 0; i--) {
int set = fp_is_bit_set(e, i);
if ((j == CT_INV_MOD_PRE_CNT) || (!set && j > 0)) {
err |= fp_mul(t, &pre[j-1], t);
err |= fp_montgomery_reduce(t, b, mp);
j = 0;
}
err |= fp_sqr(t, t);
err |= fp_montgomery_reduce(t, b, mp);
j += set;
}
if (j > 0) {
err |= fp_mul(t, &pre[j-1], c);
err |= fp_montgomery_reduce(c, b, mp);
}
else
fp_copy(t, c);
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
{
int err;
WC_DECLARE_VAR(t, fp_int, 1, 0);
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(t);
err = fp_mul(a, b, t);
if (err == FP_OKAY) {
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
if (d->size < FP_SIZE) {
err = fp_mod(t, c, t);
fp_copy(t, d);
} else
#endif
{
err = fp_mod(t, c, d);
}
}
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
int fp_submod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
{
int err;
WC_DECLARE_VAR(t, fp_int, 1, 0);
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(t);
err = fp_sub(a, b, t);
if (err == FP_OKAY) {
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
if (d->size < FP_SIZE) {
err = fp_mod(t, c, t);
fp_copy(t, d);
} else
#endif
{
err = fp_mod(t, c, d);
}
}
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
{
int err;
WC_DECLARE_VAR(t, fp_int, 1, 0);
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(t);
err = fp_add(a, b, t);
if (err == FP_OKAY) {
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
if (d->size < FP_SIZE) {
err = fp_mod(t, c, t);
fp_copy(t, d);
} else
#endif
{
err = fp_mod(t, c, d);
}
}
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
int fp_submod_ct(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
{
fp_sword w;
fp_digit mask;
int i;
if (c->used + 1 > FP_SIZE) {
return FP_VAL;
}
if (c == d) {
return FP_VAL;
}
w = 0;
for (i = 0; i < c->used; i++) {
w += a->dp[i];
w -= b->dp[i];
d->dp[i] = (fp_digit)w;
w >>= DIGIT_BIT;
}
w += a->dp[i];
w -= b->dp[i];
w >>= DIGIT_BIT;
mask = (fp_digit)0 - (w < 0);
w = 0;
for (i = 0; i < c->used; i++) {
w += d->dp[i];
w += c->dp[i] & mask;
d->dp[i] = (fp_digit)w;
w >>= DIGIT_BIT;
}
d->used = i;
d->sign = FP_ZPOS;
fp_clamp(d);
return FP_OKAY;
}
int fp_addmod_ct(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
{
fp_word w;
fp_sword s;
fp_digit mask;
int i;
if (c == d) {
return FP_VAL;
}
w = 0;
s = 0;
for (i = 0; i < c->used; i++) {
w += a->dp[i];
w += b->dp[i];
d->dp[i] = (fp_digit)w;
s += (fp_digit)w;
s -= c->dp[i];
w >>= DIGIT_BIT;
s >>= DIGIT_BIT;
}
s += (fp_digit)w;
mask = (fp_digit)0 - (s >= 0);
w = 0;
for (i = 0; i < c->used; i++) {
w += c->dp[i] & mask;
w = d->dp[i] - w;
d->dp[i] = (fp_digit)w;
w = (w >> DIGIT_BIT)&1;
}
d->used = i;
d->sign = FP_ZPOS;
fp_clamp(d);
return FP_OKAY;
}
#ifdef TFM_TIMING_RESISTANT
#ifdef WC_RSA_NONBLOCK
#ifdef WC_RSA_NONBLOCK_TIME
#ifndef FP_EXPTMOD_NB_CHECKTIME
static const word32 exptModNbInst[TFM_EXPTMOD_NB_COUNT] = {
#ifdef TFM_PPC32
#ifdef _DEBUG
11098, 8701, 3971, 178394, 858093, 1040, 822, 178056, 181574, 90883, 184339, 236813
#else
7050, 2554, 3187, 43178, 200422, 384, 275, 43024, 43550, 30450, 46270, 61376
#endif
#elif defined(TFM_X86_64)
#ifdef _DEBUG
954, 2377, 858, 19027, 90840, 287, 407, 20140, 7874, 11385, 8005, 6151
#else
765, 1007, 771, 5216, 34993, 248, 193, 4975, 4201, 3947, 4275, 3811
#endif
#else
#ifdef _DEBUG
798, 2245, 802, 16657, 66920, 352, 186, 16997, 16145, 12789, 16742, 15006
#else
775, 1084, 783, 4692, 37510, 207, 183, 4374, 4392, 3097, 4442, 4079
#endif
#endif
};
static int fp_exptmod_nb_checktime(exptModNb_t* nb)
{
word32 totalInst;
if (nb->maxBlockInst == 0 || nb->state >= TFM_EXPTMOD_NB_COUNT) {
return TFM_EXPTMOD_NB_STOP;
}
if (exptModNbInst[nb->state] == 0) {
if (++nb->totalInst < nb->maxBlockInst)
return TFM_EXPTMOD_NB_CONTINUE;
nb->totalInst = 0;
return TFM_EXPTMOD_NB_STOP;
}
totalInst = nb->totalInst + exptModNbInst[nb->state];
if (totalInst <= nb->maxBlockInst) {
return TFM_EXPTMOD_NB_CONTINUE;
}
return TFM_EXPTMOD_NB_STOP;
}
#define FP_EXPTMOD_NB_CHECKTIME(nb) fp_exptmod_nb_checktime((nb))
#endif
#endif
int fp_exptmod_nb(exptModNb_t* nb, fp_int* G, fp_int* X, fp_int* P, fp_int* Y)
{
int err, ret = FP_WOULDBLOCK;
if (nb == NULL)
return FP_VAL;
#ifdef WC_RSA_NONBLOCK_TIME
nb->totalInst = 0;
do {
nb->totalInst += exptModNbInst[nb->state];
#endif
switch (nb->state) {
case TFM_EXPTMOD_NB_INIT:
if ((err = fp_montgomery_setup(P, &nb->mp)) != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
fp_init(&nb->R[0]);
fp_init(&nb->R[1]);
#ifndef WC_NO_CACHE_RESISTANT
fp_init(&nb->R[2]);
#endif
nb->state = TFM_EXPTMOD_NB_MONT;
break;
case TFM_EXPTMOD_NB_MONT:
err = fp_montgomery_calc_normalization(&nb->R[0], P);
if (err != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
nb->state = TFM_EXPTMOD_NB_MONT_RED;
break;
case TFM_EXPTMOD_NB_MONT_RED:
if (fp_cmp_mag(P, G) != FP_GT) {
err = fp_mod(G, P, &nb->R[1]);
if (err != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
} else {
fp_copy(G, &nb->R[1]);
}
nb->state = TFM_EXPTMOD_NB_MONT_MUL;
break;
case TFM_EXPTMOD_NB_MONT_MUL:
err = fp_mul(&nb->R[1], &nb->R[0], &nb->R[1]);
if (err != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
nb->state = TFM_EXPTMOD_NB_MONT_MOD;
break;
case TFM_EXPTMOD_NB_MONT_MOD:
err = fp_div(&nb->R[1], P, NULL, &nb->R[1]);
if (err != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
nb->state = TFM_EXPTMOD_NB_MONT_MODCHK;
break;
case TFM_EXPTMOD_NB_MONT_MODCHK:
if (nb->R[1].sign != P->sign) {
err = fp_add(&nb->R[1], P, &nb->R[1]);
if (err != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
}
nb->bitcnt = 1;
nb->buf = 0;
nb->digidx = X->used - 1;
nb->state = TFM_EXPTMOD_NB_NEXT;
break;
case TFM_EXPTMOD_NB_NEXT:
if (--nb->bitcnt == 0) {
if (nb->digidx == -1) {
nb->state = TFM_EXPTMOD_NB_RED;
break;
}
nb->buf = X->dp[nb->digidx--];
nb->bitcnt = (int)DIGIT_BIT;
}
nb->y = (int)(nb->buf >> (DIGIT_BIT - 1)) & 1;
nb->buf <<= (fp_digit)1;
nb->state = TFM_EXPTMOD_NB_MUL;
FALL_THROUGH;
case TFM_EXPTMOD_NB_MUL:
fp_mul(&nb->R[0], &nb->R[1], &nb->R[nb->y^1]);
nb->state = TFM_EXPTMOD_NB_MUL_RED;
break;
case TFM_EXPTMOD_NB_MUL_RED:
err = fp_montgomery_reduce(&nb->R[nb->y^1], P, nb->mp);
if (err != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
nb->state = TFM_EXPTMOD_NB_SQR;
break;
case TFM_EXPTMOD_NB_SQR:
#ifdef WC_NO_CACHE_RESISTANT
err = fp_sqr(&nb->R[nb->y], &nb->R[nb->y]);
#else
fp_copy((fp_int*) ( ((wc_ptr_t)&nb->R[0] & wc_off_on_addr[nb->y^1]) +
((wc_ptr_t)&nb->R[1] & wc_off_on_addr[nb->y]) ),
&nb->R[2]);
err = fp_sqr(&nb->R[2], &nb->R[2]);
#endif
if (err != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
nb->state = TFM_EXPTMOD_NB_SQR_RED;
break;
case TFM_EXPTMOD_NB_SQR_RED:
#ifdef WC_NO_CACHE_RESISTANT
err = fp_montgomery_reduce(&nb->R[nb->y], P, nb->mp);
#else
err = fp_montgomery_reduce(&nb->R[2], P, nb->mp);
fp_copy(&nb->R[2],
(fp_int*) ( ((wc_ptr_t)&nb->R[0] & wc_off_on_addr[nb->y^1]) +
((wc_ptr_t)&nb->R[1] & wc_off_on_addr[nb->y]) ) );
#endif
if (err != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
nb->state = TFM_EXPTMOD_NB_NEXT;
break;
case TFM_EXPTMOD_NB_RED:
err = fp_montgomery_reduce(&nb->R[0], P, nb->mp);
if (err != FP_OKAY) {
nb->state = TFM_EXPTMOD_NB_INIT;
return err;
}
fp_copy(&nb->R[0], Y);
nb->state = TFM_EXPTMOD_NB_INIT;
ret = FP_OKAY;
break;
}
#ifdef WC_RSA_NONBLOCK_TIME
} while (ret == FP_WOULDBLOCK &&
FP_EXPTMOD_NB_CHECKTIME(nb) == TFM_EXPTMOD_NB_CONTINUE);
#endif
return ret;
}
#endif
#ifndef WC_PROTECT_ENCRYPTED_MEM
static int _fp_exptmod_ct(fp_int * G, fp_int * X, int digits, fp_int * P,
fp_int * Y)
{
#ifndef WOLFSSL_SMALL_STACK
#ifdef WC_NO_CACHE_RESISTANT
fp_int R[2];
#else
fp_int R[3];
#endif
#else
fp_int *R;
#endif
fp_digit buf, mp;
int err, bitcnt, digidx, y;
if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) {
return err;
}
#ifdef WOLFSSL_SMALL_STACK
#ifndef WC_NO_CACHE_RESISTANT
R = (fp_int*)XMALLOC(sizeof(fp_int) * 3, NULL, DYNAMIC_TYPE_BIGINT);
#else
R = (fp_int*)XMALLOC(sizeof(fp_int) * 2, NULL, DYNAMIC_TYPE_BIGINT);
#endif
if (R == NULL)
return FP_MEM;
#endif
fp_init(&R[0]);
fp_init(&R[1]);
#ifndef WC_NO_CACHE_RESISTANT
fp_init(&R[2]);
#endif
err = fp_montgomery_calc_normalization (&R[0], P);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
if (fp_cmp_mag(P, G) != FP_GT) {
err = fp_mod(G, P, &R[1]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
} else {
fp_copy(G, &R[1]);
}
err = fp_mulmod (&R[1], &R[0], P, &R[1]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
bitcnt = 1;
buf = 0;
digidx = digits - 1;
for (;;) {
if (--bitcnt == 0) {
if (digidx == -1) {
break;
}
buf = X->dp[digidx--];
bitcnt = (int)DIGIT_BIT;
}
y = (int)(buf >> (DIGIT_BIT - 1)) & 1;
buf <<= (fp_digit)1;
#ifdef WC_NO_CACHE_RESISTANT
err = fp_mul(&R[0], &R[1], &R[y^1]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_montgomery_reduce(&R[y^1], P, mp);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_sqr(&R[y], &R[y]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_montgomery_reduce(&R[y], P, mp);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
#else
err = fp_mul(&R[0], &R[1], &R[2]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_montgomery_reduce(&R[2], P, mp);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
fp_copy(&R[2],
(fp_int*) ( ((wc_ptr_t)&R[0] & wc_off_on_addr[y]) +
((wc_ptr_t)&R[1] & wc_off_on_addr[y^1]) ) );
fp_copy((fp_int*) ( ((wc_ptr_t)&R[0] & wc_off_on_addr[y^1]) +
((wc_ptr_t)&R[1] & wc_off_on_addr[y]) ),
&R[2]);
err = fp_sqr(&R[2], &R[2]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_montgomery_reduce(&R[2], P, mp);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
fp_copy(&R[2],
(fp_int*) ( ((wc_ptr_t)&R[0] & wc_off_on_addr[y^1]) +
((wc_ptr_t)&R[1] & wc_off_on_addr[y]) ) );
#endif
}
err = fp_montgomery_reduce(&R[0], P, mp);
fp_copy(&R[0], Y);
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
#else
static void fp_copy_2_ct(fp_int* a1, fp_int* a2, fp_int* r1, fp_int* r2, int y,
int size)
{
int i;
for (i = 0; i < size; i++) {
r1->dp[i] = (a1->dp[i] & ((fp_digit)wc_off_on_addr[y ])) +
(a2->dp[i] & ((fp_digit)wc_off_on_addr[y^1]));
r2->dp[i] = (a1->dp[i] & ((fp_digit)wc_off_on_addr[y^1])) +
(a2->dp[i] & ((fp_digit)wc_off_on_addr[y ]));
}
r1->used = (a1->used & ((int)wc_off_on_addr[y ])) +
(a2->used & ((int)wc_off_on_addr[y^1]));
r2->used = (a1->used & ((int)wc_off_on_addr[y^1])) +
(a2->used & ((int)wc_off_on_addr[y ]));
r1->sign = (a1->sign & ((int)wc_off_on_addr[y ])) +
(a2->sign & ((int)wc_off_on_addr[y^1]));
r2->sign = (a1->sign & ((int)wc_off_on_addr[y^1])) +
(a2->sign & ((int)wc_off_on_addr[y ]));
}
static int _fp_exptmod_ct(fp_int * G, fp_int * X, int digits, fp_int * P,
fp_int * Y)
{
#ifndef WOLFSSL_SMALL_STACK
fp_int R[4];
#else
fp_int *R;
#endif
fp_digit buf, mp;
int err, bitcnt, digidx, y;
if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) {
return err;
}
WC_ALLOC_VAR_EX(R, fp_int, 4, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(&R[0]);
fp_init(&R[1]);
fp_init(&R[2]);
fp_init(&R[3]);
err = fp_montgomery_calc_normalization (&R[0], P);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
if (fp_cmp_mag(P, G) != FP_GT) {
err = fp_mod(G, P, &R[1]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
} else {
fp_copy(G, &R[1]);
}
err = fp_mulmod (&R[1], &R[0], P, &R[1]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
bitcnt = 1;
buf = 0;
digidx = digits - 1;
for (;;) {
if (--bitcnt == 0) {
if (digidx == -1) {
break;
}
buf = X->dp[digidx--];
bitcnt = (int)DIGIT_BIT;
}
y = (int)(buf >> (DIGIT_BIT - 1)) & 1;
buf <<= (fp_digit)1;
err = fp_mul(&R[0], &R[1], &R[2]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_montgomery_reduce(&R[2], P, mp);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
fp_copy((fp_int*) ( ((wc_ptr_t)&R[0] & wc_off_on_addr[y^1]) +
((wc_ptr_t)&R[1] & wc_off_on_addr[y]) ),
&R[3]);
err = fp_sqr(&R[3], &R[3]);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
err = fp_montgomery_reduce(&R[3], P, mp);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
fp_copy_2_ct(&R[2], &R[3], &R[0], &R[1], y, P->used);
}
err = fp_montgomery_reduce(&R[0], P, mp);
fp_copy(&R[0], Y);
WC_FREE_VAR_EX(R, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
#endif
#endif
static int _fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
{
fp_int *res;
fp_digit buf, mp;
int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
#ifndef WOLFSSL_NO_MALLOC
fp_int *M;
#else
fp_int M[(1 << 6) + 1];
#endif
x = fp_count_bits (X);
if (x <= 21) {
winsize = 1;
} else if (x <= 36) {
winsize = 3;
} else if (x <= 140) {
winsize = 4;
} else if (x <= 450) {
winsize = 5;
} else {
winsize = 6;
}
if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) {
return err;
}
#ifndef WOLFSSL_NO_MALLOC
M = (fp_int*)XMALLOC(sizeof(fp_int)*((1 << winsize) + 1), NULL,
DYNAMIC_TYPE_BIGINT);
if (M == NULL) {
return FP_MEM;
}
#endif
res = &M[(word32)(1 << winsize)];
for(x = 0; x < (1 << winsize); x++)
fp_init(&M[x]);
fp_init(res);
err = fp_montgomery_calc_normalization (res, P);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
if (fp_cmp_mag(P, G) != FP_GT) {
err = fp_mod(G, P, &M[1]);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
} else {
fp_copy(G, &M[1]);
}
err = fp_mulmod (&M[1], res, P, &M[1]);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
fp_copy (&M[1], &M[(word32)(1 << (winsize - 1))]);
for (x = 0; x < (winsize - 1); x++) {
err = fp_sqr (&M[(word32)(1 << (winsize - 1))],
&M[(word32)(1 << (winsize - 1))]);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
err = fp_montgomery_reduce_ex(&M[(word32)(1 << (winsize - 1))], P, mp, 0);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
}
for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
err = fp_mul(&M[x - 1], &M[1], &M[x]);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
err = fp_montgomery_reduce_ex(&M[x], P, mp, 0);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
}
mode = 0;
bitcnt = (x % DIGIT_BIT) + 1;
buf = 0;
digidx = X->used - 1;
bitcpy = 0;
bitbuf = 0;
for (;;) {
if (--bitcnt == 0) {
if (digidx == -1) {
break;
}
buf = X->dp[digidx--];
bitcnt = (int)DIGIT_BIT;
}
y = (int)(buf >> (DIGIT_BIT - 1)) & 1;
buf <<= (fp_digit)1;
if (mode == 0 && y == 0) {
continue;
}
if (mode == 1 && y == 0) {
err = fp_sqr(res, res);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
err = fp_montgomery_reduce_ex(res, P, mp, 0);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
continue;
}
bitbuf |= (y << (winsize - ++bitcpy));
mode = 2;
if (bitcpy == winsize) {
for (x = 0; x < winsize; x++) {
err = fp_sqr(res, res);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
err = fp_montgomery_reduce_ex(res, P, mp, 0);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
}
err = fp_mul(res, &M[bitbuf], res);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
err = fp_montgomery_reduce_ex(res, P, mp, 0);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
bitcpy = 0;
bitbuf = 0;
mode = 1;
}
}
if (mode == 2 && bitcpy > 0) {
for (x = 0; x < bitcpy; x++) {
err = fp_sqr(res, res);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
err = fp_montgomery_reduce_ex(res, P, mp, 0);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
bitbuf <<= 1;
if ((bitbuf & (1 << winsize)) != 0) {
err = fp_mul(res, &M[1], res);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
err = fp_montgomery_reduce_ex(res, P, mp, 0);
if (err != FP_OKAY) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
}
}
}
err = fp_montgomery_reduce_ex(res, P, mp, 0);
fp_copy (res, Y);
#ifndef WOLFSSL_NO_MALLOC
XFREE(M, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
#ifdef TFM_TIMING_RESISTANT
#if DIGIT_BIT <= 16
#define WINSIZE 2
#define WINMASK 0x3
#elif DIGIT_BIT <= 32
#define WINSIZE 3
#define WINMASK 0x7
#elif DIGIT_BIT <= 64
#define WINSIZE 4
#define WINMASK 0xf
#elif DIGIT_BIT <= 128
#define WINSIZE 5
#define WINMASK 0x1f
#endif
static int _fp_exptmod_base_2(fp_int * X, int digits, fp_int * P,
fp_int * Y)
{
fp_digit buf, mp;
int err, bitbuf, bitcpy, bitcnt, digidx, x, y;
#ifdef WOLFSSL_SMALL_STACK
fp_int *res;
fp_int *tmp;
#else
fp_int res[1];
fp_int tmp[1];
#endif
#ifdef WOLFSSL_SMALL_STACK
res = (fp_int*)XMALLOC(2*sizeof(fp_int), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (res == NULL) {
return FP_MEM;
}
tmp = &res[1];
#endif
if ((err = fp_montgomery_setup(P, &mp)) != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
fp_init(res);
fp_init(tmp);
err = fp_mul_2d(P, 1 << WINSIZE, tmp);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = fp_montgomery_calc_normalization(res, P);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
digidx = digits - 1;
bitcpy = (digits * DIGIT_BIT) % WINSIZE;
if (bitcpy > 0) {
bitcnt = (int)DIGIT_BIT - bitcpy;
buf = X->dp[digidx--];
bitbuf = (int)(buf >> bitcnt);
err = fp_mul_2d(res, bitbuf, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = fp_add(res, tmp, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = fp_mod(res, P, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
buf <<= bitcpy;
bitcnt++;
}
else {
bitcnt = 1;
buf = 0;
}
bitbuf = 0;
bitcpy = 0;
for (;;) {
if (--bitcnt == 0) {
if (digidx == -1) {
break;
}
buf = X->dp[digidx--];
bitcnt = (int)DIGIT_BIT;
}
y = (int)(buf >> (DIGIT_BIT - 1)) & 1;
buf <<= (fp_digit)1;
#ifndef WC_PROTECT_ENCRYPTED_MEM
bitbuf |= (y << (WINSIZE - ++bitcpy));
#else
bitbuf += (WINMASK + 1) + (y << (WINSIZE - ++bitcpy));
#endif
if (bitcpy == WINSIZE) {
for (x = 0; x < WINSIZE; x++) {
err = fp_sqr(res, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = fp_montgomery_reduce(res, P, mp);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
}
#ifndef WC_PROTECT_ENCRYPTED_MEM
err = fp_mul_2d(res, bitbuf, res);
#else
err = fp_mul_2d(res, bitbuf & WINMASK, res);
#endif
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = fp_add(res, tmp, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = fp_mod(res, P, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
bitcpy = 0;
#ifndef WC_PROTECT_ENCRYPTED_MEM
bitbuf = 0;
#else
bitbuf = (WINMASK + 1) + (bitbuf & ~WINMASK);
#endif
}
}
err = fp_montgomery_reduce(res, P, mp);
fp_copy(res, Y);
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
#undef WINSIZE
#else
#if DIGIT_BIT < 16
#define WINSIZE 3
#elif DIGIT_BIT < 32
#define WINSIZE 4
#elif DIGIT_BIT < 64
#define WINSIZE 5
#elif DIGIT_BIT < 128
#define WINSIZE 6
#elif DIGIT_BIT == 128
#define WINSIZE 7
#endif
static int _fp_exptmod_base_2(fp_int * X, int digits, fp_int * P,
fp_int * Y)
{
fp_digit buf, mp;
int err, bitbuf, bitcpy, bitcnt, digidx, x, y;
WC_DECLARE_VAR(res, fp_int, 1, 0);
if ((err = fp_montgomery_setup(P, &mp)) != FP_OKAY) {
return err;
}
WC_ALLOC_VAR_EX(res, fp_int, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER,
return FP_MEM);
fp_init(res);
err = fp_montgomery_calc_normalization(res, P);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
digidx = digits - 1;
bitcpy = (digits * DIGIT_BIT) % WINSIZE;
if (bitcpy > 0) {
bitcnt = (int)DIGIT_BIT - bitcpy;
buf = X->dp[digidx--];
bitbuf = (int)(buf >> bitcnt);
err = fp_mul_2d(res, bitbuf, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = fp_mod(res, P, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
buf <<= bitcpy;
bitcnt++;
}
else {
bitcnt = 1;
buf = 0;
}
bitbuf = 0;
bitcpy = 0;
for (;;) {
if (--bitcnt == 0) {
if (digidx == -1) {
break;
}
buf = X->dp[digidx--];
bitcnt = (int)DIGIT_BIT;
}
y = (int)(buf >> (DIGIT_BIT - 1)) & 1;
buf <<= (fp_digit)1;
bitbuf |= (y << (WINSIZE - ++bitcpy));
if (bitcpy == WINSIZE) {
for (x = 0; x < WINSIZE; x++) {
err = fp_sqr(res, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = fp_montgomery_reduce(res, P, mp);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
}
err = fp_mul_2d(res, bitbuf, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = fp_mod(res, P, res);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
bitcpy = 0;
bitbuf = 0;
}
}
err = fp_montgomery_reduce(res, P, mp);
fp_copy(res, Y);
WC_FREE_VAR_EX(res, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
#undef WINSIZE
#endif
int fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
{
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD)
int retHW = FP_OKAY;
#endif
if (fp_iszero(P) || (P->used > (FP_SIZE/2))) {
return FP_VAL;
}
if (fp_isone(P)) {
fp_set(Y, 0);
return FP_OKAY;
}
if (fp_iszero(X)) {
fp_set(Y, 1);
return FP_OKAY;
}
if (fp_iszero(G)) {
fp_set(Y, 0);
return FP_OKAY;
}
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD)
if (esp_hw_validation_active()) {
ESP_LOGV(TAG, "Skipping call to esp_mp_exptmod "
"during active validation.");
}
else {
retHW = esp_mp_exptmod(G, X, P, Y);
switch (retHW) {
case MP_OKAY:
return retHW;
break;
case WC_NO_ERR_TRACE(WC_HW_WAIT_E):
case MP_HW_FALLBACK:
case WC_NO_ERR_TRACE(MP_HW_VALIDATION_ACTIVE):
break;
default:
return retHW;
break;
}
}
#endif
if (X->sign == FP_NEG) {
#ifndef POSITIVE_EXP_ONLY
int err;
WC_DECLARE_VAR(tmp, fp_int, 2, 0);
WC_ALLOC_VAR_EX(tmp, fp_int, 2, NULL, DYNAMIC_TYPE_BIGINT,
return FP_MEM);
fp_init_copy(&tmp[0], G);
fp_init_copy(&tmp[1], P);
tmp[1].sign = FP_ZPOS;
err = fp_invmod(&tmp[0], &tmp[1], &tmp[0]);
if (err == FP_OKAY) {
fp_copy(X, &tmp[1]);
tmp[1].sign = FP_ZPOS;
#ifdef TFM_TIMING_RESISTANT
err = _fp_exptmod_ct(&tmp[0], &tmp[1], tmp[1].used, P, Y);
#else
err = _fp_exptmod_nct(&tmp[0], &tmp[1], P, Y);
#endif
if ((err == 0) && (P->sign == FP_NEG)) {
err = fp_add(Y, P, Y);
}
}
WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
#else
return FP_VAL;
#endif
}
else if (G->used == 1 && G->dp[0] == 2) {
return _fp_exptmod_base_2(X, X->used, P, Y);
}
else {
#ifdef TFM_TIMING_RESISTANT
return _fp_exptmod_ct(G, X, X->used, P, Y);
#else
return _fp_exptmod_nct(G, X, P, Y);
#endif
}
}
int fp_exptmod_ex(fp_int * G, fp_int * X, int digits, fp_int * P, fp_int * Y)
{
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD)
int retHW = FP_OKAY;
#endif
if (fp_iszero(P) || (P->used > (FP_SIZE/2))) {
return FP_VAL;
}
if (fp_isone(P)) {
fp_set(Y, 0);
return FP_OKAY;
}
if (fp_iszero(X)) {
fp_set(Y, 1);
return FP_OKAY;
}
if (fp_iszero(G)) {
fp_set(Y, 0);
return FP_OKAY;
}
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD)
retHW = esp_mp_exptmod(G, X, P, Y);
switch (retHW) {
case MP_OKAY:
return retHW;
break;
case WC_NO_ERR_TRACE(WC_HW_WAIT_E):
case MP_HW_FALLBACK:
case MP_HW_VALIDATION_ACTIVE:
break;
default:
return retHW;
break;
}
#endif
if (X->sign == FP_NEG) {
#ifndef POSITIVE_EXP_ONLY
int err;
WC_DECLARE_VAR(tmp, fp_int, 2, 0);
WC_ALLOC_VAR_EX(tmp, fp_int, 2, NULL, DYNAMIC_TYPE_TMP_BUFFER,
return FP_MEM);
fp_init_copy(&tmp[0], G);
fp_init_copy(&tmp[1], P);
tmp[1].sign = FP_ZPOS;
err = fp_invmod(&tmp[0], &tmp[1], &tmp[0]);
if (err == FP_OKAY) {
X->sign = FP_ZPOS;
#ifdef TFM_TIMING_RESISTANT
err = _fp_exptmod_ct(&tmp[0], X, digits, P, Y);
#else
err = _fp_exptmod_nct(&tmp[0], X, P, Y);
(void)digits;
#endif
if (X != Y) {
X->sign = FP_NEG;
}
if ((err == 0) && (P->sign == FP_NEG)) {
err = fp_add(Y, P, Y);
}
}
WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_BIGINT);
return err;
#else
return FP_VAL;
#endif
}
else {
#ifdef TFM_TIMING_RESISTANT
return _fp_exptmod_ct(G, X, digits, P, Y);
#else
return _fp_exptmod_nct(G, X, P, Y);
#endif
}
}
int fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
{
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD)
int retHW = FP_OKAY;
#endif
if (fp_iszero(P)) {
return FP_VAL;
}
if (P->used > (FP_SIZE/2)) {
#ifdef WOLFSSL_DEBUG_CERTS
WOLFSSL_MSG_CERT_EX("TFM fp_exptmod_nct failed: P.used (%d) > (FP_SIZE/2)"
"; FP_SIZE: %d; FP_MAX_SIZE: %d",
P->used, FP_SIZE, FP_MAX_BITS, FP_MAX_SIZE);
WOLFSSL_MSG_CERT_EX("Consider adjusting current FP_MAX_BITS: %d",
FP_MAX_BITS);
#endif
return FP_VAL;
}
if (fp_isone(P)) {
fp_set(Y, 0);
return FP_OKAY;
}
if (fp_iszero(X)) {
fp_set(Y, 1);
return FP_OKAY;
}
if (fp_iszero(G)) {
fp_set(Y, 0);
return FP_OKAY;
}
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD)
retHW = esp_mp_exptmod(G, X, P, Y);
switch (retHW) {
case MP_OKAY:
return retHW;
break;
case WC_NO_ERR_TRACE(WC_HW_WAIT_E):
case MP_HW_FALLBACK:
case MP_HW_VALIDATION_ACTIVE:
break;
default:
return retHW;
break;
}
#endif
if (X->sign == FP_NEG) {
#ifndef POSITIVE_EXP_ONLY
int err;
WC_DECLARE_VAR(tmp, fp_int, 2, 0);
WC_ALLOC_VAR_EX(tmp, fp_int, 2, NULL, DYNAMIC_TYPE_TMP_BUFFER,
return FP_MEM);
fp_init_copy(&tmp[0], G);
fp_init_copy(&tmp[1], P);
tmp[1].sign = FP_ZPOS;
err = fp_invmod(&tmp[0], &tmp[1], &tmp[0]);
if (err == FP_OKAY) {
X->sign = FP_ZPOS;
err = _fp_exptmod_nct(&tmp[0], X, P, Y);
if (X != Y) {
X->sign = FP_NEG;
}
if ((err == 0) && (P->sign == FP_NEG)) {
err = fp_add(Y, P, Y);
}
}
WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_BIGINT);
return err;
#else
return FP_VAL;
#endif
}
else {
return _fp_exptmod_nct(G, X, P, Y);
}
}
void fp_2expt(fp_int *a, int b)
{
int z;
fp_zero (a);
if (b < 0) {
return;
}
z = b / DIGIT_BIT;
if (z >= FP_SIZE) {
return;
}
a->used = z + 1;
a->dp[z] = ((fp_digit)1) << (b % DIGIT_BIT);
}
int fp_sqr(fp_int *A, fp_int *B)
{
int err;
int y, oldused;
oldused = B->used;
y = A->used;
if (y + y >= FP_SIZE) {
err = FP_VAL;
goto clean;
}
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL)
if (esp_hw_validation_active()) {
ESP_LOGV(TAG, "Skipping call to esp_mp_mul "
"during active validation.");
}
else {
err = esp_mp_mul(A, A, B);
switch (err) {
case MP_OKAY:
goto clean;
break;
case WC_NO_ERR_TRACE(WC_HW_WAIT_E):
case MP_HW_FALLBACK:
case MP_HW_VALIDATION_ACTIVE:
break;
default:
goto clean;
break;
}
}
#endif
#if defined(TFM_SQR3) && FP_SIZE >= 6
if (y <= 3) {
err = fp_sqr_comba3(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR4) && FP_SIZE >= 8
if (y == 4) {
err = fp_sqr_comba4(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR6) && FP_SIZE >= 12
if (y <= 6) {
err = fp_sqr_comba6(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR7) && FP_SIZE >= 14
if (y == 7) {
err = fp_sqr_comba7(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR8) && FP_SIZE >= 16
if (y == 8) {
err = fp_sqr_comba8(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR9) && FP_SIZE >= 18
if (y == 9) {
err = fp_sqr_comba9(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR12) && FP_SIZE >= 24
if (y <= 12) {
err = fp_sqr_comba12(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR17) && FP_SIZE >= 34
if (y <= 17) {
err = fp_sqr_comba17(A,B);
goto clean;
}
#endif
#if defined(TFM_SMALL_SET)
if (y <= 16) {
err = fp_sqr_comba_small(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR20) && FP_SIZE >= 40
if (y <= 20) {
err = fp_sqr_comba20(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR24) && FP_SIZE >= 48
if (y <= 24) {
err = fp_sqr_comba24(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR28) && FP_SIZE >= 56
if (y <= 28) {
err = fp_sqr_comba28(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR32) && FP_SIZE >= 64
if (y <= 32) {
err = fp_sqr_comba32(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR48) && FP_SIZE >= 96
if (y <= 48) {
err = fp_sqr_comba48(A,B);
goto clean;
}
#endif
#if defined(TFM_SQR64) && FP_SIZE >= 128
if (y <= 64) {
err = fp_sqr_comba64(A,B);
goto clean;
}
#endif
err = fp_sqr_comba(A, B);
clean:
for (y = B->used; y >= 0 && y < oldused; y++) {
B->dp[y] = 0;
}
return err;
}
int fp_sqr_comba(fp_int *A, fp_int *B)
{
int pa, ix, iz;
fp_digit c0, c1, c2;
#ifdef TFM_ISO
fp_word tt = 0;
#endif
fp_int *dst;
WC_DECLARE_VAR(tmp, fp_int, 1, 0);
WC_ALLOC_VAR_EX(tmp, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT,
return FP_MEM);
pa = A->used + A->used;
if (pa >= FP_SIZE) {
pa = FP_SIZE-1;
}
COMBA_START;
COMBA_CLEAR;
if (A == B) {
fp_init(tmp);
dst = tmp;
} else {
fp_zero(B);
dst = B;
}
for (ix = 0; ix < pa; ix++) {
int tx, ty, iy;
fp_digit *tmpy, *tmpx;
ty = MIN(A->used-1, ix);
tx = ix - ty;
tmpx = A->dp + tx;
tmpy = A->dp + ty;
iy = MIN(A->used-tx, ty+1);
iy = MIN(iy, (ty-tx+1)>>1);
COMBA_FORWARD;
for (iz = 0; iz < iy; iz++) {
SQRADD2(*tmpx++, *tmpy--);
}
if ((ix&1) == 0) {
SQRADD(A->dp[ix>>1], A->dp[ix>>1]);
}
COMBA_STORE(dst->dp[ix]);
}
COMBA_FINI;
dst->used = pa;
fp_clamp (dst);
if (dst != B) {
fp_copy(dst, B);
}
(void)c0; (void)c1; (void)c2;
#ifdef TFM_ISO
(void)tt;
#endif
WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
int fp_cmp(fp_int *a, fp_int *b)
{
if (a->sign == FP_NEG && b->sign == FP_ZPOS) {
return FP_LT;
} else if (a->sign == FP_ZPOS && b->sign == FP_NEG) {
return FP_GT;
} else {
if (a->sign == FP_NEG) {
return fp_cmp_mag(b, a);
} else {
return fp_cmp_mag(a, b);
}
}
}
int fp_cmp_d(fp_int *a, fp_digit b)
{
if (a->used == 0 && b == 0)
return FP_EQ;
if ((b && a->used == 0) || a->sign == FP_NEG) {
return FP_LT;
}
if (a->used > 1) {
return FP_GT;
}
if (a->dp[0] > b) {
return FP_GT;
} else if (a->dp[0] < b) {
return FP_LT;
} else {
return FP_EQ;
}
}
int fp_cmp_mag(fp_int *a, fp_int *b)
{
int x;
if (a->used > b->used) {
return FP_GT;
} else if (a->used < b->used) {
return FP_LT;
} else {
for (x = a->used - 1; x >= 0; x--) {
if (a->dp[x] > b->dp[x]) {
return FP_GT;
} else if (a->dp[x] < b->dp[x]) {
return FP_LT;
}
}
}
return FP_EQ;
}
int fp_montgomery_setup(fp_int *a, fp_digit *rho)
{
fp_digit x, b;
b = a->dp[0];
if ((b & 1) == 0) {
return FP_VAL;
}
x = (((b + 2) & 4) << 1) + b;
x *= 2 - b * x;
x *= 2 - b * x;
x *= 2 - b * x;
#ifdef FP_64BIT
x *= 2 - b * x;
#endif
*rho = (fp_digit) (((fp_word) 1 << ((fp_word) DIGIT_BIT)) - ((fp_word)x));
return FP_OKAY;
}
int fp_montgomery_calc_normalization(fp_int *a, fp_int *b)
{
int x, bits;
bits = fp_count_bits (b) % DIGIT_BIT;
if (!bits) bits = DIGIT_BIT;
if (b->used > 1) {
fp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1);
} else {
fp_set(a, 1);
bits = 1;
}
for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
int err = fp_mul_2 (a, a);
if (err != FP_OKAY) {
return err;
}
if (fp_cmp_mag (a, b) != FP_LT) {
s_fp_sub (a, b, a);
}
}
return FP_OKAY;
}
#ifdef TFM_SMALL_MONT_SET
#include "fp_mont_small.i"
#endif
#ifdef HAVE_INTEL_MULX
static WC_INLINE void innermul8_mulx(fp_digit *c_mulx, fp_digit *cy_mulx, fp_digit *tmpm, fp_digit mu)
{
fp_digit cy = *cy_mulx ;
INNERMUL8_MULX ;
*cy_mulx = cy ;
}
static int fp_montgomery_reduce_mulx(fp_int *a, fp_int *m, fp_digit mp, int ct)
{
WC_DECLARE_VAR(c, fp_digit, FP_SIZE+1, 0);
fp_digit *_c, *tmpm, mu = 0;
int oldused, x, y, pa;
if (m->used > (FP_SIZE/2)) {
(void)mu;
return FP_VAL;
}
#ifdef TFM_SMALL_MONT_SET
if (m->used <= 16) {
return fp_montgomery_reduce_small(a, m, mp);
}
#endif
WC_ALLOC_VAR_EX(c, fp_digit, (FP_SIZE+1), NULL, DYNAMIC_TYPE_BIGINT,
return FP_MEM);
XMEMSET(c, 0, sizeof(fp_digit)*(FP_SIZE + 1));
pa = m->used;
#ifdef TFM_TIMING_RESISTANT
if (a->used <= m->used) {
oldused = m->used;
}
else {
oldused = m->used * 2;
}
#else
oldused = a->used;
#endif
for (x = 0; x < oldused; x++) {
c[x] = a->dp[x];
}
MONT_START;
for (x = 0; x < pa; x++) {
fp_digit cy = 0;
LOOP_START;
_c = c + x;
tmpm = m->dp;
y = 0;
for (; y < (pa & ~7); y += 8) {
innermul8_mulx(_c, &cy, tmpm, mu) ;
_c += 8;
tmpm += 8;
}
for (; y < pa; y++) {
INNERMUL;
++_c;
}
LOOP_END;
while (cy) {
PROPCARRY;
++_c;
}
}
_c = c + pa;
tmpm = a->dp;
for (x = 0; x < pa+1; x++) {
*tmpm++ = *_c++;
}
for (; x < oldused; x++) {
*tmpm++ = 0;
}
MONT_FINI;
a->used = pa+1;
fp_clamp(a);
#ifndef WOLFSSL_MONT_RED_CT
if (fp_cmp_mag (a, m) != FP_LT) {
s_fp_sub (a, m, a);
}
(void)ct;
#else
if (ct) {
fp_submod_ct(a, m, m, a);
}
else if (fp_cmp_mag (a, m) != FP_LT) {
s_fp_sub (a, m, a);
}
#endif
WC_FREE_VAR_EX(c, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
#endif
int fp_montgomery_reduce_ex(fp_int *a, fp_int *m, fp_digit mp, int ct)
{
WC_DECLARE_VAR(c, fp_digit, FP_SIZE+1, 0);
fp_digit *_c, *tmpm, mu = 0;
int oldused, x, y, pa, err = 0;
IF_HAVE_INTEL_MULX(err=fp_montgomery_reduce_mulx(a, m, mp, ct), return err) ;
(void)err;
if (m->used > (FP_SIZE/2)) {
(void)mu;
return FP_VAL;
}
#ifdef TFM_SMALL_MONT_SET
if (m->used <= 16) {
return fp_montgomery_reduce_small(a, m, mp);
}
#endif
WC_ALLOC_VAR_EX(c, fp_digit, (FP_SIZE+1), NULL, DYNAMIC_TYPE_BIGINT,
return FP_MEM);
XMEMSET(c, 0, sizeof(fp_digit)*(FP_SIZE + 1));
pa = m->used;
#ifdef TFM_TIMING_RESISTANT
if (a->used <= m->used) {
oldused = m->used;
}
else {
oldused = m->used * 2;
}
#else
oldused = a->used;
#endif
for (x = 0; x < oldused; x++) {
c[x] = a->dp[x];
}
MONT_START;
for (x = 0; x < pa; x++) {
fp_digit cy = 0;
LOOP_START;
_c = c + x;
tmpm = m->dp;
y = 0;
#if defined(INNERMUL8)
for (; y < (pa & ~7); y += 8) {
INNERMUL8 ;
_c += 8;
tmpm += 8;
}
#endif
for (; y < pa; y++) {
INNERMUL;
++_c;
}
LOOP_END;
while (cy) {
PROPCARRY;
++_c;
}
}
_c = c + pa;
tmpm = a->dp;
for (x = 0; x < pa+1; x++) {
*tmpm++ = *_c++;
}
for (; x < oldused; x++) {
*tmpm++ = 0;
}
MONT_FINI;
a->used = pa+1;
fp_clamp(a);
#ifndef WOLFSSL_MONT_RED_CT
if (fp_cmp_mag (a, m) != FP_LT) {
s_fp_sub (a, m, a);
}
(void)ct;
#else
if (ct) {
fp_submod_ct(a, m, m, a);
}
else if (fp_cmp_mag (a, m) != FP_LT) {
s_fp_sub (a, m, a);
}
#endif
WC_FREE_VAR_EX(c, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
int fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp)
{
return fp_montgomery_reduce_ex(a, m, mp, 1);
}
int fp_read_unsigned_bin(fp_int *a, const unsigned char *b, int c)
{
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
const word32 maxC = (a->size * sizeof(fp_digit));
#else
const word32 maxC = (FP_SIZE * sizeof(fp_digit));
#endif
fp_zero (a);
if (c < 0) {
return FP_VAL;
}
if (c == 0) {
return FP_OKAY;
}
if ((word32)c > maxC) {
int excess = (c - maxC);
c -= excess;
b += excess;
}
#if defined(LITTLE_ENDIAN_ORDER) && defined(BIG_ENDIAN_ORDER)
#error Both LITTLE_ENDIAN_ORDER and BIG_ENDIAN_ORDER defined.
#endif
#if (defined(LITTLE_ENDIAN_ORDER) || defined(BIG_ENDIAN_ORDER)) && \
(defined(FP_32BIT) || defined(FP_64BIT))
#ifdef FP_32BIT
{
unsigned char *pd = (unsigned char *)a->dp;
a->used = (c + sizeof(fp_digit) - 1)/sizeof(fp_digit);
#ifdef BIG_ENDIAN_ORDER
{
int idx = (c - 1) & ~3;
switch (c % 4) {
case 0: do { pd[idx+0] = *b++; FALL_THROUGH;
case 3: pd[idx+1] = *b++; FALL_THROUGH;
case 2: pd[idx+2] = *b++; FALL_THROUGH;
case 1: pd[idx+3] = *b++;
idx -= 4;
} while ((c -= 4) > 0);
}
}
#else
for (c -= 1; c >= 0; c -= 1) {
pd[c] = *b++;
}
#endif
}
#elif defined(FP_64BIT)
{
unsigned char *pd = (unsigned char *)a->dp;
a->used = (c + sizeof(fp_digit) - 1)/sizeof(fp_digit);
#ifdef BIG_ENDIAN_ORDER
{
int idx = (c - 1) & ~7;
switch (c % 8) {
case 0: do { pd[idx+0] = *b++; FALL_THROUGH;
case 7: pd[idx+1] = *b++; FALL_THROUGH;
case 6: pd[idx+2] = *b++; FALL_THROUGH;
case 5: pd[idx+3] = *b++; FALL_THROUGH;
case 4: pd[idx+4] = *b++; FALL_THROUGH;
case 3: pd[idx+5] = *b++; FALL_THROUGH;
case 2: pd[idx+6] = *b++; FALL_THROUGH;
case 1: pd[idx+7] = *b++;
idx -= 8;
} while ((c -= 8) > 0);
}
}
#else
for (c -= 1; c >= 0; c -= 1) {
pd[c] = *b++;
}
#endif
}
#endif
#else
for (; c > 0; c--) {
int err = fp_mul_2d (a, 8, a);
if (err != FP_OKAY) {
return err;
}
a->dp[0] |= *b++;
if (a->used == 0) {
a->used = 1;
}
}
#endif
fp_clamp (a);
return FP_OKAY;
}
int fp_to_unsigned_bin_at_pos(int x, fp_int *t, unsigned char *b)
{
#if DIGIT_BIT == 64 || DIGIT_BIT == 32
int i;
int j = 0;
fp_digit n;
for (i = 0; i < t->used-1; ) {
b[x++] = (unsigned char)(t->dp[i] >> j);
j += 8;
i += j == DIGIT_BIT;
j &= DIGIT_BIT - 1;
}
n = t->dp[i];
while (n != 0) {
b[x++] = (unsigned char)n;
n >>= 8;
}
return x;
#else
while (fp_iszero (t) == FP_NO) {
b[x++] = (unsigned char) (t->dp[0] & 255);
fp_div_2d (t, 8, t, NULL);
}
return x;
#endif
}
int fp_to_unsigned_bin(const fp_int *a, unsigned char *b)
{
int x;
WC_DECLARE_VAR(t, fp_int, 1, 0);
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init_copy(t, a);
x = fp_to_unsigned_bin_at_pos(0, t, b);
mp_reverse (b, x);
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
int fp_to_unsigned_bin_len_ct(fp_int *a, unsigned char *out, int outSz)
{
int err = MP_OKAY;
if ((a == NULL) || (out == NULL) || (outSz < 0)) {
err = MP_VAL;
}
#if DIGIT_BIT > 8
if (err == MP_OKAY) {
int j;
unsigned int i;
fp_digit mask = (fp_digit)-1;
fp_digit d;
i = 0;
for (j = outSz - 1; j >= 0; ) {
unsigned int b;
d = a->dp[i];
for (b = 0; (j >= 0) && (b < (DIGIT_BIT / 8)); b++) {
out[j--] = (byte)(d & mask);
d >>= 8;
}
mask &= (fp_digit)0 - (i < (unsigned int)a->used - 1);
i += (unsigned int)(1 & mask);
}
}
#else
if ((err == MP_OKAY) && ((unsigned int)outSz < a->used)) {
err = MP_VAL;
}
if (err == MP_OKAY) {
unsigned int i;
int j;
fp_digit mask = (fp_digit)-1;
i = 0;
for (j = outSz - 1; j >= 0; j--) {
out[j] = a->dp[i] & mask;
mask &= (fp_digit)0 - (i < (unsigned int)a->used - 1);
i += (unsigned int)(1 & mask);
}
}
#endif
return err;
}
int fp_to_unsigned_bin_len(fp_int *a, unsigned char *b, int c)
{
#if DIGIT_BIT == 64 || DIGIT_BIT == 32 || DIGIT_BIT == 16
int i = 0;
int j = 0;
int x;
for (x=c-1; x >= 0 && i < a->used; x--) {
b[x] = (unsigned char)(a->dp[i] >> j);
j += 8;
i += j == DIGIT_BIT;
j &= DIGIT_BIT - 1;
}
for (; x >= 0; x--) {
b[x] = 0;
}
if (i < a->used - 1) {
return FP_VAL;
}
if ((i == a->used - 1) && ((a->dp[i] >> j) != 0)) {
return FP_VAL;
}
return FP_OKAY;
#else
int x;
WC_DECLARE_VAR(t, fp_int, 1, 0);
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init_copy(t, a);
for (x = 0; x < c; x++) {
b[x] = (unsigned char) (t->dp[0] & 255);
fp_div_2d (t, 8, t, NULL);
}
mp_reverse (b, x);
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
if (!fp_iszero(t)) {
return FP_VAL;
}
return FP_OKAY;
#endif
}
int fp_unsigned_bin_size(const fp_int *a)
{
int size = fp_count_bits (a);
return (size / 8 + ((size & 7) != 0 ? 1 : 0));
}
void fp_set(fp_int *a, fp_digit b)
{
fp_zero(a);
a->dp[0] = b;
a->used = a->dp[0] ? 1 : 0;
}
#ifndef MP_SET_CHUNK_BITS
#define MP_SET_CHUNK_BITS 4
#endif
int fp_set_int(fp_int *a, unsigned long b)
{
#if ((ULONG_MAX >> (DIGIT_BIT-1)) > 0)
int x;
if (b < FP_DIGIT_MAX)
{
fp_set (a, (fp_digit)b);
return FP_OKAY;
}
fp_zero (a);
for (x = 0; x < (int)(sizeof(b) * 8) / MP_SET_CHUNK_BITS; x++) {
int err = fp_mul_2d (a, MP_SET_CHUNK_BITS, a);
if (err != FP_OKAY)
return err;
a->dp[0] |= (b >> ((sizeof(b) * 8) - MP_SET_CHUNK_BITS)) &
((1 << MP_SET_CHUNK_BITS) - 1);
b <<= MP_SET_CHUNK_BITS;
a->used += 1;
}
fp_clamp(a);
#else
fp_set (a, (fp_digit)b);
#endif
return FP_OKAY;
}
int fp_is_bit_set (fp_int *a, fp_digit b)
{
fp_digit i;
if (b > FP_MAX_BITS)
return FP_VAL;
i = b/DIGIT_BIT;
if ((fp_digit)a->used < i)
return 0;
return (int)((a->dp[i] >> b%DIGIT_BIT) & (fp_digit)1);
}
int fp_set_bit (fp_int * a, fp_digit b)
{
fp_digit i;
if (b > FP_MAX_BITS)
return FP_VAL;
i = b/DIGIT_BIT;
if (a->used < (int)(i+1))
a->used = (int)(i+1);
a->dp[i] |= ((fp_digit)1) << (b % DIGIT_BIT);
return MP_OKAY;
}
int fp_count_bits (const fp_int * a)
{
int r;
fp_digit q;
if (a->used == 0) {
return 0;
}
r = (a->used - 1) * DIGIT_BIT;
q = a->dp[a->used - 1];
while (q > ((fp_digit) 0)) {
++r;
q >>= ((fp_digit) 1);
}
return r;
}
int fp_leading_bit(fp_int *a)
{
int bit = 0;
if (a->used != 0) {
fp_digit q = a->dp[a->used - 1];
int qSz = sizeof(fp_digit);
while (qSz > 0) {
if ((unsigned char)q != 0)
bit = (q & 0x80) != 0;
q >>= 8;
qSz--;
}
}
return bit;
}
int fp_lshd(fp_int *a, int x)
{
int y;
if (a->used + x > FP_SIZE) return FP_VAL;
y = a->used + x - 1;
a->used = y + 1;
for (; y >= x; y--) {
a->dp[y] = a->dp[y-x];
}
for (; y >= 0; y--) {
a->dp[y] = 0;
}
fp_clamp(a);
return FP_OKAY;
}
void fp_rshb(fp_int *c, int x)
{
fp_digit *tmpc, mask, shift;
fp_digit r, rr;
fp_digit D = x;
if (x <= 0) return;
if (x >= DIGIT_BIT) {
fp_rshd(c, x / DIGIT_BIT);
D = x % DIGIT_BIT;
if (D == 0) return;
}
if (fp_iszero(c)) return;
mask = (((fp_digit)1) << D) - 1;
shift = DIGIT_BIT - D;
tmpc = c->dp + (c->used - 1);
r = 0;
for (x = c->used - 1; x >= 0; x--) {
rr = *tmpc & mask;
*tmpc = (*tmpc >> D) | (r << shift);
--tmpc;
r = rr;
}
fp_clamp(c);
}
void fp_rshd(fp_int *a, int x)
{
int y;
if (x >= a->used) {
fp_zero(a);
return;
}
for (y = 0; y < a->used - x; y++) {
a->dp[y] = a->dp[y+x];
}
for (; y < a->used; y++) {
a->dp[y] = 0;
}
a->used -= x;
fp_clamp(a);
}
int fp_sub_d(fp_int *a, fp_digit b, fp_int *c)
{
WC_DECLARE_VAR(tmp, fp_int, 1, 0);
int err = FP_OKAY;
WC_ALLOC_VAR_EX(tmp, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT,
return FP_MEM);
fp_init(tmp);
fp_set(tmp, b);
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
if (c->size < FP_SIZE) {
err = fp_sub(a, tmp, tmp);
fp_copy(tmp, c);
}
else
#endif
{
err = fp_sub(a, tmp, c);
}
WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
int mp_init (mp_int * a)
{
if (a)
fp_init(a);
return MP_OKAY;
}
void fp_init(fp_int *a)
{
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
a->size = FP_SIZE;
#endif
#ifdef HAVE_WOLF_BIGINT
wc_bigint_init(&a->raw);
#endif
fp_zero(a);
}
void fp_zero(fp_int *a)
{
int size;
a->used = 0;
a->sign = FP_ZPOS;
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
size = a->size;
#else
size = FP_SIZE;
#endif
XMEMSET(a->dp, 0, size * sizeof(fp_digit));
}
void fp_clear(fp_int *a)
{
#ifdef HAVE_FIPS
fp_forcezero(a);
#else
int size;
a->used = 0;
a->sign = FP_ZPOS;
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
size = a->size;
#else
size = FP_SIZE;
#endif
XMEMSET(a->dp, 0, size * sizeof(fp_digit));
fp_free(a);
#endif
}
void fp_forcezero (mp_int * a)
{
int size;
if (a == NULL)
return;
a->used = 0;
a->sign = FP_ZPOS;
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
size = a->size;
#else
size = FP_SIZE;
#endif
ForceZero(a->dp, size * sizeof(fp_digit));
#ifdef HAVE_WOLF_BIGINT
wc_bigint_zero(&a->raw);
#endif
fp_free(a);
}
void mp_forcezero (mp_int * a)
{
fp_forcezero(a);
}
void fp_free(fp_int* a)
{
#ifdef HAVE_WOLF_BIGINT
wc_bigint_free(&a->raw);
#else
(void)a;
#endif
}
void mp_clear (mp_int * a)
{
if (a == NULL)
return;
fp_clear(a);
}
void mp_free(mp_int* a)
{
fp_free(a);
}
int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d,
mp_int* e, mp_int* f)
{
if (a)
fp_init(a);
if (b)
fp_init(b);
if (c)
fp_init(c);
if (d)
fp_init(d);
if (e)
fp_init(e);
if (f)
fp_init(f);
return MP_OKAY;
}
int mp_add (mp_int * a, mp_int * b, mp_int * c)
{
return fp_add(a, b, c);
}
int mp_sub (mp_int * a, mp_int * b, mp_int * c)
{
return fp_sub(a, b, c);
}
#if defined(FREESCALE_LTC_TFM)
int wolfcrypt_mp_mul(mp_int * a, mp_int * b, mp_int * c)
#else
int mp_mul (mp_int * a, mp_int * b, mp_int * c)
#endif
{
return fp_mul(a, b, c);
}
int mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
{
return fp_mul_d(a, b, c);
}
#if defined(FREESCALE_LTC_TFM)
int wolfcrypt_mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
#else
int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
#endif
{
int ret = MP_OKAY;
#ifdef WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD
ret = esp_mp_mulmod(a, b, c, d);
switch (ret) {
case MP_OKAY:
break;
case WC_NO_ERR_TRACE(WC_HW_WAIT_E):
case MP_HW_FALLBACK:
case MP_HW_VALIDATION_ACTIVE:
ret = fp_mulmod(a, b, c, d);
break;
default:
break;
}
#else
ret = fp_mulmod(a, b, c, d);
#endif
return ret;
}
int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d)
{
return fp_submod(a, b, c, d);
}
int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d)
{
return fp_addmod(a, b, c, d);
}
int mp_submod_ct(mp_int *a, mp_int *b, mp_int *c, mp_int *d)
{
return fp_submod_ct(a, b, c, d);
}
int mp_addmod_ct(mp_int *a, mp_int *b, mp_int *c, mp_int *d)
{
return fp_addmod_ct(a, b, c, d);
}
#if defined(FREESCALE_LTC_TFM)
int wolfcrypt_mp_mod (mp_int * a, mp_int * b, mp_int * c)
#else
int mp_mod (mp_int * a, mp_int * b, mp_int * c)
#endif
{
return fp_mod (a, b, c);
}
#if defined(FREESCALE_LTC_TFM)
int wolfcrypt_mp_invmod (mp_int * a, mp_int * b, mp_int * c)
#else
int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
#endif
{
return fp_invmod(a, b, c);
}
int mp_invmod_mont_ct (mp_int * a, mp_int * b, mp_int * c, mp_digit mp)
{
return fp_invmod_mont_ct(a, b, c, mp);
}
#if defined(FREESCALE_LTC_TFM)
int wolfcrypt_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
#else
int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
#endif
{
return fp_exptmod(G, X, P, Y);
}
int mp_exptmod_ex (mp_int * G, mp_int * X, int digits, mp_int * P, mp_int * Y)
{
return fp_exptmod_ex(G, X, digits, P, Y);
}
#if defined(FREESCALE_LTC_TFM)
int wolfcrypt_mp_exptmod_nct (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
#else
int mp_exptmod_nct (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
#endif
{
return fp_exptmod_nct(G, X, P, Y);
}
int mp_cmp (const mp_int * a, const mp_int * b)
{
return fp_cmp((mp_int *)a, (mp_int *)b);
}
int mp_cmp_d(mp_int * a, mp_digit b)
{
return fp_cmp_d(a, b);
}
int mp_unsigned_bin_size (const mp_int * a)
{
return fp_unsigned_bin_size(a);
}
int mp_to_unsigned_bin_at_pos(int x, fp_int *t, unsigned char *b)
{
return fp_to_unsigned_bin_at_pos(x, t, b);
}
int mp_to_unsigned_bin(const mp_int * a, unsigned char *b)
{
return fp_to_unsigned_bin(a,b);
}
int mp_to_unsigned_bin_len_ct(mp_int * a, unsigned char *b, int c)
{
return fp_to_unsigned_bin_len_ct(a, b, c);
}
int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c)
{
return fp_to_unsigned_bin_len(a, b, c);
}
int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
{
return fp_read_unsigned_bin(a, b, c);
}
int mp_sub_d(fp_int *a, fp_digit b, fp_int *c)
{
return fp_sub_d(a, b, c);
}
int mp_mul_2d(fp_int *a, int b, fp_int *c)
{
return fp_mul_2d(a, b, c);
}
int mp_2expt(fp_int* a, int b)
{
fp_2expt(a, b);
return MP_OKAY;
}
int mp_div(fp_int * a, fp_int * b, fp_int * c, fp_int * d)
{
return fp_div(a, b, c, d);
}
int mp_div_2d(fp_int* a, int b, fp_int* c, fp_int* d)
{
fp_div_2d(a, b, c, d);
return MP_OKAY;
}
int mp_mod_2d(fp_int* a, int b, fp_int* c)
{
fp_mod_2d(a, b, c);
return MP_OKAY;
}
void fp_copy(const fp_int *a, fp_int *b)
{
if (a != b) {
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
if (b->size >= a->used) {
int x, oldused;
oldused = b->used;
b->used = a->used;
b->sign = a->sign;
XMEMCPY(b->dp, a->dp, a->used * sizeof(fp_digit));
for (x = b->used; x >= 0 && x < oldused; x++) {
b->dp[x] = 0;
}
}
else {
}
#else
b->used = a->used;
b->sign = a->sign;
XMEMCPY(b->dp, a->dp, FP_SIZE * sizeof(fp_digit));
#endif
}
}
int mp_init_copy(fp_int * a, const fp_int * b)
{
fp_init_copy(a, b);
return MP_OKAY;
}
void fp_init_copy(fp_int *a, const fp_int* b)
{
if (a != b) {
fp_init(a);
fp_copy(b, a);
}
}
int mp_copy(const fp_int* a, fp_int* b)
{
fp_copy(a, b);
return MP_OKAY;
}
int mp_isodd(const mp_int* a)
{
return fp_isodd(a);
}
int mp_iszero(const mp_int* a)
{
return fp_iszero(a);
}
int mp_count_bits (const mp_int* a)
{
return fp_count_bits(a);
}
int mp_leading_bit (mp_int* a)
{
return fp_leading_bit(a);
}
void mp_rshb (mp_int* a, int x)
{
fp_rshb(a, x);
}
void mp_rshd (mp_int* a, int x)
{
fp_rshd(a, x);
}
int mp_set_int(mp_int *a, unsigned long b)
{
return fp_set_int(a, b);
}
int mp_is_bit_set (mp_int *a, mp_digit b)
{
return fp_is_bit_set(a, b);
}
int mp_set_bit(mp_int *a, mp_digit b)
{
return fp_set_bit(a, b);
}
#if defined(WOLFSSL_KEY_GEN) || defined (HAVE_ECC) || !defined(NO_DH) || \
!defined(NO_DSA) || !defined(NO_RSA)
int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c)
{
int err;
WC_DECLARE_VAR(t, fp_int, 1, 0);
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(t);
err = fp_sqr(a, t);
if (err == FP_OKAY) {
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
if (c->size < FP_SIZE) {
err = fp_mod(t, b, t);
fp_copy(t, c);
}
else
#endif
{
err = fp_mod(t, b, c);
}
}
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c)
{
return fp_sqrmod(a, b, c);
}
int mp_montgomery_calc_normalization(mp_int *a, mp_int *b)
{
return fp_montgomery_calc_normalization(a, b);
}
#endif
static int fp_cond_swap_ct_ex(mp_int* a, mp_int* b, int c, int m, mp_int* t)
{
int i;
mp_digit mask = (mp_digit)0 - m;
t->used = (a->used ^ b->used) & mask;
for (i = 0; i < c; i++) {
t->dp[i] = (a->dp[i] ^ b->dp[i]) & mask;
}
a->used ^= t->used;
for (i = 0; i < c; i++) {
a->dp[i] ^= t->dp[i];
}
b->used ^= t->used;
for (i = 0; i < c; i++) {
b->dp[i] ^= t->dp[i];
}
return FP_OKAY;
}
static int fp_cond_swap_ct(mp_int* a, mp_int* b, int c, int m)
{
WC_DECLARE_VAR(t, fp_int, 1, 0);
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_cond_swap_ct_ex(a, b, c, m, t);
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
#if defined(WC_MP_TO_RADIX) || !defined(NO_DH) || !defined(NO_DSA) || \
!defined(NO_RSA)
#ifdef WOLFSSL_KEY_GEN
static int fp_exch (fp_int * a, fp_int * b)
{
WC_DECLARE_VAR(t, fp_int, 1, 0);
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
*t = *a;
*a = *b;
*b = *t;
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
#endif
static const int lnz[16] = {
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};
int fp_cnt_lsb(fp_int *a)
{
int x;
fp_digit q, qq;
if (fp_iszero(a) == FP_YES) {
return 0;
}
for (x = 0; x < a->used && a->dp[x] == 0; x++) {}
q = a->dp[x];
x *= DIGIT_BIT;
if ((q & 1) == 0) {
do {
qq = q & 15;
x += lnz[qq];
q >>= 4;
} while (qq == 0);
}
return x;
}
static int s_is_power_of_two(fp_digit b, int *p)
{
int x;
if ((b==0) || (b & (b-1))) {
return FP_NO;
}
for (x = 0; x < DIGIT_BIT; x++) {
if (b == (((fp_digit)1)<<x)) {
*p = x;
return FP_YES;
}
}
return FP_NO;
}
static int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d)
{
WC_DECLARE_VAR(q, fp_int, 1, 0);
fp_word w;
fp_digit t;
int ix;
if (b == 0) {
return FP_VAL;
}
if (b == 1 || fp_iszero(a) == FP_YES) {
if (d != NULL) {
*d = 0;
}
if (c != NULL) {
fp_copy(a, c);
}
return FP_OKAY;
}
if (s_is_power_of_two(b, &ix) == FP_YES) {
if (d != NULL) {
*d = a->dp[0] & ((((fp_digit)1)<<ix) - 1);
}
if (c != NULL) {
fp_div_2d(a, ix, c, NULL);
}
return FP_OKAY;
}
WC_ALLOC_VAR_EX(q, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(q);
if (c != NULL) {
q->used = a->used;
q->sign = a->sign;
}
w = 0;
for (ix = a->used - 1; ix >= 0; ix--) {
w = (w << ((fp_word)DIGIT_BIT)) | ((fp_word)a->dp[ix]);
if (w >= b) {
#ifdef WOLFSSL_LINUXKM
t = (fp_digit)w;
do_div(t, b);
#else
t = (fp_digit)(w / b);
#endif
w -= ((fp_word)t) * ((fp_word)b);
} else {
t = 0;
}
if (c != NULL)
q->dp[ix] = (fp_digit)t;
}
if (d != NULL) {
*d = (fp_digit)w;
}
if (c != NULL) {
fp_clamp(q);
fp_copy(q, c);
}
WC_FREE_VAR_EX(q, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
static int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c)
{
return fp_div_d(a, b, NULL, c);
}
int mp_mod_d(fp_int *a, fp_digit b, fp_digit *c)
{
return fp_mod_d(a, b, c);
}
#endif
#if !defined(NO_DH) || !defined(NO_DSA) || !defined(NO_RSA) || \
defined(WOLFSSL_KEY_GEN)
static int fp_isprime_ex(fp_int *a, int t, int* result);
#if defined(FREESCALE_LTC_TFM)
int wolfcrypt_mp_prime_is_prime(mp_int* a, int t, int* result)
#else
int mp_prime_is_prime(mp_int* a, int t, int* result)
#endif
{
return fp_isprime_ex(a, t, result);
}
static int fp_prime_miller_rabin_ex(fp_int * a, fp_int * b, int *result,
fp_int *n1, fp_int *y, fp_int *r)
{
int s, j;
int err;
*result = FP_NO;
if (fp_cmp_d(b, 1) != FP_GT) {
return FP_OKAY;
}
fp_copy(a, n1);
err = fp_sub_d(n1, 1, n1);
if (err != FP_OKAY) {
return err;
}
fp_copy(n1, r);
s = fp_cnt_lsb(r);
fp_div_2d (r, s, r, NULL);
fp_zero(y);
#if (defined(WOLFSSL_HAVE_SP_RSA) && !defined(WOLFSSL_RSA_PUBLIC_ONLY)) || \
defined(WOLFSSL_HAVE_SP_DH)
#ifndef WOLFSSL_SP_NO_2048
if (fp_count_bits(a) == 1024 && fp_isodd(a))
err = sp_ModExp_1024(b, r, a, y);
else if (fp_count_bits(a) == 2048 && fp_isodd(a))
err = sp_ModExp_2048(b, r, a, y);
else
#endif
#ifndef WOLFSSL_SP_NO_3072
if (fp_count_bits(a) == 1536 && fp_isodd(a))
err = sp_ModExp_1536(b, r, a, y);
else if (fp_count_bits(a) == 3072 && fp_isodd(a))
err = sp_ModExp_3072(b, r, a, y);
else
#endif
#ifdef WOLFSSL_SP_4096
if (fp_count_bits(a) == 4096 && fp_isodd(a))
err = sp_ModExp_4096(b, r, a, y);
else
#endif
#endif
err = fp_exptmod(b, r, a, y);
if (err != FP_OKAY) {
return err;
}
if (fp_cmp_d (y, 1) != FP_EQ && fp_cmp (y, n1) != FP_EQ) {
j = 1;
while ((j <= (s - 1)) && fp_cmp (y, n1) != FP_EQ) {
err = fp_sqrmod (y, a, y);
if (err != FP_OKAY)
return err;
if (fp_cmp_d (y, 1) == FP_EQ) {
return FP_OKAY;
}
++j;
}
if (fp_cmp (y, n1) != FP_EQ) {
return FP_OKAY;
}
}
*result = FP_YES;
return FP_OKAY;
}
static int fp_prime_miller_rabin(fp_int * a, fp_int * b, int *result)
{
int err;
#ifndef WOLFSSL_SMALL_STACK
fp_int n1[1], y[1], r[1];
#else
fp_int *n1, *y, *r;
#endif
#ifdef WOLFSSL_SMALL_STACK
n1 = (fp_int*)XMALLOC(sizeof(fp_int) * 3, NULL, DYNAMIC_TYPE_BIGINT);
if (n1 == NULL) {
return FP_MEM;
}
y = &n1[1]; r = &n1[2];
#endif
fp_init(n1);
fp_init(y);
fp_init(r);
err = fp_prime_miller_rabin_ex(a, b, result, n1, y, r);
fp_clear(n1);
fp_clear(y);
fp_clear(r);
WC_FREE_VAR_EX(n1, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
static const fp_digit primes[FP_PRIME_SIZE] = {
0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083,
0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
};
int fp_isprime_ex(fp_int *a, int t, int* result)
{
WC_DECLARE_VAR(b, fp_int, 1, 0);
fp_digit d;
int r, res;
int err;
if (t <= 0 || t > FP_PRIME_SIZE) {
*result = FP_NO;
return FP_VAL;
}
if (fp_isone(a)) {
*result = FP_NO;
return FP_OKAY;
}
for (r = 0; r < FP_PRIME_SIZE; r++) {
if (fp_cmp_d(a, primes[r]) == FP_EQ) {
*result = FP_YES;
return FP_OKAY;
}
}
for (r = 0; r < FP_PRIME_SIZE; r++) {
res = fp_mod_d(a, primes[r], &d);
if (res != MP_OKAY || d == 0) {
*result = FP_NO;
return res;
}
}
WC_ALLOC_VAR_EX(b, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(b);
for (r = 0; r < t; r++) {
fp_set(b, primes[r]);
err = fp_prime_miller_rabin(a, b, &res);
if ((err != FP_OKAY) || (res == FP_NO)) {
*result = res;
WC_FREE_VAR_EX(b, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
*result = FP_YES;
WC_FREE_VAR_EX(b, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
#if defined(FREESCALE_LTC_TFM)
int wolfcrypt_mp_prime_is_prime_ex(mp_int* a, int t, int* result, WC_RNG* rng)
#else
int mp_prime_is_prime_ex(mp_int* a, int t, int* result, WC_RNG* rng)
#endif
{
int ret = FP_YES;
fp_digit d;
int i;
if (a == NULL || result == NULL || rng == NULL)
return FP_VAL;
if (a->sign == FP_NEG)
return FP_VAL;
if (t <= 0 || t > FP_PRIME_SIZE)
return FP_VAL;
if (fp_isone(a)) {
*result = FP_NO;
return FP_OKAY;
}
for (i = 0; i < FP_PRIME_SIZE; i++) {
if (fp_cmp_d(a, primes[i]) == FP_EQ) {
*result = FP_YES;
return FP_OKAY;
}
}
for (i = 0; i < FP_PRIME_SIZE; i++) {
if (fp_mod_d(a, primes[i], &d) == MP_OKAY) {
if (d == 0) {
*result = FP_NO;
return FP_OKAY;
}
}
else
return FP_VAL;
}
#ifndef WC_NO_RNG
{
#ifndef WOLFSSL_SMALL_STACK
fp_int b[1], c[1], n1[1], y[1], r[1];
byte base[FP_MAX_PRIME_SIZE];
#else
fp_int *b, *c, *n1, *y, *r;
byte* base;
#endif
word32 baseSz;
word32 bitSz;
int err;
bitSz = fp_count_bits(a);
baseSz = (bitSz / 8) + ((bitSz % 8) ? 1 : 0);
bitSz %= 8;
#ifndef WOLFSSL_SMALL_STACK
if (baseSz > sizeof(base))
return FP_MEM;
#else
base = (byte*)XMALLOC(baseSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (base == NULL)
return FP_MEM;
b = (fp_int*)XMALLOC(sizeof(fp_int) * 5, NULL, DYNAMIC_TYPE_BIGINT);
if (b == NULL) {
XFREE(base, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return FP_MEM;
}
c = &b[1]; n1 = &b[2]; y= &b[3]; r = &b[4];
#endif
fp_init(b);
fp_init(c);
fp_init(n1);
fp_init(y);
fp_init(r);
err = fp_sub_d(a, 2, c);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(b, NULL, DYNAMIC_TYPE_BIGINT);
WC_FREE_VAR_EX(base, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
while (t > 0) {
if ((err = wc_RNG_GenerateBlock(rng, base, baseSz)) != 0) {
WC_FREE_VAR_EX(b, NULL, DYNAMIC_TYPE_BIGINT);
WC_FREE_VAR_EX(base, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
if (bitSz != 0)
base[0] &= (1 << bitSz) - 1;
err = fp_read_unsigned_bin(b, base, baseSz);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(b, NULL, DYNAMIC_TYPE_BIGINT);
WC_FREE_VAR_EX(base, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
if (fp_cmp_d(b, 2) != FP_GT || fp_cmp(b, c) != FP_LT) {
continue;
}
err = fp_prime_miller_rabin_ex(a, b, &ret, n1, y, r);
if (err != FP_OKAY) {
WC_FREE_VAR_EX(b, NULL, DYNAMIC_TYPE_BIGINT);
WC_FREE_VAR_EX(base, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
if (ret == FP_NO)
break;
fp_zero(b);
t--;
}
fp_clear(n1);
fp_clear(y);
fp_clear(r);
fp_clear(b);
fp_clear(c);
WC_FREE_VAR_EX(b, NULL, DYNAMIC_TYPE_BIGINT);
WC_FREE_VAR_EX(base, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#else
(void)t;
#endif
*result = ret;
return FP_OKAY;
}
#endif
int mp_cond_swap_ct_ex(mp_int* a, mp_int* b, int c, int m, mp_int* t)
{
return fp_cond_swap_ct_ex(a, b, c, m, t);
}
int mp_cond_swap_ct(mp_int* a, mp_int* b, int c, int m)
{
return fp_cond_swap_ct(a, b, c, m);
}
#ifdef WOLFSSL_KEY_GEN
static int fp_gcd(fp_int *a, fp_int *b, fp_int *c);
static int fp_lcm(fp_int *a, fp_int *b, fp_int *c);
static int fp_randprime(fp_int* a, int len, WC_RNG* rng, void* heap);
int mp_gcd(fp_int *a, fp_int *b, fp_int *c)
{
return fp_gcd(a, b, c);
}
int mp_lcm(fp_int *a, fp_int *b, fp_int *c)
{
return fp_lcm(a, b, c);
}
int mp_rand_prime(mp_int* a, int len, WC_RNG* rng, void* heap)
{
int err;
err = fp_randprime(a, len, rng, heap);
switch(err) {
case WC_NO_ERR_TRACE(MP_VAL):
return MP_VAL;
case WC_NO_ERR_TRACE(MP_MEM):
return MP_MEM;
default:
break;
}
return MP_OKAY;
}
int mp_exch (mp_int * a, mp_int * b)
{
return fp_exch(a, b);
}
int fp_randprime(fp_int* a, int len, WC_RNG* rng, void* heap)
{
static const int USE_BBS = 1;
int err, type;
int isPrime = FP_YES;
byte* buf;
(void)heap;
if (len < 0) {
type = USE_BBS;
len = -len;
} else {
type = 0;
}
if (len < 2 || len > 512) {
return FP_VAL;
}
buf = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (buf == NULL) {
return FP_MEM;
}
XMEMSET(buf, 0, len);
do {
#ifdef SHOW_GEN
printf(".");
fflush(stdout);
#endif
err = wc_RNG_GenerateBlock(rng, buf, len);
if (err != 0) {
XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER);
return FP_VAL;
}
buf[0] |= 0x80 | 0x40;
buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00);
err = fp_read_unsigned_bin(a, buf, len);
if (err != 0) {
XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
mp_prime_is_prime_ex(a, 8, &isPrime, rng);
} while (isPrime == FP_NO);
XMEMSET(buf, 0, len);
XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER);
return FP_OKAY;
}
int fp_lcm(fp_int *a, fp_int *b, fp_int *c)
{
int err;
WC_DECLARE_VAR(t, fp_int, 2, 0);
if (fp_iszero(a) == FP_YES || fp_iszero(b) == FP_YES) {
return FP_VAL;
}
WC_ALLOC_VAR_EX(t, fp_int, 2, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(&t[0]);
fp_init(&t[1]);
err = fp_gcd(a, b, &t[0]);
if (err == FP_OKAY) {
if (fp_cmp_mag(a, b) == FP_GT) {
err = fp_div(a, &t[0], &t[1], NULL);
if (err == FP_OKAY)
err = fp_mul(b, &t[1], c);
} else {
err = fp_div(b, &t[0], &t[1], NULL);
if (err == FP_OKAY)
err = fp_mul(a, &t[1], c);
}
}
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
int fp_gcd(fp_int *a, fp_int *b, fp_int *c)
{
#ifndef WOLFSSL_SMALL_STACK
fp_int u[1], v[1], r[1];
#else
fp_int *u, *v, *r;
#endif
if (fp_iszero(a) == FP_YES && fp_iszero(b) == FP_YES) {
return FP_VAL;
}
if (fp_iszero (a) == FP_YES && fp_iszero (b) == FP_NO) {
fp_abs (b, c);
return FP_OKAY;
}
if (fp_iszero (a) == FP_NO && fp_iszero (b) == FP_YES) {
fp_abs (a, c);
return FP_OKAY;
}
if (fp_iszero (a) == FP_YES) {
fp_zero(c);
return FP_OKAY;
}
#ifdef WOLFSSL_SMALL_STACK
u = (fp_int*)XMALLOC(sizeof(fp_int) * 3, NULL, DYNAMIC_TYPE_BIGINT);
if (u == NULL) {
return FP_MEM;
}
v = &u[1]; r = &u[2];
#endif
if (fp_cmp_mag(a, b) != FP_LT) {
fp_init_copy(u, a);
fp_init_copy(v, b);
} else {
fp_init_copy(u, b);
fp_init_copy(v, a);
}
u->sign = FP_ZPOS;
v->sign = FP_ZPOS;
fp_init(r);
while (fp_iszero(v) == FP_NO) {
int err = fp_mod(u, v, r);
if (err != MP_OKAY) {
WC_FREE_VAR_EX(u, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
fp_copy(v, u);
fp_copy(r, v);
}
fp_copy(u, c);
WC_FREE_VAR_EX(u, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
#endif
#if defined(HAVE_ECC) || !defined(NO_PWDBASED) || defined(OPENSSL_EXTRA) || \
defined(WC_RSA_BLINDING) || !defined(NO_DSA) || \
(!defined(NO_RSA) && !defined(NO_RSA_BOUNDS_CHECK))
int fp_add_d(fp_int *a, fp_digit b, fp_int *c)
{
WC_DECLARE_VAR(tmp, fp_int, 1, 0);
int err;
WC_ALLOC_VAR_EX(tmp, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT,
return FP_MEM);
fp_init(tmp);
fp_set(tmp, b);
err = fp_add(a, tmp, c);
WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
int mp_add_d(fp_int *a, fp_digit b, fp_int *c)
{
return fp_add_d(a, b, c);
}
#endif
#if !defined(NO_DSA) || defined(HAVE_ECC) || defined(WOLFSSL_KEY_GEN) || \
defined(HAVE_COMP_KEY) || defined(WOLFSSL_DEBUG_MATH) || \
defined(DEBUG_WOLFSSL) || defined(OPENSSL_EXTRA) || defined(WC_MP_TO_RADIX)
static wcchar fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz+/";
#endif
#if defined(OPENSSL_EXTRA) || !defined(NO_DSA) || defined(HAVE_ECC)
#if DIGIT_BIT == 64 || DIGIT_BIT == 32
static int fp_read_radix_16(fp_int *a, const char *str)
{
int i, j, k, neg;
int ch;
int eol_done = 0;
if (*str == '-') {
++str;
neg = FP_NEG;
} else {
neg = FP_ZPOS;
}
j = 0;
k = 0;
for (i = (int)(XSTRLEN(str) - 1); i >= 0; i--) {
ch = (int)HexCharToByte(str[i]);
if (ch < 0) {
if (!eol_done && CharIsWhiteSpace(str[i]))
continue;
return FP_VAL;
}
eol_done = 1;
k += j == DIGIT_BIT;
j &= DIGIT_BIT - 1;
if (k >= FP_SIZE)
return FP_VAL;
a->dp[k] |= ((fp_digit)ch) << j;
j += 4;
}
a->used = k + 1;
fp_clamp(a);
if (fp_iszero(a) != FP_YES) {
a->sign = neg;
}
return FP_OKAY;
}
#endif
static int fp_read_radix(fp_int *a, const char *str, int radix)
{
int y, neg;
char ch;
fp_zero (a);
#if DIGIT_BIT == 64 || DIGIT_BIT == 32
if (radix == 16)
return fp_read_radix_16(a, str);
#endif
if (radix < 2 || radix > 64) {
return FP_VAL;
}
if (*str == '-') {
++str;
neg = FP_NEG;
} else {
neg = FP_ZPOS;
}
while (*str) {
ch = (char)((radix <= 36) ? XTOUPPER((unsigned char)*str) : *str);
for (y = 0; y < 64; y++) {
if (ch == fp_s_rmap[y]) {
break;
}
}
if (y >= radix) {
while (CharIsWhiteSpace(*str))
++str;
if (*str)
return FP_VAL;
else
break;
}
if (y < radix) {
int ret = fp_mul_d (a, (fp_digit) radix, a);
if (ret != FP_OKAY)
return ret;
ret = fp_add_d (a, (fp_digit) y, a);
if (ret != FP_OKAY)
return ret;
} else {
break;
}
++str;
}
if (fp_iszero(a) != FP_YES) {
a->sign = neg;
}
return FP_OKAY;
}
int mp_read_radix(mp_int *a, const char *str, int radix)
{
return fp_read_radix(a, str, radix);
}
#endif
#if defined(HAVE_ECC) || (!defined(NO_RSA) && defined(WC_RSA_BLINDING))
int mp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp)
{
return fp_montgomery_reduce(a, m, mp);
}
int mp_montgomery_reduce_ex(fp_int *a, fp_int *m, fp_digit mp, int ct)
{
return fp_montgomery_reduce_ex(a, m, mp, ct);
}
int mp_montgomery_setup(fp_int *a, fp_digit *rho)
{
return fp_montgomery_setup(a, rho);
}
#endif
int mp_sqr(fp_int *A, fp_int *B)
{
return fp_sqr(A, B);
}
#ifdef HAVE_ECC
int mp_div_2(fp_int * a, fp_int * b)
{
fp_div_2(a, b);
return MP_OKAY;
}
int mp_div_2_mod_ct(mp_int *a, mp_int *b, mp_int *c)
{
return fp_div_2_mod_ct(a, b, c);
}
#ifdef HAVE_COMP_KEY
int mp_cnt_lsb(fp_int* a)
{
return fp_cnt_lsb(a);
}
#endif
#endif
#if defined(HAVE_ECC) || !defined(NO_RSA) || !defined(NO_DSA) || \
defined(WOLFSSL_KEY_GEN)
int mp_set(fp_int *a, fp_digit b)
{
fp_set(a,b);
return MP_OKAY;
}
#endif
#ifdef WC_MP_TO_RADIX
int mp_radix_size (mp_int *a, int radix, int *size)
{
int res, digs;
fp_digit d;
WC_DECLARE_VAR(t, fp_int, 1, 0);
*size = 0;
if (radix == 2) {
*size = fp_count_bits(a);
if (*size == 0)
*size = 1;
*size += (a->sign == FP_NEG ? 1 : 0) + 1;
return FP_OKAY;
}
if (radix < 2 || radix > 64) {
return FP_VAL;
}
if (fp_iszero(a) == MP_YES) {
#ifndef WC_DISABLE_RADIX_ZERO_PAD
if (radix == 16)
*size = 3;
else
#endif
*size = 2;
return FP_OKAY;
}
digs = 0;
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(t);
fp_copy(a, t);
t->sign = FP_ZPOS;
while (fp_iszero (t) == FP_NO) {
if ((res = fp_div_d (t, (mp_digit) radix, t, &d)) != FP_OKAY) {
fp_zero (t);
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return res;
}
++digs;
}
fp_zero (t);
#ifndef WC_DISABLE_RADIX_ZERO_PAD
if ((digs & 1) && (radix == 16)) {
++digs;
}
#endif
if (a->sign == FP_NEG) {
++digs;
}
*size = digs + 1;
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
int mp_toradix (mp_int *a, char *str, int radix)
{
int res, digs;
fp_digit d;
char *_s = str;
WC_DECLARE_VAR(t, fp_int, 1, 0);
if (radix < 2 || radix > 64) {
return FP_VAL;
}
if (fp_iszero(a) == FP_YES) {
#ifndef WC_DISABLE_RADIX_ZERO_PAD
if (radix == 16)
*str++ = '0';
#endif
*str++ = '0';
*str = '\0';
return FP_OKAY;
}
WC_ALLOC_VAR_EX(t, fp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, return FP_MEM);
fp_init(t);
fp_copy(a, t);
if (t->sign == FP_NEG) {
++_s;
*str++ = '-';
t->sign = FP_ZPOS;
}
digs = 0;
while (fp_iszero (t) == FP_NO) {
if ((res = fp_div_d (t, (fp_digit) radix, t, &d)) != FP_OKAY) {
fp_zero (t);
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return res;
}
*str++ = fp_s_rmap[d];
++digs;
}
#ifndef WC_DISABLE_RADIX_ZERO_PAD
if ((digs & 1) && (radix == 16)) {
*str++ = fp_s_rmap[0];
++digs;
}
#endif
mp_reverse ((unsigned char *)_s, digs);
*str = '\0';
fp_zero (t);
WC_FREE_VAR_EX(t, NULL, DYNAMIC_TYPE_BIGINT);
return FP_OKAY;
}
#ifdef WOLFSSL_DEBUG_MATH
void mp_dump(const char* desc, mp_int* a, byte verbose)
{
char buffer[FP_SIZE * sizeof(fp_digit) * 2];
int size;
#if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT)
size = a->size;
#else
size = FP_SIZE;
#endif
printf("%s: ptr=%p, used=%d, sign=%d, size=%d, fpd=%d\n",
desc, a, a->used, a->sign, size, (int)sizeof(fp_digit));
mp_tohex(a, buffer);
printf(" %s\n ", buffer);
if (verbose) {
int i;
for(i=0; i<size * (int)sizeof(fp_digit); i++) {
printf("%x ", *(((byte*)a->dp) + i));
}
printf("\n");
}
}
#endif
#endif
int mp_abs(mp_int* a, mp_int* b)
{
fp_abs(a, b);
return FP_OKAY;
}
int mp_lshd (mp_int * a, int b)
{
return fp_lshd(a, b);
}
#ifdef WOLFSSL_CHECK_MEM_ZERO
void mp_memzero_add(const char* name, mp_int* a)
{
wc_MemZero_Add(name, a->dp, sizeof(a->dp));
}
void mp_memzero_check(mp_int* a)
{
wc_MemZero_Check(a->dp, sizeof(a->dp));
}
#endif
#endif