git: f033b2223512 - main - security/kuku: fix build on powerpc64

From: Piotr Kubaj <pkubaj_at_FreeBSD.org>
Date: Thu, 15 Oct 2026 10:45:46 UTC
The branch main has been updated by pkubaj:

URL: https://cgit.FreeBSD.org/ports/commit/?id=f033b2223512e6d8c51c6cda31d3af6b61e6a5ba

commit f033b2223512e6d8c51c6cda31d3af6b61e6a5ba
Author:     Piotr Kubaj <pkubaj@FreeBSD.org>
AuthorDate: 2026-10-15 09:35:57 +0000
Commit:     Piotr Kubaj <pkubaj@FreeBSD.org>
CommitDate: 2026-10-15 10:45:23 +0000

    security/kuku: fix build on powerpc64
    
    Upstream rejects big-endian targets because item words and the BLAKE2xb-seeded
    tabulation table were read in native byte order, so a big-endian build would
    compute a different table layout than little-endian peers. Define both in
    little-endian byte order instead (a no-op on little-endian targets) and drop
    the guards.
---
 security/kuku/files/patch-CMakeLists.txt           |  19 +++
 security/kuku/files/patch-src_kuku_common.h        | 137 +++++++++++++++++++++
 security/kuku/files/patch-src_kuku_internal_hash.h |  33 +++++
 3 files changed, 189 insertions(+)

