kxco-post-quantum 1.7.2 → 1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.7.3
4
+
5
+ One resolution fix that consumers could hit, plus the ACVTS tooling and two
6
+ maturity documents. No change to any algorithm, key format or wire format.
7
+
8
+ **Every export subpath now carries a `default` condition.** All twelve declared
9
+ only `types` and `import`, so a consumer resolving outside an import context got
10
+ `ERR_PACKAGE_PATH_NOT_EXPORTED` and could not load the package at all. That is a
11
+ packaging defect rather than a library one: nothing about the code changed, only
12
+ what Node is willing to resolve. It was found from the other side, in a project
13
+ that had to pass `--conditions=import` on every test invocation to work around
14
+ it, and that workaround can come out once this is published.
15
+
16
+ The addition is purely additive. A subpath that resolved before resolves to the
17
+ same file now.
18
+
19
+ **ACVTS tooling is committed rather than kept locally.** The selftest, the
20
+ validation printer and the demo certificate verifier were written against the
21
+ NIST demo submission and existed only on one machine, which makes them evidence
22
+ nobody else can re-run.
23
+
24
+ **Two PQCMM gaps closed and Level 3 re-declared**, against the PKI Consortium's
25
+ Post-Quantum Cryptography Maturity Model, with the self-assessment written down
26
+ rather than asserted.
27
+
3
28
  ## 1.7.2
4
29
 
5
30
  Documentation, and one typing fix. No source change to the library and no wire
