From 50792af56574c8cb240cd1bdad8beb86d2346d52 Mon Sep 17 00:00:00 2001 From: nevergiveupcpp Date: Fri, 23 Oct 2026 11:57:51 +0200 Subject: [PATCH 1/6] chore: update clang format/tidy configuration --- .clang-format | 23 +++++++++++----------- .clang-tidy | 34 ++++++++++++++++----------------- .github/workflows/benchmark.yml | 0 .github/workflows/release.yml | 0 4 files changed, 28 insertions(+), 29 deletions(-) create mode 100644 .github/workflows/benchmark.yml create mode 100644 .github/workflows/release.yml diff --git a/.clang-format b/.clang-format index 551c865..4a0af45 100644 --- a/.clang-format +++ b/.clang-format @@ -3,34 +3,35 @@ Language: Cpp Standard: c++20 BasedOnStyle: LLVM -IndentWidth: 4 TabWidth: 4 +IndentWidth: 4 NamespaceIndentation: All AccessModifierOffset: -4 ColumnLimit: 120 +SortIncludes: Never + +PointerAlignment: Left +ReferenceAlignment: Left + +SpaceAfterTemplateKeyword: false +AlwaysBreakTemplateDeclarations: No +RequiresClausePosition: SingleLine + PenaltyReturnTypeOnItsOwnLine: 1000 -BinPackParameters: false +BinPackParameters: OnePerLine BinPackArguments: false AlignAfterOpenBracket: BlockIndent AllowShortFunctionsOnASingleLine: None -InsertBraces: true AllowShortLambdasOnASingleLine: Empty +InsertBraces: true BreakConstructorInitializers: AfterColon PackConstructorInitializers: CurrentLine -PointerAlignment: Left -ReferenceAlignment: Left - -SpaceAfterTemplateKeyword: false -AlwaysBreakTemplateDeclarations: No - -SortIncludes: Never - AlignTrailingComments: Kind: Always OverEmptyLines: 2 diff --git a/.clang-tidy b/.clang-tidy index 5d1cadd..0607edb 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -6,10 +6,25 @@ Checks: > -clang-diagnostic-gnu-string-literal-operator-template CheckOptions: + - key: readability-identifier-naming.NamespaceCase + value: lower_case + - key: readability-identifier-naming.ClassCase value: lower_case - key: readability-identifier-naming.StructCase value: lower_case + - key: readability-identifier-naming.EnumCase + value: lower_case + - key: readability-identifier-naming.EnumConstantCase + value: lower_case + + - key: readability-identifier-naming.TypeAliasCase + value: lower_case + - key: readability-identifier-naming.TypeAliasIgnoredRegexp + value: '^[A-Z]$' + + - key: readability-identifier-naming.TemplateParameterCase + value: CamelCase - key: readability-identifier-naming.FunctionCase value: lower_case @@ -36,21 +51,4 @@ CheckOptions: - key: readability-identifier-naming.ProtectedMemberSuffix value: '_' - key: readability-identifier-naming.ConstantMemberIgnoredRegexp - value: '^[A-Z][A-Z0-9_]*$' - - - key: readability-identifier-naming.EnumConstantCase - value: lower_case - - - key: readability-identifier-naming.EnumCase - value: lower_case - - - key: readability-identifier-naming.TemplateParameterCase - value: CamelCase - - - key: readability-identifier-naming.NamespaceCase - value: lower_case - - - key: readability-identifier-naming.TypeAliasCase - value: lower_case - - key: readability-identifier-naming.TypeAliasIgnoredRegexp - value: '^[A-Z]$' + value: '^[A-Z][A-Z0-9_]*$' \ No newline at end of file diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000..e69de29 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e69de29 From e74898aa429c9c7d8cc9990fab2111e8a209494e Mon Sep 17 00:00:00 2001 From: nevergiveupcpp Date: Fri, 23 Oct 2026 12:01:53 +0200 Subject: [PATCH 2/6] ci: split ci and benchmarks into separate workflows --- .github/workflows/benchmark.yml | 86 +++++++++++++++++++++++++++++++++ .github/workflows/ci.yml | 80 ++++++++++-------------------- 2 files changed, 112 insertions(+), 54 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index e69de29..ffc99b9 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,86 @@ +name: Benchmark + +on: + push: + branches: [main] + +permissions: + contents: read + +jobs: + benchmark: + name: Run Benchmarks + runs-on: windows-latest + + permissions: + contents: read + + env: + BENCHMARK_BIN_DIR: tests/benchmark/build/msvc-x64/Release + + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: false + + - name: Set VCPKG_ROOT + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Install Google Benchmark + run: vcpkg install benchmark:x64-windows + + - name: Configure + working-directory: tests/benchmark + run: cmake --preset msvc-x64 + + - name: Build + working-directory: tests/benchmark + run: cmake --build --preset msvc-x64 --config Release --parallel + + - name: Run + working-directory: ${{ env.BENCHMARK_BIN_DIR }} + shell: bash + run: | + ./benchmark-obfuscxx.exe \ + --benchmark_filter="BM_.*_(Low|Medium|High)" \ + --benchmark_format=json \ + --benchmark_out=result.json + + - name: Upload benchmark result + uses: actions/upload-artifact@v6 + with: + name: benchmark-result + path: ${{ env.BENCHMARK_BIN_DIR }}/result.json + if-no-files-found: error + + store: + name: Store Benchmark Results + needs: benchmark + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: false + + - name: Download benchmark result + uses: actions/download-artifact@v7 + with: + name: benchmark-result + path: artifacts + + - name: Store + uses: benchmark-action/github-action-benchmark@v1 + with: + name: Benchmark + tool: googlecpp + output-file-path: artifacts/result.json + github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: true + comment-on-alert: false + alert-threshold: '200%' + fail-on-alert: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0af1d7..22a29c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,15 +2,18 @@ name: CI on: push: - branches: ["main"] + branches: [main] + pull_request: - branches: ["main"] + branches: [main] + +permissions: + contents: read jobs: unittests: - name: ${{ matrix.name }} + name: Run Unit Tests / ${{ matrix.name }} runs-on: ${{ matrix.os }} - if: github.event_name == 'pull_request' strategy: fail-fast: false @@ -48,7 +51,9 @@ jobs: vcpkg_triplet: arm64-osx steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 + with: + persist-credentials: false - name: Set VCPKG_ROOT shell: bash @@ -63,59 +68,21 @@ jobs: - name: Build working-directory: tests/unittest - run: cmake --build --preset ${{ matrix.preset }} --config Release + run: cmake --build --preset ${{ matrix.preset }} --config Release --parallel - name: Test working-directory: tests/unittest/build/${{ matrix.preset }} run: ctest --build-config Release --output-on-failure - benchmark: - name: Benchmark - runs-on: windows-latest - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - env: - BENCHMARK_BIN_DIR: tests/benchmark/build/msvc-x64/Release + clang-format: + name: Run Clang Format + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - - name: Set VCPKG_ROOT - shell: bash - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Install Google Benchmark - run: vcpkg install benchmark:x64-windows - - - name: Configure - working-directory: tests/benchmark - run: cmake --preset msvc-x64 - - - name: Build - working-directory: tests/benchmark - run: cmake --build --preset msvc-x64 --config Release - - - name: Run - working-directory: ${{ env.BENCHMARK_BIN_DIR }} - run: ./benchmark-obfuscxx.exe --benchmark_filter="BM_.*_(Low|Medium|High)" --benchmark_format=json --benchmark_out=result.json - - - name: Store - uses: benchmark-action/github-action-benchmark@v1 + - uses: actions/checkout@v5 with: - name: Benchmark - tool: googlecpp - output-file-path: ${{ env.BENCHMARK_BIN_DIR }}/result.json - github-token: ${{ secrets.GITHUB_TOKEN }} - auto-push: true - comment-on-alert: false - alert-threshold: '200%' - fail-on-alert: true + persist-credentials: false - clang-format: - name: Clang Format - runs-on: ubuntu-latest - if: github.event_name == 'pull_request' - steps: - - uses: actions/checkout@v4 - name: Install Clang-Format 22 run: | wget https://apt.llvm.org/llvm.sh @@ -123,17 +90,21 @@ jobs: sudo ./llvm.sh 22 sudo apt-get update sudo apt-get install -y clang-format-22 + - name: Check formatting run: | find include \( -name "*.h" -o -name "*.cpp" \) | \ xargs clang-format-22 --dry-run --Werror clang-tidy: - name: Clang Tidy + name: Run Clang Tidy runs-on: ubuntu-latest - if: github.event_name == 'pull_request' + steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Install Clang-Tidy 19 run: | wget https://apt.llvm.org/llvm.sh @@ -141,15 +112,16 @@ jobs: sudo ./llvm.sh 19 sudo apt-get update sudo apt-get install -y clang-tidy-19 + - name: Check tidy run: | find include \( -name "*.h" -o -name "*.cpp" \) | \ xargs -I{} clang-tidy-19 {} --header-filter="include/.*" -- -x c++ -std=c++20 -I include all-checks: - name: All Checks + name: Check Results runs-on: ubuntu-latest - if: github.event_name == 'pull_request' needs: [unittests, clang-format, clang-tidy] + steps: - run: echo "All checks passed" From f4ffaf23fcfa37992fe107ab3e492863723515e5 Mon Sep 17 00:00:00 2001 From: nevergiveupcpp Date: Fri, 23 Oct 2026 12:03:21 +0200 Subject: [PATCH 3/6] ci: add github release workflow --- .github/workflows/release.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e69de29..ac00d23 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -0,0 +1,34 @@ +name: Release + +on: + push: + tags: ["v*"] + +permissions: + contents: read + +jobs: + release: + name: Publish Release + runs-on: ubuntu-latest + + permissions: + contents: write + + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + persist-credentials: false + + - name: Publish GitHub Release + run: | + gh release create "$GITHUB_REF_NAME" \ + include/obfuscxx/obfuscxx.h \ + --verify-tag \ + --title "obfuscxx $GITHUB_REF_NAME" \ + --generate-notes \ No newline at end of file From d7e6323c6019fe3f67b388a57c67fdc24d22b75e Mon Sep 17 00:00:00 2001 From: nevergiveupcpp Date: Fri, 23 Oct 2026 12:05:00 +0200 Subject: [PATCH 4/6] ci: add vcpkg port update workflow --- .github/scripts/update-vcpkg.sh | 36 ++++++++ .github/workflows/vcpkg.yml | 145 ++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 .github/scripts/update-vcpkg.sh create mode 100644 .github/workflows/vcpkg.yml diff --git a/.github/scripts/update-vcpkg.sh b/.github/scripts/update-vcpkg.sh new file mode 100644 index 0000000..384f582 --- /dev/null +++ b/.github/scripts/update-vcpkg.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +version=${TAG#v} +history="$VCPKG_ROOT/versions/o-/obfuscxx.json" +registered=$(jq --arg version "$version" 'any(.versions[]; .version == $version)' "$history") + +if [[ $registered == true ]]; then + echo "obfuscxx $version is already in the vcpkg registry" + echo "status=error" >> "$GITHUB_OUTPUT" + exit 1 +fi + +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT + +tag=$(jq -rn --arg tag "$TAG" '$tag | @uri') + +curl --fail --location --output "$tmp/source.tar.gz" \ + "https://github.com/$GITHUB_REPOSITORY/archive/$tag.tar.gz" + +hash=$(sha512sum "$tmp/source.tar.gz") +hash=${hash%% *} + +portfile="$VCPKG_ROOT/ports/obfuscxx/portfile.cmake" +pattern='^([[:blank:]]*SHA512[[:blank:]]+)[[:xdigit:]]{128}([[:space:]]*)$' + +sed -Ei "s/$pattern/\1${hash}\2/" "$portfile" + +manifest="$VCPKG_ROOT/ports/obfuscxx/vcpkg.json" + +jq --arg version "$version" '.version = $version | del(."port-version")' \ + "$manifest" > "$tmp/vcpkg.json" +mv "$tmp/vcpkg.json" "$manifest" + +echo "status=ok" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/vcpkg.yml b/.github/workflows/vcpkg.yml new file mode 100644 index 0000000..61e322f --- /dev/null +++ b/.github/workflows/vcpkg.yml @@ -0,0 +1,145 @@ +name: Update Vcpkg + +on: + workflow_dispatch: + inputs: + tag: + required: true + type: string + +permissions: + contents: read + +env: + TAG: ${{ inputs.tag }} + VCPKG_BRANCH: update/obfuscxx-${{ inputs.tag }} + +jobs: + vcpkg: + name: Update Vcpkg Port + runs-on: ubuntu-latest + + outputs: + base: ${{ steps.commit.outputs.base }} + + env: + VCPKG_ROOT: ${{ github.workspace }}/vcpkg + + defaults: + run: + shell: bash + working-directory: vcpkg + + steps: + - name: Check published release + working-directory: ${{ github.workspace }} + env: + GH_TOKEN: ${{ github.token }} + run: | + draft=$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json isDraft --jq '.isDraft') + if [[ $draft == true ]]; then + echo "Release $TAG is still a draft" >&2 + exit 1 + fi + + - name: Checkout repository + uses: actions/checkout@v5 + with: + path: project + persist-credentials: false + + - name: Checkout vcpkg + uses: actions/checkout@v5 + with: + repository: microsoft/vcpkg + ref: master + fetch-depth: 0 + path: vcpkg + persist-credentials: false + + - name: Update port version and source hash + id: port + run: bash "$GITHUB_WORKSPACE/project/.github/scripts/update-vcpkg.sh" + + - name: Bootstrap vcpkg + if: steps.port.outputs.status == 'ok' + run: ./bootstrap-vcpkg.sh -disableMetrics + + - name: Update version database + id: commit + if: steps.port.outputs.status == 'ok' + run: | + ./vcpkg format-manifest ports/obfuscxx/vcpkg.json + git config user.name "nevergiveupcpp" + git config user.email "nevergiveupcxx@gmail.com" + git switch --create "$VCPKG_BRANCH" + git add ports/obfuscxx + git commit -m "[obfuscxx] Update to ${TAG#v}" + ./vcpkg x-add-version obfuscxx + git add versions/baseline.json versions/o-/obfuscxx.json + git commit --amend --no-edit + echo "base=$(git rev-parse HEAD^)" >> "$GITHUB_OUTPUT" + git bundle create "$RUNNER_TEMP/vcpkg.bundle" "$VCPKG_BRANCH" "^HEAD^" + + - name: Upload prepared update + if: steps.port.outputs.status == 'ok' + uses: actions/upload-artifact@v6 + with: + name: vcpkg-update + path: ${{ runner.temp }}/vcpkg.bundle + if-no-files-found: error + + publish: + name: Publish Vcpkg Port + needs: vcpkg + runs-on: ubuntu-latest + + env: + VCPKG_FORK: ${{ github.repository_owner }}/vcpkg + + defaults: + run: + shell: bash + working-directory: vcpkg + + steps: + - name: Checkout vcpkg base + uses: actions/checkout@v5 + with: + repository: microsoft/vcpkg + ref: ${{ needs.vcpkg.outputs.base }} + fetch-depth: 0 + path: vcpkg + persist-credentials: false + + - name: Download prepared update + uses: actions/download-artifact@v7 + with: + name: vcpkg-update + path: ${{ runner.temp }}/vcpkg-update + + - name: Import prepared commit + run: | + git fetch --no-tags "$RUNNER_TEMP/vcpkg-update/vcpkg.bundle" "refs/heads/$VCPKG_BRANCH" + + - name: Open vcpkg pull request + env: + GH_TOKEN: ${{ secrets.VCPKG_PR_TOKEN }} + run: | + : "${GH_TOKEN:?Set the VCPKG_PR_TOKEN repository secret}" + gh auth setup-git --hostname github.com + git remote add fork "https://github.com/${VCPKG_FORK}.git" + git push fork "FETCH_HEAD:refs/heads/${VCPKG_BRANCH}" + + gh pr create \ + --repo microsoft/vcpkg \ + --base master \ + --head "${VCPKG_FORK%%/*}:${VCPKG_BRANCH}" \ + --title "[obfuscxx] Update to ${TAG#v}" \ + --body '- [x] Changes comply with the [maintainer guide](https://github.com/microsoft/vcpkg-docs/blob/main/vcpkg/contributing/maintainer-guide.md). + - [x] SHA512s are updated for each updated download. + - [x] The "supports" clause reflects platforms that may be fixed by this new version, or no changes were necessary. + - [x] Any fixed [CI baseline](https://github.com/microsoft/vcpkg/blob/master/scripts/ci.baseline.txt) and [CI feature baseline](https://github.com/microsoft/vcpkg/blob/master/scripts/ci.feature.baseline.txt) entries are removed from that file, or no entries needed to be changed. + - [x] All patch files in the port are applied and succeed. + - [x] The version database is updated by running `./vcpkg x-add-version obfuscxx` and committing the result. + - [x] Exactly one version is added in each modified versions file.' From cb703b3fad33d4b1850172a8dd6675e1a3ca1d2e Mon Sep 17 00:00:00 2001 From: nevergiveupcpp Date: Fri, 23 Oct 2026 15:25:23 +0200 Subject: [PATCH 5/6] feat: add preprocessor macro for disabling obfuscxx --- include/obfuscxx/obfuscxx.h | 157 +++++++++++++++++------------------- 1 file changed, 75 insertions(+), 82 deletions(-) diff --git a/include/obfuscxx/obfuscxx.h b/include/obfuscxx/obfuscxx.h index 9fb75e0..3c64c3b 100644 --- a/include/obfuscxx/obfuscxx.h +++ b/include/obfuscxx/obfuscxx.h @@ -28,6 +28,7 @@ using max_align_t = double; #include +#if !defined(OBFUSCXX_DISABLE) #if defined(__aarch64__) || defined(_M_ARM64) || defined(__ARM_NEON) #include #elif defined(_WIN32) @@ -52,6 +53,7 @@ using max_align_t = double; #elif defined(_MSC_VER) #define OBFUSCXX_VOLATILE volatile #endif +#endif #if defined(__clang__) || defined(__GNUC__) #define OBFUSCXX_FORCEINLINE __attribute__((always_inline)) inline @@ -59,6 +61,7 @@ using max_align_t = double; #define OBFUSCXX_FORCEINLINE __forceinline #endif +#if !defined(OBFUSCXX_DISABLE) #if defined(_KERNEL_MODE) || defined(_WIN64_DRIVER) #define _mm256_extract_epi32(vec, idx) (((int32_t*)&(vec))[(idx)]) #endif @@ -74,8 +77,9 @@ using max_align_t = double; #define OBFUSCXX_MEM_BARRIER(...) _ReadWriteBarrier(); #define OBFUSCXX_MEM_BARRIER_VEC(v0, v1, sum) _ReadWriteBarrier(); #endif +#endif -#ifndef OBFUSCXX_DISABLE_WARNS +#if !defined(OBFUSCXX_DISABLE_WARNS) && !defined(OBFUSCXX_DISABLE) #define OBFUSCXX_RUNTIME_WARNING \ [[deprecated( \ "OBFUSCXX: Runtime set() uses encrypt method without SIMD obfuscation. For better protection, " \ @@ -151,6 +155,7 @@ namespace ngu { } } // namespace detail +#if !defined(OBFUSCXX_DISABLE) template struct simd; #if defined(__aarch64__) || defined(_M_ARM64) @@ -239,6 +244,7 @@ namespace ngu { }; #endif #endif +#endif #define OBFUSCXX_HASH(s) ngu::detail::hash_compile_time(s) #define OBFUSCXX_HASH_RT(s) ngu::detail::hash_runtime(s) @@ -283,16 +289,17 @@ namespace ngu { static constexpr std::size_t type_size = std::is_array_v ? std::extent_v : 1; + struct passkey { + explicit passkey() = default; + }; + +#if !defined(OBFUSCXX_DISABLE) static constexpr std::size_t simd_alignment = OBFUSCXX_HAS_AVX2 ? 32 : 16; static constexpr std::size_t storage_multiple = OBFUSCXX_HAS_AVX2 ? 8 : 4; static constexpr std::size_t storage_alignment = is_array ? simd_alignment : alignof(std::uint64_t); static constexpr std::size_t storage_size = is_array ? detail::align_up(type_size, storage_multiple) : type_size; - struct passkey { - explicit passkey() = default; - }; - static constexpr std::uint64_t seed{Entropy}; static constexpr std::uint64_t iv[8] = { 0xcbf43b227a01fe5aULL ^ seed, @@ -557,118 +564,120 @@ namespace ngu { return cached; #else return false; +#endif + } +#endif + + constexpr void store(type value, std::size_t i) { +#if defined(OBFUSCXX_DISABLE) + storage_[i] = value; +#else + storage_[i] = encrypt(value); #endif } public: explicit consteval obfuscxx(passkey) { +#if !defined(OBFUSCXX_DISABLE) for (std::size_t i{}; i < type_size; ++i) { storage_[i] = seed ^ iv[i & iv_size]; } +#endif } explicit consteval obfuscxx(type val) : obfuscxx(passkey{}) { - storage_[0] = encrypt(val); + store(val, 0); } explicit consteval obfuscxx(type (&arr)[type_size]) : obfuscxx(passkey{}) { for (std::size_t i{}; i < type_size; ++i) { - storage_[i] = encrypt(arr[i]); + store(arr[i], i); } } explicit consteval obfuscxx(const type (&arr)[type_size]) : obfuscxx(passkey{}) { for (std::size_t i{}; i < type_size; ++i) { - storage_[i] = encrypt(arr[i]); + store(arr[i], i); } } consteval obfuscxx(const std::initializer_list& list) : obfuscxx(passkey{}) { for (std::size_t i{}; const auto& v : list) { - storage_[i++] = encrypt(v); + store(v, i++); } } - OBFUSCXX_FORCEINLINE type get() const - requires is_single - { + OBFUSCXX_FORCEINLINE type get() const requires is_single { +#if defined(OBFUSCXX_DISABLE) + return storage_[0]; +#else volatile const std::uint64_t* ptr = &storage_[0]; std::uint64_t val = *ptr; return decrypt(val); +#endif } - OBFUSCXX_FORCEINLINE type get(const std::size_t i) const - requires is_array - { + OBFUSCXX_FORCEINLINE type get(const std::size_t i) const requires is_array { +#if defined(OBFUSCXX_DISABLE) + return storage_[i]; +#else volatile const std::uint64_t* ptr = &storage_[i]; std::uint64_t val = *ptr; return decrypt(val); +#endif } - OBFUSCXX_FORCEINLINE void copy_to(type* out, const std::size_t count) const - requires is_array - { + OBFUSCXX_FORCEINLINE void copy_to(type* out, const std::size_t count) const requires is_array { std::size_t effective_count = (count < type_size) ? count : type_size; +#if defined(OBFUSCXX_DISABLE) + for (std::size_t i{}; i < effective_count; ++i) { + out[i] = storage_[i]; + } +#else decrypt_vectorized(storage_, out, effective_count); +#endif } - OBFUSCXX_RUNTIME_WARNING OBFUSCXX_FORCEINLINE void set(type val) - requires is_single - { - storage_[0] = encrypt(val); + OBFUSCXX_RUNTIME_WARNING OBFUSCXX_FORCEINLINE void set(type val) requires is_single { + store(val, 0); } - OBFUSCXX_RUNTIME_WARNING OBFUSCXX_FORCEINLINE void set(type val, const std::size_t i) - requires is_array - { - storage_[i] = encrypt(val); + OBFUSCXX_RUNTIME_WARNING OBFUSCXX_FORCEINLINE void set(type val, const std::size_t i) requires is_array { + store(val, i); } OBFUSCXX_RUNTIME_WARNING OBFUSCXX_FORCEINLINE void set(const std::initializer_list& list) - requires is_array - { + requires is_array { for (std::size_t i{}; const auto& val : list) { if (i < type_size) { - storage_[i++] = encrypt(val); + store(val, i++); } } } - OBFUSCXX_FORCEINLINE type operator()() const - requires is_single - { + OBFUSCXX_FORCEINLINE type operator()() const requires is_single { return get(); } - OBFUSCXX_FORCEINLINE type operator[](const std::size_t i) const - requires is_array - { + OBFUSCXX_FORCEINLINE type operator[](const std::size_t i) const requires is_array { return get(i); } - OBFUSCXX_FORCEINLINE obfuscxx& operator=(type val) - requires is_single - { + OBFUSCXX_FORCEINLINE obfuscxx& operator=(type val) requires is_single { set(val); return *this; } - OBFUSCXX_FORCEINLINE obfuscxx& operator=(const std::initializer_list& list) - requires is_array - { + OBFUSCXX_FORCEINLINE obfuscxx& operator=(const std::initializer_list& list) requires is_array { set(list); return *this; } - template OBFUSCXX_FORCEINLINE bool operator==(const rebind& rhs) const - requires is_single - { + template OBFUSCXX_FORCEINLINE bool operator==(const rebind& rhs) const requires is_single { return get() == rhs.get(); } - template OBFUSCXX_FORCEINLINE bool operator==(const rebind& rhs) const - requires is_array - { + template OBFUSCXX_FORCEINLINE bool operator==(const rebind& rhs) const requires is_array { for (std::size_t i{}; i < type_size; ++i) { if (get(i) != rhs.get(i)) { return false; @@ -681,9 +690,7 @@ namespace ngu { return !(*this == rhs); } - OBFUSCXX_FORCEINLINE operator type() const - requires is_single - { + OBFUSCXX_FORCEINLINE operator type() const requires is_single { return get(); } @@ -712,40 +719,32 @@ namespace ngu { } template OBFUSCXX_FORCEINLINE type operator*(const rebind& rhs) const - requires(!is_single_pointer) - { + requires(!is_single_pointer) { return get() * rhs.get(); } template OBFUSCXX_FORCEINLINE type operator/(const rebind& rhs) const - requires(!is_single_pointer) - { + requires(!is_single_pointer) { return get() / rhs.get(); } template OBFUSCXX_FORCEINLINE obfuscxx& operator+=(const rebind& rhs) - requires(!is_single_pointer) - { + requires(!is_single_pointer) { set(get() + rhs.get()); return *this; } template OBFUSCXX_FORCEINLINE obfuscxx& operator-=(const rebind& rhs) - requires(!is_single_pointer) - { + requires(!is_single_pointer) { set(get() - rhs.get()); return *this; } - OBFUSCXX_FORCEINLINE type operator->() - requires is_single_pointer - { + OBFUSCXX_FORCEINLINE type operator->() requires is_single_pointer { return get(); } - OBFUSCXX_FORCEINLINE type& operator*() - requires is_single_pointer - { + OBFUSCXX_FORCEINLINE type& operator*() requires is_single_pointer { return *get(); } @@ -770,16 +769,14 @@ namespace ngu { } }; - iterator begin() const - requires is_array - { + iterator begin() const requires is_array { return {this, 0}; } - iterator end() const - requires is_array - { + + iterator end() const requires is_array { return {this, type_size}; } + static constexpr std::size_t size() { return type_size; } @@ -790,14 +787,10 @@ namespace ngu { static constexpr bool is_wchar = std::is_same_v || std::is_same_v; public: - operator const char*() const - requires is_char - { + operator const char*() const requires is_char { return data; } - operator const wchar_t*() const - requires is_wchar - { + operator const wchar_t*() const requires is_wchar { return data; } @@ -844,9 +837,7 @@ namespace ngu { ArrayT data[N]; }; - OBFUSCXX_FORCEINLINE string_copy to_string() const - requires(is_char || is_wchar) - { + OBFUSCXX_FORCEINLINE string_copy to_string() const requires(is_char || is_wchar) { string_copy result{}; if constexpr (is_array) { copy_to(result.data, type_size); @@ -856,16 +847,18 @@ namespace ngu { return result; } - OBFUSCXX_FORCEINLINE array_copy to_array() const - requires(is_array) - { + OBFUSCXX_FORCEINLINE array_copy to_array() const requires(is_array) { array_copy result{}; copy_to(result.data, type_size); return result; } private: +#if defined(OBFUSCXX_DISABLE) + std::remove_cv_t storage_[type_size]{}; +#else alignas(storage_alignment) OBFUSCXX_VOLATILE std::uint64_t storage_[storage_size]{}; +#endif }; } // namespace ngu From b22be639b3adf07f56a2ebe1701d07beac94dcae Mon Sep 17 00:00:00 2001 From: nevergiveupcpp Date: Fri, 23 Oct 2026 16:37:14 +0200 Subject: [PATCH 6/6] docs: update preprocessor macro documentation --- README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d97ecb1..9463a0c 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ XTEA was chosen for several reasons. The primary one is its solid cryptographic When working with scalar data, SIMD instructions are used not for vectorization, but to complicate static analysis, data extraction, and emulation-based deobfuscation. For vector data (arrays, strings), SIMD is used to its full potential, enabling parallel decryption without compromising protection quality. ### SIMD platform support -The library supports multiple SIMD instruction sets depending on the target architecture and compiler flags. On MSVC, SSE2 is used as a fallback by default, this ensures compatibility with both older and newer processors. If support for older processors is not required, define the OBFUSCXX_MSVC_FORCE_AVX2 macro. +The library supports multiple SIMD instruction sets depending on the target architecture and compiler flags. On MSVC, SSE2 is used as a fallback by default, this ensures compatibility with both older and newer processors. See [Configuration](#configuration) to force AVX2 on MSVC. ## Decompilation view The screenshots show only a small portion of the int main() function. In reality, the function can grow to around 250 lines depending on the compiler. @@ -35,8 +35,6 @@ The screenshots show only a small portion of the int main() function. In reality ## Installation -> To disable the SSE2 fallback on MSVC, define `OBFUSCXX_MSVC_FORCE_AVX2` before including the header or in your CMakeLists.txt. - ### Single header Just add the `include/` directory to your include path and use `#include ` @@ -47,9 +45,21 @@ find_package(obfuscxx CONFIG REQUIRED) target_link_libraries(your_target PRIVATE obfuscxx::obfuscxx) ``` +## Configuration + +Define the following preprocessor macros before including `` or via CMake. Leave them undefined to use the default behavior. + +| Macro | Description | +|-------|-------------| +| `OBFUSCXX_DISABLE` | Disables obfuscation while preserving the public API. Values are stored unencrypted | +| `OBFUSCXX_DISABLE_WARNS` | Suppresses the library’s warnings | +| `OBFUSCXX_MSVC_FORCE_AVX2` | Forces AVX2 decryption on MSVC without the SSE2 fallback. Requires an AVX2-capable CPU | + ## Examples ### Basic ```cpp +#include + int main() { using namespace ngu;