kxco-verify 1.2.0 → 1.2.2

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/README.md CHANGED
@@ -1,252 +1,275 @@
1
- # kxco-verify
2
-
3
- [![npm](https://img.shields.io/npm/v/kxco-verify?label=npm&color=b0964f)](https://www.npmjs.com/package/kxco-verify)
4
- [![Socket](https://socket.dev/api/badge/npm/package/kxco-verify)](https://socket.dev/npm/package/kxco-verify)
5
- [![license](https://img.shields.io/badge/license-Apache--2.0-blue)](./LICENSE)
6
- [![node](https://img.shields.io/node/v/kxco-verify.svg)](https://nodejs.org)
7
- [![verify.kxco.ai](https://img.shields.io/badge/verify.kxco.ai-live-22c55e)](https://verify.kxco.ai)
8
-
9
- Standalone post-quantum credential and attestation verifier for KXCO ML-DSA-65 signed documents. Zero heavy dependencies. Works in any modern browser and Node 18+.
10
-
11
- ---
12
-
13
- ## When to use this
14
-
15
- This package is for the **receiving end** of a KXCO signed attestation — anyone who needs to confirm that a signature is genuine without being a KXCO institution or running the full SDK.
16
-
17
- Use this if you are:
18
-
19
- - A regulator or auditor who received a signed document and needs to confirm it cryptographically
20
- - A counterparty checking that an institution's attestation is valid before acting on it
21
- - Building a browser-based verification UI (the public [verify.kxco.ai](https://verify.kxco.ai) runs this library entirely client-side)
22
- - Writing a minimal verification script with no heavy dependencies
23
- - An end user who wants to verify a credential independently, without trusting any intermediary server
24
-
25
- If you need to **sign** attestations, see the packages listed under [Part of the KXCO stack](#part-of-the-kxco-stack).
26
-
27
- ---
28
-
29
- ## Install
30
-
31
- ```bash
32
- npm install kxco-verify
33
- ```
34
-
35
- Node 18+. ESM only.
36
-
37
- ---
38
-
39
- ## Quick start
40
-
41
- ```js
42
- import { verifyUrl } from 'kxco-verify'
43
-
44
- const result = await verifyUrl('https://www.target150.com/api/attestation')
45
-
46
- console.log(result.state) // 'valid' | 'rotated' | 'invalid' | 'error'
47
- console.log(result.algorithm) // 'ML-DSA-65'
48
- console.log(result.manifestKid) // '680f9af0bb44de3f'
49
- console.log(result.site) // 'target150.com'
50
- console.log(result.deployment) // { git_commit: '...', env: 'production', ... }
51
- console.log(result.verifiedAtMs) // timestamp (Date.now()) when verification completed
52
- ```
53
-
54
- If you already have the manifest body in hand (from a prior fetch, a file, or user paste):
55
-
56
- ```js
57
- import { verifyManifest } from 'kxco-verify'
58
-
59
- const body = await fetch('https://example.com/api/attestation').then(r => r.text())
60
- const result = await verifyManifest(body)
61
- ```
62
-
63
- ### Result states
64
-
65
- | `state` | Meaning |
66
- |---|---|
67
- | `"valid"` | Signature checks out against the manifest-declared key, and that key matches the live well-known endpoint. |
68
- | `"rotated"` | Signature checks out, but the live well-known endpoint now serves a different key. The site is mid key-rotation — retry shortly. |
69
- | `"invalid"` | The signature does not verify under the manifest-declared key, or the key identifier is inconsistent with the published key bytes. |
70
- | `"error"` | The verifier could not run: network failure, malformed JSON, or unsupported algorithm. |
71
-
72
- A `"valid"` result means the signature math checks out. It does not mean KXCO has vetted the site, its operator, or its content. See [`docs/threat-model.md`](./docs/threat-model.md).
73
-
74
- ---
75
-
76
- ## API
77
-
78
- All exports are re-exported from the main entry point (`import ... from 'kxco-verify'`). Lower-level helpers are also available from their sub-paths.
79
-
80
- ### `verifyUrl(attestationUrl, opts?) Promise<VerifyResult>`
81
-
82
- Fetches the attestation at `attestationUrl`, verifies the ML-DSA-65 signature, then fetches the live well-known pubkey endpoint declared in the manifest (`publicKey.pinAt`) to detect key rotation. May return `"rotated"` if the live endpoint now serves a different key identifier.
83
-
84
- ```ts
85
- verifyUrl(
86
- attestationUrl: string,
87
- opts?: {
88
- timeoutMs?: number // default: no timeout
89
- maxBytes?: number // max response size to accept
90
- fetchImpl?: typeof fetch // override the fetch implementation
91
- skipLivePubkey?: boolean // skip rotation check (no live fetch)
92
- }
93
- ): Promise<VerifyResult>
94
- ```
95
-
96
- ### `verifyManifest(manifestBody) → Promise<VerifyResult>`
97
-
98
- Verify a manifest you already have. Accepts a raw JSON string or a parsed object. Does not make any network requests — so the result is `"valid"`, `"invalid"`, or `"error"` only, never `"rotated"`.
99
-
100
- ```ts
101
- verifyManifest(manifestBody: string | object): Promise<VerifyResult>
102
- ```
103
-
104
- ### `VerifyResult`
105
-
106
- ```ts
107
- interface VerifyResult {
108
- state: 'valid' | 'rotated' | 'invalid' | 'error'
109
- algorithm?: 'ML-DSA-65'
110
- manifestKid?: string // key identifier declared in the manifest
111
- livePubkeyKid?: string // key identifier currently at the well-known endpoint
112
- site?: string // site identifier declared by the manifest
113
- deployment?: Record<string, unknown> // opaque deployment metadata from the manifest
114
- manifestRaw?: Record<string, unknown> // full parsed manifest JSON
115
- error?: VerifyResultError // present when state is 'error', 'invalid', or 'rotated'
116
- attestationUrl?: string
117
- pubkeyUrl?: string // well-known endpoint URL (when fetched)
118
- verifiedAtMs?: number // Date.now() when verification completed
119
- }
120
-
121
- interface VerifyResultError {
122
- kind: 'parse' | 'fetch' | 'signature' | 'consistency' | 'rotation'
123
- code: string
124
- message: string
125
- soft?: boolean // true when the math succeeded but a soft check failed
126
- }
127
- ```
128
-
129
- ### Low-level helpers
130
-
131
- These are exported for callers who want to compose their own verification logic.
132
-
133
- #### `parseManifest(input) ParseResult`
134
-
135
- Parse and validate a raw manifest body without running signature verification.
136
-
137
- ```ts
138
- parseManifest(input: string | object): ParseResult
139
- // ParseResult is { ok: true; manifest: ParsedManifest } | { ok: false; error: ParseError }
140
- ```
141
-
142
- #### `verifySignature(publicKey, message, signature) → boolean`
143
-
144
- Run ML-DSA-65 signature verification directly.
145
-
146
- ```ts
147
- verifySignature(
148
- publicKey: Uint8Array | string, // hex or bytes
149
- message: Uint8Array | string, // UTF-8 string or bytes
150
- signature: Uint8Array | string, // hex or bytes
151
- ): boolean
152
- ```
153
-
154
- #### `computeKid(publicKey) Promise<string>`
155
-
156
- Compute the KXCO key identifier: first 16 hex characters of SHA-256 of the raw public key bytes.
157
-
158
- ```ts
159
- computeKid(publicKey: Uint8Array | string): Promise<string>
160
- ```
161
-
162
- #### `getJsonBody(url, opts?) Promise<FetchOk | FetchErr>`
163
-
164
- Fetch a URL with timeout and size limits, returning the raw body string.
165
-
166
- ```ts
167
- getJsonBody(url: string, opts?: GetJsonBodyOpts): Promise<FetchOk | FetchErr>
168
- ```
169
-
170
- #### Utility: `hexToBytes`, `bytesToHex`, `hexEquals`
171
-
172
- ```ts
173
- hexToBytes(hex: string): Uint8Array
174
- bytesToHex(bytes: Uint8Array): string
175
- hexEquals(a: string, b: string): boolean
176
- ```
177
-
178
- ---
179
-
180
- ## Browser usage
181
-
182
- The library is browser-safe by construction. It uses no `Buffer`, no `node:crypto`, and no `process`. SHA-256 is taken from `crypto.subtle` where available (every modern browser and Node 20+), with a `node:crypto` fallback on Node 18.
183
-
184
- Use a bundler (Vite, esbuild, Rollup, webpack), or load as ESM via an import map:
185
-
186
- ```html
187
- <script type="importmap">
188
- {
189
- "imports": {
190
- "@noble/post-quantum/ml-dsa": "/lib/@noble/post-quantum/ml-dsa.js",
191
- "kxco-verify": "/lib/kxco-verify/src/index.js"
192
- }
193
- }
194
- </script>
195
- <script type="module">
196
- import { verifyUrl } from 'kxco-verify'
197
- const result = await verifyUrl('https://example.com/api/attestation')
198
- console.log(result.state)
199
- </script>
200
- ```
201
-
202
- This is how [verify.kxco.ai](https://verify.kxco.ai) works — no server receives your request; verification runs entirely in the browser.
203
-
204
- ---
205
-
206
- ## What this does NOT do
207
-
208
- - **Cannot sign.** To produce ML-DSA-65 attestations, use [`kxco-pq-sdk`](https://www.npmjs.com/package/kxco-post-quantum) or `kxco-pq-attest`.
209
- - **Cannot issue credentials.** Credential issuance — including KYC-backed identity documents — is handled by the full KXCO SDK and identity pipeline, not this package.
210
- - **Not a full identity client.** This package verifies one thing: whether a given ML-DSA-65 signature is mathematically valid and matches the published key. It has no concept of users, sessions, or identity records.
211
- - **No key registry.** There is no mapping from domain to approved key identifier. Anyone can generate an ML-DSA-65 keypair and publish a self-signed manifest; this library will mark it `"valid"`. A `"valid"` result is a math claim, not an endorsement.
212
- - **ML-DSA-65 only.** SLH-DSA-128s and hybrid envelopes are not supported in this release.
213
-
214
- ---
215
-
216
- ## Part of the KXCO stack
217
-
218
- This package is the receiving end of the KXCO post-quantum signing pipeline.
219
-
220
- | Role | Package |
221
- |---|---|
222
- | Sign and attest deployments | [`kxco-post-quantum`](https://www.npmjs.com/package/kxco-post-quantum) |
223
- | Issue PQ-signed credentials | `kxco-pq-attest` |
224
- | Agent-level signing and policy | `kxco-pq-agent` |
225
- | **Verify any of the above** | **`kxco-verify`** (this package) |
226
- | Public web verifier | [verify.kxco.ai](https://verify.kxco.ai) |
227
-
228
- The verifier is architecturally independent of the signer — the two share no code. That separation makes this package auditable in isolation: a change to the signing pipeline cannot influence the verifier's behaviour.
229
-
230
- ---
231
-
232
- ## Security
233
-
234
- Signature verification uses [`@noble/post-quantum`](https://github.com/paulmillr/noble-post-quantum) ML-DSA-65, with no transitive dependencies. That package has **not** been independently audited by a third party; it has been self-audited by its maintainer. Cure53's 2023 NDS-01 audit of the `@noble` ecosystem covered `ciphers`, `curves` and `hashes`, and did not cover `@noble/post-quantum`. We state this plainly because you should not adopt a verification library on the strength of an audit that does not exist.
235
-
236
- The library makes no outbound requests beyond the attestation URL you supply and the `pinAt` endpoint declared in the manifest. No data is sent to KXCO.
237
-
238
- To report a vulnerability, open a [private security advisory](https://github.com/KnightsbridgeAIQ/kxco-verify/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>.
239
-
240
- ---
241
-
242
- ## License
243
-
244
- Apache 2.0 — see [LICENSE](./LICENSE).
245
-
246
- ---
247
-
248
- ## Maintainers
249
-
250
- Shayne Heffernan and John Heffernan — [KXCO by Knightsbridge](https://kxco.ai)
251
-
252
- [knightsbridgelaw.com](https://knightsbridgelaw.com) · [target150.com](https://target150.com) · [livetradingnews.com](https://livetradingnews.com)
1
+ # kxco-verify
2
+
3
+ [![npm](https://img.shields.io/npm/v/kxco-verify?label=npm&color=b0964f)](https://www.npmjs.com/package/kxco-verify)
4
+ [![Socket](https://socket.dev/api/badge/npm/package/kxco-verify)](https://socket.dev/npm/package/kxco-verify)
5
+ [![license](https://img.shields.io/badge/license-Apache--2.0-blue)](./LICENSE)
6
+ [![node](https://img.shields.io/node/v/kxco-verify.svg)](https://nodejs.org)
7
+ [![verify.kxco.ai](https://img.shields.io/badge/verify.kxco.ai-live-22c55e)](https://verify.kxco.ai)
8
+
9
+ Standalone post-quantum credential and attestation verifier for KXCO ML-DSA-65 signed documents. Zero heavy dependencies. Works in any modern browser and Node 18+.
10
+
11
+ ---
12
+
13
+ ## Release integrity
14
+
15
+ Every release of this package is checkable without asking us for anything.
16
+
17
+ - **Provenance.** Each release carries a SLSA provenance attestation tying the
18
+ published tarball to the commit and workflow that built it. Verify with
19
+ `npm audit signatures`, or read it directly from
20
+ `registry.npmjs.org/-/npm/v1/attestations/kxco-verify@<version>`.
21
+ - **Bill of materials.** A CycloneDX SBOM is published as a GitHub Release asset
22
+ at `releases/download/v<version>/sbom.cyclonedx.json`, a permanent
23
+ unauthenticated URL. Not an expiring build artifact.
24
+ - **Pinned, not floated.** Every runtime dependency is pinned to an exact
25
+ version, never a range, so the code that performs the cryptography cannot
26
+ change without a release of this package. Every GitHub Action is pinned by
27
+ 40-character commit SHA.
28
+ - **Conformance.** The primitives are the same ones run against **2,103 NIST
29
+ ACVP vectors (0 failed)** and a **225-check cross-implementation
30
+ interoperability matrix** in
31
+ [`kxco-post-quantum`](https://www.npmjs.com/package/kxco-post-quantum),
32
+ against liboqs, Bouncy Castle and two pure-Python implementations. This
33
+ package deliberately shares no code with the signer: a verifier that reached
34
+ the primitives through the same wrapper would be checking its own work.
35
+
36
+ ## When to use this
37
+
38
+ This package is for the **receiving end** of a KXCO signed attestation — anyone who needs to confirm that a signature is genuine without being a KXCO institution or running the full SDK.
39
+
40
+ Use this if you are:
41
+
42
+ - A regulator or auditor who received a signed document and needs to confirm it cryptographically
43
+ - A counterparty checking that an institution's attestation is valid before acting on it
44
+ - Building a browser-based verification UI (the public [verify.kxco.ai](https://verify.kxco.ai) runs this library entirely client-side)
45
+ - Writing a minimal verification script with no heavy dependencies
46
+ - An end user who wants to verify a credential independently, without trusting any intermediary server
47
+
48
+ If you need to **sign** attestations, see the packages listed under [Part of the KXCO stack](#part-of-the-kxco-stack).
49
+
50
+ ---
51
+
52
+ ## Install
53
+
54
+ ```bash
55
+ npm install kxco-verify
56
+ ```
57
+
58
+ Node 18+. ESM only.
59
+
60
+ ---
61
+
62
+ ## Quick start
63
+
64
+ ```js
65
+ import { verifyUrl } from 'kxco-verify'
66
+
67
+ const result = await verifyUrl('https://www.target150.com/api/attestation')
68
+
69
+ console.log(result.state) // 'valid' | 'rotated' | 'invalid' | 'error'
70
+ console.log(result.algorithm) // 'ML-DSA-65'
71
+ console.log(result.manifestKid) // '680f9af0bb44de3f'
72
+ console.log(result.site) // 'target150.com'
73
+ console.log(result.deployment) // { git_commit: '...', env: 'production', ... }
74
+ console.log(result.verifiedAtMs) // timestamp (Date.now()) when verification completed
75
+ ```
76
+
77
+ If you already have the manifest body in hand (from a prior fetch, a file, or user paste):
78
+
79
+ ```js
80
+ import { verifyManifest } from 'kxco-verify'
81
+
82
+ const body = await fetch('https://example.com/api/attestation').then(r => r.text())
83
+ const result = await verifyManifest(body)
84
+ ```
85
+
86
+ ### Result states
87
+
88
+ | `state` | Meaning |
89
+ |---|---|
90
+ | `"valid"` | Signature checks out against the manifest-declared key, and that key matches the live well-known endpoint. |
91
+ | `"rotated"` | Signature checks out, but the live well-known endpoint now serves a different key. The site is mid key-rotation — retry shortly. |
92
+ | `"invalid"` | The signature does not verify under the manifest-declared key, or the key identifier is inconsistent with the published key bytes. |
93
+ | `"error"` | The verifier could not run: network failure, malformed JSON, or unsupported algorithm. |
94
+
95
+ A `"valid"` result means the signature math checks out. It does not mean KXCO has vetted the site, its operator, or its content. See [`docs/threat-model.md`](./docs/threat-model.md).
96
+
97
+ ---
98
+
99
+ ## API
100
+
101
+ All exports are re-exported from the main entry point (`import ... from 'kxco-verify'`). Lower-level helpers are also available from their sub-paths.
102
+
103
+ ### `verifyUrl(attestationUrl, opts?) → Promise<VerifyResult>`
104
+
105
+ Fetches the attestation at `attestationUrl`, verifies the ML-DSA-65 signature, then fetches the live well-known pubkey endpoint declared in the manifest (`publicKey.pinAt`) to detect key rotation. May return `"rotated"` if the live endpoint now serves a different key identifier.
106
+
107
+ ```ts
108
+ verifyUrl(
109
+ attestationUrl: string,
110
+ opts?: {
111
+ timeoutMs?: number // default: no timeout
112
+ maxBytes?: number // max response size to accept
113
+ fetchImpl?: typeof fetch // override the fetch implementation
114
+ skipLivePubkey?: boolean // skip rotation check (no live fetch)
115
+ }
116
+ ): Promise<VerifyResult>
117
+ ```
118
+
119
+ ### `verifyManifest(manifestBody) → Promise<VerifyResult>`
120
+
121
+ Verify a manifest you already have. Accepts a raw JSON string or a parsed object. Does not make any network requests — so the result is `"valid"`, `"invalid"`, or `"error"` only, never `"rotated"`.
122
+
123
+ ```ts
124
+ verifyManifest(manifestBody: string | object): Promise<VerifyResult>
125
+ ```
126
+
127
+ ### `VerifyResult`
128
+
129
+ ```ts
130
+ interface VerifyResult {
131
+ state: 'valid' | 'rotated' | 'invalid' | 'error'
132
+ algorithm?: 'ML-DSA-65'
133
+ manifestKid?: string // key identifier declared in the manifest
134
+ livePubkeyKid?: string // key identifier currently at the well-known endpoint
135
+ site?: string // site identifier declared by the manifest
136
+ deployment?: Record<string, unknown> // opaque deployment metadata from the manifest
137
+ manifestRaw?: Record<string, unknown> // full parsed manifest JSON
138
+ error?: VerifyResultError // present when state is 'error', 'invalid', or 'rotated'
139
+ attestationUrl?: string
140
+ pubkeyUrl?: string // well-known endpoint URL (when fetched)
141
+ verifiedAtMs?: number // Date.now() when verification completed
142
+ }
143
+
144
+ interface VerifyResultError {
145
+ kind: 'parse' | 'fetch' | 'signature' | 'consistency' | 'rotation'
146
+ code: string
147
+ message: string
148
+ soft?: boolean // true when the math succeeded but a soft check failed
149
+ }
150
+ ```
151
+
152
+ ### Low-level helpers
153
+
154
+ These are exported for callers who want to compose their own verification logic.
155
+
156
+ #### `parseManifest(input) ParseResult`
157
+
158
+ Parse and validate a raw manifest body without running signature verification.
159
+
160
+ ```ts
161
+ parseManifest(input: string | object): ParseResult
162
+ // ParseResult is { ok: true; manifest: ParsedManifest } | { ok: false; error: ParseError }
163
+ ```
164
+
165
+ #### `verifySignature(publicKey, message, signature) → boolean`
166
+
167
+ Run ML-DSA-65 signature verification directly.
168
+
169
+ ```ts
170
+ verifySignature(
171
+ publicKey: Uint8Array | string, // hex or bytes
172
+ message: Uint8Array | string, // UTF-8 string or bytes
173
+ signature: Uint8Array | string, // hex or bytes
174
+ ): boolean
175
+ ```
176
+
177
+ #### `computeKid(publicKey) → Promise<string>`
178
+
179
+ Compute the KXCO key identifier: first 16 hex characters of SHA-256 of the raw public key bytes.
180
+
181
+ ```ts
182
+ computeKid(publicKey: Uint8Array | string): Promise<string>
183
+ ```
184
+
185
+ #### `getJsonBody(url, opts?) → Promise<FetchOk | FetchErr>`
186
+
187
+ Fetch a URL with timeout and size limits, returning the raw body string.
188
+
189
+ ```ts
190
+ getJsonBody(url: string, opts?: GetJsonBodyOpts): Promise<FetchOk | FetchErr>
191
+ ```
192
+
193
+ #### Utility: `hexToBytes`, `bytesToHex`, `hexEquals`
194
+
195
+ ```ts
196
+ hexToBytes(hex: string): Uint8Array
197
+ bytesToHex(bytes: Uint8Array): string
198
+ hexEquals(a: string, b: string): boolean
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Browser usage
204
+
205
+ The library is browser-safe by construction. It uses no `Buffer`, no `node:crypto`, and no `process`. SHA-256 is taken from `crypto.subtle` where available (every modern browser and Node 20+), with a `node:crypto` fallback on Node 18.
206
+
207
+ Use a bundler (Vite, esbuild, Rollup, webpack), or load as ESM via an import map:
208
+
209
+ ```html
210
+ <script type="importmap">
211
+ {
212
+ "imports": {
213
+ "@noble/post-quantum/ml-dsa": "/lib/@noble/post-quantum/ml-dsa.js",
214
+ "kxco-verify": "/lib/kxco-verify/src/index.js"
215
+ }
216
+ }
217
+ </script>
218
+ <script type="module">
219
+ import { verifyUrl } from 'kxco-verify'
220
+ const result = await verifyUrl('https://example.com/api/attestation')
221
+ console.log(result.state)
222
+ </script>
223
+ ```
224
+
225
+ This is how [verify.kxco.ai](https://verify.kxco.ai) works no server receives your request; verification runs entirely in the browser.
226
+
227
+ ---
228
+
229
+ ## What this does NOT do
230
+
231
+ - **Cannot sign.** To produce ML-DSA-65 attestations, use [`kxco-pq-sdk`](https://www.npmjs.com/package/kxco-post-quantum) or `kxco-pq-attest`.
232
+ - **Cannot issue credentials.** Credential issuance — including KYC-backed identity documents — is handled by the full KXCO SDK and identity pipeline, not this package.
233
+ - **Not a full identity client.** This package verifies one thing: whether a given ML-DSA-65 signature is mathematically valid and matches the published key. It has no concept of users, sessions, or identity records.
234
+ - **No key registry.** There is no mapping from domain to approved key identifier. Anyone can generate an ML-DSA-65 keypair and publish a self-signed manifest; this library will mark it `"valid"`. A `"valid"` result is a math claim, not an endorsement.
235
+ - **ML-DSA-65 only.** SLH-DSA-128s and hybrid envelopes are not supported in this release.
236
+
237
+ ---
238
+
239
+ ## Part of the KXCO stack
240
+
241
+ This package is the receiving end of the KXCO post-quantum signing pipeline.
242
+
243
+ | Role | Package |
244
+ |---|---|
245
+ | Sign and attest deployments | [`kxco-post-quantum`](https://www.npmjs.com/package/kxco-post-quantum) |
246
+ | Issue PQ-signed credentials | `kxco-pq-attest` |
247
+ | Agent-level signing and policy | `kxco-pq-agent` |
248
+ | **Verify any of the above** | **`kxco-verify`** (this package) |
249
+ | Public web verifier | [verify.kxco.ai](https://verify.kxco.ai) |
250
+
251
+ The verifier is architecturally independent of the signer — the two share no code. That separation makes this package auditable in isolation: a change to the signing pipeline cannot influence the verifier's behaviour.
252
+
253
+ ---
254
+
255
+ ## Security
256
+
257
+ Signature verification uses [`@noble/post-quantum`](https://github.com/paulmillr/noble-post-quantum) ML-DSA-65, with no transitive dependencies. That package has **not** been independently audited by a third party; it has been self-audited by its maintainer. Cure53's 2023 NDS-01 audit of the `@noble` ecosystem covered `ciphers`, `curves` and `hashes`, and did not cover `@noble/post-quantum`. We state this plainly because you should not adopt a verification library on the strength of an audit that does not exist.
258
+
259
+ The library makes no outbound requests beyond the attestation URL you supply and the `pinAt` endpoint declared in the manifest. No data is sent to KXCO.
260
+
261
+ To report a vulnerability, open a [private security advisory](https://github.com/KnightsbridgeAIQ/kxco-verify/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>.
262
+
263
+ ---
264
+
265
+ ## License
266
+
267
+ Apache 2.0 — see [LICENSE](./LICENSE).
268
+
269
+ ---
270
+
271
+ ## Maintainers
272
+
273
+ Shayne Heffernan and John Heffernan — [KXCO by Knightsbridge](https://kxco.ai)
274
+
275
+ [knightsbridgelaw.com](https://knightsbridgelaw.com) · [target150.com](https://target150.com) · [livetradingnews.com](https://livetradingnews.com)