@epochcore/identity-sdk 1.0.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 +177 -0
- package/dist/index.d.ts +83 -15
- package/dist/index.js +336 -135
- package/dist/index.mjs +292 -0
- package/package.json +18 -5
- package/dist/index.d.ts.map +0 -1
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @epochcore/identity-sdk
|
|
3
|
+
* World's First Universal Infrastructure Identity SDK
|
|
4
|
+
*
|
|
5
|
+
* Provides Ed25519 cryptographic identities for:
|
|
6
|
+
* - Cloudflare Workers
|
|
7
|
+
* - D1 Databases
|
|
8
|
+
* - R2 Storage Buckets
|
|
9
|
+
* - Durable Objects
|
|
10
|
+
* - Local Daemons
|
|
11
|
+
*/
|
|
12
|
+
type IdentityType = 'worker' | 'database' | 'storage' | 'durable_object' | 'daemon';
|
|
13
|
+
interface EpochCoreIdentity {
|
|
14
|
+
did: string;
|
|
15
|
+
publicKey: string;
|
|
16
|
+
fingerprint: string;
|
|
17
|
+
type: IdentityType;
|
|
18
|
+
name: string;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
}
|
|
21
|
+
interface EpochCoreWallet {
|
|
22
|
+
address: string;
|
|
23
|
+
publicKey: string;
|
|
24
|
+
identityDid: string;
|
|
25
|
+
}
|
|
26
|
+
interface SignedPayload {
|
|
27
|
+
payload: string;
|
|
28
|
+
signature: string;
|
|
29
|
+
publicKey: string;
|
|
30
|
+
timestamp: string;
|
|
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
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Generate a new Ed25519 keypair for infrastructure identity
|
|
62
|
+
*/
|
|
63
|
+
declare function generateKeypair(): Promise<{
|
|
64
|
+
privateKey: string;
|
|
65
|
+
publicKey: string;
|
|
66
|
+
}>;
|
|
67
|
+
/**
|
|
68
|
+
* Create a DID (Decentralized Identifier) for infrastructure
|
|
69
|
+
* Format: did:epochcore:<type>:<name>:<fingerprint>
|
|
70
|
+
*/
|
|
71
|
+
declare function createDID(type: IdentityType, name: string, publicKey: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* Generate a complete infrastructure identity
|
|
74
|
+
*/
|
|
75
|
+
declare function generateIdentity(type: IdentityType, name: string): Promise<{
|
|
76
|
+
identity: EpochCoreIdentity;
|
|
77
|
+
privateKey: string;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Derive a secp256k1 wallet from an identity for Web3 operations
|
|
81
|
+
*/
|
|
82
|
+
declare function deriveWallet(privateKey: string, identityDid: string): EpochCoreWallet;
|
|
83
|
+
/**
|
|
84
|
+
* Sign a payload with Ed25519 private key
|
|
85
|
+
*/
|
|
86
|
+
declare function signPayload(payload: string, privateKey: string): Promise<SignedPayload>;
|
|
87
|
+
/**
|
|
88
|
+
* Verify an Ed25519 signature
|
|
89
|
+
*/
|
|
90
|
+
declare function verifySignature(payload: string, signature: string, publicKey: string): Promise<boolean>;
|
|
91
|
+
/**
|
|
92
|
+
* Parse a DID string into components
|
|
93
|
+
*/
|
|
94
|
+
declare function parseDID(did: string): {
|
|
95
|
+
method: string;
|
|
96
|
+
type: IdentityType;
|
|
97
|
+
name: string;
|
|
98
|
+
fingerprint: string;
|
|
99
|
+
} | null;
|
|
100
|
+
/**
|
|
101
|
+
* Generate JWKS (JSON Web Key Set) for OAuth2/OIDC integration
|
|
102
|
+
*/
|
|
103
|
+
declare function generateJWKS(publicKeys: string[]): {
|
|
104
|
+
keys: Array<{
|
|
105
|
+
kty: string;
|
|
106
|
+
crv: string;
|
|
107
|
+
x: string;
|
|
108
|
+
use: string;
|
|
109
|
+
kid: string;
|
|
110
|
+
}>;
|
|
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>;
|
|
146
|
+
declare const CONSTANTS: {
|
|
147
|
+
DID_PREFIX: string;
|
|
148
|
+
SIGNING_ALGORITHM: string;
|
|
149
|
+
PQ_SIGNING_ALGORITHM: string;
|
|
150
|
+
WALLET_ALGORITHM: string;
|
|
151
|
+
SUPPORTED_TYPES: IdentityType[];
|
|
152
|
+
VERSION: string;
|
|
153
|
+
};
|
|
154
|
+
declare const _default: {
|
|
155
|
+
generateKeypair: typeof generateKeypair;
|
|
156
|
+
generateIdentity: typeof generateIdentity;
|
|
157
|
+
generateQuantumKeypair: typeof generateQuantumKeypair;
|
|
158
|
+
generateQuantumResistantIdentity: typeof generateQuantumResistantIdentity;
|
|
159
|
+
createDID: typeof createDID;
|
|
160
|
+
parseDID: typeof parseDID;
|
|
161
|
+
deriveWallet: typeof deriveWallet;
|
|
162
|
+
signPayload: typeof signPayload;
|
|
163
|
+
signPayloadHybrid: typeof signPayloadHybrid;
|
|
164
|
+
verifySignature: typeof verifySignature;
|
|
165
|
+
verifySignatureHybrid: typeof verifySignatureHybrid;
|
|
166
|
+
generateJWKS: typeof generateJWKS;
|
|
167
|
+
CONSTANTS: {
|
|
168
|
+
DID_PREFIX: string;
|
|
169
|
+
SIGNING_ALGORITHM: string;
|
|
170
|
+
PQ_SIGNING_ALGORITHM: string;
|
|
171
|
+
WALLET_ALGORITHM: string;
|
|
172
|
+
SUPPORTED_TYPES: IdentityType[];
|
|
173
|
+
VERSION: string;
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
|
|
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
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* - Durable Objects
|
|
10
10
|
* - Local Daemons
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
type IdentityType = 'worker' | 'database' | 'storage' | 'durable_object' | 'daemon';
|
|
13
|
+
interface EpochCoreIdentity {
|
|
14
14
|
did: string;
|
|
15
15
|
publicKey: string;
|
|
16
16
|
fingerprint: string;
|
|
@@ -18,21 +18,49 @@ export interface EpochCoreIdentity {
|
|
|
18
18
|
name: string;
|
|
19
19
|
createdAt: string;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
interface EpochCoreWallet {
|
|
22
22
|
address: string;
|
|
23
23
|
publicKey: string;
|
|
24
24
|
identityDid: string;
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
interface SignedPayload {
|
|
27
27
|
payload: string;
|
|
28
28
|
signature: string;
|
|
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
|
*/
|
|
35
|
-
|
|
63
|
+
declare function generateKeypair(): Promise<{
|
|
36
64
|
privateKey: string;
|
|
37
65
|
publicKey: string;
|
|
38
66
|
}>;
|
|
@@ -40,30 +68,30 @@ export declare function generateKeypair(): Promise<{
|
|
|
40
68
|
* Create a DID (Decentralized Identifier) for infrastructure
|
|
41
69
|
* Format: did:epochcore:<type>:<name>:<fingerprint>
|
|
42
70
|
*/
|
|
43
|
-
|
|
71
|
+
declare function createDID(type: IdentityType, name: string, publicKey: string): string;
|
|
44
72
|
/**
|
|
45
73
|
* Generate a complete infrastructure identity
|
|
46
74
|
*/
|
|
47
|
-
|
|
75
|
+
declare function generateIdentity(type: IdentityType, name: string): Promise<{
|
|
48
76
|
identity: EpochCoreIdentity;
|
|
49
77
|
privateKey: string;
|
|
50
78
|
}>;
|
|
51
79
|
/**
|
|
52
80
|
* Derive a secp256k1 wallet from an identity for Web3 operations
|
|
53
81
|
*/
|
|
54
|
-
|
|
82
|
+
declare function deriveWallet(privateKey: string, identityDid: string): EpochCoreWallet;
|
|
55
83
|
/**
|
|
56
84
|
* Sign a payload with Ed25519 private key
|
|
57
85
|
*/
|
|
58
|
-
|
|
86
|
+
declare function signPayload(payload: string, privateKey: string): Promise<SignedPayload>;
|
|
59
87
|
/**
|
|
60
88
|
* Verify an Ed25519 signature
|
|
61
89
|
*/
|
|
62
|
-
|
|
90
|
+
declare function verifySignature(payload: string, signature: string, publicKey: string): Promise<boolean>;
|
|
63
91
|
/**
|
|
64
92
|
* Parse a DID string into components
|
|
65
93
|
*/
|
|
66
|
-
|
|
94
|
+
declare function parseDID(did: string): {
|
|
67
95
|
method: string;
|
|
68
96
|
type: IdentityType;
|
|
69
97
|
name: string;
|
|
@@ -72,7 +100,7 @@ export declare function parseDID(did: string): {
|
|
|
72
100
|
/**
|
|
73
101
|
* Generate JWKS (JSON Web Key Set) for OAuth2/OIDC integration
|
|
74
102
|
*/
|
|
75
|
-
|
|
103
|
+
declare function generateJWKS(publicKeys: string[]): {
|
|
76
104
|
keys: Array<{
|
|
77
105
|
kty: string;
|
|
78
106
|
crv: string;
|
|
@@ -81,9 +109,44 @@ export declare function generateJWKS(publicKeys: string[]): {
|
|
|
81
109
|
kid: string;
|
|
82
110
|
}>;
|
|
83
111
|
};
|
|
84
|
-
|
|
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>;
|
|
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 @@ export 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
|
-
|
|
109
|
-
|
|
176
|
+
|
|
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
|
@@ -1,138 +1,339 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
return ed25519.verifyAsync(hexToBytes(signature), message, hexToBytes(publicKey));
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Parse a DID string into components
|
|
93
|
-
*/
|
|
94
|
-
export function parseDID(did) {
|
|
95
|
-
const parts = did.split(':');
|
|
96
|
-
if (parts.length !== 5 || parts[0] !== 'did' || parts[1] !== 'epochcore') {
|
|
97
|
-
return null;
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
CONSTANTS: () => CONSTANTS,
|
|
34
|
+
createDID: () => createDID,
|
|
35
|
+
default: () => index_default,
|
|
36
|
+
deriveWallet: () => deriveWallet,
|
|
37
|
+
generateIdentity: () => generateIdentity,
|
|
38
|
+
generateJWKS: () => generateJWKS,
|
|
39
|
+
generateKeypair: () => generateKeypair,
|
|
40
|
+
generateQuantumKeypair: () => generateQuantumKeypair,
|
|
41
|
+
generateQuantumResistantIdentity: () => generateQuantumResistantIdentity,
|
|
42
|
+
parseDID: () => parseDID,
|
|
43
|
+
signPayload: () => signPayload,
|
|
44
|
+
signPayloadHybrid: () => signPayloadHybrid,
|
|
45
|
+
verifySignature: () => verifySignature,
|
|
46
|
+
verifySignatureHybrid: () => verifySignatureHybrid
|
|
47
|
+
});
|
|
48
|
+
module.exports = __toCommonJS(index_exports);
|
|
49
|
+
var ed25519 = __toESM(require("@noble/ed25519"));
|
|
50
|
+
var secp256k1 = __toESM(require("@noble/secp256k1"));
|
|
51
|
+
var import_sha256 = require("@noble/hashes/sha256");
|
|
52
|
+
var import_utils = require("@noble/hashes/utils");
|
|
53
|
+
var import_ml_dsa = require("@noble/post-quantum/ml-dsa");
|
|
54
|
+
var HEX_64_RE = /^[0-9a-f]{64}$/i;
|
|
55
|
+
var NAME_RE = /^[\w.-]{1,128}$/;
|
|
56
|
+
var MAX_DID_LENGTH = 512;
|
|
57
|
+
var MAX_PAYLOAD_BYTES = 1048576;
|
|
58
|
+
var SECP256K1_ORDER = BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
|
|
59
|
+
function toBase64Url(bytes) {
|
|
60
|
+
let binary = "";
|
|
61
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
62
|
+
const base64 = btoa(binary);
|
|
63
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
64
|
+
}
|
|
65
|
+
function validateHex64(value, name) {
|
|
66
|
+
if (typeof value !== "string" || !HEX_64_RE.test(value)) {
|
|
67
|
+
throw new TypeError(`${name} must be a 64-character hex string`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function validateType(type) {
|
|
71
|
+
if (typeof type !== "string" || !CONSTANTS.SUPPORTED_TYPES.includes(type)) {
|
|
72
|
+
throw new TypeError(
|
|
73
|
+
`Invalid identity type: ${String(type)}. Must be one of: ${CONSTANTS.SUPPORTED_TYPES.join(", ")}`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function validateName(name) {
|
|
78
|
+
if (typeof name !== "string" || !NAME_RE.test(name)) {
|
|
79
|
+
throw new TypeError("name must be 1-128 characters matching /^[\\w.-]+$/");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function generateKeypair() {
|
|
83
|
+
const privateKey = ed25519.utils.randomPrivateKey();
|
|
84
|
+
let allZero = true;
|
|
85
|
+
for (let i = 0; i < privateKey.length; i++) {
|
|
86
|
+
if (privateKey[i] !== 0) {
|
|
87
|
+
allZero = false;
|
|
88
|
+
break;
|
|
98
89
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
90
|
+
}
|
|
91
|
+
if (allZero) {
|
|
92
|
+
throw new Error("Key generation produced zero-entropy private key; CSPRNG may be broken");
|
|
93
|
+
}
|
|
94
|
+
const publicKey = await ed25519.getPublicKeyAsync(privateKey);
|
|
95
|
+
return {
|
|
96
|
+
privateKey: (0, import_utils.bytesToHex)(privateKey),
|
|
97
|
+
publicKey: (0, import_utils.bytesToHex)(publicKey)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function createDID(type, name, publicKey) {
|
|
101
|
+
validateType(type);
|
|
102
|
+
validateName(name);
|
|
103
|
+
validateHex64(publicKey, "publicKey");
|
|
104
|
+
const fingerprint = (0, import_utils.bytesToHex)((0, import_sha256.sha256)((0, import_utils.hexToBytes)(publicKey))).slice(0, 32);
|
|
105
|
+
return `did:epochcore:${type}:${name}:${fingerprint}`;
|
|
106
|
+
}
|
|
107
|
+
async function generateIdentity(type, name) {
|
|
108
|
+
validateType(type);
|
|
109
|
+
validateName(name);
|
|
110
|
+
const { privateKey, publicKey } = await generateKeypair();
|
|
111
|
+
const fingerprint = (0, import_utils.bytesToHex)((0, import_sha256.sha256)((0, import_utils.hexToBytes)(publicKey))).slice(0, 32);
|
|
112
|
+
const did = createDID(type, name, publicKey);
|
|
113
|
+
return {
|
|
114
|
+
identity: {
|
|
115
|
+
did,
|
|
116
|
+
publicKey,
|
|
117
|
+
fingerprint,
|
|
118
|
+
type,
|
|
119
|
+
name,
|
|
120
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
121
|
+
},
|
|
122
|
+
privateKey
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function deriveWallet(privateKey, identityDid) {
|
|
126
|
+
validateHex64(privateKey, "privateKey");
|
|
127
|
+
if (typeof identityDid !== "string" || !identityDid.startsWith("did:epochcore:")) {
|
|
128
|
+
throw new TypeError('identityDid must start with "did:epochcore:"');
|
|
129
|
+
}
|
|
130
|
+
const seedBytes = (0, import_sha256.sha256)((0, import_utils.hexToBytes)(privateKey));
|
|
131
|
+
const walletPrivKey = secp256k1.utils.normPrivateKeyToScalar(seedBytes);
|
|
132
|
+
if (walletPrivKey <= 0n || walletPrivKey >= SECP256K1_ORDER) {
|
|
133
|
+
throw new RangeError("Derived wallet private key scalar is out of valid secp256k1 range [1, n-1]");
|
|
134
|
+
}
|
|
135
|
+
const walletPubKey = secp256k1.getPublicKey(walletPrivKey, false);
|
|
136
|
+
const pubKeyHash = (0, import_sha256.sha256)(walletPubKey.slice(1));
|
|
137
|
+
const address = "0x" + (0, import_utils.bytesToHex)(pubKeyHash).slice(-40);
|
|
138
|
+
return {
|
|
139
|
+
address,
|
|
140
|
+
publicKey: (0, import_utils.bytesToHex)(walletPubKey),
|
|
141
|
+
identityDid
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async function signPayload(payload, privateKey) {
|
|
145
|
+
if (typeof payload !== "string" || payload.length === 0) {
|
|
146
|
+
throw new TypeError("payload must be a non-empty string");
|
|
147
|
+
}
|
|
148
|
+
const payloadBytes = new TextEncoder().encode(payload);
|
|
149
|
+
if (payloadBytes.byteLength > MAX_PAYLOAD_BYTES) {
|
|
150
|
+
throw new RangeError(`payload exceeds maximum size of ${MAX_PAYLOAD_BYTES} bytes`);
|
|
151
|
+
}
|
|
152
|
+
validateHex64(privateKey, "privateKey");
|
|
153
|
+
const signature = await ed25519.signAsync(payloadBytes, (0, import_utils.hexToBytes)(privateKey));
|
|
154
|
+
const publicKey = await ed25519.getPublicKeyAsync((0, import_utils.hexToBytes)(privateKey));
|
|
155
|
+
return {
|
|
156
|
+
payload,
|
|
157
|
+
signature: (0, import_utils.bytesToHex)(signature),
|
|
158
|
+
publicKey: (0, import_utils.bytesToHex)(publicKey),
|
|
159
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
async function verifySignature(payload, signature, publicKey) {
|
|
163
|
+
if (typeof payload !== "string" || payload.length === 0) {
|
|
164
|
+
throw new TypeError("payload must be a non-empty string");
|
|
165
|
+
}
|
|
166
|
+
if (typeof signature !== "string" || !/^[0-9a-f]{128}$/i.test(signature)) {
|
|
167
|
+
throw new TypeError("signature must be a 128-character hex string");
|
|
168
|
+
}
|
|
169
|
+
validateHex64(publicKey, "publicKey");
|
|
170
|
+
const message = new TextEncoder().encode(payload);
|
|
171
|
+
return ed25519.verifyAsync(
|
|
172
|
+
(0, import_utils.hexToBytes)(signature),
|
|
173
|
+
message,
|
|
174
|
+
(0, import_utils.hexToBytes)(publicKey)
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
function parseDID(did) {
|
|
178
|
+
if (typeof did !== "string" || did.length > MAX_DID_LENGTH) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const parts = did.split(":");
|
|
182
|
+
if (parts.length !== 5 || parts[0] !== "did" || parts[1] !== "epochcore") {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
if (!CONSTANTS.SUPPORTED_TYPES.includes(parts[2])) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
method: parts[1],
|
|
190
|
+
type: parts[2],
|
|
191
|
+
name: parts[3],
|
|
192
|
+
fingerprint: parts[4]
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function generateJWKS(publicKeys) {
|
|
196
|
+
if (!Array.isArray(publicKeys)) {
|
|
197
|
+
throw new TypeError("publicKeys must be an array");
|
|
198
|
+
}
|
|
199
|
+
for (let i = 0; i < publicKeys.length; i++) {
|
|
200
|
+
validateHex64(publicKeys[i], `publicKeys[${i}]`);
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
keys: publicKeys.map((pk, i) => ({
|
|
204
|
+
kty: "OKP",
|
|
205
|
+
crv: "Ed25519",
|
|
206
|
+
x: toBase64Url((0, import_utils.hexToBytes)(pk)),
|
|
207
|
+
use: "sig",
|
|
208
|
+
kid: `epochcore-${i + 1}`
|
|
209
|
+
}))
|
|
210
|
+
};
|
|
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
|
+
}
|
|
301
|
+
var CONSTANTS = {
|
|
302
|
+
DID_PREFIX: "did:epochcore",
|
|
303
|
+
SIGNING_ALGORITHM: "Ed25519",
|
|
304
|
+
PQ_SIGNING_ALGORITHM: "ML-DSA-65",
|
|
305
|
+
WALLET_ALGORITHM: "secp256k1",
|
|
306
|
+
SUPPORTED_TYPES: ["worker", "database", "storage", "durable_object", "daemon"],
|
|
307
|
+
VERSION: "1.2.0"
|
|
127
308
|
};
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
309
|
+
var index_default = {
|
|
310
|
+
generateKeypair,
|
|
311
|
+
generateIdentity,
|
|
312
|
+
generateQuantumKeypair,
|
|
313
|
+
generateQuantumResistantIdentity,
|
|
314
|
+
createDID,
|
|
315
|
+
parseDID,
|
|
316
|
+
deriveWallet,
|
|
317
|
+
signPayload,
|
|
318
|
+
signPayloadHybrid,
|
|
319
|
+
verifySignature,
|
|
320
|
+
verifySignatureHybrid,
|
|
321
|
+
generateJWKS,
|
|
322
|
+
CONSTANTS
|
|
138
323
|
};
|
|
324
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
325
|
+
0 && (module.exports = {
|
|
326
|
+
CONSTANTS,
|
|
327
|
+
createDID,
|
|
328
|
+
deriveWallet,
|
|
329
|
+
generateIdentity,
|
|
330
|
+
generateJWKS,
|
|
331
|
+
generateKeypair,
|
|
332
|
+
generateQuantumKeypair,
|
|
333
|
+
generateQuantumResistantIdentity,
|
|
334
|
+
parseDID,
|
|
335
|
+
signPayload,
|
|
336
|
+
signPayloadHybrid,
|
|
337
|
+
verifySignature,
|
|
338
|
+
verifySignatureHybrid
|
|
339
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import * as ed25519 from "@noble/ed25519";
|
|
3
|
+
import * as secp256k1 from "@noble/secp256k1";
|
|
4
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
5
|
+
import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
|
|
6
|
+
import { ml_dsa65 } from "@noble/post-quantum/ml-dsa";
|
|
7
|
+
var HEX_64_RE = /^[0-9a-f]{64}$/i;
|
|
8
|
+
var NAME_RE = /^[\w.-]{1,128}$/;
|
|
9
|
+
var MAX_DID_LENGTH = 512;
|
|
10
|
+
var MAX_PAYLOAD_BYTES = 1048576;
|
|
11
|
+
var SECP256K1_ORDER = BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
|
|
12
|
+
function toBase64Url(bytes) {
|
|
13
|
+
let binary = "";
|
|
14
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
15
|
+
const base64 = btoa(binary);
|
|
16
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
17
|
+
}
|
|
18
|
+
function validateHex64(value, name) {
|
|
19
|
+
if (typeof value !== "string" || !HEX_64_RE.test(value)) {
|
|
20
|
+
throw new TypeError(`${name} must be a 64-character hex string`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function validateType(type) {
|
|
24
|
+
if (typeof type !== "string" || !CONSTANTS.SUPPORTED_TYPES.includes(type)) {
|
|
25
|
+
throw new TypeError(
|
|
26
|
+
`Invalid identity type: ${String(type)}. Must be one of: ${CONSTANTS.SUPPORTED_TYPES.join(", ")}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function validateName(name) {
|
|
31
|
+
if (typeof name !== "string" || !NAME_RE.test(name)) {
|
|
32
|
+
throw new TypeError("name must be 1-128 characters matching /^[\\w.-]+$/");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function generateKeypair() {
|
|
36
|
+
const privateKey = ed25519.utils.randomPrivateKey();
|
|
37
|
+
let allZero = true;
|
|
38
|
+
for (let i = 0; i < privateKey.length; i++) {
|
|
39
|
+
if (privateKey[i] !== 0) {
|
|
40
|
+
allZero = false;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (allZero) {
|
|
45
|
+
throw new Error("Key generation produced zero-entropy private key; CSPRNG may be broken");
|
|
46
|
+
}
|
|
47
|
+
const publicKey = await ed25519.getPublicKeyAsync(privateKey);
|
|
48
|
+
return {
|
|
49
|
+
privateKey: bytesToHex(privateKey),
|
|
50
|
+
publicKey: bytesToHex(publicKey)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function createDID(type, name, publicKey) {
|
|
54
|
+
validateType(type);
|
|
55
|
+
validateName(name);
|
|
56
|
+
validateHex64(publicKey, "publicKey");
|
|
57
|
+
const fingerprint = bytesToHex(sha256(hexToBytes(publicKey))).slice(0, 32);
|
|
58
|
+
return `did:epochcore:${type}:${name}:${fingerprint}`;
|
|
59
|
+
}
|
|
60
|
+
async function generateIdentity(type, name) {
|
|
61
|
+
validateType(type);
|
|
62
|
+
validateName(name);
|
|
63
|
+
const { privateKey, publicKey } = await generateKeypair();
|
|
64
|
+
const fingerprint = bytesToHex(sha256(hexToBytes(publicKey))).slice(0, 32);
|
|
65
|
+
const did = createDID(type, name, publicKey);
|
|
66
|
+
return {
|
|
67
|
+
identity: {
|
|
68
|
+
did,
|
|
69
|
+
publicKey,
|
|
70
|
+
fingerprint,
|
|
71
|
+
type,
|
|
72
|
+
name,
|
|
73
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
74
|
+
},
|
|
75
|
+
privateKey
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function deriveWallet(privateKey, identityDid) {
|
|
79
|
+
validateHex64(privateKey, "privateKey");
|
|
80
|
+
if (typeof identityDid !== "string" || !identityDid.startsWith("did:epochcore:")) {
|
|
81
|
+
throw new TypeError('identityDid must start with "did:epochcore:"');
|
|
82
|
+
}
|
|
83
|
+
const seedBytes = sha256(hexToBytes(privateKey));
|
|
84
|
+
const walletPrivKey = secp256k1.utils.normPrivateKeyToScalar(seedBytes);
|
|
85
|
+
if (walletPrivKey <= 0n || walletPrivKey >= SECP256K1_ORDER) {
|
|
86
|
+
throw new RangeError("Derived wallet private key scalar is out of valid secp256k1 range [1, n-1]");
|
|
87
|
+
}
|
|
88
|
+
const walletPubKey = secp256k1.getPublicKey(walletPrivKey, false);
|
|
89
|
+
const pubKeyHash = sha256(walletPubKey.slice(1));
|
|
90
|
+
const address = "0x" + bytesToHex(pubKeyHash).slice(-40);
|
|
91
|
+
return {
|
|
92
|
+
address,
|
|
93
|
+
publicKey: bytesToHex(walletPubKey),
|
|
94
|
+
identityDid
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async function signPayload(payload, privateKey) {
|
|
98
|
+
if (typeof payload !== "string" || payload.length === 0) {
|
|
99
|
+
throw new TypeError("payload must be a non-empty string");
|
|
100
|
+
}
|
|
101
|
+
const payloadBytes = new TextEncoder().encode(payload);
|
|
102
|
+
if (payloadBytes.byteLength > MAX_PAYLOAD_BYTES) {
|
|
103
|
+
throw new RangeError(`payload exceeds maximum size of ${MAX_PAYLOAD_BYTES} bytes`);
|
|
104
|
+
}
|
|
105
|
+
validateHex64(privateKey, "privateKey");
|
|
106
|
+
const signature = await ed25519.signAsync(payloadBytes, hexToBytes(privateKey));
|
|
107
|
+
const publicKey = await ed25519.getPublicKeyAsync(hexToBytes(privateKey));
|
|
108
|
+
return {
|
|
109
|
+
payload,
|
|
110
|
+
signature: bytesToHex(signature),
|
|
111
|
+
publicKey: bytesToHex(publicKey),
|
|
112
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
async function verifySignature(payload, signature, publicKey) {
|
|
116
|
+
if (typeof payload !== "string" || payload.length === 0) {
|
|
117
|
+
throw new TypeError("payload must be a non-empty string");
|
|
118
|
+
}
|
|
119
|
+
if (typeof signature !== "string" || !/^[0-9a-f]{128}$/i.test(signature)) {
|
|
120
|
+
throw new TypeError("signature must be a 128-character hex string");
|
|
121
|
+
}
|
|
122
|
+
validateHex64(publicKey, "publicKey");
|
|
123
|
+
const message = new TextEncoder().encode(payload);
|
|
124
|
+
return ed25519.verifyAsync(
|
|
125
|
+
hexToBytes(signature),
|
|
126
|
+
message,
|
|
127
|
+
hexToBytes(publicKey)
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
function parseDID(did) {
|
|
131
|
+
if (typeof did !== "string" || did.length > MAX_DID_LENGTH) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const parts = did.split(":");
|
|
135
|
+
if (parts.length !== 5 || parts[0] !== "did" || parts[1] !== "epochcore") {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
if (!CONSTANTS.SUPPORTED_TYPES.includes(parts[2])) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
method: parts[1],
|
|
143
|
+
type: parts[2],
|
|
144
|
+
name: parts[3],
|
|
145
|
+
fingerprint: parts[4]
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function generateJWKS(publicKeys) {
|
|
149
|
+
if (!Array.isArray(publicKeys)) {
|
|
150
|
+
throw new TypeError("publicKeys must be an array");
|
|
151
|
+
}
|
|
152
|
+
for (let i = 0; i < publicKeys.length; i++) {
|
|
153
|
+
validateHex64(publicKeys[i], `publicKeys[${i}]`);
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
keys: publicKeys.map((pk, i) => ({
|
|
157
|
+
kty: "OKP",
|
|
158
|
+
crv: "Ed25519",
|
|
159
|
+
x: toBase64Url(hexToBytes(pk)),
|
|
160
|
+
use: "sig",
|
|
161
|
+
kid: `epochcore-${i + 1}`
|
|
162
|
+
}))
|
|
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
|
+
}
|
|
254
|
+
var CONSTANTS = {
|
|
255
|
+
DID_PREFIX: "did:epochcore",
|
|
256
|
+
SIGNING_ALGORITHM: "Ed25519",
|
|
257
|
+
PQ_SIGNING_ALGORITHM: "ML-DSA-65",
|
|
258
|
+
WALLET_ALGORITHM: "secp256k1",
|
|
259
|
+
SUPPORTED_TYPES: ["worker", "database", "storage", "durable_object", "daemon"],
|
|
260
|
+
VERSION: "1.2.0"
|
|
261
|
+
};
|
|
262
|
+
var index_default = {
|
|
263
|
+
generateKeypair,
|
|
264
|
+
generateIdentity,
|
|
265
|
+
generateQuantumKeypair,
|
|
266
|
+
generateQuantumResistantIdentity,
|
|
267
|
+
createDID,
|
|
268
|
+
parseDID,
|
|
269
|
+
deriveWallet,
|
|
270
|
+
signPayload,
|
|
271
|
+
signPayloadHybrid,
|
|
272
|
+
verifySignature,
|
|
273
|
+
verifySignatureHybrid,
|
|
274
|
+
generateJWKS,
|
|
275
|
+
CONSTANTS
|
|
276
|
+
};
|
|
277
|
+
export {
|
|
278
|
+
CONSTANTS,
|
|
279
|
+
createDID,
|
|
280
|
+
index_default as default,
|
|
281
|
+
deriveWallet,
|
|
282
|
+
generateIdentity,
|
|
283
|
+
generateJWKS,
|
|
284
|
+
generateKeypair,
|
|
285
|
+
generateQuantumKeypair,
|
|
286
|
+
generateQuantumResistantIdentity,
|
|
287
|
+
parseDID,
|
|
288
|
+
signPayload,
|
|
289
|
+
signPayloadHybrid,
|
|
290
|
+
verifySignature,
|
|
291
|
+
verifySignatureHybrid
|
|
292
|
+
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
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
|
+
"module": "dist/index.mjs",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
7
15
|
"scripts": {
|
|
8
|
-
"build": "
|
|
9
|
-
"test": "vitest",
|
|
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
|
+
"test": "vitest run",
|
|
10
18
|
"prepublishOnly": "npm run build"
|
|
11
19
|
},
|
|
12
20
|
"keywords": [
|
|
@@ -15,6 +23,9 @@
|
|
|
15
23
|
"infrastructure",
|
|
16
24
|
"ed25519",
|
|
17
25
|
"secp256k1",
|
|
26
|
+
"ml-dsa",
|
|
27
|
+
"dilithium",
|
|
28
|
+
"post-quantum",
|
|
18
29
|
"web3",
|
|
19
30
|
"cloudflare-workers",
|
|
20
31
|
"quantum",
|
|
@@ -30,9 +41,11 @@
|
|
|
30
41
|
"dependencies": {
|
|
31
42
|
"@noble/ed25519": "^2.0.0",
|
|
32
43
|
"@noble/secp256k1": "^2.0.0",
|
|
33
|
-
"@noble/hashes": "^1.3.0"
|
|
44
|
+
"@noble/hashes": "^1.3.0",
|
|
45
|
+
"@noble/post-quantum": "^0.2.0"
|
|
34
46
|
},
|
|
35
47
|
"devDependencies": {
|
|
48
|
+
"tsup": "^8.0.0",
|
|
36
49
|
"typescript": "^5.3.0",
|
|
37
50
|
"vitest": "^1.0.0"
|
|
38
51
|
},
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,gBAAgB,GAAG,QAAQ,CAAC;AAE3F,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAQD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,MAAM,CAGR;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IACT,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC,CAgBD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,eAAe,CAcjB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAWxB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,IAAI,CAYP;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG;IAClD,IAAI,EAAE,KAAK,CAAC;QACV,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,CAAC,EAAE,MAAM,CAAC;QACV,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;CACJ,CAUA;AAGD,eAAO,MAAM,SAAS;;;;qBAI8D,YAAY,EAAE;;CAEjG,CAAC;;;;;;;;;;;;;;yBAFkF,YAAY,EAAE;;;;AAIlG,wBAUE"}
|