From 792137f88d4b0e256a1fa59e51ba07b38a4142e4 Mon Sep 17 00:00:00 2001
From: Mathias Tausig <mathias.tausig@fh-campuswien.ac.at>
Date: Thu, 26 Oct 2017 22:28:09 +0200
Subject: [PATCH] hashes:sha3: Integrate SHA-3 into RIOT API

Add init/update/final interface
Add interface functions for direct SHA3
Add unit tests for SHA-3
Document functions and types
Reduced var scope in Keccak code
Add CCO Copyright notice to Keccak code
---
 sys/hashes/sha3.c                             | 436 ++++++++++++------
 sys/include/hashes/sha3.h                     | 180 ++++++++
 .../tests-hashes/tests-hashes-sha3.c          | 429 +++++++++++++++++
 tests/unittests/tests-hashes/tests-hashes.c   |   1 +
 tests/unittests/tests-hashes/tests-hashes.h   |   7 +
 5 files changed, 909 insertions(+), 144 deletions(-)
 create mode 100644 sys/include/hashes/sha3.h
 create mode 100644 tests/unittests/tests-hashes/tests-hashes-sha3.c

diff --git a/sys/hashes/sha3.c b/sys/hashes/sha3.c
index d4a3d705a9..5b21f06b53 100644
--- a/sys/hashes/sha3.c
+++ b/sys/hashes/sha3.c
@@ -1,131 +1,197 @@
 /*
-Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni,
-Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby
-denoted as "the implementer".
+   Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni,
+   Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby
+   denoted as "the implementer".
 
-For more information, feedback or questions, please refer to our websites:
-http://keccak.noekeon.org/
-http://keyak.noekeon.org/
-http://ketje.noekeon.org/
+   For more information, feedback or questions, please refer to our websites:
+   http://keccak.noekeon.org/
+   http://keyak.noekeon.org/
+   http://ketje.noekeon.org/
 
-To the extent possible under law, the implementer has waived all copyright
-and related or neighboring rights to the source code in this file.
-http://creativecommons.org/publicdomain/zero/1.0/
-*/
+   To the extent possible under law, the implementer has waived all copyright
+   and related or neighboring rights to the source code in this file.
+   http://creativecommons.org/publicdomain/zero/1.0/
+
+   RIOT OS adaptations by Mathias Tausig
+
+   This software is released under the Creative Commons CC0 1.0 license.
+   To the extent possible under law, the implementer has waived all copyright
+   and related or neighboring rights to the source code in this file.
+   For more information see: http://creativecommons.org/publicdomain/zero/1.0/
+ */
 
 /*
-================================================================
-The purpose of this source file is to demonstrate a readable and compact
-implementation of all the Keccak instances approved in the FIPS 202 standard,
-including the hash functions and the extendable-output functions (XOFs).
-
-We focused on clarity and on source-code compactness,
-rather than on the performance.
-
-The advantages of this implementation are:
-    + The source code is compact, after removing the comments, that is. :-)
-    + There are no tables with arbitrary constants.
-    + For clarity, the comments link the operations to the specifications using
+   ================================================================
+   The purpose of this source file is to demonstrate a readable and compact
+   implementation of all the Keccak instances approved in the FIPS 202 standard,
+   including the hash functions and the extendable-output functions (XOFs).
+
+   We focused on clarity and on source-code compactness,
+   rather than on the performance.
+
+   The advantages of this implementation are:
+ + The source code is compact, after removing the comments, that is. :-)
+ + There are no tables with arbitrary constants.
+ + For clarity, the comments link the operations to the specifications using
         the same notation as much as possible.
-    + There is no restriction in cryptographic features. In particular,
+ + There is no restriction in cryptographic features. In particular,
         the SHAKE128 and SHAKE256 XOFs can produce any output length.
-    + The code does not use much RAM, as all operations are done in place.
+ + The code does not use much RAM, as all operations are done in place.
 
-The drawbacks of this implementation are:
+   The drawbacks of this implementation are:
     - There is no message queue. The whole message must be ready in a buffer.
     - It is not optimized for peformance.
 
-The implementation is even simpler on a little endian platform. Just define the
-LITTLE_ENDIAN symbol in that case.
+   The implementation is even simpler on a little endian platform. Just define the
+   LITTLE_ENDIAN symbol in that case.
 
-For a more complete set of implementations, please refer to
-the Keccak Code Package at https://github.com/gvanas/KeccakCodePackage
+   For a more complete set of implementations, please refer to
+   the Keccak Code Package at https://github.com/gvanas/KeccakCodePackage
 
-For more information, please refer to:
-    * [Keccak Reference] http://keccak.noekeon.org/Keccak-reference-3.0.pdf
-    * [Keccak Specifications Summary] http://keccak.noekeon.org/specs_summary.html
+   For more information, please refer to:
+ * [Keccak Reference] http://keccak.noekeon.org/Keccak-reference-3.0.pdf
+ * [Keccak Specifications Summary] http://keccak.noekeon.org/specs_summary.html
 
-This file uses UTF-8 encoding, as some comments use Greek letters.
-================================================================
-*/
+   This file uses UTF-8 encoding, as some comments use Greek letters.
+   ================================================================
+ */
+
+#include <hashes/sha3.h>
 
 /**
-  * Function to compute the Keccak[r, c] sponge function over a given input.
-  * @param  rate            The value of the rate r.
-  * @param  capacity        The value of the capacity c.
-  * @param  input           Pointer to the input message.
-  * @param  inputByteLen    The number of input bytes provided in the input message.
-  * @param  delimitedSuffix Bits that will be automatically appended to the end
-  *                         of the input message, as in domain separation.
-  *                         This is a byte containing from 0 to 7 bits
-  *                         These <i>n</i> bits must be in the least significant bit positions
-  *                         and must be delimited with a bit 1 at position <i>n</i>
-  *                         (counting from 0=LSB to 7=MSB) and followed by bits 0
-  *                         from position <i>n</i>+1 to position 7.
-  *                         Some examples:
-  *                             - If no bits are to be appended, then @a delimitedSuffix must be 0x01.
-  *                             - If the 2-bit sequence 0,1 is to be appended (as for SHA3-*), @a delimitedSuffix must be 0x06.
-  *                             - If the 4-bit sequence 1,1,1,1 is to be appended (as for SHAKE*), @a delimitedSuffix must be 0x1F.
-  *                             - If the 7-bit sequence 1,1,0,1,0,0,0 is to be absorbed, @a delimitedSuffix must be 0x8B.
-  * @param  output          Pointer to the buffer where to store the output.
-  * @param  outputByteLen   The number of output bytes desired.
-  * @pre    One must have r+c=1600 and the rate a multiple of 8 bits in this implementation.
-  */
-void Keccak(unsigned int rate, unsigned int capacity, const unsigned char *input, unsigned long long int inputByteLen, unsigned char delimitedSuffix, unsigned char *output, unsigned long long int outputByteLen);
+ * Function to compute the Keccak[r, c] sponge function over a given input.
+ * @param  rate            The value of the rate r.
+ * @param  capacity        The value of the capacity c.
+ * @param  input           Pointer to the input message.
+ * @param  inputByteLen    The number of input bytes provided in the input message.
+ * @param  delimitedSuffix Bits that will be automatically appended to the end
+ *                         of the input message, as in domain separation.
+ *                         This is a byte containing from 0 to 7 bits
+ *                         These <i>n</i> bits must be in the least significant bit positions
+ *                         and must be delimited with a bit 1 at position <i>n</i>
+ *                         (counting from 0=LSB to 7=MSB) and followed by bits 0
+ *                         from position <i>n</i>+1 to position 7.
+ *                         Some examples:
+ *                           - If no bits are to be appended, then @a delimitedSuffix must be 0x01.
+ *                           - If the 2-bit sequence 0,1 is to be appended (as for SHA3-*),
+ *                              @a delimitedSuffix must be 0x06.
+ *                           - If the 4-bit sequence 1,1,1,1 is to be appended (as for SHAKE*),
+ *                              @a delimitedSuffix must be 0x1F.
+ *                           - If the 7-bit sequence 1,1,0,1,0,0,0 is to be absorbed,
+ *                              @a delimitedSuffix must be 0x8B.
+ * @param  output          Pointer to the buffer where to store the output.
+ * @param  outputByteLen   The number of output bytes desired.
+ * @pre    One must have r+c=1600 and the rate a multiple of 8 bits in this implementation.
+ */
+static void Keccak(unsigned int rate, unsigned int capacity, const unsigned char *input,
+                   unsigned long long int inputByteLen, unsigned char delimitedSuffix, unsigned char *output,
+                   unsigned long long int outputByteLen);
 
 /**
-  *  Function to compute SHAKE128 on the input message with any output length.
-  */
+ *  Function to compute SHAKE128 on the input message with any output length.
+ */
 void FIPS202_SHAKE128(const unsigned char *input, unsigned int inputByteLen, unsigned char *output, int outputByteLen)
 {
     Keccak(1344, 256, input, inputByteLen, 0x1F, output, outputByteLen);
 }
 
 /**
-  *  Function to compute SHAKE256 on the input message with any output length.
-  */
+ *  Function to compute SHAKE256 on the input message with any output length.
+ */
 void FIPS202_SHAKE256(const unsigned char *input, unsigned int inputByteLen, unsigned char *output, int outputByteLen)
 {
     Keccak(1088, 512, input, inputByteLen, 0x1F, output, outputByteLen);
 }
 
 /**
-  *  Function to compute SHA3-224 on the input message. The output length is fixed to 28 bytes.
-  */
+ *  Function to compute SHA3-224 on the input message. The output length is fixed to 28 bytes.
+ */
 void FIPS202_SHA3_224(const unsigned char *input, unsigned int inputByteLen, unsigned char *output)
 {
     Keccak(1152, 448, input, inputByteLen, 0x06, output, 28);
 }
 
