/// @file dpf/blob.hpp /// @brief Fixed-length XOR byte-string leaf (`dpf::blob`). /// @details A mailbox row or other byte payload that does not fit in one AES /// block. Keygen stretches each final seed with the exterior PRG /// (counter mode) into `N` bytes and XORs a correction of that /// length, matching Express's `genDPF` leaf. The tree and depth are /// unchanged: Boyle packing uses `ceil(8N / λ)` exterior blocks and /// `lg(outputs_per_leaf) = 0`. /// @copyright Copyright (c) 2019-2026 Ryan Henry and [others](@ref authors) /// @license Released under a GNU General Public v2.0 (GPLv2) license. #ifndef LIBDPF_INCLUDE_DPF_BLOB_HPP__ #define LIBDPF_INCLUDE_DPF_BLOB_HPP__ #include #include #include #include #include "hedley/hedley.h" #include "dpf/utils.hpp" namespace dpf { /// @brief XOR share of an `N`-byte string. /// @tparam N byte length (`N >= 1`) template struct blob { static_assert(N >= 1, "dpf::blob: N must be at least 1"); static constexpr std::size_t size = N; std::array bytes{}; HEDLEY_NO_THROW constexpr blob() noexcept = default; HEDLEY_NO_THROW explicit blob(const unsigned char * src, std::size_t n = N) noexcept { const std::size_t m = n < N ? n : N; if (m != 0) std::memcpy(bytes.data(), src, m); } HEDLEY_NO_THROW explicit blob(std::array b) noexcept : bytes{std::move(b)} { } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE unsigned char * data() noexcept { return bytes.data(); } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE const unsigned char * data() const noexcept { return bytes.data(); } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE friend constexpr bool operator==(const blob & a, const blob & b) noexcept { for (std::size_t i = 0; i < N; ++i) if (a.bytes[i] != b.bytes[i]) return false; return true; } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE friend constexpr bool operator!=(const blob & a, const blob & b) noexcept { return !(a == b); } /// @brief XOR (group addition / subtraction for this leaf). HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE friend blob operator^(const blob & a, const blob & b) noexcept { blob out; for (std::size_t i = 0; i < N; ++i) out.bytes[i] = static_cast(a.bytes[i] ^ b.bytes[i]); return out; } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE friend blob operator+(const blob & a, const blob & b) noexcept { return a ^ b; } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE friend blob operator-(const blob & a, const blob & b) noexcept { return a ^ b; } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE blob & operator^=(const blob & o) noexcept { *this = *this ^ o; return *this; } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE blob & operator+=(const blob & o) noexcept { return (*this) ^= o; } }; template struct is_blob : std::false_type {}; template struct is_blob> : std::true_type {}; template inline constexpr bool is_blob_v = is_blob>::value; namespace utils { template struct bitlength_of> : public std::integral_constant { }; template struct bitlength_of_output, NodeT> : public std::integral_constant { }; template struct has_characteristic_two> : std::true_type { }; template struct is_xor_wrapper> : std::true_type { }; } // namespace utils } // namespace dpf #endif // LIBDPF_INCLUDE_DPF_BLOB_HPP__