kit

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

blob.c (3224B)


      1 #include "blob.h"
      2 
      3 #include <string.h>
      4 
      5 #include "blake2b.h"
      6 
      7 static void put_u64le(uint8_t* p, uint64_t v) {
      8   unsigned i;
      9   for (i = 0; i < 8u; ++i) p[i] = (uint8_t)(v >> (8u * i));
     10 }
     11 
     12 static void hash_u64(DistBlake2b* h, uint64_t v) {
     13   uint8_t b[8];
     14   put_u64le(b, v);
     15   dist_blake2b_update(h, b, sizeof b);
     16 }
     17 
     18 void dist_blob_id(uint8_t out[DIST_BLAKE2B_LEN], const uint8_t* data,
     19                   size_t len) {
     20   dist_blake2b(out, data, len);
     21 }
     22 
     23 void dist_blob_leaf_hash(uint8_t out[DIST_BLAKE2B_LEN], uint64_t chunk_index,
     24                          const uint8_t* raw, size_t raw_len) {
     25   static const uint8_t dom[] = "kit blob leaf v1";
     26   DistBlake2b h;
     27   dist_blake2b_init(&h, DIST_BLAKE2B_LEN);
     28   dist_blake2b_update(&h, dom, sizeof dom - 1u);
     29   hash_u64(&h, chunk_index);
     30   hash_u64(&h, (uint64_t)raw_len);
     31   dist_blake2b_update(&h, raw, raw_len);
     32   dist_blake2b_final(&h, out);
     33 }
     34 
     35 void dist_blob_node_hash(uint8_t out[DIST_BLAKE2B_LEN],
     36                          const uint8_t left[DIST_BLAKE2B_LEN],
     37                          const uint8_t right[DIST_BLAKE2B_LEN]) {
     38   static const uint8_t dom[] = "kit blob node v1";
     39   DistBlake2b h;
     40   dist_blake2b_init(&h, DIST_BLAKE2B_LEN);
     41   dist_blake2b_update(&h, dom, sizeof dom - 1u);
     42   dist_blake2b_update(&h, left, DIST_BLAKE2B_LEN);
     43   dist_blake2b_update(&h, right, DIST_BLAKE2B_LEN);
     44   dist_blake2b_final(&h, out);
     45 }
     46 
     47 void dist_blob_empty_root(uint8_t out[DIST_BLAKE2B_LEN]) {
     48   static const uint8_t dom[] = "kit blob empty v1";
     49   dist_blake2b(out, dom, sizeof dom - 1u);
     50 }
     51 
     52 int dist_blob_root(uint8_t out[DIST_BLAKE2B_LEN], const uint8_t* data,
     53                    size_t len, size_t chunk_size) {
     54   uint8_t level[DIST_MAX_FILES][DIST_BLAKE2B_LEN];
     55   size_t leaves, i;
     56   if (chunk_size == 0) return DIST_ERR;
     57   if (len && !data) return DIST_ERR;
     58   if (len == 0) {
     59     dist_blob_empty_root(out);
     60     return DIST_OK;
     61   }
     62   leaves = (len + chunk_size - 1u) / chunk_size;
     63   if (leaves > DIST_MAX_FILES) return DIST_ERR;
     64   for (i = 0; i < leaves; ++i) {
     65     size_t off = i * chunk_size;
     66     size_t n = len - off;
     67     if (n > chunk_size) n = chunk_size;
     68     dist_blob_leaf_hash(level[i], (uint64_t)i, data + off, n);
     69   }
     70   while (leaves > 1u) {
     71     size_t outn = 0;
     72     for (i = 0; i < leaves; i += 2u) {
     73       if (i + 1u < leaves)
     74         dist_blob_node_hash(level[outn], level[i], level[i + 1u]);
     75       else
     76         memcpy(level[outn], level[i], DIST_BLAKE2B_LEN);
     77       ++outn;
     78     }
     79     leaves = outn;
     80   }
     81   {
     82     static const uint8_t dom[] = "kit blob root v1";
     83     DistBlake2b h;
     84     dist_blake2b_init(&h, DIST_BLAKE2B_LEN);
     85     dist_blake2b_update(&h, dom, sizeof dom - 1u);
     86     dist_blake2b_update(&h, level[0], DIST_BLAKE2B_LEN);
     87     dist_blake2b_final(&h, out);
     88   }
     89   return DIST_OK;
     90 }
     91 
     92 int dist_blob_info(DistBlobInfo* out, const uint8_t* data, size_t len,
     93                    size_t chunk_size) {
     94   if (!out || chunk_size == 0) return DIST_ERR;
     95   if (len && !data) return DIST_ERR;
     96   memset(out, 0, sizeof *out);
     97   dist_blob_id(out->id, data, len);
     98   if (dist_blob_root(out->root, data, len, chunk_size) != DIST_OK)
     99     return DIST_ERR;
    100   out->size = (uint64_t)len;
    101   out->chunks = len ? (uint64_t)((len + chunk_size - 1u) / chunk_size) : 0u;
    102   return DIST_OK;
    103 }