+
 /**
-  *  Function to compute SHA3-256 on the input message. The output length is fixed to 32 bytes.
-  */
-void FIPS202_SHA3_256(const unsigned char *input, unsigned int inputByteLen, unsigned char *output)
+ *  Function to compute SHA3-256 on the input message. The output length is fixed to 32 bytes.
+ */
+static void FIPS202_SHA3_256(const unsigned char *input, unsigned int inputByteLen, unsigned char *output)
+{
+    Keccak(1088, 512, input, inputByteLen, 0x06, output, SHA3_256_DIGEST_LENGTH);
+}
+
+void sha3_256(void *digest, const void *data, size_t len)
+{
+    FIPS202_SHA3_256(data, len, digest);
+}
+
+void sha3_256_init(keccak_state_t *ctx)
+{
+    Keccak_init(ctx, 1088, 512, 0x06);
+}
+
+void sha3_update(keccak_state_t *ctx, const void *data, size_t len)
+{
+    Keccak_update(ctx, data, len);
+}
+
+void sha3_256_final(keccak_state_t *ctx, void *digest)
 {
-    Keccak(1088, 512, input, inputByteLen, 0x06, output, 32);
+    Keccak_final(ctx, digest, SHA3_256_DIGEST_LENGTH);
 }
 
+
 /**
-  *  Function to compute SHA3-384 on the input message. The output length is fixed to 48 bytes.
-  */
-void FIPS202_SHA3_384(const unsigned char *input, unsigned int inputByteLen, unsigned char *output)
+ *  Function to compute SHA3-384 on the input message. The output length is fixed to 48 bytes.
+ */
+static void FIPS202_SHA3_384(const unsigned char *input, unsigned int inputByteLen, unsigned char *output)
 {
     Keccak(832, 768, input, inputByteLen, 0x06, output, 48);
 }
 
+void sha3_384(void *digest, const void *data, size_t len)
+{
+    FIPS202_SHA3_384(data, len, digest);
+}
+
+void sha3_384_init(keccak_state_t *ctx)
+{
+    Keccak_init(ctx, 832, 768, 0x06);
+}
+
+void sha3_384_final(keccak_state_t *ctx, void *digest)
+{
+    Keccak_final(ctx, digest, SHA3_384_DIGEST_LENGTH);
+}
+
 /**
-  *  Function to compute SHA3-512 on the input message. The output length is fixed to 64 bytes.
-  */
-void FIPS202_SHA3_512(const unsigned char *input, unsigned int inputByteLen, unsigned char *output)
+ *  Function to compute SHA3-512 on the input message. The output length is fixed to 64 bytes.
+ */
+static void FIPS202_SHA3_512(const unsigned char *input, unsigned int inputByteLen, unsigned char *output)
 {
     Keccak(576, 1024, input, inputByteLen, 0x06, output, 64);
 }
 
+void sha3_512(void *digest, const void *data, size_t len)
+{
+    FIPS202_SHA3_512(data, len, digest);
+}
+
+void sha3_512_init(keccak_state_t *ctx)
+{
+    Keccak_init(ctx, 576, 1024, 0x06);
+}
+
+void sha3_512_final(keccak_state_t *ctx, void *digest)
+{
+    Keccak_final(ctx, digest, SHA3_512_DIGEST_LENGTH);
+}
+
 /*
-================================================================
-Technicalities
-================================================================
-*/
+   ================================================================
+   Technicalities
+   ================================================================
+ */
 
 typedef unsigned char UINT8;
 typedef unsigned long long int UINT64;
