Skip to content

Instantly share code, notes, and snippets.

@resilar
Last active February 15, 2024 14:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save resilar/a10e01c6a244d701cf45a57885a6c867 to your computer and use it in GitHub Desktop.
Save resilar/a10e01c6a244d701cf45a57885a6c867 to your computer and use it in GitHub Desktop.
SHA-512 C implementation
#include "sha512.h"
#define ROR64(x, c) (((x) >> (c)) | ((x) << (64 - (c))))
#define LOAD64_BE(p) \
( ((uint64_t)((p)[7]) << 0) \
| ((uint64_t)((p)[6]) << 8) \
| ((uint64_t)((p)[5]) << 16) \
| ((uint64_t)((p)[4]) << 24) \
| ((uint64_t)((p)[3]) << 32) \
| ((uint64_t)((p)[2]) << 40) \
| ((uint64_t)((p)[1]) << 48) \
| ((uint64_t)((p)[0]) << 56) \
)
#define STORE64_BE(p, v) \
(p)[7] = ((v) >> 0) & 0xFF; \
(p)[6] = ((v) >> 8) & 0xFF; \
(p)[5] = ((v) >> 16) & 0xFF; \
(p)[4] = ((v) >> 24) & 0xFF; \
(p)[3] = ((v) >> 32) & 0xFF; \
(p)[2] = ((v) >> 40) & 0xFF; \
(p)[1] = ((v) >> 48) & 0xFF; \
(p)[0] = ((v) >> 56) & 0xFF;
void sha512_init(struct sha512 *ctx)
{
ctx->state[0] = 0x6a09e667f3bcc908; /* sqrt(2) */
ctx->state[1] = 0xbb67ae8584caa73b; /* sqrt(3) */
ctx->state[2] = 0x3c6ef372fe94f82b; /* sqrt(5) */
ctx->state[3] = 0xa54ff53a5f1d36f1; /* sqrt(7) */
ctx->state[4] = 0x510e527fade682d1; /* sqrt(11) */
ctx->state[5] = 0x9b05688c2b3e6c1f; /* sqrt(13) */
ctx->state[6] = 0x1f83d9abfb41bd6b; /* sqrt(17) */
ctx->state[7] = 0x5be0cd19137e2179; /* sqrt(19) */
ctx->bits[0] = ctx->bits[1] = 0;
ctx->n = 0;
}
static void sha512_block(uint64_t state[8], const uint8_t p[128])
{
uint64_t a, b, c, d, e, f, g, h, s0, s1, S0, S1, t1, t2, w[16];
static const uint64_t K512[80] = {
0x428a2f98d728ae22, 0x7137449123ef65cd,
0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019,
0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe,
0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1,
0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483,
0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210,
0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725,
0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926,
0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8,
0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001,
0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910,
0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60,
0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9,
0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207,
0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6,
0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493,
0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
0x5fcb6fab3ad6faec, 0x6c44198c4a475817
};
a = state[0]; b = state[1]; c = state[2]; d = state[3];
e = state[4]; f = state[5]; g = state[6]; h = state[7];
#define ROUND_CORE(i) \
S0 = ROR64(a, 28) ^ ROR64(a, 34) ^ ROR64(a, 39); \
S1 = ROR64(e, 14) ^ ROR64(e, 18) ^ ROR64(e, 41); \
t1 = h + S1 + ((e & f) ^ (~e & g)) + K512[i] + w[i & 0xf]; \
t2 = S0 + ((a & b) ^ (a & c) ^ (b & c)); \
h = g; g = f; f = e; e = d + t1; \
d = c; c = b; b = a; a = t1 + t2;
#define ROUND_0_15(i) w[i] = LOAD64_BE(p); p += 8; ROUND_CORE(i)
ROUND_0_15( 0) ROUND_0_15( 1) ROUND_0_15( 2) ROUND_0_15( 3)
ROUND_0_15( 4) ROUND_0_15( 5) ROUND_0_15( 6) ROUND_0_15( 7)
ROUND_0_15( 8) ROUND_0_15( 9) ROUND_0_15(10) ROUND_0_15(11)
ROUND_0_15(12) ROUND_0_15(13) ROUND_0_15(14) ROUND_0_15(15)
#undef ROUND_0_15
#define ROUND_16_79(i) \
s0 = w[(i + 1) & 0xf]; s1 = w[(i + 14) & 0xf]; \
s0 = ROR64(s0, 1) ^ ROR64(s0, 8) ^ (s0 >> 7); \
s1 = ROR64(s1, 19) ^ ROR64(s1, 61) ^ (s1 >> 6); \
w[i & 0xf] += s0 + s1 + w[(i + 9) & 0xf]; ROUND_CORE(i)
ROUND_16_79(16) ROUND_16_79(17) ROUND_16_79(18) ROUND_16_79(19)
ROUND_16_79(20) ROUND_16_79(21) ROUND_16_79(22) ROUND_16_79(23)
ROUND_16_79(24) ROUND_16_79(25) ROUND_16_79(26) ROUND_16_79(27)
ROUND_16_79(28) ROUND_16_79(29) ROUND_16_79(30) ROUND_16_79(31)
ROUND_16_79(32) ROUND_16_79(33) ROUND_16_79(34) ROUND_16_79(35)
ROUND_16_79(36) ROUND_16_79(37) ROUND_16_79(38) ROUND_16_79(39)
ROUND_16_79(40) ROUND_16_79(41) ROUND_16_79(42) ROUND_16_79(43)
ROUND_16_79(44) ROUND_16_79(45) ROUND_16_79(46) ROUND_16_79(47)
ROUND_16_79(48) ROUND_16_79(49) ROUND_16_79(50) ROUND_16_79(51)
ROUND_16_79(52) ROUND_16_79(53) ROUND_16_79(54) ROUND_16_79(55)
ROUND_16_79(56) ROUND_16_79(57) ROUND_16_79(58) ROUND_16_79(59)
ROUND_16_79(60) ROUND_16_79(61) ROUND_16_79(62) ROUND_16_79(63)
ROUND_16_79(64) ROUND_16_79(65) ROUND_16_79(66) ROUND_16_79(67)
ROUND_16_79(68) ROUND_16_79(69) ROUND_16_79(70) ROUND_16_79(71)
ROUND_16_79(72) ROUND_16_79(73) ROUND_16_79(74) ROUND_16_79(75)
ROUND_16_79(76) ROUND_16_79(77) ROUND_16_79(78) ROUND_16_79(79)
#undef ROUND_16_79
#undef ROUND_CORE
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 sha512_update(struct sha512 *ctx, const void *data, size_t n)
{
const uint8_t *input = data;
if (ctx->n || n < 128) {
while (n && ctx->n < 128) {
ctx->buffer[ctx->n++] = *input++;
n--;
}
if (ctx->n < 128)
return;
sha512_block(ctx->state, ctx->buffer);
ctx->bits[1] += !(ctx->bits[0] += 1024);
ctx->n = 0;
}
while (n >= 128) {
sha512_block(ctx->state, input);
ctx->bits[1] += !(ctx->bits[0] += 1024);
input += 128;
n -= 128;
}
while (n) {
ctx->buffer[ctx->n++] = *input++;
n--;
}
}
void sha512_final(struct sha512 *ctx, uint8_t hash[64])
{
int i;
uint8_t buf[256];
ctx->bits[0] += ctx->n * 8;
for (i = 1, buf[0] = 0x80; (ctx->n + i + 16) % 128; buf[i++] = 0);
STORE64_BE(buf + i, ctx->bits[1]);
STORE64_BE(buf + i + 8, ctx->bits[0]);
sha512_update(ctx, buf, i + 16);
STORE64_BE(hash + 0, ctx->state[0]);
STORE64_BE(hash + 8, ctx->state[1]);
STORE64_BE(hash + 16, ctx->state[2]);
STORE64_BE(hash + 24, ctx->state[3]);
STORE64_BE(hash + 32, ctx->state[4]);
STORE64_BE(hash + 40, ctx->state[5]);
STORE64_BE(hash + 48, ctx->state[6]);
STORE64_BE(hash + 56, ctx->state[7]);
}
void sha512(const void *data, size_t n, uint8_t hash[64])
{
struct sha512 ctx;
sha512_init(&ctx);
sha512_update(&ctx, data, n);
sha512_final(&ctx, hash);
}
#ifndef SHA512_H
#define SHA512_H
#include <stddef.h>
#include <stdint.h>
struct sha512 {
uint64_t state[8];
uint8_t buffer[128];
uint64_t bits[2];
int n;
};
void sha512_init(struct sha512 *ctx);
void sha512_update(struct sha512 *ctx, const void *data, size_t n);
void sha512_final(struct sha512 *ctx, uint8_t hash[64]);
void sha512(const void *data, size_t n, uint8_t hash[64]);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment