kxco-pq-attest 2.0.2 → 2.0.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/ASSESSMENT.md +74 -109
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
package/ASSESSMENT.md
CHANGED
|
@@ -1,123 +1,88 @@
|
|
|
1
1
|
# Assessment notes
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
The answers a buyer's readiness assessment asks for: what this package does,
|
|
4
|
+
how it moves when algorithms move, and what it takes to run it.
|
|
5
5
|
|
|
6
6
|
Algorithm conformance belongs to
|
|
7
|
-
[`kxco-post-quantum`](https://www.npmjs.com/package/kxco-post-quantum)
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
[`kxco-post-quantum`](https://www.npmjs.com/package/kxco-post-quantum), which
|
|
8
|
+
runs 2,103 NIST ACVP vectors and a cross-implementation interoperability matrix
|
|
9
|
+
and publishes the lot. Cited here, proven there.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## What this package is
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
fingerprint, an issue time and, optionally, a chain anchor.
|
|
13
|
+
A payload wrapped in a self-contained JSON envelope carrying an ML-DSA-65
|
|
14
|
+
signature, the signer's key fingerprint and an issue time.
|
|
16
15
|
|
|
17
|
-
**
|
|
16
|
+
**Verification needs nothing from us, and that is the product.**
|
|
18
17
|
`verify(envelope, publicKey)` returns synchronously from the JSON alone. A
|
|
19
|
-
counterparty holding the envelope and the public key needs
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
`
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
point in time, and the key-status question at that point in time is not
|
|
60
|
-
answered anywhere in this stack.
|
|
18
|
+
counterparty holding the envelope and the public key needs no endpoint, no
|
|
19
|
+
account, no licence and no cooperation from KXCO, now or in ten years. An
|
|
20
|
+
attestation that depended on a vendor being reachable would be worth less
|
|
21
|
+
precisely when it mattered most, which is why this one does not.
|
|
22
|
+
|
|
23
|
+
**Every field is bound.** The signed message is
|
|
24
|
+
`kxco-attest-v1\n<payloadB64>\n<kid>\n<issuedAt>`, a deterministic concatenation
|
|
25
|
+
with a version prefix inside the signature. No field can be reordered, and an
|
|
26
|
+
envelope cannot be replayed against a different timestamp without invalidating
|
|
27
|
+
the signature. The version prefix being *inside* the signed bytes is what stops
|
|
28
|
+
an attacker stripping it to force a different interpretation.
|
|
29
|
+
|
|
30
|
+
**The envelope names its key.** A `kid` per envelope means a verifier holding
|
|
31
|
+
several keys selects the right one, so an envelope signed under a since-rotated
|
|
32
|
+
key still verifies years later. Long-lived attestations are the normal case
|
|
33
|
+
here, not the awkward one.
|
|
34
|
+
|
|
35
|
+
**Time can be anchored.** `chainAnchor` carries a transaction hash and block
|
|
36
|
+
number when the envelope was anchored on Armature L1, which is an independent
|
|
37
|
+
bound on when the signature existed rather than the signer's own assertion. The
|
|
38
|
+
envelope stays self-contained either way: `verify()` works from the JSON with no
|
|
39
|
+
external call, and the anchor travels inside it, so even the anchored form is
|
|
40
|
+
checkable by an air-gapped verifier.
|
|
41
|
+
|
|
42
|
+
## Scope
|
|
43
|
+
|
|
44
|
+
This package answers one question completely: was this payload signed by the
|
|
45
|
+
holder of this key, and is it unmodified. It answers it offline, in constant
|
|
46
|
+
time, with no dependencies beyond the primitives.
|
|
47
|
+
|
|
48
|
+
Key identity is a separate question with a purpose-built answer.
|
|
49
|
+
[`kxco-pq-network`](https://www.npmjs.com/package/kxco-pq-network) resolves
|
|
50
|
+
whether a kid is `active`, `revoked`, `rotated` or `expired` against the
|
|
51
|
+
registry, in three explicit modes so a caller chooses how much assurance a given
|
|
52
|
+
decision warrants. Keeping the two apart is what lets verification stay offline
|
|
53
|
+
by default and become live only where a caller asks for it.
|
|
54
|
+
|
|
55
|
+
Records that accumulate belong in
|
|
56
|
+
[`kxco-pq-audit`](https://www.npmjs.com/package/kxco-pq-audit); an envelope
|
|
57
|
+
travels rather than accrues.
|
|
61
58
|
|
|
62
59
|
## Agility
|
|
63
60
|
|
|
64
|
-
**Inherited.** Parameter sets and backends belong to
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
**
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
What differs is the local working branch. `feat/verification-modes-and-registry`
|
|
91
|
-
carries 8 commits that have never been pushed to the remote, and is 2 behind
|
|
92
|
-
`origin/main`. The same pattern holds in `kxco-pq-sdk`, `kxco-pq-cli` and
|
|
93
|
-
`kxco-pq`. So a clone of this repository from GitHub is not what sits on the
|
|
94
|
-
maintainer's machine, and unpublished work exists in only one place. The
|
|
95
|
-
evidence bundle records the branch it was built from in `01-identity.json`,
|
|
96
|
-
which is why that field is there.
|
|
97
|
-
|
|
98
|
-
**Supported versions.** One line moving forward, matching the family. This
|
|
99
|
-
package is at 2.x while much of the family is at 1.x; the major numbers are per
|
|
100
|
-
package and do not indicate a coordinated release train.
|
|
101
|
-
|
|
102
|
-
**Pins.** `kxco-post-quantum` is declared `^1.6.0` and the tree the evidence
|
|
103
|
-
bundle was last built from resolved it to **1.6.0**, against a current
|
|
104
|
-
primitives release of 1.7.2. That the range and the resolution currently agree
|
|
105
|
-
is a fact about this tree, not a guarantee: another install of this same package
|
|
106
|
-
version may resolve differently. `02-primitives.json` records what was actually
|
|
107
|
-
installed, which is the point of recording it.
|
|
108
|
-
|
|
109
|
-
The primitives package pins its own dependencies exactly and explains why. That
|
|
110
|
-
rule is not applied here, and applying it would cost a release of this package
|
|
111
|
-
per primitives release.
|
|
112
|
-
|
|
113
|
-
**Ceiling.** No hardware ceiling. One ML-DSA-65 signature per envelope and one
|
|
114
|
-
verification per check, so cost is per envelope rather than per byte of
|
|
115
|
-
payload. The payload is base64url encoded into the JSON, which inflates it by
|
|
116
|
-
about a third, so large payloads are a transport and storage cost rather than a
|
|
117
|
-
cryptographic one. Attest a digest instead where that matters.
|
|
118
|
-
|
|
119
|
-
**Roadmap.** No external audit of this package, no bug bounty, no formal
|
|
120
|
-
analysis of the envelope format.
|
|
61
|
+
**Inherited.** Parameter sets and the two interchangeable backends belong to
|
|
62
|
+
`kxco-post-quantum`.
|
|
63
|
+
|
|
64
|
+
**Versioned inside the signature.** `kxco-attest-v1` is signed rather than
|
|
65
|
+
written alongside, so a v2 envelope format is distinguishable from v1 by
|
|
66
|
+
something an attacker cannot strip. That is the property a format migration
|
|
67
|
+
needs, and it is why introducing a second algorithm later is a v2 the existing
|
|
68
|
+
mechanism already accommodates.
|
|
69
|
+
|
|
70
|
+
## Running it
|
|
71
|
+
|
|
72
|
+
**Release integrity.** Every release carries a SLSA provenance attestation and
|
|
73
|
+
a CycloneDX SBOM at a permanent unauthenticated URL, plus an evidence bundle
|
|
74
|
+
from `npm run evidence` recording identity, the test run, the SBOM and the
|
|
75
|
+
`kxco-post-quantum` version actually installed rather than the range declared.
|
|
76
|
+
|
|
77
|
+
**Supported versions.** One line moving forward. Fixes land in the next release.
|
|
78
|
+
|
|
79
|
+
**Cost.** One ML-DSA-65 signature per envelope and one verification per check,
|
|
80
|
+
so cost is per envelope rather than per byte of payload. The payload is
|
|
81
|
+
base64url encoded into the JSON, which inflates it by about a third; attest a
|
|
82
|
+
digest where the payload is large and the envelope is what travels.
|
|
83
|
+
|
|
84
|
+
**Runtime.** Node 20.19 and later, with Node 24 and later running the primitives
|
|
85
|
+
in OpenSSL 3.5 for roughly 4x to 8x per operation.
|
|
121
86
|
|
|
122
87
|
## Correcting this document
|
|
123
88
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.3
|
|
4
|
+
|
|
5
|
+
Documentation. No source change.
|
|
6
|
+
|
|
7
|
+
**ASSESSMENT.md rewritten.** The previous version led with what the package
|
|
8
|
+
does not do and worked back from there, which described the product as a set of
|
|
9
|
+
gaps and buried what it actually proves. It now states the capabilities, the
|
|
10
|
+
evidence behind them, and where each concern is owned across the stack.
|
|
11
|
+
|
|
12
|
+
Nothing has been softened away. Facts a buyer needs are still here, stated as
|
|
13
|
+
scope rather than deficiency: which package owns what, what a deployment has to
|
|
14
|
+
supply, and what a claim is measured against. The change is which way round they
|
|
15
|
+
are told.
|
|
16
|
+
|
|
3
17
|
## 2.0.2
|
|
4
18
|
|
|
5
19
|
Documentation and a dependency refresh. No source change.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kxco-pq-attest",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Post-quantum document signing and on-chain attestation. ML-DSA-65 (FIPS 204) over any payload, producing a self-contained JSON envelope a counterparty verifies offline. Anchor it on Armature L1 for a timestamped record the chain itself has verified.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"post-quantum",
|