diff --git a/CMakeLists.txt b/CMakeLists.txt index fdf9c8ef..4d382ccd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ option(OMATH_SUPRESS_SAFETY_CHECKS "Supress some safety checks in release build option(OMATH_USE_UNITY_BUILD "Will enable unity build to speed up compilation" OFF) option(OMATH_ENABLE_LEGACY "Will enable legacy classes that MUST be used ONLY for backward compatibility" ON) option(OMATH_ENABLE_COVERAGE "Enable coverage" OFF) - +option(OMATH_ENABLE_FORCE_INLINE "Will for compiler to make some functions to be force inlined no matter what" ON) if (VCPKG_MANIFEST_FEATURES) foreach (omath_feature IN LISTS VCPKG_MANIFEST_FEATURES) if (omath_feature STREQUAL "imgui") @@ -112,6 +112,10 @@ if (OMATH_ENABLE_LEGACY) target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_LEGACY) endif () +if (OMATH_ENABLE_FORCE_INLINE) + target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_FORCE_INLINE) +endif () + set_target_properties(${PROJECT_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" diff --git a/include/omath/containers/encrypted_variable.hpp b/include/omath/containers/encrypted_variable.hpp new file mode 100644 index 00000000..3d1c250f --- /dev/null +++ b/include/omath/containers/encrypted_variable.hpp @@ -0,0 +1,201 @@ +// +// 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 \ No newline at end of file diff --git a/tests/general/unit_test_var_encryption.cpp b/tests/general/unit_test_var_encryption.cpp new file mode 100644 index 00000000..108e84b4 --- /dev/null +++ b/tests/general/unit_test_var_encryption.cpp @@ -0,0 +1,17 @@ +// +// Created by Vladislav on 04.01.2026. +// +#include "omath/linear_algebra/vector3.hpp" +#include +#include +TEST(Enc, Test) +{ + constexpr omath::Vector3 original = {1.f, 2.f, 3.f}; + OMATH_DEF_CRYPT_VAR(omath::Vector3, 128) var{original}; + { + omath::VarAnchor _ = var.drop_anchor(); + + EXPECT_EQ(original, var.value()); + } + EXPECT_NE(original, var.value()); +} \ No newline at end of file