Browse Source

change hash from K12 to FIPS202

Duc Nguyen 2 years ago
parent
commit
94de470802
9 changed files with 488 additions and 42 deletions
  1. 1 1
      include/decapsulation.h
  2. 1 1
      include/encapsulation.h
  3. 12 0
      include/fips202.h
  4. 1 1
      include/parameters/param.h
  5. 2 2
      makefile
  6. 12 18
      src/decapsulation.c
  7. 3 3
      src/decoding.c
  8. 11 16
      src/encapsulation.c
  9. 445 0
      src/fips202.c

+ 1 - 1
include/decapsulation.h

@@ -10,7 +10,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <keccak/KangarooTwelve.h>
+#include "fips202.h"
 
 
 #include "structures/matrix_operations.h"

+ 1 - 1
include/encapsulation.h

@@ -8,7 +8,7 @@
 #ifndef INCLUDE_ENCAPSULATION_H_
 #define INCLUDE_ENCAPSULATION_H_
 
-#include <keccak/KangarooTwelve.h>
+#include "fips202.h"
 
 #include "util/util.h"
 #include "structures/matrix_operations.h"

+ 12 - 0
include/fips202.h

@@ -0,0 +1,12 @@
+#ifndef FIPS202_H
+#define FIPS202_H
+
+#include <stdint.h>
+
+#define SHAKE128_RATE 168
+#define SHAKE256_RATE 136
+
+void shake128(unsigned char *output, unsigned long long outlen, const unsigned char *input,  unsigned long long inlen);
+void shake256(unsigned char *output, unsigned long long outlen, const unsigned char *input,  unsigned long long inlen);
+
+#endif

+ 1 - 1
include/parameters/param.h

@@ -17,7 +17,7 @@
 #endif
 
 #define extension 2 //m
-#define field_extension field*extension //
+#define field_extension (field*extension) //
 
 #define F_q_m_size (1 << field_extension) // #F_q_m
 

+ 2 - 2
makefile

@@ -14,10 +14,10 @@ DAGSVER=-DDAGS_3
 
 #clang CFLAGS
 #CFLAGS=-O3 -g3 -Wall -ffunction-sections -fdata-sections -march=native -DDEBUG
-CFLAGS=-O3 -g3 -Wall -ffunction-sections -fdata-sections -march=native -mtune=native
+CFLAGS=-O3 -g3 -Wall -ffunction-sections -fdata-sections -march=native -mtune=native -fomit-frame-pointer
 #CFLAGS=-O3 -g3 -Wall -DDEBUG
 #CFLAGS=-O3 -g3 -Wall
-LIBS=-lcrypto -lm -lsodium -lkeccak
+LIBS=-lcrypto -lm -lsodium
 # All of the sources participating in the build are defined here
 -include sources.mk
 -include src/util/subdir.mk

+ 12 - 18
src/decapsulation.c

