kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

hash.c (3446B)


      1 /* Public hashing API: one-shot and streaming SHA-256, BLAKE2b-256, and CRC-32.
      2  * A thin composition over src/core/{sha256,crc32} and src/dist/blake2b. See
      3  * <kit/hash.h>. */
      4 
      5 #include <kit/hash.h>
      6 #include <string.h>
      7 
      8 #include "core/crc32.h"
      9 #include "core/sha256.h"
     10 #include "dist/blake2b.h"
     11 
     12 /* sha256_update takes a 32-bit length; feed large inputs in bounded chunks. */
     13 #define HASH_SHA_CHUNK 0x40000000u /* 1 GiB */
     14 
     15 struct KitHasher {
     16   const KitContext* ctx;
     17   KitHashAlgo algo;
     18   union {
     19     Sha256 sha;
     20     DistBlake2b b2;
     21     uint32_t crc;
     22   } st;
     23 };
     24 
     25 size_t kit_hash_len(KitHashAlgo algo) {
     26   switch (algo) {
     27     case KIT_HASH_SHA256:
     28       return KIT_SHA256_LEN;
     29     case KIT_HASH_BLAKE2B:
     30       return KIT_BLAKE2B_LEN;
     31     case KIT_HASH_CRC32:
     32       return KIT_CRC32_LEN;
     33   }
     34   return 0;
     35 }
     36 
     37 /* Initialize the per-algo running state (shared by new + the one-shot path). */
     38 static void hasher_begin(KitHasher* h) {
     39   switch (h->algo) {
     40     case KIT_HASH_SHA256:
     41       sha256_init(&h->st.sha);
     42       break;
     43     case KIT_HASH_BLAKE2B:
     44       dist_blake2b_init(&h->st.b2, KIT_BLAKE2B_LEN);
     45       break;
     46     case KIT_HASH_CRC32:
     47       h->st.crc = 0;
     48       break;
     49   }
     50 }
     51 
     52 void kit_hasher_update(KitHasher* h, const uint8_t* data, size_t len) {
     53   if (!h || (!data && len)) return;
     54   switch (h->algo) {
     55     case KIT_HASH_SHA256:
     56       while (len) {
     57         uint32_t n = len > HASH_SHA_CHUNK ? HASH_SHA_CHUNK : (uint32_t)len;
     58         sha256_update(&h->st.sha, data, n);
     59         data += n;
     60         len -= n;
     61       }
     62       break;
     63     case KIT_HASH_BLAKE2B:
     64       dist_blake2b_update(&h->st.b2, data, len);
     65       break;
     66     case KIT_HASH_CRC32:
     67       h->st.crc = kit_crc32(h->st.crc, data, len);
     68       break;
     69   }
     70 }
     71 
     72 KitStatus kit_hasher_final(KitHasher* h, uint8_t* out, size_t* out_len) {
     73   if (!h || !out) return KIT_INVALID;
     74   switch (h->algo) {
     75     case KIT_HASH_SHA256:
     76       sha256_final(&h->st.sha, out);
     77       break;
     78     case KIT_HASH_BLAKE2B:
     79       dist_blake2b_final(&h->st.b2, out);
     80       break;
     81     case KIT_HASH_CRC32:
     82       out[0] = (uint8_t)(h->st.crc >> 24);
     83       out[1] = (uint8_t)(h->st.crc >> 16);
     84       out[2] = (uint8_t)(h->st.crc >> 8);
     85       out[3] = (uint8_t)(h->st.crc);
     86       break;
     87   }
     88   if (out_len) *out_len = kit_hash_len(h->algo);
     89   return KIT_OK;
     90 }
     91 
     92 KitStatus kit_hasher_new(const KitContext* ctx, KitHashAlgo algo,
     93                          KitHasher** out) {
     94   KitHeap* heap;
     95   KitHasher* h;
     96   if (!out) return KIT_INVALID;
     97   *out = NULL;
     98   if (!ctx || !ctx->heap) return KIT_INVALID;
     99   if (kit_hash_len(algo) == 0) return KIT_INVALID;
    100   heap = ctx->heap;
    101   h = (KitHasher*)heap->alloc(heap, sizeof(*h), _Alignof(KitHasher));
    102   if (!h) return KIT_NOMEM;
    103   memset(h, 0, sizeof(*h));
    104   h->ctx = ctx;
    105   h->algo = algo;
    106   hasher_begin(h);
    107   *out = h;
    108   return KIT_OK;
    109 }
    110 
    111 void kit_hasher_free(KitHasher* h) {
    112   KitHeap* heap;
    113   if (!h) return;
    114   heap = h->ctx->heap;
    115   heap->free(heap, h, sizeof(*h));
    116 }
    117 
    118 KitStatus kit_hash(KitHashAlgo algo, const uint8_t* data, size_t len,
    119                    uint8_t* out, size_t* out_len) {
    120   KitHasher tmp;
    121   if (!out || (!data && len)) return KIT_INVALID;
    122   if (kit_hash_len(algo) == 0) return KIT_INVALID;
    123   /* No heap needed: the running state lives on the stack and neither update
    124    * nor final touches tmp.ctx. */
    125   memset(&tmp, 0, sizeof tmp);
    126   tmp.algo = algo;
    127   hasher_begin(&tmp);
    128   kit_hasher_update(&tmp, data, len);
    129   return kit_hasher_final(&tmp, out, out_len);
    130 }