Sealing
kllm seal rewrites a local checkpoint under a model key, so that the network computes the
same function in a secret basis, encrypts under the key the permuted tokenizer that maps
its token ids to text, and, by default, locks the weights by encrypting them in place. This page describes the command, the checkpoints it accepts, the two transforms in detail, and
the files it writes.
Synopsis
$ kllm seal MODEL -o OUTPUT [--key KEYFILE] [--transform {orth,perm}] [--client] [--cloud DIR]
[--no-lock]
Argument or option |
Default |
Meaning |
|---|---|---|
|
required |
A local Hugging Face checkpoint directory. Hub model ids are not accepted; download the checkpoint first. |
|
required |
Directory for the sealed model. It must not exist. |
|
|
Key file to seal under. See Model keys. |
|
|
|
|
off |
Also write the cloud’s part for client-keyed serving. See Client-keyed mode. |
|
|
Where |
|
off |
Leave the sealed weights readable instead of locking them. See Locked weights. |
Example:
$ kllm seal ~/models/Qwen3-8B -o Qwen3-8B-sealed --transform perm
$ kllm serve Qwen3-8B-sealed --key
The transform is recorded in the sealed model, so kllm serve takes no transform option.
The sealer runs on a CUDA GPU when one is available and on the CPU otherwise.
Supported checkpoints
Family |
Architectures |
Transforms |
|---|---|---|
Qwen3, Qwen3-MoE |
|
|
Qwen2 / Qwen2.5 |
|
|
Llama 3.x |
|
|
FP8 checkpoints of the above |
block-wise or per-tensor scales ( |
|
MiniMax H3 |
FL2VA partition (text and images in, video with audio out) |
|
Z-Image |
|
its own scheme; |
The sealer detects the kind of checkpoint from its files: a directory without
model_index.json is a language model; a model_index.json whose class name names
MiniMax H3 is an H3 pipeline; a ZImagePipeline is a Z-Image pipeline. Other
architectures are refused with <architecture> is not supported yet. See
Supported models for the engines on which each family has been served.
Requirements for a language-model checkpoint
config.json, one or more*.safetensorsweight files and atokenizer.json. Weights in.bin,.ptor.pthfiles are not read, so a checkpoint that has only such files cannot be sealed.The vocabulary ids in
tokenizer.jsonare contiguous from 0, and every added (special) token has an id after the regular vocabulary.No MLP biases (
mlp_bias) and no partial rotary embeddings (partial_rotary_factorother than 1.0).No quantization other than
quant_method: fp8. FP8 has further requirements; see FP8 checkpoints.The directory is not already sealed. A checkpoint whose
config.jsonhas akllmsection is refused with<path> is already sealed.
Transforms
All transforms are static: they are derived once from the key and do not change per request. Each permutation is a Fisher-Yates shuffle driven by a ChaCha20 keystream that is keyed with HKDF of the model key under its own label; random signs, scales and orthogonal matrices come from the same kind of keystream. Distinct labels yield independent transforms, and the full 256-bit key determines each one.
The residual stream
The residual transform R is the only part that --transform selects. Weights that write
into the residual stream (the embedding, o_proj and its bias, and down_proj) are
mapped by R; weights that read from it (q_proj, k_proj, v_proj, gate_proj,
up_proj, the MoE router and the LM head) are mapped by its inverse.
orthR is a dense Haar-random orthogonal matrix over the hidden dimension. Each RMSNorm gain is folded into the projections that read the norm’s output, and the norm weights on the GPU are set to ones, so that RMSNorm(hR) = RMSNorm(h)R. V/O take a dense random orthogonal map per KV head.
permR is a random signed permutation of the hidden dimension. The RMSNorm gains stay on the GPU, permuted with the stream. V/O take a random signed permutation per KV head.
orth and perm compared
|
|
|
|---|---|---|
Residual stream |
Dense random orthogonal basis; RMSNorm gains folded into the projections. |
Random signed permutation; gains permuted. |
Sealed weights |
Rotated, then rounded again to the checkpoint dtype. |
Bit-exact original values, reordered and sign-flipped. |
Activations seen by the GPU |
Coordinates mixed: no outlier channels, no per-channel statistics. |
Channels shuffled: per-channel magnitudes and outliers survive. |
FP8 checkpoints |
Refused (the rotated values would need requantization). |
Supported; FP8 values are moved and sign-flipped only. |
Public model, or fine-tune of a public base |
Transforms and Π recoverable by the measured attack for weight changes up to 3% of the weight standard deviation (an unmodified model was not run separately). |
Transforms and Π recoverable at any fine-tune size, including an unmodified public model. |
Mean |Δ log-prob| against plain, bf16, SGLang |
0.098 (Qwen3-1.7B), 0.045 (Qwen3-8B) |
0.069 (Qwen3-1.7B), 0.031 (Qwen3-8B) |
The log-probability figures were measured on one NVIDIA A40 with SGLang 0.5.21, over 14690 tokens of license texts. For scale, serving plain Qwen3-1.7B in fp16 instead of bf16 moves log-probabilities by 0.053 on average. Choosing a transform gives guidance for a given model, and Attacks describes the fine-tune attack.
Exactness
Both transforms are exact in exact arithmetic; the test suite checks this in float64 to
1e-9 on small random models of the supported families. The sealer computes in float64 on the
CPU, and in float64 on a GPU for perm. Under orth on a GPU it computes in float32
before rounding to the checkpoint dtype. Under perm every sealed weight is an original
value, so bf16 serving changes the order of floating-point accumulation only.
FP8 checkpoints
FP8 checkpoints of the supported families (per-tensor or block-wise scales, stored as
weight_scale or weight_scale_inv) are sealed under perm only. --transform orth
is refused with FP8 checkpoints need --transform perm (orth would requantize).
Every permutation is block-structured: whole quantization blocks move, and the elements of a block are shuffled inside it.
The MLP’s powers of two are constant per block and are moved into the scales; for per-tensor scales they are 1. The FP8 values themselves are only moved and sign-flipped, so the sealed checkpoint dequantizes exactly to the transformed weights.
With block-wise scales, blocks must be square, the block size must equal the head dimension, and every permuted dimension must be a multiple of the block size. The sealer checks that the transform respects the blocks and refuses the checkpoint otherwise.
A cloud that reads the sealed FP8 weights sees which channels share a block, but not the order of the blocks or the order inside a block. See Sealing FP8 and mixture-of-experts checkpoints.
Pipelines
MiniMax H3
For a MiniMax H3 partition such as FL2VA, kllm seal seals the whole chain: the Qwen3-VL
text encoder under the selected transform, the diffusion transformer (whose residual stream
always takes a signed permutation, because AdaLN scales channels one by one), the latent
channel interfaces of the video and audio VAEs, and the tokenizer files of tokenizer/,
processor/ and text_encoder/, which are encrypted. The layout and file names of the
pipeline are unchanged, and kllm.json records the seal. perm is recommended for H3:
orth also re-rounds the rotated text-encoder weights, to which the audio stream is most
sensitive. See Sealing and serving MiniMax H3.
Z-Image
With --client, a Z-Image pipeline is sealed for client-keyed serving under orth or
perm: the text encoder takes the language-model transforms, the transformer’s latent
input and output layers work in a key-derived basis, and the tokenizer is encrypted. See
Generating images in client-keyed mode.
Without --client, a Z-Image pipeline is sealed under a separate permutation-based scheme
(d1-v1) that ignores --transform. Its text encoder, VAE and tokenizer are copied
unchanged. Such a pipeline cannot be served with kllm serve --key; only kllm demo
serves it.
Note
kllm demo up is under repair in 0.1.0.dev0 and does not start.
Files written
For a language model, the output directory contains:
File |
Content |
|---|---|
|
The original configuration, architecture unchanged, with |
|
The transformed weights, with the original tensor names, shapes and dtypes, in
shards of about 4 GiB. Locked, unless |
|
The weight map of the shards. |
|
The permuted |
Other non-weight files |
Copied unchanged, for example |
The following files of the original are not written in clear text:
tokenizer.jsonandvocab.jsonexist only in permuted form, insidetrusted.kllm.tokenizer.modelandspiece.modelare left out, because they list the vocabulary in canonical order and would reveal Π. The sealer reportsleaving out tokenizer.model: it lists the vocabulary in canonical order. The sealed model’s tokenizer is the permutedtokenizer.json.
With --client, kllm seal also writes the cloud’s part to --cloud
(default OUTPUT-cloud): every file except trusted.kllm, every tokenizer file, chat
templates and the tokenizer/, processor/ and vae/ directories. Weight shards are
written unlocked, because the keyless cloud server cannot unlock them; the other files are
hard links, or copies across file systems. kllm cloud writes the same directory later
from a sealed model (kllm cloud). Upload the cloud directory, not the sealed
directory. See
Client-keyed mode and Sealed checkpoint format.
Locked weights
Unless --no-lock is given, kllm seal finishes by locking the sealed weights. Every
floating-point weight (bf16, fp16, fp32 and the two FP8 formats) is shifted, within the
finite values of its format up to the tensor’s largest power of two, by an AES-256-CTR key
stream derived from the model key and the tensor’s name. The command reports
(weights locked).
The files keep their names, shapes and dtypes, so any engine loads them, but without the key the model computes nothing useful, and nothing in the files can be matched to the public base. Each tensor’s largest binary exponent is stored in the clear.
kllm serve --keyandkllm unlockunlock the weights into a cache directory before the engine starts (Locked weights). Unlocking is exact.kllm seal --clientandkllm cloud --keywrite the cloud’s copy unlocked, on the user’s side.kllm verifycompares locked models unlocked (kllm verify).
Locking protects the files on disk, not a model that runs: whoever runs the model holds the
unlocked weights. What this means for each party is set out in
Locked weights. --no-lock leaves the weights readable, as sealed by
earlier versions of kLLM.
Sealing time
Checkpoint |
Time |
Conditions |
|---|---|---|
1–2B language models (Qwen3-1.7B, Qwen2.5-1.5B, Llama-3.2-1B and others) |
14–20 s |
reported with the A40 measurements; device not stated |
Qwen3-30B-A3B-FP8 (mixture of experts, 128 experts) |
12 min |
CPU |
MiniMax H3 FL2VA (135 GB) |
about 15 min |
one NVIDIA A40 |
Z-Image, client-keyed mode (20 GB pipeline) |
57 s |
reported with the A40 measurements; device not stated |
Each tensor is read, transformed and written once, so sealing time grows with the size of the checkpoint. The figures above were measured before locking was added. In the catalog build on one server with an NVIDIA A40, sealing and locking together took 36 s for Qwen3-1.7B (4.1 GB) and 102 s for Z-Image in client-keyed mode (20.5 GB); the research team reports about 0.1 to 0.2 GB/s for sealing and locking.
Measured effect on serving
On one NVIDIA A40 48 GB, with SGLang 0.5.21 and vLLM 0.31.0, bf16, 1024 input and 128 output
tokens, a GPU shared with another tenant’s light job and single runs, sealed output
throughput at concurrency 16 matched plain serving in every measured keyed configuration and
was never more than 0.3% lower. For example, Qwen3-1.7B under vLLM delivered 1097 tok/s plain,
1094 under perm and 1095 under orth. Individual latency figures show visible
differences, such as a median time to first token at concurrency 1 of 98.0 ms plain and
105.2 ms under perm for Qwen3-1.7B under SGLang. On Qwen3-1.7B under vLLM, MMLU and
GSM8K scores of plain, perm and orth are within one standard error of each other. See
Benchmarking plain and sealed serving to repeat the measurements on other hardware.
Important
Sealing protects the checkpoint at rest and the mapping between token ids and text against a party that has no public relative of the weights. It does not encrypt GPU memory, and it does not keep the transforms or Π of a public model, or of a fine-tune of one, from a party that reads the sealed weights and holds the public checkpoint (Weights of a public model, or of a fine-tune of one). See Claims.
See also
Choosing a transform for choosing between
orthandperm.Sealed checkpoint format for the layout of the sealed checkpoint.
Supported models for the supported architectures.
Sealing FP8 and mixture-of-experts checkpoints and Sealing and serving MiniMax H3 for FP8, MoE and pipeline checkpoints.