@@ -68,18 +68,15 @@ int decrypt(unsigned char *secret_shared, const unsigned char *cipher_text,
 	 * Step_4 of the decapsulation :  Compute r1 = G(m1) and d1 = H(m1)
 	 */
 
-	//KangarooTwelve(m1, k_prime, r1, code_dimension, K12_custom, K12_custom_len);
-	//SHAKE256(r1, code_dimension, m1, k_prime);
-	check_return = KangarooTwelve(m1, k_prime, r1, code_dimension, K12_custom, K12_custom_len);
-	assert(check_return == 0); // Catch Error
-
+	
+	shake128(r1, code_dimension, m1, k_prime);
+	
 	// Compute d1 = H(m1) where H is  sponge SHA-512 function
 
-	check_return = KangarooTwelve(m1, k_prime, d1, k_prime, K12_custom, K12_custom_len);
-	assert(check_return == 0); // Catch Error
-
+	shake128(d1, k_prime, m1, k_prime);
+	
 	for (i = 0; i < k_prime; i++) {
-		d1[i] = d1[i] % F_q_size;
+		d1[i] = d1[i] & (F_q_size - 1);
 	}
 	// Return -1 if d distinct d1.
 	// d starts at ct+code_length.
@@ -93,10 +90,10 @@ int decrypt(unsigned char *secret_shared, const unsigned char *cipher_text,
 	for (i = 0; i < code_dimension; i++) {
 		if (i < k_sec) {
 			// Optimize modulo
-			rho2[i] = r1[i] % F_q_size; //rho2 recovery
+			rho2[i] = r1[i] & (F_q_size - 1); //rho2 recovery
 		} else {
 			// Optimize modulo
-			sigma[i - k_sec] = r1[i] % F_q_size; // sigma1 recovery
+			sigma[i - k_sec] = r1[i] & (F_q_size - 1); // sigma1 recovery
 		}
 	}
 
@@ -112,10 +109,8 @@ int decrypt(unsigned char *secret_shared, const unsigned char *cipher_text,
 
 	//test = KangarooTwelve(sigma, k_prime, hash_sigma, code_length, K12_custom, K12_custom_len);
 	//SHAKE256(hash_sigma, code_length, sigma, k_prime);
-	check_return = KangarooTwelve(sigma, k_prime, hash_sigma, code_length, K12_custom,
-	K12_custom_len);
-	assert(check_return == 0); // Catch Error
-
+	shake128(hash_sigma, code_length, sigma, k_prime);
+	
 	//Generate error vector e2 of length code_length and weight n0_w from
 	//hash_sigma1 by using random_e function.
 	random_e(hash_sigma, e2);
@@ -133,8 +128,7 @@ int decrypt(unsigned char *secret_shared, const unsigned char *cipher_text,
 	 */
 	//test = KangarooTwelve(m1, k_prime, ss, ss_length, K12_custom, K12_custom_len);
 	//SHAKE256(secret_shared, ss_length, m1, k_prime);
-	check_return = KangarooTwelve(m1, k_prime, secret_shared, ss_length, K12_custom, K12_custom_len);
-	assert(check_return == 0); // Catch Error
-
+	shake128(secret_shared, ss_length, m1, k_prime);
+	
 	return 0;
 }

+ 3 - 3
src/decoding.c

@@ -19,9 +19,9 @@ int decoding(const gf* v, const gf* y, const unsigned char *c,
 	int i, k, j, dr, position;
 	int st = (signature_block_size * pol_deg);
 	polynomial *syndrom;
-	polynomial *omega, *sigma, *re, *uu, *u, *quotient, *rest, *app, *temp,
-			*temp_sum;
-	polynomial *delta, *pos;
+	polynomial *omega, *sigma, *re, *uu, *u, *quotient;
+	polynomial *rest, *app, *temp, *temp_sum,*delta, *pos;
+	
 	gf pol_gf, tmp, tmp1, o;
 	gf alpha;
 

+ 11 - 16
src/encapsulation.c

@@ -65,20 +65,17 @@ int encrypt(unsigned char *ciphert_text, unsigned char *secret_shared,
 	}
 	PRINT_DEBUG_ENCAP("\nStarting hashing: \n");
 #endif
-	int test = KangarooTwelve(m, k_prime, r, code_dimension, K12_custom, K12_custom_len);
-	assert(test == 0); // Catch Error
-
-	// m: input type unsigned char len k_prime | d: output type unsigned char len k_prime
-	test = KangarooTwelve(m, k_prime, d, k_prime, K12_custom, K12_custom_len);
-	assert(test == 0); // Catch Error
-
+	
+	shake128(r, code_dimension, m, k_prime);
+	shake128(d, k_prime, m, k_prime);
+	
 	// Type conversion
 	if (F_q_size < UCHAR_MAX) {
 		for (i = 0; i < k_prime; i++) {
-			d[i] = d[i] % F_q_size;
+			d[i] = d[i] & (F_q_size - 1);
 		}
 		for (i = 0; i < code_dimension; i++) {
-			r[i] = r[i] % F_q_size;
+			r[i] = r[i] & (F_q_size - 1);
 		}
 	}
 
@@ -89,10 +86,9 @@ int encrypt(unsigned char *ciphert_text, unsigned char *secret_shared,
 	memcpy(&u[k_sec], m, code_dimension - k_sec);
 
 	PRINT_DEBUG_ENCAP("Generating error_array: \n");
-	/*SHAKE256(hash_sigma, code_length, sigma, k_prime);*/
-	test = KangarooTwelve(sigma, k_prime, hash_sigma, code_length, K12_custom,
-	K12_custom_len);
-	assert(test == 0); // Catch Error
+	
+	shake128(hash_sigma, code_length, sigma, k_prime);
+	
 	random_e(hash_sigma, error_array);
 
 #ifdef DEBUG_ENCAP
@@ -121,9 +117,8 @@ int encrypt(unsigned char *ciphert_text, unsigned char *secret_shared,
 	PRINT_DEBUG_ENCAP("|\nHashing (m*G) + error: \n");
 #endif
 	//SHAKE256(K, ss_length, m, k_prime);
-	test = KangarooTwelve(m, k_prime, K, ss_length, K12_custom, K12_custom_len);
-	assert(test == 0); // Catch Error
-
+	shake128(K, ss_length, m, k_prime);
+	
 	memcpy(secret_shared, K, ss_length);
 	return EXIT_SUCCESS;
 }

+ 445 - 0
src/fips202.c

@@ -0,0 +1,445 @@
+/* Based on the public domain implementation in
+ * crypto_hash/keccakc512/simple/ from http://bench.cr.yp.to/supercop.html
+ * by Ronny Van Keer 
+ * and the public domain "TweetFips202" implementation
+ * from https://twitter.com/tweetfips202
+ * by Gilles Van Assche, Daniel J. Bernstein, and Peter Schwabe */
+
+#include <stdint.h>
+#include <assert.h>
+#include "../include/fips202.h"
+
+#define NROUNDS 24
+#define ROL(a, offset) ((a << offset) ^ (a >> (64-offset)))
+
+static uint64_t load64(const unsigned char *x)
+{
+  unsigned long long r = 0, i;
+
+  for (i = 0; i < 8; ++i) {
+    r |= (unsigned long long)x[i] << 8 * i;
+  }
+  return r;
+}
+
+static void store64(uint8_t *x, uint64_t u)
+{
+  unsigned int i;
+
+  for(i=0; i<8; ++i) {
+    x[i] = u;
+    u >>= 8;
+  }
+}
+
+static const uint64_t KeccakF_RoundConstants[NROUNDS] = 
+{
+    (uint64_t)0x0000000000000001ULL,
+    (uint64_t)0x0000000000008082ULL,
+    (uint64_t)0x800000000000808aULL,
+    (uint64_t)0x8000000080008000ULL,
+    (uint64_t)0x000000000000808bULL,
+    (uint64_t)0x0000000080000001ULL,
+    (uint64_t)0x8000000080008081ULL,
+    (uint64_t)0x8000000000008009ULL,
+    (uint64_t)0x000000000000008aULL,
+    (uint64_t)0x0000000000000088ULL,
+    (uint64_t)0x0000000080008009ULL,
+    (uint64_t)0x000000008000000aULL,
+    (uint64_t)0x000000008000808bULL,
+    (uint64_t)0x800000000000008bULL,
+    (uint64_t)0x8000000000008089ULL,
+    (uint64_t)0x8000000000008003ULL,
+    (uint64_t)0x8000000000008002ULL,
+    (uint64_t)0x8000000000000080ULL,
+    (uint64_t)0x000000000000800aULL,
+    (uint64_t)0x800000008000000aULL,
+    (uint64_t)0x8000000080008081ULL,
+    (uint64_t)0x8000000000008080ULL,
+    (uint64_t)0x0000000080000001ULL,
+    (uint64_t)0x8000000080008008ULL
+};
+
+void KeccakF1600_StatePermute(uint64_t * state)
+{
+  int round;
+
+        uint64_t Aba, Abe, Abi, Abo, Abu;
+        uint64_t Aga, Age, Agi, Ago, Agu;
+        uint64_t Aka, Ake, Aki, Ako, Aku;
+        uint64_t Ama, Ame, Ami, Amo, Amu;
+        uint64_t Asa, Ase, Asi, Aso, Asu;
+        uint64_t BCa, BCe, BCi, BCo, BCu;
+        uint64_t Da, De, Di, Do, Du;
+        uint64_t Eba, Ebe, Ebi, Ebo, Ebu;
+        uint64_t Ega, Ege, Egi, Ego, Egu;
+        uint64_t Eka, Eke, Eki, Eko, Eku;
+        uint64_t Ema, Eme, Emi, Emo, Emu;
+        uint64_t Esa, Ese, Esi, Eso, Esu;
+
+        //copyFromState(A, state)
+        Aba = state[ 0];
+        Abe = state[ 1];
+        Abi = state[ 2];
+        Abo = state[ 3];
+        Abu = state[ 4];
+        Aga = state[ 5];
+        Age = state[ 6];
+        Agi = state[ 7];
+        Ago = state[ 8];
+        Agu = state[ 9];
+        Aka = state[10];
+        Ake = state[11];
+        Aki = state[12];
+        Ako = state[13];
+        Aku = state[14];
+        Ama = state[15];
+        Ame = state[16];
+        Ami = state[17];
+        Amo = state[18];
+        Amu = state[19];
+        Asa = state[20];
+        Ase = state[21];
+        Asi = state[22];
+        Aso = state[23];
+        Asu = state[24];
+
+        for( round = 0; round < NROUNDS; round += 2 )
+        {
+            //    prepareTheta
+            BCa = Aba^Aga^Aka^Ama^Asa;
+            BCe = Abe^Age^Ake^Ame^Ase;
+            BCi = Abi^Agi^Aki^Ami^Asi;
+            BCo = Abo^Ago^Ako^Amo^Aso;
+            BCu = Abu^Agu^Aku^Amu^Asu;
+
+            //thetaRhoPiChiIotaPrepareTheta(round  , A, E)
+            Da = BCu^ROL(BCe, 1);
+            De = BCa^ROL(BCi, 1);
+            Di = BCe^ROL(BCo, 1);
+            Do = BCi^ROL(BCu, 1);
+            Du = BCo^ROL(BCa, 1);
+
+            Aba ^= Da;
+            BCa = Aba;
+            Age ^= De;
+            BCe = ROL(Age, 44);
+            Aki ^= Di;
+            BCi = ROL(Aki, 43);
+            Amo ^= Do;
+            BCo = ROL(Amo, 21);
+            Asu ^= Du;
+            BCu = ROL(Asu, 14);
+            Eba =   BCa ^((~BCe)&  BCi );
+            Eba ^= (uint64_t)KeccakF_RoundConstants[round];
+            Ebe =   BCe ^((~BCi)&  BCo );
+            Ebi =   BCi ^((~BCo)&  BCu );
+            Ebo =   BCo ^((~BCu)&  BCa );
+            Ebu =   BCu ^((~BCa)&  BCe );
+
+            Abo ^= Do;
+            BCa = ROL(Abo, 28);
+            Agu ^= Du;
+            BCe = ROL(Agu, 20);
+            Aka ^= Da;
+            BCi = ROL(Aka,  3);
+            Ame ^= De;
+            BCo = ROL(Ame, 45);
+            Asi ^= Di;
+            BCu = ROL(Asi, 61);
+            Ega =   BCa ^((~BCe)&  BCi );
+            Ege =   BCe ^((~BCi)&  BCo );
+            Egi =   BCi ^((~BCo)&  BCu );
+            Ego =   BCo ^((~BCu)&  BCa );
+            Egu =   BCu ^((~BCa)&  BCe );
+
+            Abe ^= De;
+            BCa = ROL(Abe,  1);
+            Agi ^= Di;
+            BCe = ROL(Agi,  6);
+            Ako ^= Do;
+            BCi = ROL(Ako, 25);
+            Amu ^= Du;
+            BCo = ROL(Amu,  8);
+            Asa ^= Da;
+            BCu = ROL(Asa, 18);
+            Eka =   BCa ^((~BCe)&  BCi );
+            Eke =   BCe ^((~BCi)&  BCo );
+            Eki =   BCi ^((~BCo)&  BCu );
+            Eko =   BCo ^((~BCu)&  BCa );
+            Eku =   BCu ^((~BCa)&  BCe );
+
+            Abu ^= Du;
+            BCa = ROL(Abu, 27);
+            Aga ^= Da;
+            BCe = ROL(Aga, 36);
+            Ake ^= De;
+            BCi = ROL(Ake, 10);
+            Ami ^= Di;
+            BCo = ROL(Ami, 15);
+            Aso ^= Do;
+            BCu = ROL(Aso, 56);
+            Ema =   BCa ^((~BCe)&  BCi );
+            Eme =   BCe ^((~BCi)&  BCo );
+            Emi =   BCi ^((~BCo)&  BCu );
+            Emo =   BCo ^((~BCu)&  BCa );
+            Emu =   BCu ^((~BCa)&  BCe );
+
+            Abi ^= Di;
+            BCa = ROL(Abi, 62);
+            Ago ^= Do;
+            BCe = ROL(Ago, 55);
+            Aku ^= Du;
+            BCi = ROL(Aku, 39);
+            Ama ^= Da;
+            BCo = ROL(Ama, 41);
+            Ase ^= De;
+            BCu = ROL(Ase,  2);
+            Esa =   BCa ^((~BCe)&  BCi );
+            Ese =   BCe ^((~BCi)&  BCo );
+            Esi =   BCi ^((~BCo)&  BCu );
+            Eso =   BCo ^((~BCu)&  BCa );
+            Esu =   BCu ^((~BCa)&  BCe );
+
+            //    prepareTheta
+            BCa = Eba^Ega^Eka^Ema^Esa;
+            BCe = Ebe^Ege^Eke^Eme^Ese;
+            BCi = Ebi^Egi^Eki^Emi^Esi;
+            BCo = Ebo^Ego^Eko^Emo^Eso;
+            BCu = Ebu^Egu^Eku^Emu^Esu;
+
+            //thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
+            Da = BCu^ROL(BCe, 1);
+            De = BCa^ROL(BCi, 1);
+            Di = BCe^ROL(BCo, 1);
+            Do = BCi^ROL(BCu, 1);
+            Du = BCo^ROL(BCa, 1);
+
+            Eba ^= Da;
+            BCa = Eba;
+            Ege ^= De;
+            BCe = ROL(Ege, 44);
+            Eki ^= Di;
+            BCi = ROL(Eki, 43);
+            Emo ^= Do;
+            BCo = ROL(Emo, 21);
+            Esu ^= Du;
+            BCu = ROL(Esu, 14);
+            Aba =   BCa ^((~BCe)&  BCi );
+            Aba ^= (uint64_t)KeccakF_RoundConstants[round+1];
+            Abe =   BCe ^((~BCi)&  BCo );
+            Abi =   BCi ^((~BCo)&  BCu );
+            Abo =   BCo ^((~BCu)&  BCa );
+            Abu =   BCu ^((~BCa)&  BCe );
+
+            Ebo ^= Do;
+            BCa = ROL(Ebo, 28);
+            Egu ^= Du;
+            BCe = ROL(Egu, 20);
+            Eka ^= Da;
+            BCi = ROL(Eka, 3);
+            Eme ^= De;
+            BCo = ROL(Eme, 45);
+            Esi ^= Di;
+            BCu = ROL(Esi, 61);
+            Aga =   BCa ^((~BCe)&  BCi );
+            Age =   BCe ^((~BCi)&  BCo );
+            Agi =   BCi ^((~BCo)&  BCu );
+            Ago =   BCo ^((~BCu)&  BCa );
+            Agu =   BCu ^((~BCa)&  BCe );
+
+            Ebe ^= De;
+            BCa = ROL(Ebe, 1);
+            Egi ^= Di;
+            BCe = ROL(Egi, 6);
+            Eko ^= Do;
+            BCi = ROL(Eko, 25);
+            Emu ^= Du;
+            BCo = ROL(Emu, 8);
+            Esa ^= Da;
+            BCu = ROL(Esa, 18);
+            Aka =   BCa ^((~BCe)&  BCi );
+            Ake =   BCe ^((~BCi)&  BCo );
+            Aki =   BCi ^((~BCo)&  BCu );
+            Ako =   BCo ^((~BCu)&  BCa );
+            Aku =   BCu ^((~BCa)&  BCe );
+
+            Ebu ^= Du;
+            BCa = ROL(Ebu, 27);
+            Ega ^= Da;
+            BCe = ROL(Ega, 36);
+            Eke ^= De;
+            BCi = ROL(Eke, 10);
+            Emi ^= Di;
+            BCo = ROL(Emi, 15);
+            Eso ^= Do;
+            BCu = ROL(Eso, 56);
+            Ama =   BCa ^((~BCe)&  BCi );
+            Ame =   BCe ^((~BCi)&  BCo );
+            Ami =   BCi ^((~BCo)&  BCu );
+            Amo =   BCo ^((~BCu)&  BCa );
+            Amu =   BCu ^((~BCa)&  BCe );
+
+            Ebi ^= Di;
+            BCa = ROL(Ebi, 62);
+            Ego ^= Do;
+            BCe = ROL(Ego, 55);
+            Eku ^= Du;
+            BCi = ROL(Eku, 39);
+            Ema ^= Da;
+            BCo = ROL(Ema, 41);
+            Ese ^= De;
+            BCu = ROL(Ese, 2);
+            Asa =   BCa ^((~BCe)&  BCi );
+            Ase =   BCe ^((~BCi)&  BCo );
+            Asi =   BCi ^((~BCo)&  BCu );
+            Aso =   BCo ^((~BCu)&  BCa );
+            Asu =   BCu ^((~BCa)&  BCe );
+        }
+
+        //copyToState(state, A)
+        state[ 0] = Aba;
+        state[ 1] = Abe;
+        state[ 2] = Abi;
+        state[ 3] = Abo;
+        state[ 4] = Abu;
+        state[ 5] = Aga;
+        state[ 6] = Age;
+        state[ 7] = Agi;
+        state[ 8] = Ago;
+        state[ 9] = Agu;
+        state[10] = Aka;
+        state[11] = Ake;
+        state[12] = Aki;
+        state[13] = Ako;
+        state[14] = Aku;
+        state[15] = Ama;
+        state[16] = Ame;
+        state[17] = Ami;
+        state[18] = Amo;
+        state[19] = Amu;
+        state[20] = Asa;
+        state[21] = Ase;
+        state[22] = Asi;
+        state[23] = Aso;
+        state[24] = Asu;
+
+        #undef    round
+}
+
+#include <string.h>
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+
+static void keccak_absorb(uint64_t *s,
+                          unsigned int r,
+                          const unsigned char *m, unsigned long long int mlen,
+                          unsigned char p)
+{
+  unsigned long long i;
+  unsigned char t[200];
+
+  // Zero state
+  for (i = 0; i < 25; ++i)
+    s[i] = 0;
+ 
+  while (mlen >= r) 
+  {
+    for (i = 0; i < r / 8; ++i)
+      s[i] ^= load64(m + 8 * i);
+    
+    KeccakF1600_StatePermute(s);
+    mlen -= r;
+    m += r;
+  }
+
+  for (i = 0; i < r; ++i)
+    t[i] = 0;
+  for (i = 0; i < mlen; ++i)
+    t[i] = m[i];
+  t[i] = p;
+  t[r - 1] |= 128;
+  for (i = 0; i < r / 8; ++i)
+    s[i] ^= load64(t + 8 * i);
+}
+
+
+static void keccak_squeezeblocks(unsigned char *h, unsigned long long int nblocks,
+                                 uint64_t *s, 
+                                 unsigned int r)
+{
+  unsigned int i;
+  while(nblocks > 0) 
+  {
+    KeccakF1600_StatePermute(s);
+    for(i=0;i<(r>>3);i++)
+    {
+      store64(h+8*i, s[i]);
+    }
+    h += r;
+    nblocks--;
+  }
+}
+
+
+
+
+void shake128_absorb(uint64_t *s, const unsigned char *input, unsigned int inputByteLen)
+{
+  keccak_absorb(s, SHAKE128_RATE, input, inputByteLen, 0x1F);
+}
+
+void shake128_squeezeblocks(unsigned char *output, unsigned long long nblocks, uint64_t *s)
+{
+  keccak_squeezeblocks(output, nblocks, s, SHAKE128_RATE);
+}
+
+void shake256(unsigned char *output, unsigned long long outlen, 
+              const unsigned char *input,  unsigned long long inlen)
+{
+  uint64_t s[25];
+  unsigned char t[SHAKE256_RATE];
+  unsigned long long nblocks = outlen/SHAKE256_RATE;
+  size_t i;
+
+  /* Absorb input */
+  keccak_absorb(s, SHAKE256_RATE, input, inlen, 0x1F);
+
+  /* Squeeze output */
+  keccak_squeezeblocks(output, nblocks, s, SHAKE256_RATE);
+
+  output+=nblocks*SHAKE256_RATE;
+  outlen-=nblocks*SHAKE256_RATE;
+
+  if(outlen) 
+  {
+    keccak_squeezeblocks(t, 1, s, SHAKE256_RATE);
+    for(i=0;i<outlen;i++)
+      output[i] = t[i];
+  }
+}
+
+void shake128(unsigned char *output, unsigned long long outlen, 
+              const unsigned char *input,  unsigned long long inlen)
+{
+  uint64_t s[25];
+  unsigned char t[SHAKE128_RATE];
+  unsigned long long nblocks = outlen/SHAKE128_RATE;
+  size_t i;
+
+  /* Absorb input */
+  keccak_absorb(s, SHAKE128_RATE, input, inlen, 0x1F);
+
+  /* Squeeze output */
+  keccak_squeezeblocks(output, nblocks, s, SHAKE128_RATE);
+
+  output+=nblocks*SHAKE128_RATE;
+  outlen-=nblocks*SHAKE128_RATE;
+
+  if(outlen) 
+  {
+    keccak_squeezeblocks(t, 1, s, SHAKE128_RATE);
+    for(i=0;i<outlen;i++)
+      output[i] = t[i];
+  }
+}