hd-wallet-wasm 0.1.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/README.md +275 -0
- package/dist/hd-wallet.js +0 -0
- package/dist/hd-wallet.wasm +0 -0
- package/dist/index.d.ts +609 -0
- package/package.json +76 -0
- package/src/index.d.ts +609 -0
- package/src/index.mjs +2479 -0
package/src/index.mjs
ADDED
|
@@ -0,0 +1,2479 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HD Wallet WASM - JavaScript ES6 Wrapper
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive HD wallet implementation with:
|
|
5
|
+
* - BIP-32/39/44/49/84 support
|
|
6
|
+
* - Multi-curve cryptography (secp256k1, Ed25519, P-256, P-384, X25519)
|
|
7
|
+
* - Multi-chain support (Bitcoin, Ethereum, Solana, Cosmos, Polkadot)
|
|
8
|
+
* - Hardware wallet abstraction (requires bridge)
|
|
9
|
+
* - Transaction building and signing
|
|
10
|
+
*
|
|
11
|
+
* @module hd-wallet-wasm
|
|
12
|
+
* @version 0.1.0
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Enums (matching TypeScript definitions)
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Elliptic curve types
|
|
21
|
+
* @readonly
|
|
22
|
+
* @enum {number}
|
|
23
|
+
*/
|
|
24
|
+
export const Curve = Object.freeze({
|
|
25
|
+
SECP256K1: 0,
|
|
26
|
+
ED25519: 1,
|
|
27
|
+
P256: 2,
|
|
28
|
+
P384: 3,
|
|
29
|
+
X25519: 4
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* SLIP-44 coin types
|
|
34
|
+
* @readonly
|
|
35
|
+
* @enum {number}
|
|
36
|
+
*/
|
|
37
|
+
export const CoinType = Object.freeze({
|
|
38
|
+
BITCOIN: 0,
|
|
39
|
+
BITCOIN_TESTNET: 1,
|
|
40
|
+
LITECOIN: 2,
|
|
41
|
+
DOGECOIN: 3,
|
|
42
|
+
ETHEREUM: 60,
|
|
43
|
+
ETHEREUM_CLASSIC: 61,
|
|
44
|
+
COSMOS: 118,
|
|
45
|
+
STELLAR: 148,
|
|
46
|
+
BITCOIN_CASH: 145,
|
|
47
|
+
POLKADOT: 354,
|
|
48
|
+
KUSAMA: 434,
|
|
49
|
+
SOLANA: 501,
|
|
50
|
+
BINANCE: 714,
|
|
51
|
+
CARDANO: 1815
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* BIP-39 wordlist languages
|
|
56
|
+
* @readonly
|
|
57
|
+
* @enum {number}
|
|
58
|
+
*/
|
|
59
|
+
export const Language = Object.freeze({
|
|
60
|
+
ENGLISH: 0,
|
|
61
|
+
JAPANESE: 1,
|
|
62
|
+
KOREAN: 2,
|
|
63
|
+
SPANISH: 3,
|
|
64
|
+
CHINESE_SIMPLIFIED: 4,
|
|
65
|
+
CHINESE_TRADITIONAL: 5,
|
|
66
|
+
FRENCH: 6,
|
|
67
|
+
ITALIAN: 7,
|
|
68
|
+
CZECH: 8,
|
|
69
|
+
PORTUGUESE: 9
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* WASI feature flags
|
|
74
|
+
* @readonly
|
|
75
|
+
* @enum {number}
|
|
76
|
+
*/
|
|
77
|
+
export const WasiFeature = Object.freeze({
|
|
78
|
+
RANDOM: 0,
|
|
79
|
+
FILESYSTEM: 1,
|
|
80
|
+
NETWORK: 2,
|
|
81
|
+
USB_HID: 3,
|
|
82
|
+
CLOCK: 4,
|
|
83
|
+
ENVIRONMENT: 5
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* WASI warning codes
|
|
88
|
+
* @readonly
|
|
89
|
+
* @enum {number}
|
|
90
|
+
*/
|
|
91
|
+
export const WasiWarning = Object.freeze({
|
|
92
|
+
NONE: 0,
|
|
93
|
+
NEEDS_ENTROPY: 1,
|
|
94
|
+
NEEDS_BRIDGE: 2,
|
|
95
|
+
NOT_AVAILABLE_WASI: 3,
|
|
96
|
+
DISABLED_FIPS: 4,
|
|
97
|
+
NEEDS_CAPABILITY: 5
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Entropy status
|
|
102
|
+
* @readonly
|
|
103
|
+
* @enum {number}
|
|
104
|
+
*/
|
|
105
|
+
export const EntropyStatus = Object.freeze({
|
|
106
|
+
NOT_INITIALIZED: 0,
|
|
107
|
+
INITIALIZED: 1,
|
|
108
|
+
SUFFICIENT: 2
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Bitcoin address types
|
|
113
|
+
* @readonly
|
|
114
|
+
* @enum {number}
|
|
115
|
+
*/
|
|
116
|
+
export const BitcoinAddressType = Object.freeze({
|
|
117
|
+
P2PKH: 0,
|
|
118
|
+
P2SH: 1,
|
|
119
|
+
P2WPKH: 2,
|
|
120
|
+
P2WSH: 3,
|
|
121
|
+
P2TR: 4
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Network type
|
|
126
|
+
* @readonly
|
|
127
|
+
* @enum {number}
|
|
128
|
+
*/
|
|
129
|
+
export const Network = Object.freeze({
|
|
130
|
+
MAINNET: 0,
|
|
131
|
+
TESTNET: 1
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// =============================================================================
|
|
135
|
+
// Error handling
|
|
136
|
+
// =============================================================================
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* HD Wallet error codes
|
|
140
|
+
* @readonly
|
|
141
|
+
* @enum {number}
|
|
142
|
+
*/
|
|
143
|
+
const ErrorCode = Object.freeze({
|
|
144
|
+
OK: 0,
|
|
145
|
+
UNKNOWN: 1,
|
|
146
|
+
INVALID_ARGUMENT: 2,
|
|
147
|
+
NOT_SUPPORTED: 3,
|
|
148
|
+
OUT_OF_MEMORY: 4,
|
|
149
|
+
INTERNAL: 5,
|
|
150
|
+
NO_ENTROPY: 100,
|
|
151
|
+
INSUFFICIENT_ENTROPY: 101,
|
|
152
|
+
INVALID_WORD: 200,
|
|
153
|
+
INVALID_CHECKSUM: 201,
|
|
154
|
+
INVALID_MNEMONIC_LENGTH: 202,
|
|
155
|
+
INVALID_ENTROPY_LENGTH: 203,
|
|
156
|
+
INVALID_SEED: 300,
|
|
157
|
+
INVALID_PATH: 301,
|
|
158
|
+
INVALID_CHILD_INDEX: 302,
|
|
159
|
+
HARDENED_FROM_PUBLIC: 303,
|
|
160
|
+
INVALID_EXTENDED_KEY: 304,
|
|
161
|
+
INVALID_PRIVATE_KEY: 400,
|
|
162
|
+
INVALID_PUBLIC_KEY: 401,
|
|
163
|
+
INVALID_SIGNATURE: 402,
|
|
164
|
+
VERIFICATION_FAILED: 403,
|
|
165
|
+
KEY_DERIVATION_FAILED: 404,
|
|
166
|
+
INVALID_TRANSACTION: 500,
|
|
167
|
+
INSUFFICIENT_FUNDS: 501,
|
|
168
|
+
INVALID_ADDRESS: 502,
|
|
169
|
+
DEVICE_NOT_CONNECTED: 600,
|
|
170
|
+
DEVICE_COMM_ERROR: 601,
|
|
171
|
+
USER_CANCELLED: 602,
|
|
172
|
+
DEVICE_BUSY: 603,
|
|
173
|
+
DEVICE_NOT_SUPPORTED: 604,
|
|
174
|
+
BRIDGE_NOT_SET: 700,
|
|
175
|
+
BRIDGE_FAILED: 701,
|
|
176
|
+
NEEDS_BRIDGE: 702,
|
|
177
|
+
FIPS_NOT_ALLOWED: 800
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Error message map
|
|
182
|
+
*/
|
|
183
|
+
const ERROR_MESSAGES = {
|
|
184
|
+
[ErrorCode.OK]: 'Success',
|
|
185
|
+
[ErrorCode.UNKNOWN]: 'Unknown error',
|
|
186
|
+
[ErrorCode.INVALID_ARGUMENT]: 'Invalid argument',
|
|
187
|
+
[ErrorCode.NOT_SUPPORTED]: 'Operation not supported',
|
|
188
|
+
[ErrorCode.OUT_OF_MEMORY]: 'Out of memory',
|
|
189
|
+
[ErrorCode.INTERNAL]: 'Internal error',
|
|
190
|
+
[ErrorCode.NO_ENTROPY]: 'No entropy available - call injectEntropy() first',
|
|
191
|
+
[ErrorCode.INSUFFICIENT_ENTROPY]: 'Insufficient entropy',
|
|
192
|
+
[ErrorCode.INVALID_WORD]: 'Invalid mnemonic word',
|
|
193
|
+
[ErrorCode.INVALID_CHECKSUM]: 'Invalid mnemonic checksum',
|
|
194
|
+
[ErrorCode.INVALID_MNEMONIC_LENGTH]: 'Invalid mnemonic length',
|
|
195
|
+
[ErrorCode.INVALID_ENTROPY_LENGTH]: 'Invalid entropy length',
|
|
196
|
+
[ErrorCode.INVALID_SEED]: 'Invalid seed',
|
|
197
|
+
[ErrorCode.INVALID_PATH]: 'Invalid derivation path',
|
|
198
|
+
[ErrorCode.INVALID_CHILD_INDEX]: 'Invalid child index',
|
|
199
|
+
[ErrorCode.HARDENED_FROM_PUBLIC]: 'Cannot derive hardened child from public key',
|
|
200
|
+
[ErrorCode.INVALID_EXTENDED_KEY]: 'Invalid extended key format',
|
|
201
|
+
[ErrorCode.INVALID_PRIVATE_KEY]: 'Invalid private key',
|
|
202
|
+
[ErrorCode.INVALID_PUBLIC_KEY]: 'Invalid public key',
|
|
203
|
+
[ErrorCode.INVALID_SIGNATURE]: 'Invalid signature',
|
|
204
|
+
[ErrorCode.VERIFICATION_FAILED]: 'Signature verification failed',
|
|
205
|
+
[ErrorCode.KEY_DERIVATION_FAILED]: 'Key derivation failed',
|
|
206
|
+
[ErrorCode.INVALID_TRANSACTION]: 'Invalid transaction',
|
|
207
|
+
[ErrorCode.INSUFFICIENT_FUNDS]: 'Insufficient funds',
|
|
208
|
+
[ErrorCode.INVALID_ADDRESS]: 'Invalid address',
|
|
209
|
+
[ErrorCode.DEVICE_NOT_CONNECTED]: 'Hardware device not connected',
|
|
210
|
+
[ErrorCode.DEVICE_COMM_ERROR]: 'Hardware device communication error',
|
|
211
|
+
[ErrorCode.USER_CANCELLED]: 'Operation cancelled by user',
|
|
212
|
+
[ErrorCode.DEVICE_BUSY]: 'Hardware device busy',
|
|
213
|
+
[ErrorCode.DEVICE_NOT_SUPPORTED]: 'Operation not supported by this device',
|
|
214
|
+
[ErrorCode.BRIDGE_NOT_SET]: 'Bridge callback not set',
|
|
215
|
+
[ErrorCode.BRIDGE_FAILED]: 'Bridge callback failed',
|
|
216
|
+
[ErrorCode.NEEDS_BRIDGE]: 'Feature requires WASI bridge',
|
|
217
|
+
[ErrorCode.FIPS_NOT_ALLOWED]: 'Algorithm not allowed in FIPS mode'
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* HD Wallet Error class
|
|
222
|
+
*/
|
|
223
|
+
class HDWalletError extends Error {
|
|
224
|
+
/**
|
|
225
|
+
* @param {number} code - Error code
|
|
226
|
+
* @param {string} [message] - Optional custom message
|
|
227
|
+
*/
|
|
228
|
+
constructor(code, message) {
|
|
229
|
+
super(message || ERROR_MESSAGES[code] || `Error code: ${code}`);
|
|
230
|
+
this.name = 'HDWalletError';
|
|
231
|
+
this.code = code;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Check result and throw if error
|
|
237
|
+
* @param {number} result - Result code from WASM function
|
|
238
|
+
* @throws {HDWalletError} If result is non-zero
|
|
239
|
+
*/
|
|
240
|
+
function checkResult(result) {
|
|
241
|
+
if (result !== 0) {
|
|
242
|
+
throw new HDWalletError(result);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// =============================================================================
|
|
247
|
+
// Memory Helpers
|
|
248
|
+
// =============================================================================
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Allocate memory and copy data
|
|
252
|
+
* @param {WebAssembly.Module} wasm - WASM module
|
|
253
|
+
* @param {Uint8Array} data - Data to copy
|
|
254
|
+
* @returns {number} Pointer to allocated memory
|
|
255
|
+
*/
|
|
256
|
+
function allocAndCopy(wasm, data) {
|
|
257
|
+
const ptr = wasm._hd_alloc(data.length);
|
|
258
|
+
if (!ptr) throw new HDWalletError(ErrorCode.OUT_OF_MEMORY);
|
|
259
|
+
wasm.HEAPU8.set(data, ptr);
|
|
260
|
+
return ptr;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Allocate memory for string and copy
|
|
265
|
+
* @param {WebAssembly.Module} wasm - WASM module
|
|
266
|
+
* @param {string} str - String to copy
|
|
267
|
+
* @returns {number} Pointer to allocated memory
|
|
268
|
+
*/
|
|
269
|
+
function allocString(wasm, str) {
|
|
270
|
+
const len = wasm.lengthBytesUTF8(str) + 1;
|
|
271
|
+
const ptr = wasm._hd_alloc(len);
|
|
272
|
+
if (!ptr) throw new HDWalletError(ErrorCode.OUT_OF_MEMORY);
|
|
273
|
+
wasm.stringToUTF8(str, ptr, len);
|
|
274
|
+
return ptr;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Read bytes from WASM memory
|
|
279
|
+
* @param {WebAssembly.Module} wasm - WASM module
|
|
280
|
+
* @param {number} ptr - Pointer to memory
|
|
281
|
+
* @param {number} len - Number of bytes to read
|
|
282
|
+
* @returns {Uint8Array} Copy of the data
|
|
283
|
+
*/
|
|
284
|
+
function readBytes(wasm, ptr, len) {
|
|
285
|
+
return new Uint8Array(wasm.HEAPU8.buffer, ptr, len).slice();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Read null-terminated string from WASM memory
|
|
290
|
+
* @param {WebAssembly.Module} wasm - WASM module
|
|
291
|
+
* @param {number} ptr - Pointer to string
|
|
292
|
+
* @returns {string} JavaScript string
|
|
293
|
+
*/
|
|
294
|
+
function readString(wasm, ptr) {
|
|
295
|
+
return wasm.UTF8ToString(ptr);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// =============================================================================
|
|
299
|
+
// HDKey Class
|
|
300
|
+
// =============================================================================
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* BIP-32 HD Key
|
|
304
|
+
* Represents a node in the HD key derivation tree.
|
|
305
|
+
*/
|
|
306
|
+
class HDKey {
|
|
307
|
+
/**
|
|
308
|
+
* @param {WebAssembly.Module} wasm - WASM module
|
|
309
|
+
* @param {number} handle - Native key handle
|
|
310
|
+
* @param {string} [path='m'] - Derivation path
|
|
311
|
+
*/
|
|
312
|
+
constructor(wasm, handle, path = 'm') {
|
|
313
|
+
/** @private */
|
|
314
|
+
this._wasm = wasm;
|
|
315
|
+
/** @private */
|
|
316
|
+
this._handle = handle;
|
|
317
|
+
/** @private */
|
|
318
|
+
this._path = path;
|
|
319
|
+
/** @private */
|
|
320
|
+
this._destroyed = false;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Derivation path
|
|
325
|
+
* @type {string}
|
|
326
|
+
*/
|
|
327
|
+
get path() {
|
|
328
|
+
return this._path;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Key depth in derivation tree
|
|
333
|
+
* @type {number}
|
|
334
|
+
*/
|
|
335
|
+
get depth() {
|
|
336
|
+
this._checkDestroyed();
|
|
337
|
+
return this._wasm._hd_key_get_depth(this._handle);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Parent fingerprint
|
|
342
|
+
* @type {number}
|
|
343
|
+
*/
|
|
344
|
+
get parentFingerprint() {
|
|
345
|
+
this._checkDestroyed();
|
|
346
|
+
return this._wasm._hd_key_get_parent_fingerprint(this._handle);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Child index
|
|
351
|
+
* @type {number}
|
|
352
|
+
*/
|
|
353
|
+
get childIndex() {
|
|
354
|
+
this._checkDestroyed();
|
|
355
|
+
return this._wasm._hd_key_get_child_index(this._handle);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Is this a neutered (public-only) key?
|
|
360
|
+
* @type {boolean}
|
|
361
|
+
*/
|
|
362
|
+
get isNeutered() {
|
|
363
|
+
this._checkDestroyed();
|
|
364
|
+
return this._wasm._hd_key_is_neutered(this._handle) !== 0;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Elliptic curve (currently always secp256k1)
|
|
369
|
+
* @type {number}
|
|
370
|
+
*/
|
|
371
|
+
get curve() {
|
|
372
|
+
return Curve.SECP256K1;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Check if key has been destroyed
|
|
377
|
+
* @private
|
|
378
|
+
*/
|
|
379
|
+
_checkDestroyed() {
|
|
380
|
+
if (this._destroyed) {
|
|
381
|
+
throw new HDWalletError(ErrorCode.INVALID_ARGUMENT, 'Key has been destroyed');
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Get private key bytes
|
|
387
|
+
* @returns {Uint8Array} 32-byte private key
|
|
388
|
+
* @throws {HDWalletError} If key is neutered
|
|
389
|
+
*/
|
|
390
|
+
privateKey() {
|
|
391
|
+
this._checkDestroyed();
|
|
392
|
+
const ptr = this._wasm._hd_alloc(32);
|
|
393
|
+
try {
|
|
394
|
+
const result = this._wasm._hd_key_get_private(this._handle, ptr, 32);
|
|
395
|
+
checkResult(result);
|
|
396
|
+
return readBytes(this._wasm, ptr, 32);
|
|
397
|
+
} finally {
|
|
398
|
+
this._wasm._hd_dealloc(ptr);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Get compressed public key bytes
|
|
404
|
+
* @returns {Uint8Array} 33-byte compressed public key
|
|
405
|
+
*/
|
|
406
|
+
publicKey() {
|
|
407
|
+
this._checkDestroyed();
|
|
408
|
+
const ptr = this._wasm._hd_alloc(33);
|
|
409
|
+
try {
|
|
410
|
+
const result = this._wasm._hd_key_get_public(this._handle, ptr, 33);
|
|
411
|
+
checkResult(result);
|
|
412
|
+
return readBytes(this._wasm, ptr, 33);
|
|
413
|
+
} finally {
|
|
414
|
+
this._wasm._hd_dealloc(ptr);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Get uncompressed public key bytes
|
|
420
|
+
* @returns {Uint8Array} 65-byte uncompressed public key
|
|
421
|
+
*/
|
|
422
|
+
publicKeyUncompressed() {
|
|
423
|
+
this._checkDestroyed();
|
|
424
|
+
const compressed = this.publicKey();
|
|
425
|
+
const inPtr = allocAndCopy(this._wasm, compressed);
|
|
426
|
+
const outPtr = this._wasm._hd_alloc(65);
|
|
427
|
+
try {
|
|
428
|
+
const result = this._wasm._hd_curve_decompress_pubkey(inPtr, Curve.SECP256K1, outPtr, 65);
|
|
429
|
+
checkResult(result);
|
|
430
|
+
return readBytes(this._wasm, outPtr, 65);
|
|
431
|
+
} finally {
|
|
432
|
+
this._wasm._hd_dealloc(inPtr);
|
|
433
|
+
this._wasm._hd_dealloc(outPtr);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Get chain code bytes
|
|
439
|
+
* @returns {Uint8Array} 32-byte chain code
|
|
440
|
+
*/
|
|
441
|
+
chainCode() {
|
|
442
|
+
this._checkDestroyed();
|
|
443
|
+
const ptr = this._wasm._hd_alloc(32);
|
|
444
|
+
try {
|
|
445
|
+
const result = this._wasm._hd_key_get_chain_code(this._handle, ptr, 32);
|
|
446
|
+
checkResult(result);
|
|
447
|
+
return readBytes(this._wasm, ptr, 32);
|
|
448
|
+
} finally {
|
|
449
|
+
this._wasm._hd_dealloc(ptr);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Get key fingerprint
|
|
455
|
+
* @returns {number} Fingerprint (first 4 bytes of HASH160 of public key)
|
|
456
|
+
*/
|
|
457
|
+
fingerprint() {
|
|
458
|
+
this._checkDestroyed();
|
|
459
|
+
return this._wasm._hd_key_get_fingerprint(this._handle);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Derive child key at index
|
|
464
|
+
* @param {number} index - Child index
|
|
465
|
+
* @returns {HDKey} Derived child key
|
|
466
|
+
*/
|
|
467
|
+
deriveChild(index) {
|
|
468
|
+
this._checkDestroyed();
|
|
469
|
+
const childHandle = this._wasm._hd_key_derive_child(this._handle, index);
|
|
470
|
+
if (!childHandle) {
|
|
471
|
+
throw new HDWalletError(ErrorCode.KEY_DERIVATION_FAILED);
|
|
472
|
+
}
|
|
473
|
+
const childPath = `${this._path}/${index}`;
|
|
474
|
+
return new HDKey(this._wasm, childHandle, childPath);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Derive hardened child key
|
|
479
|
+
* @param {number} index - Child index (will be hardened)
|
|
480
|
+
* @returns {HDKey} Derived child key
|
|
481
|
+
*/
|
|
482
|
+
deriveHardened(index) {
|
|
483
|
+
this._checkDestroyed();
|
|
484
|
+
const childHandle = this._wasm._hd_key_derive_hardened(this._handle, index);
|
|
485
|
+
if (!childHandle) {
|
|
486
|
+
throw new HDWalletError(ErrorCode.KEY_DERIVATION_FAILED);
|
|
487
|
+
}
|
|
488
|
+
const childPath = `${this._path}/${index}'`;
|
|
489
|
+
return new HDKey(this._wasm, childHandle, childPath);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Derive key at path
|
|
494
|
+
* @param {string} path - Derivation path (e.g., "m/44'/60'/0'/0/0")
|
|
495
|
+
* @returns {HDKey} Derived key
|
|
496
|
+
*/
|
|
497
|
+
derivePath(path) {
|
|
498
|
+
this._checkDestroyed();
|
|
499
|
+
const pathPtr = allocString(this._wasm, path);
|
|
500
|
+
try {
|
|
501
|
+
const childHandle = this._wasm._hd_key_derive_path(this._handle, pathPtr);
|
|
502
|
+
if (!childHandle) {
|
|
503
|
+
throw new HDWalletError(ErrorCode.INVALID_PATH);
|
|
504
|
+
}
|
|
505
|
+
// Compute resulting path
|
|
506
|
+
let resultPath = path;
|
|
507
|
+
if (path.startsWith('m/') || path === 'm') {
|
|
508
|
+
resultPath = path;
|
|
509
|
+
} else if (path.startsWith('/')) {
|
|
510
|
+
resultPath = this._path + path;
|
|
511
|
+
} else {
|
|
512
|
+
resultPath = this._path + '/' + path;
|
|
513
|
+
}
|
|
514
|
+
return new HDKey(this._wasm, childHandle, resultPath);
|
|
515
|
+
} finally {
|
|
516
|
+
this._wasm._hd_dealloc(pathPtr);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Get neutered (public-only) version
|
|
522
|
+
* @returns {HDKey} Neutered key
|
|
523
|
+
*/
|
|
524
|
+
neutered() {
|
|
525
|
+
this._checkDestroyed();
|
|
526
|
+
const neuteredHandle = this._wasm._hd_key_neutered(this._handle);
|
|
527
|
+
if (!neuteredHandle) {
|
|
528
|
+
throw new HDWalletError(ErrorCode.INTERNAL);
|
|
529
|
+
}
|
|
530
|
+
return new HDKey(this._wasm, neuteredHandle, this._path);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Serialize as extended private key (xprv)
|
|
535
|
+
* @returns {string} Base58Check-encoded xprv
|
|
536
|
+
* @throws {HDWalletError} If key is neutered
|
|
537
|
+
*/
|
|
538
|
+
toXprv() {
|
|
539
|
+
this._checkDestroyed();
|
|
540
|
+
const ptr = this._wasm._hd_alloc(128);
|
|
541
|
+
try {
|
|
542
|
+
const result = this._wasm._hd_key_serialize_xprv(this._handle, ptr, 128);
|
|
543
|
+
checkResult(result);
|
|
544
|
+
return readString(this._wasm, ptr);
|
|
545
|
+
} finally {
|
|
546
|
+
this._wasm._hd_dealloc(ptr);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Serialize as extended public key (xpub)
|
|
552
|
+
* @returns {string} Base58Check-encoded xpub
|
|
553
|
+
*/
|
|
554
|
+
toXpub() {
|
|
555
|
+
this._checkDestroyed();
|
|
556
|
+
const ptr = this._wasm._hd_alloc(128);
|
|
557
|
+
try {
|
|
558
|
+
const result = this._wasm._hd_key_serialize_xpub(this._handle, ptr, 128);
|
|
559
|
+
checkResult(result);
|
|
560
|
+
return readString(this._wasm, ptr);
|
|
561
|
+
} finally {
|
|
562
|
+
this._wasm._hd_dealloc(ptr);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Securely wipe key from memory
|
|
568
|
+
*/
|
|
569
|
+
wipe() {
|
|
570
|
+
if (!this._destroyed && this._handle) {
|
|
571
|
+
this._wasm._hd_key_wipe(this._handle);
|
|
572
|
+
this._wasm._hd_key_destroy(this._handle);
|
|
573
|
+
this._handle = null;
|
|
574
|
+
this._destroyed = true;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Clone key
|
|
580
|
+
* @returns {HDKey} Independent copy
|
|
581
|
+
*/
|
|
582
|
+
clone() {
|
|
583
|
+
this._checkDestroyed();
|
|
584
|
+
const clonedHandle = this._wasm._hd_key_clone(this._handle);
|
|
585
|
+
if (!clonedHandle) {
|
|
586
|
+
throw new HDWalletError(ErrorCode.OUT_OF_MEMORY);
|
|
587
|
+
}
|
|
588
|
+
return new HDKey(this._wasm, clonedHandle, this._path);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// =============================================================================
|
|
593
|
+
// Module Initialization
|
|
594
|
+
// =============================================================================
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* WASM module loader URL resolver
|
|
598
|
+
* @param {string} [wasmPath] - Optional path to WASM file
|
|
599
|
+
* @returns {Promise<Function>} WASM module factory
|
|
600
|
+
*/
|
|
601
|
+
async function loadWasmModule(wasmPath) {
|
|
602
|
+
// Try to import the Emscripten-generated module
|
|
603
|
+
let HDWalletWasm;
|
|
604
|
+
|
|
605
|
+
try {
|
|
606
|
+
// Try dynamic import (works in Node.js and bundlers)
|
|
607
|
+
const module = await import('./hd-wallet.js');
|
|
608
|
+
HDWalletWasm = module.default;
|
|
609
|
+
} catch (e) {
|
|
610
|
+
// Fallback for browsers without ES module support
|
|
611
|
+
if (typeof window !== 'undefined' && window.HDWalletWasm) {
|
|
612
|
+
HDWalletWasm = window.HDWalletWasm;
|
|
613
|
+
} else {
|
|
614
|
+
throw new Error(
|
|
615
|
+
'Failed to load HD Wallet WASM module. ' +
|
|
616
|
+
'Make sure hd-wallet.js is accessible or set it on window.HDWalletWasm'
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Initialize the WASM module
|
|
622
|
+
const wasmOptions = {};
|
|
623
|
+
if (wasmPath) {
|
|
624
|
+
wasmOptions.locateFile = (path) => {
|
|
625
|
+
if (path.endsWith('.wasm')) {
|
|
626
|
+
return wasmPath;
|
|
627
|
+
}
|
|
628
|
+
return path;
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return HDWalletWasm(wasmOptions);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Create the HD Wallet module instance
|
|
637
|
+
* @param {Object} wasm - Initialized WASM module
|
|
638
|
+
* @returns {Object} HDWalletModule API
|
|
639
|
+
*/
|
|
640
|
+
function createModule(wasm) {
|
|
641
|
+
// ==========================================================================
|
|
642
|
+
// Mnemonic API
|
|
643
|
+
// ==========================================================================
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* BIP-39 Mnemonic API
|
|
647
|
+
* @type {Object}
|
|
648
|
+
*/
|
|
649
|
+
const mnemonic = {
|
|
650
|
+
/**
|
|
651
|
+
* Generate a random mnemonic phrase
|
|
652
|
+
* @param {number} [wordCount=24] - Number of words (12, 15, 18, 21, or 24)
|
|
653
|
+
* @param {number} [language=Language.ENGLISH] - Wordlist language
|
|
654
|
+
* @returns {string} Mnemonic phrase
|
|
655
|
+
* @throws {HDWalletError} If entropy not available
|
|
656
|
+
*/
|
|
657
|
+
generate(wordCount = 24, language = Language.ENGLISH) {
|
|
658
|
+
const ptr = wasm._hd_alloc(1024);
|
|
659
|
+
try {
|
|
660
|
+
const result = wasm._hd_mnemonic_generate(ptr, 1024, wordCount, language);
|
|
661
|
+
checkResult(result);
|
|
662
|
+
return readString(wasm, ptr);
|
|
663
|
+
} finally {
|
|
664
|
+
wasm._hd_dealloc(ptr);
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Validate a mnemonic phrase
|
|
670
|
+
* @param {string} mnemonicStr - Mnemonic phrase to validate
|
|
671
|
+
* @param {number} [language=Language.ENGLISH] - Wordlist language
|
|
672
|
+
* @returns {boolean} True if valid
|
|
673
|
+
*/
|
|
674
|
+
validate(mnemonicStr, language = Language.ENGLISH) {
|
|
675
|
+
const ptr = allocString(wasm, mnemonicStr);
|
|
676
|
+
try {
|
|
677
|
+
const result = wasm._hd_mnemonic_validate(ptr, language);
|
|
678
|
+
return result === 0;
|
|
679
|
+
} finally {
|
|
680
|
+
wasm._hd_dealloc(ptr);
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Convert mnemonic to 64-byte seed
|
|
686
|
+
* @param {string} mnemonicStr - Mnemonic phrase
|
|
687
|
+
* @param {string} [passphrase=''] - Optional passphrase
|
|
688
|
+
* @returns {Uint8Array} 64-byte seed
|
|
689
|
+
*/
|
|
690
|
+
toSeed(mnemonicStr, passphrase = '') {
|
|
691
|
+
const mnemonicPtr = allocString(wasm, mnemonicStr);
|
|
692
|
+
const passphrasePtr = allocString(wasm, passphrase);
|
|
693
|
+
const seedPtr = wasm._hd_alloc(64);
|
|
694
|
+
try {
|
|
695
|
+
const result = wasm._hd_mnemonic_to_seed(mnemonicPtr, passphrasePtr, seedPtr, 64);
|
|
696
|
+
checkResult(result);
|
|
697
|
+
return readBytes(wasm, seedPtr, 64);
|
|
698
|
+
} finally {
|
|
699
|
+
wasm._hd_secure_wipe(seedPtr, 64);
|
|
700
|
+
wasm._hd_dealloc(mnemonicPtr);
|
|
701
|
+
wasm._hd_dealloc(passphrasePtr);
|
|
702
|
+
wasm._hd_dealloc(seedPtr);
|
|
703
|
+
}
|
|
704
|
+
},
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Convert mnemonic to entropy bytes
|
|
708
|
+
* @param {string} mnemonicStr - Mnemonic phrase
|
|
709
|
+
* @param {number} [language=Language.ENGLISH] - Wordlist language
|
|
710
|
+
* @returns {Uint8Array} Entropy bytes
|
|
711
|
+
*/
|
|
712
|
+
toEntropy(mnemonicStr, language = Language.ENGLISH) {
|
|
713
|
+
const mnemonicPtr = allocString(wasm, mnemonicStr);
|
|
714
|
+
const entropyPtr = wasm._hd_alloc(33);
|
|
715
|
+
const sizePtr = wasm._hd_alloc(4);
|
|
716
|
+
try {
|
|
717
|
+
wasm.setValue(sizePtr, 33, 'i32');
|
|
718
|
+
const result = wasm._hd_mnemonic_to_entropy(mnemonicPtr, language, entropyPtr, sizePtr);
|
|
719
|
+
checkResult(result);
|
|
720
|
+
const size = wasm.getValue(sizePtr, 'i32');
|
|
721
|
+
return readBytes(wasm, entropyPtr, size);
|
|
722
|
+
} finally {
|
|
723
|
+
wasm._hd_dealloc(mnemonicPtr);
|
|
724
|
+
wasm._hd_dealloc(entropyPtr);
|
|
725
|
+
wasm._hd_dealloc(sizePtr);
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* Convert entropy to mnemonic
|
|
731
|
+
* @param {Uint8Array} entropy - Entropy bytes (16, 20, 24, 28, or 32 bytes)
|
|
732
|
+
* @param {number} [language=Language.ENGLISH] - Wordlist language
|
|
733
|
+
* @returns {string} Mnemonic phrase
|
|
734
|
+
*/
|
|
735
|
+
fromEntropy(entropy, language = Language.ENGLISH) {
|
|
736
|
+
const entropyPtr = allocAndCopy(wasm, entropy);
|
|
737
|
+
const outputPtr = wasm._hd_alloc(1024);
|
|
738
|
+
try {
|
|
739
|
+
const result = wasm._hd_entropy_to_mnemonic(entropyPtr, entropy.length, language, outputPtr, 1024);
|
|
740
|
+
checkResult(result);
|
|
741
|
+
return readString(wasm, outputPtr);
|
|
742
|
+
} finally {
|
|
743
|
+
wasm._hd_dealloc(entropyPtr);
|
|
744
|
+
wasm._hd_dealloc(outputPtr);
|
|
745
|
+
}
|
|
746
|
+
},
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Get wordlist for language
|
|
750
|
+
* @param {number} [language=Language.ENGLISH] - Wordlist language
|
|
751
|
+
* @returns {string[]} Array of 2048 words
|
|
752
|
+
*/
|
|
753
|
+
getWordlist(language = Language.ENGLISH) {
|
|
754
|
+
const ptr = wasm._hd_mnemonic_get_wordlist(language);
|
|
755
|
+
const json = readString(wasm, ptr);
|
|
756
|
+
return JSON.parse(json);
|
|
757
|
+
},
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Get word suggestions for autocomplete
|
|
761
|
+
* @param {string} prefix - Word prefix
|
|
762
|
+
* @param {number} [language=Language.ENGLISH] - Wordlist language
|
|
763
|
+
* @param {number} [maxSuggestions=5] - Maximum suggestions
|
|
764
|
+
* @returns {string[]} Suggested words
|
|
765
|
+
*/
|
|
766
|
+
suggestWords(prefix, language = Language.ENGLISH, maxSuggestions = 5) {
|
|
767
|
+
const prefixPtr = allocString(wasm, prefix);
|
|
768
|
+
const outputPtr = wasm._hd_alloc(1024);
|
|
769
|
+
try {
|
|
770
|
+
wasm._hd_mnemonic_suggest_word(prefixPtr, language, outputPtr, 1024, maxSuggestions);
|
|
771
|
+
const json = readString(wasm, outputPtr);
|
|
772
|
+
return JSON.parse(json);
|
|
773
|
+
} finally {
|
|
774
|
+
wasm._hd_dealloc(prefixPtr);
|
|
775
|
+
wasm._hd_dealloc(outputPtr);
|
|
776
|
+
}
|
|
777
|
+
},
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Check if word is in wordlist
|
|
781
|
+
* @param {string} word - Word to check
|
|
782
|
+
* @param {number} [language=Language.ENGLISH] - Wordlist language
|
|
783
|
+
* @returns {boolean} True if word is in wordlist
|
|
784
|
+
*/
|
|
785
|
+
checkWord(word, language = Language.ENGLISH) {
|
|
786
|
+
const wordPtr = allocString(wasm, word);
|
|
787
|
+
try {
|
|
788
|
+
const result = wasm._hd_mnemonic_check_word(wordPtr, language);
|
|
789
|
+
return result >= 0;
|
|
790
|
+
} finally {
|
|
791
|
+
wasm._hd_dealloc(wordPtr);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
// ==========================================================================
|
|
797
|
+
// HDKey API
|
|
798
|
+
// ==========================================================================
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* BIP-32 HD Key API
|
|
802
|
+
* @type {Object}
|
|
803
|
+
*/
|
|
804
|
+
const hdkey = {
|
|
805
|
+
/**
|
|
806
|
+
* Create master key from seed
|
|
807
|
+
* @param {Uint8Array} seed - 64-byte seed
|
|
808
|
+
* @param {number} [curve=Curve.SECP256K1] - Elliptic curve
|
|
809
|
+
* @returns {HDKey} Master HD key
|
|
810
|
+
*/
|
|
811
|
+
fromSeed(seed, curve = Curve.SECP256K1) {
|
|
812
|
+
if (seed.length !== 64) {
|
|
813
|
+
throw new HDWalletError(ErrorCode.INVALID_SEED, 'Seed must be 64 bytes');
|
|
814
|
+
}
|
|
815
|
+
const seedPtr = allocAndCopy(wasm, seed);
|
|
816
|
+
try {
|
|
817
|
+
const handle = wasm._hd_key_from_seed(seedPtr, 64, curve);
|
|
818
|
+
if (!handle) {
|
|
819
|
+
throw new HDWalletError(ErrorCode.INVALID_SEED);
|
|
820
|
+
}
|
|
821
|
+
return new HDKey(wasm, handle, 'm');
|
|
822
|
+
} finally {
|
|
823
|
+
wasm._hd_secure_wipe(seedPtr, 64);
|
|
824
|
+
wasm._hd_dealloc(seedPtr);
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Parse extended private key
|
|
830
|
+
* @param {string} xprv - Base58Check-encoded xprv
|
|
831
|
+
* @returns {HDKey} HD key
|
|
832
|
+
*/
|
|
833
|
+
fromXprv(xprv) {
|
|
834
|
+
const xprvPtr = allocString(wasm, xprv);
|
|
835
|
+
try {
|
|
836
|
+
const handle = wasm._hd_key_from_xprv(xprvPtr);
|
|
837
|
+
if (!handle) {
|
|
838
|
+
throw new HDWalletError(ErrorCode.INVALID_EXTENDED_KEY);
|
|
839
|
+
}
|
|
840
|
+
return new HDKey(wasm, handle);
|
|
841
|
+
} finally {
|
|
842
|
+
wasm._hd_dealloc(xprvPtr);
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Parse extended public key
|
|
848
|
+
* @param {string} xpub - Base58Check-encoded xpub
|
|
849
|
+
* @returns {HDKey} HD key (neutered)
|
|
850
|
+
*/
|
|
851
|
+
fromXpub(xpub) {
|
|
852
|
+
const xpubPtr = allocString(wasm, xpub);
|
|
853
|
+
try {
|
|
854
|
+
const handle = wasm._hd_key_from_xpub(xpubPtr);
|
|
855
|
+
if (!handle) {
|
|
856
|
+
throw new HDWalletError(ErrorCode.INVALID_EXTENDED_KEY);
|
|
857
|
+
}
|
|
858
|
+
return new HDKey(wasm, handle);
|
|
859
|
+
} finally {
|
|
860
|
+
wasm._hd_dealloc(xpubPtr);
|
|
861
|
+
}
|
|
862
|
+
},
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Build BIP-44 path
|
|
866
|
+
* @param {number} purpose - Purpose (44, 49, 84)
|
|
867
|
+
* @param {number} coinType - SLIP-44 coin type
|
|
868
|
+
* @param {number} [account=0] - Account index
|
|
869
|
+
* @param {number} [change=0] - Change (0=external, 1=internal)
|
|
870
|
+
* @param {number} [index=0] - Address index
|
|
871
|
+
* @returns {string} Derivation path
|
|
872
|
+
*/
|
|
873
|
+
buildPath(purpose, coinType, account = 0, change = 0, index = 0) {
|
|
874
|
+
const ptr = wasm._hd_alloc(128);
|
|
875
|
+
try {
|
|
876
|
+
const result = wasm._hd_path_build(ptr, 128, purpose, coinType, account, change, index);
|
|
877
|
+
checkResult(result);
|
|
878
|
+
return readString(wasm, ptr);
|
|
879
|
+
} finally {
|
|
880
|
+
wasm._hd_dealloc(ptr);
|
|
881
|
+
}
|
|
882
|
+
},
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* Parse BIP-44 path
|
|
886
|
+
* @param {string} path - Derivation path
|
|
887
|
+
* @returns {Object} Parsed path components
|
|
888
|
+
*/
|
|
889
|
+
parsePath(path) {
|
|
890
|
+
const pathPtr = allocString(wasm, path);
|
|
891
|
+
const purposePtr = wasm._hd_alloc(4);
|
|
892
|
+
const coinTypePtr = wasm._hd_alloc(4);
|
|
893
|
+
const accountPtr = wasm._hd_alloc(4);
|
|
894
|
+
const changePtr = wasm._hd_alloc(4);
|
|
895
|
+
const indexPtr = wasm._hd_alloc(4);
|
|
896
|
+
try {
|
|
897
|
+
const result = wasm._hd_path_parse(pathPtr, purposePtr, coinTypePtr, accountPtr, changePtr, indexPtr);
|
|
898
|
+
checkResult(result);
|
|
899
|
+
return {
|
|
900
|
+
purpose: wasm.getValue(purposePtr, 'i32'),
|
|
901
|
+
coinType: wasm.getValue(coinTypePtr, 'i32'),
|
|
902
|
+
account: wasm.getValue(accountPtr, 'i32'),
|
|
903
|
+
change: wasm.getValue(changePtr, 'i32'),
|
|
904
|
+
index: wasm.getValue(indexPtr, 'i32')
|
|
905
|
+
};
|
|
906
|
+
} finally {
|
|
907
|
+
wasm._hd_dealloc(pathPtr);
|
|
908
|
+
wasm._hd_dealloc(purposePtr);
|
|
909
|
+
wasm._hd_dealloc(coinTypePtr);
|
|
910
|
+
wasm._hd_dealloc(accountPtr);
|
|
911
|
+
wasm._hd_dealloc(changePtr);
|
|
912
|
+
wasm._hd_dealloc(indexPtr);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
// ==========================================================================
|
|
918
|
+
// Curves API
|
|
919
|
+
// ==========================================================================
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Multi-curve cryptography API
|
|
923
|
+
* @type {Object}
|
|
924
|
+
*/
|
|
925
|
+
const curves = {
|
|
926
|
+
/**
|
|
927
|
+
* Derive public key from private key
|
|
928
|
+
* @param {Uint8Array} privateKey - Private key bytes
|
|
929
|
+
* @param {number} curve - Curve type
|
|
930
|
+
* @returns {Uint8Array} Compressed public key
|
|
931
|
+
*/
|
|
932
|
+
publicKeyFromPrivate(privateKey, curve) {
|
|
933
|
+
const privPtr = allocAndCopy(wasm, privateKey);
|
|
934
|
+
const pubPtr = wasm._hd_alloc(65);
|
|
935
|
+
try {
|
|
936
|
+
const result = wasm._hd_curve_pubkey_from_privkey(privPtr, curve, pubPtr, 65);
|
|
937
|
+
checkResult(result);
|
|
938
|
+
return readBytes(wasm, pubPtr, 33);
|
|
939
|
+
} finally {
|
|
940
|
+
wasm._hd_secure_wipe(privPtr, privateKey.length);
|
|
941
|
+
wasm._hd_dealloc(privPtr);
|
|
942
|
+
wasm._hd_dealloc(pubPtr);
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* Compress public key
|
|
948
|
+
* @param {Uint8Array} publicKey - Uncompressed public key (65 bytes)
|
|
949
|
+
* @param {number} curve - Curve type
|
|
950
|
+
* @returns {Uint8Array} Compressed public key (33 bytes)
|
|
951
|
+
*/
|
|
952
|
+
compressPublicKey(publicKey, curve) {
|
|
953
|
+
const inPtr = allocAndCopy(wasm, publicKey);
|
|
954
|
+
const outPtr = wasm._hd_alloc(33);
|
|
955
|
+
try {
|
|
956
|
+
const result = wasm._hd_curve_compress_pubkey(inPtr, curve, outPtr, 33);
|
|
957
|
+
checkResult(result);
|
|
958
|
+
return readBytes(wasm, outPtr, 33);
|
|
959
|
+
} finally {
|
|
960
|
+
wasm._hd_dealloc(inPtr);
|
|
961
|
+
wasm._hd_dealloc(outPtr);
|
|
962
|
+
}
|
|
963
|
+
},
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Decompress public key
|
|
967
|
+
* @param {Uint8Array} publicKey - Compressed public key (33 bytes)
|
|
968
|
+
* @param {number} curve - Curve type
|
|
969
|
+
* @returns {Uint8Array} Uncompressed public key (65 bytes)
|
|
970
|
+
*/
|
|
971
|
+
decompressPublicKey(publicKey, curve) {
|
|
972
|
+
const inPtr = allocAndCopy(wasm, publicKey);
|
|
973
|
+
const outPtr = wasm._hd_alloc(65);
|
|
974
|
+
try {
|
|
975
|
+
const result = wasm._hd_curve_decompress_pubkey(inPtr, curve, outPtr, 65);
|
|
976
|
+
checkResult(result);
|
|
977
|
+
return readBytes(wasm, outPtr, 65);
|
|
978
|
+
} finally {
|
|
979
|
+
wasm._hd_dealloc(inPtr);
|
|
980
|
+
wasm._hd_dealloc(outPtr);
|
|
981
|
+
}
|
|
982
|
+
},
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* secp256k1 ECDSA operations
|
|
986
|
+
*/
|
|
987
|
+
secp256k1: {
|
|
988
|
+
/**
|
|
989
|
+
* Sign message with secp256k1
|
|
990
|
+
* @param {Uint8Array} message - Message to sign (typically 32-byte hash)
|
|
991
|
+
* @param {Uint8Array} privateKey - 32-byte private key
|
|
992
|
+
* @returns {Uint8Array} Signature
|
|
993
|
+
*/
|
|
994
|
+
sign(message, privateKey) {
|
|
995
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
996
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
997
|
+
const sigPtr = wasm._hd_alloc(72);
|
|
998
|
+
try {
|
|
999
|
+
const len = wasm._hd_secp256k1_sign(msgPtr, message.length, keyPtr, sigPtr, 72);
|
|
1000
|
+
if (len < 0) throw new HDWalletError(len);
|
|
1001
|
+
return readBytes(wasm, sigPtr, len);
|
|
1002
|
+
} finally {
|
|
1003
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1004
|
+
wasm._hd_dealloc(msgPtr);
|
|
1005
|
+
wasm._hd_dealloc(keyPtr);
|
|
1006
|
+
wasm._hd_dealloc(sigPtr);
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
|
|
1010
|
+
/**
|
|
1011
|
+
* Sign message with recovery ID
|
|
1012
|
+
* @param {Uint8Array} message - Message to sign
|
|
1013
|
+
* @param {Uint8Array} privateKey - Private key
|
|
1014
|
+
* @returns {Object} { signature: Uint8Array, recoveryId: number }
|
|
1015
|
+
*/
|
|
1016
|
+
signRecoverable(message, privateKey) {
|
|
1017
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1018
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1019
|
+
const sigPtr = wasm._hd_alloc(65);
|
|
1020
|
+
try {
|
|
1021
|
+
const recoveryId = wasm._hd_secp256k1_sign_recoverable(msgPtr, message.length, keyPtr, sigPtr, 65);
|
|
1022
|
+
if (recoveryId < 0) throw new HDWalletError(recoveryId);
|
|
1023
|
+
return {
|
|
1024
|
+
signature: readBytes(wasm, sigPtr, 64),
|
|
1025
|
+
recoveryId
|
|
1026
|
+
};
|
|
1027
|
+
} finally {
|
|
1028
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1029
|
+
wasm._hd_dealloc(msgPtr);
|
|
1030
|
+
wasm._hd_dealloc(keyPtr);
|
|
1031
|
+
wasm._hd_dealloc(sigPtr);
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* Verify secp256k1 signature
|
|
1037
|
+
* @param {Uint8Array} message - Original message
|
|
1038
|
+
* @param {Uint8Array} signature - Signature to verify
|
|
1039
|
+
* @param {Uint8Array} publicKey - Public key
|
|
1040
|
+
* @returns {boolean} True if valid
|
|
1041
|
+
*/
|
|
1042
|
+
verify(message, signature, publicKey) {
|
|
1043
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1044
|
+
const sigPtr = allocAndCopy(wasm, signature);
|
|
1045
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1046
|
+
try {
|
|
1047
|
+
const result = wasm._hd_secp256k1_verify(msgPtr, message.length, sigPtr, signature.length, pubPtr, publicKey.length);
|
|
1048
|
+
return result === 1;
|
|
1049
|
+
} finally {
|
|
1050
|
+
wasm._hd_dealloc(msgPtr);
|
|
1051
|
+
wasm._hd_dealloc(sigPtr);
|
|
1052
|
+
wasm._hd_dealloc(pubPtr);
|
|
1053
|
+
}
|
|
1054
|
+
},
|
|
1055
|
+
|
|
1056
|
+
/**
|
|
1057
|
+
* Recover public key from signature
|
|
1058
|
+
* @param {Uint8Array} message - Original message
|
|
1059
|
+
* @param {Uint8Array} signature - Signature
|
|
1060
|
+
* @param {number} recoveryId - Recovery ID (0-3)
|
|
1061
|
+
* @returns {Uint8Array} Recovered public key
|
|
1062
|
+
*/
|
|
1063
|
+
recover(message, signature, recoveryId) {
|
|
1064
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1065
|
+
const sigPtr = allocAndCopy(wasm, signature);
|
|
1066
|
+
const pubPtr = wasm._hd_alloc(65);
|
|
1067
|
+
try {
|
|
1068
|
+
const result = wasm._hd_secp256k1_recover(msgPtr, message.length, sigPtr, signature.length, recoveryId, pubPtr, 65);
|
|
1069
|
+
checkResult(result);
|
|
1070
|
+
return readBytes(wasm, pubPtr, 65);
|
|
1071
|
+
} finally {
|
|
1072
|
+
wasm._hd_dealloc(msgPtr);
|
|
1073
|
+
wasm._hd_dealloc(sigPtr);
|
|
1074
|
+
wasm._hd_dealloc(pubPtr);
|
|
1075
|
+
}
|
|
1076
|
+
},
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* ECDH shared secret
|
|
1080
|
+
* @param {Uint8Array} privateKey - Own private key
|
|
1081
|
+
* @param {Uint8Array} publicKey - Other party's public key
|
|
1082
|
+
* @returns {Uint8Array} Shared secret
|
|
1083
|
+
*/
|
|
1084
|
+
ecdh(privateKey, publicKey) {
|
|
1085
|
+
const privPtr = allocAndCopy(wasm, privateKey);
|
|
1086
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1087
|
+
const secretPtr = wasm._hd_alloc(32);
|
|
1088
|
+
try {
|
|
1089
|
+
const result = wasm._hd_ecdh_secp256k1(privPtr, pubPtr, publicKey.length, secretPtr, 32);
|
|
1090
|
+
if (result < 0) throw new HDWalletError(result);
|
|
1091
|
+
return readBytes(wasm, secretPtr, 32);
|
|
1092
|
+
} finally {
|
|
1093
|
+
wasm._hd_secure_wipe(privPtr, 32);
|
|
1094
|
+
wasm._hd_secure_wipe(secretPtr, 32);
|
|
1095
|
+
wasm._hd_dealloc(privPtr);
|
|
1096
|
+
wasm._hd_dealloc(pubPtr);
|
|
1097
|
+
wasm._hd_dealloc(secretPtr);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
},
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* Ed25519 EdDSA operations
|
|
1104
|
+
*/
|
|
1105
|
+
ed25519: {
|
|
1106
|
+
/**
|
|
1107
|
+
* Sign message with Ed25519
|
|
1108
|
+
* @param {Uint8Array} message - Message to sign
|
|
1109
|
+
* @param {Uint8Array} privateKey - 32-byte private key
|
|
1110
|
+
* @returns {Uint8Array} 64-byte signature
|
|
1111
|
+
*/
|
|
1112
|
+
sign(message, privateKey) {
|
|
1113
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1114
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1115
|
+
const sigPtr = wasm._hd_alloc(64);
|
|
1116
|
+
try {
|
|
1117
|
+
const len = wasm._hd_ed25519_sign(msgPtr, message.length, keyPtr, sigPtr, 64);
|
|
1118
|
+
if (len < 0) throw new HDWalletError(len);
|
|
1119
|
+
return readBytes(wasm, sigPtr, 64);
|
|
1120
|
+
} finally {
|
|
1121
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1122
|
+
wasm._hd_dealloc(msgPtr);
|
|
1123
|
+
wasm._hd_dealloc(keyPtr);
|
|
1124
|
+
wasm._hd_dealloc(sigPtr);
|
|
1125
|
+
}
|
|
1126
|
+
},
|
|
1127
|
+
|
|
1128
|
+
/**
|
|
1129
|
+
* Verify Ed25519 signature
|
|
1130
|
+
* @param {Uint8Array} message - Original message
|
|
1131
|
+
* @param {Uint8Array} signature - 64-byte signature
|
|
1132
|
+
* @param {Uint8Array} publicKey - 32-byte public key
|
|
1133
|
+
* @returns {boolean} True if valid
|
|
1134
|
+
*/
|
|
1135
|
+
verify(message, signature, publicKey) {
|
|
1136
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1137
|
+
const sigPtr = allocAndCopy(wasm, signature);
|
|
1138
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1139
|
+
try {
|
|
1140
|
+
const result = wasm._hd_ed25519_verify(msgPtr, message.length, sigPtr, signature.length, pubPtr, publicKey.length);
|
|
1141
|
+
return result === 1;
|
|
1142
|
+
} finally {
|
|
1143
|
+
wasm._hd_dealloc(msgPtr);
|
|
1144
|
+
wasm._hd_dealloc(sigPtr);
|
|
1145
|
+
wasm._hd_dealloc(pubPtr);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
},
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* P-256 (secp256r1) ECDSA operations
|
|
1152
|
+
*/
|
|
1153
|
+
p256: {
|
|
1154
|
+
sign(message, privateKey) {
|
|
1155
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1156
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1157
|
+
const sigPtr = wasm._hd_alloc(72);
|
|
1158
|
+
try {
|
|
1159
|
+
const len = wasm._hd_p256_sign(msgPtr, message.length, keyPtr, sigPtr, 72);
|
|
1160
|
+
if (len < 0) throw new HDWalletError(len);
|
|
1161
|
+
return readBytes(wasm, sigPtr, len);
|
|
1162
|
+
} finally {
|
|
1163
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1164
|
+
wasm._hd_dealloc(msgPtr);
|
|
1165
|
+
wasm._hd_dealloc(keyPtr);
|
|
1166
|
+
wasm._hd_dealloc(sigPtr);
|
|
1167
|
+
}
|
|
1168
|
+
},
|
|
1169
|
+
|
|
1170
|
+
verify(message, signature, publicKey) {
|
|
1171
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1172
|
+
const sigPtr = allocAndCopy(wasm, signature);
|
|
1173
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1174
|
+
try {
|
|
1175
|
+
const result = wasm._hd_p256_verify(msgPtr, message.length, sigPtr, signature.length, pubPtr, publicKey.length);
|
|
1176
|
+
return result === 1;
|
|
1177
|
+
} finally {
|
|
1178
|
+
wasm._hd_dealloc(msgPtr);
|
|
1179
|
+
wasm._hd_dealloc(sigPtr);
|
|
1180
|
+
wasm._hd_dealloc(pubPtr);
|
|
1181
|
+
}
|
|
1182
|
+
},
|
|
1183
|
+
|
|
1184
|
+
ecdh(privateKey, publicKey) {
|
|
1185
|
+
const privPtr = allocAndCopy(wasm, privateKey);
|
|
1186
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1187
|
+
const secretPtr = wasm._hd_alloc(32);
|
|
1188
|
+
try {
|
|
1189
|
+
const result = wasm._hd_ecdh_p256(privPtr, pubPtr, publicKey.length, secretPtr, 32);
|
|
1190
|
+
if (result < 0) throw new HDWalletError(result);
|
|
1191
|
+
return readBytes(wasm, secretPtr, 32);
|
|
1192
|
+
} finally {
|
|
1193
|
+
wasm._hd_secure_wipe(privPtr, 32);
|
|
1194
|
+
wasm._hd_secure_wipe(secretPtr, 32);
|
|
1195
|
+
wasm._hd_dealloc(privPtr);
|
|
1196
|
+
wasm._hd_dealloc(pubPtr);
|
|
1197
|
+
wasm._hd_dealloc(secretPtr);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
},
|
|
1201
|
+
|
|
1202
|
+
/**
|
|
1203
|
+
* P-384 (secp384r1) ECDSA operations
|
|
1204
|
+
*/
|
|
1205
|
+
p384: {
|
|
1206
|
+
sign(message, privateKey) {
|
|
1207
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1208
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1209
|
+
const sigPtr = wasm._hd_alloc(104);
|
|
1210
|
+
try {
|
|
1211
|
+
const len = wasm._hd_p384_sign(msgPtr, message.length, keyPtr, sigPtr, 104);
|
|
1212
|
+
if (len < 0) throw new HDWalletError(len);
|
|
1213
|
+
return readBytes(wasm, sigPtr, len);
|
|
1214
|
+
} finally {
|
|
1215
|
+
wasm._hd_secure_wipe(keyPtr, 48);
|
|
1216
|
+
wasm._hd_dealloc(msgPtr);
|
|
1217
|
+
wasm._hd_dealloc(keyPtr);
|
|
1218
|
+
wasm._hd_dealloc(sigPtr);
|
|
1219
|
+
}
|
|
1220
|
+
},
|
|
1221
|
+
|
|
1222
|
+
verify(message, signature, publicKey) {
|
|
1223
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1224
|
+
const sigPtr = allocAndCopy(wasm, signature);
|
|
1225
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1226
|
+
try {
|
|
1227
|
+
const result = wasm._hd_p384_verify(msgPtr, message.length, sigPtr, signature.length, pubPtr, publicKey.length);
|
|
1228
|
+
return result === 1;
|
|
1229
|
+
} finally {
|
|
1230
|
+
wasm._hd_dealloc(msgPtr);
|
|
1231
|
+
wasm._hd_dealloc(sigPtr);
|
|
1232
|
+
wasm._hd_dealloc(pubPtr);
|
|
1233
|
+
}
|
|
1234
|
+
},
|
|
1235
|
+
|
|
1236
|
+
ecdh(privateKey, publicKey) {
|
|
1237
|
+
const privPtr = allocAndCopy(wasm, privateKey);
|
|
1238
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1239
|
+
const secretPtr = wasm._hd_alloc(48);
|
|
1240
|
+
try {
|
|
1241
|
+
const result = wasm._hd_ecdh_p384(privPtr, pubPtr, publicKey.length, secretPtr, 48);
|
|
1242
|
+
if (result < 0) throw new HDWalletError(result);
|
|
1243
|
+
return readBytes(wasm, secretPtr, 48);
|
|
1244
|
+
} finally {
|
|
1245
|
+
wasm._hd_secure_wipe(privPtr, 48);
|
|
1246
|
+
wasm._hd_secure_wipe(secretPtr, 48);
|
|
1247
|
+
wasm._hd_dealloc(privPtr);
|
|
1248
|
+
wasm._hd_dealloc(pubPtr);
|
|
1249
|
+
wasm._hd_dealloc(secretPtr);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
},
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* X25519 key exchange
|
|
1256
|
+
*/
|
|
1257
|
+
x25519: {
|
|
1258
|
+
ecdh(privateKey, publicKey) {
|
|
1259
|
+
const privPtr = allocAndCopy(wasm, privateKey);
|
|
1260
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1261
|
+
const secretPtr = wasm._hd_alloc(32);
|
|
1262
|
+
try {
|
|
1263
|
+
const result = wasm._hd_ecdh_x25519(privPtr, pubPtr, secretPtr, 32);
|
|
1264
|
+
if (result < 0) throw new HDWalletError(result);
|
|
1265
|
+
return readBytes(wasm, secretPtr, 32);
|
|
1266
|
+
} finally {
|
|
1267
|
+
wasm._hd_secure_wipe(privPtr, 32);
|
|
1268
|
+
wasm._hd_secure_wipe(secretPtr, 32);
|
|
1269
|
+
wasm._hd_dealloc(privPtr);
|
|
1270
|
+
wasm._hd_dealloc(pubPtr);
|
|
1271
|
+
wasm._hd_dealloc(secretPtr);
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
|
|
1277
|
+
// ==========================================================================
|
|
1278
|
+
// Bitcoin API
|
|
1279
|
+
// ==========================================================================
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* Bitcoin API
|
|
1283
|
+
* @type {Object}
|
|
1284
|
+
*/
|
|
1285
|
+
const bitcoin = {
|
|
1286
|
+
/**
|
|
1287
|
+
* Get Bitcoin address from public key
|
|
1288
|
+
* @param {Uint8Array} publicKey - Public key
|
|
1289
|
+
* @param {number} type - Address type (P2PKH, P2SH, P2WPKH, P2WSH, P2TR)
|
|
1290
|
+
* @param {number} [network=Network.MAINNET] - Network
|
|
1291
|
+
* @returns {string} Bitcoin address
|
|
1292
|
+
*/
|
|
1293
|
+
getAddress(publicKey, type, network = Network.MAINNET) {
|
|
1294
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1295
|
+
const outPtr = wasm._hd_alloc(128);
|
|
1296
|
+
try {
|
|
1297
|
+
let result;
|
|
1298
|
+
switch (type) {
|
|
1299
|
+
case BitcoinAddressType.P2PKH:
|
|
1300
|
+
result = wasm._hd_btc_get_address_p2pkh(pubPtr, publicKey.length, network, outPtr, 128);
|
|
1301
|
+
break;
|
|
1302
|
+
case BitcoinAddressType.P2SH:
|
|
1303
|
+
result = wasm._hd_btc_get_address_p2sh(pubPtr, publicKey.length, network, outPtr, 128);
|
|
1304
|
+
break;
|
|
1305
|
+
case BitcoinAddressType.P2WPKH:
|
|
1306
|
+
result = wasm._hd_btc_get_address_p2wpkh(pubPtr, publicKey.length, network, outPtr, 128);
|
|
1307
|
+
break;
|
|
1308
|
+
case BitcoinAddressType.P2WSH:
|
|
1309
|
+
result = wasm._hd_btc_get_address_p2wsh(pubPtr, publicKey.length, network, outPtr, 128);
|
|
1310
|
+
break;
|
|
1311
|
+
case BitcoinAddressType.P2TR:
|
|
1312
|
+
result = wasm._hd_btc_get_address_taproot(pubPtr, publicKey.length, network, outPtr, 128);
|
|
1313
|
+
break;
|
|
1314
|
+
default:
|
|
1315
|
+
throw new HDWalletError(ErrorCode.INVALID_ARGUMENT, 'Invalid address type');
|
|
1316
|
+
}
|
|
1317
|
+
checkResult(result);
|
|
1318
|
+
return readString(wasm, outPtr);
|
|
1319
|
+
} finally {
|
|
1320
|
+
wasm._hd_dealloc(pubPtr);
|
|
1321
|
+
wasm._hd_dealloc(outPtr);
|
|
1322
|
+
}
|
|
1323
|
+
},
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* Validate Bitcoin address
|
|
1327
|
+
* @param {string} address - Address to validate
|
|
1328
|
+
* @returns {boolean} True if valid
|
|
1329
|
+
*/
|
|
1330
|
+
validateAddress(address) {
|
|
1331
|
+
const addrPtr = allocString(wasm, address);
|
|
1332
|
+
try {
|
|
1333
|
+
const result = wasm._hd_btc_validate_address(addrPtr);
|
|
1334
|
+
return result === 0;
|
|
1335
|
+
} finally {
|
|
1336
|
+
wasm._hd_dealloc(addrPtr);
|
|
1337
|
+
}
|
|
1338
|
+
},
|
|
1339
|
+
|
|
1340
|
+
/**
|
|
1341
|
+
* Decode Bitcoin address
|
|
1342
|
+
* @param {string} address - Address to decode
|
|
1343
|
+
* @returns {Object} { type, hash, network }
|
|
1344
|
+
*/
|
|
1345
|
+
decodeAddress(address) {
|
|
1346
|
+
const addrPtr = allocString(wasm, address);
|
|
1347
|
+
const typePtr = wasm._hd_alloc(4);
|
|
1348
|
+
const hashPtr = wasm._hd_alloc(32);
|
|
1349
|
+
const hashLenPtr = wasm._hd_alloc(4);
|
|
1350
|
+
const networkPtr = wasm._hd_alloc(4);
|
|
1351
|
+
try {
|
|
1352
|
+
wasm.setValue(hashLenPtr, 32, 'i32');
|
|
1353
|
+
const result = wasm._hd_btc_decode_address(addrPtr, typePtr, hashPtr, hashLenPtr, networkPtr);
|
|
1354
|
+
checkResult(result);
|
|
1355
|
+
const hashLen = wasm.getValue(hashLenPtr, 'i32');
|
|
1356
|
+
return {
|
|
1357
|
+
type: wasm.getValue(typePtr, 'i32'),
|
|
1358
|
+
hash: readBytes(wasm, hashPtr, hashLen),
|
|
1359
|
+
network: wasm.getValue(networkPtr, 'i32')
|
|
1360
|
+
};
|
|
1361
|
+
} finally {
|
|
1362
|
+
wasm._hd_dealloc(addrPtr);
|
|
1363
|
+
wasm._hd_dealloc(typePtr);
|
|
1364
|
+
wasm._hd_dealloc(hashPtr);
|
|
1365
|
+
wasm._hd_dealloc(hashLenPtr);
|
|
1366
|
+
wasm._hd_dealloc(networkPtr);
|
|
1367
|
+
}
|
|
1368
|
+
},
|
|
1369
|
+
|
|
1370
|
+
/**
|
|
1371
|
+
* Sign message (Bitcoin Signed Message format)
|
|
1372
|
+
* @param {string} message - Message to sign
|
|
1373
|
+
* @param {Uint8Array} privateKey - Private key
|
|
1374
|
+
* @returns {string} Base64-encoded signature
|
|
1375
|
+
*/
|
|
1376
|
+
signMessage(message, privateKey) {
|
|
1377
|
+
const msgPtr = allocString(wasm, message);
|
|
1378
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1379
|
+
const sigPtr = wasm._hd_alloc(256);
|
|
1380
|
+
try {
|
|
1381
|
+
const result = wasm._hd_btc_sign_message(msgPtr, keyPtr, sigPtr, 256);
|
|
1382
|
+
checkResult(result);
|
|
1383
|
+
return readString(wasm, sigPtr);
|
|
1384
|
+
} finally {
|
|
1385
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1386
|
+
wasm._hd_dealloc(msgPtr);
|
|
1387
|
+
wasm._hd_dealloc(keyPtr);
|
|
1388
|
+
wasm._hd_dealloc(sigPtr);
|
|
1389
|
+
}
|
|
1390
|
+
},
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Verify signed message
|
|
1394
|
+
* @param {string} message - Original message
|
|
1395
|
+
* @param {string} signature - Base64-encoded signature
|
|
1396
|
+
* @param {string} address - Expected address
|
|
1397
|
+
* @returns {boolean} True if valid
|
|
1398
|
+
*/
|
|
1399
|
+
verifyMessage(message, signature, address) {
|
|
1400
|
+
const msgPtr = allocString(wasm, message);
|
|
1401
|
+
const sigPtr = allocString(wasm, signature);
|
|
1402
|
+
const addrPtr = allocString(wasm, address);
|
|
1403
|
+
try {
|
|
1404
|
+
const result = wasm._hd_btc_verify_message(msgPtr, sigPtr, addrPtr);
|
|
1405
|
+
return result === 1;
|
|
1406
|
+
} finally {
|
|
1407
|
+
wasm._hd_dealloc(msgPtr);
|
|
1408
|
+
wasm._hd_dealloc(sigPtr);
|
|
1409
|
+
wasm._hd_dealloc(addrPtr);
|
|
1410
|
+
}
|
|
1411
|
+
},
|
|
1412
|
+
|
|
1413
|
+
/**
|
|
1414
|
+
* Transaction builder
|
|
1415
|
+
*/
|
|
1416
|
+
tx: {
|
|
1417
|
+
create() {
|
|
1418
|
+
const handle = wasm._hd_btc_tx_create();
|
|
1419
|
+
if (!handle) throw new HDWalletError(ErrorCode.NOT_SUPPORTED);
|
|
1420
|
+
|
|
1421
|
+
return {
|
|
1422
|
+
_handle: handle,
|
|
1423
|
+
|
|
1424
|
+
addInput(txid, vout, sequence = 0xffffffff) {
|
|
1425
|
+
const txidPtr = allocString(wasm, txid);
|
|
1426
|
+
try {
|
|
1427
|
+
const result = wasm._hd_btc_tx_add_input(this._handle, txidPtr, vout, sequence);
|
|
1428
|
+
checkResult(result);
|
|
1429
|
+
} finally {
|
|
1430
|
+
wasm._hd_dealloc(txidPtr);
|
|
1431
|
+
}
|
|
1432
|
+
return this;
|
|
1433
|
+
},
|
|
1434
|
+
|
|
1435
|
+
addOutput(address, amount) {
|
|
1436
|
+
const addrPtr = allocString(wasm, address);
|
|
1437
|
+
try {
|
|
1438
|
+
const result = wasm._hd_btc_tx_add_output(this._handle, addrPtr, BigInt(amount));
|
|
1439
|
+
checkResult(result);
|
|
1440
|
+
} finally {
|
|
1441
|
+
wasm._hd_dealloc(addrPtr);
|
|
1442
|
+
}
|
|
1443
|
+
return this;
|
|
1444
|
+
},
|
|
1445
|
+
|
|
1446
|
+
sign(inputIndex, privateKey, redeemScript) {
|
|
1447
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1448
|
+
const scriptPtr = redeemScript ? allocAndCopy(wasm, redeemScript) : 0;
|
|
1449
|
+
try {
|
|
1450
|
+
const result = wasm._hd_btc_tx_sign(this._handle, inputIndex, keyPtr, scriptPtr, redeemScript?.length || 0);
|
|
1451
|
+
checkResult(result);
|
|
1452
|
+
} finally {
|
|
1453
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1454
|
+
wasm._hd_dealloc(keyPtr);
|
|
1455
|
+
if (scriptPtr) wasm._hd_dealloc(scriptPtr);
|
|
1456
|
+
}
|
|
1457
|
+
return this;
|
|
1458
|
+
},
|
|
1459
|
+
|
|
1460
|
+
serialize() {
|
|
1461
|
+
const outPtr = wasm._hd_alloc(65536);
|
|
1462
|
+
const sizePtr = wasm._hd_alloc(4);
|
|
1463
|
+
try {
|
|
1464
|
+
wasm.setValue(sizePtr, 65536, 'i32');
|
|
1465
|
+
const result = wasm._hd_btc_tx_serialize(this._handle, outPtr, sizePtr);
|
|
1466
|
+
checkResult(result);
|
|
1467
|
+
const size = wasm.getValue(sizePtr, 'i32');
|
|
1468
|
+
return readBytes(wasm, outPtr, size);
|
|
1469
|
+
} finally {
|
|
1470
|
+
wasm._hd_dealloc(outPtr);
|
|
1471
|
+
wasm._hd_dealloc(sizePtr);
|
|
1472
|
+
}
|
|
1473
|
+
},
|
|
1474
|
+
|
|
1475
|
+
getTxid() {
|
|
1476
|
+
const ptr = wasm._hd_btc_tx_get_txid(this._handle);
|
|
1477
|
+
return readString(wasm, ptr);
|
|
1478
|
+
},
|
|
1479
|
+
|
|
1480
|
+
getSize() {
|
|
1481
|
+
return wasm._hd_btc_tx_get_size(this._handle);
|
|
1482
|
+
},
|
|
1483
|
+
|
|
1484
|
+
getVsize() {
|
|
1485
|
+
return wasm._hd_btc_tx_get_vsize(this._handle);
|
|
1486
|
+
},
|
|
1487
|
+
|
|
1488
|
+
destroy() {
|
|
1489
|
+
if (this._handle) {
|
|
1490
|
+
wasm._hd_btc_tx_destroy(this._handle);
|
|
1491
|
+
this._handle = null;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
|
|
1499
|
+
// ==========================================================================
|
|
1500
|
+
// Ethereum API
|
|
1501
|
+
// ==========================================================================
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
* Ethereum API
|
|
1505
|
+
* @type {Object}
|
|
1506
|
+
*/
|
|
1507
|
+
const ethereum = {
|
|
1508
|
+
/**
|
|
1509
|
+
* Get Ethereum address from public key
|
|
1510
|
+
* @param {Uint8Array} publicKey - Uncompressed public key (65 bytes)
|
|
1511
|
+
* @returns {string} Ethereum address (with 0x prefix)
|
|
1512
|
+
*/
|
|
1513
|
+
getAddress(publicKey) {
|
|
1514
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1515
|
+
const outPtr = wasm._hd_alloc(64);
|
|
1516
|
+
try {
|
|
1517
|
+
const result = wasm._hd_eth_get_address(pubPtr, publicKey.length, outPtr, 64);
|
|
1518
|
+
checkResult(result);
|
|
1519
|
+
return readString(wasm, outPtr);
|
|
1520
|
+
} finally {
|
|
1521
|
+
wasm._hd_dealloc(pubPtr);
|
|
1522
|
+
wasm._hd_dealloc(outPtr);
|
|
1523
|
+
}
|
|
1524
|
+
},
|
|
1525
|
+
|
|
1526
|
+
/**
|
|
1527
|
+
* Get checksummed address (EIP-55)
|
|
1528
|
+
* @param {string} address - Address to checksum
|
|
1529
|
+
* @returns {string} Checksummed address
|
|
1530
|
+
*/
|
|
1531
|
+
getChecksumAddress(address) {
|
|
1532
|
+
const addrPtr = allocString(wasm, address);
|
|
1533
|
+
const outPtr = wasm._hd_alloc(64);
|
|
1534
|
+
try {
|
|
1535
|
+
const result = wasm._hd_eth_get_address_checksum(addrPtr, outPtr, 64);
|
|
1536
|
+
checkResult(result);
|
|
1537
|
+
return readString(wasm, outPtr);
|
|
1538
|
+
} finally {
|
|
1539
|
+
wasm._hd_dealloc(addrPtr);
|
|
1540
|
+
wasm._hd_dealloc(outPtr);
|
|
1541
|
+
}
|
|
1542
|
+
},
|
|
1543
|
+
|
|
1544
|
+
/**
|
|
1545
|
+
* Validate Ethereum address
|
|
1546
|
+
* @param {string} address - Address to validate
|
|
1547
|
+
* @returns {boolean} True if valid
|
|
1548
|
+
*/
|
|
1549
|
+
validateAddress(address) {
|
|
1550
|
+
const addrPtr = allocString(wasm, address);
|
|
1551
|
+
try {
|
|
1552
|
+
const result = wasm._hd_eth_validate_address(addrPtr);
|
|
1553
|
+
return result === 0;
|
|
1554
|
+
} finally {
|
|
1555
|
+
wasm._hd_dealloc(addrPtr);
|
|
1556
|
+
}
|
|
1557
|
+
},
|
|
1558
|
+
|
|
1559
|
+
/**
|
|
1560
|
+
* Sign message (EIP-191)
|
|
1561
|
+
* @param {string} message - Message to sign
|
|
1562
|
+
* @param {Uint8Array} privateKey - Private key
|
|
1563
|
+
* @returns {string} Hex-encoded signature
|
|
1564
|
+
*/
|
|
1565
|
+
signMessage(message, privateKey) {
|
|
1566
|
+
const msgPtr = allocString(wasm, message);
|
|
1567
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1568
|
+
const sigPtr = wasm._hd_alloc(256);
|
|
1569
|
+
try {
|
|
1570
|
+
const result = wasm._hd_eth_sign_message(msgPtr, keyPtr, sigPtr, 256);
|
|
1571
|
+
checkResult(result);
|
|
1572
|
+
return readString(wasm, sigPtr);
|
|
1573
|
+
} finally {
|
|
1574
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1575
|
+
wasm._hd_dealloc(msgPtr);
|
|
1576
|
+
wasm._hd_dealloc(keyPtr);
|
|
1577
|
+
wasm._hd_dealloc(sigPtr);
|
|
1578
|
+
}
|
|
1579
|
+
},
|
|
1580
|
+
|
|
1581
|
+
/**
|
|
1582
|
+
* Sign typed data (EIP-712)
|
|
1583
|
+
* @param {Object} typedData - Typed data object
|
|
1584
|
+
* @param {Uint8Array} privateKey - Private key
|
|
1585
|
+
* @returns {string} Hex-encoded signature
|
|
1586
|
+
*/
|
|
1587
|
+
signTypedData(typedData, privateKey) {
|
|
1588
|
+
const jsonPtr = allocString(wasm, JSON.stringify(typedData));
|
|
1589
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1590
|
+
const sigPtr = wasm._hd_alloc(256);
|
|
1591
|
+
try {
|
|
1592
|
+
const result = wasm._hd_eth_sign_typed_data(jsonPtr, keyPtr, sigPtr, 256);
|
|
1593
|
+
checkResult(result);
|
|
1594
|
+
return readString(wasm, sigPtr);
|
|
1595
|
+
} finally {
|
|
1596
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1597
|
+
wasm._hd_dealloc(jsonPtr);
|
|
1598
|
+
wasm._hd_dealloc(keyPtr);
|
|
1599
|
+
wasm._hd_dealloc(sigPtr);
|
|
1600
|
+
}
|
|
1601
|
+
},
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* Verify message signature and recover address
|
|
1605
|
+
* @param {string} message - Original message
|
|
1606
|
+
* @param {string} signature - Hex-encoded signature
|
|
1607
|
+
* @returns {string} Recovered address
|
|
1608
|
+
*/
|
|
1609
|
+
verifyMessage(message, signature) {
|
|
1610
|
+
const msgPtr = allocString(wasm, message);
|
|
1611
|
+
const sigPtr = allocString(wasm, signature);
|
|
1612
|
+
const addrPtr = wasm._hd_alloc(64);
|
|
1613
|
+
try {
|
|
1614
|
+
const result = wasm._hd_eth_verify_message(msgPtr, sigPtr, addrPtr, 64);
|
|
1615
|
+
checkResult(result);
|
|
1616
|
+
return readString(wasm, addrPtr);
|
|
1617
|
+
} finally {
|
|
1618
|
+
wasm._hd_dealloc(msgPtr);
|
|
1619
|
+
wasm._hd_dealloc(sigPtr);
|
|
1620
|
+
wasm._hd_dealloc(addrPtr);
|
|
1621
|
+
}
|
|
1622
|
+
},
|
|
1623
|
+
|
|
1624
|
+
/**
|
|
1625
|
+
* Transaction builder
|
|
1626
|
+
*/
|
|
1627
|
+
tx: {
|
|
1628
|
+
create(params) {
|
|
1629
|
+
// Implementation placeholder
|
|
1630
|
+
throw new HDWalletError(ErrorCode.NOT_SUPPORTED);
|
|
1631
|
+
},
|
|
1632
|
+
|
|
1633
|
+
createEIP1559(params) {
|
|
1634
|
+
// Implementation placeholder
|
|
1635
|
+
throw new HDWalletError(ErrorCode.NOT_SUPPORTED);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
};
|
|
1639
|
+
|
|
1640
|
+
// ==========================================================================
|
|
1641
|
+
// Cosmos API
|
|
1642
|
+
// ==========================================================================
|
|
1643
|
+
|
|
1644
|
+
/**
|
|
1645
|
+
* Cosmos/Tendermint API
|
|
1646
|
+
* @type {Object}
|
|
1647
|
+
*/
|
|
1648
|
+
const cosmos = {
|
|
1649
|
+
getAddress(publicKey, prefix = 'cosmos') {
|
|
1650
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1651
|
+
const prefixPtr = allocString(wasm, prefix);
|
|
1652
|
+
const outPtr = wasm._hd_alloc(128);
|
|
1653
|
+
try {
|
|
1654
|
+
const result = wasm._hd_cosmos_get_address(pubPtr, publicKey.length, prefixPtr, outPtr, 128);
|
|
1655
|
+
checkResult(result);
|
|
1656
|
+
return readString(wasm, outPtr);
|
|
1657
|
+
} finally {
|
|
1658
|
+
wasm._hd_dealloc(pubPtr);
|
|
1659
|
+
wasm._hd_dealloc(prefixPtr);
|
|
1660
|
+
wasm._hd_dealloc(outPtr);
|
|
1661
|
+
}
|
|
1662
|
+
},
|
|
1663
|
+
|
|
1664
|
+
validateAddress(address) {
|
|
1665
|
+
const addrPtr = allocString(wasm, address);
|
|
1666
|
+
try {
|
|
1667
|
+
return wasm._hd_cosmos_validate_address(addrPtr) === 0;
|
|
1668
|
+
} finally {
|
|
1669
|
+
wasm._hd_dealloc(addrPtr);
|
|
1670
|
+
}
|
|
1671
|
+
},
|
|
1672
|
+
|
|
1673
|
+
signAmino(doc, privateKey) {
|
|
1674
|
+
const docPtr = allocString(wasm, JSON.stringify(doc));
|
|
1675
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1676
|
+
const outPtr = wasm._hd_alloc(1024);
|
|
1677
|
+
try {
|
|
1678
|
+
const result = wasm._hd_cosmos_sign_amino(docPtr, keyPtr, outPtr, 1024);
|
|
1679
|
+
checkResult(result);
|
|
1680
|
+
return JSON.parse(readString(wasm, outPtr));
|
|
1681
|
+
} finally {
|
|
1682
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1683
|
+
wasm._hd_dealloc(docPtr);
|
|
1684
|
+
wasm._hd_dealloc(keyPtr);
|
|
1685
|
+
wasm._hd_dealloc(outPtr);
|
|
1686
|
+
}
|
|
1687
|
+
},
|
|
1688
|
+
|
|
1689
|
+
signDirect(bodyBytes, authInfoBytes, chainId, accountNumber, privateKey) {
|
|
1690
|
+
const bodyPtr = allocAndCopy(wasm, bodyBytes);
|
|
1691
|
+
const authPtr = allocAndCopy(wasm, authInfoBytes);
|
|
1692
|
+
const chainPtr = allocString(wasm, chainId);
|
|
1693
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1694
|
+
const outPtr = wasm._hd_alloc(1024);
|
|
1695
|
+
try {
|
|
1696
|
+
const result = wasm._hd_cosmos_sign_direct(
|
|
1697
|
+
bodyPtr, bodyBytes.length,
|
|
1698
|
+
authPtr, authInfoBytes.length,
|
|
1699
|
+
chainPtr, BigInt(accountNumber),
|
|
1700
|
+
keyPtr, outPtr, 1024
|
|
1701
|
+
);
|
|
1702
|
+
checkResult(result);
|
|
1703
|
+
return JSON.parse(readString(wasm, outPtr));
|
|
1704
|
+
} finally {
|
|
1705
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1706
|
+
wasm._hd_dealloc(bodyPtr);
|
|
1707
|
+
wasm._hd_dealloc(authPtr);
|
|
1708
|
+
wasm._hd_dealloc(chainPtr);
|
|
1709
|
+
wasm._hd_dealloc(keyPtr);
|
|
1710
|
+
wasm._hd_dealloc(outPtr);
|
|
1711
|
+
}
|
|
1712
|
+
},
|
|
1713
|
+
|
|
1714
|
+
verify(signature, message, publicKey) {
|
|
1715
|
+
const sigPtr = allocAndCopy(wasm, signature);
|
|
1716
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1717
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1718
|
+
try {
|
|
1719
|
+
return wasm._hd_cosmos_verify(sigPtr, signature.length, msgPtr, message.length, pubPtr, publicKey.length) === 1;
|
|
1720
|
+
} finally {
|
|
1721
|
+
wasm._hd_dealloc(sigPtr);
|
|
1722
|
+
wasm._hd_dealloc(msgPtr);
|
|
1723
|
+
wasm._hd_dealloc(pubPtr);
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1727
|
+
|
|
1728
|
+
// ==========================================================================
|
|
1729
|
+
// Solana API
|
|
1730
|
+
// ==========================================================================
|
|
1731
|
+
|
|
1732
|
+
/**
|
|
1733
|
+
* Solana API
|
|
1734
|
+
* @type {Object}
|
|
1735
|
+
*/
|
|
1736
|
+
const solana = {
|
|
1737
|
+
getAddress(publicKey) {
|
|
1738
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1739
|
+
const outPtr = wasm._hd_alloc(64);
|
|
1740
|
+
try {
|
|
1741
|
+
const result = wasm._hd_sol_get_address(pubPtr, publicKey.length, outPtr, 64);
|
|
1742
|
+
checkResult(result);
|
|
1743
|
+
return readString(wasm, outPtr);
|
|
1744
|
+
} finally {
|
|
1745
|
+
wasm._hd_dealloc(pubPtr);
|
|
1746
|
+
wasm._hd_dealloc(outPtr);
|
|
1747
|
+
}
|
|
1748
|
+
},
|
|
1749
|
+
|
|
1750
|
+
validateAddress(address) {
|
|
1751
|
+
const addrPtr = allocString(wasm, address);
|
|
1752
|
+
try {
|
|
1753
|
+
return wasm._hd_sol_validate_address(addrPtr) === 0;
|
|
1754
|
+
} finally {
|
|
1755
|
+
wasm._hd_dealloc(addrPtr);
|
|
1756
|
+
}
|
|
1757
|
+
},
|
|
1758
|
+
|
|
1759
|
+
signMessage(message, privateKey) {
|
|
1760
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1761
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1762
|
+
const sigPtr = wasm._hd_alloc(64);
|
|
1763
|
+
try {
|
|
1764
|
+
const result = wasm._hd_sol_sign_message(msgPtr, message.length, keyPtr, sigPtr, 64);
|
|
1765
|
+
checkResult(result);
|
|
1766
|
+
return readBytes(wasm, sigPtr, 64);
|
|
1767
|
+
} finally {
|
|
1768
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1769
|
+
wasm._hd_dealloc(msgPtr);
|
|
1770
|
+
wasm._hd_dealloc(keyPtr);
|
|
1771
|
+
wasm._hd_dealloc(sigPtr);
|
|
1772
|
+
}
|
|
1773
|
+
},
|
|
1774
|
+
|
|
1775
|
+
verifyMessage(message, signature, publicKey) {
|
|
1776
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1777
|
+
const sigPtr = allocAndCopy(wasm, signature);
|
|
1778
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1779
|
+
try {
|
|
1780
|
+
return wasm._hd_sol_verify_message(msgPtr, message.length, sigPtr, signature.length, pubPtr, publicKey.length) === 1;
|
|
1781
|
+
} finally {
|
|
1782
|
+
wasm._hd_dealloc(msgPtr);
|
|
1783
|
+
wasm._hd_dealloc(sigPtr);
|
|
1784
|
+
wasm._hd_dealloc(pubPtr);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
};
|
|
1788
|
+
|
|
1789
|
+
// ==========================================================================
|
|
1790
|
+
// Polkadot API
|
|
1791
|
+
// ==========================================================================
|
|
1792
|
+
|
|
1793
|
+
/**
|
|
1794
|
+
* Polkadot/Substrate API
|
|
1795
|
+
* @type {Object}
|
|
1796
|
+
*/
|
|
1797
|
+
const polkadot = {
|
|
1798
|
+
getAddress(publicKey, ss58Prefix = 0) {
|
|
1799
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1800
|
+
const outPtr = wasm._hd_alloc(64);
|
|
1801
|
+
try {
|
|
1802
|
+
const result = wasm._hd_dot_get_address(pubPtr, publicKey.length, ss58Prefix, outPtr, 64);
|
|
1803
|
+
checkResult(result);
|
|
1804
|
+
return readString(wasm, outPtr);
|
|
1805
|
+
} finally {
|
|
1806
|
+
wasm._hd_dealloc(pubPtr);
|
|
1807
|
+
wasm._hd_dealloc(outPtr);
|
|
1808
|
+
}
|
|
1809
|
+
},
|
|
1810
|
+
|
|
1811
|
+
validateAddress(address) {
|
|
1812
|
+
const addrPtr = allocString(wasm, address);
|
|
1813
|
+
try {
|
|
1814
|
+
return wasm._hd_dot_validate_address(addrPtr) === 0;
|
|
1815
|
+
} finally {
|
|
1816
|
+
wasm._hd_dealloc(addrPtr);
|
|
1817
|
+
}
|
|
1818
|
+
},
|
|
1819
|
+
|
|
1820
|
+
signMessage(message, privateKey) {
|
|
1821
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1822
|
+
const keyPtr = allocAndCopy(wasm, privateKey);
|
|
1823
|
+
const sigPtr = wasm._hd_alloc(64);
|
|
1824
|
+
try {
|
|
1825
|
+
const result = wasm._hd_dot_sign_message(msgPtr, message.length, keyPtr, sigPtr, 64);
|
|
1826
|
+
checkResult(result);
|
|
1827
|
+
return readBytes(wasm, sigPtr, 64);
|
|
1828
|
+
} finally {
|
|
1829
|
+
wasm._hd_secure_wipe(keyPtr, 32);
|
|
1830
|
+
wasm._hd_dealloc(msgPtr);
|
|
1831
|
+
wasm._hd_dealloc(keyPtr);
|
|
1832
|
+
wasm._hd_dealloc(sigPtr);
|
|
1833
|
+
}
|
|
1834
|
+
},
|
|
1835
|
+
|
|
1836
|
+
verifyMessage(message, signature, publicKey) {
|
|
1837
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
1838
|
+
const sigPtr = allocAndCopy(wasm, signature);
|
|
1839
|
+
const pubPtr = allocAndCopy(wasm, publicKey);
|
|
1840
|
+
try {
|
|
1841
|
+
return wasm._hd_dot_verify_message(msgPtr, message.length, sigPtr, signature.length, pubPtr, publicKey.length) === 1;
|
|
1842
|
+
} finally {
|
|
1843
|
+
wasm._hd_dealloc(msgPtr);
|
|
1844
|
+
wasm._hd_dealloc(sigPtr);
|
|
1845
|
+
wasm._hd_dealloc(pubPtr);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
|
|
1850
|
+
// ==========================================================================
|
|
1851
|
+
// Hardware Wallet API
|
|
1852
|
+
// ==========================================================================
|
|
1853
|
+
|
|
1854
|
+
/**
|
|
1855
|
+
* Hardware Wallet API (requires WASI bridge)
|
|
1856
|
+
* @type {Object}
|
|
1857
|
+
*/
|
|
1858
|
+
const hardware = {
|
|
1859
|
+
/**
|
|
1860
|
+
* Check if hardware wallet support is available
|
|
1861
|
+
* @returns {boolean}
|
|
1862
|
+
*/
|
|
1863
|
+
isAvailable() {
|
|
1864
|
+
return wasm._hd_wasi_has_feature(WasiFeature.USB_HID) !== 0;
|
|
1865
|
+
},
|
|
1866
|
+
|
|
1867
|
+
/**
|
|
1868
|
+
* Enumerate connected hardware wallets
|
|
1869
|
+
* @returns {Promise<Object[]>} Array of device descriptors
|
|
1870
|
+
*/
|
|
1871
|
+
async enumerate() {
|
|
1872
|
+
const ptr = wasm._hd_hw_enumerate();
|
|
1873
|
+
const json = readString(wasm, ptr);
|
|
1874
|
+
return JSON.parse(json);
|
|
1875
|
+
},
|
|
1876
|
+
|
|
1877
|
+
/**
|
|
1878
|
+
* Connect to a hardware wallet
|
|
1879
|
+
* @param {string} devicePath - Device path from enumeration
|
|
1880
|
+
* @returns {Promise<Object>} Hardware wallet interface
|
|
1881
|
+
*/
|
|
1882
|
+
async connect(devicePath) {
|
|
1883
|
+
const pathPtr = allocString(wasm, devicePath);
|
|
1884
|
+
try {
|
|
1885
|
+
const handle = wasm._hd_hw_connect(pathPtr);
|
|
1886
|
+
if (!handle) {
|
|
1887
|
+
throw new HDWalletError(ErrorCode.DEVICE_NOT_CONNECTED);
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
return {
|
|
1891
|
+
_handle: handle,
|
|
1892
|
+
|
|
1893
|
+
get vendor() {
|
|
1894
|
+
const ptr = wasm._hd_hw_get_vendor(this._handle);
|
|
1895
|
+
return readString(wasm, ptr);
|
|
1896
|
+
},
|
|
1897
|
+
|
|
1898
|
+
get model() {
|
|
1899
|
+
const ptr = wasm._hd_hw_get_model(this._handle);
|
|
1900
|
+
return readString(wasm, ptr);
|
|
1901
|
+
},
|
|
1902
|
+
|
|
1903
|
+
get firmwareVersion() {
|
|
1904
|
+
const ptr = wasm._hd_hw_get_firmware_version(this._handle);
|
|
1905
|
+
return readString(wasm, ptr);
|
|
1906
|
+
},
|
|
1907
|
+
|
|
1908
|
+
get isConnected() {
|
|
1909
|
+
return wasm._hd_hw_is_connected(this._handle) !== 0;
|
|
1910
|
+
},
|
|
1911
|
+
|
|
1912
|
+
async getPublicKey(path, curve = Curve.SECP256K1) {
|
|
1913
|
+
const pathPtr = allocString(wasm, path);
|
|
1914
|
+
const outPtr = wasm._hd_alloc(65);
|
|
1915
|
+
try {
|
|
1916
|
+
const result = wasm._hd_hw_get_public_key(this._handle, pathPtr, curve, outPtr, 65);
|
|
1917
|
+
checkResult(result);
|
|
1918
|
+
return readBytes(wasm, outPtr, 33);
|
|
1919
|
+
} finally {
|
|
1920
|
+
wasm._hd_dealloc(pathPtr);
|
|
1921
|
+
wasm._hd_dealloc(outPtr);
|
|
1922
|
+
}
|
|
1923
|
+
},
|
|
1924
|
+
|
|
1925
|
+
async signTransaction(path, transaction) {
|
|
1926
|
+
const pathPtr = allocString(wasm, path);
|
|
1927
|
+
const txPtr = allocAndCopy(wasm, transaction);
|
|
1928
|
+
const sigPtr = wasm._hd_alloc(128);
|
|
1929
|
+
try {
|
|
1930
|
+
const result = wasm._hd_hw_sign_transaction(this._handle, pathPtr, txPtr, transaction.length, sigPtr, 128);
|
|
1931
|
+
checkResult(result);
|
|
1932
|
+
return readBytes(wasm, sigPtr, 64);
|
|
1933
|
+
} finally {
|
|
1934
|
+
wasm._hd_dealloc(pathPtr);
|
|
1935
|
+
wasm._hd_dealloc(txPtr);
|
|
1936
|
+
wasm._hd_dealloc(sigPtr);
|
|
1937
|
+
}
|
|
1938
|
+
},
|
|
1939
|
+
|
|
1940
|
+
async signMessage(path, message) {
|
|
1941
|
+
const pathPtr = allocString(wasm, path);
|
|
1942
|
+
const msgPtr = allocString(wasm, message);
|
|
1943
|
+
const sigPtr = wasm._hd_alloc(128);
|
|
1944
|
+
try {
|
|
1945
|
+
const result = wasm._hd_hw_sign_message(this._handle, pathPtr, msgPtr, sigPtr, 128);
|
|
1946
|
+
checkResult(result);
|
|
1947
|
+
return readBytes(wasm, sigPtr, 64);
|
|
1948
|
+
} finally {
|
|
1949
|
+
wasm._hd_dealloc(pathPtr);
|
|
1950
|
+
wasm._hd_dealloc(msgPtr);
|
|
1951
|
+
wasm._hd_dealloc(sigPtr);
|
|
1952
|
+
}
|
|
1953
|
+
},
|
|
1954
|
+
|
|
1955
|
+
async ping() {
|
|
1956
|
+
return wasm._hd_hw_ping(this._handle) === 0;
|
|
1957
|
+
},
|
|
1958
|
+
|
|
1959
|
+
disconnect() {
|
|
1960
|
+
if (this._handle) {
|
|
1961
|
+
wasm._hd_hw_disconnect(this._handle);
|
|
1962
|
+
this._handle = null;
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
};
|
|
1966
|
+
} finally {
|
|
1967
|
+
wasm._hd_dealloc(pathPtr);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
};
|
|
1971
|
+
|
|
1972
|
+
// ==========================================================================
|
|
1973
|
+
// Keyring API
|
|
1974
|
+
// ==========================================================================
|
|
1975
|
+
|
|
1976
|
+
/**
|
|
1977
|
+
* Keyring API
|
|
1978
|
+
* @type {Object}
|
|
1979
|
+
*/
|
|
1980
|
+
const keyring = {
|
|
1981
|
+
/**
|
|
1982
|
+
* Create a new keyring
|
|
1983
|
+
* @returns {Object} Keyring instance
|
|
1984
|
+
*/
|
|
1985
|
+
create() {
|
|
1986
|
+
const handle = wasm._hd_keyring_create();
|
|
1987
|
+
|
|
1988
|
+
return {
|
|
1989
|
+
_handle: handle,
|
|
1990
|
+
|
|
1991
|
+
addWallet(seed, name) {
|
|
1992
|
+
const seedPtr = allocAndCopy(wasm, seed);
|
|
1993
|
+
const namePtr = name ? allocString(wasm, name) : 0;
|
|
1994
|
+
try {
|
|
1995
|
+
const ptr = wasm._hd_keyring_add_wallet(this._handle, seedPtr, seed.length, namePtr);
|
|
1996
|
+
return readString(wasm, ptr);
|
|
1997
|
+
} finally {
|
|
1998
|
+
wasm._hd_secure_wipe(seedPtr, seed.length);
|
|
1999
|
+
wasm._hd_dealloc(seedPtr);
|
|
2000
|
+
if (namePtr) wasm._hd_dealloc(namePtr);
|
|
2001
|
+
}
|
|
2002
|
+
},
|
|
2003
|
+
|
|
2004
|
+
removeWallet(id) {
|
|
2005
|
+
const idPtr = allocString(wasm, id);
|
|
2006
|
+
try {
|
|
2007
|
+
const result = wasm._hd_keyring_remove_wallet(this._handle, idPtr);
|
|
2008
|
+
checkResult(result);
|
|
2009
|
+
} finally {
|
|
2010
|
+
wasm._hd_dealloc(idPtr);
|
|
2011
|
+
}
|
|
2012
|
+
},
|
|
2013
|
+
|
|
2014
|
+
getWalletCount() {
|
|
2015
|
+
return wasm._hd_keyring_get_wallet_count(this._handle);
|
|
2016
|
+
},
|
|
2017
|
+
|
|
2018
|
+
getAccounts(walletId, coinType, count = 10) {
|
|
2019
|
+
const idPtr = allocString(wasm, walletId);
|
|
2020
|
+
try {
|
|
2021
|
+
const ptr = wasm._hd_keyring_get_accounts(this._handle, idPtr, coinType, count);
|
|
2022
|
+
return JSON.parse(readString(wasm, ptr));
|
|
2023
|
+
} finally {
|
|
2024
|
+
wasm._hd_dealloc(idPtr);
|
|
2025
|
+
}
|
|
2026
|
+
},
|
|
2027
|
+
|
|
2028
|
+
signTransaction(walletId, path, transaction) {
|
|
2029
|
+
const idPtr = allocString(wasm, walletId);
|
|
2030
|
+
const pathPtr = allocString(wasm, path);
|
|
2031
|
+
const txPtr = allocAndCopy(wasm, transaction);
|
|
2032
|
+
const sigPtr = wasm._hd_alloc(128);
|
|
2033
|
+
try {
|
|
2034
|
+
const result = wasm._hd_keyring_sign_transaction(this._handle, idPtr, pathPtr, txPtr, transaction.length, sigPtr, 128);
|
|
2035
|
+
checkResult(result);
|
|
2036
|
+
return readBytes(wasm, sigPtr, 64);
|
|
2037
|
+
} finally {
|
|
2038
|
+
wasm._hd_dealloc(idPtr);
|
|
2039
|
+
wasm._hd_dealloc(pathPtr);
|
|
2040
|
+
wasm._hd_dealloc(txPtr);
|
|
2041
|
+
wasm._hd_dealloc(sigPtr);
|
|
2042
|
+
}
|
|
2043
|
+
},
|
|
2044
|
+
|
|
2045
|
+
signMessage(walletId, path, message) {
|
|
2046
|
+
const idPtr = allocString(wasm, walletId);
|
|
2047
|
+
const pathPtr = allocString(wasm, path);
|
|
2048
|
+
const msgPtr = allocAndCopy(wasm, message);
|
|
2049
|
+
const sigPtr = wasm._hd_alloc(128);
|
|
2050
|
+
try {
|
|
2051
|
+
const result = wasm._hd_keyring_sign_message(this._handle, idPtr, pathPtr, msgPtr, message.length, sigPtr, 128);
|
|
2052
|
+
checkResult(result);
|
|
2053
|
+
return readBytes(wasm, sigPtr, 64);
|
|
2054
|
+
} finally {
|
|
2055
|
+
wasm._hd_dealloc(idPtr);
|
|
2056
|
+
wasm._hd_dealloc(pathPtr);
|
|
2057
|
+
wasm._hd_dealloc(msgPtr);
|
|
2058
|
+
wasm._hd_dealloc(sigPtr);
|
|
2059
|
+
}
|
|
2060
|
+
},
|
|
2061
|
+
|
|
2062
|
+
destroy() {
|
|
2063
|
+
if (this._handle) {
|
|
2064
|
+
wasm._hd_keyring_destroy(this._handle);
|
|
2065
|
+
this._handle = null;
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2070
|
+
};
|
|
2071
|
+
|
|
2072
|
+
// ==========================================================================
|
|
2073
|
+
// Utils API
|
|
2074
|
+
// ==========================================================================
|
|
2075
|
+
|
|
2076
|
+
/**
|
|
2077
|
+
* Utility functions
|
|
2078
|
+
* @type {Object}
|
|
2079
|
+
*/
|
|
2080
|
+
const utils = {
|
|
2081
|
+
// Hashing
|
|
2082
|
+
sha256(data) {
|
|
2083
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2084
|
+
const hashPtr = wasm._hd_alloc(32);
|
|
2085
|
+
try {
|
|
2086
|
+
const result = wasm._hd_hash_sha256(dataPtr, data.length, hashPtr, 32);
|
|
2087
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2088
|
+
return readBytes(wasm, hashPtr, 32);
|
|
2089
|
+
} finally {
|
|
2090
|
+
wasm._hd_dealloc(dataPtr);
|
|
2091
|
+
wasm._hd_dealloc(hashPtr);
|
|
2092
|
+
}
|
|
2093
|
+
},
|
|
2094
|
+
|
|
2095
|
+
sha512(data) {
|
|
2096
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2097
|
+
const hashPtr = wasm._hd_alloc(64);
|
|
2098
|
+
try {
|
|
2099
|
+
const result = wasm._hd_hash_sha512(dataPtr, data.length, hashPtr, 64);
|
|
2100
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2101
|
+
return readBytes(wasm, hashPtr, 64);
|
|
2102
|
+
} finally {
|
|
2103
|
+
wasm._hd_dealloc(dataPtr);
|
|
2104
|
+
wasm._hd_dealloc(hashPtr);
|
|
2105
|
+
}
|
|
2106
|
+
},
|
|
2107
|
+
|
|
2108
|
+
keccak256(data) {
|
|
2109
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2110
|
+
const hashPtr = wasm._hd_alloc(32);
|
|
2111
|
+
try {
|
|
2112
|
+
const result = wasm._hd_hash_keccak256(dataPtr, data.length, hashPtr, 32);
|
|
2113
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2114
|
+
return readBytes(wasm, hashPtr, 32);
|
|
2115
|
+
} finally {
|
|
2116
|
+
wasm._hd_dealloc(dataPtr);
|
|
2117
|
+
wasm._hd_dealloc(hashPtr);
|
|
2118
|
+
}
|
|
2119
|
+
},
|
|
2120
|
+
|
|
2121
|
+
ripemd160(data) {
|
|
2122
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2123
|
+
const hashPtr = wasm._hd_alloc(20);
|
|
2124
|
+
try {
|
|
2125
|
+
const result = wasm._hd_hash_ripemd160(dataPtr, data.length, hashPtr, 20);
|
|
2126
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2127
|
+
return readBytes(wasm, hashPtr, 20);
|
|
2128
|
+
} finally {
|
|
2129
|
+
wasm._hd_dealloc(dataPtr);
|
|
2130
|
+
wasm._hd_dealloc(hashPtr);
|
|
2131
|
+
}
|
|
2132
|
+
},
|
|
2133
|
+
|
|
2134
|
+
hash160(data) {
|
|
2135
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2136
|
+
const hashPtr = wasm._hd_alloc(20);
|
|
2137
|
+
try {
|
|
2138
|
+
const result = wasm._hd_hash_hash160(dataPtr, data.length, hashPtr, 20);
|
|
2139
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2140
|
+
return readBytes(wasm, hashPtr, 20);
|
|
2141
|
+
} finally {
|
|
2142
|
+
wasm._hd_dealloc(dataPtr);
|
|
2143
|
+
wasm._hd_dealloc(hashPtr);
|
|
2144
|
+
}
|
|
2145
|
+
},
|
|
2146
|
+
|
|
2147
|
+
blake2b(data, outputLength = 32) {
|
|
2148
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2149
|
+
const hashPtr = wasm._hd_alloc(64);
|
|
2150
|
+
try {
|
|
2151
|
+
const result = wasm._hd_hash_blake2b(dataPtr, data.length, hashPtr, 64, outputLength);
|
|
2152
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2153
|
+
return readBytes(wasm, hashPtr, outputLength);
|
|
2154
|
+
} finally {
|
|
2155
|
+
wasm._hd_dealloc(dataPtr);
|
|
2156
|
+
wasm._hd_dealloc(hashPtr);
|
|
2157
|
+
}
|
|
2158
|
+
},
|
|
2159
|
+
|
|
2160
|
+
blake2s(data, outputLength = 32) {
|
|
2161
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2162
|
+
const hashPtr = wasm._hd_alloc(32);
|
|
2163
|
+
try {
|
|
2164
|
+
const result = wasm._hd_hash_blake2s(dataPtr, data.length, hashPtr, 32, outputLength);
|
|
2165
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2166
|
+
return readBytes(wasm, hashPtr, outputLength);
|
|
2167
|
+
} finally {
|
|
2168
|
+
wasm._hd_dealloc(dataPtr);
|
|
2169
|
+
wasm._hd_dealloc(hashPtr);
|
|
2170
|
+
}
|
|
2171
|
+
},
|
|
2172
|
+
|
|
2173
|
+
// Key derivation
|
|
2174
|
+
hkdf(ikm, salt, info, length) {
|
|
2175
|
+
const ikmPtr = allocAndCopy(wasm, ikm);
|
|
2176
|
+
const saltPtr = allocAndCopy(wasm, salt);
|
|
2177
|
+
const infoPtr = allocAndCopy(wasm, info);
|
|
2178
|
+
const outPtr = wasm._hd_alloc(length);
|
|
2179
|
+
try {
|
|
2180
|
+
const result = wasm._hd_kdf_hkdf(ikmPtr, ikm.length, saltPtr, salt.length, infoPtr, info.length, outPtr, length);
|
|
2181
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2182
|
+
return readBytes(wasm, outPtr, length);
|
|
2183
|
+
} finally {
|
|
2184
|
+
wasm._hd_secure_wipe(ikmPtr, ikm.length);
|
|
2185
|
+
wasm._hd_dealloc(ikmPtr);
|
|
2186
|
+
wasm._hd_dealloc(saltPtr);
|
|
2187
|
+
wasm._hd_dealloc(infoPtr);
|
|
2188
|
+
wasm._hd_dealloc(outPtr);
|
|
2189
|
+
}
|
|
2190
|
+
},
|
|
2191
|
+
|
|
2192
|
+
pbkdf2(password, salt, iterations, length) {
|
|
2193
|
+
const pwdPtr = allocAndCopy(wasm, password);
|
|
2194
|
+
const saltPtr = allocAndCopy(wasm, salt);
|
|
2195
|
+
const outPtr = wasm._hd_alloc(length);
|
|
2196
|
+
try {
|
|
2197
|
+
const result = wasm._hd_kdf_pbkdf2(pwdPtr, password.length, saltPtr, salt.length, iterations, outPtr, length);
|
|
2198
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2199
|
+
return readBytes(wasm, outPtr, length);
|
|
2200
|
+
} finally {
|
|
2201
|
+
wasm._hd_secure_wipe(pwdPtr, password.length);
|
|
2202
|
+
wasm._hd_dealloc(pwdPtr);
|
|
2203
|
+
wasm._hd_dealloc(saltPtr);
|
|
2204
|
+
wasm._hd_dealloc(outPtr);
|
|
2205
|
+
}
|
|
2206
|
+
},
|
|
2207
|
+
|
|
2208
|
+
scrypt(password, salt, n, r, p, length) {
|
|
2209
|
+
const pwdPtr = allocAndCopy(wasm, password);
|
|
2210
|
+
const saltPtr = allocAndCopy(wasm, salt);
|
|
2211
|
+
const outPtr = wasm._hd_alloc(length);
|
|
2212
|
+
try {
|
|
2213
|
+
const result = wasm._hd_kdf_scrypt(pwdPtr, password.length, saltPtr, salt.length, BigInt(n), r, p, outPtr, length);
|
|
2214
|
+
if (result < 0) throw new HDWalletError(result);
|
|
2215
|
+
return readBytes(wasm, outPtr, length);
|
|
2216
|
+
} finally {
|
|
2217
|
+
wasm._hd_secure_wipe(pwdPtr, password.length);
|
|
2218
|
+
wasm._hd_dealloc(pwdPtr);
|
|
2219
|
+
wasm._hd_dealloc(saltPtr);
|
|
2220
|
+
wasm._hd_dealloc(outPtr);
|
|
2221
|
+
}
|
|
2222
|
+
},
|
|
2223
|
+
|
|
2224
|
+
// Encoding
|
|
2225
|
+
encodeBase58(data) {
|
|
2226
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2227
|
+
try {
|
|
2228
|
+
const ptr = wasm._hd_encode_base58(dataPtr, data.length);
|
|
2229
|
+
return readString(wasm, ptr);
|
|
2230
|
+
} finally {
|
|
2231
|
+
wasm._hd_dealloc(dataPtr);
|
|
2232
|
+
}
|
|
2233
|
+
},
|
|
2234
|
+
|
|
2235
|
+
decodeBase58(str) {
|
|
2236
|
+
const strPtr = allocString(wasm, str);
|
|
2237
|
+
const outPtr = wasm._hd_alloc(256);
|
|
2238
|
+
const sizePtr = wasm._hd_alloc(4);
|
|
2239
|
+
try {
|
|
2240
|
+
wasm.setValue(sizePtr, 256, 'i32');
|
|
2241
|
+
const result = wasm._hd_decode_base58(strPtr, outPtr, sizePtr);
|
|
2242
|
+
checkResult(result);
|
|
2243
|
+
const size = wasm.getValue(sizePtr, 'i32');
|
|
2244
|
+
return readBytes(wasm, outPtr, size);
|
|
2245
|
+
} finally {
|
|
2246
|
+
wasm._hd_dealloc(strPtr);
|
|
2247
|
+
wasm._hd_dealloc(outPtr);
|
|
2248
|
+
wasm._hd_dealloc(sizePtr);
|
|
2249
|
+
}
|
|
2250
|
+
},
|
|
2251
|
+
|
|
2252
|
+
encodeBase58Check(data) {
|
|
2253
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2254
|
+
try {
|
|
2255
|
+
const ptr = wasm._hd_encode_base58check(dataPtr, data.length);
|
|
2256
|
+
return readString(wasm, ptr);
|
|
2257
|
+
} finally {
|
|
2258
|
+
wasm._hd_dealloc(dataPtr);
|
|
2259
|
+
}
|
|
2260
|
+
},
|
|
2261
|
+
|
|
2262
|
+
decodeBase58Check(str) {
|
|
2263
|
+
const strPtr = allocString(wasm, str);
|
|
2264
|
+
const outPtr = wasm._hd_alloc(256);
|
|
2265
|
+
const sizePtr = wasm._hd_alloc(4);
|
|
2266
|
+
try {
|
|
2267
|
+
wasm.setValue(sizePtr, 256, 'i32');
|
|
2268
|
+
const result = wasm._hd_decode_base58check(strPtr, outPtr, sizePtr);
|
|
2269
|
+
checkResult(result);
|
|
2270
|
+
const size = wasm.getValue(sizePtr, 'i32');
|
|
2271
|
+
return readBytes(wasm, outPtr, size);
|
|
2272
|
+
} finally {
|
|
2273
|
+
wasm._hd_dealloc(strPtr);
|
|
2274
|
+
wasm._hd_dealloc(outPtr);
|
|
2275
|
+
wasm._hd_dealloc(sizePtr);
|
|
2276
|
+
}
|
|
2277
|
+
},
|
|
2278
|
+
|
|
2279
|
+
encodeBech32(hrp, data) {
|
|
2280
|
+
const hrpPtr = allocString(wasm, hrp);
|
|
2281
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2282
|
+
try {
|
|
2283
|
+
const ptr = wasm._hd_encode_bech32(hrpPtr, dataPtr, data.length);
|
|
2284
|
+
return readString(wasm, ptr);
|
|
2285
|
+
} finally {
|
|
2286
|
+
wasm._hd_dealloc(hrpPtr);
|
|
2287
|
+
wasm._hd_dealloc(dataPtr);
|
|
2288
|
+
}
|
|
2289
|
+
},
|
|
2290
|
+
|
|
2291
|
+
decodeBech32(str) {
|
|
2292
|
+
const strPtr = allocString(wasm, str);
|
|
2293
|
+
const hrpPtr = wasm._hd_alloc(128);
|
|
2294
|
+
const dataPtr = wasm._hd_alloc(256);
|
|
2295
|
+
const sizePtr = wasm._hd_alloc(4);
|
|
2296
|
+
try {
|
|
2297
|
+
wasm.setValue(sizePtr, 256, 'i32');
|
|
2298
|
+
const result = wasm._hd_decode_bech32(strPtr, hrpPtr, 128, dataPtr, sizePtr);
|
|
2299
|
+
checkResult(result);
|
|
2300
|
+
const size = wasm.getValue(sizePtr, 'i32');
|
|
2301
|
+
return {
|
|
2302
|
+
hrp: readString(wasm, hrpPtr),
|
|
2303
|
+
data: readBytes(wasm, dataPtr, size)
|
|
2304
|
+
};
|
|
2305
|
+
} finally {
|
|
2306
|
+
wasm._hd_dealloc(strPtr);
|
|
2307
|
+
wasm._hd_dealloc(hrpPtr);
|
|
2308
|
+
wasm._hd_dealloc(dataPtr);
|
|
2309
|
+
wasm._hd_dealloc(sizePtr);
|
|
2310
|
+
}
|
|
2311
|
+
},
|
|
2312
|
+
|
|
2313
|
+
encodeHex(data) {
|
|
2314
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2315
|
+
try {
|
|
2316
|
+
const ptr = wasm._hd_encode_hex(dataPtr, data.length);
|
|
2317
|
+
return readString(wasm, ptr);
|
|
2318
|
+
} finally {
|
|
2319
|
+
wasm._hd_dealloc(dataPtr);
|
|
2320
|
+
}
|
|
2321
|
+
},
|
|
2322
|
+
|
|
2323
|
+
decodeHex(str) {
|
|
2324
|
+
const strPtr = allocString(wasm, str);
|
|
2325
|
+
const outPtr = wasm._hd_alloc(str.length / 2);
|
|
2326
|
+
const sizePtr = wasm._hd_alloc(4);
|
|
2327
|
+
try {
|
|
2328
|
+
wasm.setValue(sizePtr, str.length / 2, 'i32');
|
|
2329
|
+
const result = wasm._hd_decode_hex(strPtr, outPtr, sizePtr);
|
|
2330
|
+
checkResult(result);
|
|
2331
|
+
const size = wasm.getValue(sizePtr, 'i32');
|
|
2332
|
+
return readBytes(wasm, outPtr, size);
|
|
2333
|
+
} finally {
|
|
2334
|
+
wasm._hd_dealloc(strPtr);
|
|
2335
|
+
wasm._hd_dealloc(outPtr);
|
|
2336
|
+
wasm._hd_dealloc(sizePtr);
|
|
2337
|
+
}
|
|
2338
|
+
},
|
|
2339
|
+
|
|
2340
|
+
encodeBase64(data) {
|
|
2341
|
+
const dataPtr = allocAndCopy(wasm, data);
|
|
2342
|
+
try {
|
|
2343
|
+
const ptr = wasm._hd_encode_base64(dataPtr, data.length);
|
|
2344
|
+
return readString(wasm, ptr);
|
|
2345
|
+
} finally {
|
|
2346
|
+
wasm._hd_dealloc(dataPtr);
|
|
2347
|
+
}
|
|
2348
|
+
},
|
|
2349
|
+
|
|
2350
|
+
decodeBase64(str) {
|
|
2351
|
+
const strPtr = allocString(wasm, str);
|
|
2352
|
+
const outPtr = wasm._hd_alloc(str.length);
|
|
2353
|
+
const sizePtr = wasm._hd_alloc(4);
|
|
2354
|
+
try {
|
|
2355
|
+
wasm.setValue(sizePtr, str.length, 'i32');
|
|
2356
|
+
const result = wasm._hd_decode_base64(strPtr, outPtr, sizePtr);
|
|
2357
|
+
checkResult(result);
|
|
2358
|
+
const size = wasm.getValue(sizePtr, 'i32');
|
|
2359
|
+
return readBytes(wasm, outPtr, size);
|
|
2360
|
+
} finally {
|
|
2361
|
+
wasm._hd_dealloc(strPtr);
|
|
2362
|
+
wasm._hd_dealloc(outPtr);
|
|
2363
|
+
wasm._hd_dealloc(sizePtr);
|
|
2364
|
+
}
|
|
2365
|
+
},
|
|
2366
|
+
|
|
2367
|
+
// Memory
|
|
2368
|
+
secureWipe(data) {
|
|
2369
|
+
if (data instanceof Uint8Array) {
|
|
2370
|
+
// Wipe in-place
|
|
2371
|
+
for (let i = 0; i < data.length; i++) {
|
|
2372
|
+
data[i] = 0;
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
|
|
2378
|
+
// ==========================================================================
|
|
2379
|
+
// Return the module API
|
|
2380
|
+
// ==========================================================================
|
|
2381
|
+
|
|
2382
|
+
return {
|
|
2383
|
+
// Module info
|
|
2384
|
+
getVersion() {
|
|
2385
|
+
const ptr = wasm._hd_get_version_string();
|
|
2386
|
+
return readString(wasm, ptr);
|
|
2387
|
+
},
|
|
2388
|
+
|
|
2389
|
+
hasCryptopp() {
|
|
2390
|
+
return wasm._hd_has_cryptopp() !== 0;
|
|
2391
|
+
},
|
|
2392
|
+
|
|
2393
|
+
isFipsMode() {
|
|
2394
|
+
return wasm._hd_is_fips_mode() !== 0;
|
|
2395
|
+
},
|
|
2396
|
+
|
|
2397
|
+
getSupportedCoins() {
|
|
2398
|
+
const ptr = wasm._hd_get_supported_coins();
|
|
2399
|
+
return JSON.parse(readString(wasm, ptr));
|
|
2400
|
+
},
|
|
2401
|
+
|
|
2402
|
+
getSupportedCurves() {
|
|
2403
|
+
const ptr = wasm._hd_get_supported_curves();
|
|
2404
|
+
return JSON.parse(readString(wasm, ptr));
|
|
2405
|
+
},
|
|
2406
|
+
|
|
2407
|
+
// WASI bridge
|
|
2408
|
+
wasiHasFeature(feature) {
|
|
2409
|
+
return wasm._hd_wasi_has_feature(feature) !== 0;
|
|
2410
|
+
},
|
|
2411
|
+
|
|
2412
|
+
wasiGetWarning(feature) {
|
|
2413
|
+
return wasm._hd_wasi_get_warning(feature);
|
|
2414
|
+
},
|
|
2415
|
+
|
|
2416
|
+
wasiGetWarningMessage(feature) {
|
|
2417
|
+
const ptr = wasm._hd_wasi_get_warning_message(feature);
|
|
2418
|
+
return readString(wasm, ptr);
|
|
2419
|
+
},
|
|
2420
|
+
|
|
2421
|
+
// Entropy
|
|
2422
|
+
injectEntropy(entropy) {
|
|
2423
|
+
const entropyPtr = allocAndCopy(wasm, entropy);
|
|
2424
|
+
try {
|
|
2425
|
+
wasm._hd_inject_entropy(entropyPtr, entropy.length);
|
|
2426
|
+
} finally {
|
|
2427
|
+
wasm._hd_secure_wipe(entropyPtr, entropy.length);
|
|
2428
|
+
wasm._hd_dealloc(entropyPtr);
|
|
2429
|
+
}
|
|
2430
|
+
},
|
|
2431
|
+
|
|
2432
|
+
getEntropyStatus() {
|
|
2433
|
+
return wasm._hd_get_entropy_status();
|
|
2434
|
+
},
|
|
2435
|
+
|
|
2436
|
+
// APIs
|
|
2437
|
+
mnemonic,
|
|
2438
|
+
hdkey,
|
|
2439
|
+
curves,
|
|
2440
|
+
bitcoin,
|
|
2441
|
+
ethereum,
|
|
2442
|
+
cosmos,
|
|
2443
|
+
solana,
|
|
2444
|
+
polkadot,
|
|
2445
|
+
hardware,
|
|
2446
|
+
keyring,
|
|
2447
|
+
utils
|
|
2448
|
+
};
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
// =============================================================================
|
|
2452
|
+
// Module Export
|
|
2453
|
+
// =============================================================================
|
|
2454
|
+
|
|
2455
|
+
/**
|
|
2456
|
+
* Initialize the HD Wallet WASM module
|
|
2457
|
+
* @param {string} [wasmPath] - Optional path to WASM file
|
|
2458
|
+
* @returns {Promise<Object>} Initialized HDWalletModule
|
|
2459
|
+
*/
|
|
2460
|
+
export default async function init(wasmPath) {
|
|
2461
|
+
const wasm = await loadWasmModule(wasmPath);
|
|
2462
|
+
return createModule(wasm);
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
/**
|
|
2466
|
+
* Create HD Wallet instance (alternative syntax)
|
|
2467
|
+
* @param {string} [wasmPath] - Optional path to WASM file
|
|
2468
|
+
* @returns {Promise<Object>} Initialized HDWalletModule
|
|
2469
|
+
*/
|
|
2470
|
+
export async function createHDWallet(wasmPath) {
|
|
2471
|
+
return init(wasmPath);
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
// Export types and enums
|
|
2475
|
+
export {
|
|
2476
|
+
HDKey,
|
|
2477
|
+
HDWalletError,
|
|
2478
|
+
ErrorCode
|
|
2479
|
+
};
|