blob: 34708000aa33a165552af7b6e06f19d5b17aeacf [file] [log] [blame]
Jens Geyer1e5fa4b2026-03-27 00:01:45 +01001/*********************************************************************
2* Filename: sha256.h / sha256.c (combined header-only)
3* Author: Brad Conte (brad AT bradconte.com)
4* Copyright:
5* Disclaimer: This code is presented "as is" without any guarantees.
6* Details: Defines the API for the corresponding SHA-256 implementation.
7* SHA-256 is one of the three algorithms in the SHA2
8* specification. The others, SHA-384 and SHA-512, are not
9* offered in this implementation.
10* Algorithm specification can be found here:
11* * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
12* This implementation uses little endian byte order.
13*
14* Source: https://github.com/B-Con/crypto-algorithms
15* Public domain — no copyright claimed by the author.
16*
17* Modifications for Apache Thrift:
18* - Combined .h and .c into a single header-only file.
19* - Added C++ wrapper (thrift_generator::sha256) returning std::vector<uint8_t>.
20* - No algorithmic changes.
21*********************************************************************/
22
23#pragma once
24
25#include <cstring>
26#include <string>
27#include <vector>
28#include <cstdint>
29#include <cstddef>
30
31/****************************** MACROS ******************************/
32#define THRIFT_SHA256_ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
33#define THRIFT_SHA256_ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
34
35#define THRIFT_SHA256_CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
36#define THRIFT_SHA256_MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
37#define THRIFT_SHA256_EP0(x) (THRIFT_SHA256_ROTRIGHT(x,2) ^ THRIFT_SHA256_ROTRIGHT(x,13) ^ THRIFT_SHA256_ROTRIGHT(x,22))
38#define THRIFT_SHA256_EP1(x) (THRIFT_SHA256_ROTRIGHT(x,6) ^ THRIFT_SHA256_ROTRIGHT(x,11) ^ THRIFT_SHA256_ROTRIGHT(x,25))
39#define THRIFT_SHA256_SIG0(x) (THRIFT_SHA256_ROTRIGHT(x,7) ^ THRIFT_SHA256_ROTRIGHT(x,18) ^ ((x) >> 3))
40#define THRIFT_SHA256_SIG1(x) (THRIFT_SHA256_ROTRIGHT(x,17) ^ THRIFT_SHA256_ROTRIGHT(x,19) ^ ((x) >> 10))
41
42/**************************** DATA TYPES ****************************/
43#define THRIFT_SHA256_BLOCK_SIZE 32
44
45typedef struct {
46 unsigned char data[64];
47 unsigned int datalen;
48 unsigned long long bitlen;
49 unsigned int state[8];
50} THRIFT_SHA256_CTX;
51
52/**************************** VARIABLES *****************************/
53// clang-format off
54static const unsigned int thrift_sha256_k[64] = {
55 0x428a2f98u,0x71374491u,0xb5c0fbcfu,0xe9b5dba5u,0x3956c25bu,0x59f111f1u,0x923f82a4u,0xab1c5ed5u,
56 0xd807aa98u,0x12835b01u,0x243185beu,0x550c7dc3u,0x72be5d74u,0x80deb1feu,0x9bdc06a7u,0xc19bf174u,
57 0xe49b69c1u,0xefbe4786u,0x0fc19dc6u,0x240ca1ccu,0x2de92c6fu,0x4a7484aau,0x5cb0a9dcu,0x76f988dau,
58 0x983e5152u,0xa831c66du,0xb00327c8u,0xbf597fc7u,0xc6e00bf3u,0xd5a79147u,0x06ca6351u,0x14292967u,
59 0x27b70a85u,0x2e1b2138u,0x4d2c6dfcu,0x53380d13u,0x650a7354u,0x766a0abbu,0x81c2c92eu,0x92722c85u,
60 0xa2bfe8a1u,0xa81a664bu,0xc24b8b70u,0xc76c51a3u,0xd192e819u,0xd6990624u,0xf40e3585u,0x106aa070u,
61 0x19a4c116u,0x1e376c08u,0x2748774cu,0x34b0bcb5u,0x391c0cb3u,0x4ed8aa4au,0x5b9cca4fu,0x682e6ff3u,
62 0x748f82eeu,0x78a5636fu,0x84c87814u,0x8cc70208u,0x90befffau,0xa4506cebu,0xbef9a3f7u,0xc67178f2u
63};
64// clang-format on
65
66/*********************** FUNCTION DEFINITIONS ***********************/
67inline void thrift_sha256_transform(THRIFT_SHA256_CTX *ctx, const unsigned char data[])
68{
69 unsigned int a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
70
71 for (i = 0, j = 0; i < 16; ++i, j += 4)
72 m[i] = ((unsigned int)data[j] << 24) | ((unsigned int)data[j+1] << 16)
73 | ((unsigned int)data[j+2] << 8) | ((unsigned int)data[j+3]);
74 for (; i < 64; ++i)
75 m[i] = THRIFT_SHA256_SIG1(m[i-2]) + m[i-7] + THRIFT_SHA256_SIG0(m[i-15]) + m[i-16];
76
77 a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3];
78 e = ctx->state[4]; f = ctx->state[5]; g = ctx->state[6]; h = ctx->state[7];
79
80 for (i = 0; i < 64; ++i) {
81 t1 = h + THRIFT_SHA256_EP1(e) + THRIFT_SHA256_CH(e,f,g) + thrift_sha256_k[i] + m[i];
82 t2 = THRIFT_SHA256_EP0(a) + THRIFT_SHA256_MAJ(a,b,c);
83 h = g; g = f; f = e; e = d + t1;
84 d = c; c = b; b = a; a = t1 + t2;
85 }
86
87 ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d;
88 ctx->state[4] += e; ctx->state[5] += f; ctx->state[6] += g; ctx->state[7] += h;
89}
90
91inline void thrift_sha256_init(THRIFT_SHA256_CTX *ctx)
92{
93 ctx->datalen = 0;
94 ctx->bitlen = 0;
95 ctx->state[0] = 0x6a09e667u;
96 ctx->state[1] = 0xbb67ae85u;
97 ctx->state[2] = 0x3c6ef372u;
98 ctx->state[3] = 0xa54ff53au;
99 ctx->state[4] = 0x510e527fu;
100 ctx->state[5] = 0x9b05688cu;
101 ctx->state[6] = 0x1f83d9abu;
102 ctx->state[7] = 0x5be0cd19u;
103}
104
105inline void thrift_sha256_update(THRIFT_SHA256_CTX *ctx, const unsigned char data[], size_t len)
106{
107 for (size_t i = 0; i < len; ++i) {
108 ctx->data[ctx->datalen] = data[i];
109 ctx->datalen++;
110 if (ctx->datalen == 64) {
111 thrift_sha256_transform(ctx, ctx->data);
112 ctx->bitlen += 512;
113 ctx->datalen = 0;
114 }
115 }
116}
117
118inline void thrift_sha256_final(THRIFT_SHA256_CTX *ctx, unsigned char hash[])
119{
120 unsigned int i = ctx->datalen;
121
122 if (ctx->datalen < 56) {
123 ctx->data[i++] = 0x80u;
124 while (i < 56) ctx->data[i++] = 0x00u;
125 } else {
126 ctx->data[i++] = 0x80u;
127 while (i < 64) ctx->data[i++] = 0x00u;
128 thrift_sha256_transform(ctx, ctx->data);
129 memset(ctx->data, 0, 56);
130 }
131
132 ctx->bitlen += ctx->datalen * 8;
133 ctx->data[63] = (unsigned char)(ctx->bitlen);
134 ctx->data[62] = (unsigned char)(ctx->bitlen >> 8);
135 ctx->data[61] = (unsigned char)(ctx->bitlen >> 16);
136 ctx->data[60] = (unsigned char)(ctx->bitlen >> 24);
137 ctx->data[59] = (unsigned char)(ctx->bitlen >> 32);
138 ctx->data[58] = (unsigned char)(ctx->bitlen >> 40);
139 ctx->data[57] = (unsigned char)(ctx->bitlen >> 48);
140 ctx->data[56] = (unsigned char)(ctx->bitlen >> 56);
141 thrift_sha256_transform(ctx, ctx->data);
142
143 for (i = 0; i < 4; ++i) {
144 hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xffu;
145 hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xffu;
146 hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xffu;
147 hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xffu;
148 hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xffu;
149 hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xffu;
150 hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xffu;
151 hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xffu;
152 }
153}
154
155/******************** C++ convenience wrapper ********************/
156namespace thrift_generator {
157
158/** Compute SHA-256 of arbitrary bytes. Returns a 32-byte digest. */
159inline std::vector<uint8_t> sha256(const uint8_t* data, size_t len) {
160 THRIFT_SHA256_CTX ctx;
161 thrift_sha256_init(&ctx);
162 thrift_sha256_update(&ctx, reinterpret_cast<const unsigned char*>(data), len);
163 std::vector<uint8_t> digest(THRIFT_SHA256_BLOCK_SIZE);
164 thrift_sha256_final(&ctx, digest.data());
165 return digest;
166}
167
168/** Convenience overload: compute SHA-256 of a std::string. */
169inline std::vector<uint8_t> sha256(const std::string& s) {
170 return sha256(reinterpret_cast<const uint8_t*>(s.data()), s.size());
171}
172
173} // namespace thrift_generator