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 }