From e018582a4c3a19b870f664e86c3ed26b2598190f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se>
Date: Tue, 18 Oct 2016 23:17:21 +0200
Subject: [PATCH] Initial implementation of _skein512_block.

---
 ChangeLog                  |   8 ++
 Makefile.in                |   1 +
 skein.h                    |  16 ++++
 skein512-internal.c        | 171 +++++++++++++++++++++++++++++++++++++
 testsuite/.test-rules.make |   3 +
 testsuite/Makefile.in      |   3 +-
 testsuite/skein512-test.c  | 127 +++++++++++++++++++++++++++
 7 files changed, 328 insertions(+), 1 deletion(-)
 create mode 100644 skein512-internal.c
 create mode 100644 testsuite/skein512-test.c

diff --git a/ChangeLog b/ChangeLog
index 43092436..53da0cc3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2016-10-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* skein512-internal.c (_skein512_block): New file and function.
+	* skein.h: Added skein512 declarations.
+	* Makefile.in (nettle_SOURCES): Added skein512-internal.c.
+	* testsuite/skein512-test.c: New test case.
+	* testsuite/Makefile.in (TS_NETTLE_SOURCES): Added skein512-test.c.
+
 2016-10-16  Niels Möller  <nisse@lysator.liu.se>
 
 	* skein256-internal.c (_skein256_block): Keep the subkey words in
diff --git a/Makefile.in b/Makefile.in
index 46cef529..d308b828 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -129,6 +129,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
 		 sha3-384.c sha3-384-meta.c sha3-512.c sha3-512-meta.c\
 		 serpent-set-key.c serpent-encrypt.c serpent-decrypt.c \
 		 serpent-meta.c skein256.c skein256-internal.c skein256-meta.c \
+		 skein512-internal.c \
 		 twofish.c twofish-meta.c \
 		 umac-nh.c umac-nh-n.c umac-l2.c umac-l3.c \
 		 umac-poly64.c umac-poly128.c umac-set-key.c \
diff --git a/skein.h b/skein.h
index 5806763d..9d388af5 100644
--- a/skein.h
+++ b/skein.h
@@ -46,6 +46,7 @@ extern "C" {
 #define skein256_digest nettle_skein256_digest
 #define _skein256_expand _nettle_skein256_expand
 #define _skein256_block _nettle_skein256_block
+#define _skein512_block _nettle_skein512_block
 
 #define SKEIN256_BLOCK_SIZE 32
 #define SKEIN256_DIGEST_SIZE 32
@@ -80,6 +81,15 @@ skein256_digest(struct skein256_ctx *ctx,
 		size_t length,
 		uint8_t *digest);
 
+#define SKEIN512_BLOCK_SIZE 64
+#define SKEIN512_DIGEST_SIZE 64
+
+/* Internal lengths, as 64-bit words. We use *two* redundant words for
+   the key, to reduce the number of index mod operations. On the other
+   hand, tweak words are expanded on the fly. */
+#define _SKEIN512_LENGTH 8
+#define _SKEIN512_NKEYS 9
+
 #define _SKEIN_C240 0x1BD11BDAA9FC1A22ULL
 
 void
@@ -91,6 +101,12 @@ _skein256_block (uint64_t dst[_SKEIN256_LENGTH],
 		 const uint64_t tweak[_SKEIN_NTWEAK],
 		 const uint8_t src[SKEIN256_BLOCK_SIZE]);
 
+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]);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/skein512-internal.c b/skein512-internal.c
new file mode 100644
index 00000000..5b0e1a6f
--- /dev/null
+++ b/skein512-internal.c
@@ -0,0 +1,171 @@
+/* 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);
+}
diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make
index 3d2a7e11..216a0f68 100644
--- a/testsuite/.test-rules.make
+++ b/testsuite/.test-rules.make
@@ -100,6 +100,9 @@ sha3-512-test$(EXEEXT): sha3-512-test.$(OBJEXT)
 skein256-test$(EXEEXT): skein256-test.$(OBJEXT)
 	$(LINK) skein256-test.$(OBJEXT) $(TEST_OBJS) -o skein256-test$(EXEEXT)
 
+skein512-test$(EXEEXT): skein512-test.$(OBJEXT)
+	$(LINK) skein512-test.$(OBJEXT) $(TEST_OBJS) -o skein512-test$(EXEEXT)
+
 serpent-test$(EXEEXT): serpent-test.$(OBJEXT)
 	$(LINK) serpent-test.$(OBJEXT) $(TEST_OBJS) -o serpent-test$(EXEEXT)
 
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 14e49934..b8ee7ff4 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -22,7 +22,8 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
 		    sha1-test.c sha224-test.c sha256-test.c \
 		    sha384-test.c sha512-test.c sha512-224-test.c sha512-256-test.c \
 		    sha3-permute-test.c sha3-224-test.c sha3-256-test.c \
-		    sha3-384-test.c sha3-512-test.c skein256-test.c \
+		    sha3-384-test.c sha3-512-test.c \
+		    skein256-test.c skein512-test.c \
 		    serpent-test.c twofish-test.c version-test.c \
 		    knuth-lfib-test.c \
 		    cbc-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \
diff --git a/testsuite/skein512-test.c b/testsuite/skein512-test.c
new file mode 100644
index 00000000..387b7cd4
--- /dev/null
+++ b/testsuite/skein512-test.c
@@ -0,0 +1,127 @@
+#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);
+  }
+}
-- 
GitLab