Sha256
FIPS 180-4 SHA-256 of a byte span the caller already chose. The digest is 32 raw bytes. Processing uses 512-bit blocks, 64 rounds, and a big-endian 64-bit length. Digest words are written big-endian.
This module does not allocate. It is not declared from lfcrypto.h. That header includes codecs and puzzle bytes, not this hash. Hex text, when a caller wants it, goes through hex_encode or hex_encode_into in lfcodec.h (already lowercase).
Usage#
Hash with one call, or stream chunks through a caller-owned LfSha256. lf_sha256_init of a NULL pointer returns without writing.
#include "lfsha256.h"
int main(void) {
unsigned char digest[LF_SHA256_DIGEST_LEN];
LfSha256 ctx;
if (lf_sha256("abc", 3, digest) != 0) return 1;
/* digest[0..3] is ba 78 16 bf; 32 raw bytes, not text */
lf_sha256_init(&ctx);
if (lf_sha256_update(&ctx, "ab", 2) != 0) return 1;
if (lf_sha256_update(&ctx, "c", 1) != 0) return 1;
if (lf_sha256_final(&ctx, digest) != 0) return 1;
return 0;
}
The caller owns the LfSha256 object. Nothing inside it is allocated, and a bitwise copy copies the in-progress hash. Concurrent use of one context is not supported. Two contexts do not share state.
A successful lf_sha256_final finishes the context by setting block_len greater than LF_SHA256_BLOCK_LEN. Further lf_sha256_update or lf_sha256_final calls return -1 until lf_sha256_init. Those calls leave out unchanged when it is non-NULL, and they leave the finished context unchanged. lf_sha256_final with a NULL out returns -1 and does not finish or otherwise change the context.
On any failure, the output buffer and the context are left as they were. out must not overlap the context.
Structs#
LfSha256#
typedef struct {
uint32_t state[8];
uint64_t bit_len;
unsigned char block[LF_SHA256_BLOCK_LEN];
unsigned int block_len;
} LfSha256;
state is the chaining value. bit_len counts message bits accepted so far, including bytes still sitting in block. block_len is how many of those bytes are waiting (0 to 63 while hashing). After a successful final it is greater than 64, which marks the context finished.
#define LF_SHA256_DIGEST_LEN 32
#define LF_SHA256_BLOCK_LEN 64Functions#
lf_sha256_init#
Stores the FIPS 180-4 initial hash value and clears the counters. A NULL ctx returns without writing. There is no failure code and no allocation. Calling it again restarts a finished context.
void lf_sha256_init(LfSha256 *ctx);lf_sha256_update#
Appends n bytes. Returns 0 on success. Returns -1 if ctx is NULL, if data is NULL and n > 0, if the context is finished, or if n * 8 + bit_len would not fit in uint64_t. The length check happens before the context is modified. data NULL and n == 0 succeeds and adds no bytes. On failure the context is unchanged.
int lf_sha256_update(LfSha256 *ctx, const void *data, size_t n);lf_sha256_final#
Pads as FIPS 180-4 specifies, appends the big-endian bit length, and writes 32 bytes to out. Returns 0 on success. Returns -1 if ctx or out is NULL, or if the context is already finished. On failure out is unchanged and the context is unchanged. Success finishes the context; only lf_sha256_init makes it usable again.
int lf_sha256_final(LfSha256 *ctx, unsigned char out[LF_SHA256_DIGEST_LEN]);lf_sha256#
One-shot hash of n bytes, implemented with init, update, and final. Empty input is data NULL or n == 0. Returns 0 on success and -1 on the same failures as update and final, including a NULL out and a bit length that does not fit in uint64_t. On failure out is unchanged.
int lf_sha256(const void *data, size_t n, unsigned char out[LF_SHA256_DIGEST_LEN]);