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:
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;
+}