/*

 * This file is part of the openHiTLS project.

 *

 * openHiTLS is licensed under the Mulan PSL v2.

 * You can use this software according to the terms and conditions of the Mulan PSL v2.

 * You may obtain a copy of Mulan PSL v2 at:

 *

 *     http://license.coscl.org.cn/MulanPSL2

 *

 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,

 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,

 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.

 * See the Mulan PSL v2 for more details.

 */



#include "hitls_build.h"

#if defined(HITLS_CRYPTO_ENTROPY) && defined(HITLS_CRYPTO_ENTROPY_SYS)



#include <stdint.h>

#include <string.h>

#include "bsl_err_internal.h"

#include "bsl_sal.h"

#include "crypt_errno.h"

#include "es_entropy_pool.h"



ES_EntropyPool *ES_EntropyPoolInit(uint32_t size)

{

    ES_EntropyPool *pool = NULL;

    uint32_t maxSize = size + 1;

    if (size == 0) {

        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);

        return NULL;

    }



    pool = (ES_EntropyPool *)BSL_SAL_Malloc(sizeof(ES_EntropyPool));

    if (pool == NULL) {

        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);

        return NULL;

    }



    pool->buf = (uint8_t *)BSL_SAL_Malloc(maxSize);

    if (pool->buf == NULL) {

        BSL_SAL_FREE(pool);

        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);

        return NULL;

    }



    pool->front = 0;

    pool->rear = 0;

    pool->maxSize = maxSize;

    return pool;

}



void ES_EntropyPoolDeInit(ES_EntropyPool *pool)

{

    if (pool == NULL) {

        return;

    }



    BSL_SAL_ClearFree(pool->buf, pool->maxSize);
    BSL_SAL_Free(pool);

    return;

}



int32_t ES_EntropyPoolGetMaxSize(ES_EntropyPool *pool)

{

    return pool->maxSize - 1;

}



uint32_t ES_EntropyPoolGetCurSize(ES_EntropyPool *pool)

{

    return (pool->rear - pool->front + pool->maxSize) % pool->maxSize;

}



int32_t ES_EntropyPoolPushBytes(ES_EntropyPool *pool, uint8_t *buf, uint32_t bufLen)

{

    uint32_t partA, partB;

    partA = (bufLen > (pool->maxSize - pool->rear)) ? pool->maxSize - pool->rear : bufLen;

    memcpy(&pool->buf[pool->rear], buf, partA);

    pool->rear = (pool->rear + partA) % pool->maxSize;

    if (partA < bufLen) {

        partB = bufLen - partA;

        memcpy(&pool->buf[pool->rear], buf + partA, partB);

        pool->rear = (pool->rear + partB) % pool->maxSize;

    }

    return CRYPT_SUCCESS;

}



uint32_t ES_EntropyPoolPopBytes(ES_EntropyPool *pool, uint8_t *data, uint32_t size)

{

    uint32_t bufLen, partA, partB;

    if (ES_EntropyPoolGetMaxSize(pool) == 0 || size == 0) {

        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);

        return 0;

    }



    bufLen = (ES_EntropyPoolGetCurSize(pool) < size) ? ES_EntropyPoolGetCurSize(pool) : size;



    partA = (bufLen <= pool->maxSize - pool->front) ? bufLen : pool->maxSize - pool->front;

    memcpy(data, &pool->buf[pool->front], partA);

    pool->front = (pool->front + partA) % pool->maxSize;

    partB = bufLen - partA;

    if (partB != 0) {

        memcpy(data + partA, &pool->buf[pool->front], partB);

        pool->front = (pool->front + partB) % pool->maxSize;

    }



    return bufLen;

}



#endif