# The 2030 Post-Quantum Deadline in Code: 6 Changes and the Test for Each

Executive Order 14412 and OMB M-26-15, read as a diff: key establishment, signatures, agility, gateway tokens, stored data and the inventory. Every block was run against the published npm packages on 30 September 2026.

Canonical HTML: https://www.livetradingnews.com/the-2030-post-quantum-deadline-in-code-6-changes-and-the-test-for-each
Last modified: 2026-09-29

---

By Shayne Heffernan · 2026-09-29
Tags: post-quantum cryptography, PQC, developers, Node.js, OpenSSL, ML-KEM, ML-DSA, X25519MLKEM768, JWS, JWT, CBOM, CycloneDX, Executive Order 14412, OMB M-26-15, npm, KXCO, cybersecurity
Signed: ML-DSA-65, anchored on Armature L1.
Nothing in this article is investment advice.

## Your TLS client already made the first change

On 30 September a stock Node.js client negotiated X25519MLKEM768, the hybrid of X25519 and ML-KEM-768, with no options set. This is the probe, as it ran:

```
// Ask Cloudflare which key exchange a stock Node client negotiated: /cdn-cgi/trace reports kex=
import https from 'node:https'
const opts = process.argv[2] ? { ecdhCurve: process.argv[2] } : {}
https.get('https://www.cloudflare.com/cdn-cgi/trace', opts, r => {
  let b = ''; r.on('data', d => b += d); r.on('end', () => {
    const kex = (b.match(/^kex=(.*)$/m) || [])[1], tlsv = (b.match(/^tls=(.*)$/m) || [])[1]
    console.log(process.version, 'openssl', process.versions.openssl, opts.ecdhCurve ? 'ecdhCurve=' + opts.ecdhCurve : 'defaults', '->', tlsv, 'kex=' + kex)
  })
}).on('error', e => console.log('error', e.message))
```

```
$ node kexprobe.mjs
v26.1.0 openssl 3.5.6 defaults -> TLSv1.3 kex=X25519MLKEM768
$ node kexprobe.mjs X25519
v26.1.0 openssl 3.5.6 ecdhCurve=X25519 -> TLSv1.3 kex=X25519
```

