cOMS/hash/Sha1.h
Dennis Eichhorn dc9f37b726
Some checks failed
CodeQL / Analyze (${{ matrix.language }}) (autobuild, c-cpp) (push) Has been cancelled
Microsoft C++ Code Analysis / Analyze (push) Has been cancelled
update
2025-04-06 10:34:47 +00:00

171 lines
4.4 KiB
C

/**
* Jingga
*
* @copyright Jingga
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
#ifndef COMS_HASH_SHA1_H
#define COMS_HASH_SHA1_H
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "../stdlib/Types.h"
#include "../stdlib/Simd.h"
#include "Sha1Definitions.h"
#ifdef __SSE4_2__
#include "Sha1SimdX86.h"
#elif defined(__ARM_FEATURE_SVE) || defined(__ARM_NEON)
#include "Sha1SimdArm.h"
#else
static
void sha1_transform(SHA1_CTX *ctx, const byte data[64], [[mayb_unused]] int32 steps) {
uint32 a, b, c, d, e, temp;
uint32 w[80];
for (int i = 0; i < 16; i++) {
w[i] = ((uint32)data[i * 4 + 0] << 24) |
((uint32)data[i * 4 + 1] << 16) |
((uint32)data[i * 4 + 2] << 8) |
((uint32)data[i * 4 + 3]);
}
for (int i = 16; i < 80; i++) {
temp = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16];
w[i] = (temp << 1) | (temp >> 31);
}
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
// Main compression loop - unrolled for better performance
// Round 1 (0-19)
for (int i = 0; i < 20; i++) {
temp = SHA1_ROTL32(a, 5) + SHA1_Ch(b, c, d) + e + K1 + w[i];
e = d;
d = c;
c = SHA1_ROTL32(b, 30);
b = a;
a = temp;
}
// Round 2 (20-39)
for (int i = 20; i < 40; i++) {
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K2 + w[i];
e = d;
d = c;
c = SHA1_ROTL32(b, 30);
b = a;
a = temp;
}
// Round 3 (40-59)
for (int i = 40; i < 60; i++) {
temp = SHA1_ROTL32(a, 5) + SHA1_Maj(b, c, d) + e + K3 + w[i];
e = d;
d = c;
c = SHA1_ROTL32(b, 30);
b = a;
a = temp;
}
// Round 4 (60-79)
for (int i = 60; i < 80; i++) {
temp = SHA1_ROTL32(a, 5) + SHA1_Parity(b, c, d) + e + K4 + w[i];
e = d;
d = c;
c = SHA1_ROTL32(b, 30);
b = a;
a = temp;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
}
#endif
void sha1_init(SHA1_CTX* ctx) {
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
ctx->count = 0;
}
static
void sha1_update(SHA1_CTX* ctx, const byte* data, size_t len, int32 steps) {
size_t i, index, part_len;
index = (size_t)((ctx->count >> 3) & 0x3F);
ctx->count += len << 3;
part_len = 64 - index;
if (len >= part_len) {
memcpy(&ctx->buffer[index], data, part_len);
sha1_transform(ctx, ctx->buffer, steps);
for (i = part_len; i + 63 < len; i += 64) {
sha1_transform(ctx, &data[i], steps);
}
index = 0;
} else {
i = 0;
}
memcpy(&ctx->buffer[index], &data[i], len - i);
}
static
void sha1_final(SHA1_CTX* ctx, byte digest[20], int32 steps) {
byte bits[8];
uint32 index, pad_len;
for (int32 i = 0; i < 8; i++) {
bits[i] = (byte) ((ctx->count >> ((7 - i) * 8)) & 0xFF);
}
index = (uint32)((ctx->count >> 3) & 0x3F);
pad_len = (index < 56) ? (56 - index) : (120 - index);
sha1_update(ctx, (const byte*) "\x80", 1, steps);
while (pad_len-- > 1) {
sha1_update(ctx, (const byte*) "\0", 1, steps);
}
sha1_update(ctx, bits, 8, steps);
for (int32 i = 0; i < 5; i++) {
digest[i*4+0] = (byte) ((ctx->state[i] >> 24) & 0xFF);
digest[i*4+1] = (byte) ((ctx->state[i] >> 16) & 0xFF);
digest[i*4+2] = (byte) ((ctx->state[i] >> 8) & 0xFF);
digest[i*4+3] = (byte) ( ctx->state[i] & 0xFF);
}
// WARNING: We are not doing this since no sensitive data should use sha1 anyways
// Normally this would be done to reduce side channel attacks
// memset(ctx, 0, sizeof(*ctx));
}
inline
void sha1_hash(const byte* data, size_t len, byte digest[20], int32 steps = 16) {
SHA1_CTX ctx;
sha1_init(&ctx);
steps = intrin_validate_steps(data, steps);
sha1_update(&ctx, data, len, steps);
sha1_final(&ctx, digest, steps);
}
#endif