@@ -0,0 +1,227 @@
1
+ # Cryptographic inventory
2
+
3
+ Every use case in this package where cryptography is applied, mapped onto the
4
+ ten categories of the PKI Consortium PQCMM cryptographic inventory taxonomy.
5
+
6
+ The model requires that no category is omitted. A category that does not apply
7
+ is marked not applicable with a written reason, because "we do not do that" and
8
+ "we did not look" are indistinguishable from the outside unless the reason is
9
+ recorded. Four of the ten genuinely do not apply to a library with no sockets
10
+ and no persistent state, and saying so in one line each is the honest answer
11
+ rather than a padded one.
12
+
13
+ Scope: `kxco-post-quantum` 1.7.2. `BOUNDARY.md` is the companion document and
14
+ explains the difference between cryptography this package performs, depends on,
15
+ and merely offers to a caller. The distinction matters here: a caller can use
16
+ this package inside a category that the package itself does not implement.
17
+
18
+ ## 1. Data in transit
19
+
20
+ **Not applicable to the library. Applicable to its delivery.**
21
+
22
+ Nothing in `src/` opens a socket. The library performs no network operation at
23
+ any point: no licence check, no telemetry, no key server, no call home. There
24
+ is no transport for it to protect.
25
+
26
+ Its own delivery is a different matter and is not quantum-safe. Fetching the
27
+ package is classical TLS to the npm registry or to GitHub, as was the transport
28
+ that delivered any git clone. That residual is stated in `BOUNDARY.md` and is
29
+ mitigated by an ML-DSA-65 signature over every release asset plus a second copy
30
+ of the public key committed to the repository, so that a verifier is not
31
+ trusting the same channel twice. Mitigated, not eliminated.
32
+
33
+ What the package offers a caller for this category is the ML-KEM key
34
+ encapsulation below, from which a caller may build a transport. Offering a
35
+ primitive is not the same as protecting a transport, and the two should not be
36
+ reported as one.
37
+
38
+ | Use | Algorithm | Quantum-safe |
39
+ |---|---|---|
40
+ | Package delivery | TLS to registry and GitHub, classical | No, mitigated by signature |
41
+ | Primitive offered to callers | ML-KEM-768, ML-KEM-1024 | Yes |
42
+
43
+ ## 2. Data at rest
44
+
45
+ **Not applicable.** The package writes no files and keeps no state between
46
+ calls. There is no disk, database or object storage in its boundary to encrypt.
47
+
48
+ A caller who persists a key or a seed produced by this package is performing
49
+ data-at-rest protection in their own system, with their own choice of
50
+ algorithm, and this package neither sees nor constrains it. The one supported
51
+ route that removes the question is `kxco-pq-hsm`, which generates ML-DSA keys
52
+ on a PKCS#11 token with `CKA_EXTRACTABLE=false`, after which this package
53
+ handles verification only and touches no secret.
54
+
55
+ ## 3. Identity, authentication and certificates
56
+
57
+ **Applicable, and quantum-safe within the package.**
58
+
59
+ No X.509. No certificate chain, no path validation, no revocation. Identity
60
+ here is a raw key plus a key identifier, and the package deliberately does not
61
+ pretend to be a PKI.
62
+
63
+ | Use | Algorithm | Quantum-safe |
64
+ |---|---|---|
65
+ | Signature and verification | ML-DSA-65, ML-DSA-87 (FIPS 204) | Yes |
66
+ | Hash-based alternative | SLH-DSA, ten parameter sets (FIPS 205) | Yes |
67
+ | Key identifier | SHA-256 over the public key, truncated to 16 hex characters (`kid.js`) | Yes, second-preimage bound |
68
+ | Key interchange | JWK `kty: AKP` per RFC 9964, and PKCS#8 seed export | Format, not an algorithm |
69
+ | JWS signing | ML-DSA over the JWS signing input (`jws.js`) | Yes |
70
+ | Webhook delivery signing | HMAC-SHA-256 **and** ML-DSA-65, both (`webhook.js`) | Yes, hybrid |
71
+
72
+ The `kid` is a truncated SHA-256, so it is a 64-bit identifier and not a
73
+ security boundary. It identifies which key to try; it does not authenticate
74
+ anything. Grover halves the preimage work on SHA-256 and the truncation
75
+ dominates that anyway, which is why nothing in the package makes a trust
76
+ decision on a `kid` alone.
77
+
78
+ ## 4. Code, firmware and update signing
79
+
80
+ **Applicable, and quantum-safe.**
81
+
82
+ Every release asset is signed with ML-DSA-65 by this package's own signing
83
+ path, which means the signing of the package is performed by the thing being
84
+ signed. The public key is committed to the repository at
85
+ `release-signing-key.pub.hex` and published as a release asset, so a verifier
86
+ can obtain it by a path other than the one that delivered the artefact.
87
+ Verification is four lines and is in `README.md`.
88
+
89
+ No firmware. The package ships no binary and no native build of its own; the
90
+ native path calls the OpenSSL already present in the host runtime.
91
+
92
+ | Use | Algorithm | Quantum-safe |
93
+ |---|---|---|
94
+ | Release asset signing | ML-DSA-65 | Yes |
95
+ | Signature over the evidence bundle | ML-DSA-65, `.sig` beside each bundle | Yes |
96
+
97
+ ## 5. Key wrapping and key-encryption keys
98
+
99
+ **Applicable in a limited form, and quantum-safe.**
100
+
101
+ The package wraps no keys. It has no KEK hierarchy, no envelope encryption and
102
+ no key store.
103
+
104
+ What it does have is deterministic derivation, which occupies the same place in
105
+ a design without being key wrapping. `keypairFromMaster` derives a per-purpose
106
+ seed from a caller-held master secret using HKDF-SHA-512 with an empty salt and
107
+ a caller-chosen `info` string, then generates the keypair from that seed. A
108
+ master secret therefore stands in the position a KEK would occupy, and its
109
+ protection is entirely the caller's.
110
+
111
+ | Use | Algorithm | Quantum-safe |
112
+ |---|---|---|
113
+ | Seed derivation from a master secret | HKDF-SHA-512 (`derive.js`) | Yes, symmetric |
114
+ | Key encapsulation offered to callers | ML-KEM-768, ML-KEM-1024 (FIPS 203) | Yes |
115
+ | Hybrid key establishment | `deriveSeed` combines an ML-KEM shared secret with a classical secret through the KDF | Yes, holds if either half holds |
116
+
117
+ ## 6. Random number generation and entropy sources
118
+
119
+ **Applicable, and this is the entry a reader should not skim.**
120
+
121
+ **This package generates no randomness in its JavaScript backend.** There is no
122
+ `randomBytes`, no `getRandomValues`, no `randomFillSync` anywhere in `src/`
123
+ outside the native path. Every keypair is produced from a seed the caller
124
+ supplies, either directly through `keypairFromSeed` or derived from a
125
+ caller-held master through `keypairFromMaster`. Seed length is enforced against
126
+ the FIPS parameter set and a wrong length is a `RangeError`, not a silent pad.
127
+
128
+ The consequence is worth stating plainly: **in the JavaScript backend, the
129
+ quality of every private key in this system is a property of the caller's
130
+ entropy source, not of this package.** A caller who supplies a low-entropy seed
131
+ gets a low-entropy key and the library cannot detect it. This is a deliberate
132
+ design choice, because deterministic derivation is what makes the keys
133
+ reproducible and the conformance vectors pinnable, but it relocates a security
134
+ property rather than solving it.
135
+
136
+ The native backend is different. `crypto.generateKeyPairSync` in `_native.node.js`
137
+ delegates to Node and thence to the OpenSSL DRBG, so on that path entropy comes
138
+ from the operating system.
139
+
140
+ | Path | Entropy source | Whose responsibility |
141
+ |---|---|---|
142
+ | JavaScript backend | Caller-supplied seed | The caller |
143
+ | JavaScript backend, derived | HKDF-SHA-512 over a caller-supplied master | The caller |
144
+ | Native backend keygen | OpenSSL DRBG via `crypto.generateKeyPairSync` | The operating system |
145
+
146
+ No category of quantum attack applies to a DRBG in the way it applies to a
147
+ public-key primitive; the risk here is classical and it is entropy starvation.
148
+
149
+ ## 7. Telemetry, logging and audit-trail integrity
150
+
151
+ **Not applicable.** The package emits no telemetry and writes no log. It keeps
152
+ no state between calls, so there is no audit trail of its own to protect.
153
+
154
+ Log integrity in the wider KXCO estate is `kxco-pq-audit`, a separate package:
155
+ SHA-256 hash-chained entries, each signed with ML-DSA-65, with periodic seals
156
+ anchored on Armature L1 so that a verifier who does not trust the log operator
157
+ still has an independent time bound. What this package contributes to that is
158
+ the signature primitive and nothing else.
159
+
160
+ ## 8. Build, CI/CD and supply-chain signing
161
+
162
+ **Applicable, and quantum-safe for what we sign, classical for what GitHub and
163
+ npm sign.** This split is the honest answer and collapsing it would be an
164
+ overclaim.
165
+
166
+ | Use | Algorithm | Quantum-safe |
167
+ |---|---|---|
168
+ | Release assets and evidence bundle | ML-DSA-65, ours | Yes |
169
+ | SLSA provenance attestation | Sigstore, classical (ECDSA and the Fulcio and Rekor chain) | **No** |
170
+ | npm registry signature and provenance | npm's own, classical | **No** |
171
+ | Reproducible build | Not a signature. The published tarball rebuilds bit-for-bit from its own tag, verified in CI on every run | Not applicable |
172
+ | CycloneDX SBOM | Generated by `npm sbom` from the published tree; integrity carried by the ML-DSA signature over the release | Yes, via the release signature |
173
+
174
+ The reproducible build is the part of this category that does not depend on any
175
+ signature algorithm at all, and it is the reason the classical rows above are a
176
+ weaker residual than they look: a verifier who rebuilds from source is not
177
+ trusting Sigstore, npm or us.
178
+
179
+ ## 9. Attestation and remote attestation
180
+
181
+ **Applicable in the supply-chain sense only.**
182
+
183
+ There is no hardware attestation, no TPM quote, no confidential-computing
184
+ report and no remote-attestation protocol in this package.
185
+
186
+ What exists is build attestation: an in-toto statement at
187
+ `evidence.intoto.jsonl` and an evidence manifest that pins the commit, the
188
+ toolchain, the backend, the dependency versions and every step with its exact
189
+ command, result and duration, with a SHA-256 for each file in the bundle. The
190
+ in-toto and SLSA layer is signed classically by Sigstore, as row 2 of category
191
+ 8 records. The manifest and bundle are additionally signed with ML-DSA-65 by us.
192
+
193
+ ## 10. Backup, archival and long-term storage
194
+
195
+ **Applicable as a stated gap, and this is the weakest category.**
196
+
197
+ Verification of old records holds: a signature made by any version of this
198
+ package verifies under any later version. Wire formats have not changed, and
199
+ the conformance evidence is regenerated against pinned vectors on every
200
+ dependency bump, which is the control that would catch a change breaking them.
201
+
202
+ Long-term trust does not hold and is a different question. This package has no
203
+ notion of key validity windows, no revocation and no trusted timestamps. It can
204
+ tell you a signature is arithmetically valid. It cannot tell you the key was
205
+ still trusted when the signature was made. Anything that has to hold for years
206
+ needs a time anchor outside the signature. Inside the KXCO estate that anchor
207
+ is `kxco-pq-audit`'s on-chain seals. Outside it, this is a gap the deployment
208
+ has to close, and this package should not be cited as closing it.
209
+
210
+ ## Summary
211
+
212
+ | # | Category | Status |
213
+ |---|---|---|
214
+ | 1 | Data in transit | Library N/A; delivery is classical TLS, signature-mitigated |
215
+ | 2 | Data at rest | N/A, no persistence |
216
+ | 3 | Identity, authentication, certificates | Quantum-safe, no X.509 |
217
+ | 4 | Code, firmware, update signing | Quantum-safe |
218
+ | 5 | Key wrapping and KEKs | Quantum-safe, no wrapping; master secret is the caller's |
219
+ | 6 | RNG and entropy | **Relocated to the caller** in the JavaScript backend |
220
+ | 7 | Telemetry, logging, audit integrity | N/A, separate package |
221
+ | 8 | Build, CI/CD, supply chain | Split: ours quantum-safe, Sigstore and npm classical |
222
+ | 9 | Attestation | Build attestation only, classically signed at the Sigstore layer |
223
+ | 10 | Backup, archival, long-term | **Gap.** No timestamps, validity windows or revocation |
224
+
225
+ Three residuals carry forward into `PQCMM.md` and `HNDL.md` rather than being
226
+ recorded only here: classical release transport, the classical Sigstore and npm
227
+ signature layer, and the absence of long-term validation.
package/HNDL.md ADDED
@@ -0,0 +1,84 @@
1
+ # HNDL exposure register
2
+
3
+ Harvest-now-decrypt-later exposure for `kxco-post-quantum` 1.7.2, as required
4
+ at Level 3 of the PKI Consortium PQCMM: which data flows handled by the product
5
+ carry a long-lived confidentiality requirement, and which algorithm protects
6
+ each.
7
+
8
+ ## What HNDL is, and why most of this register is short
9
+
10
+ HNDL is a confidentiality attack. An adversary records ciphertext today and
11
+ decrypts it once a cryptographically relevant quantum computer exists. It
12
+ applies to data whose confidentiality must outlast that machine.
13
+
14
+ It does **not** apply to signatures in the same way. A signature forged in 2040
15
+ is worthless against a document verified in 2026, because the verification
16
+ already happened. The quantum risk to a signature scheme is forgery of *future*
17
+ verifications, which is an integrity and non-repudiation problem with a
18
+ different shape and a different deadline. Registers that fold the two together
19
+ overstate their own exposure, and this one keeps them apart.
20
+
21
+ **This package is predominantly a signing library.** Most of what it handles is
22
+ therefore outside HNDL by nature, and the register is short for a real reason
23
+ rather than an incomplete one. Where confidentiality genuinely is at stake, the
24
+ rows below say so.
25
+
26
+ ## Register
27
+
28
+ | # | Data flow | Long-lived confidentiality? | Protected by | Quantum-safe | Residual |
29
+ |---|---|---|---|---|---|
30
+ | 1 | Private keys and seeds held in caller memory | **Yes, for the key's whole life** | Nothing in this package. Caller's process isolation | Not a cryptographic control | **The primary exposure.** See below |
31
+ | 2 | Master secret used by `keypairFromMaster` | **Yes, and it is worse than a single key** | Nothing in this package. Caller's storage | Not a cryptographic control | Compromise derives every child key, past and future |
32
+ | 3 | ML-KEM shared secret, in transit | Depends entirely on the caller's use | ML-KEM-768 or ML-KEM-1024 (FIPS 203) | **Yes** | The classical half of a hybrid pairing, if the caller adds one |
33
+ | 4 | Payload a caller encrypts under an ML-KEM-derived key | Caller's to determine | The caller's AEAD, not ours | Symmetric, so Grover only | Key size is the caller's choice; this package does not perform the encryption |
34
+ | 5 | Package delivery over TLS to npm or GitHub | **No** | Classical TLS | No | Confidentiality is irrelevant: the package is public. Integrity is the concern and ML-DSA-65 covers it |
35
+ | 6 | Signatures, JWS, webhook envelopes | **No** | ML-DSA-65 or SLH-DSA, plus HMAC-SHA-256 on webhooks | Yes | Integrity risk, not HNDL. Recorded here only so its absence is deliberate |
36
+ | 7 | Evidence bundle and SBOM | **No** | Published deliberately | Not applicable | Public by design |
37
+ | 8 | Keys held on a PKCS#11 token via `kxco-pq-hsm` | Yes, but outside this boundary | `CKA_EXTRACTABLE=false` | Hardware control | The vendor's channel to the token is the vendor's, per `BOUNDARY.md` |
38
+
39
+ ## The two rows that matter
40
+
41
+ **Rows 1 and 2 are the real HNDL exposure of this product, and neither is
42
+ solved by a post-quantum algorithm.**
43
+
44
+ A private key is confidential for its entire life, which is exactly the
45
+ long-lived requirement HNDL describes. An adversary who harvests a stored
46
+ ML-DSA private key today does not need a quantum computer at all; they need the
47
+ key. The algorithm being post-quantum protects the signature against
48
+ cryptanalysis, not the key against theft. So the strongest post-quantum
49
+ posture in this package does nothing for its largest confidentiality asset.
50
+
51
+ Row 2 is worse in one specific way. A master secret under HKDF-SHA-512
52
+ regenerates every derived keypair, for every `info` string, past and future. It
53
+ is a single point whose compromise is not bounded in time. That is the correct
54
+ tradeoff for reproducible keys and pinnable conformance vectors, and it is the
55
+ right design, but the concentration of risk should be visible rather than
56
+ implied.
57
+
58
+ Neither row has a cryptographic mitigation available inside a library. What
59
+ exists is the escape in row 8: `kxco-pq-hsm` generates keys on a PKCS#11 token
60
+ with `CKA_EXTRACTABLE=false`, after which this package handles verification
61
+ only and touches no secret. **A deployment with a long-lived confidentiality
62
+ requirement on its keys should be using that path, and this register exists in
63
+ part to say so.**
64
+
65
+ ## What this register does not cover
66
+
67
+ Callers. This package has no visibility into what a caller encrypts, how long
68
+ they need it confidential, or where they put a key. Rows 3 and 4 are marked as
69
+ the caller's to determine because they genuinely are, and a register claiming
70
+ otherwise would be inventing knowledge it does not have.
71
+
72
+ The absence of long-term validation, recorded as category 10 of
73
+ `CRYPTO-INVENTORY.md`, is an adjacent gap rather than an HNDL one. No
74
+ timestamps, no validity windows, no revocation. It bears on whether an old
75
+ signature can still be trusted, not on whether old ciphertext can be read.
76
+
77
+ ## Review
78
+
79
+ This register is a claim about a shipped version and it ages. It should be
80
+ re-read whenever a new cryptographic use case enters the package, whenever a
81
+ category in `CRYPTO-INVENTORY.md` changes status, and on any change to how
82
+ seeds or master secrets are handled.
83
+
84
+ Last reviewed against 1.7.2 on 2026-09-09.
package/PQCMM.md ADDED
@@ -0,0 +1,164 @@
1
+ # PQC Maturity Model self-assessment
2
+
3
+ PKI Consortium PQC Maturity Model (PQCMM), assessed against the model as
4
+ published at <https://pkic.org/wg/pqc/pqcmm/>.
5
+
6
+ **Declared level: 3 (Advanced).**
7
+
8
+ A self-assessment is indicative, not authoritative. It is the vendor's own view
9
+ and it has not been independently verified. The model says relying parties
10
+ should treat a self-assessed level as a signal rather than a guarantee, and that
11
+ is how this document should be read. Where a criterion is not met, this document
12
+ says so and names what is missing rather than reporting a partial as a pass.
13
+
14
+ ## Scope
15
+
16
+ | Field | Value |
17
+ |---|---|
18
+ | Product | `kxco-post-quantum` |
19
+ | Version assessed | 1.7.2 |
20
+ | Commit | `90b5778b4d19ed0f78715e143a6a50b9170b70f9`, clean tree |
21
+ | Registry | <https://www.npmjs.com/package/kxco-post-quantum> |
22
+ | Licence | Apache-2.0 |
23
+ | Assurance method | Self-assessment |
24
+ | Date | 2026-09-09 |
25
+
26
+ A PQCMM assessment applies to a single product. The other `kxco-pq-*` packages
27
+ depend on this one and are not covered here; each needs its own assessment.
28
+
29
+ ## Evidence available to an assessor
30
+
31
+ Everything cited below is a permanent unauthenticated URL. No account, no
32
+ request to us, no expiring artifact.
33
+
34
+ | Artefact | Path under the release |
35
+ |---|---|
36
+ | Evidence manifest | `releases/latest/download/manifest-node24.x.json` |
37
+ | Evidence bundle | `releases/latest/download/evidence-node24.x.zip` |
38
+ | CycloneDX SBOM | `releases/latest/download/sbom.cyclonedx.json` |
39
+ | In-toto attestation | `releases/latest/download/evidence.intoto.jsonl` |
40
+ | Release signing key | `releases/latest/download/release-signing-key.pub.hex` |
41
+
42
+ Base: `https://github.com/KnightsbridgeAIQ/kxco-post-quantum/`
43
+
44
+ Two documents in the repository carry the Level 3 evidence and are cited
45
+ throughout: `CRYPTO-INVENTORY.md` for the ten-category cryptographic inventory,
46
+ and `HNDL.md` for the harvest-now-decrypt-later exposure register.
47
+
48
+ The manifest pins the commit, the toolchain (Node 24.20.0, OpenSSL 3.5.7), the
49
+ backend, the dependency versions, and every step with its exact command, its
50
+ result and its duration. Each file in the bundle carries its SHA-256. The
51
+ conformance and interop runs are reproducible from the commands recorded in the
52
+ manifest rather than taken on our word.
53
+
54
+ ## Level 1, Initial: MET
55
+
56
+ | # | Criterion | Answer | Evidence |
57
+ |---|---|---|---|
58
+ | 1 | A quantum-safe algorithm in a released build | Yes | ML-DSA-65 (FIPS 204), ML-KEM-768 (FIPS 203), SLH-DSA-SHA2-192s (FIPS 205) in 1.7.2 on the public npm stable channel. Category 5 sets ML-DSA-87 and ML-KEM-1024 also ship. |
59
+ | 2 | The feature can be enabled | Yes | Available on import. No flag, no custom build, no source modification. |
60
+ | 3 | Documented for evaluation | Yes | `README.md`, with a per-function API reference. |
61
+
62
+ Release channel is stable and public, available to all consumers, with no
63
+ programme enrolment. Ten SLH-DSA parameter sets are exposed, not one.
64
+
65
+ ## Level 2, Foundational: MET
66
+
67
+ | # | Criterion | Answer | Evidence |
68
+ |---|---|---|---|
69
+ | 1 | Quantum-safe algorithms in core production functionality | Yes | Signing, key encapsulation, key derivation and fingerprinting are the product's core, not a preview channel. |
70
+ | 2 | Compatibility with a published standard from a recognised body | Yes | NIST FIPS 203, 204 and 205. |
71
+ | 3a | Standards-conformance testing | Yes | 2,103 NIST ACVP vectors: 1,793 passed, 0 failed, 310 skipped. Every skip is this library refusing a pre-hash weaker than the parameter set, listed individually with its reason. A skip is not counted as a pass. See `CONFORMANCE.md` and manifest steps `acvp`, `acvp-fips205`, `acvp-fips205-siggen`. |
72
+ | 3b | Interoperability against an independent conformant implementation | Yes, four of them | 225 cross-implementation checks, 0 failed, both directions, with negative controls, against liboqs, Bouncy Castle and two pure-Python implementations. Run against both backends. Manifest step `interop`. |
73
+ | 3c | Functional security testing as configured for production | Yes | `npm test` recorded in the manifest, plus the fuzz corpus under `fuzz/`. |
74
+ | 3d | Smoke performance test under representative load | Yes | `BENCHMARKS.md`: per-algorithm p95 and p99 on both backends, on x86-64 and arm64, plus memory. |
75
+ | 4 | Documented for production use including known limitations | Yes | `THREAT-MODEL.md` for what is and is not defended, `BOUNDARY.md` for which cryptography this package performs versus depends on versus offers, plus `LIFECYCLE.md` and `MIGRATION.md`. |
76
+
77
+ Level 2 asks for CAVP or ACVTS results "or equivalent". Ours are the NIST ACVP
78
+ vectors run by us and published with the commands to reproduce them. That is
79
+ equivalent evidence, not a NIST certificate. **There is no CAVP certificate
80
+ number for this product.** An assessor checking the CAVP or CMVP database will
81
+ find nothing, and should record that.
82
+
83
+ ## Level 3, Advanced: MET
84
+
85
+ | # | Criterion | Answer | Evidence |
86
+ |---|---|---|---|
87
+ | 1 | Full cryptographic inventory across every applicable taxonomy category | Yes | `CRYPTO-INVENTORY.md` covers all ten categories. Four are marked not applicable with a written reason; none is omitted. |
88
+ | 2 | Non-quantum-safe features documented and flagged | Yes | `BOUNDARY.md`, "The gaps, collected", and the classical rows of `CRYPTO-INVENTORY.md` categories 1, 8 and 9. |
89
+ | 3 | SBOM or equivalent component inventory | Yes | CycloneDX SBOM as a release asset at a permanent URL, generated by `npm sbom` from the tree that was published. Manifest step `sbom`. |
90
+ | 4 | Crypto agility, two algorithms selectable in the same role | Yes | ML-DSA-65 and SLH-DSA-SHA2-192s are both available in the signature role by configuration, which is two different algorithms rather than two parameter sets of one. `AGILITY.md` separates the replacement plan, the implemented mechanism and the interoperable transition, and states what the package does not give you. |
91
+ | 5 | Documented HNDL exposure register | Yes | `HNDL.md`. Eight data flows, each with its confidentiality horizon, its protecting algorithm and its residual. |
92
+
93
+ Writing the inventory against the taxonomy produced two findings that this
94
+ package's own audit documents had not stated, and both are recorded rather than
95
+ smoothed over.
96
+
97
+ **The library generates no randomness in its JavaScript backend.** Every
98
+ keypair comes from a caller-supplied seed, or from a master secret through
99
+ HKDF-SHA-512. So in that backend the entropy quality of every private key is a
100
+ property of the caller, not of this package, and the package cannot detect a
101
+ weak seed. The native backend differs: `crypto.generateKeyPairSync` uses the
102
+ OpenSSL DRBG. `CRYPTO-INVENTORY.md` category 6.
103
+
104
+ **The largest HNDL exposure in this product has no post-quantum mitigation.**
105
+ Private keys and, more sharply, the master secret behind `keypairFromMaster`
106
+ are confidential for their whole life, which is precisely the long-lived
107
+ requirement HNDL describes. A post-quantum algorithm protects the signature
108
+ against cryptanalysis and does nothing for the key against theft. The available
109
+ answer is the PKCS#11 path in `kxco-pq-hsm`, not an algorithm choice here.
110
+ `HNDL.md`, rows 1 and 2.
111
+
112
+ ## Level 4, Managed: NOT MET
113
+
114
+ | # | Criterion | Answer | Evidence or gap |
115
+ |---|---|---|---|
116
+ | 1 | CBOM maintained | **No** | The product publishes an SBOM, not a CBOM. `CRYPTO-INVENTORY.md` now records each algorithm with its protocol context and usage purpose, which is the human-readable half of what a CBOM carries, but it is prose rather than a machine-readable CBOM and key sizes are stated by parameter set rather than per field. Closing this means emitting a CycloneDX CBOM as a release asset, which is a build change rather than a document. |
117
+ | 2 | Zero-legacy capability across every in-scope component | **Not determined** | Not assessed against the model's wording, which extends to boot, firmware update signing, hardware-bound operations and internal diagnostics. Claiming it without that determination would be an overclaim. |
118
+ | 3 | Symmetric and hash strengths adequate beyond CRQC availability | Yes | SHA-256 for key identifiers and webhook HMAC, SHA-512 under HKDF for seed derivation, via `@noble/hashes` 2.4.0. Per-use detail in `CRYPTO-INVENTORY.md`. |
119
+ | 4 | Hybrid and composite support documented, with contexts | Partial | Hybrid is documented: `webhook` performs HMAC plus ML-DSA-65 delivery signing, and `deriveSeed` exists to combine an ML-KEM shared secret with a classical secret through a KDF. Composite, in the algorithm-fused sense, is not supported and is not currently stated as unsupported. |
120
+
121
+ ## Level 5, Optimized: NOT MET
122
+
123
+ | # | Criterion | Answer | Evidence or gap |
124
+ |---|---|---|---|
125
+ | 1 | Quantum-safe by default, legacy requires explicit enablement | Yes | There is no classical algorithm to fall back to. The default parameter set is Category 3. |
126
+ | 2 | Benchmarked and tuned against operational requirements | Yes | `BENCHMARKS.md`. Two figures stated rather than hidden: ML-DSA signing keeps a rejection-sampling tail on either backend, and SLH-DSA-SHA2-192s signs in seconds rather than milliseconds. |
127
+ | 3 | Primarily follows standards from a recognised body | Yes | FIPS 203, 204 and 205. |
128
+ | 4 | **Independently verified or certified** | **No** | No FIPS 140 validation. No Common Criteria evaluation. The underlying `@noble/post-quantum` 0.7.0 has no published third-party formal security analysis covering the implemented PQC algorithms, so the library-based route in the model's wording is not available either. |
129
+
130
+ Criterion 4 is the binding constraint and it cannot be closed by documentation.
131
+ It requires a paid engagement: a CAVP or CMVP validation through an accredited
132
+ laboratory, a Common Criteria evaluation, or a published independent audit of
133
+ the cryptographic implementation.
134
+
135
+ ## Assessment methodology record
136
+
137
+ The model requires this record to accompany an assessment.
138
+
139
+ - **Evidence method.** Documentation review, plus the published evidence
140
+ manifest, plus verification of the licence state of every published package
141
+ against the public npm registry on 2026-09-09.
142
+ - **Cryptographic library.** `@noble/post-quantum` 0.7.0 and `@noble/hashes`
143
+ 2.4.0 in the JavaScript backend; `node:crypto` on OpenSSL 3.5.7 in the native
144
+ backend. Both versions are recorded in the manifest. `@noble/post-quantum` is
145
+ maintained, and its PQC support is confirmed from its public repository. It
146
+ has **not** been independently audited. Version 0.7.1 is deliberately not
147
+ adopted because it regressed SLH-DSA, so the dependency is pinned at 0.7.0.
148
+ - **Reproduction attempts.** All conformance, interop, test and SBOM steps in
149
+ the manifest ran in CI from a clean tree at commit `90b5778`, on Node
150
+ 24.20.0, linux-x64, on 2026-09-08. Every step reports `ok: true`, and
151
+ `sampling.full` is `true`.
152
+ - **Public database checks.** npm registry, all sixteen published `kxco-*`
153
+ packages, 2026-09-09: every one reports `Apache-2.0`. NIST CAVP and CMVP: no
154
+ certificate exists for this product, confirmed rather than assumed.
155
+ - **Unverified claims.** Every criterion answered Yes above is vendor-stated and
156
+ not independently verified. That is what a self-assessment is. The manifest
157
+ and the bundle exist so that an assessor can convert these into verified
158
+ findings without asking us for anything.
159
+
160
+ ## Corrections
161
+
162
+ If any statement here is wrong, it should be corrected here first, and the
163
+ correction dated. Facts about this package that are commonly recorded wrongly,
164
+ with the one-line check for each, are listed at the top of `README.md`.
package/README.md CHANGED
@@ -336,7 +336,7 @@ Install this package directly when you need ML-DSA or ML-KEM without the rest of
336
336
 
