@opendatalabs/vana-sdk 0.1.0-alpha.5f8458e → 0.1.0-alpha.606fa2d

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.
Files changed (50) hide show
  1. package/README.md +55 -4
  2. package/dist/{browser-cRpdLQ3-.d.ts → browser-Bb8gLWHp.d.ts} +61 -10
  3. package/dist/browser.d.ts +1 -1
  4. package/dist/browser.js +745 -113
  5. package/dist/browser.js.map +1 -1
  6. package/dist/chains.browser.cjs +2 -2
  7. package/dist/chains.browser.cjs.map +1 -1
  8. package/dist/chains.browser.js +2 -2
  9. package/dist/chains.browser.js.map +1 -1
  10. package/dist/chains.cjs +2 -2
  11. package/dist/chains.cjs.map +1 -1
  12. package/dist/chains.js +2 -2
  13. package/dist/chains.js.map +1 -1
  14. package/dist/chains.node.cjs +2 -2
  15. package/dist/chains.node.cjs.map +1 -1
  16. package/dist/chains.node.js +2 -2
  17. package/dist/chains.node.js.map +1 -1
  18. package/dist/index.browser.d.ts +1348 -243
  19. package/dist/index.browser.js +35080 -32770
  20. package/dist/index.browser.js.map +1 -1
  21. package/dist/index.node.cjs +35587 -33174
  22. package/dist/index.node.cjs.map +1 -1
  23. package/dist/index.node.d.cts +1136 -250
  24. package/dist/index.node.d.ts +1136 -250
  25. package/dist/index.node.js +35459 -33037
  26. package/dist/index.node.js.map +1 -1
  27. package/dist/{node-CkdgwBiv.d.cts → node-D9-F9uEP.d.cts} +3 -2
  28. package/dist/{node-CkdgwBiv.d.ts → node-D9-F9uEP.d.ts} +3 -2
  29. package/dist/node.cjs +704 -67
  30. package/dist/node.cjs.map +1 -1
  31. package/dist/node.d.cts +1 -1
  32. package/dist/node.d.ts +1 -1
  33. package/dist/node.js +716 -66
  34. package/dist/node.js.map +1 -1
  35. package/dist/platform.browser.d.ts +2 -2
  36. package/dist/platform.browser.js +808 -121
  37. package/dist/platform.browser.js.map +1 -1
  38. package/dist/platform.cjs +973 -186
  39. package/dist/platform.cjs.map +1 -1
  40. package/dist/platform.d.cts +1 -1
  41. package/dist/platform.d.ts +1 -1
  42. package/dist/platform.js +985 -186
  43. package/dist/platform.js.map +1 -1
  44. package/dist/platform.node.cjs +973 -186
  45. package/dist/platform.node.cjs.map +1 -1
  46. package/dist/platform.node.d.cts +63 -12
  47. package/dist/platform.node.d.ts +63 -12
  48. package/dist/platform.node.js +985 -186
  49. package/dist/platform.node.js.map +1 -1
  50. package/package.json +40 -23
package/dist/browser.js CHANGED
@@ -2,29 +2,6 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
 
5
- // src/platform/browser.ts
6
- import * as openpgp from "openpgp";
7
-
8
- // src/platform/shared/crypto-utils.ts
9
- function processWalletPublicKey(publicKey) {
10
- const publicKeyHex = publicKey.startsWith("0x") ? publicKey.slice(2) : publicKey;
11
- const publicKeyBytes = Buffer.from(publicKeyHex, "hex");
12
- return publicKeyBytes.length === 64 ? Buffer.concat([Buffer.from([4]), publicKeyBytes]) : publicKeyBytes;
13
- }
14
- function processWalletPrivateKey(privateKey) {
15
- const privateKeyHex = privateKey.startsWith("0x") ? privateKey.slice(2) : privateKey;
16
- return Buffer.from(privateKeyHex, "hex");
17
- }
18
- function parseEncryptedDataBuffer(encryptedBuffer) {
19
- return {
20
- iv: encryptedBuffer.slice(0, 16),
21
- ephemPublicKey: encryptedBuffer.slice(16, 81),
22
- // 65 bytes for uncompressed public key
23
- ciphertext: encryptedBuffer.slice(81, -32),
24
- mac: encryptedBuffer.slice(-32)
25
- };
26
- }
27
-
28
5
  // src/platform/shared/pgp-utils.ts
