rsys

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

commit 2c9e1acf5c593a343d6576877895111a23548505
parent 639e6c20097f82c766d8c0f94c609705ff59359e
Author: vaplv <vaplv@free.fr>
Date:   Fri, 11 Sep 2020 11:56:10 +0200

Implement the sha256 hash function

Diffstat:
Mcmake/CMakeLists.txt | 1+
Asrc/hash.c | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/hash.h | 20++++++++++++++++++++
3 files changed, 207 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -45,6 +45,7 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(RSYS_FILES_SRC clock_time.c cstr.c + hash.c image.c library.c logger.c diff --git a/src/hash.c b/src/hash.c @@ -0,0 +1,186 @@ +/* Copyright (C) 2013-2020 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200112L + +#include "endianness.h" +#include "hash.h" +#include "mem_allocator.h" + +#include <string.h> + +/* 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] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 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); +} + +static size_t +create_msg + (struct mem_allocator* allocator, + const void* data, + const size_t len, + char** out_msg) +{ + 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)0x80; + /* 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 bug 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; +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +hash_sha256 + (struct mem_allocator* mem_allocator, + const void* data, + const size_t len, + hash256_T hash) +{ + struct mem_allocator* allocator = NULL; + char* msg = NULL; + size_t msg_sz = 0; + size_t ichunk = 0; + size_t nchunks = 0; + res_T res = RES_OK; + + /* 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(hash); + + allocator = mem_allocator ? mem_allocator : &mem_default_allocator; + + msg_sz = create_msg(allocator, data, len, &msg); + if(!msg) { res = RES_MEM_ERR; goto error; } + + ASSERT((msg_sz % 64) == 0); + nchunks = msg_sz / 64; /* #chunks of 512 bits */ + + FOR_EACH(ichunk, 0, nchunks) { + const char* chunk = msg + ichunk*64; + 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; + + 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; + } + + /* 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; + } + + /* Update hash with the current compressed chunk */ + h0+=a; h1+=b; h2+=c; h3+=d; h4+=e; h5+=f; h6+=g; h7+=h; + } + + /* 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); + +exit: + if(msg) MEM_RM(allocator, msg); + return res; +error: + goto exit; +} + +void +hash256_to_cstr(const hash256_T hash, char cstr[65]) +{ + size_t i; + ASSERT(hash && cstr); + FOR_EACH(i, 0, sizeof(hash256_T)) { + sprintf(cstr+i*2, "%02x", (uint8_t)hash[i]); + } +} + diff --git a/src/hash.h b/src/hash.h @@ -18,6 +18,10 @@ #include "rsys.h" +struct mem_allocator; + +typedef char hash256_T[32]; + /* 32-bits Fowler/Noll/Vo hash function */ static INLINE uint32_t hash_fnv32(const void* data, const size_t len) @@ -56,5 +60,21 @@ hash_fnv64(const void* data, const size_t len) return hash; } +BEGIN_DECLS + +RSYS_API res_T +hash_sha256 + (struct mem_allocator* allocator, + const void* data, + const size_t len, + hash256_T hash); + +RSYS_API void +hash256_to_cstr + (const hash256_T hash, + char cstr[65]); + +END_DECLS + #endif /* HASH_H */