bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] sha512-buffer: port back to 32-bit-only hosts


From: Paul Eggert
Subject: [PATCH] sha512-buffer: port back to 32-bit-only hosts
Date: Sat, 18 May 2024 19:04:55 -0700

Port to platforms lacking 64-bit integers (something that Emacs
still attempts to do, in theory) by adding an u64bswap primitive
to u64.h and using that, instead of using bswap_64.  This fixes a
bug I made in commit 0d45ec7c033c165ad73a6509c7fa84aa67edf4ea
dated Sun Jun 17 14:35:37 2018 -0700.
* lib/sha512.c (SWAP): Use u64bswap, not bswap_64, to port
to older platforms lacking 64-bit integers.
* lib/u64.h: Include stddef.h, for size_t.
Include byteswap.h, for bswap_64 (on platforms with 64-bit int),
bswap_32.
(u64rol): Now a function, not a macro, so that it evaluates
its args only once.
(u64uint32): New typedef.
(u64, u64hilo, u64lo): Use it.
(_GL_U64_MASK32): New macro.
(u64size, u64plus, u64shl, u64shr, u64plus): Use it as needed for
odd platforms where unsigned int is wider than 32 bits.
(u64lt): Return bool, not int.
* modules/u64 (Depends-on): Add byteswap, stdbool.
* tests/test-u64.c (main): Test u64bswap.
---
 ChangeLog        | 24 +++++++++++++++++++
 lib/sha512.c     |  2 +-
 lib/u64.h        | 60 ++++++++++++++++++++++++++++++++----------------
 modules/u64      |  2 ++
 tests/test-u64.c |  7 ++++++
 5 files changed, 74 insertions(+), 21 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index fc2c42283c..b7f62031f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2024-05-18  Paul Eggert  <eggert@cs.ucla.edu>
+
+       sha512-buffer: port back to 32-bit-only hosts
+       Port to platforms lacking 64-bit integers (something that Emacs
+       still attempts to do, in theory) by adding an u64bswap primitive
+       to u64.h and using that, instead of using bswap_64.  This fixes a
+       bug I made in commit 0d45ec7c033c165ad73a6509c7fa84aa67edf4ea
+       dated Sun Jun 17 14:35:37 2018 -0700.
+       * lib/sha512.c (SWAP): Use u64bswap, not bswap_64, to port
+       to older platforms lacking 64-bit integers.
+       * lib/u64.h: Include stddef.h, for size_t.
+       Include byteswap.h, for bswap_64 (on platforms with 64-bit int),
+       bswap_32.
+       (u64rol): Now a function, not a macro, so that it evaluates
+       its args only once.
+       (u64uint32): New typedef.
+       (u64, u64hilo, u64lo): Use it.
+       (_GL_U64_MASK32): New macro.
+       (u64size, u64plus, u64shl, u64shr, u64plus): Use it as needed for
+       odd platforms where unsigned int is wider than 32 bits.
+       (u64lt): Return bool, not int.
+       * modules/u64 (Depends-on): Add byteswap, stdbool.
+       * tests/test-u64.c (main): Test u64bswap.
+
 2024-05-18  Collin Funk  <collin.funk1@gmail.com>
 
        dup3: Update documentation and expected test results.
diff --git a/lib/sha512.c b/lib/sha512.c
index 9eb036fb32..6750041bc7 100644
--- a/lib/sha512.c
+++ b/lib/sha512.c
@@ -35,7 +35,7 @@
 #ifdef WORDS_BIGENDIAN
 # define SWAP(n) (n)
 #else
-# define SWAP(n) bswap_64 (n)
+# define SWAP(n) u64bswap (n)
 #endif
 
 #if ! HAVE_OPENSSL_SHA512
diff --git a/lib/u64.h b/lib/u64.h
index 4eca03e985..cfb5588757 100644
--- a/lib/u64.h
+++ b/lib/u64.h
@@ -22,8 +22,11 @@
  #error "Please include config.h first."
 #endif
 
+#include <stddef.h>
 #include <stdint.h>
 
+#include <byteswap.h>
+
 _GL_INLINE_HEADER_BEGIN
 #ifndef _GL_U64_INLINE
 # define _GL_U64_INLINE _GL_INLINE
