/* ssl_bn.c
 *
 * Copyright (C) 2006-2025 wolfSSL Inc.
 *
 * This file is part of wolfSSL.
 *
 * wolfSSL is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * wolfSSL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
 */

#include <wolfssl/wolfcrypt/libwolfssl_sources.h>

#include <wolfssl/internal.h>
#ifndef WC_NO_RNG
    #include <wolfssl/wolfcrypt/random.h>
#endif

#if !defined(WOLFSSL_SSL_BN_INCLUDED)
    #ifndef WOLFSSL_IGNORE_FILE_WARN
        #warning ssl_bn.c does not need to be compiled separately from ssl.c
    #endif
#else

/* Check on validity of big number.
 *
 * Used for parameter validation.
 *
 * @param [in] bn  Big number.
 * @return 1 when bn is not NULL and internal representation is not NULL.
 * @return 0 otherwise.
 */
#define BN_IS_NULL(bn) (((bn) == NULL) || ((bn)->internal == NULL))

/*******************************************************************************
 * Constructor/Destructor/Initializer APIs
 ******************************************************************************/

#if defined(OPENSSL_EXTRA) && !defined(NO_ASN)
/* Set big number to be negative.
 *
 * @param [in, out] bn   Big number to make negative.
 * @param [in]      neg  Whether number is negative.
 * @return  1 on success.
 * @return  -1 when bn or internal representation of bn is NULL.
 */
static int wolfssl_bn_set_neg(WOLFSSL_BIGNUM* bn, int neg)
{
    int ret = 1;

    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = WOLFSSL_FATAL_ERROR;
    }
#if !defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_SP_INT_NEGATIVE)
    else if (neg) {
        mp_setneg((mp_int*)bn->internal);
    }
    else {
        ((mp_int*)bn->internal)->sign = MP_ZPOS;
    }
#endif

    return ret;
}
#endif /* OPENSSL_EXTRA && !NO_ASN */

#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
/* Get the internal representation value into an MP integer.
 *
 * When calling wolfssl_bn_get_value, mpi should be cleared by caller if no
 * longer used. ie mp_free(mpi). This is to free data when fastmath is
 * disabled since a copy of mpi is made by this function and placed into bn.
 *
 * @param [in]      bn   Big number to copy value from.
 * @param [in, out] mpi  MP integer to copy into.
 * @return  1 on success.
 * @return  -1 when bn or internal representation of bn is NULL.
 * @return  -1 when mpi is NULL.
 * @return  -1 when copy fails.
 */
int wolfssl_bn_get_value(WOLFSSL_BIGNUM* bn, mp_int* mpi)
{
    int ret = 1;

    WOLFSSL_MSG("Entering wolfssl_bn_get_value_mp");

    /* Validate parameters. */
    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = WOLFSSL_FATAL_ERROR;
    }
    else if (mpi == NULL) {
        WOLFSSL_MSG("mpi NULL error");
        ret = WOLFSSL_FATAL_ERROR;
    }

    /* Copy the internal representation into MP integer. */
    if ((ret == 1) && mp_copy((mp_int*)bn->internal, mpi) != MP_OKAY) {
        WOLFSSL_MSG("mp_copy error");
        ret = WOLFSSL_FATAL_ERROR;
    }

    return ret;
}

/* Set big number internal representation to value in mpi.
 *
 * Will create a new big number if bn points to NULL.
 *
 * When calling wolfssl_bn_set_value, mpi should be cleared by caller if no
 * longer used. ie mp_free(mpi). This is to free data when fastmath is
 * disabled since a copy of mpi is made by this function and placed into bn.
 *
 * @param [in, out] bn   Pointer to big number to have value.
 * @param [in]      mpi  MP integer with value to set.
 * @return  1 on success.
 * @return  -1 when mpi or bn is NULL.
 * @return  -1 when creating a new big number fails.
 * @return  -1 when copying MP integer fails.
 */
int wolfssl_bn_set_value(WOLFSSL_BIGNUM** bn, mp_int* mpi)
{
    int ret = 1;
    WOLFSSL_BIGNUM* a = NULL;

#ifdef WOLFSSL_DEBUG_OPENSSL
    WOLFSSL_ENTER("wolfssl_bn_set_value");
#endif

    /* Validate parameters. */
    if ((bn == NULL) || (mpi == NULL)) {
        WOLFSSL_MSG("mpi or bn NULL error");
        ret = WOLFSSL_FATAL_ERROR;
    }

    /* Allocate a new big number if one not passed in. */
    if ((ret == 1) && (*bn == NULL)) {
        a = wolfSSL_BN_new();
        if (a == NULL) {
            WOLFSSL_MSG("wolfssl_bn_set_value alloc failed");
            ret = WOLFSSL_FATAL_ERROR;
        }
        *bn = a;
    }

    /* Copy MP integer value into internal representation of big number. */
    if ((ret == 1) && (mp_copy(mpi, (mp_int*)((*bn)->internal)) != MP_OKAY)) {
        WOLFSSL_MSG("mp_copy error");
        ret = WOLFSSL_FATAL_ERROR;
    }

    /* Dispose of any allocated big number on error. */
    if ((ret == -1) && (a != NULL)) {
        wolfSSL_BN_free(a);
        *bn = NULL;
    }
    return ret;
}

/* Initialize a big number.
 *
 * Assumes bn is not NULL.
 *
 * @param [in, out] bn  Big number to initialize.
 */
static void wolfssl_bn_init(WOLFSSL_BIGNUM* bn)
{
    /* Clear fields of big number. */
    XMEMSET(bn, 0, sizeof(WOLFSSL_BIGNUM));
    /* Initialization only fails when passed NULL. */
    (void)mp_init(&bn->mpi);
    /* Set an internal representation. */
    bn->internal = &bn->mpi;
}

/* Create a new big number.
 *
 * @return  An allocated and initialized big number on success.
 * @return  NULL on failure.
 */
WOLFSSL_BIGNUM* wolfSSL_BN_new(void)
{
    WOLFSSL_BIGNUM* bn = NULL;

#ifdef WOLFSSL_DEBUG_OPENSSL
    WOLFSSL_ENTER("wolfSSL_BN_new");
#endif

    /* Allocate memory for big number. */
    bn = (WOLFSSL_BIGNUM*)XMALLOC(sizeof(WOLFSSL_BIGNUM), NULL,
        DYNAMIC_TYPE_BIGINT);
    if (bn == NULL) {
        WOLFSSL_MSG("wolfSSL_BN_new malloc WOLFSSL_BIGNUM failure");
    }
    else {
        /* Initialize newly allocated object. */
        wolfssl_bn_init(bn);
    }

    return bn;
}

#if !defined(USE_INTEGER_HEAP_MATH) && !defined(HAVE_WOLF_BIGINT)
/* Initialize a big number.
 *
 * Call this instead of wolfSSL_BN_new() and wolfSSL_BN_free().
 *
 * Do not call this API after wolfSSL_BN_new() or wolfSSL_BN_init().
 *
 * @param [in, out] bn  Big number to initialize.
 */
void wolfSSL_BN_init(WOLFSSL_BIGNUM* bn)
{
#ifdef WOLFSSL_DEBUG_OPENSSL
    WOLFSSL_ENTER("wolfSSL_BN_init");
#endif

    /* Validate parameter. */
    if (bn != NULL) {
        /* Initialize big number object. */
        wolfssl_bn_init(bn);
    }
}
#endif

/* Dispose of big number.
 *
 * bn is unusable after this call.
 *
 * @param [in, out] bn  Big number to free.
 */
void wolfSSL_BN_free(WOLFSSL_BIGNUM* bn)
{
#ifdef WOLFSSL_DEBUG_OPENSSL
    WOLFSSL_ENTER("wolfSSL_BN_free");
#endif

    /* Validate parameter. */
    if (bn != NULL) {
        /* Cleanup any internal representation. */
        if (bn->internal != NULL) {
            /* Free MP integer. */
            mp_free(&bn->mpi);
        }
        /* Dispose of big number object. */
        XFREE(bn, NULL, DYNAMIC_TYPE_BIGINT);
        /* bn = NULL, don't try to access or double free it */
    }
}

/* Zeroize and dispose of big number.
 *
 * bn is unusable after this call.
 *
 * @param [in, out] bn  Big number to clear and free.
 */
void wolfSSL_BN_clear_free(WOLFSSL_BIGNUM* bn)
{
#ifdef WOLFSSL_DEBUG_OPENSSL
    WOLFSSL_ENTER("wolfSSL_BN_clear_free");
#endif

    /* Validate parameter. */
    if (bn != NULL) {
        /* Check for internal representation. */
        if (bn->internal != NULL) {
            /* Zeroize MP integer. */
            mp_forcezero((mp_int*)bn->internal);
        }
        /* Dispose of big number. */
        wolfSSL_BN_free(bn);
    }
}

/* Zeroize big number.
 *
 * @param [in, out] bn  Big number to clear.
 */
void wolfSSL_BN_clear(WOLFSSL_BIGNUM* bn)
{
#ifdef WOLFSSL_DEBUG_OPENSSL
    WOLFSSL_ENTER("wolfSSL_BN_clear");
#endif

    /* Validate parameter. */
    if (!BN_IS_NULL(bn)) {
        /* Zeroize MP integer. */
        mp_forcezero((mp_int*)bn->internal);
    }
}
#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */

#ifdef OPENSSL_EXTRA

static WOLFSSL_BIGNUM* bn_one = NULL;

/* Return a big number with the value of one.
 *
 * @return  A big number with the value one on success.
 * @return  NULL on failure.
 */
