Picture a release pipeline that has just produced a thirty-gigabyte set of model weights. The signing key is a Module-Lattice-Based Digital Signature Algorithm (ML-DSA) key that lives inside a cloud key management service and can never be exported. The service's signing call accepts a few kilobytes. Nobody is going to upload thirty gigabytes to it, and nobody should. How does the release get a post-quantum signature that any verifier, anywhere, can check? And during the years when classical and post-quantum signatures travel side by side, how do you stop an attacker from simply deleting the new one? This article covers the architecture of signing when artifacts are large and keys are remote: three ways to sign something big, the context strings the new standards provide for free, signing throughput as a design input, and the verification rules that make dual signatures worth having, ending with the place where AI agents rely on all of it.

When the artifact will not fit through the door

Well-run signing keeps the private key inside a boundary it never leaves: a key management service (KMS) in the cloud or a hardware security module (HSM), a tamper-resistant device that stores keys and performs operations with them. Applications send data in and get signatures out. That model was designed for small inputs. Amazon Web Services (AWS) KMS, for example, signs ML-DSA messages of up to 4 kilobytes directly. Everything larger must be reduced to something small before the key ever sees it.

The artifacts that matter most today are anything but small: model weights, container images, datasets, firmware bundles, plug-in archives. Signing each file separately multiplies remote calls and latency; streaming a whole artifact to a remote service is slow, expensive and pointless, since the service only needs a fixed-size value derived from it. The engineering question is therefore which small value gets signed, by whom it is computed, and what a verifier must understand to check it. The three answers below have quite different consequences.

Choosing the signing path, and configuring it

The three ways to get a large artifact signed by a remote ML-DSA key, signing a small manifest of digests, the pre-hash variant HashML-DSA, and an externally computed 64-byte message representative called mu, together with why access to a sign-mu interface amounts to the ability to sign anything, are analysed in the Research article 'Pure, Pre-Hash or External Mu: Splitting an ML-DSA Signature Across a Hardware Boundary'.

In practice the choice is constrained by where the key lives, because key stores expose the paths differently. AWS KMS keeps one key and lets each Sign call choose: with the signing algorithm ML_DSA_SHAKE_256, a message type of RAW signs up to 4 kilobytes of data whole, and a message type of EXTERNAL_MU signs exactly 64 bytes of mu. Google Cloud KMS fixes the choice when a key version is created, offering, for example, PQ_SIGN_ML_DSA_65 for pure signing and PQ_SIGN_ML_DSA_65_EXTERNAL_MU for external mu, so a pipeline that needs both needs two key versions. Because a key version's algorithm cannot be changed after it is created, moving a Google Cloud pipeline from pure signing to external mu later means a new key version and a new public key to distribute, so decide the path before the key is created.

Hardware modules and libraries follow the same pattern under their own names. Thales Luna firmware 7.9 exposes an external-mu ML-DSA mechanism, Go 1.27 signals external-mu signing with a dedicated hash value, the Python cryptography package added sign_mu and verify_mu in version 49.0.0, and OpenSSL 4.0 added an ML-DSA mu digest. Write down, for every signing pipeline, which path it uses and under which name on each side, because a signer and a verifier that disagree about the path produce signatures that simply do not verify.

How pure and external-mu ML-DSA signing are selected on common platforms, as documented in October 2026.
PlatformPure signingExternal muWhere the choice is made
AWS KMSMessageType RAW, up to 4 KBMessageType EXTERNAL_MU, exactly 64 bytesPer Sign call
Google Cloud KMSPQ_SIGN_ML_DSA_44, 65 or 87PQ_SIGN_ML_DSA_44, 65 or 87 _EXTERNAL_MUPer key version
Thales Luna 7.9ML-DSA mechanismExternal-mu ML-DSA mechanismPer PKCS#11 call
Python cryptography 49signsign_mu and verify_muPer call

Locking down the external-mu path

