aboutsummaryrefslogtreecommitdiffstats
path: root/libkeccak.h
diff options
context:
space:
mode:
Diffstat (limited to 'libkeccak.h')
-rw-r--r--libkeccak.h1151
1 files changed, 1144 insertions, 7 deletions
diff --git a/libkeccak.h b/libkeccak.h
index 7c71801..21b4b47 100644
--- a/libkeccak.h
+++ b/libkeccak.h
@@ -2,12 +2,1149 @@
#ifndef LIBKECCAK_H
#define LIBKECCAK_H 1
-#include "libkeccak/spec.h"
-#include "libkeccak/generalised-spec.h"
-#include "libkeccak/state.h"
-#include "libkeccak/digest.h"
-#include "libkeccak/hex.h"
-#include "libkeccak/files.h"
-#include "libkeccak/mac/hmac.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/**
+ * Only include some C code if compiling with GCC.
+ *
+ * For internal use.
+ */
+#ifdef __GNUC__
+# define LIBKECCAK_GCC_ONLY(x) x
+#else
+# define LIBKECCAK_GCC_ONLY(x)
+#endif
+
+
+
+/**
+ * Message suffix for SHA3 hashing
+ */
+#define LIBKECCAK_SHA3_SUFFIX "01"
+
+/**
+ * Message suffix for RawSHAKE hashing
+ */
+#define LIBKECCAK_RAWSHAKE_SUFFIX "11"
+
+/**
+ * Message suffix for SHAKE hashing
+ */
+#define LIBKECCAK_SHAKE_SUFFIX "1111"
+
+
+/**
+ * Invalid `libkeccak_spec_t.bitrate`: non-positive
+ */
+#define LIBKECCAK_SPEC_ERROR_BITRATE_NONPOSITIVE 1
+
+/**
+ * Invalid `libkeccak_spec_t.bitrate`: not a multiple of 8
+ */
+#define LIBKECCAK_SPEC_ERROR_BITRATE_MOD_8 2
+
+/**
+ * Invalid `libkeccak_spec_t.capacity`: non-positive
+ */
+#define LIBKECCAK_SPEC_ERROR_CAPACITY_NONPOSITIVE 3
+
+/**
+ * Invalid `libkeccak_spec_t.capacity`: not a multiple of 8
+ */
+#define LIBKECCAK_SPEC_ERROR_CAPACITY_MOD_8 4
+
+/**
+ * Invalid `libkeccak_spec_t.output`: non-positive
+ */
+#define LIBKECCAK_SPEC_ERROR_OUTPUT_NONPOSITIVE 5
+
+/**
+ * Invalid `libkeccak_spec_t` values: `.bitrate + `.capacity`
+ * is greater 1600 which is the largest supported state size
+ */
+#define LIBKECCAK_SPEC_ERROR_STATE_TOO_LARGE 6
+
+/**
+ * Invalid `libkeccak_spec_t` values:
+ * `.bitrate + `.capacity` is not a multiple of 25
+ */
+#define LIBKECCAK_SPEC_ERROR_STATE_MOD_25 7
+
+/**
+ * Invalid `libkeccak_spec_t` values: `.bitrate + `.capacity`
+ * is a not a 2-potent multiple of 25
+ */
+#define LIBKECCAK_SPEC_ERROR_WORD_NON_2_POTENT 8
+
+/**
+ * Invalid `libkeccak_spec_t` values: `.bitrate + `.capacity`
+ * is a not multiple of 100, and thus the word size is not
+ * a multiple of 8
+ */
+#define LIBKECCAK_SPEC_ERROR_WORD_MOD_8 9
+
+
+/**
+ * Value for `libkeccak_generalised_spec_t` member that
+ * is used to automatically select the value
+ */
+#define LIBKECCAK_GENERALISED_SPEC_AUTOMATIC (-65536L)
+
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.state_size`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_NONPOSITIVE 1
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.state_size`: larger than 1600
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_TOO_LARGE 2
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.state_size`: not a multiple of 25
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_MOD_25 3
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.word_size`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_WORD_NONPOSITIVE 4
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.word_size`: larger than 1600 / 25
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_WORD_TOO_LARGE 5
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.word_size` and
+ * `libkeccak_generalised_spec_t.state_size`: `.word_size * 25 != .state_size`
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_WORD_INCOHERENCY 6
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.capacity`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_CAPACITY_NONPOSITIVE 7
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.capacity`: not a multiple of 8
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_CAPACITY_MOD_8 8
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.bitrate`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_BITRATE_NONPOSITIVE 9
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.bitrate`: not a multiple of 8
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_BITRATE_MOD_8 10
+
+/**
+ * Invalid `libkeccak_generalised_spec_t.output`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_OUTPUT_NONPOSITIVE 11
+
+
+/**
+ * Data structure that describes the parameters
+ * that should be used when hashing
+ */
+typedef struct libkeccak_spec {
+ /**
+ * The bitrate
+ */
+ long int bitrate;
+
+ /**
+ * The capacity
+ */
+ long int capacity;
+
+ /**
+ * The output size
+ */
+ long int output;
+
+} libkeccak_spec_t;
+
+/**
+ * Generalised datastructure that describes the
+ * parameters that should be used when hashing
+ */
+typedef struct libkeccak_generalised_spec
+{
+ /**
+ * The bitrate
+ */
+ long int bitrate;
+
+ /**
+ * The capacity
+ */
+ long int capacity;
+
+ /**
+ * The output size
+ */
+ long int output;
+
+ /**
+ * The state size
+ */
+ long int state_size;
+
+ /**
+ * The word size
+ */
+ long int word_size;
+
+} libkeccak_generalised_spec_t;
+
+/**
+ * Data structure that describes the state of a hashing process
+ *
+ * The `char`-size of the output hashsum is calculated by `(.n + 7) / 8`
+ */
+typedef struct libkeccak_state {
+ /**
+ * The lanes (state/sponge)
+ */
+ int64_t S[25];
+
+ /**
+ * The bitrate
+ */
+ long int r;
+
+ /**
+ * The capacity
+ */
+ long int c;
+
+ /**
+ * The output size
+ */
+ long int n;
+
+ /**
+ * The state size
+ */
+ long int b;
+
+ /**
+ * The word size
+ */
+ long int w;
+
+ /**
+ * The word mask
+ */
+ int64_t wmod;
+
+ /**
+ * ℓ, the binary logarithm of the word size
+ */
+ long int l;
+
+ /**
+ * 12 + 2ℓ, the number of rounds
+ */
+ long int nr;
+
+ /**
+ * Pointer for `M`
+ */
+ size_t mptr;
+
+ /**
+ * Size of `M`
+ */
+ size_t mlen;
+
+ /**
+ * Left over water to fill the sponge with at next update
+ */
+ char *M;
+
+} libkeccak_state_t;
+
+
+/**
+ * Fill in a `libkeccak_spec_t` for a SHA3-x hashing
+ *
+ * @param spec The specifications datastructure to fill in
+ * @param x The value of x in `SHA3-x`, the output size
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((nonnull, nothrow)))
+static inline void
+libkeccak_spec_sha3(libkeccak_spec_t *restrict spec, long int x)
+{
+ spec->bitrate = 1600 - 2 * x;
+ spec->capacity = 2 * x;
+ spec->output = x;
+}
+
+/**
+ * Fill in a `libkeccak_spec_t` for a RawSHAKEx hashing
+ *
+ * @param spec The specifications datastructure to fill in
+ * @param x The value of x in `RawSHAKEx`, half the capacity
+ * @param d The output size
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((nonnull, nothrow)))
+static inline void
+libkeccak_spec_rawshake(libkeccak_spec_t *restrict spec, long int x, long int d)
+{
+ spec->bitrate = 1600 - 2 * x;
+ spec->capacity = 2 * x;
+ spec->output = d;
+}
+
+/**
+ * Fill in a `libkeccak_spec_t` for a SHAKEx hashing
+ *
+ * @param spec:libkeccak_spec_t* The specifications datastructure to fill in
+ * @param x:long The value of x in `SHAKEx`, half the capacity
+ * @param d:long The output size
+ */
+#define libkeccak_spec_shake libkeccak_spec_rawshake
+
+/**
+ * Check for errors in a `libkeccak_spec_t`
+ *
+ * @param spec The specifications datastructure to check
+ * @return Zero if error free, a `LIBKECCAK_SPEC_ERROR_*` if an error was found
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((nonnull, nothrow, unused, warn_unused_result, pure)))
+static inline int
+libkeccak_spec_check(const libkeccak_spec_t *restrict spec)
+{
+ long int state_size = spec->capacity + spec->bitrate;
+ int32_t word_size = (int32_t)(state_size / 25);
+ if (spec->bitrate <= 0) return LIBKECCAK_SPEC_ERROR_BITRATE_NONPOSITIVE;
+ if (spec->bitrate % 8) return LIBKECCAK_SPEC_ERROR_BITRATE_MOD_8;
+ if (spec->capacity <= 0) return LIBKECCAK_SPEC_ERROR_CAPACITY_NONPOSITIVE;
+ if (spec->capacity % 8) return LIBKECCAK_SPEC_ERROR_CAPACITY_MOD_8;
+ if (spec->output <= 0) return LIBKECCAK_SPEC_ERROR_OUTPUT_NONPOSITIVE;
+ if (state_size > 1600) return LIBKECCAK_SPEC_ERROR_STATE_TOO_LARGE;
+ if (state_size % 25) return LIBKECCAK_SPEC_ERROR_STATE_MOD_25;
+ if (word_size % 8) return LIBKECCAK_SPEC_ERROR_WORD_MOD_8;
+
+ /* `(x & -x) != x` assumes two's complement, which of course is always
+ * satisfied by GCC, however C99 guarantees that `int32_t` exists,
+ * and it is basically the same thing as `long int`; with one important
+ * difference: it is guaranteed to use two's complement. */
+ if ((word_size & -word_size) != word_size)
+ return LIBKECCAK_SPEC_ERROR_WORD_NON_2_POTENT;
+
+ return 0;
+}
+
+/**
+ * Set all specification parameters to automatic
+ *
+ * @param spec The specification datastructure to fill in
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__, __unused__)))
+static inline void
+libkeccak_generalised_spec_initialise(libkeccak_generalised_spec_t *restrict spec)
+{
+ spec->bitrate = LIBKECCAK_GENERALISED_SPEC_AUTOMATIC;
+ spec->capacity = LIBKECCAK_GENERALISED_SPEC_AUTOMATIC;
+ spec->output = LIBKECCAK_GENERALISED_SPEC_AUTOMATIC;
+ spec->state_size = LIBKECCAK_GENERALISED_SPEC_AUTOMATIC;
+ spec->word_size = LIBKECCAK_GENERALISED_SPEC_AUTOMATIC;
+}
+
+/**
+ * Convert a `libkeccak_generalised_spec_t` to a `libkeccak_spec_t`
+ *
+ * @param spec The generalised input specifications, will be update with resolved automatic values
+ * @param output_spec The specification datastructure to fill in
+ * @return Zero if `spec` is valid, a `LIBKECCAK_GENERALISED_SPEC_ERROR_*` if an error was found
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__, __nothrow__)))
+int libkeccak_degeneralise_spec(libkeccak_generalised_spec_t *restrict, libkeccak_spec_t *restrict);
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__)))
+int libkeccak_state_initialise(libkeccak_state_t *restrict, const libkeccak_spec_t *restrict);
+
+/**
+ * Reset a state according to hashing specifications
+ *
+ * @param state The state that should be reset
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__, __unused__)))
+static inline void
+libkeccak_state_reset(libkeccak_state_t *restrict state)
+{
+ state->mptr = 0;
+ memset(state->S, 0, sizeof(state->S));
+}
+
+/**
+ * Release resources allocation for a state without wiping sensitive data
+ *
+ * @param state The state that should be destroyed
+ */
+static inline void
+libkeccak_state_fast_destroy(libkeccak_state_t *restrict state)
+{
+ if (state) {
+ free(state->M);
+ state->M = NULL;
+ }
+}
+
+/**
+ * Wipe data in the state's message wihout freeing any data
+ *
+ * @param state The state that should be wipe
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__, __nothrow__, __optimize__("-O0"))))
+void libkeccak_state_wipe_message(volatile libkeccak_state_t *restrict);
+
+/**
+ * Wipe data in the state's sponge wihout freeing any data
+ *
+ * @param state The state that should be wipe
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__, __nothrow__, __optimize__("-O0"))))
+void libkeccak_state_wipe_sponge(volatile libkeccak_state_t *restrict);
+
+/**
+ * Wipe sensitive data wihout freeing any data
+ *
+ * @param state The state that should be wipe
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__, __optimize__("-O0"))))
+void libkeccak_state_wipe(volatile libkeccak_state_t *restrict);
+
+/**
+ * Release resources allocation for a state and wipe sensitive data
+ *
+ * @param state The state that should be destroyed
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__unused__, __optimize__("-O0"))))
+static inline void
+libkeccak_state_destroy(volatile libkeccak_state_t *restrict state)
+{
+ if (state) {
+ libkeccak_state_wipe(state);
+ free(state->M);
+ state->M = NULL;
+ }
+}
+
+/**
+ * Wrapper for `libkeccak_state_initialise` that also allocates the states
+ *
+ * @param spec The specifications for the state
+ * @return The state, `NULL` on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __unused__, __warn_unused_result__, __malloc__)))
+static inline libkeccak_state_t *
+libkeccak_state_create(const libkeccak_spec_t *restrict spec)
+{
+ libkeccak_state_t *restrict state = malloc(sizeof(libkeccak_state_t));
+ if (!state || libkeccak_state_initialise(state, spec)) {
+ free(state);
+ return NULL;
+ }
+ return state;
+}
+
+/**
+ * Wrapper for `libkeccak_state_fast_destroy` that also frees the allocation of the state
+ *
+ * @param state The state that should be freed
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__unused__)))
+static inline void
+libkeccak_state_fast_free(libkeccak_state_t *restrict state)
+{
+ libkeccak_state_fast_destroy(state);
+ free(state);
+}
+
+/**
+ * Wrapper for `libkeccak_state_destroy` that also frees the allocation of the state
+ *
+ * @param state The state that should be freed
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__unused__, __optimize__("-O0"))))
+static inline void
+libkeccak_state_free(volatile libkeccak_state_t *restrict state)
+{
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+ libkeccak_state_destroy(state);
+ free((libkeccak_state_t *)state);
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+}
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__)))
+int libkeccak_state_copy(libkeccak_state_t *restrict, const libkeccak_state_t *restrict);
+
+/**
+ * A wrapper for `libkeccak_state_copy` that also allocates the duplicate
+ *
+ * @param src The state to duplicate
+ * @return The duplicate, `NULL` on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __unused__, __warn_unused_result__, __malloc__)))
+static inline libkeccak_state_t *
+libkeccak_state_duplicate(const libkeccak_state_t *restrict src)
+{
+ libkeccak_state_t *restrict dest = malloc(sizeof(libkeccak_state_t));
+ if (!dest || libkeccak_state_copy(dest, src)) {
+ libkeccak_state_free(dest);
+ return NULL;
+ }
+ return dest;
+}
+
+/**
+ * Calculates the allocation size required for the second argument
+ * of `libkeccak_state_marshal` (`char* restrict data)`)
+ *
+ * @param state The state as it will be marshalled by a subsequent call to `libkeccak_state_marshal`
+ * @return The allocation size needed for the buffer to which the state will be marshalled
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__, __unused__, __warn_unused_result__, __pure__)))
+static inline size_t
+libkeccak_state_marshal_size(const libkeccak_state_t *restrict state)
+{
+ return sizeof(libkeccak_state_t) - sizeof(char *) + state->mptr * sizeof(char);
+}
+
+/**
+ * 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`
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__, __nothrow__)))
+size_t libkeccak_state_marshal(const libkeccak_state_t *restrict, void *restrict);
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__)))
+size_t libkeccak_state_unmarshal(libkeccak_state_t *restrict, const void *restrict);
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__, __nothrow__, __warn_unused_result__, __pure__)))
+size_t libkeccak_state_unmarshal_skip(const void *restrict);
+
+/**
+ * Absorb more of the message to the Keccak sponge
+ * without wiping sensitive data when possible
+ *
+ * @param state The hashing state
+ * @param msg The partial message
+ * @param msglen The length of the partial message
+ * @return Zero on success, -1 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__)))
+int libkeccak_fast_update(libkeccak_state_t *restrict, const void *restrict, size_t);
+
+/**
+ * Absorb more of the message to the Keccak sponge
+ * and wipe sensitive data when possible
+ *
+ * @param state The hashing state
+ * @param msg The partial message
+ * @param msglen The length of the partial message
+ * @return Zero on success, -1 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__)))
+int libkeccak_update(libkeccak_state_t *restrict, const void *restrict, size_t);
+
+/**
+ * Absorb the last part of the message and squeeze the Keccak sponge
+ * without wiping sensitive data when possible
+ *
+ * @param state The hashing state
+ * @param msg The rest of the message, may be `NULL`
+ * @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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1))))
+int libkeccak_fast_digest(libkeccak_state_t *restrict, const void *restrict, size_t,
+ size_t, const char *restrict, void *restrict);
+
+/**
+ * Absorb the last part of the message and squeeze the Keccak sponge
+ * and wipe sensitive data when possible
+ *
+ * @param state The hashing state
+ * @param msg The rest of the message, may be `NULL`
+ * @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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1))))
+int libkeccak_digest(libkeccak_state_t *restrict, const void *restrict, size_t,
+ size_t, const char *restrict, void *restrict);
+
+/**
+ * Force some rounds of Keccak-f
+ *
+ * @param state The hashing state
+ * @param times The number of rounds
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__)))
+void libkeccak_simple_squeeze(register libkeccak_state_t *restrict, register long int);
+
+/**
+ * Squeeze as much as is needed to get a digest a number of times
+ *
+ * @param state The hashing state
+ * @param times The number of digests
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__)))
+void libkeccak_fast_squeeze(register libkeccak_state_t *restrict, register long int);
+
+/**
+ * Squeeze out another digest
+ *
+ * @param state The hashing state
+ * @param hashsum Output parameter for the hashsum
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__)))
+void libkeccak_squeeze(register libkeccak_state_t *restrict, register void *restrict);
+
+/**
+ * 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`
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__, __nothrow__)))
+void libkeccak_behex_lower(char *restrict, const void *restrict, size_t);
+
+/**
+ * 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`
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__, __nothrow__)))
+void libkeccak_behex_upper(char *restrict, const void *restrict, size_t);
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__, __nothrow__)))
+void libkeccak_unhex(void *restrict, const char *restrict);
+
+/**
+ * Calculate a Keccak-family hashsum of a file,
+ * the content of the file is assumed non-sensitive
+ *
+ * @param fd The file descriptor of the file to hash
+ * @param state The hashing state, should not be initialised (memory leak otherwise)
+ * @param spec Specifications for the hashing algorithm
+ * @param suffix The data suffix, see `libkeccak_digest`
+ * @param hashsum Output array for the hashsum, have an allocation size of
+ * at least `((spec->output + 7) / 8) * sizeof(char)`, may be `NULL`
+ * @return Zero on success, -1 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(2, 3))))
+int libkeccak_generalised_sum_fd(int, libkeccak_state_t *restrict, const libkeccak_spec_t *restrict,
+ const char *restrict, void *restrict);
+
+/**
+ * Calculate the Keccak hashsum of a file,
+ * the content of the file is assumed non-sensitive
+ *
+ * @param fd The file descriptor of the file to hash
+ * @param state The hashing state, should not be initialised (memory leak otherwise)
+ * @param spec Specifications for the hashing algorithm
+ * @param hashsum Output array for the hashsum, have an allocation size of
+ * at least `((spec->output + 7) / 8) * sizeof(char)`, may be `NULL`
+ * @return Zero on success, -1 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(2, 3), __artificial__, __gnu_inline__)))
+static inline int
+libkeccak_keccaksum_fd(int fd, libkeccak_state_t *restrict state, const libkeccak_spec_t *restrict spec, void *restrict hashsum)
+{
+ return libkeccak_generalised_sum_fd(fd, state, spec, NULL, hashsum);
+}
+
+/**
+ * Calculate the SHA3 hashsum of a file,
+ * the content of the file is assumed non-sensitive
+ *
+ * @param fd The file descriptor of the file to hash
+ * @param state The hashing state, should not be initialised (memory leak otherwise)
+ * @param output The output size parameter for the hashing algorithm
+ * @param hashsum Output array for the hashsum, have an allocation size of
+ * at least `((output + 7) / 8) * sizeof(char)`, may be `NULL`
+ * @return Zero on success, -1 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(2), __artificial__, __gnu_inline__)))
+static inline int
+libkeccak_sha3sum_fd(int fd, libkeccak_state_t *restrict state, long output, void *restrict hashsum)
+{
+ libkeccak_spec_t spec;
+ libkeccak_spec_sha3(&spec, output);
+ return libkeccak_generalised_sum_fd(fd, state, &spec, LIBKECCAK_SHA3_SUFFIX, hashsum);
+}
+
+/**
+ * Calculate the RawSHAKE hashsum of a file,
+ * the content of the file is assumed non-sensitive
+ *
+ * @param fd The file descriptor of the file to hash
+ * @param state The hashing state, should not be initialised (memory leak otherwise)
+ * @param semicapacity The semicapacity parameter for the hashing algorithm
+ * @param output The output size parameter for the hashing algorithm
+ * @param hashsum Output array for the hashsum, have an allocation size of
+ * at least `((output + 7) / 8) * sizeof(char)`, may be `NULL`
+ * @return Zero on success, -1 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(2), __artificial__, __gnu_inline__)))
+static inline int
+libkeccak_rawshakesum_fd(int fd, libkeccak_state_t *restrict state, long semicapacity, long output, void *restrict hashsum)
+{
+ libkeccak_spec_t spec;
+ libkeccak_spec_rawshake(&spec, semicapacity, output);
+ return libkeccak_generalised_sum_fd(fd, state, &spec, LIBKECCAK_RAWSHAKE_SUFFIX, hashsum);
+}
+
+/**
+ * Calculate the SHAKE hashsum of a file,
+ * the content of the file is assumed non-sensitive
+ *
+ * @param fd The file descriptor of the file to hash
+ * @param state The hashing state, should not be initialised (memory leak otherwise)
+ * @param semicapacity The semicapacity parameter for the hashing algorithm
+ * @param output The output size parameter for the hashing algorithm
+ * @param hashsum Output array for the hashsum, have an allocation size of
+ * at least `((output + 7) / 8) * sizeof(char)`, may be `NULL`
+ * @return Zero on success, -1 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(2), __artificial__, __gnu_inline__)))
+static inline int
+libkeccak_shakesum_fd(int fd, libkeccak_state_t *restrict state, long semicapacity, long output, void *restrict hashsum)
+{
+ libkeccak_spec_t spec;
+ libkeccak_spec_shake(&spec, semicapacity, output);
+ return libkeccak_generalised_sum_fd(fd, state, &spec, LIBKECCAK_SHAKE_SUFFIX, hashsum);
+}
+
+
+/*
+ * The Keccak hash-function, that was selected by NIST as the SHA-3 competition winner,
+ * doesn't need this nested approach and can be used to generate a MAC by simply prepending
+ * the key to the message. [http://keccak.noekeon.org]
+ */
+
+
+/**
+ * Datastructure that describes the state of an HMAC-hashing process
+ */
+typedef struct libkeccak_hmac_state
+{
+ /**
+ * The key right-padded and XOR:ed with the outer pad
+ */
+ char *restrict key_opad;
+
+ /**
+ * The key right-padded and XOR:ed with the inner pad
+ */
+ char *restrict key_ipad;
+ /* Not marshalled, implicitly unmarshalled using `key_opad`. */
+ /* Shares allocation with `key_opad`, do not `free`. */
+
+ /**
+ * The length of key, but at least the input block size, in bits
+ */
+ size_t key_length;
+
+ /**
+ * The state of the underlaying hash-algorithm
+ */
+ libkeccak_state_t sponge;
+
+ /**
+ * Buffer used to temporarily store bit shift message if
+ * `.key_length` is not zero modulus 8
+ */
+ char *restrict buffer;
+
+ /**
+ * The allocation size of `.buffer`
+ */
+ size_t buffer_size;
+
+ /**
+ * Part of feed key, message or digest that have not been passed yet
+ */
+ char leftover;
+
+ char __pad[sizeof(void*) / sizeof(char) - 1];
+
+} libkeccak_hmac_state_t;
+
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1))))
+int libkeccak_hmac_set_key(libkeccak_hmac_state_t *restrict, const void *restrict, size_t);
+
+/**
+ * Initialise an HMAC hashing-state according to hashing specifications
+ *
+ * @param state The state that should be initialised
+ * @param spec The specifications for the state
+ * @param key The key
+ * @param key_length The length of key, in bits
+ * @return Zero on success, -1 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__)))
+static inline int
+libkeccak_hmac_initialise(libkeccak_hmac_state_t *restrict state, const libkeccak_spec_t *restrict spec,
+ const void *restrict key, size_t key_length)
+{
+ if (libkeccak_state_initialise(&state->sponge, spec) < 0)
+ return -1;
+ if (libkeccak_hmac_set_key(state, key, key_length) < 0) {
+ libkeccak_state_destroy(&state->sponge);
+ return -1;
+ }
+ state->leftover = 0;
+ state->buffer = NULL;
+ state->buffer_size = 0;
+ return 0;
+}
+
+/**
+ * Wrapper for `libkeccak_hmac_initialise` that also allocates the states
+ *
+ * @param spec The specifications for the state
+ * @param key The key
+ * @param key_length The length of key, in bits
+ * @return The state, `NULL` on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __unused__, __warn_unused_result__, __malloc__)))
+static inline libkeccak_hmac_state_t *
+libkeccak_hmac_create(const libkeccak_spec_t *restrict spec, const void *restrict key, size_t key_length)
+{
+ libkeccak_hmac_state_t *restrict state = malloc(sizeof(libkeccak_hmac_state_t));
+ if (!state || libkeccak_hmac_initialise(state, spec, key, key_length)) {
+ free(state);
+ return NULL;
+ }
+ return state;
+}
+
+/**
+ * Reset an HMAC-hashing state according to hashing specifications,
+ * you can choose whether to change the key
+ *
+ * @param state The state that should be reset
+ * @param key The new key, `NULL` to keep the old key
+ * @param key_length The length of key, in bits, ignored if `key == NULL`
+ * @return Zero on success, -1 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1), __unused__)))
+static inline int
+libkeccak_hmac_reset(libkeccak_hmac_state_t *restrict state, const void *restrict key, size_t key_length)
+{
+ libkeccak_state_reset(&state->sponge);
+ return key ? libkeccak_hmac_set_key(state, key, key_length) : 0;
+}
+
+/**
+ * Wipe sensitive data wihout freeing any data
+ *
+ * @param state The state that should be wipe
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__, __optimize__("-O0"))))
+void libkeccak_hmac_wipe(volatile libkeccak_hmac_state_t *restrict);
+
+/**
+ * Release resources allocation for an HMAC hashing-state without wiping sensitive data
+ *
+ * @param state The state that should be destroyed
+ */
+static inline void
+libkeccak_hmac_fast_destroy(libkeccak_hmac_state_t *restrict state)
+{
+ if (!state)
+ return;
+ free(state->key_opad);
+ state->key_opad = NULL;
+ state->key_ipad = NULL;
+ state->key_length = 0;
+ free(state->buffer);
+ state->buffer = NULL;
+ state->buffer_size = 0;
+}
+
+/**
+ * Release resources allocation for an HMAC hasing-state and wipe sensitive data
+ *
+ * @param state The state that should be destroyed
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__unused__, __optimize__("-O0"))))
+static inline void
+libkeccak_hmac_destroy(volatile libkeccak_hmac_state_t *restrict state)
+{
+ if (!state)
+ return;
+ libkeccak_hmac_wipe(state);
+ free(state->key_opad);
+ state->key_opad = NULL;
+ state->key_ipad = NULL;
+ state->key_length = 0;
+ state->leftover = 0;
+ free(state->buffer);
+ state->buffer = NULL;
+ state->buffer_size = 0;
+}
+
+/**
+ * Wrapper for `libkeccak_fast_destroy` that also frees the allocation of the state
+ *
+ * @param state The state that should be freed
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__unused__)))
+static inline void
+libkeccak_hmac_fast_free(libkeccak_hmac_state_t *restrict state)
+{
+ libkeccak_hmac_fast_destroy(state);
+ free(state);
+}
+
+/**
+ * Wrapper for `libkeccak_hmac_destroy` that also frees the allocation of the state
+ *
+ * @param state The state that should be freed
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__unused__, __optimize__("-O0"))))
+static inline void
+libkeccak_hmac_free(volatile libkeccak_hmac_state_t *restrict state)
+{
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+ libkeccak_hmac_destroy(state);
+ free((libkeccak_hmac_state_t*)state);
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+}
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__)))
+int libkeccak_hmac_copy(libkeccak_hmac_state_t *restrict, const libkeccak_hmac_state_t *restrict);
+
+/**
+ * A wrapper for `libkeccak_hmac_copy` that also allocates the duplicate
+ *
+ * @param src The state to duplicate
+ * @return The duplicate, `NULL` on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __unused__, __warn_unused_result__, __malloc__)))
+static inline libkeccak_hmac_state_t *
+libkeccak_hmac_duplicate(const libkeccak_hmac_state_t *restrict src)
+{
+ libkeccak_hmac_state_t* restrict dest = malloc(sizeof(libkeccak_hmac_state_t));
+ if (!dest || libkeccak_hmac_copy(dest, src))
+ return libkeccak_hmac_free(dest), NULL;
+ return dest;
+}
+
+/**
+ * Calculates the allocation size required for the second argument
+ * of `libkeccak_hmac_marshal` (`char* restrict data)`)
+ *
+ * @param state The state as it will be marshalled by a subsequent call to `libkeccak_hamc_marshal`
+ * @return The allocation size needed for the buffer to which the state will be marshalled
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__, __unused__, __warn_unused_result__, __pure__)))
+static inline size_t
+libkeccak_hmac_marshal_size(const libkeccak_hmac_state_t *restrict state)
+{
+ return libkeccak_state_marshal_size(&state->sponge) + sizeof(size_t) +
+ ((state->key_length + 7) >> 3) + 2 * sizeof(char);
+}
+
+/**
+ * Marshal a `libkeccak_hmac_state_t` into a buffer
+ *
+ * @param state The state to marshal
+ * @param data The output buffer
+ * @return The number of bytes stored to `data`
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__)))
+static inline size_t
+libkeccak_hmac_marshal(const libkeccak_hmac_state_t *restrict state, void *restrict data_)
+{
+ char *restrict data = data_;
+ size_t written = libkeccak_state_marshal(&state->sponge, data);
+ data += written / sizeof(char);
+ *(size_t *)data = state->key_length;
+ data += sizeof(size_t) / sizeof(char);
+ memcpy(data, state->key_opad, (state->key_length + 7) >> 3);
+ data += ((state->key_length + 7) >> 3) / sizeof(char);
+ data[0] = (char)!!state->key_ipad;
+ data[1] = state->leftover;
+ return written + sizeof(size_t) + ((state->key_length + 7) >> 3) + 2 * sizeof(char);
+}
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__)))
+size_t libkeccak_hmac_unmarshal(libkeccak_hmac_state_t *restrict, const void *restrict);
+
+/**
+ * Gets the number of bytes the `libkeccak_hmac_state_t` stored
+ * at the beginning of `data` occupies
+ *
+ * @param data The data buffer
+ * @return The byte size of the stored state
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__, __warn_unused_result__, __pure__)))
+static inline size_t
+libkeccak_hmac_unmarshal_skip(const void *restrict data_)
+{
+ const char *restrict data = data_;
+ size_t skip = libkeccak_state_unmarshal_skip(data);
+ data += skip / sizeof(char);
+ return skip + sizeof(size_t) + *(const size_t *)data + 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1))))
+int libkeccak_hmac_fast_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg, size_t 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1))))
+int libkeccak_hmac_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg, size_t msglen);
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1))))
+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);
+
+/**
+ * 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
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1))))
+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);
+
#endif