Activation obfuscation on untrusted accelerators¶
Scope: the mixed-fleet pattern where a small number of confidential GPUs hold a model's activations and a larger pool of ordinary accelerators executes its matrix multiplications on obfuscated data. This page covers why a secret transform applied on the token axis passes through a weight multiplication unchanged, what an adversary reading device memory still learns, the batching-time defences the scheme depends on, the cost accounting that decides whether offloading is worth doing at all, and how to tell a tested obfuscation scheme from an untested one. The hardware-attested alternative that needs no obfuscation is GPU confidential computing; the approach that moves the secret into the weights instead of the activations is covariant obfuscation; the layer-split cousin is privacy-aware split inference.
Primary source: Anatoly Belikov and Ilya Fedotov, "Good-Enough LLM Obfuscation (GELO)", arXiv:2603.05035v2 [cs.CR], 6 March 2026, SingularityNET Foundation and Singularity Compute. No venue stated, no code released. The historical predecessor discussed under a learned obfuscator is Xu et al., arXiv:1912.09859v3, IEEE 2020.
What this page adds. Both Python blocks are executed and asserted (Python 3.13, numpy 2.4.6). The first confirms the correctness identity, then measures the covariance leak the paper concedes, verifies that shield vectors shift the observed Gram by exactly the shield covariance, and quantifies the low-precision cost of the paper's non-orthogonal mitigation, which the paper describes only qualitatively. The second reproduces the paper's own Appendix A arithmetic and then audits its headline offload fraction against published model configs. Figures labelled with a table or section number are the paper's; everything else is this page's derivation.
Read the latency numbers as a two-process microbenchmark, not as serving results. The paper states plainly that it did not integrate with an inference engine: its measurements move random batches between two processes on one machine over a socket, with no KV cache, no scheduler, and no real model in the loop.
What it is¶
A transformer layer's projections are right-multiplications. If the batch of hidden states is H with one row per token and the projection weight is W, the layer computes H W. Multiply H on the left by any invertible matrix A and the product survives:
A^-1 ((A H) W) = (A^-1 A) H W = H W
A acts on the token axis, so it commutes with anything acting on the feature axis. That gives a division of labour. The confidential GPU samples a fresh secret A, forms U = A H, and ships U plus the weights to a non-confidential accelerator. That accelerator computes Y = U W and returns it. The confidential GPU applies A^-1 and recovers the true projection exactly. The untrusted device sees U, W, and Y, and never sees H.
The scheme is applied to the query, key, value, and output projections of attention. It cannot be applied across a non-linearity: softmax, SwiGLU, and RMSNorm all act per token or per row, so the mixing must be undone before any of them run. Each offloaded GEMM therefore ends with a return trip to the trusted side.
Security rests on A being fresh for every batch. Given only U = A H, the pair (A R^-1, R H) produces the same observation for any invertible R, so H is determined only up to an unknown invertible transform. The attacker faces a single-batch blind source separation problem, and because A never repeats, statistics from different batches sit in different coordinate systems and cannot be accumulated. The paper is explicit that this is an identifiability argument and not a cryptographic reduction: "We do not offer a reduction-based or complexity-theoretic proof of security."
Why use it¶
The target deployment is a fleet with a few confidential GPUs and many ordinary ones. Confidential computing is available on Hopper and Blackwell class parts; an L40S or an older A100 has no such mode. If policy forbids plaintext activations on the non-confidential pool, that pool is idle for private work, and cluster throughput is capped by the small confidential partition.
The alternatives each fail a different constraint. Multi-party computation and homomorphic encryption carry overheads the paper puts at over 100x, and MPC additionally assumes non-colluding parties, which a single cloud tenant cannot arrange. The cheaper prior schemes fail differently, and the failure is specific to open-weight models. STIP and KV-Shield both hide data behind a static secret permutation applied to the weights. When the weights are public, the adversary observes the permuted weights being loaded onto the untrusted GPU and solves W' = W R for the secret R directly. Any scheme whose secret is recoverable from the weights alone is broken by publishing the checkpoint.
Per-batch mixing avoids that because the secret is never applied to the weights. W is shipped in the clear; only the activations are transformed, and the transform changes every batch.
When to use it (and when not)¶
The offload has to pay for itself, and in the paper's own measurements it does not. The Table 3 breakdown at batch 512 is the most useful number in the paper. Of 17.42 ms total, the offloaded GEMM is 0.441 ms and the data copy is 14.186 ms, or 81.4% of the time. The baseline is insecure offload, not local execution, so both columns pay the same copy. Computing that GEMM on the trusted side instead would cost about 0.44 ms and no copy at all. As measured, shipping the work costs roughly thirty times what doing it locally would.1 This is an artifact of a same-machine socket prototype rather than a statement about PCIe, but it means the paper contains no evidence that offloading is profitable, only that obfuscated offload is about 20% slower than unobfuscated offload.
The offloadable share is smaller than advertised, and grouped-query attention shrinks it further. The paper claims the scheme "offloads a large fraction of linear-algebra cost (e.g., ≈ 76% in a typical Llama 2 7B configuration)". Its own Appendix A puts the four attention projections at 67.1M multiply-adds per token against 135.3M for the feed-forward network. The executed audit below reproduces those figures and finds the offloadable share is 33.2% of per-token linear algebra: the FFN, which the scheme does not touch, is twice the size of everything it does touch. On models with grouped-query attention the key and value projections are a fraction of their multi-head width, and the share falls to 17.0% for Llama-3-70B and 12.5% for Qwen3-32B.
Round trips scale with depth. Query, key, and value can be fused into one offloaded GEMM, but the output projection sits behind softmax and needs a second. That is two crossings per layer, so 64 for Llama-2-7B and 160 for Llama-3-70B per forward pass, each carrying a full batch-by-hidden tensor in both directions. This is the page's derivation, not the paper's; the paper benchmarks a single projection.
Do not deploy the bare protocol. Fresh orthogonal mixing on its own is not sufficient against independent component analysis. At low padding energy the paper reports that "ICA p95 is high (≈ 0.97–0.99 for n ≥ 256), even when medians are modest", meaning the best-recovered 5% of tokens in a batch come back at near-perfect cosine similarity. Only high-energy shield vectors bring p95 below 0.28. The defence, not the mixing, is doing the work.
Do not expect low precision to be free. Table 1 reports float32 top-1 equality of 1.000000 but bfloat16 at 0.988045, which the paper describes as introducing "no meaningful numerical error". Slightly over one token in a hundred changes at the top of the distribution, and the mean per-token logit L2 distance is 6.18. Float16 does better than bfloat16 (0.998450), which is the expected ordering given the mantissa widths.
Do not use it where the threat is an active adversary. The model is honest-but-curious with read access to device memory. Tampering, timing and cache side channels, and availability attacks are all out of scope.
Architecture¶
flowchart LR
subgraph TEE["Confidential GPU (H100/H200 class)"]
HS["Hidden states H<br/>plaintext, never leaves"]
GEN["Sample fresh A per batch<br/>QR, enforce cond(A) < 100"]
MIX["U = A H<br/>+ k shield rows"]
UNMIX["A^-1 Y<br/>then softmax, RoPE, norms"]
end
subgraph WIRE["PCIe / fabric, 2 crossings per layer"]
UP["U (batch x hidden)"]
DOWN["Y (batch x proj)"]
end
subgraph GPU["Untrusted accelerator (L40S class)"]
GEMM["Y = U W<br/>weights W are public"]
ADV["Adversary reads VRAM:<br/>sees U, W, Y"]
end
HS --> GEN --> MIX --> UP --> GEMM --> DOWN --> UNMIX
UNMIX -.-> HS
GEMM -.- ADV
The load-bearing detail is that A is n x n on the token axis, not d x d on the feature axis. That is why generation cost grows as the cube of batch size and why the overhead curve turns back upward for large batches.
How to use it¶
1. Exclude the layers where the mapping to tokens is shortest. The paper's own batching-time defence list says not to apply the scheme to the first few layers or the final layer, and to compute those entirely inside the trusted device. Early hidden states sit close to the embedding table and are the easiest to match against known token vectors.
2. Build batches across users. A batch drawn from one user's session is a batch whose rows are correlated and whose content the adversary may partly control. Mixing requests from independent users reduces both.
3. Detect and disrupt flooding. An adversary who can inject many copies of a known token gains anchors. The paper's countermeasure is to track token-frequency statistics and inject random tokens when they diverge from baseline. Note this interacts badly with prefix caching, which exists precisely to exploit repeated prefixes.
4. Pad with shield vectors, and scale them. Append k secret Gaussian rows to the batch, with k around 5% of the batch and row norms 4 to 10 times the mean data row norm. The shields displace real tokens, so the throughput cost is the padding fraction.
5. Enforce conditioning when using a non-orthogonal transform. Orthogonal A is fast and stable but leaks the Gram matrix exactly. A general invertible A masks it, at the cost of an O(n^3) inverse per batch and amplified rounding. The paper's rule is cond(A) < 100; the block below shows what that buys and what violating it costs.
How to develop with it¶
The three claims worth checking before building anything are that the offload is exact, that an orthogonal transform leaks the covariance in full, and that the shield trick does what it says. All three are one-screen numpy checks.
# Runnable on system python3 (numpy only). The core claim of per-batch left-mixing
# (GELO, arXiv:2603.05035v2 Sec 3.2): a secret invertible A applied on the TOKEN axis
# commutes with right-multiplication by a weight matrix, so A^-1((A H) W) == H W.
# We assert that, then measure exactly what the untrusted device still learns.
import numpy as np
rng = np.random.default_rng(0)
n, d, p = 64, 128, 128 # n tokens in the batch, model dim d, projection width p
H = rng.standard_normal((n, d))
W = rng.standard_normal((d, p))
def haar_orthogonal(m, rng):
"""Uniform orthogonal matrix. The QR sign fix matters: without it Q is not Haar."""
Q, R = np.linalg.qr(rng.standard_normal((m, m)))
return Q * np.sign(np.diag(R))
def conditioned(m, kappa, rng):
"""Invertible matrix with condition number exactly kappa, singular values
centred on 1 so that masking is structural and not a change of scale."""
U, V = haar_orthogonal(m, rng), haar_orthogonal(m, rng)
s = np.geomspace(np.sqrt(kappa), 1.0 / np.sqrt(kappa), m)
return (U * s) @ V.T
# 1. Correctness. The offload is output-preserving in exact arithmetic.
A = haar_orthogonal(n, rng)
Y = (A @ H) @ W # the untrusted accelerator computes this and sees U = A H
rec = np.linalg.solve(A, Y) # the TEE un-mixes
assert np.allclose(rec, H @ W, atol=1e-9), "left-mixing must be output-preserving"
print(f"1. exact offload max abs err {np.abs(rec - H @ W).max():.2e}")
# 2. Adversarial: an orthogonal A leaks the feature-side Gram matrix in full.
# U^T U = H^T A^T A H = H^T H whenever A^T A = I. The attacker gets the d x d
# covariance of the hidden states for free, without solving anything.
U = A @ H
assert np.allclose(U.T @ U, H.T @ H, atol=1e-9), "orthogonal A leaks H^T H exactly"
gram_err = np.linalg.norm(U.T @ U - H.T @ H) / np.linalg.norm(H.T @ H)
print(f"2. orthogonal A, H^T H leak rel err {gram_err:.2e} (0 means fully leaked)")
# 3. The token-side spectrum leaks too: U U^T = A (H H^T) A^T is similar to H H^T,
# so every eigenvalue of the token-token similarity matrix survives the mixing.
ev_true = np.sort(np.linalg.eigvalsh(H @ H.T))
ev_obs = np.sort(np.linalg.eigvalsh(U @ U.T))
assert np.allclose(ev_true, ev_obs, atol=1e-8), "orthogonal mixing preserves eigenvalues"
print(f"3. similarity spectrum max eigval drift {np.abs(ev_true - ev_obs).max():.2e}")
# 4. Mitigation 1 (non-orthogonal A) actually masks the Gram matrix.
A_gen = conditioned(n, 50.0, rng)
assert abs(np.linalg.cond(A_gen) - 50.0) < 1e-6, "condition number must be as requested"
U_gen = A_gen @ H
masked = np.linalg.norm(U_gen.T @ U_gen - H.T @ H) / np.linalg.norm(H.T @ H)
# The identity of step 2 must be destroyed by many orders of magnitude, not marginally.
assert masked > 1e10 * gram_err, "a general invertible A must destroy the H^T H identity"
print(f"4. non-orthogonal A (k=50) H^T H rel err {masked:.2f} (vs {gram_err:.1e} orthogonal)")
# 5. Mitigation 2 (shield rows). Padding with k secret high-energy rows S shifts the
# observed Gram by exactly S^T S, so the attacker sees H^T H + S^T S and cannot
# isolate either term. Assert the identity holds exactly, not approximately.
k = max(1, int(round(0.05 * n))) # paper's k ~ 5% of n
row_norm = np.linalg.norm(H, axis=1).mean()
S = rng.standard_normal((k, d))
S *= (10.0 * row_norm) / np.linalg.norm(S, axis=1, keepdims=True) # scale 10x, per paper
H_full = np.vstack([H, S])
A_full = haar_orthogonal(n + k, rng)
U_full = A_full @ H_full
resid = np.linalg.norm(U_full.T @ U_full - (H.T @ H + S.T @ S))
assert resid < 1e-8, "shielded Gram must equal H^T H + S^T S exactly"
energy = np.linalg.norm(S) ** 2 / np.linalg.norm(H) ** 2
print(f"5. {k} shield rows ({100*k/n:.0f}% of n) Gram residual {resid:.2e}, "
f"shield/data energy {energy:.2f}")
# 6. Conditioning is load-bearing, and the paper's kappa < 100 rule is the reason.
# The accelerator returns Y in low precision; the TEE then applies A^-1, which
# amplifies that rounding by roughly kappa(A). Sweep kappa and measure.
def bf16(x):
"""Round to bfloat16 by truncating the float32 mantissa to 7 bits."""
v = np.asarray(x, dtype=np.float32).view(np.uint32)
return ((v + 0x8000) & 0xFFFF0000).view(np.float32).astype(np.float64)
print("6. un-mix error vs condition number (accelerator returns bf16):")
exact = H @ W
prev = None
for kappa in [1.0, 10.0, 100.0, 1e3, 1e4]:
Ak = haar_orthogonal(n, rng) if kappa == 1.0 else conditioned(n, kappa, rng)
err = np.linalg.norm(np.linalg.solve(Ak, bf16(( Ak @ H) @ W)) - exact) / np.linalg.norm(exact)
print(f" kappa={kappa:>8.0f} relative error {err:.3e}")
if prev is not None:
assert err > prev, "error must grow with the condition number"
prev = err
assert prev > 1e-2, "kappa=1e4 must visibly corrupt the un-mixed result"
print(" all assertions passed")
Executed output:
1. exact offload max abs err 8.97e-14
2. orthogonal A, H^T H leak rel err 6.67e-16 (0 means fully leaked)
3. similarity spectrum max eigval drift 9.09e-13
4. non-orthogonal A (k=50) H^T H rel err 11.33 (vs 6.7e-16 orthogonal)
5. 3 shield rows (5% of n) Gram residual 1.62e-11, shield/data energy 4.67
6. un-mix error vs condition number (accelerator returns bf16):
kappa= 1 relative error 1.675e-03
kappa= 10 relative error 3.518e-03
kappa= 100 relative error 1.831e-02
kappa= 1000 relative error 1.296e-01
kappa= 10000 relative error 9.877e-01
all assertions passed
Three results are worth carrying forward. The covariance leak under orthogonal mixing is total, not partial: the adversary reconstructs H^T H to machine precision without solving anything, and with it the principal subspace. The paper measures a participation ratio of 123 on 4096-dimensional Llama-2 states, so that leak reduces the attacker's search from a 4096-dimensional problem to roughly 123 dimensions. Second, shield rows work by exact construction rather than by statistical luck, but at 5% padding and 10x norm scaling the shields carry 4.67 times the total energy of the real data, which is what "pollutes higher-order statistics" means quantitatively. Third, the price of the non-orthogonal mitigation is a tenfold increase in low-precision error at the paper's own cond(A) < 100 limit, and total corruption two orders of magnitude beyond it. Choosing between the two mitigations is choosing between a known leak and a numerical budget.
Auditing the offload economics¶
# Runnable on system python3 (numpy only). Audit of the claim that TEE-anchored
# projection offload moves "about 76% of linear-algebra cost" for Llama 2 7B
# (arXiv:2603.05035v2, contributions list and Appendix A).
# Only Q/K/V/O are offloaded; the FFN and the attention core stay in the TEE.
# Shapes come from the published config.json of each model, not from the paper.
import numpy as np
MODELS = { # d, ffn_intermediate, n_heads, n_kv_heads
"Llama-2-7B (MHA)": (4096, 11008, 32, 32),
"Llama-3-70B (GQA)": (8192, 28672, 64, 8),
"Qwen3-32B (GQA)": (5120, 25600, 64, 8),
}
def per_token_madds(d, ffn, n_heads, n_kv, ctx):
"""Multiply-adds per token in one decoder layer, split by where they run."""
head = d // n_heads
qkvo = d * d + 2 * (d * head * n_kv) + d * d # W_q, W_k, W_v, W_o
mlp = 3 * d * ffn # gate, up, down
core = 2 * d * ctx # scores QK^T and the weighted sum over V
return qkvo, mlp, core
print(f"{'model':<20} {'Q/K/V/O':>10} {'FFN':>10} {'attn core':>10} "
f"{'offloadable':>12}")
print("-" * 66)
CTX = 2048
for name, (d, ffn, h, kv) in MODELS.items():
qkvo, mlp, core = per_token_madds(d, ffn, h, kv, CTX)
share = qkvo / (qkvo + mlp + core)
print(f"{name:<20} {qkvo/1e6:>9.1f}M {mlp/1e6:>9.1f}M {core/1e6:>9.1f}M "
f"{100*share:>11.1f}%")
# Reproduce the paper's own Appendix A figures for Llama 2 7B before drawing any
# conclusion, so we know we are counting the same way it does.
d, ffn, h, kv = MODELS["Llama-2-7B (MHA)"]
qkvo, mlp, _ = per_token_madds(d, ffn, h, kv, 0)
assert abs(qkvo / 1e6 - 67.1) < 0.1, "Appendix A states ~67M MAdds for Q/K/V/O"
assert abs(mlp / 1e6 - 135.3) < 0.2, "Appendix A states ~135M MAdds for the FFN"
assert abs((qkvo + mlp) / 1e6 - 202.4) < 0.3, "Appendix A states ~202M in total"
print(f"\nAppendix A reproduced: Q/K/V/O {qkvo/1e6:.1f}M + FFN {mlp/1e6:.1f}M "
f"= {(qkvo+mlp)/1e6:.1f}M MAdds/token")
# The claim under test. Against all per-token linear algebra the offloadable share
# is one third, not 76%: the FFN alone is twice the size of everything offloaded.
share_linear = qkvo / (qkvo + mlp)
print(f"offloaded / (projections + FFN) = {100*share_linear:.1f}%")
assert 0.30 < share_linear < 0.35, "Q/K/V/O is about a third of per-token linear algebra"
# 76% is recoverable only against the attention block alone, and only at one context
# length. Solve for the context at which Q/K/V/O is 76% of (Q/K/V/O + attention core).
ctx_star = qkvo * (1 - 0.76) / 0.76 / (2 * d)
core_star = 2 * d * ctx_star
assert abs(qkvo / (qkvo + core_star) - 0.76) < 1e-9
print(f"76% holds only vs the attention block, at ctx = {ctx_star:,.0f} tokens")
# Grouped-query attention shrinks exactly the tensors this scheme offloads: K and V
# are 1/8 width on Llama-3-70B, so the offloadable share falls further.
d, ffn, h, kv = MODELS["Llama-3-70B (GQA)"]
gqa, mlp70, core70 = per_token_madds(d, ffn, h, kv, CTX)
mha, _, _ = per_token_madds(d, ffn, h, h, CTX) # same model as if it were MHA
print(f"\nLlama-3-70B Q/K/V/O under GQA {gqa/1e6:.1f}M vs MHA {mha/1e6:.1f}M "
f"({100*(1-gqa/mha):.0f}% smaller)")
print(f" offloadable share GQA {100*gqa/(gqa+mlp70+core70):.1f}% "
f"MHA {100*mha/(mha+mlp70+core70):.1f}%")
assert gqa < mha, "GQA must shrink the offloadable tensors"
assert gqa / (gqa + mlp70 + core70) < 0.20, "under GQA the offloadable share is under 20%"
# Round trips are the real cost. Q/K/V can go in one fused GEMM, O needs a second,
# and everything between them is non-linear, so it must come back to the TEE.
layers = {"Llama-2-7B (MHA)": 32, "Llama-3-70B (GQA)": 80, "Qwen3-32B (GQA)": 64}
print("\nTEE <-> accelerator round trips per forward pass (2 per layer):")
for name, L in layers.items():
print(f" {name:<20} {2*L:>4} round trips")
print("all assertions passed")
Executed output:
model Q/K/V/O FFN attn core offloadable
------------------------------------------------------------------
Llama-2-7B (MHA) 67.1M 135.3M 16.8M 30.6%
Llama-3-70B (GQA) 151.0M 704.6M 33.6M 17.0%
Qwen3-32B (GQA) 59.0M 393.2M 21.0M 12.5%
Appendix A reproduced: Q/K/V/O 67.1M + FFN 135.3M = 202.4M MAdds/token
offloaded / (projections + FFN) = 33.2%
76% holds only vs the attention block, at ctx = 2,587 tokens
Llama-3-70B Q/K/V/O under GQA 151.0M vs MHA 268.4M (44% smaller)
offloadable share GQA 17.0% MHA 26.7%
TEE <-> accelerator round trips per forward pass (2 per layer):
Llama-2-7B (MHA) 64 round trips
Llama-3-70B (GQA) 160 round trips
Qwen3-32B (GQA) 128 round trips
all assertions passed
The Appendix A figures reproduce exactly, so the disagreement is about the denominator rather than about the arithmetic. Against all per-token linear algebra the offloadable share is 33.2%. The 76% figure is recoverable only if the denominator is the attention block alone and the context is about 2,587 tokens; the paper does not state either qualifier.2 Extending the scheme to the FFN, which the paper lists as future work, is what would make the economics work, and it is exactly the part that has not been evaluated.
The predecessor: a learned obfuscator¶
The same problem was attacked in 2019 with a learned transform rather than an algebraic one. ObfNet puts a small neural network on the edge device, trained by concatenating it with the frozen backend model and updating only the small network's weights, so that the backend accepts obfuscated and plaintext inputs interchangeably. Reported accuracy drops are 0.12% to 2.81% across three tasks, and per-sample cost on a Coral TPU is 0.2 to 11 ms.
It is worth reading for one reason: its privacy evaluation is a demonstration of what not to accept. The entire assessment is that ten student volunteers could not recognise the obfuscated audio or images.3 No inversion attack is attempted. The paper's security argument is that ReLU is many-to-one, which makes exact inversion "virtually impossible". That argument does not survive the threat model it states, because the honest-but-curious backend generates and distributes every ObfNet itself and therefore knows the weights; the only residual secret is which member of a small set the device selected. Compare the two 2026 schemes, which run FastICA, JADE, joint diagonalisation, anchor-based recovery, and multi-view ICA against their own defences and publish where they weaken. A scheme that reports no attack has not been shown to resist one.
How to run it in production¶
Batch size is the primary tuning knob and the overhead curve is not monotone. Table 2 gives 28.9% overhead at batch 64, a minimum near 19.9% at 256, and 50.1% at 8192. Small batches pay because generating A dominates a fast GEMM; large batches pay because generating an n x n orthogonal matrix costs O(n^3). Batches in the 256 to 512 range sit at the bottom of the curve. Note that this interacts directly with serving throughput, which normally wants the largest batch the memory budget allows.
Budget the trusted side for matrix generation, not for mixing. At batch 512 the split is 2.322 ms to generate A, 0.199 ms to mix, and 0.272 ms to un-mix. Generation is 83% of the 2.793 ms security cost, and it is pure overhead that produces no model output.
Treat the following as unbuilt rather than as configuration. There is no inference-engine integration; the paper defers vLLM and KV-cache work to future work and does not evaluate throughput. The KV cache is the specific gap: keys and values are what the cited LeftoverLocals and cache-sharing attacks actually read, and a scheme that protects the projection GEMM while leaving the resulting cache in plaintext on the untrusted device has moved the problem rather than solved it. Confirm where the cache lives before believing any deployment claim.
How to maintain it¶
Never reuse A. Reuse is the single failure that collapses the security argument from single-batch blind source separation to the classical fixed-mixing ICA problem, which is solvable with enough samples. A cache of generated matrices, a seeded generator that restarts deterministically, or a retry path that re-sends a failed batch with the same transform all reintroduce reuse.
Re-check the sensitive-layer exclusion list whenever the model changes, since it is expressed in layer indices. Re-measure the batch-size overhead curve after any change to the transport path, because its shape is set by the ratio of matrix generation to copy cost and both are hardware-specific. Verify cond(A) at generation time and reject rather than clamp: the block above shows the un-mixed result is destroyed at cond(A) = 10^4, and a silently ill-conditioned transform produces plausible but wrong logits.
Failure modes¶
- Reused or predictable
A. Cross-batch statistics become alignable and standard ICA applies. Symptom: none at runtime; the failure is silent. - Ill-conditioned
Awith low-precision returns. Logits drift without any error being raised. Atcond(A) = 10^3the relative error is already 13%. - Orthogonal
Awith no shields. The covariance and the token-similarity spectrum leak exactly, and ICA recovers the best 5% of tokens at 0.97-0.99 cosine similarity. - Anchor accumulation. If an adversary learns enough in-batch rows,
A = U H^+is solvable algebraically and the whole batch is de-mixed. The paper's own data shows anchor attacks improving sharply once anchors exceed roughly 70% of rows under shielding. - Prefix caching re-enabled. Cache reuse defeats cross-user batch mixing and supplies exactly the repeated known tokens the flooding detector exists to suppress.
- Batch size raised for throughput. Overhead climbs to 50% at 8192 as matrix generation dominates.
- Applied to the first or last layer. Hidden states near the embedding or the LM head are closest to recoverable token identities.
Open questions and validation¶
- No end-to-end serving measurement exists. The reported overhead comes from moving random tensors between two processes on one machine, with communication at 81% of total time; on a real PCIe path that ratio inverts and the relative overhead of mixing rises.
- The security evaluation is empirical negative evidence, not a proof. The authors say so. Absence of a successful off-the-shelf ICA attack is weaker than a bound.
- The anchor-attack tables are reported at two different batch sizes and only one is stated. Table 7 declares
n = 512; Table 6 declares non, yet its accompanying text says recovery improves "when more than 90% of rows are anchors" atk = 240, which is consistent only withn = 256.4 - Extension to the FFN is untested, and it is the extension that would make the offload fraction worth the round trips.
- Whether the KV cache can be kept obfuscated at rest on the untrusted device, rather than just the projection that produces it, is unaddressed and is the difference between mitigating and solving the cited attacks.
References¶
- Belikov, A., Fedotov, I. "Good-Enough LLM Obfuscation (GELO)." arXiv:2603.05035v2, 2026. https://arxiv.org/abs/2603.05035
- Xu, D., Zheng, M., Jiang, L., Gu, C., Tan, R., Cheng, P. "Lightweight and Unobtrusive Data Obfuscation at IoT Edge for Remote Inference." IEEE Internet of Things Journal, 2020. arXiv:1912.09859. https://arxiv.org/abs/1912.09859
- ObfNet reference implementation. https://github.com/ntu-aiot/ObfNet
- Sorensen, T., Khlaaf, H. "LeftoverLocals: Listening to LLM Responses Through Leaked GPU Local Memory." arXiv:2401.16603, 2024. https://arxiv.org/abs/2401.16603
- Wu, G. et al. "I Know What You Asked: Prompt Leakage via KV-Cache Sharing in Multi-Tenant LLM Serving." NDSS, 2025. https://www.ndss-symposium.org/ndss-paper/i-know-what-you-asked-prompt-leakage-via-kv-cache-sharing-in-multi-tenant-llm-serving/
- Yuan, M., Zhang, L., Li, X.-Y. "Secure Transformer Inference Protocol." arXiv:2312.00025, 2023. https://arxiv.org/abs/2312.00025
- Zheng, F., Chen, C., Han, Z., Zheng, X. "PermLLM: Private Inference of Large Language Models Within 3 Seconds Under WAN." arXiv:2405.18744, 2024. https://arxiv.org/abs/2405.18744
- Zhang, Z. et al. "No Privacy Left Outside: On the (In-)Security of TEE-Shielded DNN Partition for On-Device ML." IEEE S&P, 2024. https://arxiv.org/abs/2310.07152
- Hyvarinen, A. "Fast and Robust Fixed-Point Algorithms for Independent Component Analysis." IEEE Transactions on Neural Networks 10(3), 1999, doi:10.1109/72.761722. https://ieeexplore.ieee.org/document/761722
- NVIDIA Confidential Computing (the URL cited as reference [12] of arXiv:2603.05035v2,
developer.nvidia.com/confidential-computing, returns 404 as of 2026-08-09; this is the current canonical page). https://www.nvidia.com/en-us/data-center/solutions/confidential-computing/
Related: GPU confidential computing · Covariant obfuscation for private inference · Privacy-aware split inference · Membership inference against fine-tuned LLMs · Security, isolation and multi-tenancy · Gradient leakage in distributed training · Remote GPU verification · KV cache management · Disaggregated inference · Glossary
-
arXiv:2603.05035v2, Table 3, batch 512. GELO column: A-generation 2.322 ms, mix 0.199 ms, GEMM 0.441 ms, un-mix 0.272 ms, copy 14.186 ms, total 17.420 ms. Baseline column: GEMM 0.443 ms, copy 14.123 ms, total 14.566 ms. The paper's reading is that overhead is 19.6% and that "The majority of time (∼ 81%) in both GELO and the baseline is spent on Copy (socket+I/O), indicating the experiment is bottlenecked by inter-process communication rather than GELO's computations." That is correct as stated. The observation this page adds is that the same table shows the offloaded work is 0.441 ms against 14.186 ms of transport, so within this microbenchmark the offload itself is a net loss regardless of obfuscation. Table 2 reports a slightly different pair at the same batch size (16.11 ms against 13.41 ms, 20.1%), so the two tables are separate runs. ↩
-
arXiv:2603.05035v2, contributions list in Section 1: "showing that GELO offloads a large fraction of linear-algebra cost (e.g., ≈ 76% in a typical Llama 2 7B configuration) with modest overhead on the trusted side." The paper does not define the denominator. Appendix A, which is the only place the model's cost is broken down, gives 67M multiply-adds per token for Q/K/V/O and 135M for the FFN, and the executed block above reproduces both. The Appendix A crossover of L = 24,658 for Llama-2-7B also reproduces from those figures. Its companion figure of "roughly L = 49,000" for Llama-3-70B does not reproduce from that model's published config (hidden 8192, FFN 28672, 64 query heads over 8 key-value heads), which gives 52.2k accounting for grouped-query attention or 59.4k without it; the paper states neither the FFN width nor the attention layout it assumed. ↩
-
arXiv:1912.09859v3, Section IV. "We invited ten student volunteers (five males and five females)"; for the spoken-digit case the volunteers' recognition rate on obfuscated samples is reported as 5%, 7%, 7%, and 4% for four ObfNets, against a 10% chance baseline. The generation procedure is in Section III-B: "the backend generates multiple sets of ObfNets ... and then transmits a unique set to each of the edge devices." The claimed protection against a colluding backend covers only which ObfNet a device selected, not the weights themselves, which the backend trained. ↩
-
arXiv:2603.05035v2, Section 4.3.3. Table 7 is captioned "median Gram error; n = 512" and Table 8 "median Gram error; n = 256". Table 6 carries no batch size, and its text reads "recovery quality for the remaining unknown tokens generally decreases markedly up to the point when more than 90% of rows are anchors." Its largest anchor count is k = 240, which is 94% of 256 but only 47% of 512, so Table 6 is consistent with n = 256 and not with the n = 512 of the table it is discussed alongside. The paper does not resolve this. ↩