
#include <string.h>
#include <stdarg.h>

#ifdef USE_SCRYPTO_VER2_4
#include <openssl/scrypto_version.h>
#endif

#include <arithmetics_common.h>

#include <gpapi_log.h>

#include <tee_internal_api.h>

static int BigIntIsGuaranteedPrime(BIGNUM *bn)
{
    size_t i = 0;
    /* Not in table 'primes' */
#if defined(FIPS_SCRYPTO_MODULE_VERSION_NUM) && (FIPS_SCRYPTO_MODULE_VERSION_NUM >= 0x02052001)
    if (bn->width > 1) {
#else
    if (bn->top > 1) {
#endif
        return 0;
    }

    for (i = 1; i < NUMPRIMES; ++i) {
        if (bn->d[0] == primes[i]) {
            return 1;
        }
    }

    return 0;
}

int32_t TEE_BigIntIsProbablePrime(const TEE_BigInt *op, uint32_t confidenceLevel)
{
    int ret = TEE_SUCCESS;

    BIGNUM *bn_op = NULL;
    MPI *gpmpi1 = (MPI *) op;
    unsigned char *mpi_op = (unsigned char *) &gpmpi1->mpi;
    /* Long is the same as used in BN_mpi2bn */
    long len1 = 0;
    /* Pure length (without metadata) */
    len1 = MPIPureSize(mpi_op);
    MPICheckSize(len1);

    bn_op = BN_mpi2bn(mpi_op, len1 + OPENSSL_METADATA_SIZE_IN_BYTES, NULL);
    BNCheckNULL(bn_op);

    if (BigIntIsGuaranteedPrime(bn_op)) {
        BN_clear_free(bn_op);
        return 1;
    };
    BN_CTX *ctx = BN_CTX_new();
    if (ctx == NULL) {
        MB_LOGE("Panic reason: context is NULL\n");
        BNFreePanic(bn_op);
    }

    int openssl_ret = BN_is_prime_fasttest_ex(bn_op,
                          (confidenceLevel >= GP_MINIMAL_CONFIDENCE_LEVEL) ?
                          confidenceLevel :
                          GP_MINIMAL_CONFIDENCE_LEVEL,
                          ctx,
                          1,
                          NULL);

    if (openssl_ret == -1) {
        BN_CTX_free(ctx);
        PRINT_OSSL_ERROR();
        BNFreePanic(bn_op);
    }

    ret = (openssl_ret == 1) ? -1 : 0;

    BN_CTX_free(ctx);
    BN_clear_free(bn_op);

    return ret;
}