29
6
  var STANDARD_PGP_CONFIG = {
30
7
  preferredCompressionAlgorithm: 2,
@@ -56,131 +33,788 @@ function wrapCryptoError(operation, error) {
56
33
  return new Error(`${operation} failed: ${message}`);
57
34
  }
58
35
 
36
+ // src/utils/lazy-import.ts
37
+ function lazyImport(importFn) {
38
+ let cached = null;
39
+ return () => {
40
+ if (!cached) {
41
+ cached = importFn().catch((err) => {
42
+ cached = null;
43
+ throw new Error("Failed to load module", { cause: err });
44
+ });
45
+ }
46
+ return cached;
47
+ };
48
+ }
49
+
50
+ // src/utils/encoding.ts
51
+ function toHex(data) {
52
+ if (typeof Buffer !== "undefined" && Buffer.from) {
53
+ return Buffer.from(data).toString("hex");
54
+ }
55
+ return Array.from(data, (byte) => byte.toString(16).padStart(2, "0")).join(
56
+ ""
57
+ );
58
+ }
59
+ function fromHex(hex) {
60
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
61
+ if (cleanHex.length % 2 !== 0) {
62
+ throw new Error("Invalid hex string: odd length");
63
+ }
64
+ if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {
65
+ throw new Error("Invalid hex string: contains non-hex characters");
66
+ }
67
+ if (typeof Buffer !== "undefined" && Buffer.from) {
68
+ return new Uint8Array(Buffer.from(cleanHex, "hex"));
69
+ }
70
+ const bytes = new Uint8Array(cleanHex.length / 2);
71
+ for (let i = 0; i < cleanHex.length; i += 2) {
72
+ bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16);
73
+ }
74
+ return bytes;
75
+ }
76
+ function stringToBytes(str) {
77
+ if (typeof Buffer !== "undefined" && Buffer.from) {
78
+ return new Uint8Array(Buffer.from(str, "utf8"));
79
+ }
80
+ if (typeof TextEncoder !== "undefined") {
81
+ return new TextEncoder().encode(str);
82
+ }
83
+ const bytes = [];
84
+ for (let i = 0; i < str.length; i++) {
85
+ const char = str.charCodeAt(i);
86
+ if (char < 128) {
87
+ bytes.push(char);
88
+ } else if (char < 2048) {
89
+ bytes.push(192 | char >> 6, 128 | char & 63);
90
+ } else if (char < 55296 || char >= 57344) {
91
+ bytes.push(
92
+ 224 | char >> 12,
93
+ 128 | char >> 6 & 63,
94
+ 128 | char & 63
95
+ );
96
+ } else {
97
+ i++;
98
+ const char2 = str.charCodeAt(i);
99
+ const codePoint = 65536 + ((char & 1023) << 10 | char2 & 1023);
100
+ bytes.push(
101
+ 240 | codePoint >> 18,
102
+ 128 | codePoint >> 12 & 63,
103
+ 128 | codePoint >> 6 & 63,
104
+ 128 | codePoint & 63
105
+ );
106
+ }
107
+ }
108
+ return new Uint8Array(bytes);
109
+ }
110
+ function bytesToString(bytes) {
111
+ if (typeof Buffer !== "undefined" && Buffer.from) {
112
+ return Buffer.from(bytes).toString("utf8");
113
+ }
114
+ if (typeof TextDecoder !== "undefined") {
115
+ return new TextDecoder().decode(bytes);
116
+ }
117
+ let str = "";
118
+ let i = 0;
119
+ while (i < bytes.length) {
120
+ const byte = bytes[i];
121
+ if (byte < 128) {
122
+ str += String.fromCharCode(byte);
123
+ i++;
124
+ } else if ((byte & 224) === 192) {
125
+ str += String.fromCharCode((byte & 31) << 6 | bytes[i + 1] & 63);
126
+ i += 2;
127
+ } else if ((byte & 240) === 224) {
128
+ str += String.fromCharCode(
129
+ (byte & 15) << 12 | (bytes[i + 1] & 63) << 6 | bytes[i + 2] & 63
130
+ );
131
+ i += 3;
132
+ } else {
133
+ const codePoint = ((byte & 7) << 18 | (bytes[i + 1] & 63) << 12 | (bytes[i + 2] & 63) << 6 | bytes[i + 3] & 63) - 65536;
134
+ str += String.fromCharCode(
135
+ 55296 + (codePoint >> 10),
136
+ 56320 + (codePoint & 1023)
137
+ );
138
+ i += 4;
139
+ }
140
+ }
141
+ return str;
142
+ }
143
+
144
+ // src/utils/crypto-utils.ts
145
+ function concatBytes(...arrays) {
146
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
147
+ const result = new Uint8Array(totalLength);
148
+ let offset = 0;
149
+ for (const arr of arrays) {
150
+ result.set(arr, offset);
151
+ offset += arr.length;
152
+ }
153
+ return result;
154
+ }
155
+ function hexToBytes(hex) {
156
+ return fromHex(hex);
157
+ }
158
+ function bytesToHex(bytes) {
159
+ return toHex(bytes);
160
+ }
161
+ function processWalletPublicKey(publicKey) {
162
+ const publicKeyHex = typeof publicKey === "string" ? publicKey.startsWith("0x") ? publicKey.slice(2) : publicKey : bytesToHex(publicKey);
163
+ const publicKeyBytes = hexToBytes(publicKeyHex);
164
+ return publicKeyBytes.length === 64 ? concatBytes(new Uint8Array([4]), publicKeyBytes) : publicKeyBytes;
165
+ }
166
+ function processWalletPrivateKey(privateKey) {
167
+ const privateKeyHex = typeof privateKey === "string" ? privateKey.startsWith("0x") ? privateKey.slice(2) : privateKey : bytesToHex(privateKey);
168
+ return hexToBytes(privateKeyHex);
169
+ }
170
+ function parseEncryptedDataBuffer(encryptedBuffer) {
171
+ return {
172
+ iv: encryptedBuffer.slice(0, 16),
173
+ ephemPublicKey: encryptedBuffer.slice(16, 81),
174
+ // 65 bytes for uncompressed public key
175
+ ciphertext: encryptedBuffer.slice(81, -32),
176
+ mac: encryptedBuffer.slice(-32)
177
+ };
178
+ }
179
+
180
+ // src/crypto/services/WalletKeyEncryptionService.ts
181
+ var WalletKeyEncryptionService = class {
182
+ constructor(config) {
183
+ __publicField(this, "eciesProvider");
184
+ this.eciesProvider = config.eciesProvider;
185
+ }
186
+ /**
187
+ * Encrypts data using a wallet's public key.
188
+ *
189
+ * @param data - The plaintext message to encrypt for the wallet owner.
190
+ * @param publicKey - The recipient wallet's public key for encryption.
191
+ * @returns A promise that resolves to the encrypted data as a hex string.
192
+ * @throws {Error} When encryption fails due to invalid key format.
193
+ *
194
+ * @example
195
+ * ```typescript
196
+ * const encrypted = await processor.encryptWithWalletPublicKey(
197
+ * "Secret message",
198
+ * "0x04..." // 65-byte uncompressed public key
199
+ * );
200
+ * console.log(`Encrypted: ${encrypted}`);
201
+ * ```
202
+ */
203
+ async encryptWithWalletPublicKey(data, publicKey) {
204
+ const publicKeyBytes = processWalletPublicKey(publicKey);
205
+ const dataBytes = stringToBytes(data);
206
+ const encrypted = await this.eciesProvider.encrypt(
207
+ publicKeyBytes,
208
+ dataBytes
209
+ );
210
+ const result = concatBytes(
211
+ encrypted.iv,
212
+ encrypted.ephemPublicKey,
213
+ encrypted.ciphertext,
214
+ encrypted.mac
215
+ );
216
+ return bytesToHex(result);
217
+ }
218
+ /**
219
+ * Decrypts data using a wallet's private key.
220
+ *
221
+ * @param encryptedData - The hex-encoded encrypted data to decrypt.
222
+ * @param privateKey - The wallet's private key for decryption.
223
+ * @returns A promise that resolves to the decrypted plaintext message.
224
+ * @throws {Error} When decryption fails due to invalid data or key format.
225
+ *
226
+ * @example
227
+ * ```typescript
228
+ * const decrypted = await processor.decryptWithWalletPrivateKey(
229
+ * encryptedHexString,
230
+ * "0x..." // 32-byte private key
231
+ * );
232
+ * console.log(`Decrypted: ${decrypted}`);
233
+ * ```
234
+ */
235
+ async decryptWithWalletPrivateKey(encryptedData, privateKey) {
236
+ const privateKeyBytes = processWalletPrivateKey(privateKey);
237
+ const encryptedBytes = hexToBytes(encryptedData);
238
+ const encrypted = parseEncryptedDataBuffer(encryptedBytes);
239
+ const decrypted = await this.eciesProvider.decrypt(
240
+ privateKeyBytes,
241
+ encrypted
242
+ );
243
+ return bytesToString(decrypted);
244
+ }
245
+ /**
246
+ * Encrypts a Uint8Array with a wallet public key
247
+ *
248
+ * @param data - Binary data to encrypt
249
+ * @param publicKey - Public key as hex string or Uint8Array
250
+ * @returns Encrypted data structure
251
+ */
252
+ async encryptBinary(data, publicKey) {
253
+ const publicKeyBytes = processWalletPublicKey(publicKey);
254
+ return this.eciesProvider.encrypt(publicKeyBytes, data);
255
+ }
256
+ /**
257
+ * Decrypts to a Uint8Array with a wallet private key
258
+ *
259
+ * @param encrypted - Encrypted data structure
260
+ * @param privateKey - Private key as hex string or Uint8Array
261
+ * @returns Decrypted binary data
262
+ */
263
+ async decryptBinary(encrypted, privateKey) {
264
+ const privateKeyBytes = processWalletPrivateKey(privateKey);
265
+ return this.eciesProvider.decrypt(privateKeyBytes, encrypted);
266
+ }
267
+ /**
268
+ * Gets the underlying ECIES provider
269
+ *
270
+ * @returns The ECIES provider instance
271
+ */
272
+ getECIESProvider() {
273
+ return this.eciesProvider;
274
+ }
275
+ };
276
+
277
+ // src/crypto/ecies/utils.ts
278
+ function hexToBytes2(hex) {
279
+ if (hex.length % 2 !== 0) {
280
+ throw new Error("Hex string must have even length");
281
+ }
282
+ const bytes = new Uint8Array(hex.length / 2);
283
+ for (let i = 0; i < hex.length; i += 2) {
284
+ bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
285
+ }
286
+ return bytes;
287
+ }
288
+ function bytesToHex2(bytes) {
289
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
290
+ }
291
+ function stringToBytes2(str) {
292
+ return new TextEncoder().encode(str);
293
+ }
294
+ function bytesToString2(bytes) {
295
+ return new TextDecoder().decode(bytes);
296
+ }
297
+ function concatBytes2(...arrays) {
298
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
299
+ const result = new Uint8Array(totalLength);
300
+ let offset = 0;
301
+ for (const arr of arrays) {
302
+ result.set(arr, offset);
303
+ offset += arr.length;
304
+ }
305
+ return result;
306
+ }
307
+ function constantTimeEqual(a, b) {
308
+ if (a.length !== b.length) return false;
309
+ let result = 0;
310
+ for (let i = 0; i < a.length; i++) {
311
+ result |= a[i] ^ b[i];
312
+ }
313
+ return result === 0;
314
+ }
315
+
59
316
  // src/platform/browser.ts
