
gpu-instance-fingerprint distinguishes individual NVIDIA GPUs of the same model from the ordering of atomic additions alone, a hardware side channel documented here for authorized privacy and defense research.
| Tool | divagr18/gpu-instance-fingerprint — identifies which specific GPU a workload ran on, among identical chips, from atomic-addition arrival order |
| Category | GPU hardware fingerprinting / physical unclonable function (PUF) research |
| placeholder | Demonstrating and measuring GPU instance identification via atomicAdd scheduling order and passive torch.index_add_ output, with reproducible analysis scripts for defenders |
| Primary Use | Researching chip-level GPU fingerprinting in authorized labs, including the passive torch.index_add_ leak and the torch.use_deterministic_algorithms(True) mitigation |
| Safe Use | Educational and documentary analysis for authorized professionals evaluating hardware-identity side channels in owned datacenter and cloud GPU fleets; all experiments run on GPUs the operator controls |
| Telemetry Note | The active probe emits only numerical output from a custom kernel; the passive channel leaks through ordinary op output. torch.use_deterministic_algorithms(True) eliminates the passive channel at a 2.5-3.6x backward cost, and dense deterministic workloads produce bit-identical results across chips, giving defenders clear detection and mitigation boundaries |
divagr18/gpu-instance-fingerprint answers an unusual question with unusual rigor: when a cloud tenant rents an A40 or an RTX 4090, can software tell exactly which physical die it landed on, without reading a serial number, a UUID, or a privileged counter? The repository's answer is yes. A small cupy CUDA kernel, launched repeatedly on a fleet of 19 identical NVIDIA A40s, identifies the chip it ran on with 99.1% accuracy using nothing but the numbers it computes. The project ships the probes, every measurement dataset behind the published figures, and analysis scripts that reproduce each result on a laptop CPU without any GPU at all — a level of reproducibility that is rare in side-channel writeups and makes this repo valuable as a documentary artifact for authorized security research.
The core mechanism is elegant. The probe in probes/probe_puf.py launches 4096 blocks of 128 threads; each thread executes the same fixed chain of FMAs, and thread 0 of every block takes a ticket from a global counter via atomicAdd(counter, 1). That ticket is the block's arrival slot. Nothing in the input differs between chips — the only variable is which blocks reach the counter first, and that order is set by the hardware work distributor combined with per-SM manufacturing variation. Because each SM on a die runs marginally faster or slower than its siblings in a stable way, averaging over 3000 launches yields a mean arrival rank per block index that acts as a per-die signature, effectively a silicon physical unclonable function exposed through scheduling order.
The README distinguishes three channels extracted from one run. P3, the headline channel, is the mean per-block arrival rank read purely from the kernel's numerical output — no %smid register, no timers, no privileged counters. P2 bins the same slots by physical SM using the %smid register; binning averages out thermal noise, which is why P2 holds up under load, achieving 100% re-identification (18/18) after 60 seconds of full-load stress. P1, a histogram of a fixed float32 reduction, is weak at 1.20x separation because summation destroys most of the ordering information. Averaging and subtracting the cross-chip mean removes everything the chips share — architecture, driver, compiler — leaving a per-die residual that nearest-centroid classification matches against enrolled chips.
The robustness numbers deserve attention from anyone assessing this as a fingerprinting primitive. The signature survives reboots: after a container restart, verified same-die by UUID, all 12/12 measurements matched the correct chip on both channels. It generalizes across models — A40, RTX 3090 (7 chips across 4 driver versions, P3 100%), RTX 4090, and L40S. A driver confound is addressed directly: four A40s on the identical driver (580.159.04) still classify at 100% on both channels, so the residual is genuinely per-die, not a driver artifact. Statistical hygiene is present too, with LOO nearest-centroid classification, 2000-shuffle permutation tests (p = 0.0005 on the 8-chip set), and separation ratios of roughly 4-6x between-chip versus within-chip distance.
Perhaps the most consequential result for defenders is the passive channel. Beyond the custom kernel, a stock torch.index_add_ call leaks the chip identity through its ordinary output. On CUDA, index_add_ accumulates with atomics, so the order in which contributions land in each output bin is hardware-decided. In the usual dense regime the float32 sum averages the order away — every feature classifies at chance. But in a sparse, high-dynamic-range regime (4 contributions per bin, K=65536 bins, magnitudes spread from 2^-30 to 2^30 with random signs and a fixed seed), catastrophic cancellation makes each bin's sum dominated by addition order. The per-bin sign of the mean ULP residual against a float64 reference becomes a stable K-bit signature: 100% (9/9) identification among 6 A40s within one driver, 78% across mixed drivers. The README notes this regime resembles real workloads such as MoE dispatch, GNN aggregation, and embedding-bag backward passes with many collisions.
Signature capacity analysis strengthens the picture. Scoring every pair of single measurements with no enrollment averaging — pessimistic single-shot operating points — the passive K=65536 sign signature achieves an AUC of 0.952 with 11.1% EER on 6 A40s, and roughly 217 independent bits of capacity on A40, about 239 on RTX 4090. Even at K=4096 across 8 chips, capacity is around 97 bits — more than enough to index a very large GPU fleet. The active channel scores best via residual correlation (AUC 0.974, EER 9.3% on 19 chips) because its sign pattern is spatially correlated; the identity lives in the magnitudes rather than the signs.
Forgery resistance is quantified rather than asserted. An attacker on one chip, sweeping every launch knob it controls — the maximum an unprivileged tenant could tune — reached at best 0.616 correlation with a target chip's fingerprint, while genuine chips match themselves at 0.946 on average and never below 0.916. The passive impostor baseline sits near 0.174. This gap is what makes the technique interesting for hardware attestation scenarios on infrastructure an operator owns: the fingerprint is hard to spoof without controlling the silicon itself, since the signal originates in static manufacturing variation rather than in anything software configures.
Equally important is where the leak stops, and the README maps that boundary carefully. Vanilla transformer forward/backward (6 layers, d=512, 200 forward and 200 backward passes across 3 A40s), dense GEMM, and TF32 matmul all produce bit-identical output across identical chips — nondeterministic fraction 0.000, classification at chance (2/6). Deterministic code paths carry no instance information because nothing hardware-scheduled orders their accumulation. The one-pass defense against the passive channel is torch.use_deterministic_algorithms(True), which eliminates it entirely at a 2.5-3.6x backward cost; the active custom-kernel probe is unaffected by this setting. That asymmetry gives defenders a concrete, measurable trade-off between determinism overhead and instance-leakage exposure.
Operationally, the repository is built for legitimate research on hardware you control. The quickstart is minimal: git clone the repo, pip install -r requirements.txt (just numpy and scipy for every analysis), and run python analysis/pooled_analyze.py to reproduce the 19-A40 99.1% figure on CPU. Running the probe on a GPU requires pip install numpy cupy-cuda12x followed by python probes/probe_puf.py 3 0, which takes about two seconds per epoch and emits JSON recording the GPU UUID, driver, cupy version, and per-epoch clock and temperature alongside the measurements — honest metadata capture that makes the datasets auditable. scripts/run_remote.sh parallelizes collection across hosts you administer, and docker/Dockerfile packages CUDA 12.8 with the probe preinstalled.
Every published claim maps to a specific script and dataset: analysis/temporal_analyze.py for reboot and stress stability, analysis/cross_model_analyze.py for the consumer-card results, analysis/passive_analyze.py and analysis/channel_analyze.py for the index_add_, scatter_, and TF32 boundaries, analysis/forge_analyze.py for spoofing, analysis/roc_capacity.py for the biometric-style ROC analysis, and analysis/defense_analyze.py for the deterministic-mode mitigation. The analysis groups data by model name and labels chips by UUID, so results are traceable to physical hardware.
For authorized professionals, the relevance is twofold. Privacy-wise, this demonstrates that GPU cloud tenancy is not as anonymous as commonly assumed: stable, hard-to-forge hardware identity can in principle be derived from computations a workload already performs, relevant to deanonymization threat modeling. Defense-wise, the repository hands blue teams a precise detection and mitigation map — the exact ops that leak (atomicAdd-backed accumulation in sparse regimes), the ops that do not (dense deterministic paths), and a one-line mitigation with a measured cost. As an educational, fully reproducible study in hardware side channels — MIT-licensed, 29 stars, Python-based, with the full measurement corpus in data/ — gpu-instance-fingerprint is one of the more rigorous fingerprinting research artifacts to appear recently, and well worth study in a lab environment.
divagr18/gpu-instance-fingerprint.Educational analysis for authorized security professionals. Use only in controlled, authorized environments.
Related coverage
0 comentários:
Post a Comment
Note: Only a member of this blog may post a comment.