The Shape of an Operation Is a Signature: Inside ObfTypes
How compile-time equivalence classes, seeded operator variants, SIMD backends, and Z3 proofs can shift brittle static signatures without pretending behavior disappears.
Most obfuscation writeups start with the wrong noun.
They start with evasion, as if the interesting part is whether a detector misses a sample. That question matters in a real assessment, but it is too broad for the engineering mechanism. Before talking about signatures, endpoint products, or build variance, the load-bearing idea is simpler:
A semantic equivalence class is a set of implementations that compute the same result for a defined input domain.
ObfTypes is useful because it treats ordinary fixed-width integer operations as equivalence classes. A source-level operation such as x ^ y is not tied to one spelling, one instruction sequence, or one intermediate representation. It is a contract: for two N-bit unsigned values, produce the bitwise exclusive-or result. Several expressions satisfy that contract.
The project idea is to choose one member of that class at compile time, emit only that member into the instantiated code path, and keep the runtime behavior the same.
That is the core claim. Not universal endpoint detection and response bypass. Not a guarantee that every optimizer preserves the intended instruction shape. Not “zero overhead” in the sense of equal latency, equal code size, or identical register pressure. The narrow, defensible version is:
variant selection can happen at compile time without runtime dispatch.
Everything else depends on the operation, the compiler, the target instruction set, the optimization level, and the proof coverage for the specific variant.
The Short Version
ObfTypes wraps integral operations so the expression the compiler sees can vary by type, seed, build, or policy. For an operation such as XOR, one build might instantiate the direct operator. Another might instantiate an algebraic identity. A third might select a vectorized formulation when the target and policy allow it.
The useful properties are bounded:
- The source contract remains the native operation over a defined fixed-width domain.
- The selected variant is chosen during compilation through templates,
constexpr, orconstevalhelper logic. - The generated code path does not need a runtime switch, virtual call, function pointer table, or branch to decide which variant to execute.
- The resulting binary shape can differ across builds because the compiler receives different equivalent expressions.
- A Z3 proof can support semantic equivalence for the modeled bit-vector expression, but it does not prove a specific machine-code shape or a product-level detection outcome.
That is already enough to be interesting. A brittle byte signature that assumes one implementation shape has a harder job when the same source-level operation can appear as several equivalent data-flow graphs. A semantic analyzer, a dynamic trace, or a compiler-like simplifier has a much better starting point.
Threat Model
The honest threat model is narrow: compile-time semantic variance is aimed at brittle static matching of local instruction patterns, constants, or expression shapes in authorized research, red-team tooling, and defensive test harnesses.
It is not a general invisibility layer.
If a detector matches a specific byte sequence for a small arithmetic or bitwise routine, changing the equivalence-class member may avoid that exact pattern. If a detector lifts code to an intermediate representation, simplifies bit-vector formulas, observes runtime behavior, tracks API effects, or correlates telemetry across the process, this technique provides much less leverage.
The more precise way to say it is:
ObfTypes can create binary-shape variance for selected operations.
Binary-shape variance means the emitted code may differ in instruction mix, dependency graph, register allocation, immediates, and surrounding optimization artifacts. It does not mean the behavior disappeared.
Equivalence Before Obfuscation
Take fixed-width unsigned XOR. In C++, unsigned integer arithmetic is defined modulo 2^N, where N is the width of the type. That is the domain a proof should model. Signed overflow is a different problem because it can be undefined behavior, so signed types need either a carefully constrained contract or an unsigned internal representation.
For two unsigned values x and y, these expressions are equivalent as N-bit bit-vector formulas:
x ^ y
(x | y) & ~(x & y)
(x & ~y) | (~x & y)
(x + y) - ((x & y) << 1)
Those are not comments for a human reader. They are alternate implementations of the same operation inside one equivalence class.
The important engineering move is to make the equivalence class explicit. Once the operation is represented as “XOR over std::uint32_t” rather than “emit the token ^ and hope the resulting bytes are acceptable,” the build system or type policy can select among valid members.
Compile-Time Selection
consteval is a C++20 feature, not a C++26 feature. It is also not magic for runtime values. A consteval function must produce its result during compilation, so it is useful for choosing a variant index, validating policy, or deriving a seed-controlled decision. The operands of the obfuscated operation can still be ordinary runtime values.
A simplified shape looks like this:
#include <concepts>
#include <cstddef>
#include <cstdint>
consteval std::size_t pick_variant(std::uint64_t seed, std::size_t count) {
return count == 0 ? 0 : static_cast<std::size_t>(seed % count);
}
template <std::unsigned_integral T, std::uint64_t Seed>
constexpr T xor_equivalent(T x, T y) noexcept {
constexpr auto variant = pick_variant(Seed, 3);
if constexpr (variant == 0) {
return (x | y) & ~(x & y);
} else if constexpr (variant == 1) {
return (x & ~y) | (~x & y);
} else {
return (x + y) - ((x & y) << 1);
}
}
The if constexpr matters. Only the selected branch participates in the instantiated function body. There is no runtime selector in that function. The compiler still has full freedom to optimize the chosen expression, including the freedom to collapse it back into a canonical XOR when its optimizer recognizes the identity.
That last sentence is not a footnote. It is one of the main limits of this technique. Source-level variance is an input to code generation, not a command to the backend.
What Zero Overhead Means Here
“Zero overhead” is easy to overstate.
For this design, the defensible claim is no runtime dispatch for variant selection. A template parameter, constexpr condition, or consteval helper can decide the variant before the program runs. The emitted operation path does not need to ask which identity to execute.
That does not imply:
- same instruction count
- same latency
- same throughput
- same code size
- same register pressure
- same power behavior
- same optimizer result
Some variants may be cheaper than others after optimization. Some may be larger. Some may be optimized into the same machine code and therefore provide no binary-shape variance for a specific compiler and flag set. Claims about performance or emitted bytes require actual build artifacts, not a promise from the source expression.
SIMD Variants
SIMD variants are another equivalence-class member, not a free upgrade.
Single Instruction, Multiple Data instructions can compute lane-wise operations over vector registers. A scalar operation can sometimes be expressed by moving values into lanes, applying a vector instruction, and extracting the result. For some operation families and surrounding code shapes, vector forms can change the binary profile substantially.
The caveats are practical:
- The target CPU and operating system must support the selected instruction set.
- A build that always emits AVX2, AVX-512, or NEON is no longer portable to machines without that feature.
- A build that chooses an ISA at runtime needs feature detection and dispatch, which falls outside the no-runtime-dispatch claim.
- Lane width, signedness, saturation behavior, and shift semantics have to match the scalar contract exactly.
- Vector setup and extraction can cost more than the scalar operation.
- Wider instruction sets can affect code size, register pressure, calling convention details, and surrounding optimizer decisions.
In other words, SIMD can be a legitimate variant family when the contract and deployment target are explicit. It should not be described as a detector-blinding switch.
Proof Scope
Z3 is useful here because these operations fit naturally into bit-vector logic. For a fixed width, the proof obligation can be stated plainly:
For all x, y in BitVec(N):
variant(x, y) == native_operation(x, y)
That is a strong statement, but only inside the model. If the verifier proves the XOR identity for 32-bit bit-vectors, the proof says the formula is equivalent for every 32-bit input pair in that model. It does not say the C++ implementation is free of undefined behavior unless the implementation uses the same domain rules. It does not say the compiler emits different bytes. It does not say a detector fails. It does not prove that a SIMD intrinsic has the same behavior unless the intrinsic semantics were modeled correctly.
The useful claim map looks like this:
| Claim | Evidence | Boundary |
|---|---|---|
| Variant computes the same value | Per-width bit-vector proof | Only for modeled operation and width |
| Selection has no runtime dispatch | Template or if constexpr instantiation | Not a performance benchmark |
| Binary shape can vary | Different expressions enter codegen | Must be checked per compiler and build |
| SIMD can be equivalent | Lane-level proof or exhaustive narrow test | Requires exact ISA semantics |
| Detection impact is possible | Static pattern no longer matches that shape | Not universal evasion |
This is the difference between a useful proof and marketing language. A proof should make the safe claim easier to trust and the unsafe claim easier to reject.
Defender View
From the defender side, the lesson is not “signatures are dead.” It is that signatures over one spelling of small arithmetic are fragile.
Better approaches treat these operations as semantic families:
- Lift candidate code to an intermediate representation and simplify bit-vector formulas.
- Match data-flow properties instead of exact instruction spelling.
- Combine static features with behavior, provenance, API effects, memory permissions, and process context.
- Watch for families of generated variants rather than one byte pattern.
- Keep rules honest about what they claim: exact implementation, semantic routine, or behavioral capability.
Compile-time variance raises the cost of a narrow static rule. It does not remove the underlying computation from the program.
Non-Goals
ObfTypes, as described here, is not a packer, a loader, an anti-debugging system, or a control-flow integrity bypass. It does not make malicious behavior legitimate. It does not replace authorization, disclosure discipline, or test-scoped use.
It also does not solve every obfuscation problem. It is a focused technique for representing selected integer operations through compile-time-chosen equivalent expressions. That focus is a strength because it gives the project a concrete correctness story. Expanding the claim beyond that focus makes the correctness story worse, not better.
Limits
Several limits should stay visible:
- Compilers can canonicalize identities back into the same machine code.
- Proofs must be maintained as operations, widths, and variant families change.
- Signed arithmetic needs special care because C++ signed overflow is not modular arithmetic.
- SIMD variants need exact lane semantics and explicit ISA policy.
- Larger expressions can increase code size and register pressure.
- Semantic static analysis can recover the original operation class.
- Runtime behavior still exposes what the program does.
- This article does not provide benchmarks, disassembly, command output, or repository-wide coverage claims.
The strongest version of the idea is also the narrowest one: compile-time semantic equivalence classes let the source contract stay stable while the emitted implementation shape can vary.
That is enough. It gives builders a disciplined way to generate variance, gives proof tooling a precise target, and gives defenders a clear signal about where exact-byte assumptions stop being reliable.