/*!
    \ingroup Random

    \brief Init global Whitewood netRandom context

    \return 0 Success
    \return BAD_FUNC_ARG Either configFile is null or timeout is negative.
    \return RNG_FAILURE_E There was a failure initializing the rng.

    \param configFile Path to configuration file
    \param hmac_cb Optional to create HMAC callback.
    \param timeout A timeout duration.

    _Example_
    \code
    char* config = "path/to/config/example.conf";
    int time = // Some sufficient timeout value;

    if (wc_InitNetRandom(config, NULL, time) != 0)
    {
        // Some error occurred
    }
    \endcode

    \sa wc_FreeNetRandom
*/
int  wc_InitNetRandom(const char* configFile, wnr_hmac_key hmac_cb, int timeout);

/*!
    \ingroup Random

    \brief Free global Whitewood netRandom context.

    \return 0 Success
    \return BAD_MUTEX_E Error locking mutex on wnr_mutex

    \param none No returns.

    _Example_
    \code
    int ret = wc_FreeNetRandom();
    if(ret != 0)
    {
        // Handle the error
    }
    \endcode

    \sa wc_InitNetRandom
*/
int  wc_FreeNetRandom(void);

/*!
    \ingroup Random

    \brief Gets the seed (from OS) and key cipher for rng.  rng->drbg
    (deterministic random bit generator) allocated (should be deallocated
    with wc_FreeRng).  This is a blocking operation.

    \return 0 on success.
    \return MEMORY_E XMALLOC failed
    \return WINCRYPT_E wc_GenerateSeed: failed to acquire context
    \return CRYPTGEN_E wc_GenerateSeed: failed to get random
    \return BAD_FUNC_ARG wc_RNG_GenerateBlock input is null or sz exceeds
    MAX_REQUEST_LEN
    \return DRBG_CONT_FIPS_E wc_RNG_GenerateBlock: Hash_gen returned
    DRBG_CONT_FAILURE
    \return RNG_FAILURE_E wc_RNG_GenerateBlock: Default error.  rng’s
    status originally not ok, or set to DRBG_FAILED

    \param rng random number generator to be initialized for use
    with a seed and key cipher

    _Example_
    \code
    RNG  rng;
    int ret;

    #ifdef HAVE_CAVIUM
    ret = wc_InitRngCavium(&rng, CAVIUM_DEV_ID);
    if (ret != 0){
        printf(“RNG Nitrox init for device: %d failed”, CAVIUM_DEV_ID);
        return -1;
    }
    #endif
    ret = wc_InitRng(&rng);
    if (ret != 0){
        printf(“RNG init failed”);
        return -1;
    }
    \endcode

    \sa wc_InitRngCavium
    \sa wc_RNG_GenerateBlock
    \sa wc_RNG_GenerateByte
    \sa wc_FreeRng
    \sa wc_RNG_HealthTest
*/
int  wc_InitRng(WC_RNG*);

/*!
    \ingroup Random

    \brief Copies a sz bytes of pseudorandom data to output. Will
    reseed rng if needed (blocking).

    \return 0 on success
    \return BAD_FUNC_ARG an input is null or sz exceeds MAX_REQUEST_LEN
    \return DRBG_CONT_FIPS_E Hash_gen returned DRBG_CONT_FAILURE
    \return RNG_FAILURE_E Default error. rng’s status originally not
    ok, or set to DRBG_FAILED

    \param rng random number generator initialized with wc_InitRng
    \param output buffer to which the block is copied
    \param sz size of output in bytes

    _Example_
    \code
    RNG  rng;
    int  sz = 32;
    byte block[sz];

    int ret = wc_InitRng(&rng);
    if (ret != 0) {
        return -1; //init of rng failed!
    }

    ret = wc_RNG_GenerateBlock(&rng, block, sz);
    if (ret != 0) {
        return -1; //generating block failed!
    }
    \endcode

    \sa wc_InitRngCavium, wc_InitRng
    \sa wc_RNG_GenerateByte
    \sa wc_FreeRng
    \sa wc_RNG_HealthTest
*/
int  wc_RNG_GenerateBlock(WC_RNG* rng, byte* b, word32 sz);

/*!
    \ingroup Random

    \brief Creates a new WC_RNG structure.


    \return WC_RNG structure on success
    \return NULL on error


    \param heap pointer to a heap identifier
    \param nonce pointer to the buffer containing the nonce
    \param nonceSz length of the nonce

    _Example_
    \code
    RNG  rng;
    byte nonce[] = { initialize nonce };
    word32 nonceSz = sizeof(nonce);

    wc_rng_new(&nonce, nonceSz, &heap);


    \endcode

    \sa wc_InitRng
    \sa wc_rng_free
    \sa wc_FreeRng
    \sa wc_RNG_HealthTest
*/
WC_RNG* wc_rng_new(byte* nonce, word32 nonceSz, void* heap)

