rsys

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

commit b58c9194ac485500091749888a601f4198f285bf
parent 0abee385cd516bb0cbcd784affddb0d445911683
Author: vaplv <vaplv@free.fr>
Date:   Fri, 11 Sep 2020 11:59:11 +0200

Merge branch 'feature_sha256' into develop

Diffstat:
Mcmake/CMakeLists.txt | 4++++
Asrc/endianness.h | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/hash.c | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/hash.h | 20++++++++++++++++++++
Asrc/test_endianness.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_hash_sha256.c | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 506 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 @@ -90,6 +91,7 @@ set(RSYS_FILES_INC_API dynamic_array_uint.h dynamic_array_size_t.h dynamic_array_str.h + endianness.h float2.h float3.h float4.h @@ -209,6 +211,7 @@ if(NOT NO_TEST) new_test(test_double22) new_test(test_double33 ${MATH_LIB}) new_test(test_double44) + new_test(test_endianness) new_test(test_dynamic_array rsys) new_test(test_float2 ${MATH_LIB}) new_test(test_float3 ${MATH_LIB}) @@ -219,6 +222,7 @@ if(NOT NO_TEST) new_test(test_free_list rsys) new_test(test_func_name) new_test(test_hash_table rsys) + new_test(test_hash_sha256 rsys) new_test(test_image rsys) new_test(test_library rsys) new_test(test_list rsys) diff --git a/src/endianness.h b/src/endianness.h @@ -0,0 +1,126 @@ +/* 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/>. */ + +#ifndef ENDIANNESS_H +#define ENDIANNESS_H + +#include "rsys.h" + +#if defined(COMPILER_GCC) + #define BYTE_ORDER __BYTE_ORDER__ + #define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ + #define BIG_ENDIAN __ORDER_BIG_ENDIAN__ + #include <byteswap.h> +#elif + #include <Windows.h> + #define BYTE_ORDER REG_DWORD + #define LITTLE_ENDIAN REG_DWORD_LITTLE_ENDIAN + #define BIG_ENDIAN REG_DWORD_BIG_ENDIAN +#else + #error "Undefined byte ordering macros" +#endif + +#ifdef COMPILER_GCC +static FINLINE uint16_t byte_swap_16(const uint16_t ui) { return bswap_16(ui); } +static FINLINE uint32_t byte_swap_32(const uint32_t ui) { return bswap_32(ui); } +static FINLINE uint64_t byte_swap_64(const uint64_t ui) { return bswap_64(ui); } + +#elif defined COMPILER_CL +static FINLINE uint16_t +byte_swap_16(const uint16_t ui) +{ + STATIC_ASSERT(sizeof(unsigned short) == sizeof(uint16_t), + Unexpected_sizeof_ushort); + return _byteswap_ushort(ui); +} + +static FINLINE uint32_t +byte_swap_32(const uint32_t ui) +{ + STATIC_ASSERT(sizeof(unsigned long) == sizeof(uint32_t), + Unexpected_sizeof_ushort); + return _byteswap_ulong(ui); +} + +static FINLINE uint64_t +byte_swap_64(const uint64_t ui) +{ + STATIC_ASSERT(sizeof(unsigned long) == sizeof(uint64_t), + Unexpected_sizeof_ulong); + return _byteswap_uint64(ui); +} +#endif + +static FINLINE uint16_t +little_endian_16(const uint16_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return ui; +#elif BYTE_ORDER == BIG_ENDIAN + return byte_swap_16(ui); +#endif +} + +static FINLINE uint32_t +little_endian_32(const uint32_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return ui; +#elif BYTE_ORDER == BIG_ENDIAN + return byte_swap_32(ui); +#endif +} + +static FINLINE uint64_t +little_endian_64(const uint64_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return ui; +#elif BYTE_ORDER == BIG_ENDIAN + return byte_swap_64(ui); +#endif +} + +static FINLINE uint16_t +big_endian_16(const uint16_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return byte_swap_16(ui); +#elif BYTE_ORDER == BIG_ENDIAN + return ui; +#endif +} + +static FINLINE uint32_t +big_endian_32(const uint32_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return byte_swap_32(ui); +#elif BYTE_ORDER == BIG_ENDIAN + return ui; +#endif +} + +static FINLINE uint64_t +big_endian_64(const uint64_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return byte_swap_64(ui); +#elif BYTE_ORDER == BIG_ENDIAN + return ui; +#endif +} + +#endif /* ENDIANNESS_H */ 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 */ diff --git a/src/test_endianness.c b/src/test_endianness.c @@ -0,0 +1,51 @@ +/* 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/>. */ + +#include "endianness.h" + +int +main(int argc, char** argv) +{ + uint16_t ui16 = 0x0123; + uint32_t ui32 = 0x01234567; + uint64_t ui64 = 0x0123456789ABCDEF; + (void)argc, (void)argv; + + CHK(byte_swap_16(ui16) == 0x2301); + CHK(byte_swap_32(ui32) == 0x67452301); + CHK(byte_swap_64(ui64) == 0xEFCDAB8967452301); + +#if BYTE_ORDER == LITTLE_ENDIAN + CHK(little_endian_16(ui16) == ui16); + CHK(little_endian_32(ui32) == ui32); + CHK(little_endian_64(ui64) == ui64); + CHK(big_endian_16(ui16) == byte_swap_16(ui16)); + CHK(big_endian_32(ui32) == byte_swap_32(ui32)); + CHK(big_endian_64(ui64) == byte_swap_64(ui64)); + +#elif BYTE_ORDER == BIG_ENDIAN + CHK(little_endian_16(ui16) == byte_swap_16(ui16)); + CHK(little_endian_32(ui32) == byte_swap_32(ui32)); + CHK(little_endian_64(ui64) == byte_swap_64(ui64)); + CHK(big_endian_16(ui16) == ui16); + CHK(big_endian_32(ui32) == ui32); + CHK(big_endian_64(ui64) == ui64); + +#else + #error "Undefined endianness" +#endif + + return 0; +} diff --git a/src/test_hash_sha256.c b/src/test_hash_sha256.c @@ -0,0 +1,119 @@ +/* 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/>. */ + +#include "hash.h" +#include "mem_allocator.h" +#include <string.h> + +struct test_str { + const char* str; + const char* sha256sum; +}; +struct test_data { + const void* mem; + const size_t len; + const char* sha256sum; +}; + +static void +chk_hash(const void* data, const size_t data_len, const char* sha256sum) +{ + hash256_T hash; + char hash_str[65]; + ASSERT(sha256sum); + CHK(hash_sha256(NULL, data, data_len, hash) == RES_OK); + hash256_to_cstr(hash, hash_str); + CHK(!strcmp(hash_str, sha256sum)); +} + +int +main(int argc, char** argv) +{ + char* data = NULL; + (void)argc, (void)argv; + + CHK(data = mem_alloc(0x6000003e)); + + data[0] = '\0'; + chk_hash(data, 0, + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + + sprintf(data, "abc"); + chk_hash(data, strlen(data), + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + + sprintf(data, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); + chk_hash(data, strlen(data), + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); + + data[0] = (char)0xbd; + chk_hash(data, 1, + "68325720aabd7c82f30f554b313d0570c95accbb7dc4b5aae11204c08ffe732b"); + + data[0] = (char)0xc9; + data[1] = (char)0x8c; + data[2] = (char)0x8e; + data[3] = (char)0x55; + chk_hash(data, 4, + "7abc22c0ae5af26ce93dbb94433a0e0b2e119d014f8e7f65bd56c61ccccd9504"); + + memset(data, 0, 55); + chk_hash(data, 55, + "02779466cdec163811d078815c633f21901413081449002f24aa3e80f0b88ef7"); + + memset(data, 0, 56); + chk_hash(data, 56, + "d4817aa5497628e7c77e6b606107042bbba3130888c5f47a375e6179be789fbb"); + + memset(data, 0, 57); + chk_hash(data, 57, + "65a16cb7861335d5ace3c60718b5052e44660726da4cd13bb745381b235a1785"); + + memset(data, 0, 64); + chk_hash(data, 64, + "f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b"); + + memset(data, 0, 1000); + chk_hash(data, 1000, + "541b3e9daa09b20bf85fa273e5cbd3e80185aa4ec298e765db87742b70138a53"); + + memset(data, 'A', 1000); + chk_hash(data, 1000, + "c2e686823489ced2017f6059b8b239318b6364f6dcd835d0a519105a1eadd6e4"); + + memset(data, 'U', 1005); + chk_hash(data, 1005, + "f4d62ddec0f3dd90ea1380fa16a5ff8dc4c54b21740650f24afc4120903552b0"); + + memset(data, 0, 1000000); + chk_hash(data, 1000000, + "d29751f2649b32ff572b5e0a9f541ea660a50f94ff0beedfb0b692b924cc8025"); + + memset(data, 'Z', 0x20000000); + chk_hash(data, 0x20000000, + "15a1868c12cc53951e182344277447cd0979536badcc512ad24c67e9b2d4f3dd"); + + memset(data, 0, 0x41000000); + chk_hash(data, 0x41000000, + "461c19a93bd4344f9215f5ec64357090342bc66b15a148317d276e31cbc20b53"); + + memset(data, 'B', 0x6000003e); + chk_hash(data, 0x6000003e, + "c23ce8a7895f4b21ec0daf37920ac0a262a220045a03eb2dfed48ef9b05aabea"); + + mem_rm(data); + CHK(mem_allocated_size() == 0); + return 0; +}