rsys

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

commit 36a529a9feb4f6e5b2b7135ee66475250f78fb86
parent f214688f6b723e0cc7633128ecde65f8b629c2d5
Author: vaplv <vaplv@free.fr>
Date:   Mon,  5 Sep 2022 17:26:26 +0200

Major update of the sha256 API

Remove the hash256_chunked_data function and add the sha256_ctx API.

Diffstat:
Msrc/hash.c | 266+++++++++++++++++++++++++++++++++++++------------------------------------------
Msrc/hash.h | 27++++++++++++++++++++++-----
2 files changed, 148 insertions(+), 145 deletions(-)

diff --git a/src/hash.c b/src/hash.c @@ -55,165 +55,151 @@ rrot(const uint32_t ui, const unsigned int count) } static void -get_chunk512(char dst[64], const size_t ichunk512, void* ctx) +sha256_process_chunk(struct sha256_ctx* ctx) { - 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); + uint32_t w[64]; + uint32_t a, b, c, d, e, f, g, h; + uint32_t i; + ASSERT(ctx); + + FOR_EACH(i, 0, 16) { + w[i] = big_endian_32(((uint32_t*)ctx->chunk)[i]); + } + FOR_EACH(i, 16, 64) { + const uint32_t s0 = rrot(w[i-15],7) ^ rrot(w[i-15],18) ^ (w[i-15] >> 3); + const uint32_t s1 = rrot(w[i-2],17) ^ rrot(w[i-2], 19) ^ (w[i-2] >> 10); + w[i] = w[i-16] + s0 + w[i-7] + s1; + } + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + /* Compress the chunk */ + FOR_EACH(i, 0, 64) { + const uint32_t s0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22); + const uint32_t s1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25); + const uint32_t ch = (e & f) ^ ((~e) & g); + const uint32_t maj = (a & b) ^ (a & c) ^ (b & c); + const uint32_t tmp1 = h + s1 + ch + k[i] + w[i]; + const uint32_t tmp2 = s0 + maj; + + h = g; + g = f; + f = e; + e = d + tmp1; + d = c; + c = b; + b = a; + a = tmp1 + tmp2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; } /******************************************************************************* * Exported functions ******************************************************************************/ void -hash_sha256 - (const void* data, - const size_t len, - hash256_T hash) +sha256_ctx_init(struct sha256_ctx* ctx) { - 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; + /* Initial hash values: first 32 bits of the fractional parts of the square + * roots of the first 8 primes 2..19 */ + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; + ctx->len = 0; + ctx->nbits = 0; +} - hash_sha256_chunked_data(&desc, hash); +void +sha256_ctx_update + (struct sha256_ctx* ctx, + const char* bytes, + const size_t len) +{ + uint32_t i; + ASSERT(ctx); + ASSERT(bytes || !len); + + FOR_EACH(i, 0, len) { + ctx->chunk[ctx->len] = bytes[i]; + ctx->len += 1; + if(ctx->len == 64) { + sha256_process_chunk(ctx); + ctx->nbits += 512; + ctx->len = 0; + } + } } void -hash_sha256_chunked_data - (struct chunked_data_desc* data, - hash256_T hash) +sha256_ctx_finalize(struct sha256_ctx* ctx, 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; - size_t ichunk_last_byte = 0; /* Chunk id the last data byte */ - size_t remaining_data_sz = 0; + uint32_t i; - /* Initial hash values: first 32 bits of the fractional parts of the square - * roots of the first 8 primes 2..19 */ - uint32_t h0 = 0x6a09e667; - uint32_t h1 = 0xbb67ae85; - uint32_t h2 = 0x3c6ef372; - uint32_t h3 = 0xa54ff53a; - uint32_t h4 = 0x510e527f; - uint32_t h5 = 0x9b05688c; - uint32_t h6 = 0x1f83d9ab; - uint32_t h7 = 0x5be0cd19; - ASSERT(data && hash); - - remaining_data_sz = data->size; - - /* 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) { - 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); - } - } + ASSERT(ctx && hash); - FOR_EACH(i, 0, 16) { - w[i] = big_endian_32(((uint32_t*)chunk)[i]); - } - FOR_EACH(i, 16, 64) { - const uint32_t s0 = rrot(w[i-15],7) ^ rrot(w[i-15],18) ^ (w[i-15] >> 3); - const uint32_t s1 = rrot(w[i-2],17) ^ rrot(w[i-2], 19) ^ (w[i-2] >> 10); - w[i] = w[i-16] + s0 + w[i-7] + s1; - } + ctx->nbits += ctx->len * 8; /* Update the message's length */ + i = ctx->len; - /* Compress the chunk */ - FOR_EACH(i, 0, 64) { - const uint32_t s1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25); - const uint32_t ch = (e & f) ^ ((~e) & g); - const uint32_t tmp1 = h + s1 + ch + k[i] + w[i]; - const uint32_t s0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22); - const uint32_t maj = (a & b) ^ (a & c) ^ (b & c); - const uint32_t tmp2 = s0 + maj; - - h = g; - g = f; - f = e; - e = d + tmp1; - d = c; - c = b; - b = a; - a = tmp1 + tmp2; - } + /* Setup the '1' bit that marks the end of the data */ + ctx->chunk[i++] = (char)0x80; - /* Update hash with the current compressed chunk */ - h0+=a; h1+=b; h2+=c; h3+=d; h4+=e; h5+=f; h6+=g; h7+=h; + /* Clean up the bytes after the data up to the last 8 bytes */ + if(ctx->len < 56) { + memset(ctx->chunk+i, 0, 56-i); + } else { + memset(ctx->chunk+i, 0, 64-i); + sha256_process_chunk(ctx); + memset(ctx->chunk, 0, 56); } - /* Write the results */ - ((uint32_t*)hash)[0] = big_endian_32(h0); - ((uint32_t*)hash)[1] = big_endian_32(h1); - ((uint32_t*)hash)[2] = big_endian_32(h2); - ((uint32_t*)hash)[3] = big_endian_32(h3); - ((uint32_t*)hash)[4] = big_endian_32(h4); - ((uint32_t*)hash)[5] = big_endian_32(h5); - ((uint32_t*)hash)[6] = big_endian_32(h6); - ((uint32_t*)hash)[7] = big_endian_32(h7); + /* Store the message's length in bits */ + *((uint64_t*)(ctx->chunk + 56)) = big_endian_64(ctx->nbits); + sha256_process_chunk(ctx); + + /* Store result the result */ + ((uint32_t*)hash)[0] = big_endian_32(ctx->state[0]); + ((uint32_t*)hash)[1] = big_endian_32(ctx->state[1]); + ((uint32_t*)hash)[2] = big_endian_32(ctx->state[2]); + ((uint32_t*)hash)[3] = big_endian_32(ctx->state[3]); + ((uint32_t*)hash)[4] = big_endian_32(ctx->state[4]); + ((uint32_t*)hash)[5] = big_endian_32(ctx->state[5]); + ((uint32_t*)hash)[6] = big_endian_32(ctx->state[6]); + ((uint32_t*)hash)[7] = big_endian_32(ctx->state[7]); +} + +void +hash_sha256 + (const void* data, + const size_t len, + hash256_T hash) +{ + struct sha256_ctx ctx; + ASSERT(hash); + ASSERT(data || !len); + + sha256_ctx_init(&ctx); + sha256_ctx_update(&ctx, data, len); + sha256_ctx_finalize(&ctx, hash); } void diff --git a/src/hash.h b/src/hash.h @@ -20,6 +20,13 @@ struct mem_allocator; +struct sha256_ctx { + char chunk[64]; + uint32_t len; /* #bytes registered in chunk */ + uint32_t state[8]; /* Current hash state */ + uint64_t nbits; /* Overall size of the message in bits */ +}; + typedef char hash256_T[32]; struct chunked_data_desc { @@ -77,14 +84,24 @@ hash_fnv64(const void* data, const size_t len) BEGIN_DECLS RSYS_API void -hash_sha256 - (const void* data, - const size_t len, +sha256_ctx_init + (struct sha256_ctx* ctx); + +RSYS_API void +sha256_ctx_update + (struct sha256_ctx* ctx, + const char* bytes, + const size_t len); /* #bytes */ + +RSYS_API void +sha256_ctx_finalize + (struct sha256_ctx* ctx, hash256_T hash); RSYS_API void -hash_sha256_chunked_data - (struct chunked_data_desc* data, +hash_sha256 + (const void* data, + const size_t len, hash256_T hash); RSYS_API void