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 <egg...@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.fu...@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