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

MODEL

required

A local Hugging Face checkpoint directory. Hub model ids are not accepted; download the checkpoint first.

-o, --output

required

Directory for the sealed model. It must not exist.

--key

~/.kllm/keys/default.key

Key file to seal under. See Model keys.

--transform

orth

orth or perm. See Transforms.

--client

off

Also write the cloud’s part for client-keyed serving. See Client-keyed mode.

--cloud

OUTPUT-cloud

Where --client writes the cloud’s part. It must not exist.

--no-lock

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

Qwen3ForCausalLM, Qwen3MoeForCausalLM

orth, perm

Qwen2 / Qwen2.5

Qwen2ForCausalLM (Q/K/V biases)

orth, perm

Llama 3.x

LlamaForCausalLM (Llama 3 RoPE scaling)

orth, perm

FP8 checkpoints of the above

block-wise or per-tensor scales (quant_method: fp8)

perm only

MiniMax H3

FL2VA partition (text and images in, video with audio out)

perm (recommended), orth

Z-Image

ZImagePipeline

its own scheme; orth or perm in client-keyed mode

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 *.safetensors weight files and a tokenizer.json. Weights in .bin, .pt or .pth files are not read, so a checkpoint that has only such files cannot be sealed.

  • The vocabulary ids in tokenizer.json are 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_factor other 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.json has a kllm section 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.

orth

R 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.

perm

R 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.

Shared by both transforms

Query and key heads

q_norm, k_norm and neox-style RoPE fix the basis inside a head, so heads move only as whole grouped-query-attention groups: the KV heads are permuted, and each query head follows its KV head. Within a head, each RoPE pair (j, j + D/2) is turned by a multiple of 90 degrees, which commutes with RoPE; the q_norm and k_norm gains of a pair turned by an odd number of quarter turns are swapped.

MLP

The intermediate dimension is permuted. The rows of up_proj are scaled by ±2k with k between −2 and 2, and the columns of down_proj are scaled back. Powers of two keep bf16 values exact.

Vocabulary

A permutation Π of the regular token ids is applied to the rows of the embedding and of the LM head. Special tokens, and any embedding rows beyond the tokenizer’s regular vocabulary, keep their ids. The sealed model always has a separate LM head (tie_word_embeddings is set to false), because the embedding and the LM head are transformed differently.

Mixture of experts

The experts of each layer are permuted: the router rows and the expert tensors move to new expert slots together. Each expert’s MLP is transformed like a dense MLP, under its own permutation and scales.

Biases

The Q/K/V biases of Qwen2 and Qwen2.5 follow their heads.

orth and perm compared

orth (default)

perm

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

config.json

The original configuration, architecture unchanged, with tie_word_embeddings set to false and a kllm section: scheme (l1), transform, fingerprint, base_architecture, vocab_regular (the number of regular token ids) and, for locked weights, lock (the lock version, v1).

model-00001-of-0000N.safetensors

The transformed weights, with the original tensor names, shapes and dtypes, in shards of about 4 GiB. Locked, unless --no-lock is given; the header of each locked shard records the domain size of each tensor under kllm.lock.

model.safetensors.index.json

The weight map of the shards.

trusted.kllm

The permuted tokenizer.json and vocab.json, encrypted with AES-256-GCM in 64 MiB chunks under a key derived from the model key. Each chunk is authenticated with its index and a last-chunk flag, so chunks cannot be reordered, dropped or truncated without detection.

Other non-weight files

Copied unchanged, for example tokenizer_config.json, merges.txt and generation_config.json.

The following files of the original are not written in clear text:

  • tokenizer.json and vocab.json exist only in permuted form, inside trusted.kllm.

  • tokenizer.model and spiece.model are left out, because they list the vocabulary in canonical order and would reveal Π. The sealer reports leaving out tokenizer.model: it lists the vocabulary in canonical order. The sealed model’s tokenizer is the permuted tokenizer.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 --key and kllm unlock unlock the weights into a cache directory before the engine starts (Locked weights). Unlocking is exact.

  • kllm seal --client and kllm cloud --key write the cloud’s copy unlocked, on the user’s side.

  • kllm verify compares 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