* Copyright (c) 2022 Huawei Technologies Co.,Ltd.
*
* GR is licensed under 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.
* -------------------------------------------------------------------------
* gr_hash_optimized.c
* Minimal implementation: unified API, internally based on OpenSSL calculation, ensuring compilation.
* -------------------------------------------------------------------------
*/
#include "gr_hash_optimized.h"
#include "gr_defs.h"
#include <string.h>
#include <sys/time.h>
#include <stdlib.h>
status_t gr_hash_optimized_init(void)
{
return CM_SUCCESS;
}
void gr_hash_optimized_cleanup(void)
{
}
status_t gr_calculate_hash_optimized(const void *data, size_t size, uint8_t *hash)
{
if (data == NULL || hash == NULL || size == 0) {
return CM_ERROR;
}
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
if (mdctx == NULL) {
return CM_ERROR;
}
if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) {
EVP_MD_CTX_free(mdctx);
return CM_ERROR;
}
if (EVP_DigestUpdate(mdctx, data, size) != 1) {
EVP_MD_CTX_free(mdctx);
return CM_ERROR;
}
unsigned int digest_len = SHA256_DIGEST_LENGTH;
if (EVP_DigestFinal_ex(mdctx, hash, &digest_len) != 1) {
EVP_MD_CTX_free(mdctx);
return CM_ERROR;
}
EVP_MD_CTX_free(mdctx);
return CM_SUCCESS;
}
status_t gr_calculate_hash_batch(const void **data_array, const size_t *size_array,
uint32_t count, uint8_t (*hashes)[SHA256_DIGEST_LENGTH])
{
if (data_array == NULL || size_array == NULL || hashes == NULL) {
return CM_ERROR;
}
for (uint32_t i = 0; i < count; i++) {
status_t s = gr_calculate_hash_optimized(data_array[i], size_array[i], hashes[i]);
if (s != CM_SUCCESS) {
return s;
}
}
return CM_SUCCESS;
}
status_t gr_hash_stream_init(EVP_MD_CTX **stream_ctx)
{
if (stream_ctx == NULL) {
return CM_ERROR;
}
*stream_ctx = EVP_MD_CTX_new();
if (*stream_ctx == NULL) {
return CM_ERROR;
}
if (EVP_DigestInit_ex(*stream_ctx, EVP_sha256(), NULL) != 1) {
EVP_MD_CTX_free(*stream_ctx);
*stream_ctx = NULL;
return CM_ERROR;
}
return CM_SUCCESS;
}
status_t gr_hash_stream_update(EVP_MD_CTX *stream_ctx, const void *data, size_t size)
{
if (stream_ctx == NULL || data == NULL) {
return CM_ERROR;
}
return (EVP_DigestUpdate(stream_ctx, data, size) == 1) ? CM_SUCCESS : CM_ERROR;
}
status_t gr_hash_stream_final(EVP_MD_CTX *stream_ctx, uint8_t *hash)
{
if (stream_ctx == NULL || hash == NULL) {
return CM_ERROR;
}
unsigned int digest_len = SHA256_DIGEST_LENGTH;
return (EVP_DigestFinal_ex(stream_ctx, hash, &digest_len) == 1) ? CM_SUCCESS : CM_ERROR;
}
void gr_hash_stream_cleanup(EVP_MD_CTX *stream_ctx)
{
if (stream_ctx != NULL) {
EVP_MD_CTX_free(stream_ctx);
}
}
void gr_hash_get_stats(gr_hash_stats_t *stats)
{
if (stats == NULL) { return; }
memset(stats, 0, sizeof(*stats));
}
void gr_hash_reset_stats(void)
{
}
bool32 gr_hash_hw_acceleration_available(void)
{
return CM_FALSE;
}
status_t gr_calculate_hash_parallel(const void *data, size_t size, uint8_t *hash, uint32_t thread_count)
{
(void)thread_count;
return gr_calculate_hash_optimized(data, size, hash);
}
status_t gr_calculate_hash_aligned(const void *data, size_t size, uint8_t *hash)
{
if (data == NULL || hash == NULL || size == 0) {
return CM_ERROR;
}
if (gr_is_aligned(data, GR_HASH_ALIGN_SIZE)) {
return gr_calculate_hash_optimized(data, size, hash);
}
void *aligned_ptr = NULL;
#if defined(_ISOC11_SOURCE) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
aligned_ptr = aligned_alloc(GR_HASH_ALIGN_SIZE, size);
if (aligned_ptr == NULL) {
return CM_ERROR;
}
#else
if (posix_memalign(&aligned_ptr, GR_HASH_ALIGN_SIZE, size) != 0 || aligned_ptr == NULL) {
return CM_ERROR;
}
#endif
memcpy(aligned_ptr, data, size);
status_t s = gr_calculate_hash_optimized(aligned_ptr, size, hash);
free(aligned_ptr);
return s;
}
static gr_hash_stats_simple_t g_hash_simple_stats = {0};
static inline uint64_t gr_get_time_us_unified(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
}
status_t gr_calculate_hash_optimized_simple(const void *data, size_t size, uint8_t *hash)
{
if (data == NULL || hash == NULL || size == 0) {
return CM_ERROR;
}
uint64_t start = gr_get_time_us_unified();
status_t s = gr_calculate_hash_optimized(data, size, hash);
uint64_t endt = gr_get_time_us_unified();
if (s == CM_SUCCESS) {
g_hash_simple_stats.total_calls++;
g_hash_simple_stats.total_bytes += size;
g_hash_simple_stats.total_time_us += (endt - start);
}
return s;
}
status_t gr_calculate_hash_batch_simple(const void **data_array, const size_t *size_array,
uint32_t count, uint8_t (*hashes)[SHA256_DIGEST_LENGTH])
{
if (data_array == NULL || size_array == NULL || hashes == NULL || count == 0) {
return CM_ERROR;
}
uint64_t start = gr_get_time_us_unified();
status_t s = gr_calculate_hash_batch(data_array, size_array, count, hashes);
uint64_t endt = gr_get_time_us_unified();
if (s == CM_SUCCESS) {
g_hash_simple_stats.batch_calls++;
g_hash_simple_stats.batch_time_us += (endt - start);
for (uint32_t i = 0; i < count; i++) {
g_hash_simple_stats.batch_bytes += size_array[i];
}
}
return s;
}
status_t gr_calculate_hash_aligned_simple(const void *data, size_t size, uint8_t *hash)
{
return gr_calculate_hash_aligned(data, size, hash);
}
bool32 gr_hash_hw_acceleration_available_simple(void)
{
return gr_hash_hw_acceleration_available();
}
void gr_hash_get_stats_simple(gr_hash_stats_simple_t *stats)
{
if (stats == NULL) { return; }
*stats = g_hash_simple_stats;
}
void gr_hash_reset_stats_simple(void)
{
memset(&g_hash_simple_stats, 0, sizeof(g_hash_simple_stats));
}