Because whoever can submit mu can sign anything, the access rule on the key store is the real control, and both major clouds let you express it precisely. In AWS, the key policy can use the kms:MessageType condition key so that only the role of the service that computes mu may call Sign with EXTERNAL_MU, while other principals are limited to RAW or denied, and the kms:SigningAlgorithm condition key pins the algorithm. In Google Cloud, where external mu is its own key version, grant signing permission on that key version only to that service.

Three operational failures show up early. Sending a digest with message type RAW makes AWS KMS hash it again, which AWS warns causes verification failures with systems that assume a single hash. Sending anything other than exactly 64 bytes with EXTERNAL_MU is rejected outright. And a signature whose key identifier and signing algorithm were never recorded can become impossible to verify later, which is why AWS tells callers to record both with every signature.

Detection is cheap and worth automating. Audit logs such as AWS CloudTrail record each KMS Sign request and its caller, so alert on any external-mu signing call from a principal other than the service that computes mu. Run a daily canary that signs a fixed test manifest through the production path, fetches the public key with GetPublicKey, and verifies the signature offline with a different library; configuration drift then shows up as a failed canary instead of as a customer's failed verification.

Only the policy service may submit mu; agents are refused, every call is logged, and a canary verifies offline.Who may submit mu AI agentfull request only Policy servicecomputes mu Key storeexternal mu:policy role only Audit logevery Sign call Daily canaryverifies offline request 64-byte mu denied logged test sign Signing boundary
Only the policy service may submit mu; agents are refused, every call is logged, and a canary verifies offline.
  1. Decide per pipeline: signed manifest, external mu, or HashML-DSA only where a partner requires it.
  2. AWS: restrict EXTERNAL_MU with kms:MessageType and pin the algorithm with kms:SigningAlgorithm.
  3. Google Cloud: use a dedicated external-mu key version and grant signing only to the service that computes mu.
  4. Record key identifier and signing algorithm with every signature.
  5. Alert on unexpected external-mu callers and run a daily offline-verification canary.

Context strings: domain separation for free

Both new signature standards accept a context string alongside the message: up to 255 bytes that are bound into the signed data. FIPS 204 does this for ML-DSA, and FIPS 205 does the same for the Stateless Hash-Based Digital Signature Algorithm (SLH-DSA). A signature made with one context will not verify under a different context, even with the same key and the same message.

That is domain separation, the property that a signature produced for one purpose cannot be replayed for another, and it used to require careful custom encoding. Now it is built in. Give each signing purpose its own context, for example 'model-release-v1', 'tool-manifest-v1' or 'agent-action-v1'. Make every verifier require the expected context rather than accept any. And record the permitted contexts in the key's policy in the key store, so that a pipeline allowed to sign tool manifests cannot obtain a signature that a model loader would accept as a release.

One caution from the standards themselves: the X.509, CMS and JOSE and COSE profiles for ML-DSA (RFC 9881, RFC 9882 and RFC 9964) fix the context to the empty string, so in those formats purposes are separated by a type field in the signed payload or by separate keys, and per-purpose context strings belong to custom protocols such as agent tool-call or release-manifest signing.

Context strings cost nothing in signature size and very little in effort, but only if they are decided before signatures start circulating; adding a context later means every existing signature fails the new verification rule.

A single signing key serves several purposes, and each purpose's context keeps its signatures from being replayed elsewhere.One key, separate purposesRelease signing key model-release-v1model loaders tool-manifest-v1agent runtimes agent-action-v1audit trail context 1 context 2 context 3
A single signing key serves several purposes, and each purpose's context keeps its signatures from being replayed elsewhere.
✅
Decide contexts first. Contexts are free to use but hard to add later, because old signatures will not carry them.

Signing throughput as an architecture input

