aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2022-02-27 18:27:08 +0100
committerMattias Andrée <maandree@kth.se>2022-02-27 18:27:08 +0100
commitac2a6719f074fa43d79b31a3994549f2af55efd6 (patch)
tree5b64a6d135fef440bc48af89d846acf1b7937ebc
parentm (diff)
downloadlibkeccak-ac2a6719f074fa43d79b31a3994549f2af55efd6.tar.gz
libkeccak-ac2a6719f074fa43d79b31a3994549f2af55efd6.tar.bz2
libkeccak-ac2a6719f074fa43d79b31a3994549f2af55efd6.tar.xz
Add cSHAKE
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--Makefile5
-rw-r--r--libkeccak.72
-rw-r--r--libkeccak.h62
-rw-r--r--libkeccak_cshake_initialise.3126
-rw-r--r--libkeccak_cshake_initialise.c275
-rw-r--r--libkeccak_cshake_suffix.345
-rw-r--r--libkeccak_cshake_suffix.c5
-rw-r--r--libkeccak_degeneralise_spec.31
-rw-r--r--libkeccak_digest.318
-rw-r--r--libkeccak_fast_digest.318
-rw-r--r--libkeccak_fast_update.39
-rw-r--r--libkeccak_generalised_spec_initialise.31
-rw-r--r--libkeccak_generalised_sum_fd.317
-rw-r--r--libkeccak_generalised_sum_fd.c8
-rw-r--r--libkeccak_hmac_initialise.31
-rw-r--r--libkeccak_spec_check.32
-rw-r--r--libkeccak_spec_cshake.348
-rw-r--r--libkeccak_spec_rawshake.31
-rw-r--r--libkeccak_spec_sha3.31
-rw-r--r--libkeccak_spec_shake.31
-rw-r--r--libkeccak_state_initialise.31
-rw-r--r--libkeccak_update.39
-rw-r--r--libkeccak_zerocopy_digest.318
-rw-r--r--libkeccak_zerocopy_update.39
-rw-r--r--test.c246
25 files changed, 848 insertions, 81 deletions
diff --git a/Makefile b/Makefile
index c2a3ef3..0bb5353 100644
--- a/Makefile
+++ b/Makefile
@@ -21,6 +21,8 @@ OBJ =\
digest.o\
libkeccak_behex_lower.o\
libkeccak_behex_upper.o\
+ libkeccak_cshake_initialise.o\
+ libkeccak_cshake_suffix.o\
libkeccak_degeneralise_spec.o\
libkeccak_generalised_spec_initialise.o\
libkeccak_generalised_sum_fd.o\
@@ -73,6 +75,8 @@ HDR =\
MAN3 =\
libkeccak_behex_lower.3\
libkeccak_behex_upper.3\
+ libkeccak_cshake_initialise.3\
+ libkeccak_cshake_suffix.3\
libkeccak_degeneralise_spec.3\
libkeccak_digest.3\
libkeccak_fast_digest.3\
@@ -103,6 +107,7 @@ MAN3 =\
libkeccak_shakesum_fd.3\
libkeccak_simple_squeeze.3\
libkeccak_spec_check.3\
+ libkeccak_spec_cshake.3\
libkeccak_spec_rawshake.3\
libkeccak_spec_sha3.3\
libkeccak_spec_shake.3\
diff --git a/libkeccak.7 b/libkeccak.7
index 9ece381..34c9dba 100644
--- a/libkeccak.7
+++ b/libkeccak.7
@@ -10,6 +10,7 @@ implicit parameters, secure erasure of sensitive data, and HMAC.
Keccak-3200 may be implemented in the future.
.SH SEE ALSO
.BR libkeccak_spec_sha3 (3),
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_rawshake (3),
.BR libkeccak_spec_shake (3),
.BR libkeccak_spec_check (3),
@@ -32,6 +33,7 @@ Keccak-3200 may be implemented in the future.
.BR libkeccak_fast_update (3),
.BR libkeccak_zerocopy_update (3),
.BR libkeccak_update (3),
+.BR libkeccak_cshake_suffix (3),
.BR libkeccak_fast_digest (3),
.BR libkeccak_zerocopy_digest (3),
.BR libkeccak_digest (3),
diff --git a/libkeccak.h b/libkeccak.h
index b603cbf..84f0269 100644
--- a/libkeccak.h
+++ b/libkeccak.h
@@ -330,6 +330,15 @@ libkeccak_spec_rawshake(struct libkeccak_spec *spec, long int x, long int d)
#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
@@ -546,6 +555,30 @@ 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
*
@@ -556,7 +589,7 @@ LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__, __warn_unused_result
inline size_t
libkeccak_zerocopy_chunksize(struct libkeccak_state *state)
{
- return state->r >> 3;
+ return (size_t)state->r >> 3;
}
/**
@@ -601,6 +634,19 @@ int libkeccak_fast_update(struct libkeccak_state *restrict, const void *restrict
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
@@ -719,14 +765,17 @@ void libkeccak_unhex(void *restrict, const char *restrict);
* 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 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, 3))))
+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);
@@ -811,11 +860,14 @@ libkeccak_shakesum_fd(int fd, struct libkeccak_state *restrict state, long semic
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]
+ * 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.
*/
@@ -861,7 +913,7 @@ struct libkeccak_hmac_state {
*/
unsigned char leftover;
- char __pad[sizeof(void *) - 1];
+ char _pad[sizeof(void *) - 1];
};
diff --git a/libkeccak_cshake_initialise.3 b/libkeccak_cshake_initialise.3
new file mode 100644
index 0000000..a18f1bf
--- /dev/null
+++ b/libkeccak_cshake_initialise.3
@@ -0,0 +1,126 @@
+.TH LIBKECCAK_CSHAKE_INITIALISE 3 LIBKECCAK
+.SH NAME
+libkeccak_cshake_initialise - Initialise a sponge for cSHAKE hashing
+.SH SYNOPSIS
+.nf
+#include <libkeccak.h>
+
+void libkeccak_cshake_initialise(struct libkeccak_state *restrict \fIstate\fP,
+ const void *\fIn_text\fP, size_t \fIn_len\fP, size_t \fIn_bits\fP, const char *\fIn_suffix\fP,
+ const void *\fIs_text\fP, size_t \fIs_len\fP, size_t \fIs_bits\fP, const char *\fIs_suffix\fP);
+.fi
+.PP
+Link with
+.IR -lkeccak .
+.SH DESCRIPTION
+The
+.BR libkeccak_cshake_suffix ()
+function shall be called immediately
+after the
+.BR libkeccak_state_initialise (3)
+function (before
+.BR libkeccak_update (3)
+or
+.BR libkeccak_digest (3),
+or any variant of those functions),
+to provide the initialisation blocks,
+containing customisation data, to the
+Keccak sponge.
+.PP
+The value of the
+.I state
+parameter shall be an initialised state
+to feed the initialisation blocks to.
+.PP
+The value of the
+.I n_text
+parameter shall be the function-name
+bit-string, represented in raw bytes;
+.I n_len
+shall be value no greater than the
+number of whole bytes in
+.I n_text
+and
+.I n_bits
+shall be the number of bits in
+.I n_text
+sans the bytes covered by
+.IR n_len ,
+that is, the number of bits in
+.I n_text
+minus
+.IR (nlen_*8) .
+.I n_suffix
+shall be either
+.I NULL
+or an appendix of bits to
+.I n_suffix
+(neither
+.I n_len
+nor
+.I n_bits
+shall count these), stored as a NUL-terminated
+string of the ASCII digits
+.B 1
+and
+.BR 0 .
+.PP
+The value of the
+.I s_text
+parameter shall be the customisation
+bit-string, represented in raw bytes;
+.I s_len
+shall be value no greater than the
+number of whole bytes in
+.I s_text
+and
+.I s_bits
+shall be the number of bits in
+.I s_text
+sans the bytes covered by
+.IR s_len ,
+that is, the number of bits in
+.I s_text
+minus
+.IR (nles_*8) .
+.I s_suffix
+shall be either
+.I NULL
+or an appendix of bits to
+.I s_suffix
+(neither
+.I s_len
+nor
+.I s_bits
+shall count these), stored as a NUL-terminated
+string of the ASCII digits
+.B 1
+and
+.BR 0 .
+.PP
+For the
+.I n_suffix
+and
+.I s_suffix
+parameters,
+.I NULL
+is treated as the empty string.
+.SH RETURN VALUES
+The
+.BR libkeccak_cshake_suffix ()
+function does not return a value.
+.SH ERRORS
+The
+.BR libkeccak_cshake_suffix ()
+function cannot fail.
+.SH SEE ALSO
+.BR libkeccak_spec_cshake (3),
+.BR libkeccak_generalised_spec_initialise (3),
+.BR libkeccak_state_initialise (3),
+.BR libkeccak_cshake_initialise (3),
+.BR libkeccak_fast_update (3),
+.BR libkeccak_zerocopy_update (3),
+.BR libkeccak_update (3),
+.BR libkeccak_fast_digest (3),
+.BR libkeccak_zerocopy_digest (3),
+.BR libkeccak_digest (3)
diff --git a/libkeccak_cshake_initialise.c b/libkeccak_cshake_initialise.c
new file mode 100644
index 0000000..dd47fc6
--- /dev/null
+++ b/libkeccak_cshake_initialise.c
@@ -0,0 +1,275 @@
+#include <stdio.h>
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Encode a number in big-endian with a size prefix
+ *
+ * @param state The hashing state the feed the number to
+ * @param buf Buffer that is at least `byterate` bytes large
+ * @param byterate The byterate of the hashing algorithm
+ * @param value The number to send to the hashing sponge
+ * @param off Current offset in `buf`
+ * @return New offset in `buf`
+ */
+static size_t
+encode_left(struct libkeccak_state *restrict state, uint8_t *restrict buf, size_t byterate, size_t value, size_t off)
+{
+ size_t x, n, j, i = off;
+
+ for (x = value, n = 0; x; x >>= 8)
+ n += 1;
+ if (!n)
+ n = 1;
+ buf[i++] = (uint8_t)n;
+ if (i == byterate) {
+ libkeccak_zerocopy_update(state, buf, byterate);
+ i = 0;
+ }
+
+ for (j = 0; j < n;) {
+ buf[i++] = (uint8_t)(value >> ((n - ++j) << 3));
+ if (i == byterate) {
+ libkeccak_zerocopy_update(state, buf, byterate);
+ i = 0;
+ }
+ }
+
+ return i;
+}
+
+
+/**
+ * Encode a number in big-endian with a size prefix
+ *
+ * @param state The hashing state the feed the number to
+ * @param buf Buffer that is at least `byterate` bytes large
+ * @param byterate The byterate of the hashing algorithm
+ * @param value The number to send to the hashing sponge
+ * @param off Current offset in `buf`
+ * @param bitoff The number of bits to shift the encoded message left
+ * @return New offset in `buf`
+ */
+static size_t
+encode_left_shifted(struct libkeccak_state *restrict state, uint8_t *restrict buf,
+ size_t byterate, size_t value, size_t off, size_t bitoff)
+{
+ size_t x, n, j, i = off;
+ uint16_t v;
+
+ for (x = value, n = 0; x; x >>= 8)
+ n += 1;
+ if (!n)
+ n = 1;
+ v = (uint16_t)((n & 255UL) << bitoff);
+ buf[i++] |= (uint8_t)v;
+ if (i == byterate) {
+ libkeccak_zerocopy_update(state, buf, byterate);
+ i = 0;
+ }
+ buf[i] = (uint8_t)(n >> 8);
+
+ for (j = 0; j < n;) {
+ v = (uint16_t)(((value >> ((n - ++j) << 3)) & 255UL) << bitoff);
+ buf[i++] |= (uint8_t)v;
+ if (i == byterate) {
+ libkeccak_zerocopy_update(state, buf, byterate);
+ i = 0;
+ }
+ buf[i] = (uint8_t)(v >> 8);
+ }
+
+ return i;
+}
+
+
+/**
+ * Feed text to the sponge
+ *
+ * @param state The hashing state tofeed
+ * @param buf Buffer that is at least `byterate` bytes large
+ * @param text Text to feed the sponge
+ * @param bytes The number of whole bytes in `text`
+ * @param bits The number of bits at the end of `text`
+ * that does not make up a whole byte
+ * @param suffix Bit-string (encoded with ASCII 0/1 digits)
+ * of additional bytes after `text`
+ * @param off The current byte offset in `buf`
+ * @param byterate The byterate of the hashing algorithm
+ * @param bitoffp Output parameter for the non-whole
+ * byte bit-offset (current must be 0)
+ * @return The new byte offset in `buf`
+ */
+static size_t
+feed_text(struct libkeccak_state *restrict state, uint8_t *restrict buf, const uint8_t *restrict text, size_t bytes,
+ size_t bits, const char *restrict suffix, size_t off, size_t byterate, size_t *restrict bitoffp)
+{
+ size_t n, bitoff;
+
+ if (off) {
+ n = bytes < byterate - off ? bytes : byterate - off;
+ memcpy(&buf[off], text, n);
+ off += n;
+ if (off == byterate) {
+ libkeccak_zerocopy_update(state, buf, byterate);
+ off = 0;
+ }
+ text = &text[n];
+ bytes -= n;
+ }
+ if (bytes) {
+ n = bytes;
+ n -= bytes %= byterate;
+ libkeccak_zerocopy_update(state, text, n);
+ text = &text[n];
+ }
+ memcpy(&buf[off], text, bytes + !!bits);
+ off += bytes;
+ bitoff = bits;
+ if (!bitoff)
+ buf[off] = 0;
+ for (; *suffix; suffix++) {
+ if (*suffix == '1')
+ buf[off] |= (uint8_t)(1 << bitoff);
+ if (++bitoff == 8) {
+ if (++off == byterate) {
+ libkeccak_zerocopy_update(state, buf, byterate);
+ off = 0;
+ }
+ bitoff = 0;
+ buf[off] = 0;
+ }
+ }
+
+ *bitoffp = bitoff;
+ return off;
+}
+
+
+/**
+ * Feed text to the sponge
+ *
+ * @param state The hashing state tofeed
+ * @param buf Buffer that is at least `byterate` bytes large
+ * @param text Text to feed the sponge
+ * @param bytes The number of whole bytes in `text`
+ * @param bits The number of bits at the end of `text`
+ * that does not make up a whole byte
+ * @param suffix Bit-string (encoded with ASCII 0/1 digits)
+ * of additional bytes after `text`
+ * @param off The current byte offset in `buf`
+ * @param byterate The byterate of the hashing algorithm
+ * @param bitoffp Pointer to the non-whole byte bit-offset,
+ * shall be the current (non-zero) bit-offset
+ * upon entry and will be set to the new
+ * bit-offset on return
+ * @return The new byte offset in `buf`
+ */
+static size_t
+feed_text_shifted(struct libkeccak_state *restrict state, uint8_t *restrict buf, const uint8_t *restrict text, size_t bytes,
+ size_t bits, const char *restrict suffix, size_t off, size_t byterate, size_t *restrict bitoffp)
+{
+ size_t i, bitoff = *bitoffp;
+ uint16_t v;
+
+ for (i = 0; i < bytes; i++) {
+ v = (uint16_t)((uint16_t)text[i] << bitoff);
+ buf[off] |= (uint8_t)v;
+ if (++off == byterate) {
+ libkeccak_zerocopy_update(state, buf, byterate);
+ off = 0;
+ }
+ buf[off] = (uint8_t)(v >> 8);
+ }
+ if (bits) {
+ v = (uint16_t)((uint16_t)text[bytes] << bitoff);
+ buf[off] |= (uint8_t)v;
+ bitoff += bits;
+ if (bitoff >= 8) {
+ if (++off == byterate) {
+ libkeccak_zerocopy_update(state, buf, byterate);
+ off = 0;
+ }
+ bitoff &= 7;
+ buf[off] = (uint8_t)(v >> 8);
+ }
+ }
+ if (!bitoff)
+ buf[off] = 0;
+ for (; *suffix; suffix++) {
+ if (*suffix == '1')
+ buf[off] |= (uint8_t)(1 << bitoff);
+ if (++bitoff == 8) {
+ if (++off == byterate) {
+ libkeccak_zerocopy_update(state, buf, byterate);
+ off = 0;
+ }
+ bitoff = 0;
+ buf[off] = 0;
+ }
+ }
+
+ *bitoffp = bitoff;
+ return off;
+}
+
+
+/**
+ * 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
+ */
+void
+libkeccak_cshake_initialise(struct libkeccak_state *restrict state,
+ const void *n_text, size_t n_len, size_t n_bits, const char *n_suffix,
+ const void *s_text, size_t s_len, size_t s_bits, const char *s_suffix)
+{
+ size_t off = 0, bitoff, byterate = (size_t)state->r >> 3;
+
+ if (!n_suffix)
+ n_suffix = "";
+ if (!s_suffix)
+ s_suffix = "";
+
+ if (!n_len && !s_len && !n_bits && !s_bits && !*n_suffix && !*s_suffix)
+ return;
+
+ n_len += n_bits >> 3;
+ s_len += s_bits >> 3;
+ n_bits &= 7;
+ s_bits &= 7;
+
+ off = encode_left(state, state->M, byterate, byterate, off);
+ off = encode_left(state, state->M, byterate, (n_len << 3) + n_bits + strlen(n_suffix), off);
+ off = feed_text(state, state->M, n_text, n_len, n_bits, n_suffix, off, byterate, &bitoff);
+
+ if (!bitoff) {
+ off = encode_left(state, state->M, byterate, (s_len << 3) + s_bits + strlen(s_suffix), off);
+ off = feed_text(state, state->M, s_text, s_len, s_bits, s_suffix, off, byterate, &bitoff);
+ } else {
+ off = encode_left_shifted(state, state->M, byterate, (s_len << 3) + s_bits + strlen(s_suffix), off, bitoff);
+ off = feed_text_shifted(state, state->M, s_text, s_len, s_bits, s_suffix, off, byterate, &bitoff);
+ }
+
+ if (bitoff)
+ off++;
+ if (off) {
+ memset(&state->M[off], 0, byterate - off);
+ libkeccak_zerocopy_update(state, state->M, byterate);
+ }
+}
diff --git a/libkeccak_cshake_suffix.3 b/libkeccak_cshake_suffix.3
new file mode 100644
index 0000000..b390134
--- /dev/null
+++ b/libkeccak_cshake_suffix.3
@@ -0,0 +1,45 @@
+.TH LIBKECCAK_CSHAKE_SUFFIX 3 LIBKECCAK
+.SH NAME
+libkeccak_cshake_suffix - Get message suffix for cSHAKE hashing
+.SH SYNOPSIS
+.nf
+#include <libkeccak.h>
+
+const char *libkeccak_cshake_suffix(size_t \fInlen\fP, size_t \fIslen\fP);
+.fi
+.PP
+Link with
+.IR -lkeccak .
+.SH DESCRIPTION
+The
+.BR libkeccak_cshake_suffix ()
+function returns a string of '1':s and '0':s
+representing the bits the the message suffixed
+that shall be used.
+Canonically, the values of the
+.I nlen
+and
+.I slen
+parameters shall be the length of the cSHAKE
+function-name bit-string and the cSHAKE
+customisation bit-string, however, the function
+will only check whether these values are zero
+or non-zero.
+.SH RETURN VALUES
+The
+.BR libkeccak_cshake_suffix ()
+function returns a statically allocated,
+read-only, message suffix bit-string
+that shall be used.
+.SH ERRORS
+The
+.BR libkeccak_cshake_suffix ()
+function cannot fail.
+.SH SEE ALSO
+.BR libkeccak_spec_cshake (3),
+.BR libkeccak_generalised_spec_initialise (3),
+.BR libkeccak_state_initialise (3),
+.BR libkeccak_cshake_initialise (3),
+.BR libkeccak_fast_digest (3),
+.BR libkeccak_zerocopy_digest (3),
+.BR libkeccak_digest (3)
diff --git a/libkeccak_cshake_suffix.c b/libkeccak_cshake_suffix.c
new file mode 100644
index 0000000..f4068dd
--- /dev/null
+++ b/libkeccak_cshake_suffix.c
@@ -0,0 +1,5 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+extern inline const char *libkeccak_cshake_suffix(size_t, size_t);
diff --git a/libkeccak_degeneralise_spec.3 b/libkeccak_degeneralise_spec.3
index b4819b3..e694147 100644
--- a/libkeccak_degeneralise_spec.3
+++ b/libkeccak_degeneralise_spec.3
@@ -115,6 +115,7 @@ if ((r = libkeccak_spec_check(&spec)));
.SH SEE ALSO
.BR libkeccak_generalised_spec_initialise (3),
.BR libkeccak_spec_check (3),
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_sha3 (3),
.BR libkeccak_spec_rawshake (3),
.BR libkeccak_spec_shake (3),
diff --git a/libkeccak_digest.3 b/libkeccak_digest.3
index 726c02e..90c76c5 100644
--- a/libkeccak_digest.3
+++ b/libkeccak_digest.3
@@ -58,7 +58,9 @@ or \(dq\(dq is used. For the other algorithms the constants
.B LIBKECCAK_RAWSHAKE_SUFFIX
(for RawSHAKE), and
.B LIBKECCAK_SHAKE_SUFFIX
-(for SHAKE) are used.
+(for SHAKE), or the return of the
+.BR libkeccak_cshake_suffix (3)
+function (for cSHAKE), are used.
.PP
The hash of the message will be stored to
.IR hashsum ,
@@ -130,10 +132,24 @@ libkeccak_behex_lower(hexhash, binhash, sizeof(binhash));
printf(\(dq%s\en\(dq, hexhash);
libkeccak_state_destroy(&state);
.fi
+.SH NOTES
+For cSHAKE, the
+.BR libkeccak_cshake_initialise (3),
+must be called, once, immediately after
+state initialisation; before the first
+call to any of the
+.BR libkeccak_fast_update (),
+.BR libkeccak_zerocopy_update (),
+.BR libkeccak_update (),
+and
+.BR libkeccak_digest ()
+functions.
.SH SEE ALSO
.BR libkeccak_state_initialise (3),
+.BR libkeccak_cshake_initialise (3),
.BR libkeccak_fast_update (3),
.BR libkeccak_update (3),
+.BR libkeccak_cshake_suffix (3),
.BR libkeccak_fast_digest (3),
.BR libkeccak_zerocopy_digest (3),
.BR libkeccak_simple_squeeze (3),
diff --git a/libkeccak_fast_digest.3 b/libkeccak_fast_digest.3
index 3c1d28c..c4925e4 100644
--- a/libkeccak_fast_digest.3
+++ b/libkeccak_fast_digest.3
@@ -59,7 +59,9 @@ or \(dq\(dq is used. For the other algorithms the constants
.B LIBKECCAK_RAWSHAKE_SUFFIX
(for RawSHAKE), and
.B LIBKECCAK_SHAKE_SUFFIX
-(for SHAKE) are used.
+(for SHAKE), or the return of the
+.BR libkeccak_cshake_suffix (3)
+function (for cSHAKE), are used.
.PP
The hash of the message will be stored to
.IR hashsum ,
@@ -132,11 +134,25 @@ libkeccak_behex_lower(hexhash, binhash, sizeof(binhash));
printf(\(dq%s\en\(dq, hexhash);
libkeccak_state_fast_destroy(&state);
.fi
+.SH NOTES
+For cSHAKE, the
+.BR libkeccak_cshake_initialise (3),
+must be called, once, immediately after
+state initialisation; before the first
+call to any of the
+.BR libkeccak_fast_update (),
+.BR libkeccak_zerocopy_update (),
+.BR libkeccak_update (),
+and
+.BR libkeccak_digest_digest ()
+functions.
.SH SEE ALSO
.BR libkeccak_state_initialise (3),
+.BR libkeccak_cshake_initialise (3),
.BR libkeccak_fast_update (3),
.BR libkeccak_zerocopy_update (3),
.BR libkeccak_update (3),
+.BR libkeccak_cshake_suffix (3),
.BR libkeccak_digest (3),
.BR libkeccak_zerocopy_digest (3),
.BR libkeccak_simple_squeeze (3),
diff --git a/libkeccak_fast_update.3 b/libkeccak_fast_update.3
index 6231da9..5d38b0d 100644
--- a/libkeccak_fast_update.3
+++ b/libkeccak_fast_update.3
@@ -83,8 +83,17 @@ libkeccak_behex_lower(hexhash, binhash, sizeof(binhash));
printf(\(dq%s\en\(dq, hexhash);
libkeccak_state_fast_destroy(&state);
.fi
+.SH NOTES
+For cSHAKE, the
+.BR libkeccak_cshake_initialise (3),
+must be called, once, immediately after
+state initialisation; before the first
+call to the
+.BR libkeccak_fast_update ()
+function.
.SH SEE ALSO
.BR libkeccak_state_initialise (3),
+.BR libkeccak_cshake_initialise (3),
.BR libkeccak_zerocopy_update (3),
.BR libkeccak_update (3),
.BR libkeccak_fast_digest (3),
diff --git a/libkeccak_generalised_spec_initialise.3 b/libkeccak_generalised_spec_initialise.3
index d258f77..acfa173 100644
--- a/libkeccak_generalised_spec_initialise.3
+++ b/libkeccak_generalised_spec_initialise.3
@@ -36,6 +36,7 @@ function cannot fail.
.fi
.SH SEE ALSO
.BR libkeccak_degeneralise_spec (3),
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_sha3 (3),
.BR libkeccak_spec_rawshake (3),
.BR libkeccak_spec_shake (3)
diff --git a/libkeccak_generalised_sum_fd.3 b/libkeccak_generalised_sum_fd.3
index 3ff7e8c..9f5341a 100644
--- a/libkeccak_generalised_sum_fd.3
+++ b/libkeccak_generalised_sum_fd.3
@@ -38,13 +38,23 @@ should have an allocation size of at least
+ 7) / 8) * sizeof(char)).
.PP
.I *state
-should not be initialised.
+should not be initialised unless
+.I spec
+is
+.IR NULL .
.BR libkeccak_generalised_sum_fd ()
initialises
.I *state
-itself. Therefore there would be a memory leak if
+itself unless
+.I spec
+is
+.IR NULL .
+Therefore there would be a memory leak if
.I *state
-is already initialised.
+is already initialised and
+.I spec
+is
+.RI non- NULL .
.SH RETURN VALUES
The
.BR libkeccak_generalised_sum_fd ()
@@ -118,6 +128,7 @@ libkeccak_state_destroy(&state);
.BR libkeccak_sha3sum_fd (3),
.BR libkeccak_rawshakesum_fd (3),
.BR libkeccak_shakesum_fd (3),
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_sha3 (3),
.BR libkeccak_spec_shake (3),
.BR libkeccak_spec_rawshake (3),
diff --git a/libkeccak_generalised_sum_fd.c b/libkeccak_generalised_sum_fd.c
index 92a5c4c..11431f0 100644
--- a/libkeccak_generalised_sum_fd.c
+++ b/libkeccak_generalised_sum_fd.c
@@ -8,8 +8,10 @@
* 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 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 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`
@@ -29,7 +31,7 @@ libkeccak_generalised_sum_fd(int fd, struct libkeccak_state *restrict state, con
size_t chunksize, extrasize, extrachunks;
size_t chunks, chunkmod;
- if (libkeccak_state_initialise(state, spec) < 0)
+ if (spec && libkeccak_state_initialise(state, spec) < 0)
return -1;
chunksize = libkeccak_zerocopy_chunksize(state);
diff --git a/libkeccak_hmac_initialise.3 b/libkeccak_hmac_initialise.3
index 8570a86..db3590f 100644
--- a/libkeccak_hmac_initialise.3
+++ b/libkeccak_hmac_initialise.3
@@ -42,6 +42,7 @@ and
.BR libkeccak_hmac_destroy (3),
.BR libkeccak_hmac_fast_destroy (3),
.BR libkeccak_hmac_copy (3),
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_sha3 (3),
.BR libkeccak_spec_shake (3),
.BR libkeccak_spec_rawshake (3),
diff --git a/libkeccak_spec_check.3 b/libkeccak_spec_check.3
index f7a9c64..3b5c9df 100644
--- a/libkeccak_spec_check.3
+++ b/libkeccak_spec_check.3
@@ -18,6 +18,7 @@ function validates the parameters of
so that unusable configurations can be detected.
It is recommended to call this function after calling
.BR libkeccak_spec_sha3 (3),
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_rawshake (3),
.BR libkeccak_spec_shake (3),
or, especially, after settings the parameters
@@ -83,6 +84,7 @@ function cannot fail.
.fi
.SH SEE ALSO
.BR libkeccak_spec_sha3 (3),
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_rawshake (3),
.BR libkeccak_spec_shake (3),
.BR libkeccak_generalised_spec_initialise (3),
diff --git a/libkeccak_spec_cshake.3 b/libkeccak_spec_cshake.3
new file mode 100644
index 0000000..dfd8ee9
--- /dev/null
+++ b/libkeccak_spec_cshake.3
@@ -0,0 +1,48 @@
+.TH LIBKECCAK_SPEC_CSHAKE 3 LIBKECCAK
+.SH NAME
+libkeccak_spec_cshake - Configure cSHAKE hashing parameters
+.SH SYNOPSIS
+.nf
+#include <libkeccak.h>
+
+void libkeccak_spec_cshake(struct libkeccak_spec *\fIspec\fP, long int \fIx\fP, long int \fId\fP);
+.fi
+.PP
+Link with
+.IR -lkeccak .
+.SH DESCRIPTION
+The
+.BR libkeccak_spec_cshake ()
+function sets
+.I *spec
+to specify the Keccak parameters used for cSHAKE hashing
+with the semicapacity specified, in bits, via the
+.I x
+parameter, and the output size specified, in bits, via the
+.I d
+parameter.
+.SH RETURN VALUES
+The
+.BR libkeccak_spec_cshake ()
+function does not return any value.
+.SH ERRORS
+The
+.BR libkeccak_spec_cshake ()
+function cannot fail.
+.SH EXAMPLE
+This example configure a
+.B struct libkeccak_spec
+to specify the Keccak parameters used for cSHAKE256(, 512):
+.PP
+.nf
+struct libkeccak_spec spec;
+libkeccak_spec_cshake(&spec, 256, 512);
+.fi
+.SH SEE ALSO
+.BR libkeccak_spec_sha3 (3),
+.BR libkeccak_spec_shake (3),
+.BR libkeccak_spec_rawshake (3),
+.BR libkeccak_spec_check (3),
+.BR libkeccak_generalised_spec_initialise (3),
+.BR libkeccak_state_initialise (3),
+.BR libkeccak_hmac_initialise (3)
diff --git a/libkeccak_spec_rawshake.3 b/libkeccak_spec_rawshake.3
index 3e70b3a..5d810b2 100644
--- a/libkeccak_spec_rawshake.3
+++ b/libkeccak_spec_rawshake.3
@@ -39,6 +39,7 @@ struct libkeccak_spec spec;
libkeccak_spec_rawshake(&spec, 256, 512);
.fi
.SH SEE ALSO
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_sha3 (3),
.BR libkeccak_spec_shake (3),
.BR libkeccak_spec_check (3),
diff --git a/libkeccak_spec_sha3.3 b/libkeccak_spec_sha3.3
index 701a18a..9cafbf6 100644
--- a/libkeccak_spec_sha3.3
+++ b/libkeccak_spec_sha3.3
@@ -38,6 +38,7 @@ struct libkeccak_spec spec;
libkeccak_spec_sha3(&spec, 256);
.fi
.SH SEE ALSO
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_rawshake (3),
.BR libkeccak_spec_shake (3),
.BR libkeccak_spec_check (3),
diff --git a/libkeccak_spec_shake.3 b/libkeccak_spec_shake.3
index 1b97540..c98962f 100644
--- a/libkeccak_spec_shake.3
+++ b/libkeccak_spec_shake.3
@@ -39,6 +39,7 @@ struct libkeccak_spec spec;
libkeccak_spec_shake(&spec, 256, 512);
.fi
.SH SEE ALSO
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_sha3 (3),
.BR libkeccak_spec_rawshake (3),
.BR libkeccak_spec_check (3),
diff --git a/libkeccak_state_initialise.3 b/libkeccak_state_initialise.3
index a2ccffd..3c63af7 100644
--- a/libkeccak_state_initialise.3
+++ b/libkeccak_state_initialise.3
@@ -47,6 +47,7 @@ function may fail for any specified for the function
.BR libkeccak_sha3sum_fd (3),
.BR libkeccak_rawshakesum_fd (3),
.BR libkeccak_shakesum_fd (3),
+.BR libkeccak_spec_cshake (3),
.BR libkeccak_spec_sha3 (3),
.BR libkeccak_spec_shake (3),
.BR libkeccak_spec_rawshake (3),
diff --git a/libkeccak_update.3 b/libkeccak_update.3
index 3d295c8..384e492 100644
--- a/libkeccak_update.3
+++ b/libkeccak_update.3
@@ -82,8 +82,17 @@ libkeccak_behex_lower(hexhash, binhash, sizeof(binhash));
printf(\(dq%s\en\(dq, hexhash);
libkeccak_state_destroy(&state);
.fi
+.SH NOTES
+For cSHAKE, the
+.BR libkeccak_cshake_initialise (3),
+must be called, once, immediately after
+state initialisation; before the first
+call to the
+.BR libkeccak_update ()
+function.
.SH SEE ALSO
.BR libkeccak_state_initialise (3),
+.BR libkeccak_cshake_initialise (3),
.BR libkeccak_fast_update (3),
.BR libkeccak_zerocopy_update (3),
.BR libkeccak_fast_digest (3),
diff --git a/libkeccak_zerocopy_digest.3 b/libkeccak_zerocopy_digest.3
index 2d63df3..6b752fb 100644
--- a/libkeccak_zerocopy_digest.3
+++ b/libkeccak_zerocopy_digest.3
@@ -57,7 +57,9 @@ or \(dq\(dq is used. For the other algorithms the constants
.B LIBKECCAK_RAWSHAKE_SUFFIX
(for RawSHAKE), and
.B LIBKECCAK_SHAKE_SUFFIX
-(for SHAKE) are used.
+(for SHAKE), or the return of the
+.BR libkeccak_cshake_suffix (3)
+function (for cSHAKE), are used.
.PP
The hash of the message will be stored to
.IR hashsum ,
@@ -107,12 +109,26 @@ or
functions, with the same
.I state
argument, may cause the message to be misread.
+.SH NOTES
+For cSHAKE, the
+.BR libkeccak_cshake_initialise (3),
+must be called, once, immediately after
+state initialisation; before the first
+call to any of the
+.BR libkeccak_fast_update (),
+.BR libkeccak_zerocopy_update (),
+.BR libkeccak_update (),
+and
+.BR libkeccak_zerocopy_digest ()
+functions.
.SH SEE ALSO
.BR libkeccak_state_initialise (3),
+.BR libkeccak_cshake_initialise (3),
.BR libkeccak_zerocopy_chunksize (3),
.BR libkeccak_fast_update (3),
.BR libkeccak_zerocopy_update (3),
.BR libkeccak_update (3),
+.BR libkeccak_cshake_suffix (3),
.BR libkeccak_digest (3),
.BR libkeccak_zerocopy_digest (3),
.BR libkeccak_simple_squeeze (3),
diff --git a/libkeccak_zerocopy_update.3 b/libkeccak_zerocopy_update.3
index 4c3f006..b4086a0 100644
--- a/libkeccak_zerocopy_update.3
+++ b/libkeccak_zerocopy_update.3
@@ -70,8 +70,17 @@ or
.BR libkeccak_fast_update (3)
functions may cause the message
to be misread.
+.SH NOTES
+For cSHAKE, the
+.BR libkeccak_cshake_initialise (3),
+must be called, once, immediately after
+state initialisation; before the first
+call to the
+.BR libkeccak_zerocopy_update ()
+function.
.SH SEE ALSO
.BR libkeccak_state_initialise (3),
+.BR libkeccak_cshake_initialise (3),
.BR libkeccak_zerocopy_chunksize (3),
.BR libkeccak_fast_update (3),
.BR libkeccak_update (3),
diff --git a/test.c b/test.c
index e7d19a2..a564395 100644
--- a/test.c
+++ b/test.c
@@ -146,26 +146,24 @@ test_state(struct libkeccak_spec *restrict spec)
/**
* Run a test case for `libkeccak_digest`
*
+ * @param state Already initialised state
* @param spec The specification for the hashing
* @param suffix The message suffix (padding prefix)
* @param msg The message to digest
- * @param bits Bits at the end of `message` that does not make up a whole byte
+ * @param bytes Number of while bytes in `msg`
+ * @param bits Bits at the end of `msg` that does not make up a whole byte
* @param expected_answer The expected answer, must be lowercase
* @return Zero on success, -1 on error
*/
static int
-test_digest_case(const struct libkeccak_spec *restrict spec, const char *restrict suffix,
- const char *restrict msg, long int bits, const char *restrict expected_answer)
+test_digest_case_inited(struct libkeccak_state *restrict state, const struct libkeccak_spec *restrict spec,
+ const char *restrict suffix, const char *restrict msg, size_t bytes, size_t bits,
+ const char *restrict expected_answer)
{
- struct libkeccak_state state;
unsigned char *restrict hashsum;
char *restrict hexsum;
int ok;
- if (libkeccak_state_initialise(&state, spec)) {
- perror("libkeccak_state_initialise");
- return -1;
- }
hashsum = malloc((size_t)((spec->output + 7) / 8));
if (!hashsum) {
perror("malloc");
@@ -177,11 +175,10 @@ test_digest_case(const struct libkeccak_spec *restrict spec, const char *restric
return -1;
}
- if (libkeccak_digest(&state, msg, strlen(msg) - !!bits, (size_t)bits, suffix, hashsum)) {
+ if (libkeccak_digest(state, msg, bytes, bits, suffix, hashsum)) {
perror("libkeccak_digest");
return -1;
}
- libkeccak_state_fast_destroy(&state);
libkeccak_behex_lower(hexsum, hashsum, (size_t)((spec->output + 7) / 8));
ok = !strcmp(hexsum, expected_answer);
@@ -197,6 +194,77 @@ test_digest_case(const struct libkeccak_spec *restrict spec, const char *restric
/**
+ * Run a test case for `libkeccak_digest`
+ *
+ * @param spec The specification for the hashing
+ * @param suffix The message suffix (padding prefix)
+ * @param msg The message to digest
+ * @param bytes Number of while bytes in `msg`
+ * @param bits Bits at the end of `msg` that does not make up a whole byte
+ * @param expected_answer The expected answer, must be lowercase
+ * @return Zero on success, -1 on error
+ */
+static int
+test_digest_case(const struct libkeccak_spec *restrict spec, const char *restrict suffix,
+ const char *restrict msg, size_t bytes, size_t bits, const char *restrict expected_answer)
+{
+ struct libkeccak_state state;
+ int ret;
+ if (libkeccak_state_initialise(&state, spec)) {
+ perror("libkeccak_state_initialise");
+ return -1;
+ }
+ ret = test_digest_case_inited(&state, spec, suffix, msg, bytes, bits, expected_answer);
+ libkeccak_state_fast_destroy(&state);
+ return ret;
+}
+
+
+/**
+ * Run a test case for `libkeccak_digest` with cSHAKE
+ *
+ * @param spec The specification for the hashing
+ * @param suffix The message suffix (padding prefix)
+ * @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
+ * @param msg The message to digest
+ * @param bytes Number of while bytes in `msg`
+ * @param bits Bits at the end of `msg` that does not make up a whole byte
+ * @param expected_answer The expected answer, must be lowercase
+ * @return Zero on success, -1 on error
+ */
+static int
+test_digest_case_cshake(const struct libkeccak_spec *restrict spec, const char *restrict suffix,
+ const void *n_text, size_t n_len, size_t n_bits, const char *n_suffix,
+ const void *s_text, size_t s_len, size_t s_bits, const char *s_suffix,
+ const char *restrict msg, size_t bytes, size_t bits, const char *restrict expected_answer)
+{
+ struct libkeccak_state state;
+ int ret;
+ if (libkeccak_state_initialise(&state, spec)) {
+ perror("libkeccak_state_initialise");
+ return -1;
+ }
+ libkeccak_cshake_initialise(&state, n_text, n_len, n_bits, n_suffix, s_text, s_len, s_bits, s_suffix);
+ ret = test_digest_case_inited(&state, spec, suffix, msg, bytes, bits, expected_answer);
+ libkeccak_state_fast_destroy(&state);
+ return ret;
+}
+
+
+/**
* Run test cases for `libkeccak_digest`
*
* @return Zero on success, -1 on error
@@ -207,37 +275,37 @@ test_digest(void)
#define sha3(output, message)\
(printf(" Testing SHA3-"#output"(%s): ", #message),\
libkeccak_spec_sha3(&spec, output),\
- test_digest_case(&spec, LIBKECCAK_SHA3_SUFFIX, message, 0, answer))
+ test_digest_case(&spec, LIBKECCAK_SHA3_SUFFIX, message, strlen(message), 0, answer))
#define keccak(output, message)\
(printf(" Testing Keccak-"#output"(%s): ", #message),\
libkeccak_spec_sha3(&spec, output) /* sic! */,\
- test_digest_case(&spec, "", message, 0, answer))
+ test_digest_case(&spec, "", message, strlen(message), 0, answer))
-#define keccak_bits(output, message, bits)\
- (printf(" Testing Keccak-"#output"(%s-%i): ", #message, bits),\
+#define keccak_bits(output, message, msg_bits)\
+ (printf(" Testing Keccak-"#output"(%s:%i): ", #message, msg_bits),\
libkeccak_spec_sha3(&spec, output) /* sic! */,\
- test_digest_case(&spec, "", message, bits, answer))
+ test_digest_case(&spec, "", message, msg_bits / 8, msg_bits % 8, answer))
#define rawshake(semicapacity, output, message)\
(printf(" Testing RawSHAKE-"#semicapacity"(%s, %i): ", #message, output),\
libkeccak_spec_rawshake(&spec, semicapacity, output),\
- test_digest_case(&spec, LIBKECCAK_RAWSHAKE_SUFFIX, message, 0, answer))
+ test_digest_case(&spec, LIBKECCAK_RAWSHAKE_SUFFIX, message, strlen(message), 0, answer))
#define rawshake_bits(semicapacity, output, message, bits)\
(printf(" Testing RawSHAKE-"#semicapacity"(%s-%i, %i): ", #message, bits, output),\
libkeccak_spec_rawshake(&spec, semicapacity, output),\
- test_digest_case(&spec, LIBKECCAK_RAWSHAKE_SUFFIX, message, bits, answer))
+ test_digest_case(&spec, LIBKECCAK_RAWSHAKE_SUFFIX, message, strlen(message) - !!bits, bits, answer))
#define shake(semicapacity, output, message)\
(printf(" Testing SHAKE-"#semicapacity"(%s, %i): ", #message, output),\
libkeccak_spec_shake(&spec, semicapacity, output),\
- test_digest_case(&spec, LIBKECCAK_SHAKE_SUFFIX, message, 0, answer))
+ test_digest_case(&spec, LIBKECCAK_SHAKE_SUFFIX, message, strlen(message), 0, answer))
#define keccak_g(b, c, o, message)\
(printf(" Testing Keccak[%i,%i,%i](%s): ", b, c, o, #message),\
spec.bitrate = b, spec.capacity = c, spec.output = o,\
- test_digest_case(&spec, "", message, 0, answer))
+ test_digest_case(&spec, "", message, strlen(message), 0, answer))
struct libkeccak_spec spec;
@@ -456,25 +524,44 @@ test_digest(void)
static int
test_digest_bits(void)
{
-#define MSG0 "", 0
-#define MSG5 "\x13" /* 1 1001 */, 5
-#define MSG30 "\x53\x58\x7B\x19" /* 1100 1010 0001 1010 1101 1110 10 0110 */, 30
+#define MSG0 ""
+#define MSG5 "\x13" /* 1 1001 */
+#define MSG30 "\x53\x58\x7B\x19" /* 1100 1010 0001 1010 1101 1110 10 0110 */
#define MSG1600_32 "\xA3\xA3\xA3\xA3" /* (1100 0101)x4 */
#define MSG1600_160 MSG1600_32 MSG1600_32 MSG1600_32 MSG1600_32 MSG1600_32
#define MSG1600_800 MSG1600_160 MSG1600_160 MSG1600_160 MSG1600_160 MSG1600_160
-#define MSG1600 MSG1600_800 MSG1600_800, 1600
-#define MSG1605 MSG1600_800 MSG1600_800 "\x03", 1605
-#define MSG1630 MSG1600_800 MSG1600_800 "\xA3\xA3\xA3\x23", 1630
-
-#define sha3(output, message)\
- (printf(" Testing SHA3-"#output"(%s): ", #message),\
+#define MSG1600 MSG1600_800 MSG1600_800
+#define MSG1605 MSG1600_800 MSG1600_800 "\x03"
+#define MSG1630 MSG1600_800 MSG1600_800 "\xA3\xA3\xA3\x23"
+#define SEQ1600 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"\
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"\
+ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F"\
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F"\
+ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F"\
+ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F"\
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F"\
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F"\
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"\
+ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"\
+ "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"\
+ "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF"\
+ "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7"
+
+#define sha3(output, message, msg_bits)\
+ (printf(" Testing SHA3-"#output"(%s:%i): ", #message, msg_bits),\
libkeccak_spec_sha3(&spec, output),\
- test_digest_case(&spec, LIBKECCAK_SHA3_SUFFIX, message & 7, answer))
+ test_digest_case(&spec, LIBKECCAK_SHA3_SUFFIX, message, msg_bits / 8, msg_bits % 8, answer))
-#define shake(semicapacity, message)\
- (printf(" Testing SHAKE-"#semicapacity"(%s): ", #message),\
- libkeccak_spec_shake(&spec, semicapacity, strlen(answer) * 4),\
- test_digest_case(&spec, LIBKECCAK_SHAKE_SUFFIX, message & 7, answer))
+#define shake(semicapacity, message, msg_bits)\
+ (printf(" Testing SHAKE-"#semicapacity"(%s:%i): ", #message, msg_bits),\
+ libkeccak_spec_shake(&spec, semicapacity, (long int)strlen(answer) * 4),\
+ test_digest_case(&spec, LIBKECCAK_SHAKE_SUFFIX, message, msg_bits / 8, msg_bits % 8, answer))
+
+#define cshake(semicapacity, n, s, message, msg_bits) \
+ (printf(" Testing cSHAKE-"#semicapacity"(%s, %s, %s:%i): ", #n, #s, #message, msg_bits),\
+ libkeccak_spec_cshake(&spec, semicapacity, (long int)strlen(answer) * 4),\
+ test_digest_case_cshake(&spec, libkeccak_cshake_suffix(strlen(n), strlen(s)), n, strlen(n), 0, NULL,\
+ s, strlen(s), 0, NULL, message, msg_bits / 8, msg_bits % 8, answer))
struct libkeccak_spec spec;
@@ -494,7 +581,7 @@ test_digest_bits(void)
"d83c6d5e8ce803aa62b8d654db53d09b8dcff273cdfeb573fad8bcd45578bec2e770d01efde86e721a3f7c6cce275dab"
"e6e2143f1af18da7efddc4c7b70b5e345db93cc936bea323491ccb38a388f546a9ff00dd4e1300b9b2153d2041d205b4"
"43e41b45a653f2a5c4492c1add544512dda2529833462b71a41a45be97290b6f";
- if (shake(128, MSG0))
+ if (shake(128, MSG0, 0))
return -1;
answer = "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6"
@@ -508,25 +595,25 @@ test_digest_bits(void)
"143045d791cc85eff5b21932f23861bcf23a52b5da67eaf7baae0f5fb1369db78f3ac45f8c4ac5671d85735cdddb09d2"
"b1e34a1fc066ff4a162cb263d6541274ae2fcc865f618abe27c124cd8b074ccd516301b91875824d09958f341ef274bd"
"ab0bae316339894304e35877b0c28a9b1fd166c796b9cc258a064a8f57e27f2a";
- if (shake(256, MSG0))
+ if (shake(256, MSG0, 0))
return -1;
answer = "ffbad5da96bad71789330206dc6768ecaeb1b32dca6b3301489674ab";
- if (sha3(224, MSG5))
+ if (sha3(224, MSG5, 5))
return -1;
answer = "7b0047cf5a456882363cbf0fb05322cf65f4b7059a46365e830132e3b5d957af";
- if (sha3(256, MSG5))
+ if (sha3(256, MSG5, 5))
return -1;
answer = "737c9b491885e9bf7428e792741a7bf8dca9653471c3e148473f2c236b6a0a6455eb1dce9f779b4b6b237fef171b1c64";
- if (sha3(384, MSG5))
+ if (sha3(384, MSG5, 5))
return -1;
answer = "a13e01494114c09800622a70288c432121ce70039d753cadd2e006e4d961cb27"
"544c1481e5814bdceb53be6733d5e099795e5e81918addb058e22a9f24883f37";
- if (sha3(512, MSG5))
+ if (sha3(512, MSG5, 5))
return -1;
answer = "2e0abfba83e6720bfbc225ff6b7ab9ffce58ba027ee3d898764fef287ddeccca3e6e5998411e7ddb32f67538f500b18c"
@@ -540,7 +627,7 @@ test_digest_bits(void)
"191e6dbbb5aa5a2afda51fc05a3af5258b87665243550f28948ae2b8beb6bc9c770b35f067eaa641efe65b1a44909d1b"
"149f97eea601391c609ec81d1930f57c18a4e0fab491d1cadfd50483449edc0f07ffb24d2c6f9a9a3bff39ae3d57f560"
"654d7d75c908abe62564753eac39d7503da6d37c2e32e1af3b8aec8ae3069cd9";
- if (shake(128, MSG5))
+ if (shake(128, MSG5, 5))
return -1;
answer = "48a5c11abaeeff092f3646ef0d6b3d3ff76c2f55f9c732ac6470c03764008212e21b1467778b181989f88858211b45df"
@@ -554,25 +641,25 @@ test_digest_bits(void)
"4618a23e10f9c229397440542d0ab1b2e10dacc5c95e597f2c7ea38438105f97803dbb03fcc0fd416b0905a41d184deb"
"238905775891f93501fb4176a3bd6c464461d36ee8b008aabd9e26a34055e80c8c813eeba07f728ab32b15605ad161a0"
"669f6fce5c5509fbb6afd24aeacc5fa4a51523e6b173246ed4bfa521d74fc6bb";
- if (shake(256, MSG5))
+ if (shake(256, MSG5, 5))
return -1;
answer = "d666a514cc9dba25ac1ba69ed3930460deaac9851b5f0baab007df3b";
- if (sha3(224, MSG30))
+ if (sha3(224, MSG30, 30))
return -1;
answer = "c8242fef409e5ae9d1f1c857ae4dc624b92b19809f62aa8c07411c54a078b1d0";
- if (sha3(256, MSG30))
+ if (sha3(256, MSG30, 30))
return -1;
answer = "955b4dd1be03261bd76f807a7efd432435c417362811b8a50c564e7ee9585e1ac7626dde2fdc030f876196ea267f08c3";
- if (sha3(384, MSG30))
+ if (sha3(384, MSG30, 30))
return -1;
answer = "9834c05a11e1c5d3da9c740e1c106d9e590a0e530b6f6aaa7830525d075ca5db"
"1bd8a6aa981a28613ac334934a01823cd45f45e49b6d7e6917f2f16778067bab";
- if (sha3(512, MSG30))
+ if (sha3(512, MSG30, 30))
return -1;
answer = "6d5d39c55f3cca567feaf422dc64ba17401d07756d78b0fa3d546d66afc27671e0010685fc69a7ec3c5367b8fa5fda39"
@@ -586,7 +673,7 @@ test_digest_bits(void)
"65cb7dba46a3340df8c3fa89c7c4db539d38dc406f1d2cf54e5905580b4404bfd7b3719561c5a59d5dfdb1bf93df1382"
"5225edcce0fa7d87efcd239feb49fc9e2de9d828feeb1f2cf579b95dd050ab2ca47105a8d30f3fd2a1154c15f87fb37b"
"2c7156bd7f3cf2b745c912a40bc1b559b656e3e903cc5733e86ba15dfef70678";
- if (shake(128, MSG30))
+ if (shake(128, MSG30, 30))
return -1;
answer = "465d081dff875e396200e4481a3e9dcd88d079aa6d66226cb6ba454107cb81a7841ab02960de279ccbe34b42c36585ad"
@@ -600,25 +687,25 @@ test_digest_bits(void)
"5546193a9b923f0590385dc4bff7c49d4915b5a365db4c84ddcb185de8f9eeb334965a42f1381c8badc22ba1f8ee4c0e"
"4daaf7a88e7f42ddb8148f3bf8d3b8d74f098155a37cb4cb27876b85da602e5c789c10e03be73407bab8c49213f8c74e"
"1266ce9b11286e674ca9c10c9c9955049a66e9051d9a2b1fc9afe26798e9cec6";
- if (shake(256, MSG30))
+ if (shake(256, MSG30, 30))
return -1;
answer = "9376816aba503f72f96ce7eb65ac095deee3be4bf9bbc2a1cb7e11e0";
- if (sha3(224, MSG1600))
+ if (sha3(224, MSG1600, 1600))
return -1;
answer = "79f38adec5c20307a98ef76e8324afbfd46cfd81b22e3973c65fa1bd9de31787";
- if (sha3(256, MSG1600))
+ if (sha3(256, MSG1600, 1600))
return -1;
answer = "1881de2ca7e41ef95dc4732b8f5f002b189cc1e42b74168ed1732649ce1dbcdd76197a31fd55ee989f2d7050dd473e8f";
- if (sha3(384, MSG1600))
+ if (sha3(384, MSG1600, 1600))
return -1;
answer = "e76dfad22084a8b1467fcf2ffa58361bec7628edf5f3fdc0e4805dc48caeeca8"
"1b7c13c30adf52a3659584739a2df46be589c51ca1a4a8416df6545a1ce8ba00";
- if (sha3(512, MSG1600))
+ if (sha3(512, MSG1600, 1600))
return -1;
answer = "131ab8d2b594946b9c81333f9bb6e0ce75c3b93104fa3469d3917457385da037cf232ef7164a6d1eb448c8908186ad85"
@@ -632,7 +719,7 @@ test_digest_bits(void)
"188d855f1b70d71ff3e50c537ac1b0f8974f0fe1a6ad295ba42f6aec74d123a7abedde6e2c0711cab36be5acb1a5a11a"
"4b1db08ba6982efccd716929a7741cfc63aa4435e0b69a9063e880795c3dc5ef3272e11c497a91acf699fefee206227a"
"44c9fb359fd56ac0a9a75a743cff6862f17d7259ab075216c0699511643b6439";
- if (shake(128, MSG1600))
+ if (shake(128, MSG1600, 1600))
return -1;
answer = "cd8a920ed141aa0407a22d59288652e9d9f1a7ee0c1e7c1ca699424da84a904d2d700caae7396ece96604440577da4f3"
@@ -646,25 +733,25 @@ test_digest_bits(void)
"149f7b62675e7d1a4d6dec48c1c7164586eae06a51208c0b791244d307726505c3ad4b26b6822377257aa152037560a7"
"39714a3ca79bd605547c9b78dd1f596f2d4f1791bc689a0e9b799a37339c04275733740143ef5d2b58b96a363d4e0807"
"6a1a9d7846436e4dca5728b6f760eef0ca92bf0be5615e96959d767197a0beeb";
- if (shake(256, MSG1600))
+ if (shake(256, MSG1600, 1600))
return -1;
answer = "22d2f7bb0b173fd8c19686f9173166e3ee62738047d7eadd69efb228";
- if (sha3(224, MSG1605))
+ if (sha3(224, MSG1605, 1605))
return -1;
answer = "81ee769bed0950862b1ddded2e84aaa6ab7bfdd3ceaa471be31163d40336363c";
- if (sha3(256, MSG1605))
+ if (sha3(256, MSG1605, 1605))
return -1;
answer = "a31fdbd8d576551c21fb1191b54bda65b6c5fe97f0f4a69103424b43f7fdb835979fdbeae8b3fe16cb82e587381eb624";
- if (sha3(384, MSG1605))
+ if (sha3(384, MSG1605, 1605))
return -1;
answer = "fc4a167ccb31a937d698fde82b04348c9539b28f0c9d3b4505709c03812350e4"
"990e9622974f6e575c47861c0d2e638ccfc2023c365bb60a93f528550698786b";
- if (sha3(512, MSG1605))
+ if (sha3(512, MSG1605, 1605))
return -1;
answer = "4ac38ebd1678b4a452792c5673f9777d36b55451aaae2424924942d318a2f6f51bbc837dcc7022c5403b69d29ac99a74"
@@ -678,7 +765,7 @@ test_digest_bits(void)
"161356a5941c799907ef9d3b1a441f09515f2831c4fafde3dc7c1e9b5aa57d3e83cd6734da3d8b9ef3fc448805ea29c9"
"9cba6b352bcabe2fd970ae9580d2bf25152b960e6b806d87d7d0608b247f61089e298692c27f19c52d03ebe395a36806"
"ad540bec2d046c18e355faf8313d2ef8995ee6aae42568f314933e3a21e5be40";
- if (shake(128, MSG1605))
+ if (shake(128, MSG1605, 1605))
return -1;
answer = "98d093b067475760124ffb9204a5b327c6bb05c54ff234f0b43fac7240415166a8c705ea0d739f0808b06576d996662c"
@@ -692,25 +779,25 @@ test_digest_bits(void)
"874e8722d03d3f5ff6ef3bebe7642fe4916c5f10ff3fd61387d5d91bcd32f9e8e4593dcaad23eccc05d2fc9be2c1cd63"
"0ea123dca9cb6938d60cddedc11e1e9bc9d268a5456ba9ccff18597c5ff9735708413b9d84b9f4721937cc6595712797"
"532b48d6f1a2d1723b07d5460bc13916d96e88180713ac33d2c232e35e764e04";
- if (shake(256, MSG1605))
+ if (shake(256, MSG1605, 1605))
return -1;
answer = "4e907bb1057861f200a599e9d4f85b02d88453bf5b8ace9ac589134c";
- if (sha3(224, MSG1630))
+ if (sha3(224, MSG1630, 1630))
return -1;
answer = "52860aa301214c610d922a6b6cab981ccd06012e54ef689d744021e738b9ed20";
- if (sha3(256, MSG1630))
+ if (sha3(256, MSG1630, 1630))
return -1;
answer = "3485d3b280bd384cf4a777844e94678173055d1cbc40c7c2c3833d9ef12345172d6fcd31923bb8795ac81847d3d8855c";
- if (sha3(384, MSG1630))
+ if (sha3(384, MSG1630, 1630))
return -1;
answer = "cf9a30ac1f1f6ac0916f9fef1919c595debe2ee80c85421210fdf05f1c6af73a"
"a9cac881d0f91db6d034a2bbadc1cf7fbcb2ecfa9d191d3a5016fb3fad8709c9";
- if (sha3(512, MSG1630))
+ if (sha3(512, MSG1630, 1630))
return -1;
answer = "89846dc776ac0f014572ea79f560773451002938248e6882569ac32aeab191fcacde68eb07557539c4845fb444108e6e"
@@ -724,7 +811,9 @@ test_digest_bits(void)
"700cd2bc3e6aab437d93d8a30f1cf692efef43602028e0ce5742eb3f4f4d5b029158dd6896acb5e3a7f684d9aa8914e7"
"0974b223a6fec38d76c7473e86e4b9b32c621e2015c55e947dd016c675c82368ce26fb456a5b65881af513bfdc88687c"
"6381676abbd2d9104ed23a9e89310246b026cedd57595b1ab6fe88a784be0c06";
- if (shake(128, MSG1630))
+ if (shake(128, MSG1630, 1630))
+ return -1;
+ if (cshake(128, "", "", MSG1630, 1630))
return -1;
answer = "8a8325079b0fc3265d52f59855cafe655df438aa639f6fec991f2494330ce32fa37f7db90f6966d8e4a46e50c5ede57b"
@@ -738,15 +827,37 @@ test_digest_bits(void)
"de45e71830a40eb0d075afccfcd9dc548d0d529460ea7ac2adac722e7678ef597dd3b495bd7d1a8ff39448bbab1dc6a8"
"8481801cf5a8010e873c31e479a5e3db3d4e67d1d948e67cc66fd75a4a19c120662ef55977bddbac0721c80d69902693"
"c83d5ef7bc27efa393af4c439fc39958e0e75537358802ef0853b7470b0f19ac";
- if (shake(256, MSG1630))
+ if (shake(256, MSG1630, 1630))
+ return -1;
+ if (cshake(256, "", "", MSG1630, 1630))
+ return -1;
+
+
+ answer = "c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5";
+ if (cshake(128, "", "Email Signature", "\x00\x01\x02\x03", 32))
+ return -1;
+
+ answer = "c5221d50e4f822d96a2e8881a961420f294b7b24fe3d2094baed2c6524cc166b";
+ if(cshake(128, "", "Email Signature", SEQ1600, 1600))
+ return -1;
+
+ answer = "d008828e2b80ac9d2218ffee1d070c48b8e4c87bff32c9699d5b6896eee0edd1"
+ "64020e2be0560858d9c00c037e34a96937c561a74c412bb4c746469527281c8c";
+ if (cshake(256, "", "Email Signature", "\x00\x01\x02\x03", 32))
+ return -1;
+
+ answer = "07dc27b11e51fbac75bc7b3c1d983e8b4b85fb1defaf218912ac864302730917"
+ "27f42b17ed1df63e8ec118f04b23633c1dfb1574c8fb55cb45da8e25afb092bb";
+ if(cshake(256, "", "Email Signature", SEQ1600, 1600))
return -1;
printf("\n");
return 0;
-#undef shake
#undef sha3
+#undef shake
+#undef cshake
#undef MSG0
#undef MSG5
#undef MSG30
@@ -756,6 +867,7 @@ test_digest_bits(void)
#undef MSG1600
#undef MSG1605
#undef MSG1630
+#undef SEQ1600
}
@@ -771,7 +883,7 @@ test_digest_trunc(void)
#define shake(semicapacity, output, output_lastbyte)\
(printf(" Testing SHAKE-"#semicapacity"('', %i): ", output),\
libkeccak_spec_shake(&spec, semicapacity, output),\
- test_digest_case(&spec, LIBKECCAK_SHAKE_SUFFIX, "", 0, INCOMPLETE_ANSWER output_lastbyte))
+ test_digest_case(&spec, LIBKECCAK_SHAKE_SUFFIX, "", 0, 0, INCOMPLETE_ANSWER output_lastbyte))
#define INCOMPLETE_ANSWER\
"7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef263cb1eea988004b93103cfb0aeefd2a68"\
"6e01fa4a58e8a3639ca8a1e3f9ae57e235b8cc873c23dc62b8d260169afa2f75ab916a58d974918835d25e6a435085b2"\