A header-only C++ library that prevents signature-based detection through compile-time polymorphic types. Each build generates different binary signatures for mathematically identical operations.
The Defensive Toolkit provides types like uint32_dt<Seed> that wrap standard integral types. These types overload operators (^, |, &, +, -, etc.) to dispatch to mathematically equivalent variants selected at compile-time based on a seed value. This creates signature variance while maintaining:
- Zero runtime overhead - all variant selection is compile-time only
- Mathematical correctness - Z3 formal verification proves equivalence
- Easy integration - header-only, drop-in replacement for standard types
#include <defensive_toolkit/toolkit.h>
// SIMPLE: Use mono_* for consistent types that interoperate
mono_uint32 hash{2166136261u};
mono_uint32 value{42};
// Operations dispatch to variants (e.g., XOR might use: (a|b) & ~(a&b))
hash = hash ^ value;
hash = hash * 16777619u;
// Get underlying value
std::uint32_t result = hash.Get();Each arithmetic/bitwise operation has multiple mathematically equivalent implementations:
| Operation | Native | Variant Examples |
|---|---|---|
| XOR | a ^ b |
(a|b) & ~(a&b), (a&~b) | (~a&b), (a+b) - ((a&b)<<1) |
| OR | a | b |
(a&b) + (a^b), (a^b) | (a&b) |
| AND | a & b |
(a|b) - (a^b), ~(~a | ~b) |
| ADD | a + b |
(a^b) + ((a&b)<<1), a - (~b) - 1 |
| MUL | a * c |
shift-add decomposition |
// Seed generation from __TIME__ and __DATE__
inline constexpr std::uint32_t DT_BUILD_SEED = /* varies each build */;
// Per-use unique seeds via __COUNTER__
#define DT_AUTO_SEED DT_UNIQUE_SEED(DT_BUILD_SEED)
// Template selects variant at compile-time
template<std::uint32_t Seed>
class PolyInt {
T operator^(const PolyInt& other) const {
constexpr auto variant = SelectVariant(Seed, OpType::XOR);
return XorImpl<T, variant>::Apply(m_value, other.m_value);
}
};Different builds select different variants:
Build 1 (10:15:30): XOR → Variant 2 → "(a&~b) | (~a&b)"
Build 2 (10:16:45): XOR → Variant 4 → "(a|b) - (a&b)"
Build 3 (10:18:00): XOR → Variant 0 → "a ^ b" (native)
Static signatures fail because each build produces different binary code for the same algorithm.
The toolkit includes SIMD (Single Instruction, Multiple Data) variants for scalar operations. These variants use SIMD instructions to compute scalar results, adding another layer of signature variance.
| Platform | Instruction Set | Compiler Flag |
|---|---|---|
| x86_64 | SSE2 | -msse2 |
| x86_64 | AVX2 | -mavx2 |
| x86_64 | AVX-512 | -mavx512f |
| ARM64 | NEON | Auto-detected |
When SIMD is available, additional operation variants are included:
// Example: XOR with SSE2
template<IntegralType T>
T XorViaSIMD_SSE2(T a, T b) noexcept
{
__m128i va = _mm_cvtsi32_si128(a);
__m128i vb = _mm_cvtsi32_si128(b);
__m128i result = _mm_xor_si128(va, vb);
return _mm_cvtsi128_si32(result);
}Control when SIMD variants are used via compile-time configuration:
// Never use SIMD for scalar operations (default for compatibility)
#define DT_SIMD_USAGE ::defensive_toolkit::detail::SIMDUsage::Never
// Always use SIMD when available
#define DT_SIMD_USAGE ::defensive_toolkit::detail::SIMDUsage::Always
// Use SIMD probabilistically based on seed (~50% of the time)
#define DT_SIMD_USAGE ::defensive_toolkit::detail::SIMDUsage::ProbabilisticDefault is Probabilistic, which uses SIMD approximately 50% of the time based on seed value.
| Operation | Scalar Variants | +SSE2 | +AVX2 | +NEON |
|---|---|---|---|---|
| XOR | 5 | +1 | +2 | +1 |
| OR | 3 | +1 | +1 | +1 |
| AND | 3 | +1 | +1 | +1 |
| ADD | 3 | +1 | +2 | +1 |
| SUB | 2 | +1 | +1 | +1 |
Total XOR variants:
- Scalar only: 5
- With SSE2: 6
- With AVX2: 7
- With NEON: 6
# Build and run SIMD demonstration
make SIMD=sse2
./build/simd_demoThe demo shows:
- CPU feature detection
- SIMD vector operations (128-bit, 256-bit, 512-bit)
- Performance benchmarks
- Polymorphic SIMD operations
- C++26/latest compiler (Clang or GCC)
- Google Test (for tests)
- Python 3 + Z3 (for verification)
make # Build examples with Clang
make CXX=g++ # Build with GCC
make test # Build and run tests
make verify # Run Z3 formal verification
# SIMD builds (x86_64 only)
make SIMD=sse2 # Build with SSE2 SIMD support
make SIMD=avx2 # Build with AVX2 SIMD support
make SIMD=avx512 # Build with AVX-512 SIMD supportNote: ARM builds automatically use NEON SIMD instructions when available (no additional flags needed).
| Target | Description |
|---|---|
make |
Build examples (default) |
make examples |
Build example programs |
make tests |
Build test suite |
make test |
Build and run all tests |
make verify |
Run Z3 verification |
make clean |
Remove build artifacts |
make info |
Show compiler information |
make help |
Show all targets |
Visual Studio solution and project files are provided for Windows development:
# Open in Visual Studio
start DefensiveToolkit.slnAvailable configurations:
- Debug/Release: Standard builds
- Debug_SSE2/Release_SSE2: SSE2 SIMD builds
- Debug_AVX2/Release_AVX2: AVX2 SIMD builds
| Platform | Architecture | SIMD Support |
|---|---|---|
| Windows | x86_64 | SSE2, AVX2, AVX-512 |
| Linux | x86_64 | SSE2, AVX2, AVX-512 |
| macOS | x86_64 | SSE2, AVX2 |
| macOS | ARM64 (Apple Silicon) | NEON |
| Linux | ARM64 | NEON |
The easiest way to use the toolkit is with mono_* and poly_* macros:
#include <defensive_toolkit/toolkit.h>
// MONOMORPHIC: All instances share the same build seed
// - Same operation variants throughout the program
// - Types can interoperate (same underlying type)
// - Still varies build-to-build
mono_uint32 a{10};
mono_uint32 b{20};
auto c = a ^ b; // Works - same type
// POLYMORPHIC: Each usage gets a unique seed
// - Different operation variants for maximum diversity
// - Types cannot interoperate (different underlying types)
poly_uint32 x{10}; // Unique seed
poly_uint32 y{20}; // Different unique seed
// x ^ y won't compile - different types| Macro | Behavior | Use Case |
|---|---|---|
mono_uint32 |
Same seed for all | Functions, classes, interoperating values |
poly_uint32 |
Unique seed per use | Maximum signature diversity |
Available macro types:
- Unsigned:
mono_uint8,mono_uint16,mono_uint32,mono_uint64 - Signed:
mono_int8,mono_int16,mono_int32,mono_int64 - Platform:
mono_size,mono_uintptr,mono_intptr,mono_ptrdiff - Poly versions: Same names with
poly_prefix
For explicit seed control, use template aliases:
#include <defensive_toolkit/toolkit.h>
using namespace defensive_toolkit;
// Fixed-width types with explicit seed
uint8_dt<Seed> u8;
uint16_dt<Seed> u16;
uint32_dt<Seed> u32;
uint64_dt<Seed> u64;
int8_dt<Seed> i8;
int16_dt<Seed> i16;
int32_dt<Seed> i32;
int64_dt<Seed> i64;
// Platform-specific types
size_dt<Seed> sz;
uintptr_dt<Seed> ptr;
ptrdiff_dt<Seed> diff;
// Character types
char_dt<Seed> c;
char16_dt<Seed> c16;
char32_dt<Seed> c32;// Build seed - changes every compilation
constexpr auto seed1 = DT_BUILD_SEED;
// Unique seed per use (uses __COUNTER__)
constexpr auto seed2 = DT_UNIQUE_SEED(DT_BUILD_SEED);
constexpr auto seed3 = DT_UNIQUE_SEED(DT_BUILD_SEED);
// seed2 != seed3
// Automatic unique seed (recommended)
uint32_dt<DT_AUTO_SEED> value{42};mono_uint32 a{10};
mono_uint32 b{20};
// Bitwise operations
auto xorResult = a ^ b;
auto orResult = a | b;
auto andResult = a & b;
auto notResult = ~a;
// Arithmetic operations
auto sum = a + b;
auto diff = a - b;
auto product = a * b; // Native multiplication
// Shift operations
auto shifted = a << 5;
// Multiplication by compile-time constant (provides signature variance)
auto fnvProduct = a.MultiplyBy<16777619u>();
// Compound assignment
a ^= b;
a += b;
a *= b;
a <<= 3;
// Comparison (always uses native - correctness critical)
bool equal = (a == b);
auto ordering = (a <=> b);
// Conversion
std::uint32_t native = a.Get();
std::uint32_t native2 = static_cast<std::uint32_t>(a);Prove mathematical equivalence of all variants:
cd verify
pip install -r requirements.txt
python3 verify_ops.pyAll checks should return UNSAT (proven equivalent). See verify/README.md for details.
SIMD scalar operations (SSE2, AVX2, NEON) are mathematically equivalent to their scalar counterparts by design - they use the same underlying CPU instructions, just loaded/stored via SIMD registers. To verify:
-
Functional Equivalence: SIMD intrinsics (
_mm_xor_si128,veor_u32, etc.) map directly to native instructions -
Z3 Verification: SIMD variants can be verified by treating them as the native operation:
# In verify_ops.py, SIMD variants are equivalent to variant 0 (native) simd_result = xor_native(a, b) # Same as SIMD via registers solver.add(simd_result != xor_native(a, b)) assert solver.check() == unsat # Proven equivalent
-
Runtime Testing: Unit tests verify SIMD operations produce identical results:
make test # Tests include SIMD variant verification
Note: The toolkit uses SIMD for signature variance (different instruction encodings), not for algorithm changes. Mathematical correctness is preserved.
Runtime validation with random testing:
make testTests verify:
- Operation correctness across 1000+ random inputs
- Consistency across different seeds
- Type behavior (construction, comparison, etc.)
- Overflow behavior matches native types
// Using mono_* for simple, interoperable types
mono_uint32 FNV1aHash(std::string_view str)
{
mono_uint32 hash{2166136261u};
for (unsigned char c : str)
{
hash = hash ^ mono_uint32{c}; // Variant XOR
hash = hash.MultiplyBy<16777619u>(); // Variant MUL
}
return hash;
}
// All calls use same operation variants, results interoperate
auto hash1 = FNV1aHash("test");
auto hash2 = FNV1aHash("hello");
bool different = (hash1 != hash2); // Works - same type// Using templates for maximum diversity per call site
template<std::uint32_t Seed>
uint32_dt<Seed> FNV1aHash(std::string_view str)
{
uint32_dt<Seed> hash{2166136261u};
for (unsigned char c : str)
{
hash = hash ^ uint32_dt<Seed>{c};
hash = hash.template MultiplyBy<16777619u>();
}
return hash;
}
// Each call site uses different operation variants
auto hash1 = FNV1aHash<DT_AUTO_SEED>("test");
auto hash2 = FNV1aHash<DT_AUTO_SEED>("test");
// hash1.Get() == hash2.Get() (same result, different code paths)See examples/string_lookup.cpp for a complete example using mono_uint32:
- FNV-1a hash implementation
- String lookup table class
- CRC-32 checksum
- Demonstrates interoperating monomorphic types
Run:
make examples
./build/string_lookupObfTypes/
├── include/defensive_toolkit/
│ ├── config.h # Seed generation
│ ├── operations.h # Operation variants
│ ├── types.h # PolyInt wrapper
│ ├── simd.h # SIMD vector types
│ ├── simd_scalar.h # x86 SIMD scalar variants
│ ├── simd_scalar_neon.h # ARM NEON scalar variants
│ └── toolkit.h # Master include
├── examples/
│ ├── string_lookup.cpp # Hash and lookup demo
│ ├── name_lookup.cpp # Simple name hash demo
│ └── simd_demo.cpp # SIMD demonstration
├── tests/
│ ├── test_operations.cpp # Operation tests
│ └── test_types.cpp # Type behavior tests
├── verify/
│ ├── verify_ops.py # Z3 verification
│ ├── llm_prompt_z3_gen.md # Auto-generate verification
│ ├── requirements.txt # Python dependencies
│ └── README.md
├── DefensiveToolkit.sln # Visual Studio solution
├── DefensiveToolkit.vcxproj # VS project (library)
├── Examples.vcxproj # VS project (examples)
├── Tests.vcxproj # VS project (tests)
├── Makefile # Build system
├── .gitignore
└── README.md
- Zero Runtime Overhead - All polymorphism resolved at compile-time via templates
- Mathematical Correctness - Z3 proves variant equivalence before trusting implementation
- Build-Time Variance - Every compilation produces different binary via
__TIME__/__DATE__ - Per-Use Variance -
__COUNTER__enables multiple variants in same build - Type Safety - Concepts constrain templates; comparison operators never use variants
- No Exceptions - Pure header-only, types are infallible
- Modern C++26 - Leverages
consteval, concepts, spaceship operator
- Add variant implementation to
include/defensive_toolkit/operations.h - Use
verify/llm_prompt_z3_gen.mdto generate Z3 verification - Add verification to
verify/verify_ops.py - Run
make verifyto prove equivalence - Run
make testto validate runtime correctness
See verify/llm_prompt_z3_gen.md for automated workflow using LLMs.
- Zero overhead: Release builds optimize to same performance as native operations
- Binary size: Each variant adds ~10-50 bytes per instantiation
- Compile time: Minimal impact (~5-10% increase)
Benchmark:
# Native loop
for (int i = 0; i < 1M; i++) result ^= data[i];
# PolyInt loop (same speed in -O2/-O3)
for (int i = 0; i < 1M; i++) result = result ^ PolyInt{data[i]};- Requires C++26/latest (uses
consteval, concepts, `<=>') - Header-only (can increase compile time for large projects)
- No floating-point support (integral types only)
Copyright 2025 DOTW Limited. All rights reserved.
- Z3 Theorem Prover: https://github.com/Z3Prover/z3
- C++26 Draft: https://eel.is/c++draft/
- Bit Twiddling Hacks: https://graphics.stanford.edu/~seander/bithacks.html