hd-wallet-wasm 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -570,7 +570,7 @@ export interface Keyring {
570
570
  // =============================================================================
571
571
 
572
572
  export interface UtilsAPI {
573
- // Hashing
573
+ // Hashing (sync - Crypto++)
574
574
  sha256(data: Uint8Array): Uint8Array;
575
575
  sha512(data: Uint8Array): Uint8Array;
576
576
  keccak256(data: Uint8Array): Uint8Array;
@@ -579,11 +579,29 @@ export interface UtilsAPI {
579
579
  blake2b(data: Uint8Array, outputLength?: number): Uint8Array;
580
580
  blake2s(data: Uint8Array, outputLength?: number): Uint8Array;
581
581
 
582
- // Key derivation
582
+ // Key derivation (sync - Crypto++)
583
583
  hkdf(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Uint8Array;
584
584
  pbkdf2(password: Uint8Array, salt: Uint8Array, iterations: number, length: number): Uint8Array;
585
585
  scrypt(password: Uint8Array, salt: Uint8Array, n: number, r: number, p: number, length: number): Uint8Array;
586
586
 
587
+ // Key derivation (async - WebCrypto, hardware accelerated)
588
+ hkdfSha256Async(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Promise<Uint8Array>;
589
+ hkdfSha384Async(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Promise<Uint8Array>;
590
+
591
+ // AES-GCM encryption/decryption (async - WebCrypto, hardware accelerated)
592
+ aesGcm: {
593
+ encrypt(key: Uint8Array, plaintext: Uint8Array, iv: Uint8Array, aad?: Uint8Array): Promise<{ ciphertext: Uint8Array; tag: Uint8Array }>;
594
+ decrypt(key: Uint8Array, ciphertext: Uint8Array, tag: Uint8Array, iv: Uint8Array, aad?: Uint8Array): Promise<Uint8Array>;
595
+ generateIv(): Uint8Array;
596
+ generateKey(bits?: number): Uint8Array;
597
+ };
598
+
599
+ // WebCrypto availability
600
+ isWebCryptoAvailable(): boolean;
601
+
602
+ // Random number generation
603
+ getRandomBytes(length: number): Uint8Array;
604
+
587
605
  // Encoding
588
606
  encodeBase58(data: Uint8Array): string;
589
607
  decodeBase58(str: string): Uint8Array;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hd-wallet-wasm",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "description": "Comprehensive HD Wallet implementation in WebAssembly - BIP-32/39/44, multi-curve, multi-chain support",
5
5
  "type": "module",
6
6
  "main": "src/index.mjs",
@@ -25,6 +25,7 @@
25
25
  "files": [
26
26
  "src/index.mjs",
27
27
  "src/index.d.ts",
28
+ "src/webcrypto.mjs",
28
29
  "src/aligned.mjs",
29
30
  "src/aligned.d.ts",
30
31
  "src/generated/",
package/src/index.d.ts CHANGED
@@ -570,7 +570,7 @@ export interface Keyring {
570
570
  // =============================================================================
571
571
 
572
572
  export interface UtilsAPI {
573
- // Hashing
573
+ // Hashing (sync - Crypto++)
574
574
  sha256(data: Uint8Array): Uint8Array;
575
575
  sha512(data: Uint8Array): Uint8Array;
576
576
  keccak256(data: Uint8Array): Uint8Array;
@@ -579,11 +579,29 @@ export interface UtilsAPI {
579
579
  blake2b(data: Uint8Array, outputLength?: number): Uint8Array;
580
580
  blake2s(data: Uint8Array, outputLength?: number): Uint8Array;
581
581
 
582
- // Key derivation
582
+ // Key derivation (sync - Crypto++)
583
583
  hkdf(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Uint8Array;
584
584
  pbkdf2(password: Uint8Array, salt: Uint8Array, iterations: number, length: number): Uint8Array;
585
585
  scrypt(password: Uint8Array, salt: Uint8Array, n: number, r: number, p: number, length: number): Uint8Array;
586
586
 
587
+ // Key derivation (async - WebCrypto, hardware accelerated)
588
+ hkdfSha256Async(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Promise<Uint8Array>;
589
+ hkdfSha384Async(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Promise<Uint8Array>;
590
+
591
+ // AES-GCM encryption/decryption (async - WebCrypto, hardware accelerated)
592
+ aesGcm: {
593
+ encrypt(key: Uint8Array, plaintext: Uint8Array, iv: Uint8Array, aad?: Uint8Array): Promise<{ ciphertext: Uint8Array; tag: Uint8Array }>;
594
+ decrypt(key: Uint8Array, ciphertext: Uint8Array, tag: Uint8Array, iv: Uint8Array, aad?: Uint8Array): Promise<Uint8Array>;
595
+ generateIv(): Uint8Array;
596
+ generateKey(bits?: number): Uint8Array;
597
+ };
598
+
599
+ // WebCrypto availability
600
+ isWebCryptoAvailable(): boolean;
601
+
602
+ // Random number generation
603
+ getRandomBytes(length: number): Uint8Array;
604
+
587
605
  // Encoding
588
606
  encodeBase58(data: Uint8Array): string;
589
607
  decodeBase58(str: string): Uint8Array;
package/src/index.mjs CHANGED
@@ -15,6 +15,9 @@
15
15
  // Import aligned API for batch operations
16
16
  import { AlignedAPI } from './aligned.mjs';
17
17
 
18
+ // Import WebCrypto bridge for hardware-accelerated async operations
19
+ import * as WebCrypto from './webcrypto.mjs';
20
+
18
21
  // =============================================================================
19
22
  // Enums (matching TypeScript definitions)
20
23
  // =============================================================================
@@ -2219,7 +2222,7 @@ function createModule(wasm) {
2219
2222
  }
2220
2223
  },
2221
2224
 
2222
- // Key derivation
2225
+ // Key derivation (sync - uses Crypto++ in WASM)
2223
2226
  hkdf(ikm, salt, info, length) {
2224
2227
  const ikmPtr = allocAndCopy(wasm, ikm);
2225
2228
  const saltPtr = allocAndCopy(wasm, salt);
@@ -2238,6 +2241,46 @@ function createModule(wasm) {
2238
2241
  }
2239
2242
  },
2240
2243
 
2244
+ // Key derivation (async - uses WebCrypto for hardware acceleration)
2245
+ hkdfSha256Async: WebCrypto.hkdfSha256,
2246
+ hkdfSha384Async: WebCrypto.hkdfSha384,
2247
+
2248
+ // AES-GCM encryption/decryption (async - uses WebCrypto)
2249
+ aesGcm: {
2250
+ /**
2251
+ * Encrypt data with AES-GCM (WebCrypto)
2252
+ * @param {Uint8Array} key - AES key (16, 24, or 32 bytes)
2253
+ * @param {Uint8Array} plaintext - Data to encrypt
2254
+ * @param {Uint8Array} iv - Initialization vector (12 bytes recommended)
2255
+ * @param {Uint8Array} [aad] - Additional authenticated data
2256
+ * @returns {Promise<{ciphertext: Uint8Array, tag: Uint8Array}>}
2257
+ */
2258
+ encrypt: WebCrypto.aesGcmEncrypt,
2259
+
2260
+ /**
2261
+ * Decrypt data with AES-GCM (WebCrypto)
2262
+ * @param {Uint8Array} key - AES key
2263
+ * @param {Uint8Array} ciphertext - Encrypted data
2264
+ * @param {Uint8Array} tag - Authentication tag (16 bytes)
2265
+ * @param {Uint8Array} iv - Initialization vector
2266
+ * @param {Uint8Array} [aad] - Additional authenticated data
2267
+ * @returns {Promise<Uint8Array>} Decrypted plaintext
2268
+ */
2269
+ decrypt: WebCrypto.aesGcmDecrypt,
2270
+
2271
+ /** Generate a random IV (12 bytes) */
2272
+ generateIv: WebCrypto.generateIv,
2273
+
2274
+ /** Generate a random AES key (default 256 bits) */
2275
+ generateKey: WebCrypto.generateAesKey
2276
+ },
2277
+
2278
+ /** Check if WebCrypto is available */
2279
+ isWebCryptoAvailable: WebCrypto.isWebCryptoAvailable,
2280
+
2281
+ /** Generate cryptographically secure random bytes */
2282
+ getRandomBytes: WebCrypto.getRandomBytes,
2283
+
2241
2284
  pbkdf2(password, salt, iterations, length) {
2242
2285
  const pwdPtr = allocAndCopy(wasm, password);
2243
2286
  const saltPtr = allocAndCopy(wasm, salt);
@@ -0,0 +1,216 @@
1
+ /**
2
+ * WebCrypto Bridge - Hardware-accelerated cryptographic operations
3
+ *
4
+ * These functions use the browser's native WebCrypto API for
5
+ * hardware-accelerated, constant-time cryptographic operations.
6
+ *
7
+ * All functions are async because WebCrypto is Promise-based.
8
+ */
9
+
10
+ /**
11
+ * Check if WebCrypto is available
12
+ * @returns {boolean}
13
+ */
14
+ export function isWebCryptoAvailable() {
15
+ return typeof globalThis.crypto !== 'undefined' &&
16
+ typeof globalThis.crypto.subtle !== 'undefined';
17
+ }
18
+
19
+ /**
20
+ * AES-GCM Encryption using WebCrypto
21
+ * @param {Uint8Array} key - AES key (128, 192, or 256 bits = 16, 24, or 32 bytes)
22
+ * @param {Uint8Array} plaintext - Data to encrypt
23
+ * @param {Uint8Array} iv - Initialization vector (12 bytes recommended for GCM)
24
+ * @param {Uint8Array} [aad] - Additional authenticated data (optional)
25
+ * @returns {Promise<{ciphertext: Uint8Array, tag: Uint8Array}>}
26
+ */
27
+ export async function aesGcmEncrypt(key, plaintext, iv, aad = null) {
28
+ if (!isWebCryptoAvailable()) {
29
+ throw new Error('WebCrypto not available');
30
+ }
31
+
32
+ const cryptoKey = await crypto.subtle.importKey(
33
+ 'raw',
34
+ key,
35
+ { name: 'AES-GCM' },
36
+ false,
37
+ ['encrypt']
38
+ );
39
+
40
+ const algorithmParams = {
41
+ name: 'AES-GCM',
42
+ iv: iv,
43
+ tagLength: 128 // 16 bytes
44
+ };
45
+
46
+ if (aad && aad.length > 0) {
47
+ algorithmParams.additionalData = aad;
48
+ }
49
+
50
+ const encrypted = await crypto.subtle.encrypt(
51
+ algorithmParams,
52
+ cryptoKey,
53
+ plaintext
54
+ );
55
+
56
+ // WebCrypto returns ciphertext + tag combined
57
+ const fullResult = new Uint8Array(encrypted);
58
+ const ciphertext = fullResult.slice(0, fullResult.length - 16);
59
+ const tag = fullResult.slice(fullResult.length - 16);
60
+
61
+ return { ciphertext, tag };
62
+ }
63
+
64
+ /**
65
+ * AES-GCM Decryption using WebCrypto
66
+ * @param {Uint8Array} key - AES key (128, 192, or 256 bits)
67
+ * @param {Uint8Array} ciphertext - Encrypted data
68
+ * @param {Uint8Array} tag - Authentication tag (16 bytes)
69
+ * @param {Uint8Array} iv - Initialization vector used during encryption
70
+ * @param {Uint8Array} [aad] - Additional authenticated data (must match encryption)
71
+ * @returns {Promise<Uint8Array>} Decrypted plaintext
72
+ * @throws {Error} If decryption fails (invalid tag, wrong key, etc.)
73
+ */
74
+ export async function aesGcmDecrypt(key, ciphertext, tag, iv, aad = null) {
75
+ if (!isWebCryptoAvailable()) {
76
+ throw new Error('WebCrypto not available');
77
+ }
78
+
79
+ const cryptoKey = await crypto.subtle.importKey(
80
+ 'raw',
81
+ key,
82
+ { name: 'AES-GCM' },
83
+ false,
84
+ ['decrypt']
85
+ );
86
+
87
+ // Reconstruct the full ciphertext + tag format WebCrypto expects
88
+ const encrypted = new Uint8Array(ciphertext.length + tag.length);
89
+ encrypted.set(ciphertext, 0);
90
+ encrypted.set(tag, ciphertext.length);
91
+
92
+ const algorithmParams = {
93
+ name: 'AES-GCM',
94
+ iv: iv,
95
+ tagLength: 128
96
+ };
97
+
98
+ if (aad && aad.length > 0) {
99
+ algorithmParams.additionalData = aad;
100
+ }
101
+
102
+ try {
103
+ const decrypted = await crypto.subtle.decrypt(
104
+ algorithmParams,
105
+ cryptoKey,
106
+ encrypted
107
+ );
108
+ return new Uint8Array(decrypted);
109
+ } catch (err) {
110
+ throw new Error('AES-GCM decryption failed: authentication tag mismatch or invalid data');
111
+ }
112
+ }
113
+
114
+ /**
115
+ * HKDF using WebCrypto (SHA-256)
116
+ * @param {Uint8Array} ikm - Input keying material
117
+ * @param {Uint8Array} salt - Salt value (can be empty Uint8Array)
118
+ * @param {Uint8Array} info - Context/application-specific info (can be empty)
119
+ * @param {number} length - Desired output length in bytes
120
+ * @returns {Promise<Uint8Array>} Derived key material
121
+ */
122
+ export async function hkdfSha256(ikm, salt, info, length) {
123
+ if (!isWebCryptoAvailable()) {
124
+ throw new Error('WebCrypto not available');
125
+ }
126
+
127
+ const keyMaterial = await crypto.subtle.importKey(
128
+ 'raw',
129
+ ikm,
130
+ { name: 'HKDF' },
131
+ false,
132
+ ['deriveBits']
133
+ );
134
+
135
+ const derivedBits = await crypto.subtle.deriveBits(
136
+ {
137
+ name: 'HKDF',
138
+ hash: 'SHA-256',
139
+ salt: salt.length > 0 ? salt : new Uint8Array(32), // WebCrypto requires non-empty salt
140
+ info: info
141
+ },
142
+ keyMaterial,
143
+ length * 8
144
+ );
145
+
146
+ return new Uint8Array(derivedBits);
147
+ }
148
+
149
+ /**
150
+ * HKDF using WebCrypto (SHA-384)
151
+ * @param {Uint8Array} ikm - Input keying material
152
+ * @param {Uint8Array} salt - Salt value
153
+ * @param {Uint8Array} info - Context/application-specific info
154
+ * @param {number} length - Desired output length in bytes
155
+ * @returns {Promise<Uint8Array>} Derived key material
156
+ */
157
+ export async function hkdfSha384(ikm, salt, info, length) {
158
+ if (!isWebCryptoAvailable()) {
159
+ throw new Error('WebCrypto not available');
160
+ }
161
+
162
+ const keyMaterial = await crypto.subtle.importKey(
163
+ 'raw',
164
+ ikm,
165
+ { name: 'HKDF' },
166
+ false,
167
+ ['deriveBits']
168
+ );
169
+
170
+ const derivedBits = await crypto.subtle.deriveBits(
171
+ {
172
+ name: 'HKDF',
173
+ hash: 'SHA-384',
174
+ salt: salt.length > 0 ? salt : new Uint8Array(48),
175
+ info: info
176
+ },
177
+ keyMaterial,
178
+ length * 8
179
+ );
180
+
181
+ return new Uint8Array(derivedBits);
182
+ }
183
+
184
+ /**
185
+ * Generate cryptographically secure random bytes
186
+ * @param {number} length - Number of random bytes to generate
187
+ * @returns {Uint8Array} Random bytes
188
+ */
189
+ export function getRandomBytes(length) {
190
+ if (!isWebCryptoAvailable()) {
191
+ throw new Error('WebCrypto not available');
192
+ }
193
+ const bytes = new Uint8Array(length);
194
+ crypto.getRandomValues(bytes);
195
+ return bytes;
196
+ }
197
+
198
+ /**
199
+ * Generate a random AES-GCM IV (12 bytes recommended)
200
+ * @returns {Uint8Array} 12-byte IV
201
+ */
202
+ export function generateIv() {
203
+ return getRandomBytes(12);
204
+ }
205
+
206
+ /**
207
+ * Generate a random AES key
208
+ * @param {number} [bits=256] - Key size in bits (128, 192, or 256)
209
+ * @returns {Uint8Array} Random key
210
+ */
211
+ export function generateAesKey(bits = 256) {
212
+ if (![128, 192, 256].includes(bits)) {
213
+ throw new Error('AES key size must be 128, 192, or 256 bits');
214
+ }
215
+ return getRandomBytes(bits / 8);
216
+ }