@beclab/olaresid 0.1.3 → 0.1.5
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/business/index.d.ts +3 -3
- package/dist/business/index.d.ts.map +1 -1
- package/dist/business/index.js +49 -63
- package/dist/business/index.js.map +1 -1
- package/dist/cli.js +3 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/crypto-utils.d.ts +71 -4
- package/dist/utils/crypto-utils.d.ts.map +1 -1
- package/dist/utils/crypto-utils.js +163 -51
- package/dist/utils/crypto-utils.js.map +1 -1
- package/examples/crypto-utilities.ts +3 -3
- package/examples/ed25519-jwk.ts +73 -0
- package/examples/encoding-utils.ts +96 -0
- package/examples/generate-mnemonic.ts +3 -3
- package/examples/register-subdomain.ts +4 -3
- package/examples/transfer-domain.ts +1 -1
- package/examples/wallet-management.ts +8 -8
- package/package.json +2 -3
- package/src/business/index.ts +47 -58
- package/src/cli.ts +3 -3
- package/src/index.ts +8 -23
- package/src/utils/crypto-utils.ts +198 -64
|
@@ -6,45 +6,15 @@
|
|
|
6
6
|
* compatibility across the entire Olares ecosystem.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import * as bip39 from 'bip39';
|
|
10
9
|
import * as varint from 'varint';
|
|
10
|
+
import { base58btc } from 'multiformats/bases/base58';
|
|
11
|
+
import { base64url } from 'multiformats/bases/base64';
|
|
11
12
|
|
|
12
13
|
// Browser globals type declaration
|
|
13
14
|
declare const window: any;
|
|
15
|
+
declare const atob: (input: string) => string;
|
|
14
16
|
declare const btoa: (input: string) => string;
|
|
15
17
|
|
|
16
|
-
// Base58 Bitcoin alphabet
|
|
17
|
-
const BASE58_ALPHABET =
|
|
18
|
-
'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Encode bytes to base58btc format
|
|
22
|
-
* This is a pure implementation compatible with multiformats/bases/base58
|
|
23
|
-
*/
|
|
24
|
-
function base58Encode(bytes: Uint8Array): string {
|
|
25
|
-
// Convert bytes to bigint
|
|
26
|
-
let num = 0n;
|
|
27
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
28
|
-
num = num * 256n + BigInt(bytes[i]);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Convert to base58
|
|
32
|
-
let encoded = '';
|
|
33
|
-
while (num > 0n) {
|
|
34
|
-
const remainder = Number(num % 58n);
|
|
35
|
-
encoded = BASE58_ALPHABET[remainder] + encoded;
|
|
36
|
-
num = num / 58n;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Add leading '1's for leading zero bytes
|
|
40
|
-
for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
|
|
41
|
-
encoded = '1' + encoded;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Add 'z' prefix for base58btc multibase
|
|
45
|
-
return 'z' + encoded;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
18
|
export interface RSAPublicKeyData {
|
|
49
19
|
rsaPublicKey: string;
|
|
50
20
|
rsaPrivateKey: string;
|
|
@@ -56,6 +26,61 @@ export interface DIDKeyData {
|
|
|
56
26
|
mnemonic: string;
|
|
57
27
|
}
|
|
58
28
|
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Cross-platform encoding utilities (Browser + Node.js compatible)
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Convert base64 string to Uint8Array (cross-platform)
|
|
35
|
+
* Works in both browser and Node.js environments
|
|
36
|
+
* @param base64 base64 encoded string
|
|
37
|
+
* @returns Uint8Array
|
|
38
|
+
*/
|
|
39
|
+
export function base64ToUint8Array(base64: string): Uint8Array {
|
|
40
|
+
const binaryString = atob(base64);
|
|
41
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
42
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
43
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
44
|
+
}
|
|
45
|
+
return bytes;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Convert Uint8Array to hex string (cross-platform)
|
|
50
|
+
* @param bytes Uint8Array to convert
|
|
51
|
+
* @returns hex string without '0x' prefix
|
|
52
|
+
*/
|
|
53
|
+
export function uint8ArrayToHex(bytes: Uint8Array): string {
|
|
54
|
+
return Array.from(bytes)
|
|
55
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
56
|
+
.join('');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Convert hex string to Uint8Array (cross-platform)
|
|
61
|
+
* @param hex hex string (with or without '0x' prefix)
|
|
62
|
+
* @returns Uint8Array
|
|
63
|
+
*/
|
|
64
|
+
export function hexToUint8Array(hex: string): Uint8Array {
|
|
65
|
+
const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
66
|
+
const bytes = new Uint8Array(cleanHex.length / 2);
|
|
67
|
+
for (let i = 0; i < cleanHex.length; i += 2) {
|
|
68
|
+
bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
|
|
69
|
+
}
|
|
70
|
+
return bytes;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Convert Uint8Array to base64 string (cross-platform)
|
|
75
|
+
* Works in both browser and Node.js environments
|
|
76
|
+
* @param bytes Uint8Array to convert
|
|
77
|
+
* @returns base64 encoded string
|
|
78
|
+
*/
|
|
79
|
+
export function uint8ArrayToBase64(bytes: Uint8Array): string {
|
|
80
|
+
const binaryString = String.fromCharCode(...bytes);
|
|
81
|
+
return btoa(binaryString);
|
|
82
|
+
}
|
|
83
|
+
|
|
59
84
|
// ============================================================================
|
|
60
85
|
// Trust Wallet Core Management
|
|
61
86
|
// ============================================================================
|
|
@@ -82,19 +107,9 @@ async function loadWalletCore(): Promise<any> {
|
|
|
82
107
|
// Start loading
|
|
83
108
|
loadingPromise = (async () => {
|
|
84
109
|
try {
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
typeof require === 'undefined'
|
|
89
|
-
) {
|
|
90
|
-
// Browser environment with ES modules
|
|
91
|
-
const { initWasm } = await import('@trustwallet/wallet-core');
|
|
92
|
-
walletCore = await initWasm();
|
|
93
|
-
} else {
|
|
94
|
-
// Node.js environment
|
|
95
|
-
const { initWasm } = require('@trustwallet/wallet-core');
|
|
96
|
-
walletCore = await initWasm();
|
|
97
|
-
}
|
|
110
|
+
// Dynamic import works in both Node.js ESM and browser ESM
|
|
111
|
+
const { initWasm } = await import('@trustwallet/wallet-core');
|
|
112
|
+
walletCore = await initWasm();
|
|
98
113
|
|
|
99
114
|
walletCoreLoaded = true;
|
|
100
115
|
return walletCore;
|
|
@@ -114,23 +129,38 @@ async function loadWalletCore(): Promise<any> {
|
|
|
114
129
|
// multicodec code for Ed25519 keys (0xed)
|
|
115
130
|
const ED25519_CODEC_ID = varint.encode(parseInt('0xed', 16));
|
|
116
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Simple mnemonic validation (checks word count)
|
|
134
|
+
* @param mnemonic BIP39 mnemonic phrase
|
|
135
|
+
* @returns true if mnemonic has valid word count (12, 15, 18, 21, or 24 words)
|
|
136
|
+
*/
|
|
137
|
+
function validateMnemonic(mnemonic: string): boolean {
|
|
138
|
+
const words = mnemonic.trim().split(/\s+/);
|
|
139
|
+
const validWordCounts = [12, 15, 18, 21, 24];
|
|
140
|
+
return validWordCounts.includes(words.length);
|
|
141
|
+
}
|
|
142
|
+
|
|
117
143
|
// ============================================================================
|
|
118
144
|
// Mnemonic and Key Derivation Functions
|
|
119
145
|
// ============================================================================
|
|
120
146
|
|
|
121
147
|
/**
|
|
122
|
-
* Generate a random BIP39 mnemonic phrase
|
|
148
|
+
* Generate a random BIP39 mnemonic phrase using Trust Wallet Core
|
|
149
|
+
* Works in both Node.js and browser environments
|
|
150
|
+
*
|
|
123
151
|
* @param wordCount Number of words (12, 15, 18, 21, or 24), default is 12
|
|
124
|
-
* @returns A mnemonic phrase string
|
|
152
|
+
* @returns A promise that resolves to a mnemonic phrase string
|
|
125
153
|
*
|
|
126
154
|
* @example
|
|
127
155
|
* ```typescript
|
|
128
|
-
* const mnemonic = generateMnemonic(12);
|
|
156
|
+
* const mnemonic = await generateMnemonic(12);
|
|
129
157
|
* console.log(mnemonic);
|
|
130
158
|
* // Output: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
|
131
159
|
* ```
|
|
132
160
|
*/
|
|
133
|
-
export function generateMnemonic(
|
|
161
|
+
export async function generateMnemonic(
|
|
162
|
+
wordCount: number = 12
|
|
163
|
+
): Promise<string> {
|
|
134
164
|
// Convert word count to entropy bits
|
|
135
165
|
// 12 words = 128 bits, 15 words = 160 bits, etc.
|
|
136
166
|
const strengthMap: Record<number, number> = {
|
|
@@ -148,7 +178,14 @@ export function generateMnemonic(wordCount: number = 12): string {
|
|
|
148
178
|
);
|
|
149
179
|
}
|
|
150
180
|
|
|
151
|
-
|
|
181
|
+
// Ensure Wallet Core is loaded
|
|
182
|
+
const core = await loadWalletCore();
|
|
183
|
+
const { HDWallet } = core;
|
|
184
|
+
|
|
185
|
+
const wallet = HDWallet.create(strength, '');
|
|
186
|
+
const mnemonic = wallet.mnemonic();
|
|
187
|
+
|
|
188
|
+
return mnemonic;
|
|
152
189
|
}
|
|
153
190
|
|
|
154
191
|
/**
|
|
@@ -168,8 +205,10 @@ export async function getEthereumAddressFromMnemonic(
|
|
|
168
205
|
mnemonic: string
|
|
169
206
|
): Promise<string> {
|
|
170
207
|
// Validate mnemonic
|
|
171
|
-
if (!
|
|
172
|
-
throw new Error(
|
|
208
|
+
if (!validateMnemonic(mnemonic)) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
'Invalid mnemonic phrase: must have 12, 15, 18, 21, or 24 words'
|
|
211
|
+
);
|
|
173
212
|
}
|
|
174
213
|
|
|
175
214
|
const core = await loadWalletCore();
|
|
@@ -197,8 +236,10 @@ export async function getEVMPrivateKeyFromMnemonic(
|
|
|
197
236
|
mnemonic: string
|
|
198
237
|
): Promise<string> {
|
|
199
238
|
// Validate mnemonic
|
|
200
|
-
if (!
|
|
201
|
-
throw new Error(
|
|
239
|
+
if (!validateMnemonic(mnemonic)) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
'Invalid mnemonic phrase: must have 12, 15, 18, 21, or 24 words'
|
|
242
|
+
);
|
|
202
243
|
}
|
|
203
244
|
|
|
204
245
|
const core = await loadWalletCore();
|
|
@@ -209,9 +250,9 @@ export async function getEVMPrivateKeyFromMnemonic(
|
|
|
209
250
|
// Get private key for Ethereum
|
|
210
251
|
const privateKeyData = wallet.getKeyForCoin(CoinType.ethereum);
|
|
211
252
|
|
|
212
|
-
// Convert to hex string with 0x prefix
|
|
213
|
-
const
|
|
214
|
-
|
|
253
|
+
// Convert to hex string with 0x prefix (cross-platform)
|
|
254
|
+
const privateKeyBytes = new Uint8Array(privateKeyData.data());
|
|
255
|
+
const privateKeyHex = '0x' + uint8ArrayToHex(privateKeyBytes);
|
|
215
256
|
|
|
216
257
|
return privateKeyHex;
|
|
217
258
|
}
|
|
@@ -239,7 +280,7 @@ async function getID(mnemonic: string): Promise<string> {
|
|
|
239
280
|
idBytes.set(publicKey.data(), ED25519_CODEC_ID.length);
|
|
240
281
|
|
|
241
282
|
// Encode to base58btc
|
|
242
|
-
const id =
|
|
283
|
+
const id = base58btc.encode(idBytes);
|
|
243
284
|
return id;
|
|
244
285
|
}
|
|
245
286
|
|
|
@@ -260,14 +301,105 @@ async function getID(mnemonic: string): Promise<string> {
|
|
|
260
301
|
*/
|
|
261
302
|
export async function getDIDFromMnemonic(mnemonic: string): Promise<string> {
|
|
262
303
|
// Validate mnemonic
|
|
263
|
-
if (!
|
|
264
|
-
throw new Error(
|
|
304
|
+
if (!validateMnemonic(mnemonic)) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
'Invalid mnemonic phrase: must have 12, 15, 18, 21, or 24 words'
|
|
307
|
+
);
|
|
265
308
|
}
|
|
266
309
|
|
|
267
310
|
const id = await getID(mnemonic);
|
|
268
311
|
return `did:key:${id}`;
|
|
269
312
|
}
|
|
270
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Generate Ed25519 JWK (JSON Web Key) from BIP39 mnemonic phrase
|
|
316
|
+
* Uses Trust Wallet Core for key derivation, ensuring compatibility with TermiPass
|
|
317
|
+
*
|
|
318
|
+
* @param mnemonic BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
|
|
319
|
+
* @returns Object containing publicJwk and privateJwk in RFC 7517 format
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```typescript
|
|
323
|
+
* const { publicJwk, privateJwk } = await getEd25519JwkFromMnemonic(mnemonic);
|
|
324
|
+
*
|
|
325
|
+
* // Public JWK (safe to share)
|
|
326
|
+
* console.log(publicJwk);
|
|
327
|
+
* // {
|
|
328
|
+
* // "kty": "OKP",
|
|
329
|
+
* // "crv": "Ed25519",
|
|
330
|
+
* // "alg": "EdDSA",
|
|
331
|
+
* // "use": "sig",
|
|
332
|
+
* // "kid": "did:key:z6Mk...#z6Mk...",
|
|
333
|
+
* // "x": "base64url-encoded-public-key"
|
|
334
|
+
* // }
|
|
335
|
+
*
|
|
336
|
+
* // Private JWK (keep secure!)
|
|
337
|
+
* console.log(privateJwk);
|
|
338
|
+
* // {
|
|
339
|
+
* // "kty": "OKP",
|
|
340
|
+
* // "crv": "Ed25519",
|
|
341
|
+
* // "alg": "EdDSA",
|
|
342
|
+
* // "use": "sig",
|
|
343
|
+
* // "kid": "did:key:z6Mk...#z6Mk...",
|
|
344
|
+
* // "x": "base64url-encoded-public-key",
|
|
345
|
+
* // "d": "base64url-encoded-private-key"
|
|
346
|
+
* // }
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
export async function getEd25519JwkFromMnemonic(mnemonic: string): Promise<{
|
|
350
|
+
publicJwk: any;
|
|
351
|
+
privateJwk: any;
|
|
352
|
+
}> {
|
|
353
|
+
// Validate mnemonic
|
|
354
|
+
if (!validateMnemonic(mnemonic)) {
|
|
355
|
+
throw new Error(
|
|
356
|
+
'Invalid mnemonic phrase: must have 12, 15, 18, 21, or 24 words'
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const core = await loadWalletCore();
|
|
361
|
+
const { HDWallet, Curve } = core;
|
|
362
|
+
|
|
363
|
+
const wallet = HDWallet.createWithMnemonic(mnemonic, '');
|
|
364
|
+
const privateKey = wallet.getMasterKey(Curve.ed25519);
|
|
365
|
+
const publicKey = privateKey.getPublicKeyEd25519();
|
|
366
|
+
|
|
367
|
+
// Get key data
|
|
368
|
+
const publicKeyBytes = publicKey.data();
|
|
369
|
+
const privateKeyBytes = privateKey.data();
|
|
370
|
+
|
|
371
|
+
const idBytes = new Uint8Array(
|
|
372
|
+
publicKeyBytes.length + ED25519_CODEC_ID.length
|
|
373
|
+
);
|
|
374
|
+
idBytes.set(ED25519_CODEC_ID, 0);
|
|
375
|
+
idBytes.set(publicKeyBytes, ED25519_CODEC_ID.length);
|
|
376
|
+
const id = base58btc.encode(idBytes);
|
|
377
|
+
const did = `did:key:${id}`;
|
|
378
|
+
const keyId = `${did}#${id}`;
|
|
379
|
+
|
|
380
|
+
// Base64url encode the keys
|
|
381
|
+
const x = base64url.baseEncode(publicKeyBytes);
|
|
382
|
+
const d = base64url.baseEncode(privateKeyBytes);
|
|
383
|
+
|
|
384
|
+
// Public JWK (contains only public key material)
|
|
385
|
+
const publicJwk = {
|
|
386
|
+
kty: 'OKP', // Key Type: Octet Key Pair
|
|
387
|
+
crv: 'Ed25519', // Curve: Ed25519
|
|
388
|
+
alg: 'EdDSA', // Algorithm: EdDSA
|
|
389
|
+
use: 'sig', // Use: signature
|
|
390
|
+
kid: keyId, // Key ID
|
|
391
|
+
x: x // Public key parameter
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// Private JWK (contains both public and private key material)
|
|
395
|
+
const privateJwk = {
|
|
396
|
+
...publicJwk,
|
|
397
|
+
d: d // Private key parameter
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
return { publicJwk, privateJwk };
|
|
401
|
+
}
|
|
402
|
+
|
|
271
403
|
/**
|
|
272
404
|
* Derive both owner (Ethereum address) and DID from existing mnemonic
|
|
273
405
|
*
|
|
@@ -286,8 +418,10 @@ export async function deriveDIDFromMnemonic(mnemonic: string): Promise<{
|
|
|
286
418
|
did: string;
|
|
287
419
|
}> {
|
|
288
420
|
// Validate mnemonic once upfront
|
|
289
|
-
if (!
|
|
290
|
-
throw new Error(
|
|
421
|
+
if (!validateMnemonic(mnemonic)) {
|
|
422
|
+
throw new Error(
|
|
423
|
+
'Invalid mnemonic phrase: must have 12, 15, 18, 21, or 24 words'
|
|
424
|
+
);
|
|
291
425
|
}
|
|
292
426
|
|
|
293
427
|
// Derive both in parallel for better performance
|
|
@@ -316,7 +450,7 @@ export async function deriveDIDFromMnemonic(mnemonic: string): Promise<{
|
|
|
316
450
|
export async function generateDIDKeyData(
|
|
317
451
|
wordCount: number = 12
|
|
318
452
|
): Promise<DIDKeyData> {
|
|
319
|
-
const mnemonic = generateMnemonic(wordCount);
|
|
453
|
+
const mnemonic = await generateMnemonic(wordCount);
|
|
320
454
|
const { owner, did } = await deriveDIDFromMnemonic(mnemonic);
|
|
321
455
|
|
|
322
456
|
return {
|