@opendatalabs/vana-sdk 0.1.0-alpha.c3ea747 → 0.1.0-alpha.ca99685

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