ML-DSA signing is fast enough for per-artifact pipelines. Its signing loop repeats internally a variable number of times until a candidate signature passes the standard's checks, so individual signing times vary, but that variation is a normal feature of the algorithm rather than a problem to engineer around. SLH-DSA is different. Its small-signature 's' parameter sets were designed for compact signatures at the cost of slow signing. Either way, SLH-DSA belongs on rare, high-value keys, such as a release root or a firmware signing key, rather than on keys that sign every build. The 'f' sets sign faster than the 's' sets but produce much larger signatures.

Remote signing adds its own costs: network round trips, service rate limits and per-call charges. Those costs, more than the algorithm's raw speed, usually decide the architecture. A manifest or external mu reduces thousands of files to one signing call; batching several artifacts into one manifest reduces it further.

Finally, keep the hedged default for signing. FIPS 204 signs with fresh randomness mixed in by default, which helps against some physical attacks on signing hardware, and allows a deterministic variant. Deterministic signing is useful for reproducible test vectors; in production key stores, leave hedging on.

Verification has its own budget. ML-DSA verification is fast, and SLH-DSA verification, although it involves more hashing than verifying a lattice signature, is far cheaper than SLH-DSA signing, which is what makes SLH-DSA practical for artifacts signed once and verified many times. The place where verification cost matters is where it happens most: an agent runtime or package manager that re-verifies every installed component at start-up multiplies the per-signature cost by the number of components, which is another argument for verifying one signed manifest rather than many individual signatures.

Two signatures during the transition

For several years many artifacts will carry both a classical signature, verifiable by everything deployed today, and a post-quantum one, verifiable by updated software. There are two ways to package that. Detached dual signatures are simply two independent signatures attached side by side; they are easy to add to existing formats. Composite signatures, defined in an Internet Engineering Task Force (IETF) document that reached the RFC Editor queue in April 2026, combine an ML-DSA signature and a classical signature under one algorithm identifier, and the composite verifies only if both parts verify.

Formats are catching up. RFC 9964, published in May 2026, registers ML-DSA for JSON Object Signing and Encryption (JOSE) and CBOR Object Signing and Encryption (COSE), the formats behind JSON Web Tokens and many compact attestations, with COSE algorithm values -48, -49 and -50 for the three sizes. SLH-DSA for COSE was still a draft at the time of checking.

Whichever packaging you choose, adding the second signature is the easy part. The hard part is the rule verifiers apply, and the order in which that rule changes.

Detached signatures raise a quieter question: what a verifier does with a signature it does not understand. A verifier that silently skips unknown algorithms and accepts whatever remains is applying the 'accept either' rule in disguise, because an attacker can attach a garbage signature under a new algorithm name and let the old one carry the decision. Unknown algorithms should be logged and, once the policy requires a post-quantum signature, treated as missing.

Verification policy moves from classical only to requiring the post-quantum signature in deliberate steps.Moving a verifier fleet safelyClassical only Sign with bothverifiers unchanged Check both, recordfleet upgraded Require post-quantum Retire classical key add PQ ship verifiers all can verify no longer needed
Verification policy moves from classical only to requiring the post-quantum signature in deliberate steps.

The stripping problem

Suppose verifiers accept an artifact if either signature is valid. That rule is the natural first step, because it never breaks anything. It also gives the post-quantum signature no security value at all. An attacker who can forge the classical signature, whether with a future quantum computer or, much sooner, with a stolen classical key, simply deletes the post-quantum signature and presents the classical one. The verifier sees one valid signature and accepts.

The safe sequence therefore has four steps. First, sign with both. Second, ship verifiers that check both signatures when both are present, and record which ones verified, so you can see when the fleet is ready. Third, once every verifier can check the post-quantum signature, change the rule to require it, or to require both. Fourth, retire the classical key. Composite signatures shortcut part of this, because the two signatures are bound together and neither can be removed alone, but they require every verifier to understand the composite format before anything is signed with it.

The step that teams most often skip is the third one. Until the rule requires the post-quantum signature, the migration has added bytes and buys no protection against forgery.