317
+ import * as secp256k12 from "@noble/secp256k1";
318
+
319
+ // src/crypto/ecies/browser.ts
320
+ import * as secp256k1 from "@noble/secp256k1";
321
+
322
+ // src/crypto/ecies/constants.ts
323
+ var CURVE = {
324
+ /** The elliptic curve used (secp256k1 - same as Bitcoin/Ethereum) */
325
+ name: "secp256k1",
326
+ /** Private key length in bytes */
327
+ PRIVATE_KEY_LENGTH: 32,
328
+ /** Compressed public key length in bytes (0x02 or 0x03 prefix + 32 bytes) */
329
+ COMPRESSED_PUBLIC_KEY_LENGTH: 33,
330
+ /** Uncompressed public key length in bytes (0x04 prefix + 64 bytes) */
331
+ UNCOMPRESSED_PUBLIC_KEY_LENGTH: 65,
332
+ /** ECDH shared secret X coordinate length */
333
+ SHARED_SECRET_LENGTH: 32,
334
+ /** Public key prefixes */
335
+ PREFIX: {
336
+ /** Uncompressed public key prefix */
337
+ UNCOMPRESSED: 4,
338
+ /** Compressed public key prefix for even Y */
339
+ COMPRESSED_EVEN: 2,
340
+ /** Compressed public key prefix for odd Y */
341
+ COMPRESSED_ODD: 3
342
+ },
343
+ /** X coordinate starts at byte 1 (after prefix) */
344
+ X_COORDINATE_OFFSET: 1,
345
+ /** X coordinate ends at byte 33 (1 + 32) */
346
+ X_COORDINATE_END: 33
347
+ };
348
+ var CIPHER = {
349
+ /** Cipher algorithm - must match eccrypto */
350
+ algorithm: "aes-256-cbc",
351
+ /** AES key length in bytes */
352
+ KEY_LENGTH: 32,
353
+ /** Initialization vector length in bytes */
354
+ IV_LENGTH: 16,
355
+ /** Block size for AES */
356
+ BLOCK_SIZE: 16
357
+ };
358
+ var KDF = {
359
+ /** Hash algorithm for key derivation - must match eccrypto */
360
+ algorithm: "sha512",
361
+ /** Output length of SHA-512 in bytes */
362
+ OUTPUT_LENGTH: 64,
363
+ /** Encryption key slice (first 32 bytes of KDF output) */
364
+ ENCRYPTION_KEY_OFFSET: 0,
365
+ ENCRYPTION_KEY_LENGTH: 32,
366
+ /** MAC key slice (last 32 bytes of KDF output) */
367
+ MAC_KEY_OFFSET: 32,
368
+ MAC_KEY_LENGTH: 32
369
+ };
370
+ var MAC = {
371
+ /** MAC algorithm - must match eccrypto */
372
+ algorithm: "sha256",
373
+ /** HMAC-SHA256 output length in bytes */
374
+ LENGTH: 32
375
+ };
376
+ var FORMAT = {
377
+ /** Offsets for each component in serialized format */
378
+ IV_OFFSET: 0,
379
+ IV_LENGTH: CIPHER.IV_LENGTH,
380
+ /** Ephemeral public key (always uncompressed in eccrypto format) */
381
+ EPHEMERAL_KEY_OFFSET: CIPHER.IV_LENGTH,
382
+ EPHEMERAL_KEY_LENGTH: CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,
383
+ /** Ciphertext starts after IV and ephemeral key */
384
+ CIPHERTEXT_OFFSET: CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,
385
+ /** MAC is always the last 32 bytes */
386
+ MAC_LENGTH: MAC.LENGTH,
387
+ /** Minimum size of encrypted data (IV + ephemKey + MAC, no ciphertext) */
388
+ MIN_ENCRYPTED_LENGTH: CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH + MAC.LENGTH,
389
+ /**
390
+ * Helper to calculate total length of encrypted data
391
+ *
392
+ * @param ciphertextLength - Length of the ciphertext portion
393
+ * @returns Total length including all components
394
+ */
395
+ getTotalLength: (ciphertextLength) => CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH + ciphertextLength + MAC.LENGTH
396
+ };
397
+
398
+ // src/crypto/ecies/interface.ts
399
+ var ECIESError = class extends Error {
400
+ constructor(message, code, cause) {
401
+ super(message);
402
+ this.code = code;
403
+ this.cause = cause;
404
+ this.name = "ECIESError";
405
+ }
406
+ };
407
+ function isECIESEncrypted(obj) {
408
+ if (!obj || typeof obj !== "object") return false;
409
+ const enc = obj;
410
+ const isUint8Array = (value) => {
411
+ return value instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(value);
412
+ };
413
+ return isUint8Array(enc.iv) && enc.iv.length === CIPHER.IV_LENGTH && isUint8Array(enc.ephemPublicKey) && (enc.ephemPublicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH || enc.ephemPublicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) && isUint8Array(enc.ciphertext) && enc.ciphertext.length > 0 && isUint8Array(enc.mac) && enc.mac.length === MAC.LENGTH;
414
+ }
415
+
416
+ // src/crypto/ecies/base.ts
417
+ var _BaseECIESUint8 = class _BaseECIESUint8 {
418
+ /**
419
+ * Normalizes a public key to uncompressed format.
420
+ *
421
+ * @param publicKey - Public key in any format.
422
+ * @returns Uncompressed public key (65 bytes).
423
+ * @throws {ECIESError} If key format is invalid.
424
+ */
425
+ normalizePublicKey(publicKey) {
426
+ if (_BaseECIESUint8.validatedKeys.has(publicKey)) {
427
+ return publicKey;
428
+ }
429
+ if (publicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH) {
430
+ if (publicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {
431
+ throw new ECIESError(
432
+ "Invalid uncompressed public key prefix",
433
+ "INVALID_KEY"
434
+ );
435
+ }
436
+ if (!this.validatePublicKey(publicKey)) {
437
+ throw new ECIESError("Invalid public key", "INVALID_KEY");
438
+ }
439
+ _BaseECIESUint8.validatedKeys.set(publicKey, true);
440
+ return publicKey;
441
+ }
442
+ if (publicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) {
443
+ const decompressed = this.decompressPublicKey(publicKey);
444
+ if (!decompressed) {
445
+ throw new ECIESError("Failed to decompress public key", "INVALID_KEY");
446
+ }
447
+ _BaseECIESUint8.validatedKeys.set(decompressed, true);
448
+ return decompressed;
449
+ }
450
+ throw new ECIESError(
451
+ `Invalid public key length: ${publicKey.length}`,
452
+ "INVALID_KEY"
453
+ );
454
+ }
455
+ /**
456
+ * Encrypts data using ECIES.
457
+ *
458
+ * @param publicKey - The recipient's public key (compressed or uncompressed)
459
+ * @param message - The data to encrypt
460
+ * @returns Promise resolving to encrypted data structure
461
+ */
462
+ async encrypt(publicKey, message) {
463
+ try {
464
+ if (!(publicKey instanceof Uint8Array)) {
465
+ throw new ECIESError("Public key must be a Uint8Array", "INVALID_KEY");
466
+ }
467
+ if (!(message instanceof Uint8Array)) {
468
+ throw new ECIESError(
469
+ "Message must be a Uint8Array",
470
+ "ENCRYPTION_FAILED"
471
+ );
472
+ }
473
+ if (publicKey.length === 0) {
474
+ throw new ECIESError("Public key cannot be empty", "INVALID_KEY");
475
+ }
476
+ const pubKey = this.normalizePublicKey(publicKey);
477
+ let ephemeralPrivateKey;
478
+ do {
479
+ ephemeralPrivateKey = this.generateRandomBytes(
480
+ CURVE.PRIVATE_KEY_LENGTH
481
+ );
482
+ } while (!this.verifyPrivateKey(ephemeralPrivateKey));
483
+ const ephemeralPublicKey = this.createPublicKey(
484
+ ephemeralPrivateKey,
485
+ false
486
+ );
487
+ if (!ephemeralPublicKey) {
488
+ throw new ECIESError(
489
+ "Failed to generate ephemeral public key",
490
+ "ENCRYPTION_FAILED"
491
+ );
492
+ }
493
+ const sharedSecret = this.performECDH(pubKey, ephemeralPrivateKey);
494
+ const kdf = this.sha512(sharedSecret);
495
+ const encryptionKey = kdf.slice(
496
+ KDF.ENCRYPTION_KEY_OFFSET,
497
+ KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH
498
+ );
499
+ const macKey = kdf.slice(
500
+ KDF.MAC_KEY_OFFSET,
501
+ KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH
502
+ );
503
+ const iv = this.generateRandomBytes(CIPHER.IV_LENGTH);
504
+ const ciphertext = await this.aesEncrypt(encryptionKey, iv, message);
505
+ const macData = concatBytes2(iv, ephemeralPublicKey, ciphertext);
506
+ const mac = this.hmacSha256(macKey, macData);
507
+ this.clearBuffer(ephemeralPrivateKey);
508
+ this.clearBuffer(sharedSecret);
509
+ this.clearBuffer(kdf);
510
+ return {
511
+ iv,
512
+ ephemPublicKey: ephemeralPublicKey,
513
+ ciphertext,
514
+ mac
515
+ };
516
+ } catch (error) {
517
+ if (error instanceof ECIESError) throw error;
518
+ throw new ECIESError(
519
+ `Encryption failed: ${error instanceof Error ? error.message : "Unknown error"}`,
520
+ "ENCRYPTION_FAILED",
521
+ error instanceof Error ? error : void 0
522
+ );
523
+ }
524
+ }
525
+ /**
526
+ * Decrypts ECIES encrypted data.
527
+ *
528
+ * @param privateKey - The recipient's private key (32 bytes)
529
+ * @param encrypted - The encrypted data structure from encrypt()
530
+ * @returns Promise resolving to the original plaintext
531
+ */
532
+ async decrypt(privateKey, encrypted) {
533
+ try {
534
+ if (!(privateKey instanceof Uint8Array)) {
535
+ throw new ECIESError("Private key must be a Uint8Array", "INVALID_KEY");
536
+ }
537
+ if (!isECIESEncrypted(encrypted)) {
538
+ throw new ECIESError(
539
+ "Invalid encrypted data structure",
540
+ "DECRYPTION_FAILED"
541
+ );
542
+ }
543
+ if (privateKey.length !== CURVE.PRIVATE_KEY_LENGTH) {
544
+ throw new ECIESError(
545
+ `Invalid private key length: ${privateKey.length}`,
546
+ "INVALID_KEY"
547
+ );
548
+ }
549
+ if (!this.verifyPrivateKey(privateKey)) {
550
+ throw new ECIESError("Invalid private key", "INVALID_KEY");
551
+ }
552
+ const ephemeralPublicKey = this.normalizePublicKey(
553
+ encrypted.ephemPublicKey
554
+ );
555
+ const sharedSecret = this.performECDH(ephemeralPublicKey, privateKey);
556
+ const kdf = this.sha512(sharedSecret);
557
+ const encryptionKey = kdf.slice(
558
+ KDF.ENCRYPTION_KEY_OFFSET,
559
+ KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH
560
+ );
561
+ const macKey = kdf.slice(
562
+ KDF.MAC_KEY_OFFSET,
563
+ KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH
564
+ );
565
+ const macData = concatBytes2(
566
+ encrypted.iv,
567
+ encrypted.ephemPublicKey,
568
+ encrypted.ciphertext
569
+ );
570
+ const expectedMac = this.hmacSha256(macKey, macData);
571
+ if (!constantTimeEqual(encrypted.mac, expectedMac)) {
572
+ throw new ECIESError("MAC verification failed", "MAC_MISMATCH");
573
+ }
574
+ const decrypted = await this.aesDecrypt(
575
+ encryptionKey,
576
+ encrypted.iv,
577
+ encrypted.ciphertext
578
+ );
579
+ this.clearBuffer(sharedSecret);
580
+ this.clearBuffer(kdf);
581
+ return decrypted;
582
+ } catch (error) {
583
+ if (error instanceof ECIESError) throw error;
584
+ throw new ECIESError(
585
+ `Decryption failed: ${error instanceof Error ? error.message : "Unknown error"}`,
586
+ "DECRYPTION_FAILED",
587
+ error instanceof Error ? error : void 0
588
+ );
589
+ }
590
+ }
591
+ /**
592
+ * Clears sensitive data from memory using multi-pass overwrite.
593
+ *
594
+ * @remarks
595
+ * Uses multiple passes with different patterns to make it harder
596
+ * for JIT compilers to optimize away the operation. While not
597
+ * guaranteed in JavaScript, this is a best-effort approach to
598
+ * clear sensitive data from memory.
599
+ *
600
+ * @param buffer - The buffer to clear
601
+ */
602
+ clearBuffer(buffer) {
603
+ if (buffer && buffer.length > 0) {
604
+ buffer.fill(0);
605
+ buffer.fill(255);
606
+ buffer.fill(170);
607
+ buffer.fill(0);
608
+ for (let i = 0; i < buffer.length; i++) {
609
+ buffer[i] = i & 255 ^ 90;
610
+ }
611
+ buffer.fill(0);
612
+ }
613
+ }
614
+ };
615
+ // Cache for validated public keys to avoid repeated validation
616
+ __publicField(_BaseECIESUint8, "validatedKeys", /* @__PURE__ */ new WeakMap());
617
+ var BaseECIESUint8 = _BaseECIESUint8;
618
+
619
+ // src/crypto/ecies/browser.ts
620
+ import { hmac } from "@noble/hashes/hmac";
621
+ import { sha256, sha512 as nobleSha512 } from "@noble/hashes/sha2";
622
+ var BrowserECIESUint8Provider = class extends BaseECIESUint8 {
623
+ generateRandomBytes(length) {
624
+ const bytes = new Uint8Array(length);
625
+ crypto.getRandomValues(bytes);
626
+ return bytes;
627
+ }
628
+ verifyPrivateKey(privateKey) {
629
+ try {
630
+ return secp256k1.utils.isValidPrivateKey(privateKey);
631
+ } catch {
632
+ return false;
633
+ }
634
+ }
635
+ createPublicKey(privateKey, compressed) {
636
+ try {
637
+ return secp256k1.getPublicKey(privateKey, compressed);
638
+ } catch {
639
+ return null;
640
+ }
641
+ }
642
+ validatePublicKey(publicKey) {
643
+ try {
644
+ secp256k1.Point.fromHex(publicKey);
645
+ return true;
646
+ } catch {
647
+ return false;
648
+ }
649
+ }
650
+ decompressPublicKey(publicKey) {
651
+ try {
652
+ const point = secp256k1.Point.fromHex(publicKey);
653
+ return point.toRawBytes(false);
654
+ } catch {
655
+ return null;
656
+ }
657
+ }
658
+ performECDH(publicKey, privateKey) {
659
+ try {
660
+ const sharedPoint = secp256k1.getSharedSecret(
661
+ privateKey,
662
+ publicKey,
663
+ true
664
+ );
665
+ return sharedPoint.slice(1);
666
+ } catch (error) {
667
+ throw new Error(
668
+ `ECDH failed: ${error instanceof Error ? error.message : "Unknown error"}`
669
+ );
670
+ }
671
+ }
672
+ sha512(data) {
673
+ return nobleSha512(data);
674
+ }
675
+ hmacSha256(key, data) {
676
+ return hmac(sha256, key, data);
677
+ }
678
+ async aesEncrypt(key, iv, plaintext) {
679
+ const cryptoKey = await crypto.subtle.importKey(
680
+ "raw",
681
+ key,
682
+ { name: "AES-CBC" },
683
+ false,
684
+ ["encrypt"]
685
+ );
686
+ const encrypted = await crypto.subtle.encrypt(
687
+ { name: "AES-CBC", iv },
688
+ cryptoKey,
689
+ plaintext
690
+ );
691
+ return new Uint8Array(encrypted);
692
+ }
693
+ async aesDecrypt(key, iv, ciphertext) {
694
+ const cryptoKey = await crypto.subtle.importKey(
695
+ "raw",
696
+ key,
697
+ { name: "AES-CBC" },
698
+ false,
699
+ ["decrypt"]
700
+ );
701
+ const decrypted = await crypto.subtle.decrypt(
702
+ { name: "AES-CBC", iv },
703
+ cryptoKey,
704
+ ciphertext
705
+ );
706
+ return new Uint8Array(decrypted);
707
+ }
708
+ };
709
+
710
+ // src/platform/browser.ts
711
+ var getOpenPGP = lazyImport(() => import("openpgp"));
60
712
  var BrowserCryptoAdapter = class {
713
+ constructor() {
714
+ __publicField(this, "eciesProvider", new BrowserECIESUint8Provider());
715
+ __publicField(this, "walletKeyEncryptionService", new WalletKeyEncryptionService({
716
+ eciesProvider: this.eciesProvider
717
+ }));
718
+ }
61
719
  async encryptWithPublicKey(data, publicKeyHex) {
62
720
  try {
63
- const eccrypto = await import("eccrypto-js");
64
- const publicKeyBuffer = Buffer.from(publicKeyHex, "hex");
65
- const encrypted = await eccrypto.encrypt(
66
- publicKeyBuffer,
67
- Buffer.from(data, "utf8")
721
+ const publicKeyBytes = hexToBytes2(publicKeyHex);
722
+ const encrypted = await this.eciesProvider.encrypt(
723
+ publicKeyBytes,
724
+ stringToBytes2(data)
68
725
  );
69
- const result = Buffer.concat([
726
+ const result = concatBytes2(
70
727
  encrypted.iv,
71
728
  encrypted.ephemPublicKey,
72
729
  encrypted.ciphertext,
73
730
  encrypted.mac
74
- ]);
75
- return result.toString("hex");
731
+ );
732
+ return bytesToHex2(result);
76
733
  } catch (error) {
77
- throw new Error(`Encryption failed: ${error}`);
734
+ throw wrapCryptoError("encryptWithPublicKey", error);
78
735
  }
79
736
  }
80
737
  async decryptWithPrivateKey(encryptedData, privateKeyHex) {
81
738
  try {
82
- const eccrypto = await import("eccrypto-js");
83
- const privateKeyBuffer = processWalletPrivateKey(privateKeyHex);
84
- const encryptedBuffer = Buffer.from(encryptedData, "hex");
85
- const { iv, ephemPublicKey, ciphertext, mac } = parseEncryptedDataBuffer(encryptedBuffer);
86
- const encryptedObj = { iv, ephemPublicKey, ciphertext, mac };
87
- const decryptedBuffer = await eccrypto.decrypt(
88
- privateKeyBuffer,
89
- encryptedObj
739
+ const encryptedBytes = hexToBytes2(encryptedData);
740
+ const privateKeyBytes = hexToBytes2(privateKeyHex);
741
+ const encrypted = parseEncryptedDataBuffer(encryptedBytes);
742
+ const decrypted = await this.eciesProvider.decrypt(
743
+ privateKeyBytes,
744
+ encrypted
90
745
  );
91
- return decryptedBuffer.toString("utf8");
746
+ return bytesToString2(decrypted);
92
747
  } catch (error) {
93
- throw new Error(`Decryption failed: ${error}`);
748
+ throw wrapCryptoError("decryptWithPrivateKey", error);
94
749
  }
95
750
  }
96
- async generateKeyPair() {
751
+ async encryptWithWalletPublicKey(data, publicKey) {
97
752
  try {
98
- const eccrypto = await import("eccrypto-js");
99
- const privateKeyBytes = new Uint8Array(32);
100
- crypto.getRandomValues(privateKeyBytes);
101
- const privateKey = Buffer.from(privateKeyBytes);
102
- const publicKey = eccrypto.getPublicCompressed(privateKey);
103
- return {
104
- privateKey: privateKey.toString("hex"),
105
- publicKey: publicKey.toString("hex")
106
- };
753
+ return await this.walletKeyEncryptionService.encryptWithWalletPublicKey(
754
+ data,
755
+ publicKey
756
+ );
107
757
  } catch (error) {
108
- throw wrapCryptoError("key generation", error);
758
+ throw wrapCryptoError("encryptWithWalletPublicKey", error);
109
759
  }
110
760
  }
111
- async encryptWithWalletPublicKey(data, publicKey) {
761
+ async decryptWithWalletPrivateKey(encryptedData, privateKey) {
112
762
  try {
113
- const eccrypto = await import("eccrypto-js");
114
- const uncompressedKey = processWalletPublicKey(publicKey);
115
- const encryptedBuffer = await eccrypto.encrypt(
116
- uncompressedKey,
117
- Buffer.from(data)
763
+ return await this.walletKeyEncryptionService.decryptWithWalletPrivateKey(
764
+ encryptedData,
765
+ privateKey
118
766
  );
119
- const result = Buffer.concat([
120
- encryptedBuffer.iv,
121
- encryptedBuffer.ephemPublicKey,
122
- encryptedBuffer.ciphertext,
123
- encryptedBuffer.mac
124
- ]);
125
- return result.toString("hex");
126
767
  } catch (error) {
127
- throw wrapCryptoError("encrypt with wallet public key", error);
768
+ throw wrapCryptoError("decryptWithWalletPrivateKey", error);
128
769
  }
129
770
  }
130
- async decryptWithWalletPrivateKey(encryptedData, privateKey) {
771
+ async generateKeyPair() {
131
772
  try {
132
- const eccrypto = await import("eccrypto-js");
133
- const privateKeyBuffer = processWalletPrivateKey(privateKey);
134
- const encryptedBuffer = Buffer.from(encryptedData, "hex");
135
- const { iv, ephemPublicKey, ciphertext, mac } = parseEncryptedDataBuffer(encryptedBuffer);
136
- const encryptedObj = { iv, ephemPublicKey, ciphertext, mac };
137
- const decryptedBuffer = await eccrypto.decrypt(
138
- privateKeyBuffer,
139
- encryptedObj
140
- );
141
- return decryptedBuffer.toString("utf8");
773
+ const privateKeyBytes = secp256k12.utils.randomPrivateKey();
774
+ const publicKeyBytes = secp256k12.getPublicKey(privateKeyBytes, true);
775
+ return {
776
+ privateKey: bytesToHex2(privateKeyBytes),
777
+ publicKey: bytesToHex2(publicKeyBytes)
778
+ };
142
779
  } catch (error) {
143
- throw wrapCryptoError("decrypt with wallet private key", error);
780
+ throw wrapCryptoError("generateKeyPair", error);
144
781
  }
145
782
  }
146
783
  async encryptWithPassword(data, password) {
147
784
  try {
148
- const openpgp2 = await import("openpgp");
149
- const message = await openpgp2.createMessage({
150
- binary: data
151
- });
152
- const encrypted = await openpgp2.encrypt({
785
+ const openpgp = await getOpenPGP();
786
+ const message = await openpgp.createMessage({ binary: data });
787
+ const encrypted = await openpgp.encrypt({
153
788
  message,
154
789
  passwords: [password],
155
790
  format: "binary"
156
791
  });
157
- const response = new Response(encrypted);
158
- const arrayBuffer = await response.arrayBuffer();
159
- return new Uint8Array(arrayBuffer);
792
+ return new Uint8Array(encrypted);
160
793
  } catch (error) {
161
- throw new Error(`Failed to encrypt with password: ${error}`);
794
+ throw wrapCryptoError("encryptWithPassword", error);
162
795
  }
163
796
  }
164
797
  async decryptWithPassword(encryptedData, password) {
165
798
  try {
166
- const openpgp2 = await import("openpgp");
167
- const message = await openpgp2.readMessage({
799
+ const openpgp = await getOpenPGP();
800
+ const message = await openpgp.readMessage({
168
801
  binaryMessage: encryptedData
169
802
  });
170
- const { data: decrypted } = await openpgp2.decrypt({
803
+ const { data } = await openpgp.decrypt({
171
804
  message,
172
805
  passwords: [password],
173
806
  format: "binary"
174
807
  });
175
- return new Uint8Array(decrypted);
808
+ return new Uint8Array(data);
176
809
  } catch (error) {
177
- throw new Error(`Failed to decrypt with password: ${error}`);
810
+ throw wrapCryptoError("decryptWithPassword", error);
178
811
  }
179
812
  }
180
813
  };
181
814
  var BrowserPGPAdapter = class {
182
815
  async encrypt(data, publicKeyArmored) {
183
816
  try {
817
+ const openpgp = await getOpenPGP();
184
818
  const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
185
819
  const encrypted = await openpgp.encrypt({
186
820
  message: await openpgp.createMessage({ text: data }),
@@ -196,6 +830,7 @@ var BrowserPGPAdapter = class {
196
830
  }
197
831
  async decrypt(encryptedData, privateKeyArmored) {
198
832
  try {
833
+ const openpgp = await getOpenPGP();
199
834
  const privateKey = await openpgp.readPrivateKey({
200
835
  armoredKey: privateKeyArmored
201
836
  });
@@ -213,6 +848,7 @@ var BrowserPGPAdapter = class {
213
848
  }
214
849
  async generateKeyPair(options) {
215
850
  try {
851
+ const openpgp = await getOpenPGP();
216
852
  const keyGenParams = getPGPKeyGenParams(options);
217
853
  const { privateKey, publicKey } = await openpgp.generateKey(keyGenParams);
218
854
  return { publicKey, privateKey };
@@ -223,9 +859,6 @@ var BrowserPGPAdapter = class {
223
859
  };
224
860
  var BrowserHttpAdapter = class {
225
861
  async fetch(url, options) {
226
- if (typeof fetch === "undefined") {
227
- throw new Error("Fetch API not available in this browser environment");
228
- }
229
862
  return fetch(url, options);
230
863
  }
231
864
  };
@@ -245,17 +878,19 @@ var BrowserCacheAdapter = class {
245
878
  }
246
879
  set(key, value) {
247
880
  try {
248
- if (typeof sessionStorage !== "undefined") {
249
- sessionStorage.setItem(this.prefix + key, value);
881
+ if (typeof sessionStorage === "undefined") {
882
+ return;
250
883
  }
884
+ sessionStorage.setItem(this.prefix + key, value);
251
885
  } catch {
252
886
  }
253
887
  }
254
888
  delete(key) {
255
889
  try {
256
- if (typeof sessionStorage !== "undefined") {
257
- sessionStorage.removeItem(this.prefix + key);
890
+ if (typeof sessionStorage === "undefined") {
891
+ return;
258
892
  }
893
+ sessionStorage.removeItem(this.prefix + key);
259
894
  } catch {
260
895
  }
261
896
  }
@@ -264,30 +899,27 @@ var BrowserCacheAdapter = class {
264
899
  if (typeof sessionStorage === "undefined") {
265
900
  return;
266
901
  }
267
- const keys = Object.keys(sessionStorage);
268
- for (const key of keys) {
269
- if (key.startsWith(this.prefix)) {
270
- sessionStorage.removeItem(key);
902
+ const keysToRemove = [];
903
+ for (let i = 0; i < sessionStorage.length; i++) {
904
+ const key = sessionStorage.key(i);
905
+ if (key?.startsWith(this.prefix)) {
906
+ keysToRemove.push(key);
271
907
  }
272
908
  }
909
+ keysToRemove.forEach((key) => sessionStorage.removeItem(key));
273
910
  } catch {
274
911
  }
275
912
  }
276
913
  };
277
914
  var BrowserPlatformAdapter = class {
278
915
  constructor() {
279
- __publicField(this, "crypto");
280
- __publicField(this, "pgp");
281
- __publicField(this, "http");
282
- __publicField(this, "cache");
916
+ __publicField(this, "crypto", new BrowserCryptoAdapter());
917
+ __publicField(this, "pgp", new BrowserPGPAdapter());
918
+ __publicField(this, "http", new BrowserHttpAdapter());
919
+ __publicField(this, "cache", new BrowserCacheAdapter());
283
920
  __publicField(this, "platform", "browser");
284
- this.crypto = new BrowserCryptoAdapter();
285
- this.pgp = new BrowserPGPAdapter();
286
- this.http = new BrowserHttpAdapter();
287
- this.cache = new BrowserCacheAdapter();
288
921
  }
289
922
  };
290
- var browserPlatformAdapter = new BrowserPlatformAdapter();
291
923
  export {
292
924
  BrowserPlatformAdapter
293
925
  };