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