const WOLFSSL_BIGNUM* wolfSSL_BN_value_one(void)
{
    WOLFSSL_BIGNUM* one;

    WOLFSSL_ENTER("wolfSSL_BN_value_one");

    /* Get the global object. */
    one = bn_one;
    /* Create a new big number if global not set. */
    if ((one == NULL) && ((one = wolfSSL_BN_new()) != NULL)) {
        /* Set internal representation to have a value of 1. */
        if (mp_set_int((mp_int*)one->internal, 1) != MP_OKAY) {
            /* Dispose of big number on error. */
            wolfSSL_BN_free(one);
            one = NULL;
        }
        else
    #ifndef SINGLE_THREADED
        /* Ensure global has not been set by another thread. */
        if (bn_one == NULL)
    #endif
        {
            /* Set this big number as the global. */
            bn_one = one;
        }
    #ifndef SINGLE_THREADED
        /* Check if another thread has set the global. */
        if (bn_one != one) {
            /* Dispose of this big number and return the global.  */
            wolfSSL_BN_free(one);
            one = bn_one;
        }
    #endif
    }

    return one;
}

static void wolfSSL_BN_free_one(void) {
    wolfSSL_BN_free(bn_one);
    bn_one = NULL;
}

/* Create a new big number with the same value as the one passed in.
 *
 * @param [in] bn  Big number to duplicate.
 * @return  Big number on success.
 * @return  NULL when bn or internal representation of bn is NULL.
 * @return  NULL when creating a new big number fails.
 * @return  NULL when copying the internal representation fails.
 */
WOLFSSL_BIGNUM* wolfSSL_BN_dup(const WOLFSSL_BIGNUM* bn)
{
    int err = 0;
    WOLFSSL_BIGNUM* ret = NULL;

    WOLFSSL_ENTER("wolfSSL_BN_dup");

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        err = 1;
    }

    /* Create a new big number to return. */
    if ((!err) && ((ret = wolfSSL_BN_new()) == NULL)) {
        WOLFSSL_MSG("bn new error");
        err = 1;
    }

    if (!err) {
        err = (wolfSSL_BN_copy(ret, bn) == NULL);
    }

    if (err) {
         /* Dispose of dynamically allocated data. */
         wolfSSL_BN_free(ret);
         ret = NULL;
    }
    return ret;
}

/* Copy value from bn into another r.
 *
 * @param [in, out] r   Big number to copy into.
 * @param [in]      bn  Big number to copy from.
 * @return  Big number copied into on success.
 * @return  NULL when r or bn is NULL.
 * @return  NULL when copying fails.
 */
WOLFSSL_BIGNUM* wolfSSL_BN_copy(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* bn)
{
    WOLFSSL_ENTER("wolfSSL_BN_copy");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(bn)) {
        WOLFSSL_MSG("r or bn NULL error");
        r = NULL;
    }

    /* Copy the value in. */
    if ((r != NULL) && mp_copy((mp_int*)bn->internal, (mp_int*)r->internal) !=
            MP_OKAY) {
        WOLFSSL_MSG("mp_copy error");
        r = NULL;
    }

    if (r != NULL) {
        /* Copy other fields in a big number. */
        r->neg = bn->neg;
    }

    return r;
}


/*******************************************************************************
 * Encode/Decode APIs.
 ******************************************************************************/

/* Encode the number is a big-endian byte array.
 *
 * Assumes byte array is large enough to hold encoding when not NULL.
 * Use NULL for byte array to get length.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in]  bn  Big number to reduced
 * @param [out] r   Byte array to encode into. May be NULL.
 * @return  Length of big number in bytes on success.
 * @return  -1 when bn is NULL or encoding fails.
 */
int wolfSSL_BN_bn2bin(const WOLFSSL_BIGNUM* bn, unsigned char* r)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_bn2bin");

    /* Validate parameters. */
    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("NULL bn error");
        ret = WOLFSSL_FATAL_ERROR;
    }
    else {
        /* Get the length of the encoding. */
        ret = mp_unsigned_bin_size((mp_int*)bn->internal);
        /* Encode if byte array supplied. */
        if ((r != NULL) && (mp_to_unsigned_bin((mp_int*)bn->internal, r) !=
                MP_OKAY)) {
            WOLFSSL_MSG("mp_to_unsigned_bin error");
            ret = WOLFSSL_FATAL_ERROR;
        }
    }

    return ret;
}


/* Return a big number with value of the decoding of the big-endian byte array.
 *
 * Returns ret when not NULL.
 * Allocates a big number when ret is NULL.
 * Assumes str is not NULL.
 *
 * @param [in]      data  Byte array to decode.
 * @param [in]      len   Number of bytes in byte array.
 * @param [in, out] ret   Big number to reduced. May be NULL.
 * @return  A big number on success.
 * @return  NULL on failure.
 */
WOLFSSL_BIGNUM* wolfSSL_BN_bin2bn(const unsigned char* data, int len,
    WOLFSSL_BIGNUM* ret)
{
    WOLFSSL_BIGNUM* bn = NULL;

    WOLFSSL_ENTER("wolfSSL_BN_bin2bn");

    /* Validate parameters. */
    if (len < 0) {
        ret = NULL;
    }
    /* Allocate a new big number when ret is NULL. */
    else if (ret == NULL) {
        ret = wolfSSL_BN_new();
        bn = ret;
    }

    /* Check ret is usable. */
    if (ret != NULL) {
        /* Check internal representation is usable. */
        if (ret->internal == NULL) {
            ret = NULL;
        }
        else if (data != NULL) {
            /* Decode into big number. */
            if (mp_read_unsigned_bin((mp_int*)ret->internal, data, (word32)len)
                    != 0) {
                WOLFSSL_MSG("mp_read_unsigned_bin failure");
                /* Don't return anything on failure. bn will be freed if set. */
                ret = NULL;
            }
            else {
                /* Don't free bn as we are returning it. */
                bn = NULL;
            }
        }
        else if (data == NULL) {
            wolfSSL_BN_zero(ret);
            /* Don't free bn as we are returning it. */
            bn = NULL;
        }
    }

    /* Dispose of allocated BN not being returned. */
    wolfSSL_BN_free(bn);

    return ret;
}

/* Encode the big number value into a string, of the radix, that is allocated.
 *
 * @param [in] bn     Big number to encode.
 * @param [in] radix  Radix to encode to.
 * @return  String with encoding on success.
 * @return  NULL when bn or internal representation of bn is NULL.
 * @return  NULL on failure.
 */
static char* wolfssl_bn_bn2radix(const WOLFSSL_BIGNUM* bn, int radix)
{
    int err = 0;
    int len = 0;
    char* str = NULL;


    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        err = 1;
    }

    /* Determine length of encoding. */
    if ((!err) && (mp_radix_size((mp_int*)bn->internal, radix, &len) !=
            MP_OKAY)) {
        WOLFSSL_MSG("mp_radix_size failure");
        err = 1;
    }

    if (!err) {
        /* Allocate string. */
        str = (char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_OPENSSL);
        if (str == NULL) {
            WOLFSSL_MSG("BN_bn2hex malloc string failure");
            err = 1;
        }
    }

    /* Encode into string using wolfCrypt. */
    if ((!err) && (mp_toradix((mp_int*)bn->internal, str, radix) != MP_OKAY)) {
        err = 1;
    }

    if (err) {
        /* Dispose of dynamically allocated data. */
        XFREE(str, NULL, DYNAMIC_TYPE_OPENSSL);
        /* Don't return freed string. */
        str = NULL;
    }
    return str;
}

/* Encode the big number value into hex string that is allocated.
 *
 * @param [in] bn  Big number to encode.
 * @return  String with encoding on success.
 * @return  NULL when bn or internal representation of bn is NULL.
 * @return  NULL on failure.
 */
char* wolfSSL_BN_bn2hex(const WOLFSSL_BIGNUM *bn)
{
    WOLFSSL_ENTER("wolfSSL_BN_bn2hex");
    return wolfssl_bn_bn2radix(bn, MP_RADIX_HEX);
}

/* Decode string of a radix into a big number.
 *
 * If bn is a pointer to NULL, then a new big number is allocated and assigned.
 *
 * Note on use: this function expects str to be an even length. It is
 * converting pairs of bytes into 8-bit values. As an example, the RSA
 * public exponent is commonly 0x010001. To get it to convert, you need
 * to pass in the string "010001", it will fail if you use "10001". This
 * is an affect of how Base16_Decode() works.
 *
 * @param [in, out] bn     Pointer to a big number. May point to NULL.
 * @param [in]      str    Hex string to decode.
 * @param [in]      radix  Radix to decode from.
 * @return  1 on success.
 * @return  0 when bn or str is NULL or str is zero length.
 * @return  0 when creating a new big number fails.
 * @return  0 when decoding fails.
 */
static int wolfssl_bn_radix2bn(WOLFSSL_BIGNUM** bn, const char* str, int radix)
{
    int ret = 1;
    WOLFSSL_BIGNUM* a = NULL;

    /* Validate parameters. */
    if ((bn == NULL) || (str == NULL) || (str[0] == '\0')) {
        WOLFSSL_MSG("Bad function argument");
        ret = 0;
    }
    /* Check if we have a big number to decode into. */
    if ((ret == 1) && (*bn == NULL)) {
        /* Allocate a new big number. */
        a = wolfSSL_BN_new();
        if (a == NULL) {
            WOLFSSL_MSG("BN new failed");
            ret = 0;
        }
        /* Return allocated big number. */
        *bn = a;
    }
    /* Decode hex string into internal representation. */
    if ((ret == 1) && (mp_read_radix((mp_int*)(*bn)->internal, str, radix) !=
            MP_OKAY)) {
        WOLFSSL_MSG("Bad read_radix error");
        ret = 0;
    }

    if ((ret == 0) && (a != NULL)) {
        /* Dispose of big number. */
        wolfSSL_BN_free(a);
        /* Don't return freed big number. */
        *bn = NULL;
    }
    return ret;
}

