BLAKE2.c (6553B)
1 /* 2 * BLAKE2b Implementation 3 * RFC 7693 4 * 5 * Fast cryptographic hash function, faster than SHA-2/SHA-3 6 * Optimized for 64-bit platforms 7 */ 8 9 #include <stdint.h> 10 #include <string.h> 11 #include <stdlib.h> 12 13 /* BLAKE2b IV */ 14 static const uint64_t blake2b_iv[8] = { 15 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 16 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 17 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 18 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL 19 }; 20 21 /* BLAKE2b sigma (message schedule) */ 22 static const uint8_t blake2b_sigma[12][16] = { 23 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 24 {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, 25 {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, 26 {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, 27 {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, 28 {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, 29 {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, 30 {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, 31 {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, 32 {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, 33 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 34 {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3} 35 }; 36 37 #define ROR64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) 38 39 /* Load 64-bit little-endian */ 40 static inline uint64_t load64_le(const uint8_t *src) { 41 return (uint64_t)src[0] | 42 ((uint64_t)src[1] << 8) | 43 ((uint64_t)src[2] << 16) | 44 ((uint64_t)src[3] << 24) | 45 ((uint64_t)src[4] << 32) | 46 ((uint64_t)src[5] << 40) | 47 ((uint64_t)src[6] << 48) | 48 ((uint64_t)src[7] << 56); 49 } 50 51 /* Store 64-bit little-endian */ 52 static inline void store64_le(uint8_t *dst, uint64_t w) { 53 dst[0] = (uint8_t)w; 54 dst[1] = (uint8_t)(w >> 8); 55 dst[2] = (uint8_t)(w >> 16); 56 dst[3] = (uint8_t)(w >> 24); 57 dst[4] = (uint8_t)(w >> 32); 58 dst[5] = (uint8_t)(w >> 40); 59 dst[6] = (uint8_t)(w >> 48); 60 dst[7] = (uint8_t)(w >> 56); 61 } 62 63 /* BLAKE2b mixing function G */ 64 #define G(r, i, a, b, c, d, m) \ 65 do { \ 66 a = a + b + m[blake2b_sigma[r][2 * i]]; \ 67 d = ROR64(d ^ a, 32); \ 68 c = c + d; \ 69 b = ROR64(b ^ c, 24); \ 70 a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ 71 d = ROR64(d ^ a, 16); \ 72 c = c + d; \ 73 b = ROR64(b ^ c, 63); \ 74 } while (0) 75 76 /* BLAKE2b compression function */ 77 static void blake2b_compress(uint64_t h[8], const uint8_t block[128], 78 uint64_t t0, uint64_t t1, int last) { 79 uint64_t v[16], m[16]; 80 81 /* Initialize work vector */ 82 for (int i = 0; i < 8; i++) { 83 v[i] = h[i]; 84 v[i + 8] = blake2b_iv[i]; 85 } 86 87 v[12] ^= t0; 88 v[13] ^= t1; 89 90 if (last) { 91 v[14] = ~v[14]; 92 } 93 94 /* Load message */ 95 for (int i = 0; i < 16; i++) { 96 m[i] = load64_le(block + i * 8); 97 } 98 99 /* 12 rounds */ 100 for (int r = 0; r < 12; r++) { 101 G(r, 0, v[0], v[4], v[8], v[12], m); 102 G(r, 1, v[1], v[5], v[9], v[13], m); 103 G(r, 2, v[2], v[6], v[10], v[14], m); 104 G(r, 3, v[3], v[7], v[11], v[15], m); 105 G(r, 4, v[0], v[5], v[10], v[15], m); 106 G(r, 5, v[1], v[6], v[11], v[12], m); 107 G(r, 6, v[2], v[7], v[8], v[13], m); 108 G(r, 7, v[3], v[4], v[9], v[14], m); 109 } 110 111 /* Update hash */ 112 for (int i = 0; i < 8; i++) { 113 h[i] ^= v[i] ^ v[i + 8]; 114 } 115 } 116 117 /* BLAKE2b context */ 118 typedef struct { 119 uint64_t h[8]; 120 uint64_t t[2]; 121 uint8_t buf[128]; 122 size_t buflen; 123 size_t outlen; 124 } blake2b_context; 125 126 /* Initialize BLAKE2b */ 127 static void blake2b_init(blake2b_context *ctx, size_t outlen, const uint8_t *key, size_t keylen) { 128 memset(ctx, 0, sizeof(blake2b_context)); 129 130 ctx->outlen = outlen; 131 132 /* Initialize hash state */ 133 for (int i = 0; i < 8; i++) { 134 ctx->h[i] = blake2b_iv[i]; 135 } 136 137 /* Parameter block */ 138 ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen; 139 140 /* Process key if present */ 141 if (keylen > 0) { 142 memcpy(ctx->buf, key, keylen); 143 ctx->buflen = 128; 144 } 145 } 146 147 /* Update BLAKE2b */ 148 static void blake2b_update(blake2b_context *ctx, const uint8_t *data, size_t len) { 149 while (len > 0) { 150 size_t take = 128 - ctx->buflen; 151 if (take > len) take = len; 152 153 memcpy(ctx->buf + ctx->buflen, data, take); 154 ctx->buflen += take; 155 data += take; 156 len -= take; 157 158 if (ctx->buflen == 128) { 159 ctx->t[0] += 128; 160 if (ctx->t[0] < 128) ctx->t[1]++; 161 162 blake2b_compress(ctx->h, ctx->buf, ctx->t[0], ctx->t[1], 0); 163 ctx->buflen = 0; 164 } 165 } 166 } 167 168 /* Finalize BLAKE2b */ 169 static void blake2b_final(blake2b_context *ctx, uint8_t *out) { 170 ctx->t[0] += ctx->buflen; 171 if (ctx->t[0] < ctx->buflen) ctx->t[1]++; 172 173 /* Pad with zeros */ 174 memset(ctx->buf + ctx->buflen, 0, 128 - ctx->buflen); 175 176 blake2b_compress(ctx->h, ctx->buf, ctx->t[0], ctx->t[1], 1); 177 178 /* Output hash */ 179 for (size_t i = 0; i < ctx->outlen / 8; i++) { 180 store64_le(out + i * 8, ctx->h[i]); 181 } 182 183 /* Handle partial word */ 184 if (ctx->outlen % 8) { 185 uint8_t temp[8]; 186 store64_le(temp, ctx->h[ctx->outlen / 8]); 187 memcpy(out + (ctx->outlen / 8) * 8, temp, ctx->outlen % 8); 188 } 189 } 190 191 /* BLAKE2b hash function (simple interface) */ 192 void blake2b(const uint8_t *data, size_t len, uint8_t *out, size_t outlen) { 193 blake2b_context ctx; 194 blake2b_init(&ctx, outlen, NULL, 0); 195 blake2b_update(&ctx, data, len); 196 blake2b_final(&ctx, out); 197 memset(&ctx, 0, sizeof(ctx)); 198 } 199 200 /* BLAKE2b-256 (32 bytes) */ 201 void blake2b_256(const uint8_t *data, size_t len, uint8_t digest[32]) { 202 blake2b(data, len, digest, 32); 203 } 204 205 /* BLAKE2b-512 (64 bytes) */ 206 void blake2b_512(const uint8_t *data, size_t len, uint8_t digest[64]) { 207 blake2b(data, len, digest, 64); 208 } 209 210 /* BLAKE2b with key (MAC) */ 211 void blake2b_mac(const uint8_t *key, size_t keylen, 212 const uint8_t *data, size_t len, 213 uint8_t *out, size_t outlen) { 214 blake2b_context ctx; 215 blake2b_init(&ctx, outlen, key, keylen); 216 blake2b_update(&ctx, data, len); 217 blake2b_final(&ctx, out); 218 memset(&ctx, 0, sizeof(ctx)); 219 }