337
337
  ## Security
338
338
 
339
- Cryptographic operations delegate entirely to [`@noble/post-quantum`](https://github.com/paulmillr/noble-post-quantum) and [`@noble/hashes`](https://github.com/paulmillr/noble-hashes) — this package does not reimplement any NIST primitive. `@noble/hashes` falls under Cure53's 2023 audit of the `@noble` ecosystem (`ciphers`, `curves`, `hashes`); `@noble/post-quantum` was **not** in that audit's scope and has been self-audited by its maintainer. See [AUDIT.md](./AUDIT.md) for the full posture.
339
+ Cryptographic operations delegate entirely to [`@noble/post-quantum`](https://github.com/paulmillr/noble-post-quantum) and [`@noble/hashes`](https://github.com/paulmillr/noble-hashes); this package does not reimplement any NIST primitive. `@noble/post-quantum` has never been audited by a third party. It has been self-audited by its maintainer (v0.6.1, April 2026). The other Noble packages were audited separately, at different dates, and none of those engagements covered the post-quantum package: `@noble/hashes` by Cure53 in January 2022, `@noble/curves` by Trail of Bits in February 2023, Kudelski Security in September 2023 and Cure53 in September 2024, and `@noble/ciphers` by Cure53 in September 2024. See [AUDIT.md](./AUDIT.md) for the full posture.
340
340
 
341
341
  To report a vulnerability: [open a private security advisory](https://github.com/KnightsbridgeAIQ/kxco-post-quantum/security/advisories/new) or email **john@knightsbridgelaw.com**. Acknowledgement within 2 business days, triage decision within 5. Full policy, including safe harbour for good-faith research: <https://kxco.ai/security>.
342
342
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kxco-post-quantum",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "ML-DSA-65, ML-KEM-768 and SLH-DSA-SHA2-192s with key fingerprinting. OpenSSL 3.5 primitives on Node 24+, JavaScript elsewhere. 2,103 NIST ACVP vectors: 1,793 passed, 0 failed, 310 skipped. 225 interop checks, 0 failed. Reproducible builds and provenance.",
5
5
  "keywords": [
6
6
  "post-quantum",
@@ -12,6 +12,7 @@
12
12
  "dilithium",
13
13
  "kyber",
14
14
  "nist",
15
+ "acvp",
15
16
  "fips-203",
16
17
  "fips-204",
17
18
  "fips-205",
@@ -61,51 +62,63 @@
61
62
  "exports": {
62
63
  ".": {
63
64
  "types": "./src/index.d.ts",
64
- "import": "./src/index.js"
65
+ "import": "./src/index.js",
66
+ "default": "./src/index.js"
65
67
  },
66
68
  "./ml-dsa": {
67
69
  "types": "./src/ml-dsa.d.ts",
68
- "import": "./src/ml-dsa.js"
70
+ "import": "./src/ml-dsa.js",
71
+ "default": "./src/ml-dsa.js"
69
72
  },
70
73
  "./ml-dsa-87": {
71
74
  "types": "./src/ml-dsa-87.d.ts",
72
- "import": "./src/ml-dsa-87.js"
75
+ "import": "./src/ml-dsa-87.js",
76
+ "default": "./src/ml-dsa-87.js"
73
77
  },
74
78
  "./ml-kem": {
75
79
  "types": "./src/ml-kem.d.ts",
76
- "import": "./src/ml-kem.js"
80
+ "import": "./src/ml-kem.js",
81
+ "default": "./src/ml-kem.js"
77
82
  },
78
83
  "./ml-kem-1024": {
79
84
  "types": "./src/ml-kem-1024.d.ts",
80
- "import": "./src/ml-kem-1024.js"
85
+ "import": "./src/ml-kem-1024.js",
86
+ "default": "./src/ml-kem-1024.js"
81
87
  },
82
88
  "./slh-dsa": {
83
89
  "types": "./src/slh-dsa.d.ts",
84
- "import": "./src/slh-dsa.js"
90
+ "import": "./src/slh-dsa.js",
91
+ "default": "./src/slh-dsa.js"
85
92
  },
86
93
  "./derive": {
87
94
  "types": "./src/derive.d.ts",
88
- "import": "./src/derive.js"
95
+ "import": "./src/derive.js",
96
+ "default": "./src/derive.js"
89
97
  },
90
98
  "./webhook": {
91
99
  "types": "./src/webhook.d.ts",
92
- "import": "./src/webhook.js"
100
+ "import": "./src/webhook.js",
101
+ "default": "./src/webhook.js"
93
102
  },
94
103
  "./kid": {
95
104
  "types": "./src/kid.d.ts",
96
- "import": "./src/kid.js"
105
+ "import": "./src/kid.js",
106
+ "default": "./src/kid.js"
97
107
  },
98
108
  "./seed": {
99
109
  "types": "./src/seed.d.ts",
100
- "import": "./src/seed.js"
110
+ "import": "./src/seed.js",
111
+ "default": "./src/seed.js"
101
112
  },
102
113
  "./jws": {
103
114
  "types": "./src/jws.d.ts",
104
- "import": "./src/jws.js"
115
+ "import": "./src/jws.js",
116
+ "default": "./src/jws.js"
105
117
  },
106
118
  "./backend": {
107
119
  "types": "./src/backend.d.ts",
108
- "import": "./src/backend.js"
120
+ "import": "./src/backend.js",
121
+ "default": "./src/backend.js"
109
122
  }
110
123
  },
111
124
  "files": [
@@ -114,11 +127,14 @@
114
127
  "BOUNDARY.md",
115
128
  "CHANGELOG.md",
116
129
  "CONFORMANCE.md",
130
+ "CRYPTO-INVENTORY.md",
117
131
  "DEPENDENCIES.md",
132
+ "HNDL.md",
118
133
  "LICENCE-PRODUCT.md",
119
134
  "LICENSE",
120
135
  "LIFECYCLE.md",
121
136
  "MIGRATION.md",
137
+ "PQCMM.md",
122
138
  "README.md",
123
139
  "SECURITY.md",
124
140
  "THREAT-MODEL.md",