/* Decode hex string into a big number.
 *
 * If bn is a pointer to NULL, then a new big number is allocated and assigned.
 *
 * Note on use: this function expects str to be an even length. It is
 * converting pairs of bytes into 8-bit values. As an example, the RSA
 * public exponent is commonly 0x010001. To get it to convert, you need
 * to pass in the string "010001", it will fail if you use "10001". This
 * is an affect of how Base16_Decode() works.
 *
 * @param [in, out] bn   Pointer to a big number. May point to NULL.
 * @param [in]      str  Hex string to decode.
 * @return  1 on success.
 * @return  0 when bn or str is NULL or str is zero length.
 * @return  0 when creating a new big number fails.
 * @return  0 when decoding fails.
 */
int wolfSSL_BN_hex2bn(WOLFSSL_BIGNUM** bn, const char* str)
{
    WOLFSSL_ENTER("wolfSSL_BN_hex2bn");
    return wolfssl_bn_radix2bn(bn, str, MP_RADIX_HEX);
}

#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY)
/* Encode big number into decimal string.
 *
 * @param [in] bn  Big number to encode.
 * @return  String with encoding on success.
 * @return  NULL when bn or internal representation of bn is NULL.
 * @return  NULL on failure.
 */
char* wolfSSL_BN_bn2dec(const WOLFSSL_BIGNUM *bn)
{
    WOLFSSL_ENTER("wolfSSL_BN_bn2hex");
    return wolfssl_bn_bn2radix(bn, MP_RADIX_DEC);
}
#else
/* Encode big number into decimal string.
 *
 * @param [in] bn  Big number to encode.
 * @return  NULL as implementation not available.
 */
char* wolfSSL_BN_bn2dec(const WOLFSSL_BIGNUM* bn)
{
    (void)bn;
    WOLFSSL_ENTER("wolfSSL_BN_bn2dec");
    return NULL;
}
#endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) */


#ifndef NO_RSA
/* Decode hex string into a big number.
 *
 * If bn is a pointer to NULL, then a new big number is allocated and assigned.
 *
 * Note on use: this function expects str to be an even length. It is
 * converting pairs of bytes into 8-bit values. As an example, the RSA
 * public exponent is commonly 0x010001. To get it to convert, you need
 * to pass in the string "010001", it will fail if you use "10001". This
 * is an affect of how Base16_Decode() works.
 *
 * @param [in, out] bn   Pointer to a big number. May point to NULL.
 * @param [in]      str  Hex string to decode.
 * @return  1 on success.
 * @return  0 when bn or str is NULL or str is zero length.
 * @return  0 when creating a new big number fails.
 * @return  0 when decoding fails.
 */
int wolfSSL_BN_dec2bn(WOLFSSL_BIGNUM** bn, const char* str)
{
    WOLFSSL_ENTER("wolfSSL_BN_bn2dec");
    return wolfssl_bn_radix2bn(bn, str, MP_RADIX_DEC);
}
#else
/* Decode hex string into a big number.
 *
 * @param [in, out] bn   Pointer to a big number. May point to NULL.
 * @param [in]      str  Hex string to decode.
 * @return  0 as implementation not available..
 */
int wolfSSL_BN_dec2bn(WOLFSSL_BIGNUM** bn, const char* str)
{
    (void)bn;
    (void)str;
    WOLFSSL_ENTER("wolfSSL_BN_bn2dec");
    return 0;
}
#endif

/*******************************************************************************
 * Get/Set APIs
 ******************************************************************************/

/* Calculate the number of bytes need to represent big number.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in] bn  Big number to use.
 * @return  Size of BIGNUM in bytes on success.
 * @return  0 when bn or internal representation of bn is NULL.
 */
int wolfSSL_BN_num_bytes(const WOLFSSL_BIGNUM* bn)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_num_bytes");

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        ret = 0;
    }
    else {
        /* Get size from wolfCrypt. */
        ret = mp_unsigned_bin_size((mp_int*)bn->internal);
    }

    return ret;
}

/* Calculate the number of bits need to represent big number.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in] bn  Big number to use.
 * @return  Size of BIGNUM in bits on success.
 * @return  0 when bn or internal representation of bn is NULL.
 */
int wolfSSL_BN_num_bits(const WOLFSSL_BIGNUM* bn)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_num_bits");

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        ret = 0;
    }
    else {
        /* Get size from wolfCrypt. */
        ret = mp_count_bits((mp_int*)bn->internal);
    }

    return ret;
}

/* Indicates whether a big number is negative.
 *
 * @param [in] bn  Big number to use.
 * @return  1 when number is negative.
 * @return  0 when number is positive.
 * @return  0 when bn is NULL.
 */
int wolfSSL_BN_is_negative(const WOLFSSL_BIGNUM* bn)
{
    int ret;

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        ret = 0;
    }
    else {
        /* Check sign with wolfCrypt. */
        ret = mp_isneg((mp_int*)bn->internal);
    }

    return ret;
}

/* Indicates whether a big number is odd.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in] bn  Big number to use.
 * @return  1 when number is odd.
 * @return  0 when number is even.
 * @return  0 when bn or internal representation of bn is NULL.
 */
int wolfSSL_BN_is_odd(const WOLFSSL_BIGNUM* bn)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_is_odd");

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        ret = 0;
    }
    else {
        /* wolfCrypt checks whether value is odd. */
        ret = (mp_isodd((mp_int*)bn->internal) == MP_YES);
    }

    return ret;
}

#ifndef NO_WOLFSSL_STUB
/* Mask the lowest n bits.
 *
 * TODO: mp_mod_2d()
 *
 * Return compliant with OpenSSL.
 *
 * @param [in, out] bn  Big number to operation on.
 * @param [in]      n   Number of bits.
 * @return  0 on failure.
 */
int wolfSSL_mask_bits(WOLFSSL_BIGNUM* bn, int n)
{
    (void)bn;
    (void)n;
    WOLFSSL_ENTER("wolfSSL_BN_mask_bits");
    WOLFSSL_STUB("BN_mask_bits");
    return 0;
}
#endif

/* Set a bit of the value in a big number.
 *
 * Return code compliant with OpenSSL.
 *
 * @param [in, out] bn  Big number to modify.
 * @return  1 on success.
 * @return  0 when bn or internal representation of bn is NULL.
 * @return  0 when failed to set bit.
 */
int wolfSSL_BN_set_bit(WOLFSSL_BIGNUM* bn, int n)
{
    int ret = 1;

    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }
    else if (mp_set_bit((mp_int*)bn->internal, n) != MP_OKAY) {
        WOLFSSL_MSG("mp_set_bit error");
        ret = 0;
    }

    return ret;
}

/* Clear a bit of the value in a big number.
 *
 * Return code compliant with OpenSSL.
 *
 * @param [in] bn  Big number to check.
 * @param [in] n   Inidex of bit to check.
 * @return  1 on success.
 * @return  0 when bn or internal representation of bn is NULL.
 * @return  0 when failed to clear bit.
 */
int wolfSSL_BN_clear_bit(WOLFSSL_BIGNUM* bn, int n)
{
    int ret = 1;
    WC_DECLARE_VAR(tmp, mp_int, 1, 0);

    /* Validate parameters. */
    if (BN_IS_NULL(bn) || (n < 0)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }
    /* Check if bit is set to clear. */
    if ((ret == 1) && (mp_is_bit_set((mp_int*)bn->internal, n))) {
        /* Allocate a new MP integer to hold bit to clear. */
        WC_ALLOC_VAR_EX(tmp, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, ret=0);
        if (ret == 1) {
            /* Reset new MP integer. */
            XMEMSET(tmp, 0, sizeof(mp_int));
            if (mp_init(tmp) != MP_OKAY) {
                ret = 0;
            }
        }
        /* Set the bit to clear into temporary MP integer. */
        if ((ret == 1) && (mp_set_bit(tmp, n) != MP_OKAY)) {
            ret = 0;
        }
        /* Clear bit by sutraction. */
        if ((ret == 1) && (mp_sub((mp_int*)bn->internal, tmp,
                (mp_int*)bn->internal) != MP_OKAY)) {
            ret = 0;
        }

        /* Free any dynamic memory in MP integer. */
        mp_clear(tmp);
        WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_BIGINT);
    }

    return ret;
}

/* Returns whether the bit is set in the value of the big number.
 *
 * When bn is NULL, returns 0.
 *
 * Return code compliant with OpenSSL.
 *
 * @param [in] bn  Big number to check.
 * @param [in] n   Inidex of bit to check.
 * @return  1 if bit set.
 * @return  0 otherwise.
 */
int wolfSSL_BN_is_bit_set(const WOLFSSL_BIGNUM* bn, int n)
{
    int ret;

    /* Check for big number value. */
    if (BN_IS_NULL(bn) || (n < 0)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }
    else {
        /* Set bit with wolfCrypt. */
        ret = mp_is_bit_set((mp_int*)bn->internal, (mp_digit)n);
    }

    return ret;
}

/* Set the big number to the value 0.
 *
 * @param [in, out] bn  Big number to use.
 */
void wolfSSL_BN_zero(WOLFSSL_BIGNUM* bn)
{
    /* Validate parameter. */
    if (!BN_IS_NULL(bn)) {
        /* Set wolfCrypt representation to 0. */
        mp_zero((mp_int*)bn->internal);
    }
}

/* Set the big number to the value 0.
 *
 * @param [in, out] bn  Big number to use.
 * @return  1 on success.
 * @return  0 when bn or internal representation of bn is NULL.
 */
int wolfSSL_BN_one(WOLFSSL_BIGNUM* bn)
{
    int ret;

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        ret = 0;
    }
    else {
        /* Set to value one. */
        ret = wolfSSL_BN_set_word(bn, 1);
    }

    return ret;
}

