// // Created by Vladislav on 04.01.2026. // #pragma once #include #include #include #include #ifdef OMATH_ENABLE_FORCE_INLINE #ifdef _MSC_VER #define OMATH_FORCE_INLINE __forceinline #else #define OMATH_FORCE_INLINE __attribute__((always_inline)) inline #endif #else #define OMATH_FORCE_INLINE #endif namespace omath::detail { [[nodiscard]] consteval std::uint64_t fnv1a_64(const char* s) { std::uint64_t h = 14695981039346656037ull; while (*s) { h ^= static_cast(*s++); h *= 1099511628211ull; } return h; } // SplitMix64 mixer (good quality for seeding / scrambling) [[nodiscard]] consteval std::uint64_t splitmix64(std::uint64_t x) { x += 0x9E3779B97F4A7C15ull; x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9ull; x = (x ^ (x >> 27)) * 0x94D049BB133111EBull; return x ^ (x >> 31); } // Choose your policy: // - If you want reproducible builds, REMOVE __DATE__/__TIME__. // - If you want "different each build", keep them. [[nodiscard]] consteval std::uint64_t base_seed() { std::uint64_t h = 0; h ^= fnv1a_64(__FILE__); h ^= splitmix64(fnv1a_64(__DATE__)); h ^= splitmix64(fnv1a_64(__TIME__)); return splitmix64(h); } // Produce a "random" 64-bit value for a given stream index (compile-time) template [[nodiscard]] consteval std::uint64_t rand_u64() { // Stream is usually __COUNTER__ so each call site differs return splitmix64(base_seed() + 0xD1B54A32D192ED03ull * (Stream + 1)); } [[nodiscard]] consteval std::uint64_t bounded_u64(const std::uint64_t x, const std::uint64_t bound) { return (x * bound) >> 64; } template [[nodiscard]] consteval std::int64_t rand_uint8_t() { static_assert(Lo <= Hi); const std::uint64_t span = static_cast(Hi - Lo) + 1ull; const std::uint64_t r = rand_u64(); return static_cast(bounded_u64(r, span)) + Lo; } [[nodiscard]] consteval std::uint64_t rand_u64(const std::uint64_t seed, const std::uint64_t i) { return splitmix64(seed + 0xD1B54A32D192ED03ull * (i + 1ull)); } // Convert to int (uses low 32 bits; you can also use high bits if you prefer) [[nodiscard]] consteval std::uint8_t rand_uint8t(const std::uint64_t seed, const std::uint64_t i) { return static_cast(rand_u64(seed, i)); // narrowing is fine/deterministic } template [[nodiscard]] consteval std::array make_array_impl(std::index_sequence) { return {rand_uint8t(Seed, static_cast(I))...}; } template [[nodiscard]] consteval std::array make_array() { return make_array_impl(std::make_index_sequence{}); } } // namespace omath::detail namespace omath { template class VarAnchor; template key> class EncryptedVariable final { using value_type = std::remove_cvref_t; bool m_is_encrypted{}; value_type m_data{}; OMATH_FORCE_INLINE constexpr void xor_contained_var_by_key() { // Safe, keeps const-correctness, and avoids reinterpret_cast issues auto bytes = std::as_writable_bytes(std::span{&m_data, 1}); for (std::size_t i = 0; i < bytes.size(); ++i) { const std::uint8_t k = static_cast(key[i % key_size] + (i * key_size)); bytes[i] ^= static_cast(k); } } public: OMATH_FORCE_INLINE constexpr explicit EncryptedVariable(const value_type& data) : m_is_encrypted(false), m_data(data) { encrypt(); } [[nodiscard]] constexpr bool is_encrypted() const { return m_is_encrypted; } OMATH_FORCE_INLINE constexpr void decrypt() { if (!m_is_encrypted) return; xor_contained_var_by_key(); m_is_encrypted = false; } OMATH_FORCE_INLINE constexpr void encrypt() { if (m_is_encrypted) return; xor_contained_var_by_key(); m_is_encrypted = true; } [[nodiscard]] OMATH_FORCE_INLINE constexpr value_type& value() { return m_data; } [[nodiscard]] OMATH_FORCE_INLINE constexpr const value_type& value() const { return m_data; } constexpr OMATH_FORCE_INLINE ~EncryptedVariable() { decrypt(); } [[nodiscard]] constexpr OMATH_FORCE_INLINE auto drop_anchor() { return VarAnchor{*this}; } }; template class VarAnchor final { public: // ReSharper disable once CppNonExplicitConvertingConstructor OMATH_FORCE_INLINE constexpr VarAnchor(EncryptedVarType& var): m_var(var) { m_var.decrypt(); } OMATH_FORCE_INLINE constexpr ~VarAnchor() { m_var.encrypt(); } private: EncryptedVarType& m_var; }; } // namespace omath #define OMATH_CT_RAND_ARRAY_BYTE(N) \ (::omath::detail::make_array<(N), (::omath::detail::base_seed() ^ static_cast(__COUNTER__))>()) #define OMATH_DEF_CRYPT_VAR(TYPE, KEY_SIZE) omath::EncryptedVariable