git: f033b2223512 - main - security/kuku: fix build on powerpc64
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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