/* Get the value of the MP integer as a word.
 *
 * Assumes the MP integer value will fit in a word.
 *
 * @param [in] mp  MP integer.
 * @return  Value of MP integer as an unsigned long.
 */
static WOLFSSL_BN_ULONG wolfssl_bn_get_word_1(mp_int *mp) {
#if DIGIT_BIT >= (SIZEOF_LONG * CHAR_BIT)
    return (WOLFSSL_BN_ULONG)mp->dp[0];
#else
    WOLFSSL_BN_ULONG ret = 0UL;
    unsigned int i;

    for (i = 0; i < (unsigned int)mp->used; ++i) {
        ret |= ((WOLFSSL_BN_ULONG)mp->dp[i]) << (DIGIT_BIT * i);
    }

    return ret;
#endif
}

/* Return the value of big number as an unsigned long if possible.
 *
 * @param [in] bn  Big number to get value from.
 * @return  Value or 0xFFFFFFFFL if bigger than unsigned long.
 */
WOLFSSL_BN_ULONG wolfSSL_BN_get_word(const WOLFSSL_BIGNUM* bn)
{
    WOLFSSL_BN_ULONG ret;

    WOLFSSL_ENTER("wolfSSL_BN_get_word");

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("Invalid argument");
        ret = 0;
    }
    /* Check whether big number is to fit in an unsigned long. */
    else if (wolfSSL_BN_num_bytes(bn) > (int)sizeof(unsigned long)) {
        WOLFSSL_MSG("bignum is larger than unsigned long");
        ret = WOLFSSL_BN_MAX_VAL;
    }
    else {
        /* Get the word from the internal representation. */
        ret = wolfssl_bn_get_word_1((mp_int*)bn->internal);
    }

    return ret;
}

/* Set the big number to the value in the word.
 *
 * Return code compliant with OpenSSL.
 *
 * @param [in, out] bn  Big number to set.
 * @param [in       w   Word to set.
 * @return  1 on success.
 * @return  0 when bn is NULL or setting value failed.
 */
int wolfSSL_BN_set_word(WOLFSSL_BIGNUM* bn, unsigned long w)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_BN_set_word");

    /* Validate parameters. */
    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }

    /* Set the word into the internal representation. */
    if ((ret == 1) && (mp_set_int((mp_int*)bn->internal, w) != MP_OKAY)) {
        WOLFSSL_MSG("mp_init_set_int error");
        ret = 0;
    }

    return ret;
}

/*******************************************************************************
 * Comparison APIs
 ******************************************************************************/

/* Compares two big numbers. a <=> b
 *
 * NULL equals NULL
 * NULL less than not NULL
 * not NULL greater than NULL.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in] bn  First big number to compare.
 * @param [in] bn  Second big number to compare.
 * @return  -1 when a is less than b (a < b).
 * @return  0 when a is equal to b (a == b).
 * @return  1 when a is greater than b (a > b).
 * @return  0 when bn or internal representation of bn is NULL.
 */
int wolfSSL_BN_cmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b)
{
    int ret;
    int bIsNull;

    WOLFSSL_ENTER("wolfSSL_BN_cmp");

    /* Must know whether b is NULL. */
    bIsNull = BN_IS_NULL(b);
    /* Check whether a is NULL. */
    if (BN_IS_NULL(a)) {
        if (bIsNull) {
            /* NULL equals NULL. */
            ret = 0;
        }
        else {
            ret = -1; /* NULL less than not NULL. */
        }
    }
    else if (bIsNull) {
        /* not NULL greater than NULL. */
        ret = 1;
    }
    else {
        PRAGMA_GCC_DIAG_PUSH
        PRAGMA_GCC("GCC diagnostic ignored \"-Wduplicated-branches\"")
        /* Compare big numbers with wolfCrypt. */
        ret = mp_cmp((mp_int*)a->internal, (mp_int*)b->internal);
        /* Convert wolfCrypt return value. */
        if (ret == MP_EQ) {
            ret = 0;
        }
        else if (ret == MP_GT) {
            ret = 1;
        }
        else if (ret == MP_LT) {
            ret = -1;
        }
        else {
            /* ignored warning here because the same return value
               was intentional */
            ret = WOLFSSL_FATAL_ERROR; /* also -1 */
        }
        PRAGMA_GCC_DIAG_POP
    }

    return ret;
}

/* Same as above, but compare absolute value. */
int wolfSSL_BN_ucmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b)
{
    int ret = 0;
    int bIsNull;

    WOLFSSL_ENTER("wolfSSL_BN_ucmp");

    /* Must know whether b is NULL. */
    bIsNull = BN_IS_NULL(b);
    /* Check whether a is NULL. */
    if (BN_IS_NULL(a)) {
        if (bIsNull) {
            /* NULL equals NULL. */
            ret = 0;
        }
        else {
            ret = -1; /* NULL less than not NULL. */
        }
    }
    else if (bIsNull) {
        /* not NULL greater than NULL. */
        ret = 1;
    }
    else {
        /* Neither are NULL; copy to new instances and switch to positive if
         * required, compare, and then free.  Must copy because there is
         * possibility of switch to positive but they are declared const.
         * wolfssl_bn_set_neg() only returns -1 if the bn is NULL, but we
         * already check that so we can ignore the return code. Note for
         * wolfSSL_BN_is_negative if n=1 then set to positive. */
        WOLFSSL_BIGNUM* abs_a = wolfSSL_BN_dup(a);
        WOLFSSL_BIGNUM* abs_b = wolfSSL_BN_dup(b);

        if (abs_a == NULL || abs_b == NULL) {
            WOLFSSL_MSG("wolfSSL_BN_dup failed");
            wolfSSL_BN_free(abs_a);
            wolfSSL_BN_free(abs_b);
            return WOLFSSL_FATAL_ERROR;
        }

        if (wolfSSL_BN_is_negative(abs_a)) {
            wolfssl_bn_set_neg(abs_a, 1);
        }

        if (wolfSSL_BN_is_negative(abs_b)) {
            wolfssl_bn_set_neg(abs_b, 1);
        }

        ret = wolfSSL_BN_cmp(abs_a, abs_b);
        wolfSSL_BN_free(abs_a);
        wolfSSL_BN_free(abs_b);
    }
    return ret;
}

/* Indicates whether a big number is the value 0.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in] bn  Big number to use.
 * @return  1 when number is zero.
 * @return  0 when number is not zero.
 * @return  0 when bn or internal representation of bn is NULL.
 */
int wolfSSL_BN_is_zero(const WOLFSSL_BIGNUM* bn)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_is_zero");

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        ret = 0;
    }
    else {
        /* wolfCrypt checks whether value is 0. */
        ret = (mp_iszero((mp_int*)bn->internal) == MP_YES);
    }

    return ret;
}

/* Indicates whether a big number is the value 1.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in] bn  Big number to use.
 * @return  1 when number is one.
 * @return  0 when number is not one.
 * @return  0 when bn or internal representation of bn is NULL.
 */
int wolfSSL_BN_is_one(const WOLFSSL_BIGNUM* bn)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_is_one");

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        ret = 0;
    }
    else {
        /* wolfCrypt checks whether value is 1. */
        ret = (mp_cmp_d((mp_int*)bn->internal, 1) == MP_EQ);
    }

    return ret;
}

/* Indicates whether a big number is the value passed in.
 *
 * Return compliant with OpenSSL.
 *
 * @param [in] bn  Big number to use.
 * @return  1 when big number is the value.
 * @return  0 when big number is not the value.
 * @return  0 when bn or internal representation of bn is NULL.
 */
int wolfSSL_BN_is_word(const WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_is_word");

    /* Validate parameter. */
    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }
    else
#if DIGIT_BIT < (SIZEOF_LONG * CHAR_BIT)
    /* When value is greater than what can be stored in one digit - special
     * case. */
    if (w > (WOLFSSL_BN_ULONG)MP_MASK) {
        /* TODO: small stack */
        mp_int w_mp;

        /* Create a MP to hold the number. */
        if (mp_init(&w_mp) != MP_OKAY) {
            ret = 0;
        }
        /* Set the value - held in more than one digit. */
        else if (mp_set_int(&w_mp, w) != MP_OKAY) {
            ret = 0;
        }
        else {
            /* Compare MP representations. */
            ret = (mp_cmp((mp_int *)bn->internal, &w_mp) == MP_EQ);
            mp_free(&w_mp);
        }
    }
    else
#endif
    {
        /* wolfCrypt checks whether it is the value. */
        ret = (mp_isword((mp_int*)bn->internal, (mp_digit)w) == MP_YES);
    }

    return ret;
}


/*******************************************************************************
 * Word operation APIs.
 ******************************************************************************/

enum BN_WORD_OP {
    BN_WORD_ADD = 0,
    BN_WORD_SUB = 1,
    BN_WORD_MUL = 2,
    BN_WORD_DIV = 3,
    BN_WORD_MOD = 4
};

/* Helper function for word operations.
 *
 * @param [in, out] bn  Big number to operate on.
 * @param [in]      w   Word to operate with.
 * @param [in]      op  Operation to perform. See BN_WORD_OP for valid values.
 * @param [out]     mod_res Result of the modulo operation.
 * @return  1 on success.
 * @return  0 on failure.
 */
static int bn_word_helper(const WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w,
        enum BN_WORD_OP op, WOLFSSL_BN_ULONG* mod_res)
{
    int ret = 1;

    WOLFSSL_ENTER("bn_word_helper");

    /* Validate parameters. */
    if (ret == 1 && BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }

