7 n__sha256_8c
gullradriel edited this page 2026-10-29 20:54:40 +01:00

src/n_sha256.c

SHA-256 in portable C, fed a piece at a time (FIPS 180-4). More...

Functions

Name
void _sha256_block(uint32_t state[8], const unsigned char block[64])
helper: hash one 64 byte block into the state

Attributes

Name
const uint32_t[64] _sha256_k
the round constants: the first 32 bits of the fractional parts of the cube roots of the first 64 primes

Defines

Name
N_SHA256_ROTR(x, n)
rotate right

Detailed Description

SHA-256 in portable C, fed a piece at a time (FIPS 180-4).

Author: Castagnier Mickael

Version: 1.0

Date: 28/09/2026

Functions Documentation

function _sha256_block

static void _sha256_block(
    uint32_t state[8],
    const unsigned char block[64]
)

helper: hash one 64 byte block into the state

Attributes Documentation

variable _sha256_k

static const uint32_t[64] _sha256_k                             = {
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};

the round constants: the first 32 bits of the fractional parts of the cube roots of the first 64 primes

Macros Documentation

define N_SHA256_ROTR

#define N_SHA256_ROTR(
    x,
    n
)
(((x) >> (n)) | ((x) << (32 - (n))))

rotate right

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include <stdio.h>
#include <string.h>

#include "nilorea/n_sha256.h"

static const uint32_t _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};

#define N_SHA256_ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n))))

static void _sha256_block(uint32_t state[8], const unsigned char block[64]) {
    uint32_t w[64];
    uint32_t a = state[0], b = state[1], c = state[2], d = state[3];
    uint32_t e = state[4], f = state[5], g = state[6], h = state[7];
    int i = 0;

    for (i = 0; i < 16; i++)
        w[i] = ((uint32_t)block[i * 4] << 24) | ((uint32_t)block[i * 4 + 1] << 16) | ((uint32_t)block[i * 4 + 2] << 8) |
               (uint32_t)block[i * 4 + 3];
    for (i = 16; i < 64; i++) {
        uint32_t s0 = N_SHA256_ROTR(w[i - 15], 7) ^ N_SHA256_ROTR(w[i - 15], 18) ^ (w[i - 15] >> 3);
        uint32_t s1 = N_SHA256_ROTR(w[i - 2], 17) ^ N_SHA256_ROTR(w[i - 2], 19) ^ (w[i - 2] >> 10);

        w[i] = w[i - 16] + s0 + w[i - 7] + s1;
    }
    for (i = 0; i < 64; i++) {
        uint32_t s1 = N_SHA256_ROTR(e, 6) ^ N_SHA256_ROTR(e, 11) ^ N_SHA256_ROTR(e, 25);
        uint32_t ch = (e & f) ^ (~e & g);
        uint32_t t1 = h + s1 + ch + _sha256_k[i] + w[i];
        uint32_t s0 = N_SHA256_ROTR(a, 2) ^ N_SHA256_ROTR(a, 13) ^ N_SHA256_ROTR(a, 22);
        uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
        uint32_t t2 = s0 + maj;

        h = g;
        g = f;
        f = e;
        e = d + t1;
        d = c;
        c = b;
        b = a;
        a = t1 + t2;
    }
    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 n_sha256_init(N_SHA256* ctx) {
    /* the first 32 bits of the fractional parts of the square roots of the
     * first eight primes */
    static const uint32_t initial[8] = {0x6a09e667u, 0xbb67ae85u, 0x3c6ef372u, 0xa54ff53au,
                                        0x510e527fu, 0x9b05688cu, 0x1f83d9abu, 0x5be0cd19u};

    if (!ctx) return;
    memcpy(ctx->state, initial, sizeof(initial));
    ctx->length = 0;
    ctx->used = 0;
}

void n_sha256_update(N_SHA256* ctx, const void* data, size_t len) {
    const unsigned char* p = (const unsigned char*)data;

    if (!ctx || !p || !len) return;
    ctx->length += (uint64_t)len;
    /* Top up a partial block first, then whole blocks straight from the
     * caller's bytes, then keep what is left. */
    if (ctx->used) {
        size_t take = 64 - ctx->used < len ? 64 - ctx->used : len;

        memcpy(ctx->block + ctx->used, p, take);
        ctx->used += take;
        p += take;
        len -= take;
        if (ctx->used < 64) return;
        _sha256_block(ctx->state, ctx->block);
        ctx->used = 0;
    }
    while (len >= 64) {
        _sha256_block(ctx->state, p);
        p += 64;
        len -= 64;
    }
    if (len) {
        memcpy(ctx->block, p, len);
        ctx->used = len;
    }
}

void n_sha256_final(N_SHA256* ctx, unsigned char out[N_SHA256_LEN]) {
    uint64_t bits = 0;
    int i = 0;

    if (!ctx || !out) return;
    bits = ctx->length * 8u;
    /* a one bit, zeros to 56 bytes into a block, the length in bits */
    ctx->block[ctx->used++] = 0x80;
    if (ctx->used > 56) {
        memset(ctx->block + ctx->used, 0, 64 - ctx->used);
        _sha256_block(ctx->state, ctx->block);
        ctx->used = 0;
    }
    memset(ctx->block + ctx->used, 0, 56 - ctx->used);
    for (i = 0; i < 8; i++)
        ctx->block[56 + i] = (unsigned char)(bits >> (56 - 8 * i));
    _sha256_block(ctx->state, ctx->block);
    for (i = 0; i < 8; i++) {
        out[i * 4] = (unsigned char)(ctx->state[i] >> 24);
        out[i * 4 + 1] = (unsigned char)(ctx->state[i] >> 16);
        out[i * 4 + 2] = (unsigned char)(ctx->state[i] >> 8);
        out[i * 4 + 3] = (unsigned char)ctx->state[i];
    }
    ctx->used = 0;
}

void n_sha256(const void* data, size_t len, unsigned char out[N_SHA256_LEN]) {
    N_SHA256 ctx;

    n_sha256_init(&ctx);
    n_sha256_update(&ctx, data, len);
    n_sha256_final(&ctx, out);
}

int n_sha256_file(const char* path, unsigned char out[N_SHA256_LEN]) {
    unsigned char buffer[65536];
    N_SHA256 ctx;
    FILE* f = NULL;
    int failed = 0;

    if (!path || !out) return -1;
    f = fopen(path, "rb");
    if (!f) return -1;
    n_sha256_init(&ctx);
    /* A read shorter than asked is the end of the file or an error, and is
     * the last one: reading again after either does nothing at the end and
     * reads from an indeterminate position after an error (C11 7.21.8.1).
     * ferror() below says which it was. */
    for (;;) {
        size_t got = fread(buffer, 1, sizeof(buffer), f);

        if (got > 0)
            n_sha256_update(&ctx, buffer, got);
        if (got < sizeof(buffer))
            break;
    }
    failed = ferror(f);
    fclose(f);
    if (failed) return -1;
    n_sha256_final(&ctx, out);
    return 0;
}

void n_sha256_hex(const unsigned char digest[N_SHA256_LEN], char out[N_SHA256_HEX_LEN]) {
    static const char digits[] = "0123456789abcdef";
    int i = 0;

    if (!digest || !out) return;
    for (i = 0; i < N_SHA256_LEN; i++) {
        out[i * 2] = digits[digest[i] >> 4];
        out[i * 2 + 1] = digits[digest[i] & 15];
    }
    out[N_SHA256_HEX_LEN - 1] = '\0';
}