--- /dev/null
+/* skein512-internal.c
+
+ Copyright (C) 2016 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle 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 copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "skein.h"
+
+#include "macros.h"
+
+/*
+ Subkeys used:
+
+ Round 0,9,18: k0, k1, k2, k3, k4, k5+t0, k6+t1, k7
+ Round 1,10: k1, k2, k3, k4, k5, k6+t1, k7+t2, k8+1
+ Round 2,11: k2, k3, k4, k5, k6, k7+t2, k8+t0, k0+2
+ Round 3,12: k3, k4, k5, k6, k7, k8+t0, k0+t1, k1+3
+ Round 4,13: k4, k5, k6, k7, k8, k0+t1, k1+t2, k2+4
+ Round 5,14: k5, k6, k7, k8, k0, k1+t2, k2+t0, k3+5
+ Round 6,15: k6, k7, k8, k0, k1, k2+t0, k3+t1, k4+6
+ Round 7,16: k7, k8, k0, k1, k2, k3+t1, k4+t2, k5+7
+ Round 8,17: k8, k0, k1, k2, k3, k4+t2, k5+t0, k6+8
+
+ Single round mangling:
+
+ w0 += w1;
+ w1 <<<= r_d0; { 46, 33, 17, 44, 39, 13, 25, 8 }
+ w1 ^= w0
+
+ w2 += w3;
+ w3 <<<= r_d1; { 36, 27, 49, 9, 30, 50, 29, 35 }
+ w3 ^= w2;
+
+ w4 += w5;
+ w5 <<<= r_d2; { 19, 14, 36, 54, 34, 10, 39, 56 }
+ w5 ^= w4
+
+ w6 += w7;
+ w7 <<<= r_d3; { 37, 42, 39, 56, 24, 17, 43, 22 }
+ w7 ^= w6;
+
+ Permute: 0->2->4->6->0, 3<->7, 1->1, 5->5
+ Pairs mixed:
+
+ (0,1),(2,3),(4,5),(6,7)
+ (2,1),(4,7),(6,5),(0,3)
+ (4,1),(6,3),(0,5),(2,7)
+ (6,1),(0,7),(2,5),(4,3)
+*/
+
+#define ROUND(w0, w1, w2, w3, w4, w5, w6, w7, c0, c1, c2, c3) do { \
+ w0 += w1; \
+ w1 = ROTL64(c0, w1); \
+ w1 ^= w0; \
+ \
+ w2 += w3; \
+ w3 = ROTL64(c1, w3); \
+ w3 ^= w2; \
+ \
+ w4 += w5; \
+ w5 = ROTL64(c2, w5); \
+ w5 ^= w4; \
+ \
+ w6 += w7; \
+ w7 = ROTL64(c3, w7); \
+ w7 ^= w6; \
+ } while(0)
+
+void
+_skein512_block (uint64_t dst[_SKEIN512_LENGTH],
+ const uint64_t keys[_SKEIN512_NKEYS],
+ const uint64_t tweak[_SKEIN_NTWEAK],
+ const uint8_t src[SKEIN512_BLOCK_SIZE])
+{
+ uint64_t w0, w1, w2, w3, w4, w5, w6, w7;
+ uint64_t t0, t1;
+ unsigned i;
+
+ w0 = LE_READ_UINT64(src);
+ w1 = LE_READ_UINT64(src + 8);
+ w2 = LE_READ_UINT64(src + 16);
+ w3 = LE_READ_UINT64(src + 24);
+ w4 = LE_READ_UINT64(src + 32);
+ w5 = LE_READ_UINT64(src + 40);
+ w6 = LE_READ_UINT64(src + 48);
+ w7 = LE_READ_UINT64(src + 56);
+
+ t0 = tweak[0];
+ t1 = tweak[1];
+
+ for (i = 0; i < 18; i+=2)
+ {
+ w0 += keys[(i+0) % 9];
+ w1 += keys[(i+1) % 9];
+ w2 += keys[(i+2) % 9];
+ w3 += keys[(i+3) % 9];
+ w4 += keys[(i+4) % 9];
+ w5 += keys[(i+5) % 9] + t0;
+ w6 += keys[(i+6) % 9] + t1;
+ w7 += keys[(i+7) % 9] + i;
+
+ t0 ^= t1;
+
+ ROUND(w0, w1, w2, w3, w4, w5, w6, w7, 46, 36, 19, 37);
+ ROUND(w2, w1, w4, w7, w6, w5, w0, w3, 33, 27, 14, 42);
+ ROUND(w4, w1, w6, w3, w0, w5, w2, w7, 17, 49, 36, 39);
+ ROUND(w6, w1, w0, w7, w2, w5, w4, w3, 44, 9, 54, 56);
+
+ w0 += keys[(i+1) % 9];
+ w1 += keys[(i+2) % 9];
+ w2 += keys[(i+3) % 9];
+ w3 += keys[(i+4) % 9];
+ w4 += keys[(i+5) % 9];
+ w5 += keys[(i+6) % 9] + t1;
+ w6 += keys[(i+7) % 9] + t0;
+ w7 += keys[(i+8) % 9] + i + 1;
+
+ t1 ^= t0;
+
+ ROUND(w0, w1, w2, w3, w4, w5, w6, w7, 39, 30, 34, 24);
+ ROUND(w2, w1, w4, w7, w6, w5, w0, w3, 13, 50, 10, 17);
+ ROUND(w4, w1, w6, w3, w0, w5, w2, w7, 25, 29, 39, 43);
+ ROUND(w6, w1, w0, w7, w2, w5, w4, w3, 8, 35, 56, 22);
+ }
+ w0 += keys[0];
+ w1 += keys[1];
+ w2 += keys[2];
+ w3 += keys[3];
+ w4 += keys[4];
+ w5 += keys[5] + t0;
+ w6 += keys[6] + t1;
+ w7 += keys[7] + 18;
+
+ dst[0] = w0 ^ LE_READ_UINT64(src);
+ dst[1] = w1 ^ LE_READ_UINT64(src + 8);
+ dst[2] = w2 ^ LE_READ_UINT64(src + 16);
+ dst[3] = w3 ^ LE_READ_UINT64(src + 24);
+ dst[4] = w4 ^ LE_READ_UINT64(src + 32);
+ dst[5] = w5 ^ LE_READ_UINT64(src + 40);
+ dst[6] = w6 ^ LE_READ_UINT64(src + 48);
+ dst[7] = w7 ^ LE_READ_UINT64(src + 56);
+}
--- /dev/null
+#include "testutils.h"
+
+#include "skein.h"
+
+static void
+print_array(const char *label, size_t n, const uint64_t *x)
+{
+ size_t i;
+ printf("%s:", label);
+ for (i = 0; i < n; i++)
+ printf("%s%016llx", (i && !(i%4)) ? "\n " : " ",
+ (unsigned long long) x[i]);
+ printf("\n");
+}
+
+static void
+test_skein512_block (const uint64_t keys[4],
+ const uint64_t tweak[2],
+ const uint8_t msg[SKEIN512_BLOCK_SIZE],
+ const uint64_t ref[_SKEIN512_LENGTH])
+{
+ uint64_t keys_expanded[_SKEIN512_NKEYS];
+ uint64_t output[_SKEIN512_LENGTH];
+ unsigned i;
+ uint64_t sum;
+
+ memcpy (keys_expanded, keys, _SKEIN512_LENGTH * sizeof(*keys));
+ for (i = 0, sum = _SKEIN_C240; i < _SKEIN512_LENGTH; i++)
+ sum ^= keys[i];
+ keys_expanded[_SKEIN512_LENGTH] = sum;
+ _skein512_block(output, keys_expanded, tweak, msg);
+ if (memcmp (output, ref, sizeof(output)) != 0)
+ {
+ printf ("Skein 512 failed:\n");
+ print_array("key", _SKEIN512_LENGTH, keys);
+ print_array("tweak", _SKEIN_NTWEAK, tweak);
+ printf ("msg: ");
+ print_hex(SKEIN512_BLOCK_SIZE, msg);
+ print_array("out", _SKEIN512_LENGTH, output);
+ print_array("ref", _SKEIN512_LENGTH, ref);
+ FAIL();
+ }
+}
+
+void
+test_main(void)
+{
+ /* From skein_golden_kat_short_internals.txt in
+ http://www.skein-hash.info/sites/default/files/NIST_CD_102610.zip. */
+ {
+ static const uint64_t zeros[8] = {
+ 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ static const uint64_t ref[_SKEIN512_LENGTH] = {
+ 0xBC2560EFC6BBA2B1ull,
+ 0xE3361F162238EB40ull,
+ 0xFB8631EE0ABBD175ull,
+ 0x7B9479D4C5479ED1ull,
+ 0xCFF0356E58F8C27Bull,
+ 0xB1B7B08430F0E7F7ull,
+ 0xE9A380A56139ABF1ull,
+ 0xBE7B6D4AA11EB47Eull,
+ };
+ test_skein512_block(zeros, zeros,
+ H("0000000000000000 0000000000000000"
+ "0000000000000000 0000000000000000"
+ "0000000000000000 0000000000000000"
+ "0000000000000000 0000000000000000"),
+ ref);
+ }
+ {
+ static const uint64_t keys[8] = {
+ 0x1716151413121110ull,
+ 0x1F1E1D1C1B1A1918ull,
+ 0x2726252423222120ull,
+ 0x2F2E2D2C2B2A2928ull,
+ 0x3736353433323130ull,
+ 0x3F3E3D3C3B3A3938ull,
+ 0x4746454443424140ull,
+ 0x4F4E4D4C4B4A4948ull,
+ };
+ static const uint64_t tweak[2] = {
+ 0x0706050403020100ull,
+ 0x0F0E0D0C0B0A0908ull,
+ };
+ static const uint64_t ref[8] = {
+ 0xD4A32EDD6ABEFA1Cull,
+ 0x6AD5C4252C3FF743ull,
+ 0x35AC875BE2DED68Cull,
+ 0x99A6C774EA5CD06Cull,
+ 0xDCEC9C4251D7F4F8ull,
+ 0xF5761BCB3EF592AFull,
+ 0xFCABCB6A3212DF60ull,
+ 0xFD6EDE9FF9A2E14Eull,
+ };
+ test_skein512_block(keys, tweak,
+ H("FFFEFDFCFBFAF9F8 F7F6F5F4F3F2F1F0"
+ "EFEEEDECEBEAE9E8 E7E6E5E4E3E2E1E0"
+ "DFDEDDDCDBDAD9D8 D7D6D5D4D3D2D1D0"
+ "CFCECDCCCBCAC9C8 C7C6C5C4C3C2C1C0"),
+ ref);
+
+ }
+ {
+ /* skein512 G0 = E(zeros, tweak, config string) */
+ static const uint64_t zero_keys[_SKEIN512_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ static const uint64_t tweak[_SKEIN_NTWEAK] = {
+ 32, /* message length */
+ 0xc4ull << 56, /* first and final, type 4 */
+ };
+ static const uint64_t ref[_SKEIN512_LENGTH] = {
+ 0x4903ADFF749C51CEull, 0x0D95DE399746DF03ull,
+ 0x8FD1934127C79BCEull, 0x9A255629FF352CB1ull,
+ 0x5DB62599DF6CA7B0ull, 0xEABE394CA9D5C3F4ull,
+ 0x991112C71A75B523ull, 0xAE18A40B660FCC33ull,
+ };
+ test_skein512_block(zero_keys, tweak,
+ H("5348413301000000 0002000000000000"
+ /* SHA3 v1 output bits (512) */
+ "0000000000000000 0000000000000000"
+ "0000000000000000 0000000000000000"
+ "0000000000000000 0000000000000000"),
+ ref);
+ }
+}