    if (ret == 1) {
        int rc = MP_OKAY;
#if DIGIT_BIT < (SIZEOF_LONG * CHAR_BIT)
        /* When input 'w' is greater than what can be stored in one digit */
        if (w > (WOLFSSL_BN_ULONG)MP_MASK) {
            DECL_MP_INT_SIZE_DYN(w_mp, sizeof(WOLFSSL_BN_ULONG) * CHAR_BIT,
                                       sizeof(WOLFSSL_BN_ULONG) * CHAR_BIT);
            NEW_MP_INT_SIZE(w_mp, sizeof(WOLFSSL_BN_ULONG) * CHAR_BIT, NULL,
                    DYNAMIC_TYPE_TMP_BUFFER);
#ifdef MP_INT_SIZE_CHECK_NULL
            if (w_mp == NULL) {
                WOLFSSL_MSG("NEW_MP_INT_SIZE error");
                ret = 0;
            }
#endif
            if (ret == 1 && mp_set_int(w_mp, w) != MP_OKAY) {
                WOLFSSL_MSG("mp_set_int error");
                ret = 0;
            }
            if (ret == 1) {
                switch (op) {
                    case BN_WORD_ADD:
                        rc = mp_add((mp_int*)bn->internal, w_mp,
                                (mp_int*)bn->internal);
                        break;
                    case BN_WORD_SUB:
                        rc = mp_sub((mp_int*)bn->internal, w_mp,
                                (mp_int*)bn->internal);
                        break;
                    case BN_WORD_MUL:
                        rc = mp_mul((mp_int*)bn->internal, w_mp,
                                (mp_int*)bn->internal);
                        break;
                    case BN_WORD_DIV:
                        rc = mp_div((mp_int*)bn->internal, w_mp,
                                (mp_int*)bn->internal, NULL);
                        break;
                    case BN_WORD_MOD:
                        rc = mp_mod((mp_int*) bn->internal, w_mp,
                                w_mp);
                        if (rc == MP_OKAY && mod_res != NULL)
                            *mod_res = wolfssl_bn_get_word_1(w_mp);
                        break;
                    default:
                        rc = WOLFSSL_NOT_IMPLEMENTED;
                        break;
                }
            }
            FREE_MP_INT_SIZE(w_mp, NULL, DYNAMIC_TYPE_RSA);
        }
        else
#endif
        {
            switch (op) {
                case BN_WORD_ADD:
                    rc = mp_add_d((mp_int*)bn->internal, (mp_digit)w,
                            (mp_int*)bn->internal);
                    break;
                case BN_WORD_SUB:
                    rc = mp_sub_d((mp_int*)bn->internal, (mp_digit)w,
                            (mp_int*)bn->internal);
                    break;
                case BN_WORD_MUL:
                    rc = mp_mul_d((mp_int*)bn->internal, (mp_digit)w,
                            (mp_int*)bn->internal);
                    break;
                case BN_WORD_DIV:
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
/* copied from sp_int.h */
#if (defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_VERIFY_ONLY)) || \
    defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || \
    defined(WC_MP_TO_RADIX)
                    rc = mp_div_d((mp_int*)bn->internal, (mp_digit)w,
                            (mp_int*)bn->internal, NULL);
#else
                    rc = WOLFSSL_NOT_IMPLEMENTED;
#endif
#else
                    rc = WOLFSSL_NOT_IMPLEMENTED;
#endif
                    break;
                case BN_WORD_MOD:
                    {
                        mp_digit _mod_res;
                        rc = mp_mod_d((mp_int*) bn->internal, (mp_digit) w,
                                &_mod_res);
                        if (rc == MP_OKAY && mod_res != NULL)
                            *mod_res = (WOLFSSL_BN_ULONG)_mod_res;
                    }
                    break;
                default:
                    rc = WOLFSSL_NOT_IMPLEMENTED;
                    break;
            }
        }
        if (ret == 1 && rc != MP_OKAY) {
            WOLFSSL_MSG("mp word operation error or not implemented");
            ret = 0;
        }
    }

    WOLFSSL_LEAVE("bn_word_helper", ret);

    return ret;
}

/* Add a word to a big number.
 *
 * Return code compliant with OpenSSL.
 *
 * @param [in, out] bn   Big number to operate on.
 * @param [in]      w    Word to operate with.
 * @return  1 on success.
 * @return  0 in failure.
 */
int wolfSSL_BN_add_word(WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_add_word");

    ret = bn_word_helper(bn, w, BN_WORD_ADD, NULL);

    WOLFSSL_LEAVE("wolfSSL_BN_add_word", ret);

    return ret;
}

/* Subtract a word from a big number.
 *
 * Return code compliant with OpenSSL.
 *
 * @param [in, out] bn   Big number to operate on.
 * @param [in]      w    Word to operate with.
 * @return  1 on success.
 * @return  0 in failure.
 */
int wolfSSL_BN_sub_word(WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_sub_word");

    ret = bn_word_helper(bn, w, BN_WORD_SUB, NULL);

    WOLFSSL_LEAVE("wolfSSL_BN_sub_word", ret);

    return ret;
}

int wolfSSL_BN_mul_word(WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_mul_word");

    ret = bn_word_helper(bn, w, BN_WORD_MUL, NULL);

    WOLFSSL_LEAVE("wolfSSL_BN_mul_word", ret);

    return ret;
}


int wolfSSL_BN_div_word(WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w)
{
    int ret;

    WOLFSSL_ENTER("wolfSSL_BN_div_word");

    ret = bn_word_helper(bn, w, BN_WORD_DIV, NULL);

    WOLFSSL_LEAVE("wolfSSL_BN_div_word", ret);

    return ret;
}

#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_RSA) || !defined(NO_DH) || \
    !defined(NO_DSA))
/* Calculate bn modulo word w. bn % w
 *
 * Return code compliant with OpenSSL.
 *
 * @return  Word result on success
 * @return  -1 on error
 */
WOLFSSL_BN_ULONG wolfSSL_BN_mod_word(const WOLFSSL_BIGNUM *bn,
    WOLFSSL_BN_ULONG w)
{
    int ret;
    WOLFSSL_BN_ULONG res = 0;

    WOLFSSL_ENTER("wolfSSL_BN_mod_word");

    ret = bn_word_helper(bn, w, BN_WORD_MOD, &res);

    WOLFSSL_LEAVE("wolfSSL_BN_mod_word", ret);

    return ret == 1 ? res : (WOLFSSL_BN_ULONG)-1;
}
#endif /* WOLFSSL_KEY_GEN && (!NO_RSA || !NO_DH || !NO_DSA) */

/*******************************************************************************
 * Shift APIs
 ******************************************************************************/

#ifndef WOLFSSL_SP_MATH
/* Shift the value in bn left by n bits into r. r = bn << n
 *
 * Return code compliant with OpenSSL.
 *
 * @return  1 on success.
 * @return  0 when r or bn or internal representation is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_lshift(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *bn, int n)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_BN_lshift");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }
    else if (n < 0) {
        WOLFSSL_MSG("n value error");
        ret = 0;
    }

    /* Use wolfCrypt perform operation. */
    if ((ret == 1) && (mp_mul_2d((mp_int*)bn->internal, n,
            (mp_int*)r->internal) != MP_OKAY)) {
        WOLFSSL_MSG("mp_mul_2d error");
        ret = 0;
    }

    return ret;
}

/* Shift the value in bn right by n bits into r. r = bn >> n
 *
 * Return code compliant with OpenSSL.
 *
 * @return  1 on success.
 * @return  0 when r or bn or internal representation is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_rshift(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *bn, int n)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_BN_rshift");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }
    else if (n < 0) {
        WOLFSSL_MSG("n value error");
        ret = 0;
    }

    /* Use wolfCrypt perform operation. */
    if ((ret == 1) && (mp_div_2d((mp_int*)bn->internal, n, (mp_int*)r->internal,
            NULL) != MP_OKAY)) {
        WOLFSSL_MSG("mp_mul_2d error");
        ret = 0;
    }

    return ret;
}
#endif

/*******************************************************************************
 * Simple Math APIs
 ******************************************************************************/

/* Add a to b into r. r = a + b
 *
 * Return code compliant with OpenSSL.
 *
 * @param [out] r  Big number to put result into.
 * @param [in]  a  Big number to be added to.
 * @param [in]  b  Big number to add with.
 *
 * @return  1 on success.
 * @return  0 when r, a or b or internal representation is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_add(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a, WOLFSSL_BIGNUM *b)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_BN_add");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }

    /* Add the internal representations into internal representation. */
    if ((ret == 1) && (mp_add((mp_int*)a->internal, (mp_int*)b->internal,
            (mp_int*)r->internal) != MP_OKAY)) {
        WOLFSSL_MSG("mp_add_d error");
        ret = 0;
    }

    return ret;
}

/* Subtract a from b into r. r = a - b
 *
 * @param [out] r  Big number to put result into.
 * @param [in]  a  Big number to be subtracted from.
 * @param [in]  b  Big number to subtract with.
 *
 * @return  1 on success.
 * @return  0 when r, a or b is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_sub(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a,
    const WOLFSSL_BIGNUM* b)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_BN_sub");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
        ret = 0;
    }

    /* Have wolfCrypt perform operation with internal representations. */
    if ((ret == 1) && (mp_sub((mp_int*)a->internal,(mp_int*)b->internal,
            (mp_int*)r->internal) != MP_OKAY)) {
        ret = 0;
    }

    WOLFSSL_LEAVE("wolfSSL_BN_sub mp_sub", ret);
    return ret;
}

