+/*
+ * sha3-test.c: test harness for SHA3 and related functions
+ *
+ * (The implementations originally came with different test arrangements,
+ * with complicated external dependencies. This file replicates the original
+ * tests, but without the dependencies.)
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2019 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+
+#include "secnet.h"
+
+#include "keccak1600.h"
+#include "sha3.h"
+#include "crypto-test.h"
+
+enum {
+ RH, NROUT,
+ RM = NROUT, RN, RFUNC, RPERSO, NREG
+};
+
+struct test_context {
+ size_t step;
+ size_t outsz;
+};
+
+static void run_sha3_kat(struct test_state *state, const struct test *test)
+{
+ static const unsigned steps[] = { 1, 7, 192, -1 };
+ unsigned i = 0;
+ struct test_context ctx;
+
+ ctx.outsz = state->in[RH].v.bytes.sz;
+ do {
+ ctx.step = steps[i];
+ test->fn(state->out, state->in, &ctx);
+ check_test_output(state, test);
+ } while (steps[i++] != (unsigned)-1);
+}
+
+#define SHA3_VARIANTS(_) _(224) _(256) _(384) _(512)
+
+#define SHA3_TESTFUNCS(w) \
+ \
+static void test_sha3_##w##_kat(struct reg *out, \
+ const struct reg *in, void *vctx) \
+{ \
+ struct test_context *ctx = vctx; \
+ sha3_ctx hctx; \
+ const octet *p = in[RM].v.bytes.p; \
+ size_t sz = in[RM].v.bytes.sz, n; \
+ \
+ allocate_bytes(&out[RH].v, SHA3_##w##_HASHSZ); \
+ sha3_##w##_init(&hctx); \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ sha3_hash(&hctx, p, n); p += n; sz -= n; \
+ } \
+ sha3_done(&hctx, out[RH].v.bytes.p); \
+} \
+ \
+static void test_sha3_##w##_mct(struct reg *out, \
+ const struct reg *in, void *vctx) \
+{ \
+ sha3_ctx hctx; \
+ octet *p; \
+ unsigned i, n = in[RN].v.u; \
+ \
+ allocate_bytes(&out[RH].v, SHA3_##w##_HASHSZ); \
+ p = out[RH].v.bytes.p; \
+ memcpy(p, in[RM].v.bytes.p, SHA3_##w##_HASHSZ); \
+ for (i = 0; i < n; i++) { \
+ sha3_##w##_init(&hctx); \
+ sha3_hash(&hctx, p, SHA3_##w##_HASHSZ); \
+ sha3_done(&hctx, p); \
+ } \
+}
+
+SHA3_VARIANTS(SHA3_TESTFUNCS)
+
+#define SHAKE_VARIANTS(_) _(128) _(256)
+
+#define SHAKE_TESTFUNCS(w) \
+ \
+static void test_shake##w##_kat(struct reg *out, \
+ const struct reg *in, void *vctx) \
+{ \
+ struct test_context *ctx = vctx; \
+ shake_ctx hctx; \
+ const octet *p = in[RM].v.bytes.p; octet *q; \
+ size_t sz = in[RM].v.bytes.sz, n; \
+ \
+ allocate_bytes(&out[RH].v, ctx->outsz); \
+ shake##w##_init(&hctx); \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ shake_hash(&hctx, p, n); p += n; sz -= n; \
+ } \
+ shake_xof(&hctx); \
+ q = out[RH].v.bytes.p; sz = ctx->outsz; \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ shake_get(&hctx, q, n); q += n; sz -= n; \
+ } \
+} \
+ \
+static void test_cshake##w##_kat(struct reg *out, \
+ const struct reg *in, void *vctx) \
+{ \
+ struct test_context *ctx = vctx; \
+ shake_ctx hctx; \
+ const octet *p = in[RM].v.bytes.p; octet *q; \
+ size_t sz = in[RM].v.bytes.sz, n; \
+ \
+ allocate_bytes(&out[RH].v, ctx->outsz); \
+ cshake##w##_init(&hctx, \
+ in[RFUNC].v.str.p, in[RFUNC].v.str.sz, \
+ in[RPERSO].v.str.p, in[RPERSO].v.str.sz); \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ shake_hash(&hctx, p, n); p += n; sz -= n; \
+ } \
+ shake_xof(&hctx); \
+ q = out[RH].v.bytes.p; sz = ctx->outsz; \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ shake_get(&hctx, q, n); q += n; sz -= n; \
+ } \
+}
+
+SHAKE_VARIANTS(SHAKE_TESTFUNCS)
+
+#define REG_M { "m", RM, ®ty_bytes, 0 }
+#define REG_N { "n", RN, ®ty_uint, 0 }
+#define REG_FUNC { "func", RFUNC, ®ty_string, 0 }
+#define REG_PERSO { "perso", RPERSO, ®ty_string, 0 }
+#define REG_H { "h", RH, ®ty_bytes, 0 }
+static const struct regdef
+ hash_kat_regs[] = { REG_M, REG_H, REGLIST_END },
+ hash_mct_regs[] = { REG_M, REG_N, REG_H, REGLIST_END },
+ cshake_regs[] = { REG_M, REG_FUNC, REG_PERSO, REG_H, REGLIST_END };
+
+#define SHA3_TESTDEFS(w) \
+ { "sha3-" #w "-hex", run_sha3_kat, \
+ hash_kat_regs, test_sha3_##w##_kat }, \
+ { "sha3-" #w "-mct", run_test, \
+ hash_mct_regs, test_sha3_##w##_mct },
+#define SHAKE_TESTDEFS(w) \
+ { "shake" #w, run_sha3_kat, \
+ hash_kat_regs, test_shake##w##_kat }, \
+ { "cshake" #w, run_sha3_kat, \
+ cshake_regs, test_cshake##w##_kat },
+static const struct test tests[] = {
+ SHA3_VARIANTS(SHA3_TESTDEFS)
+ SHAKE_VARIANTS(SHAKE_TESTDEFS)
+ { 0 }
+};
+
+int main(void)
+ { return run_test_suite(NROUT, NREG, sizeof(struct reg), tests, stdin); }