@@ -133,14 +199,14 @@ typedef UINT64 tKeccakLane;
 
 #ifndef LITTLE_ENDIAN
 /** Function to load a 64-bit value using the little-endian (LE) convention.
-  * On a LE platform, this could be greatly simplified using a cast.
-  */
+ * On a LE platform, this could be greatly simplified using a cast.
+ */
 static UINT64 load64(const UINT8 *x)
 {
     int i;
-    UINT64 u=0;
+    UINT64 u = 0;
 
-    for(i=7; i>=0; --i) {
+    for (i = 7; i >= 0; --i) {
         u <<= 8;
         u |= x[i];
     }
@@ -148,26 +214,26 @@ static UINT64 load64(const UINT8 *x)
 }
 
 /** Function to store a 64-bit value using the little-endian (LE) convention.
-  * On a LE platform, this could be greatly simplified using a cast.
-  */
+ * On a LE platform, this could be greatly simplified using a cast.
+ */
 static void store64(UINT8 *x, UINT64 u)
 {
     unsigned int i;
 
-    for(i=0; i<8; ++i) {
+    for (i = 0; i < 8; ++i) {
         x[i] = u;
         u >>= 8;
     }
 }
 
 /** Function to XOR into a 64-bit value using the little-endian (LE) convention.
-  * On a LE platform, this could be greatly simplified using a cast.
-  */
+ * On a LE platform, this could be greatly simplified using a cast.
+ */
 static void xor64(UINT8 *x, UINT64 u)
 {
     unsigned int i;
 
-    for(i=0; i<8; ++i) {
+    for (i = 0; i < 8; ++i) {
         x[i] ^= u;
         u >>= 8;
     }
@@ -175,76 +241,80 @@ static void xor64(UINT8 *x, UINT64 u)
 #endif
 
 /*
-================================================================
-A readable and compact implementation of the Keccak-f[1600] permutation.
-================================================================
-*/
+   ================================================================
+   A readable and compact implementation of the Keccak-f[1600] permutation.
+   ================================================================
+ */
 
-#define ROL64(a, offset) ((((UINT64)a) << offset) ^ (((UINT64)a) >> (64-offset)))
-#define i(x, y) ((x)+5*(y))
+#define ROL64(a, offset) ((((UINT64)a) << offset) ^ (((UINT64)a) >> (64 - offset)))
+#define i(x, y) ((x) + 5 * (y))
 
 #ifdef LITTLE_ENDIAN
-    #define readLane(x, y)          (((tKeccakLane*)state)[i(x, y)])
-    #define writeLane(x, y, lane)   (((tKeccakLane*)state)[i(x, y)]) = (lane)
-    #define XORLane(x, y, lane)     (((tKeccakLane*)state)[i(x, y)]) ^= (lane)
+    #define readLane(x, y)          (((tKeccakLane *)state)[i(x, y)])
+    #define writeLane(x, y, lane)   (((tKeccakLane *)state)[i(x, y)]) = (lane)
+    #define XORLane(x, y, lane)     (((tKeccakLane *)state)[i(x, y)]) ^= (lane)
 #else
-    #define readLane(x, y)          load64((UINT8*)state+sizeof(tKeccakLane)*i(x, y))
-    #define writeLane(x, y, lane)   store64((UINT8*)state+sizeof(tKeccakLane)*i(x, y), lane)
-    #define XORLane(x, y, lane)     xor64((UINT8*)state+sizeof(tKeccakLane)*i(x, y), lane)
+    #define readLane(x, y)          load64((UINT8 *)state + sizeof(tKeccakLane) * i(x, y))
+    #define writeLane(x, y, lane)   store64((UINT8 *)state + sizeof(tKeccakLane) * i(x, y), lane)
+    #define XORLane(x, y, lane)     xor64((UINT8 *)state + sizeof(tKeccakLane) * i(x, y), lane)
 #endif
 
 /**
-  * Function that computes the linear feedback shift register (LFSR) used to
-  * define the round constants (see [Keccak Reference, Section 1.2]).
-  */
-int LFSR86540(UINT8 *LFSR)
+ * Function that computes the linear feedback shift register (LFSR) used to
+ * define the round constants (see [Keccak Reference, Section 1.2]).
+ */
+static int LFSR86540(UINT8 *LFSR)
 {
     int result = ((*LFSR) & 0x01) != 0;
-    if (((*LFSR) & 0x80) != 0)
+
+    if (((*LFSR) & 0x80) != 0) {
         /* Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1 */
         (*LFSR) = ((*LFSR) << 1) ^ 0x71;
-    else
+    }
+    else {
         (*LFSR) <<= 1;
+    }
     return result;
 }
 
 /**
  * Function that computes the Keccak-f[1600] permutation on the given state.
  */
-void KeccakF1600_StatePermute(void *state)
+static void KeccakF1600_StatePermute(void *state)
 {
     unsigned int round, x, y, j, t;
     UINT8 LFSRstate = 0x01;
 
-    for(round=0; round<24; round++) {
+    for (round = 0; round < 24; round++) {
         {   /* === θ step (see [Keccak Reference, Section 2.3.2]) === */
-            tKeccakLane C[5], D;
+            tKeccakLane C[5];
 
             /* Compute the parity of the columns */
-            for(x=0; x<5; x++)
-                C[x] = readLane(x, 0) ^ readLane(x, 1) ^ readLane(x, 2) ^ readLane(x, 3) ^ readLane(x, 4);
-            for(x=0; x<5; x++) {
+            for (x = 0; x < 5; x++)
+                C[x] = readLane(x, 0) ^ readLane(x, 1) ^ readLane(x, 2) ^ readLane(x, 3) ^
+                       readLane(x, 4);
+            for (x = 0; x < 5; x++) {
                 /* Compute the θ effect for a given column */
-                D = C[(x+4)%5] ^ ROL64(C[(x+1)%5], 1);
+                tKeccakLane D = C[(x + 4) % 5] ^ ROL64(C[(x + 1) % 5], 1);
                 /* Add the θ effect to the whole column */
-                for (y=0; y<5; y++)
+                for (y = 0; y < 5; y++)
                     XORLane(x, y, D);
             }
         }
 
         {   /* === ρ and π steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4]) === */
-            tKeccakLane current, temp;
+            tKeccakLane current;
             /* Start at coordinates (1 0) */
             x = 1; y = 0;
             current = readLane(x, y);
             /* Iterate over ((0 1)(2 3))^t * (1 0) for 0 ≤ t ≤ 23 */
-            for(t=0; t<24; t++) {
+            for (t = 0; t < 24; t++) {
                 /* Compute the rotation constant r = (t+1)(t+2)/2 */
-                unsigned int r = ((t+1)*(t+2)/2)%64;
+                unsigned int r = ((t + 1) * (t + 2) / 2) % 64;
                 /* Compute ((0 1)(2 3)) * (x y) */
-                unsigned int Y = (2*x+3*y)%5; x = y; y = Y;
+                unsigned int Y = (2 * x + 3 * y) % 5; x = y; y = Y;
                 /* Swap current and state(x,y), and rotate */
-                temp = readLane(x, y);
+                tKeccakLane temp = readLane(x, y);
                 writeLane(x, y, ROL64(current, r));
                 current = temp;
             }
@@ -252,53 +322,58 @@ void KeccakF1600_StatePermute(void *state)
 
         {   /* === χ step (see [Keccak Reference, Section 2.3.1]) === */
             tKeccakLane temp[5];
-            for(y=0; y<5; y++) {
+            for (y = 0; y < 5; y++) {
                 /* Take a copy of the plane */
-                for(x=0; x<5; x++)
+                for (x = 0; x < 5; x++)
                     temp[x] = readLane(x, y);
                 /* Compute χ on the plane */
-                for(x=0; x<5; x++)
-                    writeLane(x, y, temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5]));
+                for (x = 0; x < 5; x++)
+                    writeLane(x, y, temp[x] ^ ((~temp[(x + 1) % 5]) & temp[(x + 2) % 5]));
             }
         }
 
-        {   /* === ι step (see [Keccak Reference, Section 2.3.5]) === */
-            for(j=0; j<7; j++) {
-                unsigned int bitPosition = (1<<j)-1; /* 2^j-1 */
-                if (LFSR86540(&LFSRstate))
-                    XORLane(0, 0, (tKeccakLane)1<<bitPosition);
+        {
+            /* === ι step (see [Keccak Reference, Section 2.3.5]) === */
+            for (j = 0; j < 7; j++) {
+                unsigned int bitPosition = (1 << j) - 1;    /* 2^j-1 */
+                if (LFSR86540(&LFSRstate)) {
+                    XORLane(0, 0, (tKeccakLane)1 << bitPosition);
+                }
             }
         }
     }
 }
 
 /*
-================================================================
-A readable and compact implementation of the Keccak sponge functions
-that use the Keccak-f[1600] permutation.
-================================================================
-*/
+   ================================================================
+   A readable and compact implementation of the Keccak sponge functions
+   that use the Keccak-f[1600] permutation.
+   ================================================================
+ */
 
 #include <string.h>
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 
-void Keccak(unsigned int rate, unsigned int capacity, const unsigned char *input, unsigned long long int inputByteLen, unsigned char delimitedSuffix, unsigned char *output, unsigned long long int outputByteLen)
+static void Keccak(unsigned int rate, unsigned int capacity, const unsigned char *input,
+                   unsigned long long int inputByteLen, unsigned char delimitedSuffix,
+                   unsigned char *output, unsigned long long int outputByteLen)
 {
     UINT8 state[200];
-    unsigned int rateInBytes = rate/8;
+    unsigned int rateInBytes = rate / 8;
     unsigned int blockSize = 0;
     unsigned int i;
 
-    if (((rate + capacity) != 1600) || ((rate % 8) != 0))
+    if (((rate + capacity) != 1600) || ((rate % 8) != 0)) {
         return;
+    }
 
     /* === Initialize the state === */
     memset(state, 0, sizeof(state));
 
     /* === Absorb all the input blocks === */
-    while(inputByteLen > 0) {
+    while (inputByteLen > 0) {
         blockSize = MIN(inputByteLen, rateInBytes);
-        for(i=0; i<blockSize; i++)
+        for (i = 0; i < blockSize; i++)
             state[i] ^= input[i];
         input += blockSize;
         inputByteLen -= blockSize;
@@ -310,24 +385,97 @@ void Keccak(unsigned int rate, unsigned int capacity, const unsigned char *input
     }
 
     /* === Do the padding and switch to the squeezing phase === */
-    /* Absorb the last few bits and add the first bit of padding (which coincides with the delimiter in delimitedSuffix) */
+    /* Absorb the last few bits and add the first bit of padding (which coincides with the
+       delimiter in delimitedSuffix) */
     state[blockSize] ^= delimitedSuffix;
-    /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */
-    if (((delimitedSuffix & 0x80) != 0) && (blockSize == (rateInBytes-1)))
+    /* If the first bit of padding is at position rate-1, we need a whole new block for the
+       second bit of padding */
+    if (((delimitedSuffix & 0x80) != 0) && (blockSize == (rateInBytes - 1))) {
         KeccakF1600_StatePermute(state);
+    }
     /* Add the second bit of padding */
-    state[rateInBytes-1] ^= 0x80;
+    state[rateInBytes - 1] ^= 0x80;
     /* Switch to the squeezing phase */
     KeccakF1600_StatePermute(state);
 
     /* === Squeeze out all the output blocks === */
-    while(outputByteLen > 0) {
+    while (outputByteLen > 0) {
         blockSize = MIN(outputByteLen, rateInBytes);
         memcpy(output, state, blockSize);
         output += blockSize;
         outputByteLen -= blockSize;
 
-        if (outputByteLen > 0)
+        if (outputByteLen > 0) {
             KeccakF1600_StatePermute(state);
+        }
+    }
+}
+
+void Keccak_init(keccak_state_t *ctx, unsigned int rate, unsigned int capacity,
+                 unsigned char delimitedSuffix)
+{
+    ctx->rateInBytes = rate / 8;
+
+    if (((rate + capacity) != 1600) || ((rate % 8) != 0)) {
+        return;
+    }
+
+    /* === Initialize the state === */
+    memset(ctx->state, 0, sizeof(ctx->state));
+    ctx->i = 0;
+
+    ctx->rate = rate;
+    ctx->capacity = capacity;
+    ctx->delimitedSuffix = delimitedSuffix;
+}
+
+void Keccak_update(keccak_state_t *ctx, const unsigned char *input,
+                   unsigned long long int inputByteLen)
+{
+    /* === Absorb all the input blocks === */
+    while (inputByteLen > 0) {
+        unsigned int blockSize = MIN(inputByteLen + ctx->i, ctx->rateInBytes);
+        while (ctx->i < blockSize) {
+            ctx->state[ctx->i] ^= *input;
+            ++(ctx->i);
+            input++;
+            --inputByteLen;
+        }
+
+        if (blockSize == ctx->rateInBytes) {
+            KeccakF1600_StatePermute(ctx->state);
+            blockSize = 0;
+            ctx->i = 0;
+        }
+    }
+}
+
+void Keccak_final(keccak_state_t *ctx, unsigned char *output, unsigned long long int outputByteLen)
+{
+
+    /* === Do the padding and switch to the squeezing phase === */
+    /* Absorb the last few bits and add the first bit of padding (which coincides with the
+       delimiter in delimitedSuffix) */
+    ctx->state[ctx->i] ^= ctx->delimitedSuffix;
+    /* If the first bit of padding is at position rate-1, we need a whole new block for the
+       second bit of padding */
+    if (((ctx->delimitedSuffix & 0x80) != 0) && (ctx->i == (ctx->rateInBytes - 1))) {
+        KeccakF1600_StatePermute(ctx->state);
+    }
+    /* Add the second bit of padding */
+    ctx->state[ctx->rateInBytes - 1] ^= 0x80;
+    /* Switch to the squeezing phase */
+    KeccakF1600_StatePermute(ctx->state);
+
+    /* === Squeeze out all the output blocks === */
+    while (outputByteLen > 0) {
+        unsigned int blockSize = MIN(outputByteLen, ctx->rateInBytes);
+        memcpy(output, ctx->state, blockSize);
+        output += blockSize;
+        outputByteLen -= blockSize;
+
+        if (outputByteLen > 0) {
+            KeccakF1600_StatePermute(ctx->state);
+        }
     }
 }
diff --git a/sys/include/hashes/sha3.h b/sys/include/hashes/sha3.h
new file mode 100644
index 0000000000..0d09677050
--- /dev/null
+++ b/sys/include/hashes/sha3.h
@@ -0,0 +1,180 @@
+/*-
+ * Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni,
+ * Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby
+ * denoted as "the implementer".
+ *
+ * RIOT-OS adaptaion by Mathias Tausig
+ *
+ * This software is released under the Creative Commons CC0 1.0 license.
+ * To the extent possible under law, the implementer has waived all copyright
+ * and related or neighboring rights to the source code in this file.
+ * For more information see: http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * @ingroup     sys_hashes
+ * @{
+ *
+ * @file
+ * @brief       Header definitions for the SHA-3 hash function
+ *
+ * @author      Implementation by the Keccak, Keyak and Ketje Teams (https://keccak.team/)
+ * @author      RIOT OS adaptations by Mathias Tausig
+ */
+
+#ifndef HASHES_SHA3_H
+#define HASHES_SHA3_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SHA3_256_DIGEST_LENGTH 32
+#define SHA3_384_DIGEST_LENGTH 48
+#define SHA3_512_DIGEST_LENGTH 64
+
+/**
+ * @brief Context for operations on a sponge with keccak permutation
+ */
+typedef struct {
+    /** State of the Keccak sponge */
+    unsigned char state[200];
+    /** Current position within the state */
+    unsigned int i;
+    /** The suffix used for padding */
+    unsigned char delimitedSuffix;
+    /** The bitrate of the sponge */
+    unsigned int rate;
+    /** The capacity in bits of the sponge */
+    unsigned int capacity;
+    /** The rate in bytes of the sponge */
+    unsigned int rateInBytes;
+} keccak_state_t;
+
+/**
+ * @brief Initialise a sponge based on a keccak-1600 permutation
+ *
+ * @param[out] ctx             context handle to initialise
+ * @param[in] rate             the desired rate of the sponge
+ * @param[in] capacity         the desired capcity of the sponge
+ * @param[in] delimitedSuffix  suffix to be appended to the message after the absorbation phase
+ */
+void Keccak_init(keccak_state_t *ctx, unsigned int rate, unsigned int capacity,
+                 unsigned char delimitedSuffix);
+
+/**
+ * @brief Absorbs data into a sponge. Can be called multiple times
+ *
+ * @param[in,out] ctx       context handle of the sponge
+ * @param[in] input         pointer to the data to be absorbed
+ * @param[in] inputByteLen  length of the input data in bytes
+ */
+void Keccak_update(keccak_state_t *ctx, const unsigned char *input,
+                   unsigned long long int inputByteLen);
+
+/**
+ * @brief Squeeze data from a sponge
+ *
+ * @param[in,out] ctx        context handle of the sponge
+ * @param[out] output        the squeezed data
+ * @param[in] outputByteLen  size of the data to be squeezed.
+ */
+void Keccak_final(keccak_state_t *ctx, unsigned char *output,
+                  unsigned long long int outputByteLen);
+
+/**
+ * @brief SHA-3-256 initialization.  Begins a SHA-3-256 operation.
+ *
+ * @param[in] ctx  keccak_state_t handle to initialise
+ */
+void sha3_256_init(keccak_state_t *ctx);
+
+/**
+ * @brief Add bytes into the hash
+ *
+ * @param[in,out] ctx  context handle to use
+ * @param[in] data     Input data
+ * @param[in] len      Length of @p data
+ */
+void sha3_update(keccak_state_t *ctx, const void *data, size_t len);
+
+/**
+ * @brief SHA-3-256 finalization.  Pads the input data and exports the hash value
+ *
+ * @param[in,out] ctx    context handle to use
+ * @param[out] digest    resulting digest, this is the hash of all the bytes
+ */
+void sha3_256_final(keccak_state_t *ctx, void *digest);
+
+/**
+ * @brief SHA-3-384 initialization.  Begins a SHA-3-256 operation.
+ *
+ * @param[in] ctx  keccak_state_t handle to initialise
+ */
+void sha3_384_init(keccak_state_t *ctx);
+
+/**
+ * @brief SHA-3-384 finalization.  Pads the input data and exports the hash value
+ *
+ * @param[in,out] ctx    context handle to use
+ * @param[out] digest    resulting digest, this is the hash of all the bytes
+ */
+void sha3_384_final(keccak_state_t *ctx, void *digest);
+
+/**
+ * @brief SHA-3-512 initialization.  Begins a SHA-3-256 operation.
+ *
+ * @param[in] ctx  keccak_state_t handle to initialise
+ */
+void sha3_512_init(keccak_state_t *ctx);
+
+/**
+ * @brief SHA-3-512 finalization.  Pads the input data and exports the hash value
+ *
+ * @param[in,out] ctx    context handle to use
+ * @param[out] digest    resulting digest, this is the hash of all the bytes
+ */
+
+void sha3_512_final(keccak_state_t *ctx, void *digest);
+
+/**
+ * @brief A wrapper function to simplify the generation of a hash, this is
+ * usefull for generating SHA-3-256 from one buffer
+ *
+ * @param[in] data     pointer to the buffer to generate hash from
+ * @param[in] len      length of the buffer
+ * @param[out] digest  pointer to an array for the result, length must
+ *                     be SHA3_256_DIGEST_LENGTH
+ */
+void sha3_256(void *digest, const void *data, size_t len);
+
+/**
+ * @brief A wrapper function to simplify the generation of a hash, this is
+ * usefull for generating SHA-3-384 from one buffer
+ *
+ * @param[in] data     pointer to the buffer to generate hash from
+ * @param[in] len      length of the buffer
+ * @param[out] digest  pointer to an array for the result, length must
+ *                     be SHA3_384_DIGEST_LENGTH
+ */
+void sha3_384(void *digest, const void *data, size_t len);
+
+/**
+ * @brief A wrapper function to simplify the generation of a hash, this is
+ * usefull for generating SHA-3-512 from one buffer
+ *
+ * @param[in] data     pointer to the buffer to generate hash from
+ * @param[in] len      length of the buffer
+ * @param[out] digest  pointer to an array for the result, length must
+ *                     be SHA3_512_DIGEST_LENGTH
+ */
+void sha3_512(void *digest, const void *data, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HASHES_SHA3_H */
+/** @} */
diff --git a/tests/unittests/tests-hashes/tests-hashes-sha3.c b/tests/unittests/tests-hashes/tests-hashes-sha3.c
new file mode 100644
index 0000000000..dbb41051e0
--- /dev/null
+++ b/tests/unittests/tests-hashes/tests-hashes-sha3.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2017-2018 Mathias Tausig <mathias.tausig@fh-campsuwien.ac.at>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     unittests
+ * @{
+ *
+ * @file
+ * @brief       Test cases for the SHA-3 hash implementation
+ *
+ * @author      Mathias Tausig <mathias.tausig@fh-campsuwien.ac.at>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "hashes/sha3.h"
+#include "embUnit/embUnit.h"
+
+/**
+ * @brief expected SHA3-256 hash for test 01
+ *
+ * All test values taken from the Keccak code pacakge:
+ * https://github.com/gvanas/KeccakCodePackage
+ * Files: TestVectors/ShortMsgKAT_SHA3-256.txt, TestVectors/ShortMsgKAT_SHA3-384.txt,
+ *        TestVectors/ShortMsgKAT_SHA3-512.txt
+ *
+ * * converted using:
+ * s=$(echo '<hash string>' | sed -e 's/../0x&, /g' | sed 's/, $//'); echo {$s}\;
+ *
+ * where <hash string> is the above sequence of characters A7...4A
+ *
+ *  msg = ''
+ *  md_256 = A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A
+ *  md_384 = 0C63A75B845E4F7D01107D852E4C2485C51A50AAAA94FC61995E71BBEE983A2A
+ *           C3713831264ADB47FB6BD1E058D5F004
+ *  md_512 = A69F73CCA23A9AC5C8B567DC185A756E97C982164FE25859E0D1DCC1475C80A6
+ *           15B2123AF1F5F94C11E3E9402C3AC558F500199D95B6D3E301758586281DCD26
+ *
+ */
+static const uint8_t m01[1];
+size_t m01_len = 0;
+static const uint8_t m01_1[1];
+size_t m01_1_len = 0;
+static const uint8_t m01_2[1];
+size_t m01_2_len = 0;
+static const uint8_t h01_256[] = { 0xA7, 0xFF, 0xC6, 0xF8, 0xBF, 0x1E, 0xD7, 0x66,
+                                   0x51, 0xC1, 0x47, 0x56, 0xA0, 0x61, 0xD6, 0x62,
+                                   0xF5, 0x80, 0xFF, 0x4D, 0xE4, 0x3B, 0x49, 0xFA,
+                                   0x82, 0xD8, 0x0A, 0x4B, 0x80, 0xF8, 0x43, 0x4A };
+static const uint8_t h01_384[] = { 0x0C, 0x63, 0xA7, 0x5B, 0x84, 0x5E, 0x4F, 0x7D,
+                                   0x01, 0x10, 0x7D, 0x85, 0x2E, 0x4C, 0x24, 0x85,
+                                   0xC5, 0x1A, 0x50, 0xAA, 0xAA, 0x94, 0xFC, 0x61,
+                                   0x99, 0x5E, 0x71, 0xBB, 0xEE, 0x98, 0x3A, 0x2A,
+                                   0xC3, 0x71, 0x38, 0x31, 0x26, 0x4A, 0xDB, 0x47,
+                                   0xFB, 0x6B, 0xD1, 0xE0, 0x58, 0xD5, 0xF0, 0x04 };
+static const uint8_t h01_512[] = { 0xA6, 0x9F, 0x73, 0xCC, 0xA2, 0x3A, 0x9A, 0xC5,
+                                   0xC8, 0xB5, 0x67, 0xDC, 0x18, 0x5A, 0x75, 0x6E,
+                                   0x97, 0xC9, 0x82, 0x16, 0x4F, 0xE2, 0x58, 0x59,
+                                   0xE0, 0xD1, 0xDC, 0xC1, 0x47, 0x5C, 0x80, 0xA6,
+                                   0x15, 0xB2, 0x12, 0x3A, 0xF1, 0xF5, 0xF9, 0x4C,
+                                   0x11, 0xE3, 0xE9, 0x40, 0x2C, 0x3A, 0xC5, 0x58,
+                                   0xF5, 0x00, 0x19, 0x9D, 0x95, 0xB6, 0xD3, 0xE3,
+                                   0x01, 0x75, 0x85, 0x86, 0x28, 0x1D, 0xCD, 0x26 };
+
+/**
+ * @brief expected SHA3-256 hash for test 02
+   msg = '4A4F202484512526'
+   md_256 = BA4FB009D57A5CEB85FC64D54E5C55A55854B41CC47AD15294BC41F32165DFBA
+   md_384 = 89DBF4C39B8FB46FDF0A6926CEC0355A4BDBF9C6A446E140B7C8BD08FF6F489F
+            205DAF8EFFE160F437F67491EF897C23
+   md_512 = 150D787D6EB49670C2A4CCD17E6CCE7A04C1FE30FCE03D1EF2501752D92AE04C
+            B345FD42E51038C83B2B4F8FD438D1B4B55CC588C6B913132F1A658FB122CB52
+ */
+static const uint8_t m02[] = { 0x4A, 0x4F, 0x20, 0x24, 0x84, 0x51, 0x25, 0x26 };
+size_t m02_len = sizeof(m02);
+static const uint8_t m02_1[] = { 0x4A, 0x4F };
+size_t m02_1_len = sizeof(m02_1);
+static const uint8_t m02_2[] = { 0x20, 0x24, 0x84, 0x51, 0x25, 0x26 };
+size_t m02_2_len = sizeof(m02_2);
+static const uint8_t h02_256[] = { 0xBA, 0x4F, 0xB0, 0x09, 0xD5, 0x7A, 0x5C, 0xEB,
+                                   0x85, 0xFC, 0x64, 0xD5, 0x4E, 0x5C, 0x55, 0xA5,
+                                   0x58, 0x54, 0xB4, 0x1C, 0xC4, 0x7A, 0xD1, 0x52,
+                                   0x94, 0xBC, 0x41, 0xF3, 0x21, 0x65, 0xDF, 0xBA };
+static const uint8_t h02_384[] = { 0x89, 0xDB, 0xF4, 0xC3, 0x9B, 0x8F, 0xB4, 0x6F,
+                                   0xDF, 0x0A, 0x69, 0x26, 0xCE, 0xC0, 0x35, 0x5A,
+                                   0x4B, 0xDB, 0xF9, 0xC6, 0xA4, 0x46, 0xE1, 0x40,
+                                   0xB7, 0xC8, 0xBD, 0x08, 0xFF, 0x6F, 0x48, 0x9F,
+                                   0x20, 0x5D, 0xAF, 0x8E, 0xFF, 0xE1, 0x60, 0xF4,
+                                   0x37, 0xF6, 0x74, 0x91, 0xEF, 0x89, 0x7C, 0x23 };
+static const uint8_t h02_512[] = { 0x15, 0x0D, 0x78, 0x7D, 0x6E, 0xB4, 0x96, 0x70,
+                                   0xC2, 0xA4, 0xCC, 0xD1, 0x7E, 0x6C, 0xCE, 0x7A,
+                                   0x04, 0xC1, 0xFE, 0x30, 0xFC, 0xE0, 0x3D, 0x1E,
+                                   0xF2, 0x50, 0x17, 0x52, 0xD9, 0x2A, 0xE0, 0x4C,
+                                   0xB3, 0x45, 0xFD, 0x42, 0xE5, 0x10, 0x38, 0xC8,
+                                   0x3B, 0x2B, 0x4F, 0x8F, 0xD4, 0x38, 0xD1, 0xB4,
+                                   0xB5, 0x5C, 0xC5, 0x88, 0xC6, 0xB9, 0x13, 0x13,
+                                   0x2F, 0x1A, 0x65, 0x8F, 0xB1, 0x22, 0xCB, 0x52 };
+
+/* @brief expected SHA3-256 hash for test 03
+   msg = '2B6DB7CED8665EBE9DEB080295218426BDAA7C6DA9ADD2088932CDFFBAA1C14129
+          BCCDD70F369EFB149285858D2B1D155D14DE2FDB680A8B027284055182A0CAE275
+          234CC9C92863C1B4AB66F304CF0621CD54565F5BFF461D3B461BD40DF28198E373
+          2501B4860EADD503D26D6E69338F4E0456E9E9BAF3D827AE685FB1D817'
+   md_256 = B7D031AA69B7B4D26A35B896D761314F1D61EB12DCC1E72AAF61B9CD48003AF9
+   md_384 = 8FD01909381EB713803419361D8E82E92476A08EDCC225BB8A135D215CB48D07
+            B074624FCF2E73E666DBA59334719839
+   md_512 = 4FAB45806B4628068458B5D0A2D4BF101B8BFC9276EF86AD5D883765C43F72CE
+            8A5F7B4C5B535A915130BB185E699AB62228014E54DF790C0E93AADBE7E39E19
+ */
+static const uint8_t m03[] = { 0x2B, 0x6D, 0xB7, 0xCE, 0xD8, 0x66, 0x5E, 0xBE, 0x9D,
+                               0xEB, 0x08, 0x02, 0x95, 0x21, 0x84, 0x26, 0xBD, 0xAA,
+                               0x7C, 0x6D, 0xA9, 0xAD, 0xD2, 0x08, 0x89, 0x32, 0xCD,
+                               0xFF, 0xBA, 0xA1, 0xC1, 0x41, 0x29, 0xBC, 0xCD, 0xD7,
+                               0x0F, 0x36, 0x9E, 0xFB, 0x14, 0x92, 0x85, 0x85, 0x8D,
+                               0x2B, 0x1D, 0x15, 0x5D, 0x14, 0xDE, 0x2F, 0xDB, 0x68,
+                               0x0A, 0x8B, 0x02, 0x72, 0x84, 0x05, 0x51, 0x82, 0xA0,
+                               0xCA, 0xE2, 0x75, 0x23, 0x4C, 0xC9, 0xC9, 0x28, 0x63,
+                               0xC1, 0xB4, 0xAB, 0x66, 0xF3, 0x04, 0xCF, 0x06, 0x21,
+                               0xCD, 0x54, 0x56, 0x5F, 0x5B, 0xFF, 0x46, 0x1D, 0x3B,
+                               0x46, 0x1B, 0xD4, 0x0D, 0xF2, 0x81, 0x98, 0xE3, 0x73,
+                               0x25, 0x01, 0xB4, 0x86, 0x0E, 0xAD, 0xD5, 0x03, 0xD2,
+                               0x6D, 0x6E, 0x69, 0x33, 0x8F, 0x4E, 0x04, 0x56, 0xE9,
+                               0xE9, 0xBA, 0xF3, 0xD8, 0x27, 0xAE, 0x68, 0x5F, 0xB1,
+                               0xD8, 0x17 };
+const size_t m03_len = sizeof(m03);
+static const uint8_t m03_1[] = { 0x2B, 0x6D, 0xB7, 0xCE, 0xD8, 0x66, 0x5E, 0xBE, 0x9D,
+                                 0xEB, 0x08, 0x02, 0x95, 0x21, 0x84, 0x26, 0xBD };
+size_t m03_1_len = sizeof(m03_1);
+static const uint8_t m03_2[] = { 0xAA, 0x7C, 0x6D, 0xA9, 0xAD, 0xD2, 0x08, 0x89, 0x32,
+                                 0xCD, 0xFF, 0xBA, 0xA1, 0xC1, 0x41, 0x29, 0xBC, 0xCD,
+                                 0xD7, 0x0F, 0x36, 0x9E, 0xFB, 0x14, 0x92, 0x85, 0x85,
+                                 0x8D, 0x2B, 0x1D, 0x15, 0x5D, 0x14, 0xDE, 0x2F, 0xDB,
+                                 0x68, 0x0A, 0x8B, 0x02, 0x72, 0x84, 0x05, 0x51, 0x82,
+                                 0xA0, 0xCA, 0xE2, 0x75, 0x23, 0x4C, 0xC9, 0xC9, 0x28,
+                                 0x63, 0xC1, 0xB4, 0xAB, 0x66, 0xF3, 0x04, 0xCF, 0x06,
+                                 0x21, 0xCD, 0x54, 0x56, 0x5F, 0x5B, 0xFF, 0x46, 0x1D,
+                                 0x3B, 0x46, 0x1B, 0xD4, 0x0D, 0xF2, 0x81, 0x98, 0xE3,
+                                 0x73, 0x25, 0x01, 0xB4, 0x86, 0x0E, 0xAD, 0xD5, 0x03,
+                                 0xD2, 0x6D, 0x6E, 0x69, 0x33, 0x8F, 0x4E, 0x04, 0x56,
+                                 0xE9, 0xE9, 0xBA, 0xF3, 0xD8, 0x27, 0xAE, 0x68, 0x5F,
+                                 0xB1, 0xD8, 0x17 };
+size_t m03_2_len = sizeof(m03_2);
+
+
+static const uint8_t h03_256[] = { 0xB7, 0xD0, 0x31, 0xAA, 0x69, 0xB7, 0xB4, 0xD2,
+                                   0x6A, 0x35, 0xB8, 0x96, 0xD7, 0x61, 0x31, 0x4F,
+                                   0x1D, 0x61, 0xEB, 0x12, 0xDC, 0xC1, 0xE7, 0x2A,
+                                   0xAF, 0x61, 0xB9, 0xCD, 0x48, 0x00, 0x3A, 0xF9 };
+static const uint8_t h03_384[] = { 0x8F, 0xD0, 0x19, 0x09, 0x38, 0x1E, 0xB7, 0x13,
+                                   0x80, 0x34, 0x19, 0x36, 0x1D, 0x8E, 0x82, 0xE9,
+                                   0x24, 0x76, 0xA0, 0x8E, 0xDC, 0xC2, 0x25, 0xBB,
+                                   0x8A, 0x13, 0x5D, 0x21, 0x5C, 0xB4, 0x8D, 0x07,
+                                   0xB0, 0x74, 0x62, 0x4F, 0xCF, 0x2E, 0x73, 0xE6,
+                                   0x66, 0xDB, 0xA5, 0x93, 0x34, 0x71, 0x98, 0x39 };
+static const uint8_t h03_512[] = { 0x4F, 0xAB, 0x45, 0x80, 0x6B, 0x46, 0x28, 0x06,
+                                   0x84, 0x58, 0xB5, 0xD0, 0xA2, 0xD4, 0xBF, 0x10,
+                                   0x1B, 0x8B, 0xFC, 0x92, 0x76, 0xEF, 0x86, 0xAD,
+                                   0x5D, 0x88, 0x37, 0x65, 0xC4, 0x3F, 0x72, 0xCE,
+                                   0x8A, 0x5F, 0x7B, 0x4C, 0x5B, 0x53, 0x5A, 0x91,
+                                   0x51, 0x30, 0xBB, 0x18, 0x5E, 0x69, 0x9A, 0xB6,
+                                   0x22, 0x28, 0x01, 0x4E, 0x54, 0xDF, 0x79, 0x0C,
+                                   0x0E, 0x93, 0xAA, 0xDB, 0xE7, 0xE3, 0x9E, 0x19 };
+
+/* @brief expected SHA3-256 hash for test 04
+   msg = '3A3A819C48EFDE2AD914FBF00E18AB6BC4F14513AB27D0C178A188B61431E7F562
+          3CB66B23346775D386B50E982C493ADBBFC54B9A3CD383382336A1A0B2150A1535
+          8F336D03AE18F666C7573D55C4FD181C29E6CCFDE63EA35F0ADF5885CFC0A3D84A
+          2B2E4DD24496DB789E663170CEF74798AA1BBCD4574EA0BBA40489D764B2F83AAD
+          C66B148B4A0CD95246C127D5871C4F11418690A5DDF01246A0C80A43C70088B618
+          3639DCFDA4125BD113A8F49EE23ED306FAAC576C3FB0C1E256671D817FC2534A52
+          F5B439F72E424DE376F4C565CCA82307DD9EF76DA5B7C4EB7E085172E328807C02
+          D011FFBF33785378D79DC266F6A5BE6BB0E4A92ECEEBAEB1'
+   md_256 = C11F3522A8FB7B3532D80B6D40023A92B489ADDAD93BF5D64B23F35E9663521C
+   md_384 = 128DC611762BE9B135B3739484CFAADCA7481D68514F3DFD6F5D78BB1863AE68
+            130835CDC7061A7ED964B32F1DB75EE1
+   md_512 = 6E8B8BD195BDD560689AF2348BDC74AB7CD05ED8B9A57711E9BE71E9726FDA45
+            91FEE12205EDACAF82FFBBAF16DFF9E702A708862080166C2FF6BA379BC7FFC2
+ */
+static const uint8_t m04[] = { 0x3A, 0x3A, 0x81, 0x9C, 0x48, 0xEF, 0xDE, 0x2A,
+                               0xD9, 0x14, 0xFB, 0xF0, 0x0E, 0x18, 0xAB, 0x6B,
+                               0xC4, 0xF1, 0x45, 0x13, 0xAB, 0x27, 0xD0, 0xC1,
+                               0x78, 0xA1, 0x88, 0xB6, 0x14, 0x31, 0xE7, 0xF5,
+                               0x62, 0x3C, 0xB6, 0x6B, 0x23, 0x34, 0x67, 0x75,
+                               0xD3, 0x86, 0xB5, 0x0E, 0x98, 0x2C, 0x49, 0x3A,
+                               0xDB, 0xBF, 0xC5, 0x4B, 0x9A, 0x3C, 0xD3, 0x83,
+                               0x38, 0x23, 0x36, 0xA1, 0xA0, 0xB2, 0x15, 0x0A,
+                               0x15, 0x35, 0x8F, 0x33, 0x6D, 0x03, 0xAE, 0x18,
+                               0xF6, 0x66, 0xC7, 0x57, 0x3D, 0x55, 0xC4, 0xFD,
+                               0x18, 0x1C, 0x29, 0xE6, 0xCC, 0xFD, 0xE6, 0x3E,
+                               0xA3, 0x5F, 0x0A, 0xDF, 0x58, 0x85, 0xCF, 0xC0,
+                               0xA3, 0xD8, 0x4A, 0x2B, 0x2E, 0x4D, 0xD2, 0x44,
+                               0x96, 0xDB, 0x78, 0x9E, 0x66, 0x31, 0x70, 0xCE,
+                               0xF7, 0x47, 0x98, 0xAA, 0x1B, 0xBC, 0xD4, 0x57,
+                               0x4E, 0xA0, 0xBB, 0xA4, 0x04, 0x89, 0xD7, 0x64,
+                               0xB2, 0xF8, 0x3A, 0xAD, 0xC6, 0x6B, 0x14, 0x8B,
+                               0x4A, 0x0C, 0xD9, 0x52, 0x46, 0xC1, 0x27, 0xD5,
+                               0x87, 0x1C, 0x4F, 0x11, 0x41, 0x86, 0x90, 0xA5,
+                               0xDD, 0xF0, 0x12, 0x46, 0xA0, 0xC8, 0x0A, 0x43,
+                               0xC7, 0x00, 0x88, 0xB6, 0x18, 0x36, 0x39, 0xDC,
+                               0xFD, 0xA4, 0x12, 0x5B, 0xD1, 0x13, 0xA8, 0xF4,
+                               0x9E, 0xE2, 0x3E, 0xD3, 0x06, 0xFA, 0xAC, 0x57,
+                               0x6C, 0x3F, 0xB0, 0xC1, 0xE2, 0x56, 0x67, 0x1D,
+                               0x81, 0x7F, 0xC2, 0x53, 0x4A, 0x52, 0xF5, 0xB4,
+                               0x39, 0xF7, 0x2E, 0x42, 0x4D, 0xE3, 0x76, 0xF4,
+                               0xC5, 0x65, 0xCC, 0xA8, 0x23, 0x07, 0xDD, 0x9E,
+                               0xF7, 0x6D, 0xA5, 0xB7, 0xC4, 0xEB, 0x7E, 0x08,
+                               0x51, 0x72, 0xE3, 0x28, 0x80, 0x7C, 0x02, 0xD0,
+                               0x11, 0xFF, 0xBF, 0x33, 0x78, 0x53, 0x78, 0xD7,
+                               0x9D, 0xC2, 0x66, 0xF6, 0xA5, 0xBE, 0x6B, 0xB0,
+                               0xE4, 0xA9, 0x2E, 0xCE, 0xEB, 0xAE, 0xB1 };
+size_t m04_len = sizeof(m04);
+static const uint8_t m04_1[] = { 0x3A, 0x3A, 0x81, 0x9C, 0x48, 0xEF, 0xDE, 0x2A,
+                                 0xD9, 0x14, 0xFB, 0xF0, 0x0E, 0x18, 0xAB, 0x6B,
+                                 0xC4, 0xF1, 0x45, 0x13, 0xAB, 0x27, 0xD0, 0xC1,
+                                 0x78, 0xA1, 0x88, 0xB6, 0x14, 0x31, 0xE7, 0xF5,
+                                 0x62, 0x3C, 0xB6, 0x6B, 0x23, 0x34, 0x67, 0x75,
+                                 0xD3, 0x86, 0xB5, 0x0E, 0x98, 0x2C, 0x49, 0x3A,
+                                 0xDB, 0xBF, 0xC5, 0x4B, 0x9A, 0x3C, 0xD3, 0x83,
+                                 0x38, 0x23, 0x36, 0xA1, 0xA0, 0xB2, 0x15, 0x0A,
+                                 0x15, 0x35, 0x8F, 0x33, 0x6D, 0x03, 0xAE, 0x18,
+                                 0xF6, 0x66, 0xC7, 0x57, 0x3D, 0x55, 0xC4, 0xFD,
+                                 0x18, 0x1C, 0x29, 0xE6, 0xCC, 0xFD, 0xE6, 0x3E,
+                                 0xA3, 0x5F, 0x0A, 0xDF, 0x58, 0x85, 0xCF, 0xC0,
+                                 0xA3, 0xD8, 0x4A, 0x2B, 0x2E, 0x4D, 0xD2, 0x44,
+                                 0x96, 0xDB, 0x78, 0x9E, 0x66, 0x31, 0x70, 0xCE,
+                                 0xF7, 0x47, 0x98, 0xAA, 0x1B, 0xBC, 0xD4, 0x57,
+                                 0x4E, 0xA0, 0xBB, 0xA4, 0x04, 0x89, 0xD7, 0x64,
+                                 0xB2, 0xF8, 0x3A, 0xAD, 0xC6, 0x6B, 0x14, 0x8B,
+                                 0x4A, 0x0C, 0xD9, 0x52, 0x46, 0xC1, 0x27, 0xD5,
+                                 0x87, 0x1C, 0x4F, 0x11, 0x41, 0x86, 0x90, 0xA5,
+                                 0xDD, 0xF0, 0x12, 0x46, 0xA0, 0xC8, 0x0A, 0x43,
+                                 0xC7, 0x00, 0x88, 0xB6, 0x18, 0x36, 0x39, 0xDC,
+                                 0xFD, 0xA4, 0x12, 0x5B, 0xD1, 0x13, 0xA8, 0xF4,
+                                 0x9E, 0xE2, 0x3E, 0xD3, 0x06, 0xFA, 0xAC, 0x57,
+                                 0x6C, 0x3F, 0xB0, 0xC1, 0xE2, 0x56, 0x67, 0x1D,
+                                 0x81, 0x7F, 0xC2, 0x53, 0x4A, 0x52, 0xF5, 0xB4,
+                                 0x39, 0xF7, 0x2E, 0x42, 0x4D, 0xE3, 0x76, 0xF4,
+                                 0xC5, 0x65, 0xCC, 0xA8, 0x23, 0x07, 0xDD, 0x9E,
+                                 0xF7, 0x6D, 0xA5, 0xB7, 0xC4, 0xEB, 0x7E, 0x08,
+                                 0x51, 0x72, 0xE3, 0x28, 0x80, 0x7C, 0x02, 0xD0,
+                                 0x11, 0xFF, 0xBF, 0x33, 0x78, 0x53, 0x78, 0xD7,
+                                 0x9D, 0xC2, 0x66, 0xF6, 0xA5, 0xBE, 0x6B, 0xB0 };
+
+size_t m04_1_len = sizeof(m04_1);
+static const uint8_t m04_2[] = { 0xE4, 0xA9, 0x2E, 0xCE, 0xEB, 0xAE, 0xB1 };
+size_t m04_2_len = sizeof(m04_2);
+
+static const uint8_t h04_256[] = { 0xC1, 0x1F, 0x35, 0x22, 0xA8, 0xFB, 0x7B, 0x35,
+                                   0x32, 0xD8, 0x0B, 0x6D, 0x40, 0x02, 0x3A, 0x92,
+                                   0xB4, 0x89, 0xAD, 0xDA, 0xD9, 0x3B, 0xF5, 0xD6,
+                                   0x4B, 0x23, 0xF3, 0x5E, 0x96, 0x63, 0x52, 0x1C };
+static const uint8_t h04_384[] = { 0x12, 0x8D, 0xC6, 0x11, 0x76, 0x2B, 0xE9, 0xB1,
+                                   0x35, 0xB3, 0x73, 0x94, 0x84, 0xCF, 0xAA, 0xDC,
+                                   0xA7, 0x48, 0x1D, 0x68, 0x51, 0x4F, 0x3D, 0xFD,
+                                   0x6F, 0x5D, 0x78, 0xBB, 0x18, 0x63, 0xAE, 0x68,
+                                   0x13, 0x08, 0x35, 0xCD, 0xC7, 0x06, 0x1A, 0x7E,
+                                   0xD9, 0x64, 0xB3, 0x2F, 0x1D, 0xB7, 0x5E, 0xE1 };
+static const uint8_t h04_512[] = { 0x6E, 0x8B, 0x8B, 0xD1, 0x95, 0xBD, 0xD5, 0x60,
+                                   0x68, 0x9A, 0xF2, 0x34, 0x8B, 0xDC, 0x74, 0xAB,
+                                   0x7C, 0xD0, 0x5E, 0xD8, 0xB9, 0xA5, 0x77, 0x11,
+                                   0xE9, 0xBE, 0x71, 0xE9, 0x72, 0x6F, 0xDA, 0x45,
+                                   0x91, 0xFE, 0xE1, 0x22, 0x05, 0xED, 0xAC, 0xAF,
+                                   0x82, 0xFF, 0xBB, 0xAF, 0x16, 0xDF, 0xF9, 0xE7,
+                                   0x02, 0xA7, 0x08, 0x86, 0x20, 0x80, 0x16, 0x6C,
+                                   0x2F, 0xF6, 0xBA, 0x37, 0x9B, 0xC7, 0xFF, 0xC2 };
+
+static const uint8_t mfail[] = { 0x4A, 0x4F, 0x20, 0x24, 0x84, 0x51, 0x25, 0x27 };
+size_t mfail_len = sizeof(mfail);
+static const uint8_t hfail_256[] = { 0xBA, 0x4F, 0xB0, 0x09, 0xD5, 0x7A, 0x5C, 0xEB,
+                                     0x85, 0xFC, 0x64, 0xD5, 0x4E, 0x5C, 0x55, 0xA5,
+                                     0x58, 0x54, 0xB4, 0x1C, 0xC4, 0x7A, 0xD1, 0x52,
+                                     0x94, 0xBC, 0x41, 0xF3, 0x21, 0x65, 0xDF, 0xBA };
+static const uint8_t hfail_384[] = { 0x89, 0xDB, 0xF4, 0xC3, 0x9B, 0x8F, 0xB4, 0x6F,
+                                     0xDF, 0x0A, 0x69, 0x26, 0xCE, 0xC0, 0x35, 0x5A,
+                                     0x4B, 0xDB, 0xF9, 0xC6, 0xA4, 0x46, 0xE1, 0x40,
+                                     0xB7, 0xC8, 0xBD, 0x08, 0xFF, 0x6F, 0x48, 0x9F,
+                                     0x20, 0x5D, 0xAF, 0x8E, 0xFF, 0xE1, 0x60, 0xF4,
+                                     0x37, 0xF6, 0x74, 0x91, 0xEF, 0x89, 0x7C, 0x23 };
+static const uint8_t hfail_512[] = { 0x15, 0x0D, 0x78, 0x7D, 0x6E, 0xB4, 0x96, 0x70,
+                                     0xC2, 0xA4, 0xCC, 0xD1, 0x7E, 0x6C, 0xCE, 0x7A,
+                                     0x04, 0xC1, 0xFE, 0x30, 0xFC, 0xE0, 0x3D, 0x1E,
+                                     0xF2, 0x50, 0x17, 0x52, 0xD9, 0x2A, 0xE0, 0x4C,
+                                     0xB3, 0x45, 0xFD, 0x42, 0xE5, 0x10, 0x38, 0xC8,
+                                     0x3B, 0x2B, 0x4F, 0x8F, 0xD4, 0x38, 0xD1, 0xB4,
+                                     0xB5, 0x5C, 0xC5, 0x88, 0xC6, 0xB9, 0x13, 0x13,
+                                     0x2F, 0x1A, 0x65, 0x8F, 0xB1, 0x22, 0xCB, 0x52 };
+
+
+static int calc_and_compare_hash_256(const uint8_t *msg, size_t msg_len, const uint8_t *expected)
+{
+    static unsigned char hash[SHA3_256_DIGEST_LENGTH];
+
+    sha3_256(hash, msg, msg_len);
+
+    return (memcmp(expected, hash, sizeof(hash)) == 0);
+}
+
+static int calc_steps_and_compare_hash_256(const uint8_t *msg1, size_t msg1_len,
+                                           const uint8_t *msg2, size_t msg2_len, const uint8_t *expected)
+{
+    static unsigned char hash[SHA3_256_DIGEST_LENGTH];
+    keccak_state_t state;
+
+    sha3_256_init(&state);
+    sha3_update(&state, msg1, msg1_len);
+    sha3_update(&state, msg2, msg2_len);
+    sha3_256_final(&state, hash);
+
+    return (memcmp(expected, hash, sizeof(hash)) == 0);
+}
+
+static int calc_and_compare_hash_384(const uint8_t *msg, size_t msg_len, const uint8_t *expected)
+{
+    static unsigned char hash[SHA3_384_DIGEST_LENGTH];
+
+    sha3_384(hash, msg, msg_len);
+
+    return (memcmp(expected, hash, sizeof(hash)) == 0);
+}
+
+static int calc_steps_and_compare_hash_384(const uint8_t *msg1, size_t msg1_len,
+                                           const uint8_t *msg2, size_t msg2_len, const uint8_t *expected)
+{
+    static unsigned char hash[SHA3_384_DIGEST_LENGTH];
+    keccak_state_t state;
+
+    sha3_384_init(&state);
+    sha3_update(&state, msg1, msg1_len);
+    sha3_update(&state, msg2, msg2_len);
+    sha3_384_final(&state, hash);
+
+    return (memcmp(expected, hash, sizeof(hash)) == 0);
+}
+
+static int calc_and_compare_hash_512(const uint8_t *msg, size_t msg_len, const uint8_t *expected)
+{
+    static unsigned char hash[SHA3_512_DIGEST_LENGTH];
+
+    sha3_512(hash, msg, msg_len);
+
+    return (memcmp(expected, hash, sizeof(hash)) == 0);
+}
+
+static int calc_steps_and_compare_hash_512(const uint8_t *msg1, size_t msg1_len,
+                                           const uint8_t *msg2, size_t msg2_len, const uint8_t *expected)
+{
+    static unsigned char hash[SHA3_512_DIGEST_LENGTH];
+    keccak_state_t state;
+
+    sha3_512_init(&state);
+    sha3_update(&state, msg1, msg1_len);
+    sha3_update(&state, msg2, msg2_len);
+    sha3_512_final(&state, hash);
+
+    return (memcmp(expected, hash, sizeof(hash)) == 0);
+}
+
+static void test_hashes_sha3_hash_sequence_01(void)
+{
+    TEST_ASSERT(calc_and_compare_hash_256(m01, m01_len, h01_256));
+    TEST_ASSERT(calc_steps_and_compare_hash_256(m01_1, m01_1_len, m01_2, m01_2_len, h01_256));
+    TEST_ASSERT(calc_and_compare_hash_384(m01, m01_len, h01_384));
+    TEST_ASSERT(calc_steps_and_compare_hash_384(m01_1, m01_1_len, m01_2, m01_2_len, h01_384));
+    TEST_ASSERT(calc_and_compare_hash_512(m01, m01_len, h01_512));
+    TEST_ASSERT(calc_steps_and_compare_hash_512(m01_1, m01_1_len, m01_2, m01_2_len, h01_512));
+}
+static void test_hashes_sha3_hash_sequence_02(void)
+{
+    TEST_ASSERT(calc_and_compare_hash_256(m02, m02_len, h02_256));
+    TEST_ASSERT(calc_steps_and_compare_hash_256(m02_1, m02_1_len, m02_2, m02_2_len, h02_256));
+    TEST_ASSERT(calc_and_compare_hash_384(m02, m02_len, h02_384));
+    TEST_ASSERT(calc_steps_and_compare_hash_384(m02_1, m02_1_len, m02_2, m02_2_len, h02_384));
+    TEST_ASSERT(calc_and_compare_hash_512(m02, m02_len, h02_512));
+    TEST_ASSERT(calc_steps_and_compare_hash_512(m02_1, m02_1_len, m02_2, m02_2_len, h02_512));
+}
+
+static void test_hashes_sha3_hash_sequence_03(void)
+{
+    TEST_ASSERT(calc_and_compare_hash_256(m03, m03_len, h03_256));
+    TEST_ASSERT(calc_steps_and_compare_hash_256(m03_1, m03_1_len, m03_2, m03_2_len, h03_256));
+    TEST_ASSERT(calc_and_compare_hash_384(m03, m03_len, h03_384));
+    TEST_ASSERT(calc_steps_and_compare_hash_384(m03_1, m03_1_len, m03_2, m03_2_len, h03_384));
+    TEST_ASSERT(calc_and_compare_hash_512(m03, m03_len, h03_512));
+    TEST_ASSERT(calc_steps_and_compare_hash_512(m03_1, m03_1_len, m03_2, m03_2_len, h03_512));
+}
+
+static void test_hashes_sha3_hash_sequence_04(void)
+{
+    TEST_ASSERT(calc_and_compare_hash_256(m04, m04_len, h04_256));
+    TEST_ASSERT(calc_steps_and_compare_hash_256(m04_1, m04_1_len, m04_2, m04_2_len, h04_256));
+    TEST_ASSERT(calc_and_compare_hash_384(m04, m04_len, h04_384));
+    TEST_ASSERT(calc_steps_and_compare_hash_384(m04_1, m04_1_len, m04_2, m04_2_len, h04_384));
+    TEST_ASSERT(calc_and_compare_hash_512(m04, m04_len, h04_512));
+    TEST_ASSERT(calc_steps_and_compare_hash_512(m04_1, m04_1_len, m04_2, m04_2_len, h04_512));
+}
+
+static void test_hashes_sha3_hash_sequence_failing_compare(void)
+{
+    /* failing compare (message from testcase 02 alterered slightly) */
+    TEST_ASSERT(!calc_and_compare_hash_256(mfail, mfail_len, hfail_256));
+    TEST_ASSERT(!calc_and_compare_hash_384(mfail, mfail_len, hfail_384));
+    TEST_ASSERT(!calc_and_compare_hash_512(mfail, mfail_len, hfail_512));
+}
+
+
+Test *tests_hashes_sha3_tests(void)
+{
+    EMB_UNIT_TESTFIXTURES(fixtures) {
+        new_TestFixture(test_hashes_sha3_hash_sequence_01),
+        new_TestFixture(test_hashes_sha3_hash_sequence_02),
+        new_TestFixture(test_hashes_sha3_hash_sequence_03),
+        new_TestFixture(test_hashes_sha3_hash_sequence_04),
+        new_TestFixture(test_hashes_sha3_hash_sequence_failing_compare),
+    };
+
+    EMB_UNIT_TESTCALLER(hashes_sha3_tests, NULL, NULL,
+                        fixtures);
+
+    return (Test *)&hashes_sha3_tests;
+}
diff --git a/tests/unittests/tests-hashes/tests-hashes.c b/tests/unittests/tests-hashes/tests-hashes.c
index aec41907d9..a815c58043 100644
--- a/tests/unittests/tests-hashes/tests-hashes.c
+++ b/tests/unittests/tests-hashes/tests-hashes.c
@@ -28,4 +28,5 @@ void tests_hashes(void)
     TESTS_RUN(tests_hashes_sha256_tests());
     TESTS_RUN(tests_hashes_sha256_hmac_tests());
     TESTS_RUN(tests_hashes_sha256_chain_tests());
+    TESTS_RUN(tests_hashes_sha3_tests());
 }
diff --git a/tests/unittests/tests-hashes/tests-hashes.h b/tests/unittests/tests-hashes/tests-hashes.h
index f72c4f9441..19a0d20ad4 100644
--- a/tests/unittests/tests-hashes/tests-hashes.h
+++ b/tests/unittests/tests-hashes/tests-hashes.h
@@ -72,6 +72,13 @@ Test *tests_hashes_sha256_hmac_tests(void);
  */
 Test *tests_hashes_sha256_chain_tests(void);
 
+  /**
+ * @brief   Generates tests for hashes/sha3.h
+ *
+ * @return  embUnit tests if successful, NULL if not.
+ */
+Test *tests_hashes_sha3_tests(void);
+
 #ifdef __cplusplus
 }
 #endif
-- 
GitLab