X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/3f8f973351d3273e6ef43e1029c0469508aa763c..5bf585d21927a684ae9c16eb2a28cd786cec433c:/sha3-test.c diff --git a/sha3-test.c b/sha3-test.c new file mode 100644 index 0000000..81d7610 --- /dev/null +++ b/sha3-test.c @@ -0,0 +1,184 @@ +/* + * 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 + +#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); }