aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-09-15 00:37:13 +0200
committerMattias Andrée <maandree@kth.se>2024-09-15 00:37:13 +0200
commit0ab7b5a1ce4ed6735b40e167f8b05b8bf1fede59 (patch)
treeaf2a138767835010d50611790265bbd2bdc2adae
parentm (diff)
downloadlibkeccak-0ab7b5a1ce4ed6735b40e167f8b05b8bf1fede59.tar.gz
libkeccak-0ab7b5a1ce4ed6735b40e167f8b05b8bf1fede59.tar.bz2
libkeccak-0ab7b5a1ce4ed6735b40e167f8b05b8bf1fede59.tar.xz
Split libkeccak.h and fix support for architectures that do not allow misaligned memory
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--Makefile24
-rw-r--r--TODO2
-rw-r--r--common.h1
-rw-r--r--libkeccak-legacy.h42
-rw-r--r--libkeccak.h798
-rw-r--r--libkeccak/cshake.h54
-rw-r--r--libkeccak/hmac.h358
-rw-r--r--libkeccak/keccak.h237
-rw-r--r--libkeccak/legacy.h53
-rw-r--r--libkeccak/rawshake.h46
-rw-r--r--libkeccak/sha3.h44
-rw-r--r--libkeccak/shake.h39
-rw-r--r--libkeccak/util.h54
-rw-r--r--libkeccak_hmac_unmarshal.c4
-rw-r--r--libkeccak_state_marshal.c33
-rw-r--r--libkeccak_state_unmarshal.c37
16 files changed, 958 insertions, 868 deletions
diff --git a/Makefile b/Makefile
index 81430c3..62dc927 100644
--- a/Makefile
+++ b/Makefile
@@ -69,8 +69,18 @@ OBJ =\
HDR =\
libkeccak.h\
- libkeccak-legacy.h\
- common.h
+ common.h\
+ $(SUBHDR)
+
+SUBHDR =\
+ libkeccak/keccak.h\
+ libkeccak/sha3.h\
+ libkeccak/rawshake.h\
+ libkeccak/shake.h\
+ libkeccak/cshake.h\
+ libkeccak/hmac.h\
+ libkeccak/legacy.h\
+ libkeccak/util.h
MAN3 =\
libkeccak_behex_lower.3\
@@ -183,8 +193,9 @@ install: libkeccak.$(LIBEXT) libkeccak.a
ln -sf -- libkeccak.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libkeccak.$(LIBMAJOREXT)"
ln -sf -- libkeccak.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libkeccak.$(LIBEXT)"
cp -- libkeccak.a "$(DESTDIR)$(PREFIX)/lib/libkeccak.a"
- mkdir -p -- "$(DESTDIR)$(PREFIX)/include"
- cp -- libkeccak.h libkeccak-legacy.h "$(DESTDIR)$(PREFIX)/include/"
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/include/libkeccak"
+ cp -- libkeccak.h "$(DESTDIR)$(PREFIX)/include/"
+ cp -- $(SUBHDR) "$(DESTDIR)$(PREFIX)/include/libkeccak/"
mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man3"
mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man7"
cp -- $(MAN3) "$(DESTDIR)$(MANPREFIX)/man3"
@@ -197,14 +208,13 @@ uninstall:
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libkeccak.$(LIBMAJOREXT)"
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libkeccak.$(LIBEXT)"
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libkeccak.a"
- -rm -f -- "$(DESTDIR)$(PREFIX)/include/libkeccak.h"
- -rm -f -- "$(DESTDIR)$(PREFIX)/include/libkeccak-legacy.h"
+ -cd -- "$(DESTDIR)$(PREFIX)/include/" && rm -f $(SUBHDIR)
-cd -- "$(DESTDIR)$(MANPREFIX)/man3" && rm -f -- $(MAN3)
-cd -- "$(DESTDIR)$(MANPREFIX)/man7" && rm -f -- $(MAN7)
-rm -rf -- "$(DESTDIR)$(PREFIX)/share/licenses/libkeccak"
clean:
- -rm -f -- *.o *.su libkeccak/*.o libkeccak/*.su test benchmark benchfile
+ -rm -f -- *.o *.su test benchmark benchfile
-rm -f -- *.a libkeccak.$(LIBEXT) libkeccak.$(LIBEXT).* libkeccak.*.$(LIBEXT)
.SUFFIXES:
diff --git a/TODO b/TODO
index 39c9750..ec8eda0 100644
--- a/TODO
+++ b/TODO
@@ -8,7 +8,7 @@ Just for fun:
Add tests for HMAC
-Add libkeccak_cshakesum_fd (TODO in libkeccak.h)
+Add libkeccak_cshakesum_fd (TODO in libkeccak/cshake.h)
Add KMAC and KMACXOF
Add TupleHash and TupleHashXOF
diff --git a/common.h b/common.h
index 9d23b8e..4b95a06 100644
--- a/common.h
+++ b/common.h
@@ -28,6 +28,7 @@
# define __builtin_memset(dest, c, n) memset(dest, c, n)
# define __builtin_memcpy(dest, src, n) memcpy(dest, src, n)
# define __builtin_memmove(dest, src, n) memmove(dest, src, n)
+# define __builtin_strlen(s) strlen(s)
#endif
diff --git a/libkeccak-legacy.h b/libkeccak-legacy.h
deleted file mode 100644
index 3516053..0000000
--- a/libkeccak-legacy.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-
-
-LIBKECCAK_GCC_ONLY(__attribute__((__deprecated__("Use struct libkeccak_spec instead of libkeccak_spec_t"))))
-typedef struct libkeccak_spec libkeccak_spec_t;
-
-LIBKECCAK_GCC_ONLY(__attribute__((__deprecated__("Use struct libkeccak_generalised_spec instead of libkeccak_generalised_spec_t"))))
-typedef struct libkeccak_generalised_spec libkeccak_generalised_spec_t;
-
-LIBKECCAK_GCC_ONLY(__attribute__((__deprecated__("Use struct libkeccak_state instead of libkeccak_state_t"))))
-typedef struct libkeccak_state libkeccak_state_t;
-
-LIBKECCAK_GCC_ONLY(__attribute__((__deprecated__("Use struct libkeccak_hmac_state instead of libkeccak_hmac_state_t"))))
-typedef struct libkeccak_hmac_state libkeccak_hmac_state_t;
-
-LIBKECCAK_GCC_ONLY(__attribute__((__deprecated__("Use libkeccak_hmac_unmarshal(NULL, data) instead of libkeccak_hmac_unmarshal_skip(data)"))))
-static inline size_t
-libkeccak_hmac_unmarshal_skip(const void *data)
-{
- return libkeccak_hmac_unmarshal(NULL, data);
-}
-
-LIBKECCAK_GCC_ONLY(__attribute__((__deprecated__("Use libkeccak_state_unmarshal(NULL, data) instead of libkeccak_state_unmarshal_skip(data)"))))
-static inline size_t
-libkeccak_state_unmarshal_skip(const void *data)
-{
- return libkeccak_state_unmarshal(NULL, data);
-}
-
-LIBKECCAK_GCC_ONLY(__attribute__((__deprecated__("Use libkeccak_hmac_marshal(state, NULL) instead of libkeccak_hmac_marshal_size(state)"))))
-static inline size_t
-libkeccak_hmac_marshal_size(const struct libkeccak_hmac_state *state)
-{
- return libkeccak_hmac_marshal(state, NULL);
-}
-
-LIBKECCAK_GCC_ONLY(__attribute__((__deprecated__("Use libkeccak_state_marshal(state, NULL) instead of libkeccak_state_marshal_size(state)"))))
-static inline size_t
-libkeccak_state_marshal_size(const struct libkeccak_state *state)
-{
- return libkeccak_state_marshal(state, NULL);
-}
diff --git a/libkeccak.h b/libkeccak.h
index 84f0269..081e9e2 100644
--- a/libkeccak.h
+++ b/libkeccak.h
@@ -29,146 +29,6 @@
#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 `struct libkeccak_spec.bitrate`: non-positive
- */
-#define LIBKECCAK_SPEC_ERROR_BITRATE_NONPOSITIVE 1
-
-/**
- * Invalid `struct libkeccak_spec.bitrate`: not a multiple of 8
- */
-#define LIBKECCAK_SPEC_ERROR_BITRATE_MOD_8 2
-
-/**
- * Invalid `struct libkeccak_spec.capacity`: non-positive
- */
-#define LIBKECCAK_SPEC_ERROR_CAPACITY_NONPOSITIVE 3
-
-/**
- * Invalid `struct libkeccak_spec.capacity`: not a multiple of 8
- */
-#define LIBKECCAK_SPEC_ERROR_CAPACITY_MOD_8 4
-
-/**
- * Invalid `struct libkeccak_spec.output`: non-positive
- */
-#define LIBKECCAK_SPEC_ERROR_OUTPUT_NONPOSITIVE 5
-
-/**
- * Invalid `struct libkeccak_spec` values: `.bitrate + `.capacity`
- * is greater 1600 which is the largest supported state size
- */
-#define LIBKECCAK_SPEC_ERROR_STATE_TOO_LARGE 6
-
-/**
- * Invalid `struct libkeccak_spec` values:
- * `.bitrate + `.capacity` is not a multiple of 25
- */
-#define LIBKECCAK_SPEC_ERROR_STATE_MOD_25 7
-
-/**
- * Invalid `struct libkeccak_spec` values: `.bitrate + `.capacity`
- * is a not a 2-potent multiple of 25
- */
-#define LIBKECCAK_SPEC_ERROR_WORD_NON_2_POTENT 8
-
-/**
- * Invalid `struct libkeccak_spec` 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 `struct libkeccak_generalised_spec` member that
- * is used to automatically select the value
- */
-#define LIBKECCAK_GENERALISED_SPEC_AUTOMATIC (-65536L)
-
-
-/**
- * Invalid `struct libkeccak_generalised_spec.state_size`: non-positive
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_NONPOSITIVE 1
-
-/**
- * Invalid `struct libkeccak_generalised_spec.state_size`: larger than 1600
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_TOO_LARGE 2
-
-/**
- * Invalid `struct libkeccak_generalised_spec.state_size`: not a multiple of 25
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_MOD_25 3
-
-/**
- * Invalid `struct libkeccak_generalised_spec.word_size`: non-positive
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_WORD_NONPOSITIVE 4
-
-/**
- * Invalid `struct libkeccak_generalised_spec.word_size`: larger than 1600 / 25
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_WORD_TOO_LARGE 5
-
-/**
- * Invalid `struct libkeccak_generalised_spec.word_size` and
- * `struct libkeccak_generalised_spec.state_size`: `.word_size * 25 != .state_size`
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_WORD_INCOHERENCY 6
-
-/**
- * Invalid `struct libkeccak_generalised_spec.capacity`: non-positive
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_CAPACITY_NONPOSITIVE 7
-
-/**
- * Invalid `struct libkeccak_generalised_spec.capacity`: not a multiple of 8
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_CAPACITY_MOD_8 8
-
-/**
- * Invalid `struct libkeccak_generalised_spec.bitrate`: non-positive
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_BITRATE_NONPOSITIVE 9
-
-/**
- * Invalid `struct libkeccak_generalised_spec.bitrate`: not a multiple of 8
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_BITRATE_MOD_8 10
-
-/**
- * Invalid `struct libkeccak_generalised_spec.output`: non-positive
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_OUTPUT_NONPOSITIVE 11
-
-/**
- * Invalid `struct libkeccak_generalised_spec.state_size`,
- * `struct libkeccak_generalised_spec.bitrate`, and
- * `struct libkeccak_generalised_spec.capacity`:
- * `.bitrate + .capacity != .state_size`
- */
-#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_BITRATE_CAPACITY_INCONSISTENCY 12
-
-
/**
* Data structure that describes the parameters
* that should be used when hashing
@@ -191,37 +51,6 @@ struct libkeccak_spec {
};
/**
- * Generalised datastructure that describes the
- * parameters that should be used when hashing
- */
-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;
-};
-
-/**
* Data structure that describes the state of a hashing process
*
* The `char`-size of the output hashsum is calculated by `(.n + 7) / 8`
@@ -288,114 +117,6 @@ struct libkeccak_state {
unsigned char *M;
};
-
-/**
- * Fill in a `struct libkeccak_spec` 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__)))
-inline void
-libkeccak_spec_sha3(struct libkeccak_spec *spec, long int x)
-{
- spec->bitrate = 1600 - 2 * x;
- spec->capacity = 2 * x;
- spec->output = x;
-}
-
-/**
- * Fill in a `struct libkeccak_spec` 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__)))
-inline void
-libkeccak_spec_rawshake(struct libkeccak_spec *spec, long int x, long int d)
-{
- spec->bitrate = 1600 - 2 * x;
- spec->capacity = 2 * x;
- spec->output = d;
-}
-
-/**
- * Fill in a `struct libkeccak_spec` for a SHAKEx hashing
- *
- * @param spec:struct libkeccak_spec * 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
-
-/**
- * Fill in a `struct libkeccak_spec` for a cSHAKEx hashing
- *
- * @param spec:struct libkeccak_spec * The specifications datastructure to fill in
- * @param x:long The value of x in `cSHAKEx`, half the capacity
- * @param d:long The output size
- */
-#define libkeccak_spec_cshake libkeccak_spec_rawshake
-
-/**
- * Check for errors in a `struct libkeccak_spec`
- *
- * @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__, __warn_unused_result__, __pure__)))
-inline int
-libkeccak_spec_check(const struct libkeccak_spec *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__)))
-inline void
-libkeccak_generalised_spec_initialise(struct libkeccak_generalised_spec *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 `struct libkeccak_generalised_spec` to a `struct libkeccak_spec`
- *
- * @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(struct libkeccak_generalised_spec *, struct libkeccak_spec *);
-
/**
* Initialise a state according to hashing specifications
*
@@ -555,30 +276,6 @@ LIBKECCAK_GCC_ONLY(__attribute__((__leaf__, __nonnull__(2))))
size_t libkeccak_state_unmarshal(struct libkeccak_state *restrict, const void *restrict);
/**
- * Create and absorb the initialisation blocks for cSHAKE hashing
- *
- * @param state The hashing state
- * @param n_text Function name-string
- * @param n_len Byte-length of `n_text` (only whole byte)
- * @param n_bits Bit-length of `n_text`, minus `n_len * 8`
- * @param n_suffix Bit-string, represented by a NUL-terminated
- * string of '1':s and '0's:, making up the part
- * after `n_text` of the function-name bit-string;
- * `NULL` is treated as the empty string
- * @param s_text Customisation-string
- * @param s_len Byte-length of `s_text` (only whole byte)
- * @param s_bits Bit-length of `s_text`, minus `s_len * 8`
- * @param s_suffix Bit-string, represented by a NUL-terminated
- * string of '1':s and '0's:, making up the part
- * after `s_text` of the customisation bit-string;
- * `NULL` is treated as the empty string
- */
-LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1), __nothrow__)))
-void libkeccak_cshake_initialise(struct libkeccak_state *restrict,
- const void *, size_t, size_t, const char *,
- const void *, size_t, size_t, const char *);
-
-/**
* Get the number of bytes that are absorbed during
* one pass of the absorption phase
*
@@ -635,20 +332,6 @@ LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__)))
int libkeccak_update(struct libkeccak_state *restrict, const void *restrict, size_t);
/**
- * Get message suffix for cSHAKE hashing
- *
- * @param nlen Whether the function-name bit string is non-empty
- * @param slen Whether the customisation bit string is non-empty
- * @return The message suffix to use
- */
-LIBKECCAK_GCC_ONLY(__attribute__((__nothrow__, __warn_unused_result__, __const__, __returns_nonnull__)))
-inline const char *
-libkeccak_cshake_suffix(size_t nlen, size_t slen)
-{
- return (nlen || slen) ? "00" : LIBKECCAK_SHAKE_SUFFIX;
-}
-
-/**
* Absorb the last part of the message and squeeze the Keccak sponge
* without copying the data to an internal buffer
*
@@ -730,481 +413,16 @@ void libkeccak_fast_squeeze(register struct libkeccak_state *, register long int
LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__)))
void libkeccak_squeeze(register struct libkeccak_state *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 unless
- * `spec` is `NULL` (memory leak otherwise)
- * @param spec Specifications for the hashing algorithm; or `NULL`
- * if `spec` is already initialised
- * @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))))
-int libkeccak_generalised_sum_fd(int, struct libkeccak_state *restrict, const struct libkeccak_spec *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__)))
-inline int
-libkeccak_keccaksum_fd(int fd, struct libkeccak_state *restrict state,
- const struct libkeccak_spec *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__)))
-inline int
-libkeccak_sha3sum_fd(int fd, struct libkeccak_state *restrict state, long output, void *restrict hashsum)
-{
- struct libkeccak_spec 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__)))
-inline int
-libkeccak_rawshakesum_fd(int fd, struct libkeccak_state *restrict state, long semicapacity, long output, void *restrict hashsum)
-{
- struct libkeccak_spec 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__)))
-inline int
-libkeccak_shakesum_fd(int fd, struct libkeccak_state *restrict state, long semicapacity, long output, void *restrict hashsum)
-{
- struct libkeccak_spec spec;
- libkeccak_spec_shake(&spec, semicapacity, output);
- return libkeccak_generalised_sum_fd(fd, state, &spec, LIBKECCAK_SHAKE_SUFFIX, hashsum);
-}
-
-/* TODO add libkeccak_cshakesum_fd */
-
-
-/*
- * 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] HMAC-SHA3-224, HMAC-SHA3-256,
- * HMAC-SHA3-384, and HMAC-SHA3-512 are however approved by NIST.
- */
-
-
-/**
- * Data structure that describes the state of an HMAC-hashing process
- */
-struct libkeccak_hmac_state {
- /**
- * The key right-padded and XOR:ed with the outer pad
- */
- unsigned char *restrict key_opad;
-
- /**
- * The key right-padded and XOR:ed with the inner pad
- */
- unsigned 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
- */
- struct libkeccak_state sponge;
-
- /**
- * Buffer used to temporarily store bit shift message if
- * `.key_length` is not zero modulus 8
- */
- unsigned 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
- */
- unsigned char leftover;
-
- char _pad[sizeof(void *) - 1];
-};
-
-
-/**
- * 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(struct libkeccak_hmac_state *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__)))
-inline int
-libkeccak_hmac_initialise(struct libkeccak_hmac_state *restrict state, const struct libkeccak_spec *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__, __warn_unused_result__, __malloc__)))
-inline struct libkeccak_hmac_state *
-libkeccak_hmac_create(const struct libkeccak_spec *restrict spec, const void *restrict key, size_t key_length)
-{
- struct libkeccak_hmac_state *state = malloc(sizeof(struct libkeccak_hmac_state));
- 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))))
-inline int
-libkeccak_hmac_reset(struct libkeccak_hmac_state *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 struct libkeccak_hmac_state *);
-
-/**
- * Release resources allocation for an HMAC hashing-state without wiping sensitive data
- *
- * @param state The state that should be destroyed
- */
-inline void
-libkeccak_hmac_fast_destroy(struct libkeccak_hmac_state *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__((__optimize__("-O0"))))
-inline void
-libkeccak_hmac_destroy(volatile struct libkeccak_hmac_state *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
- */
-inline void
-libkeccak_hmac_fast_free(struct libkeccak_hmac_state *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__((__optimize__("-O0"))))
-inline void
-libkeccak_hmac_free(volatile struct libkeccak_hmac_state *state)
-{
-#ifdef __GNUC__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wcast-qual"
-#endif
- libkeccak_hmac_destroy(state);
- free((struct libkeccak_hmac_state *)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(struct libkeccak_hmac_state *restrict, const struct libkeccak_hmac_state *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__, __warn_unused_result__, __malloc__)))
-inline struct libkeccak_hmac_state *
-libkeccak_hmac_duplicate(const struct libkeccak_hmac_state *src)
-{
- struct libkeccak_hmac_state *dest = malloc(sizeof(struct libkeccak_hmac_state));
- if (!dest || libkeccak_hmac_copy(dest, src)) {
- libkeccak_hmac_free(dest);
- return NULL;
- }
- return dest;
-}
-
-/**
- * Marshal a `struct libkeccak_hmac_state` into a buffer
- *
- * @param state The state to marshal
- * @param data The output buffer, can be `NULL`
- * @return The number of bytes stored to `data`
- */
-LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1), __nothrow__)))
-inline size_t
-libkeccak_hmac_marshal(const struct libkeccak_hmac_state *restrict state, void *restrict data_)
-{
- unsigned char *restrict data = data_;
- size_t written = libkeccak_state_marshal(&state->sponge, data);
- if (data) {
- data += written;
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wcast-align"
-#endif
- *(size_t *)data = state->key_length;
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#endif
- data += sizeof(size_t);
- memcpy(data, state->key_opad, (state->key_length + 7) >> 3);
- data += (state->key_length + 7) >> 3;
- data[0] = (unsigned char)!!state->key_ipad;
- data[1] = state->leftover;
- }
- return written + sizeof(size_t) + ((state->key_length + 7) >> 3) + 2 * sizeof(char);
-}
-
-/**
- * Unmarshal a `struct libkeccak_hmac_state` from a buffer
- *
- * @param state The slot for the unmarshalled state, must not be
- * initialised (memory leak otherwise), can be `NULL`
- * @param data The input buffer
- * @return The number of bytes read from `data`, 0 on error
- */
-LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(2))))
-size_t libkeccak_hmac_unmarshal(struct libkeccak_hmac_state *restrict, const void *restrict);
-
-/**
- * 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(struct libkeccak_hmac_state *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(struct libkeccak_hmac_state *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(struct libkeccak_hmac_state *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(struct libkeccak_hmac_state *restrict state, const void *restrict msg, size_t msglen,
- size_t bits, const char *restrict suffix, void *restrict hashsum);
+#include "libkeccak/hmac.h"
+#include "libkeccak/legacy.h"
+#include "libkeccak/util.h"
-#include "libkeccak-legacy.h"
+#include "libkeccak/keccak.h"
+#include "libkeccak/sha3.h"
+#include "libkeccak/rawshake.h"
+#include "libkeccak/shake.h"
+#include "libkeccak/cshake.h"
#if defined(__clang__)
diff --git a/libkeccak/cshake.h b/libkeccak/cshake.h
new file mode 100644
index 0000000..6e341fe
--- /dev/null
+++ b/libkeccak/cshake.h
@@ -0,0 +1,54 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Get message suffix for cSHAKE hashing
+ *
+ * @param nlen Whether the function-name bit string is non-empty
+ * @param slen Whether the customisation bit string is non-empty
+ * @return The message suffix to use
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nothrow__, __warn_unused_result__, __const__, __returns_nonnull__)))
+inline const char *
+libkeccak_cshake_suffix(size_t nlen, size_t slen)
+{
+ return (nlen || slen) ? "00" : LIBKECCAK_SHAKE_SUFFIX;
+}
+
+
+/**
+ * Fill in a `struct libkeccak_spec` for a cSHAKEx hashing
+ *
+ * @param spec:struct libkeccak_spec * The specifications datastructure to fill in
+ * @param x:long The value of x in `cSHAKEx`, half the capacity
+ * @param d:long The output size
+ */
+#define libkeccak_spec_cshake libkeccak_spec_rawshake
+
+
+/**
+ * Create and absorb the initialisation blocks for cSHAKE hashing
+ *
+ * @param state The hashing state
+ * @param n_text Function name-string
+ * @param n_len Byte-length of `n_text` (only whole byte)
+ * @param n_bits Bit-length of `n_text`, minus `n_len * 8`
+ * @param n_suffix Bit-string, represented by a NUL-terminated
+ * string of '1':s and '0's:, making up the part
+ * after `n_text` of the function-name bit-string;
+ * `NULL` is treated as the empty string
+ * @param s_text Customisation-string
+ * @param s_len Byte-length of `s_text` (only whole byte)
+ * @param s_bits Bit-length of `s_text`, minus `s_len * 8`
+ * @param s_suffix Bit-string, represented by a NUL-terminated
+ * string of '1':s and '0's:, making up the part
+ * after `s_text` of the customisation bit-string;
+ * `NULL` is treated as the empty string
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1), __nothrow__)))
+void libkeccak_cshake_initialise(struct libkeccak_state *restrict,
+ const void *, size_t, size_t, const char *,
+ const void *, size_t, size_t, const char *);
+
+
+/* TODO add libkeccak_cshakesum_fd */
diff --git a/libkeccak/hmac.h b/libkeccak/hmac.h
new file mode 100644
index 0000000..583a427
--- /dev/null
+++ b/libkeccak/hmac.h
@@ -0,0 +1,358 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/*
+ * 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] HMAC-SHA3-224, HMAC-SHA3-256,
+ * HMAC-SHA3-384, and HMAC-SHA3-512 are however approved by NIST.
+ */
+
+
+/**
+ * Data structure that describes the state of an HMAC-hashing process
+ */
+struct libkeccak_hmac_state {
+ /**
+ * The key right-padded and XOR:ed with the outer pad
+ */
+ unsigned char *restrict key_opad;
+
+ /**
+ * The key right-padded and XOR:ed with the inner pad
+ */
+ unsigned 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
+ */
+ struct libkeccak_state sponge;
+
+ /**
+ * Buffer used to temporarily store bit shift message if
+ * `.key_length` is not zero modulus 8
+ */
+ unsigned 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
+ */
+ unsigned char leftover;
+
+ char _pad[sizeof(void *) - 1];
+};
+
+
+/**
+ * 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(struct libkeccak_hmac_state *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__)))
+inline int
+libkeccak_hmac_initialise(struct libkeccak_hmac_state *restrict state, const struct libkeccak_spec *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__, __warn_unused_result__, __malloc__)))
+inline struct libkeccak_hmac_state *
+libkeccak_hmac_create(const struct libkeccak_spec *restrict spec, const void *restrict key, size_t key_length)
+{
+ struct libkeccak_hmac_state *state = malloc(sizeof(struct libkeccak_hmac_state));
+ 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))))
+inline int
+libkeccak_hmac_reset(struct libkeccak_hmac_state *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 struct libkeccak_hmac_state *);
+
+
+/**
+ * Release resources allocation for an HMAC hashing-state without wiping sensitive data
+ *
+ * @param state The state that should be destroyed
+ */
+inline void
+libkeccak_hmac_fast_destroy(struct libkeccak_hmac_state *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__((__optimize__("-O0"))))
+inline void
+libkeccak_hmac_destroy(volatile struct libkeccak_hmac_state *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
+ */
+inline void
+libkeccak_hmac_fast_free(struct libkeccak_hmac_state *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__((__optimize__("-O0"))))
+inline void
+libkeccak_hmac_free(volatile struct libkeccak_hmac_state *state)
+{
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+ libkeccak_hmac_destroy(state);
+ free((struct libkeccak_hmac_state *)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(struct libkeccak_hmac_state *restrict, const struct libkeccak_hmac_state *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__, __warn_unused_result__, __malloc__)))
+inline struct libkeccak_hmac_state *
+libkeccak_hmac_duplicate(const struct libkeccak_hmac_state *src)
+{
+ struct libkeccak_hmac_state *dest = malloc(sizeof(struct libkeccak_hmac_state));
+ if (!dest || libkeccak_hmac_copy(dest, src)) {
+ libkeccak_hmac_free(dest);
+ return NULL;
+ }
+ return dest;
+}
+
+
+/**
+ * Marshal a `struct libkeccak_hmac_state` into a buffer
+ *
+ * @param state The state to marshal
+ * @param data The output buffer, can be `NULL`
+ * @return The number of bytes stored to `data`
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(1), __nothrow__)))
+inline size_t
+libkeccak_hmac_marshal(const struct libkeccak_hmac_state *restrict state, void *restrict data_)
+{
+ unsigned char *restrict data = data_;
+ size_t written = libkeccak_state_marshal(&state->sponge, data);
+ if (data) {
+ data += written;
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wcast-align"
+#endif
+ memcpy(data, &state->key_length, sizeof(state->key_length));
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+ data += sizeof(size_t);
+ memcpy(data, state->key_opad, (state->key_length + 7) >> 3);
+ data += (state->key_length + 7) >> 3;
+ data[0] = (unsigned char)!!state->key_ipad;
+ data[1] = state->leftover;
+ }
+ return written + sizeof(size_t) + ((state->key_length + 7) >> 3) + 2 * sizeof(char);
+}
+
+
+/**
+ * Unmarshal a `struct libkeccak_hmac_state` from a buffer
+ *
+ * @param state The slot for the unmarshalled state, must not be
+ * initialised (memory leak otherwise), can be `NULL`
+ * @param data The input buffer
+ * @return The number of bytes read from `data`, 0 on error
+ */
+LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__(2))))
+size_t libkeccak_hmac_unmarshal(struct libkeccak_hmac_state *restrict, const void *restrict);
+
+
+/**
+ * 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(struct libkeccak_hmac_state *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(struct libkeccak_hmac_state *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(struct libkeccak_hmac_state *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(struct libkeccak_hmac_state *restrict state, const void *restrict msg, size_t msglen,
+ size_t bits, const char *restrict suffix, void *restrict hashsum);
diff --git a/libkeccak/keccak.h b/libkeccak/keccak.h
new file mode 100644
index 0000000..0d3cce0
--- /dev/null
+++ b/libkeccak/keccak.h
@@ -0,0 +1,237 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Invalid `struct libkeccak_spec.bitrate`: non-positive
+ */
+#define LIBKECCAK_SPEC_ERROR_BITRATE_NONPOSITIVE 1
+
+/**
+ * Invalid `struct libkeccak_spec.bitrate`: not a multiple of 8
+ */
+#define LIBKECCAK_SPEC_ERROR_BITRATE_MOD_8 2
+
+/**
+ * Invalid `struct libkeccak_spec.capacity`: non-positive
+ */
+#define LIBKECCAK_SPEC_ERROR_CAPACITY_NONPOSITIVE 3
+
+/**
+ * Invalid `struct libkeccak_spec.capacity`: not a multiple of 8
+ */
+#define LIBKECCAK_SPEC_ERROR_CAPACITY_MOD_8 4
+
+/**
+ * Invalid `struct libkeccak_spec.output`: non-positive
+ */
+#define LIBKECCAK_SPEC_ERROR_OUTPUT_NONPOSITIVE 5
+
+/**
+ * Invalid `struct libkeccak_spec` values: `.bitrate + `.capacity`
+ * is greater 1600 which is the largest supported state size
+ */
+#define LIBKECCAK_SPEC_ERROR_STATE_TOO_LARGE 6
+
+/**
+ * Invalid `struct libkeccak_spec` values:
+ * `.bitrate + `.capacity` is not a multiple of 25
+ */
+#define LIBKECCAK_SPEC_ERROR_STATE_MOD_25 7
+
+/**
+ * Invalid `struct libkeccak_spec` values: `.bitrate + `.capacity`
+ * is a not a 2-potent multiple of 25
+ */
+#define LIBKECCAK_SPEC_ERROR_WORD_NON_2_POTENT 8
+
+/**
+ * Invalid `struct libkeccak_spec` 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 `struct libkeccak_generalised_spec` member that
+ * is used to automatically select the value
+ */
+#define LIBKECCAK_GENERALISED_SPEC_AUTOMATIC (-65536L)
+
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.state_size`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_NONPOSITIVE 1
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.state_size`: larger than 1600
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_TOO_LARGE 2
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.state_size`: not a multiple of 25
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_MOD_25 3
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.word_size`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_WORD_NONPOSITIVE 4
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.word_size`: larger than 1600 / 25
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_WORD_TOO_LARGE 5
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.word_size` and
+ * `struct libkeccak_generalised_spec.state_size`: `.word_size * 25 != .state_size`
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_WORD_INCOHERENCY 6
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.capacity`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_CAPACITY_NONPOSITIVE 7
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.capacity`: not a multiple of 8
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_CAPACITY_MOD_8 8
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.bitrate`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_BITRATE_NONPOSITIVE 9
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.bitrate`: not a multiple of 8
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_BITRATE_MOD_8 10
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.output`: non-positive
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_OUTPUT_NONPOSITIVE 11
+
+/**
+ * Invalid `struct libkeccak_generalised_spec.state_size`,
+ * `struct libkeccak_generalised_spec.bitrate`, and
+ * `struct libkeccak_generalised_spec.capacity`:
+ * `.bitrate + .capacity != .state_size`
+ */
+#define LIBKECCAK_GENERALISED_SPEC_ERROR_STATE_BITRATE_CAPACITY_INCONSISTENCY 12
+
+
+/**
+ * Generalised datastructure that describes the
+ * parameters that should be used when hashing
+ */
+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;
+};
+
+
+/**
+ * Check for errors in a `struct libkeccak_spec`
+ *
+ * @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__, __warn_unused_result__, __pure__)))
+inline int
+libkeccak_spec_check(const struct libkeccak_spec *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__)))
+inline void
+libkeccak_generalised_spec_initialise(struct libkeccak_generalised_spec *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 `struct libkeccak_generalised_spec` to a `struct libkeccak_spec`
+ *
+ * @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(struct libkeccak_generalised_spec *, struct libkeccak_spec *);
+
+
+/**
+ * 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__)))
+inline int
+libkeccak_keccaksum_fd(int fd, struct libkeccak_state *restrict state,
+ const struct libkeccak_spec *restrict spec, void *restrict hashsum)
+{
+ return libkeccak_generalised_sum_fd(fd, state, spec, NULL, hashsum);
+}
diff --git a/libkeccak/legacy.h b/libkeccak/legacy.h
new file mode 100644
index 0000000..ad183a5
--- /dev/null
+++ b/libkeccak/legacy.h
@@ -0,0 +1,53 @@
+/* See LICENSE file for copyright and license details. */
+
+
+#define LIBKECCAK_DEPRECATED(MSG) \
+ LIBKECCAK_GCC_ONLY(__attribute__((__deprecated__(MSG))))
+
+
+LIBKECCAK_DEPRECATED("Use struct libkeccak_spec instead of libkeccak_spec_t")
+typedef struct libkeccak_spec libkeccak_spec_t;
+
+
+LIBKECCAK_DEPRECATED("Use struct libkeccak_generalised_spec instead of libkeccak_generalised_spec_t")
+typedef struct libkeccak_generalised_spec libkeccak_generalised_spec_t;
+
+
+LIBKECCAK_DEPRECATED("Use struct libkeccak_state instead of libkeccak_state_t")
+typedef struct libkeccak_state libkeccak_state_t;
+
+
+LIBKECCAK_DEPRECATED("Use struct libkeccak_hmac_state instead of libkeccak_hmac_state_t")
+typedef struct libkeccak_hmac_state libkeccak_hmac_state_t;
+
+
+LIBKECCAK_DEPRECATED("Use libkeccak_hmac_unmarshal(NULL, data) instead of libkeccak_hmac_unmarshal_skip(data)")
+static inline size_t
+libkeccak_hmac_unmarshal_skip(const void *data)
+{
+ return libkeccak_hmac_unmarshal(NULL, data);
+}
+
+
+LIBKECCAK_DEPRECATED("Use libkeccak_state_unmarshal(NULL, data) instead of libkeccak_state_unmarshal_skip(data)")
+static inline size_t
+libkeccak_state_unmarshal_skip(const void *data)
+{
+ return libkeccak_state_unmarshal(NULL, data);
+}
+
+
+LIBKECCAK_DEPRECATED("Use libkeccak_hmac_marshal(state, NULL) instead of libkeccak_hmac_marshal_size(state)")
+static inline size_t
+libkeccak_hmac_marshal_size(const struct libkeccak_hmac_state *state)
+{
+ return libkeccak_hmac_marshal(state, NULL);
+}
+
+
+LIBKECCAK_DEPRECATED("Use libkeccak_state_marshal(state, NULL) instead of libkeccak_state_marshal_size(state)")
+static inline size_t
+libkeccak_state_marshal_size(const struct libkeccak_state *state)
+{
+ return libkeccak_state_marshal(state, NULL);
+}
diff --git a/libkeccak/rawshake.h b/libkeccak/rawshake.h
new file mode 100644
index 0000000..e1caf71
--- /dev/null
+++ b/libkeccak/rawshake.h
@@ -0,0 +1,46 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Message suffix for RawSHAKE hashing
+ */
+#define LIBKECCAK_RAWSHAKE_SUFFIX "11"
+
+
+/**
+ * Fill in a `struct libkeccak_spec` 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__)))
+inline void
+libkeccak_spec_rawshake(struct libkeccak_spec *spec, long int x, long int d)
+{
+ spec->bitrate = 1600 - 2 * x;
+ spec->capacity = 2 * x;
+ spec->output = d;
+}
+
+
+/**
+ * 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__)))
+inline int
+libkeccak_rawshakesum_fd(int fd, struct libkeccak_state *restrict state, long semicapacity, long output, void *restrict hashsum)
+{
+ struct libkeccak_spec spec;
+ libkeccak_spec_rawshake(&spec, semicapacity, output);
+ return libkeccak_generalised_sum_fd(fd, state, &spec, LIBKECCAK_RAWSHAKE_SUFFIX, hashsum);
+}
diff --git a/libkeccak/sha3.h b/libkeccak/sha3.h
new file mode 100644
index 0000000..7d75ace
--- /dev/null
+++ b/libkeccak/sha3.h
@@ -0,0 +1,44 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Message suffix for SHA3 hashing
+ */
+#define LIBKECCAK_SHA3_SUFFIX "01"
+
+
+/**
+ * Fill in a `struct libkeccak_spec` 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__)))
+inline void
+libkeccak_spec_sha3(struct libkeccak_spec *spec, long int x)
+{
+ spec->bitrate = 1600 - 2 * x;
+ spec->capacity = 2 * x;
+ spec->output = x;
+}
+
+
+/**
+ * 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__)))
+inline int
+libkeccak_sha3sum_fd(int fd, struct libkeccak_state *restrict state, long output, void *restrict hashsum)
+{
+ struct libkeccak_spec spec;
+ libkeccak_spec_sha3(&spec, output);
+ return libkeccak_generalised_sum_fd(fd, state, &spec, LIBKECCAK_SHA3_SUFFIX, hashsum);
+}
diff --git a/libkeccak/shake.h b/libkeccak/shake.h
new file mode 100644
index 0000000..2635e3e
--- /dev/null
+++ b/libkeccak/shake.h
@@ -0,0 +1,39 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Message suffix for SHAKE hashing
+ */
+#define LIBKECCAK_SHAKE_SUFFIX "1111"
+
+
+/**
+ * Fill in a `struct libkeccak_spec` for a SHAKEx hashing
+ *
+ * @param spec:struct libkeccak_spec * 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
+
+
+/**
+ * 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__)))
+inline int
+libkeccak_shakesum_fd(int fd, struct libkeccak_state *restrict state, long semicapacity, long output, void *restrict hashsum)
+{
+ struct libkeccak_spec spec;
+ libkeccak_spec_shake(&spec, semicapacity, output);
+ return libkeccak_generalised_sum_fd(fd, state, &spec, LIBKECCAK_SHAKE_SUFFIX, hashsum);
+}
diff --git a/libkeccak/util.h b/libkeccak/util.h
new file mode 100644
index 0000000..6611b50
--- /dev/null
+++ b/libkeccak/util.h
@@ -0,0 +1,54 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * 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 unless
+ * `spec` is `NULL` (memory leak otherwise)
+ * @param spec Specifications for the hashing algorithm; or `NULL`
+ * if `spec` is already initialised
+ * @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))))
+int libkeccak_generalised_sum_fd(int, struct libkeccak_state *restrict, const struct libkeccak_spec *restrict,
+ const char *restrict, void *restrict);
diff --git a/libkeccak_hmac_unmarshal.c b/libkeccak_hmac_unmarshal.c
index d4fb647..070c7b5 100644
--- a/libkeccak_hmac_unmarshal.c
+++ b/libkeccak_hmac_unmarshal.c
@@ -28,7 +28,7 @@ libkeccak_hmac_unmarshal(struct libkeccak_hmac_state *restrict state, const void
return 0;
data += parsed;
- size = *(const size_t *)data;
+ __builtin_memcpy(&size, data, sizeof(size));
data += sizeof(size_t);
if (state)
size = state->key_length;
@@ -44,7 +44,7 @@ libkeccak_hmac_unmarshal(struct libkeccak_hmac_state *restrict state, const void
data += size;
if (data[0]) {
- state->key_ipad = state->key_opad + size;
+ state->key_ipad = &state->key_opad[size];
memcpy(state->key_ipad, state->key_opad, size);
for (i = 0; i < size; i++)
state->key_ipad[i] ^= (char)(HMAC_OUTER_PAD ^ HMAC_INNER_PAD);
diff --git a/libkeccak_state_marshal.c b/libkeccak_state_marshal.c
index 6563038..480b4a4 100644
--- a/libkeccak_state_marshal.c
+++ b/libkeccak_state_marshal.c
@@ -17,9 +17,15 @@
size_t
libkeccak_state_marshal(const struct libkeccak_state *restrict state, void *restrict data_)
{
-#define set(type, var) *(type *)data = state->var, data += sizeof(type)
+#define set(VAR)\
+ do {\
+ __builtin_memcpy(data, &state->VAR, sizeof(state->VAR));\
+ data += sizeof(state->VAR);\
+ } while (0)
+
unsigned char *restrict start = data_;
unsigned char *restrict data = start;
+
if (!data) {
return 7 * sizeof(long int) +
1 * sizeof(int64_t) +
@@ -27,20 +33,23 @@ libkeccak_state_marshal(const struct libkeccak_state *restrict state, void *rest
2 * sizeof(size_t) +
state->mptr;
}
- 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));
+
+ set(r);
+ set(c);
+ set(n);
+ set(b);
+ set(w);
+ set(wmod);
+ set(l);
+ set(nr);
+ __builtin_memcpy(data, state->S, sizeof(state->S));
data += sizeof(state->S);
- set(size_t, mptr);
- set(size_t, mlen);
+ set(mptr);
+ set(mlen);
memcpy(data, state->M, state->mptr * sizeof(char));
data += state->mptr;
+
return (size_t)(data - start);
+
#undef set
}
diff --git a/libkeccak_state_unmarshal.c b/libkeccak_state_unmarshal.c
index f221fad..f9604a2 100644
--- a/libkeccak_state_unmarshal.c
+++ b/libkeccak_state_unmarshal.c
@@ -18,31 +18,38 @@
size_t
libkeccak_state_unmarshal(struct libkeccak_state *restrict state, const void *restrict data_)
{
-#define get(type, var) state->var = *(const type *)data, data += sizeof(type)
+#define get(VAR) \
+ do {\
+ __builtin_memcpy(&state->VAR, data, sizeof(state->VAR));\
+ data += sizeof(state->VAR);\
+ } while (0)
+
const unsigned char *restrict start = data_;
const unsigned char *restrict data = start;
size_t mptr;
+
if (!state) {
- data += 7 * sizeof(long int);
- data += 1 * sizeof(int64_t);
+ data += 7U * sizeof(long int);
+ data += 1U * sizeof(int64_t);
data += sizeof(state->S);
mptr = *(const size_t *)data;
- data += 2 * sizeof(size_t);
+ data += 2U * sizeof(size_t);
data += mptr;
return (size_t)(data - start);
}
- 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);
+
+ get(r);
+ get(c);
+ get(n);
+ get(b);
+ get(w);
+ get(wmod);
+ get(l);
+ get(nr);
memcpy(state->S, data, sizeof(state->S));
data += sizeof(state->S);
- get(size_t, mptr);
- get(size_t, mlen);
+ get(mptr);
+ get(mlen);
if (state->mptr) {
state->M = malloc(state->mptr * sizeof(char));
if (!state->M)
@@ -52,6 +59,8 @@ libkeccak_state_unmarshal(struct libkeccak_state *restrict state, const void *re
} else {
state->M = NULL;
}
+
return (size_t)(data - start);
+
#undef get
}