[PATCH] Tweak Keccak for small speed-up

Jussi Kivilinna jussi.kivilinna at iki.fi
Sat Nov 7 16:20:29 CET 2015


* cipher/keccak_permute_32.h (KECCAK_F1600_PERMUTE_FUNC_NAME): Track
rounds with round constant pointer instead of separate round counter.
* cipher/keccak_permute_64.h (KECCAK_F1600_PERMUTE_FUNC_NAME): Ditto.
(KECCAK_F1600_ABSORB_FUNC_NAME): Tweak lanes pointer increment for bulk
absorb loops.
--

Patch makes small tweaks to improve performance.

Benchmark on Intel Haswell @ 3.2 Ghz:

Before:
                |  nanosecs/byte   mebibytes/sec   cycles/byte
 SHAKE128       |      2.27 ns/B     420.5 MiB/s      7.26 c/B
 SHAKE256       |      2.79 ns/B     341.4 MiB/s      8.94 c/B
 SHA3-224       |      2.64 ns/B     361.7 MiB/s      8.44 c/B
 SHA3-256       |      2.79 ns/B     341.4 MiB/s      8.94 c/B
 SHA3-384       |      3.65 ns/B     261.3 MiB/s     11.68 c/B
 SHA3-512       |      5.27 ns/B     181.0 MiB/s     16.86 c/B

After:
                |  nanosecs/byte   mebibytes/sec   cycles/byte
 SHAKE128       |      2.25 ns/B     423.5 MiB/s      7.21 c/B
 SHAKE256       |      2.77 ns/B     343.9 MiB/s      8.88 c/B
 SHA3-224       |      2.62 ns/B     364.1 MiB/s      8.38 c/B
 SHA3-256       |      2.77 ns/B     343.8 MiB/s      8.88 c/B
 SHA3-384       |      3.63 ns/B     262.6 MiB/s     11.63 c/B
 SHA3-512       |      5.23 ns/B     182.3 MiB/s     16.75 c/B

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 cipher/keccak_permute_32.h |   13 +++++++------
 cipher/keccak_permute_64.h |   44 ++++++++++++++++++++------------------------
 2 files changed, 27 insertions(+), 30 deletions(-)

