@epochcore/identity-sdk 1.1.0 → 1.2.0
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/dist/index.d.mts +69 -1
- package/dist/index.d.ts +69 -1
- package/dist/index.js +106 -3
- package/dist/index.mjs +101 -2
- package/package.json +8 -4
package/dist/index.d.mts
CHANGED
|
@@ -29,6 +29,34 @@ interface SignedPayload {
|
|
|
29
29
|
publicKey: string;
|
|
30
30
|
timestamp: string;
|
|
31
31
|
}
|
|
32
|
+
interface QuantumResistantKeypair {
|
|
33
|
+
/** ML-DSA-65 (CRYSTALS-Dilithium3) secret key — hex-encoded */
|
|
34
|
+
secretKey: string;
|
|
35
|
+
/** ML-DSA-65 public key — hex-encoded */
|
|
36
|
+
publicKey: string;
|
|
37
|
+
/** Algorithm identifier */
|
|
38
|
+
algorithm: 'ML-DSA-65';
|
|
39
|
+
}
|
|
40
|
+
interface HybridIdentity {
|
|
41
|
+
/** Standard Ed25519 identity */
|
|
42
|
+
classical: EpochCoreIdentity;
|
|
43
|
+
/** Post-quantum ML-DSA-65 public key — hex-encoded */
|
|
44
|
+
quantumPublicKey: string;
|
|
45
|
+
/** DID with quantum-resistant tag */
|
|
46
|
+
quantumDid: string;
|
|
47
|
+
}
|
|
48
|
+
interface HybridSignedPayload {
|
|
49
|
+
payload: string;
|
|
50
|
+
/** Ed25519 signature — hex */
|
|
51
|
+
classicalSignature: string;
|
|
52
|
+
/** ML-DSA-65 signature — hex */
|
|
53
|
+
quantumSignature: string;
|
|
54
|
+
/** Ed25519 public key — hex */
|
|
55
|
+
classicalPublicKey: string;
|
|
56
|
+
/** ML-DSA-65 public key — hex */
|
|
57
|
+
quantumPublicKey: string;
|
|
58
|
+
timestamp: string;
|
|
59
|
+
}
|
|
32
60
|
/**
|
|
33
61
|
* Generate a new Ed25519 keypair for infrastructure identity
|
|
34
62
|
*/
|
|
@@ -81,9 +109,44 @@ declare function generateJWKS(publicKeys: string[]): {
|
|
|
81
109
|
kid: string;
|
|
82
110
|
}>;
|
|
83
111
|
};
|
|
112
|
+
/**
|
|
113
|
+
* Generate a post-quantum ML-DSA-65 keypair.
|
|
114
|
+
* ML-DSA-65 (Dilithium3) provides NIST Security Level 3 — resistant to
|
|
115
|
+
* both classical and quantum attacks (Shor's algorithm).
|
|
116
|
+
*
|
|
117
|
+
* @param seed - Optional 32-byte seed (hex). If omitted, uses CSPRNG.
|
|
118
|
+
*/
|
|
119
|
+
declare function generateQuantumKeypair(seed?: string): QuantumResistantKeypair;
|
|
120
|
+
/**
|
|
121
|
+
* Generate a hybrid identity with both Ed25519 (classical) and ML-DSA-65
|
|
122
|
+
* (post-quantum) keys. This provides quantum-resistance while maintaining
|
|
123
|
+
* backward compatibility with existing Ed25519 infrastructure.
|
|
124
|
+
*/
|
|
125
|
+
declare function generateQuantumResistantIdentity(type: IdentityType, name: string): Promise<{
|
|
126
|
+
hybrid: HybridIdentity;
|
|
127
|
+
classicalPrivateKey: string;
|
|
128
|
+
quantumSecretKey: string;
|
|
129
|
+
}>;
|
|
130
|
+
/**
|
|
131
|
+
* Sign a payload with both Ed25519 and ML-DSA-65 (hybrid signature).
|
|
132
|
+
* Verifiers can check either or both signatures — providing quantum
|
|
133
|
+
* safety while maintaining classical compatibility.
|
|
134
|
+
*
|
|
135
|
+
* @param payload - String data to sign
|
|
136
|
+
* @param classicalPrivateKey - Ed25519 private key (64 hex chars)
|
|
137
|
+
* @param quantumSecretKey - ML-DSA-65 secret key (hex, 8064 chars / 4032 bytes)
|
|
138
|
+
* @param quantumPublicKey - ML-DSA-65 public key (hex, 3904 chars / 1952 bytes)
|
|
139
|
+
*/
|
|
140
|
+
declare function signPayloadHybrid(payload: string, classicalPrivateKey: string, quantumSecretKey: string, quantumPublicKey: string): Promise<HybridSignedPayload>;
|
|
141
|
+
/**
|
|
142
|
+
* Verify a hybrid signature (Ed25519 + ML-DSA-65).
|
|
143
|
+
* Returns true only if BOTH signatures are valid.
|
|
144
|
+
*/
|
|
145
|
+
declare function verifySignatureHybrid(payload: string, classicalSignature: string, quantumSignature: string, classicalPublicKey: string, quantumPublicKey: string): Promise<boolean>;
|
|
84
146
|
declare const CONSTANTS: {
|
|
85
147
|
DID_PREFIX: string;
|
|
86
148
|
SIGNING_ALGORITHM: string;
|
|
149
|
+
PQ_SIGNING_ALGORITHM: string;
|
|
87
150
|
WALLET_ALGORITHM: string;
|
|
88
151
|
SUPPORTED_TYPES: IdentityType[];
|
|
89
152
|
VERSION: string;
|
|
@@ -91,19 +154,24 @@ declare const CONSTANTS: {
|
|
|
91
154
|
declare const _default: {
|
|
92
155
|
generateKeypair: typeof generateKeypair;
|
|
93
156
|
generateIdentity: typeof generateIdentity;
|
|
157
|
+
generateQuantumKeypair: typeof generateQuantumKeypair;
|
|
158
|
+
generateQuantumResistantIdentity: typeof generateQuantumResistantIdentity;
|
|
94
159
|
createDID: typeof createDID;
|
|
95
160
|
parseDID: typeof parseDID;
|
|
96
161
|
deriveWallet: typeof deriveWallet;
|
|
97
162
|
signPayload: typeof signPayload;
|
|
163
|
+
signPayloadHybrid: typeof signPayloadHybrid;
|
|
98
164
|
verifySignature: typeof verifySignature;
|
|
165
|
+
verifySignatureHybrid: typeof verifySignatureHybrid;
|
|
99
166
|
generateJWKS: typeof generateJWKS;
|
|
100
167
|
CONSTANTS: {
|
|
101
168
|
DID_PREFIX: string;
|
|
102
169
|
SIGNING_ALGORITHM: string;
|
|
170
|
+
PQ_SIGNING_ALGORITHM: string;
|
|
103
171
|
WALLET_ALGORITHM: string;
|
|
104
172
|
SUPPORTED_TYPES: IdentityType[];
|
|
105
173
|
VERSION: string;
|
|
106
174
|
};
|
|
107
175
|
};
|
|
108
176
|
|
|
109
|
-
export { CONSTANTS, type EpochCoreIdentity, type EpochCoreWallet, type IdentityType, type SignedPayload, createDID, _default as default, deriveWallet, generateIdentity, generateJWKS, generateKeypair, parseDID, signPayload, verifySignature };
|
|
177
|
+
export { CONSTANTS, type EpochCoreIdentity, type EpochCoreWallet, type HybridIdentity, type HybridSignedPayload, type IdentityType, type QuantumResistantKeypair, type SignedPayload, createDID, _default as default, deriveWallet, generateIdentity, generateJWKS, generateKeypair, generateQuantumKeypair, generateQuantumResistantIdentity, parseDID, signPayload, signPayloadHybrid, verifySignature, verifySignatureHybrid };
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,34 @@ interface SignedPayload {
|
|
|
29
29
|
publicKey: string;
|
|
30
30
|
timestamp: string;
|
|
31
31
|
}
|
|
32
|
+
interface QuantumResistantKeypair {
|
|
33
|
+
/** ML-DSA-65 (CRYSTALS-Dilithium3) secret key — hex-encoded */
|
|
34
|
+
secretKey: string;
|
|
35
|
+
/** ML-DSA-65 public key — hex-encoded */
|
|
36
|
+
publicKey: string;
|
|
37
|
+
/** Algorithm identifier */
|
|
38
|
+
algorithm: 'ML-DSA-65';
|
|
39
|
+
}
|
|
40
|
+
interface HybridIdentity {
|
|
41
|
+
/** Standard Ed25519 identity */
|
|
42
|
+
classical: EpochCoreIdentity;
|
|
43
|
+
/** Post-quantum ML-DSA-65 public key — hex-encoded */
|
|
44
|
+
quantumPublicKey: string;
|
|
45
|
+
/** DID with quantum-resistant tag */
|
|
46
|
+
quantumDid: string;
|
|
47
|
+
}
|
|
48
|
+
interface HybridSignedPayload {
|
|
49
|
+
payload: string;
|
|
50
|
+
/** Ed25519 signature — hex */
|
|
51
|
+
classicalSignature: string;
|
|
52
|
+
/** ML-DSA-65 signature — hex */
|
|
53
|
+
quantumSignature: string;
|
|
54
|
+
/** Ed25519 public key — hex */
|
|
55
|
+
classicalPublicKey: string;
|
|
56
|
+
/** ML-DSA-65 public key — hex */
|
|
57
|
+
quantumPublicKey: string;
|
|
58
|
+
timestamp: string;
|
|
59
|
+
}
|
|
32
60
|
/**
|
|
33
61
|
* Generate a new Ed25519 keypair for infrastructure identity
|
|
34
62
|
*/
|
|
@@ -81,9 +109,44 @@ declare function generateJWKS(publicKeys: string[]): {
|
|
|
81
109
|
kid: string;
|
|
82
110
|
}>;
|
|
83
111
|
};
|
|
112
|
+
/**
|
|
113
|
+
* Generate a post-quantum ML-DSA-65 keypair.
|
|
114
|
+
* ML-DSA-65 (Dilithium3) provides NIST Security Level 3 — resistant to
|
|
115
|
+
* both classical and quantum attacks (Shor's algorithm).
|
|
116
|
+
*
|
|
117
|
+
* @param seed - Optional 32-byte seed (hex). If omitted, uses CSPRNG.
|
|
118
|
+
*/
|
|
119
|
+
declare function generateQuantumKeypair(seed?: string): QuantumResistantKeypair;
|
|
120
|
+
/**
|
|
121
|
+
* Generate a hybrid identity with both Ed25519 (classical) and ML-DSA-65
|
|
122
|
+
* (post-quantum) keys. This provides quantum-resistance while maintaining
|
|
123
|
+
* backward compatibility with existing Ed25519 infrastructure.
|
|
124
|
+
*/
|
|
125
|
+
declare function generateQuantumResistantIdentity(type: IdentityType, name: string): Promise<{
|
|
126
|
+
hybrid: HybridIdentity;
|
|
127
|
+
classicalPrivateKey: string;
|
|
128
|
+
quantumSecretKey: string;
|
|
129
|
+
}>;
|
|
130
|
+
/**
|
|
131
|
+
* Sign a payload with both Ed25519 and ML-DSA-65 (hybrid signature).
|
|
132
|
+
* Verifiers can check either or both signatures — providing quantum
|
|
133
|
+
* safety while maintaining classical compatibility.
|
|
134
|
+
*
|
|
135
|
+
* @param payload - String data to sign
|
|
136
|
+
* @param classicalPrivateKey - Ed25519 private key (64 hex chars)
|
|
137
|
+
* @param quantumSecretKey - ML-DSA-65 secret key (hex, 8064 chars / 4032 bytes)
|
|
138
|
+
* @param quantumPublicKey - ML-DSA-65 public key (hex, 3904 chars / 1952 bytes)
|
|
139
|
+
*/
|
|
140
|
+
declare function signPayloadHybrid(payload: string, classicalPrivateKey: string, quantumSecretKey: string, quantumPublicKey: string): Promise<HybridSignedPayload>;
|
|
141
|
+
/**
|
|
142
|
+
* Verify a hybrid signature (Ed25519 + ML-DSA-65).
|
|
143
|
+
* Returns true only if BOTH signatures are valid.
|
|
144
|
+
*/
|
|
145
|
+
declare function verifySignatureHybrid(payload: string, classicalSignature: string, quantumSignature: string, classicalPublicKey: string, quantumPublicKey: string): Promise<boolean>;
|
|
84
146
|
declare const CONSTANTS: {
|
|
85
147
|
DID_PREFIX: string;
|
|
86
148
|
SIGNING_ALGORITHM: string;
|
|
149
|
+
PQ_SIGNING_ALGORITHM: string;
|
|
87
150
|
WALLET_ALGORITHM: string;
|
|
88
151
|
SUPPORTED_TYPES: IdentityType[];
|
|
89
152
|
VERSION: string;
|
|
@@ -91,19 +154,24 @@ declare const CONSTANTS: {
|
|
|
91
154
|
declare const _default: {
|
|
92
155
|
generateKeypair: typeof generateKeypair;
|
|
93
156
|
generateIdentity: typeof generateIdentity;
|
|
157
|
+
generateQuantumKeypair: typeof generateQuantumKeypair;
|
|
158
|
+
generateQuantumResistantIdentity: typeof generateQuantumResistantIdentity;
|
|
94
159
|
createDID: typeof createDID;
|
|
95
160
|
parseDID: typeof parseDID;
|
|
96
161
|
deriveWallet: typeof deriveWallet;
|
|
97
162
|
signPayload: typeof signPayload;
|
|
163
|
+
signPayloadHybrid: typeof signPayloadHybrid;
|
|
98
164
|
verifySignature: typeof verifySignature;
|
|
165
|
+
verifySignatureHybrid: typeof verifySignatureHybrid;
|
|
99
166
|
generateJWKS: typeof generateJWKS;
|
|
100
167
|
CONSTANTS: {
|
|
101
168
|
DID_PREFIX: string;
|
|
102
169
|
SIGNING_ALGORITHM: string;
|
|
170
|
+
PQ_SIGNING_ALGORITHM: string;
|
|
103
171
|
WALLET_ALGORITHM: string;
|
|
104
172
|
SUPPORTED_TYPES: IdentityType[];
|
|
105
173
|
VERSION: string;
|
|
106
174
|
};
|
|
107
175
|
};
|
|
108
176
|
|
|
109
|
-
export { CONSTANTS, type EpochCoreIdentity, type EpochCoreWallet, type IdentityType, type SignedPayload, createDID, _default as default, deriveWallet, generateIdentity, generateJWKS, generateKeypair, parseDID, signPayload, verifySignature };
|
|
177
|
+
export { CONSTANTS, type EpochCoreIdentity, type EpochCoreWallet, type HybridIdentity, type HybridSignedPayload, type IdentityType, type QuantumResistantKeypair, type SignedPayload, createDID, _default as default, deriveWallet, generateIdentity, generateJWKS, generateKeypair, generateQuantumKeypair, generateQuantumResistantIdentity, parseDID, signPayload, signPayloadHybrid, verifySignature, verifySignatureHybrid };
|
package/dist/index.js
CHANGED
|
@@ -37,15 +37,20 @@ __export(index_exports, {
|
|
|
37
37
|
generateIdentity: () => generateIdentity,
|
|
38
38
|
generateJWKS: () => generateJWKS,
|
|
39
39
|
generateKeypair: () => generateKeypair,
|
|
40
|
+
generateQuantumKeypair: () => generateQuantumKeypair,
|
|
41
|
+
generateQuantumResistantIdentity: () => generateQuantumResistantIdentity,
|
|
40
42
|
parseDID: () => parseDID,
|
|
41
43
|
signPayload: () => signPayload,
|
|
42
|
-
|
|
44
|
+
signPayloadHybrid: () => signPayloadHybrid,
|
|
45
|
+
verifySignature: () => verifySignature,
|
|
46
|
+
verifySignatureHybrid: () => verifySignatureHybrid
|
|
43
47
|
});
|
|
44
48
|
module.exports = __toCommonJS(index_exports);
|
|
45
49
|
var ed25519 = __toESM(require("@noble/ed25519"));
|
|
46
50
|
var secp256k1 = __toESM(require("@noble/secp256k1"));
|
|
47
51
|
var import_sha256 = require("@noble/hashes/sha256");
|
|
48
52
|
var import_utils = require("@noble/hashes/utils");
|
|
53
|
+
var import_ml_dsa = require("@noble/post-quantum/ml-dsa");
|
|
49
54
|
var HEX_64_RE = /^[0-9a-f]{64}$/i;
|
|
50
55
|
var NAME_RE = /^[\w.-]{1,128}$/;
|
|
51
56
|
var MAX_DID_LENGTH = 512;
|
|
@@ -204,21 +209,115 @@ function generateJWKS(publicKeys) {
|
|
|
204
209
|
}))
|
|
205
210
|
};
|
|
206
211
|
}
|
|
212
|
+
function generateQuantumKeypair(seed) {
|
|
213
|
+
let seedBytes;
|
|
214
|
+
if (seed) {
|
|
215
|
+
if (typeof seed !== "string" || !/^[0-9a-f]{64}$/i.test(seed)) {
|
|
216
|
+
throw new TypeError("seed must be a 64-character hex string (32 bytes)");
|
|
217
|
+
}
|
|
218
|
+
seedBytes = (0, import_utils.hexToBytes)(seed);
|
|
219
|
+
} else {
|
|
220
|
+
seedBytes = new Uint8Array(32);
|
|
221
|
+
globalThis.crypto.getRandomValues(seedBytes);
|
|
222
|
+
}
|
|
223
|
+
const { secretKey, publicKey } = import_ml_dsa.ml_dsa65.keygen(seedBytes);
|
|
224
|
+
return {
|
|
225
|
+
secretKey: (0, import_utils.bytesToHex)(secretKey),
|
|
226
|
+
publicKey: (0, import_utils.bytesToHex)(publicKey),
|
|
227
|
+
algorithm: "ML-DSA-65"
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
async function generateQuantumResistantIdentity(type, name) {
|
|
231
|
+
validateType(type);
|
|
232
|
+
validateName(name);
|
|
233
|
+
const { identity, privateKey: classicalPrivateKey } = await generateIdentity(type, name);
|
|
234
|
+
const quantumKeypair = generateQuantumKeypair();
|
|
235
|
+
const qFingerprint = (0, import_utils.bytesToHex)((0, import_sha256.sha256)((0, import_utils.hexToBytes)(quantumKeypair.publicKey.slice(0, 64)))).slice(0, 32);
|
|
236
|
+
const quantumDid = `did:epochcore:pq:${type}:${name}:${qFingerprint}`;
|
|
237
|
+
return {
|
|
238
|
+
hybrid: {
|
|
239
|
+
classical: identity,
|
|
240
|
+
quantumPublicKey: quantumKeypair.publicKey,
|
|
241
|
+
quantumDid
|
|
242
|
+
},
|
|
243
|
+
classicalPrivateKey,
|
|
244
|
+
quantumSecretKey: quantumKeypair.secretKey
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
async function signPayloadHybrid(payload, classicalPrivateKey, quantumSecretKey, quantumPublicKey) {
|
|
248
|
+
if (typeof payload !== "string" || payload.length === 0) {
|
|
249
|
+
throw new TypeError("payload must be a non-empty string");
|
|
250
|
+
}
|
|
251
|
+
const payloadBytes = new TextEncoder().encode(payload);
|
|
252
|
+
if (payloadBytes.byteLength > MAX_PAYLOAD_BYTES) {
|
|
253
|
+
throw new RangeError(`payload exceeds maximum size of ${MAX_PAYLOAD_BYTES} bytes`);
|
|
254
|
+
}
|
|
255
|
+
validateHex64(classicalPrivateKey, "classicalPrivateKey");
|
|
256
|
+
if (typeof quantumSecretKey !== "string" || quantumSecretKey.length === 0) {
|
|
257
|
+
throw new TypeError("quantumSecretKey must be a non-empty hex string");
|
|
258
|
+
}
|
|
259
|
+
if (typeof quantumPublicKey !== "string" || quantumPublicKey.length === 0) {
|
|
260
|
+
throw new TypeError("quantumPublicKey must be a non-empty hex string");
|
|
261
|
+
}
|
|
262
|
+
const classicalSig = await ed25519.signAsync(payloadBytes, (0, import_utils.hexToBytes)(classicalPrivateKey));
|
|
263
|
+
const classicalPub = await ed25519.getPublicKeyAsync((0, import_utils.hexToBytes)(classicalPrivateKey));
|
|
264
|
+
const quantumSig = import_ml_dsa.ml_dsa65.sign((0, import_utils.hexToBytes)(quantumSecretKey), payloadBytes);
|
|
265
|
+
return {
|
|
266
|
+
payload,
|
|
267
|
+
classicalSignature: (0, import_utils.bytesToHex)(classicalSig),
|
|
268
|
+
quantumSignature: (0, import_utils.bytesToHex)(quantumSig),
|
|
269
|
+
classicalPublicKey: (0, import_utils.bytesToHex)(classicalPub),
|
|
270
|
+
quantumPublicKey,
|
|
271
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
async function verifySignatureHybrid(payload, classicalSignature, quantumSignature, classicalPublicKey, quantumPublicKey) {
|
|
275
|
+
if (typeof payload !== "string" || payload.length === 0) {
|
|
276
|
+
throw new TypeError("payload must be a non-empty string");
|
|
277
|
+
}
|
|
278
|
+
const payloadBytes = new TextEncoder().encode(payload);
|
|
279
|
+
if (typeof classicalSignature !== "string" || !/^[0-9a-f]{128}$/i.test(classicalSignature)) {
|
|
280
|
+
throw new TypeError("classicalSignature must be a 128-character hex string");
|
|
281
|
+
}
|
|
282
|
+
validateHex64(classicalPublicKey, "classicalPublicKey");
|
|
283
|
+
const classicalValid = await ed25519.verifyAsync(
|
|
284
|
+
(0, import_utils.hexToBytes)(classicalSignature),
|
|
285
|
+
payloadBytes,
|
|
286
|
+
(0, import_utils.hexToBytes)(classicalPublicKey)
|
|
287
|
+
);
|
|
288
|
+
if (typeof quantumSignature !== "string" || quantumSignature.length === 0) {
|
|
289
|
+
throw new TypeError("quantumSignature must be a non-empty hex string");
|
|
290
|
+
}
|
|
291
|
+
if (typeof quantumPublicKey !== "string" || quantumPublicKey.length === 0) {
|
|
292
|
+
throw new TypeError("quantumPublicKey must be a non-empty hex string");
|
|
293
|
+
}
|
|
294
|
+
const quantumValid = import_ml_dsa.ml_dsa65.verify(
|
|
295
|
+
(0, import_utils.hexToBytes)(quantumPublicKey),
|
|
296
|
+
payloadBytes,
|
|
297
|
+
(0, import_utils.hexToBytes)(quantumSignature)
|
|
298
|
+
);
|
|
299
|
+
return classicalValid && quantumValid;
|
|
300
|
+
}
|
|
207
301
|
var CONSTANTS = {
|
|
208
302
|
DID_PREFIX: "did:epochcore",
|
|
209
303
|
SIGNING_ALGORITHM: "Ed25519",
|
|
304
|
+
PQ_SIGNING_ALGORITHM: "ML-DSA-65",
|
|
210
305
|
WALLET_ALGORITHM: "secp256k1",
|
|
211
306
|
SUPPORTED_TYPES: ["worker", "database", "storage", "durable_object", "daemon"],
|
|
212
|
-
VERSION: "1.
|
|
307
|
+
VERSION: "1.2.0"
|
|
213
308
|
};
|
|
214
309
|
var index_default = {
|
|
215
310
|
generateKeypair,
|
|
216
311
|
generateIdentity,
|
|
312
|
+
generateQuantumKeypair,
|
|
313
|
+
generateQuantumResistantIdentity,
|
|
217
314
|
createDID,
|
|
218
315
|
parseDID,
|
|
219
316
|
deriveWallet,
|
|
220
317
|
signPayload,
|
|
318
|
+
signPayloadHybrid,
|
|
221
319
|
verifySignature,
|
|
320
|
+
verifySignatureHybrid,
|
|
222
321
|
generateJWKS,
|
|
223
322
|
CONSTANTS
|
|
224
323
|
};
|
|
@@ -230,7 +329,11 @@ var index_default = {
|
|
|
230
329
|
generateIdentity,
|
|
231
330
|
generateJWKS,
|
|
232
331
|
generateKeypair,
|
|
332
|
+
generateQuantumKeypair,
|
|
333
|
+
generateQuantumResistantIdentity,
|
|
233
334
|
parseDID,
|
|
234
335
|
signPayload,
|
|
235
|
-
|
|
336
|
+
signPayloadHybrid,
|
|
337
|
+
verifySignature,
|
|
338
|
+
verifySignatureHybrid
|
|
236
339
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import * as ed25519 from "@noble/ed25519";
|
|
|
3
3
|
import * as secp256k1 from "@noble/secp256k1";
|
|
4
4
|
import { sha256 } from "@noble/hashes/sha256";
|
|
5
5
|
import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
|
|
6
|
+
import { ml_dsa65 } from "@noble/post-quantum/ml-dsa";
|
|
6
7
|
var HEX_64_RE = /^[0-9a-f]{64}$/i;
|
|
7
8
|
var NAME_RE = /^[\w.-]{1,128}$/;
|
|
8
9
|
var MAX_DID_LENGTH = 512;
|
|
@@ -161,21 +162,115 @@ function generateJWKS(publicKeys) {
|
|
|
161
162
|
}))
|
|
162
163
|
};
|
|
163
164
|
}
|
|
165
|
+
function generateQuantumKeypair(seed) {
|
|
166
|
+
let seedBytes;
|
|
167
|
+
if (seed) {
|
|
168
|
+
if (typeof seed !== "string" || !/^[0-9a-f]{64}$/i.test(seed)) {
|
|
169
|
+
throw new TypeError("seed must be a 64-character hex string (32 bytes)");
|
|
170
|
+
}
|
|
171
|
+
seedBytes = hexToBytes(seed);
|
|
172
|
+
} else {
|
|
173
|
+
seedBytes = new Uint8Array(32);
|
|
174
|
+
globalThis.crypto.getRandomValues(seedBytes);
|
|
175
|
+
}
|
|
176
|
+
const { secretKey, publicKey } = ml_dsa65.keygen(seedBytes);
|
|
177
|
+
return {
|
|
178
|
+
secretKey: bytesToHex(secretKey),
|
|
179
|
+
publicKey: bytesToHex(publicKey),
|
|
180
|
+
algorithm: "ML-DSA-65"
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
async function generateQuantumResistantIdentity(type, name) {
|
|
184
|
+
validateType(type);
|
|
185
|
+
validateName(name);
|
|
186
|
+
const { identity, privateKey: classicalPrivateKey } = await generateIdentity(type, name);
|
|
187
|
+
const quantumKeypair = generateQuantumKeypair();
|
|
188
|
+
const qFingerprint = bytesToHex(sha256(hexToBytes(quantumKeypair.publicKey.slice(0, 64)))).slice(0, 32);
|
|
189
|
+
const quantumDid = `did:epochcore:pq:${type}:${name}:${qFingerprint}`;
|
|
190
|
+
return {
|
|
191
|
+
hybrid: {
|
|
192
|
+
classical: identity,
|
|
193
|
+
quantumPublicKey: quantumKeypair.publicKey,
|
|
194
|
+
quantumDid
|
|
195
|
+
},
|
|
196
|
+
classicalPrivateKey,
|
|
197
|
+
quantumSecretKey: quantumKeypair.secretKey
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
async function signPayloadHybrid(payload, classicalPrivateKey, quantumSecretKey, quantumPublicKey) {
|
|
201
|
+
if (typeof payload !== "string" || payload.length === 0) {
|
|
202
|
+
throw new TypeError("payload must be a non-empty string");
|
|
203
|
+
}
|
|
204
|
+
const payloadBytes = new TextEncoder().encode(payload);
|
|
205
|
+
if (payloadBytes.byteLength > MAX_PAYLOAD_BYTES) {
|
|
206
|
+
throw new RangeError(`payload exceeds maximum size of ${MAX_PAYLOAD_BYTES} bytes`);
|
|
207
|
+
}
|
|
208
|
+
validateHex64(classicalPrivateKey, "classicalPrivateKey");
|
|
209
|
+
if (typeof quantumSecretKey !== "string" || quantumSecretKey.length === 0) {
|
|
210
|
+
throw new TypeError("quantumSecretKey must be a non-empty hex string");
|
|
211
|
+
}
|
|
212
|
+
if (typeof quantumPublicKey !== "string" || quantumPublicKey.length === 0) {
|
|
213
|
+
throw new TypeError("quantumPublicKey must be a non-empty hex string");
|
|
214
|
+
}
|
|
215
|
+
const classicalSig = await ed25519.signAsync(payloadBytes, hexToBytes(classicalPrivateKey));
|
|
216
|
+
const classicalPub = await ed25519.getPublicKeyAsync(hexToBytes(classicalPrivateKey));
|
|
217
|
+
const quantumSig = ml_dsa65.sign(hexToBytes(quantumSecretKey), payloadBytes);
|
|
218
|
+
return {
|
|
219
|
+
payload,
|
|
220
|
+
classicalSignature: bytesToHex(classicalSig),
|
|
221
|
+
quantumSignature: bytesToHex(quantumSig),
|
|
222
|
+
classicalPublicKey: bytesToHex(classicalPub),
|
|
223
|
+
quantumPublicKey,
|
|
224
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
async function verifySignatureHybrid(payload, classicalSignature, quantumSignature, classicalPublicKey, quantumPublicKey) {
|
|
228
|
+
if (typeof payload !== "string" || payload.length === 0) {
|
|
229
|
+
throw new TypeError("payload must be a non-empty string");
|
|
230
|
+
}
|
|
231
|
+
const payloadBytes = new TextEncoder().encode(payload);
|
|
232
|
+
if (typeof classicalSignature !== "string" || !/^[0-9a-f]{128}$/i.test(classicalSignature)) {
|
|
233
|
+
throw new TypeError("classicalSignature must be a 128-character hex string");
|
|
234
|
+
}
|
|
235
|
+
validateHex64(classicalPublicKey, "classicalPublicKey");
|
|
236
|
+
const classicalValid = await ed25519.verifyAsync(
|
|
237
|
+
hexToBytes(classicalSignature),
|
|
238
|
+
payloadBytes,
|
|
239
|
+
hexToBytes(classicalPublicKey)
|
|
240
|
+
);
|
|
241
|
+
if (typeof quantumSignature !== "string" || quantumSignature.length === 0) {
|
|
242
|
+
throw new TypeError("quantumSignature must be a non-empty hex string");
|
|
243
|
+
}
|
|
244
|
+
if (typeof quantumPublicKey !== "string" || quantumPublicKey.length === 0) {
|
|
245
|
+
throw new TypeError("quantumPublicKey must be a non-empty hex string");
|
|
246
|
+
}
|
|
247
|
+
const quantumValid = ml_dsa65.verify(
|
|
248
|
+
hexToBytes(quantumPublicKey),
|
|
249
|
+
payloadBytes,
|
|
250
|
+
hexToBytes(quantumSignature)
|
|
251
|
+
);
|
|
252
|
+
return classicalValid && quantumValid;
|
|
253
|
+
}
|
|
164
254
|
var CONSTANTS = {
|
|
165
255
|
DID_PREFIX: "did:epochcore",
|
|
166
256
|
SIGNING_ALGORITHM: "Ed25519",
|
|
257
|
+
PQ_SIGNING_ALGORITHM: "ML-DSA-65",
|
|
167
258
|
WALLET_ALGORITHM: "secp256k1",
|
|
168
259
|
SUPPORTED_TYPES: ["worker", "database", "storage", "durable_object", "daemon"],
|
|
169
|
-
VERSION: "1.
|
|
260
|
+
VERSION: "1.2.0"
|
|
170
261
|
};
|
|
171
262
|
var index_default = {
|
|
172
263
|
generateKeypair,
|
|
173
264
|
generateIdentity,
|
|
265
|
+
generateQuantumKeypair,
|
|
266
|
+
generateQuantumResistantIdentity,
|
|
174
267
|
createDID,
|
|
175
268
|
parseDID,
|
|
176
269
|
deriveWallet,
|
|
177
270
|
signPayload,
|
|
271
|
+
signPayloadHybrid,
|
|
178
272
|
verifySignature,
|
|
273
|
+
verifySignatureHybrid,
|
|
179
274
|
generateJWKS,
|
|
180
275
|
CONSTANTS
|
|
181
276
|
};
|
|
@@ -187,7 +282,11 @@ export {
|
|
|
187
282
|
generateIdentity,
|
|
188
283
|
generateJWKS,
|
|
189
284
|
generateKeypair,
|
|
285
|
+
generateQuantumKeypair,
|
|
286
|
+
generateQuantumResistantIdentity,
|
|
190
287
|
parseDID,
|
|
191
288
|
signPayload,
|
|
192
|
-
|
|
289
|
+
signPayloadHybrid,
|
|
290
|
+
verifySignature,
|
|
291
|
+
verifySignatureHybrid
|
|
193
292
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epochcore/identity-sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "World's First Universal Infrastructure Identity SDK - Ed25519 cryptographic identities for workers, databases, storage, and daemons",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "World's First Universal Infrastructure Identity SDK - Ed25519 + ML-DSA-65 (post-quantum) cryptographic identities for workers, databases, storage, and daemons",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"build": "tsup src/index.ts --format cjs,esm --dts --clean --external @noble/ed25519 --external @noble/secp256k1 --external @noble/hashes",
|
|
16
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean --external @noble/ed25519 --external @noble/secp256k1 --external @noble/hashes --external @noble/post-quantum",
|
|
17
17
|
"test": "vitest run",
|
|
18
18
|
"prepublishOnly": "npm run build"
|
|
19
19
|
},
|
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
"infrastructure",
|
|
24
24
|
"ed25519",
|
|
25
25
|
"secp256k1",
|
|
26
|
+
"ml-dsa",
|
|
27
|
+
"dilithium",
|
|
28
|
+
"post-quantum",
|
|
26
29
|
"web3",
|
|
27
30
|
"cloudflare-workers",
|
|
28
31
|
"quantum",
|
|
@@ -38,7 +41,8 @@
|
|
|
38
41
|
"dependencies": {
|
|
39
42
|
"@noble/ed25519": "^2.0.0",
|
|
40
43
|
"@noble/secp256k1": "^2.0.0",
|
|
41
|
-
"@noble/hashes": "^1.3.0"
|
|
44
|
+
"@noble/hashes": "^1.3.0",
|
|
45
|
+
"@noble/post-quantum": "^0.2.0"
|
|
42
46
|
},
|
|
43
47
|
"devDependencies": {
|
|
44
48
|
"tsup": "^8.0.0",
|