commit 2c9e1acf5c593a343d6576877895111a23548505
parent 639e6c20097f82c766d8c0f94c609705ff59359e
Author: vaplv <vaplv@free.fr>
Date: Fri, 11 Sep 2020 11:56:10 +0200
Implement the sha256 hash function
Diffstat:
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 */