diff --git a/security/kuku/files/patch-CMakeLists.txt b/security/kuku/files/patch-CMakeLists.txt
new file mode 100644
index 000000000000..a3c26bdddc55
--- /dev/null
+++ b/security/kuku/files/patch-CMakeLists.txt
@@ -0,0 +1,19 @@
+--- CMakeLists.txt.orig	2026-09-08 22:03:06 UTC
++++ CMakeLists.txt
+@@ -32,16 +32,6 @@ endif()
+         "Release" "Debug" "MinSizeRel" "RelWithDebInfo")
+ endif()
+ 
+-# Kuku's table layout is defined only for little-endian targets; the static_assert in
+-# src/kuku/common.h explains why and is the primary guard. This is the backstop for
+-# compilers that define no __BYTE_ORDER__ macro, and it reports the problem at configure
+-# time with a clearer message than a compile error buried in a header.
+-if(DEFINED CMAKE_CXX_BYTE_ORDER AND NOT CMAKE_CXX_BYTE_ORDER STREQUAL "LITTLE_ENDIAN")
+-    message(FATAL_ERROR
+-        "Kuku supports little-endian targets only, but CMAKE_CXX_BYTE_ORDER is "
+-        "'${CMAKE_CXX_BYTE_ORDER}'.")
+-endif()
+-
+ if(CMAKE_CONFIGURATION_TYPES)
+     message(STATUS "Multi-config generator detected. Configurations: ${CMAKE_CONFIGURATION_TYPES}")
+ else()
diff --git a/security/kuku/files/patch-src_kuku_common.h b/security/kuku/files/patch-src_kuku_common.h
new file mode 100644
index 000000000000..918d7fa0d546
--- /dev/null
+++ b/security/kuku/files/patch-src_kuku_common.h
@@ -0,0 +1,137 @@
+--- src/kuku/common.h.orig	2026-09-08 22:03:06 UTC
++++ src/kuku/common.h
+@@ -20,30 +20,28 @@ namespace kuku
+     */
+     using item_type = std::array<unsigned char, 16>;
+ 
+-    // Kuku's table layout is defined only for LITTLE-ENDIAN targets.
++    // Kuku's table layout is defined in terms of LITTLE-ENDIAN byte order, independently of
++    // the target's native byte order.
+     //
+-    // An item is 16 raw bytes, and those raw bytes are what BLAKE2xb hashes. Several places
+-    // reinterpret them as integers using the native byte order: the word accessors below,
+-    // increment_item, and HashFunc, which lets BLAKE2xb write its output directly into an
+-    // array of location_type. On a big-endian target each of those reinterpretations yields
+-    // different values, so the derived location functions - and hence the table layout -
+-    // differ from a little-endian peer's.
++    // An item is 16 raw bytes, and those raw bytes are what BLAKE2xb hashes. Two places
++    // interpret bytes as integers: the word accessors below (on which increment_item is
++    // built), and HashFunc, which lets BLAKE2xb write its output directly into an array of
++    // location_type. Both read and write those integers in little-endian byte order, so the
++    // derived location functions - and hence the table layout - are the same on every
++    // target. This matters because Kuku's consumers are two-party protocols that must agree
++    // on where items live, and the two parties need not share a byte order.
+     //
+-    // The failure mode is what makes this worth a hard error. A big-endian build would not
+-    // crash or produce a visibly wrong answer: it would compile, pass every test, and simply
+-    // disagree with a little-endian peer about where items live. For a library whose
+-    // consumers are two-party protocols that must agree on placement, a silent divergence is
+-    // the worst available outcome, so the assumption fails loudly at compile time instead.
++    // On a little-endian target the conversions are the identity, and the accessors reduce
++    // to a single std::memcpy; that fast path is selected here. Every other target - a
++    // big-endian one, or a compiler that exposes no byte-order macro - takes a portable
++    // byte-by-byte path that is correct whatever the native byte order is. Correctness
++    // therefore never depends on this detection being right; only speed does.
+     //
+     // MSVC defines no __BYTE_ORDER__, but every architecture it targets - x86, x64, ARM,
+-    // ARM64 - is little-endian, so there is nothing to check there. Compilers defining
+-    // neither macro fall through to the configure-time check in CMakeLists.txt.
+-#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
+-    static_assert(
+-        __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
+-        "Kuku's table layout is defined only for little-endian targets. On a big-endian "
+-        "target Kuku would build and pass its tests while computing a different table layout "
+-        "from its little-endian peers.");
++    // ARM64 - is little-endian.
++#if defined(_MSC_VER) || \
++    (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
++#define KUKU_NATIVE_LITTLE_ENDIAN
+ #endif
+ 
+     /**
+@@ -144,28 +142,57 @@ namespace kuku
+     }
+ 
+     /**
+-    Returns the low 64-bit word of the item.
++    Reads a 64-bit word stored in little-endian byte order. See the note on byte order above.
+ 
+-    Uses std::memcpy to avoid strict-aliasing/alignment UB: item_type is
+-    std::array<unsigned char, 16> with alignment 1, so reinterpret_cast<uint64_t*>
++    On a little-endian target this is a std::memcpy, which avoids strict-aliasing/alignment
++    UB: item_type is std::array<unsigned char, 16> with alignment 1, so reinterpret_cast<uint64_t*>
+     on item.data() can be misaligned on strict-alignment targets (e.g., some ARM).
+     */
+-    inline std::uint64_t get_low_word(const item_type &item) noexcept
++    inline std::uint64_t load_word(const unsigned char *in) noexcept
+     {
++#if defined(KUKU_NATIVE_LITTLE_ENDIAN)
+         std::uint64_t value{};
+-        std::memcpy(&value, item.data(), sizeof(value));
++        std::memcpy(&value, in, sizeof(value));
+         return value;
++#else
++        std::uint64_t value = 0;
++        for (std::size_t i = 0; i < sizeof(value); i++)
++        {
++            value |= static_cast<std::uint64_t>(in[i]) << (8U * i);
++        }
++        return value;
++#endif
+     }
+ 
+     /**
+-    Returns the high 64-bit word of the item. See get_low_word for the rationale
+-    behind the std::memcpy-based implementation.
++    Stores a 64-bit word in little-endian byte order. See load_word.
+     */
++    inline void store_word(std::uint64_t value, unsigned char *out) noexcept
++    {
++#if defined(KUKU_NATIVE_LITTLE_ENDIAN)
++        std::memcpy(out, &value, sizeof(value));
++#else
++        for (std::size_t i = 0; i < sizeof(value); i++)
++        {
++            out[i] = static_cast<unsigned char>(value >> (8U * i));
++        }
++#endif
++    }
++
++    /**
++    Returns the low 64-bit word of the item.
++    */
++    inline std::uint64_t get_low_word(const item_type &item) noexcept
++    {
++        return load_word(item.data());
++    }
++
++    /**
++    Returns the high 64-bit word of the item.
++    */
+     inline std::uint64_t get_high_word(const item_type &item) noexcept
+     {
+-        std::uint64_t value{};
+-        std::memcpy(&value, item.data() + bytes_per_uint64, sizeof(value));
+-        return value;
++        return load_word(item.data() + bytes_per_uint64);
+     }
+ 
+     /**
+@@ -173,7 +200,7 @@ namespace kuku
+     */
+     inline void set_low_word(std::uint64_t value, item_type &destination) noexcept
+     {
+-        std::memcpy(destination.data(), &value, sizeof(value));
++        store_word(value, destination.data());
+     }
+ 
+     /**
+@@ -181,7 +208,7 @@ namespace kuku
+     */
+     inline void set_high_word(std::uint64_t value, item_type &destination) noexcept
+     {
+-        std::memcpy(destination.data() + bytes_per_uint64, &value, sizeof(value));
++        store_word(value, destination.data() + bytes_per_uint64);
+     }
+ 
+     /**
diff --git a/security/kuku/files/patch-src_kuku_internal_hash.h b/security/kuku/files/patch-src_kuku_internal_hash.h
new file mode 100644
index 000000000000..aa2c1b36af16
--- /dev/null
+++ b/security/kuku/files/patch-src_kuku_internal_hash.h
@@ -0,0 +1,33 @@
+--- src/kuku/internal/hash.h.orig	2026-09-08 22:03:06 UTC
++++ src/kuku/internal/hash.h
+@@ -8,6 +8,7 @@
+ #include <array>
+ #include <cstddef>
+ #include <cstdint>
++#include <cstring>
+ #include <stdexcept>
+ 
+ namespace kuku
+@@ -23,6 +24,22 @@ namespace kuku
+             {
+                 throw std::runtime_error("blake2xb failed");
+             }
++#if !defined(KUKU_NATIVE_LITTLE_ENDIAN)
++            // BLAKE2xb wrote its output into random_array_ as raw bytes. Reread each entry as a
++            // little-endian word, so that the tabulation table - and hence every location this
++            // function returns - matches a little-endian peer's. See the note on byte order in
++            // kuku/common.h.
++            for (location_type &entry : random_array_)
++            {
++                std::array<unsigned char, sizeof(location_type)> bytes{};
++                std::memcpy(bytes.data(), &entry, bytes.size());
++                entry = 0;
++                for (std::size_t i = 0; i < bytes.size(); i++)
++                {
++                    entry |= static_cast<location_type>(bytes[i]) << (8U * i);
++                }
++            }
++#endif
+         }
+ 
+         location_type operator()(item_type item) const noexcept