Choosing a transform

kllm seal --transform selects how the residual stream of the model is hidden: orth (the default) or perm. Everything else is shared by both transforms: the permutation of attention heads per grouped-query-attention group with quarter turns of RoPE pairs, the permutation of the MLP’s intermediate dimension with ±2k scales, and the permutation of the regular vocabulary. This page explains how to choose between the two for a given model. Transforms describes the mechanics.

The transform is recorded in the sealed model, so kllm serve takes no transform option. To change the transform, seal the original checkpoint again; a sealed directory is refused as a source with <path> is already sealed.

Quick decision

Model

Transform

Reason

FP8 checkpoint of a supported family

perm (required)

orth would require requantizing the rotated values and is refused with FP8 checkpoints need --transform perm (orth would requantize).

MiniMax H3 (FL2VA)

perm (recommended)

orth re-rounds the rotated text-encoder weights, to which the audio stream is most sensitive; measured drift is larger. See Sealing and serving MiniMax H3.

Z-Image, client-keyed

orth or perm

Both are accepted. The published fidelity figures were measured with orth.

bf16 LLM (Qwen3, Qwen3-MoE, Qwen2, Qwen2.5, Llama 3.x)

either

Weigh fidelity against what the activations and weights reveal; see below.

For bf16 LLMs, choose perm when the smallest numerical difference from plain serving matters most, or when the sealed weights must keep their original values exactly. Choose orth when hiding per-channel statistics of the activations matters more than the additional rounding. Neither choice protects user text from an operator who reads GPU memory, and neither keeps a public model, or a fine-tune of one, secret from a party that holds the public checkpoint.

Comparison

orth

perm

Residual stream

Dense random orthogonal basis. RMSNorm gains are folded into the projections that read the norm’s output; the GPU norms become ones.

Random signed permutation. RMSNorm gains stay on the GPU, permuted.

Sealed weights

Rotated, then rounded again to the checkpoint dtype.

Bit-exact original values, reordered and sign-flipped (the MLP up to powers of two).

Activations seen by the GPU

Coordinates mixed: no outlier channels, no per-channel statistics.

Channels shuffled: per-channel magnitudes and outliers survive.

User tokens against a reader of GPU memory

Substitution cipher over tokens. The transform is an isometry, so activations still cluster by token.

The same: a signed permutation is also an isometry.

Public model, or fine-tune of a public base

Recovered by the measured attack for weight changes up to 3% of the weight standard deviation; the attack’s spectral start failed at 5%.

Recovered at every measured size, up to 10%.

Weights with no public relative

No known attack, and no proof.

Per-channel statistics survive, which gives an attacker more structure.

FP8 checkpoints

Refused.

Supported.

INT8 DiT attention kernel (H3)

Does not commute to the last bit: V’s per-channel scales change.

Commutes, up to an occasional last-bit rounding of P·V.

Fidelity

Both transforms are exact in exact arithmetic; the test suite checks this in float64 to 1e-9 on small random models of every supported family. In bf16 serving they differ in how much rounding they add. Mean absolute log-probability difference against plain serving, over 14690 tokens of the GPL-3, GFDL-1.3 and Apache-2.0 license texts, on one NVIDIA A40:

Model and engine

perm

orth

Qwen3-1.7B, SGLang 0.5.21

0.069

0.098

Qwen3-8B, SGLang 0.5.21

0.031

0.045

Qwen3-1.7B, vLLM 0.31.0

0.061

0.090

Qwen2.5-1.5B-Instruct, SGLang

0.014

0.021

Llama-3.2-1B-Instruct, SGLang

0.043

0.061

For scale, serving plain Qwen3-1.7B in fp16 instead of bf16 moves log-probabilities by 0.053 on average. Served in fp16, perm moves them by 0.008, which is accumulation order alone, and orth by 0.032, most of which is the rounding of the rotated weights.

On task accuracy the difference is not measurable at this scale. Qwen3-1.7B under vLLM scored MMLU 0.5562 (perm) and 0.5548 (orth) against 0.5560 plain, and GSM8K (strict) 0.6952 and 0.6960 against 0.6945 plain, all within one standard error (0.004 for MMLU, 0.013 for GSM8K).

Serving speed does not depend on the transform: the sealed model has the same shapes and runs the same kernels either way. See Benchmarking plain and sealed serving for the measured tables.

Exposure

The transforms are static: they are derived once from the key and do not change per request. This limits what either one can hide.

  • User text. Token ids reach the GPU under a fixed vocabulary permutation, which is a substitution cipher (unigram frequency matching alone decoded 23.8% of tokens on Qwen3-8B). Both transforms are isometries of the residual stream, so activations cluster by token in either case (1-nearest-neighbor same-token rate 99.4% at layer 1).

  • Weights of a public model or of a fine-tune. With the public base model, an attacker recovers the transforms, the vocabulary permutation and, for a fine-tune, the fine-tuned weights. Under perm each column of the LM head keeps its values, only reordered, so sorted magnitudes identify it at any fine-tune size.

  • Activations. Under perm the GPU sees the original per-channel magnitudes and outlier channels, in a shuffled order. Under orth these are mixed away.

See Attacks for the measurements and Claims for what kLLM claims.

Comparing both on a model

To measure both transforms on a specific model and engine, run the LLM benchmark, which seals the model under each transform with a fresh key, serves plain and sealed variants one after another on the same GPU, and prints perplexity, log-probability drift, TTFT, TPOT and throughput:

$ benchmarks/llm.sh ~/models/Qwen3-8B
$ ENGINE=vllm TRANSFORMS="perm orth" benchmarks/llm.sh ~/models/Qwen3-8B

For FP8 checkpoints set TRANSFORMS=perm. To measure the weight-recovery attack under each transform:

$ python tools/attacks/weights.py --base ~/models/Qwen3-8B --transform orth
$ python tools/attacks/weights.py --base ~/models/Qwen3-8B --transform perm

See Benchmarking plain and sealed serving for the prerequisites and settings of each script.

See also