xoonya 3.1.12 → 3.1.13
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/RELEASE_NOTES.md
CHANGED
|
@@ -1 +1,4 @@
|
|
|
1
|
-
`xoonya` 3.1.
|
|
1
|
+
`xoonya` 3.1.13 adds ML-DSA (FIPS-204) to detached-signature verification.
|
|
2
|
+
|
|
3
|
+
- `verifyExternalProofSignature` (and the import-path detached verify) now accepts `ML-DSA-44`, `ML-DSA-65`, and `ML-DSA-87` with SPKI public keys, alongside EdDSA, ECDSA, and RSA. The declared algorithm is bound to the key's parameter set, so an ML-DSA signature cannot be checked under another algorithm, and key refs use the same `<key type>-spki-sha256:<hex>` format, so a declared `expected_key_ref` anchors trust exactly as before.
|
|
4
|
+
- This lets xoonya independently verify both legs of a hybrid Ed25519 + ML-DSA-65 signature, such as the signed delivery receipts the naxytra runtime issues. Machine-evidence verification only — not identity, custody, or chain truth.
|
|
@@ -17,8 +17,9 @@
|
|
|
17
17
|
// itself, treated as trusted.
|
|
18
18
|
//
|
|
19
19
|
// Dependency-free (node crypto). Supports compact JWS (EdDSA, ES256/384/512,
|
|
20
|
-
// ES256K, RS256/384/512, PS256/384/512) and generic detached signatures
|
|
21
|
-
//
|
|
20
|
+
// ES256K, RS256/384/512, PS256/384/512) and generic detached signatures, which
|
|
21
|
+
// additionally accept ML-DSA-44/65/87 (FIPS-204, SPKI keys). Private key material
|
|
22
|
+
// (e.g. a JWK with a `d` component) is refused.
|
|
22
23
|
|
|
23
24
|
const crypto = require("crypto");
|
|
24
25
|
|
|
@@ -41,7 +42,12 @@ const JWS_ALG = {
|
|
|
41
42
|
RS512: { hash: "sha512", kind: "rsa" },
|
|
42
43
|
PS256: { hash: "sha256", kind: "rsapss" },
|
|
43
44
|
PS384: { hash: "sha384", kind: "rsapss" },
|
|
44
|
-
PS512: { hash: "sha512", kind: "rsapss" }
|
|
45
|
+
PS512: { hash: "sha512", kind: "rsapss" },
|
|
46
|
+
// FIPS-204 ML-DSA (pure mode, as named by the JOSE ML-DSA draft). Needs Node >= 24
|
|
47
|
+
// (node:crypto ML-DSA); on an older runtime the key cannot be parsed and verify fails closed.
|
|
48
|
+
"ML-DSA-44": { hash: null, kind: "mldsa", keyType: "ml-dsa-44" },
|
|
49
|
+
"ML-DSA-65": { hash: null, kind: "mldsa", keyType: "ml-dsa-65" },
|
|
50
|
+
"ML-DSA-87": { hash: null, kind: "mldsa", keyType: "ml-dsa-87" }
|
|
45
51
|
};
|
|
46
52
|
|
|
47
53
|
function isPrivateJwk(obj) {
|
|
@@ -82,6 +88,7 @@ function keyMatchesAlg(keyObject, alg) {
|
|
|
82
88
|
if (!spec || !keyObject) return false;
|
|
83
89
|
const t = keyObject.asymmetricKeyType;
|
|
84
90
|
if (spec.kind === "eddsa") return t === "ed25519";
|
|
91
|
+
if (spec.kind === "mldsa") return t === spec.keyType;
|
|
85
92
|
if (spec.kind === "ecdsa") {
|
|
86
93
|
if (t !== "ec") return false;
|
|
87
94
|
const details = keyObject.asymmetricKeyDetails || {};
|
|
@@ -97,7 +104,7 @@ function verifyWithAlg(alg, signingInput, signature, keyObject) {
|
|
|
97
104
|
if (!keyMatchesAlg(keyObject, alg)) return false; // bind declared alg to the key
|
|
98
105
|
const data = Buffer.isBuffer(signingInput) ? signingInput : Buffer.from(String(signingInput), "utf8");
|
|
99
106
|
try {
|
|
100
|
-
if (spec.kind === "eddsa") return crypto.verify(null, data, keyObject, signature);
|
|
107
|
+
if (spec.kind === "eddsa" || spec.kind === "mldsa") return crypto.verify(null, data, keyObject, signature);
|
|
101
108
|
if (spec.kind === "ecdsa") return crypto.verify(spec.hash, data, { key: keyObject, dsaEncoding: "ieee-p1363" }, signature);
|
|
102
109
|
if (spec.kind === "rsa") return crypto.verify(spec.hash, data, keyObject, signature);
|
|
103
110
|
if (spec.kind === "rsapss") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xoonya",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.13",
|
|
4
4
|
"description": "Deterministic proof and review engine with post-quantum verification (Ed25519 + ML-DSA-65 hybrid) for receipts, handoffs, governance, and the native XNYA machine-evidence format. Verified live via the paid x402 lane.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -122,6 +122,20 @@ function main() {
|
|
|
122
122
|
assert.strictEqual(proofSdk.verifyExternalProofSignature({ jws: edJws, trusted_public_key: edPubPem }).signature_valid, true);
|
|
123
123
|
assert.strictEqual(proofSdk.verifyExternalProofSignature({}).reason, "no_signature_verification_input");
|
|
124
124
|
|
|
125
|
+
// Detached ML-DSA-65 (FIPS-204): valid verifies + anchors to the declared key ref; tampered
|
|
126
|
+
// material fails; the declared alg is bound to the key type (no cross-alg confusion).
|
|
127
|
+
const mldsa = crypto.generateKeyPairSync("ml-dsa-65");
|
|
128
|
+
const mlSpki = mldsa.publicKey.export({ type: "spki", format: "der" }).toString("base64");
|
|
129
|
+
const mlRef = "ml-dsa-65-spki-sha256:" + crypto.createHash("sha256").update(mldsa.publicKey.export({ type: "spki", format: "der" })).digest("hex");
|
|
130
|
+
const mlMaterial = '{"receipt":"x","v":1}';
|
|
131
|
+
const mlSig = crypto.sign(null, Buffer.from(mlMaterial, "utf8"), mldsa.privateKey).toString("base64");
|
|
132
|
+
const mlOk = proofSdk.verifyExternalProofSignature({ material: mlMaterial, signature: mlSig, algorithm: "ML-DSA-65", public_key: mlSpki, expected_key_ref: mlRef });
|
|
133
|
+
assert.strictEqual(mlOk.signature_valid, true, "ML-DSA-65 detached signature verifies");
|
|
134
|
+
assert.strictEqual(mlOk.trust_anchored, true, "ML-DSA-65 anchors to the declared key ref");
|
|
135
|
+
assert.strictEqual(proofSdk.verifyExternalProofSignature({ material: mlMaterial + " ", signature: mlSig, algorithm: "ML-DSA-65", public_key: mlSpki }).signature_valid, false, "ML-DSA-65 tampered material fails");
|
|
136
|
+
assert.strictEqual(proofSdk.verifyExternalProofSignature({ material: mlMaterial, signature: mlSig, algorithm: "ML-DSA-44", public_key: mlSpki }).signature_valid, false, "ML-DSA alg bound to the key's parameter set");
|
|
137
|
+
assert.strictEqual(proofSdk.verifyExternalProofSignature({ material: mlMaterial, signature: mlSig, algorithm: "EdDSA", public_key: mlSpki }).signature_valid, false, "EdDSA cannot verify with an ML-DSA key");
|
|
138
|
+
|
|
125
139
|
console.log("verify_external_proof_signature: all checks passed");
|
|
126
140
|
}
|
|
127
141
|
|