/*!
    \ingroup Random

    \brief Calls wc_RNG_GenerateBlock to copy a byte of pseudorandom
    data to b. Will reseed rng if needed.

    \return 0 on success
    \return BAD_FUNC_ARG an input is null or sz exceeds MAX_REQUEST_LEN
    \return DRBG_CONT_FIPS_E Hash_gen returned DRBG_CONT_FAILURE
    \return RNG_FAILURE_E Default error.  rng’s status originally not
    ok, or set to DRBG_FAILED

    \param rng: random number generator initialized with wc_InitRng
    \param b one byte buffer to which the block is copied

    _Example_
    \code
    RNG  rng;
    int  sz = 32;
    byte b[1];

    int ret = wc_InitRng(&rng);
    if (ret != 0) {
        return -1; //init of rng failed!
    }

    ret = wc_RNG_GenerateByte(&rng, b);
    if (ret != 0) {
        return -1; //generating block failed!
    }
    \endcode

    \sa wc_InitRngCavium
    \sa wc_InitRng
    \sa wc_RNG_GenerateBlock
    \sa wc_FreeRng
    \sa wc_RNG_HealthTest
*/
int  wc_RNG_GenerateByte(WC_RNG* rng, byte* b);

/*!
    \ingroup Random

    \brief Should be called when RNG no longer needed in order to securely
    free drgb.  Zeros and XFREEs rng-drbg.

    \return 0 on success
    \return BAD_FUNC_ARG rng or rng->drgb null
    \return RNG_FAILURE_E Failed to deallocated drbg

    \param rng random number generator initialized with wc_InitRng

    _Example_
    \code
    RNG  rng;
    int ret = wc_InitRng(&rng);
    if (ret != 0) {
        return -1; //init of rng failed!
    }

    int ret = wc_FreeRng(&rng);
    if (ret != 0) {
        return -1; //free of rng failed!
    }
    \endcode

    \sa wc_InitRngCavium
    \sa wc_InitRng
    \sa wc_RNG_GenerateBlock
    \sa wc_RNG_GenerateByte,
    \sa wc_RNG_HealthTest
*/
int  wc_FreeRng(WC_RNG*);

/*!
    \ingroup Random

    \brief Should be called when RNG no longer needed in order to securely
    free rng.


    \param rng random number generator initialized with wc_InitRng

    _Example_
    \code
    RNG  rng;
    byte nonce[] = { initialize nonce };
    word32 nonceSz = sizeof(nonce);

    rng = wc_rng_new(&nonce, nonceSz, &heap);

    // use rng

    wc_rng_free(&rng);

    \endcode

    \sa wc_InitRng
    \sa wc_rng_new
    \sa wc_FreeRng
    \sa wc_RNG_HealthTest
*/
WC_RNG* wc_rng_free(WC_RNG* rng);

/*!
    \ingroup Random

    \brief Creates and tests functionality of drbg.

    \return 0 on success
    \return BAD_FUNC_ARG seedA and output must not be null.  If reseed
    set seedB must not be null
    \return -1 test failed

    \param int reseed: if set, will test reseed functionality
    \param seedA: seed to instantiate drgb with
    \param seedASz: size of seedA in bytes
    \param seedB: If reseed set, drbg will be reseeded with seedB
    \param seedBSz: size of seedB in bytes
    \param output: initialized to random data seeded with seedB if
    seedrandom is set, and seedA otherwise
    \param outputSz: length of output in bytes

    _Example_
    \code
    byte output[SHA256_DIGEST_SIZE * 4];
    const byte test1EntropyB[] = ....; // test input for reseed false
    const byte test1Output[] = ....;   // testvector: expected output of
                                   // reseed false
    ret = wc_RNG_HealthTest(0, test1Entropy, sizeof(test1Entropy), NULL, 0,
                        output, sizeof(output));
    if (ret != 0)
        return -1;//healthtest without reseed failed

    if (XMEMCMP(test1Output, output, sizeof(output)) != 0)
        return -1; //compare to testvector failed: unexpected output

    const byte test2EntropyB[] = ....; // test input for reseed
    const byte test2Output[] = ....;   // testvector expected output of reseed
    ret = wc_RNG_HealthTest(1, test2EntropyA, sizeof(test2EntropyA),
                        test2EntropyB, sizeof(test2EntropyB),
                        output, sizeof(output));

    if (XMEMCMP(test2Output, output, sizeof(output)) != 0)
        return -1; //compare to testvector failed
    \endcode

    \sa wc_InitRngCavium
    \sa wc_InitRng
    \sa wc_RNG_GenerateBlock
    \sa wc_RNG_GenerateByte
    \sa wc_FreeRng
*/
int wc_RNG_HealthTest(int reseed, const byte* seedA, word32 seedASz,
        const byte* seedB, word32 seedBSz,
        byte* output, word32 outputSz);
