GCM: GHASH optimizations
authorJussi Kivilinna <jussi.kivilinna@iki.fi>
Tue, 19 Nov 2013 21:26:26 +0000 (23:26 +0200)
committerJussi Kivilinna <jussi.kivilinna@iki.fi>
Wed, 20 Nov 2013 14:49:15 +0000 (16:49 +0200)
* cipher/cipher-gcm.c [GCM_USE_TABLES] (gcmR, ghash): Replace with new.
[GCM_USE_TABLES] [GCM_TABLES_USE_U64] (bshift, fillM, do_ghash): New.
[GCM_USE_TABLES] [!GCM_TABLES_USE_U64] (bshift, fillM): Replace with
new.
[GCM_USE_TABLES] [!GCM_TABLES_USE_U64] (do_ghash): New.
(_gcry_cipher_gcm_tag): Remove extra memcpy to outbuf and use
buf_eq_const for comparing authentication tag.
* cipher/cipher-internal.h (gcry_cipher_handle): Different 'gcm_table'
for 32-bit and 64-bit platforms.
--

Patch improves GHASH speed.

Intel Haswell (x86-64):
Old:
       GCM auth |     26.22 ns/B     36.38 MiB/s     83.89 c/B
New:
       GCM auth |      3.18 ns/B     300.0 MiB/s     10.17 c/B

Intel Haswell (mingw32):
Old:
       GCM auth |     27.27 ns/B     34.97 MiB/s     87.27 c/B
New:
       GCM auth |      7.58 ns/B     125.7 MiB/s     24.27 c/B

Cortex-A8:
Old:
       GCM auth |     231.4 ns/B      4.12 MiB/s     233.3 c/B
New:
       GCM auth |     30.82 ns/B     30.94 MiB/s     31.07 c/B

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
cipher/cipher-gcm.c
cipher/cipher-internal.h

index b6c50bf..d7fc0d8 100644 (file)
 #include "./cipher-internal.h"
 
 #ifdef GCM_USE_TABLES