/* Multiply a with b into r. r = a * b
 *
 * @param [out] r    Big number to put result into.
 * @param [in]  a    Big number to be multiplied.
 * @param [in]  b    Big number to multiply with.
 * @param [in]  ctx  BN context object. Unused.
 *
 * @return  1 on success.
 * @return  0 when r, a or b is NULL.
 * @return  0 when internal representation of r, a or b is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_mul(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a, WOLFSSL_BIGNUM *b,
    WOLFSSL_BN_CTX *ctx)
{
    int ret = 1;

    (void)ctx;

    WOLFSSL_ENTER("wolfSSL_BN_mul");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
        ret = 0;
    }

    /* Have wolfCrypt perform operation with internal representations. */
    if ((ret == 1) && (mp_mul((mp_int*)a->internal, (mp_int*)b->internal,
            (mp_int*)r->internal) != MP_OKAY)) {
        ret = 0;
    }

    WOLFSSL_LEAVE("wolfSSL_BN_mul", ret);
    return ret;
}

#ifndef WOLFSSL_SP_MATH
/* Divide a by b into dv and put remainder into rem. dv = a / b, rem = a % b
 *
 * @param [out] dv   Big number to put division result into.
 * @param [out] rem  Big number to put remainder into.
 * @param [in]  a    Big number to be divided.
 * @param [in]  b    Big number to divide with.
 * @param [in]  ctx  BN context object. Unused.
 *
 * @return  1 on success.
 * @return  0 when dv, rem, a or b is NULL.
 * @return  0 when internal representation of dv, rem, a or b is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_div(WOLFSSL_BIGNUM* dv, WOLFSSL_BIGNUM* rem,
    const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* d, WOLFSSL_BN_CTX* ctx)
{
    int ret = 1;
    WOLFSSL_BIGNUM* res = dv;

    /* BN context not needed. */
    (void)ctx;

    WOLFSSL_ENTER("wolfSSL_BN_div");

    if (BN_IS_NULL(res)) {
        res = wolfSSL_BN_new();
    }

    /* Validate parameters. */
    if (BN_IS_NULL(res) || BN_IS_NULL(rem) || BN_IS_NULL(a) || BN_IS_NULL(d)) {
        ret = 0;
    }

    /* Have wolfCrypt perform operation with internal representations. */
    if ((ret == 1) && (mp_div((mp_int*)a->internal, (mp_int*)d->internal,
            (mp_int*)res->internal, (mp_int*)rem->internal) != MP_OKAY)) {
        ret = 0;
    }

    if (res != dv)
        wolfSSL_BN_free(res);

    WOLFSSL_LEAVE("wolfSSL_BN_div", ret);
    return ret;
}
#endif

/* Calculate a mod b into r. r = a % b
 *
 * @param [out] r    Big number to put result into.
 * @param [in]  a    Big number to reduced
 * @param [in]  b    Big number to reduce with.
 * @param [in]  ctx  BN context object. Unused.
 *
 * @return  1 on success.
 * @return  0 when r, a or b is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_mod(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a,
                  const WOLFSSL_BIGNUM* b, const WOLFSSL_BN_CTX* c)
{
    int ret = 1;

    (void)c;

    WOLFSSL_ENTER("wolfSSL_BN_mod");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
        ret = 0;
    }

    /* Have wolfCrypt perform operation with internal representations. */
    if ((ret == 1) && (mp_mod((mp_int*)a->internal,(mp_int*)b->internal,
            (mp_int*)r->internal) != MP_OKAY)) {
        ret = 0;
    }

    WOLFSSL_LEAVE("wolfSSL_BN_mod mp_mod", ret);
    return ret;
}

/*******************************************************************************
 * Math and Mod APIs
 ******************************************************************************/

#ifndef WOLFSSL_SP_MATH
/* Add a to b modulo m into r. r = a + b (mod m)
 *
 * @param [in, out] r    Big number to hold result.
 * @param [in]      a    Big number to add to.
 * @param [in]      b    Big number to add with.
 * @param [in]      m    Big number that is the modulus.
 * @param [in]      ctx  BN context. Not used.
 * @return  1 on success.
 * @return  0 when r, a or b or internal representation is NULL.
 * @return  0 on calculation failure.
 */
int wolfSSL_BN_mod_add(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
    const WOLFSSL_BIGNUM *b, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx)
{
    int ret = 1;

    /* BN context not needed. */
    (void)ctx;

    WOLFSSL_ENTER("wolfSSL_BN_add");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b) || BN_IS_NULL(m)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }

    /* Perform operation with wolfCrypt. */
    if ((ret == 1) && (mp_addmod((mp_int*)a->internal, (mp_int*)b->internal,
            (mp_int*)m->internal, (mp_int*)r->internal) != MP_OKAY)) {
        WOLFSSL_MSG("mp_add_d error");
        ret = 0;
    }

    return ret;
}
#endif

/* Calculate a multiplied by b, mod m into r. r = (a * b) % m
 *
 * @param [out] r    Big number to put result into.
 * @param [in]  a    Base as a big number.
 * @param [in]  b    Multiplier as a big number.
 * @param [in]  m    Modulus as a big number.
 * @param [in]  ctx  BN context object. Unused.
 *
 * @return  1 on success.
 * @return  0 when r, a, b or m is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_mod_mul(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
    const WOLFSSL_BIGNUM *b, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx)
{
    int ret = 1;

    /* BN context not needed. */
    (void)ctx;

    WOLFSSL_ENTER("wolfSSL_BN_mod_mul");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b) || BN_IS_NULL(m)) {
        WOLFSSL_MSG("Bad Argument");
        ret = 0;
    }

    /* Have wolfCrypt perform operation with internal representations. */
    if ((ret == 1) && (mp_mulmod((mp_int*)a->internal, (mp_int*)b->internal,
            (mp_int*)m->internal, (mp_int*)r->internal)) != MP_OKAY) {
        ret = 0;
    }

    WOLFSSL_LEAVE("wolfSSL_BN_mod_mul", ret);
    return ret;
}


/* Calculate a to the power of e, mod m into r. r = (a ^ e) % m
 *
 * @param [out] r    Big number to put result into.
 * @param [in]  a    Base as a big number.
 * @param [in]  e    Exponent as a big number.
 * @param [in]  m    Modulus as a big number.
 * @param [in]  ctx  BN context object. Unused.
 *
 * @return  1 on success.
 * @return  0 when r, a, p or m is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_mod_exp(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
    const WOLFSSL_BIGNUM *e, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx)
{
    int ret = 1;

    /* BN context not needed. */
    (void)ctx;

    WOLFSSL_ENTER("wolfSSL_BN_mod_exp");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(e) || BN_IS_NULL(m)) {
        WOLFSSL_MSG("Bad Argument");
        ret = 0;
    }

    /* Have wolfCrypt perform operation with internal representations. */
    if ((ret == 1) && (mp_exptmod((mp_int*)a->internal, (mp_int*)e->internal,
            (mp_int*)m->internal, (mp_int*)r->internal)) != MP_OKAY) {
        ret = 0;
    }

    WOLFSSL_LEAVE("wolfSSL_BN_mod_exp", ret);
    return ret;
}

/* Calculate the modular inverse of a mod m into r. r = a^-1 mod m
 *
 * A new big number is allocated when r is NULL.
 *
 * @param [in, out] r    Big number to hold result. May be NULL.
 * @param [in]      a    Big number to invert.
 * @param [in]      m    Big number that is the modulus.
 * @param [in]      ctx  BN context. Not used.
 * @return  Big number holding result on success.
 * @return  NULL on failure.
 */
WOLFSSL_BIGNUM *wolfSSL_BN_mod_inverse(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a,
    const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx)
{
    int err = 0;
    WOLFSSL_BIGNUM* t = NULL;

    /* BN context not needed. */
    (void)ctx;

    WOLFSSL_ENTER("wolfSSL_BN_mod_inverse");

    /* Validate parameters. */
    if (BN_IS_NULL(a) || BN_IS_NULL(m) || ((r != NULL) &&
            (r->internal == NULL))) {
        WOLFSSL_MSG("a or n NULL error");
        err = 1;
    }
    /* Check whether we have a result big number. */
    if ((!err) && (r == NULL)) {
        /* Allocate a new big number to hold result and be returned. */
        t = wolfSSL_BN_new();
        if (t == NULL){
            WOLFSSL_MSG("WolfSSL_BN_new() failed");
            err = 1;
        }
        r = t;
    }

    /* Compute inverse of a modulo n and return in r */
    if ((!err) && (mp_invmod((mp_int *)a->internal, (mp_int *)m->internal,
            (mp_int*)r->internal) != MP_OKAY)) {
        WOLFSSL_MSG("mp_invmod() error");
        err = 1;
    }

    if (err) {
        wolfSSL_BN_free(t);
        r = NULL;
    }
    return r;
}

/*******************************************************************************
 * Other Math APIs
 ******************************************************************************/

#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
/* Needed to get mp_gcd. */
/* Greatest Common Divisor (GCM) of a and b into r. r = GCD(a, b)
 *
 * @param [out] r    Big number to put result into.
 * @param [in]  a    First big number.
 * @param [in]  b    Second big number.
 * @param [in]  ctx  BN context object. Unused.
 *
 * @return  1 on success.
 * @return  0 when r, a or b is NULL.
 * @return  0 when internal representation of r, a or b is NULL.
 * @return  0 on failure.
 */
int wolfSSL_BN_gcd(WOLFSSL_BIGNUM* r, WOLFSSL_BIGNUM* a, WOLFSSL_BIGNUM* b,
    WOLFSSL_BN_CTX* ctx)
{
    int ret = 1;

    /* BN context not needed. */
    (void)ctx;

    WOLFSSL_ENTER("wolfSSL_BN_gcd");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
        ret = 0;
    }

    /* Have wolfCrypt perform operation with internal representations. */
    if ((ret == 1) && (mp_gcd((mp_int*)a->internal, (mp_int*)b->internal,
            (mp_int*)r->internal) != MP_OKAY)) {
        ret = 0;
    }

    WOLFSSL_LEAVE("wolfSSL_BN_gcd", ret);
    return ret;
}
#endif /* !NO_RSA && WOLFSSL_KEY_GEN */

