From 5e4b9682e66311c2f559ea20424d0241d79afcb8 Mon Sep 17 00:00:00 2001 From: MrWater00 Date: Wed, 7 Oct 2026 11:21:15 +0530 Subject: [PATCH 1/3] Fix endianness detection when __BYTE_ORDER__ is undefined (MSVC) plat_local.h tests __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ without checking that the macros exist. MSVC defines neither, so the preprocessor replaces both with 0 and the condition is true. The byte-swap helpers rev8_be32 and rev8_be64 then become no-ops on little-endian MSVC targets, and SLH-DSA computes non-standard results. Guard both tests with defined(...) so that the byte-swapping versions are used when the macros are missing. Tested with MSVC 19.44 (x64): building xfips205 and running the ACVP keyGen vectors (v1.1.0.40) gives 0/120 passes before this change (SHA2 0/60, SHAKE 0/60) and 120/120 after (60/60 each). Signed-off-by: MrWater00 --- plat_local.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plat_local.h b/plat_local.h index f1bf1e3..9ea7d3c 100644 --- a/plat_local.h +++ b/plat_local.h @@ -107,7 +107,8 @@ extern "C" /* revert if not big endian */ -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) /* nop */ #define rev8_be32(x) (x) #else @@ -120,7 +121,8 @@ static SLH_INLINE uint32_t rev8_be32(uint32_t x) } #endif -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) #define rev8_be64(x) (x) #else /* RISC-V: grev(x, 0x38) or rev8(x) */ From 8082e84f1f2a7737433389a37c80335bf09d5dd6 Mon Sep 17 00:00:00 2001 From: MrWater00 Date: Thu, 8 Oct 2026 10:13:22 +0530 Subject: [PATCH 2/3] Centralize endianness detection and add portable fallback Move endianness detection into slh_sys.h, following mlkem-native and mldsa-native: use __BYTE_ORDER__ when the compiler provides it, and assume little endian for MSVC on x86, x64 and ARM64, which does not define it. plat_local.h now selects rev8_be32 and rev8_be64 from SLH_SYS_BIG_ENDIAN / SLH_SYS_LITTLE_ENDIAN. If the endianness cannot be detected, they use portable code that checks the byte order at run time instead of assuming little endian. Tested with MSVC 19.44 (x64): the ACVP keyGen vectors (v1.1.0.40) pass 120/120. Signed-off-by: MrWater00 --- plat_local.h | 62 +++++++++++++++++++++++++++++++++------------------- slh_sys.h | 22 +++++++++++++++++++ 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/plat_local.h b/plat_local.h index 9ea7d3c..7d247b1 100644 --- a/plat_local.h +++ b/plat_local.h @@ -107,33 +107,51 @@ extern "C" /* revert if not big endian */ -#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + /* unconditional byte swaps */ + + /* RISC-V: grev(x, 0x18) or rev8 */ + static SLH_INLINE uint32_t plat_bswap32(uint32_t x) + { + return ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | + ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24); + } + + /* RISC-V: grev(x, 0x38) or rev8(x) */ + static SLH_INLINE uint64_t plat_bswap64(uint64_t x) + { + return (x << 56) | ((x & 0x000000000000FF00LL) << 40) | + ((x & 0x0000000000FF0000LL) << 24) | + ((x & 0x00000000FF000000LL) << 8) | + ((x & 0x000000FF00000000LL) >> 8) | + ((x & 0x0000FF0000000000LL) >> 24) | + ((x & 0x00FF000000000000LL) >> 40) | (x >> 56); + } + +#if defined(SLH_SYS_BIG_ENDIAN) /* nop */ #define rev8_be32(x) (x) +#define rev8_be64(x) (x) +#elif defined(SLH_SYS_LITTLE_ENDIAN) +#define rev8_be32(x) plat_bswap32(x) +#define rev8_be64(x) plat_bswap64(x) #else -/* RISC-V: grev(x, 0x18) or rev8 */ + /* Endianness could not be detected: use portable code that checks at run + * time. Compilers will typically fold this away. */ + static SLH_INLINE int plat_is_little_endian(void) + { + const uint16_t one = 1; + return *(const uint8_t *)&one == 1; + } -static SLH_INLINE uint32_t rev8_be32(uint32_t x) -{ - return ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | - ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24); -} -#endif + static SLH_INLINE uint32_t rev8_be32(uint32_t x) + { + return plat_is_little_endian() ? plat_bswap32(x) : x; + } -#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#define rev8_be64(x) (x) -#else -/* RISC-V: grev(x, 0x38) or rev8(x) */ -static SLH_INLINE uint64_t rev8_be64(uint64_t x) -{ - return (x << 56) | ((x & 0x000000000000FF00LL) << 40) | - ((x & 0x0000000000FF0000LL) << 24) | - ((x & 0x00000000FF000000LL) << 8) | ((x & 0x000000FF00000000LL) >> 8) | - ((x & 0x0000FF0000000000LL) >> 24) | - ((x & 0x00FF000000000000LL) >> 40) | (x >> 56); -} + static SLH_INLINE uint64_t rev8_be64(uint64_t x) + { + return plat_is_little_endian() ? plat_bswap64(x) : x; + } #endif /* rotate left */ diff --git a/slh_sys.h b/slh_sys.h index 48eabf2..6169061 100644 --- a/slh_sys.h +++ b/slh_sys.h @@ -7,6 +7,28 @@ #ifndef SLH_SYS_H #define SLH_SYS_H +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(SLH_SYS_LITTLE_ENDIAN) && !defined(SLH_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define SLH_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define SLH_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define SLH_SYS_LITTLE_ENDIAN +#endif + +#endif /* !SLH_SYS_LITTLE_ENDIAN && !SLH_SYS_BIG_ENDIAN */ + /* * C90 does not have the inline compiler directive yet. * We don't use it in C90 builds. From 63ed89761a22c507efda178b90cfd4f5990d526c Mon Sep 17 00:00:00 2001 From: MrWater00 Date: Wed, 14 Oct 2026 13:44:53 +0530 Subject: [PATCH 3/3] Use a little-endian and a portable rev8 implementation Address review feedback: instead of three code paths (big-endian no-op, little-endian swap and run-time detection), use two: - SLH_SYS_LITTLE_ENDIAN: byte swap with shifts and masks. - Otherwise: portable code that reads the bytes of the argument and assembles the value in big-endian order, independent of the host byte order. Signed-off-by: MrWater00 --- plat_local.h | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/plat_local.h b/plat_local.h index 7d247b1..a98ef3d 100644 --- a/plat_local.h +++ b/plat_local.h @@ -107,17 +107,17 @@ extern "C" /* revert if not big endian */ - /* unconditional byte swaps */ +#if defined(SLH_SYS_LITTLE_ENDIAN) /* RISC-V: grev(x, 0x18) or rev8 */ - static SLH_INLINE uint32_t plat_bswap32(uint32_t x) + static SLH_INLINE uint32_t rev8_be32(uint32_t x) { return ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24); } /* RISC-V: grev(x, 0x38) or rev8(x) */ - static SLH_INLINE uint64_t plat_bswap64(uint64_t x) + static SLH_INLINE uint64_t rev8_be64(uint64_t x) { return (x << 56) | ((x & 0x000000000000FF00LL) << 40) | ((x & 0x0000000000FF0000LL) << 24) | @@ -127,31 +127,27 @@ extern "C" ((x & 0x00FF000000000000LL) >> 40) | (x >> 56); } -#if defined(SLH_SYS_BIG_ENDIAN) -/* nop */ -#define rev8_be32(x) (x) -#define rev8_be64(x) (x) -#elif defined(SLH_SYS_LITTLE_ENDIAN) -#define rev8_be32(x) plat_bswap32(x) -#define rev8_be64(x) plat_bswap64(x) #else - /* Endianness could not be detected: use portable code that checks at run - * time. Compilers will typically fold this away. */ - static SLH_INLINE int plat_is_little_endian(void) - { - const uint16_t one = 1; - return *(const uint8_t *)&one == 1; - } + /* Portable versions that do not depend on the endianness of the host: + * read the bytes of the argument in memory order and assemble the + * result in big-endian order. */ static SLH_INLINE uint32_t rev8_be32(uint32_t x) { - return plat_is_little_endian() ? plat_bswap32(x) : x; + const uint8_t *p = (const uint8_t *)&x; + return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | + ((uint32_t)p[2] << 8) | (uint32_t)p[3]; } static SLH_INLINE uint64_t rev8_be64(uint64_t x) { - return plat_is_little_endian() ? plat_bswap64(x) : x; + const uint8_t *p = (const uint8_t *)&x; + return ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) | + ((uint64_t)p[2] << 40) | ((uint64_t)p[3] << 32) | + ((uint64_t)p[4] << 24) | ((uint64_t)p[5] << 16) | + ((uint64_t)p[6] << 8) | (uint64_t)p[7]; } + #endif /* rotate left */