commit e6dcee35e511b33033626579e0fec9d2837ea0c2
parent 24b4a57b0b2beac2ec1b49263b33a390d009beeb
Author: vaplv <vaplv@free.fr>
Date: Tue, 19 Jan 2021 15:33:21 +0100
Upd the hash_sha256 profile
The hash_sha256 function does not allocate temporary memory space
anymore. It iterate over original data clustered in chunks of 512 bits.
This commit provides also the new hash_sha256_chunked_data function that
allows the caller to control the memory layout of the data to hash: in
hash_sha256, input data must be stored in a continuous memory block.
Diffstat:
3 files changed, 144 insertions(+), 55 deletions(-)
diff --git a/src/hash.c b/src/hash.c
@@ -17,10 +17,16 @@
#include "endianness.h"
#include "hash.h"
+#include "math.h"
#include "mem_allocator.h"
#include <string.h>
+struct buffer {
+ const char* mem;
+ size_t len;
+};
+
/* Array of round constants: first 32 bits of the fractional parts of the cube
* roots of the first 64 primes 2..311 */
static const uint32_t k[64] = {
@@ -48,56 +54,60 @@ rrot(const uint32_t ui, const unsigned int count)
return ui >> count | ui << (32 - count);
}
-static size_t
-create_msg
- (struct mem_allocator* allocator,
- const void* data,
- const size_t len,
- char** out_msg)
+static void
+get_chunk512(char dst[64], const size_t ichunk512, void* ctx)
{
- char* msg = NULL;
- size_t msg_sz = 0;
- ASSERT(allocator && out_msg);
-
- msg_sz = ALIGN_SIZE(len + 1/*Byte of the '1' bit*/ + 8/*message len*/, 64u);
- msg = MEM_ALLOC(allocator, msg_sz);
- if(!msg) goto error;
-
- memcpy(msg, data, len);
-
- /* Setup the '1' bit that marks the end of the msg */
- msg[len] = (char)0x80u;
- /* Clean up the bytes after the msg up to the last 8 bytes */
- memset(msg+len+1, 0, msg_sz - len - 1 - 8);
- /* Store the message 8*len in big endian */
- *(uint64_t*)(msg+msg_sz-8) = big_endian_64(len*8);
-
-exit:
- *out_msg = msg;
- return msg_sz;
-
-error:
- msg_sz = 0;
- if(msg) { MEM_RM(allocator, msg); msg = NULL; }
- goto exit;
+ struct buffer* buf = ctx;
+ const char* chunk = NULL;
+ size_t chunk_sz = 0;
+ const size_t offset = ichunk512*(sizeof(char[64]));
+ ASSERT(buf && offset < buf->len);
+
+ chunk = buf->mem + offset;
+ chunk_sz = MMIN(buf->len - offset, sizeof(char[64]));
+ memcpy(dst, chunk, chunk_sz);
}
/*******************************************************************************
* Exported functions
******************************************************************************/
-res_T
+void
hash_sha256
- (struct mem_allocator* mem_allocator,
- const void* data,
+ (const void* data,
const size_t len,
hash256_T hash)
{
- struct mem_allocator* allocator = NULL;
- char* msg = NULL;
+ struct chunked_data_desc desc = CHUNKED_DATA_DESC_NULL;
+ struct buffer buf;
+
+ buf.mem = data;
+ buf.len = len;
+
+ desc.get_chunk512 = get_chunk512;
+ desc.size = len;
+ desc.context = &buf;
+
+ hash_sha256_chunked_data(&desc, hash);
+}
+
+void
+hash_sha256_chunked_data
+ (struct chunked_data_desc* data,
+ hash256_T hash)
+{
+ /* Actually, the size of one chunk is 64 bytes. Anyway, note that after the
+ * last byte of the data to digest, one has to store 9 additionnal bytes: 1
+ * to mark the end of the data and 8 used to save the effective data length.
+ * Such tailing bytes can exceed the 64 bytes length of the chunk. Since the
+ * overall message length must be aligned on 64 bytes we thus pre-allocate an
+ * array whose size is 2 times the chunk size */
+ char buffer[64*2];
+
size_t msg_sz = 0;
size_t ichunk = 0;
size_t nchunks = 0;
- res_T res = RES_OK;
+ size_t ichunk_last_byte = 0; /* Chunk id the last data byte */
+ size_t remaining_data_sz = 0;
/* Initial hash values: first 32 bits of the fractional parts of the square
* roots of the first 8 primes 2..19 */
@@ -109,22 +119,60 @@ hash_sha256
uint32_t h5 = 0x9b05688c;
uint32_t h6 = 0x1f83d9ab;
uint32_t h7 = 0x5be0cd19;
- ASSERT(hash);
+ ASSERT(data && hash);
- allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
+ remaining_data_sz = data->size;
- msg_sz = create_msg(allocator, data, len, &msg);
- if(!msg) { res = RES_MEM_ERR; goto error; }
+ /* Compute the overall size of the message */
+ msg_sz = ALIGN_SIZE
+ (data->size + 1/*Byte of the '1' bit*/ + 8/*message len*/, 64u);
ASSERT((msg_sz % 64) == 0);
nchunks = msg_sz / 64; /* #chunks of 512 bits */
+ /* Index of the chunk containing the last data byte */
+ ichunk_last_byte = data->size / 64;
+
FOR_EACH(ichunk, 0, nchunks) {
- const char* chunk = msg + ichunk*64;
+ char* chunk = NULL;
uint32_t w[64] = {0};
uint32_t a=h0, b=h1, c=h2, d=h3, e=h4, f=h5, g=h6, h=h7;
int i;
+ if(ichunk > ichunk_last_byte) {
+ chunk = buffer + 64;
+ } else {
+ chunk = buffer;
+
+ /* Fetch the user data if any */
+ if(remaining_data_sz) {
+ ASSERT(data->get_chunk512);
+ data->get_chunk512(buffer, ichunk, data->context);
+ remaining_data_sz = remaining_data_sz > 64
+ ? remaining_data_sz - 64 : 0;
+ }
+
+ /* Setup the tailing bytes of the message */
+ if(ichunk == ichunk_last_byte) {
+ char* remaining_msg = buffer;
+ const size_t remaining_msg_sz = ichunk_last_byte==nchunks-1 ? 64 : 128;
+
+ /* Id after the last data byte */
+ const size_t ibyte_len = data->size % 64;
+
+ /* Setup the '1' bit that marks the end of the data */
+ remaining_msg[ibyte_len] = (char)0x80u;
+
+ /* Clean up the bytes after the data up to the last 8 bytes */
+ memset(remaining_msg + ibyte_len + 1, 0,
+ remaining_msg_sz - ibyte_len - 1 - 8);
+
+ /* Store the message 8*len in big endian */
+ *(uint64_t*)(remaining_msg + remaining_msg_sz-8) =
+ big_endian_64(data->size*8);
+ }
+ }
+
FOR_EACH(i, 0, 16) {
w[i] = big_endian_32(((uint32_t*)chunk)[i]);
}
@@ -166,12 +214,6 @@ hash_sha256
((uint32_t*)hash)[5] = big_endian_32(h5);
((uint32_t*)hash)[6] = big_endian_32(h6);
((uint32_t*)hash)[7] = big_endian_32(h7);
-
-exit:
- if(msg) MEM_RM(allocator, msg);
- return res;
-error:
- goto exit;
}
void
diff --git a/src/hash.h b/src/hash.h
@@ -22,6 +22,20 @@ struct mem_allocator;
typedef char hash256_T[32];
+struct chunked_data_desc {
+ /* Get the data per chunk of 512 bits. The last chunk length can be lesser
+ * than 512 bits */
+ void (*get_chunk512)
+ (char dst[64], /* Destination */
+ const size_t ichunk512, /* Indices of the chunck of 512 bits to fetch */
+ void* ctx); /* User defined variable */
+ size_t size; /* Size in bytes of the data */
+ void* context; /* User defined variable */
+};
+#define CHUNKED_DATA_DESC_NULL__ {NULL, 0, NULL}
+static const struct chunked_data_desc CHUNKED_DATA_DESC_NULL =
+ CHUNKED_DATA_DESC_NULL__;
+
/* 32-bits Fowler/Noll/Vo hash function */
static INLINE uint32_t
hash_fnv32(const void* data, const size_t len)
@@ -62,14 +76,18 @@ hash_fnv64(const void* data, const size_t len)
BEGIN_DECLS
-RSYS_API res_T
+RSYS_API void
hash_sha256
- (struct mem_allocator* allocator,
- const void* data,
+ (const void* data,
const size_t len,
hash256_T hash);
RSYS_API void
+hash_sha256_chunked_data
+ (struct chunked_data_desc* data,
+ hash256_T hash);
+
+RSYS_API void
hash256_to_cstr
(const hash256_T hash,
char cstr[65]);
diff --git a/src/test_hash_sha256.c b/src/test_hash_sha256.c
@@ -15,6 +15,7 @@
#include "endianness.h"
#include "hash.h"
+#include "math.h"
#include "mem_allocator.h"
#include <string.h>
@@ -28,14 +29,42 @@ struct test_data {
const char* sha256sum;
};
+struct buf {
+ const char* mem;
+ size_t len;
+};
+
+static void
+get_chunk512(char dst[64], const size_t ichunk, void* ctx)
+{
+ struct buf* buf = ctx;
+ size_t offset = 0;
+ CHK(dst && buf && ichunk < (buf->len + 63/*ceil*/)/64);
+
+ offset = ichunk * 64;
+ memcpy(dst, buf->mem + offset, MMIN(64, buf->len - offset));
+}
+
static void
chk_hash(const void* data, const size_t data_len, const char* sha256sum)
{
- hash256_T hash;
+ struct buf buf;
+ struct chunked_data_desc chunked_data = CHUNKED_DATA_DESC_NULL;
+ hash256_T hash0;
+ hash256_T hash1;
char hash_str[65];
ASSERT(sha256sum);
- CHK(hash_sha256(NULL, data, data_len, hash) == RES_OK);
- hash256_to_cstr(hash, hash_str);
+
+ buf.mem = data;
+ buf.len = data_len;
+ chunked_data.get_chunk512 = get_chunk512;
+ chunked_data.size = data_len;
+ chunked_data.context = &buf;
+
+ hash_sha256(data, data_len, hash0);
+ hash_sha256_chunked_data(&chunked_data, hash1);
+ hash256_eq(hash0, hash1);
+ hash256_to_cstr(hash0, hash_str);
CHK(!strcmp(hash_str, sha256sum));
}
@@ -53,7 +82,7 @@ main(int argc, char** argv)
chk_hash(data, 0,
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
- CHK(hash_sha256(&mem_default_allocator, data, 0, hash0) == RES_OK);
+ hash_sha256(data, 0, hash0);
((uint32_t*)hash1)[0] = big_endian_32(0xe3b0c442);
((uint32_t*)hash1)[1] = big_endian_32(0x98fc1c14);
((uint32_t*)hash1)[2] = big_endian_32(0x9afbf4c8);