int hydro_hash_update(hydro_hash_state *state, const void *in_, size_t in_len) { const uint8_t *in = (const uint8_t *) in_; uint8_t *buf = (uint8_t *) (void *) state->state; size_t left; size_t ps; size_t i; while (in_len > 0) { left = gimli_RATE - state->buf_off; if ((ps = in_len) > left) { ps = left; } for (i = 0; i < ps; i++) { buf[state->buf_off + i] ^= in[i]; } in += ps; in_len -= ps; state->buf_off += (uint8_t) ps; if (state->buf_off == gimli_RATE) { gimli_core_u8(buf, 0); state->buf_off = 0; } } return 0; } /* pad(str_enc("kmac") || str_enc(context)) || pad(str_enc(k)) || msg || right_enc(msg_len) || 0x00 */ int hydro_hash_init(hydro_hash_state *state, const char ctx[hydro_hash_CONTEXTBYTES], const uint8_t key[hydro_hash_KEYBYTES]) { uint8_t block[64] = { 4, 'k', 'm', 'a', 'c', 8 }; size_t p; COMPILER_ASSERT(hydro_hash_KEYBYTES <= sizeof block - gimli_RATE - 1); COMPILER_ASSERT(hydro_hash_CONTEXTBYTES == 8); mem_zero(block + 14, sizeof block - 14); memcpy(block + 6, ctx, 8); if (key != NULL) { block[gimli_RATE] = (uint8_t) hydro_hash_KEYBYTES; memcpy(block + gimli_RATE + 1, key, hydro_hash_KEYBYTES); p = (gimli_RATE + 1 + hydro_hash_KEYBYTES + (gimli_RATE - 1)) & ~(size_t) (gimli_RATE - 1); } else { block[gimli_RATE] = (uint8_t) 0; p = (gimli_RATE + 1 + 0 + (gimli_RATE - 1)) & ~(size_t) (gimli_RATE - 1); } mem_zero(state, sizeof *state); hydro_hash_update(state, block, p); return 0; } /* pad(str_enc("tmac") || str_enc(context)) || pad(str_enc(k)) || pad(right_enc(tweak)) || msg || right_enc(msg_len) || 0x00 */ static int hydro_hash_init_with_tweak(hydro_hash_state *state, const char ctx[hydro_hash_CONTEXTBYTES], uint64_t tweak, const uint8_t key[hydro_hash_KEYBYTES]) { uint8_t block[80] = { 4, 't', 'm', 'a', 'c', 8 }; size_t p; COMPILER_ASSERT(hydro_hash_KEYBYTES <= sizeof block - 2 * gimli_RATE - 1); COMPILER_ASSERT(hydro_hash_CONTEXTBYTES == 8); mem_zero(block + 14, sizeof block - 14); memcpy(block + 6, ctx, 8); if (key != NULL) { block[gimli_RATE] = (uint8_t) hydro_hash_KEYBYTES; memcpy(block + gimli_RATE + 1, key, hydro_hash_KEYBYTES); p = (gimli_RATE + 1 + hydro_hash_KEYBYTES + (gimli_RATE - 1)) & ~(size_t) (gimli_RATE - 1); } else { block[gimli_RATE] = (uint8_t) 0; p = (gimli_RATE + 1 + 0 + (gimli_RATE - 1)) & ~(size_t) (gimli_RATE - 1); } block[p] = (uint8_t) sizeof tweak; STORE64_LE(&block[p + 1], tweak); p += gimli_RATE; mem_zero(state, sizeof *state); hydro_hash_update(state, block, p); return 0; } int hydro_hash_final(hydro_hash_state *state, uint8_t *out, size_t out_len) { uint8_t lc[4]; uint8_t *buf = (uint8_t *) (void *) state->state; size_t i; size_t lc_len; size_t leftover; if (out_len < hydro_hash_BYTES_MIN || out_len > hydro_hash_BYTES_MAX) { return -1; } COMPILER_ASSERT(hydro_hash_BYTES_MAX <= 0xffff); lc[1] = (uint8_t) out_len; lc[2] = (uint8_t) (out_len >> 8); lc[3] = 0; lc_len = (size_t) (1 + (lc[2] != 0)); lc[0] = (uint8_t) lc_len; hydro_hash_update(state, lc, 1 + lc_len + 1); gimli_pad_u8(buf, state->buf_off, gimli_DOMAIN_XOF); for (i = 0; i < out_len / gimli_RATE; i++) { gimli_core_u8(buf, 0); memcpy(out + i * gimli_RATE, buf, gimli_RATE); } leftover = out_len % gimli_RATE; if (leftover != 0) { gimli_core_u8(buf, 0); mem_cpy(out + i * gimli_RATE, buf, leftover); } state->buf_off = gimli_RATE; return 0; } int hydro_hash_hash(uint8_t *out, size_t out_len, const void *in_, size_t in_len, const char ctx[hydro_hash_CONTEXTBYTES], const uint8_t key[hydro_hash_KEYBYTES]) { hydro_hash_state st; const uint8_t *in = (const uint8_t *) in_; if (hydro_hash_init(&st, ctx, key) != 0 || hydro_hash_update(&st, in, in_len) != 0 || hydro_hash_final(&st, out, out_len) != 0) { return -1; } return 0; } void hydro_hash_keygen(uint8_t key[hydro_hash_KEYBYTES]) { hydro_random_buf(key, hydro_hash_KEYBYTES); }