diff --git a/cipher/keccak_permute_32.h b/cipher/keccak_permute_32.h
index fed9383..1ce42a4 100644
--- a/cipher/keccak_permute_32.h
+++ b/cipher/keccak_permute_32.h
@@ -27,6 +27,7 @@ static unsigned int
 KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
 {
   const u32 *round_consts = round_consts_32bit;
+  const u32 *round_consts_end = round_consts_32bit + 2 * 24;
   u32 Aba0, Abe0, Abi0, Abo0, Abu0;
   u32 Aba1, Abe1, Abi1, Abo1, Abu1;
   u32 Aga0, Age0, Agi0, Ago0, Agu0;
@@ -52,7 +53,6 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
   u32 Esa0, Ese0, Esi0, Eso0, Esu0;
   u32 Esa1, Ese1, Esi1, Eso1, Esu1;
   u32 *state = hd->u.state32bi;
-  unsigned int round;
 
   Aba0 = state[0];
   Aba1 = state[1];
@@ -105,7 +105,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
   Asu0 = state[48];
   Asu1 = state[49];
 
-  for (round = 0; round < 24; round += 2)
+  do
     {
       /* prepareTheta */
       BCa0 = Aba0 ^ Aga0 ^ Aka0 ^ Ama0 ^ Asa0;
@@ -142,7 +142,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
       Asu0 ^= Du0;
       BCu0 = ROL32(Asu0, 7);
       Eba0 = BCa0 ^ ANDN32(BCe0, BCi0);
-      Eba0 ^= round_consts[round * 2 + 0];
+      Eba0 ^= *(round_consts++);
       Ebe0 = BCe0 ^ ANDN32(BCi0, BCo0);
       Ebi0 = BCi0 ^ ANDN32(BCo0, BCu0);
       Ebo0 = BCo0 ^ ANDN32(BCu0, BCa0);
@@ -159,7 +159,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
       Asu1 ^= Du1;
       BCu1 = ROL32(Asu1, 7);
       Eba1 = BCa1 ^ ANDN32(BCe1, BCi1);
-      Eba1 ^= round_consts[round * 2 + 1];
+      Eba1 ^= *(round_consts++);
       Ebe1 = BCe1 ^ ANDN32(BCi1, BCo1);
       Ebi1 = BCi1 ^ ANDN32(BCo1, BCu1);
       Ebo1 = BCo1 ^ ANDN32(BCu1, BCa1);
@@ -328,7 +328,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
       Esu0 ^= Du0;
       BCu0 = ROL32(Esu0, 7);
       Aba0 = BCa0 ^ ANDN32(BCe0, BCi0);
-      Aba0 ^= round_consts[round * 2 + 2];
+      Aba0 ^= *(round_consts++);
       Abe0 = BCe0 ^ ANDN32(BCi0, BCo0);
       Abi0 = BCi0 ^ ANDN32(BCo0, BCu0);
       Abo0 = BCo0 ^ ANDN32(BCu0, BCa0);
@@ -345,7 +345,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
       Esu1 ^= Du1;
       BCu1 = ROL32(Esu1, 7);
       Aba1 = BCa1 ^ ANDN32(BCe1, BCi1);
-      Aba1 ^= round_consts[round * 2 + 3];
+      Aba1 ^= *(round_consts++);
       Abe1 = BCe1 ^ ANDN32(BCi1, BCo1);
       Abi1 = BCi1 ^ ANDN32(BCo1, BCu1);
       Abo1 = BCo1 ^ ANDN32(BCu1, BCa1);
@@ -479,6 +479,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
       Aso1 = BCo1 ^ ANDN32(BCu1, BCa1);
       Asu1 = BCu1 ^ ANDN32(BCa1, BCe1);
     }
+  while (round_consts < round_consts_end);
 
   state[0] = Aba0;
   state[1] = Aba1;
diff --git a/cipher/keccak_permute_64.h b/cipher/keccak_permute_64.h
index 1a80192..b28c871 100644
--- a/cipher/keccak_permute_64.h
+++ b/cipher/keccak_permute_64.h
@@ -26,6 +26,7 @@ static unsigned int
 KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
 {
   const u64 *round_consts = _gcry_keccak_round_consts_64bit;
+  const u64 *round_consts_end = _gcry_keccak_round_consts_64bit + 24;
   u64 Aba, Abe, Abi, Abo, Abu;
   u64 Aga, Age, Agi, Ago, Agu;
   u64 Aka, Ake, Aki, Ako, Aku;
@@ -39,7 +40,6 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
   u64 Ema, Eme, Emi, Emo, Emu;
   u64 Esa, Ese, Esi, Eso, Esu;
   u64 *state = hd->u.state64;
-  unsigned int round;
 
   Aba = state[0];
   Abe = state[1];
@@ -67,7 +67,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
   Aso = state[23];
   Asu = state[24];
 
-  for (round = 0; round < 24; round += 2)
+  do
     {
       /* prepareTheta */
       BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa;
@@ -94,7 +94,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
       Asu ^= Du;
       BCu = ROL64(Asu, 14);
       Eba = BCa ^ ANDN64(BCe, BCi);
-      Eba ^= (u64)round_consts[round];
+      Eba ^= *(round_consts++);
       Ebe = BCe ^ ANDN64(BCi, BCo);
       Ebi = BCi ^ ANDN64(BCo, BCu);
       Ebo = BCo ^ ANDN64(BCu, BCa);
@@ -189,7 +189,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
       Esu ^= Du;
       BCu = ROL64(Esu, 14);
       Aba = BCa ^ ANDN64(BCe, BCi);
-      Aba ^= (u64)round_consts[round + 1];
+      Aba ^= *(round_consts++);
       Abe = BCe ^ ANDN64(BCi, BCo);
       Abi = BCi ^ ANDN64(BCo, BCu);
       Abo = BCo ^ ANDN64(BCu, BCa);
@@ -259,6 +259,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
       Aso = BCo ^ ANDN64(BCu, BCa);
       Asu = BCu ^ ANDN64(BCa, BCe);
     }
+  while (round_consts < round_consts_end);
 
   state[0] = Aba;
   state[1] = Abe;
@@ -303,12 +304,11 @@ KECCAK_F1600_ABSORB_FUNC_NAME(KECCAK_STATE *hd, int pos, const byte *lanes,
 	  /* SHAKE128 */
 	  while (pos == 0 && nlanes >= 21)
 	    {
-	      absorb_lanes64_8(&hd->u.state64[0], lanes + 8 * 0);
-	      absorb_lanes64_4(&hd->u.state64[8], lanes + 8 * 8);
-	      absorb_lanes64_8(&hd->u.state64[12], lanes + 8 * 12);
-	      absorb_lanes64_1(&hd->u.state64[20], lanes + 8 * 20);
-	      lanes += 8 * 21;
 	      nlanes -= 21;
+	      absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8;
+	      absorb_lanes64_8(&hd->u.state64[8], lanes); lanes += 8 * 8;
+	      absorb_lanes64_4(&hd->u.state64[16], lanes); lanes += 8 * 4;
+	      absorb_lanes64_1(&hd->u.state64[20], lanes); lanes += 8 * 1;
 
 	      burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd);
 	    }
@@ -318,11 +318,10 @@ KECCAK_F1600_ABSORB_FUNC_NAME(KECCAK_STATE *hd, int pos, const byte *lanes,
 	  /* SHA3-224 */
 	  while (pos == 0 && nlanes >= 18)
 	    {
-	      absorb_lanes64_8(&hd->u.state64[0], lanes + 8 * 0);
-	      absorb_lanes64_2(&hd->u.state64[8], lanes + 8 * 8);
-	      absorb_lanes64_8(&hd->u.state64[10], lanes + 8 * 10);
-	      lanes += 8 * 18;
 	      nlanes -= 18;
+	      absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8;
+	      absorb_lanes64_8(&hd->u.state64[8], lanes); lanes += 8 * 8;
+	      absorb_lanes64_2(&hd->u.state64[16], lanes); lanes += 8 * 2;
 
 	      burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd);
 	    }
@@ -332,11 +331,10 @@ KECCAK_F1600_ABSORB_FUNC_NAME(KECCAK_STATE *hd, int pos, const byte *lanes,
 	  /* SHA3-256 & SHAKE256 */
 	  while (pos == 0 && nlanes >= 17)
 	    {
-	      absorb_lanes64_8(&hd->u.state64[0], lanes + 8 * 0);
-	      absorb_lanes64_8(&hd->u.state64[8], lanes + 8 * 8);
-	      absorb_lanes64_1(&hd->u.state64[16], lanes + 8 * 16);
-	      lanes += 8 * 17;
 	      nlanes -= 17;
+	      absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8;
+	      absorb_lanes64_8(&hd->u.state64[8], lanes); lanes += 8 * 8;
+	      absorb_lanes64_1(&hd->u.state64[16], lanes); lanes += 8 * 1;
 
 	      burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd);
 	    }
@@ -346,11 +344,10 @@ KECCAK_F1600_ABSORB_FUNC_NAME(KECCAK_STATE *hd, int pos, const byte *lanes,
 	  /* SHA3-384 */
 	  while (pos == 0 && nlanes >= 13)
 	    {
-	      absorb_lanes64_8(&hd->u.state64[0], lanes + 8 * 0);
-	      absorb_lanes64_4(&hd->u.state64[8], lanes + 8 * 8);
-	      absorb_lanes64_1(&hd->u.state64[12], lanes + 8 * 12);
-	      lanes += 8 * 13;
 	      nlanes -= 13;
+	      absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8;
+	      absorb_lanes64_4(&hd->u.state64[8], lanes); lanes += 8 * 4;
+	      absorb_lanes64_1(&hd->u.state64[12], lanes); lanes += 8 * 1;
 
 	      burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd);
 	    }
@@ -360,10 +357,9 @@ KECCAK_F1600_ABSORB_FUNC_NAME(KECCAK_STATE *hd, int pos, const byte *lanes,
 	  /* SHA3-512 */
 	  while (pos == 0 && nlanes >= 9)
 	    {
-	      absorb_lanes64_8(&hd->u.state64[0], lanes + 8 * 0);
-	      absorb_lanes64_1(&hd->u.state64[8], lanes + 8 * 8);
-	      lanes += 8 * 9;
 	      nlanes -= 9;
+	      absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8;
+	      absorb_lanes64_1(&hd->u.state64[8], lanes); lanes += 8 * 1;
 
 	      burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd);
 	    }




More information about the Gcrypt-devel mailing list