#include "semq_sha256.h"
#include "core/semq_dispatch.h"
#include <string.h>
#include "semq.h"
const uint32_t semqi_sha256_k[64] = {
0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u, 0x3956c25bu, 0x59f111f1u,
0x923f82a4u, 0xab1c5ed5u, 0xd807aa98u, 0x12835b01u, 0x243185beu, 0x550c7dc3u,
0x72be5d74u, 0x80deb1feu, 0x9bdc06a7u, 0xc19bf174u, 0xe49b69c1u, 0xefbe4786u,
0x0fc19dc6u, 0x240ca1ccu, 0x2de92c6fu, 0x4a7484aau, 0x5cb0a9dcu, 0x76f988dau,
0x983e5152u, 0xa831c66du, 0xb00327c8u, 0xbf597fc7u, 0xc6e00bf3u, 0xd5a79147u,
0x06ca6351u, 0x14292967u, 0x27b70a85u, 0x2e1b2138u, 0x4d2c6dfcu, 0x53380d13u,
0x650a7354u, 0x766a0abbu, 0x81c2c92eu, 0x92722c85u, 0xa2bfe8a1u, 0xa81a664bu,
0xc24b8b70u, 0xc76c51a3u, 0xd192e819u, 0xd6990624u, 0xf40e3585u, 0x106aa070u,
0x19a4c116u, 0x1e376c08u, 0x2748774cu, 0x34b0bcb5u, 0x391c0cb3u, 0x4ed8aa4au,
0x5b9cca4fu, 0x682e6ff3u, 0x748f82eeu, 0x78a5636fu, 0x84c87814u, 0x8cc70208u,
0x90befffau, 0xa4506cebu, 0xbef9a3f7u, 0xc67178f2u
};
static inline uint32_t rotr(uint32_t x, uint32_t n) {
return (x >> n) | (x << (32u - n));
}
static void sha256_block_scalar(uint32_t state[8], const uint8_t block[64]) {
uint32_t w[64];
for (size_t i = 0u; i < 16u; i++) {
w[i] = ((uint32_t)block[i * 4u] << 24) | ((uint32_t)block[i * 4u + 1u] << 16)
| ((uint32_t)block[i * 4u + 2u] << 8) | (uint32_t)block[i * 4u + 3u];
}
for (uint32_t i = 16u; i < 64u; i++) {
const uint32_t s0 = rotr(w[i - 15u], 7) ^ rotr(w[i - 15u], 18) ^ (w[i - 15u] >> 3);
const uint32_t s1 = rotr(w[i - 2u], 17) ^ rotr(w[i - 2u], 19) ^ (w[i - 2u] >> 10);
w[i] = w[i - 16u] + s0 + w[i - 7u] + s1;
}
uint32_t a = state[0], b = state[1], c = state[2], d = state[3];
uint32_t e = state[4], f = state[5], g = state[6], h = state[7];
for (uint32_t i = 0u; i < 64u; i++) {
const uint32_t S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
const uint32_t ch = (e & f) ^ (~e & g);
const uint32_t t1 = h + S1 + ch + semqi_sha256_k[i] + w[i];
const uint32_t S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
const uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
const uint32_t t2 = S0 + maj;
h = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
state[0] += a; state[1] += b; state[2] += c; state[3] += d;
state[4] += e; state[5] += f; state[6] += g; state[7] += h;
}
void semq_sha256_init(semq_sha256_ctx_t* ctx) {
ctx->state[0] = 0x6a09e667u; ctx->state[1] = 0xbb67ae85u;
ctx->state[2] = 0x3c6ef372u; ctx->state[3] = 0xa54ff53au;
ctx->state[4] = 0x510e527fu; ctx->state[5] = 0x9b05688cu;
ctx->state[6] = 0x1f83d9abu; ctx->state[7] = 0x5be0cd19u;
ctx->bit_len = 0u;
ctx->buffered = 0u;
ctx->sha_checked = 0u;
ctx->block = sha256_block_scalar;
}
void semq_sha256_update(semq_sha256_ctx_t* ctx, const uint8_t* data, size_t len) {
ctx->bit_len += (uint64_t)len * 8u;
#if defined(__aarch64__) || defined(_M_ARM64)
if (!ctx->sha_checked && ctx->bit_len >= UINT64_C(512) * 8u) {
ctx->sha_checked = 1u;
if (semq_dispatch_has_sha256()) ctx->block = semqi_sha256_block_arm;
}
#endif
if (ctx->buffered > 0u) {
const size_t take = (64u - ctx->buffered < len) ? (64u - ctx->buffered) : len;
memcpy(ctx->buffer + ctx->buffered, data, take);
ctx->buffered += (uint32_t)take;
data += take;
len -= take;
if (ctx->buffered == 64u) {
ctx->block(ctx->state, ctx->buffer);
ctx->buffered = 0u;
}
}
while (len >= 64u) {
ctx->block(ctx->state, data);
data += 64u;
len -= 64u;
}
if (len > 0u) {
memcpy(ctx->buffer, data, len);
ctx->buffered = (uint32_t)len;
}
}
void semq_sha256_final(semq_sha256_ctx_t* ctx, uint8_t out[32]) {
const uint64_t bits = ctx->bit_len;
uint8_t pad[72];
memset(pad, 0, sizeof(pad));
pad[0] = 0x80u;
const uint32_t pad_len = (ctx->buffered < 56u) ? (56u - ctx->buffered) : (120u - ctx->buffered);
uint8_t len_be[8];
for (uint32_t i = 0u; i < 8u; i++) {
len_be[i] = (uint8_t)(bits >> (56u - 8u * i));
}
const uint64_t saved = ctx->bit_len;
semq_sha256_update(ctx, pad, pad_len);
semq_sha256_update(ctx, len_be, 8u);
ctx->bit_len = saved;
for (size_t i = 0u; i < 8u; i++) {
out[i * 4u] = (uint8_t)(ctx->state[i] >> 24);
out[i * 4u + 1u] = (uint8_t)(ctx->state[i] >> 16);
out[i * 4u + 2u] = (uint8_t)(ctx->state[i] >> 8);
out[i * 4u + 3u] = (uint8_t)(ctx->state[i]);
}
}
SEMQ_API void semq_sha256(const uint8_t* data, uint64_t len, uint8_t out[32]) {
semq_sha256_ctx_t ctx;
semq_sha256_init(&ctx);
while (len > 0u) {
const size_t chunk = (len > (uint64_t)SIZE_MAX) ? SIZE_MAX : (size_t)len;
semq_sha256_update(&ctx, data, chunk);
data += chunk;
len -= chunk;
}
semq_sha256_final(&ctx, out);
}