Node 22.23.3 and Node 24.21.0, both on OpenSSL 3.5.8, returned the same X25519MLKEM768. The second run is the control. Force the classical group and the reading changes, so the first reading is real. [OpenSSL 3.5.0](https://github.com/openssl/openssl/blob/openssl-3.5/NEWS.md) made the hybrid a default keyshare on 8 April 2025. [Node.js 24.7.0](https://nodejs.org/en/blog/release/v24.7.0) put ML-KEM and ML-DSA into node:crypto on 27 August 2025.

That settles TLS 1.3 wherever the server offers the hybrid group. It settles nothing the application owns. [Executive Order 14412](https://www.federalregister.gov/documents/2026/06/25/2026-12909/securing-the-nation-against-advanced-cryptographic-attacks) and [OMB M-26-15](https://www.whitehouse.gov/wp-content/uploads/2026/06/M-26-15-Execution-of-the-Migration-to-Post-Quantum-Cryptography.pdf) name those parts, and Exhibit 1 maps each one to a change in code and a package.

![Exhibit 1: knowledge graph of six requirements from EO 14412 and OMB M-26-15, the change in code each asks for, and the npm package that ships it: kxco-post-quantum, kxco-pq-vault and kxco-pq-scan.](https://livetradingnews-media.nyc3.digitaloceanspaces.com/media/2026/09/29/cmpgg3-1d2e3b8d24c79711.svg)

*Exhibit 1. Each requirement is quoted from its primary text and each package was installed from npm and imported when the figure was built. The build fails on a missing quote or a missing export.*

Every block below was run against the published packages on 30 September, from one file, with an assertion behind each comment. On Node 24 and later the maths runs in OpenSSL 3.5; on Node 20.19 and 22 it runs in JavaScript, with identical bytes on the wire.

```
npm install kxco-post-quantum kxco-pq-vault kxco-pq-scan
```

## 1. Key establishment in your own protocol, by 31 December 2030

Section 4(b)(ii) of the Order dates post-quantum key establishment on high-value systems to 31 December 2030. TLS is covered above. A message queue, an application envelope or a handshake of your own is not, and there the primitive is ML-KEM-768 from FIPS 203.

```
import { mlKem } from 'kxco-post-quantum'

const kem = mlKem.keypairFromMaster(crypto.getRandomValues(new Uint8Array(32)), 'channel-v1')

// the sender, holding only the public key
const { ciphertext, sharedSecret } = mlKem.encapsulate(kem.publicKey)

// the key holder, receiving 1,088 bytes of ciphertext
const recovered = mlKem.decapsulate(ciphertext, kem.secretKey)   // equals sharedSecret, 32 bytes
```

The sender needs only the public key. The holder of the private key recovers the same 32-byte secret, which then keys AES-256-GCM or feeds a KDF. On a live channel, pair it with X25519, the same hybrid OpenSSL now offers by default, so the session is no weaker than today's if either half fails.

## 2. Signatures, by 31 December 2031

Section 4(b)(iii) moves signatures on the same systems a year later. The primitive is ML-DSA-65 from FIPS 204.

```
import { mlDsa, mlDsa87, fingerprint } from 'kxco-post-quantum'

const master = crypto.getRandomValues(new Uint8Array(32))   // in production: from your KMS
const key = mlDsa.keypairFromMaster(master, 'payments-signing-v1')

const sig = mlDsa.sign(key.secretKey, 'settlement 4471: 2,500,000.00 GBP')
mlDsa.verify(key.publicKey, 'settlement 4471: 2,500,000.00 GBP', sig)   // true
mlDsa.verify(key.publicKey, 'settlement 4471: 2,500,000.01 GBP', sig)   // false
```

One penny moved and the signature fails. The pair is derived from the master with HKDF-SHA-512 under a label, so the master stays in the KMS and the label versions the key.

Size is the migration cost. An ML-DSA-65 public key is 1,952 bytes and a signature 3,309 bytes, per FIPS 204 Table 2, and the test file asserts both. Check every fixed-width column, header and message field that holds a key or a signature before the first one arrives.

## 3. Agility: the parameter set is one import

OMB M-26-15 says development practice "must mandate the use of PQC-agile libraries for all new applications". CNSA 2.0 asks for Level V parameters, and FIPS 204 puts ML-DSA-87 at security category 5.

```
// Category 5, the level CNSA 2.0 requires: same API, one import changed
const key87 = mlDsa87.keypairFromMaster(master, 'payments-signing-87-v1')   // its own label, so its own seed
mlDsa87.verify(key87.publicKey, 'hello', mlDsa87.sign(key87.secretKey, 'hello'))   // true
```

Give each parameter set its own label. The label is the domain separation, so one master under one label yields one seed, and the test file asserts exactly that. A signature from one set never verifies under the other, which the test file asserts too, so moving to Category 5 is a new key, rolled out like any rotation. ML-KEM-1024 sits behind the same API as `mlKem1024`.

## 4. PQC-signed tokens at the gateway

M-26-15 says "API gateways and application workloads must be configured to issue and validate PQC-signed tokens". The format the gateway already parses is compact JWS, so that is the shape the token keeps.

```
import { jws } from 'kxco-post-quantum'

const token = jws.signJws(
  { sub: 'svc-payments', aud: 'api-gateway', iat: Math.floor(Date.now() / 1000) },
  key.secretKey,
  { kid: fingerprint(key.publicKey) },
)

// at the gateway: the algorithm is pinned, never read from the token
const result = jws.verifyJws(token, key.publicKey, { alg: 'ML-DSA-65' })
result.valid   // true
```

The header carries `ML-DSA-65`. Rewrite the claim set to `svc-admin` and keep the signature, and `verifyJws` returns `valid: false`. Pinning `alg` at the verifier closes the best-known JWT hole, where the token names its own algorithm.

## 5. Long-lived data, re-encrypted

M-26-15 tells agencies to prioritise "re-encrypting long-lived sensitive data using keys protected by PQC mechanisms". That is archives, backups and ledgers, the data a recording adversary wants most. kxco-pq-vault does it from the terminal.

```
npx kxco-vault keygen --out archive.kxco
RECIPIENT=$(npx kxco-vault recipient archive.kxco)   # the public recipient string, to share
npx kxco-vault encrypt ledger-2019.csv --recipient "$RECIPIENT" --out ledger-2019.csv.kxco
npx kxco-vault inspect ledger-2019.csv.kxco
npx kxco-vault decrypt ledger-2019.csv.kxco --identity archive.kxco --out restored.csv
```

```
version:    KXCO-VAULT/1.0
algorithm:  ml-kem-768+aes-256-gcm
recipients: 1
```

`restored.csv` came back byte-identical. The same file opened with a different identity exits 1 with `recipient kid not in envelope`. An envelope can name several recipients, so an archive can be readable by a key in each region without sharing one.

## 6. The inventory: a CBOM from the lockfile

Section 5(d) gives CISA until 19 March 2027 to set the "minimum elements for a cryptographic bill of materials". The inventory starts before that. Run against a project that depends on jsonwebtoken, kxco-pq-scan printed:

```
$ npx kxco-pq-scan

  app: 15 packages installed

  QUANTUM-VULNERABLE (4)
    ecdsa-sig-formatter@1.0.11  ECDSA
      pulled in by: jwa
    jsonwebtoken@9.0.3  RSA, ECDSA
      pulled in by: (root)
      note: only when signing with RS*, PS* or ES*; HS* is HMAC and is not broken
    jwa@2.0.1  RSA, ECDSA
      pulled in by: jws
    jws@4.0.1  RSA, ECDSA
      pulled in by: jsonwebtoken
```

It exits 1, so it can gate CI. `npx kxco-pq-scan --cbom > cbom.json` writes the same finding as CycloneDX 1.6, with RSA and ECDSA recorded as cryptographic assets. The "pulled in by" line is the useful part. Here 3 of the 4 findings are transitive, and the one to change is jsonwebtoken at the root.

## A control for the auditor's first question

The auditor's first question is which module performs the cryptography. Section 6(b) of the Order tells NIST to "accelerate validations of cryptographic modules", and validation is where that answer gets checked. On Node 24 and later the answer for this code is OpenSSL, and the application can prove it at startup.

```
import { requireNativeBackend, backend } from 'kxco-post-quantum'

requireNativeBackend(['ML-DSA-65', 'ML-KEM-768'])   // throws ERR_KXCO_PQ_BACKEND unless OpenSSL does the maths
backend()   // { kind: 'openssl', openssl: '3.5.x', ... }
```

Run the same file with `KXCO_PQ_BACKEND=javascript` and it stops with `ERR_KXCO_PQ_BACKEND` and exits 1. That is the negative control, and it turns an answer on a questionnaire into a line that fails the deployment.

## What the packages carry

- [kxco-post-quantum](https://www.npmjs.com/package/kxco-post-quantum) 1.7.7: ML-KEM-768, ML-DSA-65 and SLH-DSA from FIPS 203, 204 and 205, ML-DSA-87 and ML-KEM-1024 behind the same API, compact JWS, and the backend control.
- It passes 1,793 NIST ACVP test vectors with 0 failed, and 225 interoperability checks against liboqs, Bouncy Castle and the Python reference implementations with 0 failed, per [CONFORMANCE.md](https://github.com/KnightsbridgeAIQ/kxco-post-quantum/blob/main/CONFORMANCE.md).
- [kxco-pq-vault](https://www.npmjs.com/package/kxco-pq-vault) 1.1.7: ML-KEM-768 with AES-256-GCM envelopes for files and payloads, one or many recipients.
- [kxco-pq-scan](https://www.npmjs.com/package/kxco-pq-scan) 1.1.2: the lockfile scan and the CycloneDX 1.6 CBOM.

All 3 are Apache-2.0, and each installed version was npm's latest on 30 September and carries a provenance attestation.

## For institutions

The cryptography is free, works offline and needs nothing from KXCO. What KXCO sells is the part that has to be operated. A hosted key registry answers, at the moment a signature is checked, whether the key is active, revoked or rotated. Live revocation confirms that a signing key is still trusted now. An on-chain timestamp is anchored on Armature L1, where the chain itself checks it. A relay submits signed intents, so the institution never holds a token or runs a node. Support comes with an SLA and a named contact. It is priced in US dollars, per seat, per year. KXCO is a software company and holds no customer assets. Write to admin@kxco.ai, or start at [kxco.ai/contact](https://kxco.ai/contact).

## What to watch

The FAR Council's proposed rule under section 6(c) is due by 19 December 2026. It is the first draft of the contract clause that carries the 2030 date to every covered contractor, and it is the text a vendor's legal team will read first. CISA's minimum CBOM elements follow by 19 March 2027, and the scan output above is what gets checked against them.

## Sources

Executive Order 14412, 22 June 2026, 91 FR 38483, sections 4(b), 5(d), 6(b) and 6(c). OMB M-26-15, 24 June 2026. NIST FIPS 203 and FIPS 204, August 2024. NSA CNSA 2.0 Algorithms advisory. OpenSSL NEWS for 3.5.0, 8 April 2025. Node.js 24.7.0 release notes, 27 August 2025. Key exchange measured by this desk against Cloudflare's /cdn-cgi/trace endpoint, 30 September 2026 at 00:27 Bangkok time, 17:27 UTC on 29 September. Code run against kxco-post-quantum 1.7.7, kxco-pq-vault 1.1.7 and kxco-pq-scan 1.1.2 from the npm registry, 30 September 2026.

Shayne Heffernan, Ph.D., is the founder of Live Trading News, the KnightsBridge Group, Knightsbridge Law and the KXCO.ai ecosystem spanning post-quantum cryptography, identity, attestation and enterprise ontology.

*This note is commentary. It is not legal advice. Code is shown as it ran on the versions named. Read the primary text before you plan against a date.*

---

This Markdown mirrors https://www.livetradingnews.com/the-2030-post-quantum-deadline-in-code-6-changes-and-the-test-for-each. The HTML page is canonical.
Site index for AI clients: https://www.livetradingnews.com/llms.txt
