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