aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile31
-rw-r--r--common.h19
-rw-r--r--digest.c (renamed from libkeccak/digest.c)0
-rw-r--r--libkeccak.7 (renamed from man7/libkeccak.7)0
-rw-r--r--libkeccak/hex.c65
-rw-r--r--libkeccak/hmac.c423
-rw-r--r--libkeccak/state.c174
-rw-r--r--libkeccak_behex_lower.3 (renamed from man3/libkeccak_behex_lower.3)0
-rw-r--r--libkeccak_behex_lower.c21
-rw-r--r--libkeccak_behex_upper.3 (renamed from man3/libkeccak_behex_upper.3)0
-rw-r--r--libkeccak_behex_upper.c21
-rw-r--r--libkeccak_degeneralise_spec.3 (renamed from man3/libkeccak_degeneralise_spec.3)0
-rw-r--r--libkeccak_degeneralise_spec.c (renamed from libkeccak/generalised-spec.c)3
-rw-r--r--libkeccak_digest.3 (renamed from man3/libkeccak_digest.3)0
-rw-r--r--libkeccak_fast_digest.3 (renamed from man3/libkeccak_fast_digest.3)0
-rw-r--r--libkeccak_fast_squeeze.3 (renamed from man3/libkeccak_fast_squeeze.3)0
-rw-r--r--libkeccak_fast_update.3 (renamed from man3/libkeccak_fast_update.3)0
-rw-r--r--libkeccak_generalised_spec_initialise.3 (renamed from man3/libkeccak_generalised_spec_initialise.3)0
-rw-r--r--libkeccak_generalised_sum_fd.3 (renamed from man3/libkeccak_generalised_sum_fd.3)0
-rw-r--r--libkeccak_generalised_sum_fd.c (renamed from libkeccak/files.c)2
-rw-r--r--libkeccak_hmac_copy.3 (renamed from man3/libkeccak_hmac_copy.3)0
-rw-r--r--libkeccak_hmac_copy.c38
-rw-r--r--libkeccak_hmac_create.3 (renamed from man3/libkeccak_hmac_create.3)0
-rw-r--r--libkeccak_hmac_destroy.3 (renamed from man3/libkeccak_hmac_destroy.3)0
-rw-r--r--libkeccak_hmac_digest.3 (renamed from man3/libkeccak_hmac_digest.3)0
-rw-r--r--libkeccak_hmac_digest.c80
-rw-r--r--libkeccak_hmac_duplicate.3 (renamed from man3/libkeccak_hmac_duplicate.3)0
-rw-r--r--libkeccak_hmac_fast_destroy.3 (renamed from man3/libkeccak_hmac_fast_destroy.3)0
-rw-r--r--libkeccak_hmac_fast_digest.3 (renamed from man3/libkeccak_hmac_fast_digest.3)0
-rw-r--r--libkeccak_hmac_fast_digest.c78
-rw-r--r--libkeccak_hmac_fast_free.3 (renamed from man3/libkeccak_hmac_fast_free.3)0
-rw-r--r--libkeccak_hmac_fast_update.3 (renamed from man3/libkeccak_hmac_fast_update.3)0
-rw-r--r--libkeccak_hmac_fast_update.c51
-rw-r--r--libkeccak_hmac_free.3 (renamed from man3/libkeccak_hmac_free.3)0
-rw-r--r--libkeccak_hmac_initialise.3 (renamed from man3/libkeccak_hmac_initialise.3)0
-rw-r--r--libkeccak_hmac_marshal.3 (renamed from man3/libkeccak_hmac_marshal.3)0
-rw-r--r--libkeccak_hmac_marshal_size.3 (renamed from man3/libkeccak_hmac_marshal_size.3)0
-rw-r--r--libkeccak_hmac_reset.3 (renamed from man3/libkeccak_hmac_reset.3)0
-rw-r--r--libkeccak_hmac_set_key.3 (renamed from man3/libkeccak_hmac_set_key.3)0
-rw-r--r--libkeccak_hmac_set_key.c46
-rw-r--r--libkeccak_hmac_unmarshal.3 (renamed from man3/libkeccak_hmac_unmarshal.3)0
-rw-r--r--libkeccak_hmac_unmarshal.c50
-rw-r--r--libkeccak_hmac_unmarshal_skip.3 (renamed from man3/libkeccak_hmac_unmarshal_skip.3)0
-rw-r--r--libkeccak_hmac_update.3 (renamed from man3/libkeccak_hmac_update.3)0
-rw-r--r--libkeccak_hmac_update.c52
-rw-r--r--libkeccak_hmac_wipe.3 (renamed from man3/libkeccak_hmac_wipe.3)0
-rw-r--r--libkeccak_hmac_wipe.c22
-rw-r--r--libkeccak_keccaksum_fd.3 (renamed from man3/libkeccak_keccaksum_fd.3)0
-rw-r--r--libkeccak_rawshakesum_fd.3 (renamed from man3/libkeccak_rawshakesum_fd.3)0
-rw-r--r--libkeccak_sha3sum_fd.3 (renamed from man3/libkeccak_sha3sum_fd.3)0
-rw-r--r--libkeccak_shakesum_fd.3 (renamed from man3/libkeccak_shakesum_fd.3)0
-rw-r--r--libkeccak_simple_squeeze.3 (renamed from man3/libkeccak_simple_squeeze.3)0
-rw-r--r--libkeccak_spec_check.3 (renamed from man3/libkeccak_spec_check.3)0
-rw-r--r--libkeccak_spec_rawshake.3 (renamed from man3/libkeccak_spec_rawshake.3)0
-rw-r--r--libkeccak_spec_sha3.3 (renamed from man3/libkeccak_spec_sha3.3)0
-rw-r--r--libkeccak_spec_shake.3 (renamed from man3/libkeccak_spec_shake.3)0
-rw-r--r--libkeccak_squeeze.3 (renamed from man3/libkeccak_squeeze.3)0
-rw-r--r--libkeccak_state_copy.3 (renamed from man3/libkeccak_state_copy.3)0
-rw-r--r--libkeccak_state_copy.c21
-rw-r--r--libkeccak_state_create.3 (renamed from man3/libkeccak_state_create.3)0
-rw-r--r--libkeccak_state_destroy.3 (renamed from man3/libkeccak_state_destroy.3)0
-rw-r--r--libkeccak_state_duplicate.3 (renamed from man3/libkeccak_state_duplicate.3)0
-rw-r--r--libkeccak_state_fast_destroy.3 (renamed from man3/libkeccak_state_fast_destroy.3)0
-rw-r--r--libkeccak_state_fast_free.3 (renamed from man3/libkeccak_state_fast_free.3)0
-rw-r--r--libkeccak_state_free.3 (renamed from man3/libkeccak_state_free.3)0
-rw-r--r--libkeccak_state_initialise.3 (renamed from man3/libkeccak_state_initialise.3)0
-rw-r--r--libkeccak_state_initialise.c33
-rw-r--r--libkeccak_state_marshal.3 (renamed from man3/libkeccak_state_marshal.3)0
-rw-r--r--libkeccak_state_marshal.c33
-rw-r--r--libkeccak_state_marshal_size.3 (renamed from man3/libkeccak_state_marshal_size.3)0
-rw-r--r--libkeccak_state_reset.3 (renamed from man3/libkeccak_state_reset.3)0
-rw-r--r--libkeccak_state_unmarshal.3 (renamed from man3/libkeccak_state_unmarshal.3)0
-rw-r--r--libkeccak_state_unmarshal.c36
-rw-r--r--libkeccak_state_unmarshal_skip.3 (renamed from man3/libkeccak_state_unmarshal_skip.3)0
-rw-r--r--libkeccak_state_unmarshal_skip.c18
-rw-r--r--libkeccak_state_wipe.3 (renamed from man3/libkeccak_state_wipe.3)0
-rw-r--r--libkeccak_state_wipe.c15
-rw-r--r--libkeccak_state_wipe_message.3 (renamed from man3/libkeccak_state_wipe_message.3)0
-rw-r--r--libkeccak_state_wipe_message.c17
-rw-r--r--libkeccak_state_wipe_sponge.3 (renamed from man3/libkeccak_state_wipe_sponge.3)0
-rw-r--r--libkeccak_state_wipe_sponge.c17
-rw-r--r--libkeccak_unhex.3 (renamed from man3/libkeccak_unhex.3)0
-rw-r--r--libkeccak_unhex.c29
-rw-r--r--libkeccak_update.3 (renamed from man3/libkeccak_update.3)0
84 files changed, 723 insertions, 672 deletions
diff --git a/Makefile b/Makefile
index e8c9b80..9a51de9 100644
--- a/Makefile
+++ b/Makefile
@@ -18,12 +18,28 @@ LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR)
OBJ =\
- libkeccak/digest.o\
- libkeccak/files.o\
- libkeccak/generalised-spec.o\
- libkeccak/hex.o\
- libkeccak/state.o\
- libkeccak/hmac.o
+ digest.o\
+ libkeccak_behex_lower.o\
+ libkeccak_behex_upper.o\
+ libkeccak_degeneralise_spec.o\
+ libkeccak_generalised_sum_fd.o\
+ libkeccak_hmac_copy.o\
+ libkeccak_hmac_digest.o\
+ libkeccak_hmac_fast_digest.o\
+ libkeccak_hmac_fast_update.o\
+ libkeccak_hmac_set_key.o\
+ libkeccak_hmac_unmarshal.o\
+ libkeccak_hmac_update.o\
+ libkeccak_hmac_wipe.o\
+ libkeccak_state_copy.o\
+ libkeccak_state_initialise.o\
+ libkeccak_state_marshal.o\
+ libkeccak_state_unmarshal.o\
+ libkeccak_state_unmarshal_skip.o\
+ libkeccak_state_wipe.o\
+ libkeccak_state_wipe_message.o\
+ libkeccak_state_wipe_sponge.o\
+ libkeccak_unhex.o
HDR =\
libkeccak.h\
@@ -154,7 +170,8 @@ uninstall:
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libkeccak.a"
-rm -rf -- "$(DESTDIR)$(PREFIX)/include/libkeccak"
-rm -f -- "$(DESTDIR)$(PREFIX)/include/libkeccak.h"
- -cd -- "$(DESTDIR)$(MANPREFIX)" && rm -f -- $(MAN3) $(MAN7)
+ -cd -- "$(DESTDIR)$(MANPREFIX)/man3" && rm -f -- $(MAN3)
+ -cd -- "$(DESTDIR)$(MANPREFIX)/man7" && rm -f -- $(MAN7)
-rm -rf -- "$(DESTDIR)$(PREFIX)/share/licenses/libkeccak"
clean:
diff --git a/common.h b/common.h
index 1245bf6..df8b53c 100644
--- a/common.h
+++ b/common.h
@@ -15,3 +15,22 @@
# define __builtin_memcpy(dest, src, n) memcpy(dest, src, n)
# define __builtin_memmove(dest, src, n) memmove(dest, src, n)
#endif
+
+
+/**
+ * The outer pad pattern for HMAC
+ */
+#define HMAC_OUTER_PAD 0x5C
+
+/**
+ * The inner pad pattern for HMAC
+ */
+#define HMAC_INNER_PAD 0x36
+
+
+static void *(*volatile my_explicit_memset)(void *, int, size_t) = memset;
+static __attribute__((__optimize__("-O0"))) void
+my_explicit_bzero(void *ptr, size_t size)
+{
+ (*my_explicit_memset)(ptr, 0, size);
+}
diff --git a/libkeccak/digest.c b/digest.c
index 891b471..891b471 100644
--- a/libkeccak/digest.c
+++ b/digest.c
diff --git a/man7/libkeccak.7 b/libkeccak.7
index 0a6ef04..0a6ef04 100644
--- a/man7/libkeccak.7
+++ b/libkeccak.7
diff --git a/libkeccak/hex.c b/libkeccak/hex.c
deleted file mode 100644
index 7db49a6..0000000
--- a/libkeccak/hex.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "../libkeccak.h"
-
-
-/**
- * Convert a binary hashsum to lower case hexadecimal representation
- *
- * @param output Output array, should have an allocation size of at least `2 * n + 1`
- * @param hashsum The hashsum to convert
- * @param n The size of `hashsum`
- */
-void
-libkeccak_behex_lower(char *restrict output, const void *restrict hashsum_, size_t n)
-{
- const char *restrict hashsum = hashsum_;
- output[2 * n] = '\0';
- while (n--) {
- output[2 * n + 0] = "0123456789abcdef"[(hashsum[n] >> 4) & 15];
- output[2 * n + 1] = "0123456789abcdef"[(hashsum[n] >> 0) & 15];
- }
-}
-
-
-/**
- * Convert a binary hashsum to upper case hexadecimal representation
- *
- * @param output Output array, should have an allocation size of at least `2 * n + 1`
- * @param hashsum The hashsum to convert
- * @param n The size of `hashsum`
- */
-void
-libkeccak_behex_upper(char *restrict output, const void *restrict hashsum_, size_t n)
-{
- const char *restrict hashsum = hashsum_;
- output[2 * n] = '\0';
- while (n--) {
- output[2 * n + 0] = "0123456789ABCDEF"[(hashsum[n] >> 4) & 15];
- output[2 * n + 1] = "0123456789ABCDEF"[(hashsum[n] >> 0) & 15];
- }
-}
-
-
-/**
- * Convert a hexadecimal hashsum (both lower case, upper
- * case and mixed is supported) to binary representation
- *
- * @param output Output array, should have an allocation size of at least `strlen(hashsum) / 2`
- * @param hashsum The hashsum to convert
- */
-void
-libkeccak_unhex(void *restrict output_, const char *restrict hashsum)
-{
- char *restrict output = output_;
- size_t n = strlen(hashsum) / 2;
- char a, b;
- while (n--) {
- a = hashsum[2 * n + 0];
- b = hashsum[2 * n + 1];
-
- a = (char)((a & 15) + (a > '9' ? 9 : 0));
- b = (char)((b & 15) + (b > '9' ? 9 : 0));
-
- output[n] = (char)((a << 4) | b);
- }
-}
diff --git a/libkeccak/hmac.c b/libkeccak/hmac.c
deleted file mode 100644
index 8b14eba..0000000
--- a/libkeccak/hmac.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "../common.h"
-
-
-
-/**
- * The outer pad pattern
- */
-#define OUTER_PAD 0x5C
-
-/**
- * The inner pad pattern
- */
-#define INNER_PAD 0x36
-
-
-
-static void *(*volatile my_explicit_memset)(void *, int, size_t) = memset;
-static __attribute__((__optimize__("-O0"))) void
-my_explicit_bzero(void *ptr, size_t size)
-{
- (*my_explicit_memset)(ptr, 0, size);
-}
-
-
-/**
- * Change the HMAC-hashing key on the state
- *
- * @param state The state that should be reset
- * @param key The new key
- * @param key_length The length of key, in bits
- * @return Zero on success, -1 on error
- */
-int
-libkeccak_hmac_set_key(libkeccak_hmac_state_t *restrict state, const void *restrict key, size_t key_length)
-{
- size_t i, size, new_key_length, key_bytes;
- char *old;
-
- size = (size_t)(state->sponge.r) > key_length ? (size_t)(state->sponge.r) : key_length;
- new_key_length = size;
- size = (size + 7) >> 3;
- key_bytes = (key_length + 7) >> 3;
-
- if (size != key_bytes) {
- state->key_opad = realloc(old = state->key_opad, 2 * size);
- if (!state->key_opad)
- return state->key_opad = old, -1;
- state->key_ipad = state->key_opad + size / sizeof(char);
- }
-
- memcpy(state->key_opad, key, key_bytes);
- if (key_length & 7)
- state->key_opad[(key_bytes >> 3) - 1] &= (char)((1 << (key_length & 7)) - 1);
-
- if ((size_t)(state->sponge.r) > key_length)
- __builtin_memset(state->key_opad + key_bytes / sizeof(char), 0, size - key_bytes);
-
- for (i = 0; i < size; i++) {
- state->key_ipad[i] = state->key_opad[i] ^ INNER_PAD;
- state->key_opad[i] ^= OUTER_PAD;
- }
-
- state->key_length = new_key_length;
-
- return 0;
-}
-
-
-/**
- * Wipe sensitive data wihout freeing any data
- *
- * @param state The state that should be wipe
- */
-void
-libkeccak_hmac_wipe(volatile libkeccak_hmac_state_t *restrict state)
-{
- volatile char *restrict key_pads;
- size_t i, size;
- key_pads = state->key_opad;
- size = 2 * ((state->key_length + 7) >> 3);
- libkeccak_state_wipe(&state->sponge);
- for (i = 0; i < size; i++)
- key_pads[i] = 0;
- state->leftover = 0;
- __builtin_memset(state->buffer, 0, state->buffer_size);
-}
-
-
-/**
- * Make a copy of an HMAC hashing-state
- *
- * @param dest The slot for the duplicate, must not be initialised (memory leak otherwise)
- * @param src The state to duplicate
- * @return Zero on success, -1 on error
- */
-int
-libkeccak_hmac_copy(libkeccak_hmac_state_t *restrict dest, const libkeccak_hmac_state_t *restrict src)
-{
- size_t size;
-
- dest->key_opad = NULL;
- dest->key_ipad = NULL;
-
- if (libkeccak_state_copy(&dest->sponge, &src->sponge) < 0)
- return -1;
-
- dest->key_length = src->key_length;
- dest->leftover = src->leftover;
-
- size = (src->key_length + 7) >> 3;
- dest->key_opad = malloc(2 * size);
- if (dest->key_opad == NULL)
- return libkeccak_state_destroy(&dest->sponge), -1;
- dest->key_ipad = dest->key_opad + size / sizeof(char);
-
- memcpy(dest->key_opad, src->key_opad, size);
- memcpy(dest->key_ipad, src->key_ipad, size);
-
- return 0;
-}
-
-
-/**
- * Unmarshal a `libkeccak_hmac_state_t` from a buffer
- *
- * @param state The slot for the unmarshalled state, must not be initialised (memory leak otherwise)
- * @param data The input buffer
- * @return The number of bytes read from `data`, 0 on error
- */
-size_t
-libkeccak_hmac_unmarshal(libkeccak_hmac_state_t *restrict state, const void *restrict data_)
-{
- const char *restrict data = data_;
- size_t parsed, size, i;
-
- state->key_opad = NULL;
- state->key_ipad = NULL;
-
- parsed = libkeccak_state_unmarshal(&state->sponge, data);
- if (parsed == 0)
- return 0;
-
- data += parsed / sizeof(char);
- state->key_length = *(const size_t *)data;
- data += sizeof(size_t) / sizeof(char);
- size = (state->key_length + 7) >> 3;
-
- state->key_opad = malloc(2 * size);
- if (!state->key_opad) {
- libkeccak_state_destroy(&state->sponge);
- return 0;
- }
- memcpy(state->key_opad, data, size);
- data += size / sizeof(char);
-
- if (data[0]) {
- state->key_ipad = state->key_opad + size / sizeof(char);
- memcpy(state->key_ipad, state->key_opad, size);
- for (i = 0; i < size / sizeof(char); i++)
- state->key_ipad[i] ^= (char)(OUTER_PAD ^ INNER_PAD);
- }
-
- state->leftover = data[1];
- state->buffer = NULL;
- state->buffer_size = 0;
-
- return parsed + sizeof(size_t) + size + 2 * sizeof(char);
-}
-
-
-/**
- * Absorb more, or the first part, of the message
- * without wiping sensitive data when possible
- *
- * @param state The hashing state
- * @param msg The partial message
- * @param msglen The length of the partial message, in bytes
- * @return Zero on success, -1 on error
- */
-int
-libkeccak_hmac_fast_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen)
-{
- const char *restrict msg = msg_;
- char *old;
- size_t i;
- int n, cn;
-
- if (state->key_ipad) {
- if (libkeccak_fast_update(&state->sponge, state->key_ipad, state->key_length >> 3) < 0)
- return -1;
- if (state->key_length & 7)
- state->leftover = state->key_ipad[state->key_length >> 3];
- state->key_ipad = NULL;
- }
-
- if (!msg || !msglen)
- return 0;
-
- if (!(state->key_length & 7))
- return libkeccak_fast_update(&state->sponge, msg, msglen);
-
- if (msglen != state->buffer_size) {
- state->buffer = realloc(old = state->buffer, msglen);
- if (!state->buffer)
- return state->buffer = old, -1;
- state->buffer_size = msglen;
- }
-
- n = (int)(state->key_length & 7);
- cn = 8 - n;
- for (i = 1; i < msglen; i++)
- state->buffer[i] = (char)((msg[i - 1] >> cn) | (msg[i] << n));
- state->buffer[0] = (char)((state->leftover & ((1 << n) - 1)) | (msg[0] << n));
- state->leftover = (char)((unsigned char)msg[msglen - 1] >> cn);
-
- return libkeccak_fast_update(&state->sponge, state->buffer, msglen);
-}
-
-
-/**
- * Absorb more, or the first part, of the message
- * and wipe sensitive data when possible
- *
- * @param state The hashing state
- * @param msg The partial message
- * @param msglen The length of the partial message, in bytes
- * @return Zero on success, -1 on error
- */
-int
-libkeccak_hmac_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen)
-{
- const char *restrict msg = msg_;
- size_t i;
- int n, cn, r;
-
- if (state->key_ipad) {
- if (libkeccak_update(&state->sponge, state->key_ipad, state->key_length >> 3) < 0)
- return -1;
- if (state->key_length & 7)
- state->leftover = state->key_ipad[state->key_length >> 3];
- state->key_ipad = NULL;
- }
-
- if (!msg || !msglen)
- return 0;
-
- if (!(state->key_length & 7))
- return libkeccak_update(&state->sponge, msg, msglen);
-
- if (msglen != state->buffer_size) {
- free(state->buffer);
- state->buffer = malloc(state->buffer_size = msglen);
- if (!state->buffer)
- return -1;
- }
-
- n = (int)(state->key_length & 7);
- cn = 8 - n;
- for (i = 1; i < msglen; i++)
- state->buffer[i] = (char)(((unsigned char)msg[i - 1] >> cn) | (msg[i] << n));
- state->buffer[0] = (char)((state->leftover & ((1 << n) - 1)) | (msg[0] << n));
- state->leftover = (char)((unsigned char)msg[msglen - 1] >> cn);
-
- r = libkeccak_update(&state->sponge, state->buffer, msglen);
- my_explicit_bzero(state->buffer, msglen);
- return r;
-}
-
-
-/**
- * Absorb the last part of the message and fetch the hash
- * without wiping sensitive data when possible
- *
- * You may use `&state->sponge` for continued squeezing
- *
- * @param state The hashing state
- * @param msg The rest of the message, may be `NULL`, may be modified
- * @param msglen The length of the partial message
- * @param bits The number of bits at the end of the message not covered by `msglen`
- * @param suffix The suffix concatenate to the message, only '1':s and '0':s, and NUL-termination
- * @param hashsum Output parameter for the hashsum, may be `NULL`
- * @return Zero on success, -1 on error
- */
-int
-libkeccak_hmac_fast_digest(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen,
- size_t bits, const char *restrict suffix, void *restrict hashsum)
-{
- const char *restrict msg = msg_;
- size_t hashsize = (size_t)state->sponge.n >> 3;
- char *tmp = malloc((size_t)((state->sponge.n + 7) >> 3) * sizeof(char));
- char leftover[2];
- size_t newlen;
-
- if (!tmp)
- return -1;
-
- if (!(state->key_length & 7)) {
- if (libkeccak_fast_digest(&state->sponge, msg, msglen, bits, suffix, tmp) < 0)
- goto fail;
- goto stage_2;
- }
-
- if (libkeccak_hmac_fast_update(state, msg, msglen) < 0)
- goto fail;
- leftover[0] = state->leftover;
- if (bits) {
- leftover[0] |= (char)(msg[msglen] >> (state->key_length & 7));
- leftover[1] = (char)((unsigned char)msg[msglen] << (8 - (state->key_length & 7)));
- }
- newlen = (state->key_length & 7) + bits;
- if (libkeccak_fast_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0)
- goto fail;
-
-stage_2:
- bits = state->sponge.n & 7;
- state->key_ipad = state->key_opad;
- if (libkeccak_hmac_fast_update(state, NULL, 0) < 0)
- goto fail;
-
- if (!(state->key_length & 7)) {
- if (libkeccak_fast_digest(&state->sponge, tmp, hashsize, bits, suffix, hashsum) < 0)
- goto fail;
- goto stage_3;
- }
-
- if (libkeccak_hmac_fast_update(state, tmp, hashsize) < 0)
- goto fail;
- leftover[0] = state->leftover;
- if (bits) {
- leftover[0] |= (char)(tmp[hashsize] >> (state->key_length & 7));
- leftover[1] = (char)((unsigned char)tmp[hashsize] << (8 - (state->key_length & 7)));
- }
- newlen = (state->key_length & 7) + bits;
- if (libkeccak_fast_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0)
- goto fail;
-
-stage_3:
- free(tmp);
- return 0;
-fail:
- free(tmp);
- return -1;
-}
-
-
-/**
- * Absorb the last part of the message and fetch the hash
- * and wipe sensitive data when possible
- *
- * You may use `&state->sponge` for continued squeezing
- *
- * @param state The hashing state
- * @param msg The rest of the message, may be `NULL`, may be modified
- * @param msglen The length of the partial message
- * @param bits The number of bits at the end of the message not covered by `msglen`
- * @param suffix The suffix concatenate to the message, only '1':s and '0':s, and NUL-termination
- * @param hashsum Output parameter for the hashsum, may be `NULL`
- * @return Zero on success, -1 on error
- */
-int
-libkeccak_hmac_digest(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen,
- size_t bits, const char *restrict suffix, void *restrict hashsum)
-{
- const char *restrict msg = msg_;
- size_t hashsize = (size_t)(state->sponge.n >> 3);
- char *tmp = malloc((size_t)((state->sponge.n + 7) >> 3) * sizeof(char));
- char leftover[2];
- size_t newlen;
-
- if (!tmp)
- return -1;
-
- if (!(state->key_length & 7)) {
- if (libkeccak_digest(&state->sponge, msg, msglen, bits, suffix, tmp) < 0)
- goto fail;
- goto stage_2;
- }
-
- if (libkeccak_hmac_update(state, msg, msglen) < 0)
- goto fail;
- leftover[0] = state->leftover;
- if (bits) {
- leftover[0] |= (char)(msg[msglen] >> (state->key_length & 7));
- leftover[1] = (char)((unsigned char)msg[msglen] << (8 - (state->key_length & 7)));
- }
- newlen = (state->key_length & 7) + bits;
- if (libkeccak_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0)
- goto fail;
-
-stage_2:
- bits = state->sponge.n & 7;
- state->key_ipad = state->key_opad;
- if (libkeccak_hmac_update(state, NULL, 0) < 0)
- goto fail;
-
- if (!(state->key_length & 7)) {
- if (libkeccak_digest(&state->sponge, tmp, hashsize, bits, suffix, hashsum) < 0)
- goto fail;
- goto stage_3;
- }
-
- if (libkeccak_hmac_update(state, tmp, hashsize) < 0)
- goto fail;
- leftover[0] = state->leftover;
- if (bits) {
- leftover[0] |= (char)(tmp[hashsize] >> (state->key_length & 7));
- leftover[1] = (char)((unsigned char)tmp[hashsize] << (8 - (state->key_length & 7)));
- }
- newlen = (state->key_length & 7) + bits;
- if (libkeccak_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0)
- goto fail;
-
-stage_3:
- my_explicit_bzero(tmp, (size_t)((state->sponge.n + 7) >> 3) * sizeof(char));
- free(tmp);
- return 0;
-fail:
- my_explicit_bzero(tmp, (size_t)((state->sponge.n + 7) >> 3) * sizeof(char));
- free(tmp);
- return -1;
-}
-
diff --git a/libkeccak/state.c b/libkeccak/state.c
deleted file mode 100644
index 9e0ffb1..0000000
--- a/libkeccak/state.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "../common.h"
-
-
-/**
- * Initialise a state according to hashing specifications
- *
- * @param state The state that should be initialised
- * @param spec The specifications for the state
- * @return Zero on success, -1 on error
- */
-int
-libkeccak_state_initialise(libkeccak_state_t *restrict state, const libkeccak_spec_t *restrict spec)
-{
- long int x;
- state->r = spec->bitrate;
- state->n = spec->output;
- state->c = spec->capacity;
- state->b = state->r + state->c;
- state->w = x = state->b / 25;
- state->l = 0;
- if (x & 0xF0L) state->l |= 4, x >>= 4;
- if (x & 0x0CL) state->l |= 2, x >>= 2;
- if (x & 0x02L) state->l |= 1;
- state->nr = 12 + (state->l << 1);
- state->wmod = (state->w == 64) ? ~0LL : (int64_t)((1ULL << state->w) - 1);
- for (x = 0; x < 25; x++)
- state->S[x] = 0;
- state->mptr = 0;
- state->mlen = (size_t)(state->r * state->b) >> 2;
- state->M = malloc(state->mlen * sizeof(char));
- return state->M == NULL ? -1 : 0;
-}
-
-
-/**
- * Wipe data in the state's message wihout freeing any data
- *
- * @param state The state that should be wipe
- */
-void
-libkeccak_state_wipe_message(volatile libkeccak_state_t *restrict state)
-{
- volatile char *restrict M = state->M;
- size_t i;
- for (i = 0; i < state->mptr; i++)
- M[i] = 0;
-}
-
-/**
- * Wipe data in the state's sponge wihout freeing any data
- *
- * @param state The state that should be wipe
- */
-void
-libkeccak_state_wipe_sponge(volatile libkeccak_state_t *restrict state)
-{
- volatile int64_t *restrict S = state->S;
- size_t i;
- for (i = 0; i < 25; i++)
- S[i] = 0;
-}
-
-/**
- * Wipe sensitive data wihout freeing any data
- *
- * @param state The state that should be wipe
- */
-void
-libkeccak_state_wipe(volatile libkeccak_state_t *restrict state)
-{
- libkeccak_state_wipe_message(state);
- libkeccak_state_wipe_sponge(state);
-}
-
-
-/**
- * Make a copy of a state
- *
- * @param dest The slot for the duplicate, must not be initialised (memory leak otherwise)
- * @param src The state to duplicate
- * @return Zero on success, -1 on error
- */
-int
-libkeccak_state_copy(libkeccak_state_t *restrict dest, const libkeccak_state_t *restrict src)
-{
- memcpy(dest, src, sizeof(libkeccak_state_t));
- dest->M = malloc(src->mlen * sizeof(char));
- if (!dest->M)
- return -1;
- memcpy(dest->M, src->M, src->mptr * sizeof(char));
- return 0;
-}
-
-
-/**
- * Marshal a `libkeccak_state_t` into a buffer
- *
- * @param state The state to marshal
- * @param data The output buffer
- * @return The number of bytes stored to `data`
- */
-size_t
-libkeccak_state_marshal(const libkeccak_state_t *restrict state, void *restrict data_)
-{
-#define set(type, var) *((type *)data) = state->var, data += sizeof(type) / sizeof(char)
- char *restrict data = data_;
- set(long int, r);
- set(long int, c);
- set(long int, n);
- set(long int, b);
- set(long int, w);
- set(int64_t, wmod);
- set(long int, l);
- set(long int, nr);
- memcpy(data, state->S, sizeof(state->S));
- data += sizeof(state->S) / sizeof(char);
- set(size_t, mptr);
- set(size_t, mlen);
- memcpy(data, state->M, state->mptr * sizeof(char));
- data += state->mptr;
- return sizeof(libkeccak_state_t) - sizeof(char *) + state->mptr * sizeof(char);
-#undef set
-}
-
-
-/**
- * Unmarshal a `libkeccak_state_t` from a buffer
- *
- * @param state The slot for the unmarshalled state, must not be initialised (memory leak otherwise)
- * @param data The input buffer
- * @return The number of bytes read from `data`, 0 on error
- */
-size_t
-libkeccak_state_unmarshal(libkeccak_state_t *restrict state, const void *restrict data_)
-{
-#define get(type, var) state->var = *((const type *)data), data += sizeof(type) / sizeof(char)
- const char *restrict data = data_;
- get(long int, r);
- get(long int, c);
- get(long int, n);
- get(long int, b);
- get(long int, w);
- get(int64_t, wmod);
- get(long int, l);
- get(long int, nr);
- memcpy(state->S, data, sizeof(state->S));
- data += sizeof(state->S) / sizeof(char);
- get(size_t, mptr);
- get(size_t, mlen);
- state->M = malloc(state->mptr * sizeof(char));
- if (!state->M)
- return 0;
- memcpy(state->M, data, state->mptr * sizeof(char));
- data += state->mptr;
- return sizeof(libkeccak_state_t) - sizeof(char *) + state->mptr * sizeof(char);
-#undef get
-}
-
-
-/**
- * Gets the number of bytes the `libkeccak_state_t` stored
- * at the beginning of `data` occupies
- *
- * @param data The data buffer
- * @return The byte size of the stored state
- */
-size_t
-libkeccak_state_unmarshal_skip(const void *restrict data_)
-{
- const char *restrict data = data_;
- data += (7 * sizeof(long int) + 26 * sizeof(int64_t)) / sizeof(char);
- return sizeof(libkeccak_state_t) - sizeof(char *) + *(const size_t *)data * sizeof(char);
-}
diff --git a/man3/libkeccak_behex_lower.3 b/libkeccak_behex_lower.3
index 2078790..2078790 100644
--- a/man3/libkeccak_behex_lower.3
+++ b/libkeccak_behex_lower.3
diff --git a/libkeccak_behex_lower.c b/libkeccak_behex_lower.c
new file mode 100644
index 0000000..77e48c1
--- /dev/null
+++ b/libkeccak_behex_lower.c
@@ -0,0 +1,21 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Convert a binary hashsum to lower case hexadecimal representation
+ *
+ * @param output Output array, should have an allocation size of at least `2 * n + 1`
+ * @param hashsum The hashsum to convert
+ * @param n The size of `hashsum`
+ */
+void
+libkeccak_behex_lower(char *restrict output, const void *restrict hashsum_, size_t n)
+{
+ const unsigned char *restrict hashsum = hashsum_;
+ output[2 * n] = '\0';
+ while (n--) {
+ output[2 * n + 0] = "0123456789abcdef"[(hashsum[n] >> 4) & 15];
+ output[2 * n + 1] = "0123456789abcdef"[(hashsum[n] >> 0) & 15];
+ }
+}
diff --git a/man3/libkeccak_behex_upper.3 b/libkeccak_behex_upper.3
index b5c67bb..b5c67bb 100644
--- a/man3/libkeccak_behex_upper.3
+++ b/libkeccak_behex_upper.3
diff --git a/libkeccak_behex_upper.c b/libkeccak_behex_upper.c
new file mode 100644
index 0000000..73a67a1
--- /dev/null
+++ b/libkeccak_behex_upper.c
@@ -0,0 +1,21 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Convert a binary hashsum to upper case hexadecimal representation
+ *
+ * @param output Output array, should have an allocation size of at least `2 * n + 1`
+ * @param hashsum The hashsum to convert
+ * @param n The size of `hashsum`
+ */
+void
+libkeccak_behex_upper(char *restrict output, const void *restrict hashsum_, size_t n)
+{
+ const unsigned char *restrict hashsum = hashsum_;
+ output[2 * n] = '\0';
+ while (n--) {
+ output[2 * n + 0] = "0123456789ABCDEF"[(hashsum[n] >> 4) & 15];
+ output[2 * n + 1] = "0123456789ABCDEF"[(hashsum[n] >> 0) & 15];
+ }
+}
diff --git a/man3/libkeccak_degeneralise_spec.3 b/libkeccak_degeneralise_spec.3
index 7ec2b72..7ec2b72 100644
--- a/man3/libkeccak_degeneralise_spec.3
+++ b/libkeccak_degeneralise_spec.3
diff --git a/libkeccak/generalised-spec.c b/libkeccak_degeneralise_spec.c
index 0f78583..13963f8 100644
--- a/libkeccak/generalised-spec.c
+++ b/libkeccak_degeneralise_spec.c
@@ -1,5 +1,5 @@
/* See LICENSE file for copyright and license details. */
-#include "../common.h"
+#include "common.h"
#ifdef __GNUC__
@@ -12,7 +12,6 @@
#define deft(v, dv) (have_##v ? v : (dv))
-
/**
* Convert a `libkeccak_generalised_spec_t` to a `libkeccak_spec_t`
*
diff --git a/man3/libkeccak_digest.3 b/libkeccak_digest.3
index 5f42796..5f42796 100644
--- a/man3/libkeccak_digest.3
+++ b/libkeccak_digest.3
diff --git a/man3/libkeccak_fast_digest.3 b/libkeccak_fast_digest.3
index 9e9c1f3..9e9c1f3 100644
--- a/man3/libkeccak_fast_digest.3
+++ b/libkeccak_fast_digest.3
diff --git a/man3/libkeccak_fast_squeeze.3 b/libkeccak_fast_squeeze.3
index 393e264..393e264 100644
--- a/man3/libkeccak_fast_squeeze.3
+++ b/libkeccak_fast_squeeze.3
diff --git a/man3/libkeccak_fast_update.3 b/libkeccak_fast_update.3
index 3398984..3398984 100644
--- a/man3/libkeccak_fast_update.3
+++ b/libkeccak_fast_update.3
diff --git a/man3/libkeccak_generalised_spec_initialise.3 b/libkeccak_generalised_spec_initialise.3
index 1a3bccb..1a3bccb 100644
--- a/man3/libkeccak_generalised_spec_initialise.3
+++ b/libkeccak_generalised_spec_initialise.3
diff --git a/man3/libkeccak_generalised_sum_fd.3 b/libkeccak_generalised_sum_fd.3
index bae5bae..bae5bae 100644
--- a/man3/libkeccak_generalised_sum_fd.3
+++ b/libkeccak_generalised_sum_fd.3
diff --git a/libkeccak/files.c b/libkeccak_generalised_sum_fd.c
index 14a4290..133ffa9 100644
--- a/libkeccak/files.c
+++ b/libkeccak_generalised_sum_fd.c
@@ -1,5 +1,5 @@
/* See LICENSE file for copyright and license details. */
-#include "../common.h"
+#include "common.h"
/**
diff --git a/man3/libkeccak_hmac_copy.3 b/libkeccak_hmac_copy.3
index 0f29ae8..0f29ae8 100644
--- a/man3/libkeccak_hmac_copy.3
+++ b/libkeccak_hmac_copy.3
diff --git a/libkeccak_hmac_copy.c b/libkeccak_hmac_copy.c
new file mode 100644
index 0000000..49fc1e7
--- /dev/null
+++ b/libkeccak_hmac_copy.c
@@ -0,0 +1,38 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Make a copy of an HMAC hashing-state
+ *
+ * @param dest The slot for the duplicate, must not be initialised (memory leak otherwise)
+ * @param src The state to duplicate
+ * @return Zero on success, -1 on error
+ */
+int
+libkeccak_hmac_copy(libkeccak_hmac_state_t *restrict dest, const libkeccak_hmac_state_t *restrict src)
+{
+ size_t size;
+
+ dest->key_opad = NULL;
+ dest->key_ipad = NULL;
+
+ if (libkeccak_state_copy(&dest->sponge, &src->sponge) < 0)
+ return -1;
+
+ dest->key_length = src->key_length;
+ dest->leftover = src->leftover;
+
+ size = (src->key_length + 7) >> 3;
+ dest->key_opad = malloc(2 * size);
+ if (dest->key_opad == NULL) {
+ libkeccak_state_destroy(&dest->sponge);
+ return -1;
+ }
+ dest->key_ipad = dest->key_opad + size / sizeof(char);
+
+ memcpy(dest->key_opad, src->key_opad, size);
+ memcpy(dest->key_ipad, src->key_ipad, size);
+
+ return 0;
+}
diff --git a/man3/libkeccak_hmac_create.3 b/libkeccak_hmac_create.3
index 91bb8a1..91bb8a1 100644
--- a/man3/libkeccak_hmac_create.3
+++ b/libkeccak_hmac_create.3
diff --git a/man3/libkeccak_hmac_destroy.3 b/libkeccak_hmac_destroy.3
index 0038eca..0038eca 100644
--- a/man3/libkeccak_hmac_destroy.3
+++ b/libkeccak_hmac_destroy.3
diff --git a/man3/libkeccak_hmac_digest.3 b/libkeccak_hmac_digest.3
index 99e460a..99e460a 100644
--- a/man3/libkeccak_hmac_digest.3
+++ b/libkeccak_hmac_digest.3
diff --git a/libkeccak_hmac_digest.c b/libkeccak_hmac_digest.c
new file mode 100644
index 0000000..1cba224
--- /dev/null
+++ b/libkeccak_hmac_digest.c
@@ -0,0 +1,80 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Absorb the last part of the message and fetch the hash
+ * and wipe sensitive data when possible
+ *
+ * You may use `&state->sponge` for continued squeezing
+ *
+ * @param state The hashing state
+ * @param msg The rest of the message, may be `NULL`, may be modified
+ * @param msglen The length of the partial message
+ * @param bits The number of bits at the end of the message not covered by `msglen`
+ * @param suffix The suffix concatenate to the message, only '1':s and '0':s, and NUL-termination
+ * @param hashsum Output parameter for the hashsum, may be `NULL`
+ * @return Zero on success, -1 on error
+ */
+int
+libkeccak_hmac_digest(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen,
+ size_t bits, const char *restrict suffix, void *restrict hashsum)
+{
+ const char *restrict msg = msg_;
+ size_t hashsize = (size_t)(state->sponge.n >> 3);
+ char *tmp = malloc((size_t)((state->sponge.n + 7) >> 3) * sizeof(char));
+ char leftover[2];
+ size_t newlen;
+
+ if (!tmp)
+ return -1;
+
+ if (!(state->key_length & 7)) {
+ if (libkeccak_digest(&state->sponge, msg, msglen, bits, suffix, tmp) < 0)
+ goto fail;
+ goto stage_2;
+ }
+
+ if (libkeccak_hmac_update(state, msg, msglen) < 0)
+ goto fail;
+ leftover[0] = state->leftover;
+ if (bits) {
+ leftover[0] |= (char)(msg[msglen] >> (state->key_length & 7));
+ leftover[1] = (char)((unsigned char)msg[msglen] << (8 - (state->key_length & 7)));
+ }
+ newlen = (state->key_length & 7) + bits;
+ if (libkeccak_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0)
+ goto fail;
+
+stage_2:
+ bits = state->sponge.n & 7;
+ state->key_ipad = state->key_opad;
+ if (libkeccak_hmac_update(state, NULL, 0) < 0)
+ goto fail;
+
+ if (!(state->key_length & 7)) {
+ if (libkeccak_digest(&state->sponge, tmp, hashsize, bits, suffix, hashsum) < 0)
+ goto fail;
+ goto stage_3;
+ }
+
+ if (libkeccak_hmac_update(state, tmp, hashsize) < 0)
+ goto fail;
+ leftover[0] = state->leftover;
+ if (bits) {
+ leftover[0] |= (char)(tmp[hashsize] >> (state->key_length & 7));
+ leftover[1] = (char)((unsigned char)tmp[hashsize] << (8 - (state->key_length & 7)));
+ }
+ newlen = (state->key_length & 7) + bits;
+ if (libkeccak_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0)
+ goto fail;
+
+stage_3:
+ my_explicit_bzero(tmp, (size_t)((state->sponge.n + 7) >> 3) * sizeof(char));
+ free(tmp);
+ return 0;
+fail:
+ my_explicit_bzero(tmp, (size_t)((state->sponge.n + 7) >> 3) * sizeof(char));
+ free(tmp);
+ return -1;
+}
diff --git a/man3/libkeccak_hmac_duplicate.3 b/libkeccak_hmac_duplicate.3
index bb16139..bb16139 100644
--- a/man3/libkeccak_hmac_duplicate.3
+++ b/libkeccak_hmac_duplicate.3
diff --git a/man3/libkeccak_hmac_fast_destroy.3 b/libkeccak_hmac_fast_destroy.3
index 31bf894..31bf894 100644
--- a/man3/libkeccak_hmac_fast_destroy.3
+++ b/libkeccak_hmac_fast_destroy.3
diff --git a/man3/libkeccak_hmac_fast_digest.3 b/libkeccak_hmac_fast_digest.3
index 68fcc69..68fcc69 100644
--- a/man3/libkeccak_hmac_fast_digest.3
+++ b/libkeccak_hmac_fast_digest.3
diff --git a/libkeccak_hmac_fast_digest.c b/libkeccak_hmac_fast_digest.c
new file mode 100644
index 0000000..d4bacb8
--- /dev/null
+++ b/libkeccak_hmac_fast_digest.c
@@ -0,0 +1,78 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Absorb the last part of the message and fetch the hash
+ * without wiping sensitive data when possible
+ *
+ * You may use `&state->sponge` for continued squeezing
+ *
+ * @param state The hashing state
+ * @param msg The rest of the message, may be `NULL`, may be modified
+ * @param msglen The length of the partial message
+ * @param bits The number of bits at the end of the message not covered by `msglen`
+ * @param suffix The suffix concatenate to the message, only '1':s and '0':s, and NUL-termination
+ * @param hashsum Output parameter for the hashsum, may be `NULL`
+ * @return Zero on success, -1 on error
+ */
+int
+libkeccak_hmac_fast_digest(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen,
+ size_t bits, const char *restrict suffix, void *restrict hashsum)
+{
+ const char *restrict msg = msg_;
+ size_t hashsize = (size_t)state->sponge.n >> 3;
+ char *tmp = malloc((size_t)((state->sponge.n + 7) >> 3) * sizeof(char));
+ char leftover[2];
+ size_t newlen;
+
+ if (!tmp)
+ return -1;
+
+ if (!(state->key_length & 7)) {
+ if (libkeccak_fast_digest(&state->sponge, msg, msglen, bits, suffix, tmp) < 0)
+ goto fail;
+ goto stage_2;
+ }
+
+ if (libkeccak_hmac_fast_update(state, msg, msglen) < 0)
+ goto fail;
+ leftover[0] = state->leftover;
+ if (bits) {
+ leftover[0] |= (char)(msg[msglen] >> (state->key_length & 7));
+ leftover[1] = (char)((unsigned char)msg[msglen] << (8 - (state->key_length & 7)));
+ }
+ newlen = (state->key_length & 7) + bits;
+ if (libkeccak_fast_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0)
+ goto fail;
+
+stage_2:
+ bits = state->sponge.n & 7;
+ state->key_ipad = state->key_opad;
+ if (libkeccak_hmac_fast_update(state, NULL, 0) < 0)
+ goto fail;
+
+ if (!(state->key_length & 7)) {
+ if (libkeccak_fast_digest(&state->sponge, tmp, hashsize, bits, suffix, hashsum) < 0)
+ goto fail;
+ goto stage_3;
+ }
+
+ if (libkeccak_hmac_fast_update(state, tmp, hashsize) < 0)
+ goto fail;
+ leftover[0] = state->leftover;
+ if (bits) {
+ leftover[0] |= (char)(tmp[hashsize] >> (state->key_length & 7));
+ leftover[1] = (char)((unsigned char)tmp[hashsize] << (8 - (state->key_length & 7)));
+ }
+ newlen = (state->key_length & 7) + bits;
+ if (libkeccak_fast_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0)
+ goto fail;
+
+stage_3:
+ free(tmp);
+ return 0;
+fail:
+ free(tmp);
+ return -1;
+}
diff --git a/man3/libkeccak_hmac_fast_free.3 b/libkeccak_hmac_fast_free.3
index f888872..f888872 100644
--- a/man3/libkeccak_hmac_fast_free.3
+++ b/libkeccak_hmac_fast_free.3
diff --git a/man3/libkeccak_hmac_fast_update.3 b/libkeccak_hmac_fast_update.3
index a41b72f..a41b72f 100644
--- a/man3/libkeccak_hmac_fast_update.3
+++ b/libkeccak_hmac_fast_update.3
diff --git a/libkeccak_hmac_fast_update.c b/libkeccak_hmac_fast_update.c
new file mode 100644
index 0000000..d4a3fbe
--- /dev/null
+++ b/libkeccak_hmac_fast_update.c
@@ -0,0 +1,51 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Absorb more, or the first part, of the message
+ * without wiping sensitive data when possible
+ *
+ * @param state The hashing state
+ * @param msg The partial message
+ * @param msglen The length of the partial message, in bytes
+ * @return Zero on success, -1 on error
+ */
+int
+libkeccak_hmac_fast_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen)
+{
+ const char *restrict msg = msg_;
+ char *old;
+ size_t i;
+ int n, cn;
+
+ if (state->key_ipad) {
+ if (libkeccak_fast_update(&state->sponge, state->key_ipad, state->key_length >> 3) < 0)
+ return -1;
+ if (state->key_length & 7)
+ state->leftover = state->key_ipad[state->key_length >> 3];
+ state->key_ipad = NULL;
+ }
+
+ if (!msg || !msglen)
+ return 0;
+
+ if (!(state->key_length & 7))
+ return libkeccak_fast_update(&state->sponge, msg, msglen);
+
+ if (msglen != state->buffer_size) {
+ state->buffer = realloc(old = state->buffer, msglen);
+ if (!state->buffer)
+ return state->buffer = old, -1;
+ state->buffer_size = msglen;
+ }
+
+ n = (int)(state->key_length & 7);
+ cn = 8 - n;
+ for (i = 1; i < msglen; i++)
+ state->buffer[i] = (char)((msg[i - 1] >> cn) | (msg[i] << n));
+ state->buffer[0] = (char)((state->leftover & ((1 << n) - 1)) | (msg[0] << n));
+ state->leftover = (char)((unsigned char)msg[msglen - 1] >> cn);
+
+ return libkeccak_fast_update(&state->sponge, state->buffer, msglen);
+}
diff --git a/man3/libkeccak_hmac_free.3 b/libkeccak_hmac_free.3
index c70f369..c70f369 100644
--- a/man3/libkeccak_hmac_free.3
+++ b/libkeccak_hmac_free.3
diff --git a/man3/libkeccak_hmac_initialise.3 b/libkeccak_hmac_initialise.3
index 17b2b9f..17b2b9f 100644
--- a/man3/libkeccak_hmac_initialise.3
+++ b/libkeccak_hmac_initialise.3
diff --git a/man3/libkeccak_hmac_marshal.3 b/libkeccak_hmac_marshal.3
index 2e31dd7..2e31dd7 100644
--- a/man3/libkeccak_hmac_marshal.3
+++ b/libkeccak_hmac_marshal.3
diff --git a/man3/libkeccak_hmac_marshal_size.3 b/libkeccak_hmac_marshal_size.3
index fe8ec2f..fe8ec2f 100644
--- a/man3/libkeccak_hmac_marshal_size.3
+++ b/libkeccak_hmac_marshal_size.3
diff --git a/man3/libkeccak_hmac_reset.3 b/libkeccak_hmac_reset.3
index 4a9aadf..4a9aadf 100644
--- a/man3/libkeccak_hmac_reset.3
+++ b/libkeccak_hmac_reset.3
diff --git a/man3/libkeccak_hmac_set_key.3 b/libkeccak_hmac_set_key.3
index ea8084e..ea8084e 100644
--- a/man3/libkeccak_hmac_set_key.3
+++ b/libkeccak_hmac_set_key.3
diff --git a/libkeccak_hmac_set_key.c b/libkeccak_hmac_set_key.c
new file mode 100644
index 0000000..4f450f8
--- /dev/null
+++ b/libkeccak_hmac_set_key.c
@@ -0,0 +1,46 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Change the HMAC-hashing key on the state
+ *
+ * @param state The state that should be reset
+ * @param key The new key
+ * @param key_length The length of key, in bits
+ * @return Zero on success, -1 on error
+ */
+int
+libkeccak_hmac_set_key(libkeccak_hmac_state_t *restrict state, const void *restrict key, size_t key_length)
+{
+ size_t i, size, new_key_length, key_bytes;
+ char *old;
+
+ size = (size_t)(state->sponge.r) > key_length ? (size_t)(state->sponge.r) : key_length;
+ new_key_length = size;
+ size = (size + 7) >> 3;
+ key_bytes = (key_length + 7) >> 3;
+
+ if (size != key_bytes) {
+ state->key_opad = realloc(old = state->key_opad, 2 * size);
+ if (!state->key_opad)
+ return state->key_opad = old, -1;
+ state->key_ipad = state->key_opad + size / sizeof(char);
+ }
+
+ memcpy(state->key_opad, key, key_bytes);
+ if (key_length & 7)
+ state->key_opad[(key_bytes >> 3) - 1] &= (char)((1 << (key_length & 7)) - 1);
+
+ if ((size_t)(state->sponge.r) > key_length)
+ __builtin_memset(state->key_opad + key_bytes / sizeof(char), 0, size - key_bytes);
+
+ for (i = 0; i < size; i++) {
+ state->key_ipad[i] = state->key_opad[i] ^ HMAC_INNER_PAD;
+ state->key_opad[i] ^= HMAC_OUTER_PAD;
+ }
+
+ state->key_length = new_key_length;
+
+ return 0;
+}
diff --git a/man3/libkeccak_hmac_unmarshal.3 b/libkeccak_hmac_unmarshal.3
index c3ed187..c3ed187 100644
--- a/man3/libkeccak_hmac_unmarshal.3
+++ b/libkeccak_hmac_unmarshal.3
diff --git a/libkeccak_hmac_unmarshal.c b/libkeccak_hmac_unmarshal.c
new file mode 100644
index 0000000..e64cd08
--- /dev/null
+++ b/libkeccak_hmac_unmarshal.c
@@ -0,0 +1,50 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Unmarshal a `libkeccak_hmac_state_t` from a buffer
+ *
+ * @param state The slot for the unmarshalled state, must not be initialised (memory leak otherwise)
+ * @param data The input buffer
+ * @return The number of bytes read from `data`, 0 on error
+ */
+size_t
+libkeccak_hmac_unmarshal(libkeccak_hmac_state_t *restrict state, const void *restrict data_)
+{
+ const char *restrict data = data_;
+ size_t parsed, size, i;
+
+ state->key_opad = NULL;
+ state->key_ipad = NULL;
+
+ parsed = libkeccak_state_unmarshal(&state->sponge, data);
+ if (parsed == 0)
+ return 0;
+
+ data += parsed / sizeof(char);
+ state->key_length = *(const size_t *)data;
+ data += sizeof(size_t) / sizeof(char);
+ size = (state->key_length + 7) >> 3;
+
+ state->key_opad = malloc(2 * size);
+ if (!state->key_opad) {
+ libkeccak_state_destroy(&state->sponge);
+ return 0;
+ }
+ memcpy(state->key_opad, data, size);
+ data += size / sizeof(char);
+
+ if (data[0]) {
+ state->key_ipad = state->key_opad + size / sizeof(char);
+ memcpy(state->key_ipad, state->key_opad, size);
+ for (i = 0; i < size / sizeof(char); i++)
+ state->key_ipad[i] ^= (char)(HMAC_OUTER_PAD ^ HMAC_INNER_PAD);
+ }
+
+ state->leftover = data[1];
+ state->buffer = NULL;
+ state->buffer_size = 0;
+
+ return parsed + sizeof(size_t) + size + 2 * sizeof(char);
+}
diff --git a/man3/libkeccak_hmac_unmarshal_skip.3 b/libkeccak_hmac_unmarshal_skip.3
index 25db1ba..25db1ba 100644
--- a/man3/libkeccak_hmac_unmarshal_skip.3
+++ b/libkeccak_hmac_unmarshal_skip.3
diff --git a/man3/libkeccak_hmac_update.3 b/libkeccak_hmac_update.3
index 13891cb..13891cb 100644
--- a/man3/libkeccak_hmac_update.3
+++ b/libkeccak_hmac_update.3
diff --git a/libkeccak_hmac_update.c b/libkeccak_hmac_update.c
new file mode 100644
index 0000000..b2321f2
--- /dev/null
+++ b/libkeccak_hmac_update.c
@@ -0,0 +1,52 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Absorb more, or the first part, of the message
+ * and wipe sensitive data when possible
+ *
+ * @param state The hashing state
+ * @param msg The partial message
+ * @param msglen The length of the partial message, in bytes
+ * @return Zero on success, -1 on error
+ */
+int
+libkeccak_hmac_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen)
+{
+ const char *restrict msg = msg_;
+ size_t i;
+ int n, cn, r;
+
+ if (state->key_ipad) {
+ if (libkeccak_update(&state->sponge, state->key_ipad, state->key_length >> 3) < 0)
+ return -1;
+ if (state->key_length & 7)
+ state->leftover = state->key_ipad[state->key_length >> 3];
+ state->key_ipad = NULL;
+ }
+
+ if (!msg || !msglen)
+ return 0;
+
+ if (!(state->key_length & 7))
+ return libkeccak_update(&state->sponge, msg, msglen);
+
+ if (msglen != state->buffer_size) {
+ free(state->buffer);
+ state->buffer = malloc(state->buffer_size = msglen);
+ if (!state->buffer)
+ return -1;
+ }
+
+ n = (int)(state->key_length & 7);
+ cn = 8 - n;
+ for (i = 1; i < msglen; i++)
+ state->buffer[i] = (char)(((unsigned char)msg[i - 1] >> cn) | (msg[i] << n));
+ state->buffer[0] = (char)((state->leftover & ((1 << n) - 1)) | (msg[0] << n));
+ state->leftover = (char)((unsigned char)msg[msglen - 1] >> cn);
+
+ r = libkeccak_update(&state->sponge, state->buffer, msglen);
+ my_explicit_bzero(state->buffer, msglen);
+ return r;
+}
diff --git a/man3/libkeccak_hmac_wipe.3 b/libkeccak_hmac_wipe.3
index 471a9a8..471a9a8 100644
--- a/man3/libkeccak_hmac_wipe.3
+++ b/libkeccak_hmac_wipe.3
diff --git a/libkeccak_hmac_wipe.c b/libkeccak_hmac_wipe.c
new file mode 100644
index 0000000..fd99c48
--- /dev/null
+++ b/libkeccak_hmac_wipe.c
@@ -0,0 +1,22 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Wipe sensitive data wihout freeing any data
+ *
+ * @param state The state that should be wipe
+ */
+void
+libkeccak_hmac_wipe(volatile libkeccak_hmac_state_t *restrict state)
+{
+ volatile char *restrict key_pads;
+ size_t i, size;
+ key_pads = state->key_opad;
+ size = 2 * ((state->key_length + 7) >> 3);
+ libkeccak_state_wipe(&state->sponge);
+ for (i = 0; i < size; i++)
+ key_pads[i] = 0;
+ state->leftover = 0;
+ __builtin_memset(state->buffer, 0, state->buffer_size);
+}
diff --git a/man3/libkeccak_keccaksum_fd.3 b/libkeccak_keccaksum_fd.3
index ccd1f8a..ccd1f8a 100644
--- a/man3/libkeccak_keccaksum_fd.3
+++ b/libkeccak_keccaksum_fd.3
diff --git a/man3/libkeccak_rawshakesum_fd.3 b/libkeccak_rawshakesum_fd.3
index 8fad150..8fad150 100644
--- a/man3/libkeccak_rawshakesum_fd.3
+++ b/libkeccak_rawshakesum_fd.3
diff --git a/man3/libkeccak_sha3sum_fd.3 b/libkeccak_sha3sum_fd.3
index 0d697e6..0d697e6 100644
--- a/man3/libkeccak_sha3sum_fd.3
+++ b/libkeccak_sha3sum_fd.3
diff --git a/man3/libkeccak_shakesum_fd.3 b/libkeccak_shakesum_fd.3
index 441c549..441c549 100644
--- a/man3/libkeccak_shakesum_fd.3
+++ b/libkeccak_shakesum_fd.3
diff --git a/man3/libkeccak_simple_squeeze.3 b/libkeccak_simple_squeeze.3
index 8626f5a..8626f5a 100644
--- a/man3/libkeccak_simple_squeeze.3
+++ b/libkeccak_simple_squeeze.3
diff --git a/man3/libkeccak_spec_check.3 b/libkeccak_spec_check.3
index 7dd19d8..7dd19d8 100644
--- a/man3/libkeccak_spec_check.3
+++ b/libkeccak_spec_check.3
diff --git a/man3/libkeccak_spec_rawshake.3 b/libkeccak_spec_rawshake.3
index f5f16b8..f5f16b8 100644
--- a/man3/libkeccak_spec_rawshake.3
+++ b/libkeccak_spec_rawshake.3
diff --git a/man3/libkeccak_spec_sha3.3 b/libkeccak_spec_sha3.3
index 1320631..1320631 100644
--- a/man3/libkeccak_spec_sha3.3
+++ b/libkeccak_spec_sha3.3
diff --git a/man3/libkeccak_spec_shake.3 b/libkeccak_spec_shake.3
index 4beea49..4beea49 100644
--- a/man3/libkeccak_spec_shake.3
+++ b/libkeccak_spec_shake.3
diff --git a/man3/libkeccak_squeeze.3 b/libkeccak_squeeze.3
index 67430a4..67430a4 100644
--- a/man3/libkeccak_squeeze.3
+++ b/libkeccak_squeeze.3
diff --git a/man3/libkeccak_state_copy.3 b/libkeccak_state_copy.3
index 4bd892c..4bd892c 100644
--- a/man3/libkeccak_state_copy.3
+++ b/libkeccak_state_copy.3
diff --git a/libkeccak_state_copy.c b/libkeccak_state_copy.c
new file mode 100644
index 0000000..76672d2
--- /dev/null
+++ b/libkeccak_state_copy.c
@@ -0,0 +1,21 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Make a copy of a state
+ *
+ * @param dest The slot for the duplicate, must not be initialised (memory leak otherwise)
+ * @param src The state to duplicate
+ * @return Zero on success, -1 on error
+ */
+int
+libkeccak_state_copy(libkeccak_state_t *restrict dest, const libkeccak_state_t *restrict src)
+{
+ memcpy(dest, src, sizeof(libkeccak_state_t));
+ dest->M = malloc(src->mlen * sizeof(char));
+ if (!dest->M)
+ return -1;
+ memcpy(dest->M, src->M, src->mptr * sizeof(char));
+ return 0;
+}
diff --git a/man3/libkeccak_state_create.3 b/libkeccak_state_create.3
index f27e124..f27e124 100644
--- a/man3/libkeccak_state_create.3
+++ b/libkeccak_state_create.3
diff --git a/man3/libkeccak_state_destroy.3 b/libkeccak_state_destroy.3
index 2df1f49..2df1f49 100644
--- a/man3/libkeccak_state_destroy.3
+++ b/libkeccak_state_destroy.3
diff --git a/man3/libkeccak_state_duplicate.3 b/libkeccak_state_duplicate.3
index dfd0612..dfd0612 100644
--- a/man3/libkeccak_state_duplicate.3
+++ b/libkeccak_state_duplicate.3
diff --git a/man3/libkeccak_state_fast_destroy.3 b/libkeccak_state_fast_destroy.3
index f346611..f346611 100644
--- a/man3/libkeccak_state_fast_destroy.3
+++ b/libkeccak_state_fast_destroy.3
diff --git a/man3/libkeccak_state_fast_free.3 b/libkeccak_state_fast_free.3
index 01d0ed8..01d0ed8 100644
--- a/man3/libkeccak_state_fast_free.3
+++ b/libkeccak_state_fast_free.3
diff --git a/man3/libkeccak_state_free.3 b/libkeccak_state_free.3
index 8761d54..8761d54 100644
--- a/man3/libkeccak_state_free.3
+++ b/libkeccak_state_free.3
diff --git a/man3/libkeccak_state_initialise.3 b/libkeccak_state_initialise.3
index cef4d3d..cef4d3d 100644
--- a/man3/libkeccak_state_initialise.3
+++ b/libkeccak_state_initialise.3
diff --git a/libkeccak_state_initialise.c b/libkeccak_state_initialise.c
new file mode 100644
index 0000000..2559f47
--- /dev/null
+++ b/libkeccak_state_initialise.c
@@ -0,0 +1,33 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Initialise a state according to hashing specifications
+ *
+ * @param state The state that should be initialised
+ * @param spec The specifications for the state
+ * @return Zero on success, -1 on error
+ */
+int
+libkeccak_state_initialise(libkeccak_state_t *restrict state, const libkeccak_spec_t *restrict spec)
+{
+ long int x;
+ state->r = spec->bitrate;
+ state->n = spec->output;
+ state->c = spec->capacity;
+ state->b = state->r + state->c;
+ state->w = x = state->b / 25;
+ state->l = 0;
+ if (x & 0xF0L) state->l |= 4, x >>= 4;
+ if (x & 0x0CL) state->l |= 2, x >>= 2;
+ if (x & 0x02L) state->l |= 1;
+ state->nr = 12 + (state->l << 1);
+ state->wmod = (state->w == 64) ? ~0LL : (int64_t)((1ULL << state->w) - 1);
+ for (x = 0; x < 25; x++)
+ state->S[x] = 0;
+ state->mptr = 0;
+ state->mlen = (size_t)(state->r * state->b) >> 2;
+ state->M = malloc(state->mlen * sizeof(char));
+ return state->M == NULL ? -1 : 0;
+}
diff --git a/man3/libkeccak_state_marshal.3 b/libkeccak_state_marshal.3
index ae21d17..ae21d17 100644
--- a/man3/libkeccak_state_marshal.3
+++ b/libkeccak_state_marshal.3
diff --git a/libkeccak_state_marshal.c b/libkeccak_state_marshal.c
new file mode 100644
index 0000000..2714a52
--- /dev/null
+++ b/libkeccak_state_marshal.c
@@ -0,0 +1,33 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Marshal a `libkeccak_state_t` into a buffer
+ *
+ * @param state The state to marshal
+ * @param data The output buffer
+ * @return The number of bytes stored to `data`
+ */
+size_t
+libkeccak_state_marshal(const libkeccak_state_t *restrict state, void *restrict data_)
+{
+#define set(type, var) *((type *)data) = state->var, data += sizeof(type) / sizeof(char)
+ char *restrict data = data_;
+ set(long int, r);
+ set(long int, c);
+ set(long int, n);
+ set(long int, b);
+ set(long int, w);
+ set(int64_t, wmod);
+ set(long int, l);
+ set(long int, nr);
+ memcpy(data, state->S, sizeof(state->S));
+ data += sizeof(state->S) / sizeof(char);
+ set(size_t, mptr);
+ set(size_t, mlen);
+ memcpy(data, state->M, state->mptr * sizeof(char));
+ data += state->mptr;
+ return sizeof(libkeccak_state_t) - sizeof(char *) + state->mptr * sizeof(char);
+#undef set
+}
diff --git a/man3/libkeccak_state_marshal_size.3 b/libkeccak_state_marshal_size.3
index 9eca42b..9eca42b 100644
--- a/man3/libkeccak_state_marshal_size.3
+++ b/libkeccak_state_marshal_size.3
diff --git a/man3/libkeccak_state_reset.3 b/libkeccak_state_reset.3
index 566bd6b..566bd6b 100644
--- a/man3/libkeccak_state_reset.3
+++ b/libkeccak_state_reset.3
diff --git a/man3/libkeccak_state_unmarshal.3 b/libkeccak_state_unmarshal.3
index 8643164..8643164 100644
--- a/man3/libkeccak_state_unmarshal.3
+++ b/libkeccak_state_unmarshal.3
diff --git a/libkeccak_state_unmarshal.c b/libkeccak_state_unmarshal.c
new file mode 100644
index 0000000..7177bd5
--- /dev/null
+++ b/libkeccak_state_unmarshal.c
@@ -0,0 +1,36 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Unmarshal a `libkeccak_state_t` from a buffer
+ *
+ * @param state The slot for the unmarshalled state, must not be initialised (memory leak otherwise)
+ * @param data The input buffer
+ * @return The number of bytes read from `data`, 0 on error
+ */
+size_t
+libkeccak_state_unmarshal(libkeccak_state_t *restrict state, const void *restrict data_)
+{
+#define get(type, var) state->var = *((const type *)data), data += sizeof(type) / sizeof(char)
+ const char *restrict data = data_;
+ get(long int, r);
+ get(long int, c);
+ get(long int, n);
+ get(long int, b);
+ get(long int, w);
+ get(int64_t, wmod);
+ get(long int, l);
+ get(long int, nr);
+ memcpy(state->S, data, sizeof(state->S));
+ data += sizeof(state->S) / sizeof(char);
+ get(size_t, mptr);
+ get(size_t, mlen);
+ state->M = malloc(state->mptr * sizeof(char));
+ if (!state->M)
+ return 0;
+ memcpy(state->M, data, state->mptr * sizeof(char));
+ data += state->mptr;
+ return sizeof(libkeccak_state_t) - sizeof(char *) + state->mptr * sizeof(char);
+#undef get
+}
diff --git a/man3/libkeccak_state_unmarshal_skip.3 b/libkeccak_state_unmarshal_skip.3
index 9fb9336..9fb9336 100644
--- a/man3/libkeccak_state_unmarshal_skip.3
+++ b/libkeccak_state_unmarshal_skip.3
diff --git a/libkeccak_state_unmarshal_skip.c b/libkeccak_state_unmarshal_skip.c
new file mode 100644
index 0000000..df488bf
--- /dev/null
+++ b/libkeccak_state_unmarshal_skip.c
@@ -0,0 +1,18 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Gets the number of bytes the `libkeccak_state_t` stored
+ * at the beginning of `data` occupies
+ *
+ * @param data The data buffer
+ * @return The byte size of the stored state
+ */
+size_t
+libkeccak_state_unmarshal_skip(const void *restrict data_)
+{
+ const char *restrict data = data_;
+ data += (7 * sizeof(long int) + 26 * sizeof(int64_t)) / sizeof(char);
+ return sizeof(libkeccak_state_t) - sizeof(char *) + *(const size_t *)data * sizeof(char);
+}
diff --git a/man3/libkeccak_state_wipe.3 b/libkeccak_state_wipe.3
index 1ae2759..1ae2759 100644
--- a/man3/libkeccak_state_wipe.3
+++ b/libkeccak_state_wipe.3
diff --git a/libkeccak_state_wipe.c b/libkeccak_state_wipe.c
new file mode 100644
index 0000000..e5c721c
--- /dev/null
+++ b/libkeccak_state_wipe.c
@@ -0,0 +1,15 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Wipe sensitive data wihout freeing any data
+ *
+ * @param state The state that should be wipe
+ */
+void
+libkeccak_state_wipe(volatile libkeccak_state_t *restrict state)
+{
+ libkeccak_state_wipe_message(state);
+ libkeccak_state_wipe_sponge(state);
+}
diff --git a/man3/libkeccak_state_wipe_message.3 b/libkeccak_state_wipe_message.3
index 7d53afb..7d53afb 100644
--- a/man3/libkeccak_state_wipe_message.3
+++ b/libkeccak_state_wipe_message.3
diff --git a/libkeccak_state_wipe_message.c b/libkeccak_state_wipe_message.c
new file mode 100644
index 0000000..d6bc8a0
--- /dev/null
+++ b/libkeccak_state_wipe_message.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Wipe data in the state's message wihout freeing any data
+ *
+ * @param state The state that should be wipe
+ */
+void
+libkeccak_state_wipe_message(volatile libkeccak_state_t *restrict state)
+{
+ volatile char *restrict M = state->M;
+ size_t i;
+ for (i = 0; i < state->mptr; i++)
+ M[i] = 0;
+}
diff --git a/man3/libkeccak_state_wipe_sponge.3 b/libkeccak_state_wipe_sponge.3
index 31d6c66..31d6c66 100644
--- a/man3/libkeccak_state_wipe_sponge.3
+++ b/libkeccak_state_wipe_sponge.3
diff --git a/libkeccak_state_wipe_sponge.c b/libkeccak_state_wipe_sponge.c
new file mode 100644
index 0000000..ad8c29f
--- /dev/null
+++ b/libkeccak_state_wipe_sponge.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Wipe data in the state's sponge wihout freeing any data
+ *
+ * @param state The state that should be wipe
+ */
+void
+libkeccak_state_wipe_sponge(volatile libkeccak_state_t *restrict state)
+{
+ volatile int64_t *restrict S = state->S;
+ size_t i;
+ for (i = 0; i < 25; i++)
+ S[i] = 0;
+}
diff --git a/man3/libkeccak_unhex.3 b/libkeccak_unhex.3
index c7dc9bc..c7dc9bc 100644
--- a/man3/libkeccak_unhex.3
+++ b/libkeccak_unhex.3
diff --git a/libkeccak_unhex.c b/libkeccak_unhex.c
new file mode 100644
index 0000000..a12beb1
--- /dev/null
+++ b/libkeccak_unhex.c
@@ -0,0 +1,29 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Convert a hexadecimal hashsum (both lower case, upper
+ * case and mixed is supported) to binary representation
+ *
+ * @param output Output array, should have an allocation size of at least `strlen(hashsum) / 2`
+ * @param hashsum The hashsum to convert
+ */
+void
+libkeccak_unhex(void *restrict output_, const char *restrict hashsum)
+{
+ unsigned char *restrict output = output_;
+ size_t n = strlen(hashsum) / 2;
+ unsigned char a, b;
+ while (n--) {
+ a = (unsigned char)hashsum[2 * n + 0];
+ b = (unsigned char)hashsum[2 * n + 1];
+
+ a = (unsigned char)((a & 15) + (a > '9' ? 9 : 0));
+ b = (unsigned char)((b & 15) + (b > '9' ? 9 : 0));
+
+ a <<= 4;
+ a |= b;
+ output[n] = a;
+ }
+}
diff --git a/man3/libkeccak_update.3 b/libkeccak_update.3
index 4e9f584..4e9f584 100644
--- a/man3/libkeccak_update.3
+++ b/libkeccak_update.3