[PATCH 10/10] const-time: add 64-bit fast paths for const-time buffer functions

Jussi Kivilinna jussi.kivilinna at iki.fi
Sat Sep 27 09:54:19 CEST 2025


* src/const-time.c (_gcry_ct_not_memequal, _gcry_ct_memequal): Add
64-bit processing for larger than 7 byte inputs.
--

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 src/const-time.c | 70 +++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 57 insertions(+), 13 deletions(-)

diff --git a/src/const-time.c b/src/const-time.c
index 0fb53a07..917170fc 100644
--- a/src/const-time.c
+++ b/src/const-time.c
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include "g10lib.h"
 #include "const-time.h"
+#include "../cipher/bufhelp.h"
 
 
 #ifndef HAVE_GCC_ASM_VOLATILE_MEMORY
@@ -42,19 +43,46 @@ _gcry_ct_not_memequal (const void *b1, const void *b2, size_t len)
 {
   const byte *a = b1;
   const byte *b = b2;
-  int ab, ba;
-  size_t i;
+  u32 ab = 0;
+  u32 ba = 0;
 
   /* Constant-time compare. */
-  for (i = 0, ab = 0, ba = 0; i < len; i++)
+
+  if (len >= sizeof(u64))
+    {
+      u64 ab8 = 0;
+      u64 ba8 = 0;
+
+      while (len >= sizeof(u64))
+	{
+	  u64 a8 = buf_get_he64 (a);
+	  u64 b8 = buf_get_he64 (b);
+
+	  /* If a8 != b8, either ab8 or ba8 will have high bit set. */
+	  ab8 |= a8 - b8;
+	  ba8 |= b8 - a8;
+
+	  a += sizeof(u64);
+	  b += sizeof(u64);
+	  len -= sizeof(u64);
+	}
+
+      ab = ct_u64_gen_mask ((ab8 >> (sizeof(u64) * 8 - 1)) & 1);
+      ba = ct_u64_gen_mask ((ba8 >> (sizeof(u64) * 8 - 1)) & 1);
+    }
+
+  while (len > 0)
     {
-      /* If a[i] != b[i], either ab or ba will be negative. */
-      ab |= a[i] - b[i];
-      ba |= b[i] - a[i];
+      /* If *a != *b, either ab or ba will have high bit set. */
+      ab |= *a - *b;
+      ba |= *b - *a;
+      a++;
+      b++;
+      len--;
     }
 
-  /* 'ab | ba' is negative when buffers are not equal, extract sign bit.  */
-  return ((unsigned int)(ab | ba) >> (sizeof(unsigned int) * 8 - 1)) & 1;
+  /* 'ab | ba' has high bit set when buffers are not equal.  */
+  return ((ab | ba) >> (sizeof(u32) * 8 - 1)) & 1;
 }
 
 /*
@@ -77,12 +105,28 @@ _gcry_ct_memmov_cond (void *dst, const void *src, size_t len,
 		      unsigned long op_enable)
 {
   /* Note: dual mask with AND/OR used for EM leakage mitigation */
-  unsigned char mask1 = ct_ulong_gen_mask(op_enable);
-  unsigned char mask2 = ct_ulong_gen_inv_mask(op_enable);
+  u64 mask1 = ct_u64_gen_mask (op_enable);
+  u64 mask2 = ct_u64_gen_inv_mask (op_enable);
   unsigned char *b_dst = dst;
   const unsigned char *b_src = src;
-  size_t i;
 
-  for (i = 0; i < len; i++)
-    b_dst[i] = (b_dst[i] & mask2) | (b_src[i] & mask1);
+  while (len >= sizeof(u64))
+    {
+      u64 dst8 = buf_get_he64 (b_dst);
+      u64 src8 = buf_get_he64 (b_src);
+
+      buf_put_he64 (b_dst, (dst8 & mask2) | (src8 & mask1));
+
+      b_dst += sizeof(u64);
+      b_src += sizeof(u64);
+      len -= sizeof(u64);
+    }
+
+  while (len > 0)
+    {
+      *b_dst = (*b_dst & mask2) | (*b_src & mask1);
+      b_dst++;
+      b_src++;
+      len--;
+    }
 }
-- 
2.48.1




More information about the Gcrypt-devel mailing list