blob: 34708000aa33a165552af7b6e06f19d5b17aeacf [file] [log] [blame]
/*********************************************************************
* Filename: sha256.h / sha256.c (combined header-only)
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding SHA-256 implementation.
* SHA-256 is one of the three algorithms in the SHA2
* specification. The others, SHA-384 and SHA-512, are not
* offered in this implementation.
* Algorithm specification can be found here:
* * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
* This implementation uses little endian byte order.
*
* Source: https://github.com/B-Con/crypto-algorithms
* Public domain — no copyright claimed by the author.
*
* Modifications for Apache Thrift:
* - Combined .h and .c into a single header-only file.
* - Added C++ wrapper (thrift_generator::sha256) returning std::vector<uint8_t>.
* - No algorithmic changes.
*********************************************************************/
#pragma once
#include <cstring>
#include <string>
#include <vector>
#include <cstdint>
#include <cstddef>
/****************************** MACROS ******************************/
#define THRIFT_SHA256_ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
#define THRIFT_SHA256_ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
#define THRIFT_SHA256_CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define THRIFT_SHA256_MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define THRIFT_SHA256_EP0(x) (THRIFT_SHA256_ROTRIGHT(x,2) ^ THRIFT_SHA256_ROTRIGHT(x,13) ^ THRIFT_SHA256_ROTRIGHT(x,22))
#define THRIFT_SHA256_EP1(x) (THRIFT_SHA256_ROTRIGHT(x,6) ^ THRIFT_SHA256_ROTRIGHT(x,11) ^ THRIFT_SHA256_ROTRIGHT(x,25))
#define THRIFT_SHA256_SIG0(x) (THRIFT_SHA256_ROTRIGHT(x,7) ^ THRIFT_SHA256_ROTRIGHT(x,18) ^ ((x) >> 3))
#define THRIFT_SHA256_SIG1(x) (THRIFT_SHA256_ROTRIGHT(x,17) ^ THRIFT_SHA256_ROTRIGHT(x,19) ^ ((x) >> 10))
/**************************** DATA TYPES ****************************/
#define THRIFT_SHA256_BLOCK_SIZE 32
typedef struct {
unsigned char data[64];
unsigned int datalen;
unsigned long long bitlen;
unsigned int state[8];
} THRIFT_SHA256_CTX;
/**************************** VARIABLES *****************************/
// clang-format off
static const unsigned int thrift_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
};
// clang-format on
/*********************** FUNCTION DEFINITIONS ***********************/
inline void thrift_sha256_transform(THRIFT_SHA256_CTX *ctx, const unsigned char data[])
{
unsigned int a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = ((unsigned int)data[j] << 24) | ((unsigned int)data[j+1] << 16)
| ((unsigned int)data[j+2] << 8) | ((unsigned int)data[j+3]);
for (; i < 64; ++i)
m[i] = THRIFT_SHA256_SIG1(m[i-2]) + m[i-7] + THRIFT_SHA256_SIG0(m[i-15]) + m[i-16];
a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3];
e = ctx->state[4]; f = ctx->state[5]; g = ctx->state[6]; h = ctx->state[7];
for (i = 0; i < 64; ++i) {
t1 = h + THRIFT_SHA256_EP1(e) + THRIFT_SHA256_CH(e,f,g) + thrift_sha256_k[i] + m[i];
t2 = THRIFT_SHA256_EP0(a) + THRIFT_SHA256_MAJ(a,b,c);
h = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d;
ctx->state[4] += e; ctx->state[5] += f; ctx->state[6] += g; ctx->state[7] += h;
}
inline void thrift_sha256_init(THRIFT_SHA256_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen = 0;
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;
}
inline void thrift_sha256_update(THRIFT_SHA256_CTX *ctx, const unsigned char data[], size_t len)
{
for (size_t i = 0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
thrift_sha256_transform(ctx, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
inline void thrift_sha256_final(THRIFT_SHA256_CTX *ctx, unsigned char hash[])
{
unsigned int i = ctx->datalen;
if (ctx->datalen < 56) {
ctx->data[i++] = 0x80u;
while (i < 56) ctx->data[i++] = 0x00u;
} else {
ctx->data[i++] = 0x80u;
while (i < 64) ctx->data[i++] = 0x00u;
thrift_sha256_transform(ctx, ctx->data);
memset(ctx->data, 0, 56);
}
ctx->bitlen += ctx->datalen * 8;
ctx->data[63] = (unsigned char)(ctx->bitlen);
ctx->data[62] = (unsigned char)(ctx->bitlen >> 8);
ctx->data[61] = (unsigned char)(ctx->bitlen >> 16);
ctx->data[60] = (unsigned char)(ctx->bitlen >> 24);
ctx->data[59] = (unsigned char)(ctx->bitlen >> 32);
ctx->data[58] = (unsigned char)(ctx->bitlen >> 40);
ctx->data[57] = (unsigned char)(ctx->bitlen >> 48);
ctx->data[56] = (unsigned char)(ctx->bitlen >> 56);
thrift_sha256_transform(ctx, ctx->data);
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xffu;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xffu;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xffu;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xffu;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xffu;
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xffu;
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xffu;
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xffu;
}
}
/******************** C++ convenience wrapper ********************/
namespace thrift_generator {
/** Compute SHA-256 of arbitrary bytes. Returns a 32-byte digest. */
inline std::vector<uint8_t> sha256(const uint8_t* data, size_t len) {
THRIFT_SHA256_CTX ctx;
thrift_sha256_init(&ctx);
thrift_sha256_update(&ctx, reinterpret_cast<const unsigned char*>(data), len);
std::vector<uint8_t> digest(THRIFT_SHA256_BLOCK_SIZE);
thrift_sha256_final(&ctx, digest.data());
return digest;
}
/** Convenience overload: compute SHA-256 of a std::string. */
inline std::vector<uint8_t> sha256(const std::string& s) {
return sha256(reinterpret_cast<const uint8_t*>(s.data()), s.size());
}
} // namespace thrift_generator