@@ -34,9 +37,6 @@ extern "C" {
 #endif
 
 
-/* Return X rotated left by N bits, where 0 < N < 64.  */
-#define u64rol(x, n) u64or (u64shl (x, n), u64shr (x, 64 - n))
-
 #ifdef UINT64_MAX
 
 /* Native implementations are trivial.  See below for comments on what
@@ -53,24 +53,30 @@ typedef uint64_t u64;
 # define u64plus(x, y) ((x) + (y))
 # define u64shl(x, n) ((x) << (n))
 # define u64shr(x, n) ((x) >> (n))
+# define u64bswap(x) bswap_64 (x)
 
 #else
 
-/* u64 is a 64-bit unsigned integer value.
+# define _GL_U64_MASK32 0xfffffffful /* 2**32 - 1.  */
+
+/* u64 represents a 64-bit unsigned integer value equal to (HI << 32) + LO.
+   Implement it with unsigned int, which the GNU coding standards say
+   is wide enough to hold 32 bits, and which does not signal an error
+   when adding (theoretically possible with types like uint_fast32_t).
    u64init (HI, LO), is like u64hilo (HI, LO), but for use in
    initializer contexts.  */
 # ifdef WORDS_BIGENDIAN
-typedef struct { uint32_t hi, lo; } u64;
+typedef struct { unsigned int hi, lo; } u64;
 #  define u64init(hi, lo) { hi, lo }
 # else
-typedef struct { uint32_t lo, hi; } u64;
+typedef struct { unsigned int lo, hi; } u64;
 #  define u64init(hi, lo) { lo, hi }
 # endif
 
 /* Given the high and low-order 32-bit quantities HI and LO, return a u64
    value representing (HI << 32) + LO.  */
 _GL_U64_INLINE u64
-u64hilo (uint32_t hi, uint32_t lo)
+u64hilo (unsigned int hi, unsigned int lo)
 {
   u64 r;
   r.hi = hi;
@@ -78,9 +84,9 @@ u64hilo (uint32_t hi, uint32_t lo)
   return r;
 }
 
-/* Return a u64 value representing LO.  */
+/* Return a u64 value representing the 32-bit quantity LO.  */
 _GL_U64_INLINE u64
-u64lo (uint32_t lo)
+u64lo (unsigned int lo)
 {
   u64 r;
   r.hi = 0;
@@ -88,18 +94,18 @@ u64lo (uint32_t lo)
   return r;
 }
 
-/* Return a u64 value representing SIZE.  */
+/* Return a u64 value representing SIZE, where 0 <= SIZE < 2**64.  */
 _GL_U64_INLINE u64
 u64size (size_t size)
 {
   u64 r;
   r.hi = size >> 31 >> 1;
-  r.lo = size;
+  r.lo = size & _GL_U64_MASK32;
   return r;
 }
 
 /* Return X < Y.  */
-_GL_U64_INLINE int
+_GL_U64_INLINE bool
 u64lt (u64 x, u64 y)
 {
   return x.hi < y.hi || (x.hi == y.hi && x.lo < y.lo);
@@ -135,29 +141,29 @@ u64xor (u64 x, u64 y)
   return r;
 }
 
-/* Return X + Y.  */
+/* Return X + Y, wrapping around on overflow.  */
 _GL_U64_INLINE u64
 u64plus (u64 x, u64 y)
 {
   u64 r;
-  r.lo = x.lo + y.lo;
-  r.hi = x.hi + y.hi + (r.lo < x.lo);
+  r.lo = (x.lo + y.lo) & _GL_U64_MASK32;
+  r.hi = (x.hi + y.hi + (r.lo < x.lo)) & _GL_U64_MASK32;
   return r;
 }
 
-/* Return X << N.  */
+/* Return X << N, where 0 <= N < 64.  */
 _GL_U64_INLINE u64
 u64shl (u64 x, int n)
 {
   u64 r;
   if (n < 32)
     {
-      r.hi = (x.hi << n) | (x.lo >> (32 - n));
-      r.lo = x.lo << n;
+      r.hi = (x.hi << n & _GL_U64_MASK32) | x.lo >> (32 - n);
+      r.lo = x.lo << n & _GL_U64_MASK32;
     }
   else
     {
-      r.hi = x.lo << (n - 32);
+      r.hi = x.lo << (n - 32) & _GL_U64_MASK32;
       r.lo = 0;
     }
   return r;
@@ -171,7 +177,7 @@ u64shr (u64 x, int n)
   if (n < 32)
     {
       r.hi = x.hi >> n;
-      r.lo = (x.hi << (32 - n)) | (x.lo >> n);
+      r.lo = (x.hi << (32 - n) & _GL_U64_MASK32) | x.lo >> n;
     }
   else
     {
@@ -181,8 +187,22 @@ u64shr (u64 x, int n)
   return r;
 }
 
+/* Return X with bytes in reverse order.  */
+_GL_U64_INLINE u64
+u64bswap (u64 x)
+{
+  return u64hilo (bswap_32 (x.lo), bswap_32 (x.hi));
+}
+
 #endif
 
+/* Return X rotated left by N bits, where 0 < N < 64.  */
+_GL_U64_INLINE u64
+u64rol (u64 x, int n)
+{
+  return u64or (u64shl (x, n), u64shr (x, 64 - n));
+}
+
 
 #ifdef __cplusplus
 }
diff --git a/modules/u64 b/modules/u64
index f678c32caa..1be7420bda 100644
--- a/modules/u64
+++ b/modules/u64
@@ -6,7 +6,9 @@ lib/u64.h
 lib/u64.c
 
 Depends-on:
+byteswap
 extern-inline
+stdbool
 stdint
 
 configure.ac:
diff --git a/tests/test-u64.c b/tests/test-u64.c
index 1c84eb3e25..a78e66421a 100644
--- a/tests/test-u64.c
+++ b/tests/test-u64.c
@@ -43,5 +43,12 @@ main (void)
   if (u64lt (k, l) || u64lt (l, k))
     return 1;
 
+  u64
+    m = u64hilo (0x01020304, 0x05060708),
+    n = u64hilo (0x08070605, 0x04030201),
+    o = u64bswap (m);
+  if (u64lt (n, o) || u64lt (o, n))
+    return 1;
+
   return 0;
 }
-- 
2.40.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]