/*******************************************************************************
 * Random APIs
 ******************************************************************************/

/* Generates a random number up to bits long.
 *
 * @param [in, out] bn       Big number to generate into.
 * @param [in]      bits     Number of bits in word.
 * @param [in]      top      Whether top bits must be set.
 *                           Valid values: WOLFSSL_BN_RAND_TOP_ANY,
 *                           WOLFSSL_BN_RAND_TOP_ONE, WOLFSSL_BN_RAND_TOP_TWO.
 * @param [in]      bottom   Whether bottom bit must be set.
 *                           Valid values: WOLFSSL_BN_RAND_BOTTOM_ANY,
                             WOLFSSL_BN_RAND_BOTTOM_ODD.
 * @return  1 on success.
 * @return  0 when bn is NULL.
 * @return  0 when bits is invalid.
 * @return  0 when bits and top/bottom are invalid.
 * @return  0 when generation fails.
 */
int wolfSSL_BN_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom)
{
    int ret = 1;
    word32 len = (word32)((bits + 7) / 8);
    WC_RNG* rng;

    WOLFSSL_ENTER("wolfSSL_BN_rand");

    /* Validate parameters. */
    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("Bad argument - bn");
        ret = 0;
    }
    else if (bits < 0) {
        WOLFSSL_MSG("Bad argument - bits < 0");
        ret = 0;
    }
    else if ((bits == 0) && ((bottom != WOLFSSL_BN_RAND_BOTTOM_ANY) ||
            (top != WOLFSSL_BN_RAND_TOP_ANY))) {
        WOLFSSL_MSG("Bad top/bottom - bits == 0");
        ret = 0;
    }
    else if ((bits == 1) && (top > WOLFSSL_BN_RAND_TOP_ONE)) {
        WOLFSSL_MSG("Bad top - bits == 1");
        ret = 0;
    }

    /* Handle simple case of zero bits. */
    if ((ret == 1) && (bits == 0)) {
        mp_zero((mp_int*)bn->internal);
    }
    else if (ret == 1) {
        byte* buff = NULL;

        /* Get random to global random to generate bits. */
        if ((rng = wolfssl_make_global_rng()) == NULL) {
            WOLFSSL_MSG("Failed to use global RNG.");
            ret = 0;
        }

        /* Allocate buffer to hold generated bits. */
        if ((ret == 1) && ((buff = (byte*)XMALLOC(len, NULL,
                DYNAMIC_TYPE_TMP_BUFFER)) == NULL)) {
            WOLFSSL_MSG("Failed to allocate buffer.");
            ret = 0;
        }
        /* Generate bytes to cover bits. */
        if ((ret == 1) && wc_RNG_GenerateBlock(rng, buff, len) != 0) {
            WOLFSSL_MSG("wc_RNG_GenerateBlock failed");
            ret = 0;
        }
        /* Read bytes in to big number. */
        if ((ret == 1) && mp_read_unsigned_bin((mp_int*)bn->internal, buff, len)
                != MP_OKAY) {
            WOLFSSL_MSG("mp_read_unsigned_bin failed");
            ret = 0;
        }
        /* Dispose of buffer - no longer needed. */
        XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);

        if (ret == 1) {
            /* Truncate to requested bit length. */
            mp_rshb((mp_int*)bn->internal, 8 - (bits % 8));
        }

        /* Set top bit when required. */
        if ((ret == 1) && (top >= WOLFSSL_BN_RAND_TOP_ONE) &&
                (mp_set_bit((mp_int*)bn->internal, bits - 1) != MP_OKAY)) {
            WOLFSSL_MSG("Failed to set top bit");
            ret = 0;
        }
        /* Set second top bit when required. */
        if ((ret == 1) && (top > WOLFSSL_BN_RAND_TOP_ONE) &&
                (mp_set_bit((mp_int*)bn->internal, bits - 2) != MP_OKAY)) {
            WOLFSSL_MSG("Failed to set second top bit");
            ret = 0;
        }
        /* Set bottom bit when required. */
        if ((ret == 1) && (bottom == WOLFSSL_BN_RAND_BOTTOM_ODD) &&
                (mp_set_bit((mp_int*)bn->internal, 0) != MP_OKAY)) {
            WOLFSSL_MSG("Failed to set 0th bit");
            ret = 0;
        }
    }

    WOLFSSL_LEAVE("wolfSSL_BN_rand", ret);

    return ret;
}

/* Generates a pseudo-random number up to bits long.
 *
 * Implemented using wolfSSL_BN_rand().
 *
 * @param [in, out] bn       Big number to generate into.
 * @param [in]      bits     Number of bits in word.
 * @param [in]      top      Whether top bits must be set.
 *                           Valid values: WOLFSSL_BN_RAND_TOP_ANY,
 *                           WOLFSSL_BN_RAND_TOP_ONE, WOLFSSL_BN_RAND_TOP_TWO.
 * @param [in]      bottom   Whether bottom bit must be set.
 *                           Valid values: WOLFSSL_BN_RAND_BOTTOM_ANY,
                             WOLFSSL_BN_RAND_BOTTOM_ODD.
 * @return  1 on success.
 * @return  0 when bn is NULL.
 * @return  0 when bits is invalid.
 * @return  0 when bits and top/bottom are invalid.
 * @return  0 when generation fails.
 */
int wolfSSL_BN_pseudo_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom)
{
    return wolfSSL_BN_rand(bn, bits, top, bottom);
}

/* Maximum number of trials to attempt at generating a number in range. */
#define RANGE_MAX_TRIALS    100

/* Generate big number to be a value between 0 and range-1.
 *
 * N = length of range input var
 *
 * Generate N-bit length numbers until generated number is less than range
 * @param [in] r      Big number to generate into.
 * @param [in] range  The upper limit of generated number.
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_BN_rand_range(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *range)
{
    int ret = 1;

    WOLFSSL_ENTER("wolfSSL_BN_rand_range");

    /* Validate parameters. */
    if (BN_IS_NULL(r) || BN_IS_NULL(range)) {
        WOLFSSL_MSG("Bad parameter");
        ret = 0;
    }

    if (ret == 1) {
        /* Calculate number of bits in modulus. */
        int n = wolfSSL_BN_num_bits(range);

        if (n <= 1) {
            /* Modulus is 0 or 1. */
            wolfSSL_BN_zero(r);
        }
        else {
            int i;
            /* Try generating a number in range for a limited number of trials.
             */
            for (i = 0; (ret == 1) && (i < RANGE_MAX_TRIALS); i++) {
                /* Generate a random number in range. */
                if (wolfSSL_BN_pseudo_rand(r, n, WOLFSSL_BN_RAND_TOP_ANY,
                        WOLFSSL_BN_RAND_BOTTOM_ANY) == 0) {
                    WOLFSSL_MSG("wolfSSL_BN_rand error");
                    ret = 0;
                }
                /* Check if in range. */
                else if (wolfSSL_BN_cmp(r, range) < 0) {
                    break;
                }
            }
            /* Fail if max trial attempts made. */
            if (i >= RANGE_MAX_TRIALS) {
                WOLFSSL_MSG("wolfSSL_BN_rand_range too many iterations");
                ret = 0;
            }
        }
    }

    return ret;
}

/*******************************************************************************
 * Prime APIs
 ******************************************************************************/

#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_RSA) || !defined(NO_DH) || \
    !defined(NO_DSA))

/* Generate a prime number.
 *
 * @param [in, out] prime  Big number to generate into.
 * @param [in]      bits   Number of bits in generated number.
 * @param [in]      safe   Whether number must be a safe prime.
 * @param [in]      add    Value to add when generating. Not used.
 * @param [in]      rem    Remainder of number modulo add. Not used.
 * @param [in]      cb     Generation callback. Not used.
 * @return  1 on success.
 * @return  0 when prime is NULL.
 * @return  0 when safe required or add or rem is not NULL.
 * @return  0 on generation failure.
 */
int wolfSSL_BN_generate_prime_ex(WOLFSSL_BIGNUM* prime, int bits,
    int safe, const WOLFSSL_BIGNUM* add, const WOLFSSL_BIGNUM* rem,
    WOLFSSL_BN_GENCB* cb)
{
    int ret = 1;
    WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0);
    WC_RNG* rng = NULL;
    int localRng = 0;

    /* Callback not used. */
    (void)cb;

    WOLFSSL_ENTER("wolfSSL_BN_generate_prime_ex");

    /* Check unsupported parameters. */
    if ((safe == 1) || (add != NULL) || (rem != NULL)) {
        ret = 0;
    }
    /* Validate parameters. */
    else if (BN_IS_NULL(prime)) {
        ret = 0;
    }

    /* Create a new RNG or use global. */
    if ((ret == 1) && ((rng = wolfssl_make_rng(tmpRng, &localRng)) == NULL)) {
        ret = 0;
    }

    /* Use wolfCrypt to generate a prime. */
    if ((ret == 1) && (mp_rand_prime((mp_int*)prime->internal, (bits + 7) / 8,
            rng, NULL) != MP_OKAY)) {
        ret = 0;
    }

    if (localRng) {
        /* Dispose of local RNG that was created. */
        wc_FreeRng(rng);
        WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG);
    }

    WOLFSSL_LEAVE("wolfSSL_BN_generate_prime_ex", ret);

    return ret;
}

/* Check whether a big number is prime.
 *
 * Return code compliant with OpenSSL.
 *
 * @param [in] bn      Big number to check.
 * @param [in] checks  Number of Miller-Rabin tests to perform.
 * @param [in] ctx     BN context. Not used.
 * @param [in] cb      Generation callback. Not used.
 * @return  1 when number is prime.
 * @return  0 when number is not prime.
 * @return  -1 when bn is NULL or failure when checking.
 */