The policy itself must not travel with the artifact. If an artifact's metadata says which signatures are required, an attacker who can alter the artifact can alter that metadata too and declare the classical signature sufficient. Required algorithms, contexts and trusted keys belong in the verifier's own configuration or in a separately signed trust policy, so that the artifact can prove what it is but cannot decide how it is checked.

Accepting either signature lets an attacker strip the new one; requiring it closes the gap.Either versus required Policy: accept either signature Policy: require the post-quantum one Accept eitherstrip PQ, forge classical Attack succeedsno added security Require post-quantumor require both Stripping failsmissing signature rejected
Accepting either signature lets an attacker strip the new one; requiring it closes the gap.

AI agents verify what they install

AI agents, software that plans and acts by calling tools, increasingly install things at run time and often unattended: tool packages, Model Context Protocol (MCP) server packages that expose tools to agents, plug-ins and model weights. Each installation is a signature verification that no human watches. The agent runtime's verifier policy is therefore the policy that matters most, and the stripping problem applies to it directly: a runtime that accepts any valid signature gains nothing from post-quantum signing.

The practical rules mirror the rest of this article. Sign tool manifests and model releases with a manifest or external mu, each with its own context string. Configure agent runtimes to require the expected context and, once supported, to require the post-quantum signature for publishers who have adopted it, never falling back to 'any valid signature'. When agents sign their own outputs or actions, have them call a key store with a per-agent, per-purpose context and permission, so the signature records which agent acted and why, and no agent ever holds a private key.

These are the decisions practitioners and platform owners actually face when post-quantum signing moves into real pipelines.

  1. Choose manifest signing or external mu for large artifacts, and use HashML-DSA only when explicitly required.
  2. Protect and log the environment that computes digests and mu, since the key store no longer sees the message.
  3. Assign a context string to every signing purpose and make verifiers require it.
  4. Put SLH-DSA on rare, high-value keys and keep hedged signing in production.
  5. Plan the verifier rule change from either signature to required post-quantum, and track fleet readiness.
  6. Make agent runtimes require the expected context and signature, and give agents scoped signing permissions instead of keys.

Key takeaways

  • Large artifacts are signed through a small value: a signed manifest, an externally computed mu, or HashML-DSA only where required.
  • Platforms expose external mu differently: per Sign call in AWS KMS, per key version in Google Cloud KMS, as named mechanisms or functions in HSMs and libraries.
  • Restrict who may submit mu with kms:MessageType or a dedicated key version, record key and algorithm with every signature, and run an offline-verification canary.
  • Context strings separate purposes in custom protocols; the X.509, CMS and JOSE/COSE profiles fix the context to empty.
  • Dual signatures add security only when verifiers require the post-quantum one; accepting either lets an attacker strip it.
  • Agent runtimes that install tools and models must require the expected signature, and agents should sign through a policy service, never with keys they hold.

Glossary

Message representative (mu)
The 64-byte value ML-DSA actually signs, computed from a digest of the public key, the context string and the message.
External mu
Computing mu outside the key store and sending only those 64 bytes to be signed, yielding an ordinary ML-DSA signature.
HashML-DSA
ML-DSA's pre-hash variant, which signs a hash and a hash identifier and has its own algorithm identifiers.
Context string
Up to 255 bytes bound into an ML-DSA or SLH-DSA signature so it verifies only for the intended purpose.
Signed manifest
A small document listing artifact files and their digests, signed once in place of the files themselves.
Composite signature
A classical and a post-quantum signature combined under one identifier, valid only if both verify.
Stripping attack
Removing the stronger of two signatures so a verifier that accepts either relies on the weaker one.
Hedged signing
Signing with fresh randomness mixed in, the default in FIPS 204.

Further reading

  1. AWS KMS Sign API reference: MessageType RAW, DIGEST, EXTERNAL_MU (Amazon Web Services)
  2. AWS KMS condition keys, including kms:MessageType (Amazon Web Services)
  3. Cloud KMS key purposes and algorithms (Google Cloud)
  4. Pure, Pre-Hash or External Mu (Research article, this site)