#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#ifndef NO_BIG_INT
#if !defined(USE_FAST_MATH) && defined(USE_INTEGER_HEAP_MATH)
#ifndef WOLFSSL_SP_MATH
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#include <wolfssl/wolfcrypt/wolfmath.h>
#if defined(FREESCALE_LTC_TFM)
#include <wolfssl/wolfcrypt/port/nxp/ksdk_port.h>
#endif
#ifdef WOLFSSL_DEBUG_MATH
#include <stdio.h>
#endif
#ifdef SHOW_GEN
#ifndef NO_STDIO_FILESYSTEM
#include <stdio.h>
#endif
#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
static void
bn_reverse (unsigned char *s, int len)
{
int ix, iy;
unsigned char t;
ix = 0;
iy = len - 1;
while (ix < iy) {
t = s[ix];
s[ix] = s[iy];
s[iy] = t;
++ix;
--iy;
}
}
word32 CheckRunTimeSettings(void)
{
return CTC_SETTINGS;
}
int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e,
mp_int* f)
{
int res = MP_OKAY;
if (a) XMEMSET(a, 0, sizeof(mp_int));
if (b) XMEMSET(b, 0, sizeof(mp_int));
if (c) XMEMSET(c, 0, sizeof(mp_int));
if (d) XMEMSET(d, 0, sizeof(mp_int));
if (e) XMEMSET(e, 0, sizeof(mp_int));
if (f) XMEMSET(f, 0, sizeof(mp_int));
if (a && ((res = mp_init(a)) != MP_OKAY))
return res;
if (b && ((res = mp_init(b)) != MP_OKAY)) {
mp_clear(a);
return res;
}
if (c && ((res = mp_init(c)) != MP_OKAY)) {
mp_clear(a); mp_clear(b);
return res;
}
if (d && ((res = mp_init(d)) != MP_OKAY)) {
mp_clear(a); mp_clear(b); mp_clear(c);
return res;
}
if (e && ((res = mp_init(e)) != MP_OKAY)) {
mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d);
return res;
}
if (f && ((res = mp_init(f)) != MP_OKAY)) {
mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d); mp_clear(e);
return res;
}
return res;
}
int mp_init (mp_int * a)
{
if (a == NULL)
return MP_VAL;
a->dp = NULL;
a->used = 0;
a->alloc = 0;
a->sign = MP_ZPOS;
#ifdef HAVE_WOLF_BIGINT
wc_bigint_init(&a->raw);
#endif
return MP_OKAY;
}
void mp_clear (mp_int * a)
{
#ifdef HAVE_FIPS
mp_forcezero(a);
#else
int i;
if (a == NULL)
return;
#ifndef HAVE_WOLF_BIGINT
if (a->dp != NULL)
#endif
{
for (i = 0; i < a->used; i++) {
a->dp[i] = 0;
}
mp_free(a);
a->alloc = a->used = 0;
a->sign = MP_ZPOS;
}
#endif
}
void mp_free (mp_int * a)
{
if (a->dp != NULL) {
XFREE(a->dp, 0, DYNAMIC_TYPE_BIGINT);
a->dp = NULL;
}
#ifdef HAVE_WOLF_BIGINT
wc_bigint_free(&a->raw);
#endif
}
void mp_forcezero(mp_int * a)
{
if (a == NULL)
return;
if (a->dp != NULL) {
ForceZero(a->dp, a->used * sizeof(mp_digit));
#ifdef HAVE_WOLF_BIGINT
wc_bigint_zero(&a->raw);
#endif
mp_free(a);
a->alloc = a->used = 0;
a->sign = MP_ZPOS;
}
a->sign = MP_ZPOS;
a->used = 0;
}
int mp_unsigned_bin_size (const mp_int * a)
{
int size = mp_count_bits (a);
return (size / 8 + ((size & 7) != 0 ? 1 : 0));
}
int mp_count_bits (const mp_int * a)
{
int r;
mp_digit q;
if (a->used == 0) {
return 0;
}
r = (a->used - 1) * DIGIT_BIT;
q = a->dp[a->used - 1];
while (q > ((mp_digit) 0)) {
++r;
q >>= ((mp_digit) 1);
}
return r;
}
int mp_leading_bit (mp_int * a)
{
int c = mp_count_bits(a);
if (c == 0) return 0;
return (c % 8) == 0;
}
int mp_to_unsigned_bin_at_pos(int x, mp_int *t, unsigned char *b)
{
int res = 0;
while (mp_iszero(t) == MP_NO) {
#ifndef MP_8BIT
b[x++] = (unsigned char) (t->dp[0] & 255);
#else
b[x++] = (unsigned char) (t->dp[0] | ((t->dp[1] & 0x01) << 7));
#endif
if ((res = mp_div_2d (t, 8, t, NULL)) != MP_OKAY) {
return res;
}
res = x;
}
return res;
}
int mp_to_unsigned_bin (const mp_int * a, unsigned char *b)
{
int x, res;
mp_int t;
if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
return res;
}
x = mp_to_unsigned_bin_at_pos(0, &t, b);
if (x < 0) {
mp_clear(&t);
return x;
}
bn_reverse (b, x);
mp_clear (&t);
return res;
}
int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c)
{
int i, len;
len = mp_unsigned_bin_size(a);
if (len > c) {
return MP_VAL;
}
for (i = 0; i < c - len; i++) {
b[i] = 0x00;
}
return mp_to_unsigned_bin(a, b + i);
}
int mp_init_copy (mp_int * a, const mp_int * b)
{
int res;
if ((res = mp_init_size (a, b->used)) != MP_OKAY) {
return res;
}
if((res = mp_copy (b, a)) != MP_OKAY) {
mp_clear(a);
}
return res;
}
int mp_copy (const mp_int * a, mp_int * b)
{
int res, n;
if (a == NULL || b == NULL)
return MP_VAL;
if (a == b) {
return MP_OKAY;
}
if (b->alloc < a->used || b->alloc == 0) {
if ((res = mp_grow (b, a->used)) != MP_OKAY) {
return res;
}
}
{
mp_digit *tmpa, *tmpb;
tmpa = a->dp;
tmpb = b->dp;
for (n = 0; n < a->used; n++) {
*tmpb++ = *tmpa++;
}
for (; n < b->used && b->dp; n++) {
*tmpb++ = 0;
}
}
b->used = a->used;
b->sign = a->sign;
return MP_OKAY;
}
int mp_grow (mp_int * a, int size)
{
mp_digit *tmp;
if ((a->alloc < size) || (size == 0) || (a->alloc == 0)) {
size += (MP_PREC * 2) - (size % MP_PREC);
tmp = (mp_digit *)XREALLOC (a->dp, sizeof (mp_digit) * size, NULL,
DYNAMIC_TYPE_BIGINT);
if (tmp == NULL) {
return MP_MEM;
}
a->dp = tmp;
XMEMSET(&a->dp[a->alloc], 0, sizeof (mp_digit) * (size - a->alloc));
a->alloc = size;
}
else if (a->dp == NULL) {
return MP_VAL;
}
return MP_OKAY;
}
int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
{
int D, res;
mp_int t;
if (b <= 0) {
res = mp_copy (a, c);
if (d != NULL) {
mp_zero (d);
}
return res;
}
if ((res = mp_init (&t)) != MP_OKAY) {
return res;
}
if (d != NULL) {
if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
mp_clear (&t);
return res;
}
}
if ((res = mp_copy (a, c)) != MP_OKAY) {
mp_clear (&t);
return res;
}
if (b >= (int)DIGIT_BIT) {
mp_rshd (c, b / DIGIT_BIT);
}
D = (b % DIGIT_BIT);
if (D != 0) {
mp_rshb(c, D);
}
mp_clamp (c);
if (d != NULL) {
mp_exch (&t, d);
}
mp_clear (&t);
return MP_OKAY;
}
void mp_zero (mp_int * a)
{
int n;
mp_digit *tmp;
if (a == NULL)
return;
a->sign = MP_ZPOS;
a->used = 0;
tmp = a->dp;
for (n = 0; tmp != NULL && n < a->alloc; n++) {
*tmp++ = 0;
}
}
void mp_clamp (mp_int * a)
{
while (a->used > 0 && a->dp[a->used - 1] == 0) {
--(a->used);
}
if (a->used == 0) {
a->sign = MP_ZPOS;
}
}
int mp_exch (mp_int * a, mp_int * b)
{
mp_int t;
t = *a;
*a = *b;
*b = t;
return MP_OKAY;
}
int mp_cond_swap_ct_ex (mp_int * a, mp_int * b, int c, int m, mp_int * t)
{
(void)c;
(void)t;
if (m == 1)
mp_exch(a, b);
return MP_OKAY;
}
int mp_cond_swap_ct (mp_int * a, mp_int * b, int c, int m)
{
(void)c;
if (m == 1)
mp_exch(a, b);
return MP_OKAY;
}
void mp_rshb (mp_int *c, int x)
{
mp_digit *tmpc, mask, shift;
mp_digit r, rr;
mp_digit D = x;
if (x <= 0) return;
if (x >= DIGIT_BIT) {
mp_rshd(c, x / DIGIT_BIT);
D = x % DIGIT_BIT;
if (D == 0) return;
}
if (mp_iszero(c)) return;
mask = (((mp_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;
}
mp_clamp(c);
}
void mp_rshd (mp_int * a, int b)
{
int x;
if (b <= 0) {
return;
}
if (a->used <= b) {
mp_zero (a);
return;
}
{
mp_digit *bottom, *top;
bottom = a->dp;
top = a->dp + b;
for (x = 0; x < (a->used - b); x++) {
*bottom++ = *top++;
}
for (; x < a->used; x++) {
*bottom++ = 0;
}
}
a->used -= b;
}
int mp_mod_2d (mp_int * a, int b, mp_int * c)
{
int x, res, bmax;
if (b <= 0) {
mp_zero (c);
return MP_OKAY;
}
if (a->sign == MP_ZPOS && b >= (int) (a->used * DIGIT_BIT)) {
res = mp_copy (a, c);
return res;
}
if ((res = mp_copy (a, c)) != MP_OKAY) {
return res;
}
bmax = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1);
for (x = bmax; x < c->used; x++) {
c->dp[x] = 0;
}
if (c->sign == MP_NEG) {
mp_digit carry = 0;
if ((res = mp_grow(c, bmax)) != MP_OKAY) {
return res;
}
for (x = 0; x < c->used; x++) {
mp_digit next = c->dp[x] > 0;
c->dp[x] = ((mp_digit)0 - c->dp[x] - carry) & MP_MASK;
carry |= next;
}
for (; x < bmax; x++) {
c->dp[x] = ((mp_digit)0 - carry) & MP_MASK;
}
c->used = bmax;
c->sign = MP_ZPOS;
}
x = DIGIT_BIT - (b % DIGIT_BIT);
if (x != DIGIT_BIT) {
c->dp[bmax - 1] &=
((mp_digit)~((mp_digit)0)) >> (x + ((sizeof(mp_digit)*8) - DIGIT_BIT));
}
mp_clamp (c);
return MP_OKAY;
}
int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
{
int res;
int digits_needed;
while (c > 0 && b[0] == 0) {
c--;
b++;
}
digits_needed = ((c * CHAR_BIT) + DIGIT_BIT - 1) / DIGIT_BIT;
if (a->alloc < digits_needed) {
if ((res = mp_grow(a, digits_needed)) != MP_OKAY) {
return res;
}
}
mp_zero (a);
while (c-- > 0) {
if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
return res;
}
#ifndef MP_8BIT
a->dp[0] |= *b++;
if (a->used == 0)
a->used = 1;
#else
a->dp[0] = (*b & MP_MASK);
a->dp[1] |= ((*b++ >> 7U) & 1);
if (a->used == 0)
a->used = 2;
#endif
}
mp_clamp (a);
return MP_OKAY;
}
int mp_mul_2d (mp_int * a, int b, mp_int * c)
{
mp_digit d;
int res;
if (a != c) {
if ((res = mp_copy (a, c)) != MP_OKAY) {
return res;
}
}
if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
return res;
}
}
if (b >= (int)DIGIT_BIT) {
if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
return res;
}
}
d = (mp_digit) (b % DIGIT_BIT);
if (d != 0) {
mp_digit *tmpc, shift, mask, r, rr;
int x;
mask = (((mp_digit)1) << d) - 1;
shift = DIGIT_BIT - d;
tmpc = c->dp;
r = 0;
for (x = 0; x < c->used; x++) {
rr = (*tmpc >> shift) & mask;
*tmpc = (mp_digit)(((*tmpc << d) | r) & MP_MASK);
++tmpc;
r = rr;
}
if (r != 0) {
c->dp[(c->used)++] = r;
}
}
mp_clamp (c);
return MP_OKAY;
}
int mp_lshd (mp_int * a, int b)
{
int x, res;
if (b <= 0) {
return MP_OKAY;
}
if (a->alloc < a->used + b) {
if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
return res;
}
}
{
mp_digit *top, *bottom;
a->used += b;
top = a->dp + a->used - 1;
bottom = a->dp + a->used - 1 - b;
for (x = a->used - 1; x >= b; x--) {
*top-- = *bottom--;
}
top = a->dp;
for (x = 0; x < b; x++) {
*top++ = 0;
}
}
return MP_OKAY;
}
#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
{
int dr;
if (mp_iszero(P) || P->sign == MP_NEG) {
return MP_VAL;
}
if (mp_isone(P)) {
return mp_set(Y, 0);
}
if (mp_iszero(X)) {
return mp_set(Y, 1);
}
if (mp_iszero(G)) {
return mp_set(Y, 0);
}
if (X->sign == MP_NEG) {
#ifdef BN_MP_INVMOD_C
mp_int tmpG, tmpX;
int err;
if ((err = mp_init(&tmpG)) != MP_OKAY) {
return err;
}
if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
mp_clear(&tmpG);
return err;
}
if ((err = mp_init(&tmpX)) != MP_OKAY) {
mp_clear(&tmpG);
return err;
}
if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
mp_clear(&tmpG);
mp_clear(&tmpX);
return err;
}
err = mp_exptmod(&tmpG, &tmpX, P, Y);
mp_clear(&tmpG);
mp_clear(&tmpX);
return err;
#else
return MP_VAL;
#endif
}
#ifdef BN_MP_EXPTMOD_BASE_2
if (G->used == 1 && G->dp[0] == 2 && mp_isodd(P) == MP_YES) {
return mp_exptmod_base_2(X, P, Y);
}
#endif
#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && \
defined(BN_S_MP_EXPTMOD_C)
if (mp_reduce_is_2k_l(P) == MP_YES) {
return s_mp_exptmod(G, X, P, Y, 1);
}
#endif
#ifdef BN_MP_DR_IS_MODULUS_C
dr = mp_dr_is_modulus(P);
#else
dr = 0;
#endif
(void)dr;
#ifdef BN_MP_REDUCE_IS_2K_C
if (dr == 0) {
dr = mp_reduce_is_2k(P) << 1;
}
#endif
#ifdef BN_MP_EXPTMOD_FAST_C
if (mp_isodd (P) == MP_YES || dr != 0) {
return mp_exptmod_fast (G, X, P, Y, dr);
} else {
#endif
#ifdef BN_S_MP_EXPTMOD_C
return s_mp_exptmod (G, X, P, Y, 0);
#else
return MP_VAL;
#endif
#ifdef BN_MP_EXPTMOD_FAST_C
}
#endif
}
int mp_exptmod_ex (mp_int * G, mp_int * X, int digits, mp_int * P, mp_int * Y)
{
(void)digits;
return mp_exptmod(G, X, P, Y);
}
int mp_abs (mp_int * a, mp_int * b)
{
int res;
if (a != b) {
if ((res = mp_copy (a, b)) != MP_OKAY) {
return res;
}
}
b->sign = MP_ZPOS;
return MP_OKAY;
}
#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
{
if (b->sign == MP_NEG || mp_iszero(b) == MP_YES || mp_iszero(a) == MP_YES) {
return MP_VAL;
}
#ifdef BN_FAST_MP_INVMOD_C
if ((mp_isodd(b) == MP_YES) && (mp_cmp_d(b, 1) != MP_EQ)) {
return fast_mp_invmod (a, b, c);
}
#endif
#ifdef BN_MP_INVMOD_SLOW_C
return mp_invmod_slow(a, b, c);
#else
return MP_VAL;
#endif
}
int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c)
{
mp_int x, y, u, v, B, D;
int res, loop_check = 0;
if (mp_iseven (b) == MP_YES) {
return MP_VAL;
}
if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D)) != MP_OKAY) {
return res;
}
if ((res = mp_copy (b, &x)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_mod (a, b, &y)) != MP_OKAY) {
goto LBL_ERR;
}
if (mp_iszero (&y) == MP_YES) {
res = MP_VAL;
goto LBL_ERR;
}
if ((res = mp_copy (&x, &u)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_copy (&y, &v)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_set (&D, 1)) != MP_OKAY) {
goto LBL_ERR;
}
top:
while (mp_iseven (&u) == MP_YES) {
if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
goto LBL_ERR;
}
if (mp_isodd (&B) == MP_YES) {
if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
goto LBL_ERR;
}
}
if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
goto LBL_ERR;
}
}
while (mp_iseven (&v) == MP_YES) {
if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
goto LBL_ERR;
}
if (mp_isodd (&D) == MP_YES) {
if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
if (mp_cmp (&u, &v) != MP_LT) {
if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
goto LBL_ERR;
}
} else {
if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
if (mp_iszero (&u) == MP_NO) {
if (++loop_check > MAX_INVMOD_SZ) {
res = MP_VAL;
goto LBL_ERR;
}
goto top;
}
if (mp_cmp_d (&v, 1) != MP_EQ) {
res = MP_VAL;
goto LBL_ERR;
}
while (D.sign == MP_NEG) {
if ((res = mp_add (&D, b, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
while (mp_cmp_mag(&D, b) != MP_LT) {
if ((res = mp_sub(&D, b, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
mp_exch (&D, c);
res = MP_OKAY;
LBL_ERR:mp_clear(&x);
mp_clear(&y);
mp_clear(&u);
mp_clear(&v);
mp_clear(&B);
mp_clear(&D);
return res;
}
int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
{
mp_int x, y, u, v, A, B, C, D;
int res;
if (b->sign == MP_NEG || mp_iszero(b) == MP_YES) {
return MP_VAL;
}
if ((res = mp_init_multi(&x, &y, &u, &v,
&A, &B)) != MP_OKAY) {
return res;
}
if ((res = mp_init_multi(&C, &D, 0, 0, 0, 0)) != MP_OKAY) {
mp_clear(&x);
mp_clear(&y);
mp_clear(&u);
mp_clear(&v);
mp_clear(&A);
mp_clear(&B);
return res;
}
if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
goto LBL_ERR;
}
if (mp_iszero (&x) == MP_YES) {
res = MP_VAL;
goto LBL_ERR;
}
if (mp_isone(&x)) {
res = mp_set(c, 1);
goto LBL_ERR;
}
if ((res = mp_copy (b, &y)) != MP_OKAY) {
goto LBL_ERR;
}
if (mp_iseven (&x) == MP_YES && mp_iseven (&y) == MP_YES) {
res = MP_VAL;
goto LBL_ERR;
}
if ((res = mp_copy (&x, &u)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_copy (&y, &v)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_set (&A, 1)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_set (&D, 1)) != MP_OKAY) {
goto LBL_ERR;
}
top:
while (mp_iseven (&u) == MP_YES) {
if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
goto LBL_ERR;
}
if (mp_isodd (&A) == MP_YES || mp_isodd (&B) == MP_YES) {
if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
goto LBL_ERR;
}
}
if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
goto LBL_ERR;
}
}
while (mp_iseven (&v) == MP_YES) {
if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
goto LBL_ERR;
}
if (mp_isodd (&C) == MP_YES || mp_isodd (&D) == MP_YES) {
if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
if (mp_cmp (&u, &v) != MP_LT) {
if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
goto LBL_ERR;
}
} else {
if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
if (mp_iszero (&u) == MP_NO)
goto top;
if (mp_cmp_d (&v, 1) != MP_EQ) {
res = MP_VAL;
goto LBL_ERR;
}
while (mp_cmp_d(&C, 0) == MP_LT) {
if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
goto LBL_ERR;
}
}
while (mp_cmp_mag(&C, b) != MP_LT) {
if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
goto LBL_ERR;
}
}
mp_exch (&C, c);
res = MP_OKAY;
LBL_ERR:mp_clear(&x);
mp_clear(&y);
mp_clear(&u);
mp_clear(&v);
mp_clear(&A);
mp_clear(&B);
mp_clear(&C);
mp_clear(&D);
return res;
}
int mp_cmp_mag (const mp_int * a, const mp_int * b)
{
int n;
const mp_digit *tmpa, *tmpb;
if (a->used > b->used) {
return MP_GT;
}
if (a->used < b->used) {
return MP_LT;
}
if (a->used == 0)
return MP_EQ;
tmpa = a->dp + (a->used - 1);
tmpb = b->dp + (a->used - 1);
for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
if (*tmpa > *tmpb) {
return MP_GT;
}
if (*tmpa < *tmpb) {
return MP_LT;
}
}
return MP_EQ;
}
int mp_cmp (const mp_int * a, const mp_int * b)
{
if (a->sign != b->sign) {
if (a->sign == MP_NEG) {
return MP_LT;
} else {
return MP_GT;
}
}
if (a->sign == MP_NEG) {
return mp_cmp_mag(b, a);
} else {
return mp_cmp_mag(a, b);
}
}
int mp_cmp_d(mp_int * a, mp_digit b)
{
if (a->used == 0 && b == 0)
return MP_EQ;
if ((b && a->used == 0) || a->sign == MP_NEG) {
return MP_LT;
}
if (a->used > 1) {
return MP_GT;
}
if (a->dp[0] > b) {
return MP_GT;
} else if (a->dp[0] < b) {
return MP_LT;
} else {
return MP_EQ;
}
}
int mp_set (mp_int * a, mp_digit b)
{
int res;
mp_zero (a);
res = mp_grow (a, 1);
if (res == MP_OKAY) {
a->dp[0] = (mp_digit)(b & MP_MASK);
a->used = (a->dp[0] != 0) ? 1 : 0;
}
return res;
}
int mp_is_bit_set (mp_int *a, mp_digit b)
{
mp_digit i = b / DIGIT_BIT;
mp_digit s = b % DIGIT_BIT;
if ((mp_digit)a->used <= i) {
return 0;
}
return (int)((a->dp[i] >> s) & (mp_digit)1);
}
#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
{
mp_int t;
int res;
if ((res = mp_init_size (&t, b->used)) != MP_OKAY) {
return res;
}
if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
mp_clear (&t);
return res;
}
if ((mp_iszero(&t) != MP_NO) || (t.sign == b->sign)) {
res = MP_OKAY;
mp_exch (&t, c);
} else {
res = mp_add (b, &t, c);
}
mp_clear (&t);
return res;
}
int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
{
mp_int ta, tb, tq, q;
int res, n, n2;
if (mp_iszero (b) == MP_YES) {
return MP_VAL;
}
if (mp_cmp_mag (a, b) == MP_LT) {
if (d != NULL) {
res = mp_copy (a, d);
} else {
res = MP_OKAY;
}
if (c != NULL) {
mp_zero (c);
}
return res;
}
if ((res = mp_init_multi(&ta, &tb, &tq, &q, 0, 0)) != MP_OKAY) {
return res;
}
if ((res = mp_set(&tq, 1)) != MP_OKAY) {
return res;
}
n = mp_count_bits(a) - mp_count_bits(b);
if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
((res = mp_abs(b, &tb)) != MP_OKAY) ||
((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
goto LBL_ERR;
}
while (n-- >= 0) {
if (mp_cmp(&tb, &ta) != MP_GT) {
if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
goto LBL_ERR;
}
}
if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
goto LBL_ERR;
}
}
n = a->sign;
n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
if (c != NULL) {
mp_exch(c, &q);
c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
}
if (d != NULL) {
mp_exch(d, &ta);
d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
}
LBL_ERR:
mp_clear(&ta);
mp_clear(&tb);
mp_clear(&tq);
mp_clear(&q);
return res;
}
int mp_div_2(mp_int * a, mp_int * b)
{
int x, res, oldused;
if (b->alloc < a->used) {
if ((res = mp_grow (b, a->used)) != MP_OKAY) {
return res;
}
}
oldused = b->used;
b->used = a->used;
{
mp_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;
mp_clamp (b);
return MP_OKAY;
}
int mp_div_2_mod_ct(mp_int *a, mp_int *b, mp_int *c)
{
int res;
if (mp_isodd(a)) {
res = mp_add(a, b, c);
if (res == MP_OKAY) {
res = mp_div_2(c, c);
}
}
else {
res = mp_div_2(a, c);
}
return res;
}
int mp_add (mp_int * a, mp_int * b, mp_int * c)
{
int sa, sb, res;
sa = a->sign;
sb = b->sign;
if (sa == sb) {
c->sign = sa;
res = s_mp_add (a, b, c);
} else {
if (mp_cmp_mag (a, b) == MP_LT) {
c->sign = sb;
res = s_mp_sub (b, a, c);
} else {
c->sign = sa;
res = s_mp_sub (a, b, c);
}
}
return res;
}
int s_mp_add (mp_int * a, mp_int * b, mp_int * c)
{
mp_int *x;
int olduse, res, min_ab, max_ab;
if (a->used > b->used) {
min_ab = b->used;
max_ab = a->used;
x = a;
} else {
min_ab = a->used;
max_ab = b->used;
x = b;
}
if (c->dp == NULL || c->alloc < max_ab + 1) {
if ((res = mp_grow (c, max_ab + 1)) != MP_OKAY) {
return res;
}
}
olduse = c->used;
c->used = max_ab + 1;
{
mp_digit u, *tmpa, *tmpb, *tmpc;
int i;
tmpa = a->dp;
tmpb = b->dp;
tmpc = c->dp;
if ((min_ab > 0) &&
((tmpa == NULL) || (tmpb == NULL) || (tmpc == NULL)))
{
return MP_VAL;
}
u = 0;
for (i = 0; i < min_ab; i++) {
*tmpc = *tmpa++ + *tmpb++ + u;
u = *tmpc >> ((mp_digit)DIGIT_BIT);
*tmpc++ &= MP_MASK;
}
if (min_ab != max_ab) {
for (; i < max_ab; i++) {
*tmpc = x->dp[i] + u;
u = *tmpc >> ((mp_digit)DIGIT_BIT);
*tmpc++ &= MP_MASK;
}
}
*tmpc++ = u;
for (i = c->used; i < olduse; i++) {
*tmpc++ = 0;
}
}
mp_clamp (c);
return MP_OKAY;
}
int s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
{
int olduse, res, min_b, max_a;
min_b = b->used;
max_a = a->used;
if (c->alloc < max_a) {
if ((res = mp_grow (c, max_a)) != MP_OKAY) {
return res;
}
}
if (c->dp == NULL)
return MP_VAL;
olduse = c->used;
c->used = max_a;
{
mp_digit u, *tmpa, *tmpb, *tmpc;
int i;
tmpa = a->dp;
tmpb = b->dp;
tmpc = c->dp;
if ((min_b > 0) &&
((tmpa == NULL) || (tmpb == NULL)))
{
return MP_VAL;
}
u = 0;
for (i = 0; i < min_b; i++) {
*tmpc = *tmpa++ - *tmpb++ - u;
u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
*tmpc++ &= MP_MASK;
}
for (; i < max_a; i++) {
*tmpc = *tmpa++ - u;
u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
*tmpc++ &= MP_MASK;
}
for (i = c->used; i < olduse; i++) {
*tmpc++ = 0;
}
}
mp_clamp (c);
return MP_OKAY;
}
int mp_sub (mp_int * a, mp_int * b, mp_int * c)
{
int sa, sb, res;
sa = a->sign;
sb = b->sign;
if (sa != sb) {
c->sign = sa;
res = s_mp_add (a, b, c);
} else {
if (mp_cmp_mag (a, b) != MP_LT) {
c->sign = sa;
res = s_mp_sub (a, b, c);
} else {
c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
res = s_mp_sub (b, a, c);
}
}
return res;
}
int mp_reduce_is_2k_l(mp_int *a)
{
int ix, iy;
if (a->used == 0) {
return MP_NO;
} else if (a->used == 1) {
return MP_YES;
} else if (a->used > 1) {
for (iy = ix = 0; ix < a->used; ix++) {
if (a->dp[ix] == MP_MASK) {
++iy;
}
}
return (iy >= (a->used/2)) ? MP_YES : MP_NO;
}
return MP_NO;
}
int mp_reduce_is_2k(mp_int *a)
{
int ix, iy, iw;
mp_digit iz;
if (a->used == 0) {
return MP_NO;
} else if (a->used == 1) {
return MP_YES;
} else if (a->used > 1) {
iy = mp_count_bits(a);
iz = 1;
iw = 1;
for (ix = DIGIT_BIT; ix < iy; ix++) {
if ((a->dp[iw] & iz) == 0) {
return MP_NO;
}
iz <<= 1;
if (iz > (mp_digit)MP_MASK) {
++iw;
iz = 1;
}
}
}
return MP_YES;
}
int mp_dr_is_modulus(mp_int *a)
{
int ix;
if (a->used < 2) {
return 0;
}
for (ix = 1; ix < a->used; ix++) {
if (a->dp[ix] != MP_MASK) {
return 0;
}
}
return 1;
}
#ifdef MP_LOW_MEM
#define TAB_SIZE 32
#else
#define TAB_SIZE 256
#endif
int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y,
int redmode)
{
mp_int res;
mp_digit buf, mp;
int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
WC_DECLARE_VAR(M, mp_int, TAB_SIZE, 0);
int (*redux)(mp_int*,mp_int*,mp_digit) = NULL;
WC_ALLOC_VAR_EX(M, mp_int, TAB_SIZE, NULL, DYNAMIC_TYPE_BIGINT,
return MP_MEM);
x = 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;
}
#ifdef MP_LOW_MEM
if (winsize > 5) {
winsize = 5;
}
#endif
if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) {
WC_FREE_VAR_EX(M, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) {
for (y = 1<<(winsize-1); y < x; y++) {
mp_clear (&M[y]);
}
mp_clear(&M[1]);
WC_FREE_VAR_EX(M, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
}
if (redmode == 0) {
#ifdef BN_MP_MONTGOMERY_SETUP_C
if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
goto LBL_M;
}
#else
err = MP_VAL;
goto LBL_M;
#endif
#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
if (((P->used * 2 + 1) < (int)MP_WARRAY) &&
P->used < (1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
redux = fast_mp_montgomery_reduce;
} else
#endif
{
#ifdef BN_MP_MONTGOMERY_REDUCE_C
redux = mp_montgomery_reduce;
#endif
}
} else if (redmode == 1) {
#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
mp_dr_setup(P, &mp);
redux = mp_dr_reduce;
#endif
} else {
#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
goto LBL_M;
}
if (mp != 0) {
redux = mp_reduce_2k;
}
#endif
}
if (redux == NULL) {
err = MP_VAL;
goto LBL_M;
}
if ((err = mp_init_size (&res, P->alloc)) != MP_OKAY) {
goto LBL_M;
}
if (redmode == 0) {
#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
goto LBL_RES;
}
#else
err = MP_VAL;
goto LBL_RES;
#endif
} else {
if ((err = mp_set(&res, 1)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
goto LBL_RES;
}
}
if ((err = mp_copy (&M[1], &M[(mp_digit)(1 << (winsize - 1))])) != MP_OKAY) {
goto LBL_RES;
}
for (x = 0; x < (winsize - 1); x++) {
if ((err = mp_sqr (&M[(mp_digit)(1 << (winsize - 1))],
&M[(mp_digit)(1 << (winsize - 1))])) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&M[(mp_digit)(1 << (winsize - 1))], P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
mode = 0;
bitcnt = 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 <<= (mp_digit)1;
if (mode == 0 && y == 0) {
continue;
}
if (mode == 1 && y == 0) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
continue;
}
bitbuf |= (y << (winsize - ++bitcpy));
mode = 2;
if (bitcpy == winsize) {
for (x = 0; x < winsize; x++) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
bitcpy = 0;
bitbuf = 0;
mode = 1;
}
}
if (mode == 2 && bitcpy > 0) {
for (x = 0; x < bitcpy; x++) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
bitbuf <<= 1;
if ((bitbuf & (1 << winsize)) != 0) {
if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
}
}
if (redmode == 0) {
if ((err = redux(&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
mp_exch (&res, Y);
err = MP_OKAY;
LBL_RES:mp_clear (&res);
LBL_M:
mp_clear(&M[1]);
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
mp_clear (&M[x]);
}
WC_FREE_VAR_EX(M, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
#ifdef BN_MP_EXPTMOD_BASE_2
#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
#endif
int mp_exptmod_base_2(mp_int * X, mp_int * P, mp_int * Y)
{
mp_digit buf, mp;
int err = MP_OKAY, bitbuf, bitcpy, bitcnt, digidx, x, y;
mp_int res[1];
int (*redux)(mp_int*,mp_int*,mp_digit) = NULL;
#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
if (((P->used * 2 + 1) < (int)MP_WARRAY) &&
P->used < (1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
redux = fast_mp_montgomery_reduce;
} else
#endif
#ifdef BN_MP_MONTGOMERY_REDUCE_C
{
redux = mp_montgomery_reduce;
}
#endif
if (redux == NULL) {
return MP_VAL;
}
if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) {
goto LBL_M;
}
if ((err = mp_init(res)) != MP_OKAY) {
goto LBL_M;
}
if ((err = mp_montgomery_calc_normalization(res, P)) != MP_OKAY) {
goto LBL_RES;
}
digidx = X->used - 1;
bitcpy = (X->used * DIGIT_BIT) % WINSIZE;
if (bitcpy > 0) {
bitcnt = (int)DIGIT_BIT - bitcpy;
buf = X->dp[digidx--];
bitbuf = (int)(buf >> bitcnt);
err = mp_mul_2d(res, bitbuf, res);
if (err != MP_OKAY) {
goto LBL_RES;
}
err = mp_mod(res, P, res);
if (err != MP_OKAY) {
goto LBL_RES;
}
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 <<= (mp_digit)1;
bitbuf |= (y << (WINSIZE - ++bitcpy));
if (bitcpy == WINSIZE) {
for (x = 0; x < WINSIZE; x++) {
err = mp_sqr(res, res);
if (err != MP_OKAY) {
goto LBL_RES;
}
err = (*redux)(res, P, mp);
if (err != MP_OKAY) {
goto LBL_RES;
}
}
err = mp_mul_2d(res, bitbuf, res);
if (err != MP_OKAY) {
goto LBL_RES;
}
err = mp_mod(res, P, res);
if (err != MP_OKAY) {
goto LBL_RES;
}
bitcpy = 0;
bitbuf = 0;
}
}
err = (*redux)(res, P, mp);
if (err != MP_OKAY) {
goto LBL_RES;
}
err = mp_copy(res, Y);
LBL_RES:mp_clear (res);
LBL_M:
return err;
}
#undef WINSIZE
#endif
int mp_montgomery_setup (mp_int * n, mp_digit * rho)
{
mp_digit x, b;
b = n->dp[0];
if ((b & 1) == 0) {
return MP_VAL;
}
x = (((b + 2) & 4) << 1) + b;
x *= 2 - b * x;
#if !defined(MP_8BIT)
x *= 2 - b * x;
#endif
#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
x *= 2 - b * x;
#endif
#ifdef MP_64BIT
x *= 2 - b * x;
#endif
*rho = (mp_digit)((((mp_digit)1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK);
return MP_OKAY;
}
int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
{
int ix, res, olduse;
WC_DECLARE_VAR(W, mp_word, MP_WARRAY, 0);
olduse = x->used;
if (x->alloc < n->used + 1) {
if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
return res;
}
}
WC_ALLOC_VAR_EX(W, mp_word, (n->used*2+2), NULL, DYNAMIC_TYPE_BIGINT,
return MP_MEM);
XMEMSET(W, 0, sizeof(mp_word) * (n->used * 2 + 2));
{
mp_word *_W;
mp_digit *tmpx;
_W = W;
tmpx = x->dp;
for (ix = 0; ix < x->used; ix++) {
*_W++ = *tmpx++;
}
}
for (ix = 0; ix < n->used; ix++) {
mp_digit mu;
mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
{
int iy;
mp_digit *tmpn;
mp_word *_W;
tmpn = n->dp;
_W = W + ix;
for (iy = 0; iy < n->used; iy++) {
*_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
}
}
W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
}
{
mp_digit *tmpx;
mp_word *_W, *_W1;
_W1 = W + ix;
_W = W + ++ix;
for (; ix <= n->used * 2 + 1; ix++) {
*_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
}
tmpx = x->dp;
_W = W + n->used;
for (ix = 0; ix < n->used + 1; ix++) {
*tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
}
for (; ix < olduse; ix++) {
*tmpx++ = 0;
}
}
x->used = n->used + 1;
mp_clamp (x);
WC_FREE_VAR_EX(W, NULL, DYNAMIC_TYPE_BIGINT);
if (mp_cmp_mag (x, n) != MP_LT) {
return s_mp_sub (x, n, x);
}
return MP_OKAY;
}
int mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
{
int ix, res, digs;
mp_digit mu;
digs = n->used * 2 + 1;
if ((digs < (int)MP_WARRAY) &&
n->used <
(1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_mp_montgomery_reduce (x, n, rho);
}
if (x->alloc < digs) {
if ((res = mp_grow (x, digs)) != MP_OKAY) {
return res;
}
}
x->used = digs;
for (ix = 0; ix < n->used; ix++) {
mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK);
{
int iy;
mp_digit *tmpn, *tmpx, u;
mp_word r;
tmpn = n->dp;
tmpx = x->dp + ix;
u = 0;
for (iy = 0; iy < n->used; iy++) {
r = ((mp_word)mu) * ((mp_word)*tmpn++) +
((mp_word) u) + ((mp_word) * tmpx);
u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
*tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK));
}
while (u) {
*tmpx += u;
u = *tmpx >> DIGIT_BIT;
*tmpx++ &= MP_MASK;
}
}
}
mp_clamp(x);
mp_rshd (x, n->used);
if (mp_cmp_mag (x, n) != MP_LT) {
return s_mp_sub (x, n, x);
}
return MP_OKAY;
}
void mp_dr_setup(mp_int *a, mp_digit *d)
{
*d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) -
((mp_word)a->dp[0]));
}
int mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k)
{
int err, i, m;
mp_word r;
mp_digit mu, *tmpx1, *tmpx2;
m = n->used;
if (x->alloc < m + m) {
if ((err = mp_grow (x, m + m)) != MP_OKAY) {
return err;
}
}
top:
tmpx1 = x->dp;
tmpx2 = x->dp + m;
mu = 0;
for (i = 0; i < m; i++) {
r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu;
*tmpx1++ = (mp_digit)(r & MP_MASK);
mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT));
}
*tmpx1++ = mu;
for (i = m + 1; i < x->used; i++) {
*tmpx1++ = 0;
}
mp_clamp (x);
if (mp_cmp_mag (x, n) != MP_LT) {
if ((err = s_mp_sub(x, n, x)) != MP_OKAY) {
return err;
}
goto top;
}
return MP_OKAY;
}
int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d)
{
mp_int q;
int p, res;
if ((res = mp_init(&q)) != MP_OKAY) {
return res;
}
p = mp_count_bits(n);
top:
if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
goto ERR;
}
if (d != 1) {
if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) {
goto ERR;
}
}
if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
goto ERR;
}
if (mp_cmp_mag(a, n) != MP_LT) {
if ((res = s_mp_sub(a, n, a)) != MP_OKAY) {
goto ERR;
}
goto top;
}
ERR:
mp_clear(&q);
return res;
}
int mp_reduce_2k_setup(mp_int *a, mp_digit *d)
{
int res, p;
mp_int tmp;
if ((res = mp_init(&tmp)) != MP_OKAY) {
return res;
}
p = mp_count_bits(a);
if ((res = mp_2expt(&tmp, p)) != MP_OKAY) {
mp_clear(&tmp);
return res;
}
if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) {
mp_clear(&tmp);
return res;
}
*d = tmp.dp[0];
mp_clear(&tmp);
return MP_OKAY;
}
int mp_set_bit (mp_int * a, int b)
{
int i = b / DIGIT_BIT, res;
if (b < 0 || (a->dp == NULL && (a->alloc != 0 || a->used != 0)))
return MP_VAL;
if (a->dp == NULL || a->used < (int)(i + 1)) {
if ((res = mp_grow (a, i + 1)) != MP_OKAY) {
return res;
}
a->used = (int)(i + 1);
}
a->dp[i] |= ((mp_digit)1) << (b % DIGIT_BIT);
return MP_OKAY;
}
int mp_2expt (mp_int * a, int b)
{
mp_zero (a);
return mp_set_bit(a, b);
}
int mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
{
mp_digit u, *tmpa, *tmpc;
mp_word r;
int ix, res, olduse;
if (c->dp == NULL || c->alloc < a->used + 1) {
if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
return res;
}
}
olduse = c->used;
c->sign = a->sign;
tmpa = a->dp;
tmpc = c->dp;
u = 0;
for (ix = 0; ix < a->used; ix++) {
r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
*tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
}
*tmpc++ = u;
++ix;
while (ix++ < olduse) {
*tmpc++ = 0;
}
c->used = a->used + 1;
mp_clamp(c);
return MP_OKAY;
}
#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 res;
mp_int t;
if ((res = mp_init_size (&t, c->used)) != MP_OKAY) {
return res;
}
res = mp_mul (a, b, &t);
if (res == MP_OKAY) {
res = mp_mod (&t, c, d);
}
mp_clear (&t);
return res;
}
int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d)
{
int res;
mp_int t;
if ((res = mp_init (&t)) != MP_OKAY) {
return res;
}
res = mp_sub (a, b, &t);
if (res == MP_OKAY) {
res = mp_mod (&t, c, d);
}
mp_clear (&t);
return res;
}
int mp_addmod(mp_int* a, mp_int* b, mp_int* c, mp_int* d)
{
int res;
mp_int t;
if ((res = mp_init (&t)) != MP_OKAY) {
return res;
}
res = mp_add (a, b, &t);
if (res == MP_OKAY) {
res = mp_mod (&t, c, d);
}
mp_clear (&t);
return res;
}
int mp_submod_ct(mp_int* a, mp_int* b, mp_int* c, mp_int* d)
{
int res;
mp_int t;
mp_int* r = d;
if (c == d) {
r = &t;
if ((res = mp_init (r)) != MP_OKAY) {
return res;
}
}
res = mp_sub (a, b, r);
if (res == MP_OKAY) {
if (mp_isneg (r)) {
res = mp_add (r, c, d);
} else if (c == d) {
res = mp_copy (r, d);
}
}
if (c == d) {
mp_clear (r);
}
return res;
}
int mp_addmod_ct(mp_int* a, mp_int* b, mp_int* c, mp_int* d)
{
int res;
mp_int t;
mp_int* r = d;
if (c == d) {
r = &t;
if ((res = mp_init (r)) != MP_OKAY) {
return res;
}
}
res = mp_add (a, b, r);
if (res == MP_OKAY) {
if (mp_cmp (r, c) != MP_LT) {
res = mp_sub (r, c, d);
} else if (c == d) {
res = mp_copy (r, d);
}
}
if (c == d) {
mp_clear (r);
}
return res;
}
int mp_sqr (mp_int * a, mp_int * b)
{
int res;
{
#ifdef BN_FAST_S_MP_SQR_C
if ((a->used * 2 + 1) < (int)MP_WARRAY &&
a->used <
(1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
res = fast_s_mp_sqr (a, b);
} else
#endif
#ifdef BN_S_MP_SQR_C
res = s_mp_sqr (a, b);
#else
res = MP_VAL;
#endif
}
b->sign = MP_ZPOS;
return res;
}
#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
{
int res, neg;
neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
{
#ifdef BN_FAST_S_MP_MUL_DIGS_C
int digs = a->used + b->used + 1;
if ((digs < (int)MP_WARRAY) &&
MIN(a->used, b->used) <=
(1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
res = fast_s_mp_mul_digs (a, b, c, digs);
} else
#endif
#ifdef BN_S_MP_MUL_DIGS_C
res = s_mp_mul (a, b, c);
#else
res = MP_VAL;
#endif
}
c->sign = (c->used > 0) ? neg : MP_ZPOS;
return res;
}
int mp_mul_2(mp_int * a, mp_int * b)
{
int x, res, oldused;
if (b->alloc < a->used + 1) {
if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
return res;
}
}
oldused = b->used;
b->used = a->used;
{
mp_digit r, rr, *tmpa, *tmpb;
tmpa = a->dp;
tmpb = b->dp;
r = 0;
for (x = 0; x < a->used; x++) {
rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
*tmpb++ = (mp_digit)(((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK);
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 MP_OKAY;
}
int mp_div_3 (mp_int * a, mp_int *c, mp_digit * d)
{
mp_int q;
mp_word w, t;
mp_digit b;
int res, ix;
b = (mp_digit) ( (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3) );
if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
return res;
}
q.used = a->used;
q.sign = a->sign;
w = 0;
if (a->used == 0) {
mp_clear(&q);
return MP_VAL;
}
for (ix = a->used - 1; ix >= 0; ix--) {
w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
if (w >= 3) {
t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT);
w -= t+t+t;
while (w >= 3) {
t += 1;
w -= 3;
}
} else {
t = 0;
}
q.dp[ix] = (mp_digit)t;
}
if (d != NULL) {
*d = (mp_digit)w;
}
if (c != NULL) {
mp_clamp(&q);
mp_exch(&q, c);
}
mp_clear(&q);
return res;
}
int mp_init_size (mp_int * a, int size)
{
size += (MP_PREC * 2) - (size % MP_PREC);
a->dp = (mp_digit *)XMALLOC (sizeof (mp_digit) * size, NULL,
DYNAMIC_TYPE_BIGINT);
if (a->dp == NULL) {
return MP_MEM;
}
a->used = 0;
a->alloc = size;
a->sign = MP_ZPOS;
#ifdef HAVE_WOLF_BIGINT
wc_bigint_init(&a->raw);
#endif
XMEMSET(a->dp, 0, sizeof (mp_digit) * size);
return MP_OKAY;
}
int fast_s_mp_sqr (mp_int * a, mp_int * b)
{
int olduse, res, pa, ix, iz;
WC_DECLARE_VAR(W, mp_digit, MP_WARRAY, 0);
mp_digit *tmpx;
mp_word W1;
pa = a->used + a->used;
if (b->alloc < pa) {
if ((res = mp_grow (b, pa)) != MP_OKAY) {
return res;
}
}
if (pa > (int)MP_WARRAY)
return MP_RANGE;
if (pa == 0) {
mp_zero(b);
return MP_OKAY;
}
WC_ALLOC_VAR_EX(W, mp_digit, pa, NULL, DYNAMIC_TYPE_BIGINT,
return MP_MEM);
W1 = 0;
for (ix = 0; ix < pa; ix++) {
int tx, ty, iy;
mp_word _W;
mp_digit *tmpy;
_W = 0;
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);
for (iz = 0; iz < iy; iz++) {
_W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
}
_W = _W + _W + W1;
if ((ix&1) == 0) {
_W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
}
W[ix] = (mp_digit)(_W & MP_MASK);
W1 = _W >> ((mp_word)DIGIT_BIT);
}
olduse = b->used;
b->used = a->used+a->used;
{
mp_digit *tmpb;
tmpb = b->dp;
for (ix = 0; ix < pa; ix++) {
*tmpb++ = (mp_digit)(W[ix] & MP_MASK);
}
for (; ix < olduse; ix++) {
*tmpb++ = 0;
}
}
mp_clamp (b);
WC_FREE_VAR_EX(W, NULL, DYNAMIC_TYPE_BIGINT);
return MP_OKAY;
}
int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
{
int olduse, res, pa, ix, iz;
WC_DECLARE_VAR(W, mp_digit, MP_WARRAY, 0);
mp_word _W;
if (c->alloc < digs) {
if ((res = mp_grow (c, digs)) != MP_OKAY) {
return res;
}
}
pa = MIN(digs, a->used + b->used);
if (pa > (int)MP_WARRAY)
return MP_RANGE;
if (pa == 0) {
mp_zero(c);
return MP_OKAY;
}
WC_ALLOC_VAR_EX(W, mp_digit, pa, NULL, DYNAMIC_TYPE_BIGINT,
return MP_MEM);
_W = 0;
for (ix = 0; ix < pa; ix++) {
int tx, ty;
int iy;
mp_digit *tmpx, *tmpy;
if ((a->used > 0) && (b->used > 0)) {
ty = MIN(b->used-1, ix);
tx = ix - ty;
tmpx = a->dp + tx;
tmpy = b->dp + ty;
iy = MIN(a->used-tx, ty+1);
for (iz = 0; iz < iy; ++iz) {
_W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
}
}
W[ix] = (mp_digit)(((mp_digit)_W) & MP_MASK);
_W = _W >> ((mp_word)DIGIT_BIT);
}
olduse = c->used;
c->used = pa;
{
mp_digit *tmpc;
tmpc = c->dp;
for (ix = 0; ix < pa; ix++) {
*tmpc++ = W[ix];
}
for (; ix < olduse; ix++) {
*tmpc++ = 0;
}
}
mp_clamp (c);
WC_FREE_VAR_EX(W, NULL, DYNAMIC_TYPE_BIGINT);
return MP_OKAY;
}
int s_mp_sqr (mp_int * a, mp_int * b)
{
mp_int t;
int res, ix, iy, pa;
mp_word r;
mp_digit u, tmpx, *tmpt;
pa = a->used;
if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
return res;
}
t.used = 2*pa + 1;
for (ix = 0; ix < pa; ix++) {
r = ((mp_word) t.dp[2*ix]) +
((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
tmpx = a->dp[ix];
tmpt = t.dp + (2*ix + 1);
for (iy = ix + 1; iy < pa; iy++) {
r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
r = ((mp_word) *tmpt) + r + r + ((mp_word) u);
*tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
}
while (u != ((mp_digit) 0)) {
r = ((mp_word) *tmpt) + ((mp_word) u);
*tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
}
}
mp_clamp (&t);
mp_exch (&t, b);
mp_clear (&t);
return MP_OKAY;
}
int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
{
mp_int t;
int res, pa, pb, ix, iy;
mp_digit u;
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
if ((digs < (int)MP_WARRAY) &&
MIN (a->used, b->used) <
(1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_s_mp_mul_digs (a, b, c, digs);
}
if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
return res;
}
t.used = digs;
pa = a->used;
for (ix = 0; ix < pa; ix++) {
u = 0;
pb = MIN (b->used, digs - ix);
tmpx = a->dp[ix];
tmpt = t.dp + ix;
tmpy = b->dp;
for (iy = 0; iy < pb; iy++) {
r = ((mp_word)*tmpt) +
((mp_word)tmpx) * ((mp_word)*tmpy++) +
((mp_word) u);
*tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
}
if (ix + iy < digs) {
*tmpt = u;
}
}
mp_clamp (&t);
mp_exch (&t, c);
mp_clear (&t);
return MP_OKAY;
}
int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
{
int x, bits, res;
bits = mp_count_bits (b) % DIGIT_BIT;
if (b->used > 1) {
if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1))
!= MP_OKAY) {
return res;
}
} else {
if ((res = mp_set(a, 1)) != MP_OKAY) {
return res;
}
bits = 1;
}
for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
return res;
}
if (mp_cmp_mag (a, b) != MP_LT) {
if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
return res;
}
}
}
return MP_OKAY;
}
#ifdef MP_LOW_MEM
#define TAB_SIZE 32
#else
#define TAB_SIZE 256
#endif
int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
{
mp_int M[TAB_SIZE], res, mu;
mp_digit buf;
int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
int (*redux)(mp_int*,mp_int*,mp_int*);
x = 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;
}
#ifdef MP_LOW_MEM
if (winsize > 5) {
winsize = 5;
}
#endif
if ((err = mp_init(&M[1])) != MP_OKAY) {
return err;
}
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
if ((err = mp_init(&M[x])) != MP_OKAY) {
for (y = 1<<(winsize-1); y < x; y++) {
mp_clear (&M[y]);
}
mp_clear(&M[1]);
return err;
}
}
if ((err = mp_init (&mu)) != MP_OKAY) {
goto LBL_M;
}
if (redmode == 0) {
if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
goto LBL_MU;
}
redux = mp_reduce;
} else {
if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
goto LBL_MU;
}
redux = mp_reduce_2k_l;
}
if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
goto LBL_MU;
}
if ((err = mp_copy (&M[1], &M[(mp_digit)(1 << (winsize - 1))])) != MP_OKAY) {
goto LBL_MU;
}
for (x = 0; x < (winsize - 1); x++) {
if ((err = mp_sqr (&M[(mp_digit)(1 << (winsize - 1))],
&M[(mp_digit)(1 << (winsize - 1))])) != MP_OKAY) {
goto LBL_MU;
}
if ((err = redux (&M[(mp_digit)(1 << (winsize - 1))], P, &mu)) != MP_OKAY) {
goto LBL_MU;
}
}
for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
goto LBL_MU;
}
if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
goto LBL_MU;
}
}
if ((err = mp_init (&res)) != MP_OKAY) {
goto LBL_MU;
}
if ((err = mp_set (&res, 1)) != MP_OKAY) {
goto LBL_MU;
}
mode = 0;
bitcnt = 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 >> (mp_digit)(DIGIT_BIT - 1)) & 1;
buf <<= (mp_digit)1;
if (mode == 0 && y == 0) {
continue;
}
if (mode == 1 && y == 0) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
continue;
}
bitbuf |= (y << (winsize - ++bitcpy));
mode = 2;
if (bitcpy == winsize) {
for (x = 0; x < winsize; x++) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
}
if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
bitcpy = 0;
bitbuf = 0;
mode = 1;
}
}
if (mode == 2 && bitcpy > 0) {
for (x = 0; x < bitcpy; x++) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
bitbuf <<= 1;
if ((bitbuf & (1 << winsize)) != 0) {
if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
}
}
}
mp_exch (&res, Y);
err = MP_OKAY;
LBL_RES:mp_clear (&res);
LBL_MU:mp_clear (&mu);
LBL_M:
mp_clear(&M[1]);
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
mp_clear (&M[x]);
}
return err;
}
int mp_reduce_setup (mp_int * a, mp_int * b)
{
int res;
if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
return res;
}
return mp_div (a, b, a, NULL);
}
int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
{
mp_int q;
int res, um = m->used;
if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
return res;
}
mp_rshd (&q, um - 1);
if (((mp_word) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
goto CLEANUP;
}
} else {
#ifdef BN_S_MP_MUL_HIGH_DIGS_C
if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
goto CLEANUP;
}
#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
goto CLEANUP;
}
#else
{
res = MP_VAL;
goto CLEANUP;
}
#endif
}
mp_rshd (&q, um + 1);
if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
goto CLEANUP;
}
if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
goto CLEANUP;
}
if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
goto CLEANUP;
}
if (mp_cmp_d (x, 0) == MP_LT) {
if ((res = mp_set (&q, 1)) != MP_OKAY)
goto CLEANUP;
if ((res = mp_lshd (&q, um + 1)) != MP_OKAY)
goto CLEANUP;
if ((res = mp_add (x, &q, x)) != MP_OKAY)
goto CLEANUP;
}
while (mp_cmp (x, m) != MP_LT) {
if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
goto CLEANUP;
}
}
CLEANUP:
mp_clear (&q);
return res;
}
int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
{
mp_int q;
int p, res;
if ((res = mp_init(&q)) != MP_OKAY) {
return res;
}
p = mp_count_bits(n);
top:
if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
goto ERR;
}
if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
goto ERR;
}
if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
goto ERR;
}
if (mp_cmp_mag(a, n) != MP_LT) {
if ((res = s_mp_sub(a, n, a)) != MP_OKAY) {
goto ERR;
}
goto top;
}
ERR:
mp_clear(&q);
return res;
}
int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
{
int res;
mp_int tmp;
if ((res = mp_init(&tmp)) != MP_OKAY) {
return res;
}
if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
goto ERR;
}
if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
goto ERR;
}
ERR:
mp_clear(&tmp);
return res;
}
int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
{
mp_int t;
int res, pa, pb, ix, iy;
mp_digit u;
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
if (((a->used + b->used + 1) < (int)MP_WARRAY)
&& MIN (a->used, b->used) <
(1L << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_s_mp_mul_high_digs (a, b, c, digs);
}
#endif
if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
return res;
}
t.used = a->used + b->used + 1;
pa = a->used;
pb = b->used;
for (ix = 0; ix < pa && a->dp; ix++) {
u = 0;
tmpx = a->dp[ix];
tmpt = &(t.dp[digs]);
tmpy = b->dp + (digs - ix);
for (iy = digs - ix; iy < pb; iy++) {
r = ((mp_word)*tmpt) +
((mp_word)tmpx) * ((mp_word)*tmpy++) +
((mp_word) u);
*tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
}
*tmpt = u;
}
mp_clamp (&t);
mp_exch (&t, c);
mp_clear (&t);
return MP_OKAY;
}
int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
{
int olduse, res, pa, ix, iz;
WC_DECLARE_VAR(W, mp_digit, MP_WARRAY, 0);
mp_word _W;
if (a->dp == NULL) {
return MP_VAL;
}
pa = a->used + b->used;
if (c->alloc < pa) {
if ((res = mp_grow (c, pa)) != MP_OKAY) {
return res;
}
}
if (pa > (int)MP_WARRAY)
return MP_RANGE;
WC_ALLOC_VAR_EX(W, mp_digit, pa, NULL, DYNAMIC_TYPE_BIGINT,
return MP_MEM);
_W = 0;
for (ix = digs; ix < pa; ix++) {
int tx, ty, iy;
mp_digit *tmpx, *tmpy;
ty = MIN(b->used-1, ix);
tx = ix - ty;
tmpx = a->dp + tx;
tmpy = b->dp + ty;
iy = MIN(a->used-tx, ty+1);
for (iz = 0; iz < iy; iz++) {
_W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
}
W[ix] = (mp_digit)(((mp_digit)_W) & MP_MASK);
_W = _W >> ((mp_word)DIGIT_BIT);
}
olduse = c->used;
c->used = pa;
{
mp_digit *tmpc;
tmpc = c->dp + digs;
for (ix = digs; ix < pa; ix++) {
*tmpc++ = W[ix];
}
for (; ix < olduse; ix++) {
*tmpc++ = 0;
}
}
mp_clamp (c);
WC_FREE_VAR_EX(W, NULL, DYNAMIC_TYPE_BIGINT);
return MP_OKAY;
}
#ifndef MP_SET_CHUNK_BITS
#define MP_SET_CHUNK_BITS 4
#endif
int mp_set_int (mp_int * a, unsigned long b)
{
int x, res;
if (b < MP_DIGIT_MAX) {
return mp_set (a, (mp_digit)b);
}
mp_zero (a);
for (x = 0; x < (int)(sizeof(b) * 8) / MP_SET_CHUNK_BITS; x++) {
if ((res = mp_mul_2d (a, MP_SET_CHUNK_BITS, a)) != MP_OKAY) {
return res;
}
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;
}
mp_clamp (a);
return MP_OKAY;
}
#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_ECC) || !defined(NO_RSA) || \
!defined(NO_DSA) | !defined(NO_DH)
int mp_sqrmod (mp_int * a, mp_int * b, mp_int * c)
{
int res;
mp_int t;
if ((res = mp_init (&t)) != MP_OKAY) {
return res;
}
if ((res = mp_sqr (a, &t)) != MP_OKAY) {
mp_clear (&t);
return res;
}
res = mp_mod (&t, b, c);
mp_clear (&t);
return res;
}
#endif
#if defined(HAVE_ECC) || !defined(NO_PWDBASED) || defined(WOLFSSL_SNIFFER) || \
defined(WOLFSSL_HAVE_WOLFSCEP) || defined(WOLFSSL_KEY_GEN) || \
defined(OPENSSL_EXTRA) || defined(WC_RSA_BLINDING) || \
(!defined(NO_RSA) && !defined(NO_RSA_BOUNDS_CHECK))
int mp_add_d (mp_int* a, mp_digit b, mp_int* c)
{
int res, ix, oldused;
mp_digit *tmpa, *tmpc, mu;
if (b > MP_DIGIT_MAX) return MP_VAL;
if (c->alloc < a->used + 1) {
if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
return res;
}
}
if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) {
a->sign = MP_ZPOS;
res = mp_sub_d(a, b, c);
a->sign = c->sign = MP_NEG;
mp_clamp(c);
return res;
}
oldused = c->used;
tmpa = a->dp;
tmpc = c->dp;
if (tmpa == NULL || tmpc == NULL) {
return MP_MEM;
}
if (a->sign == MP_ZPOS) {
*tmpc = *tmpa++ + b;
mu = *tmpc >> DIGIT_BIT;
*tmpc++ &= MP_MASK;
for (ix = 1; ix < a->used; ix++) {
*tmpc = *tmpa++ + mu;
mu = *tmpc >> DIGIT_BIT;
*tmpc++ &= MP_MASK;
}
if (ix < c->alloc) {
ix++;
*tmpc++ = mu;
}
c->used = a->used + 1;
} else {
c->used = 1;
if (a->used == 1) {
*tmpc++ = b - a->dp[0];
} else {
*tmpc++ = b;
}
ix = 1;
}
c->sign = MP_ZPOS;
while (ix++ < oldused) {
*tmpc++ = 0;
}
mp_clamp(c);
return MP_OKAY;
}
int mp_sub_d (mp_int * a, mp_digit b, mp_int * c)
{
mp_digit *tmpa, *tmpc, mu;
int res, ix, oldused;
if (b > MP_MASK) return MP_VAL;
if (c->alloc < a->used + 1) {
if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
return res;
}
}
if (a->sign == MP_NEG) {
a->sign = MP_ZPOS;
res = mp_add_d(a, b, c);
a->sign = c->sign = MP_NEG;
mp_clamp(c);
return res;
}
oldused = c->used;
tmpa = a->dp;
tmpc = c->dp;
if (tmpa == NULL || tmpc == NULL) {
return MP_MEM;
}
if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) {
if (a->used == 1) {
*tmpc++ = b - *tmpa;
} else {
*tmpc++ = b;
}
ix = 1;
c->sign = MP_NEG;
c->used = 1;
} else {
c->sign = MP_ZPOS;
c->used = a->used;
*tmpc = *tmpa++ - b;
mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
*tmpc++ &= MP_MASK;
for (ix = 1; ix < a->used; ix++) {
*tmpc = *tmpa++ - mu;
mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
*tmpc++ &= MP_MASK;
}
}
while (ix++ < oldused) {
*tmpc++ = 0;
}
mp_clamp(c);
return MP_OKAY;
}
#endif
#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || defined(HAVE_ECC) || \
defined(DEBUG_WOLFSSL) || !defined(NO_RSA) || !defined(NO_DSA) || \
!defined(NO_DH) || defined(WC_MP_TO_RADIX)
static const int lnz[16] = {
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};
int mp_cnt_lsb(mp_int *a)
{
int x;
mp_digit q = 0, qq;
if (mp_iszero(a) == MP_YES) {
return 0;
}
for (x = 0; x < a->used && a->dp[x] == 0; x++) {}
if (a->dp)
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(mp_digit b, int *p)
{
int x;
if ((b==0) || (b & (b-1))) {
return 0;
}
for (x = 0; x < DIGIT_BIT; x++) {
if (b == (((mp_digit)1)<<x)) {
*p = x;
return 1;
}
}
return 0;
}
static int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d)
{
mp_int q;
mp_word w;
mp_digit t;
int res = MP_OKAY, ix;
if (b == 0) {
return MP_VAL;
}
if (b == 1 || mp_iszero(a) == MP_YES) {
if (d != NULL) {
*d = 0;
}
if (c != NULL) {
return mp_copy(a, c);
}
return MP_OKAY;
}
if (s_is_power_of_two(b, &ix) == 1) {
if (d != NULL) {
*d = a->dp[0] & ((((mp_digit)1)<<ix) - 1);
}
if (c != NULL) {
return mp_div_2d(a, ix, c, NULL);
}
return MP_OKAY;
}
#ifdef BN_MP_DIV_3_C
if (b == 3) {
return mp_div_3(a, c, d);
}
#endif
if (c != NULL) {
if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
return res;
}
q.used = a->used;
q.sign = a->sign;
}
else {
if ((res = mp_init(&q)) != MP_OKAY) {
return res;
}
}
w = 0;
if (a->used == 0)
return MP_VAL;
for (ix = a->used - 1; ix >= 0; ix--) {
w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
if (w >= b) {
#ifdef WOLFSSL_LINUXKM
t = (mp_digit)w;
do_div(t, b);
#else
t = (mp_digit)(w / b);
#endif
w -= ((mp_word)t) * ((mp_word)b);
} else {
t = 0;
}
if (c != NULL)
q.dp[ix] = (mp_digit)t;
}
if (d != NULL) {
*d = (mp_digit)w;
}
if (c != NULL) {
mp_clamp(&q);
mp_exch(&q, c);
}
mp_clear(&q);
return res;
}
int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c)
{
return mp_div_d(a, b, NULL, c);
}
#endif
#if (defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA)) || !defined(NO_DH) || !defined(NO_DSA)
const FLASH_QUALIFIER mp_digit ltm_prime_tab[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,
#ifndef MP_8BIT
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
#endif
};
static int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result)
{
mp_int n1, y, r;
int s, j, err;
*result = MP_NO;
if (mp_cmp_d(b, 1) != MP_GT) {
return MP_VAL;
}
if ((err = mp_init_copy (&n1, a)) != MP_OKAY) {
return err;
}
if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) {
goto LBL_N1;
}
if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) {
goto LBL_N1;
}
s = mp_cnt_lsb(&r);
if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) {
goto LBL_R;
}
if ((err = mp_init (&y)) != MP_OKAY) {
goto LBL_R;
}
#if defined(WOLFSSL_HAVE_SP_RSA) || defined(WOLFSSL_HAVE_SP_DH)
#ifndef WOLFSSL_SP_NO_2048
if (mp_count_bits(a) == 1024 && mp_isodd(a))
err = sp_ModExp_1024(b, &r, a, &y);
else if (mp_count_bits(a) == 2048 && mp_isodd(a))
err = sp_ModExp_2048(b, &r, a, &y);
else
#endif
#ifndef WOLFSSL_SP_NO_3072
if (mp_count_bits(a) == 1536 && mp_isodd(a))
err = sp_ModExp_1536(b, &r, a, &y);
else if (mp_count_bits(a) == 3072 && mp_isodd(a))
err = sp_ModExp_3072(b, &r, a, &y);
else
#endif
#ifdef WOLFSSL_SP_4096
if (mp_count_bits(a) == 4096 && mp_isodd(a))
err = sp_ModExp_4096(b, &r, a, &y);
else
#endif
#endif
err = mp_exptmod (b, &r, a, &y);
if (err != MP_OKAY)
goto LBL_Y;
if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) {
j = 1;
while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) {
if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) {
goto LBL_Y;
}
if (mp_cmp_d (&y, 1) == MP_EQ) {
goto LBL_Y;
}
++j;
}
if (mp_cmp (&y, &n1) != MP_EQ) {
goto LBL_Y;
}
}
*result = MP_YES;
LBL_Y:mp_clear (&y);
LBL_R:mp_clear (&r);
LBL_N1:mp_clear (&n1);
return err;
}
static int mp_prime_is_divisible (mp_int * a, int *result)
{
int err, ix;
mp_digit res;
*result = MP_NO;
for (ix = 0; ix < PRIME_SIZE; ix++) {
if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) {
return err;
}
if (res == 0) {
*result = MP_YES;
return MP_OKAY;
}
}
return MP_OKAY;
}
int mp_prime_is_prime (mp_int * a, int t, int *result)
{
mp_int b;
int ix, err, res;
*result = MP_NO;
if (t <= 0 || t > PRIME_SIZE) {
return MP_VAL;
}
if (mp_isone(a)) {
*result = MP_NO;
return MP_OKAY;
}
for (ix = 0; ix < PRIME_SIZE; ix++) {
if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) {
*result = MP_YES;
return MP_OKAY;
}
}
if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) {
return err;
}
if (res == MP_YES) {
return MP_OKAY;
}
if ((err = mp_init (&b)) != MP_OKAY) {
return err;
}
for (ix = 0; ix < t; ix++) {
if ((err = mp_set (&b, ltm_prime_tab[ix])) != MP_OKAY) {
goto LBL_B;
}
if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) {
goto LBL_B;
}
if (res == MP_NO) {
goto LBL_B;
}
}
*result = MP_YES;
LBL_B:mp_clear (&b);
return err;
}
int mp_prime_is_prime_ex (mp_int * a, int t, int *result, WC_RNG *rng)
{
mp_int b, c;
int ix, err, res;
byte* base = NULL;
word32 bitSz = 0;
word32 baseSz = 0;
*result = MP_NO;
if (t <= 0 || t > PRIME_SIZE) {
return MP_VAL;
}
if (a->sign == MP_NEG) {
return MP_VAL;
}
if (mp_isone(a)) {
*result = MP_NO;
return MP_OKAY;
}
for (ix = 0; ix < PRIME_SIZE; ix++) {
if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) {
*result = MP_YES;
return MP_OKAY;
}
}
if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) {
return err;
}
if (res == MP_YES) {
return MP_OKAY;
}
if ((err = mp_init (&b)) != MP_OKAY) {
return err;
}
if ((err = mp_init (&c)) != MP_OKAY) {
mp_clear(&b);
return err;
}
bitSz = mp_count_bits(a);
baseSz = (bitSz / 8) + ((bitSz % 8) ? 1 : 0);
bitSz %= 8;
base = (byte*)XMALLOC(baseSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (base == NULL) {
err = MP_MEM;
goto LBL_B;
}
if ((err = mp_sub_d(a, 2, &c)) != MP_OKAY) {
goto LBL_B;
}
for (ix = 0; ix < t; ix++) {
if ((err = wc_RNG_GenerateBlock(rng, base, baseSz)) != 0) {
goto LBL_B;
}
if (bitSz > 0) {
base[0] &= (1 << bitSz) - 1;
}
if ((err = mp_read_unsigned_bin(&b, base, baseSz)) != MP_OKAY) {
goto LBL_B;
}
if (mp_cmp_d(&b, 2) != MP_GT || mp_cmp(&b, &c) != MP_LT) {
ix--;
continue;
}
if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) {
goto LBL_B;
}
if (res == MP_NO) {
goto LBL_B;
}
}
*result = MP_YES;
LBL_B:mp_clear (&b);
mp_clear (&c);
XFREE(base, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
#endif
#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_DH) || !defined(NO_DSA))
static const int USE_BBS = 1;
int mp_rand_prime(mp_int* a, int len, WC_RNG* rng, void* heap)
{
int err, res, type;
byte* buf;
if (a == NULL || rng == NULL)
return MP_VAL;
if (len < 0) {
type = USE_BBS;
len = -len;
} else {
type = 0;
}
if (len < 2 || len > 512) {
return MP_VAL;
}
buf = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_RSA);
if (buf == NULL) {
return MP_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_RSA);
return err;
}
buf[0] |= 0x80 | 0x40;
buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00);
if ((err = mp_read_unsigned_bin(a, buf, len)) != MP_OKAY) {
XFREE(buf, heap, DYNAMIC_TYPE_RSA);
return err;
}
if ((err = mp_prime_is_prime_ex(a, 8, &res, rng)) != MP_OKAY) {
XFREE(buf, heap, DYNAMIC_TYPE_RSA);
return err;
}
} while (res == MP_NO);
XMEMSET(buf, 0, len);
XFREE(buf, heap, DYNAMIC_TYPE_RSA);
return MP_OKAY;
}
#endif
#if defined(WOLFSSL_KEY_GEN)
int mp_lcm (mp_int * a, mp_int * b, mp_int * c)
{
int res;
mp_int t1, t2;
if (mp_iszero (a) == MP_YES || mp_iszero (b) == MP_YES) {
return MP_VAL;
}
if ((res = mp_init_multi (&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
return res;
}
if ((res = mp_gcd (a, b, &t1)) != MP_OKAY) {
goto LBL_T;
}
if (mp_cmp_mag(a, b) == MP_LT) {
if ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) {
goto LBL_T;
}
res = mp_mul(b, &t2, c);
} else {
if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) {
goto LBL_T;
}
res = mp_mul(a, &t2, c);
}
c->sign = MP_ZPOS;
LBL_T:
mp_clear(&t1);
mp_clear(&t2);
return res;
}
int mp_gcd (mp_int * a, mp_int * b, mp_int * c)
{
mp_int u, v;
int k, u_lsb, v_lsb, res;
if (mp_iszero (a) == MP_YES) {
if (mp_iszero (b) == MP_YES) {
return MP_VAL;
}
return mp_abs (b, c);
}
if (mp_iszero (b) == MP_YES) {
return mp_abs (a, c);
}
if ((res = mp_init_copy (&u, a)) != MP_OKAY) {
return res;
}
if ((res = mp_init_copy (&v, b)) != MP_OKAY) {
goto LBL_U;
}
u.sign = v.sign = MP_ZPOS;
u_lsb = mp_cnt_lsb(&u);
v_lsb = mp_cnt_lsb(&v);
k = MIN(u_lsb, v_lsb);
if (k > 0) {
if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) {
goto LBL_V;
}
if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) {
goto LBL_V;
}
}
if (u_lsb != k) {
if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) {
goto LBL_V;
}
}
if (v_lsb != k) {
if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) {
goto LBL_V;
}
}
while (mp_iszero(&v) == MP_NO) {
if (mp_cmp_mag(&u, &v) == MP_GT) {
mp_exch(&u, &v);
}
if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) {
goto LBL_V;
}
if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) {
goto LBL_V;
}
}
if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) {
goto LBL_V;
}
c->sign = MP_ZPOS;
res = MP_OKAY;
LBL_V:mp_clear (&v);
LBL_U:mp_clear (&u);
return res;
}
#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)
const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz+/";
#endif
#if !defined(NO_DSA) || defined(HAVE_ECC) || defined(OPENSSL_EXTRA)
int mp_read_radix (mp_int * a, const char *str, int radix)
{
int y, res, neg;
char ch;
mp_zero(a);
if (radix < MP_RADIX_BIN || radix > MP_RADIX_MAX) {
return MP_VAL;
}
if (*str == '-') {
++str;
neg = MP_NEG;
} else {
neg = MP_ZPOS;
}
mp_zero (a);
while (*str != '\0') {
ch = (radix <= 36) ? (char)XTOUPPER((unsigned char)*str) : *str;
for (y = 0; y < 64; y++) {
if (ch == mp_s_rmap[y]) {
break;
}
}
if (y < radix) {
if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) {
mp_zero(a);
return res;
}
if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) {
mp_zero(a);
return res;
}
} else {
break;
}
++str;
}
while (CharIsWhiteSpace(*str))
++str;
if (*str != '\0') {
mp_zero (a);
return MP_VAL;
}
if (mp_iszero(a) != MP_YES) {
a->sign = neg;
}
return MP_OKAY;
}
#endif
#ifdef WC_MP_TO_RADIX
int mp_radix_size (mp_int *a, int radix, int *size)
{
int res, digs;
mp_int t;
mp_digit d;
*size = 0;
if (radix == MP_RADIX_BIN) {
*size = mp_count_bits(a);
if (*size == 0)
*size = 1;
*size += (a->sign == MP_NEG ? 1 : 0) + 1;
return MP_OKAY;
}
if (radix < MP_RADIX_BIN || radix > MP_RADIX_MAX) {
return MP_VAL;
}
if (mp_iszero(a) == MP_YES) {
#ifndef WC_DISABLE_RADIX_ZERO_PAD
if (radix == 16)
*size = 3;
else
#endif
*size = 2;
return MP_OKAY;
}
digs = 0;
if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
return res;
}
t.sign = MP_ZPOS;
while (mp_iszero (&t) == MP_NO) {
if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) {
mp_clear (&t);
return res;
}
++digs;
}
mp_clear (&t);
#ifndef WC_DISABLE_RADIX_ZERO_PAD
if ((digs & 1) && (radix == 16)) {
++digs;
}
#endif
if (a->sign == MP_NEG) {
++digs;
}
*size = digs + 1;
return MP_OKAY;
}
int mp_toradix (mp_int *a, char *str, int radix)
{
int res, digs;
mp_int t;
mp_digit d;
char *_s = str;
if (radix < MP_RADIX_BIN || radix > MP_RADIX_MAX) {
return MP_VAL;
}
if (mp_iszero(a) == MP_YES) {
#ifndef WC_DISABLE_RADIX_ZERO_PAD
if (radix == 16) {
*str++ = '0';
}
#endif
*str++ = '0';
*str = '\0';
return MP_OKAY;
}
if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
return res;
}
if (t.sign == MP_NEG) {
++_s;
*str++ = '-';
t.sign = MP_ZPOS;
}
digs = 0;
while (mp_iszero (&t) == MP_NO) {
if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) {
mp_clear (&t);
return res;
}
*str++ = mp_s_rmap[d];
++digs;
}
#ifndef WC_DISABLE_RADIX_ZERO_PAD
if ((digs & 1) && (radix == 16)) {
*str++ = mp_s_rmap[0];
++digs;
}
#endif
bn_reverse ((unsigned char *)_s, digs);
*str = '\0';
mp_clear (&t);
return MP_OKAY;
}
#ifdef WOLFSSL_DEBUG_MATH
void mp_dump(const char* desc, mp_int* a, byte verbose)
{
char *buffer;
int size = a->alloc;
buffer = (char*)XMALLOC(size * sizeof(mp_digit) * 2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (buffer == NULL) {
return;
}
printf("%s: ptr=%p, used=%d, sign=%d, size=%d, mpd=%d\n",
desc, a, a->used, a->sign, size, (int)sizeof(mp_digit));
mp_tohex(a, buffer);
printf(" %s\n ", buffer);
if (verbose) {
int i;
for(i=0; i<a->alloc * (int)sizeof(mp_digit); i++) {
printf("%02x ", *(((byte*)a->dp) + i));
}
printf("\n");
}
XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
#endif
#endif
#endif
#endif