int wolfSSL_BN_is_prime_ex(const WOLFSSL_BIGNUM *bn, int checks,
    WOLFSSL_BN_CTX *ctx, WOLFSSL_BN_GENCB *cb)
{
    int ret = 1;
    WC_RNG* rng    = NULL;
    WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0);
    int localRng = 0;
    int res = MP_NO;

    /* BN context not needed. */
    (void)ctx;
    (void)cb;

    WOLFSSL_ENTER("wolfSSL_BN_is_prime_ex");

    if (BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = WOLFSSL_FATAL_ERROR;
    }

    /* Create a new RNG or use global. */
    if ((ret == 1) && ((rng = wolfssl_make_rng(tmpRng, &localRng)) == NULL)) {
        ret = WOLFSSL_FATAL_ERROR;
    }

    if ((ret == 1) && (mp_prime_is_prime_ex((mp_int*)bn->internal, checks, &res,
            rng) != MP_OKAY)) {
        WOLFSSL_MSG("mp_prime_is_prime_ex error");
        ret = WOLFSSL_FATAL_ERROR;
    }

    if (localRng) {
        wc_FreeRng(rng);
        WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG);
    }

    if ((ret != -1) && (res != MP_YES)) {
        WOLFSSL_MSG("mp_prime_is_prime_ex not prime");
        ret = 0;
    }

    return ret;
}

#endif /* WOLFSSL_KEY_GEN && (!NO_RSA || !NO_DH || !NO_DSA) */

/*******************************************************************************
 * Print APIs
 ******************************************************************************/

#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) && \
    defined(XFPRINTF)
/* Print big number to file pointer.
 *
 * Return code compliant with OpenSSL.
 *
 * @param [in] fp  File pointer.
 * @param [in] bn  Big number to print.
 * @return  1 on success.
 * @return  0 when fp is a bad file pointer.
 * @return  0 when bn is NULL.
 * @return  0 when creating hex string fails.
 * @return  0 when printing fails.
 */
int wolfSSL_BN_print_fp(XFILE fp, const WOLFSSL_BIGNUM *bn)
{
    int ret = 1;
    char* buf = NULL;

    WOLFSSL_ENTER("wolfSSL_BN_print_fp");

    /* Validate parameters. */
    if ((fp == XBADFILE) || BN_IS_NULL(bn)) {
        WOLFSSL_MSG("bn NULL error");
        ret = 0;
    }

    /* Create a hex string of big number. */
    if ((ret == 1) && ((buf = wolfSSL_BN_bn2hex(bn)) == NULL)) {
        WOLFSSL_MSG("wolfSSL_BN_bn2hex failure");
        ret = 0;
    }

    /* Print hex string to file pointer. */
    if ((ret == 1) && (XFPRINTF(fp, "%s", buf) < 0)) {
        ret = 0;
    }

    /* Dispose of any allocated data. */
    XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL);

    return ret;
}
#endif /* !NO_FILESYSTEM && XFPRINTF */

#ifndef NO_WOLFSSL_BN_CTX
/*******************************************************************************
 * BN_CTX APIs
 ******************************************************************************/

/* Create a new BN context object.
 *
 * @return  BN context object on success.
 * @return  NULL on failure.
 */
WOLFSSL_BN_CTX* wolfSSL_BN_CTX_new(void)
{
    WOLFSSL_BN_CTX* ctx = NULL;

    WOLFSSL_ENTER("wolfSSL_BN_CTX_new");
    ctx = (WOLFSSL_BN_CTX*)XMALLOC(sizeof(WOLFSSL_BN_CTX), NULL,
            DYNAMIC_TYPE_OPENSSL);
    if (ctx != NULL) {
        XMEMSET(ctx, 0, sizeof(WOLFSSL_BN_CTX));
    }

    return ctx;
}


#ifndef NO_WOLFSSL_STUB
/* deprecated
 *
 * Initialize a BN context object.
 * This function was removed in OpenSSL 1.1.0 and later.
 * Keeping a stub function here for older applications that have BN_CTX_init()
 * calls.
 *
 * @param [in] ctx  Dummy BN context.
 */
void wolfSSL_BN_CTX_init(WOLFSSL_BN_CTX* ctx)
{
    (void)ctx;
    WOLFSSL_ENTER("wolfSSL_BN_CTX_init");
    WOLFSSL_STUB("wolfSSL_BN_CTX_init");
    WOLFSSL_MSG("wolfSSL_BN_CTX_init is deprecated");
}
#endif


/* Free a BN context object.
 *
 * @param [in] ctx  BN context object.
 */
void wolfSSL_BN_CTX_free(WOLFSSL_BN_CTX* ctx)
{
    WOLFSSL_ENTER("wolfSSL_BN_CTX_free");
    if (ctx != NULL) {
        while (ctx->list != NULL) {
            struct WOLFSSL_BN_CTX_LIST* tmp = ctx->list;
            ctx->list = ctx->list->next;
            wolfSSL_BN_free(tmp->bn);
            XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL);
        }
        XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL);
    }
}

/* Get a big number from the BN context.
 *
 * @param [in] ctx  BN context object.
 * @return  Big number on success.
 * @return  NULL on failure.
 */
WOLFSSL_BIGNUM *wolfSSL_BN_CTX_get(WOLFSSL_BN_CTX *ctx)
{
    WOLFSSL_BIGNUM* bn = NULL;

    WOLFSSL_ENTER("wolfSSL_BN_CTX_get");
    if (ctx != NULL) {
        struct WOLFSSL_BN_CTX_LIST* node = (struct WOLFSSL_BN_CTX_LIST*)XMALLOC(
                sizeof(struct WOLFSSL_BN_CTX_LIST), NULL, DYNAMIC_TYPE_OPENSSL);
        if (node != NULL) {
            XMEMSET(node, 0, sizeof(struct WOLFSSL_BN_CTX_LIST));
            bn = node->bn = wolfSSL_BN_new();
            if (node->bn != NULL) {
                node->next = ctx->list;
                ctx->list = node;
            }
            else {
                XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL);
                node = NULL;
            }
        }
    }

    return bn;
}

#ifndef NO_WOLFSSL_STUB
/* Start stack of temporary big numbers.
 *
 * Newly allocated big numbers are returned instead of having a stack.
 *
 * @param [in] ctx  BN context. Not used.
 */
void wolfSSL_BN_CTX_start(WOLFSSL_BN_CTX *ctx)
{
    (void)ctx;

    WOLFSSL_ENTER("wolfSSL_BN_CTX_start");
    WOLFSSL_STUB("BN_CTX_start");
    WOLFSSL_MSG("wolfSSL_BN_CTX_start TBD");
}
#endif

#endif /* NO_WOLFSSL_BN_CTX */

/*******************************************************************************
 * BN_MONT_CTX APIs
 ******************************************************************************/

WOLFSSL_BN_MONT_CTX* wolfSSL_BN_MONT_CTX_new(void)
{
    /* wolfcrypt doesn't need BN MONT context. */
    static int mont;
    WOLFSSL_ENTER("wolfSSL_BN_MONT_CTX_new");
    return (WOLFSSL_BN_MONT_CTX*)&mont;
}

void wolfSSL_BN_MONT_CTX_free(WOLFSSL_BN_MONT_CTX *mont)
{
    (void)mont;
    WOLFSSL_ENTER("wolfSSL_BN_MONT_CTX_free");
    /* Don't do anything since using dummy, static BN context. */
}

int wolfSSL_BN_MONT_CTX_set(WOLFSSL_BN_MONT_CTX *mont,
        const WOLFSSL_BIGNUM *mod, WOLFSSL_BN_CTX *ctx)
{
    (void) mont;
    (void) mod;
    (void) ctx;
    WOLFSSL_ENTER("wolfSSL_BN_MONT_CTX_set");
    return WOLFSSL_SUCCESS;
}

/* Calculate r = a ^ p % m.
 *
 * @param [out] r    Big number to store the result.
 * @param [in]  a    Base as an unsigned long.
 * @param [in]  p    Exponent as a big number.
 * @param [in]  m    Modulus as a big number.
 * @param [in]  ctx  BN context object. Unused.
 * @param [in]  mont Montgomery context object. Unused.
 *
 * @return  1 on success.
 * @return  0 on failure.
 */
int wolfSSL_BN_mod_exp_mont_word(WOLFSSL_BIGNUM *r, WOLFSSL_BN_ULONG a,
        const WOLFSSL_BIGNUM *p, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx,
        WOLFSSL_BN_MONT_CTX *mont)
{
    WOLFSSL_BIGNUM* tmp = NULL;
    int ret = WOLFSSL_SUCCESS;

    (void)mont;
    WOLFSSL_ENTER("wolfSSL_BN_mod_exp_mont_word");

    if (ret == WOLFSSL_SUCCESS && (tmp = wolfSSL_BN_new()) == NULL) {
        WOLFSSL_MSG("wolfSSL_BN_new failed");
        ret = WOLFSSL_FAILURE;
    }
    if (ret == WOLFSSL_SUCCESS && (wolfSSL_BN_set_word(tmp, (unsigned long)a))
                                   == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
        WOLFSSL_MSG("wolfSSL_BN_set_word failed");
        ret = WOLFSSL_FAILURE;
    }
    if (ret == WOLFSSL_SUCCESS)
        ret = wolfSSL_BN_mod_exp(r, tmp, p, m, ctx);

    wolfSSL_BN_free(tmp);
    return ret;
}

#endif /* OPENSSL_EXTRA */

#endif /* !WOLFSSL_SSL_BN_INCLUDED */