-static const byte gcmR[256][2] = {
-  {0x00, 0x00,}, {0x01, 0xc2,}, {0x03, 0x84,}, {0x02, 0x46,},
-  {0x07, 0x08,}, {0x06, 0xca,}, {0x04, 0x8c,}, {0x05, 0x4e,},
-  {0x0e, 0x10,}, {0x0f, 0xd2,}, {0x0d, 0x94,}, {0x0c, 0x56,},
-  {0x09, 0x18,}, {0x08, 0xda,}, {0x0a, 0x9c,}, {0x0b, 0x5e,},
-  {0x1c, 0x20,}, {0x1d, 0xe2,}, {0x1f, 0xa4,}, {0x1e, 0x66,},
-  {0x1b, 0x28,}, {0x1a, 0xea,}, {0x18, 0xac,}, {0x19, 0x6e,},
-  {0x12, 0x30,}, {0x13, 0xf2,}, {0x11, 0xb4,}, {0x10, 0x76,},
-  {0x15, 0x38,}, {0x14, 0xfa,}, {0x16, 0xbc,}, {0x17, 0x7e,},
-  {0x38, 0x40,}, {0x39, 0x82,}, {0x3b, 0xc4,}, {0x3a, 0x06,},
-  {0x3f, 0x48,}, {0x3e, 0x8a,}, {0x3c, 0xcc,}, {0x3d, 0x0e,},
-  {0x36, 0x50,}, {0x37, 0x92,}, {0x35, 0xd4,}, {0x34, 0x16,},
-  {0x31, 0x58,}, {0x30, 0x9a,}, {0x32, 0xdc,}, {0x33, 0x1e,},
-  {0x24, 0x60,}, {0x25, 0xa2,}, {0x27, 0xe4,}, {0x26, 0x26,},
-  {0x23, 0x68,}, {0x22, 0xaa,}, {0x20, 0xec,}, {0x21, 0x2e,},
-  {0x2a, 0x70,}, {0x2b, 0xb2,}, {0x29, 0xf4,}, {0x28, 0x36,},
-  {0x2d, 0x78,}, {0x2c, 0xba,}, {0x2e, 0xfc,}, {0x2f, 0x3e,},
-  {0x70, 0x80,}, {0x71, 0x42,}, {0x73, 0x04,}, {0x72, 0xc6,},
-  {0x77, 0x88,}, {0x76, 0x4a,}, {0x74, 0x0c,}, {0x75, 0xce,},
-  {0x7e, 0x90,}, {0x7f, 0x52,}, {0x7d, 0x14,}, {0x7c, 0xd6,},
-  {0x79, 0x98,}, {0x78, 0x5a,}, {0x7a, 0x1c,}, {0x7b, 0xde,},
-  {0x6c, 0xa0,}, {0x6d, 0x62,}, {0x6f, 0x24,}, {0x6e, 0xe6,},
-  {0x6b, 0xa8,}, {0x6a, 0x6a,}, {0x68, 0x2c,}, {0x69, 0xee,},
-  {0x62, 0xb0,}, {0x63, 0x72,}, {0x61, 0x34,}, {0x60, 0xf6,},
-  {0x65, 0xb8,}, {0x64, 0x7a,}, {0x66, 0x3c,}, {0x67, 0xfe,},
-  {0x48, 0xc0,}, {0x49, 0x02,}, {0x4b, 0x44,}, {0x4a, 0x86,},
-  {0x4f, 0xc8,}, {0x4e, 0x0a,}, {0x4c, 0x4c,}, {0x4d, 0x8e,},
-  {0x46, 0xd0,}, {0x47, 0x12,}, {0x45, 0x54,}, {0x44, 0x96,},
-  {0x41, 0xd8,}, {0x40, 0x1a,}, {0x42, 0x5c,}, {0x43, 0x9e,},
-  {0x54, 0xe0,}, {0x55, 0x22,}, {0x57, 0x64,}, {0x56, 0xa6,},
-  {0x53, 0xe8,}, {0x52, 0x2a,}, {0x50, 0x6c,}, {0x51, 0xae,},
-  {0x5a, 0xf0,}, {0x5b, 0x32,}, {0x59, 0x74,}, {0x58, 0xb6,},
-  {0x5d, 0xf8,}, {0x5c, 0x3a,}, {0x5e, 0x7c,}, {0x5f, 0xbe,},
-  {0xe1, 0x00,}, {0xe0, 0xc2,}, {0xe2, 0x84,}, {0xe3, 0x46,},
-  {0xe6, 0x08,}, {0xe7, 0xca,}, {0xe5, 0x8c,}, {0xe4, 0x4e,},
-  {0xef, 0x10,}, {0xee, 0xd2,}, {0xec, 0x94,}, {0xed, 0x56,},
-  {0xe8, 0x18,}, {0xe9, 0xda,}, {0xeb, 0x9c,}, {0xea, 0x5e,},
-  {0xfd, 0x20,}, {0xfc, 0xe2,}, {0xfe, 0xa4,}, {0xff, 0x66,},
-  {0xfa, 0x28,}, {0xfb, 0xea,}, {0xf9, 0xac,}, {0xf8, 0x6e,},
-  {0xf3, 0x30,}, {0xf2, 0xf2,}, {0xf0, 0xb4,}, {0xf1, 0x76,},
-  {0xf4, 0x38,}, {0xf5, 0xfa,}, {0xf7, 0xbc,}, {0xf6, 0x7e,},
-  {0xd9, 0x40,}, {0xd8, 0x82,}, {0xda, 0xc4,}, {0xdb, 0x06,},
-  {0xde, 0x48,}, {0xdf, 0x8a,}, {0xdd, 0xcc,}, {0xdc, 0x0e,},
-  {0xd7, 0x50,}, {0xd6, 0x92,}, {0xd4, 0xd4,}, {0xd5, 0x16,},
-  {0xd0, 0x58,}, {0xd1, 0x9a,}, {0xd3, 0xdc,}, {0xd2, 0x1e,},
-  {0xc5, 0x60,}, {0xc4, 0xa2,}, {0xc6, 0xe4,}, {0xc7, 0x26,},
-  {0xc2, 0x68,}, {0xc3, 0xaa,}, {0xc1, 0xec,}, {0xc0, 0x2e,},
-  {0xcb, 0x70,}, {0xca, 0xb2,}, {0xc8, 0xf4,}, {0xc9, 0x36,},
-  {0xcc, 0x78,}, {0xcd, 0xba,}, {0xcf, 0xfc,}, {0xce, 0x3e,},
-  {0x91, 0x80,}, {0x90, 0x42,}, {0x92, 0x04,}, {0x93, 0xc6,},
-  {0x96, 0x88,}, {0x97, 0x4a,}, {0x95, 0x0c,}, {0x94, 0xce,},
-  {0x9f, 0x90,}, {0x9e, 0x52,}, {0x9c, 0x14,}, {0x9d, 0xd6,},
-  {0x98, 0x98,}, {0x99, 0x5a,}, {0x9b, 0x1c,}, {0x9a, 0xde,},
-  {0x8d, 0xa0,}, {0x8c, 0x62,}, {0x8e, 0x24,}, {0x8f, 0xe6,},
-  {0x8a, 0xa8,}, {0x8b, 0x6a,}, {0x89, 0x2c,}, {0x88, 0xee,},
-  {0x83, 0xb0,}, {0x82, 0x72,}, {0x80, 0x34,}, {0x81, 0xf6,},
-  {0x84, 0xb8,}, {0x85, 0x7a,}, {0x87, 0x3c,}, {0x86, 0xfe,},
-  {0xa9, 0xc0,}, {0xa8, 0x02,}, {0xaa, 0x44,}, {0xab, 0x86,},
-  {0xae, 0xc8,}, {0xaf, 0x0a,}, {0xad, 0x4c,}, {0xac, 0x8e,},
-  {0xa7, 0xd0,}, {0xa6, 0x12,}, {0xa4, 0x54,}, {0xa5, 0x96,},
-  {0xa0, 0xd8,}, {0xa1, 0x1a,}, {0xa3, 0x5c,}, {0xa2, 0x9e,},
-  {0xb5, 0xe0,}, {0xb4, 0x22,}, {0xb6, 0x64,}, {0xb7, 0xa6,},
-  {0xb2, 0xe8,}, {0xb3, 0x2a,}, {0xb1, 0x6c,}, {0xb0, 0xae,},
-  {0xbb, 0xf0,}, {0xba, 0x32,}, {0xb8, 0x74,}, {0xb9, 0xb6,},
-  {0xbc, 0xf8,}, {0xbd, 0x3a,}, {0xbf, 0x7c,}, {0xbe, 0xbe,},
+static const u16 gcmR[256] = {
+  0x0000, 0x01c2, 0x0384, 0x0246, 0x0708, 0x06ca, 0x048c, 0x054e,
+  0x0e10, 0x0fd2, 0x0d94, 0x0c56, 0x0918, 0x08da, 0x0a9c, 0x0b5e,
+  0x1c20, 0x1de2, 0x1fa4, 0x1e66, 0x1b28, 0x1aea, 0x18ac, 0x196e,
+  0x1230, 0x13f2, 0x11b4, 0x1076, 0x1538, 0x14fa, 0x16bc, 0x177e,
+  0x3840, 0x3982, 0x3bc4, 0x3a06, 0x3f48, 0x3e8a, 0x3ccc, 0x3d0e,
+  0x3650, 0x3792, 0x35d4, 0x3416, 0x3158, 0x309a, 0x32dc, 0x331e,
+  0x2460, 0x25a2, 0x27e4, 0x2626, 0x2368, 0x22aa, 0x20ec, 0x212e,
+  0x2a70, 0x2bb2, 0x29f4, 0x2836, 0x2d78, 0x2cba, 0x2efc, 0x2f3e,
+  0x7080, 0x7142, 0x7304, 0x72c6, 0x7788, 0x764a, 0x740c, 0x75ce,
+  0x7e90, 0x7f52, 0x7d14, 0x7cd6, 0x7998, 0x785a, 0x7a1c, 0x7bde,
+  0x6ca0, 0x6d62, 0x6f24, 0x6ee6, 0x6ba8, 0x6a6a, 0x682c, 0x69ee,
+  0x62b0, 0x6372, 0x6134, 0x60f6, 0x65b8, 0x647a, 0x663c, 0x67fe,
+  0x48c0, 0x4902, 0x4b44, 0x4a86, 0x4fc8, 0x4e0a, 0x4c4c, 0x4d8e,
+  0x46d0, 0x4712, 0x4554, 0x4496, 0x41d8, 0x401a, 0x425c, 0x439e,
+  0x54e0, 0x5522, 0x5764, 0x56a6, 0x53e8, 0x522a, 0x506c, 0x51ae,
+  0x5af0, 0x5b32, 0x5974, 0x58b6, 0x5df8, 0x5c3a, 0x5e7c, 0x5fbe,
+  0xe100, 0xe0c2, 0xe284, 0xe346, 0xe608, 0xe7ca, 0xe58c, 0xe44e,
+  0xef10, 0xeed2, 0xec94, 0xed56, 0xe818, 0xe9da, 0xeb9c, 0xea5e,
+  0xfd20, 0xfce2, 0xfea4, 0xff66, 0xfa28, 0xfbea, 0xf9ac, 0xf86e,
+  0xf330, 0xf2f2, 0xf0b4, 0xf176, 0xf438, 0xf5fa, 0xf7bc, 0xf67e,
+  0xd940, 0xd882, 0xdac4, 0xdb06, 0xde48, 0xdf8a, 0xddcc, 0xdc0e,
+  0xd750, 0xd692, 0xd4d4, 0xd516, 0xd058, 0xd19a, 0xd3dc, 0xd21e,
+  0xc560, 0xc4a2, 0xc6e4, 0xc726, 0xc268, 0xc3aa, 0xc1ec, 0xc02e,
+  0xcb70, 0xcab2, 0xc8f4, 0xc936, 0xcc78, 0xcdba, 0xcffc, 0xce3e,
+  0x9180, 0x9042, 0x9204, 0x93c6, 0x9688, 0x974a, 0x950c, 0x94ce,
+  0x9f90, 0x9e52, 0x9c14, 0x9dd6, 0x9898, 0x995a, 0x9b1c, 0x9ade,
+  0x8da0, 0x8c62, 0x8e24, 0x8fe6, 0x8aa8, 0x8b6a, 0x892c, 0x88ee,
+  0x83b0, 0x8272, 0x8034, 0x81f6, 0x84b8, 0x857a, 0x873c, 0x86fe,
+  0xa9c0, 0xa802, 0xaa44, 0xab86, 0xaec8, 0xaf0a, 0xad4c, 0xac8e,
+  0xa7d0, 0xa612, 0xa454, 0xa596, 0xa0d8, 0xa11a, 0xa35c, 0xa29e,
+  0xb5e0, 0xb422, 0xb664, 0xb7a6, 0xb2e8, 0xb32a, 0xb16c, 0xb0ae,
+  0xbbf0, 0xba32, 0xb874, 0xb9b6, 0xbcf8, 0xbd3a, 0xbf7c, 0xbebe,
 };
 
-static unsigned
-bshift (unsigned char *b)
+#ifdef GCM_TABLES_USE_U64
+static void
+bshift (u64 * b0, u64 * b1)
+{
+  u64 t[2], mask;
+
+  t[0] = *b0;
+  t[1] = *b1;
+  mask = t[1] & 1 ? 0xe1 : 0;
+  mask <<= 56;
+
+  *b1 = (t[1] >> 1) ^ (t[0] << 63);
+  *b0 = (t[0] >> 1) ^ mask;
+}
+
+static void
+fillM (unsigned char *h, u64 * M)
+{
+  int i, j;
+
+  M[0 + 0] = 0;
+  M[0 + 16] = 0;
+
+  M[8 + 0] = buf_get_be64 (h + 0);
+  M[8 + 16] = buf_get_be64 (h + 8);
+
+  for (i = 4; i > 0; i /= 2)
+    {
+      M[i + 0] = M[2 * i + 0];
+      M[i + 16] = M[2 * i + 16];
+
+      bshift (&M[i], &M[i + 16]);
+    }
+
+  for (i = 2; i < 16; i *= 2)
+    for (j = 1; j < i; j++)
+      {
+        M[(i + j) + 0] = M[i + 0] ^ M[j + 0];
+        M[(i + j) + 16] = M[i + 16] ^ M[j + 16];
+      }
+}
+
+static void
+do_ghash (unsigned char *result, const unsigned char *buf, const u64 * gcmM)
 {
-  unsigned char c;
+  u64 V[2];
+  u64 tmp[2];
+  const u64 *M;
+  u64 T;
+  u32 A;
   int i;
-  c = b[15] & 1;
-  for (i = 15; i > 0; i--)
+
+  buf_xor (V, result, buf, 16);
+  V[0] = be_bswap64 (V[0]);
+  V[1] = be_bswap64 (V[1]);
+
+  /* First round can be manually tweaked based on fact that 'tmp' is zero. */
+  i = 15;
+
+  M = &gcmM[(V[1] & 0xf)];
+  V[1] >>= 4;
+  tmp[0] = (M[0] >> 4) ^ ((u64) gcmR[(M[16] & 0xf) << 4] << 48);
+  tmp[1] = (M[16] >> 4) ^ (M[0] << 60);
+  tmp[0] ^= gcmM[(V[1] & 0xf) + 0];
+  tmp[1] ^= gcmM[(V[1] & 0xf) + 16];
+  V[1] >>= 4;
+
+  --i;
+  while (1)
     {
-      b[i] = (b[i] >> 1) | (b[i - 1] << 7);
+      M = &gcmM[(V[1] & 0xf)];
+      V[1] >>= 4;
+
+      A = tmp[1] & 0xff;
+      T = tmp[0];
+      tmp[0] = (T >> 8) ^ ((u64) gcmR[A] << 48) ^ gcmM[(V[1] & 0xf) + 0];
+      tmp[1] = (T << 56) ^ (tmp[1] >> 8) ^ gcmM[(V[1] & 0xf) + 16];
+
+      tmp[0] ^= (M[0] >> 4) ^ ((u64) gcmR[(M[16] & 0xf) << 4] << 48);
+      tmp[1] ^= (M[16] >> 4) ^ (M[0] << 60);
+
+      if (i == 0)
+        break;
+      else if (i == 8)
+        V[1] = V[0];
+      else
+        V[1] >>= 4;
+      --i;
     }
-  b[i] >>= 1;
-  return c;
+
+  buf_put_be64 (result + 0, tmp[0]);
+  buf_put_be64 (result + 8, tmp[1]);
+}
+
+#else
+
+static void
+bshift (u32 * M, int i)
+{
+  u32 t[4], mask;
+
+  t[0] = M[i * 4 + 0];
+  t[1] = M[i * 4 + 1];
+  t[2] = M[i * 4 + 2];
+  t[3] = M[i * 4 + 3];
+  mask = t[3] & 1 ? 0xe1 : 0;
+
+  M[i * 4 + 3] = (t[3] >> 1) ^ (t[2] << 31);
+  M[i * 4 + 2] = (t[2] >> 1) ^ (t[1] << 31);
+  M[i * 4 + 1] = (t[1] >> 1) ^ (t[0] << 31);
+  M[i * 4 + 0] = (t[0] >> 1) ^ (mask << 24);
 }
 
 static void
-fillM (unsigned char *h, unsigned char *M)
+fillM (unsigned char *h, u32 * M)
 {
   int i, j;
-  memset (&M[0 * 16], 0, 16);
-  memcpy (&M[8 * 16], h, 16);
+
+  M[0 * 4 + 0] = 0;
+  M[0 * 4 + 1] = 0;
+  M[0 * 4 + 2] = 0;
+  M[0 * 4 + 3] = 0;
+
+  M[8 * 4 + 0] = buf_get_be32 (h + 0);
+  M[8 * 4 + 1] = buf_get_be32 (h + 4);
+  M[8 * 4 + 2] = buf_get_be32 (h + 8);
+  M[8 * 4 + 3] = buf_get_be32 (h + 12);
+
   for (i = 4; i > 0; i /= 2)
     {
-      memcpy (&M[i * 16], &M[2 * i * 16], 16);
-      if (bshift (&M[i * 16]))
-        M[i * 16 + 0] ^= 0xe1;
+      M[i * 4 + 0] = M[2 * i * 4 + 0];
+      M[i * 4 + 1] = M[2 * i * 4 + 1];
+      M[i * 4 + 2] = M[2 * i * 4 + 2];
+      M[i * 4 + 3] = M[2 * i * 4 + 3];
+
+      bshift (M, i);
     }
+
   for (i = 2; i < 16; i *= 2)
     for (j = 1; j < i; j++)
-      buf_xor (&M[(i + j) * 16], &M[i * 16], &M[j * 16], 16);
+      {
+        M[(i + j) * 4 + 0] = M[i * 4 + 0] ^ M[j * 4 + 0];
+        M[(i + j) * 4 + 1] = M[i * 4 + 1] ^ M[j * 4 + 1];
+        M[(i + j) * 4 + 2] = M[i * 4 + 2] ^ M[j * 4 + 2];
+        M[(i + j) * 4 + 3] = M[i * 4 + 3] ^ M[j * 4 + 3];
+      }
 }
 
 static void
-ghash (unsigned char *result, const unsigned char *buf,
-       const unsigned char *gcmM)
+do_ghash (unsigned char *result, const unsigned char *buf, const u32 * gcmM)
 {
-  unsigned char V[16];
+  byte V[16];
+  u32 tmp[4];
+  u32 v;
+  const u32 *M, *m;
+  u32 T[3];
   int i;
 
-  buf_xor (V, result, buf, 16);
+  buf_xor (V, result, buf, 16); /* V is big-endian */
+
+  /* First round can be manually tweaked based on fact that 'tmp' is zero. */
+  i = 15;
 
-  memset (result, 0, 16);
+  v = V[i];
+  M = &gcmM[(v & 0xf) * 4];
+  v = (v & 0xf0) >> 4;
+  m = &gcmM[v * 4];
+  v = V[--i];
 
-  for (i = 15; i >= 0; i--)
+  tmp[0] = (M[0] >> 4) ^ ((u64) gcmR[(M[3] << 4) & 0xf0] << 16) ^ m[0];
+  tmp[1] = (M[1] >> 4) ^ (M[0] << 28) ^ m[1];
+  tmp[2] = (M[2] >> 4) ^ (M[1] << 28) ^ m[2];
+  tmp[3] = (M[3] >> 4) ^ (M[2] << 28) ^ m[3];
+
+  while (1)
     {
-      byte A = result[15];
-      byte T[16];
-      int j;
-      const byte *M = &gcmM[(V[i] & 0xf) * 16];
-
-      memmove (result + 1, result, 15);
-      result[0] = gcmR[A][0];
-      result[1] ^= gcmR[A][1];
-
-      T[0] = M[0] >> 4;
-      for (j = 1; j < 16; j++)
-        T[j] = (M[j] >> 4) | (M[j - 1] << 4);
-      T[0] ^= gcmR[(M[15] & 0xf) << 4][0];
-      T[1] ^= gcmR[(M[15] & 0xf) << 4][1];
-      buf_xor (T, T, &gcmM[(V[i] >> 4) * 16], 16);
-      buf_xor (result, result, T, 16);
+      M = &gcmM[(v & 0xf) * 4];
+      v = (v & 0xf0) >> 4;
+      m = &gcmM[v * 4];
+
+      T[0] = tmp[0];
+      T[1] = tmp[1];
+      T[2] = tmp[2];
+      tmp[0] = (T[0] >> 8) ^ ((u32) gcmR[tmp[3] & 0xff] << 16) ^ m[0];
+      tmp[1] = (T[0] << 24) ^ (tmp[1] >> 8) ^ m[1];
+      tmp[2] = (T[1] << 24) ^ (tmp[2] >> 8) ^ m[2];
+      tmp[3] = (T[2] << 24) ^ (tmp[3] >> 8) ^ m[3];
+
+      tmp[0] ^= (M[0] >> 4) ^ ((u64) gcmR[(M[3] << 4) & 0xf0] << 16);
+      tmp[1] ^= (M[1] >> 4) ^ (M[0] << 28);
+      tmp[2] ^= (M[2] >> 4) ^ (M[1] << 28);
+      tmp[3] ^= (M[3] >> 4) ^ (M[2] << 28);
+
+      if (i == 0)
+        break;
+
+      v = V[--i];
     }
+
+  buf_put_be32 (result + 0, tmp[0]);
+  buf_put_be32 (result + 4, tmp[1]);
+  buf_put_be32 (result + 8, tmp[2]);
+  buf_put_be32 (result + 12, tmp[3]);
+}
+#endif
+
+static void
+ghash (unsigned char *result, const unsigned char *buf, const void *gcmM)
+{
+  do_ghash (result, buf, gcmM);
 }
 
 #define GHASH(c, result, buf) ghash (result, buf, c->gcm_table);
@@ -447,7 +564,7 @@ _gcry_cipher_gcm_tag (gcry_cipher_hd_t c,
       buf_xor (c->u_tag.tag, c->lastiv, c->u_tag.tag, 16);
       c->marks.tag = 1;
     }
-  memcpy (outbuf, c->u_tag.tag, 16);
+
   if (!check)
     {
       memcpy (outbuf, c->u_tag.tag, outbuflen);
@@ -455,13 +572,8 @@ _gcry_cipher_gcm_tag (gcry_cipher_hd_t c,
     }
   else
     {
-      int diff, i;
-
-      /* Constant-time compare. */
-      for (i = 0, diff = 0; i < outbuflen; i++)
-        diff -= ! !(outbuf[i] - c->u_tag.tag[i]);
-
-      return !diff ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
+      return buf_eq_const(outbuf, c->u_tag.tag, outbuflen) ?
+               GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
     }
 
   return 0;
@@ -474,7 +586,6 @@ _gcry_cipher_gcm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
   return _gcry_cipher_gcm_tag (c, outtag, taglen, 0);
 }
 
-
 gcry_err_code_t
 _gcry_cipher_gcm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
                             size_t taglen)
index 7da9c68..b4d0ff9 100644 (file)
@@ -129,7 +129,14 @@ struct gcry_cipher_handle
   int unused;  /* Number of unused bytes in LASTIV. */
   unsigned char length[MAX_BLOCKSIZE]; /* bit counters for GCM */
 #ifdef GCM_USE_TABLES
-  unsigned char gcm_table[16 * 16]; /* pre-calculated table for GCM */
+ #if defined(HAVE_U64_TYPEDEF) && \
+     (SIZEOF_UNSIGNED_LONG == 8 || defined(__x86_64__))
+  #define GCM_TABLES_USE_U64 1
+  u64 gcm_table[2 * 16]; /* pre-calculated table for GCM */
+ #else
+  #undef GCM_TABLES_USE_U64
+  u32 gcm_table[4 * 16]; /* pre-calculated table for GCM */
+ #endif
 #endif
 
   union {