SplittingSecrets is a compiler-based tool designed to harden software against Data Memory-Dependent Prefetcher (DMP) side-channels. It mitigates speculative leaks by transforming how sensitive data is stored in memory, ensuring it never resembles valid virtual addresses that hardware prefetchers might dereference.
Authors: Reshabh Kumar Sharma, Dan Grossman, David Kohlbrenner
Affiliation: University of Washington
Modern high-performance processors (such as the Apple M-series and Intel Raptor Lake) utilize Data Memory-Dependent Prefetchers (DMPs). These hardware units scan data memory for patterns that resemble pointers and speculatively prefetch the targets.
This creates a critical side-channel: if a secret key (or a derivative) in memory incidentally resembles a valid pointer, the DMP may attempt to access it. This speculative access creates measurable contention or cache state changes that an attacker can monitor to recover the secret bit-by-bit (e.g., the Augury attack).
SplittingSecrets neutralizes this threat by enforcing a "Safe Encoding" invariant: Secret data must never appear in memory as a canonical 64-bit pointer.
The defense is implemented primarily as a modification to the LLVM compiler backend, specifically targeting AArch64 (ARM64).
To prevent the DMP from recognizing a 64-bit secret as a pointer, SplittingSecrets breaks the atomicity of the store operation. A 64-bit secret is never stored contiguously in a way that forms a valid virtual address.
- Splitting: The 64-bit value is split into two 32-bit chunks: and .
- Prefixing/Masking: Each chunk is combined with a "Safe Prefix" (a high-bit pattern known to be invalid for the target virtual address space).
- Store 1:
(Safe_Prefix << 32) | S_low - Store 2:
(Safe_Prefix << 32) | S_high
Because the hardware sees two invalid addresses (or non-canonical values) instead of one valid pointer, the DMP logic is never triggered.
Unlike source-to-source transformations, SplittingSecrets operates deep within the compiler backend to guarantee safety even for compiler-generated memory traffic.
- MIR Pass (Machine IR): The primary logic resides in a Machine Intermediate Representation pass running after register allocation. This ensures that spills and fills—stores generated by the compiler when it runs out of CPU registers—are also protected. If the compiler spills a secret register to the stack, it uses the split-store mechanism described above.
- Instruction Selection: Custom lowering rules intercept explicit stores of annotated secret variables, converting them into the split instruction sequence before machine code generation.
The runtime library (dmp-rt) provides necessary support for the transformed binary, including:
- Signal handling for potential faults during development/debugging of split accesses.
- Management of "safe" memory regions if specific heap allocators are required to ensure the prefixes remain invalid in the target process's address space.
This organization hosts the complete toolchain required to build and deploy SplittingSecrets.
- dmp-llvm The modified LLVM compiler containing the SplittingSecrets AArch64 backend pass and MIR transformations.
- dmp-rt
The runtime library required by binaries compiled with
dmp-llvm. Handles environment setup and safe-region management.
- libNa A fork of the libsodium cryptography library, patched with SplittingSecrets annotations to demonstrate a fully protected cryptographic workflow.
- dmp-bench Benchmarking suite to evaluate the performance overhead of the defense on various workloads.
- dmp-test Unit test suite verifying the correctness of the split transformations and the security of the generated assembly code.
If you use this work in your research, please cite the paper:
@inproceedings{splittingsecrets2026,
title={SplittingSecrets: A Compiler-Based Defense for Preventing Data Memory-Dependent Prefetcher Side-Channels},
author={Sharma, Reshabh Kumar and Grossman, Dan and Kohlbrenner, David},
booktitle={2nd Microarchitecture Security Conference (uASC '26)},
year={2026},
month={February}
}