rsys

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

commit 55f8e8949b162f512e35ceb72c305641e468ed64
parent ee9242b65847d58d08b93abb9ce4cd5e51413d78
Author: vaplv <vaplv@free.fr>
Date:   Wed, 12 Oct 2022 09:08:55 +0200

Merge remote-tracking branch 'origin/develop' into feature_posix_make

Diffstat:
Mcmake/CMakeLists.txt | 4++--
Msrc/hash.c | 355++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/hash.h | 27++++++++++++++++++++++-----
3 files changed, 230 insertions(+), 156 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -38,8 +38,8 @@ include(rcmake) # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 12) -set(VERSION_PATCH 1) +set(VERSION_MINOR 13) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(RSYS_FILES_SRC diff --git a/src/hash.c b/src/hash.c @@ -43,177 +43,234 @@ static const uint32_t k[64] = { 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; -/******************************************************************************* - * Helper functions - ******************************************************************************/ -/* Right rotation */ -static FINLINE uint32_t -rrot(const uint32_t ui, const unsigned int count) -{ - ASSERT(count <= 32); - return ui >> count | ui << (32 - count); -} - +/* Most of this code comes from GnuPG's cipher/sha1.c */ static void -get_chunk512(char dst[64], const size_t ichunk512, void* ctx) +sha256_process_chunk(struct sha256_ctx* ctx, const char chunk[64]) { - 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[16]; + uint32_t a, b, c, d, e, f, g, h; + uint32_t i; + + uint32_t tm; + uint32_t t0, t1; + + ASSERT(ctx); + + FOR_EACH(i, 0, 16) { + w[i] = big_endian_32(((uint32_t*)chunk)[i]); + } + + 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]; + + #define ROL(X, N) (((X) << (N)) | ((X) >> (32 - (N)))) + #define S0(X) (ROL(X,25)^ROL(X,14)^(X>>3)) + #define S1(X) (ROL(X,15)^ROL(X,13)^(X>>10)) + #define SS0(X) (ROL(X,30)^ROL(X,19)^ROL(X,10)) + #define SS1(X) (ROL(X,26)^ROL(X,21)^ROL(X,7)) + #define M(I) (tm = S1(w[(I- 2)&0x0f]) + w[(I-7)&0x0f] \ + + S0(w[(I-15)&0x0f]) + w[I&0x0f], w[I&0x0f] = tm) + #define F2(A, B, C) (( A & B ) | (C & (A | B))) + #define F1(E, F, G) (G ^ (E & (F ^ G))) + #define R(A, B, C, D, E, F, G, H, K, M) { \ + t0 = SS0(A) + F2(A, B, C); \ + t1 = H + SS1(E) + F1(E, F, G) + K + M; \ + D += t1; \ + H = t0 + t1; \ + } (void)0 + + R( a, b, c, d, e, f, g, h, k[ 0], w[ 0] ); + R( h, a, b, c, d, e, f, g, k[ 1], w[ 1] ); + R( g, h, a, b, c, d, e, f, k[ 2], w[ 2] ); + R( f, g, h, a, b, c, d, e, k[ 3], w[ 3] ); + R( e, f, g, h, a, b, c, d, k[ 4], w[ 4] ); + R( d, e, f, g, h, a, b, c, k[ 5], w[ 5] ); + R( c, d, e, f, g, h, a, b, k[ 6], w[ 6] ); + R( b, c, d, e, f, g, h, a, k[ 7], w[ 7] ); + R( a, b, c, d, e, f, g, h, k[ 8], w[ 8] ); + R( h, a, b, c, d, e, f, g, k[ 9], w[ 9] ); + R( g, h, a, b, c, d, e, f, k[10], w[10] ); + R( f, g, h, a, b, c, d, e, k[11], w[11] ); + R( e, f, g, h, a, b, c, d, k[12], w[12] ); + R( d, e, f, g, h, a, b, c, k[13], w[13] ); + R( c, d, e, f, g, h, a, b, k[14], w[14] ); + R( b, c, d, e, f, g, h, a, k[15], w[15] ); + R( a, b, c, d, e, f, g, h, k[16], M(16) ); + R( h, a, b, c, d, e, f, g, k[17], M(17) ); + R( g, h, a, b, c, d, e, f, k[18], M(18) ); + R( f, g, h, a, b, c, d, e, k[19], M(19) ); + R( e, f, g, h, a, b, c, d, k[20], M(20) ); + R( d, e, f, g, h, a, b, c, k[21], M(21) ); + R( c, d, e, f, g, h, a, b, k[22], M(22) ); + R( b, c, d, e, f, g, h, a, k[23], M(23) ); + R( a, b, c, d, e, f, g, h, k[24], M(24) ); + R( h, a, b, c, d, e, f, g, k[25], M(25) ); + R( g, h, a, b, c, d, e, f, k[26], M(26) ); + R( f, g, h, a, b, c, d, e, k[27], M(27) ); + R( e, f, g, h, a, b, c, d, k[28], M(28) ); + R( d, e, f, g, h, a, b, c, k[29], M(29) ); + R( c, d, e, f, g, h, a, b, k[30], M(30) ); + R( b, c, d, e, f, g, h, a, k[31], M(31) ); + R( a, b, c, d, e, f, g, h, k[32], M(32) ); + R( h, a, b, c, d, e, f, g, k[33], M(33) ); + R( g, h, a, b, c, d, e, f, k[34], M(34) ); + R( f, g, h, a, b, c, d, e, k[35], M(35) ); + R( e, f, g, h, a, b, c, d, k[36], M(36) ); + R( d, e, f, g, h, a, b, c, k[37], M(37) ); + R( c, d, e, f, g, h, a, b, k[38], M(38) ); + R( b, c, d, e, f, g, h, a, k[39], M(39) ); + R( a, b, c, d, e, f, g, h, k[40], M(40) ); + R( h, a, b, c, d, e, f, g, k[41], M(41) ); + R( g, h, a, b, c, d, e, f, k[42], M(42) ); + R( f, g, h, a, b, c, d, e, k[43], M(43) ); + R( e, f, g, h, a, b, c, d, k[44], M(44) ); + R( d, e, f, g, h, a, b, c, k[45], M(45) ); + R( c, d, e, f, g, h, a, b, k[46], M(46) ); + R( b, c, d, e, f, g, h, a, k[47], M(47) ); + R( a, b, c, d, e, f, g, h, k[48], M(48) ); + R( h, a, b, c, d, e, f, g, k[49], M(49) ); + R( g, h, a, b, c, d, e, f, k[50], M(50) ); + R( f, g, h, a, b, c, d, e, k[51], M(51) ); + R( e, f, g, h, a, b, c, d, k[52], M(52) ); + R( d, e, f, g, h, a, b, c, k[53], M(53) ); + R( c, d, e, f, g, h, a, b, k[54], M(54) ); + R( b, c, d, e, f, g, h, a, k[55], M(55) ); + R( a, b, c, d, e, f, g, h, k[56], M(56) ); + R( h, a, b, c, d, e, f, g, k[57], M(57) ); + R( g, h, a, b, c, d, e, f, k[58], M(58) ); + R( f, g, h, a, b, c, d, e, k[59], M(59) ); + R( e, f, g, h, a, b, c, d, k[60], M(60) ); + R( d, e, f, g, h, a, b, c, k[61], M(61) ); + R( c, d, e, f, g, h, a, b, k[62], M(62) ); + R( b, c, d, e, f, g, h, a, k[63], M(63) ); + + 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; + /* 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; +} - buf.mem = data; - buf.len = len; +void +sha256_ctx_update + (struct sha256_ctx* ctx, + const char* bytes, + size_t len) +{ + size_t n; + uint32_t i; + ASSERT(ctx); + ASSERT(bytes || !len); + + if(ctx->len) { + n = MMIN(64 - ctx->len, len); + memcpy(ctx->chunk + ctx->len, bytes, n); + ctx->len += (uint32_t)n; + bytes += n; + len -= n; + + if(ctx->len == 64) { + sha256_process_chunk(ctx, ctx->chunk); + ctx->nbits += 512; + ctx->len = 0; + } + } - desc.get_chunk512 = get_chunk512; - desc.size = len; - desc.context = &buf; + if(len >= 64) { + n = len / 64; + FOR_EACH(i, 0, n) { + sha256_process_chunk(ctx, bytes); + bytes += 64; + } + ctx->nbits += n * 512; + len -= n * 64; + } - hash_sha256_chunked_data(&desc, hash); + if(len) { + memcpy(ctx->chunk, bytes, len); + ctx->len = (uint32_t)len; + } } 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, ctx->chunk); + 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, ctx->chunk); + + /* 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