rsys

Basic data structures and low-level features
git clone git://git.meso-star.fr/rsys.git
Log | Files | Refs | README | LICENSE

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:
Msrc/hash.c | 138+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/hash.h | 24+++++++++++++++++++++---
Msrc/test_hash_sha256.c | 37+++++++++++++++++++++++++++++++++----
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);